aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBibiko <bibiko@eva.mpg.de>2010-08-24 09:13:57 +0000
committerBibiko <bibiko@eva.mpg.de>2010-08-24 09:13:57 +0000
commit8e737837b17f564e9c04f336858d1bea4d1a13a5 (patch)
tree52077fde7a91ab0f0cc974de14bb793d07c70dff
parent3a072cc8ff3b6aad3951f19c23391c98f4e953fd (diff)
downloadsequelpro-8e737837b17f564e9c04f336858d1bea4d1a13a5.tar.gz
sequelpro-8e737837b17f564e9c04f336858d1bea4d1a13a5.tar.bz2
sequelpro-8e737837b17f564e9c04f336858d1bea4d1a13a5.zip
• introduced tri-state sort order for Content and Custom Query tables
- by clicking a the same table header the sort will changed to desc, asc, no sort order, desc, asc, etc. • fixed sorting issue for Custom Query table - reset sort order status before executing a new custom query • code cosmetics: reduced file size for SPCustomQuery.m
-rw-r--r--Source/SPCustomQuery.m397
-rw-r--r--Source/SPTableContent.m33
2 files changed, 242 insertions, 188 deletions
diff --git a/Source/SPCustomQuery.m b/Source/SPCustomQuery.m
index c7e0a9bf..8c2d7e83 100644
--- a/Source/SPCustomQuery.m
+++ b/Source/SPCustomQuery.m
@@ -68,6 +68,11 @@
return;
}
+ // Re-init sort order
+ isDesc = NO;
+ sortColumn = nil;
+ if(sortField) [sortField release], sortField = nil;
+
// Retrieve the custom query string and split it into separate SQL queries
queryParser = [[SPSQLParser alloc] initWithString:[textView string]];
[queryParser setDelimiterSupport:YES];
@@ -134,6 +139,11 @@
// Prevent multiple runs by holding the keys down
if ([tableDocumentInstance isWorking]) return;
+ // Re-init sort order
+ isDesc = NO;
+ sortColumn = nil;
+ if(sortField) [sortField release], sortField = nil;
+
// If the current selection is a single caret position, run the current query.
if (selectedRange.length == 0) {
// BOOL doLookBehind = YES;
@@ -192,7 +202,7 @@
- (IBAction)chooseQueryFavorite:(id)sender
{
if ([queryFavoritesButton indexOfSelectedItem] == 1) {
-
+
// This should never evaluate to true as we are now performing menu validation, meaning the 'Save Query to Favorites' menu item will
// only be enabled if the query text view has at least one character present.
if ([[textView string] isEqualToString:@""]) {
@@ -202,15 +212,15 @@
}
if ([tableDocumentInstance isUntitled]) [saveQueryFavoriteGlobal setState:NSOnState];
- [NSApp beginSheet:queryFavoritesSheet
- modalForWindow:[tableDocumentInstance parentWindow]
- modalDelegate:self
- didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:)
+ [NSApp beginSheet:queryFavoritesSheet
+ modalForWindow:[tableDocumentInstance parentWindow]
+ modalDelegate:self
+ didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:)
contextInfo:@"addSelectionToNewQueryFavorite"];
}
if ([queryFavoritesButton indexOfSelectedItem] == 2) {
-
+
// This should never evaluate to true as we are now performing menu validation, meaning the 'Save Query to Favorites' menu item will
// only be enabled if the query text view has at least one character present.
if ([[textView string] isEqualToString:@""]) {
@@ -220,10 +230,10 @@
}
if ([tableDocumentInstance isUntitled]) [saveQueryFavoriteGlobal setState:NSOnState];
- [NSApp beginSheet:queryFavoritesSheet
- modalForWindow:[tableDocumentInstance parentWindow]
- modalDelegate:self
- didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:)
+ [NSApp beginSheet:queryFavoritesSheet
+ modalForWindow:[tableDocumentInstance parentWindow]
+ modalDelegate:self
+ didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:)
contextInfo:@"addAllToNewQueryFavorite"];
}
else if ([queryFavoritesButton indexOfSelectedItem] == 3) {
@@ -234,12 +244,12 @@
favoritesManager = [[SPQueryFavoriteManager alloc] initWithDelegate:self];
// Open query favorite manager
- [NSApp beginSheet:[favoritesManager window]
- modalForWindow:[tableDocumentInstance parentWindow]
+ [NSApp beginSheet:[favoritesManager window]
+ modalForWindow:[tableDocumentInstance parentWindow]
modalDelegate:favoritesManager
- didEndSelector:nil
+ didEndSelector:nil
contextInfo:nil];
- }
+ }
else if ([queryFavoritesButton indexOfSelectedItem] > 5) {
// Choose favorite
BOOL replaceContent = [prefs boolForKey:SPQueryFavoriteReplacesContent];
@@ -339,14 +349,14 @@
[textView shiftSelectionLeft];
}
- // "Comment Line/Selection" menu item - Add or remove "-- " for each line
- // in a line or selection resp. or wrap the selection into /* */
+ // "Comment Line/Selection" menu item - Add or remove "-- " for each line
+ // in a line or selection resp. or wrap the selection into /* */
// if the selection does not end at the end of a line (in-line comment)
if (sender == commentLineOrSelectionMenuItem) {
[self commentOut];
}
- // "Comment Current Query" menu item - Add or remove "-- " for each line
+ // "Comment Current Query" menu item - Add or remove "-- " for each line
// in the current query
if (sender == commentCurrentQueryMenuItem) {
[self commentOutCurrentQueryTakingSelection:NO];
@@ -408,18 +418,18 @@
- (IBAction)saveQueryHistory:(id)sender
{
NSSavePanel *panel = [NSSavePanel savePanel];
-
+
[panel setRequiredFileType:SPFileExtensionSQL];
-
+
[panel setExtensionHidden:NO];
[panel setAllowsOtherFileTypes:YES];
[panel setCanSelectHiddenExtension:YES];
[panel setCanCreateDirectories:YES];
[panel setAccessoryView:[SPEncodingPopupAccessory encodingAccessory:[prefs integerForKey:SPLastSQLFileEncoding] includeDefaultEntry:NO encodingPopUp:&encodingPopUp]];
-
+
[encodingPopUp setEnabled:YES];
-
+
[panel beginSheetForDirectory:nil file:@"history" modalForWindow:[tableDocumentInstance parentWindow] modalDelegate:self didEndSelector:@selector(savePanelDidEnd:returnCode:contextInfo:) contextInfo:@"saveHistory"];
}
@@ -444,24 +454,24 @@
else
infoString = [NSString stringWithFormat:NSLocalizedString(@"Are you sure you want to clear the history list for “%@”? This action cannot be undone.", @"clear history list for “%@” informative message"), [tableDocumentInstance displayName]];
- NSAlert *alert = [NSAlert alertWithMessageText:NSLocalizedString(@"Clear History?", @"clear history message")
+ NSAlert *alert = [NSAlert alertWithMessageText:NSLocalizedString(@"Clear History?", @"clear history message")
defaultButton:NSLocalizedString(@"Clear", @"clear button")
alternateButton:NSLocalizedString(@"Cancel", @"cancel button")
otherButton:nil
informativeTextWithFormat:infoString];
[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:0] setKeyEquivalentModifierMask:NSCommandKeyMask];
[[buttons objectAtIndex:1] setKeyEquivalent:@"\r"];
-
- [alert beginSheetModalForWindow:[tableDocumentInstance parentWindow]
- modalDelegate:self
- didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:)
+
+ [alert beginSheetModalForWindow:[tableDocumentInstance parentWindow]
+ modalDelegate:self
+ didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:)
contextInfo:@"clearHistory"];
}
@@ -480,7 +490,7 @@
- (IBAction)toggleQueryInfoPaneCollapse:(id)sender
{
[queryInfoPaneSplitView toggleCollapse:sender];
-
+
[sender setToolTip:([sender state] == NSOffState) ? NSLocalizedString(@"Show Query Information", @"Show Query Information") : NSLocalizedString(@"Hide Query Information", @"Hide Query Information")];
}
@@ -507,7 +517,7 @@
if (customQueryCallbackMethod)
encodedCallbackMethod = [NSValue valueWithBytes:&customQueryCallbackMethod objCType:@encode(SEL)];
NSDictionary *taskArguments = [NSDictionary dictionaryWithObjectsAndKeys:queries, @"queries", encodedCallbackMethod, @"callback", nil];
-
+
// If a helper thread is already running, execute inline - otherwise detach a new thread for the queries
if ([NSThread isMainThread]) {
[NSThread detachNewThreadSelector:@selector(performQueriesTask:) toTarget:self withObject:taskArguments];
@@ -524,7 +534,7 @@
NSMutableString *errors = [NSMutableString string];
SEL callbackMethod = NULL;
NSString *taskButtonString;
-
+
NSInteger i, totalQueriesRun = 0, totalAffectedRows = 0;
double executionTime = 0;
NSInteger firstErrorOccuredInQuery = -1;
@@ -532,7 +542,7 @@
BOOL tableListNeedsReload = NO;
BOOL databaseWasChanged = NO;
// BOOL queriesSeparatedByDelimiter = NO;
-
+
NSCharacterSet *whitespaceAndNewlineSet = [NSCharacterSet whitespaceAndNewlineCharacterSet];
[tableDocumentInstance setQueryMode:SPCustomQueryQueryMode];
@@ -714,22 +724,22 @@
[tablesListInstance updateTables:self];
}
-
+
if(usedQuery)
[usedQuery release];
-
+
// if(!queriesSeparatedByDelimiter) // TODO: How to combine queries delimited by DELIMITER?
usedQuery = [[NSString stringWithString:[tempQueries componentsJoinedByString:@";\n"]] retain];
-
+
lastExecutedQuery = [[tempQueries lastObject] retain];
-
+
// Perform empty query if no query is given
if ( !queryCount ) {
streamingResult = [mySQLConnection streamingQueryString:@""];
[streamingResult cancelResultLoad];
[errors setString:[mySQLConnection getLastErrorMessage]];
}
-
+
// add query to history
if(!reloadingExistingResult && [usedQuery length])
[self performSelectorOnMainThread:@selector(addHistoryEntry:) withObject:usedQuery waitUntilDone:NO];
@@ -740,7 +750,7 @@
[NSNumber numberWithInteger:firstErrorOccuredInQuery], @"firstErrorQueryNumber",
nil];
[self performSelectorOnMainThread:@selector(updateStatusInterfaceWithDetails:) withObject:statusDetails waitUntilDone:YES];
-
+
// Set up the status string
if ( [mySQLConnection queryCancelled] ) {
if (totalQueriesRun > 1) {
@@ -786,7 +796,7 @@
[mySQLConnection setAllowQueryRetries:YES];
[tableDocumentInstance setQueryMode:SPInterfaceQueryMode];
-
+
// If no results were returned, redraw the empty table and post notifications before returning.
if ( !resultDataCount ) {
[customQueryView performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:YES];
@@ -796,7 +806,7 @@
// Perform the Growl notification for query completion
[[SPGrowlController sharedGrowlController] notifyWithTitle:@"Query Finished"
- description:[NSString stringWithFormat:NSLocalizedString(@"%@",@"description for query finished growl notification"), [errorText stringValue]]
+ description:[NSString stringWithFormat:NSLocalizedString(@"%@",@"description for query finished growl notification"), [errorText stringValue]]
document:tableDocumentInstance
notificationName:@"Query Finished"];
@@ -832,10 +842,10 @@
//query finished
[[NSNotificationCenter defaultCenter] postNotificationOnMainThreadWithName:@"SMySQLQueryHasBeenPerformed" object:tableDocumentInstance];
-
- // Query finished Growl notification
+
+ // Query finished Growl notification
[[SPGrowlController sharedGrowlController] notifyWithTitle:@"Query Finished"
- description:[NSString stringWithFormat:NSLocalizedString(@"%@",@"description for query finished growl notification"), [errorText stringValue]]
+ description:[NSString stringWithFormat:NSLocalizedString(@"%@",@"description for query finished growl notification"), [errorText stringValue]]
document:tableDocumentInstance
notificationName:@"Query Finished"];
@@ -896,13 +906,13 @@
[customQueryView performSelectorOnMainThread:@selector(noteNumberOfRowsChanged) withObject:nil waitUntilDone:NO];
[customQueryView setNeedsDisplay:YES];
-
+
// Clean up the autorelease pool
[dataLoadingPool drain];
}
/*
- * Retrieve the range of the query at a position specified
+ * Retrieve the range of the query at a position specified
* within the custom query text view.
*/
- (NSRange)queryRangeAtPosition:(NSUInteger)position lookBehind:(BOOL *)doLookBehind
@@ -911,7 +921,7 @@
NSArray *queries;
NSString *query = nil;
NSRange queryRange;
-
+
NSUInteger i, j, queryPosition = 0;
NSUInteger queryCount;
@@ -948,7 +958,7 @@
queryStartPosition = queryRange.location;
if (queryPosition >= position) {
-
+
// If lookbehind is enabled, check whether the current position could be considered to
// be within the previous query. A position just after a semicolon is always considered
// to be within the previous query; otherwise, if there is only whitespace *and newlines*
@@ -958,10 +968,10 @@
// If the caret is at the very start of the string, always associate
if (position == queryStartPosition) positionAssociatedWithPreviousQuery = YES;
-
+
// If the caret is in between a user-defined delimiter whose length is >1, always associate
if (!positionAssociatedWithPreviousQuery && i && NSMaxRange([NSArrayObjectAtIndex(queries, i-1) rangeValue]) < position && position < queryStartPosition) positionAssociatedWithPreviousQuery = YES;
-
+
// Otherwise associate if only whitespace since previous, and a newline before next.
if (!positionAssociatedWithPreviousQuery) {
@try{
@@ -996,12 +1006,12 @@
if (*doLookBehind && position == [[textView string] length])
{
queryRange = [[queries lastObject] rangeValue];
- }
+ }
[queries release];
-
- queryRange = NSIntersectionRange(queryRange, NSMakeRange(0, [[textView string] length]));
+
+ queryRange = NSIntersectionRange(queryRange, NSMakeRange(0, [[textView string] length]));
if (!queryRange.length) {
return NSMakeRange(NSNotFound, 0);
}
@@ -1027,7 +1037,7 @@
/*
* Retrieve the range of the query for the passed index seen from a start position
- * specified within the custom query text view.
+ * specified within the custom query text view.
*/
- (NSRange)queryTextRangeForQuery:(NSInteger)anIndex startPosition:(NSUInteger)position
{
@@ -1054,9 +1064,9 @@
NSRange theQueryRange = [[queries objectAtIndex:anIndex] rangeValue];
NSString *theQueryString = [[textView string] substringWithRange:theQueryRange];
-
+
[queries release];
-
+
// Remove all leading and trailing white spaces
NSInteger offset = [theQueryString rangeOfRegex:@"^(\\s*)"].length;
theQueryRange.location += offset;
@@ -1079,7 +1089,7 @@
BOOL lookBehind = *doLookBehind;
NSRange queryRange = [self queryRangeAtPosition:position lookBehind:&lookBehind];
*doLookBehind = lookBehind;
-
+
return (queryRange.length) ? [[textView string] substringWithRange:queryRange] : nil;
}
@@ -1099,7 +1109,7 @@
BOOL isUncomment = NO;
NSRange oldRange = [textView selectedRange];
-
+
NSRange workingRange = oldRange;
if(!takeSelection)
workingRange = currentQueryRange;
@@ -1113,14 +1123,14 @@
[n replaceOccurrencesOfRegex:@"\\n\\Z" withString:@""];
}
- // Escape given */ by *\/
+ // Escape given */ by *\/
[n replaceOccurrencesOfRegex:@"\\*/(?=.)" withString:@"*\\\\/"];
[n replaceOccurrencesOfRegex:@"\\*/(?=\\n)" withString:@"*\\\\/"];
// Wrap current query into /* */
[n replaceOccurrencesOfRegex:@"^" withString:@"/* "];
[n appendString:@" */"];
-
+
// Check if current query/selection is already commented out, if so uncomment it
if([n isMatchedByRegex:@"^/\\* \\s*/\\*\\s*(.|\\n)*?\\s*\\*/ \\*/\\s*$"]) {
[n replaceOccurrencesOfRegex:@"^/\\* \\s*/\\*\\s*" withString:@""];
@@ -1133,8 +1143,8 @@
// Replace current query/selection by (un)commented string
[textView setSelectedRange:workingRange];
[textView insertText:n];
-
- // If commenting out locate the caret just after the first /* to allow to enter
+
+ // If commenting out locate the caret just after the first /* to allow to enter
// something like /*!400000 or similar
if(!isUncomment)
[textView setSelectedRange:NSMakeRange(workingRange.location+2,0)];
@@ -1150,11 +1160,11 @@
{
NSRange oldRange = [textView selectedRange];
-
+
if(oldRange.length) { // (un)comment selection
[self commentOutCurrentQueryTakingSelection:YES];
} else { // single line
-
+
// get the current line range
NSRange lineRange = [[textView string] lineRangeForRange:oldRange];
NSMutableString *n = [NSMutableString string];
@@ -1165,27 +1175,27 @@
// Check if current line is already commented out, if so uncomment it
// and preserve the original indention via regex:@"^-- (\\s*)"
if([n isMatchedByRegex:@"^-- \\s*(--\\s|#)"]) {
- [n replaceOccurrencesOfRegex:@"^-- \\s*(--\\s|#)"
- withString:[n substringWithRange:[n rangeOfRegex:@"^-- (\\s*)"
- options:RKLNoOptions
- inRange:NSMakeRange(0,[n length])
+ [n replaceOccurrencesOfRegex:@"^-- \\s*(--\\s|#)"
+ withString:[n substringWithRange:[n rangeOfRegex:@"^-- (\\s*)"
+ options:RKLNoOptions
+ inRange:NSMakeRange(0,[n length])
capture:1
error: nil]]];
} else if ([n isMatchedByRegex:@"^-- \\s*/\\*.*? ?\\*/\\s*$"]) {
- [n replaceOccurrencesOfRegex:@"^-- \\s*/\\* ?"
- withString:[n substringWithRange:[n rangeOfRegex:@"^-- (\\s*)"
- options:RKLNoOptions
- inRange:NSMakeRange(0,[n length])
+ [n replaceOccurrencesOfRegex:@"^-- \\s*/\\* ?"
+ withString:[n substringWithRange:[n rangeOfRegex:@"^-- (\\s*)"
+ options:RKLNoOptions
+ inRange:NSMakeRange(0,[n length])
capture:1
error: nil]]];
- [n replaceOccurrencesOfRegex:@" ?\\*/\\s*$"
- withString:[n substringWithRange:[n rangeOfRegex:@" ?\\*/(\\s*)$"
- options:RKLNoOptions
- inRange:NSMakeRange(0,[n length])
+ [n replaceOccurrencesOfRegex:@" ?\\*/\\s*$"
+ withString:[n substringWithRange:[n rangeOfRegex:@" ?\\*/(\\s*)$"
+ options:RKLNoOptions
+ inRange:NSMakeRange(0,[n length])
capture:1
error: nil]]];
}
-
+
// Replace current line by (un)commented string
// The caret will be placed at the beginning of the next line if present to
// allow a fast (un)commenting of lines
@@ -1249,7 +1259,7 @@
[textView selectLineNumber:errorAtLine+lineOffset ignoreLeadingNewLines:YES];
}
} else { // Select first erroneous query entirely
-
+
NSRange queryRange;
if(firstErrorOccuredInQuery == -1) // for current or previous query
{
@@ -1351,8 +1361,8 @@
#pragma mark Accessors
/*
- * Returns the current result (as shown in custom result view) as array,
- * the first object containing the field names as array,
+ * Returns the current result (as shown in custom result view) as array,
+ * the first object containing the field names as array,
* the following objects containing the rows as array
*/
- (NSArray *)currentResult
@@ -1363,13 +1373,13 @@
NSMutableArray *currentResult = [NSMutableArray array];
NSMutableArray *tempRow = [NSMutableArray array];
NSInteger i;
-
+
//set field names as first line
while ( (tableColumn = [enumerator nextObject]) ) {
[tempRow addObject:[[tableColumn headerCell] stringValue]];
}
[currentResult addObject:[NSArray arrayWithArray:tempRow]];
-
+
//add rows
for ( i = 0 ; i < [self numberOfRowsInTableView:customQueryView] ; i++) {
[tempRow removeAllObjects];
@@ -1386,7 +1396,7 @@
#pragma mark Additional methods
/*
- * Sets the connection (received from SPDatabaseDocument) and makes things that have to be done only once
+ * Sets the connection (received from SPDatabaseDocument) and makes things that have to be done only once
*/
- (void)setConnection:(MCPConnection *)theConnection
{
@@ -1406,7 +1416,7 @@
// Populate query favorites
[self queryFavoritesHaveBeenUpdated:nil];
-
+
// Disable runSelectionMenuItem in the gear menu
[runSelectionMenuItem setEnabled:NO];
}
@@ -1599,7 +1609,7 @@
dataRow = [resultData rowContentsAtIndex:rowIndex];
// Get the primary key if there is one
- MCPResult *theResult = [mySQLConnection queryString:[NSString stringWithFormat:@"SHOW COLUMNS FROM %@.%@",
+ MCPResult *theResult = [mySQLConnection queryString:[NSString stringWithFormat:@"SHOW COLUMNS FROM %@.%@",
[database backtickQuotedString], [tableForColumn backtickQuotedString]]];
[theResult setReturnDataAsStrings:YES];
if ([theResult numOfRows]) [theResult dataSeek:0];
@@ -1610,17 +1620,17 @@
for(field in columnsForFieldTableName) {
id aValue = [dataRow objectAtIndex:[[field objectForKey:@"datacolumnindex"] integerValue]];
if([[field objectForKey:@"org_name"] isEqualToString:[theRow objectForKey:@"Field"]]) {
- [fieldIDQueryStr appendFormat:@"%@.%@.%@ = %@)",
- [database backtickQuotedString],
- [tableForColumn backtickQuotedString],
- [[theRow objectForKey:@"Field"] backtickQuotedString],
+ [fieldIDQueryStr appendFormat:@"%@.%@.%@ = %@)",
+ [database backtickQuotedString],
+ [tableForColumn backtickQuotedString],
+ [[theRow objectForKey:@"Field"] backtickQuotedString],
[aValue description]];
return fieldIDQueryStr;
}
}
}
}
-
+
// If there is no primary key, all found fields belonging to the same table are used in the argument
for(field in columnsForFieldTableName) {
id aValue = [dataRow objectAtIndex:[[field objectForKey:@"datacolumnindex"] integerValue]];
@@ -1637,13 +1647,13 @@
else
[fieldIDQueryStr appendFormat:@"'%@'", [mySQLConnection prepareString:aValue]];
}
-
+
[fieldIDQueryStr appendString:@" AND "];
}
// Remove last " AND "
if([fieldIDQueryStr length]>12)
[fieldIDQueryStr replaceCharactersInRange:NSMakeRange([fieldIDQueryStr length]-5,5) withString:@")"];
-
+
return fieldIDQueryStr;
}
@@ -1657,7 +1667,7 @@
{
if (aTableView == customQueryView) {
return (resultData == nil) ? 0 : resultDataCount;
- }
+ }
else {
return 0;
}
@@ -1667,10 +1677,10 @@
* This function changes the text color of text/blob fields whose content is NULL.
*/
- (void)tableView:(SPCopyTable *)aTableView willDisplayCell:(id)cell forTableColumn:(NSTableColumn*)aTableColumn row:(NSInteger)rowIndex
-{
+{
if (aTableView == customQueryView) {
- // For NULL cell's display the user's NULL value placeholder in grey to easily distinguish it from other values
+ // For NULL cell's display the user's NULL value placeholder in grey to easily distinguish it from other values
if ([cell respondsToSelector:@selector(setTextColor:)]) {
NSUInteger columnIndex = [[aTableColumn identifier] integerValue];
id theValue = nil;
@@ -1692,7 +1702,7 @@
} else {
theValue = SPDataStorageObjectAtRowAndColumn(resultData, rowIndex, columnIndex);
}
-
+
[cell setTextColor:[theValue isNSNull] ? [NSColor lightGrayColor] : [NSColor blackColor]];
}
}
@@ -1722,7 +1732,7 @@
} else {
theValue = SPDataStorageObjectAtRowAndColumn(resultData, rowIndex, columnIndex);
}
-
+
if ([theValue isKindOfClass:[NSData class]])
return [theValue shortStringRepresentationUsingEncoding:[mySQLConnection encoding]];
@@ -1772,7 +1782,7 @@
NSInteger numberOfPossibleUpdateRows = [[[[mySQLConnection queryString:[NSString stringWithFormat:@"SELECT COUNT(1) FROM %@.%@ %@", [[columnDefinition objectForKey:@"db"] backtickQuotedString], [tableForColumn backtickQuotedString], fieldIDQueryString]] fetchRowAsArray] objectAtIndex:0] integerValue];
if(numberOfPossibleUpdateRows == 1) {
// [[NSNotificationCenter defaultCenter] postNotificationName:@"SMySQLQueryWillBePerformed" object:tableDocumentInstance];
-
+
NSString *newObject = nil;
if ( [anObject isKindOfClass:[NSCalendarDate class]] ) {
newObject = [NSString stringWithFormat:@"'%@'", [mySQLConnection prepareString:[anObject description]]];
@@ -1796,10 +1806,10 @@
}
[mySQLConnection queryString:
- [NSString stringWithFormat:@"UPDATE %@.%@ SET %@.%@.%@ = %@ %@ LIMIT 1",
+ [NSString stringWithFormat:@"UPDATE %@.%@ SET %@.%@.%@ = %@ %@ LIMIT 1",
[[columnDefinition objectForKey:@"db"] backtickQuotedString], [tableForColumn backtickQuotedString],
[[columnDefinition objectForKey:@"db"] backtickQuotedString], [tableForColumn backtickQuotedString], [columnName backtickQuotedString], newObject, fieldIDQueryString]];
-
+
// [[NSNotificationCenter defaultCenter] postNotificationName:@"SMySQLQueryHasBeenPerformed" object:tableDocumentInstance];
// Check for errors while UPDATE
@@ -1821,7 +1831,7 @@
}
return;
}
-
+
// On success reload table data by executing the last query if reloading is enabled
if ([prefs boolForKey:SPReloadAfterEditingRow]) {
reloadingExistingResult = YES;
@@ -1834,7 +1844,7 @@
}
} else {
SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [tableDocumentInstance parentWindow], self, nil, nil,
- [NSString stringWithFormat:NSLocalizedString(@"Updating field content failed. Couldn't identify field origin unambiguously (%ld match%@). It's very likely that while editing this field the table `%@` was changed by an other user.", @"message of panel when error while updating field to db after enabling it"),
+ [NSString stringWithFormat:NSLocalizedString(@"Updating field content failed. Couldn't identify field origin unambiguously (%ld match%@). It's very likely that while editing this field the table `%@` was changed by an other user.", @"message of panel when error while updating field to db after enabling it"),
(long)numberOfPossibleUpdateRows, (numberOfPossibleUpdateRows>1)?@"es":@"", tableForColumn]);
}
@@ -1854,20 +1864,46 @@
NSMutableString *queryString = [NSMutableString stringWithString:lastExecutedQuery];
- //sets order descending if a header is clicked twice
- if ( sortField && [[tableColumn identifier] isEqualToNumber:sortField] ) {
- isDesc = !isDesc;
+ // Sets column order as tri-state descending, ascending, no sort, descending, ascending etc. order if the same
+ // header is clicked several times
+ if (sortField && [[tableColumn identifier] isEqualToNumber:sortField]) {
+ if(isDesc) {
+ [sortField release];
+ sortField = nil;
+ } else {
+ if (sortField) [sortField release];
+ sortField = [[NSNumber alloc] initWithInteger:[[tableColumn identifier] integerValue]];
+ isDesc = !isDesc;
+ }
} else {
isDesc = NO;
- if (sortField) [customQueryView setIndicatorImage:nil inTableColumn:[customQueryView tableColumnWithIdentifier:sortField]];
+ [[customQueryView onMainThread] setIndicatorImage:nil inTableColumn:[customQueryView tableColumnWithIdentifier:sortField]];
+ if (sortField) [sortField release];
+ sortField = [[NSNumber alloc] initWithInteger:[[tableColumn identifier] integerValue]];
}
- if (sortField) [sortField release];
- sortField = [[NSNumber alloc] initWithInteger:[[tableColumn identifier] integerValue]];
+ if(sortField) {
+ // Set the highlight and indicatorImage
+ [[customQueryView onMainThread] setHighlightedTableColumn:tableColumn];
+ if (isDesc) {
+ [[customQueryView onMainThread] setIndicatorImage:[NSImage imageNamed:@"NSDescendingSortIndicator"] inTableColumn:tableColumn];
+ } else {
+ [[customQueryView onMainThread] setIndicatorImage:[NSImage imageNamed:@"NSAscendingSortIndicator"] inTableColumn:tableColumn];
+ }
+ } else {
+ // If no sort order deselect column header and
+ // remove indicator image
+ [[customQueryView onMainThread] setHighlightedTableColumn:nil];
+ [[customQueryView onMainThread] setIndicatorImage:nil inTableColumn:tableColumn];
+ }
+
+ // Order by the column position number to avoid ambiguous name errors if any
+ NSString* newOrder;
+ if(sortField)
+ newOrder = [NSString stringWithFormat:@" ORDER BY %ld %@ ", (long)([[tableColumn identifier] integerValue]+1), (isDesc)?@"DESC":@"ASC"];
+ else
+ newOrder = @"";
- // Order by the column position number to avoid ambiguous name errors
- NSString* newOrder = [NSString stringWithFormat:@" ORDER BY %ld %@ ", (long)([[tableColumn identifier] integerValue]+1), (isDesc)?@"DESC":@"ASC"];
-
// Remove any comments
[queryString replaceOccurrencesOfRegex:@"--.*?\n" withString:@""];
[queryString replaceOccurrencesOfRegex:@"--.*?$" withString:@""];
@@ -1935,7 +1971,10 @@
reloadingExistingResult = YES;
[self storeCurrentResultViewForRestoration];
queryIsTableSorter = YES;
- sortColumn = tableColumn;
+ if(sortField)
+ sortColumn = tableColumn;
+ else
+ sortColumn = nil;
[self performQueries:[NSArray arrayWithObject:queryString] withCallback:@selector(tableSortCallback)];
}
@@ -1967,7 +2006,7 @@
NSString *tmp = [customQueryView draggedRowsAsTabString];
if ( nil != tmp )
{
- [pboard declareTypes:[NSArray arrayWithObjects: NSTabularTextPboardType,
+ [pboard declareTypes:[NSArray arrayWithObjects: NSTabularTextPboardType,
NSStringPboardType, nil]
owner:nil];
[pboard setString:tmp forType:NSStringPboardType];
@@ -1992,7 +2031,7 @@
if ([[pboardTypes objectAtIndex:0] isEqualToString:@"SequelProPasteboard"]==YES && operation==NSTableViewDropAbove)
{
originalRow = [[[info draggingPasteboard] stringForType:@"SequelProPasteboard"] intValue];
-
+
if (row != originalRow && row != (originalRow+1))
{
return NSDragOperationMove;
@@ -2014,17 +2053,17 @@
if ( aTableView == queryFavoritesView ) {
originalRow = [[[info draggingPasteboard] stringForType:@"SequelProPasteboard"] intValue];
destinationRow = row;
-
+
if ( destinationRow > originalRow )
destinationRow--;
-
+
draggedRow = [queryFavorites objectAtIndex:originalRow];
[queryFavorites removeObjectAtIndex:originalRow];
[queryFavorites insertObject:draggedRow atIndex:destinationRow];
-
+
[queryFavoritesView reloadData];
[queryFavoritesView selectRowIndexes:[NSIndexSet indexSetWithIndex:destinationRow] byExtendingSelection:NO];
-
+
return YES;
} else {
return NO;
@@ -2072,12 +2111,12 @@
// Show the cell string value as tooltip (including line breaks and tabs)
// by using the cell's font
- [SPTooltip showWithObject:[aCell stringValue]
- atLocation:pos
- ofType:@"text"
+ [SPTooltip showWithObject:[aCell stringValue]
+ atLocation:pos
+ ofType:@"text"
displayOptions:[NSDictionary dictionaryWithObjectsAndKeys:
- [[aCell font] familyName], @"fontname",
- [NSString stringWithFormat:@"%f",[[aCell font] pointSize]], @"fontsize",
+ [[aCell font] familyName], @"fontname",
+ [NSString stringWithFormat:@"%f",[[aCell font] pointSize]], @"fontsize",
nil]];
return nil;
@@ -2127,11 +2166,11 @@
// or the field data are not bound to any table as in SELECT 1 or if column database is unset
if(!tableForColumn || ![tableForColumn length] || ![dbForColumn length])
noTableName = YES;
-
+
if(!noTableName) {
// if table and database name are given check if field can be identified unambiguously
fieldIDQueryString = [self argumentForRow:rowIndex ofTable:tableForColumn andDatabase:[columnDefinition objectForKey:@"db"]];
-
+
// Actual check whether field can be identified bijectively
numberOfPossibleUpdateRows = [[[[mySQLConnection queryString:[NSString stringWithFormat:@"SELECT COUNT(1) FROM %@.%@ %@", [[columnDefinition objectForKey:@"db"] backtickQuotedString], [tableForColumn backtickQuotedString], fieldIDQueryString]] fetchRowAsArray] objectAtIndex:0] integerValue];
@@ -2168,9 +2207,9 @@
id editData = [[fieldEditor editWithObject:originalData
fieldName:[columnDefinition objectForKey:@"name"]
- usingEncoding:[mySQLConnection encoding]
- isObjectBlob:isBlob
- isEditable:isFieldEditable
+ usingEncoding:[mySQLConnection encoding]
+ isObjectBlob:isBlob
+ isEditable:isFieldEditable
withWindow:[tableDocumentInstance parentWindow]] retain];
if ( editData )
@@ -2221,7 +2260,7 @@
NSString *host_db = [NSString stringWithFormat:@"%@@%@", [columnDefinition objectForKey:@"db"], [tableDocumentInstance host]];
NSString *table = [columnDefinition objectForKey:@"org_table"];
NSString *col = [columnDefinition objectForKey:@"org_name"];
-
+
// Retrieve or instantiate the tableColumnWidths object
if ([prefs objectForKey:SPTableColumnWidths] != nil) {
tableColumnWidths = [NSMutableDictionary dictionaryWithDictionary:[prefs objectForKey:SPTableColumnWidths]];
@@ -2235,7 +2274,7 @@
} else {
[tableColumnWidths setObject:[NSMutableDictionary dictionaryWithDictionary:[tableColumnWidths objectForKey:host_db]] forKey:host_db];
}
-
+
// Edit or create table object
if ([[tableColumnWidths objectForKey:host_db] objectForKey:table] == nil) {
[[tableColumnWidths objectForKey:host_db] setObject:[NSMutableDictionary dictionary] forKey:table];
@@ -2304,7 +2343,7 @@
} else {
return NO;
}
-
+
} else if ( aTextView == valueTextField ) {
if ( [aTextView methodForSelector:aSelector] == [aTextView methodForSelector:@selector(insertNewline:)] )
{
@@ -2467,7 +2506,7 @@
{
mySQLversion = [[theVersion substringToIndex:3] retain];
[textView setConnection:mySQLConnection withVersion:[[[mySQLversion componentsSeparatedByString:@"."] objectAtIndex:0] integerValue]];
-
+
}
/*
@@ -2498,7 +2537,7 @@
{
// set title of the Help window
[helpWebViewWindow setTitle:[NSString stringWithFormat:@"%@ (%@ %@)", NSLocalizedString(@"MySQL Help", @"mysql help"), NSLocalizedString(@"version", @"version"), mySQLversion]];
-
+
// init goback/forward buttons
if([[helpWebView backForwardList] backListCount] < 1)
{
@@ -2517,15 +2556,15 @@
// order out Help window if Help is available
if(![helpString isEqualToString:SP_HELP_NOT_AVAILABLE])
[helpWebViewWindow orderFront:helpWebView];
-
+
}
// close Help window if no Help available
if([helpString isEqualToString:SP_HELP_NOT_AVAILABLE])
[helpWebViewWindow close];
-
+
if(![helpString length]) return;
-
+
// add searchString to history list
if(addToHistory)
{
@@ -2537,10 +2576,10 @@
// validate goback/forward buttons
[helpNavigator setEnabled:[[helpWebView backForwardList] backListCount] forSegment:SP_HELP_GOBACK_BUTTON];
[helpNavigator setEnabled:[[helpWebView backForwardList] forwardListCount] forSegment:SP_HELP_GOFORWARD_BUTTON];
-
+
// load HTML formatted help into the webview
[[helpWebView mainFrame] loadHTMLString:helpString baseURL:nil];
-
+
}
@@ -2635,7 +2674,7 @@
// validate goback and goforward buttons according history
[helpNavigator setEnabled:[[helpWebView backForwardList] backListCount] forSegment:SP_HELP_GOBACK_BUTTON];
[helpNavigator setEnabled:[[helpWebView backForwardList] forwardListCount] forSegment:SP_HELP_GOFORWARD_BUTTON];
-
+
}
/*
@@ -2730,14 +2769,14 @@
{
if(![searchString length]) return @"";
-
+
NSRange aRange;
MCPResult *theResult = nil;
NSDictionary *tableDetails;
NSMutableString *theHelp = [NSMutableString string];
[theHelp setString:@""];
-
+
// search via: HELP 'searchString'
theResult = [mySQLConnection queryString:[NSString stringWithFormat:@"HELP '%@'", [searchString stringByReplacingOccurrencesOfString:@"'" withString:@"\\'"]]];
if ([mySQLConnection queryErrored])
@@ -2771,7 +2810,7 @@
NSMutableString *desc = [NSMutableString string];
NSError *err1 = NULL;
NSString *aUrl;
-
+
[desc setString:[[[tableDetails objectForKey:@"description"] copy] autorelease]];
//[desc replaceOccurrencesOfString:[searchString uppercaseString] withString:[NSString stringWithFormat:@"<span class='searchstring'>%@</span>", [searchString uppercaseString]] options:NSLiteralSearch range:NSMakeRange(0,[desc length])];
@@ -2847,14 +2886,14 @@
for ( i = 0 ; i < r ; i++ ) {
NSArray *anArray = [theResult fetchRowAsArray];
NSString *topic = [anArray objectAtIndex:[anArray count]-2];
- [theHelp appendFormat:@"<li><a title='%@ “%@”' href='%@' class='internallink'>%@</a></li>",
+ [theHelp appendFormat:@"<li><a title='%@ “%@”' href='%@' class='internallink'>%@</a></li>",
NSLocalizedString(@"Show MySQL help for", @"show mysql help for"), topic, topic, topic];
}
[theHelp appendString:@"</ul>"];
}
[tableDetails release];
-
+
return [NSString stringWithFormat:helpHTMLTemplate, theHelp];
}
@@ -2908,10 +2947,10 @@
{
NSMutableArray *webViewMenuItems = [[defaultMenuItems mutableCopy] autorelease];
-
+
if (webViewMenuItems)
{
- // Remove all needless default menu items
+ // Remove all needless default menu items
NSEnumerator *itemEnumerator = [defaultMenuItems objectEnumerator];
NSMenuItem *menuItem = nil;
while (menuItem = [itemEnumerator nextObject])
@@ -2943,8 +2982,8 @@
}
// Add two menu items for a selection if no link is given
- if(webViewMenuItems
- && [[element objectForKey:@"WebElementIsSelected"] boolValue]
+ if(webViewMenuItems
+ && [[element objectForKey:@"WebElementIsSelected"] boolValue]
&& ![[element objectForKey:@"WebElementLinkIsLive"] boolValue])
{
@@ -2986,7 +3025,7 @@
NSMenu* historyMenu = [queryHistoryButton menu];
while([queryHistoryButton numberOfItems] > 7)
[queryHistoryButton removeItemAtIndex:[queryHistoryButton numberOfItems]-1];
-
+
NSUInteger numberOfHistoryItems = [[SPQueryController sharedQueryController] numberOfHistoryItemsForFileURL:[tableDocumentInstance fileURL]];
if(numberOfHistoryItems>0)
for(id historyMenuItem in [[SPQueryController sharedQueryController] historyMenuItemsForFileURL:[tableDocumentInstance fileURL]])
@@ -3003,13 +3042,13 @@
// Remove all favorites beginning from the end
while([queryFavoritesButton numberOfItems] > 7)
[queryFavoritesButton removeItemAtIndex:[queryFavoritesButton numberOfItems]-1];
-
+
// Build document-based list
headerMenuItem = [[NSMenuItem alloc] initWithTitle:
- [[[[tableDocumentInstance fileURL] absoluteString] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding] lastPathComponent]
+ [[[[tableDocumentInstance fileURL] absoluteString] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding] lastPathComponent]
action:NULL keyEquivalent:@""];
[headerMenuItem setTag:SP_FAVORITE_HEADER_MENUITEM_TAG];
- [headerMenuItem setToolTip:[NSString stringWithFormat:@"‘%@’ based favorites",
+ [headerMenuItem setToolTip:[NSString stringWithFormat:@"‘%@’ based favorites",
[[[[tableDocumentInstance fileURL] absoluteString] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding] lastPathComponent]]];
[headerMenuItem setIndentationLevel:0];
[menu addItem:headerMenuItem];
@@ -3126,7 +3165,7 @@
* This method is called as part of Key Value Observing which is used to watch for prefernce changes which effect the interface.
*/
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
-{
+{
// Display table veiew vertical gridlines preference changed
if ([keyPath isEqualToString:SPDisplayTableViewVerticalGridlines]) {
[customQueryView setGridStyleMask:([[change objectForKey:NSKeyValueChangeNewKey] boolValue]) ? NSTableViewSolidVerticalGridLineMask : NSTableViewGridNone];
@@ -3161,7 +3200,7 @@
if ([contextInfo isEqualToString:@"addAllToNewQueryFavorite"] || [contextInfo isEqualToString:@"addSelectionToNewQueryFavorite"]) {
if (returnCode == NSOKButton) {
-
+
// Add the new query favorite directly the user's preferences here instead of asking the manager to do it
// as it may not have been fully initialized yet.
NSMutableArray *favorites = [NSMutableArray arrayWithArray:[prefs objectForKey:SPQueryFavorites]];
@@ -3182,16 +3221,16 @@
} else {
queryToBeAddded = [textView string];
}
-
+
if([saveQueryFavoriteGlobal state] == NSOnState) {
[favorites addObject:[NSMutableDictionary dictionaryWithObjects:
- [NSArray arrayWithObjects:[queryFavoriteNameTextField stringValue], queryToBeAddded, nil]
+ [NSArray arrayWithObjects:[queryFavoriteNameTextField stringValue], queryToBeAddded, nil]
forKeys:[NSArray arrayWithObjects:@"name", @"query", nil]]];
-
+
[prefs setObject:favorites forKey:SPQueryFavorites];
} else {
[[SPQueryController sharedQueryController] addFavorite:[NSMutableDictionary dictionaryWithObjects:
- [NSArray arrayWithObjects:[queryFavoriteNameTextField stringValue], [[queryToBeAddded mutableCopy] autorelease], nil]
+ [NSArray arrayWithObjects:[queryFavoriteNameTextField stringValue], [[queryToBeAddded mutableCopy] autorelease], nil]
forKeys:[NSArray arrayWithObjects:@"name", @"query", nil]] forFileURL:[tableDocumentInstance fileURL]];
}
@@ -3201,7 +3240,7 @@
}
}
-
+
[queryFavoriteNameTextField setStringValue:@""];
}
@@ -3210,15 +3249,15 @@
if([contextInfo isEqualToString:@"saveHistory"]) {
if (returnCode == NSOKButton) {
NSError *error = nil;
-
+
[prefs setInteger:[[encodingPopUp selectedItem] tag] forKey:SPLastSQLFileEncoding];
[prefs synchronize];
-
- [[self buildHistoryString] writeToFile:[panel filename]
- atomically:YES
- encoding:[[encodingPopUp selectedItem] tag]
+
+ [[self buildHistoryString] writeToFile:[panel filename]
+ atomically:YES
+ encoding:[[encodingPopUp selectedItem] tag]
error:&error];
-
+
if (error) [[NSAlert alertWithError:error] runModal];
}
}
@@ -3271,7 +3310,7 @@
- (id)init
{
if ((self = [super init])) {
-
+
usedQuery = [[NSString stringWithString:@""] retain];
sortField = nil;
@@ -3287,22 +3326,22 @@
// init helpHTMLTemplate
NSError *error;
-
+
helpHTMLTemplate = [[NSString alloc]
initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:SPHTMLHelpTemplate ofType:@"html"]
encoding:NSUTF8StringEncoding
error:&error];
-
+
// an error occurred while reading
if (helpHTMLTemplate == nil) {
NSLog(@"%@", [NSString stringWithFormat:@"Error reading “%@.html”!<br>%@", SPHTMLHelpTemplate, [error localizedFailureReason]]);
NSBeep();
}
-
+
// init search history
[helpWebView setMaintainsBackForwardList:YES];
[[helpWebView backForwardList] setCapacity:20];
-
+
// init tableView's data source
resultDataCount = 0;
resultData = [[SPDataStorage alloc] init];
@@ -3328,10 +3367,10 @@
NSUInteger i;
NSMenu *menu = [queryFavoritesButton menu];
NSString *searchPattern = [queryFavoritesSearchField stringValue];
-
+
for (i = 7; i < [menu numberOfItems]; i++)
{
- [[menu itemAtIndex:i] setHidden:([[menu itemAtIndex:i] tag] != SP_FAVORITE_HEADER_MENUITEM_TAG
+ [[menu itemAtIndex:i] setHidden:([[menu itemAtIndex:i] tag] != SP_FAVORITE_HEADER_MENUITEM_TAG
&& ![[[menu itemAtIndex:i] title] isMatchedByRegex:[NSString stringWithFormat:@"(?i).*%@.*", searchPattern]])];
}
}
@@ -3384,7 +3423,7 @@
// if(item == queryHistorySearchMenuItem) {
// [queryHistorySearchField selectText:nil];
// }
-//
+//
// }
/**
@@ -3392,13 +3431,13 @@
*/
- (void)awakeFromNib
{
- // Set pre-defined menu tags
+ // Set pre-defined menu tags
[queryFavoritesSaveAsMenuItem setTag:SP_SAVE_SELECTION_FAVORTITE_MENUITEM_TAG];
[queryFavoritesSaveAllMenuItem setTag:SP_SAVE_ALL_FAVORTITE_MENUITEM_TAG];
// Set the structure and index view's vertical gridlines if required
- [customQueryView setGridStyleMask:([prefs boolForKey:SPDisplayTableViewVerticalGridlines]) ? NSTableViewSolidVerticalGridLineMask : NSTableViewGridNone];
-
+ [customQueryView setGridStyleMask:([prefs boolForKey:SPDisplayTableViewVerticalGridlines]) ? NSTableViewSolidVerticalGridLineMask : NSTableViewGridNone];
+
// Add observers for document task activity
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(startDocumentTaskForTab:)
@@ -3415,7 +3454,7 @@
/*if ([queryInfoPaneSplitView collapsibleSubview]) {
[queryInfoButton setNextState];
[queryInfoButton setToolTip:NSLocalizedString(@"Show Query Information", @"Show Query Information")];
-
+
[queryInfoPaneSplitView setValue:[NSNumber numberWithFloat:[queryInfoPaneSplitView collapsibleSubview].frame.size.height] forKey:@"uncollapsedSize"];
[[queryInfoPaneSplitView collapsibleSubview] setAutoresizesSubviews:NO];
[[queryInfoPaneSplitView collapsibleSubview] setFrameSize:NSMakeSize([queryInfoPaneSplitView collapsibleSubview].frame.size.width, 0)];
@@ -3437,15 +3476,15 @@
[usedQuery release];
[resultData release];
[favoritesManager release];
-
+
if (helpHTMLTemplate) [helpHTMLTemplate release];
if (mySQLversion) [mySQLversion release];
if (sortField) [sortField release];
if (cqColumnDefinition) [cqColumnDefinition release];
if (selectionIndexToRestore) [selectionIndexToRestore release];
if (currentQueryRanges) [currentQueryRanges release];
-
+
[super dealloc];
}
-
+
@end
diff --git a/Source/SPTableContent.m b/Source/SPTableContent.m
index 1194be97..4017f42a 100644
--- a/Source/SPTableContent.m
+++ b/Source/SPTableContent.m
@@ -3313,22 +3313,37 @@
return;
}
- // Sets order descending if a header is clicked twice
+ // Sets column order as tri-state descending, ascending, no sort, descending, ascending etc. order if the same
+ // header is clicked several times
if ([[tableColumn identifier] isEqualTo:sortCol]) {
- isDesc = !isDesc;
+ if(isDesc) {
+ [sortCol release];
+ sortCol = nil;
+ } else {
+ if (sortCol) [sortCol release];
+ sortCol = [[NSNumber alloc] initWithInteger:[[tableColumn identifier] integerValue]];
+ isDesc = !isDesc;
+ }
} else {
isDesc = NO;
[[tableContentView onMainThread] setIndicatorImage:nil inTableColumn:[tableContentView tableColumnWithIdentifier:sortCol]];
+ if (sortCol) [sortCol release];
+ sortCol = [[NSNumber alloc] initWithInteger:[[tableColumn identifier] integerValue]];
}
- if (sortCol) [sortCol release];
- sortCol = [[NSNumber alloc] initWithInteger:[[tableColumn identifier] integerValue]];
- // Set the highlight and indicatorImage
- [[tableContentView onMainThread] setHighlightedTableColumn:tableColumn];
- if (isDesc) {
- [[tableContentView onMainThread] setIndicatorImage:[NSImage imageNamed:@"NSDescendingSortIndicator"] inTableColumn:tableColumn];
+ if(sortCol) {
+ // Set the highlight and indicatorImage
+ [[tableContentView onMainThread] setHighlightedTableColumn:tableColumn];
+ if (isDesc) {
+ [[tableContentView onMainThread] setIndicatorImage:[NSImage imageNamed:@"NSDescendingSortIndicator"] inTableColumn:tableColumn];
+ } else {
+ [[tableContentView onMainThread] setIndicatorImage:[NSImage imageNamed:@"NSAscendingSortIndicator"] inTableColumn:tableColumn];
+ }
} else {
- [[tableContentView onMainThread] setIndicatorImage:[NSImage imageNamed:@"NSAscendingSortIndicator"] inTableColumn:tableColumn];
+ // If no sort order deselect column header and
+ // remove indicator image
+ [[tableContentView onMainThread] setHighlightedTableColumn:nil];
+ [[tableContentView onMainThread] setIndicatorImage:nil inTableColumn:tableColumn];
}
// Update data using the new sort order