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