diff options
author | stuconnolly <stuart02@gmail.com> | 2008-12-10 16:52:52 +0000 |
---|---|---|
committer | stuconnolly <stuart02@gmail.com> | 2008-12-10 16:52:52 +0000 |
commit | fab9a6506cd04ec8f840c98772a80c44a79c74a7 (patch) | |
tree | 3cd483487bef381c934717f10df71d306c7eaf97 /TableContent.m | |
parent | 4c3b208fad0572d8d1a79bba1bd1b8147fd0f8a6 (diff) | |
download | sequelpro-fab9a6506cd04ec8f840c98772a80c44a79c74a7.tar.gz sequelpro-fab9a6506cd04ec8f840c98772a80c44a79c74a7.tar.bz2 sequelpro-fab9a6506cd04ec8f840c98772a80c44a79c74a7.zip |
MERGED r262:266 from branches/stuart02 to trunk to include new project structure.
Diffstat (limited to 'TableContent.m')
-rw-r--r-- | TableContent.m | 2018 |
1 files changed, 0 insertions, 2018 deletions
diff --git a/TableContent.m b/TableContent.m deleted file mode 100644 index 1aa939f2..00000000 --- a/TableContent.m +++ /dev/null @@ -1,2018 +0,0 @@ -// -// TableDocument.h -// sequel-pro -// -// Created by lorenz textor (lorenz@textor.ch) on Wed May 01 2002. -// Copyright (c) 2002-2003 Lorenz Textor. All rights reserved. -// -// Forked by Abhi Beckert (abhibeckert.com) 2008-04-04 -// -// 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 "TableContent.h" -#import "TableDocument.h" -#import "TablesList.h" -#import "TableSource.h" -#import "CMImageView.h" - - -@implementation TableContent - -- (id)init -{ - if (![super init]) - return nil; - - fullResult = [[NSMutableArray alloc] init]; - filteredResult = [[NSMutableArray alloc] init]; - oldRow = [[NSMutableDictionary alloc] init]; - selectedTable = nil; - sortField = nil; - areShowingAllRows = false; - - return self; -} - -- (void)awakeFromNib -{ -} - -/* - Loads aTable, retrieving column information and updating the tableViewColumns before - reloading table data into the fullResults array and redrawing the table. - */ -- (void)loadTable:(NSString *)aTable -{ - int i; - NSNumber *colWidth; - NSArray *theColumns; - NSTableColumn *theCol; - NSString *query; - CMMCPResult *queryResult; - BOOL preserveCurrentView = [aTable isEqualToString:selectedTable]; - NSString *preservedFilterField = nil, *preservedFilterComparison, *preservedFilterValue; - - // Clear the selection, and abort the reload if the user is still editing a row - [tableContentView deselectAll:self]; - if ( isEditingRow ) - return; - - // Store the newly selected table name - selectedTable = aTable; - - // Reset table key store for use in argumentForRow: - if ( keys ) - keys = nil; - - // Restore the table content view to the top left - [tableContentView scrollRowToVisible:0]; - [tableContentView scrollColumnToVisible:0]; - - // If no table has been supplied, reset the view to a blank table and disabled elements - if ( [aTable isEqualToString:@""] || !aTable ) - { - - // Empty the table and stored data arrays - theColumns = [tableContentView tableColumns]; - while ([theColumns count]) { - [tableContentView removeTableColumn:[theColumns objectAtIndex:0]]; - } - [fullResult removeAllObjects]; - [filteredResult removeAllObjects]; - [tableContentView reloadData]; - areShowingAllRows = YES; - [countText setStringValue:@""]; - - // Empty and disable filter options - [fieldField setEnabled:NO]; - [fieldField removeAllItems]; - [fieldField addItemWithTitle:NSLocalizedString(@"field", @"popup menuitem for field (showing only if disabled)")]; - [compareField setEnabled:NO]; - [compareField removeAllItems]; - [compareField addItemWithTitle:NSLocalizedString(@"is", @"popup menuitem for field IS value")]; - [argumentField setEnabled:NO]; - [argumentField setStringValue:@""]; - [filterButton setEnabled:NO]; - - // Empty and disable the limit field - [limitRowsField setStringValue:@""]; - [limitRowsText setStringValue:NSLocalizedString(@"No limit", @"text showing that the result isn't limited")]; - [limitRowsField setEnabled:NO]; - [limitRowsButton setEnabled:NO]; - [limitRowsStepper setEnabled:NO]; - - // Disable table action buttons - [addButton setEnabled:NO]; - [copyButton setEnabled:NO]; - [removeButton setEnabled:NO]; - - return; - } - - // Post a notification that a query will be performed - [[NSNotificationCenter defaultCenter] postNotificationName:@"SMySQLQueryWillBePerformed" object:self]; - - - // Make a fast query to get fieldNames and fieldTypes for this table. This is used to decide whether to preserve the - // current filter/sort settings, and also used when grabbing all the data as part of the fieldListForQuery method. - queryResult = [mySQLConnection queryString:[NSString stringWithFormat:@"SELECT * FROM `%@` LIMIT 0", selectedTable]]; - if ( queryResult == nil ) { - NSLog(@"Loading table columns for %@ failed", aTable); - return; - } - fieldNames = [[queryResult fetchFieldNames] retain]; - fieldTypes = [[queryResult fetchTypesAsArray] retain]; - - // Retrieve the number of rows in the table and initially mark all as being visible. - numRows = [self getNumberOfRows]; - areShowingAllRows = YES; - - // Remove existing columns from the table - theColumns = [tableContentView tableColumns]; - while ([theColumns count]) { - [tableContentView removeTableColumn:[theColumns objectAtIndex:0]]; - } - - // Add the new columns to the table - for ( i = 0 ; i < [fieldNames count] ; i++ ) { - - // Set up the column - theCol = [[NSTableColumn alloc] initWithIdentifier:[fieldNames objectAtIndex:i]]; - [theCol setEditable:YES]; - if ( [theCol respondsToSelector:@selector(setResizingMask:)] ) { - // Mac OS X 10.4+ - [theCol setResizingMask:NSTableColumnUserResizingMask]; - } else { - // Mac OS X pre-10.4 - [theCol setResizable:YES]; - } - [[theCol headerCell] setStringValue:[fieldNames objectAtIndex:i]]; - - // Set up the data cell depending on the column type - NSComboBoxCell *dataCell; - if ( [[tableSourceInstance enumFields] objectForKey:[fieldNames objectAtIndex:i]] ) - { - dataCell = [[[NSComboBoxCell alloc] initTextCell:@""] autorelease]; - [dataCell setButtonBordered:NO]; - [dataCell setBezeled:NO]; - [dataCell setDrawsBackground:NO]; - [dataCell setCompletes:YES]; - [dataCell setControlSize:NSSmallControlSize]; - [dataCell addItemWithObjectValue:@"NULL"]; - [dataCell addItemsWithObjectValues:[[tableSourceInstance enumFields] objectForKey:[fieldNames objectAtIndex:i]]]; - } - else - { - dataCell = [[[NSTextFieldCell alloc] initTextCell:@""] autorelease]; - } - [dataCell setEditable:YES]; - - if ( [dataCell respondsToSelector:@selector(setLineBreakMode:)] ) { - // Mac OS X 10.4+ - [dataCell setLineBreakMode:NSLineBreakByTruncatingTail]; - } - - // Set the data cell font according to the preferences - if ( [prefs boolForKey:@"useMonospacedFonts"] ) - { - [dataCell setFont:[NSFont fontWithName:@"Monaco" size:10]]; - } - else - { - [dataCell setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]]; - } - - // Assign the data cell - [theCol setDataCell:dataCell]; - - // Set the width of this column to saved value if exists - colWidth = [[[[prefs objectForKey:@"tableColumnWidths"] objectForKey:[NSString stringWithFormat:@"%@@%@", [tableDocumentInstance database], [tableDocumentInstance host]]] objectForKey:[tablesListInstance table]] objectForKey:[fieldNames objectAtIndex:i]]; - if ( colWidth ) - { - [theCol setWidth:[colWidth floatValue]]; - } - - // Add the column to the table - [tableContentView addTableColumn:theCol]; - [theCol release]; - } - - // If the table has been reloaded and the previously selected sort column is still present, reselect it. - if (preserveCurrentView && [fieldNames containsObject:sortField]) - { - theCol = [tableContentView tableColumnWithIdentifier:sortField]; - [tableContentView setHighlightedTableColumn:theCol]; - if ( isDesc ) { - [tableContentView setIndicatorImage:[NSImage imageNamed:@"NSDescendingSortIndicator"] inTableColumn:theCol]; - } else { - [tableContentView setIndicatorImage:[NSImage imageNamed:@"NSAscendingSortIndicator"] inTableColumn:theCol]; - } - } - - // Otherwise, clear sorting - else - { - sortField = nil; - isDesc = NO; - } - - // Preserve the stored filter settings if appropriate - if (preserveCurrentView && [fieldField isEnabled]) - { - preservedFilterField = [NSString stringWithString:[[fieldField selectedItem] title]]; - preservedFilterComparison = [NSString stringWithString:[[compareField selectedItem] title]]; - preservedFilterValue = [NSString stringWithString:[argumentField stringValue]]; - } - - // Enable and initialize filter fields (with tags for position of menu item and field position) - [fieldField setEnabled:YES]; - [fieldField removeAllItems]; - [fieldField addItemsWithTitles:fieldNames]; - for ( i = 0 ; i < [fieldField numberOfItems] ; i++ ) { - [[fieldField itemAtIndex:i] setTag:i]; - } - [compareField setEnabled:YES]; - [self setCompareTypes:self]; - [argumentField setEnabled:YES]; - [argumentField setStringValue:@""]; - [filterButton setEnabled:YES]; - - // Restore preserved filter settings if appropriate and valid - if (preserveCurrentView && preservedFilterField != nil && [fieldField itemWithTitle:preservedFilterField]) - { - [fieldField selectItemWithTitle:preservedFilterField]; - [self setCompareTypes:self]; - } - if (preserveCurrentView && preservedFilterField != nil - && [fieldField itemWithTitle:preservedFilterField] - && [compareField itemWithTitle:preservedFilterComparison]) - { - [compareField selectItemWithTitle:preservedFilterComparison]; - [argumentField setStringValue:preservedFilterValue]; - areShowingAllRows = NO; - } - - // Enable or disable the limit fields according to preference setting - if ( [prefs boolForKey:@"limitRows"] ) - { - - // Attempt to preserve the limit value if it's still valid - if (!preserveCurrentView || [limitRowsField intValue] < 1 || [limitRowsField intValue] >= numRows) { - [limitRowsField setStringValue:@"1"]; - } - [limitRowsField setEnabled:YES]; - [limitRowsButton setEnabled:YES]; - [limitRowsStepper setEnabled:YES]; - [limitRowsText setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Limited to %d rows starting with row", @"text showing the number of rows the result is limited to"), - [prefs integerForKey:@"limitRowsValue"]]]; - if ([prefs integerForKey:@"limitRowsValue"] < numRows) - areShowingAllRows = NO; - } - else - { - [limitRowsField setEnabled:NO]; - [limitRowsButton setEnabled:NO]; - [limitRowsStepper setEnabled:NO]; - [limitRowsField setStringValue:@""]; - [limitRowsText setStringValue:NSLocalizedString(@"No limit", @"text showing that the result isn't limited")]; - } - - // Enable the table buttons - [addButton setEnabled:YES]; - [copyButton setEnabled:YES]; - [removeButton setEnabled:YES]; - - - // Perform the data query and store the result as an array containing a dictionary per result row - query = [NSString stringWithFormat:@"SELECT %@ FROM `%@`", [self fieldListForQuery], selectedTable]; - if ( sortField ) - { - query = [NSString stringWithFormat:@"%@ ORDER BY `%@`", query, sortField]; - if ( isDesc ) - query = [query stringByAppendingString:@" DESC"]; - } - if ( [prefs boolForKey:@"limitRows"] ) - { - if ( [limitRowsField intValue] <= 0 ) - { - [limitRowsField setStringValue:@"1"]; - } - query = [query stringByAppendingString: - [NSString stringWithFormat:@" LIMIT %d,%d", - [limitRowsField intValue]-1, [prefs integerForKey:@"limitRowsValue"]]]; - } - queryResult = [mySQLConnection queryString:query]; - if ( queryResult == nil ) { - NSLog(@"Loading table data for %@ failed, query string was: %@", aTable, query); - return; - } - [fullResult setArray:[self fetchResultAsArray:queryResult]]; - - // Apply any filtering and update the row count - if ( !areShowingAllRows ) { - [self filterTable:self]; - [countText setStringValue:[NSString stringWithFormat:NSLocalizedString(@"%d rows of %d selected", @"text showing how many rows are in the filtered result"), [filteredResult count], numRows]]; - } else { - [filteredResult setArray:fullResult]; - [countText setStringValue:[NSString stringWithFormat:NSLocalizedString(@"%d rows in table", @"text showing how many rows are in the result"), numRows]]; - } - - // Reload the table data. - [tableContentView reloadData]; - - // Post the notification that the query is finished - [[NSNotificationCenter defaultCenter] postNotificationName:@"SMySQLQueryHasBeenPerformed" object:self]; -} - -/* - Reloads the current table data, performing a new SQL query. Now attempts to preserve sort order, filters, and viewport. - */ -- (IBAction)reloadTable:(id)sender -{ - // Store the current viewport location - NSRect viewRect = [tableContentView visibleRect]; - - [self loadTable:selectedTable]; - - // Restore the viewport - [tableContentView scrollRectToVisible:viewRect]; -} - -- (IBAction)reloadTableValues:(id)sender -/* - reload the table values without reconfiguring the tableView (with filter and limit if set) - */ -{ - NSString *queryString; - CMMCPResult *queryResult; - - //query started - [[NSNotificationCenter defaultCenter] postNotificationName:@"SMySQLQueryWillBePerformed" object:self]; - - //enable or disable limit fields - if ( [prefs boolForKey:@"limitRows"] ) { - [limitRowsField setEnabled:YES]; - [limitRowsButton setEnabled:YES]; - [limitRowsStepper setEnabled:YES]; - [limitRowsText setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Limited to %d rows starting with row", @"text showing the number of rows the result is limited to"), - [prefs integerForKey:@"limitRowsValue"]]]; - } else { - [limitRowsField setEnabled:NO]; - [limitRowsButton setEnabled:NO]; - [limitRowsStepper setEnabled:NO]; - [limitRowsText setStringValue:NSLocalizedString(@"No limit", @"text showing that the result isn't limited")]; - [limitRowsField setStringValue:@""]; - } - - // queryString = [@"SELECT * FROM " stringByAppendingString:selectedTable]; - queryString = [NSString stringWithFormat:@"SELECT %@ FROM `%@`", [self fieldListForQuery], selectedTable]; - if ( sortField ) { - queryString = [NSString stringWithFormat:@"%@ ORDER BY `%@`", queryString, sortField]; - // queryString = [queryString stringByAppendingString:[NSString stringWithFormat:@" ORDER BY `%@`", sortField]]; - if ( isDesc ) - queryString = [queryString stringByAppendingString:@" DESC"]; - } - if ( [prefs boolForKey:@"limitRows"] ) { - if ( [limitRowsField intValue] <= 0 ) { - [limitRowsField setStringValue:@"1"]; - } - queryString = [queryString stringByAppendingString: - [NSString stringWithFormat:@" LIMIT %d,%d", - [limitRowsField intValue]-1, [prefs integerForKey:@"limitRowsValue"]]]; - [limitRowsField selectText:self]; - } - queryResult = [mySQLConnection queryString:queryString]; - // [fullResult setArray:[[self fetchResultAsArray:queryResult] retain]]; - [fullResult setArray:[self fetchResultAsArray:queryResult]]; - numRows = [self getNumberOfRows]; - if ( !areShowingAllRows ) { - [self filterTable:self]; - [countText setStringValue:[NSString stringWithFormat:NSLocalizedString(@"%d rows of %d selected", @"text showing how many rows are in the filtered result"), [filteredResult count], numRows]]; - } else { - [filteredResult setArray:fullResult]; - [countText setStringValue:[NSString stringWithFormat:NSLocalizedString(@"%d rows in table", @"text showing how many rows are in the result"), numRows]]; - } - [tableContentView reloadData]; - - //query finished - [[NSNotificationCenter defaultCenter] postNotificationName:@"SMySQLQueryHasBeenPerformed" object:self]; -} - -/** - * filter the table with arguments given by the user - */ -- (IBAction)filterTable:(id)sender -{ - CMMCPResult *theResult; - int tag = [[compareField selectedItem] tag]; - NSString *compareOperator = @""; - NSMutableString *argument = [[NSMutableString alloc] initWithString:[argumentField stringValue]]; - NSString *queryString; - int i; - - // Update negative limits - if ( [limitRowsField intValue] <= 0 ) { - [limitRowsField setStringValue:@"1"]; - } - - // If the filter field is empty, the limit field is at 1, and the selected filter is not looking - // for NULLs or NOT NULLs, then don't allow filtering. - if (([argument length] == 0) && (![[[compareField selectedItem] title] hasSuffix:@"NULL"]) && (![prefs boolForKey:@"limitRows"] || [limitRowsField intValue] == 1)) { - [argument release]; - [self showAll:sender]; - return; - } - - //query started - [[NSNotificationCenter defaultCenter] postNotificationName:@"SMySQLQueryWillBePerformed" object:self]; - - BOOL doQuote = YES; - BOOL ignoreArgument = NO; - - // Start building the query string - queryString = [NSString stringWithFormat:@"SELECT %@ FROM `%@`", - [self fieldListForQuery], selectedTable]; - - // Add filter if appropriate - if (([argument length] > 0) || [[[compareField selectedItem] title] hasSuffix:@"NULL"]) { - if ( ![compareType isEqualToString:@""] ) { - if ( [compareType isEqualToString:@"string"] ) { - //string comparision - switch ( tag ) { - case 0: - compareOperator = @"LIKE"; - break; - case 1: - compareOperator = @"NOT LIKE"; - break; - case 2: - compareOperator = @"LIKE"; - [argument setString:[[@"%" stringByAppendingString:argument] stringByAppendingString:@"%"]]; - break; - case 3: - compareOperator = @"NOT LIKE"; - [argument setString:[[@"%" stringByAppendingString:argument] stringByAppendingString:@"%"]]; - break; - case 4: - compareOperator = @"IN"; - doQuote = NO; - [argument setString:[[@"(" stringByAppendingString:argument] stringByAppendingString:@")"]]; - break; - case 5: - compareOperator = @"IS NULL"; - doQuote = NO; - ignoreArgument = YES; - break; - case 6: - compareOperator = @"IS NOT NULL"; - doQuote = NO; - ignoreArgument = YES; - break; - } - } else if ( [compareType isEqualToString:@"number"] ) { - //number comparision - switch ( tag ) { - case 0: - compareOperator = @"="; - break; - case 1: - compareOperator = @"!="; - break; - case 2: - compareOperator = @">"; - break; - case 3: - compareOperator = @"<"; - break; - case 4: - compareOperator = @">="; - break; - case 5: - compareOperator = @"<="; - break; - case 6: - compareOperator = @"IN"; - doQuote = NO; - [argument setString:[[@"(" stringByAppendingString:argument] stringByAppendingString:@")"]]; - break; - case 7: - compareOperator = @"IS NULL"; - doQuote = NO; - ignoreArgument = YES; - break; - case 8: - compareOperator = @"IS NOT NULL"; - doQuote = NO; - ignoreArgument = YES; - break; - } - } else if ( [compareType isEqualToString:@"date"] ) { - //date comparision - switch ( tag ) { - case 0: - compareOperator = @"="; - break; - case 1: - compareOperator = @"!="; - break; - case 2: - compareOperator = @"<"; - break; - case 3: - compareOperator = @">"; - break; - case 4: - compareOperator = @"<="; - break; - case 5: - compareOperator = @">="; - break; - case 6: - compareOperator = @"IS NULL"; - doQuote = NO; - ignoreArgument = YES; - break; - case 7: - compareOperator = @"IS NOT NULL"; - doQuote = NO; - ignoreArgument = YES; - break; - } - } else { - doQuote = NO; - ignoreArgument = YES; - NSLog(@"ERROR: unknown compare type %@", compareType); - } - - if (doQuote) { - //escape special characters - for ( i = 0 ; i < [argument length] ; i++ ) { - if ( [argument characterAtIndex:i] == '\\' ) { - [argument insertString:@"\\" atIndex:i]; - i++; - } - } - [argument setString:[mySQLConnection prepareString:argument]]; - queryString = [NSString stringWithFormat:@"%@ WHERE `%@` %@ \"%@\"", - queryString, [fieldField titleOfSelectedItem], compareOperator, argument]; - } else { - queryString = [NSString stringWithFormat:@"%@ WHERE `%@` %@ %@", - queryString, [fieldField titleOfSelectedItem], - compareOperator, (ignoreArgument) ? @"" : argument]; - } - } - } - - // Add sorting details if appropriate - if ( sortField ) { - queryString = [NSString stringWithFormat:@"%@ ORDER BY `%@`", queryString, sortField]; - if ( isDesc ) - queryString = [queryString stringByAppendingString:@" DESC"]; - } - - // LIMIT if appropriate - if ( [prefs boolForKey:@"limitRows"] ) { - queryString = [NSString stringWithFormat:@"%@ LIMIT %d,%d", queryString, - [limitRowsField intValue]-1, [prefs integerForKey:@"limitRowsValue"]]; - } - - theResult = [mySQLConnection queryString:queryString]; - [filteredResult setArray:[self fetchResultAsArray:theResult]]; - - [countText setStringValue:[NSString stringWithFormat:NSLocalizedString(@"%d rows of %d selected", @"text showing how many rows are in the filtered result"), [filteredResult count], numRows]]; - - // Reset the table view - [tableContentView scrollPoint:NSMakePoint(0.0, 0.0)]; - [tableContentView reloadData]; - areShowingAllRows = NO; - - //query finished - [[NSNotificationCenter defaultCenter] postNotificationName:@"SMySQLQueryHasBeenPerformed" object:self]; - [argument release]; -} - -/** - * reload tableView with all results shown (no new mysql-query, it uses simply the fullResult array) - */ -- (IBAction)showAll:(id)sender -{ - [filteredResult setArray:fullResult]; - [tableContentView reloadData]; - areShowingAllRows = YES; - - [countText setStringValue:[NSString stringWithFormat:NSLocalizedString(@"%d rows in table", @"text showing how many rows are in the result"), numRows]]; -} - -/** - * Enables or disables the filter input field based on the selected filter type. - */ -- (IBAction)toggleFilterField:(id)sender -{ - // If the user is filtering for NULLs then disabled the filter field, otherwise enable it. - [argumentField setEnabled:(![[[compareField selectedItem] title] hasSuffix:@"NULL"])]; -} - - -//edit methods -- (IBAction)addRow:(id)sender -/* - adds an empty row to the table-array and goes into edit mode - */ -{ - NSMutableDictionary *newRow = [NSMutableDictionary dictionary]; - int i; - - if ( ![self selectionShouldChangeInTableView:nil] ) - return; - - for ( i = 0 ; i < [fieldNames count] ; i++ ) { - // [newRow setObject:[prefs stringForKey:@"nullValue"] forKey:[fieldNames objectAtIndex:i]]; - [newRow setObject:[tableSourceInstance defaultValueForField:[fieldNames objectAtIndex:i]] - forKey:[fieldNames objectAtIndex:i]]; - } - [filteredResult addObject:newRow]; - - isEditingRow = YES; - isEditingNewRow = YES; - [tableContentView reloadData]; - [tableContentView selectRow:[tableContentView numberOfRows]-1 byExtendingSelection:NO]; - if ( [multipleLineEditingButton state] == NSOffState ) - [tableContentView editColumn:0 row:[tableContentView numberOfRows]-1 withEvent:nil select:YES]; -} - -- (IBAction)copyRow:(id)sender -/* - copies a row of the table-array and goes into edit mode - */ -{ - NSMutableDictionary *tempRow; - CMMCPResult *queryResult; - NSDictionary *row; - int i; - - if ( ![self selectionShouldChangeInTableView:nil] ) - return; - if ( [tableContentView numberOfSelectedRows] < 1 ) - return; - if ( [tableContentView numberOfSelectedRows] > 1 ) { - NSBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, tableWindow, self, nil, nil, nil, NSLocalizedString(@"You can only copy single rows.", @"message of panel when trying to copy multiple rows")); - return; - } - - //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]; - for ( i = 0 ; i < [queryResult numOfRows] ; i++ ) { - row = [queryResult fetchRowAsDictionary]; - if ( [[row objectForKey:@"Extra"] isEqualToString:@"auto_increment"] ) { - [tempRow setObject:[prefs stringForKey:@"nullValue"] forKey:[row objectForKey:@"Field"]]; - } - } - //select row and go in edit mode - [tableContentView reloadData]; - [tableContentView selectRow:[tableContentView selectedRow]+1 byExtendingSelection:NO]; - if ( [multipleLineEditingButton state] == NSOffState ) - [tableContentView editColumn:0 row:[tableContentView selectedRow] withEvent:nil select:YES]; -} - -- (IBAction)removeRow:(id)sender -/* - asks user if he really wants to delete the selected rows - */ -{ - if ( ![self selectionShouldChangeInTableView:nil] ) - return; - if ( ![tableContentView numberOfSelectedRows] ) - return; - /* - if ( ([tableContentView numberOfSelectedRows] == [self numberOfRowsInTableView:tableContentView]) && - areShowingAllRows && - (![prefs boolForKey:@"limitRows"] || ([tableContentView numberOfSelectedRows] < [prefs integerForKey:@"limitRowsValue"])) ) { - */ - if ( ([tableContentView numberOfSelectedRows] == [tableContentView numberOfRows]) && - (([prefs boolForKey:@"limitRows"] && [tableContentView numberOfSelectedRows] == [self fetchNumberOfRows]) || - (![prefs boolForKey:@"limitRows"] && [tableContentView numberOfSelectedRows] == [self getNumberOfRows])) ) { - NSBeginAlertSheet(NSLocalizedString(@"Warning", @"warning"), NSLocalizedString(@"Delete", @"delete button"), NSLocalizedString(@"Cancel", @"cancel button"), nil, tableWindow, self, @selector(sheetDidEnd:returnCode:contextInfo:), - nil, @"removeallrows", NSLocalizedString(@"Do you really want to delete all rows?", @"message of panel asking for confirmation for deleting all rows")); - } else if ( [tableContentView numberOfSelectedRows] == 1 ) { - NSBeginAlertSheet(NSLocalizedString(@"Warning", @"warning"), NSLocalizedString(@"Delete", @"delete button"), NSLocalizedString(@"Cancel", @"cancel button"), nil, tableWindow, self, @selector(sheetDidEnd:returnCode:contextInfo:), - nil, @"removerow", NSLocalizedString(@"Do you really want to delete the selected row?", @"message of panel asking for confirmation for deleting the selected row")); - } else { - NSBeginAlertSheet(NSLocalizedString(@"Warning", @"warning"), NSLocalizedString(@"Delete", @"delete button"), NSLocalizedString(@"Cancel", @"cancel button"), nil, tableWindow, self, @selector(sheetDidEnd:returnCode:contextInfo:), - nil, @"removerow", - [NSString stringWithFormat:NSLocalizedString(@"Do you really want to delete the selected %d rows?", @"message of panel asking for confirmation for deleting the selected rows"), [tableContentView numberOfSelectedRows]]); - } -} - - -//editSheet methods -- (IBAction)closeEditSheet:(id)sender -{ - [NSApp stopModalWithCode:[sender tag]]; -} - -- (IBAction)openEditSheet:(id)sender -/* - loads a file into the editSheet - */ -{ - NSOpenPanel *panel = [NSOpenPanel openPanel]; - - if ( [panel runModal] == NSOKButton ) { - NSString *fileName = [panel filename]; - - // free old data - if ( editData != nil ) { - [editData release]; - } - - // load new data/images - editData = [[NSData alloc] initWithContentsOfFile:fileName]; - NSImage *image = [[[NSImage alloc] initByReferencingFile:fileName] autorelease]; - NSString *contents = [[NSString stringWithContentsOfFile:fileName] autorelease]; - - // set the image preview, string contents and hex representation - [editImage setImage:image]; - [editTextView setString:contents]; - [hexTextView setString:[self dataToHex:editData]]; - } -} - -- (IBAction)saveEditSheet:(id)sender -/* - saves a file containing the content of the editSheet - */ -{ - NSSavePanel *panel = [NSSavePanel savePanel]; - - if ( [panel runModal] == NSOKButton ) { - NSString *fileName = [panel filename]; - NSString *data; - - if ( [editData isKindOfClass:[NSData class]] ) { - data = editData; - } else { - data = [editData description]; - } - if ( [editData respondsToSelector:@selector(writeToFile:atomically:encoding:error:)] ) { - // mac os 10.4 or later - [editData writeToFile:fileName atomically:YES encoding:[CMMCPConnection encodingForMySQLEncoding:[(NSString *)[tableDocumentInstance encoding] UTF8String]] error:NULL]; - } else { - // mac os pre 10.4 - [editData writeToFile:fileName atomically:YES]; - } - } -} - -- (IBAction)dropImage:(id)sender -/* - invoked when user drag&drops image on imageView - */ -{ - // load new data/images - if (nil != editData) - { - [editData release]; - } - editData = [[[NSData alloc] initWithContentsOfFile:[sender draggedFilePath]] retain]; - NSString *contents = [NSString stringWithContentsOfFile:[sender draggedFilePath]]; - - // set the string contents and hex representation - [editTextView setString:contents]; - [hexTextView setString:[self dataToHex:editData]]; -} - -- (void)textDidChange:(NSNotification *)notification -/* - invoked when the user changes the string in the editSheet - */ -{ - // clear the image and hex (since i doubt someone can "type" a gif) - [editImage setImage:nil]; - [hexTextView setString:@""]; - - // free old data - if ( editData != nil ) { - [editData release]; - } - - // set edit data to text - editData = [[editTextView string] retain]; -} - -- (NSString *)dataToHex:(NSData *)data -/* - returns the hex representation of the given data - */ -{ - unsigned i; - unsigned totalLength = [data length]; - int bytesPerLine = 16; - NSMutableString *retVal = [NSMutableString string]; - unsigned char *nodisplay = "\t\n\r\f"; - - // get the length of the longest location - int longest = [(NSString *)[NSString stringWithFormat:@"%X", totalLength - ( totalLength % bytesPerLine )] length]; - - for ( i = 0; i < totalLength; i += bytesPerLine ) { - int j; - NSMutableString *hex = [[NSMutableString alloc] initWithCapacity:(3 * bytesPerLine - 1)]; - NSMutableString *location = [[NSMutableString alloc] initWithCapacity:(longest + 2)]; - NSMutableString *chars = [[NSMutableString alloc] init]; - unsigned char *buffer; - int buffLength = bytesPerLine; - - // add hex value of location - [location appendString:[NSString stringWithFormat:@"%X", i]]; - - // pad it - while( longest > [location length] ) { - [location insertString:@"0" atIndex:0]; - } - - // get the chars from the NSData obj - if ( i + buffLength >= totalLength ) { - buffLength = totalLength - i; - } - buffer = (unsigned char*) malloc( sizeof( unsigned char ) * buffLength ); - NSRange range = { i, buffLength }; - [data getBytes:buffer range:range]; - - // build the hex string - for ( j = 0; j < buffLength; j++ ) { - unsigned char byte = *(buffer + j); - if ( byte < 16 ) { - [hex appendString:@"0"]; - } - [hex appendString:[NSString stringWithFormat:@"%X", byte]]; - [hex appendString:@" "]; - - // if the char is undisplayable, replace it with "." - unsigned char current; - int count = 0; - while ( ( current = *(nodisplay + count++) ) > 0 ) { - if ( current == byte ) { - *(buffer + j) = '.'; - break; - } - } - } - - // add padding to missing hex values. - for ( j = 0; j < bytesPerLine - buffLength; j++ ) { - [hex appendString:@" "]; - } - - // remove extra ghost characters - [chars appendString:[NSString stringWithCString:buffer]]; - if ( [chars length] > bytesPerLine ) { - [chars deleteCharactersInRange:NSMakeRange( bytesPerLine, [chars length] - bytesPerLine )]; - } - - // build line - [retVal appendString:location]; - [retVal appendString:@" "]; - [retVal appendString:hex]; - [retVal appendString:@" "]; - [retVal appendString:chars]; - [retVal appendString:@"\n"]; - - // clean up - [hex release]; - [chars release]; - [location release]; - free( buffer ); - } - - return retVal; -} - -//getter methods -- (NSArray *)currentResult -/* - 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 *tableColumns; - NSEnumerator *enumerator; - id tableColumn; - NSMutableArray *currentResult = [NSMutableArray array]; - NSMutableArray *tempRow = [NSMutableArray array]; - int i; - - //load table if not already done - if ( ![tablesListInstance contentLoaded] ) { - [self loadTable:(NSString *)[tablesListInstance table]]; - } - - tableColumns = [tableContentView tableColumns]; - enumerator = [tableColumns objectEnumerator]; - - //set field names as first line - while ( (tableColumn = [enumerator nextObject]) ) { - [tempRow addObject:[[tableColumn headerCell] stringValue]]; - } - [currentResult addObject:[NSArray arrayWithArray:tempRow]]; - - //add rows - for ( i = 0 ; i < [self numberOfRowsInTableView:nil] ; i++) { - [tempRow removeAllObjects]; - enumerator = [tableColumns objectEnumerator]; - while ( (tableColumn = [enumerator nextObject]) ) { - [tempRow addObject:[self tableView:nil objectValueForTableColumn:tableColumn row:i]]; - } - [currentResult addObject:[NSArray arrayWithArray:tempRow]]; - } - return currentResult; -} - - -//additional methods -- (void)setConnection:(CMMCPConnection *)theConnection -/* - sets the connection (received from TableDocument) and makes things that have to be done only once - */ -{ - mySQLConnection = theConnection; - - [tableContentView setVerticalMotionCanBeginDrag:NO]; - - prefs = [[NSUserDefaults standardUserDefaults] retain]; - if ( [prefs boolForKey:@"useMonospacedFonts"] ) { - [argumentField setFont:[NSFont fontWithName:@"Monaco" size:10]]; - [limitRowsField setFont:[NSFont fontWithName:@"Monaco" size:[NSFont smallSystemFontSize]]]; - [editTextView setFont:[NSFont fontWithName:@"Monaco" size:[NSFont smallSystemFontSize]]]; - } else { - [editTextView setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]]; - [limitRowsField setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]]; - [argumentField setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]]; - } - [hexTextView setFont:[NSFont fontWithName:@"Monaco" size:[NSFont smallSystemFontSize]]]; - [limitRowsStepper setEnabled:NO]; - if ( [prefs boolForKey:@"limitRows"] ) { - [limitRowsText setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Limited to %d rows starting with row", @"text showing the number of rows the result is limited to"), - [prefs integerForKey:@"limitRowsValue"]]]; - } else { - [limitRowsText setStringValue:NSLocalizedString(@"No limit", @"text showing that the result isn't limited")]; - [limitRowsField setStringValue:@""]; - } -} - -/** - * Sets the compare types for the filter and the appropriate formatter for the textField - */ -- (IBAction)setCompareTypes:(id)sender -{ - NSArray *stringFields = [NSArray arrayWithObjects:@"varstring", @"string", @"tinyblob", @"blob", @"mediumblob", @"longblob", @"set", @"enum", nil]; - NSArray *stringTypes = [NSArray arrayWithObjects:NSLocalizedString(@"is", @"popup menuitem for field IS value"), NSLocalizedString(@"is not", @"popup menuitem for field IS NOT value"), NSLocalizedString(@"contains", @"popup menuitem for field CONTAINS value"), NSLocalizedString(@"contains not", @"popup menuitem for field CONTAINS NOT value"), @"IN", nil]; - NSArray *numberFields = [NSArray arrayWithObjects:@"tiny", @"short", @"long", @"int24", @"longlong", @"decimal", @"float", @"double", nil]; - NSArray *numberTypes = [NSArray arrayWithObjects:@"=", @"≠", @">", @"<", @"≥", @"≤", @"IN", nil]; - NSArray *dateFields = [NSArray arrayWithObjects:@"timestamp", @"date", @"time", @"datetime", @"year", nil]; - NSArray *dateTypes = [NSArray arrayWithObjects:NSLocalizedString(@"is", @"popup menuitem for field IS value"), NSLocalizedString(@"is not", @"popup menuitem for field IS NOT value"), NSLocalizedString(@"older than", @"popup menuitem for field OLDER THAN value"), NSLocalizedString(@"younger than", @"popup menuitem for field YOUNGER THAN value"), NSLocalizedString(@"older than or equal to", @"popup menuitem for field OLDER THAN OR EQUAL TO value"), NSLocalizedString(@"younger than or equal to", @"popup menuitem for field YOUNGER THAN OR EQUAL TO value"), nil]; - NSString *fieldType = [NSString stringWithString:[fieldTypes objectAtIndex:[[fieldField selectedItem] tag]]]; - - int i; - - [compareField removeAllItems]; - - // Why do we get "string" for enum fields? (error in framework?) - if ( [stringFields containsObject:fieldType] ) { - [compareField addItemsWithTitles:stringTypes]; - compareType = @"string"; - // [argumentField setFormatter:nil]; - } else if ( [numberFields containsObject:fieldType] ) { - [compareField addItemsWithTitles:numberTypes]; - compareType = @"number"; - // [argumentField setFormatter:numberFormatter]; - } else if ( [dateFields containsObject:fieldType] ) { - [compareField addItemsWithTitles:dateTypes]; - compareType = @"date"; - /* - if ([fieldType isEqualToString:@"timestamp"]) { - [argumentField setFormatter:[[NSDateFormatter alloc] - initWithDateFormat:@"%Y-%m-%d %H:%M:%S" allowNaturalLanguage:YES]]; - } - if ([fieldType isEqualToString:@"datetime"]) { - [argumentField setFormatter:[[NSDateFormatter alloc] initWithDateFormat:@"%Y-%m-%d %H:%M:%S" allowNaturalLanguage:YES]]; - } - if ([fieldType isEqualToString:@"date"]) { - [argumentField setFormatter:[[NSDateFormatter alloc] initWithDateFormat:@"%Y-%m-%d" allowNaturalLanguage:YES]]; - } - if ([fieldType isEqualToString:@"time"]) { - [argumentField setFormatter:[[NSDateFormatter alloc] initWithDateFormat:@"%H:%M:%S" allowNaturalLanguage:YES]]; - } - if ([fieldType isEqualToString:@"year"]) { - [argumentField setFormatter:[[NSDateFormatter alloc] initWithDateFormat:@"%Y" allowNaturalLanguage:YES]]; - } - */ - } else { - NSLog(@"ERROR: unknown type for comparision: %@", fieldType); - } - - // Add IS NULL and IS NOT NULL as they should always be available - [compareField addItemWithTitle:@"IS NULL"]; - [compareField addItemWithTitle:@"IS NOT NULL"]; - - for ( i = 0 ; i < [compareField numberOfItems] ; i++ ) { - [[compareField itemAtIndex:i] setTag:i]; - } - - // Update the argumentField enabled state - [self toggleFilterField:self]; - - // set focus on argumentField - [argumentField selectText:self]; -} - -- (IBAction)stepLimitRows:(id)sender -/* - steps the start row up or down (+/- limitRowsValue) - */ -{ - if ( [limitRowsStepper intValue] > 0 ) { - [limitRowsField setIntValue:[limitRowsField intValue]+[prefs integerForKey:@"limitRowsValue"]]; - } else { - if ( ([limitRowsField intValue]-[prefs integerForKey:@"limitRowsValue"]) < 1 ) { - [limitRowsField setIntValue:1]; - } else { - [limitRowsField setIntValue:[limitRowsField intValue]-[prefs integerForKey:@"limitRowsValue"]]; - } - } - [limitRowsStepper setIntValue:0]; -} - -- (NSArray *)fetchResultAsArray:(CMMCPResult *)theResult -/* - fetches the result as an array with a dictionary for each row in it - */ -{ - NSMutableArray *tempResult = [NSMutableArray array]; - NSDictionary *tempRow; - NSMutableDictionary *modifiedRow = [NSMutableDictionary dictionary]; - NSEnumerator *enumerator; - id key; - int i,j; - - if ([theResult numOfRows]) [theResult dataSeek:0]; - for ( i = 0 ; i < [theResult numOfRows] ; i++ ) { - tempRow = [theResult fetchRowAsDictionary]; - enumerator = [tempRow keyEnumerator]; - while ( key = [enumerator nextObject] ) { - if ( [[tempRow objectForKey:key] isMemberOfClass:[NSNull class]] ) { - [modifiedRow setObject:[prefs stringForKey:@"nullValue"] forKey:key]; - /* - //NSData objects now decoded in tableView:objectValueForTableColumn:row - //object in result remains a NSData object - } else if ( [[tempRow objectForKey:key] isKindOfClass:[NSData class]] ) { - [modifiedRow setObject:[[NSString alloc] initWithData:[tempRow objectForKey:key] encoding:[mySQLConnection encoding]] - forKey:key]; - */ - } else { - [modifiedRow setObject:[tempRow objectForKey:key] forKey:key]; - } - //add values for hidden blob and text fields - if ( [prefs boolForKey:@"dontShowBlob"] ) { - for ( j = 0 ; j < [fieldTypes count] ; j++ ) { - if ( [self isBlobOrText:[fieldTypes objectAtIndex:j]] ) { - [modifiedRow setObject:NSLocalizedString(@"- blob or text -", @"value shown for hidden blob and text fields") forKey:[fieldNames objectAtIndex:j]]; - } - } - } - } - [tempResult addObject:[NSMutableDictionary dictionaryWithDictionary:modifiedRow]]; - } - return tempResult; -} - -- (BOOL)addRowToDB -/* - tries to write row to mysql-db - returns YES if row written to db, otherwies NO - returns YES if no row is beeing edited and nothing has to be written to db - */ -{ - int rowIndex = [tableContentView selectedRow]; - NSMutableArray *fieldValues = [[NSMutableArray alloc] init]; - NSMutableString *queryString; - NSString *query; - CMMCPResult *queryResult; - id rowObject; - NSMutableString *rowValue = [NSMutableString string]; - NSString *currentTime = [[NSDate date] descriptionWithCalendarFormat:@"%H:%M:%S" timeZone:nil locale:nil]; - int i; - - if ( !isEditingRow || rowIndex == -1) { - [fieldValues release]; - return YES; - } - - //get field values - for ( i=0 ; i < [fieldNames count] ; i++) { - rowObject = [[filteredResult objectAtIndex:rowIndex] objectForKey:[fieldNames 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"]] || - ([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 - // problem: when a number isn't set, sequel-pro enters 0 - // -> second if argument isn't necessary! - [rowValue setString:@"NULL"]; - } else { - if ( [rowObject isKindOfClass:[NSCalendarDate class]] ) { - // [rowValue setString:[NSString stringWithFormat:@"\"%@\"", [mySQLConnection prepareString:[rowObject description]]]]; - [rowValue setString:[NSString stringWithFormat:@"'%@'", [mySQLConnection prepareString:[rowObject description]]]]; - } else if ( [rowObject isKindOfClass:[NSNumber class]] ) { - [rowValue setString:[rowObject stringValue]]; - } else if ( [rowObject isKindOfClass:[NSData class]] ) { - [rowValue setString:[NSString stringWithFormat:@"X'%@'", [mySQLConnection prepareBinaryData:rowObject]]]; - } else { - // [rowValue setString:[NSString stringWithFormat:@"\"%@\"", [mySQLConnection prepareString:[rowObject description]]]]; - if ( [[rowObject description] isEqualToString:@"CURRENT_TIMESTAMP"] ) { - [rowValue setString:@"CURRENT_TIMESTAMP"]; - } else { - [rowValue setString:[NSString stringWithFormat:@"'%@'", [mySQLConnection prepareString:[rowObject description]]]]; - } - } - } - //escape special characters -> now escaped by framework - /* - for ( j = 0 ; j < [rowValue length] ; j++ ) { - if ( [rowValue characterAtIndex:j] == '\\' ) { - [rowValue insertString:@"\\" atIndex:j]; - j++; - } else if ( [rowValue characterAtIndex:j] == '"' ) { - [rowValue insertString:@"\\" atIndex:j]; - j++; - } - } - */ - [fieldValues addObject:[NSString stringWithString:rowValue]]; - } - - if ( isEditingNewRow ) { - //INSERT syntax - queryString = [NSString stringWithFormat:@"INSERT INTO `%@` (`%@`) VALUES (%@)", - selectedTable, [fieldNames componentsJoinedByString:@"`,`"], [fieldValues componentsJoinedByString:@","]]; - } else { - //UPDATE syntax - queryString = [NSMutableString stringWithFormat:@"UPDATE `%@` SET ", selectedTable]; - for ( i = 0 ; i < [fieldNames count] ; i++ ) { - if ( i > 0 ) { - [queryString appendString:@", "]; - } - [queryString appendString:[NSString stringWithFormat:@"`%@`=%@", - [fieldNames objectAtIndex:i], [fieldValues objectAtIndex:i]]]; - } - [fieldValues release]; - [queryString appendString:[NSString stringWithFormat:@" WHERE %@", [self argumentForRow:-2]]]; - } - [mySQLConnection queryString:queryString]; - - //NSLog( @"%@", queryString ); - - if ( ![mySQLConnection affectedRows] ) { - //no rows changed - if ( [prefs boolForKey:@"showError"] ) { - NSBeginAlertSheet(NSLocalizedString(@"Warning", @"warning"), NSLocalizedString(@"OK", @"OK button"), nil, nil, tableWindow, self, nil, 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(); - } - [filteredResult replaceObjectAtIndex:rowIndex withObject:[NSMutableDictionary dictionaryWithDictionary:oldRow]]; - isEditingRow = NO; - isEditingNewRow = NO; - [tableDocumentInstance 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; - } else if ( [[mySQLConnection getLastErrorMessage] isEqualToString:@""] ) { - //added new row with success - isEditingRow = NO; - if ( isEditingNewRow ) { - if ( [prefs boolForKey:@"reloadAfterAdding"] ) { - [self reloadTableValues:self]; - // if ( sortField ) - [tableContentView deselectAll:self]; - } else { - //set insertId for fields with auto_increment - queryResult = [mySQLConnection queryString:[NSString stringWithFormat:@"SHOW COLUMNS FROM `%@`", selectedTable]]; - if ([queryResult numOfRows]) [queryResult dataSeek:0]; - for ( i = 0 ; i < [queryResult numOfRows] ; i++ ) { - rowObject = [queryResult fetchRowAsDictionary]; - if ( [[rowObject objectForKey:@"Extra"] isEqualToString:@"auto_increment"] ) { - [[filteredResult objectAtIndex:rowIndex] setObject:[NSNumber numberWithLong:[mySQLConnection insertId]] - forKey:[rowObject objectForKey:@"Field"]]; - } - } - [fullResult addObject:[filteredResult objectAtIndex:rowIndex]]; - } - isEditingNewRow = NO; - } else { - //updated row with success - if ( [prefs boolForKey:@"reloadAfterEditing"] ) { - [self reloadTableValues:self]; - // if ( sortField ) - [tableContentView deselectAll:self]; - } else { - // query = [@"SELECT * FROM " stringByAppendingString:selectedTable]; - query = [NSString stringWithFormat:@"SELECT %@ FROM `%@`", [self fieldListForQuery], selectedTable]; - if ( sortField ) { - // query = [query stringByAppendingString:[NSString stringWithFormat:@" ORDER BY `%@`", sortField]]; - query = [NSString stringWithFormat:@"%@ ORDER BY `%@`", query, sortField]; - if ( isDesc ) - query = [query stringByAppendingString:@" DESC"]; - } - if ( [prefs boolForKey:@"limitRows"] ) { - if ( [limitRowsField intValue] <= 0 ) { - [limitRowsField setStringValue:@"1"]; - } - query = [query stringByAppendingString: - [NSString stringWithFormat:@" LIMIT %d,%d", - [limitRowsField intValue]-1, [prefs integerForKey:@"limitRowsValue"]]]; - } - queryResult = [mySQLConnection queryString:query]; - // [fullResult setArray:[[self fetchResultAsArray:queryResult] retain]]; - [fullResult setArray:[self fetchResultAsArray:queryResult]]; - } - } - return YES; - } else { - //error in mysql-query - NSBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), NSLocalizedString(@"Cancel", @"cancel button"), nil, tableWindow, self, @selector(sheetDidEnd:returnCode:contextInfo:), nil, @"addrow", - [NSString stringWithFormat:NSLocalizedString(@"Couldn't write row.\nMySQL said: %@", @"message of panel when error while adding row to db"), [mySQLConnection getLastErrorMessage]]); - return NO; - } -} - -- (NSString *)argumentForRow:(int)row -/* - returns the WHERE argument to identify a row - if row is -2, it uses the oldRow - if there is one, it uses the primary key, otherwise uses all fields as argument and sets LIMIT to 1 - */ -{ - CMMCPResult *theResult; - NSDictionary *theRow; - id tempValue; - NSMutableString *value = [NSMutableString string]; - NSMutableString *argument = [NSMutableString string]; - int i,j; - NSEnumerator *enumerator; - id type; - BOOL blob = NO; - NSArray *numberFields = [NSArray arrayWithObjects:@"tiny", @"short", @"long", @"int24", @"longlong", @"decimal", @"float", @"double", nil]; - - if ( row == -1 ) - return @""; - - //get primary key if there is one - /* - theResult = [mySQLConnection queryString:[NSString stringWithFormat:@"SHOW INDEX FROM `%@`", selectedTable]]; - if ([theResult numOfRows]) [theResult dataSeek:0]; - for ( i = 0 ; i < [theResult numOfRows] ; i++ ) { - theRow = [theResult fetchRowAsDictionary]; - if ( [[theRow objectForKey:@"Key_name"] isEqualToString:@"PRIMARY"] ) { - [keys addObject:[theRow objectForKey:@"Column_name"]]; - } - } - */ - if ( !keys ) { - setLimit = NO; - keys = [[NSMutableArray alloc] init]; - theResult = [mySQLConnection queryString:[NSString stringWithFormat:@"SHOW COLUMNS FROM `%@`", selectedTable]]; - if ([theResult numOfRows]) [theResult dataSeek:0]; - for ( i = 0 ; i < [theResult numOfRows] ; i++ ) { - theRow = [theResult fetchRowAsDictionary]; - if ( [[theRow objectForKey:@"Key"] isEqualToString:@"PRI"] ) { - [keys addObject:[theRow objectForKey:@"Field"]]; - } - } - } - - if ( ![keys count] ) { - //if there is no primary key, take all fields as argument - //here we have a problem when dontShowBlob == YES (we don't have the right values to use in the WHERE statement) - [keys setArray:fieldNames]; - setLimit = YES; - enumerator = [fieldTypes objectEnumerator]; - while ( (type = [enumerator nextObject]) ) { - if ( [self isBlobOrText:type] ) { - blob = YES; - } - } - if ( [prefs boolForKey:@"dontShowBlob"] && blob ) { - NSBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, tableWindow, self, nil, nil, nil, - NSLocalizedString(@"You can't hide blob and text fields when working with tables without index.", @"message of panel when trying to edit tables without index and with hidden blob/text fields")); - [keys removeAllObjects]; - [tableContentView deselectAll:self]; - return @""; - } - } - for ( i = 0 ; i < [keys count] ; i++ ) { - if ( i ) - [argument appendString:@" AND "]; - if ( row >= 0 ) { - //use selected row - tempValue = [[filteredResult objectAtIndex:row] objectForKey:[keys objectAtIndex:i]]; - } else { - //use oldRow - tempValue = [oldRow objectForKey:[keys objectAtIndex:i]]; - } - if ( [tempValue isKindOfClass:[NSData class]] ) { - [value setString:[[NSString alloc] initWithData:tempValue encoding:[mySQLConnection encoding]]]; - } else { - [value setString:[tempValue description]]; - } - - if ( [value isEqualToString:[prefs stringForKey:@"nullValue"]] ) { - [value setString:@"NULL"]; - } else { - //escape special characters (in WHERE statement!) - for ( j = 0 ; j < [value length] ; j++ ) { - if ( [value characterAtIndex:j] == '\\' ) { - [value insertString:@"\\" atIndex:j]; - j++; - } - } - [value setString:[mySQLConnection prepareString:value]]; - for ( j = 0 ; j < [value length] ; j++ ) { - if ( [value characterAtIndex:j] == '%' || - [value characterAtIndex:j] == '_' ) { - [value insertString:@"\\" atIndex:j]; - j++; - } - } - // [value setString:[NSString stringWithFormat:@"\"%@\"", value]]; - [value setString:[NSString stringWithFormat:@"'%@'", value]]; - } - if ( [value isEqualToString:@"NULL"] ) { - [argument appendString:[NSString stringWithFormat:@"`%@` IS NULL", [keys objectAtIndex:i]]]; - } else { - if ( [numberFields containsObject:[fieldTypes objectAtIndex:[fieldNames indexOfObject:[keys objectAtIndex:i]]]] ) { - [argument appendString:[NSString stringWithFormat:@"`%@` = %@", [keys objectAtIndex:i], value]]; - } else { - [argument appendString:[NSString stringWithFormat:@"`%@` LIKE %@", [keys objectAtIndex:i], value]]; - } - } - } - if ( setLimit ) - [argument appendString:@" LIMIT 1"]; - return argument; -} - -- (BOOL)isBlobOrText:(NSString *)fieldType -/* - returns YES if fieldType is some kind of blob or text. afaik the type of this fields is always blob, but better we test it... - it would be nice to know if it is blob or text, but mysql doesn't want to tell it... - */ -{ - if ( [fieldType isEqualToString:@"tinyblob"] || [fieldType isEqualToString:@"blob"] || - [fieldType isEqualToString:@"mediumblob"] || [fieldType isEqualToString:@"longblob"] ) { - return YES; - } else { - return NO; - } -} - -- (NSString *)fieldListForQuery -/* - returns * if dontShowBlob == NO - returns a comma-separated list of all fields which aren't of type blob or text if dontShowBlob == YES - */ -{ - int i; - NSMutableArray *fields = [NSMutableArray array]; - - if ( [prefs boolForKey:@"dontShowBlob"] ) { - for ( i = 0 ; i < [fieldTypes count] ; i++ ) { - if ( ![self isBlobOrText:[fieldTypes objectAtIndex:i]] ) { - [fields addObject:[fieldNames objectAtIndex:i]]; - } - } - if ( [fields count] == 0 ) { - return [NSString stringWithFormat:@"`%@`", [fieldNames objectAtIndex:0]]; - } else { - return [NSString stringWithFormat:@"`%@`", [fields componentsJoinedByString:@"`,`"]]; - } - } else { - return @"*"; - } -} - -- (void)sheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(NSString *)contextInfo -/* - if contextInfo == addrow: remain in edit-mode if user hits OK, otherwise cancel editing - if contextInfo == removerow: removes row if user hits OK - */ -{ - NSEnumerator *enumerator = [tableContentView selectedRowEnumerator]; - NSNumber *index; - NSMutableArray *tempArray = [NSMutableArray array]; - NSMutableArray *tempResult = [NSMutableArray array]; - NSString *queryString; - CMMCPResult *queryResult; - int i, errors; - - [sheet orderOut:self]; - - if ( [contextInfo isEqualToString:@"addrow"] ) { - if ( returnCode == NSAlertDefaultReturn ) { - //problem: reenter edit mode doesn't function - [tableContentView editColumn:0 row:[tableContentView selectedRow] withEvent:nil select:YES]; - } else { - if ( !isEditingNewRow ) { - [filteredResult replaceObjectAtIndex:[tableContentView selectedRow] - withObject:[NSMutableDictionary dictionaryWithDictionary:oldRow]]; - isEditingRow = NO; - } else { - [filteredResult removeObjectAtIndex:[tableContentView selectedRow]]; - isEditingRow = NO; - isEditingNewRow = NO; - } - } - [tableContentView reloadData]; - } else if ( [contextInfo isEqualToString:@"removeallrows"] ) { - if ( returnCode == NSAlertDefaultReturn ) { - /* - if ( ([tableContentView numberOfSelectedRows] == [self numberOfRowsInTableView:tableContentView]) && - areShowingAllRows && - ([tableContentView numberOfSelectedRows] < [prefs integerForKey:@"limitRowsValue"]) ) { - */ - [mySQLConnection queryString:[NSString stringWithFormat:@"DELETE FROM `%@`", selectedTable]]; - if ( [[mySQLConnection getLastErrorMessage] isEqualToString:@""] ) { - [self reloadTable:self]; - } else { - NSBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, tableWindow, self, nil, nil, nil, - [NSString stringWithFormat:NSLocalizedString(@"Couldn't remove rows.\nMySQL said: %@", @"message of panel when field cannot be removed"), - [mySQLConnection getLastErrorMessage]]); - } - } - } else if ( [contextInfo isEqualToString:@"removerow"] ) { - if ( returnCode == NSAlertDefaultReturn ) { - errors = 0; - - while ( (index = [enumerator nextObject]) ) { - [mySQLConnection queryString:[NSString stringWithFormat:@"DELETE FROM `%@` WHERE %@", - selectedTable, [self argumentForRow:[index intValue]]]]; - if ( ![mySQLConnection affectedRows] ) { - //no rows deleted - errors++; - } else if ( [[mySQLConnection getLastErrorMessage] isEqualToString:@""] ) { - //rows deleted with success - [tempArray addObject:index]; - } else { - //error in mysql-query - errors++; - } - } - - if ( errors ) { - NSBeginAlertSheet(NSLocalizedString(@"Warning", @"warning"), NSLocalizedString(@"OK", @"OK button"), nil, nil, tableWindow, self, nil, nil, nil, [NSString stringWithFormat:NSLocalizedString(@"%d rows have not been removed. 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"), errors]); - } - - //do deleting (after enumerating) - if ( [prefs boolForKey:@"reloadAfterRemoving"] ) { - [self reloadTableValues:self]; - } else { - for ( i = 0 ; i < [filteredResult count] ; i++ ) { - if ( ![tempArray containsObject:[NSNumber numberWithInt:i]] ) - [tempResult addObject:[filteredResult objectAtIndex:i]]; - } - [filteredResult setArray:tempResult]; - numRows = [self getNumberOfRows]; - if ( !areShowingAllRows ) { - // queryString = [@"SELECT * FROM " stringByAppendingString:selectedTable]; - queryString = [NSString stringWithFormat:@"SELECT %@ FROM `%@`", [self fieldListForQuery], selectedTable]; - if ( sortField ) { - // queryString = [queryString stringByAppendingString:[NSString stringWithFormat:@" ORDER BY `%@`", sortField]]; - queryString = [NSString stringWithFormat:@"%@ ORDER BY `%@`", queryString, sortField]; - if ( isDesc ) - queryString = [queryString stringByAppendingString:@" DESC"]; - } - if ( [prefs boolForKey:@"limitRows"] ) { - if ( [limitRowsField intValue] <= 0 ) { - [limitRowsField setStringValue:@"1"]; - } - queryString = [queryString stringByAppendingString: - [NSString stringWithFormat:@" LIMIT %d,%d", - [limitRowsField intValue]-1, [prefs integerForKey:@"limitRowsValue"]]]; - } - queryResult = [mySQLConnection queryString:queryString]; - // [fullResult setArray:[[self fetchResultAsArray:queryResult] retain]]; - [fullResult setArray:[self fetchResultAsArray:queryResult]]; - [tableContentView reloadData]; - [countText setStringValue:[NSString stringWithFormat:NSLocalizedString(@"%d rows of %d selected", @"text showing how many rows are in the filtered result"), - [filteredResult count], numRows]]; - } else { - [fullResult setArray:filteredResult]; - [tableContentView reloadData]; - [countText setStringValue:[NSString stringWithFormat:NSLocalizedString(@"%d rows in table", @"text showing how many rows are in the result"), numRows]]; - } - } - [tableContentView deselectAll:self]; - } - } -} - -- (int)getNumberOfRows -/* - returns the number of rows in the selected table - queries the number from mysql if enabled in prefs and result is limited, otherwise just return the fullResult count - */ -{ - if ( [prefs boolForKey:@"limitRows"] && [prefs boolForKey:@"fetchRowCount"] ) { - numRows = [self fetchNumberOfRows]; - } else { - numRows = [fullResult count]; - } - return numRows; -} - -- (int)fetchNumberOfRows -/* - fetches the number of rows in the selected table using a "SELECT COUNT(*)" query and return it - */ -{ - return [[[[mySQLConnection queryString:[NSString stringWithFormat:@"SELECT COUNT(*) FROM `%@`", selectedTable]] fetchRowAsArray] objectAtIndex:0] intValue]; -} - - -//tableView datasource methods -- (int)numberOfRowsInTableView:(NSTableView *)aTableView -{ - return [filteredResult count]; -} - -- (id)tableView:(NSTableView *)aTableView -objectValueForTableColumn:(NSTableColumn *)aTableColumn - row:(int)rowIndex -{ - id theRow, theValue; - - theRow = [filteredResult objectAtIndex:rowIndex]; - theValue = [theRow objectForKey:[aTableColumn identifier]]; - - if ( [theValue isKindOfClass:[NSData class]] ) { - theValue = [[NSString alloc] initWithData:theValue encoding:[mySQLConnection encoding]]; - //show only first 50 characters to speed up interface (but return everything when this method is used to return the current result) - // if ( ([theValue length] > 100) && aTableView ) { - } - -// if ( ([(NSString *)theValue length] > 100) && aTableView ) { -// theValue = [NSString stringWithFormat:@"%@(...)", [theValue substringToIndex:100]]; -// } - - return theValue; -} - -- (void)tableView:(NSTableView *)aTableView - setObjectValue:(id)anObject - forTableColumn:(NSTableColumn *)aTableColumn - row:(int)rowIndex -{ - if ( !isEditingRow ) { - [oldRow setDictionary:[filteredResult objectAtIndex:rowIndex]]; - isEditingRow = YES; - } - if ( anObject ) { - [[filteredResult objectAtIndex:rowIndex] setObject:anObject forKey:[aTableColumn identifier]]; - } else { - [[filteredResult objectAtIndex:rowIndex] setObject:@"" forKey:[aTableColumn identifier]]; - } -} - -#pragma mark - -#pragma mark tableView delegate methods - -- (void)tableView:(NSTableView*)tableView didClickTableColumn:(NSTableColumn *)tableColumn -/* - sorts the tableView by the clicked column - if clicked twice, order is descending - */ -{ - NSString *queryString; - CMMCPResult *queryResult; - - if ( [selectedTable isEqualToString:@""] || !selectedTable ) - return; - if ( ![self selectionShouldChangeInTableView:nil] ) - return; - - //query started - [[NSNotificationCenter defaultCenter] postNotificationName:@"SMySQLQueryWillBePerformed" object:self]; - - //sets order descending if a header is clicked twice - if ( [[tableColumn identifier] isEqualTo:sortField] ) { - if ( isDesc ) { - isDesc = NO; - } else { - isDesc = YES; - } - } else { - isDesc = NO; - [tableContentView setIndicatorImage:nil inTableColumn:[tableContentView tableColumnWithIdentifier:sortField]]; - } - sortField = [tableColumn identifier]; - - //make queryString and perform query - queryString = [NSString stringWithFormat:@"SELECT %@ FROM `%@` ORDER BY `%@`", [self fieldListForQuery], - selectedTable, sortField]; - if ( isDesc ) - queryString = [queryString stringByAppendingString:@" DESC"]; - if ( [prefs boolForKey:@"limitRows"] ) { - if ( [limitRowsField intValue] <= 0 ) { - [limitRowsField setStringValue:@"1"]; - } - queryString = [queryString stringByAppendingString: - [NSString stringWithFormat:@" LIMIT %d,%d", - [limitRowsField intValue]-1, [prefs integerForKey:@"limitRowsValue"]]]; - } - queryResult = [mySQLConnection queryString:queryString]; - - // [fullResult setArray:[[self fetchResultAsArray:queryResult] retain]]; - [fullResult setArray:[self fetchResultAsArray:queryResult]]; - - if ( ![[mySQLConnection getLastErrorMessage] isEqualToString:@""] ) { - NSBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, tableWindow, self, nil, nil, nil, - [NSString stringWithFormat:NSLocalizedString(@"Couldn't sort table. MySQL said: %@", @"message of panel when sorting of table failed"), [mySQLConnection getLastErrorMessage]]); - return; - } - - //sets highlight and indicatorImage - [tableContentView setHighlightedTableColumn:tableColumn]; - if ( isDesc ) { - [tableContentView setIndicatorImage:[NSImage imageNamed:@"NSDescendingSortIndicator"] inTableColumn:tableColumn]; - } else { - [tableContentView setIndicatorImage:[NSImage imageNamed:@"NSAscendingSortIndicator"] inTableColumn:tableColumn]; - } - - //query finished - [[NSNotificationCenter defaultCenter] postNotificationName:@"SMySQLQueryHasBeenPerformed" object:self]; - - //if filter is activated filters the result, otherwise shows fullResult - if ( !areShowingAllRows ) { - [self filterTable:self]; - } else { - [filteredResult setArray:fullResult]; - [tableContentView reloadData]; - } -} - -- (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 ( [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 { - [countText setStringValue:[NSString stringWithFormat:NSLocalizedString(@"%d rows", @"Text showing how many rows are in the result"), [tableContentView numberOfRows]]]; - } -} - -- (void)tableViewSelectionIsChanging:(NSNotification *)aNotification -{ - // Check our notification object is our table content view - if ([aNotification object] != tableContentView) - return; - - 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 { - [countText setStringValue:[NSString stringWithFormat:NSLocalizedString(@"%d rows", @"Text showing how many rows are in the result"), [tableContentView numberOfRows]]]; - } -} - - -- (void)tableViewColumnDidResize:(NSNotification *)aNotification -/* - saves the new column size in the preferences - */ -{ - // sometimes the column has no identifier. I can't figure out what is causing it, so we just skip over this item - if (![[[aNotification userInfo] objectForKey:@"NSTableColumn"] identifier]) - return; - - NSMutableDictionary *tableColumnWidths; - NSString *database = [NSString stringWithFormat:@"%@@%@", [tableDocumentInstance database], [tableDocumentInstance host]]; - NSString *table = (NSString *)[tablesListInstance table]; - - // get tableColumnWidths object - if ( [prefs objectForKey:@"tableColumnWidths"] != nil ) { - tableColumnWidths = [NSMutableDictionary dictionaryWithDictionary:[prefs objectForKey:@"tableColumnWidths"]]; - } else { - tableColumnWidths = [NSMutableDictionary dictionary]; - } - // get database object - if ( [tableColumnWidths objectForKey:database] == nil ) { - [tableColumnWidths setObject:[NSMutableDictionary dictionary] forKey:database]; - } else { - [tableColumnWidths setObject:[[tableColumnWidths objectForKey:database] mutableCopy] forKey:database]; - } - // get table object - if ( [[tableColumnWidths objectForKey:database] objectForKey:table] == nil ) { - [[tableColumnWidths objectForKey:database] setObject:[NSMutableDictionary dictionary] forKey:table]; - } else { - [[tableColumnWidths objectForKey:database] setObject:[[[tableColumnWidths objectForKey:database] objectForKey:table] mutableCopy] forKey:table]; - } - // save column size - [[[tableColumnWidths objectForKey:database] objectForKey:table] setObject:[NSNumber numberWithFloat:[[[aNotification userInfo] objectForKey:@"NSTableColumn"] width]] forKey:[[[aNotification userInfo] objectForKey:@"NSTableColumn"] identifier]]; - [prefs setObject:tableColumnWidths forKey:@"tableColumnWidths"]; -} - -- (BOOL)tableView:(NSTableView *)aTableView shouldEditTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex -/* - opens sheet if multipleLineEditingButton is clicked or field is a hidden blob or text field - */ -{ - NSEnumerator *enumerator; - id type; - BOOL blob = NO; - NSDictionary *tempRow; - NSMutableDictionary *modifiedRow = [NSMutableDictionary dictionary]; - id key; - int code; - NSString *query; - CMMCPResult *tempResult; - id theValue; - BOOL columnIsBlob = NO; - // int i; - // NSArray *columns = [aTableView tableColumns]; - - if ( [prefs boolForKey:@"dontShowBlob"] && !isEditingRow ) { - //get all row values if dontShowBlob == YES and table contains blob or text field and isEditingRow = NO - enumerator = [fieldTypes objectEnumerator]; - while ( (type = [enumerator nextObject]) ) { - if ( [self isBlobOrText:type] ) { - blob = YES; - } - } - - if ( blob ) { - query = [NSString stringWithFormat:@"SELECT * FROM `%@` WHERE %@", - selectedTable, [self argumentForRow:[tableContentView selectedRow]]]; - 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; - } - tempRow = [tempResult fetchRowAsDictionary]; - enumerator = [tempRow keyEnumerator]; - while ( key = [enumerator nextObject] ) { - if ( [[tempRow objectForKey:key] isMemberOfClass:[NSNull class]] ) { - [modifiedRow setObject:[prefs stringForKey:@"nullValue"] forKey:key]; - } else { - [modifiedRow setObject:[tempRow objectForKey:key] forKey:key]; - } - } - [filteredResult replaceObjectAtIndex:rowIndex - withObject:[NSMutableDictionary dictionaryWithDictionary:modifiedRow]]; - [tableContentView reloadData]; - } - } - - /* - // find the column we're trying to edit - for ( i = 0; i < [columns count]; i++ ) { - if ( [columns objectAtIndex:i] == aTableColumn ) { - // this flag will let us determine if we should "force" multi-line edit. - columnIsBlob = [self isBlobOrText:[fieldTypes objectAtIndex:i]]; - break; - } - } - */ - //is the column a blob field -> if YES force sheet editing - if ( [self isBlobOrText:[fieldTypes objectAtIndex:[fieldNames indexOfObject:[aTableColumn identifier]]]] ) { - columnIsBlob = YES; - } - - if ( [multipleLineEditingButton state] == NSOnState || columnIsBlob ) { - theValue = [[filteredResult objectAtIndex:rowIndex] objectForKey:[aTableColumn identifier]]; - NSImage *image = nil; - editData = [theValue retain]; - - if ( [theValue isKindOfClass:[NSData class]] ) { - image = [[NSImage alloc] initWithData:theValue]; - [hexTextView setString:[self dataToHex:theValue]]; - /* - // update displayed font to monospace - NSFont *font = [NSFont fontWithName:@"Courier" size:12.0f]; - NSRange hexRange = { 0, [[hexTextView string] length] - 1 }; - [hexTextView setFont:font range:hexRange]; - */ - theValue = [[NSString alloc] initWithData:theValue encoding:[mySQLConnection encoding]]; - } else { - [hexTextView setString:@""]; - theValue = [theValue description]; - } - - [editImage setImage:image]; - [editTextView setString:theValue]; - [editTextView setSelectedRange:NSMakeRange(0,[[editTextView string] length])]; - //different sheets for date (with up/down arrows), number and text - [NSApp beginSheet:editSheet - modalForWindow:tableWindow modalDelegate:self - didEndSelector:nil contextInfo:nil]; - code = [NSApp runModalForWindow:editSheet]; - - [NSApp endSheet:editSheet]; - [editSheet orderOut:nil]; - - if ( code ) { - if ( !isEditingRow ) { - [oldRow setDictionary:[filteredResult objectAtIndex:rowIndex]]; - isEditingRow = YES; - } - - [[filteredResult objectAtIndex:rowIndex] setObject:[editData copy] - forKey:[aTableColumn identifier]]; - - // clean up - [editImage setImage:nil]; - [editTextView setString:@""]; - [hexTextView setString:@""]; - if ( editData ) { - [editData release]; - } - } - return NO; - } else { - return YES; - } -} - -- (BOOL)tableView:(NSTableView *)tableView writeRows:(NSArray*)rows - toPasteboard:(NSPasteboard*)pboard -/* - enable drag from tableview - */ -{ - if ( tableView == tableContentView ) - { - NSString *tmp = [tableContentView draggedRowsAsTabString:rows]; - - if ( nil != tmp ) - { - [pboard declareTypes:[NSArray arrayWithObjects: NSTabularTextPboardType, - NSStringPboardType, nil] - owner:nil]; - - [pboard setString:tmp forType:NSStringPboardType]; - [pboard setString:tmp forType:NSTabularTextPboardType]; - return YES; - } - } - return NO; -} - -#pragma mark - - -- (BOOL)control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)command -/* - traps enter and esc an make/cancel editing without entering next row - */ -{ - int row, column, i; - - row = [tableContentView editedRow]; - column = [tableContentView editedColumn]; - - if ( [textView methodForSelector:command] == [textView methodForSelector:@selector(insertNewline:)] || - [textView methodForSelector:command] == [textView methodForSelector:@selector(insertTab:)] ) //trap enter and tab - { - //save current line - [[control window] makeFirstResponder:control]; - if ( column == ( [tableContentView numberOfColumns] - 1 ) ) { - [self addRowToDB]; - /* - if ( [self addRowToDB] && - ( [textView methodForSelector:command] == [textView methodForSelector:@selector(insertTab:)] ) && - !(sortField && ([prefs boolForKey:@"reloadAfterAdding"] || [prefs boolForKey:@"reloadAfterEditing"])) ) { - //get in edit-mode of next row if user hit tab (and result isn't sorted and reloaded) - if ( row < ([tableContentView numberOfRows] - 1) ) { - [tableContentView selectRow:row+1 byExtendingSelection:NO]; - [tableContentView editColumn:0 row:row+1 withEvent:nil select:YES]; - } else { - [tableContentView selectRow:0 byExtendingSelection:NO]; - [tableContentView editColumn:0 row:0 withEvent:nil select:YES]; - } - } - */ - } else { - //check if next column is a blob column - i = 1; - while ( [self isBlobOrText:[fieldTypes objectAtIndex:[fieldNames indexOfObject:[[[tableContentView tableColumns] objectAtIndex:column+i] identifier]]]] ) { - i++; - if ( (column+i) >= [tableContentView numberOfColumns] ) { - //there is no other column after the blob column - [self addRowToDB]; - return TRUE; - } - } - //edit the column after the blob column - [tableContentView editColumn:column+i row:row withEvent:nil select:YES]; - } - return TRUE; - } - else if ( [[control window] methodForSelector:command] == [[control window] methodForSelector:@selector(_cancelKey:)] || - [textView methodForSelector:command] == [textView methodForSelector:@selector(complete:)] ) //trap esc - { - //abort editing - [control abortEditing]; - if ( isEditingRow && !isEditingNewRow ) { - isEditingRow = NO; - [filteredResult replaceObjectAtIndex:row withObject:[NSMutableDictionary dictionaryWithDictionary:oldRow]]; - } else if ( isEditingNewRow ) { - isEditingRow = NO; - isEditingNewRow = NO; - [filteredResult removeObjectAtIndex:row]; - [tableContentView reloadData]; - } - return TRUE; - } - else - { - return FALSE; - } -} - - -//textView delegate methods -- (BOOL)textView:(NSTextView *)aTextView doCommandBySelector:(SEL)aSelector -/* - traps enter and return key and closes editSheet instead of inserting a linebreak when user hits return - */ -{ - if ( aTextView == editTextView ) { - if ( [aTextView methodForSelector:aSelector] == [aTextView methodForSelector:@selector(insertNewline:)] && - [[[NSApp currentEvent] characters] isEqualToString:@"\003"] ) - { - [NSApp stopModalWithCode:1]; - return YES; - } else { - return NO; - } - } - return NO; -} - - -//last but not least - -- (void)dealloc -{ - // NSLog(@"TableContent dealloc"); - - [editData release]; - [fullResult release]; - [filteredResult release]; - [keys release]; - [oldRow release]; - [fieldNames release]; - [fieldTypes release]; - [compareType release]; - [sortField release]; - [prefs release]; - - [super dealloc]; -} - -@end |