diff options
author | rowanbeentje <rowan@beent.je> | 2009-07-28 01:02:40 +0000 |
---|---|---|
committer | rowanbeentje <rowan@beent.je> | 2009-07-28 01:02:40 +0000 |
commit | 9c06d1219c66acc043b5f13ab29379f60eb00350 (patch) | |
tree | 57f6a57ad8a10552eb22a372fdbf297522d39d65 /Source | |
parent | 9b827edbb16a50f3e0c42e0f1c21a9bca3e7a77b (diff) | |
download | sequelpro-9c06d1219c66acc043b5f13ab29379f60eb00350.tar.gz sequelpro-9c06d1219c66acc043b5f13ab29379f60eb00350.tar.bz2 sequelpro-9c06d1219c66acc043b5f13ab29379f60eb00350.zip |
Improve TablesList significantly:
- If there are twenty or more tables, show a table quicksearch/filter at the top of the list, and update the rest of the code to match. This addresses issue #178.
- Select tables and views alphabetically by user's current locale (instead of default MySQL "A B C a b c")
- When adding or duplicating tables, insert them at the correct point
- Fix a number of minor display bugs caused by incorrect interaction with the tables list caches
Diffstat (limited to 'Source')
-rw-r--r-- | Source/NSMutableArray-MultipleSort.h | 54 | ||||
-rw-r--r-- | Source/NSMutableArray-MultipleSort.m | 77 | ||||
-rw-r--r-- | Source/TableDocument.m | 1 | ||||
-rw-r--r-- | Source/TableDump.h | 1 | ||||
-rw-r--r-- | Source/TableDump.m | 9 | ||||
-rw-r--r-- | Source/TableSource.m | 9 | ||||
-rw-r--r-- | Source/TablesList.h | 20 | ||||
-rw-r--r-- | Source/TablesList.m | 1017 |
8 files changed, 813 insertions, 375 deletions
diff --git a/Source/NSMutableArray-MultipleSort.h b/Source/NSMutableArray-MultipleSort.h new file mode 100644 index 00000000..91c8f3f2 --- /dev/null +++ b/Source/NSMutableArray-MultipleSort.h @@ -0,0 +1,54 @@ +// +// NSMutableArray-MultipleSort.h +// iContractor +// +// Created by Jeff LaMarche on 1/16/09. +// Copyright 2009 Jeff LaMarche. All rights reserved. +// + +// This category on NSMutableArray implements a shell sort based on the old NeXT example +// SortingInAction. It is functionally identical to sortArrayUsingSelector: except that +// it will sort other paired arrays based on the comparison values of the original array +// this is for use in paired array situations, such as when you use one array to store +// keys and another array to store values. This is a variadic method, so you can sort +// as many paired arrays as you have. + +// This source may be used, free of charge, for any purposes. commercial or non- +// commercial. There is no attribution requirement, nor any need to distribute +// your source code. If you do redistribute the source code, you must +// leave the original header comments, but you may add additional ones. + + +// Stride factor defines the size of the shell sort loop's stride. It can be tweaked +// for performance, though 3 seems to be a good general purpose value +#define STRIDE_FACTOR 3 + +#import <Foundation/Foundation.h> + +// This compare method was taken from the GNUStep project. GNUStep is +// licensed under the LGPL, which allows such use. +static inline NSComparisonResult compare(id elem1, id elem2, void* context) +{ + NSComparisonResult (*imp)(id, SEL, id); + + if (context == 0) { + [NSException raise: NSInvalidArgumentException + format: @"compare null selector given"]; + } + + imp = (NSComparisonResult (*)(id, SEL, id)) + [elem1 methodForSelector: context]; + + if (imp == NULL) { + [NSException raise: NSGenericException + format: @"invalid selector passed to compare"]; + } + + return (*imp)(elem1, context, elem2); +} + +@interface NSMutableArray(MultipleSort) + +// Takes a comparator and a nil-terminated list of paired arrays +- (void)sortArrayUsingSelector:(SEL)comparator withPairedMutableArrays:(NSMutableArray *)array1, ...; +@end diff --git a/Source/NSMutableArray-MultipleSort.m b/Source/NSMutableArray-MultipleSort.m new file mode 100644 index 00000000..f98732b7 --- /dev/null +++ b/Source/NSMutableArray-MultipleSort.m @@ -0,0 +1,77 @@ +// +// NSMutableArray-MultipleSort.m +// iContractor +// +// Created by Jeff LaMarche on 1/16/09. +// Copyright 2009 Jeff LaMarche Consulting. All rights reserved. +// +// This source may be used, free of charge, for any purposes. commercial or non- +// commercial. There is no attribution requirement, nor any need to distribute +// your source code. If you do redistribute the source code, you must +// leave the original header comments, but you may add additional ones. + +#import "NSMutableArray-MultipleSort.h" + +@implementation NSMutableArray(MultipleSort) +- (void)sortArrayUsingSelector:(SEL)comparator withPairedMutableArrays:(NSMutableArray *)array1, ... +{ + unsigned int stride = 1; + BOOL found = NO; + unsigned int count = [self count]; + unsigned int d; + + while (stride <= count) + stride = stride * STRIDE_FACTOR + 1; + + while (stride > (STRIDE_FACTOR - 1)) { + stride = stride / STRIDE_FACTOR; + for (unsigned int c = stride; c < count; c++) { + found = NO; + if (stride > c) break; + + d = c - stride; + while (!found) { + id a = [self objectAtIndex: d + stride]; + id b = [self objectAtIndex: d]; + + NSComparisonResult result = (*compare)(a, b, (void *)comparator); + + if (result < 0) { + [a retain]; + [self replaceObjectAtIndex: d + stride withObject: b]; + [self replaceObjectAtIndex: d withObject: a]; + + id eachObject; + va_list argumentList; + if (array1) { + id a1 = [array1 objectAtIndex:d+stride]; + id b1 = [array1 objectAtIndex:d]; + [a1 retain]; + [array1 replaceObjectAtIndex: d + stride withObject:b1]; + [array1 replaceObjectAtIndex: d withObject: a1]; + [a1 release]; + va_start(argumentList, array1); + while (eachObject = va_arg(argumentList, id)) { + id ax = [eachObject objectAtIndex:d+stride]; + id bx = [eachObject objectAtIndex:d]; + [ax retain]; + [eachObject replaceObjectAtIndex: d + stride withObject:bx]; + [eachObject replaceObjectAtIndex: d withObject: ax]; + [ax release]; + } + va_end(argumentList); + } + + [a release]; + + if (stride > d) + break; + + d -= stride; + } else + found = YES; + } + } + } +} +@end
\ No newline at end of file diff --git a/Source/TableDocument.m b/Source/TableDocument.m index 7970d0aa..07b6b42b 100644 --- a/Source/TableDocument.m +++ b/Source/TableDocument.m @@ -116,7 +116,6 @@ // Hide the tabs in the tab view (we only show them to allow switching tabs in interface builder) [tableTabView setTabViewType:NSNoTabsNoBorder]; - [tableListSplitter setDividerStyle:NSSplitViewDividerStyleThin]; // Add the icon accessory view to the title bar NSView *windowFrame = [[tableWindow contentView] superview]; diff --git a/Source/TableDump.h b/Source/TableDump.h index e0ee2c59..bb4c0284 100644 --- a/Source/TableDump.h +++ b/Source/TableDump.h @@ -37,7 +37,6 @@ IBOutlet id customQueryInstance; IBOutlet id tableWindow; - IBOutlet id tableListView; IBOutlet id exportDumpView; IBOutlet id exportCSVView; diff --git a/Source/TableDump.m b/Source/TableDump.m index 3edf0619..34ffe262 100644 --- a/Source/TableDump.m +++ b/Source/TableDump.m @@ -379,8 +379,8 @@ } - (IBAction)changeTable:(id)sender -{ - [tableListView selectRowIndexes:[NSIndexSet indexSetWithIndex:[[tablesListInstance tables] indexOfObject:[fieldMappingPopup titleOfSelectedItem]]] byExtendingSelection:NO]; +{ + [tablesListInstance selectTableOrViewWithName:[fieldMappingPopup titleOfSelectedItem]]; //set up tableView currentRow = 0; @@ -603,12 +603,9 @@ [fieldMappingPopup selectItemAtIndex:0]; } - int indexOfFirstTable = [[tablesListInstance tables] indexOfObject:[fieldMappingPopup titleOfSelectedItem]]; - - if( indexOfFirstTable == NSNotFound ){ + if( ![tablesListInstance selectTableOrViewWithName:[fieldMappingPopup titleOfSelectedItem]] ) { [errors appendString:[NSString stringWithFormat:NSLocalizedString(@"[ERROR] %@\n", @"error text when trying to import csv data, but we have no tables in the db"), @"Can't import CSV data into a database without any tables!"]]; } else { - [tableListView selectRowIndexes:[NSIndexSet indexSetWithIndex:indexOfFirstTable] byExtendingSelection:NO]; //set up tableView currentRow = 0; diff --git a/Source/TableSource.m b/Source/TableSource.m index 7fb0cdfd..48d1d75d 100644 --- a/Source/TableSource.m +++ b/Source/TableSource.m @@ -49,7 +49,12 @@ loads aTable, put it in an array, update the tableViewColumns and reload the tab // Check whether a save of the current row is required. if ( ![self saveRowOnDeselect] ) return; - selectedTable = aTable; + if (selectedTable) [selectedTable release]; + if (aTable == nil) { + selectedTable = nil; + } else { + selectedTable = [[NSString alloc] initWithString:aTable]; + } [tableSourceView deselectAll:self]; [indexView deselectAll:self]; @@ -1342,6 +1347,7 @@ traps enter and esc and make/cancel editing without entering next row currentlyEditingRow = -1; defaultValues = nil; + selectedTable = nil; prefs = [NSUserDefaults standardUserDefaults]; } @@ -1363,6 +1369,7 @@ traps enter and esc and make/cancel editing without entering next row [oldRow release]; [enumFields release]; if (defaultValues) [defaultValues release]; + if (selectedTable) [selectedTable release]; [super dealloc]; } diff --git a/Source/TablesList.h b/Source/TablesList.h index 6210f9e7..68578010 100644 --- a/Source/TablesList.h +++ b/Source/TablesList.h @@ -40,6 +40,7 @@ enum sp_table_types @interface NSObject (NSSplitView) - (NSView *)collapsibleSubview; - (IBAction)toggleCollapse:(id)sender; +- (BOOL)collapsibleSubviewIsCollapsed; - (void)setCollapsibleSubviewCollapsed:(BOOL)flag; @end @@ -74,8 +75,11 @@ enum sp_table_types IBOutlet id truncateTableButton; IBOutlet id truncateTableContextButton; IBOutlet NSSplitView *tableListSplitView; + IBOutlet NSSplitView *tableListFilterSplitView; IBOutlet NSButton *tableInfoCollapseButton; - + + IBOutlet NSSearchField *listFilterField; + IBOutlet NSMenuItem *removeTableMenuItem; IBOutlet NSMenuItem *duplicateTableMenuItem; IBOutlet NSMenuItem *renameTableMenuItem; @@ -89,7 +93,13 @@ enum sp_table_types IBOutlet NSMenuItem *separatorTableContextMenuItem; NSMutableArray *tables; + NSMutableArray *filteredTables; NSMutableArray *tableTypes; + NSMutableArray *filteredTableTypes; + int selectedTableType; + NSString *selectedTableName; + BOOL isTableListFiltered; + BOOL tableListContainsViews; BOOL structureLoaded, contentLoaded, statusLoaded, alertSheetOpened; } @@ -112,6 +122,7 @@ enum sp_table_types - (void)setConnection:(MCPConnection *)theConnection; - (void)truncateTable; - (void)doPerformQueryService:(NSString *)query; +- (void)updateSelection; // Getters - (NSString *)tableName; @@ -133,4 +144,11 @@ enum sp_table_types - (void)setStatusRequiresReload:(BOOL)reload; - (BOOL)selectTableOrViewWithName:(NSString *)theName; +// Table list filter interaction +- (void) showFilter; +- (void) hideFilter; +- (void) clearFilter; +- (IBAction) updateFilter:(id)sender; +- (void) selectTableAtIndex:(NSNumber *)rowIndex; + @end diff --git a/Source/TablesList.m b/Source/TablesList.m index a8781128..35240e46 100644 --- a/Source/TablesList.m +++ b/Source/TablesList.m @@ -34,6 +34,7 @@ #import "SPArrayAdditions.h" #import "RegexKitLite.h" #import "SPDatabaseData.h" +#import "NSMutableArray-MultipleSort.h" @implementation TablesList @@ -47,20 +48,24 @@ MCPResult *theResult; NSArray *resultRow; int i; - BOOL containsViews = NO; - NSString *selectedTable = nil; + NSString *previousSelectedTable = nil; NSInteger selectedRowIndex; selectedRowIndex = [tablesListView selectedRow]; - if(selectedRowIndex > 0 && [tables count] && selectedRowIndex < [tables count]){ - selectedTable = [NSString stringWithString:[tables objectAtIndex:selectedRowIndex]]; + if (selectedTableName) previousSelectedTable = [[NSString alloc] initWithString:selectedTableName]; + if (isTableListFiltered) { + if (filteredTables) [filteredTables release]; + filteredTables = tables; + if (filteredTableTypes) [filteredTableTypes release]; + filteredTableTypes = tableTypes; + isTableListFiltered = NO; } + tableListContainsViews = NO; [tablesListView deselectAll:self]; [tables removeAllObjects]; [tableTypes removeAllObjects]; - [tableTypes addObject:[NSNumber numberWithInt:SP_TABLETYPE_NONE]]; if ([tableDocumentInstance database]) { @@ -82,12 +87,15 @@ [tables addObject:[resultRow objectAtIndex:0]]; if ([[resultRow objectAtIndex:1] isEqualToString:@"VIEW"]) { [tableTypes addObject:[NSNumber numberWithInt:SP_TABLETYPE_VIEW]]; - containsViews = YES; + tableListContainsViews = YES; } else { [tableTypes addObject:[NSNumber numberWithInt:SP_TABLETYPE_TABLE]]; } } } + + // Reorder the tables in alphabetical order + [tables sortArrayUsingSelector:@selector(localizedCompare:) withPairedMutableArrays:tableTypes, nil]; /* grab the procedures and functions * @@ -118,7 +126,7 @@ [tables addObject:NSArrayObjectAtIndex(resultRow, 3)]; if( [NSArrayObjectAtIndex(resultRow, 4) isEqualToString:@"PROCEDURE"] ) { [tableTypes addObject:[NSNumber numberWithInt:SP_TABLETYPE_PROC]]; - } else { + } else { [tableTypes addObject:[NSNumber numberWithInt:SP_TABLETYPE_FUNC]]; } } @@ -180,17 +188,38 @@ [[NSNotificationCenter defaultCenter] postNotificationName:@"SMySQLQueryHasBeenPerformed" object:self]; } - if (containsViews) { + // Add the table headers even if no tables were found + if (tableListContainsViews) { [tables insertObject:NSLocalizedString(@"TABLES & VIEWS",@"header for table & views list") atIndex:0]; } else { [tables insertObject:NSLocalizedString(@"TABLES",@"header for table list") atIndex:0]; } + [tableTypes insertObject:[NSNumber numberWithInt:SP_TABLETYPE_NONE] atIndex:0]; [tablesListView reloadData]; // if the previous selected table still exists, select it - if( selectedTable != nil && [tables indexOfObject:selectedTable] < [tables count]) { - [tablesListView selectRowIndexes:[NSIndexSet indexSetWithIndex:[tables indexOfObject:selectedTable]] byExtendingSelection:NO]; + if( previousSelectedTable != nil && [tables indexOfObject:previousSelectedTable] < [tables count]) { + int itemToReselect = [tables indexOfObject:previousSelectedTable]; + [tablesListView selectRowIndexes:[NSIndexSet indexSetWithIndex:itemToReselect] byExtendingSelection:NO]; + if (selectedTableName) [selectedTableName release]; + selectedTableName = [[NSString alloc] initWithString:[tables objectAtIndex:itemToReselect]]; + selectedTableType = [[tableTypes objectAtIndex:itemToReselect] intValue]; + } else { + selectedTableName = nil; + selectedTableType = SP_TABLETYPE_NONE; + } + + // Determine whether or not to show the list filter based on the number of tables, and clear it + [self clearFilter]; + if ([tables count] > 20) [self showFilter]; + else [self hideFilter]; + + // Set the filter placeholder text + if ([tableDocumentInstance database]) { + if ([theResult numOfRows]) [[listFilterField cell] setPlaceholderString:NSLocalizedString(@"Filter tables, views, procs & funcs", @"Filter placeholder when all tables types are present")]; + else if (tableListContainsViews) [[listFilterField cell] setPlaceholderString:NSLocalizedString(@"Filter tables and views", @"Filter placeholder when tables and views are present")]; + else [[listFilterField cell] setPlaceholderString:NSLocalizedString(@"Filter the list of tables", @"Filter placeholder when only tables are present")]; } } @@ -254,11 +283,35 @@ [mySQLConnection queryString:createStatement]; if ([[mySQLConnection getLastErrorMessage] isEqualToString:@""]) { - // Table creation was successful - [tables insertObject:tableName atIndex:1]; - [tableTypes insertObject:[NSNumber numberWithInt:SP_TABLETYPE_TABLE] atIndex:1]; - [tablesListView reloadData]; - [tablesListView selectRow:1 byExtendingSelection:NO]; + + // Table creation was successful - insert the new item into the tables list and select it. + int addItemAtIndex = NSNotFound; + for (int i = 0; i < [tables count]; i++) { + int tableType = [[tableTypes objectAtIndex:i] intValue]; + if (tableType == SP_TABLETYPE_NONE) continue; + if (tableType == SP_TABLETYPE_PROC || tableType == SP_TABLETYPE_FUNC) { + addItemAtIndex = i - 1; + break; + } + if ([tableName localizedCompare:[tables objectAtIndex:i]] == NSOrderedAscending) { + addItemAtIndex = i; + break; + } + } + if (addItemAtIndex == NSNotFound) { + [tables addObject:tableName]; + [tableTypes addObject:[NSNumber numberWithInt:SP_TABLETYPE_TABLE]]; + } else { + [tables insertObject:tableName atIndex:addItemAtIndex]; + [tableTypes insertObject:[NSNumber numberWithInt:SP_TABLETYPE_TABLE] atIndex:addItemAtIndex]; + } + + // Set the selected table name and type, and then use updateFilter to update the filter list and selection. + if (selectedTableName) [selectedTableName release]; + selectedTableName = [[NSString alloc] initWithString:tableName]; + selectedTableType = SP_TABLETYPE_TABLE; + [self updateFilter:self]; + [tablesListView scrollRowToVisible:[tablesListView selectedRow]]; NSInteger selectedIndex = [tabView indexOfTabViewItem:[tabView selectedTabViewItem]]; @@ -299,8 +352,6 @@ [NSString stringWithFormat:NSLocalizedString(@"Couldn't add table %@.\nMySQL said: %@", @"message of panel when table cannot be created with the given name"), tableName, [mySQLConnection getLastErrorMessage]]); - [tableTypes removeObjectAtIndex:([tableTypes count] - 1)]; - [tables removeObjectAtIndex:([tables count] - 1)]; [tablesListView reloadData]; } @@ -342,25 +393,25 @@ unsigned currentIndex = [indexes lastIndex]; if ([tablesListView numberOfSelectedRows] == 1) { - if([[tableTypes objectAtIndex:currentIndex] intValue] == SP_TABLETYPE_VIEW) + if([[filteredTableTypes objectAtIndex:currentIndex] intValue] == SP_TABLETYPE_VIEW) tblTypes = NSLocalizedString(@"view", @"view"); - else if([[tableTypes objectAtIndex:currentIndex] intValue] == SP_TABLETYPE_TABLE) + else if([[filteredTableTypes objectAtIndex:currentIndex] intValue] == SP_TABLETYPE_TABLE) tblTypes = NSLocalizedString(@"table", @"table"); - else if([[tableTypes objectAtIndex:currentIndex] intValue] == SP_TABLETYPE_PROC) + else if([[filteredTableTypes objectAtIndex:currentIndex] intValue] == SP_TABLETYPE_PROC) tblTypes = NSLocalizedString(@"procedure", @"procedure"); - else if([[tableTypes objectAtIndex:currentIndex] intValue] == SP_TABLETYPE_FUNC) + else if([[filteredTableTypes objectAtIndex:currentIndex] intValue] == SP_TABLETYPE_FUNC) tblTypes = NSLocalizedString(@"function", @"function"); - [alert setMessageText:[NSString stringWithFormat:NSLocalizedString(@"Delete %@ '%@'?", @"delete table/view message"), tblTypes, [tables objectAtIndex:[tablesListView selectedRow]]]]; - [alert setInformativeText:[NSString stringWithFormat:NSLocalizedString(@"Are you sure you want to delete the %@ '%@'. This operation cannot be undone.", @"delete table/view informative message"), tblTypes, [tables objectAtIndex:[tablesListView selectedRow]]]]; + [alert setMessageText:[NSString stringWithFormat:NSLocalizedString(@"Delete %@ '%@'?", @"delete table/view message"), tblTypes, [filteredTables objectAtIndex:[tablesListView selectedRow]]]]; + [alert setInformativeText:[NSString stringWithFormat:NSLocalizedString(@"Are you sure you want to delete the %@ '%@'. This operation cannot be undone.", @"delete table/view informative message"), tblTypes, [filteredTables objectAtIndex:[tablesListView selectedRow]]]]; } else { BOOL areTableTypeEqual = YES; - int lastType = [[tableTypes objectAtIndex:currentIndex] intValue]; + int lastType = [[filteredTableTypes objectAtIndex:currentIndex] intValue]; while (currentIndex != NSNotFound) { - if([[tableTypes objectAtIndex:currentIndex] intValue]!=lastType) + if([[filteredTableTypes objectAtIndex:currentIndex] intValue]!=lastType) { areTableTypeEqual = NO; break; @@ -415,7 +466,7 @@ [tableWindow endEditingFor:nil]; // Detect table type: table or view - tblType = [[tableTypes objectAtIndex:[tablesListView selectedRow]] intValue]; + tblType = [[filteredTableTypes objectAtIndex:[tablesListView selectedRow]] intValue]; switch (tblType){ case SP_TABLETYPE_TABLE: @@ -439,7 +490,7 @@ [copyTableMessageField setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Duplicate %@ '%@' to:", @"duplicate object message"), tableType, [self tableName]]]; //open copyTableSheet - [copyTableNameField setStringValue:[NSString stringWithFormat:@"%@_copy", [tables objectAtIndex:[tablesListView selectedRow]]]]; + [copyTableNameField setStringValue:[NSString stringWithFormat:@"%@_copy", [filteredTables objectAtIndex:[tablesListView selectedRow]]]]; [copyTableContentSwitch setState:NSOffState]; [NSApp beginSheet:copyTableSheet @@ -463,7 +514,7 @@ //get table/view structure queryResult = [mySQLConnection queryString:[NSString stringWithFormat:@"SHOW CREATE %@ %@", [tableType uppercaseString], - [[tables objectAtIndex:[tablesListView selectedRow]] backtickQuotedString] + [[filteredTables objectAtIndex:[tablesListView selectedRow]] backtickQuotedString] ]]; if ( ![queryResult numOfRows] ) { @@ -492,10 +543,10 @@ { // get the create syntax MCPResult *theResult; - if([self tableType] == SP_TABLETYPE_PROC) - theResult = [mySQLConnection queryString:[NSString stringWithFormat:@"SHOW CREATE PROCEDURE %@", [[tables objectAtIndex:[tablesListView selectedRow]] backtickQuotedString]]]; + if(selectedTableType == SP_TABLETYPE_PROC) + theResult = [mySQLConnection queryString:[NSString stringWithFormat:@"SHOW CREATE PROCEDURE %@", [selectedTableName backtickQuotedString]]]; else if([self tableType] == SP_TABLETYPE_FUNC) - theResult = [mySQLConnection queryString:[NSString stringWithFormat:@"SHOW CREATE FUNCTION %@", [[tables objectAtIndex:[tablesListView selectedRow]] backtickQuotedString]]]; + theResult = [mySQLConnection queryString:[NSString stringWithFormat:@"SHOW CREATE FUNCTION %@", [selectedTableName backtickQuotedString]]]; else return; @@ -503,7 +554,7 @@ if (![[mySQLConnection getLastErrorMessage] isEqualToString:@""]) { if ([mySQLConnection isConnected]) { NSBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, tableWindow, self, nil, nil, nil, - [NSString stringWithFormat:NSLocalizedString(@"An error occured while retrieving the create syntax for '%@'.\nMySQL said: %@", @"message of panel when create syntax cannot be retrieved"), [tables objectAtIndex:[tablesListView selectedRow]], [mySQLConnection getLastErrorMessage]]); + [NSString stringWithFormat:NSLocalizedString(@"An error occured while retrieving the create syntax for '%@'.\nMySQL said: %@", @"message of panel when create syntax cannot be retrieved"), selectedTableName, [mySQLConnection getLastErrorMessage]]); } return; } @@ -535,7 +586,7 @@ [mySQLConnection queryString:[NSString stringWithFormat: @"INSERT INTO %@ SELECT * FROM %@", [[copyTableNameField stringValue] backtickQuotedString], - [[tables objectAtIndex:[tablesListView selectedRow]] backtickQuotedString] + [selectedTableName backtickQuotedString] ]]; if ( ![[mySQLConnection getLastErrorMessage] isEqualToString:@""] ) { @@ -553,13 +604,41 @@ ); } } + + // Insert the new item into the tables list and select it. + int addItemAtIndex = NSNotFound; + for (int i = 0; i < [tables count]; i++) { + int tableType = [[tableTypes objectAtIndex:i] intValue]; + if (tableType == SP_TABLETYPE_NONE) continue; + if ((tableType == SP_TABLETYPE_VIEW || tableType == SP_TABLETYPE_TABLE) + && (tblType == SP_TABLETYPE_PROC || tblType == SP_TABLETYPE_FUNC)) { + continue; + } + if ((tableType == SP_TABLETYPE_PROC || tableType == SP_TABLETYPE_FUNC) + && (tblType == SP_TABLETYPE_VIEW || tblType == SP_TABLETYPE_TABLE)) { + addItemAtIndex = i - 1; + break; + } + if ([[copyTableNameField stringValue] localizedCompare:[tables objectAtIndex:i]] == NSOrderedAscending) { + addItemAtIndex = i; + break; + } + } + if (addItemAtIndex == NSNotFound) { + [tables addObject:[copyTableNameField stringValue]]; + [tableTypes addObject:[NSNumber numberWithInt:tblType]]; + } else { + [tables insertObject:[copyTableNameField stringValue] atIndex:addItemAtIndex]; + [tableTypes insertObject:[NSNumber numberWithInt:tblType] atIndex:addItemAtIndex]; + } - [tables insertObject:[copyTableNameField stringValue] atIndex:[tablesListView selectedRow]+1]; - [tableTypes insertObject:[NSNumber numberWithInt:tblType] atIndex:[tablesListView selectedRow]+1]; - [tablesListView selectRow:[tablesListView selectedRow]+1 byExtendingSelection:NO]; - [self updateTables:self]; + // Set the selected table name and type, and use updateFilter to update the filter list and selection + if (selectedTableName) [selectedTableName release]; + selectedTableName = [[NSString alloc] initWithString:[copyTableNameField stringValue]]; + selectedTableType = tblType; + [self updateFilter:self]; + [self updateSelection]; [tablesListView scrollRowToVisible:[tablesListView selectedRow]]; - } } } @@ -622,9 +701,14 @@ } else { // If there was no error, rename the table in our list and reload the table view's data - [tables replaceObjectAtIndex:[tablesListView selectedRow] withObject:[tableRenameField stringValue]]; - + if (isTableListFiltered) { + [tables replaceObjectAtIndex:[tables indexOfObject:[self tableName]] withObject:[tableRenameField stringValue]]; + } + [filteredTables replaceObjectAtIndex:[tablesListView selectedRow] withObject:[tableRenameField stringValue]]; + if (selectedTableName) [selectedTableName release]; + selectedTableName = [[NSString alloc] initWithString:[tableRenameField stringValue]]; [tablesListView reloadData]; + [self updateSelection]; } } else { // procedures and functions can only be renamed if one creates the new one and delete the old one @@ -664,11 +748,18 @@ NSBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, tableWindow, self, nil, nil, nil, [NSString stringWithFormat:NSLocalizedString(@"Couldn't rename '%@'.\nMySQL said: %@", @"message of panel when an item cannot be renamed"), [self tableName], [mySQLConnection getLastErrorMessage]]); } else { - [tables replaceObjectAtIndex:[tablesListView selectedRow] withObject:[tableRenameField stringValue]]; + if (isTableListFiltered) { + [tables replaceObjectAtIndex:[tables indexOfObject:[self tableName]] withObject:[tableRenameField stringValue]]; + } + [filteredTables replaceObjectAtIndex:[tablesListView selectedRow] withObject:[tableRenameField stringValue]]; + if (selectedTableName) [selectedTableName release]; + selectedTableName = [[NSString alloc] initWithString:[tableRenameField stringValue]]; [tablesListView reloadData]; + [self updateSelection]; } } - // set window title + + // Set window title [tableWindow setTitle:[NSString stringWithFormat:@"(MySQL %@) %@/%@/%@", [tableDocumentInstance mySQLVersion], [tableDocumentInstance name], [tableDocumentInstance database], [tableRenameField stringValue]]]; } @@ -694,8 +785,8 @@ [[buttons objectAtIndex:1] setKeyEquivalent:@"\r"]; if ([tablesListView numberOfSelectedRows] == 1) { - [alert setMessageText:[NSString stringWithFormat:NSLocalizedString(@"Truncate table '%@'?", @"truncate table message"), [tables objectAtIndex:[tablesListView selectedRow]]]]; - [alert setInformativeText:[NSString stringWithFormat:NSLocalizedString(@"Are you sure you want to delete ALL records in the table '%@'. This operation cannot be undone.", @"truncate table informative message"), [tables objectAtIndex:[tablesListView selectedRow]]]]; + [alert setMessageText:[NSString stringWithFormat:NSLocalizedString(@"Truncate table '%@'?", @"truncate table message"), [filteredTables objectAtIndex:[tablesListView selectedRow]]]]; + [alert setInformativeText:[NSString stringWithFormat:NSLocalizedString(@"Are you sure you want to delete ALL records in the table '%@'. This operation cannot be undone.", @"truncate table informative message"), [filteredTables objectAtIndex:[tablesListView selectedRow]]]]; } else { [alert setMessageText:NSLocalizedString(@"Truncate selected tables?", @"truncate tables message")]; @@ -764,28 +855,33 @@ while (currentIndex != NSNotFound) { - if([[tableTypes objectAtIndex:currentIndex] intValue] == SP_TABLETYPE_VIEW) { + if([[filteredTableTypes objectAtIndex:currentIndex] intValue] == SP_TABLETYPE_VIEW) { [mySQLConnection queryString: [NSString stringWithFormat: @"DROP VIEW %@", - [[tables objectAtIndex:currentIndex] backtickQuotedString] + [[filteredTables objectAtIndex:currentIndex] backtickQuotedString] ]]; - } else if([[tableTypes objectAtIndex:currentIndex] intValue] == SP_TABLETYPE_TABLE) { + } else if([[filteredTableTypes objectAtIndex:currentIndex] intValue] == SP_TABLETYPE_TABLE) { [mySQLConnection queryString: [NSString stringWithFormat: @"DROP TABLE %@", - [[tables objectAtIndex:currentIndex] backtickQuotedString] + [[filteredTables objectAtIndex:currentIndex] backtickQuotedString] ]]; - } else if([[tableTypes objectAtIndex:currentIndex] intValue] == SP_TABLETYPE_PROC) { + } else if([[filteredTableTypes objectAtIndex:currentIndex] intValue] == SP_TABLETYPE_PROC) { [mySQLConnection queryString: [NSString stringWithFormat: @"DROP PROCEDURE %@", - [[tables objectAtIndex:currentIndex] backtickQuotedString] + [[filteredTables objectAtIndex:currentIndex] backtickQuotedString] ]]; - } else if([[tableTypes objectAtIndex:currentIndex] intValue] == SP_TABLETYPE_FUNC) { + } else if([[filteredTableTypes objectAtIndex:currentIndex] intValue] == SP_TABLETYPE_FUNC) { [mySQLConnection queryString: [NSString stringWithFormat: @"DROP FUNCTION %@", - [[tables objectAtIndex:currentIndex] backtickQuotedString] + [[filteredTables objectAtIndex:currentIndex] backtickQuotedString] ]]; } if ( [[mySQLConnection getLastErrorMessage] isEqualTo:@""] ) { //dropped table with success - [tables removeObjectAtIndex:currentIndex]; - [tableTypes removeObjectAtIndex:currentIndex]; + if (isTableListFiltered) { + int unfilteredIndex = [tables indexOfObject:[filteredTables objectAtIndex:currentIndex]]; + [tables removeObjectAtIndex:unfilteredIndex]; + [tableTypes removeObjectAtIndex:unfilteredIndex]; + } + [filteredTables removeObjectAtIndex:currentIndex]; + [filteredTableTypes removeObjectAtIndex:currentIndex]; } else { //couldn't drop table error = TRUE; @@ -795,6 +891,15 @@ // get next index (beginning from the end) currentIndex = [indexes indexLessThanIndex:currentIndex]; } + + // Remove the isolated "current selection" item for filtered lists if appropriate + if (isTableListFiltered && [filteredTables count] > 1 + && [[filteredTableTypes objectAtIndex:[filteredTableTypes count]-1] intValue] == SP_TABLETYPE_NONE + && [[filteredTables objectAtIndex:[filteredTables count]-1] isEqualToString:NSLocalizedString(@"CURRENT SELECTION",@"header for current selection in filtered list")]) + { + [filteredTables removeLastObject]; + [filteredTableTypes removeLastObject]; + } [tablesListView reloadData]; @@ -822,13 +927,13 @@ while (currentIndex != NSNotFound) { - [mySQLConnection queryString:[NSString stringWithFormat: @"TRUNCATE TABLE %@", [[tables objectAtIndex:currentIndex] backtickQuotedString]]]; + [mySQLConnection queryString:[NSString stringWithFormat: @"TRUNCATE TABLE %@", [[filteredTables objectAtIndex:currentIndex] backtickQuotedString]]]; // Couldn't truncate table if (![[mySQLConnection getLastErrorMessage] isEqualTo:@""]) { NSBeginAlertSheet(NSLocalizedString(@"Error truncating table", @"error truncating table message"), NSLocalizedString(@"OK", @"OK button"), nil, nil, tableWindow, self, nil, nil, nil, - [NSString stringWithFormat:NSLocalizedString(@"An error occurred while trying to truncate the table '%@'.\n\nMySQL said: %@", @"error truncating table informative message"), [tables objectAtIndex:currentIndex], [mySQLConnection getLastErrorMessage]]); + [NSString stringWithFormat:NSLocalizedString(@"An error occurred while trying to truncate the table '%@'.\n\nMySQL said: %@", @"error truncating table informative message"), [filteredTables objectAtIndex:currentIndex], [mySQLConnection getLastErrorMessage]]); } // Get next index (beginning from the end) @@ -898,6 +1003,299 @@ } } +/** + * Updates the current table selection. Triggered most times tableViewSelectionDidChange: + * fires, and also as a result of certain table actions. + */ +- (void)updateSelection +{ + if ( [tablesListView numberOfSelectedRows] == 1 && [[filteredTables objectAtIndex:[tablesListView selectedRow]] length] ) { + + // Update the selected table name and type + if (selectedTableName) [selectedTableName release]; + selectedTableName = [[NSString alloc] initWithString:[filteredTables objectAtIndex:[tablesListView selectedRow]]]; + selectedTableType = [[filteredTableTypes objectAtIndex:[tablesListView selectedRow]] intValue]; + + // Remove the "current selection" item for filtered lists if appropriate + if (isTableListFiltered && [tablesListView selectedRow] < [filteredTables count] - 2 && [filteredTables count] > 2 + && [[filteredTableTypes objectAtIndex:[filteredTableTypes count]-2] intValue] == SP_TABLETYPE_NONE + && [[filteredTables objectAtIndex:[filteredTables count]-2] isEqualToString:NSLocalizedString(@"CURRENT SELECTION",@"header for current selection in filtered list")]) + { + [filteredTables removeObjectsInRange:NSMakeRange([filteredTables count]-2, 2)]; + [filteredTableTypes removeObjectsInRange:NSMakeRange([filteredTableTypes count]-2, 2)]; + [tablesListView reloadData]; + } + + // Reset the table information caches + [tableDataInstance resetAllData]; + + [separatorTableMenuItem setHidden:NO]; + [separatorTableContextMenuItem setHidden:NO]; + + if( selectedTableType == SP_TABLETYPE_VIEW || selectedTableType == SP_TABLETYPE_TABLE) { + + // tableEncoding == nil indicates that there was an error while retrieving table data + NSString *tableEncoding = [tableDataInstance tableEncoding]; + + // If encoding is set to Autodetect, update the connection character set encoding + // based on the newly selected table's encoding - but only if it differs from the current encoding. + if ([[[NSUserDefaults standardUserDefaults] objectForKey:@"DefaultEncoding"] isEqualToString:@"Autodetect"]) { + if (tableEncoding != nil && ![tableEncoding isEqualToString:[tableDocumentInstance connectionEncoding]]) { + [tableDocumentInstance setConnectionEncoding:tableEncoding reloadingViews:NO]; + [tableDataInstance resetAllData]; + } + } + + if ( [tabView indexOfTabViewItem:[tabView selectedTabViewItem]] == 0 ) { + [tableSourceInstance loadTable:selectedTableName]; + structureLoaded = YES; + contentLoaded = NO; + statusLoaded = NO; + } else if ( [tabView indexOfTabViewItem:[tabView selectedTabViewItem]] == 1 ) { + if(tableEncoding == nil) { + [tableContentInstance loadTable:nil]; + } else { + [tableContentInstance loadTable:selectedTableName]; + } + structureLoaded = NO; + contentLoaded = YES; + statusLoaded = NO; + } else if ( [tabView indexOfTabViewItem:[tabView selectedTabViewItem]] == 3 ) { + [extendedTableInfoInstance loadTable:selectedTableName]; + structureLoaded = NO; + contentLoaded = NO; + statusLoaded = YES; + } else { + structureLoaded = NO; + contentLoaded = NO; + statusLoaded = NO; + } + } else { + + // if we are not looking at a table or view, clear these + [tableSourceInstance loadTable:nil]; + [tableContentInstance loadTable:nil]; + [extendedTableInfoInstance loadTable:nil]; + structureLoaded = NO; + contentLoaded = NO; + statusLoaded = NO; + } + + // Set gear menu items Remove/Duplicate table/view and mainMenu > Table items + // according to the table types + NSMenu *tableSubMenu = [[[NSApp mainMenu] itemAtIndex:5] submenu]; + + if(selectedTableType == SP_TABLETYPE_VIEW) + { + // Change mainMenu > Table > ... according to table type + [[tableSubMenu itemAtIndex:0] setTitle:NSLocalizedString(@"Copy Create View Syntax", @"copy create view syntax menu item")]; + [[tableSubMenu itemAtIndex:1] setTitle:NSLocalizedString(@"Show Create View Syntax", @"show create view syntax menu item")]; + [[tableSubMenu itemAtIndex:2] setHidden:NO]; // divider + [[tableSubMenu itemAtIndex:3] setHidden:NO]; + [[tableSubMenu itemAtIndex:3] setTitle:NSLocalizedString(@"Check View", @"check view menu item")]; + [[tableSubMenu itemAtIndex:4] setHidden:YES]; // repair + [[tableSubMenu itemAtIndex:5] setHidden:YES]; // divider + [[tableSubMenu itemAtIndex:6] setHidden:YES]; // analyse + [[tableSubMenu itemAtIndex:7] setHidden:YES]; // optimize + [[tableSubMenu itemAtIndex:8] setHidden:NO]; + [[tableSubMenu itemAtIndex:8] setTitle:NSLocalizedString(@"Flush View", @"flush view menu item")]; + [[tableSubMenu itemAtIndex:9] setHidden:YES]; // checksum + + [renameTableMenuItem setHidden:NO]; // we don't have to check the mysql version + [renameTableMenuItem setTitle:NSLocalizedString(@"Rename View...", @"rename view menu title")]; + [duplicateTableMenuItem setHidden:NO]; + [duplicateTableMenuItem setTitle:NSLocalizedString(@"Duplicate View...", @"duplicate view menu title")]; + [truncateTableButton setHidden:YES]; + [removeTableMenuItem setTitle:NSLocalizedString(@"Remove View", @"remove view menu title")]; + + [renameTableContextMenuItem setHidden:NO]; // we don't have to check the mysql version + [renameTableContextMenuItem setTitle:NSLocalizedString(@"Rename View...", @"rename view menu title")]; + [duplicateTableContextMenuItem setHidden:NO]; + [duplicateTableContextMenuItem setTitle:NSLocalizedString(@"Duplicate View...", @"duplicate view menu title")]; + [truncateTableContextButton setHidden:YES]; + [removeTableContextMenuItem setTitle:NSLocalizedString(@"Remove View", @"remove view menu title")]; + } + else if(selectedTableType == SP_TABLETYPE_TABLE) { + [[tableSubMenu itemAtIndex:0] setTitle:NSLocalizedString(@"Copy Create Table Syntax", @"copy create table syntax menu item")]; + [[tableSubMenu itemAtIndex:1] setTitle:NSLocalizedString(@"Show Create Table Syntax", @"show create table syntax menu item")]; + [[tableSubMenu itemAtIndex:2] setHidden:NO]; // divider + [[tableSubMenu itemAtIndex:3] setHidden:NO]; + [[tableSubMenu itemAtIndex:3] setTitle:NSLocalizedString(@"Check Table", @"check table menu item")]; + [[tableSubMenu itemAtIndex:4] setHidden:NO]; + [[tableSubMenu itemAtIndex:5] setHidden:NO]; // divider + [[tableSubMenu itemAtIndex:6] setHidden:NO]; + [[tableSubMenu itemAtIndex:7] setHidden:NO]; + [[tableSubMenu itemAtIndex:8] setHidden:NO]; + [[tableSubMenu itemAtIndex:8] setTitle:NSLocalizedString(@"Flush Table", @"flush table menu item")]; + [[tableSubMenu itemAtIndex:9] setHidden:NO]; + + [renameTableMenuItem setHidden:NO]; + [renameTableMenuItem setTitle:NSLocalizedString(@"Rename Table...", @"rename table menu title")]; + [duplicateTableMenuItem setHidden:NO]; + [duplicateTableMenuItem setTitle:NSLocalizedString(@"Duplicate Table...", @"duplicate table menu title")]; + [truncateTableButton setHidden:NO]; + [truncateTableButton setTitle:NSLocalizedString(@"Truncate Table", @"truncate table menu title")]; + [removeTableMenuItem setTitle:NSLocalizedString(@"Remove Table", @"remove table menu title")]; + + [renameTableContextMenuItem setHidden:NO]; + [renameTableContextMenuItem setTitle:NSLocalizedString(@"Rename Table...", @"rename table menu title")]; + [duplicateTableContextMenuItem setHidden:NO]; + [duplicateTableContextMenuItem setTitle:NSLocalizedString(@"Duplicate Table...", @"duplicate table menu title")]; + [truncateTableContextButton setHidden:NO]; + [truncateTableContextButton setTitle:NSLocalizedString(@"Truncate Table", @"truncate table menu title")]; + [removeTableContextMenuItem setTitle:NSLocalizedString(@"Remove Table", @"remove table menu title")]; + + } + else if(selectedTableType == SP_TABLETYPE_PROC) { + [[tableSubMenu itemAtIndex:0] setTitle:NSLocalizedString(@"Copy Create Procedure Syntax", @"copy create proc syntax menu item")]; + [[tableSubMenu itemAtIndex:1] setTitle:NSLocalizedString(@"Show Create Procedure Syntax", @"show create proc syntax menu item")]; + [[tableSubMenu itemAtIndex:2] setHidden:YES]; // divider + [[tableSubMenu itemAtIndex:3] setHidden:YES]; // copy columns + [[tableSubMenu itemAtIndex:4] setHidden:YES]; // divider + [[tableSubMenu itemAtIndex:5] setHidden:YES]; + [[tableSubMenu itemAtIndex:6] setHidden:YES]; + [[tableSubMenu itemAtIndex:7] setHidden:YES]; // divider + [[tableSubMenu itemAtIndex:8] setHidden:YES]; + [[tableSubMenu itemAtIndex:9] setHidden:YES]; + + [renameTableMenuItem setHidden:NO]; + [renameTableMenuItem setTitle:NSLocalizedString(@"Rename Procedure...", @"rename proc menu title")]; + [duplicateTableMenuItem setHidden:NO]; + [duplicateTableMenuItem setTitle:NSLocalizedString(@"Duplicate Procedure...", @"duplicate proc menu title")]; + [truncateTableButton setHidden:YES]; + [removeTableMenuItem setTitle:NSLocalizedString(@"Remove Procedure", @"remove proc menu title")]; + + [renameTableContextMenuItem setHidden:NO]; + [renameTableContextMenuItem setTitle:NSLocalizedString(@"Rename Procedure...", @"rename proc menu title")]; + [duplicateTableContextMenuItem setHidden:NO]; + [duplicateTableContextMenuItem setTitle:NSLocalizedString(@"Duplicate Procedure...", @"duplicate proc menu title")]; + [truncateTableContextButton setHidden:YES]; + [removeTableContextMenuItem setTitle:NSLocalizedString(@"Remove Procedure", @"remove proc menu title")]; + + } + else if(selectedTableType == SP_TABLETYPE_FUNC) { + [[tableSubMenu itemAtIndex:0] setTitle:NSLocalizedString(@"Copy Create Function Syntax", @"copy create func syntax menu item")]; + [[tableSubMenu itemAtIndex:1] setTitle:NSLocalizedString(@"Show Create Function Syntax", @"show create func syntax menu item")]; + [[tableSubMenu itemAtIndex:2] setHidden:YES]; // divider + [[tableSubMenu itemAtIndex:3] setHidden:YES]; // copy columns + [[tableSubMenu itemAtIndex:4] setHidden:YES]; // divider + [[tableSubMenu itemAtIndex:5] setHidden:YES]; + [[tableSubMenu itemAtIndex:6] setHidden:YES]; + [[tableSubMenu itemAtIndex:7] setHidden:YES]; // divider + [[tableSubMenu itemAtIndex:8] setHidden:YES]; + [[tableSubMenu itemAtIndex:9] setHidden:YES]; + + [renameTableMenuItem setHidden:NO]; + [renameTableMenuItem setTitle:NSLocalizedString(@"Rename Function...", @"rename func menu title")]; + [duplicateTableMenuItem setHidden:NO]; + [duplicateTableMenuItem setTitle:NSLocalizedString(@"Duplicate Function...", @"duplicate func menu title")]; + [truncateTableButton setHidden:YES]; + [removeTableMenuItem setTitle:NSLocalizedString(@"Remove Function", @"remove func menu title")]; + + [renameTableContextMenuItem setHidden:NO]; + [renameTableContextMenuItem setTitle:NSLocalizedString(@"Rename Function...", @"rename func menu title")]; + [duplicateTableContextMenuItem setHidden:NO]; + [duplicateTableContextMenuItem setTitle:NSLocalizedString(@"Duplicate Function...", @"duplicate func menu title")]; + [truncateTableContextButton setHidden:YES]; + [removeTableContextMenuItem setTitle:NSLocalizedString(@"Remove Function", @"remove func menu title")]; + + } + // set window title + [tableWindow setTitle:[NSString stringWithFormat:@"(MySQL %@) %@/%@/%@", [tableDocumentInstance mySQLVersion], + [tableDocumentInstance name], [tableDocumentInstance database], selectedTableName]]; + + // Update the "Show Create Syntax" window if it's already opened + // according to the selected table/view/proc/func + if([[tableDocumentInstance getCreateTableSyntaxWindow] isVisible]) + [tableDocumentInstance showCreateTableSyntax:self]; + + } else { + NSIndexSet *indexes = [tablesListView selectedRowIndexes]; + + // Update the selected table name and type + if (selectedTableName) [selectedTableName release]; + if ([indexes count]) { + selectedTableName = [[NSString alloc] initWithString:@""]; + } else { + selectedTableName = nil; + } + selectedTableType = SP_TABLETYPE_NONE; + + [tableSourceInstance loadTable:nil]; + [tableContentInstance loadTable:nil]; + [extendedTableInfoInstance loadTable:nil]; + structureLoaded = NO; + contentLoaded = NO; + statusLoaded = NO; + + // Set gear menu items Remove/Duplicate table/view according to the table types + // if at least one item is selected + if([indexes count]) { + unsigned int currentIndex = [indexes lastIndex]; + BOOL areTableTypeEqual = YES; + int lastType = [[filteredTableTypes objectAtIndex:currentIndex] intValue]; + while (currentIndex != NSNotFound) + { + if ([[filteredTableTypes objectAtIndex:currentIndex] intValue] != lastType) + { + areTableTypeEqual = NO; + break; + } + currentIndex = [indexes indexLessThanIndex:currentIndex]; + } + if (areTableTypeEqual) + { + switch (lastType) { + case SP_TABLETYPE_TABLE: + [removeTableMenuItem setTitle:NSLocalizedString(@"Remove Tables", @"remove tables menu title")]; + [truncateTableButton setTitle:NSLocalizedString(@"Truncate Tables", @"truncate tables menu item")]; + [removeTableContextMenuItem setTitle:NSLocalizedString(@"Remove Tables", @"remove tables menu title")]; + [truncateTableContextButton setTitle:NSLocalizedString(@"Truncate Tables", @"truncate tables menu item")]; + [truncateTableButton setHidden:NO]; + [truncateTableContextButton setHidden:NO]; + break; + case SP_TABLETYPE_VIEW: + [removeTableMenuItem setTitle:NSLocalizedString(@"Remove Views", @"remove views menu title")]; + [removeTableContextMenuItem setTitle:NSLocalizedString(@"Remove Views", @"remove views menu title")]; + [truncateTableButton setHidden:YES]; + [truncateTableContextButton setHidden:YES]; + break; + case SP_TABLETYPE_PROC: + [removeTableMenuItem setTitle:NSLocalizedString(@"Remove Procedures", @"remove procedures menu title")]; + [removeTableContextMenuItem setTitle:NSLocalizedString(@"Remove Procedures", @"remove procedures menu title")]; + [truncateTableButton setHidden:YES]; + [truncateTableContextButton setHidden:YES]; + break; + case SP_TABLETYPE_FUNC: + [removeTableMenuItem setTitle:NSLocalizedString(@"Remove Functions", @"remove functions menu title")]; + [removeTableContextMenuItem setTitle:NSLocalizedString(@"Remove Functions", @"remove functions menu title")]; + [truncateTableButton setHidden:YES]; + [truncateTableContextButton setHidden:YES]; + break; + } + + } else { + [removeTableMenuItem setTitle:NSLocalizedString(@"Remove Items", @"remove items menu title")]; + [removeTableContextMenuItem setTitle:NSLocalizedString(@"Remove Items", @"remove items menu title")]; + [truncateTableButton setHidden:YES]; + [truncateTableContextButton setHidden:YES]; + } + } + [renameTableContextMenuItem setHidden:YES]; + [duplicateTableContextMenuItem setHidden:YES]; + [separatorTableContextMenuItem setHidden:YES]; + + [renameTableMenuItem setHidden:YES]; + [duplicateTableMenuItem setHidden:YES]; + [separatorTableMenuItem setHidden:YES]; + [separatorTableContextMenuItem setHidden:YES]; + + // set window title + [tableWindow setTitle:[NSString stringWithFormat:@"(MySQL %@) %@/%@", [tableDocumentInstance mySQLVersion], + [tableDocumentInstance name], [tableDocumentInstance database]]]; + } +} + #pragma mark Getter methods /** @@ -905,13 +1303,7 @@ */ - (NSString *)tableName { - if ( [tablesListView numberOfSelectedRows] == 1 ) { - return [tables objectAtIndex:[tablesListView selectedRow]]; - } else if ([tablesListView numberOfSelectedRows] > 1) { - return @""; - } else { - return nil; - } + return selectedTableName; } /* @@ -919,13 +1311,7 @@ */ - (int) tableType { - if ( [tablesListView numberOfSelectedRows] == 1 ) { - return [[tableTypes objectAtIndex:[tablesListView selectedRow]] intValue]; - } else if ([tablesListView numberOfSelectedRows] > 1) { - return -1; - } else { - return -1; - } + return selectedTableType; } /** @@ -1068,7 +1454,7 @@ int itemIndex = NSNotFound; int caseInsensitiveItemIndex = NSNotFound; - // Loop through the tables/views to find the desired item + // Loop through the unfiltered tables/views to find the desired item for (i = 0; i < [tables count]; i++) { tableType = [[tableTypes objectAtIndex:i] intValue]; if (tableType != SP_TABLETYPE_TABLE && tableType != SP_TABLETYPE_VIEW) continue; @@ -1087,7 +1473,21 @@ // If no match found, return failure if (itemIndex == NSNotFound) return NO; - [tablesListView selectRowIndexes:[NSIndexSet indexSetWithIndex:itemIndex] byExtendingSelection:NO]; + if (!isTableListFiltered) { + [tablesListView selectRowIndexes:[NSIndexSet indexSetWithIndex:itemIndex] byExtendingSelection:NO]; + } else { + int filteredIndex = [filteredTables indexOfObject:[tables objectAtIndex:itemIndex]]; + if (filteredIndex != NSNotFound) { + [tablesListView selectRowIndexes:[NSIndexSet indexSetWithIndex:filteredIndex] byExtendingSelection:NO]; + } else { + [tablesListView deselectAll:nil]; + if (selectedTableName) [selectedTableName release]; + selectedTableName = [[NSString alloc] initWithString:[tables objectAtIndex:itemIndex]]; + selectedTableType = [[tableTypes objectAtIndex:itemIndex] intValue]; + [self updateFilter:self]; + [self updateSelection]; + } + } return YES; } @@ -1098,7 +1498,7 @@ */ - (int)numberOfRowsInTableView:(NSTableView *)aTableView { - return [tables count]; + return [filteredTables count]; } /** @@ -1106,16 +1506,15 @@ */ - (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex { - return [tables objectAtIndex:rowIndex]; + return [filteredTables objectAtIndex:rowIndex]; } /** * Renames a table (in tables-array and mysql-db). - * Removes new table from table-array if renaming had no success */ - (void)tableView:(NSTableView *)aTableView setObjectValue:(id)anObject forTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex { - if ([[tables objectAtIndex:rowIndex] isEqualToString:anObject]) { + if ([selectedTableName isEqualToString:anObject]) { // No changes in table name } else if ([anObject isEqualToString:@""]) { @@ -1125,16 +1524,16 @@ @selector(sheetDidEnd:returnCode:contextInfo:), nil, @"addRow", NSLocalizedString(@"Empty names are not allowed.", @"message of panel when no name is given for an item")); } else { - if([self tableType] == SP_TABLETYPE_VIEW || [self tableType] == SP_TABLETYPE_TABLE) + if(selectedTableType == SP_TABLETYPE_VIEW || selectedTableType == SP_TABLETYPE_TABLE) { - [mySQLConnection queryString:[NSString stringWithFormat:@"RENAME TABLE %@ TO %@", [[tables objectAtIndex:rowIndex] backtickQuotedString], [anObject backtickQuotedString]]]; + [mySQLConnection queryString:[NSString stringWithFormat:@"RENAME TABLE %@ TO %@", [selectedTableName backtickQuotedString], [anObject backtickQuotedString]]]; } else { // procedures and functions can only be renamed if one creates the new one and delete the old one // get the create syntax NSString *tableType; - switch([self tableType]){ + switch (selectedTableType){ case SP_TABLETYPE_PROC: tableType = @"PROCEDURE"; break; @@ -1143,10 +1542,10 @@ break; } MCPResult *theResult; - if([self tableType] == SP_TABLETYPE_PROC) - theResult = [mySQLConnection queryString:[NSString stringWithFormat:@"SHOW CREATE PROCEDURE %@", [[tables objectAtIndex:rowIndex] backtickQuotedString]]]; - else if([self tableType] == SP_TABLETYPE_FUNC) - theResult = [mySQLConnection queryString:[NSString stringWithFormat:@"SHOW CREATE FUNCTION %@", [[tables objectAtIndex:rowIndex] backtickQuotedString]]]; + if (selectedTableType == SP_TABLETYPE_PROC) + theResult = [mySQLConnection queryString:[NSString stringWithFormat:@"SHOW CREATE PROCEDURE %@", [selectedTableName backtickQuotedString]]]; + else if(selectedTableType == SP_TABLETYPE_FUNC) + theResult = [mySQLConnection queryString:[NSString stringWithFormat:@"SHOW CREATE FUNCTION %@", [selectedTableName backtickQuotedString]]]; else return; @@ -1155,7 +1554,7 @@ if ([mySQLConnection isConnected]) { NSBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, tableWindow, self, nil, nil, nil, - [NSString stringWithFormat:NSLocalizedString(@"An error occured while retrieving create syntax for '%@'.\n\nMySQL said: %@", @"message of panel when create syntax cannot be retrieved"), [self tableName], [mySQLConnection getLastErrorMessage]]); + [NSString stringWithFormat:NSLocalizedString(@"An error occured while retrieving create syntax for '%@'.\n\nMySQL said: %@", @"message of panel when create syntax cannot be retrieved"), selectedTableName, [mySQLConnection getLastErrorMessage]]); } return; @@ -1164,11 +1563,10 @@ id tableSyntax = [[theResult fetchRowAsArray] objectAtIndex:2]; if ([tableSyntax isKindOfClass:[NSData class]]) - tableSyntax = [[NSString alloc] initWithData:tableSyntax encoding:[mySQLConnection encoding]]; + tableSyntax = [[[NSString alloc] initWithData:tableSyntax encoding:[mySQLConnection encoding]] autorelease]; // replace the old name by the new one and drop the old one [mySQLConnection queryString:[tableSyntax stringByReplacingOccurrencesOfRegex:[NSString stringWithFormat:@"(?<=%@ )(`[^`]+?`)", tableType] withString:[anObject backtickQuotedString]]]; - [tableSyntax release]; if ([[mySQLConnection getLastErrorMessage] isEqualToString:@""]) { if ([mySQLConnection isConnected]) { [mySQLConnection queryString: [NSString stringWithFormat: @"DROP %@ %@", tableType, [[tables objectAtIndex:rowIndex] backtickQuotedString]]]; @@ -1178,8 +1576,15 @@ if ([[mySQLConnection getLastErrorMessage] isEqualToString:@""]) { // Renamed with success - [tables replaceObjectAtIndex:rowIndex withObject:anObject]; - if([self tableType] == SP_TABLETYPE_FUNC || [self tableType] == SP_TABLETYPE_PROC) + if (isTableListFiltered) { + int unfilteredIndex = [tables indexOfObject:[filteredTables objectAtIndex:rowIndex]]; + [tables replaceObjectAtIndex:unfilteredIndex withObject:anObject]; + } + [filteredTables replaceObjectAtIndex:rowIndex withObject:anObject]; + if (selectedTableName) [selectedTableName release]; + selectedTableName = [[NSString alloc] initWithString:anObject]; + + if(selectedTableType == SP_TABLETYPE_FUNC || selectedTableType == SP_TABLETYPE_PROC) return; NSInteger selectedIndex = [tabView indexOfTabViewItem:[tabView selectedTabViewItem]]; @@ -1240,13 +1645,6 @@ //abort editing [control abortEditing]; - if ( [[tables objectAtIndex:[tablesListView selectedRow]] isEqualToString:@""] ) { - //user added new table and then pressed escape - [tableTypes removeObjectAtIndex:[tablesListView selectedRow]]; - [tables removeObjectAtIndex:[tablesListView selectedRow]]; - [tablesListView reloadData]; - } - return TRUE; } else{ return FALSE; @@ -1278,264 +1676,17 @@ */ - (void)tableViewSelectionDidChange:(NSNotification *)aNotification { - if ( [tablesListView numberOfSelectedRows] == 1 && [[self tableName] length] ) { - - // Reset the table information caches - [tableDataInstance resetAllData]; - - [separatorTableMenuItem setHidden:NO]; - [separatorTableContextMenuItem setHidden:NO]; - - if( [[tableTypes objectAtIndex:[tablesListView selectedRow]] intValue] == SP_TABLETYPE_VIEW || - [[tableTypes objectAtIndex:[tablesListView selectedRow]] intValue] == SP_TABLETYPE_TABLE) { - - // tableEncoding == nil indicates that there was an error while retrieving table data - NSString *tableEncoding = [tableDataInstance tableEncoding]; - // If encoding is set to Autodetect, update the connection character set encoding - // based on the newly selected table's encoding - but only if it differs from the current encoding. - if ([[[NSUserDefaults standardUserDefaults] objectForKey:@"DefaultEncoding"] isEqualToString:@"Autodetect"]) { - if (tableEncoding != nil && ![tableEncoding isEqualToString:[tableDocumentInstance connectionEncoding]]) { - [tableDocumentInstance setConnectionEncoding:tableEncoding reloadingViews:NO]; - [tableDataInstance resetAllData]; - } - } - - if ( [tabView indexOfTabViewItem:[tabView selectedTabViewItem]] == 0 ) { - [tableSourceInstance loadTable:[tables objectAtIndex:[tablesListView selectedRow]]]; - structureLoaded = YES; - contentLoaded = NO; - statusLoaded = NO; - } else if ( [tabView indexOfTabViewItem:[tabView selectedTabViewItem]] == 1 ) { - if(tableEncoding == nil) { - [tableContentInstance loadTable:nil]; - } else { - [tableContentInstance loadTable:[tables objectAtIndex:[tablesListView selectedRow]]]; - } - structureLoaded = NO; - contentLoaded = YES; - statusLoaded = NO; - } else if ( [tabView indexOfTabViewItem:[tabView selectedTabViewItem]] == 3 ) { - [extendedTableInfoInstance loadTable:[tables objectAtIndex:[tablesListView selectedRow]]]; - structureLoaded = NO; - contentLoaded = NO; - statusLoaded = YES; - } else { - structureLoaded = NO; - contentLoaded = NO; - statusLoaded = NO; - } - } else { - // if we are not looking at a table or view, clear these - [tableSourceInstance loadTable:nil]; - [tableContentInstance loadTable:nil]; - [extendedTableInfoInstance loadTable:nil]; - structureLoaded = NO; - contentLoaded = NO; - statusLoaded = NO; - } - - // Set gear menu items Remove/Duplicate table/view and mainMenu > Table items - // according to the table types - NSMenu *tableSubMenu = [[[NSApp mainMenu] itemAtIndex:5] submenu]; - - if([[tableTypes objectAtIndex:[tablesListView selectedRow]] intValue] == SP_TABLETYPE_VIEW) - { - // Change mainMenu > Table > ... according to table type - [[tableSubMenu itemAtIndex:0] setTitle:NSLocalizedString(@"Copy Create View Syntax", @"copy create view syntax menu item")]; - [[tableSubMenu itemAtIndex:1] setTitle:NSLocalizedString(@"Show Create View Syntax", @"show create view syntax menu item")]; - [[tableSubMenu itemAtIndex:2] setHidden:NO]; // divider - [[tableSubMenu itemAtIndex:3] setHidden:NO]; - [[tableSubMenu itemAtIndex:3] setTitle:NSLocalizedString(@"Check View", @"check view menu item")]; - [[tableSubMenu itemAtIndex:4] setHidden:YES]; // repair - [[tableSubMenu itemAtIndex:5] setHidden:YES]; // divider - [[tableSubMenu itemAtIndex:6] setHidden:YES]; // analyse - [[tableSubMenu itemAtIndex:7] setHidden:YES]; // optimize - [[tableSubMenu itemAtIndex:8] setHidden:NO]; - [[tableSubMenu itemAtIndex:8] setTitle:NSLocalizedString(@"Flush View", @"flush view menu item")]; - [[tableSubMenu itemAtIndex:9] setHidden:YES]; // checksum - - [renameTableMenuItem setHidden:NO]; // we don't have to check the mysql version - [renameTableMenuItem setTitle:NSLocalizedString(@"Rename View...", @"rename view menu title")]; - [duplicateTableMenuItem setHidden:NO]; - [duplicateTableMenuItem setTitle:NSLocalizedString(@"Duplicate View...", @"duplicate view menu title")]; - [truncateTableButton setHidden:YES]; - [removeTableMenuItem setTitle:NSLocalizedString(@"Remove View", @"remove view menu title")]; - - [renameTableContextMenuItem setHidden:NO]; // we don't have to check the mysql version - [renameTableContextMenuItem setTitle:NSLocalizedString(@"Rename View...", @"rename view menu title")]; - [duplicateTableContextMenuItem setHidden:NO]; - [duplicateTableContextMenuItem setTitle:NSLocalizedString(@"Duplicate View...", @"duplicate view menu title")]; - [truncateTableContextButton setHidden:YES]; - [removeTableContextMenuItem setTitle:NSLocalizedString(@"Remove View", @"remove view menu title")]; - } - else if([[tableTypes objectAtIndex:[tablesListView selectedRow]] intValue] == SP_TABLETYPE_TABLE) { - [[tableSubMenu itemAtIndex:0] setTitle:NSLocalizedString(@"Copy Create Table Syntax", @"copy create table syntax menu item")]; - [[tableSubMenu itemAtIndex:1] setTitle:NSLocalizedString(@"Show Create Table Syntax", @"show create table syntax menu item")]; - [[tableSubMenu itemAtIndex:2] setHidden:NO]; // divider - [[tableSubMenu itemAtIndex:3] setHidden:NO]; - [[tableSubMenu itemAtIndex:3] setTitle:NSLocalizedString(@"Check Table", @"check table menu item")]; - [[tableSubMenu itemAtIndex:4] setHidden:NO]; - [[tableSubMenu itemAtIndex:5] setHidden:NO]; // divider - [[tableSubMenu itemAtIndex:6] setHidden:NO]; - [[tableSubMenu itemAtIndex:7] setHidden:NO]; - [[tableSubMenu itemAtIndex:8] setHidden:NO]; - [[tableSubMenu itemAtIndex:8] setTitle:NSLocalizedString(@"Flush Table", @"flush table menu item")]; - [[tableSubMenu itemAtIndex:9] setHidden:NO]; - - [renameTableMenuItem setHidden:NO]; - [renameTableMenuItem setTitle:NSLocalizedString(@"Rename Table...", @"rename table menu title")]; - [duplicateTableMenuItem setHidden:NO]; - [duplicateTableMenuItem setTitle:NSLocalizedString(@"Duplicate Table...", @"duplicate table menu title")]; - [truncateTableButton setHidden:NO]; - [truncateTableButton setTitle:NSLocalizedString(@"Truncate Table", @"truncate table menu title")]; - [removeTableMenuItem setTitle:NSLocalizedString(@"Remove Table", @"remove table menu title")]; - - [renameTableContextMenuItem setHidden:NO]; - [renameTableContextMenuItem setTitle:NSLocalizedString(@"Rename Table...", @"rename table menu title")]; - [duplicateTableContextMenuItem setHidden:NO]; - [duplicateTableContextMenuItem setTitle:NSLocalizedString(@"Duplicate Table...", @"duplicate table menu title")]; - [truncateTableContextButton setHidden:NO]; - [truncateTableContextButton setTitle:NSLocalizedString(@"Truncate Table", @"truncate table menu title")]; - [removeTableContextMenuItem setTitle:NSLocalizedString(@"Remove Table", @"remove table menu title")]; - - } - else if([[tableTypes objectAtIndex:[tablesListView selectedRow]] intValue] == SP_TABLETYPE_PROC) { - [[tableSubMenu itemAtIndex:0] setTitle:NSLocalizedString(@"Copy Create Procedure Syntax", @"copy create proc syntax menu item")]; - [[tableSubMenu itemAtIndex:1] setTitle:NSLocalizedString(@"Show Create Procedure Syntax", @"show create proc syntax menu item")]; - [[tableSubMenu itemAtIndex:2] setHidden:YES]; // divider - [[tableSubMenu itemAtIndex:3] setHidden:YES]; // copy columns - [[tableSubMenu itemAtIndex:4] setHidden:YES]; // divider - [[tableSubMenu itemAtIndex:5] setHidden:YES]; - [[tableSubMenu itemAtIndex:6] setHidden:YES]; - [[tableSubMenu itemAtIndex:7] setHidden:YES]; // divider - [[tableSubMenu itemAtIndex:8] setHidden:YES]; - [[tableSubMenu itemAtIndex:9] setHidden:YES]; - - [renameTableMenuItem setHidden:NO]; - [renameTableMenuItem setTitle:NSLocalizedString(@"Rename Procedure...", @"rename proc menu title")]; - [duplicateTableMenuItem setHidden:NO]; - [duplicateTableMenuItem setTitle:NSLocalizedString(@"Duplicate Procedure...", @"duplicate proc menu title")]; - [truncateTableButton setHidden:YES]; - [removeTableMenuItem setTitle:NSLocalizedString(@"Remove Procedure", @"remove proc menu title")]; - - [renameTableContextMenuItem setHidden:NO]; - [renameTableContextMenuItem setTitle:NSLocalizedString(@"Rename Procedure...", @"rename proc menu title")]; - [duplicateTableContextMenuItem setHidden:NO]; - [duplicateTableContextMenuItem setTitle:NSLocalizedString(@"Duplicate Procedure...", @"duplicate proc menu title")]; - [truncateTableContextButton setHidden:YES]; - [removeTableContextMenuItem setTitle:NSLocalizedString(@"Remove Procedure", @"remove proc menu title")]; - - } - else if([[tableTypes objectAtIndex:[tablesListView selectedRow]] intValue] == SP_TABLETYPE_FUNC) { - [[tableSubMenu itemAtIndex:0] setTitle:NSLocalizedString(@"Copy Create Function Syntax", @"copy create func syntax menu item")]; - [[tableSubMenu itemAtIndex:1] setTitle:NSLocalizedString(@"Show Create Function Syntax", @"show create func syntax menu item")]; - [[tableSubMenu itemAtIndex:2] setHidden:YES]; // divider - [[tableSubMenu itemAtIndex:3] setHidden:YES]; // copy columns - [[tableSubMenu itemAtIndex:4] setHidden:YES]; // divider - [[tableSubMenu itemAtIndex:5] setHidden:YES]; - [[tableSubMenu itemAtIndex:6] setHidden:YES]; - [[tableSubMenu itemAtIndex:7] setHidden:YES]; // divider - [[tableSubMenu itemAtIndex:8] setHidden:YES]; - [[tableSubMenu itemAtIndex:9] setHidden:YES]; - - [renameTableMenuItem setHidden:NO]; - [renameTableMenuItem setTitle:NSLocalizedString(@"Rename Function...", @"rename func menu title")]; - [duplicateTableMenuItem setHidden:NO]; - [duplicateTableMenuItem setTitle:NSLocalizedString(@"Duplicate Function...", @"duplicate func menu title")]; - [truncateTableButton setHidden:YES]; - [removeTableMenuItem setTitle:NSLocalizedString(@"Remove Function", @"remove func menu title")]; - - [renameTableContextMenuItem setHidden:NO]; - [renameTableContextMenuItem setTitle:NSLocalizedString(@"Rename Function...", @"rename func menu title")]; - [duplicateTableContextMenuItem setHidden:NO]; - [duplicateTableContextMenuItem setTitle:NSLocalizedString(@"Duplicate Function...", @"duplicate func menu title")]; - [truncateTableContextButton setHidden:YES]; - [removeTableContextMenuItem setTitle:NSLocalizedString(@"Remove Function", @"remove func menu title")]; - - } - // set window title - [tableWindow setTitle:[NSString stringWithFormat:@"(MySQL %@) %@/%@/%@", [tableDocumentInstance mySQLVersion], - [tableDocumentInstance name], [tableDocumentInstance database], [tables objectAtIndex:[tablesListView selectedRow]]]]; - - // Update the "Show Create Syntax" window if it's already opened - // according to the selected table/view/proc/func - if([[tableDocumentInstance getCreateTableSyntaxWindow] isVisible]) - [tableDocumentInstance showCreateTableSyntax:self]; - - } else { - [tableSourceInstance loadTable:nil]; - [tableContentInstance loadTable:nil]; - [extendedTableInfoInstance loadTable:nil]; - structureLoaded = NO; - contentLoaded = NO; - statusLoaded = NO; - // Set gear menu items Remove/Duplicate table/view according to the table types - // if at least one item is selected - NSIndexSet *indexes = [tablesListView selectedRowIndexes]; - if([indexes count]) { - unsigned int currentIndex = [indexes lastIndex]; - BOOL areTableTypeEqual = YES; - int lastType = [[tableTypes objectAtIndex:currentIndex] intValue]; - while (currentIndex != NSNotFound) - { - if([[tableTypes objectAtIndex:currentIndex] intValue]!=lastType) - { - areTableTypeEqual = NO; - break; - } - currentIndex = [indexes indexLessThanIndex:currentIndex]; - } - if(areTableTypeEqual) - { - switch(lastType) { - case SP_TABLETYPE_TABLE: - [removeTableMenuItem setTitle:NSLocalizedString(@"Remove Tables", @"remove tables menu title")]; - [truncateTableButton setTitle:NSLocalizedString(@"Truncate Tables", @"truncate tables menu item")]; - [removeTableContextMenuItem setTitle:NSLocalizedString(@"Remove Tables", @"remove tables menu title")]; - [truncateTableContextButton setTitle:NSLocalizedString(@"Truncate Tables", @"truncate tables menu item")]; - [truncateTableButton setHidden:NO]; - [truncateTableContextButton setHidden:NO]; - break; - case SP_TABLETYPE_VIEW: - [removeTableMenuItem setTitle:NSLocalizedString(@"Remove Views", @"remove views menu title")]; - [removeTableContextMenuItem setTitle:NSLocalizedString(@"Remove Views", @"remove views menu title")]; - [truncateTableButton setHidden:YES]; - [truncateTableContextButton setHidden:YES]; - break; - case SP_TABLETYPE_PROC: - [removeTableMenuItem setTitle:NSLocalizedString(@"Remove Procedures", @"remove procedures menu title")]; - [removeTableContextMenuItem setTitle:NSLocalizedString(@"Remove Procedures", @"remove procedures menu title")]; - [truncateTableButton setHidden:YES]; - [truncateTableContextButton setHidden:YES]; - break; - case SP_TABLETYPE_FUNC: - [removeTableMenuItem setTitle:NSLocalizedString(@"Remove Functions", @"remove functions menu title")]; - [removeTableContextMenuItem setTitle:NSLocalizedString(@"Remove Functions", @"remove functions menu title")]; - [truncateTableButton setHidden:YES]; - [truncateTableContextButton setHidden:YES]; - break; - } - - } else { - [removeTableMenuItem setTitle:NSLocalizedString(@"Remove Items", @"remove items menu title")]; - [removeTableContextMenuItem setTitle:NSLocalizedString(@"Remove Items", @"remove items menu title")]; - [truncateTableButton setHidden:YES]; - [truncateTableContextButton setHidden:YES]; - } - } - [renameTableContextMenuItem setHidden:YES]; - [duplicateTableContextMenuItem setHidden:YES]; - [separatorTableContextMenuItem setHidden:YES]; - - [renameTableMenuItem setHidden:YES]; - [duplicateTableMenuItem setHidden:YES]; - [separatorTableMenuItem setHidden:YES]; - [separatorTableContextMenuItem setHidden:YES]; - // set window title - [tableWindow setTitle:[NSString stringWithFormat:@"(MySQL %@) %@/%@", [tableDocumentInstance mySQLVersion], - [tableDocumentInstance name], [tableDocumentInstance database]]]; + // Perform no action if the selected table hasn't actually changed - reselection etc + if ([tablesListView numberOfSelectedRows] == 1 + && [[filteredTables objectAtIndex:[tablesListView selectedRow]] length] + && [selectedTableName isEqualToString:[filteredTables objectAtIndex:[tablesListView selectedRow]]] + && selectedTableType == [[filteredTableTypes objectAtIndex:[tablesListView selectedRow]] intValue]) + { + return; } + + [self updateSelection]; } /** @@ -1544,9 +1695,9 @@ - (BOOL)tableView:(NSTableView *)aTableView shouldSelectRow:(int)rowIndex { //return (rowIndex != 0); - if( [tableTypes count] == 0 ) + if( [filteredTableTypes count] == 0 ) return (rowIndex != 0 ); - return ([[tableTypes objectAtIndex:rowIndex] intValue] != SP_TABLETYPE_NONE ); + return ([[filteredTableTypes objectAtIndex:rowIndex] intValue] != SP_TABLETYPE_NONE ); } /** @@ -1555,9 +1706,9 @@ - (BOOL)tableView:(NSTableView *)aTableView isGroupRow:(int)rowIndex { //return (row == 0); - if( [tableTypes count] == 0 ) + if( [filteredTableTypes count] == 0 ) return (rowIndex == 0 ); - return ([[tableTypes objectAtIndex:rowIndex] intValue] == SP_TABLETYPE_NONE ); + return ([[filteredTableTypes objectAtIndex:rowIndex] intValue] == SP_TABLETYPE_NONE ); } /** @@ -1566,17 +1717,17 @@ - (void)tableView:(NSTableView *)aTableView willDisplayCell:(id)aCell forTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex { if (rowIndex > 0 && [[aTableColumn identifier] isEqualToString:@"tables"]) { - if ([[tableTypes objectAtIndex:rowIndex] intValue] == SP_TABLETYPE_VIEW) { + if ([[filteredTableTypes objectAtIndex:rowIndex] intValue] == SP_TABLETYPE_VIEW) { [(ImageAndTextCell*)aCell setImage:[NSImage imageNamed:@"table-view-small"]]; - } else if ([[tableTypes objectAtIndex:rowIndex] intValue] == SP_TABLETYPE_TABLE) { + } else if ([[filteredTableTypes objectAtIndex:rowIndex] intValue] == SP_TABLETYPE_TABLE) { [(ImageAndTextCell*)aCell setImage:[NSImage imageNamed:@"table-small"]]; - } else if ([[tableTypes objectAtIndex:rowIndex] intValue] == SP_TABLETYPE_PROC) { + } else if ([[filteredTableTypes objectAtIndex:rowIndex] intValue] == SP_TABLETYPE_PROC) { [(ImageAndTextCell*)aCell setImage:[NSImage imageNamed:@"proc-small"]]; - } else if ([[tableTypes objectAtIndex:rowIndex] intValue] == SP_TABLETYPE_FUNC) { + } else if ([[filteredTableTypes objectAtIndex:rowIndex] intValue] == SP_TABLETYPE_FUNC) { [(ImageAndTextCell*)aCell setImage:[NSImage imageNamed:@"func-small"]]; } - if ([[tableTypes objectAtIndex:rowIndex] intValue] == SP_TABLETYPE_NONE) { + if ([[filteredTableTypes objectAtIndex:rowIndex] intValue] == SP_TABLETYPE_NONE) { [(ImageAndTextCell*)aCell setImage:nil]; [(ImageAndTextCell*)aCell setIndentationLevel:0]; } else { @@ -1608,17 +1759,17 @@ ([self tableType] == SP_TABLETYPE_TABLE || [self tableType] == SP_TABLETYPE_VIEW) ) { if ( ([tabView indexOfTabViewItem:[tabView selectedTabViewItem]] == 0) && !structureLoaded ) { - [tableSourceInstance loadTable:[tables objectAtIndex:[tablesListView selectedRow]]]; + [tableSourceInstance loadTable:selectedTableName]; structureLoaded = YES; } if ( ([tabView indexOfTabViewItem:[tabView selectedTabViewItem]] == 1) && !contentLoaded ) { - [tableContentInstance loadTable:[tables objectAtIndex:[tablesListView selectedRow]]]; + [tableContentInstance loadTable:selectedTableName]; contentLoaded = YES; } if ( ([tabView indexOfTabViewItem:[tabView selectedTabViewItem]] == 3) && !statusLoaded ) { - [extendedTableInfoInstance loadTable:[tables objectAtIndex:[tablesListView selectedRow]]]; + [extendedTableInfoInstance loadTable:selectedTableName]; statusLoaded = YES; } } @@ -1649,6 +1800,125 @@ return [super validateMenuItem:menuItem]; } +#pragma mark Table list filter interaction + +/** + * Show the filter box if it's currently hidden. Use a delay to ensure + * action is executed on first load. + */ +- (void) showFilter +{ + if ([tableListFilterSplitView collapsibleSubviewIsCollapsed]) + [tableListFilterSplitView performSelector:@selector(toggleCollapse:) withObject:nil afterDelay:0.0]; +} + +/** + * Hide the filter box if it's currently shown. Use a delay to ensure + * action is executed on first load. + */ +- (void) hideFilter +{ + if (![tableListFilterSplitView collapsibleSubviewIsCollapsed]) + [tableListFilterSplitView performSelector:@selector(toggleCollapse:) withObject:nil afterDelay:0.0]; +} + +/** + * Clear the current content of the filter box + */ +- (void) clearFilter +{ + [listFilterField setStringValue:@""]; +} + +/** + * Update the filter search. + */ +- (IBAction) updateFilter:(id)sender +{ + if ([[listFilterField stringValue] length]) { + if (isTableListFiltered) { + [filteredTables release]; + [filteredTableTypes release]; + } + filteredTables = [[NSMutableArray alloc] init]; + filteredTableTypes = [[NSMutableArray alloc] init]; + + int i, lastTableType = NSNotFound, tableType; + NSRange substringRange; + for (i = 0; i < [tables count]; i++) { + tableType = [[tableTypes objectAtIndex:i] intValue]; + if (tableType == SP_TABLETYPE_NONE) continue; + substringRange = [[tables objectAtIndex:i] rangeOfString:[listFilterField stringValue] options:NSCaseInsensitiveSearch]; + if (substringRange.location == NSNotFound) continue; + + // Add a title if necessary + if ((tableType == SP_TABLETYPE_TABLE || tableType == SP_TABLETYPE_VIEW) && lastTableType == NSNotFound) + { + if (tableListContainsViews) { + [filteredTables addObject:NSLocalizedString(@"TABLES & VIEWS",@"header for table & views list")]; + } else { + [filteredTables addObject:NSLocalizedString(@"TABLES",@"header for table list")]; + } + [filteredTableTypes addObject:[NSNumber numberWithInt:SP_TABLETYPE_NONE]]; + } else if ((tableType == SP_TABLETYPE_PROC || tableType == SP_TABLETYPE_FUNC) + && (lastTableType == NSNotFound || lastTableType == SP_TABLETYPE_TABLE || lastTableType == SP_TABLETYPE_VIEW)) + { + [filteredTables addObject:NSLocalizedString(@"PROCS & FUNCS",@"header for procs & funcs list")]; + [filteredTableTypes addObject:[NSNumber numberWithInt:SP_TABLETYPE_NONE]]; + } + lastTableType = tableType; + + // Add the item + [filteredTables addObject:[tables objectAtIndex:i]]; + [filteredTableTypes addObject:[tableTypes objectAtIndex:i]]; + } + + // Add a "no matches" title if nothing matches the current filter settings + if (![filteredTables count]) { + [filteredTables addObject:NSLocalizedString(@"NO MATCHES",@"header for no matches in filtered list")]; + [filteredTableTypes addObject:[NSNumber numberWithInt:SP_TABLETYPE_NONE]]; + } + + // If the currently selected table isn't present in the filter list, add it as a special entry + if (selectedTableName && [filteredTables indexOfObject:selectedTableName] == NSNotFound) { + [filteredTables addObject:NSLocalizedString(@"CURRENT SELECTION",@"header for current selection in filtered list")]; + [filteredTableTypes addObject:[NSNumber numberWithInt:SP_TABLETYPE_NONE]]; + [filteredTables addObject:selectedTableName]; + [filteredTableTypes addObject:[NSNumber numberWithInt:selectedTableType]]; + } + +// [self performSelector:@selector(selectTableAtIndex:) withObject:[NSNumber numberWithInt:[filteredTables indexOfObject:selectedTableName]] afterDelay:0.0]; + isTableListFiltered = YES; + } else if (isTableListFiltered) { + isTableListFiltered = NO; + [filteredTables release]; + filteredTables = tables; + [filteredTableTypes release]; + filteredTableTypes = tableTypes; + if (selectedTableName) { +// [self performSelector:@selector(selectTableAtIndex:) withObject:[NSNumber numberWithInt:[tables indexOfObject:selectedTableName]] afterDelay:0.0]; + } + } + + // Reselect correct row and reload the table view display + if ([tablesListView numberOfRows] < [filteredTables count]) [tablesListView noteNumberOfRowsChanged]; + if (selectedTableName) [tablesListView selectRowIndexes:[NSIndexSet indexSetWithIndex:[filteredTables indexOfObject:selectedTableName]] byExtendingSelection:NO]; + [tablesListView reloadData]; +} + +/** + * Select the supplied row index; added for convenience to allow + * use with performSelector:withObject:afterDelay: for re-selection. + */ +- (void) selectTableAtIndex:(NSNumber *)rowIndex +{ +// int rowIndex = [rowIndex intValue]; +// if (rowIndex == NSNotFound || rowIndex > [filteredTables count] || [[filteredTableTypes objectAtIndex:rowIndex] intValue] == SP_TABLETYPE_NONE) +// return; +// +// [tablesListView selectRowIndexes:[NSIndexSet indexSetWithIndex:rowIndex] byExtendingSelection:NO]; +} + #pragma mark Other /** @@ -1658,10 +1928,16 @@ { if ((self = [super init])) { tables = [[NSMutableArray alloc] init]; + filteredTables = tables; tableTypes = [[NSMutableArray alloc] init]; + filteredTableTypes = tableTypes; structureLoaded = NO; contentLoaded = NO; statusLoaded = NO; + isTableListFiltered = NO; + tableListContainsViews = NO; + selectedTableType = SP_TABLETYPE_NONE; + selectedTableName = nil; [tables addObject:NSLocalizedString(@"TABLES",@"header for table list")]; } @@ -1682,6 +1958,14 @@ [[tableListSplitView collapsibleSubview] setFrameSize:NSMakeSize([tableListSplitView collapsibleSubview].frame.size.width, 0)]; [tableListSplitView setCollapsibleSubviewCollapsed:YES]; } + + // Start the table filter list collapsed + if ([tableListFilterSplitView collapsibleSubview]) { + [tableListFilterSplitView setValue:[NSNumber numberWithFloat:[tableListFilterSplitView collapsibleSubview].frame.size.height] forKey:@"uncollapsedSize"]; + [[tableListFilterSplitView collapsibleSubview] setFrameSize:NSMakeSize([tableListFilterSplitView collapsibleSubview].frame.size.width, 0)]; + [tableListFilterSplitView setCollapsibleSubviewCollapsed:YES]; + } + } /** @@ -1689,8 +1973,11 @@ */ - (void)dealloc { - [tables release], tables = nil; - [tableTypes release], tableTypes = nil; + [tables release]; + [tableTypes release]; + if (isTableListFiltered && filteredTables) [filteredTables release]; + if (isTableListFiltered && filteredTableTypes) [filteredTableTypes release]; + if (selectedTableName) [selectedTableName release]; [super dealloc]; } |