1/* ============================================================================= 2 FILE: UKPrefsPanel.h 3 4 AUTHORS: M. Uli Kusterer (UK), (c) Copyright 2003, all rights reserved. 5 6 DIRECTIONS: 7 UKPrefsPanel is ridiculously easy to use: Create a tabless NSTabView, 8 where the name of each tab is the name for the toolbar item, and the 9 identifier of each tab is the identifier to be used for the toolbar 10 item to represent it. Then create image files with the identifier as 11 their names to be used as icons in the toolbar. 12 13 Finally, drag UKPrefsPanel.h into the NIB with the NSTabView, 14 instantiate a UKPrefsPanel and connect its tabView outlet to your 15 NSTabView. When you open the window, the UKPrefsPanel will 16 automatically add a toolbar to the window with all tabs represented by 17 a toolbar item, and clicking an item will switch between the tab view's 18 items. 19 20 21 REVISIONS: 22 2003-08-13 UK Added auto-save, fixed bug with empty window titles. 23 2003-07-22 UK Added Panther stuff, documented. 24 2003-06-30 UK Created. 25 ========================================================================== */ 26 27/* ----------------------------------------------------------------------------- 28 Headers: 29 -------------------------------------------------------------------------- */ 30 31#import "UKPrefsPanel.h" 32 33 34@implementation UKPrefsPanel 35 36/* ----------------------------------------------------------------------------- 37 Constructor: 38 -------------------------------------------------------------------------- */ 39 40-(id) init 41{ 42 if ( ! ( self = [super init] ) ) 43 return nil; 44 45 46 tabView = nil; 47 itemsList = [[NSMutableDictionary alloc] init]; 48 baseWindowName = [@"" retain]; 49 autosaveName = [@"com.ulikusterer" retain]; 50 51 return self; 52} 53 54 55/* ----------------------------------------------------------------------------- 56 Destructor: 57 -------------------------------------------------------------------------- */ 58 59-(void) dealloc 60{ 61 [itemsList release]; 62 [baseWindowName release]; 63 [autosaveName release]; 64 [super dealloc]; 65} 66 67 68/* ----------------------------------------------------------------------------- 69 awakeFromNib: 70 This object and all others in the NIB have been created and hooked up. 71 Fetch the window name so we can modify it to indicate the current 72 page, and add our toolbar to the window. 73 74 This method is the great obstacle to making UKPrefsPanel an NSTabView 75 subclass. When the tab view's awakeFromNib method is called, the 76 individual tabs aren't set up yet, meaning mapTabsToToolbar gives us an 77 empty toolbar. ... bummer. 78 79 If anybody knows how to fix this, you're welcome to tell me. 80 -------------------------------------------------------------------------- */ 81 82-(void) awakeFromNib 83{ 84 NSString* key; 85 int index = 0; 86 NSString* wndTitle = nil; 87 88 // Generate a string containing the window's title so we can display the original window title plus the selected pane: 89 wndTitle = [[tabView window] title]; 90 if( [wndTitle length] > 0 ) 91 { 92 [baseWindowName release]; 93 baseWindowName = [[NSString stringWithFormat: @"%@ : ", wndTitle] retain]; 94 } 95 96 // Make sure our autosave-name is based on the one of our prefs window: 97 [self setAutosaveName: [[tabView window] frameAutosaveName]]; 98 99 // Select the preferences page the user last had selected when this window was opened: 100 key = [NSString stringWithFormat: @"%@.prefspanel.recentpage", autosaveName]; 101 index = [[NSUserDefaults standardUserDefaults] integerForKey: key]; 102 [tabView selectTabViewItemAtIndex: 0]; 103 104 // Actually hook up our toolbar and the tabs: 105 [self mapTabsToToolbar]; 106 107 id box = [[[[tabView tabViewItemAtIndex:[tabView indexOfTabViewItem:[tabView selectedTabViewItem]]] view] subviews] objectAtIndex:0]; 108 if ([box isKindOfClass:[NSBox class]]) 109 { 110 /*float sizeDifference = [box frame].size.height - [[[[[tabView tabViewItemAtIndex:[tabView indexOfTabViewItem:[tabView selectedTabViewItem]]] view] subviews] objectAtIndex:0] frame].size.height; 111 [[windowController window] setFrame:NSMakeRect([[windowController window] frame].origin.x, 112 [[windowController window] frame].origin.y, 113 [[windowController window] frame].size.width, 114 [[windowController window] frame].size.height + sizeDifference) 115 display:YES 116 animate:YES];*/ 117 [[windowController window] setContentSize:NSMakeSize([[[windowController window] contentView] frame].size.width, [box frame].size.height)]; 118 [box setFrameOrigin:NSMakePoint([box frame].origin.x, 0)]; 119 } 120} 121 122 123/* ----------------------------------------------------------------------------- 124 mapTabsToToolbar: 125 Create a toolbar based on our tab control. 126 127 Tab title - Name for toolbar item. 128 Tab identifier - Image file name and toolbar item identifier. 129 -------------------------------------------------------------------------- */ 130 131-(void) mapTabsToToolbar 132{ 133 // Create a new toolbar instance, and attach it to our document window 134 NSToolbar *toolbar =[[tabView window] toolbar]; 135 int itemCount = 0, 136 x = 0; 137 NSTabViewItem *currPage = nil; 138 139 if( toolbar == nil ) // No toolbar yet? Create one! 140 toolbar = [[[NSToolbar alloc] initWithIdentifier: [NSString stringWithFormat: @"%@.prefspanel.toolbar", autosaveName]] autorelease]; 141 142 // Set up toolbar properties: Allow customization, give a default display mode, and remember state in user defaults 143 [toolbar setAllowsUserCustomization: YES]; 144 [toolbar setAutosavesConfiguration: YES]; 145 //[toolbar setDisplayMode: NSToolbarDisplayModeIconOnly]; 146 147 // Set up item list based on Tab View: 148 itemCount = [tabView numberOfTabViewItems]; 149 150 [itemsList removeAllObjects]; // In case we already had a toolbar. 151 152 for( x = 0; x < itemCount; x++ ) 153 { 154 NSTabViewItem* theItem = [tabView tabViewItemAtIndex:x]; 155 NSString* theIdentifier = [theItem identifier]; 156 NSString* theLabel = [theItem label]; 157 158 [itemsList setObject:theLabel forKey:theIdentifier]; 159 } 160 161 // We are the delegate 162 [toolbar setDelegate: self]; 163 164 // Attach the toolbar to the document window 165 [[tabView window] setToolbar: toolbar]; 166 167 // Set up window title: 168 currPage = [tabView selectedTabViewItem]; 169 if( currPage == nil ) 170 currPage = [tabView tabViewItemAtIndex:0]; 171 [[tabView window] setTitle: [baseWindowName stringByAppendingString: [currPage label]]]; 172 173 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3 174 if( [toolbar respondsToSelector: @selector(setSelectedItemIdentifier:)] ) 175 [toolbar setSelectedItemIdentifier: [currPage identifier]]; 176 #endif 177} 178 179 180/* ----------------------------------------------------------------------------- 181 orderFrontPrefsPanel: 182 IBAction to assign to "Preferences..." menu item. 183 -------------------------------------------------------------------------- */ 184 185-(IBAction) orderFrontPrefsPanel: (id)sender 186{ 187 [[tabView window] makeKeyAndOrderFront:sender]; 188} 189 190 191/* ----------------------------------------------------------------------------- 192 setTabView: 193 Accessor for specifying the tab view to query. 194 -------------------------------------------------------------------------- */ 195 196-(void) setTabView: (NSTabView*)tv 197{ 198 tabView = tv; 199} 200 201 202-(NSTabView*) tabView 203{ 204 return tabView; 205} 206 207 208/* ----------------------------------------------------------------------------- 209 setAutosaveName: 210 Name used for saving state of prefs window. 211 -------------------------------------------------------------------------- */ 212 213-(void) setAutosaveName: (NSString*)name 214{ 215 [name retain]; 216 [autosaveName release]; 217 autosaveName = name; 218} 219 220 221-(NSString*) autosaveName 222{ 223 return autosaveName; 224} 225 226 227/* ----------------------------------------------------------------------------- 228 toolbar:itemForItemIdentifier:willBeInsertedIntoToolbar: 229 Create an item with the proper image and name based on our list 230 of tabs for the specified identifier. 231 -------------------------------------------------------------------------- */ 232 233-(NSToolbarItem *) toolbar: (NSToolbar *)toolbar itemForItemIdentifier: (NSString *) itemIdent willBeInsertedIntoToolbar:(BOOL) willBeInserted 234{ 235 // Required delegate method: Given an item identifier, this method returns an item 236 // The toolbar will use this method to obtain toolbar items that can be displayed in the customization sheet, or in the toolbar itself 237 NSToolbarItem *toolbarItem = [[[NSToolbarItem alloc] initWithItemIdentifier: itemIdent] autorelease]; 238 NSString* itemLabel; 239 240 if( (itemLabel = [itemsList objectForKey:itemIdent]) != nil ) 241 { 242 // Set the text label to be displayed in the toolbar and customization palette 243 [toolbarItem setLabel: itemLabel]; 244 [toolbarItem setPaletteLabel: itemLabel]; 245 [toolbarItem setTag:[tabView indexOfTabViewItemWithIdentifier:itemIdent]]; 246 247 // Set up a reasonable tooltip, and image Note, these aren't localized, but you will likely want to localize many of the item's properties 248 [toolbarItem setToolTip: itemLabel]; 249 [toolbarItem setImage: [NSImage imageNamed:itemIdent]]; 250 251 // Tell the item what message to send when it is clicked 252 [toolbarItem setTarget: self]; 253 [toolbarItem setAction: @selector(changePanes:)]; 254 } 255 else 256 { 257 // itemIdent refered to a toolbar item that is not provide or supported by us or cocoa 258 // Returning nil will inform the toolbar this kind of item is not supported 259 toolbarItem = nil; 260 } 261 262 return toolbarItem; 263} 264 265 266/* ----------------------------------------------------------------------------- 267 toolbarSelectableItemIdentifiers: 268 Make sure all our custom items can be selected. NSToolbar will 269 automagically select the appropriate item when it is clicked. 270 -------------------------------------------------------------------------- */ 271 272#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3 273-(NSArray*) toolbarSelectableItemIdentifiers: (NSToolbar*)toolbar 274{ 275 return [itemsList allKeys]; 276} 277#endif 278 279 280/* ----------------------------------------------------------------------------- 281 changePanes: 282 Action for our custom toolbar items that causes the window title to 283 reflect the current pane and the proper pane to be shown in response to 284 a click. 285 -------------------------------------------------------------------------- */ 286 287-(IBAction) changePanes: (id)sender 288{ 289 NSString* key; 290 291 [[tabView window] setTitle: [baseWindowName stringByAppendingString: [sender label]]]; 292 293 key = [NSString stringWithFormat: @"%@.prefspanel.recentpage", autosaveName]; 294 [[NSUserDefaults standardUserDefaults] setInteger:[sender tag] forKey:key]; 295 296 id box = [[[[tabView tabViewItemAtIndex:[sender tag]] view] subviews] objectAtIndex:0]; 297 if ([box isKindOfClass:[NSBox class]]) 298 { 299 float sizeDifference = [box frame].size.height - [[[[[tabView tabViewItemAtIndex:[tabView indexOfTabViewItem:[tabView selectedTabViewItem]]] view] subviews] objectAtIndex:0] frame].size.height; 300 [[windowController window] setFrame:NSMakeRect([[windowController window] frame].origin.x, 301 [[windowController window] frame].origin.y - sizeDifference, 302 [[windowController window] frame].size.width, 303 [[windowController window] frame].size.height + sizeDifference) 304 display:YES 305 animate:YES]; 306 [box setFrameOrigin:NSMakePoint([box frame].origin.x, 0)]; 307 } 308 [tabView selectTabViewItemAtIndex: [sender tag]]; 309} 310 311 312/* ----------------------------------------------------------------------------- 313 toolbarDefaultItemIdentifiers: 314 Return the identifiers for all toolbar items that will be shown by 315 default. 316 This is simply a list of all tab view items in order. 317 -------------------------------------------------------------------------- */ 318 319-(NSArray*) toolbarDefaultItemIdentifiers: (NSToolbar *) toolbar 320{ 321 int itemCount = [tabView numberOfTabViewItems], 322 x; 323 NSTabViewItem* theItem = [tabView tabViewItemAtIndex:0]; 324 //NSMutableArray* defaultItems = [NSMutableArray arrayWithObjects: [theItem identifier], NSToolbarSeparatorItemIdentifier, nil]; 325 NSMutableArray* defaultItems = [NSMutableArray array]; 326 327 for( x = 0; x < itemCount; x++ ) 328 { 329 theItem = [tabView tabViewItemAtIndex:x]; 330 331 [defaultItems addObject: [theItem identifier]]; 332 } 333 334 return defaultItems; 335} 336 337 338/* ----------------------------------------------------------------------------- 339 toolbarAllowedItemIdentifiers: 340 Return the identifiers for all toolbar items that *can* be put in this 341 toolbar. We allow a couple more items (flexible space, separator lines 342 etc.) in addition to our custom items. 343 -------------------------------------------------------------------------- */ 344 345-(NSArray*) toolbarAllowedItemIdentifiers: (NSToolbar *) toolbar 346{ 347 NSMutableArray* allowedItems = [[itemsList allKeys] mutableCopy]; 348 349 [allowedItems addObjectsFromArray: [NSArray arrayWithObjects: NSToolbarSeparatorItemIdentifier, 350 NSToolbarSpaceItemIdentifier, NSToolbarFlexibleSpaceItemIdentifier, 351 NSToolbarCustomizeToolbarItemIdentifier, nil] ]; 352 353 return allowedItems; 354} 355 356 357@end 358