Advertisement
Guest User

Untitled

a guest
May 22nd, 2018
80
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 18.50 KB | None | 0 0
  1. //
  2. // DPSetupWindow.m
  3. // DPSetupWindow
  4. //
  5. // Created by Dan Palmer on 05/10/2012.
  6. // Copyright (c) 2012 Dan Palmer. All rights reserved.
  7. //
  8.  
  9. #import "DPSetupWindow.h"
  10.  
  11. @interface DPSetupWindow ()
  12.  
  13. @property (retain) NSImageView *imageView;
  14. @property (retain) NSBox *contentBox;
  15. @property (retain) NSButton *cancelButton;
  16. @property (retain) NSButton *backButton;
  17. @property (retain) NSButton *nextButton;
  18.  
  19. @property (copy) void(^completionHandler)(BOOL);
  20. @property (assign) NSViewController *currentViewController;
  21.  
  22. @end
  23.  
  24. @implementation DPSetupWindow
  25.  
  26. - (id)initWithViewControllers:(NSArray *)viewControllers completionHandler:(void (^)(BOOL completed))completionHandler {
  27.  
  28. int initial_x = [[NSScreen mainScreen] frame].size.width / 2 - 290;
  29. int initial_y = [[NSScreen mainScreen] frame].size.height / 2 - 250;
  30.  
  31. NSRect contentRect = NSMakeRect(initial_x, initial_y, 580, 500);
  32.  
  33. self = [super initWithContentRect:contentRect styleMask:(NSTitledWindowMask|NSClosableWindowMask) backing:NSBackingStoreBuffered defer:YES];
  34. if (self == nil) return nil;
  35.  
  36. if (!viewControllers || [viewControllers count] == 0) return nil;
  37. if (!completionHandler) return nil;
  38.  
  39. currentStage = -1;
  40. _animates = YES;
  41. _funnelsRepresentedObjects = NO;
  42. [self setViewControllers:viewControllers];
  43. [self setCompletionHandler:completionHandler];
  44.  
  45. [self setContentView:[self initialiseContentViewForRect:contentRect]];
  46. [self next:nil];
  47. [self addNotifications];
  48.  
  49. return self;
  50. }
  51.  
  52. - (void)dealloc{
  53.  
  54. [self removeNotifications];
  55. }
  56.  
  57. - (NSView *)initialiseContentViewForRect:(NSRect)contentRect {
  58. NSView *contentView = [[NSView alloc] initWithFrame:contentRect];
  59.  
  60. _cancelButton = [[NSButton alloc] initWithFrame:NSMakeRect(10, 13, 97, 32)];
  61. [_cancelButton setBezelStyle:NSRoundedBezelStyle];
  62. [_cancelButton setTarget:self];
  63. [_cancelButton setAction:@selector(cancel:)];
  64. [_cancelButton setTitle:@"Cancel"];
  65. [_cancelButton setFont:[NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSRegularControlSize]]];
  66. [contentView addSubview:_cancelButton];
  67.  
  68. _backButton = [[NSButton alloc] initWithFrame:NSMakeRect(372, 13, 97, 32)];
  69. [_backButton setBezelStyle:NSRoundedBezelStyle];
  70. [_backButton setTarget:self];
  71. [_backButton setAction:@selector(back:)];
  72. [_backButton setFont:[NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSRegularControlSize]]];
  73. [contentView addSubview:_backButton];
  74.  
  75. _nextButton = [[NSButton alloc] initWithFrame:NSMakeRect(469, 13, 97, 32)];
  76. [_nextButton setBezelStyle:NSRoundedBezelStyle];
  77. [_nextButton setTarget:self];
  78. [_nextButton setAction:@selector(next:)];
  79. [_nextButton setFont:[NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSRegularControlSize]]];
  80. [contentView addSubview:_nextButton];
  81.  
  82. _imageView = [[NSImageView alloc] initWithFrame:NSMakeRect(10, 60, 320, 320)];
  83. [_imageView setAlphaValue:0.3];
  84. [_imageView setImageScaling:NSImageScaleProportionallyUpOrDown];
  85. [_imageView setImage:[[NSApplication sharedApplication] applicationIconImage]];
  86. [contentView addSubview:_imageView];
  87.  
  88. _contentBox = [[NSBox alloc] initWithFrame:NSMakeRect(10, 60, 560, 420)];
  89. [_contentBox setTitlePosition:(NSNoTitle)];
  90. [contentView addSubview:_contentBox];
  91.  
  92. return contentView;
  93. }
  94.  
  95. - (void) addNotifications{
  96.  
  97. [[NSNotificationCenter defaultCenter] addObserverForName:kDPNotification_addNextViewController
  98. object:nil
  99. queue:[NSOperationQueue currentQueue]
  100. usingBlock:^(NSNotification *note) {
  101.  
  102. NSDictionary *userInfo = [note userInfo];
  103.  
  104. NSViewController<DPSetupWindowStageViewController> *viewController = nil;
  105.  
  106. viewController = [userInfo objectForKey:kDPNotification_key_viewController];
  107.  
  108. if (viewController) {
  109.  
  110. NSMutableArray *newViewControllers = [[self viewControllers] mutableCopy];
  111. [newViewControllers insertObject:viewController atIndex:(currentStage + 1)];
  112. [self setViewControllers:[NSArray arrayWithArray:newViewControllers]];
  113. }
  114. }];
  115.  
  116. [[NSNotificationCenter defaultCenter] addObserverForName:kDPNotification_addFinalViewController
  117. object:nil
  118. queue:[NSOperationQueue currentQueue]
  119. usingBlock:^(NSNotification *note) {
  120.  
  121. NSDictionary *userInfo = [note userInfo];
  122.  
  123. NSViewController<DPSetupWindowStageViewController> *viewController = nil;
  124.  
  125. viewController = [userInfo objectForKey:kDPNotification_key_viewController];
  126.  
  127. if (viewController) {
  128.  
  129. NSArray *newViewControllers = [[self viewControllers] arrayByAddingObject:viewController];
  130. [self setViewControllers:newViewControllers];
  131. }
  132. }];
  133.  
  134. [[NSNotificationCenter defaultCenter] addObserverForName:kDPNotification_deleteViewController
  135. object:nil
  136. queue:[NSOperationQueue currentQueue]
  137. usingBlock:^(NSNotification *note) {
  138.  
  139. NSDictionary *userInfo = [note userInfo];
  140.  
  141. id mustDeleteController = nil;
  142. Class mustDeleteClass = nil;
  143. mustDeleteClass = [userInfo objectForKey:kDPNotification_key_viewControllerClass];
  144.  
  145. NSMutableArray *viewControllers = [[self viewControllers] mutableCopy];
  146. for (id controller in viewControllers)
  147. if ([controller class]==mustDeleteClass)
  148. mustDeleteController = controller;
  149.  
  150. if (mustDeleteController &&
  151. mustDeleteController != [viewControllers objectAtIndex:currentStage]) {
  152.  
  153. @try {
  154. [self deregisterObserversForViewController:mustDeleteController];
  155. }
  156. @catch (NSException *exception) {}
  157.  
  158. [viewControllers removeObject:mustDeleteController];
  159. [self setViewControllers:[NSArray arrayWithArray:viewControllers]];
  160. }
  161. }];
  162. }
  163.  
  164. - (void) removeNotifications{
  165.  
  166. [[NSNotificationCenter defaultCenter] removeObserver:self
  167. name:kDPNotification_addNextViewController
  168. object:nil];
  169.  
  170. [[NSNotificationCenter defaultCenter] removeObserver:self
  171. name:kDPNotification_addFinalViewController
  172. object:nil];
  173.  
  174. [[NSNotificationCenter defaultCenter] removeObserver:self
  175. name:kDPNotification_deleteViewController
  176. object:nil];
  177. }
  178.  
  179. #pragma mark -
  180. #pragma mark Customisation
  181.  
  182. - (void)setBackgroundImage:(NSImage *)backgroundImage {
  183. _backgroundImage = backgroundImage;
  184. [[self imageView] setImage:backgroundImage];
  185. }
  186.  
  187. - (NSImage *)backgroundImage {
  188. return _backgroundImage;
  189. }
  190.  
  191. #pragma mark -
  192. #pragma mark Flow Control
  193.  
  194. typedef enum {
  195. DPSetupWindowNextDirection = 1,
  196. DPSetupWindowBackDirection = -1
  197. } DPSetupWindowDirection;
  198.  
  199. - (void)progressToNextStage {
  200. [self shift:DPSetupWindowNextDirection];
  201. }
  202.  
  203. - (void)revertToPreviousStage {
  204. [self shift:DPSetupWindowBackDirection];
  205. }
  206.  
  207. - (void)resetToZeroStage{
  208.  
  209. for (id viewController in [self viewControllers])
  210. if ([viewController respondsToSelector:@selector(resetToInitialState)])
  211. [viewController resetToInitialState];
  212.  
  213. NSViewController<DPSetupWindowStageViewController> *previousViewController = nil;
  214. if(currentStage>0 &&
  215. currentStage<=[[self viewControllers] count])
  216.  
  217. previousViewController = [[self viewControllers] objectAtIndex:currentStage];
  218. else
  219. return;
  220.  
  221.  
  222. //rewind
  223. currentStage = 0;
  224. NSViewController<DPSetupWindowStageViewController> *nextViewController = [[self viewControllers] objectAtIndex:currentStage];
  225. NSView *view = [nextViewController view];
  226.  
  227. if(nextViewController != nil && [nextViewController respondsToSelector:@selector(willProgressToNextStage)]) {
  228. [nextViewController willProgressToStage];
  229. }
  230.  
  231. void (^finished)() = ^{
  232. if(previousViewController != nil && [previousViewController respondsToSelector:@selector(didProgressToNextStage)]) {
  233. [previousViewController didProgressToNextStage];
  234. }
  235.  
  236. if(nextViewController != nil && [nextViewController respondsToSelector:@selector(didProgressToStage)]) {
  237. [nextViewController didProgressToStage];
  238. }
  239. };
  240.  
  241. [view setFrame:NSMakeRect(0, 0, 560, 420)];
  242. if (previousViewController)
  243. [[previousViewController view] removeFromSuperviewWithoutNeedingDisplay];
  244.  
  245. [[self contentBox] addSubview:view];
  246. finished();
  247.  
  248.  
  249. [self registerObserversForPreviousViewController:previousViewController nextViewController:nextViewController];
  250. [self recalculateButtonEnabledStates];
  251. [self resetButtonTitles];
  252. }
  253.  
  254. - (void)next:(id)sender {
  255. [self shift:DPSetupWindowNextDirection];
  256. }
  257.  
  258. - (void)back:(id)sender {
  259. [self shift:DPSetupWindowBackDirection];
  260. }
  261.  
  262. - (void)shift:(DPSetupWindowDirection)direction {
  263.  
  264. if ((currentStage == [[self viewControllers] count] && direction == DPSetupWindowNextDirection) ||
  265. (currentStage == 0 && direction == DPSetupWindowBackDirection)) {
  266. return;
  267. }
  268.  
  269. NSViewController<DPSetupWindowStageViewController> *previousViewController = nil;
  270. if (currentStage >= 0 && currentStage < [[self viewControllers] count]) {
  271. previousViewController = [[self viewControllers] objectAtIndex:currentStage];
  272. }
  273.  
  274. if (direction == DPSetupWindowNextDirection) {
  275. if(previousViewController != nil && [previousViewController respondsToSelector:@selector(willProgressToNextStage)]) {
  276. [previousViewController willProgressToNextStage];
  277. }
  278. } else if (direction == DPSetupWindowBackDirection) {
  279. if(previousViewController != nil && [previousViewController respondsToSelector:@selector(willRevertToPreviousStage)]) {
  280. [previousViewController willRevertToPreviousStage];
  281. }
  282. }
  283.  
  284. NSInteger nextStage = currentStage + direction;
  285. if (nextStage == [[self viewControllers] count]) {
  286. //[self deregisterObserversForViewController:previousViewController];
  287. [self completionHandler](YES);
  288. return;
  289. }
  290.  
  291. NSViewController<DPSetupWindowStageViewController> *nextViewController = [[self viewControllers] objectAtIndex:nextStage];
  292. NSView *view = [nextViewController view];
  293.  
  294. if (direction == DPSetupWindowNextDirection) {
  295. if(nextViewController != nil && [nextViewController respondsToSelector:@selector(willProgressToStage)]) {
  296. [nextViewController willProgressToStage];
  297. }
  298. } else if (direction == DPSetupWindowBackDirection) {
  299. if(nextViewController != nil && [nextViewController respondsToSelector:@selector(willRevertToStage)]) {
  300. [nextViewController willRevertToStage];
  301. }
  302. }
  303.  
  304. void (^finished)() = ^{
  305. if (direction == DPSetupWindowNextDirection) {
  306. if(previousViewController != nil && [previousViewController respondsToSelector:@selector(didProgressToNextStage)]) {
  307. [previousViewController didProgressToNextStage];
  308. }
  309.  
  310. if(nextViewController != nil && [nextViewController respondsToSelector:@selector(didProgressToStage)]) {
  311. [nextViewController didProgressToStage];
  312. }
  313. } else if (direction == DPSetupWindowBackDirection) {
  314. if(previousViewController != nil && [previousViewController respondsToSelector:@selector(didRevertToPreviousStage)]) {
  315. [previousViewController didRevertToPreviousStage];
  316. }
  317.  
  318. if(nextViewController != nil && [nextViewController respondsToSelector:@selector(didRevertToStage)]) {
  319. [nextViewController didRevertToStage];
  320. }
  321. }
  322. };
  323.  
  324. if ([self funnelsRepresentedObjects]) {
  325. [nextViewController setRepresentedObject:[previousViewController representedObject]];
  326. }
  327.  
  328. if ([self animates] && previousViewController) {
  329. [NSAnimationContext beginGrouping];
  330.  
  331. if ([[NSApp currentEvent] modifierFlags] & NSShiftKeyMask) {
  332. [[NSAnimationContext currentContext] setDuration:3.0];
  333. }
  334. [[NSAnimationContext currentContext] setCompletionHandler:^{
  335. [[previousViewController view] removeFromSuperviewWithoutNeedingDisplay];
  336. finished();
  337. }];
  338.  
  339. [view setFrame:NSMakeRect((560 * direction), 0, 560, 420)];
  340. [[self contentBox] addSubview:view];
  341. [[view animator] setFrameOrigin:NSMakePoint(0, 0)];
  342. [[[previousViewController view] animator] setFrameOrigin:NSMakePoint((-560 * direction), 0)];
  343.  
  344. [NSAnimationContext endGrouping];
  345. } else {
  346. [view setFrame:NSMakeRect(0, 0, 560, 420)];
  347. if (previousViewController) {
  348. [[previousViewController view] removeFromSuperviewWithoutNeedingDisplay];
  349. }
  350. [[self contentBox] addSubview:view];
  351. finished();
  352. }
  353.  
  354. currentStage = nextStage;
  355. [self registerObserversForPreviousViewController:previousViewController nextViewController:nextViewController];
  356. [self recalculateButtonEnabledStates];
  357. [self resetButtonTitles];
  358. }
  359.  
  360. - (void)cancelOperation:(id)sender {
  361. [self cancel:sender];
  362. }
  363.  
  364. - (void)cancel:(id)sender {
  365. [[NSApplication sharedApplication] endSheet:self returnCode:0];
  366. [self completionHandler](NO);
  367. }
  368.  
  369. - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
  370. [self recalculateButtonEnabledStates];
  371. }
  372.  
  373. - (void)recalculateButtonEnabledStates {
  374. NSViewController<DPSetupWindowStageViewController> *currentViewController = [[self viewControllers] objectAtIndex:currentStage];
  375. if ([currentViewController respondsToSelector:@selector(canContinue)]) {
  376. [[self nextButton] setEnabled:[currentViewController canContinue]];
  377. } else {
  378. [[self nextButton] setEnabled:YES];
  379. }
  380.  
  381. if ([currentViewController respondsToSelector:@selector(canGoBack)]) {
  382. [[self backButton] setEnabled:[currentViewController canGoBack]];
  383. } else {
  384. [[self backButton] setEnabled:YES];
  385. }
  386.  
  387. if (currentStage == 0) {
  388. [[self backButton] setEnabled:NO];
  389. }
  390. }
  391.  
  392. - (void)registerObserversForPreviousViewController:(NSViewController *)previousViewController nextViewController:(NSViewController *)nextViewController {
  393.  
  394. [previousViewController removeObserver:self forKeyPath:@"canContinue"];
  395. [previousViewController removeObserver:self forKeyPath:@"canGoBack"];
  396. [nextViewController addObserver:self forKeyPath:@"canContinue" options:(NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld) context:NULL];
  397. [nextViewController addObserver:self forKeyPath:@"canGoBack" options:(NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld) context:NULL];
  398. }
  399.  
  400. - (void)deregisterObserversForViewController:(NSViewController *)viewController {
  401. [viewController removeObserver:self forKeyPath:@"canContinue"];
  402. [viewController removeObserver:self forKeyPath:@"canGoBack"];
  403. }
  404.  
  405. - (void)resetButtonTitles {
  406. NSViewController<DPSetupWindowStageViewController> *currentViewController = [[self viewControllers] objectAtIndex:currentStage];
  407. if ([currentViewController respondsToSelector:@selector(continueButtonTitle)]) {
  408. [[self nextButton] setTitle:[currentViewController continueButtonTitle]];
  409. } else {
  410. [[self nextButton] setTitle:@"Continue"];
  411. }
  412.  
  413. if ([currentViewController respondsToSelector:@selector(cancelButtonTitle)]) {
  414. [[self cancelButton] setTitle:[currentViewController cancelButtonTitle]];
  415. } else {
  416. [[self cancelButton] setTitle:@"Cancel"];
  417. }
  418.  
  419. if ([currentViewController respondsToSelector:@selector(backButtonTitle)]) {
  420. [[self backButton] setTitle:[currentViewController backButtonTitle]];
  421. } else {
  422. [[self backButton] setTitle:@"Back"];
  423. }
  424. }
  425.  
  426. @end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement