/Preferences/TSSTShortcutController.m

https://github.com/millenomi/Simple-Comic · Objective C · 477 lines · 388 code · 78 blank · 11 comment · 19 complexity · fa288115831e4234b42e47cf7666df9a MD5 · raw file

  1. //
  2. // TSSTShortcutController.m
  3. // SimpleComic
  4. //
  5. // Created by Alexander Rauchfuss on 1/25/08.
  6. // Copyright 2008 __MyCompanyName__. All rights reserved.
  7. //
  8. #import "TSSTShortcutController.h"
  9. NSString * TSSTKeyboardEquivalents = @"keyboardEquivalents";
  10. NSString * TSSTMenuTag = @"menuTag";
  11. NSString * TSSTMenuAction = @"menuAction";
  12. NSString * TSSTMenuKeyEquivalent = @"menuKeyEquivalent";
  13. NSString * TSSTMenuModifierKey = @"menuModifierKey";
  14. NSString * TSSTActionDescription = @"actionDescription";
  15. NSString * TSSTPreferenceKey = @"preferenceKey";
  16. NSString * TSSTFullscreenShortcut = @"fullscreenShortcut";
  17. NSString * TSSTRotateRightShortcut = @"rotateRightShortcut";
  18. NSString * TSSTRotateLeftShortcut = @"rotateLeftShortcut";
  19. NSString * TSSTToggleLoupeShortcut = @"toggleLoupeShortcut";
  20. NSString * TSSTPageOrderShortcut = @"pageOrderShortcut";
  21. NSString * TSSTTwoPageShortcut = @"twoPageShortcut";
  22. NSString * TSSTOriginalSizeShortcut = @"originalSizeShortcut";
  23. NSString * TSSTHorizontalFitShortcut = @"horizontalFitShortcut";
  24. NSString * TSSTWindowFitShortcut = @"windowFitShortcut";
  25. NSString * TSSTThumbnailShortcut = @"thumbnailShortcut";
  26. NSString * TSSTZoomInShortcut = @"zoomInShortcut";
  27. NSString * TSSTZoomOutShortcut = @"zoomOutShortcut";
  28. NSString * TSSTPageRightShortcut = @"pageRightShortcut";
  29. NSString * TSSTPageLeftShortcut = @"pageLeftShortcut";
  30. NSString * TSSTFirstPageShortcut = @"firstPageShortcut";
  31. NSString * TSSTLastPageShortcut = @"lastPageShortcut";
  32. NSString * TSSTSkipRightShortcut = @"skipRightShortcut";
  33. NSString * TSSTSkipLeftShortcut = @"skipLeftShortcut";
  34. NSString * TSSTShiftRightShortcut = @"shiftRightShortcut";
  35. NSString * TSSTShiftLeftShortcut = @"shiftLeftShortcut";
  36. NSString * TSSTPageJumpShortcut = @"pageJumpShortcut";
  37. static NSMutableArray * forbiddenShortcuts = nil;
  38. @implementation TSSTShortcutController
  39. + (void)initialize
  40. {
  41. forbiddenShortcuts = [NSMutableArray new];
  42. NSDictionary * singleShortcut;
  43. singleShortcut = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
  44. [NSString stringWithFormat: @"%C", NSLeftArrowFunctionKey], TSSTMenuKeyEquivalent, nil];
  45. [forbiddenShortcuts addObject: singleShortcut];
  46. [singleShortcut release];
  47. singleShortcut = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
  48. [NSString stringWithFormat: @"%C", NSRightArrowFunctionKey], TSSTMenuKeyEquivalent, nil];
  49. [forbiddenShortcuts addObject: singleShortcut];
  50. [singleShortcut release];
  51. singleShortcut = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
  52. [NSString stringWithFormat: @"%C", NSDownArrowFunctionKey], TSSTMenuKeyEquivalent, nil];
  53. [forbiddenShortcuts addObject: singleShortcut];
  54. [singleShortcut release];
  55. singleShortcut = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
  56. [NSString stringWithFormat: @"%C", NSUpArrowFunctionKey], TSSTMenuKeyEquivalent, nil];
  57. [forbiddenShortcuts addObject: singleShortcut];
  58. [singleShortcut release];
  59. singleShortcut = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
  60. @"b", TSSTMenuKeyEquivalent,
  61. [NSNumber numberWithUnsignedInt: NSCommandKeyMask], TSSTMenuModifierKey, nil];
  62. [forbiddenShortcuts addObject: singleShortcut];
  63. [singleShortcut release];
  64. singleShortcut = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
  65. @"B", TSSTMenuKeyEquivalent,
  66. [NSNumber numberWithUnsignedInt: NSCommandKeyMask], TSSTMenuModifierKey, nil];
  67. [forbiddenShortcuts addObject: singleShortcut];
  68. [singleShortcut release];
  69. }
  70. + (void)scrapeMenuKeyEquivalentsForMenu:(NSMenu *)menu
  71. {
  72. NSArray * menuItems = [menu itemArray];
  73. BOOL match;
  74. NSDictionary * itemDescription;
  75. NSMenu * subMenu;
  76. for(NSMenuItem * menuItem in menuItems)
  77. {
  78. itemDescription = nil;
  79. match = NO;
  80. subMenu = [menuItem submenu];
  81. if(subMenu)
  82. {
  83. [TSSTShortcutController scrapeMenuKeyEquivalentsForMenu: subMenu];
  84. }
  85. else
  86. {
  87. if([menuItem keyEquivalent] && [menuItem keyEquivalentModifierMask])
  88. {
  89. itemDescription = [NSDictionary dictionaryWithObjectsAndKeys:
  90. [menuItem keyEquivalent], TSSTMenuKeyEquivalent,
  91. [NSNumber numberWithUnsignedInt: [menuItem keyEquivalentModifierMask]], TSSTMenuModifierKey, nil];
  92. }
  93. else if([menuItem keyEquivalent])
  94. {
  95. itemDescription = [NSDictionary dictionaryWithObjectsAndKeys:
  96. [menuItem keyEquivalent], TSSTMenuKeyEquivalent, nil];
  97. }
  98. if(itemDescription)
  99. {
  100. [forbiddenShortcuts addObject: itemDescription];
  101. }
  102. }
  103. }
  104. }
  105. + (NSArray *)availableActions
  106. {
  107. NSMutableArray * actions = [NSMutableArray new];
  108. NSDictionary * singleShortcut;
  109. singleShortcut = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
  110. @"changePageOrder:", TSSTMenuAction,
  111. @"Change page order", TSSTActionDescription,
  112. @"d", TSSTMenuKeyEquivalent,
  113. [NSNumber numberWithUnsignedInt: NSCommandKeyMask], TSSTMenuModifierKey,
  114. @"pageOrderShortcut", TSSTPreferenceKey, nil];
  115. [actions addObject: singleShortcut];
  116. [singleShortcut release];
  117. singleShortcut = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
  118. @"setArchiveIcon:", TSSTMenuAction,
  119. @"Set selected page as icon", TSSTActionDescription,
  120. @"defaultIcon", TSSTPreferenceKey,
  121. @"c", TSSTMenuKeyEquivalent,
  122. [NSNumber numberWithUnsignedInt: NSCommandKeyMask], TSSTMenuModifierKey, nil];
  123. [actions addObject: singleShortcut];
  124. [singleShortcut release];
  125. singleShortcut = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
  126. @"changeTwoPage:", TSSTMenuAction,
  127. @"Toggle two page spread", TSSTActionDescription,
  128. @"twoPageShortcut", TSSTPreferenceKey,
  129. @"p", TSSTMenuKeyEquivalent,
  130. [NSNumber numberWithUnsignedInt: NSCommandKeyMask], TSSTMenuModifierKey, nil];
  131. [actions addObject: singleShortcut];
  132. [singleShortcut release];
  133. singleShortcut = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
  134. @"changeFullscreen:", TSSTMenuAction,
  135. @"Toggle fullscreen", TSSTActionDescription,
  136. @"fullscreenShortcut", TSSTPreferenceKey,
  137. @"f", TSSTMenuKeyEquivalent,
  138. [NSNumber numberWithUnsignedInt: NSCommandKeyMask], TSSTMenuModifierKey, nil];
  139. [actions addObject: singleShortcut];
  140. [singleShortcut release];
  141. singleShortcut = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
  142. @"togglePageExpose:", TSSTMenuAction,
  143. @"Thumbnail exposé", TSSTActionDescription,
  144. @"thumbnailShortcut", TSSTPreferenceKey,
  145. @"t", TSSTMenuKeyEquivalent,
  146. [NSNumber numberWithUnsignedInt: NSCommandKeyMask], TSSTMenuModifierKey, nil];
  147. [actions addObject: singleShortcut];
  148. [singleShortcut release];
  149. singleShortcut = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
  150. @"toggleLoupe:", TSSTMenuAction,
  151. @"Toggle loupe", TSSTActionDescription,
  152. @"toggleLoupeShortcut", TSSTPreferenceKey,
  153. @"u", TSSTMenuKeyEquivalent,
  154. [NSNumber numberWithUnsignedInt: NSCommandKeyMask], TSSTMenuModifierKey, nil];
  155. [actions addObject: singleShortcut];
  156. [singleShortcut release];
  157. singleShortcut = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
  158. @"zoomIn:", TSSTMenuAction,
  159. @"Zoom in", TSSTActionDescription,
  160. @"zoomInShortcut", TSSTPreferenceKey,
  161. @"=", TSSTMenuKeyEquivalent,
  162. [NSNumber numberWithUnsignedInt: NSCommandKeyMask], TSSTMenuModifierKey, nil];
  163. [actions addObject: singleShortcut];
  164. [singleShortcut release];
  165. singleShortcut = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
  166. @"zoomOut:", TSSTMenuAction,
  167. @"Zoom out", TSSTActionDescription,
  168. @"zoomOutShortcut", TSSTPreferenceKey,
  169. @"-", TSSTMenuKeyEquivalent,
  170. [NSNumber numberWithUnsignedInt: NSCommandKeyMask], TSSTMenuModifierKey, nil];
  171. [actions addObject: singleShortcut];
  172. [singleShortcut release];
  173. singleShortcut = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
  174. @"zoomReset:", TSSTMenuAction,
  175. @"Zoom reset", TSSTActionDescription,
  176. @"zoomResetShortcut", TSSTPreferenceKey,
  177. @"0", TSSTMenuKeyEquivalent,
  178. [NSNumber numberWithUnsignedInt: NSCommandKeyMask], TSSTMenuModifierKey, nil];
  179. [actions addObject: singleShortcut];
  180. [singleShortcut release];
  181. singleShortcut = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
  182. @"rotateLeft:", TSSTMenuAction,
  183. @"Rotate left", TSSTActionDescription,
  184. @"rotateLeftShortcut", TSSTPreferenceKey,
  185. @"l", TSSTMenuKeyEquivalent,
  186. [NSNumber numberWithUnsignedInt: NSCommandKeyMask], TSSTMenuModifierKey, nil];
  187. [actions addObject: singleShortcut];
  188. [singleShortcut release];
  189. singleShortcut = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
  190. @"rotateRight:", TSSTMenuAction,
  191. @"Rotate right", TSSTActionDescription,
  192. @"rotateRightShortcut", TSSTPreferenceKey,
  193. @"r", TSSTMenuKeyEquivalent,
  194. [NSNumber numberWithUnsignedInt: NSCommandKeyMask], TSSTMenuModifierKey, nil];
  195. [actions addObject: singleShortcut];
  196. [singleShortcut release];
  197. singleShortcut = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
  198. @"noRotation:", TSSTMenuAction,
  199. @"No Rotation", TSSTActionDescription,
  200. @"n", TSSTMenuKeyEquivalent,
  201. [NSNumber numberWithUnsignedInt: NSCommandKeyMask], TSSTMenuModifierKey,
  202. @"noRotationShortcut", TSSTPreferenceKey, nil];
  203. [actions addObject: singleShortcut];
  204. [singleShortcut release];
  205. singleShortcut = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
  206. @"changeScaling:", TSSTMenuAction,
  207. [NSNumber numberWithInt: 400], TSSTMenuTag,
  208. @"Original size mode", TSSTActionDescription,
  209. @"originalSizeShortcut", TSSTPreferenceKey,
  210. @"1", TSSTMenuKeyEquivalent,
  211. [NSNumber numberWithUnsignedInt: NSCommandKeyMask], TSSTMenuModifierKey, nil];
  212. [actions addObject: singleShortcut];
  213. [singleShortcut release];
  214. singleShortcut = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
  215. @"changeScaling:", TSSTMenuAction,
  216. [NSNumber numberWithInt: 401], TSSTMenuTag,
  217. @"Scale pages to fit window", TSSTActionDescription,
  218. @"windowFitShortcut", TSSTPreferenceKey,
  219. @"2", TSSTMenuKeyEquivalent,
  220. [NSNumber numberWithUnsignedInt: NSCommandKeyMask], TSSTMenuModifierKey, nil];
  221. [actions addObject: singleShortcut];
  222. [singleShortcut release];
  223. singleShortcut = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
  224. @"changeScaling:", TSSTMenuAction,
  225. [NSNumber numberWithInt: 402], TSSTMenuTag,
  226. @"Scale pages to fit window width", TSSTActionDescription,
  227. @"horizontalFitShortcut", TSSTPreferenceKey,
  228. @"3", TSSTMenuKeyEquivalent,
  229. [NSNumber numberWithUnsignedInt: NSCommandKeyMask], TSSTMenuModifierKey, nil];
  230. [actions addObject: singleShortcut];
  231. [singleShortcut release];
  232. singleShortcut = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
  233. @"pageRight:", TSSTMenuAction,
  234. @"Page right", TSSTActionDescription,
  235. TSSTPageRightShortcut, TSSTPreferenceKey,
  236. [NSString stringWithFormat: @"%C", NSRightArrowFunctionKey], TSSTMenuKeyEquivalent,
  237. [NSNumber numberWithUnsignedInt: NSCommandKeyMask], TSSTMenuModifierKey, nil];
  238. [actions addObject: singleShortcut];
  239. [singleShortcut release];
  240. singleShortcut = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
  241. @"pageLeft:", TSSTMenuAction,
  242. @"Page left", TSSTActionDescription,
  243. TSSTPageLeftShortcut, TSSTPreferenceKey,
  244. [NSString stringWithFormat: @"%C", NSLeftArrowFunctionKey], TSSTMenuKeyEquivalent,
  245. [NSNumber numberWithUnsignedInt: NSCommandKeyMask], TSSTMenuModifierKey, nil];
  246. [actions addObject: singleShortcut];
  247. [singleShortcut release];
  248. singleShortcut = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
  249. @"firstPage:", TSSTMenuAction,
  250. @"Jump to first page", TSSTActionDescription,
  251. TSSTFirstPageShortcut, TSSTPreferenceKey,
  252. [NSString stringWithFormat: @"%C", NSHomeFunctionKey], TSSTMenuKeyEquivalent, nil];
  253. [actions addObject: singleShortcut];
  254. [singleShortcut release];
  255. singleShortcut = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
  256. @"lastPage:", TSSTMenuAction,
  257. @"Jump to last page", TSSTActionDescription,
  258. TSSTLastPageShortcut, TSSTPreferenceKey,
  259. [NSString stringWithFormat: @"%C", NSEndFunctionKey], TSSTMenuKeyEquivalent, nil];
  260. [actions addObject: singleShortcut];
  261. [singleShortcut release];
  262. singleShortcut = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
  263. @"shiftPageRight:", TSSTMenuAction,
  264. @"Shift one page right", TSSTActionDescription,
  265. TSSTShiftRightShortcut, TSSTPreferenceKey,
  266. [NSString stringWithFormat: @"%C", NSRightArrowFunctionKey], TSSTMenuKeyEquivalent,
  267. [NSNumber numberWithUnsignedInt: NSAlternateKeyMask], TSSTMenuModifierKey, nil];
  268. [actions addObject: singleShortcut];
  269. [singleShortcut release];
  270. singleShortcut = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
  271. @"shiftPageLeft:", TSSTMenuAction,
  272. @"Shift one page left", TSSTActionDescription,
  273. TSSTShiftLeftShortcut, TSSTPreferenceKey,
  274. [NSString stringWithFormat: @"%C", NSLeftArrowFunctionKey], TSSTMenuKeyEquivalent,
  275. [NSNumber numberWithUnsignedInt: NSAlternateKeyMask], TSSTMenuModifierKey, nil];
  276. [actions addObject: singleShortcut];
  277. [singleShortcut release];
  278. singleShortcut = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
  279. @"skipRight:", TSSTMenuAction,
  280. @"Skip ten pages right", TSSTActionDescription,
  281. TSSTSkipRightShortcut, TSSTPreferenceKey,
  282. [NSString stringWithFormat: @"%C", NSRightArrowFunctionKey], TSSTMenuKeyEquivalent,
  283. [NSNumber numberWithUnsignedInt: NSCommandKeyMask | NSAlternateKeyMask], TSSTMenuModifierKey, nil];
  284. [actions addObject: singleShortcut];
  285. [singleShortcut release];
  286. singleShortcut = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
  287. @"skipLeft:", TSSTMenuAction,
  288. @"Skip ten pages left", TSSTActionDescription,
  289. TSSTSkipLeftShortcut, TSSTPreferenceKey,
  290. [NSString stringWithFormat: @"%C", NSLeftArrowFunctionKey], TSSTMenuKeyEquivalent,
  291. [NSNumber numberWithUnsignedInt: NSCommandKeyMask | NSAlternateKeyMask], TSSTMenuModifierKey, nil];
  292. [actions addObject: singleShortcut];
  293. [singleShortcut release];
  294. singleShortcut = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
  295. @"launchJumpPanel:", TSSTMenuAction,
  296. @"Jump to specific page", TSSTActionDescription,
  297. TSSTPageJumpShortcut, TSSTPreferenceKey,
  298. [NSString stringWithFormat: @"%C", NSCarriageReturnCharacter], TSSTMenuKeyEquivalent, nil];
  299. [actions addObject: singleShortcut];
  300. [singleShortcut release];
  301. return [actions autorelease];
  302. }
  303. + (NSArray *)forbiddenShortcuts
  304. {
  305. return forbiddenShortcuts;
  306. }
  307. + (NSMutableDictionary *)defaultShortcutMapping
  308. {
  309. NSMutableDictionary * shortcutDefaults = [NSMutableDictionary new];
  310. NSMutableDictionary * singleShortcut;
  311. NSArray * actions = [TSSTShortcutController availableActions];
  312. for(NSDictionary * action in actions)
  313. {
  314. singleShortcut = [NSMutableDictionary dictionaryWithObjectsAndKeys:
  315. [action objectForKey: TSSTMenuKeyEquivalent], TSSTMenuKeyEquivalent,
  316. [action objectForKey: TSSTMenuModifierKey], TSSTMenuModifierKey, nil];
  317. [shortcutDefaults setObject: singleShortcut forKey: [action objectForKey: TSSTPreferenceKey]];
  318. }
  319. return [shortcutDefaults autorelease];
  320. }
  321. + (void)applyEquivalentWithDescription:(NSDictionary *)description toMenu:(NSMenu *)menu
  322. {
  323. // NSLog([description description]);
  324. NSArray * menuItems = [menu itemArray];
  325. BOOL match;
  326. NSString * selectorString;
  327. for(NSMenuItem * menuItem in menuItems)
  328. {
  329. match = NO;
  330. NSMenu * subMenu = [menuItem submenu];
  331. if(subMenu)
  332. {
  333. [[self class] applyEquivalentWithDescription: description toMenu: subMenu];
  334. }
  335. else
  336. {
  337. selectorString = NSStringFromSelector([menuItem action]);
  338. if([[description valueForKey: TSSTMenuAction] isEqualToString: selectorString])
  339. {
  340. match = YES;
  341. }
  342. if([description valueForKey: TSSTMenuTag] && match)
  343. {
  344. match = [[description valueForKey: TSSTMenuTag] intValue] == [menuItem tag] ? YES : NO;
  345. }
  346. if(match)
  347. {
  348. [menuItem setKeyEquivalent: [description valueForKey: TSSTMenuKeyEquivalent]];
  349. [menuItem setKeyEquivalentModifierMask: [[description valueForKey: TSSTMenuModifierKey] unsignedIntValue]];
  350. }
  351. }
  352. }
  353. }
  354. - (void) dealloc
  355. {
  356. NSUserDefaultsController * sharedDefaults = [NSUserDefaultsController sharedUserDefaultsController];
  357. NSArray * actions = [[self class] availableActions];
  358. for(NSMutableDictionary * action in actions)
  359. {
  360. [[sharedDefaults defaults] removeObserver: self forKeyPath: [action objectForKey: TSSTPreferenceKey]];
  361. }
  362. [super dealloc];
  363. }
  364. - (void)awakeFromNib
  365. {
  366. NSMenu * applicationMenu = [[NSApplication sharedApplication] mainMenu];
  367. [[self class] scrapeMenuKeyEquivalentsForMenu: applicationMenu];
  368. NSUserDefaultsController * sharedDefaults = [NSUserDefaultsController sharedUserDefaultsController];
  369. NSDictionary * savedKey;
  370. NSArray * actions = [[self class] availableActions];
  371. for(NSMutableDictionary * action in actions)
  372. {
  373. savedKey = [[sharedDefaults values] valueForKey: [action objectForKey: TSSTPreferenceKey]];
  374. [action setValuesForKeysWithDictionary: savedKey];
  375. [[self class] applyEquivalentWithDescription: action toMenu: applicationMenu];
  376. // NSString * keyPath = [NSString stringWithFormat: @"values.%@", [action objectForKey: TSSTPreferenceKey]];
  377. [[sharedDefaults defaults] addObserver: self forKeyPath: [action objectForKey: TSSTPreferenceKey] options: 0 context: nil];
  378. }
  379. }
  380. - (void)observeValueForKeyPath:(NSString *)keyPath
  381. ofObject:(id)object
  382. change:(NSDictionary *)change
  383. context:(void *)context
  384. {
  385. // NSLog(keyPath);
  386. NSMenu * applicationMenu = [[NSApplication sharedApplication] mainMenu];
  387. NSUserDefaultsController * sharedDefaults = [NSUserDefaultsController sharedUserDefaultsController];
  388. NSArray * actions = [[self class] availableActions];
  389. NSArray * keys = [actions valueForKey: TSSTPreferenceKey];
  390. NSInteger index = [keys indexOfObject: keyPath];
  391. if(index != NSNotFound)
  392. {
  393. NSMutableDictionary * shortcutDescription = [NSMutableDictionary dictionaryWithDictionary: [actions objectAtIndex: index]];
  394. [shortcutDescription setValuesForKeysWithDictionary: [[sharedDefaults values] valueForKey: keyPath]];
  395. // NSLog([shortcutDescription description]);
  396. [[self class] applyEquivalentWithDescription: shortcutDescription toMenu: applicationMenu];
  397. }
  398. }
  399. @end