aboutsummaryrefslogtreecommitdiffstats
path: root/Source/SPEditorPreferencePane.m
diff options
context:
space:
mode:
Diffstat (limited to 'Source/SPEditorPreferencePane.m')
-rw-r--r--Source/SPEditorPreferencePane.m1027
1 files changed, 1027 insertions, 0 deletions
diff --git a/Source/SPEditorPreferencePane.m b/Source/SPEditorPreferencePane.m
new file mode 100644
index 00000000..a57980be
--- /dev/null
+++ b/Source/SPEditorPreferencePane.m
@@ -0,0 +1,1027 @@
+//
+// $Id$
+//
+// SPEditorPreferencePane.m
+// sequel-pro
+//
+// Created by Stuart Connolly (stuconnolly.com) on October 31, 2010
+// Copyright (c) 2010 Stuart Connolly. All rights reserved.
+//
+// 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
+//
+// More info at <http://code.google.com/p/sequel-pro/>
+
+#import "SPEditorPreferencePane.h"
+#import "SPPreferenceController.h"
+#import "SPColorWellCell.h"
+#import "SPAlertSheets.h"
+
+@interface SPEditorPreferencePane (PrivateAPI)
+
+- (BOOL)_checkForUnsavedTheme;
+- (NSArray *)_getAvailableThemes;
+- (void)_saveColorThemeAtPath:(NSString *)path;
+- (BOOL)_loadColorSchemeFromFile:(NSString *)filename;
+
+@end
+
+
+@implementation SPEditorPreferencePane
+
+#pragma mark -
+#pragma mark Initialisation
+
+/**
+ * Init.
+ */
+- (id)init
+{
+ if ((self = [super init])) {
+
+ themePath = [[[NSFileManager defaultManager] applicationSupportDirectoryForSubDirectory:SPThemesSupportFolder error:nil] retain];
+
+ editThemeListItems = [[NSArray arrayWithArray:[self _getAvailableThemes]] retain];
+
+ editorColors =
+ [[NSArray arrayWithObjects:
+ SPCustomQueryEditorTextColor,
+ SPCustomQueryEditorBackgroundColor,
+ SPCustomQueryEditorCaretColor,
+ SPCustomQueryEditorCommentColor,
+ SPCustomQueryEditorSQLKeywordColor,
+ SPCustomQueryEditorNumericColor,
+ SPCustomQueryEditorQuoteColor,
+ SPCustomQueryEditorBacktickColor,
+ SPCustomQueryEditorVariableColor,
+ SPCustomQueryEditorHighlightQueryColor,
+ SPCustomQueryEditorSelectionColor,
+ nil] retain];
+
+ editorNameForColors =
+ [[NSArray arrayWithObjects:
+ NSLocalizedString(@"Text", @"text label for color table (Prefs > Editor)"),
+ NSLocalizedString(@"Background", @"background label for color table (Prefs > Editor)"),
+ NSLocalizedString(@"Caret", @"caret label for color table (Prefs > Editor)"),
+ NSLocalizedString(@"Comment", @"comment label"),
+ NSLocalizedString(@"Keyword", @"keyword label for color table (Prefs > Editor)"),
+ NSLocalizedString(@"Numeric", @"numeric label for color table (Prefs > Editor)"),
+ NSLocalizedString(@"Quote", @"quote label for color table (Prefs > Editor)"),
+ NSLocalizedString(@"Backtick Quote", @"backtick quote label for color table (Prefs > Editor)"),
+ NSLocalizedString(@"Variable", @"variable label for color table (Prefs > Editor)"),
+ NSLocalizedString(@"Query Background", @"query background label for color table (Prefs > Editor)"),
+ NSLocalizedString(@"Selection", @"selection label for color table (Prefs > Editor)"),
+ nil] retain];
+ }
+
+ return self;
+}
+
+/**
+ * Initialise the UI, specifically the colours table view.
+ */
+- (void)awakeFromNib
+{
+ [NSColor setIgnoresAlpha:NO];
+
+ NSTableColumn *column = [[colorSettingTableView tableColumns] objectAtIndex:0];
+ NSTextFieldCell *textCell = [[[NSTextFieldCell alloc] init] autorelease];
+
+ [textCell setFont:[NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:SPCustomQueryEditorFont]]];
+
+ column = [[colorSettingTableView tableColumns] objectAtIndex: 1];
+
+ SPColorWellCell *colorCell = [[[SPColorWellCell alloc] init] autorelease];
+
+ [colorCell setEditable:YES];
+ [colorCell setTarget:self];
+ [colorCell setAction:@selector(colorClick:)];
+
+ [column setDataCell:colorCell];
+}
+
+#pragma mark -
+#pragma mark IB action methods
+
+- (IBAction)exportColorScheme:(id)sender
+{
+ NSSavePanel *panel = [NSSavePanel savePanel];
+
+ [panel setRequiredFileType:SPColorThemeFileExtension];
+
+ [panel setExtensionHidden:NO];
+ [panel setAllowsOtherFileTypes:NO];
+ [panel setCanSelectHiddenExtension:YES];
+ [panel setCanCreateDirectories:YES];
+
+ [panel beginSheetForDirectory:nil
+ file:[@"MyTheme" stringByAppendingPathExtension:SPColorThemeFileExtension]
+ modalForWindow:[[self view] window]
+ modalDelegate:self
+ didEndSelector:@selector(panelDidEnd:returnCode:contextInfo:)
+ contextInfo:@"exportColorScheme"];
+}
+
+- (IBAction)importColorScheme:(id)sender
+{
+ if (![self _checkForUnsavedTheme]) return;
+
+ NSOpenPanel *panel = [NSOpenPanel openPanel];
+
+ [panel setCanSelectHiddenExtension:YES];
+ [panel setDelegate:self];
+ [panel setCanChooseDirectories:NO];
+ [panel setAllowsMultipleSelection:NO];
+
+ [panel beginSheetForDirectory:nil
+ file:@""
+ types:[NSArray arrayWithObjects:SPColorThemeFileExtension, @"tmTheme", nil]
+ modalForWindow:[[self view] window]
+ modalDelegate:self
+ didEndSelector:@selector(panelDidEnd:returnCode:contextInfo:)
+ contextInfo:@"importColorScheme"];
+
+}
+
+- (IBAction)loadColorScheme:(id)sender
+{
+ if (![self _checkForUnsavedTheme]) return;
+
+ if ([self _loadColorSchemeFromFile:[NSString stringWithFormat:@"%@/%@.%@", themePath, [sender title], SPColorThemeFileExtension]]) {
+ [prefs setObject:[sender title] forKey:SPCustomQueryEditorThemeName];
+
+ [self updateDisplayColorThemeName];
+ }
+}
+
+- (IBAction)saveAsColorScheme:(id)sender
+{
+ [[NSColorPanel sharedColorPanel] close];
+
+ [enterNameAlertField setHidden:YES];
+ [enterNameInputField setStringValue:@""];
+ [enterNameLabel setStringValue:NSLocalizedString(@"Theme Name:", @"theme name label")];
+
+ [NSApp beginSheet:enterNameWindow
+ modalForWindow:[[self view] window]
+ modalDelegate:self
+ didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:)
+ contextInfo:@"saveTheme"];
+
+}
+
+- (IBAction)duplicateTheme:(id)sender
+{
+ if ([editThemeListTable numberOfSelectedRows] != 1) return;
+
+ NSString *selectedPath = [NSString stringWithFormat:@"%@/%@_copy.%@", themePath, [editThemeListItems objectAtIndex:[editThemeListTable selectedRow]], SPColorThemeFileExtension];
+
+ NSFileManager *fm = [NSFileManager defaultManager];
+
+ if (![fm fileExistsAtPath:selectedPath isDirectory:nil]) {
+ if ([fm copyItemAtPath:[NSString stringWithFormat:@"%@/%@.%@", themePath, [editThemeListItems objectAtIndex:[editThemeListTable selectedRow]], SPColorThemeFileExtension] toPath:selectedPath error:nil]) {
+
+ if (editThemeListItems) [editThemeListItems release], editThemeListItems = nil;
+
+ editThemeListItems = [[NSArray arrayWithArray:[self _getAvailableThemes]] retain];
+
+ [editThemeListTable reloadData];
+
+ [self updateDisplayColorThemeName];
+ [self updateColorSchemeSelectionMenu];
+
+ return;
+ }
+ }
+
+ NSBeep();
+
+ [editThemeListTable reloadData];
+}
+
+- (IBAction)removeTheme:(id)sender
+{
+ if ([editThemeListTable numberOfSelectedRows] != 1) return;
+
+ NSString *selectedPath = [NSString stringWithFormat:@"%@/%@.%@", themePath, [editThemeListItems objectAtIndex:[editThemeListTable selectedRow]], SPColorThemeFileExtension];
+
+ NSFileManager *fm = [NSFileManager defaultManager];
+
+ if ([fm fileExistsAtPath:selectedPath isDirectory:nil]) {
+ if ([fm removeItemAtPath:selectedPath error:nil]) {
+
+ // Refresh current color theme setting name
+ if ([[[prefs objectForKey:SPCustomQueryEditorThemeName] lowercaseString] isEqualToString:[[editThemeListItems objectAtIndex:[editThemeListTable selectedRow]] lowercaseString]]) {
+ [prefs setObject:@"User-defined" forKey:SPCustomQueryEditorThemeName];
+ }
+
+ if (editThemeListItems) [editThemeListItems release], editThemeListItems = nil;
+
+ editThemeListItems = [[NSArray arrayWithArray:[self _getAvailableThemes]] retain];
+
+ [editThemeListTable reloadData];
+
+ [self updateDisplayColorThemeName];
+ [self updateColorSchemeSelectionMenu];
+
+ return;
+ }
+ }
+
+ NSBeep();
+
+ [editThemeListTable reloadData];
+}
+
+- (IBAction)closePanelSheet:(id)sender
+{
+ [NSApp endSheet:[sender window] returnCode:[sender tag]];
+ [[sender window] orderOut:self];
+}
+
+/**
+ * Opens the font panel.
+ */
+- (IBAction)showCustomQueryFontPanel:(id)sender
+{
+ [(SPPreferenceController *)[[[self view] window] delegate] setFontChangeTarget:2];
+
+ [[NSFontPanel sharedFontPanel] setPanelFont:[NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:SPCustomQueryEditorFont]] isMultiple:NO];
+ [[NSFontPanel sharedFontPanel] makeKeyAndOrderFront:self];
+}
+
+/**
+ * Sets the syntax colours back to there defaults.
+ */
+- (IBAction)setDefaultColors:(id)sender
+{
+ if (![self _checkForUnsavedTheme]) return;
+
+ [[NSColorPanel sharedColorPanel] close];
+
+ [prefs setObject:@"Default" forKey:SPCustomQueryEditorThemeName];
+ [prefs setObject:[NSArchiver archivedDataWithRootObject:[NSColor colorWithDeviceRed:0.000 green:0.455 blue:0.000 alpha:1.000]] forKey:SPCustomQueryEditorCommentColor];
+ [prefs setObject:[NSArchiver archivedDataWithRootObject:[NSColor colorWithDeviceRed:0.769 green:0.102 blue:0.086 alpha:1.000]] forKey:SPCustomQueryEditorQuoteColor];
+ [prefs setObject:[NSArchiver archivedDataWithRootObject:[NSColor colorWithDeviceRed:0.200 green:0.250 blue:1.000 alpha:1.000]] forKey:SPCustomQueryEditorSQLKeywordColor];
+ [prefs setObject:[NSArchiver archivedDataWithRootObject:[NSColor colorWithDeviceRed:0.000 green:0.000 blue:0.658 alpha:1.000]] forKey:SPCustomQueryEditorBacktickColor];
+ [prefs setObject:[NSArchiver archivedDataWithRootObject:[NSColor colorWithDeviceRed:0.506 green:0.263 blue:0.000 alpha:1.000]] forKey:SPCustomQueryEditorNumericColor];
+ [prefs setObject:[NSArchiver archivedDataWithRootObject:[NSColor colorWithDeviceRed:0.500 green:0.500 blue:0.500 alpha:1.000]] forKey:SPCustomQueryEditorVariableColor];
+ [prefs setObject:[NSArchiver archivedDataWithRootObject:[NSColor colorWithDeviceRed:0.950 green:0.950 blue:0.950 alpha:1.000]] forKey:SPCustomQueryEditorHighlightQueryColor];
+ [prefs setObject:[NSArchiver archivedDataWithRootObject:[NSColor colorWithDeviceRed:0.7098 green:0.8352 blue:1.000 alpha:1.000]] forKey:SPCustomQueryEditorSelectionColor];
+ [prefs setObject:[NSArchiver archivedDataWithRootObject:[NSColor blackColor]] forKey:SPCustomQueryEditorTextColor];
+ [prefs setObject:[NSArchiver archivedDataWithRootObject:[NSColor blackColor]] forKey:SPCustomQueryEditorCaretColor];
+ [prefs setObject:[NSArchiver archivedDataWithRootObject:[NSColor whiteColor]] forKey:SPCustomQueryEditorBackgroundColor];
+
+ [colorSettingTableView reloadData];
+
+ [self updateDisplayColorThemeName];
+}
+
+/**
+ * Opens the theme liste sheet.
+ */
+- (IBAction)editThemeList:(id)sender
+{
+ [[NSColorPanel sharedColorPanel] close];
+
+ if (editThemeListItems) [editThemeListItems release], editThemeListItems = nil;
+
+ editThemeListItems = [[NSArray arrayWithArray:[self _getAvailableThemes]] retain];
+
+ [editThemeListTable reloadData];
+
+ [NSApp beginSheet:editThemeListWindow
+ modalForWindow:[[self view] window]
+ modalDelegate:self
+ didEndSelector:nil
+ contextInfo:nil];
+}
+
+#pragma mark -
+#pragma mark Public API
+
+/**
+ * Updates the displayed font according to the user's preferences.
+ */
+- (void)updateDisplayedEditorFontName
+{
+ NSFont *font = [NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:SPCustomQueryEditorFont]];
+
+ [editorFontName setFont:font];
+ [editorFontName setStringValue:[NSString stringWithFormat:@"%@, %.1f pt", [font displayName], [font pointSize]]];
+
+ [colorSettingTableView reloadData];
+}
+
+/**
+ * Updates the colour scheme selection menu according to the available schemes.
+ */
+- (void)updateColorSchemeSelectionMenu
+{
+ NSMenuItem *defaultItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Default", @"default label") action:@selector(setDefaultColors:) keyEquivalent:@""];
+
+ [defaultItem setTarget:self];
+
+ // Build theme selection submenu
+ [themeSelectionMenu removeAllItems];
+ [themeSelectionMenu addItem:defaultItem];
+ [themeSelectionMenu addItem:[NSMenuItem separatorItem]];
+
+ [defaultItem release];
+
+ NSArray *foundThemes = [self _getAvailableThemes];
+
+ if ([foundThemes count]) {
+ for (NSString* item in foundThemes)
+ {
+ NSMenuItem *loadItem = [[NSMenuItem alloc] initWithTitle:item action:@selector(loadColorScheme:) keyEquivalent:@""];
+
+ [loadItem setTarget:self];
+
+ [themeSelectionMenu addItem:loadItem];
+
+ [loadItem release];
+ }
+
+ [themeSelectionMenu addItem:[NSMenuItem separatorItem]];
+ }
+
+ NSMenuItem *editItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Edit Theme List…", @"edit theme list label") action:@selector(editThemeList:) keyEquivalent:@""];
+
+ [editItem setTarget:self];
+
+ [themeSelectionMenu addItem:editItem];
+
+ [editItem release];
+}
+
+/**
+ * Updates the currently selected colour scheme theme name.
+ */
+- (void)updateDisplayColorThemeName
+{
+ if (![prefs objectForKey:SPCustomQueryEditorThemeName]) {
+ [colorThemeName setHidden:YES];
+ [colorThemeNameLabel setHidden:YES];
+
+ return;
+ }
+
+ if ([[[prefs objectForKey:SPCustomQueryEditorThemeName] lowercaseString] isEqualToString:@"user-defined"]) {
+ [colorThemeName setHidden:YES];
+ [colorThemeNameLabel setHidden:YES];
+
+ return;
+ }
+
+ NSString *currentThemeName = [[prefs objectForKey:SPCustomQueryEditorThemeName] lowercaseString];
+
+ if ([currentThemeName isEqualToString:@"default"]) {
+ [colorThemeName setHidden:NO];
+ [colorThemeNameLabel setHidden:NO];
+
+ return;
+ }
+
+ BOOL nameValid = NO;
+
+ for (NSString* item in [self _getAvailableThemes])
+ {
+ if ([[item lowercaseString] isEqualToString:currentThemeName]) {
+ nameValid = YES;
+ break;
+ }
+ }
+
+ if (nameValid) {
+ [colorThemeName setHidden:NO];
+ [colorThemeNameLabel setHidden:NO];
+
+ return;
+ }
+ else {
+ [prefs setObject:@"User-defined" forKey:SPCustomQueryEditorThemeName];
+ [colorThemeName setHidden:YES];
+ [colorThemeNameLabel setHidden:YES];
+
+ [self updateColorSchemeSelectionMenu];
+
+ return;
+ }
+
+ [colorThemeName setHidden:NO];
+ [colorThemeNameLabel setHidden:NO];
+}
+
+#pragma mark -
+#pragma mark Font panel methods
+
+/**
+ * Invoked when the user clicks a colour cell.
+ */
+- (void)colorClick:(id)sender
+{
+ colorRow = [sender clickedRow];
+
+ NSColorPanel *panel = [NSColorPanel sharedColorPanel];
+
+ [panel setTarget:self];
+ [panel setAction:@selector(colorChanged:)];
+ [panel setColor:[NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:[editorColors objectAtIndex:colorRow]]]];
+
+ [colorSettingTableView deselectAll:nil];
+
+ [panel makeKeyAndOrderFront:self];
+}
+
+/**
+ * Invoked when the user changes and editor colour.
+ */
+- (void)colorChanged:(id)sender
+{
+ if (![[NSColorPanel sharedColorPanel] isVisible]) return;
+
+ [prefs setObject:[NSArchiver archivedDataWithRootObject:[sender color]] forKey:[editorColors objectAtIndex:colorRow]];
+ [colorSettingTableView reloadData];
+
+ [prefs setObject:@"User-defined" forKey:SPCustomQueryEditorThemeName];
+
+ [self updateDisplayColorThemeName];
+}
+
+/**
+ * Sets the font panel's valid modes.
+ */
+- (NSUInteger)validModesForFontPanel:(NSFontPanel *)fontPanel
+{
+ return (NSFontPanelSizeModeMask | NSFontPanelCollectionModeMask);
+}
+
+#pragma mark -
+#pragma mark Sheet callbacks
+
+- (void)checkForUnsavedThemeDidEndSheet:(NSWindow *)sheet returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo
+{
+ checkForUnsavedThemeSheetStatus = returnCode;
+}
+
+- (void)sheetDidEnd:(id)sheet returnCode:(NSInteger)returnCode contextInfo:(NSString *)contextInfo
+{
+ // Order out current sheet to suppress overlapping of sheets
+ if ([sheet respondsToSelector:@selector(orderOut:)]) {
+ [sheet orderOut:nil];
+ }
+ else if ([sheet respondsToSelector:@selector(window)]) {
+ [[sheet window] orderOut:nil];
+ }
+
+ if ([contextInfo isEqualToString:@"saveTheme"]) {
+ if (returnCode == NSOKButton) {
+ NSFileManager *fm = [NSFileManager defaultManager];
+
+ if (![fm fileExistsAtPath:themePath isDirectory:nil]) {
+ if (![fm createDirectoryAtPath:themePath withIntermediateDirectories:YES attributes:nil error:nil]) {
+ NSBeep();
+ return;
+ }
+ }
+
+ [self _saveColorThemeAtPath:[NSString stringWithFormat:@"%@/%@.%@", themePath, [enterNameInputField stringValue], SPColorThemeFileExtension]];
+ [self updateColorSchemeSelectionMenu];
+
+ [prefs setObject:[enterNameInputField stringValue] forKey:SPCustomQueryEditorThemeName];
+
+ [self updateDisplayColorThemeName];
+ }
+ }
+}
+
+- (void)panelDidEnd:(NSSavePanel *)panel returnCode:(NSInteger)returnCode contextInfo:(NSString *)contextInfo
+{
+ if ([contextInfo isEqualToString:@"exportColorScheme"]) {
+ if (returnCode == NSOKButton) {
+ [self _saveColorThemeAtPath:[panel filename]];
+ }
+ }
+ else if ([contextInfo isEqualToString:@"importColorScheme"]) {
+ if (returnCode == NSOKButton) {
+ if ([self _loadColorSchemeFromFile:[[panel filenames] objectAtIndex:0]]) {
+ [prefs setObject:@"User-defined" forKey:SPCustomQueryEditorThemeName];
+ [self updateDisplayColorThemeName];
+ }
+ }
+ }
+}
+
+#pragma mark -
+#pragma mark TableView datasource methods
+
+- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
+{
+ if (tableView == colorSettingTableView) {
+ return [editorColors count];
+ }
+ else if (tableView == editThemeListTable) {
+ return [editThemeListItems count];
+ }
+
+ return nil;
+}
+
+- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)rowIndex
+{
+ if (tableView == colorSettingTableView) {
+ return ([[tableColumn identifier] isEqualToString:@"name"]) ? [editorNameForColors objectAtIndex:rowIndex] : [NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:[editorColors objectAtIndex:rowIndex]]];
+ }
+ else if (tableView == editThemeListTable) {
+ return [editThemeListItems objectAtIndex:rowIndex];
+ }
+
+ return nil;
+}
+
+- (void)tableView:(NSTableView *)tableView setObjectValue:(id)anObject forTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex
+{
+ if (tableView == editThemeListTable) {
+
+ // Theme name editing
+ NSString *newName = (NSString*)anObject;
+
+ // Check for non-valid names
+ if (![newName length] || [[newName lowercaseString] isEqualToString:@"default"] || [[newName lowercaseString] isEqualToString:@"user-defined"]) {
+ NSBeep();
+ [editThemeListTable reloadData];
+ return;
+ }
+
+ // Check if new name already exists
+ for (NSString* item in editThemeListItems)
+ {
+ if ([[item lowercaseString] isEqualToString:newName]) {
+ NSBeep();
+ [editThemeListTable reloadData];
+ return;
+ }
+ }
+
+ // Rename theme file
+ NSFileManager *fm = [NSFileManager defaultManager];
+
+ if (![fm moveItemAtPath:[NSString stringWithFormat:@"%@/%@.%@", themePath, [editThemeListItems objectAtIndex:rowIndex], SPColorThemeFileExtension] toPath:[NSString stringWithFormat:@"%@/%@.%@", themePath, newName, SPColorThemeFileExtension] error:nil]) {
+ NSBeep();
+ [editThemeListTable reloadData];
+ return;
+ }
+
+ // Refresh current color theme setting name
+ if ([[[prefs objectForKey:SPCustomQueryEditorThemeName] lowercaseString] isEqualToString:[[editThemeListItems objectAtIndex:rowIndex] lowercaseString]]) {
+ [prefs setObject:newName forKey:SPCustomQueryEditorThemeName];
+ }
+
+ // Reload everything needed
+ if (editThemeListItems) [editThemeListItems release], editThemeListItems = nil;
+ editThemeListItems = [[NSArray arrayWithArray:[self _getAvailableThemes]] retain];
+
+ [editThemeListTable reloadData];
+
+ [self updateDisplayColorThemeName];
+ [self updateColorSchemeSelectionMenu];
+ }
+}
+
+#pragma mark -
+#pragma mark TableView delegate methods
+
+- (BOOL)tableView:(NSTableView *)aTableView shouldEditTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex
+{
+ if(aTableView == colorSettingTableView) {
+
+ NSColorPanel* panel;
+
+ colorRow = rowIndex;
+ panel = [NSColorPanel sharedColorPanel];
+
+ [panel setTarget:self];
+ [panel setAction:@selector(colorChanged:)];
+ [panel setColor:[NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:[editorColors objectAtIndex:colorRow]]]];
+ [colorSettingTableView deselectAll:nil];
+ [panel makeKeyAndOrderFront:self];
+
+ return NO;
+ }
+
+ return YES;
+}
+
+- (void)tableView:(NSTableView *)tableView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)index
+{
+ if (tableView == colorSettingTableView && [[tableColumn identifier] isEqualToString:@"name"]) {
+ if ([cell isKindOfClass:[NSTextFieldCell class]]) {
+ [cell setDrawsBackground:YES];
+
+ NSFont *nf = [NSFont fontWithName:[[[NSFontPanel sharedFontPanel] panelConvertFont:[NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:SPCustomQueryEditorFont]]] fontName] size:13.0f];
+
+ [cell setFont:nf];
+
+ switch (index)
+ {
+ case 1:
+ [cell setTextColor:[NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:SPCustomQueryEditorTextColor]]];
+ [cell setBackgroundColor:[NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:SPCustomQueryEditorBackgroundColor]]];
+ break;
+ case 9:
+ [cell setTextColor:[NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:SPCustomQueryEditorTextColor]]];
+ [cell setBackgroundColor:[NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:SPCustomQueryEditorHighlightQueryColor]]];
+ break;
+ case 10:
+ [cell setTextColor:[NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:SPCustomQueryEditorTextColor]]];
+ [cell setBackgroundColor:[NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:SPCustomQueryEditorSelectionColor]]];
+ break;
+ default:
+ [cell setTextColor:[NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:[editorColors objectAtIndex:index]]]];
+ [cell setBackgroundColor:[NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:SPCustomQueryEditorBackgroundColor]]];
+ }
+ }
+ }
+}
+
+#pragma mark -
+#pragma mark TextField delegate methods
+
+/**
+ * Trap and control the 'name' field of the selected favorite. If the user pressed
+ * 'Add Favorite' the 'name' field is set to "New Favorite". If the user do not
+ * change the 'name' field or delete that field it will be set to user@host automatically.
+ */
+- (void)controlTextDidChange:(NSNotification *)aNotification
+{
+ id field = [aNotification object];
+
+ // Validate 'Save' button for entering a valid theme name
+ if (field == enterNameInputField) {
+ NSString *name = [[enterNameInputField stringValue] lowercaseString];
+
+ if (![name length] || [name isEqualToString:@"default"] || [name isEqualToString:@"user-defined"]) {
+ [themeNameSaveButton setEnabled:NO];
+ }
+ else {
+ BOOL hide = YES;
+
+ for (NSString* item in [self _getAvailableThemes])
+ {
+ if ([[item lowercaseString] isEqualToString:name]) {
+ hide = NO;
+ break;
+ }
+ }
+
+ [enterNameAlertField setHidden:hide];
+ [themeNameSaveButton setEnabled:YES];
+ }
+
+ return;
+ }
+}
+
+#pragma mark -
+#pragma mark Preference pane protocol methods
+
+- (NSView *)preferencePaneView
+{
+ return [self view];
+}
+
+- (NSImage *)preferencePaneIcon
+{
+ return [NSImage imageNamed:@"toolbar-preferences-queryeditor"];
+}
+
+- (NSString *)preferencePaneName
+{
+ return NSLocalizedString(@"Query Editor", @"query editor preference pane name");
+}
+
+- (NSString *)preferencePaneIdentifier
+{
+ return SPPreferenceToolbarEditor;
+}
+
+- (NSString *)preferencePaneToolTip
+{
+ return NSLocalizedString(@"Query Editor Preferences", @"query editor preference pane tooltip");
+}
+
+- (BOOL)preferencePaneAllowsResizing
+{
+ return NO;
+}
+
+#pragma mark -
+#pragma mark Private API
+
+- (BOOL)_checkForUnsavedTheme
+{
+ if (![prefs objectForKey:SPCustomQueryEditorThemeName] || [[[prefs objectForKey:SPCustomQueryEditorThemeName] lowercaseString] isEqualToString:@"user-defined"]) {
+
+ [[NSColorPanel sharedColorPanel] close];
+
+ SPBeginWaitingAlertSheet(@"title",
+ NSLocalizedString(@"Proceed", @"proceed button"), NSLocalizedString(@"Cancel", @"cancel button"), nil,
+ NSWarningAlertStyle, [[self view] window], self,
+ @selector(checkForUnsavedThemeDidEndSheet:returnCode:contextInfo:),
+ nil,
+ NSLocalizedString(@"Warning", @"warning"),
+ NSLocalizedString(@"Current color theme is unsaved. Do you want to proceed without saving it?", @"Current color theme is unsaved. Do you want to proceed without saving it message"),
+ checkForUnsavedThemeSheetStatus
+ );
+
+ return (checkForUnsavedThemeSheetStatus == NSAlertDefaultReturn);
+ }
+
+ [[NSColorPanel sharedColorPanel] close];
+
+ return YES;
+}
+
+- (NSArray *)_getAvailableThemes
+{
+ // Read ~/Library/Application Support/Sequel Pro/Themes
+ NSFileManager *fm = [NSFileManager defaultManager];
+
+ if ([fm fileExistsAtPath:themePath isDirectory:nil]) {
+ NSArray *allItemsRaw = [fm contentsOfDirectoryAtPath:themePath error:NULL];
+
+ if(!allItemsRaw) return [NSArray array];
+
+ // Filter out all themes
+ NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF ENDSWITH %@", [NSString stringWithFormat:@".%@", SPColorThemeFileExtension]];
+ NSMutableArray *allItems = [NSMutableArray arrayWithArray:allItemsRaw];
+
+ [allItems filterUsingPredicate:predicate];
+
+ allItemsRaw = [NSArray arrayWithArray:allItems];
+
+ [allItems removeAllObjects];
+
+ // Remove file extension
+ for (NSString* item in allItemsRaw)
+ {
+ [allItems addObject:[item substringToIndex:[item length]-[SPColorThemeFileExtension length]-1]];
+ }
+
+ return (NSArray *)allItems;
+ }
+
+ return [NSArray array];
+}
+
+- (void)_saveColorThemeAtPath:(NSString *)path
+{
+ // Build plist dictionary
+ NSMutableDictionary *scheme = [NSMutableDictionary dictionary];
+ NSMutableDictionary *mainsettings = [NSMutableDictionary dictionary];
+ NSMutableArray *settings = [NSMutableArray array];
+
+ CGFloat red, green, blue, alpha;
+ NSInteger redInt, greenInt, blueInt, alphaInt;
+ NSString *redHexValue, *greenHexValue, *blueHexValue, *alphaHexValue;
+
+ [prefs synchronize];
+
+ NSColor *aColor = [NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:SPCustomQueryEditorBackgroundColor]];
+ [mainsettings setObject:[aColor rgbHexString] forKey:@"background"];
+
+ aColor = [NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:SPCustomQueryEditorCaretColor]];
+ [mainsettings setObject:[aColor rgbHexString] forKey:@"caret"];
+
+ aColor = [NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:SPCustomQueryEditorTextColor]];
+ [mainsettings setObject:[aColor rgbHexString] forKey:@"foreground"];
+
+ aColor = [NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:SPCustomQueryEditorHighlightQueryColor]];
+ [mainsettings setObject:[aColor rgbHexString] forKey:@"lineHighlight"];
+
+ aColor = [NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:SPCustomQueryEditorSelectionColor]];
+ [mainsettings setObject:[aColor rgbHexString] forKey:@"selection"];
+
+ [settings addObject:[NSDictionary dictionaryWithObjectsAndKeys:mainsettings, @"settings", nil]];
+
+ aColor = [NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:SPCustomQueryEditorCommentColor]];
+ [settings addObject:[NSDictionary dictionaryWithObjectsAndKeys:
+ @"Comment", @"name",
+ [NSDictionary dictionaryWithObjectsAndKeys:
+ [aColor rgbHexString], @"foreground",
+ nil
+ ], @"settings",
+ nil
+ ]];
+
+ aColor = [NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:SPCustomQueryEditorQuoteColor]];
+ [settings addObject:[NSDictionary dictionaryWithObjectsAndKeys:
+ @"String", @"name",
+ [NSDictionary dictionaryWithObjectsAndKeys:
+ [aColor rgbHexString], @"foreground",
+ nil
+ ], @"settings",
+ nil
+ ]];
+
+ aColor = [NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:SPCustomQueryEditorSQLKeywordColor]];
+ [settings addObject:[NSDictionary dictionaryWithObjectsAndKeys:
+ @"Keyword", @"name",
+ [NSDictionary dictionaryWithObjectsAndKeys:
+ [aColor rgbHexString], @"foreground",
+ nil
+ ], @"settings",
+ nil
+ ]];
+
+ aColor = [NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:SPCustomQueryEditorBacktickColor]];
+ [settings addObject:[NSDictionary dictionaryWithObjectsAndKeys:
+ @"User-defined constant", @"name",
+ [NSDictionary dictionaryWithObjectsAndKeys:
+ [aColor rgbHexString], @"foreground",
+ nil
+ ], @"settings",
+ nil
+ ]];
+
+ aColor = [NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:SPCustomQueryEditorNumericColor]];
+ [settings addObject:[NSDictionary dictionaryWithObjectsAndKeys:
+ @"Number", @"name",
+ [NSDictionary dictionaryWithObjectsAndKeys:
+ [aColor rgbHexString], @"foreground",
+ nil
+ ], @"settings",
+ nil
+ ]];
+
+ aColor = [NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:SPCustomQueryEditorVariableColor]];
+ [settings addObject:[NSDictionary dictionaryWithObjectsAndKeys:
+ @"Variable", @"name",
+ [NSDictionary dictionaryWithObjectsAndKeys:
+ [aColor rgbHexString], @"foreground",
+ nil
+ ], @"settings",
+ nil
+ ]];
+
+ [scheme setObject:settings forKey:@"settings"];
+
+ NSString *err = nil;
+ NSData *plist = [NSPropertyListSerialization dataFromPropertyList:scheme
+ format:NSPropertyListXMLFormat_v1_0
+ errorDescription:&err];
+
+ if(err != nil) {
+ NSAlert *alert = [NSAlert alertWithMessageText:[NSString stringWithFormat:NSLocalizedString(@"Error while converting color scheme data", @"error while converting color scheme data")]
+ defaultButton:NSLocalizedString(@"OK", @"OK button")
+ alternateButton:nil
+ otherButton:nil
+ informativeTextWithFormat:err];
+
+ [alert setAlertStyle:NSCriticalAlertStyle];
+ [alert runModal];
+
+ return;
+ }
+
+ NSError *error = nil;
+ [plist writeToFile:path options:NSAtomicWrite error:&error];
+
+ if (error) [[NSAlert alertWithError:error] runModal];
+}
+
+- (BOOL)_loadColorSchemeFromFile:(NSString *)filename
+{
+ NSError *readError = nil;
+ NSString *convError = nil;
+ NSPropertyListFormat format;
+
+ NSDictionary *theme = nil;
+
+ NSData *pData = [NSData dataWithContentsOfFile:filename options:NSUncachedRead error:&readError];
+
+ theme = [[NSPropertyListSerialization propertyListFromData:pData
+ mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&convError] retain];
+
+ if (!theme || readError != nil || [convError length] || !(format == NSPropertyListXMLFormat_v1_0 || format == NSPropertyListBinaryFormat_v1_0)) {
+ NSAlert *alert = [NSAlert alertWithMessageText:[NSString stringWithFormat:NSLocalizedString(@"Error while reading data file", @"error while reading data file")]
+ defaultButton:NSLocalizedString(@"OK", @"OK button")
+ alternateButton:nil
+ otherButton:nil
+ informativeTextWithFormat:NSLocalizedString(@"File couldn't be read.", @"error while reading data file")];
+
+ [alert setAlertStyle:NSCriticalAlertStyle];
+ [alert runModal];
+ if (theme) [theme release];
+ [self updateDisplayColorThemeName];
+ return NO;
+ }
+
+ if ([theme objectForKey:@"settings"]
+ && [[theme objectForKey:@"settings"] isKindOfClass:[NSArray class]]
+ && [[theme objectForKey:@"settings"] count]
+ && [[[theme objectForKey:@"settings"] objectAtIndex:0] isKindOfClass:[NSDictionary class]]
+ && [[[theme objectForKey:@"settings"] objectAtIndex:0] objectForKey:@"settings"]) {
+
+ NSInteger counter = 0;
+
+ for (NSDictionary *dict in [theme objectForKey:@"settings"])
+ {
+ if (counter == 0) {
+ if ([dict objectForKey:@"settings"]) {
+ NSDictionary *dic = [dict objectForKey:@"settings"];
+ if([dic objectForKey:@"background"])
+ [prefs setObject:[NSArchiver archivedDataWithRootObject:[NSColor colorWithRGBHexString:[dic objectForKey:@"background"]]] forKey:SPCustomQueryEditorBackgroundColor];
+ if([dic objectForKey:@"caret"])
+ [prefs setObject:[NSArchiver archivedDataWithRootObject:[NSColor colorWithRGBHexString:[dic objectForKey:@"caret"]]] forKey:SPCustomQueryEditorCaretColor];
+ if([dic objectForKey:@"foreground"])
+ [prefs setObject:[NSArchiver archivedDataWithRootObject:[NSColor colorWithRGBHexString:[dic objectForKey:@"foreground"]]] forKey:SPCustomQueryEditorTextColor];
+ if([dic objectForKey:@"lineHighlight"])
+ [prefs setObject:[NSArchiver archivedDataWithRootObject:[NSColor colorWithRGBHexString:[dic objectForKey:@"lineHighlight"]]] forKey:SPCustomQueryEditorHighlightQueryColor];
+ if([dic objectForKey:@"selection"])
+ [prefs setObject:[NSArchiver archivedDataWithRootObject:[NSColor colorWithRGBHexString:[dic objectForKey:@"selection"]]] forKey:SPCustomQueryEditorSelectionColor];
+ }
+ else {
+ continue;
+ }
+ }
+ else {
+ if ([dict objectForKey:@"name"] && [dict objectForKey:@"settings"] && [[dict objectForKey:@"settings"] isKindOfClass:[NSDictionary class]] && [[dict objectForKey:@"settings"] objectForKey:@"foreground"]) {
+ if ([[dict objectForKey:@"name"] isEqualToString:@"Comment"])
+ [prefs setObject:[NSArchiver archivedDataWithRootObject:
+ [NSColor colorWithRGBHexString:[[dict objectForKey:@"settings"] objectForKey:@"foreground"]]]
+ forKey:SPCustomQueryEditorCommentColor];
+ else if ([[dict objectForKey:@"name"] isEqualToString:@"String"])
+ [prefs setObject:[NSArchiver archivedDataWithRootObject:
+ [NSColor colorWithRGBHexString:[[dict objectForKey:@"settings"] objectForKey:@"foreground"]]]
+ forKey:SPCustomQueryEditorQuoteColor];
+ else if ([[dict objectForKey:@"name"] isEqualToString:@"Keyword"])
+ [prefs setObject:[NSArchiver archivedDataWithRootObject:
+ [NSColor colorWithRGBHexString:[[dict objectForKey:@"settings"] objectForKey:@"foreground"]]]
+ forKey:SPCustomQueryEditorSQLKeywordColor];
+ else if ([[dict objectForKey:@"name"] isEqualToString:@"User-defined constant"])
+ [prefs setObject:[NSArchiver archivedDataWithRootObject:
+ [NSColor colorWithRGBHexString:[[dict objectForKey:@"settings"] objectForKey:@"foreground"]]]
+ forKey:SPCustomQueryEditorBacktickColor];
+ else if ([[dict objectForKey:@"name"] isEqualToString:@"Number"])
+ [prefs setObject:[NSArchiver archivedDataWithRootObject:
+ [NSColor colorWithRGBHexString:[[dict objectForKey:@"settings"] objectForKey:@"foreground"]]]
+ forKey:SPCustomQueryEditorNumericColor];
+ else if ([[dict objectForKey:@"name"] isEqualToString:@"Variable"])
+ [prefs setObject:[NSArchiver archivedDataWithRootObject:
+ [NSColor colorWithRGBHexString:[[dict objectForKey:@"settings"] objectForKey:@"foreground"]]]
+ forKey:SPCustomQueryEditorVariableColor];
+ }
+ }
+
+ counter++;
+ }
+
+ [theme release];
+ [colorSettingTableView reloadData];
+ }
+ else {
+ NSAlert *alert = [NSAlert alertWithMessageText:[NSString stringWithFormat:NSLocalizedString(@"Error while reading data file", @"error while reading data file")]
+ defaultButton:NSLocalizedString(@"OK", @"OK button")
+ alternateButton:nil
+ otherButton:nil
+ informativeTextWithFormat:NSLocalizedString(@"No color theme data found.", @"error that no color theme found")];
+
+ [alert setAlertStyle:NSInformationalAlertStyle];
+ [alert runModal];
+ [theme release];
+
+ return NO;
+ }
+
+ return YES;
+}
+
+#pragma mark -
+
+/**
+ * Dealloc.
+ */
+- (void)dealloc
+{
+ if (themePath) [themePath release], themePath = nil;
+ if (editThemeListItems) [editThemeListItems release], editThemeListItems = nil;
+ if (editorColors) [editorColors release], editorColors = nil;
+ if (editorNameForColors) [editorNameForColors release], editorNameForColors = nil;
+
+ [super dealloc];
+}
+
+@end