1// 2// PXBackgroundController.m 3// Pixen-XCode 4// 5// Created by Joe Osborn on Sun Oct 26 2003. 6// Copyright (c) 2003 Open Sword Group. All rights reserved. 7// 8 9#import "PXBackgroundController.h" 10#import "PXSlashyBackground.h" 11#import "PXMonotoneBackground.h" 12#import "PXCheckeredBackground.h" 13#import "PXImageBackground.h" 14#import "PXBackground.h" 15#import "PXNamePrompter.h" 16#import "PXCanvas.h" 17 18#ifdef __COCOA__ 19static NSString *BACKGROUNDPRESET = @"Application Support/Pixen/Backgrounds/Presets"; 20#else 21static NSString *BACKGROUNDPRESET = @"Pixen/Backgrounds/Presets"; 22#endif 23 24#define SAVEASPOPUPITEMTAG 1 25#define DELETEPOPUPITEMTAG 2 26 27static NSArray *defaultBackgrounds (void) 28{ 29 static NSArray *backgrounds = nil; 30 if (! backgrounds ) 31 { 32 backgrounds = [[NSArray alloc] initWithObjects:[[PXSlashyBackground alloc] init], 33 [[PXMonotoneBackground alloc] init], 34 [[PXCheckeredBackground alloc] init], 35 [[PXImageBackground alloc] init] , 36 nil]; 37 } 38 return backgrounds; 39} 40 41 42 43@interface PXBackgroundController ( Private) 44- (void) _populatePopup: (NSPopUpButton *) aPopup withDefaultBackgroundsUsingSelectionAction: (SEL)aSelector; 45- (void) _populatePopup: (NSPopUpButton *) aPopup withUserBackgroundsUsingSelectionAction: (SEL)aSelector; 46- (void) _populateMenu: (NSPopUpButton *) aPopup selectionAction: (SEL)aSelector; 47- (void) _populateMenus; 48- (void) _setUsesAlternateBackground:(BOOL)newUsesAlternateBackground; 49- (void)_setDefaultBackgroundsFor:(id) aCanvas; 50- (void) _setMainBackground:(id) aBackground; 51- (void) _setAlternateBackground:(id) aBackground; 52@end 53 54 55@implementation PXBackgroundController ( Private ) 56 57#define PXBackgroundControllerSetBackground(bg, menu, configView, newBg)\ 58{\ 59 [[bg configurator] removeFromSuperview];\ 60 [newBg retain];\ 61 [bg release];\ 62 bg = newBg;\ 63 [menu selectItemWithTitle:[bg name]];\ 64 [configView addSubview:[bg configurator]];\ 65} 66 67 68//Defaults backgrounds create by hand 69- (void) _populatePopup:(NSPopUpButton *) aPopup withDefaultBackgroundsUsingSelectionAction:(SEL)aSelector 70{ 71 NSEnumerator *enumerator = [defaultBackgrounds() objectEnumerator]; 72 id current; 73 74 while( ( current = [enumerator nextObject] ) ) 75 { 76 77 id item = [[[NSMenuItem alloc] initWithTitle:[current name] 78 action: aSelector 79 keyEquivalent: @""] autorelease]; 80#ifndef __COCOA__ 81 [item setTarget: self]; 82#endif 83 84 [item setRepresentedObject:[[current copy] autorelease]]; 85 [[aPopup menu] addItem:item]; 86 } 87} 88 89//Users backgrounds saved by the user usally in ~/Library/Application Support/Pixen/Backgrounds/Presets ( OSX ) 90// and $GNUSTEP_USER_HOME/Library/Pixen/Backgrounds/Presets for GNUstep 91- (void) _populatePopup:(NSPopUpButton*) aPopup withUserBackgroundsUsingSelectionAction:(SEL)aSelector 92{ 93 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES); 94 95 if ( [paths count] > 0) 96 { 97 NSString *path = [[paths objectAtIndex:0] stringByAppendingPathComponent: BACKGROUNDPRESET]; 98 //TODO check if exists ??? 99 id enumerator = [[NSFileManager defaultManager] enumeratorAtPath:path]; 100 id current; 101 102 while( ( current = [enumerator nextObject] ) ) 103 { 104 if ( [[current pathExtension] isEqualToString:@"pxbgnd"] ) 105 { 106 id item = [[[NSMenuItem alloc] initWithTitle:[current stringByDeletingPathExtension] 107 action: aSelector 108 keyEquivalent: @""] 109 autorelease]; 110#ifndef __COCOA__ 111 [item setTarget :self]; 112#endif 113 114 115 [item setRepresentedObject:[NSKeyedUnarchiver unarchiveObjectWithFile: 116 [path stringByAppendingPathComponent:current]]]; 117 [[aPopup menu] addItem:item]; 118 } 119 } 120 } 121} 122 123- (void) _populateMenu: (NSPopUpButton *) aPopup selectionAction: (SEL)aSelector 124{ 125 id selected = [[[aPopup titleOfSelectedItem] retain] autorelease]; 126 id menu = [aPopup menu]; 127 128 //remove all items 129 [aPopup removeAllItems]; 130 131 //add defaults backgrounds 132 [self _populatePopup:aPopup withDefaultBackgroundsUsingSelectionAction:aSelector]; 133 134 [menu addItem:[NSMenuItem separatorItem]]; 135 136 //Add user backgrounds 137 [self _populatePopup:aPopup withUserBackgroundsUsingSelectionAction:aSelector]; 138 139 [menu addItem:[NSMenuItem separatorItem]]; 140 141 //add "Save As" item 142 id item = [[[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"BACKGROUNDS_SAVE_AS", @"Backgrounds Save As") 143 action:@selector(saveCurrentConfiguration:) 144 keyEquivalent:@""] 145 autorelease]; 146#ifndef __COCOA__ 147 [item setTarget: self]; 148#endif 149 150 151 [[aPopup menu] addItem:item]; 152 153 //Add "Delete item" 154 item = [[[NSMenuItem alloc] initWithTitle: NSLocalizedString(@"BACKGROUNDS_DELETE", @"Backgrounds Delete") 155 action:@selector(deleteCurrentConfiguration:) 156 keyEquivalent:@""] 157 autorelease]; 158 159#ifndef __COCOA__ 160 [item setTarget: self]; 161#endif 162 163 [[aPopup menu] addItem:item]; 164 165 166 //Display the first item if none is selected or id "Delete current configurator" item is selected 167 //display the selected item if not 168 if( ( ! [[aPopup itemTitles] containsObject:selected] ) 169 || ( [[aPopup selectedItem] tag] == DELETEPOPUPITEMTAG ) ) 170 { 171 [aPopup selectItemAtIndex:0]; 172 } 173 else 174 { 175 [aPopup selectItemWithTitle:selected]; 176 } 177} 178 179 180- (void) _populateMenus 181{ 182 [self _populateMenu:mainMenu selectionAction:@selector(selectMainBackground:)]; 183 [self _populateMenu:alternateMenu selectionAction:@selector(selectAlternateBackground:)]; 184} 185 186 187- (void) _setUsesAlternateBackground:(BOOL)newUsesAlternateBackground 188{ 189 usesAlternateBackground = newUsesAlternateBackground; 190 [alternateMenu setEnabled:usesAlternateBackground]; 191 [alternateBackground setConfiguratorEnabled:usesAlternateBackground]; 192 [delegate setAlternateBackground:(usesAlternateBackground ? alternateBackground : nil)]; 193 [alternateCheckbox setState:usesAlternateBackground]; 194} 195 196//Display the default Background 197//If there is no defaults select : slashed_background for the main background 198// and flat_background for the alternate background 199- (void)_setDefaultBackgroundsFor:(id) aCanvas 200{ 201 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 202 id mainBackgroundName = [defaults objectForKey:@"mainBackgroundName"]; 203 id alternateBackgroundName = [defaults objectForKey:@"alternateBackgroundName"]; 204 205 if( ! mainBackgroundName ) 206 { 207 mainBackgroundName = NSLocalizedString(@"SLASHED_BACKGROUND", @"Slashed Background"); 208 } 209 if(! alternateBackgroundName ) 210 { 211 alternateBackgroundName = NSLocalizedString(@"FLAT_BACKGROUND", @"Flat Background"); 212 } 213 214 [aCanvas setMainBackgroundName:mainBackgroundName]; 215 [aCanvas setAlternateBackgroundName:alternateBackgroundName]; 216 [self _setMainBackground:[[self class] backgroundNamed:mainBackgroundName]]; 217 [self _setAlternateBackground:[[self class] backgroundNamed:alternateBackgroundName]]; 218 [self _setUsesAlternateBackground:[defaults boolForKey:@"usesAlternateBackground"]]; 219} 220 221 222// #define PXBackgroundControllerSetBackground(bg, menu, configView, newBg)\ 223// {\ 224// [[bg configurator] removeFromSuperview];\ 225// [newBg retain];\ 226// [bg release];\ 227// bg = newBg;\ 228// [menu selectItemWithTitle:[bg name]];\ 229// [configView addSubview:[bg configurator]];\ 230// } 231 232 233- (void) _setMainBackground:(id) aBackground 234{ 235 PXBackgroundControllerSetBackground(mainBackground, mainMenu, mainConfigurator, aBackground); 236 [delegate setMainBackground:mainBackground]; 237} 238 239 240- (void) _setAlternateBackground:(id) aBackground 241{ 242 PXBackgroundControllerSetBackground(alternateBackground, alternateMenu, alternateConfigurator, aBackground); 243 [delegate setAlternateBackground:alternateBackground]; 244} 245 246@end 247 248 249/**********************************/ 250/* NamePrompterDelegate categories*/ 251/**********************************/ 252 253@implementation PXBackgroundController ( NamePrompterDelegate ) 254 255- (void)prompter:aPrompter didFinishWithName:name context:contextObject 256{ 257 PXBackground * newConfig = [[contextObject copy] autorelease]; 258 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES); 259 NSString *path; 260 if ( [paths count] == 0 ) 261 { 262 NSLog(@"WARNING Use Library directory does not exists. Should never happens !!! WARM the user !!!"); 263 return; 264 } 265 path = [paths objectAtIndex:0]; 266 267 id menu = nil; 268 269 if(contextObject == mainBackground) 270 { 271 menu = mainMenu; 272 } 273 else if( contextObject == alternateBackground) 274 { 275 menu = alternateMenu; 276 } 277 278 [newConfig setName:name]; 279#warning Put it in PXAppDelegate 280 281 path = [[paths objectAtIndex:0] stringByAppendingPathComponent:BACKGROUNDPRESET]; 282 path = [path stringByAppendingPathComponent:name]; 283 path = [path stringByAppendingPathExtension:@"pxbgnd"]; 284 NSLog(@"save FINISH path %@",path); 285 286 [NSKeyedArchiver archiveRootObject:newConfig toFile:path]; 287 288 [self _populateMenus]; 289 290 [menu selectItemWithTitle:name]; 291 [self performSelector:[[menu itemWithTitle:name] action] withObject:[menu itemWithTitle:name]]; 292} 293 294 295- (void)prompter:aPrompter didCancelWithContext:contextObject 296{ 297 id config = contextObject; 298 id menu = nil; 299 300 if(config == mainBackground) 301 menu = mainMenu; 302 else if (config == alternateBackground) 303 menu = alternateMenu; 304 305 [menu selectItemWithTitle:[config name]]; 306} 307 308@end 309 310 311 312 313 314/*******************************************/ 315/* PXBackgroundController implementation **/ 316/*******************************************/ 317 318@implementation PXBackgroundController 319 320+ backgroundNamed:aName 321{ 322 id enumerator = [defaultBackgrounds() objectEnumerator]; 323 id current; 324 NSString *path; 325 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES); 326 327 328 while( ( current = [enumerator nextObject] ) ) 329 { 330 if([[current name] isEqualToString:aName]) 331 { 332 return [[current copy] autorelease]; 333 } 334 } 335 336 if ( [paths count] > 0 ) 337 { 338 path = [paths objectAtIndex:0]; 339 path = [path stringByAppendingPathComponent:BACKGROUNDPRESET]; 340 } 341 342 343 enumerator = [[NSFileManager defaultManager] enumeratorAtPath:path]; 344 345 while(current = [enumerator nextObject]) 346 { 347 // .DS_Store not exists into GNUstep -- ok, so it'll do nothing! why was this a #warning? 348 if( ( ![current isEqualToString:@".DS_Store"] ) 349 && ( [[current stringByDeletingPathExtension] isEqualToString:aName] ) ) 350 { 351 return [NSKeyedUnarchiver unarchiveObjectWithFile:[path stringByAppendingPathComponent:current]]; 352 } 353 } 354 355 return [[[defaultBackgrounds() objectAtIndex:0] copy] autorelease]; 356} 357 358 359-(id) init 360{ 361 if ( ! (self = [super init] ) ) 362 return nil; 363 364 if ( ! [NSBundle loadNibNamed:@"PXBackgroundController" owner: self] ) 365 { 366 NSLog(@"Warm user here"); 367 } 368 369 return self; 370} 371 372 373 374- (void)dealloc 375{ 376 if ( mainBackground ) 377 [mainBackground release]; 378 if ( alternateBackground ) 379 [alternateBackground release]; 380 //probably mem leaks here 381 [super dealloc]; 382} 383 384 385- (void)awakeFromNib 386{ 387 usesAlternateBackground = YES; 388 namePrompter = [[PXNamePrompter alloc] init]; 389 [namePrompter setDelegate:self]; 390 391 [self _populateMenus]; 392 [[NSNotificationCenter defaultCenter] addObserver:self 393 selector:@selector(backgroundChanged:) 394 name:@"PXBackgroundChanged" 395 object:nil]; 396} 397 398 399- (void)setDelegate:aDelegate 400{ 401 delegate = aDelegate; 402} 403 404 405 406// 407//Actions methods 408// 409 410//Call from PopUp item saveCurrentConfiguration 411- (IBAction)saveCurrentConfiguration: (id) sender 412{ 413 id context = nil; 414 id menu = nil; 415 if( [[mainMenu titleOfSelectedItem] isEqualToString: 416 NSLocalizedString(@"BACKGROUNDS_SAVE_AS", @"Backgrounds Save As")]) 417 { 418 context = mainBackground; 419 menu = mainMenu; 420 } 421 else if( [[alternateMenu titleOfSelectedItem] isEqualToString: 422 NSLocalizedString(@"BACKGROUNDS_SAVE_AS", @"Backgrounds Save As")]) 423 { 424 context = alternateBackground; 425 menu = alternateMenu; 426 } 427 428 [namePrompter promptInWindow:panel context:context]; 429} 430 431 432//Call from PopUp item deleteCurrentConfiguration 433- (IBAction)deleteCurrentConfiguration:(id) sender 434{ 435 NSLog(@"deleteCurrentConfiguration"); 436 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES); 437 NSString *path; 438 id config = nil; 439 id menu = nil; 440 if([[mainMenu titleOfSelectedItem] isEqualToString:NSLocalizedString(@"BACKGROUNDS_DELETE", @"Backgrounds Delete")]) 441 { 442 menu = mainMenu; 443 config = mainBackground; 444 [self _setMainBackground:[defaultBackgrounds() objectAtIndex:0]]; 445 } 446 else if([[alternateMenu titleOfSelectedItem] isEqualToString:NSLocalizedString(@"BACKGROUNDS_DELETE", @"Backgrounds Delete")]) 447 { 448 config = alternateBackground; 449 menu = alternateMenu; 450 [self _setAlternateBackground:[ defaultBackgrounds() objectAtIndex:1]]; 451 } 452 453 if(![config isKindOfClass:[PXBackground class]]) 454 { 455 [menu selectItemAtIndex:0]; 456 return; 457 } 458 459 if ( [paths count] == 0 ) 460 { 461 NSLog(@"WARNING Use Library directory does not exists. Should never happens !!! WARM the user !!!"); 462 } 463 464 465 path = [[paths objectAtIndex:0] stringByAppendingPathComponent:BACKGROUNDPRESET]; 466 path = [path stringByAppendingPathComponent:[config name]]; 467 path = [path stringByAppendingPathExtension:@"pxbgnd"]; 468 469 if(![[NSFileManager defaultManager] fileExistsAtPath:path]) 470 { 471#ifdef __COCOA__ 472 NSBeep(); 473#endif 474 [menu selectItemAtIndex:0]; return; 475 } 476 [[NSFileManager defaultManager] removeFileAtPath:path handler:nil]; 477 [self _populateMenus]; 478} 479 480 481// checkBox IBAction 482- (IBAction)useAlternateBackgroundCheckboxClicked:(id) sender 483{ 484 [self _setUsesAlternateBackground:([sender state] == NSOnState)]; 485} 486 487 488- (IBAction)selectMainBackground: (id) sender 489{ 490 491 [self _setMainBackground:[sender representedObject]]; 492#ifndef __COCOA__ 493 // [mainMenu selectItemAtIndex: 2]; 494#endif 495} 496 497- (IBAction)selectAlternateBackground: (id)sender 498{ 499 [self _setAlternateBackground:[sender representedObject]]; 500} 501 502 503//sender == NSButton "use these as defaults " 504- (IBAction)useCurrentBackgroundsAsDefaults:(id) sender 505{ 506 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 507 508 [defaults setObject:[mainBackground name] forKey:@"mainBackgroundName"]; 509 [defaults setObject:[alternateBackground name] forKey:@"alternateBackgroundName"]; 510 [defaults setBool:usesAlternateBackground forKey:@"usesAlternateBackground"]; 511 512 [defaults synchronize]; 513} 514 515 516//Is it really need ? 517- (void)windowDidLoad 518{ 519#warning is it really need 520 521 if ( mainBackground ) 522 [mainConfigurator addSubview:[mainBackground configurator]]; 523 524 if ( alternateBackground ) 525 [alternateConfigurator addSubview:[alternateBackground configurator]]; 526 527} 528 529- (void)backgroundChanged:notification 530{ 531 [delegate backgroundChanged:notification]; 532} 533 534 535- (void)useBackgroundsOf:(id) aCanvas 536{ 537 //??? 538 // [self window]; 539 540 if( ! [aCanvas mainBackgroundName] ) 541 { 542 [self _setDefaultBackgroundsFor:aCanvas]; 543 return; 544 } 545 NSString * mainName = [[aCanvas mainBackgroundName] retain], * altName = [[aCanvas alternateBackgroundName] retain]; 546 [self _setMainBackground:[[self class] backgroundNamed:mainName]]; 547 if((altName == nil) || [altName isEqualToString:mainName]) 548 { 549 [self _setAlternateBackground:nil]; 550 [self _setUsesAlternateBackground:NO]; 551 } 552 else 553 { 554 [self _setAlternateBackground:[[self class] backgroundNamed:altName]]; 555 [self _setUsesAlternateBackground:YES]; 556 } 557 [mainName release]; 558 [altName release]; 559} 560 561//Accessor 562-(NSPanel *) backgroundPanel 563{ 564 return panel; 565} 566 567@end 568 569