/* GSToolbar.m The basic toolbar class. Copyright (C) 2004 Free Software Foundation, Inc. Author: Gregory John Casamento , Fabien Vallon , Quentin Mathe Date: February 2004 This file is part of the GNUstep GUI Library. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include #include "AppKit/NSApplication.h" #include "AppKit/NSToolbarItem.h" #include "AppKit/NSView.h" #include "AppKit/NSClipView.h" #include "AppKit/NSButton.h" #include "AppKit/NSNibLoading.h" #include "AppKit/NSBezierPath.h" #include "AppKit/NSImage.h" #include "AppKit/NSMenu.h" #include "AppKit/NSEvent.h" #include "AppKit/NSWindow.h" #include "AppKit/NSWindow+Toolbar.h" #include "GNUstepGUI/GSToolbarView.h" #include "GNUstepGUI/GSToolbar.h" // internal static NSNotificationCenter *nc = nil; static const int current_version = 1; static NSMutableArray *toolbars; // Validation stuff static const unsigned int ValidationInterval = 10; static id validationCenter; // Extensions @implementation NSArray (ObjectsWithValueForKey) - (NSArray *) objectsWithValue: (id)value forKey: (NSString *)key { NSMutableArray *result = [[NSMutableArray alloc] init]; NSArray *keys = [self valueForKey: key]; int i, n = 0; if (keys == nil) return nil; n = [keys count]; for (i = 0; i < n; i++) { if ([[keys objectAtIndex: i] isEqual: value]) { [result addObject: [self objectAtIndex: i]]; } } if ([result count] == 0) return nil; AUTORELEASE(result); return result; } @end // Validation support @interface GSValidationObject : NSObject { NSMutableArray *_observers; NSView *_view; } - (id) initWithView: (NSView *)view; - (NSArray *) observers; - (void) addObserver: (id)observer; - (void) removeObserver: (id)observer; - (void) validate; - (NSView *) view; @end @interface GSValidationManager : NSObject { NSWindow *_window; NSView *_trackingRectView; NSTrackingRectTag _trackingRect; NSTimer *_validationTimer; BOOL _inside; } - (id) initWithWindow: (NSWindow *)window; - (void) validate; - (void) invalidate; // Tracking rect methods - (void) mouseEntered: (NSEvent *)event; - (void) mouseExited: (NSEvent *)event; @end @interface GSValidationCenter : NSObject { NSMutableArray *_validationManagers; NSMutableArray *_validationObjects; NSWindow *_prevWindow; } + (GSValidationCenter *) sharedValidationCenter; - (id) init; - (void) viewWillMove: (NSNotification *)notification; - (void) viewDidMove: (NSNotification *)notification; - (void) unregisterValidationObject: (GSValidationObject *)validationObject; - (GSValidationObject *) validationObjectWithView: (NSView *)view; // Private methods - (GSValidationManager *) _validationManagerWithWindow: (NSWindow *)window; - (NSArray *) _validationObjectsWithWindow: (NSWindow *)window; @end // Validation mechanism @implementation GSValidationObject - (id) initWithView: (NSView *)view { if ((self = [super init]) != nil) { ASSIGN(_view, view); _observers = [[NSMutableArray alloc] init]; } return self; } - (void) dealloc { RELEASE(_view); RELEASE(_observers); [super dealloc]; } - (NSArray *) observers { return _observers; } - (void) addObserver: (id)observer { [_observers addObject: observer]; } - (void) removeObserver: (id)observer { if ([_observers containsObject: observer]) [_observers removeObject: observer]; } - (void) validate { if ([_view superview] != nil) { [_observers makeObjectsPerformSelector: @selector(_validate)]; } } - (NSView *) view { return _view; } @end @interface NSWindow (GNUstepPrivate) - (NSView *) _windowView; @end @implementation GSValidationManager - (id) initWithWindow: (NSWindow *)window { if ((self = [super init]) != nil) { NSView *vw; vw = [window _windowView]; ASSIGN(_window, window); [nc addObserver: self selector: @selector(windowDidUpdate:) name: NSWindowDidUpdateNotification object: _window]; [nc addObserver: self selector: @selector(windowWillClose:) name: NSWindowWillCloseNotification object: _window]; ASSIGN(_trackingRectView, vw); _trackingRect = [_trackingRectView addTrackingRect: [_trackingRectView bounds] owner: self userData: nil assumeInside: NO]; } return self; } - (void) invalidate { [_trackingRectView removeTrackingRect: _trackingRect]; // tracking rect retains us, that is normal ? [_validationTimer invalidate]; // timer idem } - (void) dealloc { RELEASE(_trackingRectView); RELEASE(_window); [super dealloc]; } - (void) windowWillClose: (NSNotification *)notification { GSValidationCenter *vc = [GSValidationCenter sharedValidationCenter]; NSEnumerator *e; id vo; [nc removeObserver: self]; e = [[vc _validationObjectsWithWindow: _window] objectEnumerator]; while ((vo = [e nextObject]) != nil) { [vc unregisterValidationObject: vo]; } } - (void) mouseEntered: (NSEvent *)event { _inside = YES; if (_validationTimer == nil || ![_validationTimer isValid]) { _validationTimer = [NSTimer timerWithTimeInterval: ValidationInterval target: self selector: @selector(validate) userInfo: nil repeats: YES]; [[NSRunLoop currentRunLoop] addTimer: _validationTimer forMode: NSDefaultRunLoopMode]; [self validate]; } } - (void) mouseExited: (NSEvent *)event { _inside = NO; [_validationTimer invalidate]; _validationTimer = nil; } - (void) validate { [[[GSValidationCenter sharedValidationCenter] _validationObjectsWithWindow: _window] makeObjectsPerformSelector: @selector(validate)]; } - (void) windowDidUpdate: (NSNotification *)notification { if ([[NSApp currentEvent] type] == NSLeftMouseUp) { GSValidationManager *validationManager = [[GSValidationCenter sharedValidationCenter] _validationManagerWithWindow: [notification object]]; [validationManager performSelector: @selector(validate) withObject: nil]; } } @end @implementation GSValidationCenter + (GSValidationCenter *) sharedValidationCenter { if (validationCenter == nil) validationCenter = [[GSValidationCenter alloc] init]; return validationCenter; } - (id) init { if ((self = [super init]) != nil) { _validationManagers = [[NSMutableArray alloc] init]; _validationObjects = [[NSMutableArray alloc] init]; [nc addObserver: self selector: @selector(viewWillMove:) name: @"GSViewWillMoveToWindow" object: nil]; [nc addObserver: self selector: @selector(viewDidMove:) name: @"GSViewDidMoveToWindow" object: nil]; } return self; } - (void) viewWillMove: (NSNotification *)notification { _prevWindow = [[notification object] window]; RETAIN(_prevWindow); } - (void) viewDidMove: (NSNotification *)notification { NSWindow *window = [[notification object] window]; GSValidationManager *validationManager = [self _validationManagerWithWindow : _prevWindow]; if (validationManager != nil && [[self _validationObjectsWithWindow: _prevWindow] count] == 0) { [validationManager invalidate]; [_validationManagers removeObject: validationManager]; } if (window == nil) return; validationManager = [self _validationManagerWithWindow: window]; if (validationManager == nil) { validationManager = [[GSValidationManager alloc] initWithWindow: window]; [_validationManagers addObject: validationManager]; RELEASE(validationManager); } RELEASE(_prevWindow); } /* validationObjectWithView: opposite method * Remove the object in the validation objects list. * Release the validation manager associated to the window (related to the * validation object and its view) in the case there are no other validation * objects related to this window. */ - (void) unregisterValidationObject: (GSValidationObject *)validationObject { int index; if ((index = [_validationObjects indexOfObject: validationObject]) != NSNotFound) { NSWindow *window = [[validationObject view] window]; [_validationObjects removeObjectAtIndex: index]; if ([[self _validationObjectsWithWindow: window] count] == 0) { GSValidationManager *validationManager = [self _validationManagerWithWindow: window]; [validationManager invalidate]; [_validationManagers removeObject: validationManager]; } } } /* Return the validation object associated with the parameter view. * If there is no such validation object, create it by using view and then check * that an associated validation manager (bound to the window which the view * depends on) exists. * If there is no such validation manager, create it. */ - (GSValidationObject *) validationObjectWithView: (NSView *)view { GSValidationObject *validationObject; GSValidationManager *validationManager; NSWindow *window = [view window]; if (view == nil) { NSDebugLog(@"Validation object cannot be created because the view is \ nil"); return nil; } validationObject = [[_validationObjects objectsWithValue: view forKey: @"_view"] objectAtIndex: 0]; if (validationObject == nil) { validationObject = [[GSValidationObject alloc] initWithView: view]; [_validationObjects addObject: validationObject]; if (window == nil) return nil; validationManager = [self _validationManagerWithWindow: window]; if (validationManager == nil) { validationManager = [[GSValidationManager alloc] initWithWindow: window]; [_validationManagers addObject: validationManager]; RELEASE(validationManager); } } return validationObject; } // Private methods - (GSValidationManager *) _validationManagerWithWindow: (NSWindow *)window { GSValidationManager *validationManager = [[_validationManagers objectsWithValue: window forKey: @"_window"] objectAtIndex: 0]; return validationManager; } - (NSArray *) _validationObjectsWithWindow: (NSWindow *)window { NSEnumerator *e = [_validationObjects objectEnumerator]; id validationObject; NSMutableArray *array = [NSMutableArray array]; while ((validationObject = [e nextObject]) != nil) { if ([[validationObject view] window] == window) [array addObject: validationObject]; } return array; } @end // --- @interface GSToolbar (GNUstepPrivate) // Private class method + (NSMutableArray *) _toolbars; - (void) _insertItemWithItemIdentifier: (NSString *)itemIdentifier atIndex: (int)index broadcast: (BOOL)broadcast; // Private methods with broadcast support - (void) _insertItemWithItemIdentifier: (NSString *)itemIdentifier atIndex: (int)index broadcast: (BOOL)broadcast; - (void) _removeItemAtIndex: (int)index broadcast: (BOOL)broadcast; - (void) _setAllowsUserCustomization: (BOOL)flag broadcast: (BOOL)broadcast; - (void) _setAutosavesConfiguration: (BOOL)flag broadcast: (BOOL)broadcast; - (void) _setConfigurationFromDictionary: (NSDictionary *)configDict broadcast: (BOOL)broadcast; - (void) _setDelegate: (id)delegate broadcast: (BOOL)broadcast; // Few other private methods - (void) _build; - (void) _loadConfig; - (NSToolbarItem *) _toolbarItemForIdentifier: (NSString *)itemIdent; - (GSToolbar *) _toolbarModel; - (void) _validate; // Accessors - (void) _setToolbarView: (GSToolbarView *)toolbarView; - (GSToolbarView *) _toolbarView; - (void) _setWindow: (NSWindow *)window; - (NSWindow *) _window; @end @interface NSToolbarItem (GNUstepPrivate) - (BOOL) _selectable; - (void) _setSelectable: (BOOL)selectable; - (BOOL) _selected; - (void) _setSelected: (BOOL)selected; - (void) _setToolbar: (GSToolbar *)toolbar; @end @interface GSToolbarView (GNUstepPrivate) - (void) _reload; // Accessors - (NSArray *) _visibleBackViews; - (BOOL) _usesStandardBackgroundColor; - (BOOL) _willBeVisible; - (void) _setUsesStandardBackgroundColor: (BOOL)standard; - (void) _setWillBeVisible: (BOOL)willBeVisible; @end // --- @implementation GSToolbar // Class methods // Initialize the class when it is loaded + (void) initialize { if (self == [GSToolbar class]) { [self setVersion: current_version]; nc = [NSNotificationCenter defaultCenter]; toolbars = [[NSMutableArray alloc] init]; } } // Private class method to access static variable toolbars in subclasses + (NSMutableArray *) _toolbars { return toolbars; } // Instance methods - (id) initWithIdentifier: (NSString *)identifier { return [self initWithIdentifier: identifier displayMode: NSToolbarDisplayModeIconAndLabel sizeMode: NSToolbarSizeModeRegular]; } // default initialiser - (id) initWithIdentifier: (NSString *)identifier displayMode: (NSToolbarDisplayMode)displayMode sizeMode: (NSToolbarSizeMode)sizeMode { GSToolbar *toolbarModel; if ((self = [super init]) == nil) return nil; ASSIGN(_identifier, identifier); _items = [[NSMutableArray alloc] init]; toolbarModel = [self _toolbarModel]; if (toolbarModel != nil) { _customizationPaletteIsRunning = NO; _allowsUserCustomization = [toolbarModel allowsUserCustomization]; _autosavesConfiguration = [toolbarModel autosavesConfiguration]; ASSIGN(_configurationDictionary, [toolbarModel configurationDictionary]); if ([toolbarModel displayMode] != displayMode && [toolbarModel sizeMode] != sizeMode) { // raise an exception. } //[self _loadConfig]; } else { _customizationPaletteIsRunning = NO; _allowsUserCustomization = NO; _autosavesConfiguration = NO; _configurationDictionary = nil; //[self _loadConfig]; _delegate = nil; } _displayMode = displayMode; _sizeMode = sizeMode; [toolbars addObject: self]; return self; } - (void) dealloc { // use DESTROY ? RELEASE(_identifier); RELEASE(_selectedItemIdentifier); RELEASE(_configurationDictionary); RELEASE(_items); if (_delegate != nil) { [nc removeObserver: _delegate name: nil object: self]; _delegate = nil; } [super dealloc]; } - (void) insertItemWithItemIdentifier: (NSString *)itemIdentifier atIndex: (int)index { [self _insertItemWithItemIdentifier: itemIdentifier atIndex: index broadcast: YES]; } - (void) removeItemAtIndex: (int)index { [self _removeItemAtIndex: index broadcast: YES]; } - (void) runCustomizationPalette: (id)sender { _customizationPaletteIsRunning = [NSBundle loadNibNamed: @"GSToolbarCustomizationPalette" owner: self]; if(!_customizationPaletteIsRunning) { NSLog(@"Failed to load gorm for GSToolbarCustomizationPalette"); } } - (void) validateVisibleItems { NSEnumerator *e = [[self visibleItems] objectEnumerator]; NSToolbarItem *item = nil; while((item = [e nextObject]) != nil) { [item validate]; } } // Accessors - (BOOL) allowsUserCustomization { return _allowsUserCustomization; } - (BOOL) autosavesConfiguration { return _autosavesConfiguration; } - (NSDictionary *) configurationDictionary { return _configurationDictionary; } - (BOOL) customizationPaletteIsRunning { return _customizationPaletteIsRunning; } - (id) delegate { return _delegate; } - (NSToolbarDisplayMode) displayMode { return _displayMode; } - (NSString *) identifier { return _identifier; } - (NSArray *) items { return _items; } - (NSString *) selectedItemIdentifier { return _selectedItemIdentifier; } - (NSArray *) visibleItems { if ([_toolbarView superview] == nil) { return nil; } else { return [[_toolbarView _visibleBackViews] valueForKey: @"toolbarItem"]; } } - (void) setAllowsUserCustomization: (BOOL)flag { [self _setAllowsUserCustomization: flag broadcast: YES]; } - (void) setAutosavesConfiguration: (BOOL)flag { [self _setAutosavesConfiguration: flag broadcast: YES]; } - (void) setConfigurationFromDictionary: (NSDictionary *)configDict { ASSIGN(_configurationDictionary, configDict); } /** * Sets the receivers delegate ... this is the object which will receive * -toolbar:itemForItemIdentifier:willBeInsertedIntoToolbar: * -toolbarAllowedItemIdentifiers: and -toolbarDefaultItemIdentifiers: * messages. */ - (void) setDelegate: (id)delegate { [self _setDelegate: delegate broadcast: YES]; } - (void) setSelectedItemIdentifier: (NSString *)itemIdentifier { NSArray *selectedItems; NSArray *itemsToSelect; NSEnumerator *e; NSToolbarItem *item; NSArray *selectableIdentifiers = nil; BOOL updated = NO; // First, we have to deselect the previous selected toolbar items selectedItems = [[self items] objectsWithValue: [self selectedItemIdentifier] forKey: @"_itemIdentifier"]; e = [selectedItems objectEnumerator]; while ((item = [e nextObject]) != nil) { [item _setSelected: NO]; } if ([_delegate respondsToSelector: @selector(toolbarSelectableItemIdentifiers:)]) { selectableIdentifiers = [_delegate toolbarSelectableItemIdentifiers: self]; } else { NSLog(@"toolbar delegate does not respond to %@", @selector(toolbarSelectableItemIdentifiers:)); return; } if (selectableIdentifiers == nil) { NSLog(@"toolbar delegate returns no such selectable item identifiers"); return; } itemsToSelect = [_items objectsWithValue: itemIdentifier forKey: @"_itemIdentifier"]; e = [itemsToSelect objectEnumerator]; while ((item = [e nextObject]) != nil) { if ([selectableIdentifiers containsObject: [item itemIdentifier]]) { if (![item _selected]) [item _setSelected: YES]; updated = YES; } } if (updated) { ASSIGN(_selectedItemIdentifier, itemIdentifier); } else { NSLog(@"toolbar delegate returns no such selectable item identifiers"); } } - (NSToolbarSizeMode) sizeMode { return _sizeMode; } - (BOOL) usesStandardBackgroundColor { return [_toolbarView _usesStandardBackgroundColor]; } - (void) setUsesStandardBackgroundColor: (BOOL)standard { [_toolbarView _setUsesStandardBackgroundColor: standard]; } // Private methods - (void) _build { /* * toolbar build : * will use the delegate when there is no toolbar model */ GSToolbar *toolbarModel; NSArray *wantedItemIdentifiers; NSEnumerator *e; id itemIdentifier; int i = 0; _build = YES; RELEASE(_items); _items = [[NSMutableArray alloc] init]; toolbarModel = [self _toolbarModel]; if (toolbarModel != nil && [toolbarModel delegate] == _delegate) { wantedItemIdentifiers = [[toolbarModel items] valueForKey: @"_itemIdentifier"]; } else { wantedItemIdentifiers = [_delegate toolbarDefaultItemIdentifiers:self]; } e = [wantedItemIdentifiers objectEnumerator]; while ((itemIdentifier = [e nextObject]) != nil) { [self _insertItemWithItemIdentifier: itemIdentifier atIndex: i broadcast: NO]; i++; } _build = NO; } - (void) _loadConfig { if (_identifier != nil) { NSUserDefaults *defaults; NSString *tableKey; id config; defaults = [NSUserDefaults standardUserDefaults]; tableKey = [NSString stringWithFormat: @"GSToolbar Config %@",_identifier]; config = [defaults objectForKey: tableKey]; if (config != nil) { [self setConfigurationFromDictionary: config]; } } } - (GSToolbar *) _toolbarModel { NSArray *linked; id toolbar; linked = [toolbars objectsWithValue: [self identifier] forKey: @"_identifier"]; if (linked != nil && [linked count] > 0) { toolbar = [linked objectAtIndex: 0]; // toolbar model class must be identical to self class : // an NSToolbar instance cannot use a GSToolbar instance as a model if ([toolbar isMemberOfClass: [self class]] && toolbar != self) return toolbar; } return nil; } - (NSToolbarItem *) _toolbarItemForIdentifier: (NSString *)itemIdent { NSToolbarItem *item = nil; if([itemIdent isEqual: NSToolbarSeparatorItemIdentifier] || [itemIdent isEqual: NSToolbarSpaceItemIdentifier] || [itemIdent isEqual: NSToolbarFlexibleSpaceItemIdentifier] || [itemIdent isEqual: NSToolbarShowColorsItemIdentifier] || [itemIdent isEqual: NSToolbarShowFontsItemIdentifier] || [itemIdent isEqual: NSToolbarCustomizeToolbarItemIdentifier] || [itemIdent isEqual: NSToolbarPrintItemIdentifier]) { item = [[NSToolbarItem alloc] initWithItemIdentifier: itemIdent]; } return item; } /* * * The methods below handles the toolbar edition and broacasts each associated * event to the other toolbars with identical identifiers. * Warning : broadcast process only happens between instances based on the same * class. */ #define TRANSMIT(signature) \ NSEnumerator *e = [[toolbars objectsWithValue: _identifier forKey: \ @"_identifier"] objectEnumerator]; \ GSToolbar *toolbar; \ \ while ((toolbar = [e nextObject]) != nil) \ { \ if (toolbar != self && [toolbar isMemberOfClass: [self class]]) \ [toolbar signature]; \ } - (void) _insertItemWithItemIdentifier: (NSString *)itemIdentifier atIndex: (int)index broadcast: (BOOL)broadcast { NSToolbarItem *item = nil; NSArray *allowedItems = [_delegate toolbarAllowedItemIdentifiers: self]; if([allowedItems containsObject: itemIdentifier]) { item = [self _toolbarItemForIdentifier: itemIdentifier]; if (item == nil) { item = [_delegate toolbar: self itemForItemIdentifier: itemIdentifier willBeInsertedIntoToolbar: YES]; } if (item != nil) { NSArray *selectableItems; if ([_delegate respondsToSelector: @selector(toolbarSelectableItemIdentifiers:)]) { selectableItems = [_delegate toolbarSelectableItemIdentifiers: self]; if ([selectableItems containsObject: itemIdentifier]) [item _setSelectable: YES]; } [nc postNotificationName: NSToolbarWillAddItemNotification object: self]; [item _setToolbar: self]; [_items insertObject: item atIndex: index]; // We reload the toolbarView each time a new item is added except when // we build/create the toolbar if (!_build) [_toolbarView _reload]; if (broadcast) { TRANSMIT(_insertItemWithItemIdentifier: itemIdentifier atIndex: index broadcast: NO); } } } } - (void) _removeItemAtIndex: (int)index broadcast: (BOOL)broadcast { [_items removeObjectAtIndex: index]; [_toolbarView _reload]; [nc postNotificationName: NSToolbarDidRemoveItemNotification object: self]; if (broadcast) { TRANSMIT(_removeItemAtIndex: index broadcast: NO); } } - (void) _setAllowsUserCustomization: (BOOL)flag broadcast: (BOOL)broadcast { _allowsUserCustomization = flag; if (broadcast) { TRANSMIT(_setAllowsUserCustomization: _allowsUserCustomization broadcast: NO); } } - (void) _setAutosavesConfiguration: (BOOL)flag broadcast: (BOOL)broadcast { _autosavesConfiguration = flag; if (broadcast) { TRANSMIT(_setAutosavesConfiguration: _autosavesConfiguration broadcast: NO); } } - (void) _setConfigurationFromDictionary: (NSDictionary *)configDict broadcast: (BOOL)broadcast { ASSIGN(_configurationDictionary, configDict); if (broadcast) { TRANSMIT(_setConfigurationFromDictionary: _configurationDictionary broadcast: NO); } } - (void) _setDelegate: (id)delegate broadcast: (BOOL)broadcast { if (_delegate == delegate || (broadcast == NO && [_delegate isMemberOfClass: [delegate class]])) return; /* We don't reload instances which received this message and already have a * delegate based on a class identical to the parameter delegate, it permits * to use only one nib owner class as a toolbar delegate even if a new * instance of the nib owner are created with each new window (see * MiniController.m in the toolbar example application). */ #define CHECK_REQUIRED_METHOD(selector_name) \ if (![delegate respondsToSelector: @selector(selector_name)]) \ [NSException raise: NSInternalInconsistencyException \ format: @"delegate does not respond to %@",@#selector_name] CHECK_REQUIRED_METHOD(toolbar:itemForItemIdentifier: willBeInsertedIntoToolbar:); CHECK_REQUIRED_METHOD(toolbarAllowedItemIdentifiers:); CHECK_REQUIRED_METHOD(toolbarDefaultItemIdentifiers:); if (_delegate) [nc removeObserver: _delegate name: nil object: self]; ASSIGN(_delegate, delegate); #define SET_DELEGATE_NOTIFICATION(notif_name) \ if ([_delegate respondsToSelector: @selector(toolbar##notif_name:)]) \ [nc addObserver: _delegate \ selector: @selector(toolbar##notif_name:) \ name: NSToolbar##notif_name##Notification object: self] SET_DELEGATE_NOTIFICATION(DidRemoveItem); SET_DELEGATE_NOTIFICATION(WillAddItem); [self _build]; if (_toolbarView != nil) [_toolbarView _reload]; // broadcast now... if (broadcast) { TRANSMIT(_setDelegate: _delegate broadcast: NO); } } // Private Accessors - (void) _setToolbarView: (GSToolbarView *)toolbarView { GSValidationObject *validationObject = nil; GSValidationCenter *vc = [GSValidationCenter sharedValidationCenter]; GSToolbar *toolbarModel = [self _toolbarModel]; if (_toolbarView != nil) { validationObject = [vc validationObjectWithView: _toolbarView]; if (validationObject != nil) { [validationObject removeObserver: self]; if ([[validationObject observers] count] == 0) [vc unregisterValidationObject: validationObject]; } } ASSIGN(_toolbarView, toolbarView); if (_toolbarView == nil) return; validationObject = [vc validationObjectWithView: _toolbarView]; if (validationObject != nil) [validationObject addObserver: self]; /* In the case, the user hasn't set a delegate until now, we set it. * Why ? * We don't set it before when the toolbar is inited, to do only one toolbar * content load. * ... * 1 toolbar = [[GSToolbar alloc] initWithIdentifier: @"blabla"]; * 2 [toolbar setDelegate: myDelegate]; * In case such method like 1 sets a default delegate for the identifier by * requesting a toolbar model, a toolbar content load would occur. * With a method like 2 which follows immediatly : * Another toolbar load content would occur related to a probably different * delegate. */ if (_delegate == nil) [self _setDelegate: [toolbarModel delegate] broadcast: NO]; } - (GSToolbarView *) _toolbarView { return _toolbarView; } - (void) _validate { [self validateVisibleItems]; } @end