mirror of
https://github.com/gnustep/libs-gui.git
synced 2025-04-25 05:10:57 +00:00
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@3222 72102866-910b-0410-8b05-ffd578937521
621 lines
17 KiB
Objective-C
621 lines
17 KiB
Objective-C
/*
|
|
NSEvent.m
|
|
|
|
The event class
|
|
|
|
Copyright (C) 1996 Free Software Foundation, Inc.
|
|
|
|
Author: Scott Christley <scottc@net-community.com>
|
|
Author: Ovidiu Predescu <ovidiu@net-community.com>
|
|
Date: 1996
|
|
Author: Felipe A. Rodriguez <far@ix.netcom.com>
|
|
Date: Sept 1998
|
|
|
|
This file is part of the GNUstep GUI Library.
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Library General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Library General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public
|
|
License along with this library; see the file COPYING.LIB.
|
|
If not, write to the Free Software Foundation,
|
|
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
#include <gnustep/gui/config.h>
|
|
#include <Foundation/NSDictionary.h>
|
|
#include <Foundation/NSLock.h>
|
|
#include <Foundation/NSTimer.h>
|
|
#include <Foundation/NSRunLoop.h>
|
|
#include <Foundation/NSThread.h>
|
|
#include <Foundation/NSValue.h>
|
|
#include <Foundation/NSException.h>
|
|
|
|
#include <AppKit/NSEvent.h>
|
|
#include <AppKit/NSApplication.h>
|
|
#include <AppKit/NSWindow.h>
|
|
#include <AppKit/GPSDrawContext.h>
|
|
|
|
@implementation NSEvent
|
|
|
|
// Class variables
|
|
static NSString *timerKey = @"NSEventTimersKey";
|
|
|
|
//
|
|
// Class methods
|
|
//
|
|
+ (void)initialize
|
|
{
|
|
if (self == [NSEvent class])
|
|
{
|
|
NSDebugLog(@"Initialize NSEvent class\n");
|
|
[self setVersion:1]; // Initial version
|
|
}
|
|
}
|
|
|
|
//
|
|
// Creating NSEvent objects
|
|
//
|
|
+ (NSEvent *)enterExitEventWithType:(NSEventType)type
|
|
location:(NSPoint)location
|
|
modifierFlags:(unsigned int)flags
|
|
timestamp:(NSTimeInterval)time
|
|
windowNumber:(int)windowNum
|
|
context:(GPSDrawContext *)context
|
|
eventNumber:(int)eventNum
|
|
trackingNumber:(int)trackingNum
|
|
userData:(void *)userData
|
|
{
|
|
NSEvent *e = [[[NSEvent alloc] init] autorelease];
|
|
// do nothing if
|
|
if ((type != NSMouseEntered) && (type != NSMouseExited) // event is not of
|
|
&& (type != NSCursorUpdate)) // a desired type
|
|
return nil;
|
|
|
|
e->event_type = type; // Set the event's
|
|
e->location_point = location; // fields
|
|
e->modifier_flags = flags;
|
|
e->event_time = time;
|
|
e->window_num = windowNum;
|
|
e->event_context = context;
|
|
e->event_data.tracking.event_num = eventNum;
|
|
e->event_data.tracking.tracking_num = trackingNum;
|
|
e->event_data.tracking.user_data = userData;
|
|
|
|
return e;
|
|
}
|
|
|
|
+ (NSEvent *)keyEventWithType:(NSEventType)type
|
|
location:(NSPoint)location
|
|
modifierFlags:(unsigned int)flags
|
|
timestamp:(NSTimeInterval)time
|
|
windowNumber:(int)windowNum
|
|
context:(GPSDrawContext *)context
|
|
characters:(NSString *)keys
|
|
charactersIgnoringModifiers:(NSString *)ukeys
|
|
isARepeat:(BOOL)repeatKey
|
|
keyCode:(unsigned short)code
|
|
{
|
|
NSEvent *e = [[[NSEvent alloc] init] autorelease];
|
|
// do nothing if
|
|
if ((type != NSKeyDown) && (type != NSKeyUp)) // event is not of
|
|
return nil; // a desired type
|
|
|
|
e->event_type = type; // Set the event's
|
|
e->location_point = location; // fields
|
|
e->modifier_flags = flags;
|
|
e->event_time = time;
|
|
e->window_num = windowNum;
|
|
e->event_context = context;
|
|
[keys retain];
|
|
e->event_data.key.char_keys = keys;
|
|
[ukeys retain];
|
|
e->event_data.key.unmodified_keys = ukeys;
|
|
e->event_data.key.repeat = repeatKey;
|
|
e->event_data.key.key_code = code;
|
|
|
|
return e;
|
|
}
|
|
|
|
+ (NSEvent *)mouseEventWithType:(NSEventType)type
|
|
location:(NSPoint)location
|
|
modifierFlags:(unsigned int)flags
|
|
timestamp:(NSTimeInterval)time
|
|
windowNumber:(int)windowNum
|
|
context:(GPSDrawContext *)context
|
|
eventNumber:(int)eventNum
|
|
clickCount:(int)clickNum
|
|
pressure:(float)pressureValue
|
|
{
|
|
NSEvent *e = [[[NSEvent alloc] init] autorelease]; // do nothing if
|
|
// event is not of
|
|
if ((type != NSMouseMoved) && (type != NSLeftMouseUp) // a desired type
|
|
&& (type != NSLeftMouseDown) && (type != NSRightMouseDown)
|
|
&& (type != NSRightMouseUp) && (type != NSLeftMouseDragged)
|
|
&& (type != NSRightMouseDragged))
|
|
return nil;
|
|
|
|
e->event_type = type; // Set the event's
|
|
e->location_point = location; // fields
|
|
e->modifier_flags = flags;
|
|
e->event_time = time;
|
|
e->window_num = windowNum;
|
|
e->event_context = context;
|
|
e->event_data.mouse.event_num = eventNum;
|
|
e->event_data.mouse.click = clickNum;
|
|
e->event_data.mouse.pressure = pressureValue;
|
|
|
|
return e;
|
|
}
|
|
|
|
+ (NSEvent *)otherEventWithType:(NSEventType)type
|
|
location:(NSPoint)location
|
|
modifierFlags:(unsigned int)flags
|
|
timestamp:(NSTimeInterval)time
|
|
windowNumber:(int)windowNum
|
|
context:(GPSDrawContext *)context
|
|
subtype:(short)subType
|
|
data1:(int)data1
|
|
data2:(int)data2
|
|
{
|
|
NSEvent *e = [[[NSEvent alloc] init] autorelease];
|
|
// do nothing if
|
|
if ((type != NSFlagsChanged) && (type != NSPeriodic)) // event is not of
|
|
return nil; // a desired type
|
|
|
|
e->event_type = type; // Set the event's
|
|
e->location_point = location; // fields
|
|
e->modifier_flags = flags;
|
|
e->event_time = time;
|
|
e->window_num = windowNum;
|
|
e->event_context = context;
|
|
e->event_data.misc.sub_type = subType;
|
|
e->event_data.misc.data1 = data1;
|
|
e->event_data.misc.data2 = data2;
|
|
|
|
return e;
|
|
}
|
|
|
|
//
|
|
// Requesting Periodic Events
|
|
//
|
|
+ (void)startPeriodicEventsAfterDelay:(NSTimeInterval)delaySeconds
|
|
withPeriod:(NSTimeInterval)periodSeconds
|
|
{
|
|
NSTimer* timer;
|
|
NSMutableDictionary *dict = [[NSThread currentThread] threadDictionary];
|
|
|
|
NSDebugLog (@"startPeriodicEventsAfterDelay:withPeriod:");
|
|
// Check this thread
|
|
if ([dict objectForKey: timerKey]) // for a pending timer
|
|
[NSException raise:NSInternalInconsistencyException
|
|
format:@"Periodic events are already being generated for "
|
|
@"this thread %x", [NSThread currentThread]];
|
|
// If the delay time is 0 then register
|
|
// a timer immediately. Otherwise
|
|
// register a timer with no repeat that
|
|
if (!delaySeconds) // when fired registers the real timer
|
|
timer = [NSTimer timerWithTimeInterval:periodSeconds // register an
|
|
target:self // immediate
|
|
selector:@selector(_timerFired:) // timer
|
|
userInfo:nil
|
|
repeats:YES];
|
|
else // register a one
|
|
timer = [NSTimer timerWithTimeInterval:delaySeconds // shot timer to
|
|
target:self // register a timer
|
|
selector:@selector(_registerRealTimer:)
|
|
userInfo:[NSNumber numberWithDouble:periodSeconds]
|
|
repeats:NO];
|
|
|
|
[[NSRunLoop currentRunLoop] addTimer: timer
|
|
forMode: NSEventTrackingRunLoopMode];
|
|
[dict setObject: timer forKey: timerKey];
|
|
}
|
|
|
|
+ (void)_timerFired:(NSTimer*)timer
|
|
{
|
|
NSTimeInterval timeInterval = [[NSDate date] timeIntervalSinceReferenceDate];
|
|
NSApplication *theApp = [NSApplication sharedApplication];
|
|
NSEvent* periodicEvent = [self otherEventWithType:NSPeriodic
|
|
location:NSZeroPoint
|
|
modifierFlags:0
|
|
timestamp:timeInterval
|
|
windowNumber:0
|
|
context:[theApp context]
|
|
subtype:0
|
|
data1:0
|
|
data2:0];
|
|
|
|
NSDebugLog (@"_timerFired:");
|
|
[theApp postEvent:periodicEvent atStart:NO]; // place a periodic
|
|
} // event in the queue
|
|
|
|
+ (void)_registerRealTimer:(NSTimer*)timer // this method provides a
|
|
{ // means of delaying the
|
|
NSTimer* realTimer; // start of periodic events
|
|
NSMutableDictionary *dict = [[NSThread currentThread] threadDictionary];
|
|
|
|
NSDebugLog (@"_registerRealTimer:");
|
|
|
|
realTimer = [NSTimer timerWithTimeInterval:[[timer userInfo] doubleValue]
|
|
target:self
|
|
selector:@selector(_timerFired:)
|
|
userInfo:nil
|
|
repeats:YES]; // Add the real timer to the timers
|
|
// dictionary and to the run loop
|
|
[dict setObject: realTimer forKey: timerKey];
|
|
[[NSRunLoop currentRunLoop] addTimer: realTimer
|
|
forMode: NSEventTrackingRunLoopMode];
|
|
}
|
|
|
|
+ (void)stopPeriodicEvents
|
|
{
|
|
NSTimer* timer;
|
|
NSMutableDictionary *dict = [[NSThread currentThread] threadDictionary];
|
|
|
|
NSDebugLog (@"stopPeriodicEvents");
|
|
// Remove any existing
|
|
timer = [dict objectForKey: timerKey]; // timer for this thread
|
|
[timer invalidate];
|
|
[dict removeObjectForKey: timerKey];
|
|
}
|
|
|
|
//
|
|
// Instance methods
|
|
//
|
|
- (void)dealloc
|
|
{
|
|
if ((event_type == NSKeyUp) || (event_type == NSKeyDown))
|
|
{
|
|
[event_data.key.char_keys release];
|
|
[event_data.key.unmodified_keys release];
|
|
}
|
|
|
|
[super dealloc];
|
|
}
|
|
|
|
//
|
|
// Getting General Event Information
|
|
//
|
|
- (GPSDrawContext *)context
|
|
{
|
|
return event_context;
|
|
}
|
|
|
|
- (NSPoint)locationInWindow
|
|
{
|
|
return location_point;
|
|
}
|
|
|
|
- (unsigned int)modifierFlags
|
|
{
|
|
return modifier_flags;
|
|
}
|
|
|
|
- (NSTimeInterval)timestamp
|
|
{
|
|
return event_time;
|
|
}
|
|
|
|
- (NSEventType)type
|
|
{
|
|
return event_type;
|
|
}
|
|
|
|
- (NSWindow *)window
|
|
{
|
|
return [NSWindow windowWithNumber:window_num];
|
|
}
|
|
|
|
- (int)windowNumber
|
|
{
|
|
return window_num;
|
|
}
|
|
|
|
//
|
|
// Getting Key Event Information
|
|
//
|
|
- (NSString *)characters
|
|
{
|
|
if ((event_type != NSKeyUp) && (event_type != NSKeyDown))
|
|
return nil;
|
|
|
|
return event_data.key.char_keys;
|
|
}
|
|
|
|
- (NSString *)charactersIgnoringModifiers
|
|
{
|
|
if ((event_type != NSKeyUp) && (event_type != NSKeyDown))
|
|
return nil;
|
|
|
|
return event_data.key.unmodified_keys;
|
|
}
|
|
|
|
- (BOOL)isARepeat
|
|
{
|
|
if ((event_type != NSKeyUp) && (event_type != NSKeyDown))
|
|
return NO;
|
|
|
|
return event_data.key.repeat;
|
|
}
|
|
|
|
- (unsigned short)keyCode
|
|
{
|
|
if ((event_type != NSKeyUp) && (event_type != NSKeyDown))
|
|
return 0;
|
|
|
|
return event_data.key.key_code;
|
|
}
|
|
|
|
//
|
|
// Getting Mouse Event Information
|
|
//
|
|
- (int)clickCount
|
|
{
|
|
// Make sure it is one of the right event types
|
|
if ((event_type != NSLeftMouseDown) && (event_type != NSLeftMouseUp) &&
|
|
(event_type != NSRightMouseDown) && (event_type != NSRightMouseUp) &&
|
|
(event_type != NSLeftMouseDragged) && (event_type != NSRightMouseDragged) &&
|
|
(event_type != NSMouseMoved))
|
|
return 0;
|
|
|
|
return event_data.mouse.click;
|
|
}
|
|
|
|
- (int)eventNumber
|
|
{
|
|
// Make sure it is one of the right event types
|
|
if ((event_type != NSLeftMouseDown) && (event_type != NSLeftMouseUp) &&
|
|
(event_type != NSRightMouseDown) && (event_type != NSRightMouseUp) &&
|
|
(event_type != NSLeftMouseDragged) && (event_type != NSRightMouseDragged) &&
|
|
(event_type != NSMouseMoved) &&
|
|
(event_type != NSMouseEntered) && (event_type != NSMouseExited))
|
|
return 0;
|
|
|
|
if ((event_type == NSMouseEntered) || (event_type == NSMouseExited))
|
|
return event_data.tracking.event_num;
|
|
else
|
|
return event_data.mouse.event_num;
|
|
}
|
|
|
|
- (float)pressure
|
|
{
|
|
// Make sure it is one of the right event types
|
|
if ((event_type != NSLeftMouseDown) && (event_type != NSLeftMouseUp) &&
|
|
(event_type != NSRightMouseDown) && (event_type != NSRightMouseUp) &&
|
|
(event_type != NSLeftMouseDragged) && (event_type != NSRightMouseDragged) &&
|
|
(event_type != NSMouseMoved))
|
|
return 0;
|
|
|
|
return event_data.mouse.pressure;
|
|
}
|
|
|
|
//
|
|
// Getting Tracking Event Information
|
|
//
|
|
- (int)trackingNumber
|
|
{
|
|
if ((event_type != NSMouseEntered) && (event_type != NSMouseExited)
|
|
&& (event_type != NSCursorUpdate))
|
|
return 0;
|
|
|
|
return event_data.tracking.tracking_num;
|
|
}
|
|
|
|
- (void *)userData
|
|
{
|
|
if ((event_type != NSMouseEntered) && (event_type != NSMouseExited)
|
|
&& (event_type != NSCursorUpdate))
|
|
return NULL;
|
|
|
|
return event_data.tracking.user_data;
|
|
}
|
|
|
|
//
|
|
// Getting Information about Specially Defined Events
|
|
//
|
|
- (int)data1
|
|
{
|
|
// Make sure it is one of the right event types
|
|
if ((event_type != NSFlagsChanged) && (event_type != NSPeriodic))
|
|
return 0;
|
|
|
|
return event_data.misc.data1;
|
|
}
|
|
|
|
- (int)data2
|
|
{
|
|
// Make sure it is one of the right event types
|
|
if ((event_type != NSFlagsChanged) && (event_type != NSPeriodic))
|
|
return 0;
|
|
|
|
return event_data.misc.data2;
|
|
}
|
|
|
|
- (short)subtype
|
|
{
|
|
// Make sure it is one of the right event types
|
|
if ((event_type != NSFlagsChanged) && (event_type != NSPeriodic))
|
|
return 0;
|
|
|
|
return event_data.misc.sub_type;;
|
|
}
|
|
|
|
//
|
|
// NSCoding protocol
|
|
//
|
|
- (void)encodeWithCoder:aCoder
|
|
{
|
|
[aCoder encodeValueOfObjCType: @encode(NSEventType) at: &event_type];
|
|
[aCoder encodePoint: location_point];
|
|
[aCoder encodeValueOfObjCType: "I" at: &modifier_flags];
|
|
[aCoder encodeValueOfObjCType: @encode(NSTimeInterval) at: &event_time];
|
|
[aCoder encodeValueOfObjCType: "i" at: &window_num];
|
|
// We don't want to encode the context, right?
|
|
// DPSContext doesn't conform to NSCoding
|
|
//[aCoder encodeObjectReference: event_context withName: @"Context"];
|
|
|
|
// Encode the event date based upon the event type
|
|
switch (event_type)
|
|
{
|
|
case NSLeftMouseDown:
|
|
case NSLeftMouseUp:
|
|
case NSRightMouseDown:
|
|
case NSRightMouseUp:
|
|
case NSMouseMoved:
|
|
case NSLeftMouseDragged:
|
|
case NSRightMouseDragged:
|
|
[aCoder encodeValuesOfObjCTypes: "iif", &event_data.mouse.event_num,
|
|
&event_data.mouse.click, &event_data.mouse.pressure];
|
|
break;
|
|
|
|
case NSMouseEntered:
|
|
case NSMouseExited:
|
|
case NSCursorUpdate:
|
|
// Can't do anything with the user_data!?
|
|
[aCoder encodeValuesOfObjCTypes: "ii", &event_data.tracking.event_num,
|
|
&event_data.tracking.tracking_num];
|
|
break;
|
|
|
|
case NSKeyDown:
|
|
case NSKeyUp:
|
|
[aCoder encodeValueOfObjCType: @encode(BOOL) at: &event_data.key.repeat];
|
|
[aCoder encodeObject: event_data.key.char_keys];
|
|
[aCoder encodeObject: event_data.key.unmodified_keys];
|
|
[aCoder encodeValueOfObjCType: "S" at: &event_data.key.key_code];
|
|
break;
|
|
|
|
case NSFlagsChanged:
|
|
case NSPeriodic:
|
|
[aCoder encodeValuesOfObjCTypes: "sii", &event_data.misc.sub_type,
|
|
&event_data.misc.data1, &event_data.misc.data2];
|
|
break;
|
|
}
|
|
}
|
|
|
|
- initWithCoder:aDecoder
|
|
{
|
|
[aDecoder decodeValueOfObjCType: @encode(NSEventType) at: &event_type];
|
|
location_point = [aDecoder decodePoint];
|
|
[aDecoder decodeValueOfObjCType: "I" at: &modifier_flags];
|
|
[aDecoder decodeValueOfObjCType: @encode(NSTimeInterval) at: &event_time];
|
|
[aDecoder decodeValueOfObjCType: "i" at: &window_num];
|
|
|
|
// Decode the event date based upon the event type
|
|
switch (event_type)
|
|
{
|
|
case NSLeftMouseDown:
|
|
case NSLeftMouseUp:
|
|
case NSRightMouseDown:
|
|
case NSRightMouseUp:
|
|
case NSMouseMoved:
|
|
case NSLeftMouseDragged:
|
|
case NSRightMouseDragged:
|
|
[aDecoder decodeValuesOfObjCTypes: "iif", &event_data.mouse.event_num,
|
|
&event_data.mouse.click, &event_data.mouse.pressure];
|
|
break;
|
|
|
|
case NSMouseEntered:
|
|
case NSMouseExited:
|
|
case NSCursorUpdate:
|
|
// Can't do anything with the user_data!?
|
|
[aDecoder decodeValuesOfObjCTypes: "ii", &event_data.tracking.event_num,
|
|
&event_data.tracking.tracking_num];
|
|
break;
|
|
|
|
case NSKeyDown:
|
|
case NSKeyUp:
|
|
[aDecoder decodeValueOfObjCType: @encode(BOOL)
|
|
at: &event_data.key.repeat];
|
|
event_data.key.char_keys = [aDecoder decodeObject];
|
|
event_data.key.unmodified_keys = [aDecoder decodeObject];
|
|
[aDecoder decodeValueOfObjCType: "S" at: &event_data.key.key_code];
|
|
break;
|
|
|
|
case NSFlagsChanged:
|
|
case NSPeriodic:
|
|
[aDecoder decodeValuesOfObjCTypes: "sii", &event_data.misc.sub_type,
|
|
&event_data.misc.data1, &event_data.misc.data2];
|
|
break;
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
- (NSString*)description
|
|
{
|
|
const char* eventTypes[] = { "leftMouseDown", "leftMouseUp",
|
|
"rightMouseDown", "rightMouseUp", "mouseMoved", "leftMouseDragged",
|
|
"rightMouseDragged", "mouseEntered", "mouseExited", "keyDown", "keyUp",
|
|
"flagsChanged", "periodic", "cursorUpdate"
|
|
};
|
|
|
|
switch (event_type) {
|
|
case NSLeftMouseDown:
|
|
case NSLeftMouseUp:
|
|
case NSRightMouseDown:
|
|
case NSRightMouseUp:
|
|
case NSMouseMoved:
|
|
case NSLeftMouseDragged:
|
|
case NSRightMouseDragged:
|
|
return [NSString stringWithFormat:
|
|
@"NSEvent: eventType = %s, point = { %f, %f }, modifiers = %u,"
|
|
@" time = %f, window = %d, dpsContext = %p,"
|
|
@" event number = %d, click = %d, pressure = %f",
|
|
eventTypes[event_type], location_point.x, location_point.y,
|
|
modifier_flags, event_time, window_num, event_context,
|
|
event_data.mouse.event_num, event_data.mouse.click,
|
|
event_data.mouse.pressure];
|
|
break;
|
|
|
|
case NSMouseEntered:
|
|
case NSMouseExited:
|
|
return [NSString stringWithFormat:
|
|
@"NSEvent: eventType = %s, point = { %f, %f }, modifiers = %u,"
|
|
@" time = %f, window = %d, dpsContext = %p, "
|
|
@" event number = %d, tracking number = %d, user data = %p",
|
|
eventTypes[event_type], location_point.x, location_point.y,
|
|
modifier_flags, event_time, window_num, event_context,
|
|
event_data.tracking.event_num,
|
|
event_data.tracking.tracking_num,
|
|
event_data.tracking.user_data];
|
|
break;
|
|
|
|
case NSKeyDown:
|
|
case NSKeyUp:
|
|
return [NSString stringWithFormat:
|
|
@"NSEvent: eventType = %s, point = { %f, %f }, modifiers = %u,"
|
|
@" time = %f, window = %d, dpsContext = %p, "
|
|
@" repeat = %s, keys = %@, ukeys = %@, keyCode = 0x%x",
|
|
eventTypes[event_type], location_point.x, location_point.y,
|
|
modifier_flags, event_time, window_num, event_context,
|
|
(event_data.key.repeat ? "YES" : "NO"),
|
|
event_data.key.char_keys, event_data.key.unmodified_keys,
|
|
event_data.key.key_code];
|
|
break;
|
|
|
|
case NSFlagsChanged:
|
|
case NSPeriodic:
|
|
case NSCursorUpdate:
|
|
return [NSString stringWithFormat:
|
|
@"NSEvent: eventType = %s, point = { %f, %f }, modifiers = %u,"
|
|
@" time = %f, window = %d, dpsContext = %p, "
|
|
@" subtype = %d, data1 = %p, data2 = %p",
|
|
eventTypes[event_type], location_point.x, location_point.y,
|
|
modifier_flags, event_time, window_num, event_context,
|
|
event_data.misc.sub_type, event_data.misc.data1,
|
|
event_data.misc.data2];
|
|
break;
|
|
}
|
|
|
|
return [super description];
|
|
}
|
|
|
|
@end
|