// // $Id$ // // SPQueryFavoriteManager.m // sequel-pro // // Created by Stuart Connolly (stuconnolly.com) on Aug 23, 2009 // Copyright (c) 2009 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 #import "SPQueryFavoriteManager.h" #import "ImageAndTextCell.h" #import "SPEncodingPopupAccessory.h" #define DEFAULT_QUERY_FAVORITE_FILE_EXTENSION @"sql" #define DEFAULT_SEQUELPRO_FILE_EXTENSION @"spf" #define SP_MULTIPLE_SELECTION_PLACEHOLDER_STRING NSLocalizedString(@"[multiple selection]", @"[multiple selection]") #define SP_NO_SELECTION_PLACEHOLDER_STRING NSLocalizedString(@"[no selection]", @"[no selection]") #define QUERY_FAVORITES_PB_DRAG_TYPE @"SequelProQueryFavoritesPasteboard" @interface SPQueryFavoriteManager (Private) - (void)_writePendingQueryString; @end @implementation SPQueryFavoriteManager /** * Initialize the manager with the supplied delegate */ - (id)initWithDelegate:(id)managerDelegate { if ((self = [super initWithWindowNibName:@"QueryFavoriteManager"])) { delegate = managerDelegate; prefs = [NSUserDefaults standardUserDefaults]; favoriteProperties = [[NSMutableArray alloc] init]; favorites = [[NSMutableArray alloc] init]; selectedRowBeforeChangingSelection = 0; pendingQueryString = [[NSMutableString alloc] init]; delegateRespondsToFavoriteUpdates = [delegate respondsToSelector:@selector(queryFavoritesHaveBeenUpdated:)]; } return self; } - (void)dealloc { [favoriteProperties release]; [favorites release]; [pendingQueryString release]; [super dealloc]; } /** * Upon awakening bind the query text view's background colour. */ - (void)awakeFromNib { [favoriteQueryTextView setAllowsDocumentBackgroundColorChange:YES]; NSMutableDictionary *bindingOptions = [NSMutableDictionary dictionary]; [bindingOptions setObject:NSUnarchiveFromDataTransformerName forKey:@"NSValueTransformerName"]; [favoriteQueryTextView bind:@"backgroundColor" toObject:[NSUserDefaultsController sharedUserDefaultsController] withKeyPath:@"values.CustomQueryEditorBackgroundColor" options:bindingOptions]; [favorites addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"GLOBAL", @"name", nil]]; [favoriteProperties addObject:[NSNumber numberWithInt:SP_FAVORITETYPE_HEADER]]; // Build data source for global queryFavorites (as mutable copy! otherwise each // change will be stored in the prefs at once) if([prefs objectForKey:@"queryFavorites"]) { for(id fav in [prefs objectForKey:@"queryFavorites"]) { [favorites addObject:[fav mutableCopy]]; [favoriteProperties addObject:[NSNumber numberWithInt:SP_FAVORITETYPE_GLOBAL]]; } } [favoritesTableView reloadData]; // Set Remove button state [removeButton setEnabled:([favorites count] > 1)]; // Select the first query [favoritesTableView selectRowIndexes:[NSIndexSet indexSetWithIndex:1] byExtendingSelection:NO]; // Register drag types [favoritesTableView registerForDraggedTypes:[NSArray arrayWithObject:QUERY_FAVORITES_PB_DRAG_TYPE]]; } #pragma mark - #pragma mark Accessor methods /** * Returns the global query favorites array. */ - (NSMutableArray *)globalQueryFavorites { NSMutableArray *globals = [NSMutableArray array]; NSUInteger i; for(i=1; i<[favorites count]; i++) if([[favoriteProperties objectAtIndex:i] intValue] == SP_FAVORITETYPE_GLOBAL) [globals addObject:[favorites objectAtIndex:i]]; return globals; } /** * Returns the global query favorites array. */ - (NSMutableArray *)connectionQueryFavorites { NSMutableArray *conns = [NSMutableArray array]; NSUInteger i; for(i=1; i<[favorites count]; i++) if([[favoriteProperties objectAtIndex:i] intValue] == SP_FAVORITETYPE_CONNECTION) [conns addObject:[favorites objectAtIndex:i]]; return conns; } /** * This method is only implemented to be compatible with CMTextView. */ - (id)customQueryInstance { return [[[NSApp mainWindow] delegate] valueForKey:@"customQueryInstance"]; } #pragma mark - #pragma mark IBAction methods /** * Adds a query favorite */ - (IBAction)addQueryFavorite:(id)sender { [self _writePendingQueryString]; NSMutableDictionary *favorite = [NSMutableDictionary dictionaryWithObjects:[NSArray arrayWithObjects:@"New Favorite", @"", nil] forKeys:[NSArray arrayWithObjects:@"name", @"query", nil]]; [favorites addObject:favorite]; [favoriteProperties addObject:[NSNumber numberWithInt:SP_FAVORITETYPE_GLOBAL]]; [favoritesTableView reloadData]; [favoritesTableView selectRowIndexes:[NSIndexSet indexSetWithIndex:([favorites count] - 1)] byExtendingSelection:NO]; [favoritesTableView scrollRowToVisible:[favoritesTableView selectedRow]]; selectedRowBeforeChangingSelection = [favorites count] - 1; [removeButton setEnabled:([favorites count] > 1)]; [[self window] makeFirstResponder:favoriteNameTextField]; } /** * Removes a query favorite */ - (IBAction)removeQueryFavorite:(id)sender { NSAlert *alert = [NSAlert alertWithMessageText:NSLocalizedString(@"Remove selected query favorites?", @"remove selected query favorites message") defaultButton:NSLocalizedString(@"Cancel", @"cancel button") alternateButton:NSLocalizedString(@"Remove", @"remove button") otherButton:nil informativeTextWithFormat:NSLocalizedString(@"Are you sure you want to remove all selected query favorites? This action cannot be undone.", @"remove all selected query favorites informative message")]; [alert setAlertStyle:NSCriticalAlertStyle]; NSArray *buttons = [alert buttons]; // Change the alert's cancel button to have the key equivalent of return [[buttons objectAtIndex:0] setKeyEquivalent:@"\r"]; [[buttons objectAtIndex:1] setKeyEquivalent:@""]; [alert beginSheetModalForWindow:[self window] modalDelegate:self didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) contextInfo:@"removeSelectedFavorites"]; } /** * Removes all query favorites */ - (IBAction)removeAllQueryFavorites:(id)sender { NSAlert *alert = [NSAlert alertWithMessageText:NSLocalizedString(@"Remove all query favorites?", @"remove all query favorites message") defaultButton:NSLocalizedString(@"Cancel", @"cancel button") alternateButton:NSLocalizedString(@"Remove All", @"remove all button") otherButton:nil informativeTextWithFormat:NSLocalizedString(@"Are you sure you want to remove all of your saved query favorites? This action cannot be undone.", @"remove all query favorites informative message")]; [alert setAlertStyle:NSCriticalAlertStyle]; NSArray *buttons = [alert buttons]; // Change the alert's cancel button to have the key equivalent of return [[buttons objectAtIndex:0] setKeyEquivalent:@"\r"]; [[buttons objectAtIndex:1] setKeyEquivalent:@""]; [alert beginSheetModalForWindow:[self window] modalDelegate:self didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) contextInfo:@"removeAllFavorites"]; } /** * Copies a query favorite */ - (IBAction)copyQueryFavorite:(id)sender { if ([favoritesTableView numberOfSelectedRows] == 1) { NSMutableDictionary *favorite = [NSMutableDictionary dictionaryWithObjects:[NSArray arrayWithObjects:[[favoriteNameTextField stringValue] stringByAppendingFormat:@" Copy"], [favoriteQueryTextView string], nil] forKeys:[NSArray arrayWithObjects:@"name", @"query", nil]]; [self _writePendingQueryString]; [favorites addObject:favorite]; [favoriteProperties addObject:[NSNumber numberWithInt:SP_FAVORITETYPE_GLOBAL]]; [favoritesTableView reloadData]; // Update selection [favoritesTableView selectRowIndexes:[NSIndexSet indexSetWithIndex:([favorites count] - 1)] byExtendingSelection:NO]; selectedRowBeforeChangingSelection = [favorites count] - 1; [favoritesTableView scrollRowToVisible:[favoritesTableView selectedRow]]; [[self window] makeFirstResponder:favoriteNameTextField]; } } /** * Saves the currently selected query favorite to a user specified file. */ - (IBAction)saveFavoriteToFile:(id)sender { NSSavePanel *panel = [NSSavePanel savePanel]; [panel setRequiredFileType:DEFAULT_QUERY_FAVORITE_FILE_EXTENSION]; [panel setExtensionHidden:NO]; [panel setAllowsOtherFileTypes:YES]; [panel setCanSelectHiddenExtension:YES]; [panel setCanCreateDirectories:YES]; [panel setAccessoryView:[SPEncodingPopupAccessory encodingAccessory:[prefs integerForKey:@"lastSqlFileEncoding"] includeDefaultEntry:NO encodingPopUp:&encodingPopUp]]; [encodingPopUp setEnabled:YES]; [panel beginSheetForDirectory:nil file:[favoriteNameTextField stringValue] modalForWindow:[self window] modalDelegate:self didEndSelector:@selector(savePanelDidEnd:returnCode:contextInfo:) contextInfo:@"saveQuery"]; } - (IBAction)exportFavorites:(id)sender { NSSavePanel *panel = [NSSavePanel savePanel]; [panel setRequiredFileType:DEFAULT_SEQUELPRO_FILE_EXTENSION]; [panel setExtensionHidden:NO]; [panel setAllowsOtherFileTypes:NO]; [panel setCanSelectHiddenExtension:YES]; [panel setCanCreateDirectories:YES]; [panel beginSheetForDirectory:nil file:nil modalForWindow:[self window] modalDelegate:self didEndSelector:@selector(savePanelDidEnd:returnCode:contextInfo:) contextInfo:@"exportFavorites"]; } - (IBAction)importFavoritesByAdding:(id)sender { } - (IBAction)importFavoritesByReplacing:(id)sender { } /** * Closes the query favorite manager */ - (IBAction)closeQueryManagerSheet:(id)sender { // First check for ESC if pressed while inline editing if(![sender tag] && isTableCellEditing) { [favoritesTableView abortEditing]; isTableCellEditing = NO; return; } [NSApp endSheet:[self window] returnCode:0]; [[self window] orderOut:self]; // Save button was pressed if([sender tag]) { // Ensure that last changes will be written to prefs // if only one favorite is selected; otherwise unstable state if ([favoritesTableView numberOfSelectedRows] == 1) { [self _writePendingQueryString]; [[self window] makeFirstResponder:favoritesTableView]; [favoritesTableView selectRowIndexes:[NSIndexSet indexSetWithIndex:selectedRowBeforeChangingSelection] byExtendingSelection:NO]; } // Inform the delegate that the query favorites have been updated if (delegateRespondsToFavoriteUpdates) [delegate queryFavoritesHaveBeenUpdated:self]; } } #pragma mark - #pragma mark SplitView delegate methods /** * Return the maximum possible size of the splitview. */ - (float)splitView:(NSSplitView *)sender constrainMaxCoordinate:(float)proposedMax ofSubviewAt:(int)offset { return (proposedMax - 220); } /** * Return the minimum possible size of the splitview. */ - (float)splitView:(NSSplitView *)sender constrainMinCoordinate:(float)proposedMin ofSubviewAt:(int)offset { return (proposedMin + 120); } #pragma mark - #pragma mark TableView datasource methods /** * Returns the number of query favorites. */ - (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView { return [favorites count]; } /** * Returns the value for the requested table column and row index. */ - (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex { if(![[favorites objectAtIndex:rowIndex] objectForKey:[aTableColumn identifier]]) return @""; return [[favorites objectAtIndex:rowIndex] objectForKey:[aTableColumn identifier]]; } /* * Save favorite names if inline edited (suppress empty names) */ - (void)tableView:(NSTableView *)aTableView setObjectValue:(id)anObject forTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex { if([[aTableColumn identifier] isEqualToString:@"name"] && [anObject length]) { [[favorites objectAtIndex:rowIndex] setObject:[anObject description] forKey:@"name"]; [[favorites objectAtIndex:rowIndex] setObject:[favoriteQueryTextView string] forKey:@"query"]; [favoriteNameTextField setStringValue:[anObject description]]; } [favoritesTableView reloadData]; } /* * Before selecting an other favorite save pending query string changes * and make sure that no group table item can be selected */ - (BOOL)tableView:(NSTableView *)aTableView shouldSelectRow:(NSInteger)rowIndex { [pendingQueryString setString:[favoriteQueryTextView string]]; [self _writePendingQueryString]; return ([[favoriteProperties objectAtIndex:rowIndex] intValue] == SP_FAVORITETYPE_HEADER) ? NO : YES; } /* * Update name and query view and control several table selection modi */ - (void)tableViewSelectionDidChange:(NSNotification *)aNotification { // store the last selected favorite for writing the pending query string // - for a single favorite selection if([favoritesTableView numberOfSelectedRows] == 1) selectedRowBeforeChangingSelection = [favoritesTableView selectedRow]; // - for multiple favorite selection if([favoritesTableView numberOfSelectedRows] > 1) { // Save query string directly if(selectedRowBeforeChangingSelection > 0 && selectedRowBeforeChangingSelection < [favorites count]) [[favorites objectAtIndex:selectedRowBeforeChangingSelection] setObject:[favoriteQueryTextView string] forKey:@"query"]; // Update name text field [[favoriteNameTextField cell] setPlaceholderString:SP_MULTIPLE_SELECTION_PLACEHOLDER_STRING]; [favoriteNameTextField setStringValue:@""]; [favoriteNameTextField setEditable:NO]; [favoriteNameTextField setSelectable:NO]; // This is an "hack"; if one set it to @"" it could happen that // the wrong pending query string will be saved [favoriteQueryTextView setTextColor:[NSColor clearColor]]; [favoriteQueryTextView setEditable:NO]; [favoriteQueryTextView setSelectable:NO]; return; } else { [favoriteNameTextField setEditable:YES]; [favoriteNameTextField setSelectable:YES]; [favoriteQueryTextView setSelectable:YES]; [favoriteQueryTextView setEditable:YES]; } // only the "GLOBAL" header is in the table if([favorites count] < 2) { [self _writePendingQueryString]; [[self window] makeFirstResponder:favoritesTableView]; [[favoriteNameTextField cell] setPlaceholderString:SP_NO_SELECTION_PLACEHOLDER_STRING]; [favoriteNameTextField setStringValue:@""]; [favoriteQueryTextView setString:@""]; [pendingQueryString setString:@""]; selectedRowBeforeChangingSelection = -1; return; } // Update name and query field contents NSUInteger row = (NSUInteger)[[aNotification object] selectedRow]; // This is needed if one deletes the last table item if(row > [favorites count] - 1) row = [favorites count] - 1; if(row < 1) row = 1; [favoriteNameTextField setStringValue:[[favorites objectAtIndex:row] objectForKey:@"name"]]; [favoriteQueryTextView setString:[[favorites objectAtIndex:row] objectForKey:@"query"]]; } /* * Set indention levels for headers and favorites * (maybe in the future use an image for headers for expanding and collapsing) */ - (void)tableView:(NSTableView *)aTableView willDisplayCell:(id)aCell forTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex { if([[favoriteProperties objectAtIndex:rowIndex] intValue] == SP_FAVORITETYPE_HEADER && [[aTableColumn identifier] isEqualToString:@"name"]) { // if([[[favoriteProperties objectAtIndex:rowIndex] objectForKey:@"isGroup"] isEqualToString:@"1"]) // [(ImageAndTextCell*)aCell setImage:[NSImage imageNamed:@"NSRightFacingTriangleTemplate"]]; // else // [(ImageAndTextCell*)aCell setImage:[NSImage imageNamed:@"NSLeftFacingTriangleTemplate"]]; [(ImageAndTextCell*)aCell setIndentationLevel:0]; } else if([[favoriteProperties objectAtIndex:rowIndex] intValue] != SP_FAVORITETYPE_HEADER && [[aTableColumn identifier] isEqualToString:@"name"]) { // [(ImageAndTextCell*)aCell setImage:[NSImage imageNamed:@"dummy-small"]]; [(ImageAndTextCell*)aCell setIndentationLevel:1]; } } /* * A row of an header return is slighlty larger */ - (CGFloat)tableView:(NSTableView *)aTableView heightOfRow:(NSInteger)rowIndex { return ([[favoriteProperties objectAtIndex:rowIndex] intValue] == SP_FAVORITETYPE_HEADER) ? 20 : 18; } /* * Only favorite name can be edited inline */ - (BOOL)tableView:(NSTableView *)aTableView shouldEditTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex { if([[favoriteProperties objectAtIndex:rowIndex] intValue] == SP_FAVORITETYPE_HEADER) { return NO; } else { isTableCellEditing = YES; return YES; } } /* * favoriteProperties holds the data if a table row is a group header or not */ - (BOOL)tableView:(NSTableView *)aTableView isGroupRow:(NSInteger)rowIndex { return ([[favoriteProperties objectAtIndex:rowIndex] intValue] == SP_FAVORITETYPE_HEADER) ? YES : NO; } /* * Detect if inline editing was done - then ESC to close the sheet will be activate */ - (void)controlTextDidEndEditing:(NSNotification *)aNotification { isTableCellEditing = NO; } /* * Changes in the name text field will be saved in data source directly * to update the table view accordingly */ - (void)controlTextDidChange:(NSNotification *)notification { // Do nothing if no favorite is selected if([favoritesTableView selectedRow] < 1) return; id object = [notification object]; if(object == favoriteNameTextField) { [[favorites objectAtIndex:[favoritesTableView selectedRow]] setObject:[favoriteNameTextField stringValue] forKey:@"name"]; [favoritesTableView reloadData]; } } /* * Changes in the query text view will be cached as pending query string which will update * the data source before selecting an other favorite or before an other event. * If multiple rows are selected update name field. */ - (void)textViewDidChangeSelection:(NSNotification *)notification { id object = [notification object]; if(object == favoriteQueryTextView) { if(![favoriteQueryTextView isEditable]) return; [pendingQueryString setString:[NSString stringWithString:[favoriteQueryTextView string]]]; if([favoritesTableView numberOfSelectedRows] > 1) { [[favoriteNameTextField cell] setPlaceholderString:SP_MULTIPLE_SELECTION_PLACEHOLDER_STRING]; [favoriteNameTextField setStringValue:@""]; selectedRowBeforeChangingSelection = -1; return; } } } #pragma mark - #pragma mark Menu validation /** * Menu item validation. */ - (BOOL)validateMenuItem:(NSMenuItem *)menuItem { // Disable all if only GLOBAL is in the table if([favorites count] < 2) return NO; SEL action = [menuItem action]; if ( (action == @selector(copyQueryFavorite:)) || (action == @selector(saveFavoriteToFile:))) { return ([favoritesTableView numberOfSelectedRows] == 1); } else if ( (action == @selector(removeQueryFavorite:)) || ( action == @selector(exportFavorites:))) { return ([favoritesTableView numberOfSelectedRows] > 0); } else if (action == @selector(removeAllQueryFavorites:)) { return ([favorites count] > 0); } return YES; } #pragma mark - #pragma mark TableView drag & drop delegate methods /** * Return whether or not the supplied rows can be written. */ - (BOOL)tableView:(NSTableView *)tableView writeRows:(NSArray *)rows toPasteboard:(NSPasteboard *)pboard { if ([rows count] == 1) { NSArray *pboardTypes = [NSArray arrayWithObject:QUERY_FAVORITES_PB_DRAG_TYPE]; NSInteger originalRow = [[rows objectAtIndex:0] intValue]; [pboard declareTypes:pboardTypes owner:nil]; [pboard setString:[[NSNumber numberWithInt:originalRow] stringValue] forType:QUERY_FAVORITES_PB_DRAG_TYPE]; // Save query string before dragging // and suppress the writing of pending query string changes [[favorites objectAtIndex:selectedRowBeforeChangingSelection] setObject:[favoriteQueryTextView string] forKey:@"query"]; selectedRowBeforeChangingSelection = -1; return YES; } else { [favoritesTableView selectRowIndexes:[NSIndexSet indexSetWithIndex:selectedRowBeforeChangingSelection] byExtendingSelection:NO]; [[favoriteNameTextField cell] setPlaceholderString:SP_MULTIPLE_SELECTION_PLACEHOLDER_STRING]; [favoriteNameTextField setStringValue:@""]; [favoriteQueryTextView setTextColor:[NSColor clearColor]]; } return NO; } /** * Validate the proposed drop of the supplied rows. */ - (NSDragOperation)tableView:(NSTableView *)tableView validateDrop:(id )info proposedRow:(NSInteger)row proposedDropOperation:(NSTableViewDropOperation)operation { NSArray *pboardTypes = [[info draggingPasteboard] types]; if (([pboardTypes count] > 1) && (row != -1)) { if (([pboardTypes containsObject:QUERY_FAVORITES_PB_DRAG_TYPE]) && (operation == NSTableViewDropAbove)) { NSInteger originalRow = [[[info draggingPasteboard] stringForType:QUERY_FAVORITES_PB_DRAG_TYPE] intValue]; if ((row != originalRow) && (row != (originalRow + 1)) && (row > 0)) { return NSDragOperationMove; } } } return NSDragOperationNone; } /** * Return whether or not to accept the drop of the supplied rows. */ - (BOOL)tableView:(NSTableView *)tableView acceptDrop:(id )info row:(NSInteger)row dropOperation:(NSTableViewDropOperation)operation { NSInteger originalRow = [[[info draggingPasteboard] stringForType:QUERY_FAVORITES_PB_DRAG_TYPE] intValue]; NSInteger destinationRow = row; if (destinationRow > originalRow) destinationRow--; NSMutableDictionary *draggedRow = [NSMutableDictionary dictionaryWithDictionary:[favorites objectAtIndex:originalRow]]; [favorites removeObjectAtIndex:originalRow]; [favorites insertObject:draggedRow atIndex:destinationRow]; [favoritesTableView reloadData]; [favoritesTableView selectRowIndexes:[NSIndexSet indexSetWithIndex:destinationRow] byExtendingSelection:NO]; return YES; } #pragma mark - #pragma mark Other /** * Sheet did end method */ - (void)sheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(NSString *)contextInfo { // Is disabled - do we need that? // if ([contextInfo isEqualToString:@"removeAllFavorites"]) { // if (returnCode == NSAlertAlternateReturn) { // [favorites removeObjects:[queryFavoritesController arrangedObjects]]; // } // } if([contextInfo isEqualToString:@"removeSelectedFavorites"]) { if (returnCode == NSAlertAlternateReturn) { NSIndexSet *indexes = [favoritesTableView selectedRowIndexes]; // get last index NSUInteger currentIndex = [indexes lastIndex]; NSUInteger idx = currentIndex; // Prevend to write pending changes selectedRowBeforeChangingSelection = -1; [pendingQueryString setString:@""]; while (currentIndex != NSNotFound) { [favorites removeObjectAtIndex:currentIndex]; [favoriteProperties removeObjectAtIndex:currentIndex]; // get next index (beginning from the end) currentIndex = [indexes indexLessThanIndex:currentIndex]; [favoritesTableView reloadData]; } // Set focus to favorite list to avoid an unstable state [[self window] makeFirstResponder:favoritesTableView]; // Try to reselect a favorite [favoritesTableView selectRowIndexes:[NSIndexSet indexSet] byExtendingSelection:NO]; if(idx > [favorites count]-1) idx = [favorites count]-1; if(idx != 0) [favoritesTableView selectRowIndexes:[NSIndexSet indexSetWithIndex:idx] byExtendingSelection:NO]; if(idx > 1) { [favoriteNameTextField setStringValue:[[favorites objectAtIndex:idx] objectForKey:@"name"]]; [favoriteQueryTextView setString:[[favorites objectAtIndex:idx] objectForKey:@"query"]]; } [removeButton setEnabled:([favorites count] > 1)]; } } } /** * Save panel did end method. */ - (void)savePanelDidEnd:(NSSavePanel *)panel returnCode:(int)returnCode contextInfo:(NSString *)contextInfo { if([contextInfo isEqualToString:@"saveQuery"]) { if (returnCode == NSOKButton) { NSError *error = nil; [prefs setInteger:[[encodingPopUp selectedItem] tag] forKey:@"lastSqlFileEncoding"]; [prefs synchronize]; [[favoriteQueryTextView string] writeToFile:[panel filename] atomically:YES encoding:[[encodingPopUp selectedItem] tag] error:&error]; if (error) [[NSAlert alertWithError:error] runModal]; } } else if([contextInfo isEqualToString:@"exportFavorites"]) { if (returnCode == NSOKButton) { // Build a SPF with format = "query favorites" NSMutableDictionary *spfdata = [NSMutableDictionary dictionary]; NSMutableArray *favoriteData = [NSMutableArray array]; NSMutableDictionary *data = [NSMutableDictionary dictionary]; [spfdata setObject:[NSNumber numberWithInt:1] forKey:@"version"]; [spfdata setObject:@"query favorites" forKey:@"format"]; [spfdata setObject:[NSNumber numberWithBool:NO] forKey:@"encrypted"]; NSIndexSet *indexes = [favoritesTableView selectedRowIndexes]; // Get selected items and preserve the order NSUInteger i; for (i=1; i<[favorites count]; i++) if([indexes containsIndex:i]) [favoriteData addObject:[favorites objectAtIndex:i]]; [data setObject:favoriteData forKey:@"queryFavorites"]; [spfdata setObject:data forKey:@"data"]; NSString *err = nil; NSData *plist = [NSPropertyListSerialization dataFromPropertyList:spfdata format:NSPropertyListXMLFormat_v1_0 errorDescription:&err]; if(err != nil) { NSAlert *alert = [NSAlert alertWithMessageText:[NSString stringWithFormat:NSLocalizedString(@"Error while converting query favorite data", @"error while converting query favorite data")] defaultButton:NSLocalizedString(@"OK", @"OK button") alternateButton:nil otherButton:nil informativeTextWithFormat:err]; [alert setAlertStyle:NSCriticalAlertStyle]; [alert runModal]; return; } NSError *error = nil; [plist writeToFile:[panel filename] options:NSAtomicWrite error:&error]; if (error) [[NSAlert alertWithError:error] runModal]; } } } /* * Before an other favorite will be chosen or an other event will unfocus the * query text view store the query into the data source */ - (void)_writePendingQueryString { if(selectedRowBeforeChangingSelection > 0 && selectedRowBeforeChangingSelection < [favorites count] ) { [[favorites objectAtIndex:selectedRowBeforeChangingSelection] setObject:[NSString stringWithString:pendingQueryString] forKey:@"query"]; } else if(selectedRowBeforeChangingSelection = 0) { [[favorites objectAtIndex:[favoritesTableView selectedRow]] setObject:[NSString stringWithString:pendingQueryString] forKey:@"query"]; } [pendingQueryString setString:@""]; } @end