diff options
Diffstat (limited to 'Source/SPExportController.m')
-rw-r--r-- | Source/SPExportController.m | 766 |
1 files changed, 477 insertions, 289 deletions
diff --git a/Source/SPExportController.m b/Source/SPExportController.m index 559e8071..83c87ea6 100644 --- a/Source/SPExportController.m +++ b/Source/SPExportController.m @@ -5,6 +5,7 @@ // sequel-pro // // Created by Ben Perry (benperry.com.au) on 21/02/09. +// Modified by Stuart Connolly (stuconnolly.com) // // 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 @@ -22,39 +23,68 @@ // // More info at <http://code.google.com/p/sequel-pro/> +#import <MCPKit/MCPKit.h> + #import "SPExportController.h" -#import "SPCSVExporter.h" +#import "SPExportInitializer.h" #import "TablesList.h" #import "SPTableData.h" -#import "TableDocument.h" +#import "TableContent.h" #import "SPArrayAdditions.h" #import "SPStringAdditions.h" #import "SPConstants.h" +#import "SPGrowlController.h" @interface SPExportController (PrivateAPI) -- (void)_initializeExportUsingSelectedOptions; -- (BOOL)_exportTables:(NSArray *)exportTables asType:(SPExportType)type toMultipleFiles:(BOOL)multipleFiles; +- (void)_toggleExportButton; +- (void)_resizeWindowByHeightDelta:(NSInteger)delta; @end @implementation SPExportController @synthesize connection; +@synthesize exportToMultipleFiles; @synthesize exportCancelled; +#pragma mark - +#pragma mark Initialization + /** * Initializes an instance of SPExportController */ - (id)init { - if ((self = [super init])) { + if (self = [super initWithWindowNibName:@"ExportDialog"]) { + [self setExportCancelled:NO]; + [self setExportToMultipleFiles:YES]; + + exportType = 0; + exportTableCount = 0; + currentTableExportIndex = 0; + + exportFilename = @""; + exportTypeLabel = @""; + + createCustomFilename = NO; + sqlPreviousConnectionEncodingViaLatin1 = NO; tables = [[NSMutableArray alloc] init]; + exporters = [[NSMutableArray alloc] init]; operationQueue = [[NSOperationQueue alloc] init]; - tableExportMapping = [NSMutableDictionary dictionary]; - nibObjectsToRelease = [[NSMutableArray alloc] init]; + + showAdvancedView = NO; + + heightOffset = 0; + windowMinWidth = [[self window] minSize].width; + windowMinHeigth = [[self window] minSize].height; + + prefs = [NSUserDefaults standardUserDefaults]; + + // Default filename tokens + availableFilenameTokens = @"host,database,table,date,time"; } return self; @@ -64,9 +94,12 @@ * Upon awakening select the first toolbar item */ - (void)awakeFromNib -{ +{ // Upon awakening select the SQL tab [exportToolbar setSelectedItemIdentifier:[[[exportToolbar items] objectAtIndex:0] itemIdentifier]]; + + // Select the 'selected tables' option + [exportInputMatrix selectCellAtRow:2 column:0]; } #pragma mark - @@ -76,52 +109,166 @@ * Display the export window allowing the user to select what and of what type to export. */ - (void)export -{ +{ + [self exportTables:nil asFormat:0]; +} - // If the dialog hasn't been loaded yet, do so, retaining a reference to the top-level objects that need releasing. - if (!exportWindow) - { - NSArray *exportDialogTopLevelObjects = nil; - NSNib *nibLoader = [[NSNib alloc] initWithNibNamed:@"ExportDialog" bundle:[NSBundle mainBundle]]; - [nibLoader instantiateNibWithOwner:self topLevelObjects:&exportDialogTopLevelObjects]; - [nibObjectsToRelease addObjectsFromArray:exportDialogTopLevelObjects]; - [nibLoader release]; +/** + * Displays the export window with the supplied tables and export type/format selected. + */ +- (void)exportTables:(NSArray *)exportTables asFormat:(SPExportType)format +{ + [self refreshTableList:self]; + + if (exportTables && format) { + + // Select the correct tab according to the supplied export type + [exportToolbar setSelectedItemIdentifier:[[[exportToolbar items] objectAtIndex:(format - 1)] itemIdentifier]]; + + // Select the 'selected tables' source option + [exportInputMatrix selectCellAtRow:2 column:0]; + + // Disable all tables + for (NSMutableArray *table in tables) + { + [table replaceObjectAtIndex:1 withObject:[NSNumber numberWithBool:NO]]; + [table replaceObjectAtIndex:2 withObject:[NSNumber numberWithBool:NO]]; + [table replaceObjectAtIndex:3 withObject:[NSNumber numberWithBool:NO]]; + } + + // Select the supplied tables + for (NSMutableArray *table in tables) + { + for (NSString *exportTable in exportTables) + { + if ([exportTable isEqualToString:[table objectAtIndex:0]]) { + [table replaceObjectAtIndex:1 withObject:[NSNumber numberWithBool:YES]]; + [table replaceObjectAtIndex:2 withObject:[NSNumber numberWithBool:YES]]; + [table replaceObjectAtIndex:3 withObject:[NSNumber numberWithBool:YES]]; + } + } + } + + [exportTableList reloadData]; + + // Ensure interface validation + [self switchTab:[[exportToolbar items] objectAtIndex:(format - 1)]]; } - NSUInteger i; + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDesktopDirectory, NSUserDomainMask, YES); - [tables removeAllObjects]; + // If found the set the default path to the user's desktop, otherwise use their home directory + [exportPathField setStringValue:([paths count] > 0) ? [paths objectAtIndex:0] : NSHomeDirectory()]; - MCPResult *queryResult = (MCPResult *)[[self connection] listTables]; + [NSApp beginSheet:[self window] + modalForWindow:[tableDocumentInstance parentWindow] + modalDelegate:self + didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) + contextInfo:nil]; +} + +/** + * Opens the errors sheet and displays the supplied errors string. + */ +- (void)openExportErrorsSheetWithString:(NSString *)errors +{ + [errorsTextView setString:@""]; + [errorsTextView setString:errors]; - if ([queryResult numOfRows]) [queryResult dataSeek:0]; + [NSApp beginSheet:errorsWindow + modalForWindow:[tableDocumentInstance parentWindow] + modalDelegate:self + didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) + contextInfo:nil]; +} + +/** + * Displays the export finished Growl notification. + */ +- (void)displayExportFinishedGrowlNotification +{ + // Export finished Growl notification + [[SPGrowlController sharedGrowlController] notifyWithTitle:@"Export Finished" + description:[NSString stringWithFormat:NSLocalizedString(@"Finished exporting to %@", @"description for finished exporting growl notification"), exportFilename] + window:[tableDocumentInstance parentWindow] + notificationName:@"Export Finished"]; +} + +/** + * Expands the custom filename format based on the selected tokens. + */ +- (NSString *)expandCustomFilenameFormatFromString:(NSString *)format usingTableName:(NSString *)table +{ + NSMutableString *string = [NSMutableString stringWithString:format]; - for ( i = 0 ; i < [queryResult numOfRows] ; i++ ) - { - [tables addObject:[NSMutableArray arrayWithObjects: - [NSNumber numberWithBool:YES], - NSArrayObjectAtIndex([queryResult fetchRowAsArray], 0), - nil]]; + NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; + + [dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4]; + + [dateFormatter setDateStyle:NSDateFormatterShortStyle]; + [dateFormatter setTimeStyle:NSDateFormatterNoStyle]; + + [string replaceOccurrencesOfString:@"host" withString:[tableDocumentInstance host] + options:NSLiteralSearch + range:NSMakeRange(0, [string length])]; + + [string replaceOccurrencesOfString:@"database" withString:[tableDocumentInstance database] + options:NSLiteralSearch + range:NSMakeRange(0, [string length])]; + + if (table) { + [string replaceOccurrencesOfString:@"table" withString:table + options:NSLiteralSearch + range:NSMakeRange(0, [string length])]; + } + else { + [string replaceOccurrencesOfString:@"table" withString:@"" + options:NSLiteralSearch + range:NSMakeRange(0, [string length])]; } - [exportTableList reloadData]; - - [exportPathField setStringValue:NSHomeDirectory()]; + [string replaceOccurrencesOfString:@"date" withString:[dateFormatter stringFromDate:[NSDate date]] + options:NSLiteralSearch + range:NSMakeRange(0, [string length])]; - [NSApp beginSheet:exportWindow - modalForWindow:[tableDocumentInstance parentWindow] - modalDelegate:self - didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) - contextInfo:nil]; + [dateFormatter setDateStyle:NSDateFormatterNoStyle]; + [dateFormatter setTimeStyle:NSDateFormatterShortStyle]; + + [string replaceOccurrencesOfString:@"time" withString:[dateFormatter stringFromDate:[NSDate date]] + options:NSLiteralSearch + range:NSMakeRange(0, [string length])]; + + // Strip comma separators + [string replaceOccurrencesOfString:@"," withString:@"" + options:NSLiteralSearch + range:NSMakeRange(0, [string length])]; + + // Replace colons with hyphens + [string replaceOccurrencesOfString:@":" withString:@"-" + options:NSLiteralSearch + range:NSMakeRange(0, [string length])]; + + [dateFormatter release]; + + return string; } /** - * Closes the export dialog + * Closes the export dialog. */ - (IBAction)closeSheet:(id)sender { - [NSApp endSheet:exportWindow returnCode:[sender tag]]; - [exportWindow orderOut:self]; + if ([sender window] == [self window]) { + + // Close the advanced options view if it's open + [exportAdvancedOptionsView setHidden:YES]; + [exportAdvancedOptionsViewButton setState:NSOffState]; + + [self _resizeWindowByHeightDelta:0]; + } + + [NSApp endSheet:[sender window] returnCode:[sender tag]]; + [[sender window] orderOut:self]; } /** @@ -130,20 +277,70 @@ - (IBAction)switchTab:(id)sender { if ([sender isKindOfClass:[NSToolbarItem class]]) { - [exportTabBar selectTabViewItemWithIdentifier:[[sender label] lowercaseString]]; + + currentToolbarItem = sender; + + NSString *label = [[currentToolbarItem label] lowercaseString]; + + [exportTabBar selectTabViewItemWithIdentifier:label]; + + BOOL isSQL = [label isEqualToString:@"sql"]; + BOOL isCSV = [label isEqualToString:@"csv"]; + BOOL isXML = [label isEqualToString:@"xml"]; + BOOL isHTML = [label isEqualToString:@"html"]; + BOOL isPDF = [label isEqualToString:@"pdf"]; + BOOL isDot = [label isEqualToString:@"dot"]; + + BOOL disable = (isCSV || isXML || isHTML || isPDF || isDot); + + [exportFilePerTableCheck setHidden:(isSQL || isDot)]; + [exportFilePerTableNote setHidden:(isSQL || isDot)]; + + [exportTableList setEnabled:(!isDot)]; + [exportSelectAllTablesButton setEnabled:(!isDot)]; + [exportDeselectAllTablesButton setEnabled:(!isDot)]; + [exportRefreshTablesButton setEnabled:(!isDot)]; + + [[exportInputMatrix cellAtRow:2 column:0] setEnabled:(!isDot)]; + + if (isDot) { + // Disable all source checkboxes + [[exportInputMatrix cellAtRow:0 column:0] setEnabled:NO]; + [[exportInputMatrix cellAtRow:1 column:0] setEnabled:NO]; + } + else { + // Enable/disable the 'filtered result' and 'query result' options + [[exportInputMatrix cellAtRow:0 column:0] setEnabled:((disable) && ([[tableContentInstance currentResult] count] > 1))]; + [[exportInputMatrix cellAtRow:1 column:0] setEnabled:((disable) && ([[customQueryInstance currentResult] count] > 1))]; + } - [exportFilePerTableCheck setHidden:[[sender label] isEqualToString:@"Excel"]]; - [exportFilePerTableNote setHidden:[[sender label] isEqualToString:@"Excel"]]; + [[exportTableList tableColumnWithIdentifier:@"structure"] setHidden:disable]; + [[exportTableList tableColumnWithIdentifier:@"drop"] setHidden:disable]; + + [[[exportTableList tableColumnWithIdentifier:@"content"] headerCell] setStringValue:(disable) ? @"" : @"C"]; + + [exportCSVNULLValuesAsTextField setStringValue:[prefs stringForKey:SPNullValue]]; } } /** - * + * Enables/disables and shows/hides various interface controls depending on the selected item. */ - (IBAction)switchInput:(id)sender { if ([sender isKindOfClass:[NSMatrix class]]) { - [exportTableList setEnabled:([[sender selectedCell] tag] == 3)]; + + BOOL isSelectedTables = ([[sender selectedCell] tag] == SPTableExport); + + [exportFilePerTableCheck setHidden:(!isSelectedTables)]; + [exportFilePerTableNote setHidden:(!isSelectedTables)]; + + [exportTableList setEnabled:isSelectedTables]; + [exportSelectAllTablesButton setEnabled:isSelectedTables]; + [exportDeselectAllTablesButton setEnabled:isSelectedTables]; + [exportRefreshTablesButton setEnabled:isSelectedTables]; + + availableFilenameTokens = ([[sender selectedCell] tag] == SPQueryExport) ? @"host,database,date,time" : @"host,database,table,date,time"; } } @@ -164,24 +361,161 @@ } /** - * + * Opens the open panel when user selects to change the output path. */ - (IBAction)changeExportOutputPath:(id)sender { + [exportCustomFilenameTokenField setStringValue:@""]; + [exportCustomFilenameTokensField setStringValue:availableFilenameTokens]; + NSOpenPanel *panel = [NSOpenPanel openPanel]; [panel setCanChooseFiles:NO]; [panel setCanChooseDirectories:YES]; [panel setCanCreateDirectories:YES]; + [panel setAccessoryView:exportCustomFilenameView]; + + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDesktopDirectory, NSUserDomainMask, YES); - [panel beginSheetForDirectory:NSHomeDirectory() + [panel beginSheetForDirectory:([paths count] > 0) ? [paths objectAtIndex:0] : NSHomeDirectory() file:nil - modalForWindow:exportWindow + modalForWindow:[self window] modalDelegate:self didEndSelector:@selector(savePanelDidEnd:returnCode:contextInfo:) contextInfo:nil]; } +/** + * Refreshes the table list. + */ +- (IBAction)refreshTableList:(id)sender +{ + NSUInteger i; + + [tables removeAllObjects]; + + // For all modes, retrieve table and view names + NSArray *tablesAndViews = [tablesListInstance allTableAndViewNames]; + + for (id itemName in tablesAndViews) { + [tables addObject:[NSMutableArray arrayWithObjects: + itemName, + [NSNumber numberWithBool:YES], + [NSNumber numberWithBool:YES], + [NSNumber numberWithBool:YES], + [NSNumber numberWithInt:SPTableTypeTable], + nil]]; + } + + // For SQL only, add procedures and functions + if ([[[currentToolbarItem label] lowercaseString] isEqualToString:@"sql"]) { + NSArray *procedures = [tablesListInstance allProcedureNames]; + + for (id procName in procedures) + { + [tables addObject:[NSMutableArray arrayWithObjects: + procName, + [NSNumber numberWithBool:YES], + [NSNumber numberWithBool:YES], + [NSNumber numberWithBool:YES], + [NSNumber numberWithInt:SPTableTypeProc], + nil]]; + } + + NSArray *functions = [tablesListInstance allFunctionNames]; + + for (id funcName in functions) + { + [tables addObject:[NSMutableArray arrayWithObjects: + funcName, + [NSNumber numberWithBool:YES], + [NSNumber numberWithBool:YES], + [NSNumber numberWithBool:YES], + [NSNumber numberWithInt:SPTableTypeFunc], + nil]]; + } + } + + [exportTableList reloadData]; +} + +/** + * Selects or de-selects all tables. + */ +- (IBAction)selectDeselectAllTables:(id)sender +{ + [self refreshTableList:self]; + + for (NSMutableArray *table in tables) + { + [table replaceObjectAtIndex:2 withObject:[NSNumber numberWithBool:[sender tag]]]; + } + + [exportTableList reloadData]; + + [self _toggleExportButton]; +} + +/** + * Toggles the state of the custom filename format token fields. + */ +- (IBAction)toggleCustomFilenameFormat:(id)sender +{ + [exportCustomFilenameTokenField setEnabled:[sender state]]; + [exportCustomFilenameTokensField setEnabled:[sender state]]; +} + +/** + * Toggles the display of the advanced options box. + */ +- (IBAction)toggleAdvancedExportOptionsView:(id)sender +{ + showAdvancedView = !showAdvancedView; + + if (showAdvancedView) { + [exportAdvancedOptionsViewButton setState:NSOnState]; + [self _resizeWindowByHeightDelta:([exportAdvancedOptionsView frame].size.height + 10)]; + [exportAdvancedOptionsView setHidden:NO]; + } + else { + [exportAdvancedOptionsViewButton setState:NSOffState]; + [self _resizeWindowByHeightDelta:0]; + [exportAdvancedOptionsView setHidden:YES]; + } +} + +/** + * Toggles the export button when choosing to include or table structures in an SQL export. + */ +- (IBAction)toggleSQLIncludeStructure:(id)sender +{ + [[exportTableList tableColumnWithIdentifier:@"structure"] setHidden:(![sender state])]; + + [self _toggleExportButton]; +} + +/** + * Toggles the export button when choosing to include or exclude table contents in an SQL export. + */ +- (IBAction)toggleSQLIncludeContent:(id)sender +{ + [sender setTag:[sender state]]; + + [self selectDeselectAllTables:sender]; + + [self _toggleExportButton]; +} + +/** + * Toggles the export button when choosing to include or exclude table drop syntax in an SQL export. + */ +- (IBAction)toggleSQLIncludeDropSyntax:(id)sender +{ + [[exportTableList tableColumnWithIdentifier:@"drop"] setHidden:(![sender state])]; + + [self _toggleExportButton]; +} + #pragma mark - #pragma mark Table view datasource methods @@ -190,30 +524,32 @@ return [tables count]; } -- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex -{ - return NSArrayObjectAtIndex([tables objectAtIndex:rowIndex], ([[aTableColumn identifier] isEqualToString:@"switch"]) ? 0 : 1); +- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)rowIndex +{ + return NSArrayObjectAtIndex([tables objectAtIndex:rowIndex], [exportTableList columnWithIdentifier:[tableColumn identifier]]); } -- (void)tableView:(NSTableView *)aTableView setObjectValue:(id)anObject forTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex -{ - [[tables objectAtIndex:rowIndex] replaceObjectAtIndex:0 withObject:anObject]; +- (void)tableView:(NSTableView *)tableView setObjectValue:(id)anObject forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)rowIndex +{ + [[tables objectAtIndex:rowIndex] replaceObjectAtIndex:[exportTableList columnWithIdentifier:[tableColumn identifier]] withObject:anObject]; + + [self _toggleExportButton]; } #pragma mark - #pragma mark Table view delegate methods -- (BOOL)tableView:(NSTableView *)aTableView shouldSelectRow:(NSInteger)rowIndex +- (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(NSInteger)rowIndex { - return (aTableView != exportTableList); + return (tableView != exportTableList); } -- (BOOL)tableView:(NSTableView *)aTableView shouldTrackCell:(NSCell *)cell forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row +- (BOOL)tableView:(NSTableView *)tableView shouldTrackCell:(NSCell *)cell forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)rowIndex { - return (aTableView == exportTableList); + return (tableView == exportTableList); } -- (void)tableView:(NSTableView *)aTableView willDisplayCell:(id)aCell forTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex +- (void)tableView:(NSTableView *)tableView willDisplayCell:(id)aCell forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)rowIndex { [aCell setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]]; } @@ -223,7 +559,7 @@ - (NSArray *)toolbarSelectableItemIdentifiers:(NSToolbar *)toolbar { - NSMutableArray *items = [NSMutableArray arrayWithCapacity:6]; + NSMutableArray *items = [NSMutableArray array]; for (NSToolbarItem *item in [toolbar items]) { @@ -234,21 +570,16 @@ } #pragma mark - -#pragma mark SPExporterDataAccess protocol methods +#pragma mark Text field delegate methods -/** - * This method is part of the SPExporterDataAccess protocol. It is called when an expoter complete it's data - * conversion process and the operation is effectively complete. The resulting data can be accessed via - * SPExporter's exportData method. - */ -- (void)exporterDataConversionProcessComplete:(SPExporter *)exporter -{ - // Do something with the data... - - // If there are no more operations in the queue, close the progress sheet - if ([[operationQueue operations] count] == 0) { - [NSApp endSheet:exportProgressWindow returnCode:0]; - [exportProgressWindow orderOut:self]; +- (void)controlTextDidChange:(NSNotification *)notification +{ + if ([notification object] == exportCustomFilenameTokenField) { + + // Create the table name, but since this is only an example, use the first table in the list + NSString *filename = [self expandCustomFilenameFormatFromString:[exportCustomFilenameTokenField stringValue] usingTableName:[[tablesListInstance tables] objectAtIndex:1]]; + + [exportCustomFilenameExampleTextField setStringValue:[NSString stringWithFormat:@"%@: %@", NSLocalizedString(@"Example", @"example label"), filename]]; } } @@ -256,7 +587,7 @@ #pragma mark Other /** - * Invoked when the user + * Invoked when the user dismissing the export dialog and starts the export process if required. */ - (void)sheetDidEnd:(NSWindow *)sheet returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo { @@ -264,12 +595,12 @@ if (returnCode == NSOKButton) { // Initialize the export after half a second to give the export sheet a chance to close - [self performSelector:@selector(_initializeExportUsingSelectedOptions) withObject:nil afterDelay:0.5]; + [self performSelector:@selector(initializeExportUsingSelectedOptions) withObject:nil afterDelay:0.5]; } } /** - * Invoked when the user dismisses the save panel. Updates the selected directory is they clicked OK. + * Invoked when the user dismisses the save panel. Updates the selected directory if they clicked OK. */ - (void)savePanelDidEnd:(NSSavePanel *)panel returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo { @@ -286,247 +617,104 @@ - (void)dealloc { [tables release], tables = nil; + [exporters release], exporters = nil; [operationQueue release], operationQueue = nil; - for (id retainedObject in nibObjectsToRelease) [retainedObject release]; - [nibObjectsToRelease release], nibObjectsToRelease = nil; + + if (sqlPreviousConnectionEncoding) [sqlPreviousConnectionEncoding release], sqlPreviousConnectionEncoding = nil; [super dealloc]; } -@end - -@implementation SPExportController (PrivateAPI) +#pragma mark - +#pragma mark Private API /** - * + * Enables or disables the export button based on the state of various interface controls. */ -- (void)_initializeExportUsingSelectedOptions +- (void)_toggleExportButton { - // First determine what type of export the user selected - SPExportType exportType = 0; + NSString *label = [[currentToolbarItem label] lowercaseString]; - for (NSToolbarItem *item in [exportToolbar items]) - { - if ([[item itemIdentifier] isEqualToString:[exportToolbar selectedItemIdentifier]]) { - exportType = [item tag]; - break; - } - } - - // Determine what data to use (filtered result, custom query result or selected table(s)) for the export operation - SPExportSource exportSource = ([exportInputMatrix selectedRow] + 1); - - NSMutableArray *exportTables = [NSMutableArray array]; - - // Get the data depending on the source - switch (exportSource) - { - case SP_FILTERED_EXPORT: - - break; - case SP_CUSTOM_QUERY_EXPORT: - - break; - case SP_TABLE_EXPORT: - // Create an array of tables to export - for (NSMutableArray *table in tables) - { - if ([[table objectAtIndex:0] boolValue]) { - [exportTables addObject:[table objectAtIndex:1]]; - } + BOOL isSQL = [label isEqualToString:@"sql"]; + BOOL isCSV = [label isEqualToString:@"csv"]; + BOOL isXML = [label isEqualToString:@"xml"]; + BOOL isHTML = [label isEqualToString:@"html"]; + BOOL isPDF = [label isEqualToString:@"pdf"]; + + if (isCSV || isXML || isHTML || isPDF) { + [exportButton setEnabled:NO]; + + // Only enable the button if at least one table is selected + for (NSArray *table in tables) + { + if ([NSArrayObjectAtIndex(table, 2) boolValue]) { + [exportButton setEnabled:YES]; + break; } - - break; + } } - - // Begin the export based on the type - switch (exportSource) - { - case SP_FILTERED_EXPORT: - - break; - case SP_CUSTOM_QUERY_EXPORT: - - break; - case SP_TABLE_EXPORT: - [self _exportTables:exportTables asType:exportType toMultipleFiles:[exportFilePerTableCheck state]]; - break; + else if (isSQL) { + BOOL structureEnabled = [exportSQLIncludeStructureCheck state]; + BOOL contentEnabled = [exportSQLIncludeContentCheck state]; + BOOL dropEnabled = [exportSQLIncludeDropSyntaxCheck state]; + + // Disable if all are unchecked + if ((!contentEnabled) && (!structureEnabled) && (!dropEnabled)) { + [exportButton setEnabled:NO]; + } + // Disable if structure is unchecked, but content and drop are as dropping a table then trying to insert + // into it is obviously an error + else if (contentEnabled && (!structureEnabled) && (dropEnabled)) { + [exportButton setEnabled:NO]; + } + else { + [exportButton setEnabled:(contentEnabled || (structureEnabled || dropEnabled))]; + } } } /** - * Exports the contents' of the supplied array of tables. Note that this method currently only supports - * exporting in CSV and XML formats. + * Resizes the export window's height by the supplied delta, while retaining the position of + * all interface controls. */ -- (BOOL)_exportTables:(NSArray *)exportTables asType:(SPExportType)type toMultipleFiles:(BOOL)multipleFiles +- (void)_resizeWindowByHeightDelta:(NSInteger)delta { - NSUInteger i; + NSUInteger scrollMask = [exportTablelistScrollView autoresizingMask]; + NSUInteger buttonBarMask = [exportTableListButtonBar autoresizingMask]; + NSUInteger tabBarMask = [exportTabBar autoresizingMask]; + NSUInteger buttonMask = [exportAdvancedOptionsViewButton autoresizingMask]; + NSUInteger textFieldMask = [exportAdvancedOptionsViewLabelButton autoresizingMask]; + NSUInteger advancedViewMask = [exportAdvancedOptionsView autoresizingMask]; - NSMutableString *errors = [NSMutableString string]; + NSRect frame = [[self window] frame]; - NSDictionary *tableDetails = nil; - //NSStringEncoding encoding = [[self connection] encoding]; + [exportTablelistScrollView setAutoresizingMask:NSViewNotSizable | NSViewMinYMargin]; + [exportTableListButtonBar setAutoresizingMask:NSViewNotSizable | NSViewMinYMargin]; + [exportTabBar setAutoresizingMask:NSViewNotSizable | NSViewMinYMargin]; + [exportAdvancedOptionsViewButton setAutoresizingMask:NSViewNotSizable | NSViewMinYMargin]; + [exportAdvancedOptionsViewLabelButton setAutoresizingMask:NSViewNotSizable | NSViewMinYMargin]; + [exportAdvancedOptionsView setAutoresizingMask:NSViewNotSizable | NSViewMinYMargin]; - // Reset the interface - [exportProgressTitle setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Exporting %@", @"text showing that the application is importing a supplied format"), @"CSV"]]; - [exportProgressText setStringValue:NSLocalizedString(@"Writing...", @"text showing that app is writing text file")]; - [exportProgressText displayIfNeeded]; - [exportProgressIndicator setDoubleValue:0]; - [exportProgressIndicator displayIfNeeded]; + NSInteger newMinHeight = (windowMinHeigth - heightOffset + delta < windowMinHeigth) ? windowMinHeigth : windowMinHeigth - heightOffset + delta; - // Open the progress sheet - [NSApp beginSheet:exportProgressWindow - modalForWindow:[tableDocumentInstance parentWindow] - modalDelegate:self - didEndSelector:nil - contextInfo:nil]; - - // Add a dump header to the dump file - NSMutableString *csvLineEnd = [NSMutableString stringWithString:[exportCSVLinesTerminatedField stringValue]]; - - [csvLineEnd replaceOccurrencesOfString:@"\\t" withString:@"\t" - options:NSLiteralSearch - range:NSMakeRange(0, [csvLineEnd length])]; - - [csvLineEnd replaceOccurrencesOfString:@"\\n" withString:@"\n" - options:NSLiteralSearch - range:NSMakeRange(0, [csvLineEnd length])]; + [[self window] setMinSize:NSMakeSize(windowMinWidth, newMinHeight)]; - [csvLineEnd replaceOccurrencesOfString:@"\\r" withString:@"\r" - options:NSLiteralSearch - range:NSMakeRange(0, [csvLineEnd length])]; + frame.origin.y += heightOffset; + frame.size.height -= heightOffset; - NSUInteger tableCount = [exportTables count]; + heightOffset = delta; - // If - if ((type == SP_CSV_EXPORT) && (!multipleFiles) && (tableCount > 1)) { - - } + frame.origin.y -= heightOffset; + frame.size.height += heightOffset; - /*if ([exportTables count] > 1) { - [infoString setString:[NSString stringWithFormat:@"Host: %@ Database: %@ Generation Time: %@%@%@", - [tableDocumentInstance host], [tableDocumentInstance database], [NSDate date], csvLineEnd, csvLineEnd]]; - }*/ - - // Loop through the tables - for (i = 0 ; i < tableCount; i++) - { - if ([self exportCancelled]) break; - - // Update the progress text and reset the progress bar to indeterminate status - NSString *tableName = [exportTables objectAtIndex:i]; - - [exportProgressText setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Table %lu of %l (%@): fetching data...", @"text showing that app is fetching data for table dump"), (unsigned long)(i + 1), (unsigned long)tableCount, tableName]]; - [exportProgressText displayIfNeeded]; - - [exportProgressIndicator setIndeterminate:YES]; - [exportProgressIndicator setUsesThreadedAnimation:YES]; - [exportProgressIndicator startAnimation:self]; - - // For CSV exports of more than one table, output the name of the table - /*if (tableCount > 1) { - [fileHandle writeData:[[NSString stringWithFormat:@"Table %@%@%@", tableName, csvLineEnd, csvLineEnd] dataUsingEncoding:encoding]]; - }*/ - - // Determine whether this table is a table or a view via the create table command, and get the table details - MCPResult *queryResult = [connection queryString:[NSString stringWithFormat:@"SHOW CREATE TABLE %@", [tableName backtickQuotedString]]]; - [queryResult setReturnDataAsStrings:YES]; - - if ([queryResult numOfRows]) { - tableDetails = [NSDictionary dictionaryWithDictionary:[queryResult fetchRowAsDictionary]]; - - tableDetails = [NSDictionary dictionaryWithDictionary:([tableDetails objectForKey:@"Create View"]) ? [tableDataInstance informationForView:tableName] : [tableDataInstance informationForTable:tableName]]; - } - - // Retrieve the table details via the data class, and use it to build an array containing column numeric status - NSMutableArray *tableColumnNumericStatus = [NSMutableArray array]; - - for (NSDictionary *column in [tableDetails objectForKey:@"columns"]) - { - NSString *tableColumnTypeGrouping = [column objectForKey:@"typegrouping"]; - - [tableColumnNumericStatus addObject:[NSNumber numberWithBool:([tableColumnTypeGrouping isEqualToString:@"bit"] || - [tableColumnTypeGrouping isEqualToString:@"integer"] || - [tableColumnTypeGrouping isEqualToString:@"float"])]]; - } - - // Use low memory export? - BOOL useLowMemoryBlockingStreaming = ([exportProcessLowMemory state] == NSOnState); - - // Make a streaming request for the data - MCPStreamingResult *queryResultStreaming = [connection streamingQueryString:[NSString stringWithFormat:@"SELECT * FROM %@", [tableName backtickQuotedString]] useLowMemoryBlockingStreaming:useLowMemoryBlockingStreaming]; - - // Note any errors during retrieval - if ([connection queryErrored]) { - [errors appendString:[NSString stringWithFormat:@"%@\n", [connection getLastErrorMessage]]]; - } - - SPExporter *exporter = nil; - SPCSVExporter *csvExporter = nil; - - // Based on the type of export create a new instance of the corresponding exporter and set it's specific options - switch (type) - { - case SP_SQL_EXPORT: - - break; - case SP_CSV_EXPORT: - csvExporter = [[SPCSVExporter alloc] initWithDelegate:self]; - - [csvExporter setCsvOutputFieldNames:[exportCSVIncludeFieldNamesCheck state]]; - [csvExporter setCsvFieldSeparatorString:[exportCSVFieldsTerminatedField stringValue]]; - [csvExporter setCsvEnclosingCharacterString:[exportCSVFieldsWrappedField stringValue]]; - [csvExporter setCsvLineEndingString:[exportCSVLinesTerminatedField stringValue]]; - [csvExporter setCsvEscapeString:[exportCSVFieldsEscapedField stringValue]]; - - [csvExporter setExportOutputEncoding:[MCPConnection encodingForMySQLEncoding:[[tableDocumentInstance connectionEncoding] UTF8String]]]; - [csvExporter setCsvNULLString:[[NSUserDefaults standardUserDefaults] objectForKey:SPNullValue]]; - - [csvExporter setCsvTableColumnNumericStatus:tableColumnNumericStatus]; - - // Assign the data to the exporter - [csvExporter setCsvDataResult:queryResultStreaming]; - - exporter = csvExporter; - - break; - case SP_XML_EXPORT: - - break; - case SP_PDF_EXPORT: - - break; - case SP_HTML_EXPORT: - - break; - case SP_EXCEL_EXPORT: - - break; - } - - // Update the progress text and set the progress bar back to determinate - [exportProgressText setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Table %lu of %lu (%@): Writing...", @"text showing that app is writing data for table export"), (unsigned long)(i + 1), (unsigned long)tableCount, tableName]]; - [exportProgressText displayIfNeeded]; - - [exportProgressIndicator stopAnimation:self]; - [exportProgressIndicator setUsesThreadedAnimation:NO]; - [exportProgressIndicator setIndeterminate:NO]; - [exportProgressIndicator setDoubleValue:0]; - [exportProgressIndicator displayIfNeeded]; - - // Start the actual data conversion process by placing the exporter on the operation queue. - // Note that although it is highly likely there is no guarantee that the operation will executed - // as soon as it's placed on the queue. There may be a delay if the queue is already executing it's - // maximum number of concurrent operations. See the docs for more details. - [operationQueue addOperation:exporter]; - - if (csvExporter) [csvExporter release]; - - // Add a spacer to the file - //[fileHandle writeData:[[NSString stringWithFormat:@"%@%@%@", csvLineEnd, csvLineEnd, csvLineEnd] dataUsingEncoding:encoding]]; - } + [[self window] setFrame:frame display:YES animate:YES]; - return YES; + [exportTablelistScrollView setAutoresizingMask:scrollMask]; + [exportTableListButtonBar setAutoresizingMask:buttonBarMask]; + [exportTabBar setAutoresizingMask:tabBarMask]; + [exportAdvancedOptionsViewButton setAutoresizingMask:buttonMask]; + [exportAdvancedOptionsViewLabelButton setAutoresizingMask:textFieldMask]; + [exportAdvancedOptionsView setAutoresizingMask:advancedViewMask]; } @end |