/* -*- mode: C++; tab-width: 4; c-basic-offset: 4; -*- */ /* AbiWord / AbiBits / CarbonToolbar * * Copyright (C) 2005 AbiSource, Inc. * Copyright (C) 2005 Francis James Franklin * * 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., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #import "AbiCarbonToolbar_Configuration.h" #import "AbiCarbonToolbar_LogController.h" static NSString * s_escapeXML (NSString * str) { NSMutableString * name = [NSMutableString stringWithCapacity:32]; [name setString:str]; [name replaceOccurrencesOfString:@"&" withString:@"&" options:NSLiteralSearch range:NSMakeRange(0,[name length])]; [name replaceOccurrencesOfString:@"<" withString:@"<" options:NSLiteralSearch range:NSMakeRange(0,[name length])]; [name replaceOccurrencesOfString:@">" withString:@">" options:NSLiteralSearch range:NSMakeRange(0,[name length])]; [name replaceOccurrencesOfString:@"\"" withString:@""" options:NSLiteralSearch range:NSMakeRange(0,[name length])]; return name; } @implementation AbiCarbonToolbar_EditData - (id)initWithProvider:(NSString *)name identifier:(NSString *)identifier description:(NSString *)description { if (self = [super init]) { m_name = name; [m_name retain]; m_identifier = identifier; [m_identifier retain]; m_description = description; [m_description retain]; m_tools = 0; m_bProvider = NO; } return self; } - (id)initWithProvider:(id )provider { if (self = [super init]) { NSArray * toolIdentifiers = [provider toolIdentifiers]; unsigned count = [toolIdentifiers count]; unsigned i; m_name = [provider name]; [m_name retain]; m_identifier = 0; m_description = 0; m_tools = [[NSMutableArray alloc] initWithCapacity:16]; for (i = 0; i < count; i++) { NSString * identifier = [toolIdentifiers objectAtIndex:i]; NSString * description = [provider toolDescription:identifier]; AbiCarbonToolbar_EditData * data = [[AbiCarbonToolbar_EditData alloc] initWithProvider:m_name identifier:identifier description:description]; [m_tools addObject:data]; [data release]; } m_bProvider = YES; } return self; } - (void)dealloc { if (m_name) { [m_name release]; m_name = 0; } if (m_identifier) { [m_identifier release]; m_identifier = 0; } if (m_description) { [m_description release]; m_description = 0; } if (m_tools) { [m_tools release]; m_tools = 0; } [super dealloc]; } - (NSString *)name { return m_name; } - (NSString *)identifier { return m_identifier; } - (NSString *)description { return m_description; } - (NSArray *)tools { return m_tools; } - (BOOL)isProvider { return m_bProvider; } @end @implementation AbiCarbonToolbar_ConfigurationTool - (id)initWithIdentifier:(NSString *)identifier description:(NSString *)description provider:(id )provider { if (self = [super init]) { m_identifier = identifier; [m_identifier retain]; m_description = description; [m_description retain]; m_provider = provider; [m_provider retain]; m_toolbar = 0; } return self; } - (void)dealloc { [m_identifier release]; [m_description release]; [m_provider release]; [super dealloc]; } - (BOOL)isToolbar { return NO; } - (NSString *)identifier { return m_identifier; } - (NSString *)description { return m_description; } - (id )provider { return m_provider; } - (void)setToolbar:(AbiCarbonToolbar_ConfigurationToolbar *)toolbar { m_toolbar = toolbar; } - (AbiCarbonToolbar_ConfigurationToolbar *)toolbar { return m_toolbar; } @end @implementation AbiCarbonToolbar_ConfigurationToolbar - (id)initWithAbiWord:(XAP_CocoaPlugin *)AbiWord controller:(AbiCarbonToolbar_LogController *)controller toolbarName:(NSString *)name { if (self = [super init]) { m_AbiWord = AbiWord; m_Controller = controller; m_name = name; [m_name retain]; m_tools = [[NSMutableArray alloc] initWithCapacity:16]; } return self; } - (void)dealloc { [m_name release]; [m_tools release]; [super dealloc]; } - (BOOL)isToolbar { return YES; } - (NSString *)name { return m_name; } - (NSArray *)tools { return m_tools; } - (AbiCarbonToolbar_ConfigurationTool *)addTool:(NSString *)identifier provider:(NSString *)provider_name { [self insertTool:identifier provider:provider_name atIndex:[m_tools count]]; } - (AbiCarbonToolbar_ConfigurationTool *)insertTool:(NSString *)identifier provider:(NSString *)provider_name atIndex:(unsigned)index { AbiCarbonToolbar_ConfigurationTool * new_tool = 0; unsigned count = [m_tools count]; unsigned i; if (index > count) index = count; if (!identifier || !provider_name) return 0; if (([provider_name length] == 0) || ([identifier length] == 0)) return 0; for (i = 0; i < count; i++) { AbiCarbonToolbar_ConfigurationTool * tool = (AbiCarbonToolbar_ConfigurationTool *) [m_tools objectAtIndex:i]; if ([provider_name isEqualToString:[[tool provider] name]]) if ([identifier isEqualToString:[tool identifier]]) { new_tool = tool; if (i < index) { [m_tools insertObject:new_tool atIndex:index]; [m_tools removeObjectAtIndex:i]; } else if (i > index) { [new_tool retain]; [m_tools removeObjectAtIndex:i]; [m_tools insertObject:new_tool atIndex:index]; [new_tool release]; } break; } } if (new_tool) { [m_Controller logEntry:@"Tool already exists in toolbar." forMethod:@"insertTool:provider:atIndex:"]; } else { id provider = [m_AbiWord toolProvider:provider_name]; if (provider) { NSString * description = [provider toolDescription:identifier]; if (description) { NSString * message = [NSString stringWithFormat:@"Add tool \"%@\" using provider \"%@\".", identifier, provider_name]; [m_Controller logEntry:message forMethod:@"insertTool:provider:atIndex:"]; new_tool = [[AbiCarbonToolbar_ConfigurationTool alloc] initWithIdentifier:identifier description:description provider:provider]; [m_tools insertObject:new_tool atIndex:index]; [new_tool setToolbar:self]; [new_tool release]; } else { NSString * message = [NSString stringWithFormat:@"Unable to add tool - provider \"%@\" does not support tool \"%@\"!", provider_name, identifier]; [m_Controller logError:message forMethod:@"insertTool:provider:atIndex:"]; } } else { NSString * message = [NSString stringWithFormat:@"Unable to add tool - can't find provider \"%@\"!", provider_name]; [m_Controller logError:message forMethod:@"insertTool:provider:atIndex:"]; } } return new_tool; } - (void)removeTool:(NSString *)identifier provider:(NSString *)provider_name { unsigned count = [m_tools count]; unsigned i; if (!identifier || !provider_name) return; if (([provider_name length] == 0) || ([identifier length] == 0)) return; for (i = 0; i < count; i++) { AbiCarbonToolbar_ConfigurationTool * tool = (AbiCarbonToolbar_ConfigurationTool *) [m_tools objectAtIndex:i]; if ([provider_name isEqualToString:[[tool provider] name]]) if ([identifier isEqualToString:[tool identifier]]) { NSString * message = [NSString stringWithFormat:@"Remove tool \"%@\" with provider \"%@\".", identifier, provider_name]; [m_Controller logEntry:message forMethod:@"removeTool:provider:"]; [m_tools removeObjectAtIndex:i]; break; } } } @end @implementation AbiCarbonToolbar_Configuration - (id)initWithAbiWord:(XAP_CocoaPlugin *)AbiWord controller:(AbiCarbonToolbar_LogController *)controller { if (self = [super init]) { m_toolbars = [[NSMutableArray alloc] initWithCapacity:16]; m_AbiWord = AbiWord; m_Controller = controller; m_current = 0; m_bLoading = NO; } return self; } - (void)dealloc { [m_toolbars release]; [super dealloc]; } - (NSArray *)toolbars { return m_toolbars; } - (void)removeSelectedToolOrToolbar:(NSOutlineView *)outlineView { id config_data = 0; int selectedRow = [outlineView selectedRow]; if (selectedRow < 0) return; config_data = (id ) [outlineView itemAtRow:selectedRow]; if ([config_data isToolbar]) { AbiCarbonToolbar_ConfigurationToolbar * toolbar = (AbiCarbonToolbar_ConfigurationToolbar *) config_data; [self removeToolbar:[toolbar name]]; } else { AbiCarbonToolbar_ConfigurationTool * tool = (AbiCarbonToolbar_ConfigurationTool *) config_data; [[tool toolbar] removeTool:[tool identifier] provider:[[tool provider] name]]; } } - (void)removeToolbar:(NSString *)name { int count = [m_toolbars count]; int i; if (!name) return; if ([name length] == 0) return; for (i = 0; i < count; i++) { AbiCarbonToolbar_ConfigurationToolbar * toolbar = (AbiCarbonToolbar_ConfigurationToolbar *) [m_toolbars objectAtIndex:i]; if ([[toolbar name] isEqualToString:name]) { [m_toolbars removeObjectAtIndex:i]; break; } } } - (void)addUntitledToolbar { int count = [m_toolbars count]; int n = 0; NSString * name = nil; while (true) { bool bAvailable = true; int i; ++n; name = [NSString stringWithFormat:@"Toolbar %d",n]; for (i = 0; i < count; i++) { AbiCarbonToolbar_ConfigurationToolbar * toolbar = (AbiCarbonToolbar_ConfigurationToolbar *) [m_toolbars objectAtIndex:i]; if ([[toolbar name] isEqualToString:name]) { bAvailable = false; break; } } if (bAvailable) break; } [self addToolbar:name]; } - (AbiCarbonToolbar_ConfigurationToolbar *)addToolbar:(NSString *)name { AbiCarbonToolbar_ConfigurationToolbar * new_toolbar = 0; int count = [m_toolbars count]; int i; if (!name) return 0; if ([name length] == 0) return 0; for (i = 0; i < count; i++) { AbiCarbonToolbar_ConfigurationToolbar * toolbar = (AbiCarbonToolbar_ConfigurationToolbar *) [m_toolbars objectAtIndex:i]; if ([[toolbar name] isEqualToString:name]) { new_toolbar = toolbar; break; } } if (new_toolbar) { [m_Controller logEntry:@"Using existing toolbar." forMethod:@"addToolbar:"]; } else { new_toolbar = [[AbiCarbonToolbar_ConfigurationToolbar alloc] initWithAbiWord:m_AbiWord controller:m_Controller toolbarName:name]; [m_toolbars addObject:new_toolbar]; [new_toolbar release]; } return new_toolbar; } - (int)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item { id config_data = (id ) item; int count = 0; if (config_data) { if ([config_data isToolbar]) { AbiCarbonToolbar_ConfigurationToolbar * toolbar = (AbiCarbonToolbar_ConfigurationToolbar *) config_data; count = [[toolbar tools] count]; } } else { count = [m_toolbars count]; } return count; } - (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item { id config_data = (id ) item; return [config_data isToolbar]; } - (id)outlineView:(NSOutlineView *)outlineView child:(int)index ofItem:(id)item { AbiCarbonToolbar_ConfigurationToolbar * toolbar = (AbiCarbonToolbar_ConfigurationToolbar *) item; id child; if (toolbar) { child = [[toolbar tools] objectAtIndex:index]; } else { child = [m_toolbars objectAtIndex:index]; } return child; } - (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item { id config_data = (id ) item; NSString * identifier = [tableColumn identifier]; NSString * str = @""; if ([config_data isToolbar]) { AbiCarbonToolbar_ConfigurationToolbar * toolbar = (AbiCarbonToolbar_ConfigurationToolbar *) config_data; if ([identifier isEqualToString:@"Toolbar"]) str = [toolbar name]; } else { AbiCarbonToolbar_ConfigurationTool * tool = (AbiCarbonToolbar_ConfigurationTool *) config_data; if ([identifier isEqualToString:@"Toolbar"]) str = [tool description]; else if ([identifier isEqualToString:@"Provider"]) str = [[tool provider] name]; } return str; } - (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item { // ... } - (BOOL)outlineView:(NSOutlineView *)outlineView acceptDrop:(id )info item:(id)item childIndex:(int)index { id config_data = (id ) item; NSPasteboard * pboard = [info draggingPasteboard]; NSArray * types = [pboard types]; if (!item) return NO; if ([config_data isToolbar]) { AbiCarbonToolbar_ConfigurationToolbar * toolbar = (AbiCarbonToolbar_ConfigurationToolbar *) config_data; if ([types containsObject:AbiCarbonToolbar_DragType_ProviderView]) { NSArray * tools = (NSArray *) [pboard propertyListForType:AbiCarbonToolbar_DragType_ProviderView]; unsigned count = [tools count]; unsigned i; for (i = 0; i < count; i++) { NSArray * tool = (NSArray *) [tools objectAtIndex:((count - 1) - i)]; NSString * provider = (NSString *) [tool objectAtIndex:0]; NSString * identifier = (NSString *) [tool objectAtIndex:1]; [toolbar insertTool:identifier provider:provider atIndex:((unsigned) index)]; [outlineView reloadData]; [outlineView setNeedsDisplay:YES]; } return YES; } } return NO; } - (NSDragOperation)outlineView:(NSOutlineView *)outlineView validateDrop:(id )info proposedItem:(id)item proposedChildIndex:(int)index { id config_data = (id ) item; if (!item) return NSDragOperationNone; return ([config_data isToolbar] ? NSDragOperationCopy : NSDragOperationNone); } - (BOOL)outlineView:(NSOutlineView *)outlineView writeItems:(NSArray *)items toPasteboard:(NSPasteboard *)pboard { if ([items count] == 1) { id config_data = (id ) [items objectAtIndex:0]; if (![config_data isToolbar]) { AbiCarbonToolbar_ConfigurationTool * tool = (AbiCarbonToolbar_ConfigurationTool *) config_data; NSString * provider = [[tool provider] name]; NSString * identifier = [tool identifier]; NSArray * tools = [NSArray arrayWithObject:[NSArray arrayWithObjects:provider,identifier,nil]]; [pboard declareTypes:[NSArray arrayWithObject:AbiCarbonToolbar_DragType_ProviderView] owner:self]; [pboard setPropertyList:tools forType:AbiCarbonToolbar_DragType_ProviderView]; return YES; } } return NO; } - (BOOL)startElement:(NSString *)name attributes:(NSDictionary *)attributes { BOOL bOkay = YES; if (!m_bLoading) return NO; if ([name isEqualToString:@"toolbar"]) { NSString * name = [attributes objectForKey:@"name"]; if (name) { if ([name length]) { [m_Controller logEntry:[NSString stringWithFormat:@"Add toolbar \"%@\".", name] forMethod:@"startElement:attributes:"]; } else { [m_Controller logError:@"Unable to add toolbar - empty name!" forMethod:@"startElement:attributes:"]; bOkay = NO; } } else { [m_Controller logError:@"Unable to add toolbar - no name!" forMethod:@"startElement:attributes:"]; bOkay = NO; } if (bOkay) { m_current = [self addToolbar:name]; } } else if (m_current && [name isEqualToString:@"tool"]) { NSString * provider_name = [attributes objectForKey:@"provider"]; NSString * identifier = [attributes objectForKey:@"identifier"]; if (provider_name && identifier) { if ([provider_name length] && [identifier length]) { [m_current addTool:identifier provider:provider_name]; } else { [m_Controller logError:@"Unable to add tool - require non-empty \"provider\" and \"identifier\" attributes!" forMethod:@"startElement:attributes:"]; } } else { [m_Controller logError:@"Unable to add tool - require \"provider\" and \"identifier\" attributes!" forMethod:@"startElement:attributes:"]; } } return bOkay; } - (BOOL)endElement:(NSString *)name { if (!m_bLoading) return NO; if ([name isEqualToString:@"toolbar"]) { m_current = 0; } return YES; } - (BOOL)characterData:(NSString *)data { if (!m_bLoading) return NO; // ... return YES; } - (NSString *)configurationFile { return [m_AbiWord findResourcePath:@"AbiCarbonToolbar/config.xml"]; } - (BOOL)loadConfiguration:(NSString *)path { NSString * error_message = 0; m_current = 0; m_bLoading = YES; if (error_message = [m_AbiWord parseFile:path simpleXML:self]) { [m_Controller logError:error_message forMethod:@"loadConfiguration:"]; } m_bLoading = NO; return (error_message == 0); } - (BOOL)saveConfiguration { NSString * config = [m_AbiWord userResourcePath:@"AbiCarbonToolbar/config.xml"]; NSString * folder = [config stringByDeletingLastPathComponent]; NSFileManager * FM = [NSFileManager defaultManager]; BOOL bIsDir = NO; FILE * out = 0; int i; int i_count = [m_toolbars count]; if ([FM fileExistsAtPath:folder isDirectory:&bIsDir]) { if (!bIsDir) { [m_Controller logError:[NSString stringWithFormat:@"Configuration path \"%@\" exists but is not a folder.", folder] forMethod:@"saveConfiguration"]; return NO; } } else if ([FM createDirectoryAtPath:folder attributes:nil] == NO) { [m_Controller logError:[NSString stringWithFormat:@"Unable to create configuration folder \"%@\"!", folder] forMethod:@"saveConfiguration"]; return NO; } if ((out = fopen ([config UTF8String], "w")) == 0) { [m_Controller logError:[NSString stringWithFormat:@"Unable to write to configuration file \"%@\"!", config] forMethod:@"saveConfiguration"]; return NO; } fputs ("\n", out); fputs ("\n", out); // TODO fputs ("\n", out); for (i = 0; i < i_count; i++) { AbiCarbonToolbar_ConfigurationToolbar * toolbar = (AbiCarbonToolbar_ConfigurationToolbar *) [m_toolbars objectAtIndex:i]; NSArray * tools = [toolbar tools]; int j; int j_count = [tools count]; NSString * name = s_escapeXML ([toolbar name]); fprintf (out, " \n", [name UTF8String]); for (j = 0; j < j_count; j++) { AbiCarbonToolbar_ConfigurationTool * tool = (AbiCarbonToolbar_ConfigurationTool *) [tools objectAtIndex:j]; NSString * provider = s_escapeXML ([[tool provider] name]); NSString * identifier = s_escapeXML ( [tool identifier]); NSString * description = s_escapeXML ( [tool description]); fprintf (out, " \n", [provider UTF8String], [identifier UTF8String], [description UTF8String]); } fputs (" \n", out); } fputs ("\n", out); fclose (out); [m_Controller logEntry:[NSString stringWithFormat:@"Configuration written to \"%@\".", config] forMethod:@"saveConfiguration"]; return YES; } @end