PageRenderTime 17ms CodeModel.GetById 12ms app.highlight 2ms RepoModel.GetById 1ms app.codeStats 0ms

/AppKit/CPResponder.j

http://github.com/cacaodev/cappuccino
Unknown | 393 lines | 339 code | 54 blank | 0 comment | 0 complexity | 18bc00e561977b64c28ea8eb8a3c993a MD5 | raw file
  1/*
  2 * CPResponder.j
  3 * AppKit
  4 *
  5 * Created by Francisco Tolmasky.
  6 * Copyright 2008, 280 North, Inc.
  7 *
  8 * This library is free software; you can redistribute it and/or
  9 * modify it under the terms of the GNU Lesser General Public
 10 * License as published by the Free Software Foundation; either
 11 * version 2.1 of the License, or (at your option) any later version.
 12 *
 13 * This library is distributed in the hope that it will be useful,
 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 16 * Lesser General Public License for more details.
 17 *
 18 * You should have received a copy of the GNU Lesser General Public
 19 * License along with this library; if not, write to the Free Software
 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 21 */
 22
 23@import <Foundation/CPObject.j>
 24@import <Foundation/CPObjJRuntime.j>
 25
 26@import "CPEvent.j"
 27
 28@class CPKeyBinding
 29@class CPMenu
 30
 31CPDeleteKeyCode         = 8;
 32CPTabKeyCode            = 9;
 33CPReturnKeyCode         = 13;
 34CPEscapeKeyCode         = 27;
 35CPSpaceKeyCode          = 32;
 36CPPageUpKeyCode         = 33;
 37CPPageDownKeyCode       = 34;
 38CPLeftArrowKeyCode      = 37;
 39CPUpArrowKeyCode        = 38;
 40CPRightArrowKeyCode     = 39;
 41CPDownArrowKeyCode      = 40;
 42CPDeleteForwardKeyCode  = 46;
 43
 44/*!
 45    @ingroup appkit
 46    @class CPResponder
 47
 48    Subclasses of CPResonder can be part of the responder chain.
 49*/
 50@implementation CPResponder : CPObject
 51{
 52    CPMenu      _menu;
 53    CPResponder _nextResponder;
 54}
 55
 56// Changing the first responder
 57/*!
 58    Returns \c YES if the receiver is able to become the first responder. \c NO otherwise.
 59*/
 60- (BOOL)acceptsFirstResponder
 61{
 62    return NO;
 63}
 64
 65/*!
 66    Notifies the receiver that it will become the first responder. The receiver can reject first
 67    responder if it returns \c NO. The default implementation always returns \c YES.
 68    @return \c YES if the receiver accepts first responder status.
 69*/
 70- (BOOL)becomeFirstResponder
 71{
 72    return YES;
 73}
 74
 75/*!
 76    Notifies the receiver that it has been asked to give up first responder status.
 77    @return \c YES if the receiver is willing to give up first responder status.
 78*/
 79- (BOOL)resignFirstResponder
 80{
 81    return YES;
 82}
 83
 84// Setting the next responder
 85/*!
 86    Sets the receiver's next responder.
 87    @param aResponder the responder after the receiver
 88*/
 89- (void)setNextResponder:(CPResponder)aResponder
 90{
 91    _nextResponder = aResponder;
 92}
 93
 94/*!
 95    Returns the responder after the receiver.
 96*/
 97- (CPResponder)nextResponder
 98{
 99    return _nextResponder;
100}
101
102/*!
103    Called to interpret a series of key events.
104    @param events an array of key CPEvents
105*/
106- (void)interpretKeyEvents:(CPArray)events
107{
108    var index = 0,
109        count = [events count];
110
111    for (; index < count; ++index)
112    {
113        var event = events[index],
114            modifierFlags = [event modifierFlags],
115            character = [event charactersIgnoringModifiers],
116            selectorNames = [CPKeyBinding selectorsForKey:character modifierFlags:modifierFlags];
117
118        if (selectorNames)
119        {
120            for (var s = 0, scount = selectorNames.length; s < scount; s++)
121            {
122                var selector = selectorNames[s];
123                if (!selector)
124                    continue;
125
126                [self doCommandBySelector:CPSelectorFromString(selector)];
127            }
128        }
129        else if (!(modifierFlags & (CPCommandKeyMask | CPControlKeyMask)) && [self respondsToSelector:@selector(insertText:)])
130            [self insertText:[event characters]];
131    }
132}
133
134/*!
135    Notifies the receiver that the user has clicked the mouse down in its area.
136    @param anEvent contains information about the click
137*/
138- (void)mouseDown:(CPEvent)anEvent
139{
140    [_nextResponder performSelector:_cmd withObject:anEvent];
141}
142
143/*!
144    Notifies the receiver that the user has clicked the right mouse down in its area.
145    @param anEvent contains information about the right click
146*/
147- (void)rightMouseDown:(CPEvent)anEvent
148{
149    [_nextResponder performSelector:_cmd withObject:anEvent];
150}
151
152/*!
153    Notifies the receiver that the user has initiated a drag
154    over it. A drag is a mouse movement while the left button is down.
155    @param anEvent contains information about the drag
156*/
157- (void)mouseDragged:(CPEvent)anEvent
158{
159    [_nextResponder performSelector:_cmd withObject:anEvent];
160}
161
162/*!
163    Notifies the receiver that the user has released the left mouse button.
164    @param anEvent contains information about the release
165*/
166- (void)mouseUp:(CPEvent)anEvent
167{
168    [_nextResponder performSelector:_cmd withObject:anEvent];
169}
170
171/*!
172    Notifies the receiver that the user has released the right mouse button.
173    @param anEvent contains information about the release
174*/
175- (void)rightMouseUp:(CPEvent)anEvent
176{
177    [_nextResponder performSelector:_cmd withObject:anEvent];
178}
179
180/*!
181    Notifies the receiver that the user has moved the mouse (with no buttons down).
182    @param anEvent contains information about the movement
183*/
184- (void)mouseMoved:(CPEvent)anEvent
185{
186    [_nextResponder performSelector:_cmd withObject:anEvent];
187}
188
189- (void)mouseEntered:(CPEvent)anEvent
190{
191    [_nextResponder performSelector:_cmd withObject:anEvent];
192}
193
194/*!
195    Notifies the receiver that the mouse exited the receiver's area.
196    @param anEvent contains information about the exit
197*/
198- (void)mouseExited:(CPEvent)anEvent
199{
200    [_nextResponder performSelector:_cmd withObject:anEvent];
201}
202
203/*!
204    Notifies the receiver that the mouse scroll wheel has moved.
205    @param anEvent information about the scroll
206*/
207- (void)scrollWheel:(CPEvent)anEvent
208{
209    [_nextResponder performSelector:_cmd withObject:anEvent];
210}
211
212/*!
213    Notifies the receiver that the user has pressed a key.
214    @param anEvent information about the key press
215*/
216- (void)keyDown:(CPEvent)anEvent
217{
218    [_nextResponder performSelector:_cmd withObject:anEvent];
219}
220
221/*!
222    Notifies the receiver that the user has released a key.
223    @param anEvent information about the key press
224*/
225- (void)keyUp:(CPEvent)anEvent
226{
227    [_nextResponder performSelector:_cmd withObject:anEvent];
228}
229
230/*!
231    Notifies the receiver that the user has pressed or released a modifier key (Shift, Control, and so on).
232    @param anEvent information about the key press
233*/
234- (void)flagsChanged:(CPEvent)anEvent
235{
236    [_nextResponder performSelector:_cmd withObject:anEvent];
237}
238
239/*!
240    Overridden by subclasses to handle a key equivalent.
241
242    If the character code or codes in \c anEvent match the receiver’s key equivalent,
243    the receiver should respond to the event and return \c YES. The default implementation
244    does nothing and returns \c NO.
245
246    You should extract the characters for a key equivalent using
247    \ref CPEvent::charactersIgnoringModifiers "[anEvent charactersIgnoringModifiers]".
248
249    @param anEvent An event object that represents the key equivalent pressed
250    @return \c YES if theEvent is a key equivalent that the receiver handled, \c NO if it is not a key equivalent that it should handle.
251*/
252- (BOOL)performKeyEquivalent:(CPEvent)anEvent
253{
254    return NO;
255}
256
257// Action Methods
258/*!
259    Insert a line break at the caret position or selection.
260    @param aSender the object requesting this
261*/
262- (void)insertLineBreak:(id)aSender
263{
264    [self insertNewline:aSender];
265}
266
267/*!
268    Insert a line break at the caret position or selection.
269    @param aSender the object requesting this
270*/
271- (void)insertNewline:(id)aSender
272{
273    [[self nextResponder] insertNewline:aSender];
274}
275
276- (void)insertTab:(id)sender
277{
278}
279
280- (void)insertBackTab:(id)sender
281{
282}
283
284/*!
285    Inserts some text at the caret position or selection.
286    @param aString the string to insert
287*/
288- (void)insertText:(CPString)aString
289{
290}
291
292// Dispatch methods
293/*!
294    The receiver will attempt to perform the command,
295    if it responds to it. If not, the \c -nextResponder will be called to do it.
296    @param aSelector the command to attempt
297*/
298- (void)doCommandBySelector:(SEL)aSelector
299{
300    if ([self respondsToSelector:aSelector])
301        [self performSelector:aSelector];
302    else
303        [_nextResponder doCommandBySelector:aSelector];
304}
305
306/*!
307    The receiver will attempt to perform the command, or pass it on to the next responder if it doesn't respond to it.
308    @param aSelector the command to perform
309    @param anObject the argument to the method
310    @return \c YES if the receiver was able to perform the command, or a responder down the chain was
311    able to perform the command.
312*/
313- (BOOL)tryToPerform:(SEL)aSelector with:(id)anObject
314{
315    if ([self respondsToSelector:aSelector])
316    {
317        [self performSelector:aSelector withObject:anObject];
318
319        return YES;
320    }
321
322    return [_nextResponder tryToPerform:aSelector with:anObject];
323}
324
325// Managing a Responder's menu
326
327- (void)setMenu:(CPMenu)aMenu
328{
329    _menu = aMenu;
330}
331
332- (CPMenu)menu
333{
334    return _menu;
335}
336
337// Getting the Undo Manager
338/*!
339    Returns the undo manager for the receiver.
340*/
341- (CPUndoManager)undoManager
342{
343    return [_nextResponder performSelector:_cmd];
344}
345
346// Terminating the responder chain
347/*!
348    Called when an event finds no suitable responder.
349    @param anEventSelector the command that failed
350*/
351- (void)noResponderFor:(SEL)anEventSelector
352{
353}
354
355@end
356
357var CPResponderNextResponderKey = @"CPResponderNextResponderKey",
358    CPResponderMenuKey = @"CPResponderMenuKey";
359
360@implementation CPResponder (CPCoding) <CPCoding>
361
362/*!
363    Initializes the responder with data from a coder.
364    @param aCoder the coder from which data will be read
365    @return the initialized responder
366*/
367- (id)initWithCoder:(CPCoder)aCoder
368{
369    self = [super init];
370
371    if (self)
372    {
373        [self setNextResponder:[aCoder decodeObjectForKey:CPResponderNextResponderKey]];
374        [self setMenu:[aCoder decodeObjectForKey:CPResponderMenuKey]];
375    }
376
377    return self;
378}
379
380/*!
381    Archives the responder to a coder.
382    @param aCoder the coder to which the responder will be archived
383*/
384- (void)encodeWithCoder:(CPCoder)aCoder
385{
386    // This will come out nil on the other side with decodeObjectForKey:
387    if (_nextResponder !== nil)
388        [aCoder encodeConditionalObject:_nextResponder forKey:CPResponderNextResponderKey];
389
390    [aCoder encodeObject:_menu forKey:CPResponderMenuKey];
391}
392
393@end