aboutsummaryrefslogtreecommitdiffstats
path: root/Source/TableContent.m
diff options
context:
space:
mode:
authorrowanbeentje <rowan@beent.je>2009-03-03 23:39:15 +0000
committerrowanbeentje <rowan@beent.je>2009-03-03 23:39:15 +0000
commitf716a08986866455792ccbb3a7d16c4e72028ade (patch)
treeebaca750fce2911d60f70c8ffdf409a122cff527 /Source/TableContent.m
parentedd1d6f093a5d6d3301a8f8cade43b051bd69083 (diff)
downloadsequelpro-f716a08986866455792ccbb3a7d16c4e72028ade.tar.gz
sequelpro-f716a08986866455792ccbb3a7d16c4e72028ade.tar.bz2
sequelpro-f716a08986866455792ccbb3a7d16c4e72028ade.zip
- BLOB and binary fields are now fully visible and editable again (fixes Issue #155)
- Added basic support for viewing, filtering, and editing BIT columns (resolves Issue #127 in basic form) - Rewrites selection/save handling. Rows are now only written to database if their content has changed, resolving a long-standing complaint; row selection and editing has also been improved, improving edit/save interaction (fixes Issue #157) and allowing re-editing of the row on failure (fixes Issue #115). Hopefully also addresses #Issue 131, and improves Issue #172. - Hides the console window when the associated document window closes
Diffstat (limited to 'Source/TableContent.m')
-rw-r--r--Source/TableContent.m139
1 files changed, 93 insertions, 46 deletions
diff --git a/Source/TableContent.m b/Source/TableContent.m
index b3044c94..1e40e99d 100644
--- a/Source/TableContent.m
+++ b/Source/TableContent.m
@@ -44,6 +44,7 @@
selectedTable = nil;
sortField = nil;
areShowingAllRows = false;
+ currentlyEditingRow = -1;
return self;
}
@@ -312,6 +313,10 @@
*/
- (IBAction)reloadTable:(id)sender
{
+
+ // Check whether a save of the current row is required.
+ if ( ![self saveRowOnDeselect] ) return;
+
// Store the current viewport location
NSRect viewRect = [tableContentView visibleRect];
@@ -398,6 +403,12 @@
NSString *queryString;
int i;
+ // Check whether a save of the current row is required.
+ if ( ![self saveRowOnDeselect] ) {
+ [argument release];
+ return;
+ }
+
// Update negative limits
if ( [limitRowsField intValue] <= 0 ) {
[limitRowsField setStringValue:@"1"];
@@ -583,6 +594,10 @@
*/
- (IBAction)showAll:(id)sender
{
+
+ // Check whether a save of the current row is required.
+ if ( ![self saveRowOnDeselect] ) return;
+
[filteredResult setArray:fullResult];
[tableContentView reloadData];
areShowingAllRows = YES;
@@ -611,8 +626,8 @@
NSMutableDictionary *column, *newRow = [NSMutableDictionary dictionary];
int i;
- if ( ![self selectionShouldChangeInTableView:nil] )
- return;
+ // Check whether a save of the current row is required.
+ if ( ![self saveRowOnDeselect] ) return;
columns = [[NSArray alloc] initWithArray:[tableDataInstance columns]];
for ( i = 0 ; i < [columns count] ; i++ ) {
@@ -626,10 +641,11 @@
[filteredResult addObject:newRow];
[columns release];
- isEditingRow = YES;
- isEditingNewRow = YES;
[tableContentView reloadData];
[tableContentView selectRow:[tableContentView numberOfRows]-1 byExtendingSelection:NO];
+ isEditingRow = YES;
+ isEditingNewRow = YES;
+ currentlyEditingRow = [tableContentView selectedRow];
if ( [multipleLineEditingButton state] == NSOffState )
[tableContentView editColumn:0 row:[tableContentView numberOfRows]-1 withEvent:nil select:YES];
}
@@ -644,8 +660,9 @@
NSDictionary *row;
int i;
- if ( ![self selectionShouldChangeInTableView:nil] )
- return;
+ // Check whether a save of the current row is required.
+ if ( ![self saveRowOnDeselect] ) return;
+
if ( [tableContentView numberOfSelectedRows] < 1 )
return;
if ( [tableContentView numberOfSelectedRows] > 1 ) {
@@ -656,8 +673,6 @@
//copy row
tempRow = [NSMutableDictionary dictionaryWithDictionary:[filteredResult objectAtIndex:[tableContentView selectedRow]]];
[filteredResult insertObject:tempRow atIndex:[tableContentView selectedRow]+1];
- isEditingRow = YES;
- isEditingNewRow = YES;
//set autoincrement fields to NULL
queryResult = [mySQLConnection queryString:[NSString stringWithFormat:@"SHOW COLUMNS FROM `%@`", selectedTable]];
if ([queryResult numOfRows]) [queryResult dataSeek:0];
@@ -670,6 +685,9 @@
//select row and go in edit mode
[tableContentView reloadData];
[tableContentView selectRow:[tableContentView selectedRow]+1 byExtendingSelection:NO];
+ isEditingRow = YES;
+ isEditingNewRow = YES;
+ currentlyEditingRow = [tableContentView selectedRow];
if ( [multipleLineEditingButton state] == NSOffState )
[tableContentView editColumn:0 row:[tableContentView selectedRow] withEvent:nil select:YES];
}
@@ -679,8 +697,9 @@
asks user if he really wants to delete the selected rows
*/
{
- if ( ![self selectionShouldChangeInTableView:nil] )
- return;
+ // Check whether a save of the current row is required.
+ if ( ![self saveRowOnDeselect] ) return;
+
if ( ![tableContentView numberOfSelectedRows] )
return;
/*
@@ -1097,7 +1116,6 @@
*/
- (BOOL)addRowToDB
{
- int rowIndex = [tableContentView selectedRow];
NSArray *theColumns, *columnNames;
NSMutableArray *fieldValues = [[NSMutableArray alloc] init];
NSMutableString *queryString;
@@ -1108,11 +1126,15 @@
NSString *currentTime = [[NSDate date] descriptionWithCalendarFormat:@"%H:%M:%S" timeZone:nil locale:nil];
int i;
- if ( !isEditingRow || rowIndex == -1) {
+ if ( !isEditingRow || currentlyEditingRow == -1) {
[fieldValues release];
return YES;
}
+
+ // If editing, compare the new row to the old row and if they're the same do nothing.
+ if ( !isEditingNewRow && [oldRow isEqualToDictionary:[filteredResult objectAtIndex:currentlyEditingRow]] ) return YES;
+
// 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.
theColumns = [tableDataInstance columns];
@@ -1120,7 +1142,7 @@
// Get the field values
for ( i = 0 ; i < [columnNames count] ; i++ ) {
- rowObject = [[filteredResult objectAtIndex:rowIndex] objectForKey:[columnNames objectAtIndex:i]];
+ rowObject = [[filteredResult objectAtIndex:currentlyEditingRow] objectForKey:[columnNames objectAtIndex:i]];
// Convert the object to a string (here we can add special treatment for date-, number- and data-fields)
if ( [[rowObject description] isEqualToString:[prefs stringForKey:@"nullValue"]]
@@ -1142,6 +1164,8 @@
} else {
if ( [[rowObject description] isEqualToString:@"CURRENT_TIMESTAMP"] ) {
[rowValue setString:@"CURRENT_TIMESTAMP"];
+ } else if ([[[theColumns objectAtIndex:i] objectForKey:@"typegrouping"] isEqualToString:@"bit"]) {
+ [rowValue setString:((![[rowObject description] length] || [[rowObject description] isEqualToString:@"0"])?@"0":@"1")];
} else {
[rowValue setString:[NSString stringWithFormat:@"'%@'", [mySQLConnection prepareString:[rowObject description]]]];
}
@@ -1178,9 +1202,10 @@
} else {
NSBeep();
}
- [filteredResult replaceObjectAtIndex:rowIndex withObject:[NSMutableDictionary dictionaryWithDictionary:oldRow]];
+ [filteredResult replaceObjectAtIndex:currentlyEditingRow withObject:[NSMutableDictionary dictionaryWithDictionary:oldRow]];
isEditingRow = NO;
isEditingNewRow = NO;
+ currentlyEditingRow = -1;
[queryConsoleInstance showErrorInConsole:[NSString stringWithFormat:NSLocalizedString(@"/* WARNING %@ No rows have been affected */\n", @"warning shown in the console when no rows have been affected after writing to the db"), currentTime]];
return YES;
@@ -1193,16 +1218,17 @@
if ( [prefs boolForKey:@"reloadAfterAdding"] ) {
[self reloadTableValues:self];
[tableContentView deselectAll:self];
+ [tableWindow endEditingFor:nil];
} else {
// Set the insertId for fields with auto_increment
for ( i = 0; i < [theColumns count] ; i++ ) {
if ([[theColumns objectAtIndex:i] objectForKey:@"autoincrement"]) {
- [[filteredResult objectAtIndex:rowIndex] setObject:[NSNumber numberWithLong:[mySQLConnection insertId]]
+ [[filteredResult objectAtIndex:currentlyEditingRow] setObject:[NSNumber numberWithLong:[mySQLConnection insertId]]
forKey:[columnNames objectAtIndex:i]];
}
}
- [fullResult addObject:[filteredResult objectAtIndex:rowIndex]];
+ [fullResult addObject:[filteredResult objectAtIndex:currentlyEditingRow]];
}
isEditingNewRow = NO;
@@ -1211,6 +1237,7 @@
if ( [prefs boolForKey:@"reloadAfterEditing"] ) {
[self reloadTableValues:self];
[tableContentView deselectAll:self];
+ [tableWindow endEditingFor:nil];
// TODO: this probably needs looking at... it's reloading it all itself?
} else {
@@ -1232,6 +1259,7 @@
[fullResult setArray:[self fetchResultAsArray:queryResult]];
}
}
+ currentlyEditingRow = -1;
return YES;
// Report errors which have occurred
@@ -1242,6 +1270,27 @@
}
}
+
+/*
+ * A method to be called whenever the table selection changes; checks whether the current
+ * row is being edited, and if so attempts to save it. Returns YES if no save was necessary
+ * or the save was successful, and NO if a save was necessary and failed - in which case further
+ * editing is required. In that case this method will reselect the row in question for reediting.
+ */
+- (BOOL)saveRowOnDeselect
+{
+
+ // If no rows are currently being edited, return success at once.
+ if (!isEditingRow) return YES;
+
+ // Attempt to save the row, and return YES if the save succeeded.
+ if ([self addRowToDB]) return YES;
+
+ // Saving failed - reselect the old row and return failure.
+ [tableContentView selectRow:currentlyEditingRow byExtendingSelection:NO];
+ return NO;
+}
+
/*
* Returns the WHERE argument to identify a row.
* If "row" is -2, it uses the oldRow.
@@ -1311,6 +1360,8 @@
if ( [tempValue isKindOfClass:[NSData class]] ) {
NSString *tmpString = [[NSString alloc] initWithData:tempValue encoding:[mySQLConnection encoding]];
+ if (tmpString == nil)
+ tmpString = [[NSString alloc] initWithData:tempValue encoding:NSASCIIStringEncoding];
[value setString:[NSString stringWithString:tmpString]];
[tmpString release];
} else {
@@ -1339,7 +1390,7 @@
[value setString:[NSString stringWithFormat:@"'%@'", value]];
columnType = [[tableDataInstance columnWithName:[keys objectAtIndex:i]] objectForKey:@"typegrouping"];
- if ( [columnType isEqualToString:@"integer"] || [columnType isEqualToString:@"float"] ) {
+ if ( [columnType isEqualToString:@"integer"] || [columnType isEqualToString:@"float"] || [columnType isEqualToString:@"bit"] ) {
[argument appendString:[NSString stringWithFormat:@"`%@` = %@", [keys objectAtIndex:i], value]];
} else {
[argument appendString:[NSString stringWithFormat:@"`%@` LIKE %@", [keys objectAtIndex:i], value]];
@@ -1433,6 +1484,7 @@
isEditingRow = NO;
isEditingNewRow = NO;
}
+ currentlyEditingRow = -1;
}
[tableContentView reloadData];
} else if ( [contextInfo isEqualToString:@"removeallrows"] ) {
@@ -1556,12 +1608,14 @@ objectValueForTableColumn:(NSTableColumn *)aTableColumn
theRow = [filteredResult objectAtIndex:rowIndex];
theValue = [theRow objectForKey:[aTableColumn identifier]];
- // Convert data objects to their string representation in the current encoding.
+ // Convert data objects to their string representation in the current encoding, falling back to ascii
if ( [theValue isKindOfClass:[NSData class]] ) {
NSString *dataRepresentation = [[NSString alloc] initWithData:theValue encoding:[mySQLConnection encoding]];
+ if (dataRepresentation == nil)
+ dataRepresentation = [[NSString alloc] initWithData:theValue encoding:NSASCIIStringEncoding];
if (dataRepresentation == nil) theValue = @"- cannot be displayed -";
else theValue = [NSString stringWithString:dataRepresentation];
- [dataRepresentation release];
+ if (dataRepresentation) [dataRepresentation release];
}
return theValue;
@@ -1575,6 +1629,7 @@ objectValueForTableColumn:(NSTableColumn *)aTableColumn
if ( !isEditingRow ) {
[oldRow setDictionary:[filteredResult objectAtIndex:rowIndex]];
isEditingRow = YES;
+ currentlyEditingRow = rowIndex;
}
if ( anObject ) {
[[filteredResult objectAtIndex:rowIndex] setObject:anObject forKey:[aTableColumn identifier]];
@@ -1597,9 +1652,10 @@ objectValueForTableColumn:(NSTableColumn *)aTableColumn
if ( [selectedTable isEqualToString:@""] || !selectedTable )
return;
- if ( ![self selectionShouldChangeInTableView:nil] )
- return;
+ // Check whether a save of the current row is required.
+ if ( ![self saveRowOnDeselect] ) return;
+
//query started
[[NSNotificationCenter defaultCenter] postNotificationName:@"SMySQLQueryWillBePerformed" object:self];
@@ -1660,32 +1716,16 @@ objectValueForTableColumn:(NSTableColumn *)aTableColumn
}
}
-- (BOOL)selectionShouldChangeInTableView:(NSTableView *)aTableView
-{
- /*
- int row = [tableContentView editedRow];
- int column = [tableContentView editedColumn];
- NSTableColumn *tableColumn;
- NSCell *cell;
-
- if ( row != -1 ) {
- tableColumn = [[tableContentView tableColumns] objectAtIndex:column];
- cell = [tableColumn dataCellForRow:row];
- [cell endEditing:[tableContentView currentEditor]];
- }
- */
- //end editing (otherwise problems when user hits reload button)
- [tableWindow endEditingFor:nil];
-
- return [self addRowToDB];
-}
-
- (void)tableViewSelectionDidChange:(NSNotification *)aNotification
{
// Check our notification object is our table content view
if ([aNotification object] != tableContentView)
return;
+
+ // If we are editing a row, attempt to save that row - if saving failed, reselect the edit row.
+ if ( isEditingRow && [tableContentView selectedRow] != currentlyEditingRow && ![self saveRowOnDeselect] ) return;
+ // Update the row selection count
if ( [tableContentView numberOfSelectedRows] > 0 ) {
[countText setStringValue:[NSString stringWithFormat:NSLocalizedString(@"%d of %d rows selected", @"Text showing how many rows are selected"), [tableContentView numberOfSelectedRows], [tableContentView numberOfRows]]];
} else {
@@ -1750,7 +1790,7 @@ objectValueForTableColumn:(NSTableColumn *)aTableColumn
- (BOOL)tableView:(NSTableView *)aTableView shouldEditTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex
{
int code;
- NSString *columnTypeGrouping, *query;
+ NSString *columnTypeGrouping, *query, *stringValue = nil;
NSEnumerator *enumerator;
NSDictionary *tempRow;
NSMutableDictionary *modifiedRow = [NSMutableDictionary dictionary];
@@ -1800,15 +1840,20 @@ objectValueForTableColumn:(NSTableColumn *)aTableColumn
if ( [theValue isKindOfClass:[NSData class]] ) {
image = [[NSImage alloc] initWithData:theValue];
[hexTextView setString:[self dataToHex:theValue]];
- theValue = [[NSString alloc] initWithData:theValue encoding:[mySQLConnection encoding]];
+ stringValue = [[NSString alloc] initWithData:theValue encoding:[mySQLConnection encoding]];
+ if (stringValue == nil)
+ stringValue = [[NSString alloc] initWithData:theValue encoding:NSASCIIStringEncoding];
} else {
[hexTextView setString:@""];
- theValue = [theValue description];
+ stringValue = [[NSString alloc] initWithString:[theValue description]];
}
[editImage setImage:image];
- [editTextView setString:theValue];
- [editTextView setSelectedRange:NSMakeRange(0,[[editTextView string] length])];
+ if (stringValue) {
+ [editTextView setString:stringValue];
+ [editTextView setSelectedRange:NSMakeRange(0,[[editTextView string] length])];
+ [stringValue release];
+ }
[NSApp beginSheet:editSheet modalForWindow:tableWindow modalDelegate:self didEndSelector:nil contextInfo:nil];
code = [NSApp runModalForWindow:editSheet];
@@ -1820,6 +1865,7 @@ objectValueForTableColumn:(NSTableColumn *)aTableColumn
if ( !isEditingRow ) {
[oldRow setDictionary:[filteredResult objectAtIndex:rowIndex]];
isEditingRow = YES;
+ currentlyEditingRow = rowIndex;
}
[[filteredResult objectAtIndex:rowIndex] setObject:[editData copy] forKey:[aTableColumn identifier]];
@@ -1924,6 +1970,7 @@ objectValueForTableColumn:(NSTableColumn *)aTableColumn
[filteredResult removeObjectAtIndex:row];
[tableContentView reloadData];
}
+ currentlyEditingRow = -1;
return TRUE;
}
else