aboutsummaryrefslogtreecommitdiffstats
path: root/Source/SPExportController.m
diff options
context:
space:
mode:
Diffstat (limited to 'Source/SPExportController.m')
-rw-r--r--Source/SPExportController.m493
1 files changed, 351 insertions, 142 deletions
diff --git a/Source/SPExportController.m b/Source/SPExportController.m
index 5acc40c0..ba6fab79 100644
--- a/Source/SPExportController.m
+++ b/Source/SPExportController.m
@@ -25,17 +25,32 @@
#import "SPExportController.h"
#import "SPCSVExporter.h"
#import "TablesList.h"
+#import "SPTableData.h"
#import "TableDocument.h"
#import "SPArrayAdditions.h"
+#import "SPStringAdditions.h"
+
+@interface SPExportController (PrivateAPI)
+
+- (void)_loadTables;
+- (NSString *)_htmlEscapeString:(NSString *)string;
+- (void)_initializeExportUsingSelectedOptions;
+- (BOOL)_exportTablesAsCSV:(NSArray *)exportTables toFileHandle:(NSFileHandle *)fileHandle usingDataExporter:(SPExporter *)exporter;
+
+@end
@implementation SPExportController
+@synthesize connection;
+@synthesize exportCancelled;
+
/**
* Initializes an instance of SPExportController
*/
- (id)init
{
if ((self = [super init])) {
+ [self setExportCancelled:NO];
tables = [[NSMutableArray alloc] init];
}
@@ -52,7 +67,7 @@
}
#pragma mark -
-#pragma mark Export methods
+#pragma mark IB action methods
/**
* Display the export window allowing the user to select what and of what type to export.
@@ -61,7 +76,7 @@
{
if (!exportWindow) [NSBundle loadNibNamed:@"ExportDialog" owner:self];
- [self loadTables];
+ [self _loadTables];
[exportPathField setStringValue:NSHomeDirectory()];
@@ -73,7 +88,7 @@
}
/**
- * Close the export dialog
+ * Closes the export dialog
*/
- (IBAction)closeSheet:(id)sender
{
@@ -84,145 +99,6 @@
/**
*
*/
-- (IBAction)cancelExport:(id)sender
-{
- // Cancel the export operation here
-}
-
-- (IBAction)changeExportOutputPath:(id)sender
-{
- NSOpenPanel *panel = [NSOpenPanel openPanel];
-
- [panel setCanChooseFiles:NO];
- [panel setCanChooseDirectories:YES];
- [panel setCanCreateDirectories:YES];
-
- [panel beginSheetForDirectory:NSHomeDirectory() file:nil modalForWindow:exportWindow modalDelegate:self didEndSelector:@selector(savePanelDidEnd:returnCode:contextInfo:) contextInfo:nil];
-}
-
-- (void)sheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
-{
- // Perform the export
- if (returnCode == NSOKButton) {
-
- // First determine what type of export the user selected
- SPExportType exportType = 0;
-
- 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 tables) 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]];
- }
- }
-
- break;
- }
-
- // Create the file handle
-
-
- SPExporter *exporter;
- SPCSVExporter *csvExporter;
-
- // Based on the type of export create a new instance of the corresponding exporter and set it's specific options
- switch (exportType)
- {
- case SP_SQL_EXPORT:
-
- break;
- case SP_CSV_EXPORT:
- csvExporter = [[SPCSVExporter alloc] init];
-
- [csvExporter setCsvOutputFieldNames:[exportCSVIncludeFieldNamesCheck state]];
- [csvExporter setCsvFieldSeparatorString:[exportCSVFieldsTerminatedField stringValue]];
- [csvExporter setCsvEnclosingCharacterString:[exportCSVFieldsWrappedField stringValue]];
- [csvExporter setCsvLineEndingString:[exportCSVLinesTerminatedField stringValue]];
- [csvExporter setCsvEscapeString:[exportCSVFieldsEscapedField stringValue]];
-
- [csvExporter setCsvOutputEncoding:[MCPConnection encodingForMySQLEncoding:[[tableDocumentInstance connectionEncoding] UTF8String]]];
- [csvExporter setCsvNULLString:[[NSUserDefaults standardUserDefaults] objectForKey:@"NullValue"]];
-
- exporter = csvExporter;
- break;
- case SP_XML_EXPORT:
-
- break;
- case SP_PDF_EXPORT:
-
- break;
- case SP_HTML_EXPORT:
-
- break;
- case SP_EXCEL_EXPORT:
-
- break;
- }
-
- // Set the exporter's delegate
- [exporter setDelegate:self];
- }
-}
-
-- (void)savePanelDidEnd:(NSSavePanel *)panel returnCode:(int)returnCode contextInfo:(void *)contextInfo
-{
- if (returnCode == NSOKButton) {
- [exportPathField setStringValue:[panel directory]];
- }
-}
-
-#pragma mark -
-#pragma mark Utility methods
-
-- (void)setConnection:(MCPConnection *)theConnection
-{
- mySQLConnection = theConnection;
-}
-
-- (void)loadTables
-{
- NSUInteger i;
-
- [tables removeAllObjects];
-
- MCPResult *queryResult = (MCPResult *)[mySQLConnection listTables];
-
- if ([queryResult numOfRows]) [queryResult dataSeek:0];
-
- for ( i = 0 ; i < [queryResult numOfRows] ; i++ )
- {
- [tables addObject:[NSMutableArray arrayWithObjects:
- [NSNumber numberWithBool:YES],
- NSArrayObjectAtIndex([queryResult fetchRowAsArray], 0),
- nil]];
- }
-
- [exportTableList reloadData];
-}
-
- (IBAction)switchTab:(id)sender
{
if ([sender isKindOfClass:[NSToolbarItem class]]) {
@@ -233,6 +109,9 @@
}
}
+/**
+ *
+ */
- (IBAction)switchInput:(id)sender
{
if ([sender isKindOfClass:[NSMatrix class]]) {
@@ -240,6 +119,28 @@
}
}
+/**
+ *
+ */
+- (IBAction)cancelExport:(id)sender
+{
+ // Cancel the export operation here
+}
+
+/**
+ *
+ */
+- (IBAction)changeExportOutputPath:(id)sender
+{
+ NSOpenPanel *panel = [NSOpenPanel openPanel];
+
+ [panel setCanChooseFiles:NO];
+ [panel setCanChooseDirectories:YES];
+ [panel setCanCreateDirectories:YES];
+
+ [panel beginSheetForDirectory:NSHomeDirectory() file:nil modalForWindow:exportWindow modalDelegate:self didEndSelector:@selector(savePanelDidEnd:returnCode:contextInfo:) contextInfo:nil];
+}
+
#pragma mark -
#pragma mark Table view datasource methods
@@ -294,6 +195,32 @@
#pragma mark -
#pragma mark Other
+/**
+ * Invoked when the user
+ */
+- (void)sheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
+{
+ // Perform the export
+ 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];
+ }
+}
+
+/**
+ * Invoked when the user dismisses the save panel. Updates the selected directory is they clicked OK.
+ */
+- (void)savePanelDidEnd:(NSSavePanel *)panel returnCode:(int)returnCode contextInfo:(void *)contextInfo
+{
+ if (returnCode == NSOKButton) {
+ [exportPathField setStringValue:[panel directory]];
+ }
+}
+
+/**
+ * Dealloc
+ */
- (void)dealloc
{
[tables release], tables = nil;
@@ -302,3 +229,285 @@
}
@end
+
+@implementation SPExportController (PrivateAPI)
+
+/**
+ * Loads all the available database tables in table view.
+ */
+- (void)_loadTables
+{
+ NSUInteger i;
+
+ [tables removeAllObjects];
+
+ MCPResult *queryResult = (MCPResult *)[[self connection] listTables];
+
+ if ([queryResult numOfRows]) [queryResult dataSeek:0];
+
+ for ( i = 0 ; i < [queryResult numOfRows] ; i++ )
+ {
+ [tables addObject:[NSMutableArray arrayWithObjects:
+ [NSNumber numberWithBool:YES],
+ NSArrayObjectAtIndex([queryResult fetchRowAsArray], 0),
+ nil]];
+ }
+
+ [exportTableList reloadData];
+}
+
+/**
+ * Escapes the supplied HTML string
+ */
+- (NSString *)_htmlEscapeString:(NSString *)string
+{
+ NSMutableString *mutableString = [NSMutableString stringWithString:string];
+
+ [mutableString replaceOccurrencesOfString:@"&" withString:@"&amp;"
+ options:NSLiteralSearch
+ range:NSMakeRange(0, [mutableString length])];
+
+ [mutableString replaceOccurrencesOfString:@"<" withString:@"&lt;"
+ options:NSLiteralSearch
+ range:NSMakeRange(0, [mutableString length])];
+
+ [mutableString replaceOccurrencesOfString:@">" withString:@"&gt;"
+ options:NSLiteralSearch
+ range:NSMakeRange(0, [mutableString length])];
+
+ [mutableString replaceOccurrencesOfString:@"\"" withString:@"&quot;"
+ options:NSLiteralSearch
+ range:NSMakeRange(0, [mutableString length])];
+
+ return [NSString stringWithString:mutableString];
+}
+
+/**
+ *
+ */
+- (void)_initializeExportUsingSelectedOptions
+{
+ // First determine what type of export the user selected
+ SPExportType exportType = 0;
+
+ 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 tables) 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]];
+ }
+ }
+
+ break;
+ }
+
+ SPExporter *exporter;
+ SPCSVExporter *csvExporter;
+
+ // Based on the type of export create a new instance of the corresponding exporter and set it's specific options
+ switch (exportType)
+ {
+ case SP_SQL_EXPORT:
+
+ break;
+ case SP_CSV_EXPORT:
+ csvExporter = [[SPCSVExporter alloc] init];
+
+ [csvExporter setCsvFileHandle:[NSFileHandle fileHandleForWritingAtPath:@"/Users/stuart/Desktop/output.csv"]];
+
+ [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:@"NullValue"]];
+
+ exporter = csvExporter;
+ break;
+ case SP_XML_EXPORT:
+
+ break;
+ case SP_PDF_EXPORT:
+
+ break;
+ case SP_HTML_EXPORT:
+
+ break;
+ case SP_EXCEL_EXPORT:
+
+ break;
+ }
+
+ // Set the exporter's delegate
+ [exporter setDelegate:self];
+
+ switch (exportSource)
+ {
+ case SP_FILTERED_EXPORT:
+
+ break;
+ case SP_CUSTOM_QUERY_EXPORT:
+
+ break;
+ case SP_TABLE_EXPORT:
+ [self _exportTablesAsCSV:exportTables toFileHandle:[NSFileHandle fileHandleForWritingAtPath:@"/Users/stuart/Desktop/output.csv"] usingDataExporter:exporter];
+ break;
+ }
+}
+
+/**
+ * Exports the contents' of the supplied array of tables using the supplied exporter and export type. Note that
+ * this method currently only supports exporting in CSV and XML formats.
+ */
+- (BOOL)_exportTablesAsCSV:(NSArray *)exportTables toFileHandle:(NSFileHandle *)fileHandle usingDataExporter:(SPExporter *)exporter
+{
+ NSUInteger tableCount, i, j;
+
+ NSMutableString *errors = [NSMutableString string];
+ NSMutableString *infoString = [NSMutableString string];
+
+ NSDictionary *tableDetails;
+ NSMutableArray *tableColumnNumericStatus;
+ NSStringEncoding encoding = [[self connection] encoding];
+
+ // 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];
+
+ // Open the progress sheet
+ [NSApp beginSheet:exportProgressWindow
+ modalForWindow:tableWindow
+ 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])];
+
+ [csvLineEnd replaceOccurrencesOfString:@"\\r" withString:@"\r"
+ options:NSLiteralSearch
+ range:NSMakeRange(0, [csvLineEnd length])];
+
+ if ([exportTables count] > 1) {
+ [infoString setString:[NSString stringWithFormat:@"Host: %@ Database: %@ Generation Time: %@%@%@",
+ [tableDocumentInstance host], [tableDocumentInstance database], [NSDate date], csvLineEnd, csvLineEnd]];
+ }
+
+ [fileHandle writeData:[infoString dataUsingEncoding:encoding]];
+
+ tableCount = [exportTables count];
+
+ // Loop through the tables
+ for (i = 0 ; i < ((tableCount) && (![self exportCancelled])); i++)
+ {
+ // Update the progress text and reset the progress bar to indeterminate status
+ NSString *tableName = [exportTables objectAtIndex:i];
+
+ [exportProgressText setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Table %i of %i (%@): fetching data...", @"text showing that app is fetching data for table dump"), (i + 1), 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]]];
+
+ 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
+ tableColumnNumericStatus = [NSMutableArray array];
+
+ for (j = 0; j < [[tableDetails objectForKey:@"columns"] count]; j++)
+ {
+ NSString *tableColumnTypeGrouping = [[[tableDetails objectForKey:@"columns"] objectAtIndex:j] objectForKey:@"typegrouping"];
+
+ if ([tableColumnTypeGrouping isEqualToString:@"bit"] ||
+ [tableColumnTypeGrouping isEqualToString:@"integer"] ||
+ [tableColumnTypeGrouping isEqualToString:@"float"])
+ {
+ [tableColumnNumericStatus addObject:[NSNumber numberWithBool:YES]];
+ }
+ else {
+ [tableColumnNumericStatus addObject:[NSNumber numberWithBool:NO]];
+ }
+ }
+
+ // Retrieve all the content within this table
+ queryResult = [connection queryString:[NSString stringWithFormat:@"SELECT * FROM %@", [tableName backtickQuotedString]]];
+
+ // Note any errors during retrieval
+ if (![[connection getLastErrorMessage] isEqualToString:@""]) {
+ [errors appendString:[NSString stringWithFormat:@"%@\n", [connection getLastErrorMessage]]];
+ }
+
+ // Update the progress text and set the progress bar back to determinate
+ [exportProgressText setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Table %d of %d (%@): Writing...", @"text showing that app is writing data for table export"), (i + 1), tableCount, tableName]];
+ [exportProgressText displayIfNeeded];
+
+ [exportProgressIndicator stopAnimation:self];
+ [exportProgressIndicator setUsesThreadedAnimation:NO];
+ [exportProgressIndicator setIndeterminate:NO];
+ [exportProgressIndicator setDoubleValue:0];
+ [exportProgressIndicator displayIfNeeded];
+
+ // Start the actual export process in a separate thread using the supplied exporter instance
+ //[exporter startExportProcess];
+
+ // Add a spacer to the file
+ [fileHandle writeData:[[NSString stringWithFormat:@"%@%@%@", csvLineEnd, csvLineEnd, csvLineEnd] dataUsingEncoding:encoding]];
+ }
+
+ // Close the progress sheet
+ [NSApp endSheet:exportProgressWindow returnCode:0];
+ [exportProgressWindow orderOut:self];
+
+ return YES;
+}
+
+@end