aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Frameworks/MCPKit/MCPFoundationKit/MCPNull.m2
-rw-r--r--Source/CMCopyTable.m24
-rw-r--r--Source/CustomQuery.m30
-rw-r--r--Source/SPNotLoaded.h41
-rw-r--r--Source/SPNotLoaded.m91
-rw-r--r--Source/TableContent.m191
-rw-r--r--sequel-pro.xcodeproj/project.pbxproj6
7 files changed, 245 insertions, 140 deletions
diff --git a/Frameworks/MCPKit/MCPFoundationKit/MCPNull.m b/Frameworks/MCPKit/MCPFoundationKit/MCPNull.m
index 76d9cfb1..4232fb2a 100644
--- a/Frameworks/MCPKit/MCPFoundationKit/MCPNull.m
+++ b/Frameworks/MCPKit/MCPFoundationKit/MCPNull.m
@@ -36,7 +36,7 @@
- (BOOL) isNSNull
{
static id NSNullForComparison;
- if (!NSNullForComparison) NSNullForComparison = [NSNull null];;
+ if (!NSNullForComparison) NSNullForComparison = [NSNull null];
return (self == NSNullForComparison);
}
diff --git a/Source/CMCopyTable.m b/Source/CMCopyTable.m
index f42ff783..23bf7804 100644
--- a/Source/CMCopyTable.m
+++ b/Source/CMCopyTable.m
@@ -29,6 +29,7 @@
#import "SPStringAdditions.h"
#import "TableContent.h"
#import "CustomQuery.h"
+#import "SPNotLoaded.h"
int MENU_EDIT_COPY_WITH_COLUMN = 2001;
int MENU_EDIT_COPY_AS_SQL = 2002;
@@ -131,7 +132,12 @@ int MENU_EDIT_COPY_AS_SQL = 2002;
if ( nil != rowData )
{
- [result appendString:[NSString stringWithFormat:@"%@\t", [rowData description] ] ];
+ if ([rowData isNSNull])
+ [result appendString:[NSString stringWithFormat:@"%@\t", [prefs objectForKey:@"nullValue"]]];
+ else if ([rowData isSPNotLoaded])
+ [result appendString:[NSString stringWithFormat:@"%@\t", NSLocalizedString(@"(not loaded)", @"value shown for hidden blob and text fields")]];
+ else
+ [result appendString:[NSString stringWithFormat:@"%@\t", [rowData description] ] ];
}
else
{
@@ -175,7 +181,6 @@ int MENU_EDIT_COPY_AS_SQL = 2002;
NSUInteger numColumns = [columns count];
NSIndexSet *selectedRows = [self selectedRowIndexes];
- NSString *spNULL = [prefs objectForKey:@"NullValue"];
NSMutableString *value = [NSMutableString stringWithCapacity:10];
NSArray *dbDataRow;
NSMutableArray *columnMappings;
@@ -227,8 +232,8 @@ int MENU_EDIT_COPY_AS_SQL = 2002;
{
rowData = [[tableData objectAtIndex:rowIndex] objectAtIndex:[[columnMappings objectAtIndex:c] intValue]];
- // Check for NULL value - TODO this is not safe!!
- if([[rowData description] isEqualToString:spNULL]){
+ // Check for NULL value
+ if([rowData isNSNull]) {
[value appendString:@"NULL, "];
continue;
}
@@ -243,7 +248,7 @@ int MENU_EDIT_COPY_AS_SQL = 2002;
[mySQLConnection prepareString:[rowData description]]]];
break;
case 2: // blob
- if (![[self delegate] isKindOfClass:[CustomQuery class]] && [prefs boolForKey:@"LoadBlobsAsNeeded"]) {
+ if (![[self delegate] isKindOfClass:[CustomQuery class]] && [rowData isSPNotLoaded]) {
// Abort if there are no indices on this table or if there's no table name given.
if (![[tableInstance argumentForRow:rowIndex] length] || selectedTable == nil)
@@ -253,7 +258,7 @@ int MENU_EDIT_COPY_AS_SQL = 2002;
dbDataRow = [[mySQLConnection queryString:
[NSString stringWithFormat:@"SELECT * FROM %@ WHERE %@",
[selectedTable backtickQuotedString], [tableInstance argumentForRow:rowIndex]]] fetchRowAsArray];
- if([[dbDataRow objectAtIndex:[[columnMappings objectAtIndex:c] intValue]] isKindOfClass:[NSNull class]])
+ if([[dbDataRow objectAtIndex:[[columnMappings objectAtIndex:c] intValue]] isNSNull])
[value appendString:@"NULL, "];
else
[value appendString:[NSString stringWithFormat:@"X'%@', ",
@@ -365,7 +370,12 @@ int MENU_EDIT_COPY_AS_SQL = 2002;
if ( nil != rowData )
{
- [result appendString:[NSString stringWithFormat:@"%@\t", [rowData description] ] ];
+ if ([rowData isNSNull])
+ [result appendString:[NSString stringWithFormat:@"%@\t", [prefs objectForKey:@"nullValue"]]];
+ else if ([rowData isSPNotLoaded])
+ [result appendString:[NSString stringWithFormat:@"%@\t", NSLocalizedString(@"(not loaded)", @"value shown for hidden blob and text fields")]];
+ else
+ [result appendString:[NSString stringWithFormat:@"%@\t", [rowData description] ] ];
}
else
{
diff --git a/Source/CustomQuery.m b/Source/CustomQuery.m
index f04f9fd1..0589ab6f 100644
--- a/Source/CustomQuery.m
+++ b/Source/CustomQuery.m
@@ -686,13 +686,8 @@
- (void)processResultIntoDataStorage:(MCPStreamingResult *)theResult
{
NSArray *tempRow;
- NSMutableArray *newRow;
- int i;
long rowsProcessed = 0;
- long columnsCount = 0;
NSAutoreleasePool *dataLoadingPool;
- id prefsNullValue = [[prefs objectForKey:@"NullValue"] retain];
- Class nullClass = [NSNull class];
// Remove all items from the table
[fullResult removeAllObjects];
@@ -702,16 +697,8 @@
// Loop through the result rows as they become available
while (tempRow = [theResult fetchNextRowAsArray]) {
- if (columnsCount == 0) columnsCount = [tempRow count];
NSMutableArrayAddObject(fullResult, [NSMutableArray arrayWithArray:tempRow]);
- newRow = NSArrayObjectAtIndex(fullResult, rowsProcessed);
-
- // Process the retrieved row
- for ( i = 0; i < columnsCount; i++ ) {
- if ( [NSArrayObjectAtIndex(tempRow, i) isMemberOfClass:nullClass] )
- [newRow replaceObjectAtIndex:i withObject:prefsNullValue];
- }
// Update the count of rows processed
rowsProcessed++;
@@ -725,7 +712,6 @@
// Clean up the autorelease pool
[dataLoadingPool drain];
- [prefsNullValue release];
}
/*
@@ -1182,7 +1168,7 @@
// If there is no primary key, all found fields belonging to the same table are used in the argument
for(field in columnsForFieldTableName) {
id aValue = [dataRow objectAtIndex:[[field objectForKey:@"datacolumnindex"] intValue]];
- if ([aValue isKindOfClass:[NSNull class]] || [[aValue description] isEqualToString:[prefs stringForKey:@"NullValue"]]) {
+ if ([aValue isKindOfClass:[NSNull class]] || [aValue isNSNull]) {
[fieldIDQueryStr appendFormat:@"%@ IS NULL", [[field objectForKey:@"org_name"] backtickQuotedString]];
} else {
[fieldIDQueryStr appendFormat:@"%@=", [[field objectForKey:@"org_name"] backtickQuotedString]];
@@ -1233,11 +1219,8 @@
// For NULL cell's display the user's NULL value placeholder in grey to easily distinguish it from other values
if ([cell respondsToSelector:@selector(setTextColor:)]) {
- // Note that this approach of changing the color of NULL placeholders is dependent on the cell's value matching that
- // of the user's NULL value preference which was set in the result array when it was retrieved (see fetchResultAsArray).
- // Also, as an added measure check that the table column actually allows NULLs to make sure we don't change a cell that
- // happens to have a value matching the NULL placeholder, but the column doesn't allow NULLs.
- [cell setTextColor:([[cell stringValue] isEqualToString:[prefs objectForKey:@"NullValue"]]) ? [NSColor lightGrayColor] : [NSColor blackColor]];
+ id theValue = NSArrayObjectAtIndex(NSArrayObjectAtIndex(fullResult, row), [[aTableColumn identifier] intValue]);
+ [cell setTextColor:[theValue isNSNull] ? [NSColor lightGrayColor] : [NSColor blackColor]];
}
}
@@ -1255,7 +1238,7 @@
if ( [theValue isKindOfClass:[NSData class]] )
return [theValue shortStringRepresentationUsingEncoding:[mySQLConnection encoding]];
- if ( [theValue isMemberOfClass:[NSNull class]] )
+ if ( [theValue isNSNull] )
return [prefs objectForKey:@"NullValue"];
return theValue;
@@ -1659,7 +1642,10 @@
&& [columnDefinition valueForKey:@"char_length"])
[fieldEditor setTextMaxLength:[[columnDefinition valueForKey:@"char_length"] intValue]];
- id editData = [[fieldEditor editWithObject:[[fullResult objectAtIndex:rowIndex] objectAtIndex:[[aTableColumn identifier] intValue]]
+ id originalData = [[fullResult objectAtIndex:rowIndex] objectAtIndex:[[aTableColumn identifier] intValue]];
+ if ([originalData isNSNull]) originalData = [prefs objectForKey:@"nullValue"];
+
+ id editData = [[fieldEditor editWithObject:originalData
fieldName:[columnDefinition objectForKey:@"name"]
usingEncoding:[mySQLConnection encoding]
isObjectBlob:isBlob
diff --git a/Source/SPNotLoaded.h b/Source/SPNotLoaded.h
new file mode 100644
index 00000000..e2026525
--- /dev/null
+++ b/Source/SPNotLoaded.h
@@ -0,0 +1,41 @@
+//
+// $Id$
+//
+// SPNotLoaded.h
+// sequel-pro
+//
+// Created by Rowan Beentje on 07/10/2009.
+// Copyright 2009 Rowan Beentje. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// More info at <http://code.google.com/p/sequel-pro/>
+
+#import <Cocoa/Cocoa.h>
+
+@interface SPNotLoaded : NSObject {
+
+}
+
++ (SPNotLoaded *) notLoaded;
+
+@end
+
+// Also provide a method for testing objects
+@interface NSObject (SPNotLoadedTest)
+
+- (BOOL) isSPNotLoaded;
+
+@end \ No newline at end of file
diff --git a/Source/SPNotLoaded.m b/Source/SPNotLoaded.m
new file mode 100644
index 00000000..f8afda1b
--- /dev/null
+++ b/Source/SPNotLoaded.m
@@ -0,0 +1,91 @@
+//
+// $Id$
+//
+// SPNotLoaded.m
+// sequel-pro
+//
+// Created by Rowan Beentje on 07/10/2009.
+// Copyright 2009 Rowan Beentje. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// More info at <http://code.google.com/p/sequel-pro/>
+
+#import "SPNotLoaded.h"
+
+static SPNotLoaded *notLoaded = nil;
+
+@implementation SPNotLoaded
+
+// Return the singleton object
++ (SPNotLoaded *) notLoaded
+{
+ @synchronized(self) {
+ if (notLoaded == nil) {
+ [[self alloc] init];
+ }
+ }
+ return notLoaded;
+}
+
++ (id) allocWithZone:(NSZone *)zone
+{
+ @synchronized(self) {
+ if (notLoaded == nil) {
+ return [super allocWithZone:zone];
+ }
+ }
+ return notLoaded;
+}
+
+- (id) init
+{
+ Class notLoadedClass = [self class];
+ @synchronized(notLoadedClass) {
+ if (notLoaded == nil) {
+ if (self = [super init]) {
+ notLoaded = self;
+ }
+ }
+ }
+ return notLoaded;
+}
+
+- (id) copyWithZone:(NSZone *)zone { return self; }
+
+- (id) retain { return self; }
+
+- (unsigned) retainCount { return UINT_MAX; }
+
+- (void) release {}
+
+- (id) autorelease { return self; }
+
+@end
+
+
+/**
+ * This Category is intended to allow easy testing of all objects for SPNotLoaded.
+ */
+@implementation NSObject (SPNotLoadedTest)
+
+- (BOOL) isSPNotLoaded
+{
+ static id SPNotLoadedForComparison;
+ if (!SPNotLoadedForComparison) SPNotLoadedForComparison = [SPNotLoaded notLoaded];
+ return (self == SPNotLoadedForComparison);
+}
+
+@end \ No newline at end of file
diff --git a/Source/TableContent.m b/Source/TableContent.m
index 6537f574..1fa9d193 100644
--- a/Source/TableContent.m
+++ b/Source/TableContent.m
@@ -46,6 +46,7 @@
#import "SPTooltip.h"
#import "RegexKitLite.h"
#import "SPContentFilterManager.h"
+#import "SPNotLoaded.h"
@implementation TableContent
@@ -160,7 +161,7 @@
// If no table has been supplied, reset the view to a blank table and disabled elements.
// [tableDataInstance tableEncoding] == nil indicates that an error occured while retrieving table data
- if ( [[[tableDataInstance statusValues] objectForKey:@"Rows"] isKindOfClass:[NSNull class]] || [aTable isEqualToString:@""] || !aTable || [tableDataInstance tableEncoding] == nil)
+ if ( [[[tableDataInstance statusValues] objectForKey:@"Rows"] isNSNull] || [aTable isEqualToString:@""] || !aTable || [tableDataInstance tableEncoding] == nil)
{
// Empty the stored data arrays
[tableValues removeAllObjects];
@@ -851,7 +852,7 @@
for ( i = 0 ; i < [dataColumns count] ; i++ ) {
column = NSArrayObjectAtIndex(dataColumns, i);
if ([column objectForKey:@"default"] == nil || [[column objectForKey:@"default"] isEqualToString:@"NULL"]) {
- [newRow addObject:[prefs stringForKey:@"NullValue"]];
+ [newRow addObject:[NSNull null]];
} else {
[newRow addObject:[column objectForKey:@"default"]];
}
@@ -909,15 +910,9 @@
for ( i = 0 ; i < [queryResult numOfRows] ; i++ ) {
row = [queryResult fetchRowAsDictionary];
if ( [[row objectForKey:@"Extra"] isEqualToString:@"auto_increment"] ) {
- [tempRow replaceObjectAtIndex:i withObject:[prefs stringForKey:@"NullValue"]];
+ [tempRow replaceObjectAtIndex:i withObject:[NSNull null]];
} else if ( [tableDataInstance columnIsBlobOrText:[row objectForKey:@"Field"]] && [prefs boolForKey:@"LoadBlobsAsNeeded"] && dbDataRow) {
- NSString *valueString = nil;
- //if what we read from DB is NULL (NSNull), we replace it with the string NULL
- if([[dbDataRow objectAtIndex:i] isKindOfClass:[NSNull class]])
- valueString = [prefs objectForKey:@"NullValue"];
- else
- valueString = [dbDataRow objectAtIndex:i];
- [tempRow replaceObjectAtIndex:i withObject:valueString];
+ [tempRow replaceObjectAtIndex:i withObject:[dbDataRow objectAtIndex:i]];
}
}
@@ -1005,8 +1000,10 @@
enumerator = [tableColumns objectEnumerator];
while ( (tableColumn = [enumerator nextObject]) ) {
id o = [NSArrayObjectAtIndex(tableValues, i) objectAtIndex:[[tableColumn identifier] intValue]];
- if([o isKindOfClass:[NSNull class]])
+ if([o isNSNull])
[tempRow addObject:@"NULL"];
+ else if ([o isSPNotLoaded])
+ [tempRow addObject:NSLocalizedString(@"(not loaded)", @"value shown for hidden blob and text fields")];
else if([o isKindOfClass:[NSString class]])
[tempRow addObject:[o description]];
else {
@@ -1117,7 +1114,7 @@
NSDictionary *filterSettings = [NSDictionary dictionaryWithObjectsAndKeys:
[refDictionary objectForKey:@"column"], @"filterField",
targetFilterValue, @"filterValue",
- ([targetFilterValue isEqualToString:[prefs objectForKey:@"NullValue"]]?@"IS NULL":nil), @"filterComparison",
+ ([targetFilterValue isNSNull]?@"IS NULL":nil), @"filterComparison",
nil];
[self setFiltersToRestore:filterSettings];
@@ -1317,9 +1314,7 @@
NSAutoreleasePool *dataLoadingPool;
NSProgressIndicator *dataLoadingIndicator = [tableDocumentInstance valueForKey:@"queryProgressBar"];
- id prefsNullValue = [[prefs objectForKey:@"NullValue"] retain];
BOOL prefsLoadBlobsAsNeeded = [prefs boolForKey:@"LoadBlobsAsNeeded"];
- Class nullClass = [NSNull class];
// Build up an array of which columns are blobs for faster iteration
for ( i = 0; i < columnsCount ; i++ ) {
@@ -1337,25 +1332,22 @@
// Loop through the result rows as they become available
while (tempRow = [theResult fetchNextRowAsArray]) {
- NSMutableArrayAddObject(tableValues, [NSMutableArray arrayWithCapacity:columnsCount]);
- newRow = NSArrayObjectAtIndex(tableValues, rowsProcessed);
-
- // Process the retrieved row
- for ( i = 0; i < columnsCount; i++ ) {
- if ( [NSArrayObjectAtIndex(tempRow, i) isMemberOfClass:nullClass] ) {
- NSMutableArrayAddObject(newRow, prefsNullValue);
- } else {
- NSMutableArrayAddObject(newRow, NSArrayObjectAtIndex(tempRow, i));
- }
- }
// Add values for hidden blob and text fields if appropriate
if ( prefsLoadBlobsAsNeeded ) {
+ NSMutableArrayAddObject(tableValues, [NSMutableArray arrayWithCapacity:columnsCount]);
+ newRow = NSArrayObjectAtIndex(tableValues, rowsProcessed);
for ( i = 0 ; i < columnsCount ; i++ ) {
if ( [NSArrayObjectAtIndex(columnBlobStatuses, i) boolValue] ) {
- [newRow replaceObjectAtIndex:i withObject:NSLocalizedString(@"(not loaded)", @"value shown for hidden blob and text fields")];
+ [newRow addObject:[SPNotLoaded notLoaded]];
+ } else {
+ NSMutableArrayAddObject(newRow, NSArrayObjectAtIndex(tempRow, i));
}
}
+
+ // Otherwise just add the new row
+ } else {
+ NSMutableArrayAddObject(tableValues, [NSMutableArray arrayWithArray:tempRow]);
}
// Update the progress bar as necessary, minimising updates
@@ -1382,7 +1374,6 @@
[dataLoadingIndicator setIndeterminate:YES];
[columnBlobStatuses release];
- [prefsNullValue release];
}
@@ -1419,11 +1410,10 @@
for ( i = 0 ; i < [dataColumns count] ; i++ ) {
rowObject = [NSArrayObjectAtIndex(tableValues, currentlyEditingRow) objectAtIndex:i];
- // Add (not loaded) placeholders directly for easy comparsion when added
- if (prefsLoadBlobsAsNeeded && !isEditingNewRow
- && [rowObject isEqualToString:NSLocalizedString(@"(not loaded)", @"value shown for hidden blob and text fields")])
+ // Add not loaded placeholders directly for easy comparison when added
+ if (prefsLoadBlobsAsNeeded && !isEditingNewRow && [rowObject isSPNotLoaded])
{
- [fieldValues addObject:[NSString stringWithString:rowObject]];
+ [fieldValues addObject:[SPNotLoaded notLoaded]];
continue;
// Catch CURRENT_TIMESTAMP automatic updates - if the row is new and the cell value matches
@@ -1435,7 +1425,7 @@
[rowValue setString:@"CURRENT_TIMESTAMP"];
// Convert the object to a string (here we can add special treatment for date-, number- and data-fields)
- } else if ( [[rowObject description] isEqualToString:[prefs stringForKey:@"NullValue"]]
+ } else if ( [rowObject isNSNull]
|| ([rowObject isMemberOfClass:[NSString class]] && [[rowObject description] isEqualToString:@""]) ) {
//NULL when user entered the nullValue string defined in the prefs or when a number field isn't set
@@ -1467,7 +1457,7 @@
[fieldValues addObject:[NSString stringWithString:rowValue]];
}
- // Use INSERT syntax when creating new rows - no need to do (not loaded) checking, as all values have been entered
+ // Use INSERT syntax when creating new rows - no need to do not loaded checking, as all values have been entered
if ( isEditingNewRow ) {
queryString = [NSString stringWithFormat:@"INSERT INTO %@ (%@) VALUES (%@)",
[selectedTable backtickQuotedString], [[tableDataInstance columnNames] componentsJoinedAndBacktickQuoted], [fieldValues componentsJoinedByString:@","]];
@@ -1479,7 +1469,7 @@
for ( i = 0 ; i < [dataColumns count] ; i++ ) {
// If data column loading is deferred and the value is the not loaded string, skip this cell
- if (prefsLoadBlobsAsNeeded && [[fieldValues objectAtIndex:i] isEqualToString:NSLocalizedString(@"(not loaded)", @"value shown for hidden blob and text fields")]) continue;
+ if (prefsLoadBlobsAsNeeded && [[fieldValues objectAtIndex:i] isSPNotLoaded]) continue;
if (firstCellOutput) [queryString appendString:@", "];
else firstCellOutput = YES;
@@ -1653,7 +1643,7 @@
[value setString:[tempValue description]];
}
- if ( [value isEqualToString:[prefs stringForKey:@"NullValue"]] ) {
+ if ( [value isNSNull] ) {
[argument appendString:[NSString stringWithFormat:@"%@ IS NULL", [NSArrayObjectAtIndex(keys, i) backtickQuotedString]]];
} else {
@@ -2100,14 +2090,23 @@
if ([theValue isKindOfClass:[NSData class]])
return [theValue shortStringRepresentationUsingEncoding:[mySQLConnection encoding]];
+ if ([theValue isNSNull])
+ return [prefs objectForKey:@"NullValue"];
+
+ if ([theValue isSPNotLoaded])
+ return NSLocalizedString(@"(not loaded)", @"value shown for hidden blob and text fields");
+
return theValue;
}
/**
- * This function changes the text color of text/blob fields which are not yet loaded to gray
+ * This function changes the text color of text/blob fields which are null or not yet loaded to gray
*/
- (void)tableView:(CMCopyTable *)aTableView willDisplayCell:(id)cell forTableColumn:(NSTableColumn*)aTableColumn row:(int)row
{
+
+ if (![cell respondsToSelector:@selector(setTextColor:)]) return;
+
// If user wants to edit 'cell' set text color to black and return to avoid
// writing in gray if value was NULL
if ( [aTableView editedColumn] == [[aTableColumn identifier] intValue] && [aTableView editedRow] == row) {
@@ -2115,46 +2114,15 @@
return;
}
- NSDictionary *column = NSArrayObjectAtIndex(dataColumns, [[aTableColumn identifier] intValue]);
+ id theValue = NSArrayObjectAtIndex(NSArrayObjectAtIndex(tableValues, row), [[aTableColumn identifier] intValue]);
- // For NULL cell's display the user's NULL value placeholder in grey to easily distinguish it from other values
- if ([cell respondsToSelector:@selector(setTextColor:)]) {
-
- // Note that this approach of changing the color of NULL placeholders is dependent on the cell's value matching that
- // of the user's NULL value preference which was set in the result array when it was retrieved (see fetchResultAsArray).
- // Also, as an added measure check that the table column actually allows NULLs to make sure we don't change a cell that
- // happens to have a value matching the NULL placeholder, but the column doesn't allow NULLs.
- [cell setTextColor:([[cell stringValue] isEqualToString:[prefs objectForKey:@"NullValue"]] && [[column objectForKey:@"null"] boolValue]) ? [NSColor lightGrayColor] : [NSColor blackColor]];
- }
+ // For null cells and not loaded cells, display the contents in gray.
+ if ([theValue isNSNull] || [theValue isSPNotLoaded]) {
+ [cell setTextColor:[NSColor lightGrayColor]];
- // Check if loading of text/blob fields is disabled
- // If not, all text fields are loaded and we don't have to make them gray
- if ([prefs boolForKey:@"LoadBlobsAsNeeded"])
- {
- // Make sure that the cell actually responds to setTextColor:
- // In the future, we might use different cells for the table view
- // that don't support this selector
- if ([cell respondsToSelector:@selector(setTextColor:)])
- {
- // Test if the current column is a text or a blob field
- NSString *columnTypeGrouping = [column objectForKey:@"typegrouping"];
-
- if ([columnTypeGrouping isEqualToString:@"textdata"] || [columnTypeGrouping isEqualToString:@"blobdata"]) {
-
- // now check if the field has been loaded already or not
- if ([[cell stringValue] isEqualToString:NSLocalizedString(@"(not loaded)", @"value shown for hidden blob and text fields")])
- {
- // change the text color of the cell to gray
- [cell setTextColor:[NSColor lightGrayColor]];
- }
- else {
- // Change the text color back to black
- // This is necessary because NSTableView reuses
- // the NSCell to draw further rows in the column
- [cell setTextColor:([[cell stringValue] isEqualToString:[prefs objectForKey:@"NullValue"]] && [[column objectForKey:@"null"] boolValue]) ? [NSColor lightGrayColor] : [NSColor blackColor]];
- }
- }
- }
+ // Otherwise, set the color to black - required as NSTableView reuses NSCells.
+ } else {
+ [cell setTextColor:[NSColor blackColor]];
}
}
@@ -2167,12 +2135,19 @@
isEditingRow = YES;
currentlyEditingRow = rowIndex;
}
+
+ NSDictionary *column = NSArrayObjectAtIndex(dataColumns, [[aTableColumn identifier] intValue]);
- if (anObject)
+ if (anObject) {
+
+ // Restore NULLs if necessary
+ if ([anObject isEqualToString:[prefs objectForKey:@"NullValue"]] && [[column objectForKey:@"null"] boolValue])
+ anObject = [NSNull null];
+
[NSArrayObjectAtIndex(tableValues, rowIndex) replaceObjectAtIndex:[[aTableColumn identifier] intValue] withObject:anObject];
- else
+ } else {
[NSArrayObjectAtIndex(tableValues, rowIndex) replaceObjectAtIndex:[[aTableColumn identifier] intValue] withObject:@""];
-
+ }
}
#pragma mark -
@@ -2291,39 +2266,26 @@
*/
- (BOOL)tableView:(NSTableView *)aTableView shouldEditTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex
{
- NSUInteger i;
- // If the preference value for not showing blobs is set, check whether the row contains any blobs.
- if ([prefs boolForKey:@"LoadBlobsAsNeeded"]) {
+ // If the selected cell hasn't been loaded, load it.
+ if ([NSArrayObjectAtIndex(NSArrayObjectAtIndex(tableValues, rowIndex), [[aTableColumn identifier] intValue]) isSPNotLoaded]) {
- // If the table does contain blob or text fields, load the values ready for editing.
- if ([self tableContainsBlobOrTextColumns]) {
- NSString *wherePart = [NSString stringWithString:[self argumentForRow:[tableContentView selectedRow]]];
-
- if ([wherePart length] == 0) return NO;
-
- // Only get the data for the selected column, not all of them
- NSString *query = [NSString stringWithFormat:@"SELECT %@ FROM %@ WHERE %@", [[[aTableColumn headerCell] stringValue] backtickQuotedString], [selectedTable backtickQuotedString], wherePart];
-
- MCPResult *tempResult = [mySQLConnection queryString:query];
-
- if (![tempResult numOfRows]) {
- NSBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, tableWindow, self, nil, nil, nil,
- NSLocalizedString(@"Couldn't load the row. Reload the table to be sure that the row exists and use a primary key for your table.", @"message of panel when loading of row failed"));
- return NO;
- }
-
- NSArray *tempRow = [tempResult fetchRowAsArray];
- NSMutableArray *modifiedRow = [NSMutableArray array];
-
- for (i = 0; i < [tempRow count]; i++)
- {
- [modifiedRow addObject:([[tempRow objectAtIndex:i] isMemberOfClass:[NSNull class]]) ? [prefs stringForKey:@"NullValue"] : [tempRow objectAtIndex:i]];
- }
-
- [[tableValues objectAtIndex:rowIndex] replaceObjectAtIndex:[[tableContentView tableColumns] indexOfObject:aTableColumn] withObject:[modifiedRow objectAtIndex:0]];
- [tableContentView reloadData];
+ NSString *wherePart = [NSString stringWithString:[self argumentForRow:[tableContentView selectedRow]]];
+ if ([wherePart length] == 0) return NO;
+
+ // Only get the data for the selected column, not all of them
+ NSString *query = [NSString stringWithFormat:@"SELECT %@ FROM %@ WHERE %@", [[[aTableColumn headerCell] stringValue] backtickQuotedString], [selectedTable backtickQuotedString], wherePart];
+
+ MCPResult *tempResult = [mySQLConnection queryString:query];
+ if (![tempResult numOfRows]) {
+ NSBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, tableWindow, self, nil, nil, nil,
+ NSLocalizedString(@"Couldn't load the row. Reload the table to be sure that the row exists and use a primary key for your table.", @"message of panel when loading of row failed"));
+ return NO;
}
+
+ NSArray *tempRow = [tempResult fetchRowAsArray];
+ [[tableValues objectAtIndex:rowIndex] replaceObjectAtIndex:[[tableContentView tableColumns] indexOfObject:aTableColumn] withObject:[tempRow objectAtIndex:0]];
+ [tableContentView reloadData];
}
BOOL isBlob = [tableDataInstance columnIsBlobOrText:[[aTableColumn headerCell] stringValue]];
@@ -2335,7 +2297,10 @@
[fieldEditor setTextMaxLength:[[[aTableColumn dataCellForRow:rowIndex] formatter] textLimit]];
- id editData = [[fieldEditor editWithObject:[[tableValues objectAtIndex:rowIndex] objectAtIndex:[[aTableColumn identifier] intValue]]
+ id cellValue = [[tableValues objectAtIndex:rowIndex] objectAtIndex:[[aTableColumn identifier] intValue]];
+ if ([cellValue isNSNull]) cellValue = [NSString stringWithString:[prefs objectForKey:@"nullValue"]];
+
+ id editData = [[fieldEditor editWithObject:cellValue
fieldName:[[aTableColumn headerCell] stringValue]
usingEncoding:[mySQLConnection encoding]
isObjectBlob:isBlob
@@ -2348,8 +2313,14 @@
isEditingRow = YES;
currentlyEditingRow = rowIndex;
}
-
- [[tableValues objectAtIndex:rowIndex] replaceObjectAtIndex:[[aTableColumn identifier] intValue] withObject:[editData copy]];
+
+ if ([editData isEqualToString:[prefs objectForKey:@"NullValue"]]
+ && [[NSArrayObjectAtIndex(dataColumns, [[aTableColumn identifier] intValue]) objectForKey:@"null"] boolValue])
+ {
+ [editData release];
+ editData = [[NSNull null] retain];
+ }
+ [[tableValues objectAtIndex:rowIndex] replaceObjectAtIndex:[[aTableColumn identifier] intValue] withObject:[[editData copy] autorelease]];
}
[fieldEditor release];
diff --git a/sequel-pro.xcodeproj/project.pbxproj b/sequel-pro.xcodeproj/project.pbxproj
index d678b0bb..adf4032a 100644
--- a/sequel-pro.xcodeproj/project.pbxproj
+++ b/sequel-pro.xcodeproj/project.pbxproj
@@ -141,6 +141,7 @@
5822C9B51000DB2400DCC3D6 /* SPConnectionController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5822C9B41000DB2400DCC3D6 /* SPConnectionController.m */; };
5822CAE110011C8000DCC3D6 /* ConnectionView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5822CADF10011C8000DCC3D6 /* ConnectionView.xib */; };
5822D3091061833C00CE2157 /* SPCSVParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 5822D3081061833C00CE2157 /* SPCSVParser.m */; };
+ 582A01E9107C0C170027D42B /* SPNotLoaded.m in Sources */ = {isa = PBXBuildFile; fileRef = 582A01E8107C0C170027D42B /* SPNotLoaded.m */; };
583B77D4103870C800B21F7E /* MCPStreamingResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 583B779810386B0200B21F7E /* MCPStreamingResult.m */; };
5841423F0F97E11000A34B47 /* NoodleLineNumberView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5841423E0F97E11000A34B47 /* NoodleLineNumberView.m */; };
584192A1101E57BB0089807F /* NSMutableArray-MultipleSort.m in Sources */ = {isa = PBXBuildFile; fileRef = 584192A0101E57BB0089807F /* NSMutableArray-MultipleSort.m */; };
@@ -523,6 +524,8 @@
5822CAE010011C8000DCC3D6 /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = English.lproj/ConnectionView.xib; sourceTree = "<group>"; };
5822D3071061833C00CE2157 /* SPCSVParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SPCSVParser.h; sourceTree = "<group>"; };
5822D3081061833C00CE2157 /* SPCSVParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SPCSVParser.m; sourceTree = "<group>"; };
+ 582A01E7107C0C170027D42B /* SPNotLoaded.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SPNotLoaded.h; sourceTree = "<group>"; };
+ 582A01E8107C0C170027D42B /* SPNotLoaded.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SPNotLoaded.m; sourceTree = "<group>"; };
583B779710386B0200B21F7E /* MCPStreamingResult.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 4; path = MCPStreamingResult.h; sourceTree = "<group>"; };
583B779810386B0200B21F7E /* MCPStreamingResult.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MCPStreamingResult.m; sourceTree = "<group>"; };
5841423D0F97E11000A34B47 /* NoodleLineNumberView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NoodleLineNumberView.h; sourceTree = "<group>"; };
@@ -1349,6 +1352,8 @@
B57747D80F7A8990003B34F9 /* SPWindowAdditions.m */,
BC2C16D20FEBEDF10003993B /* SPDataAdditions.h */,
BC2C16D30FEBEDF10003993B /* SPDataAdditions.m */,
+ 582A01E7107C0C170027D42B /* SPNotLoaded.h */,
+ 582A01E8107C0C170027D42B /* SPNotLoaded.m */,
);
name = "Category Additions";
sourceTree = "<group>";
@@ -1773,6 +1778,7 @@
5822D3091061833C00CE2157 /* SPCSVParser.m in Sources */,
BC675A141072039C00C5ACD4 /* SPContentFilterManager.m in Sources */,
17292443107AC41000B21980 /* SPXMLExporter.m in Sources */,
+ 582A01E9107C0C170027D42B /* SPNotLoaded.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};