diff options
Diffstat (limited to 'Source/SPTableContent.m')
-rw-r--r-- | Source/SPTableContent.m | 851 |
1 files changed, 513 insertions, 338 deletions
diff --git a/Source/SPTableContent.m b/Source/SPTableContent.m index df4eccf7..14f07866 100644 --- a/Source/SPTableContent.m +++ b/Source/SPTableContent.m @@ -35,8 +35,11 @@ #import "SPDataCellFormatter.h" #import "SPTableData.h" #import "SPQueryController.h" +#import "SPQueryDocumentsController.h" #import "SPTextAndLinkCell.h" +#ifndef SP_REFACTOR #import "QLPreviewPanel.h" +#endif #import "SPFieldEditorController.h" #import "SPTooltip.h" #import "RegexKitLite.h" @@ -59,31 +62,59 @@ @implementation SPTableContent +#ifdef SP_REFACTOR +@synthesize addButton; +@synthesize argumentField; +@synthesize betweenTextField; +@synthesize compareField; +@synthesize copyButton; +@synthesize fieldField; +@synthesize filterButton; +@synthesize firstBetweenField; +@synthesize paginationNextButton; +@synthesize paginationPageField; +@synthesize paginationPreviousButton; +@synthesize reloadButton; +@synthesize removeButton; +@synthesize secondBetweenField; +@synthesize tableContentView; +@synthesize tableDataInstance; +@synthesize tableDocumentInstance; +@synthesize tableSourceInstance; +@synthesize tablesListInstance; +#endif + /** * Standard init method. Initialize various ivars. */ - (id)init { - if ((self == [super init])) { + if ((self = [super init])) { _mainNibLoaded = NO; isWorking = NO; pthread_mutex_init(&tableValuesLock, NULL); +#ifndef SP_REFACTOR nibObjectsToRelease = [[NSMutableArray alloc] init]; +#endif tableValues = [[SPDataStorage alloc] init]; dataColumns = [[NSMutableArray alloc] init]; oldRow = [[NSMutableArray alloc] init]; +#ifndef SP_REFACTOR filterTableData = [[NSMutableDictionary alloc] initWithCapacity:1]; +#endif tableRowsCount = 0; previousTableRowsCount = 0; +#ifndef SP_REFACTOR filterTableNegate = NO; filterTableDistinct = NO; filterTableIsSwapped = NO; lastEditedFilterTableValue = nil; activeFilter = 0; schemeFilter = nil; +#endif selectedTable = nil; sortCol = nil; @@ -133,10 +164,12 @@ [contentFilters setDictionary:[NSPropertyListSerialization propertyListFromData:defaultFilterData mutabilityOption:NSPropertyListMutableContainersAndLeaves format:&format errorDescription:&convError]]; - if(contentFilters == nil || readError != nil || convError != nil) { + + if (contentFilters == nil || readError != nil || convError != nil) { NSLog(@"Error while reading 'ContentFilters.plist':\n%@\n%@", [readError localizedDescription], convError); NSBeep(); - } else { + } + else { [numberOfDefaultFilters setObject:[NSNumber numberWithInteger:[[contentFilters objectForKey:@"number"] count]] forKey:@"number"]; [numberOfDefaultFilters setObject:[NSNumber numberWithInteger:[[contentFilters objectForKey:@"date"] count]] forKey:@"date"]; [numberOfDefaultFilters setObject:[NSNumber numberWithInteger:[[contentFilters objectForKey:@"string"] count]] forKey:@"string"]; @@ -146,7 +179,6 @@ kCellEditorErrorNoMatch = NSLocalizedString(@"Field is not editable. No matching record found.\nReload table, check the encoding, or try to add\na primary key field or more fields\nin the view declaration of '%@' to identify\nfield origin unambiguously.", @"Table Content result editing error - could not identify original row"); kCellEditorErrorNoMultiTabDb = NSLocalizedString(@"Field is not editable. Field has no or multiple table or database origin(s).",@"field is not editable due to no table/database"); kCellEditorErrorTooManyMatches = NSLocalizedString(@"Field is not editable. Couldn't identify field origin unambiguously (%ld match%@).", @"Query result editing error - could not match row being edited uniquely"); - } return self; @@ -163,7 +195,6 @@ #ifndef SP_REFACTOR /* ui manipulation */ // Set the table content view's vertical gridlines if required [tableContentView setGridStyleMask:([prefs boolForKey:SPDisplayTableViewVerticalGridlines]) ? NSTableViewSolidVerticalGridLineMask : NSTableViewGridNone]; -#endif // Set the double-click action in blank areas of the table to create new rows [tableContentView setEmptyDoubleClickAction:@selector(addRow:)]; @@ -187,17 +218,20 @@ paginationViewFrame.size.height = 0; [paginationView setFrame:paginationViewFrame]; [contentViewPane addSubview:paginationView]; +#endif [tableContentView setFieldEditorSelectedRange:NSMakeRange(0,0)]; +#ifndef SP_REFACTOR // Init Filter Table GUI [filterTableDistinctMenuItem setState:(filterTableDistinct) ? NSOnState : NSOffState]; [filterTableNegateCheckbox setState:(filterTableNegate) ? NSOnState : NSOffState]; [filterTableLiveSearchCheckbox setState:NSOffState]; +#endif #ifndef SP_REFACTOR /* patch */ filterTableDefaultOperator = [[self escapeFilterTableDefaultOperator:[prefs objectForKey:SPFilterTableDefaultOperator]] retain]; #else - filterTableDefaultOperator = [[self escapeFilterTableDefaultOperator:nil] retain]; +// filterTableDefaultOperator = [[self escapeFilterTableDefaultOperator:nil] retain]; #endif // Add observers for document task activity @@ -219,13 +253,11 @@ * reloading table data into the data array and redrawing the table. * * @param aTable The to be loaded table name - * */ - (void)loadTable:(NSString *)aTable { // Abort the reload if the user is still editing a row - if ( isEditingRow ) - return; + if (isEditingRow) return; // If no table has been supplied, clear the table interface and return if (!aTable || [aTable isEqualToString:@""]) { @@ -306,15 +338,16 @@ - (void) setTableDetails:(NSDictionary *)tableDetails { NSString *newTableName; - NSInteger i; - NSNumber + NSInteger i, sortColumnNumberToRestore = NSNotFound; #ifndef SP_REFACTOR - *colWidth, + NSNumber *colWidth; #endif - *sortColumnNumberToRestore = nil; NSArray *columnNames; NSDictionary *columnDefinition; - NSTableColumn *theCol, *filterCol; + NSTableColumn *theCol; +#ifndef SP_REFACTOR + NSTableColumn *filterCol; +#endif BOOL enableInteraction = #ifndef SP_REFACTOR /* checking toolbar state */ ![[tableDocumentInstance selectedToolbarItemIdentifier] isEqualToString:SPMainToolbarTableContent] || @@ -331,8 +364,10 @@ newTableName = [tableDetails objectForKey:@"name"]; } +#ifndef SP_REFACTOR // Ensure the pagination view hides itself if visible, after a tiny delay for smoothness [self performSelector:@selector(setPaginationViewVisibility:) withObject:nil afterDelay:0.1]; +#endif // Reset table key store for use in argumentForRow: if (keys) [keys release], keys = nil; @@ -379,7 +414,9 @@ [tableContentView reloadData]; isFiltered = NO; isLimited = NO; +#ifndef SP_REFACTOR [countText setStringValue:@""]; +#endif // Reset sort column if (sortCol) [sortCol release]; sortCol = nil; @@ -408,8 +445,10 @@ // Disable pagination [paginationPreviousButton setEnabled:NO]; +#ifndef SP_REFACTOR [paginationButton setEnabled:NO]; [paginationButton setTitle:@""]; +#endif [paginationNextButton setEnabled:NO]; // Disable table action buttons @@ -420,6 +459,7 @@ // Clear restoration settings [self clearDetailsToRestore]; +#ifndef SP_REFACTOR // Clear filter table while ([[filterTableView tableColumns] count]) { [filterTableView removeTableColumn:NSArrayObjectAtIndex([filterTableView tableColumns], 0)]; @@ -428,6 +468,7 @@ [filterTableData removeAllObjects]; [filterTableWhereClause setString:@""]; activeFilter = 0; +#endif return; } @@ -437,6 +478,7 @@ while ([[tableContentView tableColumns] count]) { [tableContentView removeTableColumn:NSArrayObjectAtIndex([tableContentView tableColumns], 0)]; } +#ifndef SP_REFACTOR // Remove existing columns from the filter table [filterTableView abortEditing]; while ([[filterTableView tableColumns] count]) { @@ -446,6 +488,7 @@ [filterTableData removeAllObjects]; [filterTableWhereClause setString:@""]; activeFilter = 0; +#endif // Retrieve the field names and types for this table from the data cache. This is used when requesting all data as part // of the fieldListForQuery method, and also to decide whether or not to preserve the current filter/sort settings. @@ -496,6 +539,7 @@ ]]; [theCol setEditable:YES]; +#ifndef SP_REFACTOR // Set up column for filterTable filterCol = [[NSTableColumn alloc] initWithIdentifier:[columnDefinition objectForKey:@"datacolumnindex"]]; [[filterCol headerCell] setStringValue:[columnDefinition objectForKey:@"name"]]; @@ -511,6 +555,7 @@ [columnDefinition objectForKey:@"typegrouping"], @"typegrouping", [NSMutableArray arrayWithObjects:@"", @"", @"", @"", @"", @"", @"", @"", @"", @"", nil], @"filter", nil] forKey:[columnDefinition objectForKey:@"datacolumnindex"]]; +#endif // Set up the data cell depending on the column type id dataCell; @@ -574,22 +619,24 @@ // Set the column to be reselected for sorting if appropriate if (sortColumnToRestore && [sortColumnToRestore isEqualToString:[columnDefinition objectForKey:@"name"]]) - sortColumnNumberToRestore = [columnDefinition objectForKey:@"datacolumnindex"]; + sortColumnNumberToRestore = [[columnDefinition objectForKey:@"datacolumnindex"] integerValue]; // Add the column to the table [tableContentView addTableColumn:theCol]; [theCol release]; } +#ifndef SP_REFACTOR [filterTableView setDelegate:self]; [filterTableView setDataSource:self]; [filterTableView reloadData]; +#endif // If the table has been reloaded and the previously selected sort column is still present, reselect it. - if (sortColumnNumberToRestore) { - theCol = [tableContentView tableColumnWithIdentifier:sortColumnNumberToRestore]; + if (sortColumnNumberToRestore != NSNotFound) { + theCol = [tableContentView tableColumnWithIdentifier:[NSString stringWithFormat:@"%lld", (long long)sortColumnNumberToRestore]]; if (sortCol) [sortCol release]; - sortCol = [sortColumnNumberToRestore copy]; + sortCol = [[NSNumber alloc] initWithInteger:sortColumnNumberToRestore]; [tableContentView setHighlightedTableColumn:theCol]; isDesc = !sortColumnToRestoreIsAsc; if ( isDesc ) { @@ -660,7 +707,9 @@ if (!previousTableRowsCount) { [self clearTableValues]; } +#ifndef SP_REFACTOR [filterTableView reloadData]; +#endif } @@ -699,7 +748,9 @@ MCPStreamingResult *streamingResult; NSInteger rowsToLoad = [[tableDataInstance statusValueForKey:@"Rows"] integerValue]; +#ifndef SP_REFACTOR [countText setStringValue:NSLocalizedString(@"Loading table data...", @"Loading table data string")]; +#endif // Notify any listeners that a query has started #ifndef SP_REFACTOR @@ -709,7 +760,12 @@ #endif // Start construction of the query string - queryString = [NSMutableString stringWithFormat:@"SELECT %@%@ FROM %@", (activeFilter == 1 && [self tableFilterString] && filterTableDistinct) ? @"DISTINCT " : @"", [self fieldListForQuery], [selectedTable backtickQuotedString]]; + queryString = [NSMutableString stringWithFormat:@"SELECT %@%@ FROM %@", +#ifndef SP_REFACTOR + (activeFilter == 1 && [self tableFilterString] && filterTableDistinct) ? @"DISTINCT " : +#endif + @"", + [self fieldListForQuery], [selectedTable backtickQuotedString]]; // Add a filter string if appropriate filterString = [self tableFilterString]; @@ -734,7 +790,7 @@ if (contentPage <= 0) contentPage = 1; else if (contentPage > 1 && (NSInteger)(contentPage - 1) * [prefs integerForKey:SPLimitResultsValue] >= maxNumRows) - contentPage = ceil((CGFloat)maxNumRows / [prefs floatForKey:SPLimitResultsValue]); + contentPage = ceilf((CGFloat)maxNumRows / [prefs floatForKey:SPLimitResultsValue]); // If the result set is from a late page, take a copy of the string to allow resetting limit // if no results are found @@ -824,7 +880,9 @@ #endif if ([mySQLConnection queryErrored] && ![mySQLConnection queryCancelled]) { +#ifndef SP_REFACTOR if(activeFilter == 0) { +#endif if(filterString) SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [tableDocumentInstance parentWindow], self, nil, nil, [NSString stringWithFormat:NSLocalizedString(@"The table data couldn't be loaded presumably due to used filter clause. \n\nMySQL said: %@", @"message of panel when loading of table failed and presumably due to used filter argument"), [mySQLConnection getLastErrorMessage]]); @@ -832,14 +890,20 @@ SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [tableDocumentInstance parentWindow], self, nil, nil, [NSString stringWithFormat:NSLocalizedString(@"The table data couldn't be loaded.\n\nMySQL said: %@", @"message of panel when loading of table failed"), [mySQLConnection getLastErrorMessage]]); } +#ifndef SP_REFACTOR // Filter task came from filter table else if(activeFilter == 1){ [filterTableWindow setTitle:[NSString stringWithFormat:@"%@ – %@", NSLocalizedString(@"Filter", @"filter label"), NSLocalizedString(@"WHERE clause not valid", @"WHERE clause not valid")]]; } - } else { + } +#endif + else + { +#ifndef SP_REFACTOR // Trigger a full reload if required if (fullTableReloadRequired) [self reloadTable:self]; [[filterTableWindow onMainThread] setTitle:NSLocalizedString(@"Filter", @"filter label")]; +#endif } } @@ -862,7 +926,11 @@ [[self onMainThread] initTableLoadTimer]; NSAutoreleasePool *dataLoadingPool; +#ifndef SP_REFACTOR NSProgressIndicator *dataLoadingIndicator = [tableDocumentInstance valueForKey:@"queryProgressBar"]; +#else + NSProgressIndicator *dataLoadingIndicator = [tableDocumentInstance queryProgressBar]; +#endif BOOL prefsLoadBlobsAsNeeded = #ifndef SP_REFACTOR [prefs boolForKey:SPLoadBlobsAsNeeded] @@ -945,6 +1013,7 @@ - (NSString *)tableFilterString { +#ifndef SP_REFACTOR // If filter command was passed by sequelpro url scheme if(activeFilter == 2) { if(schemeFilter) @@ -963,6 +1032,7 @@ return nil; } +#endif // If the clause has the placeholder $BINARY that placeholder will be replaced // by BINARY if the user pressed ⇧ while invoking 'Filter' otherwise it will @@ -1202,7 +1272,9 @@ [countString appendFormat:NSLocalizedString(@"%@ %@ selected", @"text showing how many rows are selected"), [numberFormatter stringFromNumber:[NSNumber numberWithInteger:[tableContentView numberOfSelectedRows]]], rowString]; } +#ifndef SP_REFACTOR [[countText onMainThread] setStringValue:countString]; +#endif } /** @@ -1337,6 +1409,8 @@ */ - (IBAction)filterTable:(id)sender { +#ifndef SP_REFACTOR + if(sender == filterTableFilterButton) activeFilter = 1; else if([sender isKindOfClass:[NSString class]] && [(NSString *)sender length]) { @@ -1346,12 +1420,15 @@ } else activeFilter = 0; +#endif NSString *taskString; if ([tableDocumentInstance isWorking]) return; if (![self saveRowOnDeselect]) return; +#ifndef SP_REFACTOR [self setPaginationViewVisibility:FALSE]; +#endif // Select the correct pagination value if (![prefs boolForKey:SPLimitResults] || [paginationPageField integerValue] <= 0) @@ -1384,8 +1461,10 @@ // Check whether a save of the current row is required. if (![[self onMainThread] saveRowOnDeselect]) return; +#ifndef SP_REFACTOR // Update history [spHistoryControllerInstance updateHistoryEntries]; +#endif // Reset and reload data using the new filter settings previousTableRowsCount = 0; @@ -1489,17 +1568,20 @@ * When the Pagination button is pressed, show or hide the pagination * layer depending on the current state. */ +#ifndef SP_REFACTOR - (IBAction) togglePagination:(id)sender { if ([sender state] == NSOnState) [self setPaginationViewVisibility:YES]; else [self setPaginationViewVisibility:NO]; } +#endif /** * Show or hide the pagination layer, also changing the first responder as appropriate. */ - (void) setPaginationViewVisibility:(BOOL)makeVisible { +#ifndef SP_REFACTOR NSRect paginationViewFrame = [paginationView frame]; if (makeVisible) { @@ -1524,6 +1606,7 @@ } [[paginationView animator] setFrame:paginationViewFrame]; +#endif } /** @@ -1553,14 +1636,18 @@ else [paginationNextButton setEnabled:NO]; +#ifndef SP_REFACTOR // As long as a table is selected (which it will be if this is called), enable pagination detail button [paginationButton setEnabled:enabledMode]; +#endif // Set the values and maximums for the text field and associated pager [paginationPageField setStringValue:[numberFormatter stringFromNumber:[NSNumber numberWithUnsignedInteger:contentPage]]]; [[paginationPageField formatter] setMaximum:[NSNumber numberWithUnsignedInteger:maxPage]]; +#ifndef SP_REFACTOR [paginationPageStepper setIntegerValue:contentPage]; [paginationPageStepper setMaxValue:maxPage]; +#endif } #pragma mark - @@ -1575,79 +1662,78 @@ NSArray *dataRow; NSDictionary *theRow; id field; + NSMutableArray *argumentParts = [NSMutableArray array]; - //Look for all columns which are coming from "tableForColumn" - NSMutableArray *columnsForFieldTableName = [NSMutableArray array]; + // Check the table/view columns and select only those coming from the supplied database and table + NSMutableArray *columnsInSpecifiedTable = [NSMutableArray array]; for(field in cqColumnDefinition) { - if([[field objectForKey:@"org_table"] isEqualToString:tableForColumn]) - [columnsForFieldTableName addObject:field]; + if([[field objectForKey:@"db"] isEqualToString:database] && [[field objectForKey:@"org_table"] isEqualToString:tableForColumn]) + [columnsInSpecifiedTable addObject:field]; } - // Try to identify the field bijectively - NSMutableString *fieldIDQueryStr = [NSMutableString string]; - [fieldIDQueryStr setString:@"WHERE ("]; - // --- Build WHERE clause --- dataRow = [tableValues rowContentsAtIndex:rowIndex]; - // Get the primary key if there is one + // Get the primary key if there is one, using any columns present within it MCPResult *theResult = [mySQLConnection queryString:[NSString stringWithFormat:@"SHOW COLUMNS FROM %@.%@", [database backtickQuotedString], [tableForColumn backtickQuotedString]]]; [theResult setReturnDataAsStrings:YES]; if ([theResult numOfRows]) [theResult dataSeek:0]; + NSMutableArray *primaryColumnsInSpecifiedTable = [NSMutableArray array]; NSUInteger i; for ( i = 0 ; i < [theResult numOfRows] ; i++ ) { theRow = [theResult fetchRowAsDictionary]; if ( [[theRow objectForKey:@"Key"] isEqualToString:@"PRI"] ) { - for(field in columnsForFieldTableName) { - id aValue = [dataRow objectAtIndex:[[field objectForKey:@"datacolumnindex"] integerValue]]; + for (field in columnsInSpecifiedTable) { if([[field objectForKey:@"org_name"] isEqualToString:[theRow objectForKey:@"Field"]]) { - [fieldIDQueryStr appendFormat:@"%@.%@.%@ = %@)", - [database backtickQuotedString], - [tableForColumn backtickQuotedString], - [[theRow objectForKey:@"Field"] backtickQuotedString], - [aValue description]]; - return fieldIDQueryStr; + [primaryColumnsInSpecifiedTable addObject:field]; } } } } - // If there is no primary key, all found fields belonging to the same table are used in the argument - for(field in columnsForFieldTableName) { + // Determine whether to use the primary keys list or fall back to all fields when building the query string + NSMutableArray *columnsToQuery = [primaryColumnsInSpecifiedTable count] ? primaryColumnsInSpecifiedTable : columnsInSpecifiedTable; + + // Build up the argument + for (field in columnsToQuery) { id aValue = [dataRow objectAtIndex:[[field objectForKey:@"datacolumnindex"] integerValue]]; if ([aValue isKindOfClass:[NSNull class]] || [aValue isNSNull]) { - [fieldIDQueryStr appendFormat:@"%@ IS NULL AND ", [[field objectForKey:@"org_name"] backtickQuotedString]]; + [argumentParts addObject:[NSString stringWithFormat:@"%@ IS NULL", [[field objectForKey:@"org_name"] backtickQuotedString]]]; } else { - if ([[field objectForKey:@"typegrouping"] isEqualToString:@"textdata"]) { - if(includeBlobs) { - [fieldIDQueryStr appendFormat:@"%@='%@' AND ", [[field objectForKey:@"org_name"] backtickQuotedString], [mySQLConnection prepareString:aValue]]; - } - } - else if ([[field objectForKey:@"typegrouping"] isEqualToString:@"blobdata"] || [[field objectForKey:@"type"] isEqualToString:@"BINARY"] || [[field objectForKey:@"type"] isEqualToString:@"VARBINARY"]) { - if(includeBlobs) { - [fieldIDQueryStr appendFormat:@"%@=X'%@' AND ", [[field objectForKey:@"org_name"] backtickQuotedString], [mySQLConnection prepareBinaryData:aValue]]; - } + NSString *fieldTypeGrouping = [field objectForKey:@"typegrouping"]; + + // Skip blob-type fields if requested + if (!includeBlobs + && ([fieldTypeGrouping isEqualToString:@"textdata"] + || [fieldTypeGrouping isEqualToString:@"blobdata"] + || [[field objectForKey:@"type"] isEqualToString:@"BINARY"] + || [[field objectForKey:@"type"] isEqualToString:@"VARBINARY"])) + { + continue; } - else if ([[field objectForKey:@"typegrouping"] isEqualToString:@"bit"]) { - [fieldIDQueryStr appendFormat:@"%@=b'%@' AND ", [[field objectForKey:@"org_name"] backtickQuotedString], [aValue description]]; + + // If the field is of type BIT then it needs a binary prefix + if ([fieldTypeGrouping isEqualToString:@"bit"]) { + [argumentParts addObject:[NSString stringWithFormat:@"%@=b'%@'", [[field objectForKey:@"org_name"] backtickQuotedString], [aValue description]]]; } - else if ([[field objectForKey:@"typegrouping"] isEqualToString:@"integer"]) { - [fieldIDQueryStr appendFormat:@"%@=%@ AND ", [[field objectForKey:@"org_name"] backtickQuotedString], [aValue description]]; + else if ([fieldTypeGrouping isEqualToString:@"geometry"]) { + [argumentParts addObject:[NSString stringWithFormat:@"%@=X'%@'", [[field objectForKey:@"org_name"] backtickQuotedString], [mySQLConnection prepareBinaryData:[aValue data]]]]; } - else if ([[field objectForKey:@"typegrouping"] isEqualToString:@"geometry"]) { - [fieldIDQueryStr appendFormat:@"%@=X'%@' AND ", [[field objectForKey:@"org_name"] backtickQuotedString], [mySQLConnection prepareBinaryData:[aValue data]]]; + // BLOB/TEXT data + else if ([aValue isKindOfClass:[NSData class]]) { + [argumentParts addObject:[NSString stringWithFormat:@"%@=X'%@'", [[field objectForKey:@"org_name"] backtickQuotedString], [mySQLConnection prepareBinaryData:aValue]]]; } else { - [fieldIDQueryStr appendFormat:@"%@='%@' AND ", [[field objectForKey:@"org_name"] backtickQuotedString], [mySQLConnection prepareString:aValue]]; + [argumentParts addObject:[NSString stringWithFormat:@"%@='%@'", [[field objectForKey:@"org_name"] backtickQuotedString], [mySQLConnection prepareString:aValue]]]; } } } - // Remove last " AND " - if([fieldIDQueryStr length]>12) - [fieldIDQueryStr replaceCharactersInRange:NSMakeRange([fieldIDQueryStr length]-5,5) withString:@")"]; - return fieldIDQueryStr; + // Check for empty strings + if (![argumentParts count]) return nil; + + return [NSString stringWithFormat:@"WHERE (%@)", [argumentParts componentsJoinedByString:@" AND "]]; } /** @@ -1692,7 +1778,9 @@ isEditingRow = YES; isEditingNewRow = YES; currentlyEditingRow = [tableContentView selectedRow]; +#ifndef SP_REFACTOR if ( [multipleLineEditingButton state] == NSOffState ) +#endif [tableContentView editColumn:0 row:[tableContentView numberOfRows]-1 withEvent:nil select:YES]; } @@ -1706,42 +1794,50 @@ NSDictionary *row; NSArray *dbDataRow = nil; NSUInteger i; - + // Check whether a save of the current row is required. - if ( ![self saveRowOnDeselect] ) return; + if (![self saveRowOnDeselect]) return; - if ( [tableContentView numberOfSelectedRows] < 1 ) - return; - if ( [tableContentView numberOfSelectedRows] > 1 ) { + if (![tableContentView numberOfSelectedRows]) return; + + if ([tableContentView numberOfSelectedRows] > 1) { SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [tableDocumentInstance parentWindow], self, nil, nil, NSLocalizedString(@"You can only copy single rows.", @"message of panel when trying to copy multiple rows")); return; } - - //copy row + + // Row contents tempRow = [tableValues rowContentsAtIndex:[tableContentView selectedRow]]; #ifndef SP_REFACTOR - //if we don't show blobs, read data for this duplicate column from db + // If we don't show blobs, read data for this duplicate column from db if ([prefs boolForKey:SPLoadBlobsAsNeeded]) { + // Abort if there are no indices on this table - argumentForRow will display an error. - if (![[self argumentForRow:[tableContentView selectedRow]] length]){ + if (![[self argumentForRow:[tableContentView selectedRow]] length]) { return; } - //if we have indexes, use argumentForRow + + // If we have indexes, use argumentForRow queryResult = [mySQLConnection queryString:[NSString stringWithFormat:@"SELECT * FROM %@ WHERE %@", [selectedTable backtickQuotedString], [self argumentForRow:[tableContentView selectedRow]]]]; dbDataRow = [queryResult fetchRowAsArray]; } #endif - //set autoincrement fields to NULL + // Set autoincrement fields to NULL queryResult = [mySQLConnection queryString:[NSString stringWithFormat:@"SHOW COLUMNS FROM %@", [selectedTable backtickQuotedString]]]; + [queryResult setReturnDataAsStrings:YES]; + if ([queryResult numOfRows]) [queryResult dataSeek:0]; - for ( i = 0 ; i < [queryResult numOfRows] ; i++ ) { + + for (i = 0; i < [queryResult numOfRows]; i++) + { row = [queryResult fetchRowAsDictionary]; - if ( [[row objectForKey:@"Extra"] isEqualToString:@"auto_increment"] ) { + + if ([[row objectForKey:@"Extra"] isEqualToString:@"auto_increment"]) { [tempRow replaceObjectAtIndex:i withObject:[NSNull null]]; - } else if ( [tableDataInstance columnIsBlobOrText:[row objectForKey:@"Field"]] && + } + else if ([tableDataInstance columnIsBlobOrText:[row objectForKey:@"Field"]] && #ifndef SP_REFACTOR [prefs boolForKey:SPLoadBlobsAsNeeded] #else @@ -1752,18 +1848,25 @@ } } - //insert the copied row - [tableValues insertRowContents:tempRow atIndex:[tableContentView selectedRow]+1]; + // Insert the copied row + [tableValues insertRowContents:tempRow atIndex:[tableContentView selectedRow] + 1]; tableRowsCount++; - //select row and go in edit mode + // Select row and go in edit mode [tableContentView reloadData]; - [tableContentView selectRowIndexes:[NSIndexSet indexSetWithIndex:[tableContentView selectedRow]+1] byExtendingSelection:NO]; + [tableContentView selectRowIndexes:[NSIndexSet indexSetWithIndex:[tableContentView selectedRow] + 1] byExtendingSelection:NO]; + isEditingRow = YES; isEditingNewRow = YES; + currentlyEditingRow = [tableContentView selectedRow]; - if ( [multipleLineEditingButton state] == NSOffState ) +#ifndef SP_REFACTOR + if ([multipleLineEditingButton state]) { +#endif [tableContentView editColumn:0 row:[tableContentView selectedRow] withEvent:nil select:YES]; +#ifndef SP_REFACTOR + } +#endif } /** @@ -1771,16 +1874,10 @@ */ - (IBAction)removeRow:(id)sender { - // Check whether a save of the current row is required. - // if (![self saveRowOnDeselect]) - // return; - // cancel editing (maybe this is not the ideal method -- see xcode docs for that method) [[tableDocumentInstance parentWindow] endEditingFor:nil]; - - if (![tableContentView numberOfSelectedRows]) - return; + if (![tableContentView numberOfSelectedRows]) return; NSAlert *alert = [NSAlert alertWithMessageText:@"" defaultButton:NSLocalizedString(@"Delete", @"delete button") @@ -1802,7 +1899,7 @@ NSString *contextInfo = @"removerow"; - if (([tableContentView numberOfSelectedRows] == [tableContentView numberOfRows]) && !isFiltered && !isLimited && !isInterruptedLoad && !isEditingNewRow) { + if (([tableContentView numberOfSelectedRows] == [tableContentView numberOfRows]) && [tableContentView numberOfSelectedRows] > 50 && !isFiltered && !isLimited && !isInterruptedLoad && !isEditingNewRow) { contextInfo = @"removeallrows"; @@ -2022,7 +2119,8 @@ } errors = (affectedRows > 0) ? [selectedRows count] - affectedRows : [selectedRows count]; - } else { + } + else { // if table has more than one PRIMARY KEY // delete the row by using all PRIMARY KEYs in an OR clause NSMutableString *deleteQuery = [NSMutableString string]; @@ -2071,37 +2169,50 @@ [[SPQueryController sharedQueryController] setAllowConsoleUpdate:consoleUpdateStatus]; if (errors) { - NSArray *message; - //TODO: The following three messages are NOT localisable! + NSMutableString *messageText = [NSMutableString stringWithCapacity:50]; + NSString *messageTitle = NSLocalizedString(@"Unexpected number of rows removed!", @"Table Content : Remove Row : Result : n Error title"); + if (errors < 0) { - message = [NSArray arrayWithObjects:NSLocalizedString(@"Warning", @"warning"), - [NSString stringWithFormat:NSLocalizedString(@"%ld row%@ more %@ deleted! Please check the Console and inform the Sequel Pro team!", @"message of panel when more rows were deleted"), (long)(errors*-1), ((errors*-1)>1)?@"s":@"", (errors>1)?@"were":@"was"], - nil]; + long numErrors = (long)(errors *- 1); + if(numErrors == 1) + [messageText appendString:NSLocalizedString(@"One additional row was removed!",@"Table Content : Remove Row : Result : Too Many : Part 1 : n+1 rows instead of n selected were deleted.")]; + else + [messageText appendFormat:NSLocalizedString(@"%ld additional rows were removed!",@"Table Content : Remove Row : Result : Too Many : Part 1 : n+y (y!=1) rows instead of n selected were deleted."),numErrors]; + + [messageText appendString:NSLocalizedString(@" Please check the Console and inform the Sequel Pro team!",@"Table Content : Remove Row : Result : Too Many : Part 2 : Generic text")]; + } else { + //part 1 number of rows not deleted + if(errors == 1) + [messageText appendString:NSLocalizedString(@"One row was not removed.",@"Table Content : Remove Row : Result : Too Few : Part 1 : Only n-1 of n selected rows were deleted.")]; + else + [messageText appendFormat:NSLocalizedString(@"%ld rows were not removed.",@"Table Content : Remove Row : Result : Too Few : Part 1 : n-x (x!=1) of n selected rows were deleted."),errors]; + //part 2 generic help text + [messageText appendString:NSLocalizedString(@" Reload the table to be sure that the contents have not changed in the meantime.",@"Table Content : Remove Row : Result : Too Few : Part 2 : Generic help message")]; + //part 3 primary keys if (primaryKeyFieldNames == nil) - message = [NSArray arrayWithObjects:NSLocalizedString(@"Warning", @"warning"), - [NSString stringWithFormat:NSLocalizedString(@"%ld row%@ ha%@ not been deleted. Reload the table to be sure that the rows exist and use a primary key for your table.", @"message of panel when not all selected fields have been deleted"), (long)errors, (errors>1)?@"s":@"", (errors>1)?@"ve":@"s"], - nil]; + [messageText appendString:NSLocalizedString(@" You should also add a primary key to this table!",@"Table Content : Remove Row : Result : Too Few : Part 3 : no primary key in table generic message")]; else - message = [NSArray arrayWithObjects:NSLocalizedString(@"Warning", @"warning"), - [NSString stringWithFormat:NSLocalizedString(@"%ld row%@ ha%@ not been deleted. Reload the table to be sure that the rows exist and check the Console for possible errors inside the primary key%@ for your table.", @"message of panel when not all selected fields have been deleted by using primary keys"), (long)errors, (errors>1)?@"s":@"", (errors>1)?@"ve":@"s", (errors>1)?@"s":@""], - nil]; + [messageText appendString:NSLocalizedString(@" Check the Console for possible errors inside the primary key(s) of this table!",@"Table Content : Remove Row : Result : Too Few : Part 3 : Row not deleted when using primary key for DELETE statement.")]; } [self performSelector:@selector(showErrorSheetWith:) - withObject:message + withObject:[NSArray arrayWithObjects:messageTitle,messageText,nil] afterDelay:0.3]; } // Refresh table content - if ( errors || reloadAfterRemovingRow ) { + if (errors || reloadAfterRemovingRow) { previousTableRowsCount = tableRowsCount; [self loadTableValues]; - } else { - for ( i = tableRowsCount - 1 ; i >= 0 ; i-- ) { + } + else { + for ( i = tableRowsCount - 1; i >= 0; i--) + { if ([selectedRows containsIndex:i]) [tableValues removeRowAtIndex:i]; } + tableRowsCount = [tableValues count]; [tableContentView reloadData]; @@ -2109,92 +2220,110 @@ maxNumRows -= affectedRows; [self updateCountText]; } + [tableContentView deselectAll:self]; - } else { - // The user clicked cancel in the "sure you wanna delete" message - // restore editing or whatever - } - + } } } -// Accessors +#pragma mark - +#pragma mark Data accessors /** * Returns the current result (as shown in table content view) as array, the first object containing the field * names as array, the following objects containing the rows as array. */ -- (NSArray *)currentDataResult +- (NSArray *)currentDataResultWithNULLs:(BOOL)includeNULLs { + NSInteger i; NSArray *tableColumns; NSMutableArray *currentResult = [NSMutableArray array]; NSMutableArray *tempRow = [NSMutableArray array]; - NSInteger i; // Load table if not already done - if ( ![tableDocumentInstance contentLoaded] ) { + if (![tableDocumentInstance contentLoaded]) { [self loadTable:[tableDocumentInstance table]]; } tableColumns = [tableContentView tableColumns]; // Set field names as first line - for (NSTableColumn *aTableColumn in tableColumns) { + for (NSTableColumn *aTableColumn in tableColumns) + { [tempRow addObject:[[aTableColumn headerCell] stringValue]]; } + [currentResult addObject:[NSArray arrayWithArray:tempRow]]; // Add rows - for ( i = 0 ; i < [self numberOfRowsInTableView:tableContentView] ; i++) { + for (i = 0; i < [self numberOfRowsInTableView:tableContentView]; i++) + { [tempRow removeAllObjects]; - for (NSTableColumn *aTableColumn in tableColumns) { + + for (NSTableColumn *aTableColumn in tableColumns) + { id o = SPDataStorageObjectAtRowAndColumn(tableValues, i, [[aTableColumn identifier] integerValue]); - if ([o isNSNull]) - [tempRow addObject:@"NULL"]; - else if ([o isSPNotLoaded]) + + if ([o isNSNull]) { + [tempRow addObject:(includeNULLs) ? [NSNull null] : [prefs objectForKey:SPNullValue]]; + } + else if ([o isSPNotLoaded]) { [tempRow addObject:NSLocalizedString(@"(not loaded)", @"value shown for hidden blob and text fields")]; - else if([o isKindOfClass:[NSString class]]) + } + else if([o isKindOfClass:[NSString class]]) { [tempRow addObject:[o description]]; + } else if([o isKindOfClass:[MCPGeometryData class]]) { SPGeometryDataView *v = [[SPGeometryDataView alloc] initWithCoordinates:[o coordinates]]; NSImage *image = [v thumbnailImage]; NSString *imageStr = @""; + if(image) { NSString *maxSizeValue = @"WIDTH"; NSInteger imageWidth = [image size].width; NSInteger imageHeight = [image size].height; + if(imageHeight > imageWidth) { maxSizeValue = @"HEIGHT"; imageWidth = imageHeight; } + if (imageWidth > 100) imageWidth = 100; + imageStr = [NSString stringWithFormat: @"<BR><IMG %@='%ld' SRC=\"data:image/auto;base64,%@\">", maxSizeValue, (long)imageWidth, [[image TIFFRepresentationUsingCompression:NSTIFFCompressionJPEG factor:0.01f] base64EncodingWithLineLength:0]]; } + [v release]; [tempRow addObject:[NSString stringWithFormat:@"%@%@", [o wktString], imageStr]]; } else { NSImage *image = [[NSImage alloc] initWithData:o]; + if (image) { NSInteger imageWidth = [image size].width; + if (imageWidth > 100) imageWidth = 100; [tempRow addObject:[NSString stringWithFormat: @"<IMG WIDTH='%ld' SRC=\"data:image/auto;base64,%@\">", (long)imageWidth, [[image TIFFRepresentationUsingCompression:NSTIFFCompressionJPEG factor:0.01f] base64EncodingWithLineLength:0]]]; - } else { + } + else { [tempRow addObject:@"<BLOB>"]; } + if(image) [image release]; } } + [currentResult addObject:[NSArray arrayWithArray:tempRow]]; } + return currentResult; } @@ -2234,6 +2363,8 @@ return currentResult; } +#pragma mark - + // Additional methods /** @@ -2281,9 +2412,11 @@ return; } +#ifndef SP_REFACTOR // Save existing scroll position and details and mark that state is being modified [spHistoryControllerInstance updateHistoryEntries]; [spHistoryControllerInstance setModifyingState:YES]; +#endif NSString *targetFilterValue = [tableValues cellDataAtRow:[theArrowCell getClickedRow] column:dataColumnIndex]; @@ -2314,16 +2447,20 @@ } } +#ifndef SP_REFACTOR // End state and ensure a new history entry [spHistoryControllerInstance setModifyingState:NO]; [spHistoryControllerInstance updateHistoryEntries]; +#endif // End the task [tableDocumentInstance endTask]; +#ifndef SP_REFACTOR // If the same table is the target, trigger a filter task on the main thread if (tableFilterRequired) [self performSelectorOnMainThread:@selector(filterTable:) withObject:self waitUntilDone:NO]; +#endif // Empty the loading pool and exit the thread [linkPool drain]; @@ -2463,12 +2600,14 @@ i++; } +#ifndef SP_REFACTOR [menu addItem:[NSMenuItem separatorItem]]; NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Edit Filters…", @"edit filter") action:NULL keyEquivalent:@""]; [item setToolTip:NSLocalizedString(@"Edit user-defined Filters…", @"edit user-defined filter")]; [item setTag:i]; [menu addItem:item]; [item release]; +#endif // Attempt to reselect the previously selected title, falling back to the first // item on failure, as long as there is no filter selection to be restored. @@ -2504,7 +2643,6 @@ contextInfo:nil]; } - /** * Tries to write a new row to the table. * Returns YES if row is written to table, otherwise NO; also returns YES if no row @@ -2512,7 +2650,6 @@ */ - (BOOL)saveRowToTable { - // Only handle tables - views should be handled per-cell. if ([tablesListInstance tableType] == SPTableTypeView) return NO; @@ -2532,7 +2669,9 @@ NSUInteger i; NSDictionary *fieldDefinition; id rowObject; - for (i = 0; i < [dataColumns count]; i++) { + + for (i = 0; i < [dataColumns count]; i++) + { rowObject = [tableValues cellDataAtRow:currentlyEditingRow column:i]; fieldDefinition = NSArrayObjectAtIndex(dataColumns, i); @@ -2664,7 +2803,8 @@ [[tableDocumentInstance parentWindow] endEditingFor:nil]; previousTableRowsCount = tableRowsCount; [self loadTableValues]; - } else { + } + else { #endif // Set the insertId for fields with auto_increment for ( i = 0; i < [dataColumns count] ; i++ ) { @@ -2682,7 +2822,7 @@ // Reload table if set to - otherwise no action required. #ifndef SP_REFACTOR - if ( [prefs boolForKey:SPReloadAfterEditingRow] ) { + if ([prefs boolForKey:SPReloadAfterEditingRow]) { [[tableDocumentInstance parentWindow] endEditingFor:nil]; previousTableRowsCount = tableRowsCount; [self loadTableValues]; @@ -2694,7 +2834,8 @@ return YES; // Report errors which have occurred - } else { + } + else { SPBeginAlertSheet(NSLocalizedString(@"Couldn't write row", @"Couldn't write row error"), NSLocalizedString(@"Edit row", @"Edit row button"), NSLocalizedString(@"Discard changes", @"discard changes button"), nil, [tableDocumentInstance parentWindow], self, @selector(addRowErrorSheetDidEnd:returnCode:contextInfo:), nil, [NSString stringWithFormat:NSLocalizedString(@"MySQL said:\n\n%@", @"message of panel when error while adding row to db"), [mySQLConnection getLastErrorMessage]]); return NO; @@ -2729,8 +2870,7 @@ */ - (BOOL)saveRowOnDeselect { - - if([tablesListInstance tableType] == SPTableTypeView) { + if ([tablesListInstance tableType] == SPTableTypeView) { isSavingRow = NO; return YES; } @@ -2743,6 +2883,7 @@ // If no rows are currently being edited, or a save is in progress, return success at once. if (!isEditingRow || isSavingRow) return YES; + isSavingRow = YES; // Attempt to save the row, and return YES if the save succeeded. @@ -2753,6 +2894,7 @@ // Saving failed - return failure. isSavingRow = NO; + return NO; } @@ -2949,17 +3091,11 @@ * -2 for other errors * and the used WHERE clause to identify */ -- (NSArray*)fieldEditStatusForRow:(NSInteger)rowIndex andColumn:(NSNumber *)columnIndex +- (NSArray*)fieldEditStatusForRow:(NSInteger)rowIndex andColumn:(NSInteger)columnIndex { - NSDictionary *columnDefinition = nil; // Retrieve the column defintion - for(id c in cqColumnDefinition) { - if([[c objectForKey:@"datacolumnindex"] isEqualToNumber:columnIndex]) { - columnDefinition = [NSDictionary dictionaryWithDictionary:c]; - break; - } - } + NSDictionary *columnDefinition = [NSDictionary dictionaryWithDictionary:[cqColumnDefinition objectAtIndex:[[[[tableContentView tableColumns] objectAtIndex:columnIndex] identifier] integerValue]]]; if(!columnDefinition) return [NSArray arrayWithObjects:[NSNumber numberWithInteger:-2], @"", nil]; @@ -3037,6 +3173,7 @@ */ - (void)sheetDidEnd:(id)sheet returnCode:(NSInteger)returnCode contextInfo:(NSString *)contextInfo { +#ifndef SP_REFACTOR [sheet orderOut:self]; if([contextInfo isEqualToString:@"setdefaultoperator"]) { @@ -3044,18 +3181,15 @@ if(filterTableDefaultOperator) [filterTableDefaultOperator release]; NSString *newOperator = [filterTableSetDefaultOperatorValue stringValue]; filterTableDefaultOperator = [[self escapeFilterTableDefaultOperator:newOperator] retain]; -#ifndef SP_REFACTOR [prefs setObject:newOperator forKey:SPFilterTableDefaultOperator]; -#endif + if(![newOperator isMatchedByRegex:@"(?i)like\\s+['\"]%@%['\"]\\s*"]) { -#ifndef SP_REFACTOR if(![prefs objectForKey:SPFilterTableDefaultOperatorLastItems]) [prefs setObject:[NSMutableArray array] forKey:SPFilterTableDefaultOperatorLastItems]; -#endif + NSMutableArray *lastItems = [NSMutableArray array]; -#ifndef SP_REFACTOR [lastItems setArray:[prefs objectForKey:SPFilterTableDefaultOperatorLastItems]]; -#endif + if([lastItems containsObject:newOperator]) [lastItems removeObject:newOperator]; if([lastItems count] > 0) @@ -3066,13 +3200,13 @@ if([lastItems count] > 15) while([lastItems count] > 15) [filterTableSetDefaultOperatorValue removeItemAtIndex:[lastItems count]-1]; -#ifndef SP_REFACTOR + [prefs setObject:lastItems forKey:SPFilterTableDefaultOperatorLastItems]; -#endif } [self updateFilterTableClause:nil]; } } +#endif } /** @@ -3092,15 +3226,14 @@ NSInteger row = -1; NSInteger column = -1; - NSInteger editedColumn = -1; if(contextInfo) { - row = [[contextInfo objectForKey:@"row"] integerValue]; - column = [[contextInfo objectForKey:@"column"] integerValue]; - editedColumn = [[contextInfo objectForKey:@"editedColumn"] integerValue]; + row = [[contextInfo objectForKey:@"rowIndex"] integerValue]; + column = [[contextInfo objectForKey:@"columnIndex"] integerValue]; } if (data && contextInfo) { + NSTableColumn *theTableColumn = [[tableContentView tableColumns] objectAtIndex:column]; BOOL isFieldEditable = ([contextInfo objectForKey:@"isFieldEditable"]) ? YES : NO; if (!isEditingRow && [tablesListInstance tableType] != SPTableTypeView) { [oldRow setArray:[tableValues rowContentsAtIndex:row]]; @@ -3109,18 +3242,22 @@ } if ([data isKindOfClass:[NSString class]] - && [data isEqualToString:[prefs objectForKey:SPNullValue]] && [[NSArrayObjectAtIndex(dataColumns, column) objectForKey:@"null"] boolValue]) + && [data isEqualToString:[prefs objectForKey:SPNullValue]] && [[NSArrayObjectAtIndex(dataColumns, [[theTableColumn identifier] integerValue]) objectForKey:@"null"] boolValue]) { data = [[NSNull null] retain]; } if(isFieldEditable) { - if([tablesListInstance tableType] == SPTableTypeView) { + if ([tablesListInstance tableType] == SPTableTypeView) { + // since in a view we're editing a field rather than a row isEditingRow = NO; + // update the field and refresh the table - [self tableView:tableContentView setObjectValue:[[data copy] autorelease] forTableColumn:[tableContentView tableColumnWithIdentifier:[contextInfo objectForKey:@"column"]] row:row]; + [self saveViewCellValue:[[data copy] autorelease] forTableColumn:theTableColumn row:row]; + + // Otherwise, in tables, save back to the row store } else { - [tableValues replaceObjectInRow:row column:column withObject:[[data copy] autorelease]]; + [tableValues replaceObjectInRow:row column:[[theTableColumn identifier] integerValue] withObject:[[data copy] autorelease]]; } } } @@ -3132,8 +3269,130 @@ [[tableContentView window] makeFirstResponder:tableContentView]; - if(row > -1 && editedColumn > -1) - [tableContentView editColumn:editedColumn row:row withEvent:nil select:YES]; + if(row > -1 && column > -1) + [tableContentView editColumn:column row:row withEvent:nil select:YES]; +} + +- (void)saveViewCellValue:(id)anObject forTableColumn:(NSTableColumn *)aTableColumn row:(NSUInteger)rowIndex +{ + + // Field editing + NSDictionary *columnDefinition = [cqColumnDefinition objectAtIndex:[[aTableColumn identifier] integerValue]]; + + // Resolve the original table name for current column if AS was used + NSString *tableForColumn = [columnDefinition objectForKey:@"org_table"]; + + if (!tableForColumn || ![tableForColumn length]) { + NSPoint pos = [NSEvent mouseLocation]; + pos.y -= 20; + [SPTooltip showWithObject:NSLocalizedString(@"Field is not editable. Field has no or multiple table or database origin(s).",@"field is not editable due to no table/database") + atLocation:pos + ofType:@"text"]; + NSBeep(); + return; + } + + // Resolve the original column name if AS was used + NSString *columnName = [columnDefinition objectForKey:@"org_name"]; + + [tableDocumentInstance startTaskWithDescription:NSLocalizedString(@"Updating field data...", @"updating field task description")]; + [[NSNotificationCenter defaultCenter] postNotificationName:@"SMySQLQueryWillBePerformed" object:tableDocumentInstance]; + + [self storeCurrentDetailsForRestoration]; + + // Check if the IDstring identifies the current field bijectively and get the WHERE clause + NSArray *editStatus = [self fieldEditStatusForRow:rowIndex andColumn:[[aTableColumn identifier] integerValue]]; + NSString *fieldIDQueryStr = [editStatus objectAtIndex:1]; + NSInteger numberOfPossibleUpdateRows = [[editStatus objectAtIndex:0] integerValue]; + + if(numberOfPossibleUpdateRows == 1) { + + NSString *newObject = nil; + if ( [anObject isKindOfClass:[NSCalendarDate class]] ) { + newObject = [NSString stringWithFormat:@"'%@'", [mySQLConnection prepareString:[anObject description]]]; + } else if ( [anObject isKindOfClass:[NSNumber class]] ) { + newObject = [anObject stringValue]; + } else if ( [anObject isKindOfClass:[NSData class]] ) { + newObject = [NSString stringWithFormat:@"X'%@'", [mySQLConnection prepareBinaryData:anObject]]; + } else { + if ( [[anObject description] isEqualToString:@"CURRENT_TIMESTAMP"] ) { + newObject = @"CURRENT_TIMESTAMP"; + } else if([anObject isEqualToString:[prefs stringForKey:SPNullValue]]) { + newObject = @"NULL"; + } else if ([[columnDefinition objectForKey:@"typegrouping"] isEqualToString:@"geometry"]) { + newObject = [(NSString*)anObject getGeomFromTextString]; + } else if ([[columnDefinition objectForKey:@"typegrouping"] isEqualToString:@"bit"]) { + newObject = [NSString stringWithFormat:@"b'%@'", ((![[anObject description] length] || [[anObject description] isEqualToString:@"0"]) ? @"0" : [anObject description])]; + } else if ([[columnDefinition objectForKey:@"typegrouping"] isEqualToString:@"date"] + && [[anObject description] isEqualToString:@"NOW()"]) { + newObject = @"NOW()"; + } else { + newObject = [NSString stringWithFormat:@"'%@'", [mySQLConnection prepareString:[anObject description]]]; + } + } + + [mySQLConnection queryString: + [NSString stringWithFormat:@"UPDATE %@.%@ SET %@.%@.%@ = %@ %@ LIMIT 1", + [[columnDefinition objectForKey:@"db"] backtickQuotedString], [tableForColumn backtickQuotedString], + [[columnDefinition objectForKey:@"db"] backtickQuotedString], [tableForColumn backtickQuotedString], [columnName backtickQuotedString], newObject, fieldIDQueryStr]]; + + + // Check for errors while UPDATE + if ([mySQLConnection queryErrored]) { + SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), NSLocalizedString(@"Cancel", @"cancel button"), nil, [tableDocumentInstance parentWindow], self, nil, nil, + [NSString stringWithFormat:NSLocalizedString(@"Couldn't write field.\nMySQL said: %@", @"message of panel when error while updating field to db"), [mySQLConnection getLastErrorMessage]]); + + [tableDocumentInstance endTask]; + [[NSNotificationCenter defaultCenter] postNotificationName:@"SMySQLQueryHasBeenPerformed" object:tableDocumentInstance]; + return; + } + + + // This shouldn't happen – for safety reasons + if ( ![mySQLConnection affectedRows] ) { +#ifndef SP_REFACTOR + if ( [prefs boolForKey:SPShowNoAffectedRowsError] ) { + SPBeginAlertSheet(NSLocalizedString(@"Warning", @"warning"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [tableDocumentInstance parentWindow], self, nil, nil, + NSLocalizedString(@"The row was not written to the MySQL database. You probably haven't changed anything.\nReload the table to be sure that the row exists and use a primary key for your table.\n(This error can be turned off in the preferences.)", @"message of panel when no rows have been affected after writing to the db")); + } else { + NSBeep(); + } +#endif + [tableDocumentInstance endTask]; + [[NSNotificationCenter defaultCenter] postNotificationName:@"SMySQLQueryHasBeenPerformed" object:tableDocumentInstance]; + return; + } + + } 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"), + (long)numberOfPossibleUpdateRows, (numberOfPossibleUpdateRows>1)?@"es":@"", tableForColumn]); + + [[NSNotificationCenter defaultCenter] postNotificationName:@"SMySQLQueryHasBeenPerformed" object:tableDocumentInstance]; + [tableDocumentInstance endTask]; + return; + + } + + // Reload table after each editing due to complex declarations + if (isFirstChangeInView) { + + // Set up the table details for the new table, and trigger an interface update + // if the view was modified for the very first time + NSDictionary *tableDetails = [NSDictionary dictionaryWithObjectsAndKeys: + selectedTable, @"name", + [tableDataInstance columns], @"columns", + [tableDataInstance columnNames], @"columnNames", + [tableDataInstance getConstraints], @"constraints", + nil]; + [self performSelectorOnMainThread:@selector(setTableDetails:) withObject:tableDetails waitUntilDone:YES]; + isFirstChangeInView = NO; + } + + [[NSNotificationCenter defaultCenter] postNotificationName:@"SMySQLQueryHasBeenPerformed" object:tableDocumentInstance]; + [tableDocumentInstance endTask]; + + [self loadTableValues]; } #pragma mark - @@ -3144,6 +3403,7 @@ */ - (IBAction)tableFilterClear:(id)sender { +#ifndef SP_REFACTOR [filterTableView abortEditing]; @@ -3162,6 +3422,7 @@ } +#endif } /** @@ -3169,19 +3430,19 @@ */ - (IBAction)showFilterTable:(id)sender { +#ifndef SP_REFACTOR [filterTableWindow makeKeyAndOrderFront:nil]; [filterTableWhereClause setContinuousSpellCheckingEnabled:NO]; [filterTableWhereClause setAutoindent:NO]; [filterTableWhereClause setAutoindentIgnoresEnter:NO]; -#ifndef SP_REFACTOR [filterTableWhereClause setAutopair:[prefs boolForKey:SPCustomQueryAutoPairCharacters]]; [filterTableWhereClause setAutohelp:NO]; [filterTableWhereClause setAutouppercaseKeywords:[prefs boolForKey:SPCustomQueryAutoUppercaseKeywords]]; -#endif [filterTableWhereClause setCompletionWasReinvokedAutomatically:NO]; [filterTableWhereClause insertText:@""]; [filterTableWhereClause didChangeText]; [[filterTableView window] makeFirstResponder:filterTableView]; +#endif } /** @@ -3189,11 +3450,13 @@ */ - (IBAction)toggleNegateClause:(id)sender { +#ifndef SP_REFACTOR filterTableNegate = !filterTableNegate; // If live search is set perform filtering if([filterTableLiveSearchCheckbox state] == NSOnState) [self filterTable:filterTableFilterButton]; +#endif } @@ -3202,6 +3465,7 @@ */ - (IBAction)toggleDistinctSelect:(id)sender { +#ifndef SP_REFACTOR filterTableDistinct = !filterTableDistinct; [filterTableDistinctMenuItem setState:(filterTableDistinct) ? NSOnState : NSOffState]; @@ -3209,6 +3473,7 @@ // If live search is set perform filtering if([filterTableLiveSearchCheckbox state] == NSOnState) [self filterTable:filterTableFilterButton]; +#endif } @@ -3217,11 +3482,11 @@ */ - (IBAction)setDefaultOperator:(id)sender { +#ifndef SP_REFACTOR [filterTableWindow makeFirstResponder:filterTableView]; // Load history -#ifndef SP_REFACTOR if([prefs objectForKey:SPFilterTableDefaultOperatorLastItems]) { NSMutableArray *lastItems = [NSMutableArray array]; NSString *defaultItem = @"LIKE '%@%'"; @@ -3234,13 +3499,13 @@ } [filterTableSetDefaultOperatorValue setStringValue:[prefs objectForKey:SPFilterTableDefaultOperator]]; -#endif [NSApp beginSheet:filterTableSetDefaultOperatorSheet modalForWindow:filterTableWindow modalDelegate:self didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) contextInfo:@"setdefaultoperator"]; +#endif } @@ -3256,9 +3521,11 @@ { [self updateFilterTableClause:sender]; +#ifndef SP_REFACTOR // If live search is set perform filtering if([filterTableLiveSearchCheckbox state] == NSOnState) [self filterTable:filterTableFilterButton]; +#endif } @@ -3271,6 +3538,14 @@ [[sender window] orderOut:self]; } +/** + * Opens the content filter help page in the default browser. + */ +- (IBAction)showDefaultOperaterHelp:(id)sender +{ + [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:SPLOCALIZEDURL_CONTENTFILTERHELP]]; +} + #pragma mark - #pragma mark Retrieving and setting table state @@ -3426,8 +3701,13 @@ if ([filterSettings objectForKey:@"secondBetweenField"]) secondBetweenValueToRestore = [[NSString alloc] initWithString:[filterSettings objectForKey:@"secondBetweenField"]]; } else { - if ([filterSettings objectForKey:@"filterValue"] && ![[filterSettings objectForKey:@"filterValue"] isNSNull]) - filterValueToRestore = [[NSString alloc] initWithString:[filterSettings objectForKey:@"filterValue"]]; + if ([filterSettings objectForKey:@"filterValue"] && ![[filterSettings objectForKey:@"filterValue"] isNSNull]) { + if ([[filterSettings objectForKey:@"filterValue"] isKindOfClass:[NSData class]]) { + filterValueToRestore = [[NSString alloc] initWithData:[filterSettings objectForKey:@"filterValue"] encoding:[mySQLConnection stringEncoding]]; + } else { + filterValueToRestore = [[NSString alloc] initWithString:[filterSettings objectForKey:@"filterValue"]]; + } + } } } } @@ -3458,21 +3738,27 @@ - (void) setFilterTableData:(NSData*)arcData { +#ifndef SP_REFACTOR if(!arcData) return; NSDictionary *filterData = [NSUnarchiver unarchiveObjectWithData:arcData]; [filterTableData removeAllObjects]; [filterTableData addEntriesFromDictionary:filterData]; [filterTableWindow makeKeyAndOrderFront:nil]; // [filterTableView reloadData]; +#endif } - (NSData*) filterTableData { +#ifndef SP_REFACTOR if(![filterTableWindow isVisible]) return nil; [filterTableView deselectAll:nil]; return [NSArchiver archivedDataWithRootObject:filterTableData]; +#else + return nil; +#endif } #pragma mark - @@ -3496,8 +3782,8 @@ maxNumRowsIsEstimate = NO; [tableDataInstance setStatusValue:[NSString stringWithFormat:@"%ld", (long)maxNumRows] forKey:@"Rows"]; [tableDataInstance setStatusValue:@"y" forKey:@"RowsCountAccurate"]; - [[tableInfoInstance onMainThread] tableChanged:nil]; #ifndef SP_REFACTOR + [[tableInfoInstance onMainThread] tableChanged:nil]; [[[tableDocumentInstance valueForKey:@"extendedTableInfoInstance"] onMainThread] loadTable:selectedTable]; #endif @@ -3530,7 +3816,9 @@ maxNumRowsIsEstimate = NO; [tableDataInstance setStatusValue:[NSString stringWithFormat:@"%ld", (long)maxNumRows] forKey:@"Rows"]; [tableDataInstance setStatusValue:@"y" forKey:@"RowsCountAccurate"]; +#ifndef SP_REFACTOR [[tableInfoInstance onMainThread] tableChanged:nil]; +#endif [[[tableDocumentInstance valueForKey:@"extendedTableInfoInstance"] onMainThread] loadTable:selectedTable]; // Use the estimate count @@ -3565,7 +3853,9 @@ } [tableDataInstance setStatusValue:[NSString stringWithFormat:@"%ld", (long)maxNumRows] forKey:@"Rows"]; [tableDataInstance setStatusValue:maxNumRowsIsEstimate?@"n":@"y" forKey:@"RowsCountAccurate"]; +#ifndef SP_REFACTOR [[tableInfoInstance onMainThread] tableChanged:nil]; +#endif } } @@ -3596,7 +3886,7 @@ // Otherwise set the column width NSTableColumn *aTableColumn = [tableContentView tableColumnWithIdentifier:[columnDefinition objectForKey:@"datacolumnindex"]]; - NSUInteger targetWidth = [[columnWidths objectForKey:[columnDefinition objectForKey:@"datacolumnindex"]] unsignedIntegerValue]; + NSInteger targetWidth = [[columnWidths objectForKey:[columnDefinition objectForKey:@"datacolumnindex"]] integerValue]; [aTableColumn setWidth:targetWidth]; } [tableContentView setDelegate:self]; @@ -3691,13 +3981,16 @@ - (NSInteger)numberOfRowsInTableView:(SPCopyTable *)aTableView { +#ifndef SP_REFACTOR if (aTableView == filterTableView) { if (filterTableIsSwapped) return [filterTableData count]; else return [[[filterTableData objectForKey:[NSNumber numberWithInteger:0]] objectForKey:@"filter"] count]; } - else if (aTableView == tableContentView) { + else +#endif + if (aTableView == tableContentView) { return tableRowsCount; } @@ -3706,6 +3999,7 @@ - (id)tableView:(SPCopyTable *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex { +#ifndef SP_REFACTOR if (aTableView == filterTableView) { if (filterTableIsSwapped) // First column shows the field names @@ -3718,7 +4012,9 @@ return NSArrayObjectAtIndex([[filterTableData objectForKey:[aTableColumn identifier]] objectForKey:@"filter"], rowIndex); } } - else if (aTableView == tableContentView) { + else +#endif + if (aTableView == tableContentView) { NSUInteger columnIndex = [[aTableColumn identifier] integerValue]; id theValue = nil; @@ -3762,7 +4058,7 @@ */ - (void)tableView:(SPCopyTable *)aTableView willDisplayCell:(id)cell forTableColumn:(NSTableColumn*)aTableColumn row:(NSInteger)rowIndex { - +#ifndef SP_REFACTOR if(aTableView == filterTableView) { if(filterTableIsSwapped && [[aTableColumn identifier] integerValue] == 0) { [cell setDrawsBackground:YES]; @@ -3772,7 +4068,9 @@ } return; } - else if(aTableView == tableContentView) { + else +#endif + if(aTableView == tableContentView) { if (![cell respondsToSelector:@selector(setTextColor:)]) return; @@ -3801,7 +4099,7 @@ // writing in gray if value was NULL if ([aTableView editedColumn] != -1 && [aTableView editedRow] == rowIndex - && [[NSArrayObjectAtIndex([aTableView tableColumns], [aTableView editedColumn]) identifier] unsignedIntegerValue] == columnIndex) { + && (NSUInteger)[[NSArrayObjectAtIndex([aTableView tableColumns], [aTableView editedColumn]) identifier] integerValue] == columnIndex) { [cell setTextColor:blackColor]; return; } @@ -3819,6 +4117,7 @@ - (void)tableView:(NSTableView *)aTableView setObjectValue:(id)anObject forTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex { +#ifndef SP_REFACTOR if(aTableView == filterTableView) { if(filterTableIsSwapped) [[[filterTableData objectForKey:[NSNumber numberWithInteger:rowIndex]] objectForKey:@"filter"] replaceObjectAtIndex:([[aTableColumn identifier] integerValue]-1) withObject:(NSString*)anObject]; @@ -3827,137 +4126,20 @@ [self updateFilterTableClause:nil]; return; } - else if(aTableView == tableContentView) { - // If table data come from a view - if([tablesListInstance tableType] == SPTableTypeView) { - - // Field editing - // if (fieldIDQueryString == nil) return; - NSDictionary *columnDefinition; - - // Retrieve the column defintion - for(id c in cqColumnDefinition) { - if([[c objectForKey:@"datacolumnindex"] isEqualToNumber:[aTableColumn identifier]]) { - columnDefinition = [NSDictionary dictionaryWithDictionary:c]; - break; - } - } - - // Resolve the original table name for current column if AS was used - NSString *tableForColumn = [columnDefinition objectForKey:@"org_table"]; - - if(!tableForColumn || ![tableForColumn length]) { - NSPoint pos = [NSEvent mouseLocation]; - pos.y -= 20; - [SPTooltip showWithObject:NSLocalizedString(@"Field is not editable. Field has no or multiple table or database origin(s).",@"field is not editable due to no table/database") - atLocation:pos - ofType:@"text"]; - NSBeep(); - return; - } - - // Resolve the original column name if AS was used - NSString *columnName = [columnDefinition objectForKey:@"org_name"]; - - [tableDocumentInstance startTaskWithDescription:NSLocalizedString(@"Updating field data...", @"updating field task description")]; - [[NSNotificationCenter defaultCenter] postNotificationName:@"SMySQLQueryWillBePerformed" object:tableDocumentInstance]; - - [self storeCurrentDetailsForRestoration]; - - // Check if the IDstring identifies the current field bijectively and get the WHERE clause - NSArray *editStatus = [self fieldEditStatusForRow:rowIndex andColumn:[aTableColumn identifier]]; - NSString *fieldIDQueryStr = [editStatus objectAtIndex:1]; - NSInteger numberOfPossibleUpdateRows = [[editStatus objectAtIndex:0] integerValue]; - - if(numberOfPossibleUpdateRows == 1) { - - NSString *newObject = nil; - if ( [anObject isKindOfClass:[NSCalendarDate class]] ) { - newObject = [NSString stringWithFormat:@"'%@'", [mySQLConnection prepareString:[anObject description]]]; - } else if ( [anObject isKindOfClass:[NSNumber class]] ) { - newObject = [anObject stringValue]; - } else if ( [anObject isKindOfClass:[NSData class]] ) { - newObject = [NSString stringWithFormat:@"X'%@'", [mySQLConnection prepareBinaryData:anObject]]; - } else { - if ( [[anObject description] isEqualToString:@"CURRENT_TIMESTAMP"] ) { - newObject = @"CURRENT_TIMESTAMP"; - } else if([anObject isEqualToString:[prefs stringForKey:SPNullValue]]) { - newObject = @"NULL"; - } else if ([[columnDefinition objectForKey:@"typegrouping"] isEqualToString:@"geometry"]) { - newObject = [(NSString*)anObject getGeomFromTextString]; - } else if ([[columnDefinition objectForKey:@"typegrouping"] isEqualToString:@"bit"]) { - newObject = [NSString stringWithFormat:@"b'%@'", ((![[anObject description] length] || [[anObject description] isEqualToString:@"0"]) ? @"0" : [anObject description])]; - } else if ([[columnDefinition objectForKey:@"typegrouping"] isEqualToString:@"date"] - && [[anObject description] isEqualToString:@"NOW()"]) { - newObject = @"NOW()"; - } else { - newObject = [NSString stringWithFormat:@"'%@'", [mySQLConnection prepareString:[anObject description]]]; - } - } - - [mySQLConnection queryString: - [NSString stringWithFormat:@"UPDATE %@.%@ SET %@.%@.%@ = %@ %@ LIMIT 1", - [[columnDefinition objectForKey:@"db"] backtickQuotedString], [tableForColumn backtickQuotedString], - [[columnDefinition objectForKey:@"db"] backtickQuotedString], [tableForColumn backtickQuotedString], [columnName backtickQuotedString], newObject, fieldIDQueryStr]]; - - - // Check for errors while UPDATE - if ([mySQLConnection queryErrored]) { - SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), NSLocalizedString(@"Cancel", @"cancel button"), nil, [tableDocumentInstance parentWindow], self, nil, nil, - [NSString stringWithFormat:NSLocalizedString(@"Couldn't write field.\nMySQL said: %@", @"message of panel when error while updating field to db"), [mySQLConnection getLastErrorMessage]]); - - [tableDocumentInstance endTask]; - [[NSNotificationCenter defaultCenter] postNotificationName:@"SMySQLQueryHasBeenPerformed" object:tableDocumentInstance]; - return; - } - - - // This shouldn't happen – for safety reasons - if ( ![mySQLConnection affectedRows] ) { -#ifndef SP_REFACTOR - if ( [prefs boolForKey:SPShowNoAffectedRowsError] ) { - SPBeginAlertSheet(NSLocalizedString(@"Warning", @"warning"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [tableDocumentInstance parentWindow], self, nil, nil, - NSLocalizedString(@"The row was not written to the MySQL database. You probably haven't changed anything.\nReload the table to be sure that the row exists and use a primary key for your table.\n(This error can be turned off in the preferences.)", @"message of panel when no rows have been affected after writing to the db")); - } else { - NSBeep(); - } + else #endif - [tableDocumentInstance endTask]; - [[NSNotificationCenter defaultCenter] postNotificationName:@"SMySQLQueryHasBeenPerformed" object:tableDocumentInstance]; - return; - } - - } 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"), - (long)numberOfPossibleUpdateRows, (numberOfPossibleUpdateRows>1)?@"es":@"", tableForColumn]); - - [[NSNotificationCenter defaultCenter] postNotificationName:@"SMySQLQueryHasBeenPerformed" object:tableDocumentInstance]; - [tableDocumentInstance endTask]; - return; - - } - - // Reload table after each editing due to complex declarations - if(isFirstChangeInView) { - // Set up the table details for the new table, and trigger an interface update - // if the view was modified for the very first time - NSDictionary *tableDetails = [NSDictionary dictionaryWithObjectsAndKeys: - selectedTable, @"name", - [tableDataInstance columns], @"columns", - [tableDataInstance columnNames], @"columnNames", - [tableDataInstance getConstraints], @"constraints", - nil]; - [self performSelectorOnMainThread:@selector(setTableDetails:) withObject:tableDetails waitUntilDone:YES]; - isFirstChangeInView = NO; - } - [[NSNotificationCenter defaultCenter] postNotificationName:@"SMySQLQueryHasBeenPerformed" object:tableDocumentInstance]; - [tableDocumentInstance endTask]; - - [self loadTableValues]; + if(aTableView == tableContentView) { + // If the current cell should have been edited in a sheet, do nothing - field closing will have already + // updated the field. + if ([tableContentView shouldUseFieldEditorForRow:rowIndex column:[[aTableColumn identifier] integerValue]]) { return; + } + // If table data comes from a view, save back to the view + if([tablesListInstance tableType] == SPTableTypeView) { + [self saveViewCellValue:anObject forTableColumn:aTableColumn row:rowIndex]; + return; } // Catch editing events in the row and if the row isn't currently being edited, @@ -4023,7 +4205,7 @@ // 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]) { + if (sortCol && [[tableColumn identifier] integerValue] == [sortCol integerValue]) { if(isDesc) { [sortCol release]; sortCol = nil; @@ -4034,12 +4216,12 @@ } } else { isDesc = NO; - [[tableContentView onMainThread] setIndicatorImage:nil inTableColumn:[tableContentView tableColumnWithIdentifier:sortCol]]; + [[tableContentView onMainThread] setIndicatorImage:nil inTableColumn:[tableContentView tableColumnWithIdentifier:[NSString stringWithFormat:@"%lld", (long long)[sortCol integerValue]]]]; if (sortCol) [sortCol release]; sortCol = [[NSNumber alloc] initWithInteger:[[tableColumn identifier] integerValue]]; } - if(sortCol) { + if (sortCol) { // Set the highlight and indicatorImage [[tableContentView onMainThread] setHighlightedTableColumn:tableColumn]; if (isDesc) { @@ -4078,7 +4260,6 @@ isFirstChangeInView = YES; - [addButton setEnabled:([tablesListInstance tableType] == SPTableTypeTable)]; // If we are editing a row, attempt to save that row - if saving failed, reselect the edit row. @@ -4200,13 +4381,16 @@ { if ([tableDocumentInstance isWorking]) return NO; +#ifndef SP_REFACTOR if(aTableView == filterTableView) { if(filterTableIsSwapped && [[aTableColumn identifier] integerValue] == 0) return NO; else return YES; } - else if ( aTableView == tableContentView ) { + else +#endif + if ( aTableView == tableContentView ) { // Ensure that row is editable since it could contain "(not loaded)" columns together with // issue that the table has no primary key @@ -4231,27 +4415,20 @@ [tableContentView reloadData]; } - BOOL isBlob = [tableDataInstance columnIsBlobOrText:[[aTableColumn headerCell] stringValue]]; - BOOL isFieldEditable = YES; - - // Retrieve the column defintion - NSDictionary *columnDefinition = nil; - for(id c in cqColumnDefinition) { - if([[c objectForKey:@"datacolumnindex"] isEqualToNumber:[aTableColumn identifier]]) { - columnDefinition = [NSDictionary dictionaryWithDictionary:c]; - break; - } - } + // Open the editing sheet if required + if ([tableContentView shouldUseFieldEditorForRow:rowIndex column:[[aTableColumn identifier] integerValue]]) + { - // Open the sheet if the multipleLineEditingButton is enabled or the column was a blob or a text. - if (([multipleLineEditingButton state] == NSOnState || isBlob) && ![[columnDefinition objectForKey:@"typegrouping"] isEqualToString:@"enum"]) { + // Retrieve the column definition + NSDictionary *columnDefinition = [cqColumnDefinition objectAtIndex:[[aTableColumn identifier] integerValue]]; + BOOL isBlob = [tableDataInstance columnIsBlobOrText:[[aTableColumn headerCell] stringValue]]; - // A table is per definitionem editable - isFieldEditable = YES; + // A table is per definition editable + BOOL isFieldEditable = YES; // Check for Views if field is editable if([tablesListInstance tableType] == SPTableTypeView) { - NSArray *editStatus = [self fieldEditStatusForRow:rowIndex andColumn:[aTableColumn identifier]]; + NSArray *editStatus = [self fieldEditStatusForRow:rowIndex andColumn:[[aTableColumn identifier] integerValue]]; isFieldEditable = ([[editStatus objectAtIndex:0] integerValue] == 1) ? YES : NO; } @@ -4286,7 +4463,7 @@ NSInteger editedColumn = 0; for(NSTableColumn* col in [tableContentView tableColumns]) { - if([[col identifier] isEqualToNumber:[aTableColumn identifier]]) break; + if([[col identifier] isEqualToString:[aTableColumn identifier]]) break; editedColumn++; } @@ -4298,9 +4475,8 @@ withWindow:[tableDocumentInstance parentWindow] sender:self contextInfo:[NSDictionary dictionaryWithObjectsAndKeys: - [NSNumber numberWithInteger:rowIndex], @"row", - [aTableColumn identifier], @"column", - [NSNumber numberWithInteger:editedColumn], @"editedColumn", + [NSNumber numberWithInteger:rowIndex], @"rowIndex", + [NSNumber numberWithInteger:editedColumn], @"columnIndex", [NSNumber numberWithBool:isFieldEditable], @"isFieldEditable", nil]]; @@ -4348,10 +4524,13 @@ */ - (BOOL)tableView:(NSTableView *)aTableView shouldSelectRow:(NSInteger)rowIndex { +#ifndef SP_REFACTOR if(aTableView == filterTableView) return YES; - else if(aTableView == tableContentView) + else +#endif + if(aTableView == tableContentView) return tableRowsSelectable; else return YES; @@ -4472,7 +4651,9 @@ tableRowsSelectable = NO; [paginationPreviousButton setEnabled:NO]; [paginationNextButton setEnabled:NO]; +#ifndef SP_REFACTOR [paginationButton setEnabled:NO]; +#endif } /** @@ -4493,12 +4674,14 @@ [self updatePaginationState]; [reloadButton setEnabled:YES]; } + if ([tableContentView numberOfSelectedRows] > 0) { if([tablesListInstance tableType] == SPTableTypeTable) { [removeButton setEnabled:YES]; [copyButton setEnabled:YES]; } } + [filterButton setEnabled:[fieldField isEnabled]]; tableRowsSelectable = YES; } @@ -4508,6 +4691,7 @@ - (void)controlTextDidChange:(NSNotification *)notification { +#ifndef SP_REFACTOR if ([notification object] == filterTableView) { NSString *str = [[[[notification userInfo] objectForKey:@"NSFieldEditor"] textStorage] string]; @@ -4518,6 +4702,7 @@ [self updateFilterTableClause:str]; } +#endif } /** * If user selected a table cell which is a blob field and tried to edit it @@ -4539,7 +4724,7 @@ // from the keyboard show an error tooltip // or bypass if numberOfPossibleUpdateRows == 1 if([tableContentView isCellEditingMode]) { - NSArray *editStatus = [self fieldEditStatusForRow:row andColumn:[NSArrayObjectAtIndex([tableContentView tableColumns], column) identifier]]; + NSArray *editStatus = [self fieldEditStatusForRow:row andColumn:[[NSArrayObjectAtIndex([tableContentView tableColumns], column) identifier] integerValue]]; NSInteger numberOfPossibleUpdateRows = [[editStatus objectAtIndex:0] integerValue]; NSPoint pos = [[tableDocumentInstance parentWindow] convertBaseToScreen:[tableContentView convertPoint:[tableContentView frameOfCellAtColumn:column row:row].origin toView:nil]]; pos.y -= 20; @@ -4570,11 +4755,8 @@ } - NSString *fieldType; - - // Check if current edited field is a blob - if ((fieldType = [[tableDataInstance columnWithName:[[NSArrayObjectAtIndex([tableContentView tableColumns], column) headerCell] stringValue]] objectForKey:@"typegrouping"]) - && ![fieldType isEqualToString:@"enum"] && ([fieldType isEqualToString:@"textdata"] || [fieldType isEqualToString:@"blobdata"] || [multipleLineEditingButton state] == NSOnState)) + // Open the field editor sheet if required + if ([tableContentView shouldUseFieldEditorForRow:row column:column]) { [tableContentView setFieldEditorSelectedRange:[aFieldEditor selectedRange]]; @@ -4696,6 +4878,7 @@ */ - (void)updateFilterTableClause:(id)currentValue { +#ifndef SP_REFACTOR NSMutableString *clause = [NSMutableString string]; NSInteger numberOfRows = [self numberOfRowsInTableView:filterTableView]; NSInteger numberOfCols = [[filterTableView tableColumns] count]; @@ -4833,6 +5016,7 @@ // If live search is set perform filtering if([filterTableLiveSearchCheckbox state] == NSOnState) [self filterTable:filterTableFilterButton]; +#endif } /** @@ -4868,17 +5052,6 @@ return [tableContentView fieldEditorSelectedRange]; } -#ifdef SP_REFACTOR /* glue */ -- (void)setDatabaseDocument:(SPDatabaseDocument*)doc -{ - tableDocumentInstance = doc; -} - -- (void)setTableListInstance:(SPTablesList*)list -{ - tablesListInstance = list; -} -#endif #pragma mark - @@ -4901,9 +5074,11 @@ pthread_mutex_destroy(&tableValuesLock); [dataColumns release]; [oldRow release]; +#ifndef SP_REFACTOR [filterTableData release]; if (lastEditedFilterTableValue) [lastEditedFilterTableValue release]; if (filterTableDefaultOperator) [filterTableDefaultOperator release]; +#endif if (selectedTable) [selectedTable release]; if (contentFilters) [contentFilters release]; if (numberOfDefaultFilters) [numberOfDefaultFilters release]; |