2006-09-04 14:06:23 -04:00
# import "SS_PrefsController.h"
# import "SS_PreferencePaneProtocol.h"
@ implementation SS_PrefsController
# define Last_Pane _Defaults _Key [ [ [ NSBundle mainBundle ] bundleIdentifier ] stringByAppendingString : @ "_Preferences_Last_Pane_Defaults_Key" ]
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// version / init / dealloc / constructors
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ ( int ) version
{
return 1 ; // 28 th June 2003
}
+ ( id ) preferencesWithPanesSearchPath : ( NSString * ) path bundleExtension : ( NSString * ) ext
{
return [ [ [ SS_PrefsController alloc ] initWithPanesSearchPath : path bundleExtension : ext ] autorelease ] ;
}
+ ( id ) preferencesWithBundleExtension : ( NSString * ) ext
{
return [ [ [ SS_PrefsController alloc ] initWithBundleExtension : ext ] autorelease ] ;
}
+ ( id ) preferencesWithPanesSearchPath : ( NSString * ) path
{
return [ [ [ SS_PrefsController alloc ] initWithPanesSearchPath : path ] autorelease ] ;
}
+ ( id ) preferences
{
return [ [ [ SS_PrefsController alloc ] init ] autorelease ] ;
}
- ( id ) init
{
return [ self initWithPanesSearchPath : nil bundleExtension : nil ] ;
}
- ( id ) initWithPanesSearchPath : ( NSString * ) path
{
return [ self initWithPanesSearchPath : path bundleExtension : nil ] ;
}
- ( id ) initWithBundleExtension : ( NSString * ) ext
{
return [ self initWithPanesSearchPath : nil bundleExtension : ext ] ;
}
// Designated initializer
- ( id ) initWithPanesSearchPath : ( NSString * ) path bundleExtension : ( NSString * ) ext
{
2007-07-04 21:16:25 -04:00
if ( self = [ super init ] )
{
2006-09-04 14:06:23 -04:00
[ self setDebug : NO ] ;
preferencePanes = [ [ NSMutableDictionary alloc ] init ] ;
panesOrder = [ [ NSMutableArray alloc ] init ] ;
[ self setToolbarDisplayMode : NSToolbarDisplayModeIconAndLabel ] ;
# if MAC_OS _X _VERSION _MAX _ALLOWED >= MAC_OS _X _VERSION _10 _2
[ self setToolbarSizeMode : NSToolbarSizeModeDefault ] ;
# endif
[ self setUsesTexturedWindow : NO ] ;
[ self setAlwaysShowsToolbar : NO ] ;
[ self setAlwaysOpensCentered : YES ] ;
if ( ! ext || [ ext isEqualToString : @ "" ] ) {
bundleExtension = [ [ NSString alloc ] initWithString : @ "preferencePane" ] ;
} else {
bundleExtension = [ ext retain ] ;
}
if ( ! path || [ path isEqualToString : @ "" ] ) {
searchPath = [ [ NSString alloc ] initWithString : [ [ NSBundle mainBundle ] resourcePath ] ] ;
} else {
searchPath = [ path retain ] ;
}
// Read PreferencePanes
if ( searchPath ) {
NSEnumerator * enumerator = [ [ NSBundle pathsForResourcesOfType : bundleExtension inDirectory : searchPath ] objectEnumerator ] ;
NSString * panePath ;
while ( ( panePath = [ enumerator nextObject ] ) ) {
[ self activatePane : panePath ] ;
}
}
return self ;
}
return nil ;
}
- ( void ) dealloc
{
if ( prefsWindow ) {
[ prefsWindow release ] ;
}
if ( prefsToolbar ) {
[ prefsToolbar release ] ;
}
if ( prefsToolbarItems ) {
[ prefsToolbarItems release ] ;
}
if ( preferencePanes ) {
[ preferencePanes release ] ;
}
if ( panesOrder ) {
[ panesOrder release ] ;
}
if ( bundleExtension ) {
[ bundleExtension release ] ;
}
if ( searchPath ) {
[ searchPath release ] ;
}
[ super dealloc ] ;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// Preferences methods
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- ( void ) showPreferencesWindow
{
[ self createPreferencesWindowAndDisplay : YES ] ;
}
- ( void ) createPreferencesWindow
{
[ self createPreferencesWindowAndDisplay : YES ] ;
}
- ( void ) createPreferencesWindowAndDisplay : ( BOOL ) shouldDisplay
{
if ( prefsWindow ) {
if ( alwaysOpensCentered && ! [ prefsWindow isVisible ] ) {
[ prefsWindow center ] ;
}
[ prefsWindow makeKeyAndOrderFront : nil ] ;
return ;
}
// Create prefs window
unsigned int styleMask = ( NSClosableWindowMask | NSResizableWindowMask ) ;
if ( usesTexturedWindow ) {
styleMask = ( styleMask | NSTexturedBackgroundWindowMask ) ;
}
prefsWindow = [ [ NSWindow alloc ] initWithContentRect : NSMakeRect ( 0 , 0 , 350 , 200 )
styleMask : styleMask
backing : NSBackingStoreBuffered
defer : NO ] ;
[ prefsWindow setReleasedWhenClosed : NO ] ;
[ prefsWindow setTitle : @ "Preferences" ] ; // initial default title
2007-07-04 21:16:25 -04:00
[ prefsWindow setShowsToolbarButton : NO ] ;
2006-09-04 14:06:23 -04:00
[ prefsWindow center ] ;
[ self createPrefsToolbar ] ;
// Register defaults
NSUserDefaults * defaults = [ NSUserDefaults standardUserDefaults ] ;
if ( panesOrder && ( [ panesOrder count ] > 0 ) ) {
NSMutableDictionary * defaultValues = [ NSMutableDictionary dictionary ] ;
[ defaultValues setObject : [ panesOrder objectAtIndex : 0 ] forKey : Last_Pane _Defaults _Key ] ;
[ defaults registerDefaults : defaultValues ] ;
}
// Load last view
NSString * lastViewName = [ defaults objectForKey : Last_Pane _Defaults _Key ] ;
if ( [ panesOrder containsObject : lastViewName ] && [ self loadPrefsPaneNamed : lastViewName display : NO ] ) {
if ( shouldDisplay ) {
[ prefsWindow makeKeyAndOrderFront : nil ] ;
}
return ;
}
[ self debugLog : [ NSString stringWithFormat : @ "Could not load last-used preference pane \" % @ \ ". Trying to load another pane instead." , lastViewName ] ] ;
// Try to load each prefpane in turn if loading the last - viewed one fails .
NSEnumerator * panes = [ panesOrder objectEnumerator ] ;
NSString * pane ;
while ( pane = [ panes nextObject ] ) {
if ( ! [ pane isEqualToString : lastViewName ] ) {
if ( [ self loadPrefsPaneNamed : pane display : NO ] ) {
if ( shouldDisplay ) {
[ prefsWindow makeKeyAndOrderFront : nil ] ;
}
return ;
}
}
}
[ self debugLog : [ NSString stringWithFormat : @ "Could not load any valid preference panes. The preference pane bundle extension was \" % @ \ " and the search path was: %@" , bundleExtension , searchPath ] ] ;
// Show alert dialog .
NSString * appName = [ [ NSBundle mainBundle ] objectForInfoDictionaryKey : @ "CFBundleName" ] ;
NSRunAlertPanel ( @ "Preferences" ,
[ NSString stringWithFormat : @ "Preferences are not available for %@." , appName ] ,
@ "OK" ,
nil ,
nil ) ;
[ prefsWindow release ] ;
prefsWindow = nil ;
}
- ( void ) destroyPreferencesWindow
{
if ( prefsWindow ) {
[ prefsWindow release ] ;
}
prefsWindow = nil ;
}
- ( void ) activatePane : ( NSString * ) path {
NSBundle * paneBundle = [ NSBundle bundleWithPath : path ] ;
if ( paneBundle ) {
NSDictionary * paneDict = [ paneBundle infoDictionary ] ;
NSString * paneName = [ paneDict objectForKey : @ "NSPrincipalClass" ] ;
if ( paneName ) {
Class paneClass = NSClassFromString ( paneName ) ;
if ( ! paneClass ) {
paneClass = [ paneBundle principalClass ] ;
if ( [ paneClass conformsToProtocol : @ protocol ( SS_PreferencePaneProtocol ) ] && [ paneClass isKindOfClass : [ NSObject class ] ] ) {
NSArray * panes = [ paneClass preferencePanes ] ;
NSEnumerator * enumerator = [ panes objectEnumerator ] ;
id < SS_PreferencePaneProtocol > aPane ;
while ( aPane = [ enumerator nextObject ] ) {
[ panesOrder addObject : [ aPane paneName ] ] ;
[ preferencePanes setObject : aPane forKey : [ aPane paneName ] ] ;
}
} else {
[ self debugLog : [ NSString stringWithFormat : @ "Did not load bundle: %@ because its Principal Class is either not an NSObject subclass, or does not conform to the PreferencePane Protocol." , paneBundle ] ] ;
}
} else {
[ self debugLog : [ NSString stringWithFormat : @ "Did not load bundle: %@ because its Principal Class was already used in another Preference pane." , paneBundle ] ] ;
}
} else {
[ self debugLog : [ NSString stringWithFormat : @ "Could not obtain name of Principal Class for bundle: %@" , paneBundle ] ] ;
}
} else {
[ self debugLog : [ NSString stringWithFormat : @ "Could not initialize bundle: %@" , paneBundle ] ] ;
}
}
- ( BOOL ) loadPreferencePaneNamed : ( NSString * ) name
{
return [ self loadPrefsPaneNamed : ( NSString * ) name display : YES ] ;
}
- ( NSArray * ) loadedPanes
{
if ( preferencePanes ) {
return [ preferencePanes allKeys ] ;
}
return nil ;
}
- ( BOOL ) loadPrefsPaneNamed : ( NSString * ) name display : ( BOOL ) disp
{
if ( ! prefsWindow ) {
NSBeep ( ) ;
[ self debugLog : [ NSString stringWithFormat : @ "Could not load \" % @ \ " preference pane because the Preferences window seems to no longer exist." , name ] ] ;
return NO ;
}
id tempPane = nil ;
tempPane = [ preferencePanes objectForKey : name ] ;
if ( ! tempPane ) {
[ self debugLog : [ NSString stringWithFormat : @ "Could not load preference pane \" % @ \ ", because that pane does not exist." , name ] ] ;
return NO ;
}
NSView * prefsView = nil ;
prefsView = [ tempPane paneView ] ;
if ( ! prefsView ) {
[ self debugLog : [ NSString stringWithFormat : @ "Could not load \" % @ \ " preference pane because its view could not be loaded from the bundle." , name ] ] ;
return NO ;
}
// Get rid of old view before resizing , for display purposes .
if ( disp ) {
NSView * tempView = [ [ NSView alloc ] initWithFrame : [ [ prefsWindow contentView ] frame ] ] ;
[ prefsWindow setContentView : tempView ] ;
[ tempView release ] ;
}
// Preserve upper left point of window during resize .
NSRect newFrame = [ prefsWindow frame ] ;
newFrame . size . height = [ prefsView frame ] . size . height + ( [ prefsWindow frame ] . size . height - [ [ prefsWindow contentView ] frame ] . size . height ) ;
newFrame . size . width = [ prefsView frame ] . size . width ;
newFrame . origin . y + = ( [ [ prefsWindow contentView ] frame ] . size . height - [ prefsView frame ] . size . height ) ;
id < SS_PreferencePaneProtocol > pane = [ preferencePanes objectForKey : name ] ;
[ prefsWindow setShowsResizeIndicator : ( [ pane allowsHorizontalResizing ] || [ pane allowsHorizontalResizing ] ) ] ;
[ prefsWindow setFrame : newFrame display : disp animate : disp ] ;
[ prefsWindow setContentView : prefsView ] ;
// Set appropriate resizing on window .
NSSize theSize = [ prefsWindow frame ] . size ;
theSize . height - = ToolbarHeightForWindow ( prefsWindow ) ;
[ prefsWindow setMinSize : theSize ] ;
BOOL canResize = NO ;
if ( [ pane allowsHorizontalResizing ] ) {
theSize . width = FLT_MAX ;
canResize = YES ;
}
if ( [ pane allowsVerticalResizing ] ) {
theSize . height = FLT_MAX ;
canResize = YES ;
}
[ prefsWindow setMaxSize : theSize ] ;
[ prefsWindow setShowsResizeIndicator : canResize ] ;
if ( ( prefsToolbarItems && ( [ prefsToolbarItems count ] > 1 ) ) || alwaysShowsToolbar ) {
[ prefsWindow setTitle : [ @ "Preferences: " stringByAppendingString : name ] ] ;
}
// Update defaults
NSUserDefaults * defaults = [ NSUserDefaults standardUserDefaults ] ;
[ defaults setObject : name forKey : Last_Pane _Defaults _Key ] ;
2007-07-06 23:59:57 -04:00
[ prefsToolbar setSelectedItemIdentifier : name ] ;
2006-09-04 14:06:23 -04:00
return YES ;
}
- ( void ) debugLog : ( NSString * ) msg
{
if ( debug ) {
NSLog ( @ "[--- PREFERENCES DEBUG MESSAGE ---]\r%@\r\r" , msg ) ;
}
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// Prefs Toolbar methods
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
float ToolbarHeightForWindow ( NSWindow * window )
{
NSToolbar * toolbar ;
float toolbarHeight = 0.0 ;
NSRect windowFrame ;
toolbar = [ window toolbar ] ;
if ( toolbar && [ toolbar isVisible ] )
{
windowFrame = [ NSWindow contentRectForFrameRect : [ window frame ]
styleMask : [ window styleMask ] ] ;
toolbarHeight = NSHeight ( windowFrame )
- NSHeight ( [ [ window contentView ] frame ] ) ;
}
return toolbarHeight ;
}
- ( void ) createPrefsToolbar
{
// Create toolbar items
prefsToolbarItems = [ [ NSMutableDictionary alloc ] init ] ;
NSEnumerator * itemEnumerator = [ panesOrder objectEnumerator ] ;
NSString * name ;
NSImage * itemImage ;
while ( name = [ itemEnumerator nextObject ] ) {
if ( [ preferencePanes objectForKey : name ] ! = nil ) {
NSToolbarItem * item = [ [ NSToolbarItem alloc ] initWithItemIdentifier : name ] ;
[ item setPaletteLabel : name ] ; // item ' s label in the "Customize Toolbar" sheet ( not relevant here , but we set it anyway )
[ item setLabel : name ] ; // item ' s label in the toolbar
NSString * tempTip = [ [ preferencePanes objectForKey : name ] paneToolTip ] ;
if ( ! tempTip || [ tempTip isEqualToString : @ "" ] ) {
[ item setToolTip : nil ] ;
} else {
[ item setToolTip : tempTip ] ;
}
itemImage = [ [ preferencePanes objectForKey : name ] paneIcon ] ;
[ item setImage : itemImage ] ;
[ item setTarget : self ] ;
[ item setAction : @ selector ( prefsToolbarItemClicked : ) ] ; // action called when item is clicked
[ prefsToolbarItems setObject : item forKey : name ] ; // add to items
[ item release ] ;
} else {
[ self debugLog : [ NSString stringWithFormat : @ "Could not create toolbar item for preference pane \" % @ \ ", because that pane does not exist." , name ] ] ;
}
}
NSString * bundleIdentifier = [ [ NSBundle mainBundle ] bundleIdentifier ] ;
prefsToolbar = [ [ NSToolbar alloc ] initWithIdentifier : [ bundleIdentifier stringByAppendingString : @ "_Preferences_Toolbar_Identifier" ] ] ;
[ prefsToolbar setDelegate : self ] ;
[ prefsToolbar setAllowsUserCustomization : NO ] ;
[ prefsToolbar setAutosavesConfiguration : NO ] ;
[ prefsToolbar setDisplayMode : toolbarDisplayMode ] ;
# if MAC_OS _X _VERSION _MAX _ALLOWED >= MAC_OS _X _VERSION _10 _2
[ prefsToolbar setSizeMode : toolbarSizeMode ] ;
# endif
if ( ( prefsToolbarItems && ( [ prefsToolbarItems count ] > 1 ) ) || alwaysShowsToolbar ) {
[ prefsWindow setToolbar : prefsToolbar ] ;
} else if ( ! alwaysShowsToolbar && prefsToolbarItems && ( [ prefsToolbarItems count ] = = 1 ) ) {
[ self debugLog : @ "Not showing toolbar in Preferences window because there is only one preference pane loaded. You can override this behaviour using -[setAlwaysShowsToolbar:YES]." ] ;
}
}
- ( NSToolbarDisplayMode ) toolbarDisplayMode
{
return toolbarDisplayMode ;
}
- ( void ) setToolbarDisplayMode : ( NSToolbarDisplayMode ) displayMode
{
toolbarDisplayMode = displayMode ;
}
# if MAC_OS _X _VERSION _MAX _ALLOWED >= MAC_OS _X _VERSION _10 _2
- ( NSToolbarSizeMode ) toolbarSizeMode
{
return toolbarSizeMode ;
}
- ( void ) setToolbarSizeMode : ( NSToolbarSizeMode ) sizeMode
{
toolbarSizeMode = sizeMode ;
}
# endif
- ( void ) prefsToolbarItemClicked : ( NSToolbarItem * ) item
{
if ( ! [ [ item itemIdentifier ] isEqualToString : [ prefsWindow title ] ] ) {
[ self loadPrefsPaneNamed : [ item itemIdentifier ] display : YES ] ;
}
}
- ( NSArray * ) toolbarAllowedItemIdentifiers : ( NSToolbar * ) toolbar
{
return panesOrder ;
}
2007-07-04 21:16:25 -04:00
- ( NSArray * ) toolbarSelectableItemIdentifiers : ( NSToolbar * ) toolbar
{
return panesOrder ;
}
2006-09-04 14:06:23 -04:00
- ( NSArray * ) toolbarDefaultItemIdentifiers : ( NSToolbar * ) toolbar
{
return panesOrder ;
}
- ( NSToolbarItem * ) toolbar : ( NSToolbar * ) toolbar itemForItemIdentifier : ( NSString * ) itemIdentifier willBeInsertedIntoToolbar : ( BOOL ) flag
{
return [ prefsToolbarItems objectForKey : itemIdentifier ] ;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// Accessors
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- ( NSWindow * ) preferencesWindow
{
return prefsWindow ;
}
- ( NSString * ) bundleExtension
{
return bundleExtension ;
}
- ( NSString * ) searchPath
{
return searchPath ;
}
- ( NSArray * ) panesOrder
{
return panesOrder ;
}
- ( void ) setPanesOrder : ( NSArray * ) newPanesOrder
{
[ panesOrder removeAllObjects ] ;
NSEnumerator * enumerator = [ newPanesOrder objectEnumerator ] ;
NSString * name ;
while ( name = [ enumerator nextObject ] ) {
if ( [ preferencePanes objectForKey : name ] ! = nil ) {
[ panesOrder addObject : name ] ;
} else {
[ self debugLog : [ NSString stringWithFormat : @ "Did not add preference pane \" % @ \ " to the toolbar ordering array, because that pane does not exist." , name ] ] ;
}
}
}
- ( BOOL ) debug
{
return debug ;
}
- ( void ) setDebug : ( BOOL ) newDebug
{
debug = newDebug ;
}
- ( BOOL ) usesTexturedWindow
{
return usesTexturedWindow ;
}
- ( void ) setUsesTexturedWindow : ( BOOL ) newUsesTexturedWindow
{
usesTexturedWindow = newUsesTexturedWindow ;
}
- ( BOOL ) alwaysShowsToolbar
{
return alwaysShowsToolbar ;
}
- ( void ) setAlwaysShowsToolbar : ( BOOL ) newAlwaysShowsToolbar
{
alwaysShowsToolbar = newAlwaysShowsToolbar ;
}
- ( BOOL ) alwaysOpensCentered
{
return alwaysOpensCentered ;
}
- ( void ) setAlwaysOpensCentered : ( BOOL ) newAlwaysOpensCentered
{
alwaysOpensCentered = newAlwaysOpensCentered ;
}
@ end