aboutsummaryrefslogtreecommitdiffstats
path: root/Source/SPTableContent.m
diff options
context:
space:
mode:
Diffstat (limited to 'Source/SPTableContent.m')
-rw-r--r--Source/SPTableContent.m352
1 files changed, 215 insertions, 137 deletions
diff --git a/Source/SPTableContent.m b/Source/SPTableContent.m
index 7b012f45..9e50bb67 100644
--- a/Source/SPTableContent.m
+++ b/Source/SPTableContent.m
@@ -91,6 +91,7 @@
secondBetweenValueToRestore = nil;
tableRowsSelectable = YES;
contentFilterManager = nil;
+ isFirstChangeInView = YES;
isFiltered = NO;
isLimited = NO;
@@ -519,7 +520,7 @@
[[tableDocumentInstance parentWindow] makeFirstResponder:currentFirstResponder];
// Set the state of the table buttons
- [addButton setEnabled:enableInteraction];
+ [addButton setEnabled:(enableInteraction && [tablesListInstance tableType] == SPTableTypeTable)];
[copyButton setEnabled:NO];
[removeButton setEnabled:NO];
@@ -2624,6 +2625,60 @@
}
/*
+ * Check if table cell is editable
+ * Returns the number of possible changes or
+ * -1 if no table name can be found or multiple table origins
+ */
+- (NSInteger)fieldEditStatusForRow:(NSInteger)rowIndex andColumn:(NSInteger)columnIndex
+{
+ NSDictionary *columnDefinition;
+
+ // Retrieve the column defintion
+ for(id c in cqColumnDefinition) {
+ if([[c objectForKey:@"datacolumnindex"] isEqualToNumber:columnIndex]) {
+ columnDefinition = [NSDictionary dictionaryWithDictionary:c];
+ break;
+ }
+ }
+
+ // Resolve the original table name for current column if AS was used
+ NSString *tableForColumn = [columnDefinition objectForKey:@"org_table"];
+
+ // Get the database name which the field belongs to
+ NSString *dbForColumn = [columnDefinition objectForKey:@"db"];
+
+ // No table/database name found indicates that the field's column contains data from more than one table as for UNION
+ // 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])
+ return -1;
+
+ // if table and database name are given check if field can be identified unambiguously
+ NSString *fieldIDQueryStr = [self argumentForRow:rowIndex ofTable:tableForColumn andDatabase:[columnDefinition objectForKey:@"db"]];
+ if(!fieldIDQueryStr)
+ return -1;
+
+ [tableDocumentInstance startTaskWithDescription:NSLocalizedString(@"Checking field data for editing...", @"checking field data for editing task description")];
+
+ // Actual check whether field can be identified bijectively
+ MCPResult *tempResult = [mySQLConnection queryString:[NSString stringWithFormat:@"SELECT COUNT(1) FROM %@.%@ %@",
+ [[columnDefinition objectForKey:@"db"] backtickQuotedString],
+ [tableForColumn backtickQuotedString],
+ fieldIDQueryStr]];
+
+ [tableDocumentInstance endTask];
+
+ if ([mySQLConnection queryErrored])
+ return -1;
+
+ NSArray *tempRow = [tempResult fetchRowAsArray];
+
+ if(![tempRow count])
+ return -1;
+
+ return [[tempRow objectAtIndex:0] integerValue];
+
+}
+/*
* Close an open sheet.
*/
- (void)sheetDidEnd:(id)sheet returnCode:(NSInteger)returnCode contextInfo:(NSString *)contextInfo
@@ -3095,15 +3150,14 @@
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")];
-
- NSString *fieldIDQueryStringB = [self argumentForRow:rowIndex ofTable:tableForColumn andDatabase:[columnDefinition objectForKey:@"db"]];
-
[[NSNotificationCenter defaultCenter] postNotificationName:@"SMySQLQueryWillBePerformed" object:tableDocumentInstance];
+ NSString *fieldIDQueryStringB = [self argumentForRow:rowIndex ofTable:tableForColumn andDatabase:[columnDefinition objectForKey:@"db"]];
// Check if the IDstring identifies the current field bijectively
NSInteger numberOfPossibleUpdateRows = [[[[mySQLConnection queryString:[NSString stringWithFormat:@"SELECT COUNT(1) FROM %@.%@ %@", [[columnDefinition objectForKey:@"db"] backtickQuotedString], [tableForColumn backtickQuotedString], fieldIDQueryStringB]] fetchRowAsArray] objectAtIndex:0] integerValue];
@@ -3138,13 +3192,12 @@
[[columnDefinition objectForKey:@"db"] backtickQuotedString], [tableForColumn backtickQuotedString], [columnName backtickQuotedString], newObject, fieldIDQueryStringB]];
- [tableDocumentInstance endTask];
-
// 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;
}
@@ -3158,6 +3211,7 @@
} else {
NSBeep();
}
+ [tableDocumentInstance endTask];
[[NSNotificationCenter defaultCenter] postNotificationName:@"SMySQLQueryHasBeenPerformed" object:tableDocumentInstance];
return;
}
@@ -3172,12 +3226,25 @@
return;
}
- [[NSNotificationCenter defaultCenter] postNotificationName:@"SMySQLQueryHasBeenPerformed" object:tableDocumentInstance];
- [tableDocumentInstance endTask];
// Reload table after each editing due to complex declarations
- [self reloadTable:self];
+ 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:
+ tableForColumn, @"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];
return;
@@ -3277,6 +3344,12 @@
- (void)tableViewSelectionDidChange:(NSNotification *)aNotification
{
+ isFirstChangeInView = YES;
+
+
+ [addButton setEnabled:([tablesListInstance tableType] == SPTableTypeTable)];
+
+
// Check our notification object is our table content view
if ([aNotification object] != tableContentView) return;
@@ -3284,14 +3357,18 @@
if (isEditingRow && [tableContentView selectedRow] != currentlyEditingRow && ![self saveRowOnDeselect]) return;
if (![tableDocumentInstance isWorking]) {
-
// Update the row selection count
// and update the status of the delete/duplicate buttons
- if ([tableContentView numberOfSelectedRows] > 0) {
- [copyButton setEnabled:YES];
- [removeButton setEnabled:YES];
- }
- else {
+ if([tablesListInstance tableType] == SPTableTypeTable) {
+ if ([tableContentView numberOfSelectedRows] > 0) {
+ [copyButton setEnabled:([tableContentView numberOfSelectedRows] == 1)];
+ [removeButton setEnabled:YES];
+ }
+ else {
+ [copyButton setEnabled:NO];
+ [removeButton setEnabled:NO];
+ }
+ } else {
[copyButton setEnabled:NO];
[removeButton setEnabled:NO];
}
@@ -3375,72 +3452,48 @@
// If a data come from a view check if the clicked table field is editable
if([tablesListInstance tableType] == SPTableTypeView) {
- NSDictionary *columnDefinition;
- BOOL noTableName = NO;
- BOOL otherErrorWasDisplayed = NO;
- isFieldEditable = NO;
- NSInteger numberOfPossibleUpdateRows = -1;
-
- // 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"];
-
- // Get the database name which the field belongs to
- NSString *dbForColumn = [columnDefinition objectForKey:@"db"];
-
- // No table/database name found indicates that the field's column contains data from more than one table as for UNION
- // 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"]];
+ NSInteger numberOfPossibleUpdateRows = [self fieldEditStatusForRow:rowIndex andColumn:[aTableColumn identifier]];
+ isFieldEditable = (numberOfPossibleUpdateRows == 1) ? YES : NO;
+ NSPoint pos = [NSEvent mouseLocation];
+ pos.y -= 20;
+ switch(numberOfPossibleUpdateRows) {
+ case -1:
+ [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"];
+ isFieldEditable = NO;
+ // Allow to display blobs even it's not editable
+ if(!isBlob && [multipleLineEditingButton state] == NSOffState)
+ return NO;
+ break;
- [tableDocumentInstance startTaskWithDescription:NSLocalizedString(@"Checking field data for editing...", @"checking field data for editing task description")];
+ case 0:
+ [SPTooltip showWithObject:[NSString stringWithFormat:NSLocalizedString(@"Field is not editable. No matching record found.\nReload table or try to add a 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"), selectedTable]
+ atLocation:pos
+ ofType:@"text"];
- // 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];
+ isFieldEditable = NO;
+ // Allow to display blobs even it's not editable
+ if(!isBlob && [multipleLineEditingButton state] == NSOffState)
+ return NO;
+ break;
- [tableDocumentInstance endTask];
+ case 1:
+ isFieldEditable = YES;
+ if(!isBlob && [multipleLineEditingButton state] == NSOffState)
+ return YES;
+ break;
- isFieldEditable = (numberOfPossibleUpdateRows == 1) ? YES : NO;
-
- if(!isFieldEditable) {
- fieldIDQueryString = nil;
- otherErrorWasDisplayed = YES;
- NSPoint pos = [NSEvent mouseLocation];
- pos.y -= 20;
- if(numberOfPossibleUpdateRows == 0)
- [SPTooltip showWithObject:[NSString stringWithFormat:NSLocalizedString(@"Field is not editable. No matching record found.\nReload table or try to add a 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"), tableForColumn]
- atLocation:pos
- ofType:@"text"];
- else
- [SPTooltip showWithObject:[NSString stringWithFormat:NSLocalizedString(@"Field is not editable. Couldn't identify field origin unambiguously (%ld match%@).", @"Table Content result editing error - could not match row being edited uniquely"), (long)numberOfPossibleUpdateRows, (numberOfPossibleUpdateRows>1)?NSLocalizedString(@"es", @"Plural suffix for row count, eg 4 match*es*"):@""]
- atLocation:pos
- ofType:@"text"];
- // Allow to display blobs even it's not editable
- if(!isBlob && [multipleLineEditingButton state] == NSOffState)
- return NO;
- }
- }
- if(!isFieldEditable && !otherErrorWasDisplayed) {
- 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")
+ default:
+ [SPTooltip showWithObject:[NSString stringWithFormat:NSLocalizedString(@"Field is not editable. Couldn't identify field origin unambiguously (%ld match%@).", @"Table Content result editing error - could not match row being edited uniquely"), (long)numberOfPossibleUpdateRows, (numberOfPossibleUpdateRows>1)?NSLocalizedString(@"es", @"Plural suffix for row count, eg 4 match*es*"):@""]
atLocation:pos
ofType:@"text"];
-
+
+ isFieldEditable = NO;
// Allow to display blobs even it's not editable
if(!isBlob && [multipleLineEditingButton state] == NSOffState)
return NO;
+
}
}
@@ -3463,7 +3516,7 @@
withWindow:[tableDocumentInstance parentWindow]] retain];
if (editData) {
- if (!isEditingRow) {
+ if (!isEditingRow && [tablesListInstance tableType] != SPTableTypeView) {
[oldRow setArray:[tableValues rowContentsAtIndex:rowIndex]];
isEditingRow = YES;
currentlyEditingRow = rowIndex;
@@ -3629,13 +3682,15 @@
return;
if ( ![[[tableDataInstance statusValues] objectForKey:@"Rows"] isNSNull] && selectedTable && [selectedTable length] && [tableDataInstance tableEncoding]) {
- [addButton setEnabled:YES];
+ [addButton setEnabled:([tablesListInstance tableType] == SPTableTypeTable)];
[self updatePaginationState];
[reloadButton setEnabled:YES];
}
if ([tableContentView numberOfSelectedRows] > 0) {
- [removeButton setEnabled:YES];
- [copyButton setEnabled:YES];
+ if([tablesListInstance tableType] == SPTableTypeTable) {
+ [removeButton setEnabled:YES];
+ [copyButton setEnabled:YES];
+ }
}
[filterButton setEnabled:[fieldField isEnabled]];
tableRowsSelectable = YES;
@@ -3651,8 +3706,6 @@
- (BOOL)control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)command
{
- if([tablesListInstance tableType] == SPTableTypeView) return;
-
NSString *fieldType;
NSUInteger row, column, i;
@@ -3664,73 +3717,98 @@
{
[[control window] makeFirstResponder:control];
- // Save the current line if it's the last field in the table
- if ( column == ( [tableContentView numberOfColumns] - 1 ) ) {
- [self addRowToDB];
+ if([tablesListInstance tableType] == SPTableTypeView) {
+ // Check if next column is a blob column or not editable, and skip to the next non-blob column and editable field
+ if ( column != ( [tableContentView numberOfColumns] - 1 ) ) {
+ i = 1;
+ while (
+ (fieldType = [[tableDataInstance columnWithName:[[NSArrayObjectAtIndex([tableContentView tableColumns], column+i) headerCell] stringValue]] objectForKey:@"typegrouping"])
+ && ([fieldType isEqualToString:@"textdata"] || [fieldType isEqualToString:@"blobdata"])
+ || [self fieldEditStatusForRow:row andColumn:[NSArrayObjectAtIndex([tableContentView tableColumns], column+i) identifier]] != 1
+ ) {
+ i++;
+
+ // If there are no columns after the latest blob or text column, save the current line.
+ if ( (column+i) >= [tableContentView numberOfColumns] ) {
+ return TRUE;
+ }
+ }
+
+ [tableContentView editColumn:column+i row:row withEvent:nil select:YES];
+
+ }
} else {
+ // Save the current line if it's the last field in the table
+ if ( column == ( [tableContentView numberOfColumns] - 1 ) ) {
+ [self addRowToDB];
+ } else {
- // Check if next column is a blob column, and skip to the next non-blob column
- i = 1;
- while (
- (fieldType = [[tableDataInstance columnWithName:[[NSArrayObjectAtIndex([tableContentView tableColumns], column+i) headerCell] stringValue]] objectForKey:@"typegrouping"])
- && ([fieldType isEqualToString:@"textdata"] || [fieldType isEqualToString:@"blobdata"])
- ) {
- i++;
-
- // If there are no columns after the latest blob or text column, save the current line.
- if ( (column+i) >= [tableContentView numberOfColumns] ) {
- [self addRowToDB];
- return TRUE;
+ // Check if next column is a blob column, and skip to the next non-blob column
+ i = 1;
+ while (
+ (fieldType = [[tableDataInstance columnWithName:[[NSArrayObjectAtIndex([tableContentView tableColumns], column+i) headerCell] stringValue]] objectForKey:@"typegrouping"])
+ && ([fieldType isEqualToString:@"textdata"] || [fieldType isEqualToString:@"blobdata"])
+ ) {
+ i++;
+
+ // If there are no columns after the latest blob or text column, save the current line.
+ if ( (column+i) >= [tableContentView numberOfColumns] ) {
+ [self addRowToDB];
+ return TRUE;
+ }
}
- }
- // Edit the column after the blob column
- [tableContentView editColumn:column+i row:row withEvent:nil select:YES];
+ // Edit the column after the blob column
+ [tableContentView editColumn:column+i row:row withEvent:nil select:YES];
+ }
}
return TRUE;
}
-
- // Trap enter key
- else if ( [textView methodForSelector:command] == [textView methodForSelector:@selector(insertNewline:)] )
- {
- [[control window] makeFirstResponder:control];
- [self addRowToDB];
+
+ // Trap enter key
+ else if ( [textView methodForSelector:command] == [textView methodForSelector:@selector(insertNewline:)] )
+ {
+ [[control window] makeFirstResponder:control];
+ if([tablesListInstance tableType] != SPTableTypeView)
+ [self addRowToDB];
return TRUE;
- }
-
- // Trap down arrow key
- else if ( [textView methodForSelector:command] == [textView methodForSelector:@selector(moveDown:)] )
- {
- NSUInteger newRow = row+1;
- if (newRow>=tableRowsCount) return TRUE; //check if we're already at the end of the list
-
- [[control window] makeFirstResponder:control];
- [self addRowToDB];
-
- if (newRow>=tableRowsCount) return TRUE; //check again. addRowToDB could reload the table and change the number of rows
- if (column>=[tableValues columnCount]) return TRUE; //the column count could change too
-
- [tableContentView selectRowIndexes:[NSIndexSet indexSetWithIndex:newRow] byExtendingSelection:NO];
- [tableContentView editColumn:column row:newRow withEvent:nil select:YES];
+ }
+
+ // Trap down arrow key
+ else if ( [textView methodForSelector:command] == [textView methodForSelector:@selector(moveDown:)] )
+ {
+ NSUInteger newRow = row+1;
+ if (newRow>=tableRowsCount) return TRUE; //check if we're already at the end of the list
+
+ [[control window] makeFirstResponder:control];
+ if([tablesListInstance tableType] != SPTableTypeView)
+ [self addRowToDB];
+
+ if (newRow>=tableRowsCount) return TRUE; //check again. addRowToDB could reload the table and change the number of rows
+ if (column>=[tableValues columnCount]) return TRUE; //the column count could change too
+
+ [tableContentView selectRowIndexes:[NSIndexSet indexSetWithIndex:newRow] byExtendingSelection:NO];
+ [tableContentView editColumn:column row:newRow withEvent:nil select:YES];
return TRUE;
- }
-
- // Trap up arrow key
- else if ( [textView methodForSelector:command] == [textView methodForSelector:@selector(moveUp:)] )
- {
- if (row==0) return TRUE; //already at the beginning of the list
- NSUInteger newRow = row-1;
-
- [[control window] makeFirstResponder:control];
- [self addRowToDB];
-
- if (newRow>=tableRowsCount) return TRUE; // addRowToDB could reload the table and change the number of rows
- if (column>=[tableValues columnCount]) return TRUE; //the column count could change too
-
- [tableContentView selectRowIndexes:[NSIndexSet indexSetWithIndex:newRow] byExtendingSelection:NO];
- [tableContentView editColumn:column row:newRow withEvent:nil select:YES];
+ }
+
+ // Trap up arrow key
+ else if ( [textView methodForSelector:command] == [textView methodForSelector:@selector(moveUp:)] )
+ {
+ if (row==0) return TRUE; //already at the beginning of the list
+ NSUInteger newRow = row-1;
+
+ [[control window] makeFirstResponder:control];
+ if([tablesListInstance tableType] != SPTableTypeView)
+ [self addRowToDB];
+
+ if (newRow>=tableRowsCount) return TRUE; // addRowToDB could reload the table and change the number of rows
+ if (column>=[tableValues columnCount]) return TRUE; //the column count could change too
+
+ [tableContentView selectRowIndexes:[NSIndexSet indexSetWithIndex:newRow] byExtendingSelection:NO];
+ [tableContentView editColumn:column row:newRow withEvent:nil select:YES];
return TRUE;
- }
+ }
// Trap the escape key
else if ( [[control window] methodForSelector:command] == [[control window] methodForSelector:@selector(_cancelKey:)] ||
@@ -3786,12 +3864,12 @@
if ([menuItem action] == @selector(removeRow:)) {
[menuItem setTitle:([tableContentView numberOfSelectedRows] > 1) ? @"Delete Rows" : @"Delete Row"];
- return ([tableContentView numberOfSelectedRows] > 0);
+ return ([tableContentView numberOfSelectedRows] > 0 && [tablesListInstance tableType] == SPTableTypeTable);
}
// Duplicate row
if ([menuItem action] == @selector(copyRow:)) {
- return ([tableContentView numberOfSelectedRows] == 1);
+ return ([tableContentView numberOfSelectedRows] == 1 && [tablesListInstance tableType] == SPTableTypeTable);
}
return YES;