/* ** PreferencesPanelController.m ** ** Copyright (c) 2002 ** ** Author: Ludovic Marcotte ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2 of the License, or ** (at your option) any later version. ** ** This program 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 General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #import "PreferencesPanelController.h" #import "ConfigureWindowController.h" #import "Constants.h" #import "ExtendedTableColumn.h" #import "NSStringExtensions.h" #import "Plop.h" #import "PlopFolio.h" #import "PreferencesPanel.h" // XML Headers needed under GNUstep #ifndef MACOSX #import // XML Headers needed under Cocoa #else #import #endif @implementation PreferencesPanelController // // // - (id) initWithWindowNibName: (NSString *) theNibName { #ifdef MACOSX self = [super initWithWindowNibName: theNibName]; #else PreferencesPanel *thePanel; thePanel = [[PreferencesPanel alloc] initWithContentRect:NSMakeRect(100,100,355,275) styleMask: (NSClosableWindowMask|NSResizableWindowMask) backing: NSBackingStoreBuffered defer: NO]; self = [super initWithWindow: thePanel]; [thePanel layoutPanel]; [thePanel setDelegate: self]; // We link our outlets tableView = [thePanel tableView]; browserPopUpButton = [thePanel browserPopUpButton]; browserField = [thePanel browserField]; RELEASE(thePanel); #endif // We set our title [[self window] setTitle: _(@"Preferences...")]; // We set our custom table column on OS X #ifdef MACOSX { ExtendedTableColumn *extendedTableColumn; ExtendedButtonCell *cell; cell = [[ExtendedButtonCell alloc] init]; [cell setButtonType: NSSwitchButton]; [cell setImagePosition: NSImageOnly]; [cell setControlSize: NSSmallControlSize]; extendedTableColumn = (ExtendedTableColumn *)[tableView tableColumnWithIdentifier: @"active"]; [extendedTableColumn setDataCell: cell]; [extendedTableColumn setShouldUseMouse: YES]; [extendedTableColumn setShouldUseAndSetState: YES]; RELEASE(cell); } #endif // We get our defaults for this panel [self initializeFromDefaults]; return self; } // // // - (void) dealloc { [super dealloc]; } // // // - (void) initializeFromDefaults { int index; index = [[NSUserDefaults standardUserDefaults] integerForKey: @"BROWSER_SOURCE"]; [browserPopUpButton selectItemAtIndex: index]; [browserPopUpButton synchronizeTitleAndSelectedItem]; if ( index > 0 ) { [browserField setEditable: YES]; } else { [browserField setEditable: NO]; } if ( [[NSUserDefaults standardUserDefaults] objectForKey: @"BROWSER_PATH"] ) { [browserField setStringValue: [[NSUserDefaults standardUserDefaults] objectForKey: @"BROWSER_PATH"] ]; } } // // datasource methods // - (id) tableView: (NSTableView *) aTableView objectValueForTableColumn: (NSTableColumn *) aTableColumn row: (int) rowIndex { Plop *aPlop; aPlop = [[(PlopFolio *)[NSApp delegate] allPlops] objectAtIndex: rowIndex]; if ( [[[aTableColumn headerCell] stringValue] isEqual: _(@"Name")] ) { return [aPlop title]; } else { return ( [aPlop isActive] ? _(@"Yes") : _(@"No") ); } } // // // - (int) numberOfRowsInTableView: (NSTableView *) aTableView { return [[(PlopFolio *)[NSApp delegate] allPlops] count]; } // // // - (int) tableView: (NSTableView *) aTableView stateForTableColumn: (NSTableColumn *) aTableColumn row: (int) rowIndex { Plop *aPlop; aPlop = [[(PlopFolio *)[NSApp delegate] allPlops] objectAtIndex: rowIndex]; return ( [aPlop isActive] ? NSOnState : NSOffState ); } // // // - (void) tableView: (NSTableView *) aTableView setState: (int) aState forTableColumn: (NSTableColumn *) aTableColumn row: (int) rowIndex { Plop *aPlop; aPlop = [[(PlopFolio *)[NSApp delegate] allPlops] objectAtIndex: rowIndex]; if (aState == NSOnState) { [aPlop setActive: YES]; } else if (aState == NSOffState) { [aPlop setActive: NO]; } } // // delegate methods // - (void) windowWillClose: (id) sender { NSLog(@"Closing the Preferences Panel."); // We save our userdefaults [browserPopUpButton synchronizeTitleAndSelectedItem]; [[NSUserDefaults standardUserDefaults] setInteger: [browserPopUpButton indexOfSelectedItem] forKey: @"BROWSER_SOURCE"]; [[NSUserDefaults standardUserDefaults] setObject: [browserField stringValue] forKey: @"BROWSER_PATH"]; [[NSUserDefaults standardUserDefaults] synchronize]; // We synchronize our plops [(PlopFolio *)[NSApp delegate] synchronize]; [(PlopFolio *)[NSApp delegate] showAllPlops]; } // // action methods // - (IBAction) configureClicked: (id) sender { ConfigureWindowController *aConfigureWindowController; int index; index = [tableView selectedRow]; if ( index < 0 ) { NSBeep(); return; } aConfigureWindowController = [[ConfigureWindowController alloc] initWithWindowNibName: @"ConfigureWindow"]; [aConfigureWindowController setPlop: [[(PlopFolio *)[NSApp delegate] allPlops] objectAtIndex: index]]; [[aConfigureWindowController window] orderFront: nil]; } - (IBAction) deleteClicked: (id) sender { int choice, index; index = [tableView selectedRow]; if ( index < 0 ) { NSBeep(); return; } choice = NSRunAlertPanel(_(@"Delete..."), _(@"Are you sure you want to delete this Plop?"), _(@"Cancel"), // default _(@"Yes"), // alternate NULL); // If we must delete it... if ( choice == NSAlertAlternateReturn ) { Plop *aPlop; aPlop = [[(PlopFolio *)[NSApp delegate] allPlops] objectAtIndex: index]; // We remove the icon of the plop [[NSFileManager defaultManager] removeFileAtPath: [NSString stringWithFormat: @"%@/%@", PlopFolioUserLibraryPath(), [aPlop iconName]] handler: nil]; // We remove the plop [[(PlopFolio *)[NSApp delegate] allPlops] removeObjectAtIndex: index]; [tableView reloadData]; } } // // // - (IBAction) importClicked: (id) sender { NSOpenPanel *oPanel; int result; oPanel = [NSOpenPanel openPanel]; [oPanel setAllowsMultipleSelection:NO]; result = [oPanel runModalForDirectory: NSHomeDirectory() file: nil types: nil]; if ( result == NSOKButton ) { NSArray *fileToOpen; int count; fileToOpen = [oPanel filenames]; count = [fileToOpen count]; if ( count > 0 ) { [self _importKlipUsingPath: [fileToOpen objectAtIndex: 0]]; } } } // // // - (IBAction) selectionInBrowserPopUpButtonHasChanged: (id) sender { [browserPopUpButton synchronizeTitleAndSelectedItem]; if ( [browserPopUpButton indexOfSelectedItem] == 0 ) { [browserField setEditable: NO]; } else { [browserField setEditable: YES]; } } @end // // private methods // @implementation PreferencesPanelController (Private) - (void) _importKlipUsingPath: (NSString *) thePath { // GNUstep XML Parsing Code #ifndef MACOSX GSXMLParser *aParser; NSData *aData; aData = [NSData dataWithContentsOfFile: thePath]; aParser = [GSXMLParser parserWithData: aData]; [aParser keepBlanks: NO]; if ( [aParser parse] ) { GSXMLDocument *aDocument; GSXMLNode *aRoot, *aNode; Plop *aPlop; aDocument = [aParser document]; aRoot = [aDocument root]; if ( [[aRoot name] caseInsensitiveCompare: @"KLIP"] != NSOrderedSame ) { NSLog(@"Not a Klip. Ignoring."); return; } aNode = [aRoot firstChildElement]; // We initialize our plop aPlop = [[Plop alloc] init]; // // We loop inside our owner/identity/locations/setup/script nodes // while (aNode != nil) { [self _parseKlipInformationsFromNode: aNode plop: aPlop]; // We get the next node aNode = [aNode nextElement]; } // We add our plop to our list of active plops [aPlop cache]; [[(PlopFolio *)[NSApp delegate] allPlops] addObject: aPlop]; [(PlopFolio *)[NSApp delegate] synchronize]; RELEASE(aPlop); } else { NSLog(@"error occured while parsing .klip"); } // Cocoa XML Parsing Code #else CFXMLTreeRef aTreeRef, xmlTreeRoot; CFXMLNodeRef xmlRoot; NSData *aData; int i; aData = [NSData dataWithContentsOfFile: thePath]; aTreeRef = CFXMLTreeCreateFromData(kCFAllocatorDefault, (CFDataRef)aData, NULL, kCFXMLParserSkipWhitespace|kCFXMLParserSkipMetaData, kCFXMLNodeCurrentVersion); if ( !aTreeRef ) { NSRunAlertPanel(_(@"Error!"), _(@"Corrupted XML. Ignoring Klip."), _(@"OK"), NULL, NULL); return; } for (i = 0; i < CFTreeGetChildCount(aTreeRef); i++) { xmlTreeRoot = CFTreeGetChildAtIndex(aTreeRef, i); xmlRoot = CFXMLTreeGetNode(xmlTreeRoot); if ( [(NSString*)CFXMLNodeGetString(xmlRoot) caseInsensitiveCompare: @"KLIP"] == NSOrderedSame ) { // We found a klip! CFXMLTreeRef xmlSubTreeRef; CFXMLNodeRef aNode; int j; Plop *aPlop; // We initialize our plop aPlop = [[Plop alloc] init]; for (j = 0; j < CFTreeGetChildCount(xmlTreeRoot); j++) { xmlSubTreeRef = CFTreeGetChildAtIndex(xmlTreeRoot, j); aNode = CFXMLTreeGetNode(xmlSubTreeRef); if ( CFXMLNodeGetTypeCode(aNode) == kCFXMLNodeTypeElement ) { [self _parseKlipInformationsFromNode: (id)xmlSubTreeRef plop: aPlop]; } } // We add our plop to our list of active plops [aPlop cache]; [[(PlopFolio *)[NSApp delegate] allPlops] addObject: aPlop]; [(PlopFolio *)[NSApp delegate] synchronize]; RELEASE(aPlop); } } #endif [tableView reloadData]; } // // // - (void) _updatePlop: (Plop *) thePlop name: (NSString *) theName content: (NSString *) theContent { if ( [theName caseInsensitiveCompare: @"TITLE"] == NSOrderedSame ) { [thePlop setTitle: theContent]; } else if ( [theName caseInsensitiveCompare: @"ICON"] == NSOrderedSame ) { [thePlop setIconSource: [NSURL URLWithString: theContent]]; } else if ( [theName caseInsensitiveCompare: @"BANNER"] == NSOrderedSame ) { [thePlop setBannerSource: [NSURL URLWithString: theContent] ]; } else if ( [theName caseInsensitiveCompare: @"CONTENTSOURCE"] == NSOrderedSame ) { [thePlop setContentSource: [NSURL URLWithString: theContent] ]; } else if ( [theName caseInsensitiveCompare: @"DEFAULTLINK"] == NSOrderedSame ) { [thePlop setDefaultLink: [NSURL URLWithString: theContent] ]; } else if ( [theName caseInsensitiveCompare: @"DESCRIPTION"] == NSOrderedSame ) { [thePlop setDescription: theContent]; } else if ( [theName caseInsensitiveCompare: @"REFRESH"] == NSOrderedSame ) { [thePlop setRefresh: [theContent intValue] ]; } else if ( [theName caseInsensitiveCompare: @"VERSION"] == NSOrderedSame ) { [thePlop setPlopVersion: theContent]; } } // // // - (void) _parseKlipInformationsFromNode: (id) theNode plop: (Plop *) thePlop { // // GNUstep XML Parsing Code // #ifndef MACOSX GSXMLNode *aChild; static int textNodeType = -1; if (textNodeType < 0) { textNodeType = [GSXMLNode typeFromDescription: @"XML_TEXT_NODE"]; } // We loop inside our channel/image/item node attributes if ( (aChild = [theNode firstChildElement]) ) { while ( aChild ) { NSString *aName, *aContent; GSXMLNode *aNode; aNode = [aChild firstChild]; while ( aNode ) { if ( [aNode type] == textNodeType ) { if ( [[[aNode content] stringByTrimmingWhiteSpaces] length] > 0 ) { break; } } aNode = [aNode next]; } if ( !aNode ) { aChild = [aChild next]; continue; } aName = [aChild name]; aContent = [[aNode content] stringByTrimmingWhiteSpaces]; if (aName && aContent) { [self _updatePlop: thePlop name: aName content: aContent]; } aChild = [aChild nextElement]; } } else { NSLog(@"No children"); } #else int i; for (i = 0; i < CFTreeGetChildCount((CFXMLTreeRef)theNode); i++) { CFXMLTreeRef xmlTreeRef; CFXMLNodeRef xmlNode; xmlTreeRef = CFTreeGetChildAtIndex((CFXMLTreeRef)theNode, i); xmlNode = CFXMLTreeGetNode(xmlTreeRef); if ( CFXMLNodeGetTypeCode(xmlNode) == kCFXMLNodeTypeElement ) { NSString *aName, *aContent; CFXMLTreeRef xmlSubTreeRef; CFXMLNodeRef xmlSubNode; int j; xmlSubTreeRef = NULL; xmlSubNode = NULL; for ( j = 0; j < CFTreeGetChildCount(xmlTreeRef); j++ ) { xmlSubTreeRef = CFTreeGetChildAtIndex(xmlTreeRef, j); xmlSubNode = CFXMLTreeGetNode(xmlSubTreeRef); if ( CFXMLNodeGetTypeCode(xmlNode) == kCFXMLNodeTypeElement ) { break; } else { xmlSubNode = NULL; } } if ( !xmlSubNode ) { continue; } aName = (NSString *)CFXMLNodeGetString(xmlNode); aContent = [(NSString *)CFXMLNodeGetString(xmlSubNode) stringByTrimmingWhiteSpaces]; if (aName && aContent) { [self _updatePlop: thePlop name: aName content: aContent]; } } } #endif } @end // // Custom NSButton cell // @implementation ExtendedButtonCell @end