Merge branch 'pu/pb/index_quick_fix' into stable
[GitX.git] / DBPrefsWindowController.m
blob3988a99a33d5466986667b02e5bad01a14a385e9
1 //
2 //  DBPrefsWindowController.m
3 //
5 #import "DBPrefsWindowController.h"
8 static DBPrefsWindowController *_sharedPrefsWindowController = nil;
11 @implementation DBPrefsWindowController
16 #pragma mark -
17 #pragma mark Class Methods
20 + (DBPrefsWindowController *)sharedPrefsWindowController
22         if (!_sharedPrefsWindowController) {
23                 _sharedPrefsWindowController = [[self alloc] initWithWindowNibName:[self nibName]];
24         }
25         return _sharedPrefsWindowController;
31 + (NSString *)nibName
32         // Subclasses can override this to use a nib with a different name.
34    return @"Preferences";
40 #pragma mark -
41 #pragma mark Setup & Teardown
44 - (id)initWithWindow:(NSWindow *)window
45   // -initWithWindow: is the designated initializer for NSWindowController.
47         self = [super initWithWindow:nil];
48         if (self != nil) {
49                         // Set up an array and some dictionaries to keep track
50                         // of the views we'll be displaying.
51                 toolbarIdentifiers = [[NSMutableArray alloc] init];
52                 toolbarViews = [[NSMutableDictionary alloc] init];
53                 toolbarItems = [[NSMutableDictionary alloc] init];
55                         // Set up an NSViewAnimation to animate the transitions.
56                 viewAnimation = [[NSViewAnimation alloc] init];
57                 [viewAnimation setAnimationBlockingMode:NSAnimationNonblocking];
58                 [viewAnimation setAnimationCurve:NSAnimationEaseInOut];
59                 [viewAnimation setDelegate:self];
61                 [self setCrossFade:YES];
62                 [self setShiftSlowsAnimation:YES];
63         }
64         return self;
66         (void)window;  // To prevent compiler warnings.
72 - (void)windowDidLoad
74                 // Create a new window to display the preference views.
75                 // If the developer attached a window to this controller
76                 // in Interface Builder, it gets replaced with this one.
77         NSWindow *window = [[[NSWindow alloc] initWithContentRect:NSMakeRect(0,0,1000,1000)
78                                                                                                     styleMask:(NSTitledWindowMask |
79                                                                                                                            NSClosableWindowMask |
80                                                                                                                            NSMiniaturizableWindowMask)
81                                                                                                           backing:NSBackingStoreBuffered
82                                                                                                             defer:YES] autorelease];
83         [self setWindow:window];
84         contentSubview = [[[NSView alloc] initWithFrame:[[[self window] contentView] frame]] autorelease];
85         [contentSubview setAutoresizingMask:(NSViewMinYMargin | NSViewWidthSizable)];
86         [[[self window] contentView] addSubview:contentSubview];
87         [[self window] setShowsToolbarButton:NO];
93 - (void) dealloc {
94         [toolbarIdentifiers release];
95         [toolbarViews release];
96         [toolbarItems release];
97         [viewAnimation release];
98         [super dealloc];
104 #pragma mark -
105 #pragma mark Configuration
108 - (void)setupToolbar
110         // Subclasses must override this method to add items to the
111         // toolbar by calling -addView:label: or -addView:label:image:.
117 - (void)addView:(NSView *)view label:(NSString *)label
119         [self addView:view
120                         label:label
121                         image:[NSImage imageNamed:label]];
127 - (void)addView:(NSView *)view label:(NSString *)label image:(NSImage *)image
129         NSAssert (view != nil,
130                           @"Attempted to add a nil view when calling -addView:label:image:.");
132         NSString *identifier = [[label copy] autorelease];
134         [toolbarIdentifiers addObject:identifier];
135         [toolbarViews setObject:view forKey:identifier];
137         NSToolbarItem *item = [[[NSToolbarItem alloc] initWithItemIdentifier:identifier] autorelease];
138         [item setLabel:label];
139         [item setImage:image];
140         [item setTarget:self];
141         [item setAction:@selector(toggleActivePreferenceView:)];
143         [toolbarItems setObject:item forKey:identifier];
149 #pragma mark -
150 #pragma mark Accessor Methods
153 - (BOOL)crossFade
155     return _crossFade;
161 - (void)setCrossFade:(BOOL)fade
163     _crossFade = fade;
169 - (BOOL)shiftSlowsAnimation
171     return _shiftSlowsAnimation;
177 - (void)setShiftSlowsAnimation:(BOOL)slows
179     _shiftSlowsAnimation = slows;
185 #pragma mark -
186 #pragma mark Overriding Methods
189 - (IBAction)showWindow:(id)sender
191                 // This forces the resources in the nib to load.
192         (void)[self window];
194                 // Clear the last setup and get a fresh one.
195         [toolbarIdentifiers removeAllObjects];
196         [toolbarViews removeAllObjects];
197         [toolbarItems removeAllObjects];
198         [self setupToolbar];
200         NSAssert (([toolbarIdentifiers count] > 0),
201                           @"No items were added to the toolbar in -setupToolbar.");
203         if ([[self window] toolbar] == nil) {
204                 NSToolbar *toolbar = [[NSToolbar alloc] initWithIdentifier:@"DBPreferencesToolbar"];
205                 [toolbar setAllowsUserCustomization:NO];
206                 [toolbar setAutosavesConfiguration:NO];
207                 [toolbar setSizeMode:NSToolbarSizeModeDefault];
208                 [toolbar setDisplayMode:NSToolbarDisplayModeIconAndLabel];
209                 [toolbar setDelegate:self];
210                 [[self window] setToolbar:toolbar];
211                 [toolbar release];
212         }
214         NSString *firstIdentifier = [toolbarIdentifiers objectAtIndex:0];
215         [[[self window] toolbar] setSelectedItemIdentifier:firstIdentifier];
216         [self displayViewForIdentifier:firstIdentifier animate:NO];
218         [[self window] center];
220         [super showWindow:sender];
226 #pragma mark -
227 #pragma mark Toolbar
230 - (NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar*)toolbar
232         return toolbarIdentifiers;
234         (void)toolbar;
240 - (NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar*)toolbar
242         return toolbarIdentifiers;
244         (void)toolbar;
250 - (NSArray *)toolbarSelectableItemIdentifiers:(NSToolbar *)toolbar
252         return toolbarIdentifiers;
253         (void)toolbar;
259 - (NSToolbarItem *)toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSString *)identifier willBeInsertedIntoToolbar:(BOOL)willBeInserted
261         return [toolbarItems objectForKey:identifier];
262         (void)toolbar;
263         (void)willBeInserted;
269 - (void)toggleActivePreferenceView:(NSToolbarItem *)toolbarItem
271         [self displayViewForIdentifier:[toolbarItem itemIdentifier] animate:YES];
277 - (void)displayViewForIdentifier:(NSString *)identifier animate:(BOOL)animate
279                 // Find the view we want to display.
280         NSView *newView = [toolbarViews objectForKey:identifier];
282                 // See if there are any visible views.
283         NSView *oldView = nil;
284         if ([[contentSubview subviews] count] > 0) {
285                         // Get a list of all of the views in the window. Usually at this
286                         // point there is just one visible view. But if the last fade
287                         // hasn't finished, we need to get rid of it now before we move on.
288                 NSEnumerator *subviewsEnum = [[contentSubview subviews] reverseObjectEnumerator];
290                         // The first one (last one added) is our visible view.
291                 oldView = [subviewsEnum nextObject];
293                         // Remove any others.
294                 NSView *reallyOldView = nil;
295                 while ((reallyOldView = [subviewsEnum nextObject]) != nil) {
296                         [reallyOldView removeFromSuperviewWithoutNeedingDisplay];
297                 }
298         }
300         if (![newView isEqualTo:oldView]) {
301                 NSRect frame = [newView bounds];
302                 frame.origin.y = NSHeight([contentSubview frame]) - NSHeight([newView bounds]);
303                 [newView setFrame:frame];
304                 [contentSubview addSubview:newView];
305                 [[self window] setInitialFirstResponder:newView];
307                 if (animate && [self crossFade])
308                         [self crossFadeView:oldView withView:newView];
309                 else {
310                         [oldView removeFromSuperviewWithoutNeedingDisplay];
311                         [newView setHidden:NO];
312                         [[self window] setFrame:[self frameForView:newView] display:YES animate:animate];
313                 }
315                 [[self window] setTitle:[[toolbarItems objectForKey:identifier] label]];
316         }
322 #pragma mark -
323 #pragma mark Cross-Fading Methods
326 - (void)crossFadeView:(NSView *)oldView withView:(NSView *)newView
328         [viewAnimation stopAnimation];
330     if ([self shiftSlowsAnimation] && [[[self window] currentEvent] modifierFlags] & NSShiftKeyMask)
331                 [viewAnimation setDuration:1.25];
332     else
333                 [viewAnimation setDuration:0.25];
335         NSDictionary *fadeOutDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
336                 oldView, NSViewAnimationTargetKey,
337                 NSViewAnimationFadeOutEffect, NSViewAnimationEffectKey,
338                 nil];
340         NSDictionary *fadeInDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
341                 newView, NSViewAnimationTargetKey,
342                 NSViewAnimationFadeInEffect, NSViewAnimationEffectKey,
343                 nil];
345         NSDictionary *resizeDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
346                 [self window], NSViewAnimationTargetKey,
347                 [NSValue valueWithRect:[[self window] frame]], NSViewAnimationStartFrameKey,
348                 [NSValue valueWithRect:[self frameForView:newView]], NSViewAnimationEndFrameKey,
349                 nil];
351         NSArray *animationArray = [NSArray arrayWithObjects:
352                 fadeOutDictionary,
353                 fadeInDictionary,
354                 resizeDictionary,
355                 nil];
357         [viewAnimation setViewAnimations:animationArray];
358         [viewAnimation startAnimation];
364 - (void)animationDidEnd:(NSAnimation *)animation
366         NSView *subview;
368                 // Get a list of all of the views in the window. Hopefully
369                 // at this point there are two. One is visible and one is hidden.
370         NSEnumerator *subviewsEnum = [[contentSubview subviews] reverseObjectEnumerator];
372                 // This is our visible view. Just get past it.
373         subview = [subviewsEnum nextObject];
375                 // Remove everything else. There should be just one, but
376                 // if the user does a lot of fast clicking, we might have
377                 // more than one to remove.
378         while ((subview = [subviewsEnum nextObject]) != nil) {
379                 [subview removeFromSuperviewWithoutNeedingDisplay];
380         }
382                 // This is a work-around that prevents the first
383                 // toolbar icon from becoming highlighted.
384         [[self window] makeFirstResponder:nil];
386         (void)animation;
392 - (NSRect)frameForView:(NSView *)view
393         // Calculate the window size for the new view.
395         NSRect windowFrame = [[self window] frame];
396         NSRect contentRect = [[self window] contentRectForFrameRect:windowFrame];
397         float windowTitleAndToolbarHeight = NSHeight(windowFrame) - NSHeight(contentRect);
399         windowFrame.size.height = NSHeight([view frame]) + windowTitleAndToolbarHeight;
400         windowFrame.size.width = NSWidth([view frame]);
401         windowFrame.origin.y = NSMaxY([[self window] frame]) - NSHeight(windowFrame);
403         return windowFrame;
409 @end