aboutsummaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
Diffstat (limited to 'Source')
-rw-r--r--Source/SPCSVExporterDelegate.h43
-rw-r--r--Source/SPCSVExporterDelegate.m124
-rw-r--r--Source/SPDatabaseStructure.m6
-rw-r--r--Source/SPDotExporterDelegate.h43
-rw-r--r--Source/SPDotExporterDelegate.m78
-rw-r--r--Source/SPExportController+SharedPrivateAPI.h36
-rw-r--r--Source/SPExportController.h62
-rw-r--r--Source/SPExportController.m2697
-rw-r--r--Source/SPExportControllerDelegate.h42
-rw-r--r--Source/SPExportControllerDelegate.m359
-rw-r--r--Source/SPExportFileUtilities.h49
-rw-r--r--Source/SPExportFileUtilities.m372
-rw-r--r--Source/SPExportFilenameUtilities.h51
-rw-r--r--Source/SPExportFilenameUtilities.m332
-rw-r--r--Source/SPExportInitializer.h54
-rw-r--r--Source/SPExportInitializer.m611
-rw-r--r--Source/SPExportInterfaceController.h42
-rw-r--r--Source/SPExportInterfaceController.m150
-rw-r--r--Source/SPExportSettingsPersistence.h64
-rw-r--r--Source/SPExportSettingsPersistence.m803
-rw-r--r--Source/SPFieldMapperController.m2
-rw-r--r--Source/SPHTMLExporterDelegate.h43
-rw-r--r--Source/SPHTMLExporterDelegate.m49
-rw-r--r--Source/SPPDFExporterDelegate.h43
-rw-r--r--Source/SPPDFExporterDelegate.m49
-rw-r--r--Source/SPProcessListController.m66
-rw-r--r--Source/SPProcessListControllerDataSource.h33
-rw-r--r--Source/SPProcessListControllerDataSource.m96
-rw-r--r--Source/SPSQLExporterDelegate.h43
-rw-r--r--Source/SPSQLExporterDelegate.m82
-rw-r--r--Source/SPTableData.m2
-rw-r--r--Source/SPXMLExporterDelegate.h43
-rw-r--r--Source/SPXMLExporterDelegate.m134
33 files changed, 2822 insertions, 3881 deletions
diff --git a/Source/SPCSVExporterDelegate.h b/Source/SPCSVExporterDelegate.h
deleted file mode 100644
index b20d9cfb..00000000
--- a/Source/SPCSVExporterDelegate.h
+++ /dev/null
@@ -1,43 +0,0 @@
-//
-// SPCSVExporterDelegate.h
-// sequel-pro
-//
-// Created by Stuart Connolly (stuconnolly.com) on March 21, 2010.
-// Copyright (c) 2010 Stuart Connolly. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person
-// obtaining a copy of this software and associated documentation
-// files (the "Software"), to deal in the Software without
-// restriction, including without limitation the rights to use,
-// copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following
-// conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-// OTHER DEALINGS IN THE SOFTWARE.
-//
-// More info at <https://github.com/sequelpro/sequelpro>
-
-#import "SPExportController.h"
-#import "SPCSVExporterProtocol.h"
-
-/**
- * @category SPCSVExporterDelegate SPCSVExporterDelegate.h
- *
- * @author Stuart Connolly http://stuconnolly.com/
- *
- * CSV exporter delegate category.
- */
-@interface SPExportController (SPCSVExporterDelegate) <SPCSVExporterProtocol>
-
-@end
diff --git a/Source/SPCSVExporterDelegate.m b/Source/SPCSVExporterDelegate.m
deleted file mode 100644
index 38176776..00000000
--- a/Source/SPCSVExporterDelegate.m
+++ /dev/null
@@ -1,124 +0,0 @@
-//
-// SPCSVExporterDelegate.m
-// sequel-pro
-//
-// Created by Stuart Connolly (stuconnolly.com) on March 21, 2010.
-// Copyright (c) 2010 Stuart Connolly. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person
-// obtaining a copy of this software and associated documentation
-// files (the "Software"), to deal in the Software without
-// restriction, including without limitation the rights to use,
-// copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following
-// conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-// OTHER DEALINGS IN THE SOFTWARE.
-//
-// More info at <https://github.com/sequelpro/sequelpro>
-
-#import "SPCSVExporter.h"
-#import "SPCSVExporterDelegate.h"
-#import "SPExportFile.h"
-#import "SPExportInitializer.h"
-
-@implementation SPExportController (SPCSVExporterDelegate)
-
-- (void)csvExportProcessWillBegin:(SPCSVExporter *)exporter
-{
- [exportProgressText displayIfNeeded];
-
- [exportProgressIndicator setIndeterminate:YES];
- [exportProgressIndicator setUsesThreadedAnimation:YES];
- [exportProgressIndicator startAnimation:self];
-
- // Only update the progress text if this is a table export
- if (exportSource == SPTableExport) {
- // Update the current table export index
- currentTableExportIndex = (exportTableCount - [exporters count]);
-
- [exportProgressText setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Table %lu of %lu (%@): Fetching data...", @"export label showing that the app is fetching data for a specific table"), currentTableExportIndex, exportTableCount, [exporter csvTableName]]];
- }
- else {
- [exportProgressText setStringValue:NSLocalizedString(@"Fetching data...", @"export label showing that the app is fetching data")];
- }
-
- [exportProgressText displayIfNeeded];
-}
-
-- (void)csvExportProcessComplete:(SPCSVExporter *)exporter
-{
- NSUInteger exportCount = [exporters count];
-
- // If required add the next exporter to the operation queue
- if ((exportCount > 0) && (exportSource == SPTableExport)) {
-
- // If we're only exporting to a single file then write a header for the next table
- if (!exportToMultipleFiles) {
-
- // If we're exporting multiple tables to a single file then append some space and the next table's
- // name, but only if there is at least 2 exportes left.
- [[exporter exportOutputFile] writeData:[[NSString stringWithFormat:@"%@%@%@ %@%@%@",
- [exporter csvLineEndingString],
- [exporter csvLineEndingString],
- NSLocalizedString(@"Table", @"csv export table heading"),
- [(SPCSVExporter *)[exporters objectAtIndex:0] csvTableName],
- [exporter csvLineEndingString],
- [exporter csvLineEndingString]] dataUsingEncoding:[exporter exportOutputEncoding]]];
- }
- // Otherwise close the file handle of the exporter that just finished
- // ensuring it's data is written to disk.
- else {
- [[exporter exportOutputFile] close];
- }
-
- [operationQueue addOperation:[exporters objectAtIndex:0]];
-
- // Remove the exporter we just added to the operation queue from our list of exporters
- // so we know it's already been done.
- [exporters removeObjectAtIndex:0];
- }
- // Otherwise if the exporter list is empty, close the progress sheet
- else {
- // Close the last exporter's file handle
- [[exporter exportOutputFile] close];
-
- [self exportEnded];
- }
-}
-
-- (void)csvExportProcessWillBeginWritingData:(SPCSVExporter *)exporter
-{
- // Only update the progress text if this is a table export
- if (exportSource == SPTableExport) {
- [exportProgressText setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Table %lu of %lu (%@): Writing data...", @"export label showing app if writing data for a specific table"), currentTableExportIndex, exportTableCount, [exporter csvTableName]]];
- }
- else {
- [exportProgressText setStringValue:NSLocalizedString(@"Writing data...", @"export label showing app is writing data")];
- }
-
- [exportProgressText displayIfNeeded];
-
- [exportProgressIndicator stopAnimation:self];
- [exportProgressIndicator setUsesThreadedAnimation:NO];
- [exportProgressIndicator setIndeterminate:NO];
- [exportProgressIndicator setDoubleValue:0];
-}
-
-- (void)csvExportProcessProgressUpdated:(SPCSVExporter *)exporter
-{
- [exportProgressIndicator setDoubleValue:[exporter exportProgressValue]];
-}
-
-@end
diff --git a/Source/SPDatabaseStructure.m b/Source/SPDatabaseStructure.m
index 477b3986..9289b13b 100644
--- a/Source/SPDatabaseStructure.m
+++ b/Source/SPDatabaseStructure.m
@@ -36,7 +36,7 @@
#import <pthread.h>
-@interface SPDatabaseStructure (Private_API)
+@interface SPDatabaseStructure ()
- (void)_destroy:(NSNotification *)notification;
@@ -469,13 +469,9 @@ cleanup_thread_and_pool:
[super dealloc];
}
-@end
-
#pragma mark -
#pragma mark Private API
-@implementation SPDatabaseStructure (Private_API)
-
/**
* Ensure that processing is completed.
*/
diff --git a/Source/SPDotExporterDelegate.h b/Source/SPDotExporterDelegate.h
deleted file mode 100644
index 497ac2b2..00000000
--- a/Source/SPDotExporterDelegate.h
+++ /dev/null
@@ -1,43 +0,0 @@
-//
-// SPDotExporterDelegate.h
-// sequel-pro
-//
-// Created by Stuart Connolly (stuconnolly.com) on April 17, 2010.
-// Copyright (c) 2010 Stuart Connolly. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person
-// obtaining a copy of this software and associated documentation
-// files (the "Software"), to deal in the Software without
-// restriction, including without limitation the rights to use,
-// copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following
-// conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-// OTHER DEALINGS IN THE SOFTWARE.
-//
-// More info at <https://github.com/sequelpro/sequelpro>
-
-#import "SPExportController.h"
-#import "SPDotExporterProtocol.h"
-
-/**
- * @category SPDotExporterDelegate SPDotExporterDelegate.h
- *
- * @author Stuart Connolly http://stuconnolly.com/
- *
- * Dot exporter delegate category.
- */
-@interface SPExportController (SPDotExporterDelegate) <SPDotExporterProtocol>
-
-@end
diff --git a/Source/SPDotExporterDelegate.m b/Source/SPDotExporterDelegate.m
deleted file mode 100644
index 47054a1e..00000000
--- a/Source/SPDotExporterDelegate.m
+++ /dev/null
@@ -1,78 +0,0 @@
-//
-// SPDotExporterDelegate.m
-// sequel-pro
-//
-// Created by Stuart Connolly (stuconnolly.com) on April 17, 2010.
-// Copyright (c) 2010 Stuart Connolly. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person
-// obtaining a copy of this software and associated documentation
-// files (the "Software"), to deal in the Software without
-// restriction, including without limitation the rights to use,
-// copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following
-// conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-// OTHER DEALINGS IN THE SOFTWARE.
-//
-// More info at <https://github.com/sequelpro/sequelpro>
-
-#import "SPDotExporterDelegate.h"
-#import "SPDotExporter.h"
-#import "SPExportInitializer.h"
-
-@implementation SPExportController (SPDotExporterDelegate)
-
-- (void)dotExportProcessWillBegin:(SPDotExporter *)exporter
-{
- [exportProgressTitle setStringValue:NSLocalizedString(@"Exporting Dot File", @"text showing that the application is exporting a Dot file")];
- [exportProgressText setStringValue:NSLocalizedString(@"Dumping...", @"text showing that app is writing dump")];
-
- [exportProgressTitle displayIfNeeded];
- [exportProgressText displayIfNeeded];
- [exportProgressIndicator stopAnimation:self];
- [exportProgressIndicator setIndeterminate:NO];
-}
-
-- (void)dotExportProcessComplete:(SPDotExporter *)exporter
-{
- [self exportEnded];
-}
-
-- (void)dotExportProcessProgressUpdated:(SPDotExporter *)exporter
-{
- [exportProgressIndicator setDoubleValue:[exporter exportProgressValue]];
-}
-
-- (void)dotExportProcessWillBeginFetchingData:(SPDotExporter *)exporter forTableWithIndex:(NSUInteger)tableIndex
-{
- // Update the current table export index
- currentTableExportIndex = tableIndex;
-
- [exportProgressText setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Table %lu of %lu (%@): Fetching data...", @"export label showing that the app is fetching data for a specific table"), currentTableExportIndex, exportTableCount, [exporter dotExportCurrentTable]]];
-
- [exportProgressText displayIfNeeded];
-}
-
-- (void)dotExportProcessWillBeginFetchingRelationsData:(SPDotExporter *)exporter
-{
- [exportProgressText setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Table %lu of %lu (%@): Fetching relations data...", @"export label showing app is fetching relations data for a specific table"), currentTableExportIndex, exportTableCount, [exporter dotExportCurrentTable]]];
-
- [exportProgressText displayIfNeeded];
- [exportProgressIndicator setIndeterminate:YES];
- [exportProgressIndicator setUsesThreadedAnimation:YES];
- [exportProgressIndicator startAnimation:self];
-}
-
-@end
diff --git a/Source/SPExportController+SharedPrivateAPI.h b/Source/SPExportController+SharedPrivateAPI.h
deleted file mode 100644
index d8382824..00000000
--- a/Source/SPExportController+SharedPrivateAPI.h
+++ /dev/null
@@ -1,36 +0,0 @@
-//
-// SPExportController+SharedPrivateAPI.h
-// sequel-pro
-//
-// Created by Max Lohrmann on 03.02.15.
-// Copyright (c) 2015 Max Lohrmann. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person
-// obtaining a copy of this software and associated documentation
-// files (the "Software"), to deal in the Software without
-// restriction, including without limitation the rights to use,
-// copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following
-// conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-// OTHER DEALINGS IN THE SOFTWARE.
-//
-// More info at <https://github.com/sequelpro/sequelpro>
-
-#import "SPExportController.h"
-
-@interface SPExportController (SharedPrivateAPI)
-- (void)sheetDidEnd:(NSWindow *)sheet returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo;
-- (void)_hideExportProgress;
-@end
diff --git a/Source/SPExportController.h b/Source/SPExportController.h
index bef547d8..5eb15a9f 100644
--- a/Source/SPExportController.h
+++ b/Source/SPExportController.h
@@ -35,6 +35,9 @@
@class SPTableData;
@class SPMySQLConnection;
@class SPServerSupport;
+@class SPCSVExporter;
+@class SPXMLExporter;
+@class SPExportFile;
/**
* @class SPExportController SPExportController.h
@@ -284,4 +287,63 @@
- (IBAction)toggleSQLIncludeDropSyntax:(NSButton *)sender;
- (IBAction)toggleNewFilePerTable:(NSButton *)sender;
+#pragma mark - SPExportInitializer
+
+- (void)startExport;
+- (void)exportEnded;
+- (void)initializeExportUsingSelectedOptions;
+
+- (void)exportTables:(NSArray *)exportTables orDataArray:(NSArray *)dataArray;
+
+- (SPCSVExporter *)initializeCSVExporterForTable:(NSString *)table orDataArray:(NSArray *)dataArray;
+- (SPXMLExporter *)initializeXMLExporterForTable:(NSString *)table orDataArray:(NSArray *)dataArray;
+
+#pragma mark - SPExportFileUtilities
+
+- (void)writeCSVHeaderToExportFile:(SPExportFile *)file;
+- (void)writeXMLHeaderToExportFile:(SPExportFile *)file;
+
+- (void)errorCreatingExportFileHandles:(NSArray *)files;
+
+#pragma mark - SPExportFilenameUtilities
+
+- (void)updateDisplayedExportFilename;
+- (void)updateAvailableExportFilenameTokens;
+- (NSArray *)currentAllowedExportFilenameTokens;
+- (NSString *)generateDefaultExportFilename;
+- (NSString *)currentDefaultExportFileExtension;
+- (NSString *)expandCustomFilenameFormatUsingTableName:(NSString *)table;
+- (NSString *)customFilenamePathExtension;
+- (BOOL)isTableTokenAllowed;
+
+#pragma mark - SPExportSettingsPersistence
+
+- (IBAction)exportCurrentSettings:(id)sender;
+- (IBAction)importCurrentSettings:(id)sender;
+
+/**
+ * @return The current settings as a dictionary which can be serialized
+ */
+- (NSDictionary *)currentSettingsAsDictionary;
+
+/** Overwrite current export settings with those defined in dict
+ * @param dict The new settings to apply (passing nil is an error.)
+ * @param err Errors while applying (will mostly be about invalid format, type)
+ * Can pass NULL, if not interested in details.
+ * Will NOT be changed unless the method also returns NO
+ * @return success
+ */
+- (BOOL)applySettingsFromDictionary:(NSDictionary *)dict error:(NSError **)err;
+
+/**
+ * @return A serialized form of the "custom filename" field
+ */
+- (NSArray *)currentCustomFilenameAsArray;
+
+/**
+ * @param tokenList A serialized form of the "custom filename" field
+ * @see currentCustomFilenameAsArray
+ */
+- (void)setCustomFilenameFromArray:(NSArray *)tokenList;
+
@end
diff --git a/Source/SPExportController.m b/Source/SPExportController.m
index 28e29dac..c6e82baa 100644
--- a/Source/SPExportController.m
+++ b/Source/SPExportController.m
@@ -29,20 +29,28 @@
// More info at <https://github.com/sequelpro/sequelpro>
#import "SPExportController.h"
-#import "SPExportInitializer.h"
#import "SPTablesList.h"
#import "SPTableData.h"
#import "SPTableContent.h"
#import "SPGrowlController.h"
#import "SPExportFile.h"
#import "SPAlertSheets.h"
-#import "SPExportFilenameUtilities.h"
#import "SPExportFileNameTokenObject.h"
#import "SPDatabaseDocument.h"
#import "SPThreadAdditions.h"
#import "SPCustomQuery.h"
-#import "SPExportController+SharedPrivateAPI.h"
-#import "SPExportSettingsPersistence.h"
+#import "SPCSVExporter.h"
+#import "SPSQLExporter.h"
+#import "SPXMLExporter.h"
+#import "SPDotExporter.h"
+#import "SPConnectionControllerDelegateProtocol.h"
+#import "SPExporter.h"
+#import "SPCSVExporterProtocol.h"
+#import "SPSQLExporterProtocol.h"
+#import "SPXMLExporterProtocol.h"
+#import "SPDotExporterProtocol.h"
+#import "SPPDFExporterProtocol.h"
+#import "SPHTMLExporterProtocol.h"
#import <SPMySQL/SPMySQL.h>
@@ -57,7 +65,29 @@ static const NSString *SPSQLExportStructureEnabled = @"SQLExportStructureEnable
static const NSString *SPSQLExportContentEnabled = @"SQLExportContentEnabled";
static const NSString *SPSQLExportDropEnabled = @"SQLExportDropEnabled";
-@interface SPExportController (PrivateAPI)
+typedef enum
+{
+ SPExportErrorCancelExport = 0,
+ SPExportErrorReplaceFiles = 1,
+ SPExportErrorSkipErrorFiles = 2
+}
+SPExportErrorChoice;
+
+static inline BOOL IS_TOKEN(id x);
+static inline BOOL IS_STRING(id x);
+
+/**
+ * converts a ([obj state] == NSOnState) to @YES / @NO
+ * (because doing @([obj state] == NSOnState) will result in an integer 0/1)
+ */
+static inline NSNumber *IsOn(id obj);
+
+/**
+ * Sets the state of obj to NSOnState or NSOffState based on the value of ref
+ */
+static inline void SetOnOff(NSNumber *ref,id obj);
+
+@interface SPExportController () <SPCSVExporterProtocol, SPSQLExporterProtocol, SPXMLExporterProtocol, SPDotExporterProtocol, SPPDFExporterProtocol, SPHTMLExporterProtocol>
- (void)_switchTab;
- (void)_checkForDatabaseChanges;
@@ -75,6 +105,61 @@ static const NSString *SPSQLExportDropEnabled = @"SQLExportDropEnabled";
- (void)_waitUntilQueueIsEmptyAfterCancelling:(id)sender;
- (void)_queueIsEmptyAfterCancelling:(id)sender;
+#pragma mark - SPExportFileUtilitiesPrivateAPI
+
+- (void)_reopenExportSheet;
+
+#pragma mark - SPExportControllerDelegate
+
+- (NSArray *)_updateTokensForMixedContent:(NSArray *)tokens;
+- (void)_tokenizeCustomFilenameTokenField;
+
+#pragma mark - SPExportSettingsPersistence
+
+// those methods will convert the name of a C enum constant to a NSString
++ (NSString *)describeExportSource:(SPExportSource)es;
++ (NSString *)describeExportType:(SPExportType)et;
++ (NSString *)describeCompressionFormat:(SPFileCompressionFormat)cf;
++ (NSString *)describeXMLExportFormat:(SPXMLExportFormat)xf;
++ (NSString *)describeSQLExportInsertDivider:(SPSQLExportInsertDivider)eid;
+
+// these will store the C enum constant named by NSString in dst and return YES,
+// if a valid mapping exists. Otherwise will just return NO and not modify dst.
++ (BOOL)copyExportSourceForDescription:(NSString *)esd to:(SPExportSource *)dst;
++ (BOOL)copyCompressionFormatForDescription:(NSString *)esd to:(SPFileCompressionFormat *)dst;
++ (BOOL)copyExportTypeForDescription:(NSString *)esd to:(SPExportType *)dst;
++ (BOOL)copyXMLExportFormatForDescription:(NSString *)xfd to:(SPXMLExportFormat *)dst;
++ (BOOL)copySQLExportInsertDividerForDescription:(NSString *)xfd to:(SPSQLExportInsertDivider *)dst;
+
+- (NSDictionary *)exporterSettings;
+- (NSDictionary *)csvSettings;
+- (NSDictionary *)dotSettings;
+- (NSDictionary *)xmlSettings;
+- (NSDictionary *)sqlSettings;
+
+- (void)applyExporterSettings:(NSDictionary *)settings;
+- (void)applyCsvSettings:(NSDictionary *)settings;
+- (void)applyDotSettings:(NSDictionary *)settings;
+- (void)applyXmlSettings:(NSDictionary *)settings;
+- (void)applySqlSettings:(NSDictionary *)settings;
+
+- (id)exporterSpecificSettingsForSchemaObject:(NSString *)name ofType:(SPTableType)type;
+- (id)dotSpecificSettingsForSchemaObject:(NSString *)name ofType:(SPTableType)type;
+- (id)xmlSpecificSettingsForSchemaObject:(NSString *)name ofType:(SPTableType)type;
+- (id)csvSpecificSettingsForSchemaObject:(NSString *)name ofType:(SPTableType)type;
+- (id)sqlSpecificSettingsForSchemaObject:(NSString *)name ofType:(SPTableType)type;
+
+- (void)applyExporterSpecificSettings:(id)settings forSchemaObject:(NSString *)name ofType:(SPTableType)type;
+- (void)applyDotSpecificSettings:(id)settings forSchemaObject:(NSString *)name ofType:(SPTableType)type;
+- (void)applyXmlSpecificSettings:(id)settings forSchemaObject:(NSString *)name ofType:(SPTableType)type;
+- (void)applyCsvSpecificSettings:(id)settings forSchemaObject:(NSString *)name ofType:(SPTableType)type;
+- (void)applySqlSpecificSettings:(id)settings forSchemaObject:(NSString *)name ofType:(SPTableType)type;
+
+#pragma mark - Shared Private
+
+- (void)sheetDidEnd:(NSWindow *)sheet returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo;
+- (void)_hideExportProgress;
+
@end
@implementation SPExportController
@@ -1073,6 +1158,2586 @@ set_input:
[exportButton setEnabled:[enable boolValue]];
}
+
+#pragma mark - SPExportInitializer
+
+/**
+ * Starts the export process by placing the first exporter on the operation queue. Also opens the progress
+ * sheet if it's not already visible.
+ */
+- (void)startExport
+{
+ // Start progress indicator
+ [exportProgressTitle setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Exporting %@", @"text showing that the application is importing a supplied format"), exportTypeLabel]];
+ [exportProgressText setStringValue:NSLocalizedString(@"Writing...", @"text showing that app is writing text file")];
+
+ [exportProgressIndicator setUsesThreadedAnimation:NO];
+ [exportProgressIndicator setIndeterminate:NO];
+ [exportProgressIndicator setDoubleValue:0];
+
+ // If it's not already displayed, open the progress sheet
+ if (![exportProgressWindow isVisible]) {
+ [NSApp beginSheet:exportProgressWindow
+ modalForWindow:[tableDocumentInstance parentWindow]
+ modalDelegate:self
+ didEndSelector:nil
+ contextInfo:nil];
+ }
+
+ // cache the current connection encoding so the exporter can do what it wants.
+ previousConnectionEncoding = [[NSString alloc] initWithString:[connection encoding]];
+ previousConnectionEncodingViaLatin1 = [connection encodingUsesLatin1Transport];
+
+ // Add the first exporter to the operation queue
+ [operationQueue addOperation:[exporters objectAtIndex:0]];
+
+ // Remove the exporter we just added to the operation queue from our list of exporters
+ // so we know it's already been done.
+ [exporters removeObjectAtIndex:0];
+}
+
+/**
+ * @see _queueIsEmptyAfterCancelling:
+ */
+- (void)exportEnded
+{
+ [self _hideExportProgress];
+
+ // Restore query mode
+ [tableDocumentInstance setQueryMode:SPInterfaceQueryMode];
+
+ // Display Growl notification
+ [self displayExportFinishedGrowlNotification];
+
+ // Restore the connection encoding to it's pre-export value
+ [tableDocumentInstance setConnectionEncoding:[NSString stringWithFormat:@"%@%@", previousConnectionEncoding, (previousConnectionEncodingViaLatin1) ? @"-" : @""] reloadingViews:NO];
+}
+
+/**
+ * Initializes the export process by analysing the selected criteria.
+ */
+- (void)initializeExportUsingSelectedOptions
+{
+ NSArray *dataArray = nil;
+
+ // Get rid of the cached connection encoding
+ if (previousConnectionEncoding) SPClear(previousConnectionEncoding);
+
+ createCustomFilename = ([[exportCustomFilenameTokenField stringValue] length] > 0);
+
+ NSMutableArray *exportTables = [NSMutableArray array];
+
+ // Set whether or not we are to export to multiple files
+ [self setExportToMultipleFiles:[exportFilePerTableCheck state]];
+
+ // Get the data depending on the source
+ switch (exportSource)
+ {
+ case SPFilteredExport:
+ dataArray = [tableContentInstance currentDataResultWithNULLs:YES hideBLOBs:NO];
+ break;
+ case SPQueryExport:
+ dataArray = [customQueryInstance currentDataResultWithNULLs:YES truncateDataFields:NO];
+ break;
+ case SPTableExport:
+ // Create an array of tables to export
+ for (NSMutableArray *table in tables)
+ {
+ if (exportType == SPSQLExport) {
+ if ([[table objectAtIndex:1] boolValue] || [[table objectAtIndex:2] boolValue] || [[table objectAtIndex:3] boolValue]) {
+
+ // Check the overall export settings
+ if ([[table objectAtIndex:1] boolValue] && (![exportSQLIncludeStructureCheck state])) {
+ [table replaceObjectAtIndex:1 withObject:@NO];
+ }
+
+ if ([[table objectAtIndex:2] boolValue] && (![exportSQLIncludeContentCheck state])) {
+ [table replaceObjectAtIndex:2 withObject:@NO];
+ }
+
+ if ([[table objectAtIndex:3] boolValue] && (![exportSQLIncludeDropSyntaxCheck state])) {
+ [table replaceObjectAtIndex:3 withObject:@NO];
+ }
+
+ [exportTables addObject:table];
+ }
+ }
+ else if (exportType == SPDotExport) {
+ [exportTables addObject:[table objectAtIndex:0]];
+ }
+ else {
+ if ([[table objectAtIndex:2] boolValue]) {
+ [exportTables addObject:[table objectAtIndex:0]];
+ }
+ }
+ }
+
+ break;
+ }
+
+ // Set the export type label
+ switch (exportType)
+ {
+ case SPSQLExport:
+ exportTypeLabel = @"SQL";
+ break;
+ case SPCSVExport:
+ exportTypeLabel = @"CSV";
+ break;
+ case SPXMLExport:
+ exportTypeLabel = @"XML";
+ break;
+ case SPDotExport:
+ exportTypeLabel = @"Dot";
+ break;
+ case SPPDFExport:
+ case SPHTMLExport:
+ case SPExcelExport:
+ default:
+ [NSException raise:NSInvalidArgumentException format:@"unsupported exportType=%lu",exportType];
+ return;
+ }
+
+ // Begin the export based on the source
+ switch (exportSource)
+ {
+ case SPFilteredExport:
+ case SPQueryExport:
+ [self exportTables:nil orDataArray:dataArray];
+ break;
+ case SPTableExport:
+ [self exportTables:exportTables orDataArray:nil];
+ break;
+ }
+}
+
+/**
+ * Exports the contents of the supplied array of tables or data array.
+ *
+ * Note that at least one of these parameters must not be nil.
+ *
+ * @param exportTables An array of table/view names to be exported (can be nil).
+ * @param dataArray A MySQL result set array to be exported (can be nil).
+ */
+- (void)exportTables:(NSArray *)exportTables orDataArray:(NSArray *)dataArray
+{
+ BOOL singleFileHandleSet = NO;
+ SPExportFile *singleExportFile = nil, *file = nil;
+
+ // Change query logging mode
+ [tableDocumentInstance setQueryMode:SPImportExportQueryMode];
+
+ // Start the notification timer to allow notifications to be shown even if frontmost for long queries
+ [[SPGrowlController sharedGrowlController] setVisibilityForNotificationName:@"Export Finished"];
+
+ // Setup the progress sheet
+ [exportProgressTitle setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Exporting %@", @"text showing that the application is importing a supplied format"), exportTypeLabel]];
+ [exportProgressText setStringValue:NSLocalizedString(@"Initializing...", @"initializing export label")];
+
+ [exportProgressIndicator setIndeterminate:YES];
+ [exportProgressIndicator setUsesThreadedAnimation:YES];
+
+ // Open the progress sheet
+ [NSApp beginSheet:exportProgressWindow
+ modalForWindow:[tableDocumentInstance parentWindow]
+ modalDelegate:self
+ didEndSelector:nil
+ contextInfo:nil];
+
+ // CSV export
+ if (exportType == SPCSVExport) {
+
+ SPCSVExporter *csvExporter = nil;
+
+ // If the user has selected to only export to a single file or this is a filtered or custom query
+ // export, create the single file now and assign it to all subsequently created exporters.
+ if ((![self exportToMultipleFiles]) || (exportSource == SPFilteredExport) || (exportSource == SPQueryExport)) {
+ NSString *selectedTableName = nil;
+
+ if (exportSource == SPTableExport && [exportTables count] == 1) selectedTableName = [exportTables objectAtIndex:0];
+
+ [exportFilename setString:createCustomFilename ? [self expandCustomFilenameFormatUsingTableName:selectedTableName] : [self generateDefaultExportFilename]];
+
+ // Only append the extension if necessary
+ if (![[exportFilename pathExtension] length]) {
+ [exportFilename setString:[exportFilename stringByAppendingPathExtension:[self currentDefaultExportFileExtension]]];
+ }
+
+ singleExportFile = [SPExportFile exportFileAtPath:[[exportPathField stringValue] stringByAppendingPathComponent:exportFilename]];
+ }
+
+ // Start the export process depending on the data source
+ if (exportSource == SPTableExport) {
+
+ // Cache the number of tables being exported
+ exportTableCount = [exportTables count];
+
+ // Loop through the tables, creating an exporter for each
+ for (NSString *table in exportTables)
+ {
+ csvExporter = [self initializeCSVExporterForTable:table orDataArray:nil];
+
+ // If required create a single file handle for all CSV exports
+ if (![self exportToMultipleFiles]) {
+ if (!singleFileHandleSet) {
+ [singleExportFile setExportFileNeedsCSVHeader:YES];
+
+ [exportFiles addObject:singleExportFile];
+
+ singleFileHandleSet = YES;
+ }
+
+ [csvExporter setExportOutputFile:singleExportFile];
+ }
+
+ [exporters addObject:csvExporter];
+ }
+ }
+ else {
+ csvExporter = [self initializeCSVExporterForTable:nil orDataArray:dataArray];
+
+ [exportFiles addObject:singleExportFile];
+
+ [csvExporter setExportOutputFile:singleExportFile];
+
+ [exporters addObject:csvExporter];
+ }
+ }
+ // SQL export
+ else if (exportType == SPSQLExport) {
+
+ // Cache the number of tables being exported
+ exportTableCount = [exportTables count];
+
+ SPSQLExporter *sqlExporter = [[SPSQLExporter alloc] initWithDelegate:self];
+
+ [sqlExporter setSqlDatabaseHost:[tableDocumentInstance host]];
+ [sqlExporter setSqlDatabaseName:[tableDocumentInstance database]];
+ [sqlExporter setSqlDatabaseVersion:[tableDocumentInstance mySQLVersion]];
+
+ [sqlExporter setSqlOutputIncludeUTF8BOM:[exportUseUTF8BOMButton state]];
+ [sqlExporter setSqlOutputEncodeBLOBasHex:[exportSQLBLOBFieldsAsHexCheck state]];
+ [sqlExporter setSqlOutputIncludeErrors:[exportSQLIncludeErrorsCheck state]];
+ [sqlExporter setSqlOutputIncludeAutoIncrement:([exportSQLIncludeStructureCheck state] && [exportSQLIncludeAutoIncrementValueButton state])];
+
+ [sqlExporter setSqlInsertAfterNValue:[exportSQLInsertNValueTextField integerValue]];
+ [sqlExporter setSqlInsertDivider:[exportSQLInsertDividerPopUpButton indexOfSelectedItem]];
+
+ [sqlExporter setSqlExportTables:exportTables];
+
+ // Create custom filename if required
+ NSString *selectedTableName = (exportSource == SPTableExport && [exportTables count] == 1)? [[exportTables objectAtIndex:0] objectAtIndex:0] : nil;
+ [exportFilename setString:(createCustomFilename) ? [self expandCustomFilenameFormatUsingTableName:selectedTableName] : [self generateDefaultExportFilename]];
+
+ // Only append the extension if necessary
+ if (![[exportFilename pathExtension] length]) {
+ [exportFilename setString:[exportFilename stringByAppendingPathExtension:[self currentDefaultExportFileExtension]]];
+ }
+
+ file = [SPExportFile exportFileAtPath:[[exportPathField stringValue] stringByAppendingPathComponent:exportFilename]];
+
+ [exportFiles addObject:file];
+
+ [sqlExporter setExportOutputFile:file];
+
+ [exporters addObject:sqlExporter];
+
+ [sqlExporter release];
+ }
+ // XML export
+ else if (exportType == SPXMLExport) {
+
+ SPXMLExporter *xmlExporter = nil;
+
+ // If the user has selected to only export to a single file or this is a filtered or custom query
+ // export, create the single file now and assign it to all subsequently created exporters.
+ if ((![self exportToMultipleFiles]) || (exportSource == SPFilteredExport) || (exportSource == SPQueryExport)) {
+ NSString *selectedTableName = nil;
+ if (exportSource == SPTableExport && [exportTables count] == 1) selectedTableName = [exportTables objectAtIndex:0];
+
+ [exportFilename setString:(createCustomFilename) ? [self expandCustomFilenameFormatUsingTableName:selectedTableName] : [self generateDefaultExportFilename]];
+
+ // Only append the extension if necessary
+ if (![[exportFilename pathExtension] length]) {
+ [exportFilename setString:[exportFilename stringByAppendingPathExtension:[self currentDefaultExportFileExtension]]];
+ }
+
+ singleExportFile = [SPExportFile exportFileAtPath:[[exportPathField stringValue] stringByAppendingPathComponent:exportFilename]];
+ }
+
+ // Start the export process depending on the data source
+ if (exportSource == SPTableExport) {
+
+ // Cache the number of tables being exported
+ exportTableCount = [exportTables count];
+
+ // Loop through the tables, creating an exporter for each
+ for (NSString *table in exportTables)
+ {
+ xmlExporter = [self initializeXMLExporterForTable:table orDataArray:nil];
+
+ // If required create a single file handle for all XML exports
+ if (![self exportToMultipleFiles]) {
+ if (!singleFileHandleSet) {
+ [singleExportFile setExportFileNeedsXMLHeader:YES];
+
+ [exportFiles addObject:singleExportFile];
+
+ singleFileHandleSet = YES;
+ }
+
+ [xmlExporter setExportOutputFile:singleExportFile];
+ }
+
+ [exporters addObject:xmlExporter];
+ }
+ }
+ else {
+ xmlExporter = [self initializeXMLExporterForTable:nil orDataArray:dataArray];
+
+ [singleExportFile setExportFileNeedsXMLHeader:YES];
+
+ [exportFiles addObject:singleExportFile];
+
+ [xmlExporter setExportOutputFile:singleExportFile];
+
+ [exporters addObject:xmlExporter];
+ }
+ }
+ // Dot export
+ else if (exportType == SPDotExport) {
+
+ // Cache the number of tables being exported
+ exportTableCount = [exportTables count];
+
+ SPDotExporter *dotExporter = [[SPDotExporter alloc] initWithDelegate:self];
+
+ [dotExporter setDotTableData:tableDataInstance];
+ [dotExporter setDotForceLowerTableNames:[exportDotForceLowerTableNamesCheck state]];
+ [dotExporter setDotDatabaseHost:[tableDocumentInstance host]];
+ [dotExporter setDotDatabaseName:[tableDocumentInstance database]];
+ [dotExporter setDotDatabaseVersion:[tableDocumentInstance mySQLVersion]];
+
+ [dotExporter setDotExportTables:exportTables];
+
+ // Create custom filename if required
+ if (createCustomFilename) {
+ [exportFilename setString:[self expandCustomFilenameFormatUsingTableName:nil]];
+ }
+ else {
+ [exportFilename setString:[tableDocumentInstance database]];
+ }
+
+ // Only append the extension if necessary
+ if (![[exportFilename pathExtension] length]) {
+ [exportFilename setString:[exportFilename stringByAppendingPathExtension:[self currentDefaultExportFileExtension]]];
+ }
+
+ file = [SPExportFile exportFileAtPath:[[exportPathField stringValue] stringByAppendingPathComponent:exportFilename]];
+
+ [exportFiles addObject:file];
+
+ [dotExporter setExportOutputFile:file];
+
+ [exporters addObject:dotExporter];
+
+ [dotExporter release];
+ }
+
+ // For each of the created exporters, set their generic properties
+ for (SPExporter *exporter in exporters)
+ {
+ [exporter setConnection:connection];
+ [exporter setServerSupport:[self serverSupport]];
+ [exporter setExportOutputEncoding:[connection stringEncoding]];
+ [exporter setExportMaxProgress:(NSInteger)[exportProgressIndicator bounds].size.width];
+ [exporter setExportUsingLowMemoryBlockingStreaming:([exportProcessLowMemoryButton state] == NSOnState)];
+ [exporter setExportOutputCompressionFormat:(SPFileCompressionFormat)[exportOutputCompressionFormatPopupButton indexOfSelectedItem]];
+ [exporter setExportOutputCompressFile:([exportOutputCompressionFormatPopupButton indexOfSelectedItem] != SPNoCompression)];
+ }
+
+ NSMutableArray *problemFiles = [[NSMutableArray alloc] init];
+
+ // Create the actual file handles while dealing with errors (e.g. file already exists, etc) during creation
+ for (SPExportFile *exportFile in exportFiles)
+ {
+ if ([exportFile createExportFileHandle:NO] == SPExportFileHandleCreated) {
+
+ [exportFile setCompressionFormat:(SPFileCompressionFormat)[exportOutputCompressionFormatPopupButton indexOfSelectedItem]];
+
+ if ([exportFile exportFileNeedsCSVHeader]) {
+ [self writeCSVHeaderToExportFile:exportFile];
+ }
+ else if ([exportFile exportFileNeedsXMLHeader]) {
+ [self writeXMLHeaderToExportFile:exportFile];
+ }
+ }
+ else {
+ [problemFiles addObject:exportFile];
+ }
+ }
+
+ // Deal with any file handles that we failed to create for whatever reason
+ if ([problemFiles count] > 0) {
+ [self errorCreatingExportFileHandles:problemFiles];
+ }
+ else {
+ [self startExport];
+ }
+
+ [problemFiles release];
+}
+
+/**
+ * Initialises a CSV exporter for the supplied table name or data array.
+ *
+ * @param table The table name for which the exporter should be cerated for (can be nil).
+ * @param dataArray The MySQL result data array for which the exporter should be created for (can be nil).
+ */
+- (SPCSVExporter *)initializeCSVExporterForTable:(NSString *)table orDataArray:(NSArray *)dataArray
+{
+ SPCSVExporter *csvExporter = [[SPCSVExporter alloc] initWithDelegate:self];
+
+ // Depeding on the export source, set the table name or data array
+ if (exportSource == SPTableExport) {
+ [csvExporter setCsvTableName:table];
+ }
+ else {
+ [csvExporter setCsvDataArray:dataArray];
+ }
+
+ [csvExporter setCsvTableData:tableDataInstance];
+ [csvExporter setCsvOutputFieldNames:[exportCSVIncludeFieldNamesCheck state]];
+ [csvExporter setCsvFieldSeparatorString:[exportCSVFieldsTerminatedField stringValue]];
+ [csvExporter setCsvEnclosingCharacterString:[exportCSVFieldsWrappedField stringValue]];
+ [csvExporter setCsvLineEndingString:[exportCSVLinesTerminatedField stringValue]];
+ [csvExporter setCsvEscapeString:[exportCSVFieldsEscapedField stringValue]];
+ [csvExporter setCsvNULLString:[exportCSVNULLValuesAsTextField stringValue]];
+
+ // If required create separate files
+ if (exportSource == SPTableExport && [self exportToMultipleFiles]) {
+
+ if (createCustomFilename) {
+
+ // Create custom filename based on the selected format
+ [exportFilename setString:[self expandCustomFilenameFormatUsingTableName:table]];
+
+ // If the user chose to use a custom filename format and we exporting to multiple files, make
+ // sure the table name is included to ensure the output files are unique.
+ if (exportTableCount > 1) {
+ BOOL tableNameInTokens = NO;
+ NSArray *representedObjects = [exportCustomFilenameTokenField objectValue];
+ for (id representedObject in representedObjects) {
+ if ([representedObject isKindOfClass:[SPExportFileNameTokenObject class]] && [[representedObject tokenId] isEqualToString:SPFileNameTableTokenName]) tableNameInTokens = YES;
+ }
+ [exportFilename setString:(tableNameInTokens ? exportFilename : [exportFilename stringByAppendingFormat:@"_%@", table])];
+ }
+ }
+ else {
+ [exportFilename setString:(dataArray) ? [tableDocumentInstance database] : table];
+ }
+
+ // Only append the extension if necessary
+ if (![[exportFilename pathExtension] length]) {
+ [exportFilename setString:[exportFilename stringByAppendingPathExtension:[self currentDefaultExportFileExtension]]];
+ }
+
+ SPExportFile *file = [SPExportFile exportFileAtPath:[[exportPathField stringValue] stringByAppendingPathComponent:exportFilename]];
+
+ [exportFiles addObject:file];
+
+ [csvExporter setExportOutputFile:file];
+ }
+
+ return [csvExporter autorelease];
+}
+
+/**
+ * Initialises a XML exporter for the supplied table name or data array.
+ *
+ * @param table The table name for which the exporter should be cerated for (can be nil).
+ * @param dataArray The MySQL result data array for which the exporter should be created for (can be nil).
+ */
+- (SPXMLExporter *)initializeXMLExporterForTable:(NSString *)table orDataArray:(NSArray *)dataArray
+{
+ SPXMLExporter *xmlExporter = [[SPXMLExporter alloc] initWithDelegate:self];
+
+ // if required set the data array
+ if (exportSource != SPTableExport) {
+ [xmlExporter setXmlDataArray:dataArray];
+ }
+
+ // Regardless of the export source, set exporter's table name as it's used in the output
+ // of table and table content exports.
+ [xmlExporter setXmlTableName:table];
+
+ [xmlExporter setXmlFormat:[exportXMLFormatPopUpButton indexOfSelectedItem]];
+ [xmlExporter setXmlOutputIncludeStructure:[exportXMLIncludeStructure state]];
+ [xmlExporter setXmlOutputIncludeContent:[exportXMLIncludeContent state]];
+ [xmlExporter setXmlNULLString:[exportXMLNULLValuesAsTextField stringValue]];
+
+ // If required create separate files
+ if ((exportSource == SPTableExport) && exportToMultipleFiles && (exportTableCount > 0)) {
+
+ if (createCustomFilename) {
+
+ // Create custom filename based on the selected format
+ [exportFilename setString:[self expandCustomFilenameFormatUsingTableName:table]];
+
+ // If the user chose to use a custom filename format and we exporting to multiple files, make
+ // sure the table name is included to ensure the output files are unique.
+ if (exportTableCount > 1) {
+ BOOL tableNameInTokens = NO;
+ NSArray *representedObjects = [exportCustomFilenameTokenField objectValue];
+ for (id representedObject in representedObjects) {
+ if ([representedObject isKindOfClass:[SPExportFileNameTokenObject class]] && [[representedObject tokenId] isEqualToString:SPFileNameTableTokenName]) tableNameInTokens = YES;
+ }
+ [exportFilename setString:(tableNameInTokens ? exportFilename : [exportFilename stringByAppendingFormat:@"_%@", table])];
+ }
+ }
+ else {
+ [exportFilename setString:(dataArray) ? [tableDocumentInstance database] : table];
+ }
+
+ // Only append the extension if necessary
+ if (![[exportFilename pathExtension] length]) {
+ [exportFilename setString:[exportFilename stringByAppendingPathExtension:[self currentDefaultExportFileExtension]]];
+ }
+
+ SPExportFile *file = [SPExportFile exportFileAtPath:[[exportPathField stringValue] stringByAppendingPathComponent:exportFilename]];
+
+ [file setExportFileNeedsXMLHeader:YES];
+
+ [exportFiles addObject:file];
+
+ [xmlExporter setExportOutputFile:file];
+ }
+
+ return [xmlExporter autorelease];
+}
+
+#pragma mark - SPExportFileUtilitiesPrivateAPI
+
+/**
+ * Writes the CSV file header to the supplied export file.
+ *
+ * @param file The export file to write the header to.
+ */
+- (void)writeCSVHeaderToExportFile:(SPExportFile *)file
+{
+ NSMutableString *lineEnding = [NSMutableString stringWithString:[exportCSVLinesTerminatedField stringValue]];
+
+ // Escape tabs, line endings and carriage returns
+ [lineEnding replaceOccurrencesOfString:@"\\t" withString:@"\t"
+ options:NSLiteralSearch
+ range:NSMakeRange(0, [lineEnding length])];
+
+
+ [lineEnding replaceOccurrencesOfString:@"\\n" withString:@"\n"
+ options:NSLiteralSearch
+ range:NSMakeRange(0, [lineEnding length])];
+
+ [lineEnding replaceOccurrencesOfString:@"\\r" withString:@"\r"
+ options:NSLiteralSearch
+ range:NSMakeRange(0, [lineEnding length])];
+
+ // Write the file header and the first table name
+ [file writeData:[[NSMutableString stringWithFormat:@"%@: %@ %@: %@ %@: %@%@%@%@ %@%@%@",
+ NSLocalizedString(@"Host", @"export header host label"),
+ [tableDocumentInstance host],
+ NSLocalizedString(@"Database", @"export header database label"),
+ [tableDocumentInstance database],
+ NSLocalizedString(@"Generation Time", @"export header generation time label"),
+ [NSDate date],
+ lineEnding,
+ lineEnding,
+ NSLocalizedString(@"Table", @"csv export table heading"),
+ [[tables objectAtIndex:0] objectAtIndex:0],
+ lineEnding,
+ lineEnding] dataUsingEncoding:[connection stringEncoding]]];
+}
+
+/**
+ * Writes the XML file header to the supplied export file.
+ *
+ * @param file The export file to write the header to.
+ */
+- (void)writeXMLHeaderToExportFile:(SPExportFile *)file
+{
+ NSMutableString *header = [NSMutableString string];
+
+ [header setString:@"<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n\n"];
+ [header appendString:@"<!--\n-\n"];
+ [header appendString:@"- Sequel Pro XML dump\n"];
+ [header appendFormat:@"- %@ %@\n-\n", NSLocalizedString(@"Version", @"export header version label"), [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]];
+ [header appendFormat:@"- %@\n- %@\n-\n", SPLOCALIZEDURL_HOMEPAGE, SPDevURL];
+ [header appendFormat:@"- %@: %@ (MySQL %@)\n", NSLocalizedString(@"Host", @"export header host label"), [tableDocumentInstance host], [tableDocumentInstance mySQLVersion]];
+ [header appendFormat:@"- %@: %@\n", NSLocalizedString(@"Database", @"export header database label"), [tableDocumentInstance database]];
+ [header appendFormat:@"- %@ Time: %@\n", NSLocalizedString(@"Generation Time", @"export header generation time label"), [NSDate date]];
+ [header appendString:@"-\n-->\n\n"];
+
+ if ([exportXMLFormatPopUpButton indexOfSelectedItem] == SPXMLExportMySQLFormat) {
+
+ NSString *tag;
+
+ if (exportSource == SPTableExport) {
+ tag = [NSString stringWithFormat:@"<mysqldump xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n<database name=\"%@\">\n\n", [tableDocumentInstance database]];
+ }
+ else {
+ tag = [NSString stringWithFormat:@"<resultset statement=\"%@\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n\n", (exportSource == SPFilteredExport) ? [tableContentInstance usedQuery] : [customQueryInstance usedQuery]];
+ }
+
+ [header appendString:tag];
+ }
+ else {
+ [header appendFormat:@"<%@>\n\n", [[tableDocumentInstance database] HTMLEscapeString]];
+ }
+
+ [file writeData:[header dataUsingEncoding:NSUTF8StringEncoding]];
+}
+
+/**
+ * Indicates that one or more errors occurred while attempting to create the export file handles. Asks the
+ * user how to proceed.
+ *
+ * @param files An array of export files (SPExportFile) that failed to be created.
+ */
+- (void)errorCreatingExportFileHandles:(NSArray *)files
+{
+ // We don't know where "files" came from, but we know 2 things:
+ // - NSAlert will NOT retain it as contextInfo
+ // - This method continues execution after [alert beginSheet:...], thus even if files was retained before, it could be released before the alert ends
+ [files retain];
+
+ // Get the number of files that already exist as well as couldn't be created because of other reasons
+ NSUInteger filesAlreadyExisting = 0;
+ NSUInteger parentFoldersMissing = 0;
+ NSUInteger parentFoldersNotWritable = 0;
+ NSUInteger filesFailed = 0;
+
+ for (SPExportFile *file in files)
+ {
+ if ([file exportFileHandleStatus] == SPExportFileHandleExists) {
+ filesAlreadyExisting++;
+ }
+ // For file handles that we failed to create for some unknown reason, ignore them and remove any
+ // exporters that are associated with them.
+ else if ([file exportFileHandleStatus] == SPExportFileHandleFailed) {
+
+ filesFailed++;
+
+ NSMutableArray *exportersToRemove = [[NSMutableArray alloc] init];
+
+ for (SPExporter *exporter in exporters)
+ {
+ if ([[exporter exportOutputFile] isEqualTo:file]) {
+ [exportersToRemove addObject:exporter];
+ }
+ }
+
+ [exporters removeObjectsInArray:exportersToRemove];
+
+ [exportersToRemove release];
+
+ // Check the parent folder to see if it still is present
+ BOOL parentIsFolder = NO;
+ if (![[NSFileManager defaultManager] fileExistsAtPath:[[[file exportFilePath] stringByDeletingLastPathComponent] stringByExpandingTildeInPath] isDirectory:&parentIsFolder] || !parentIsFolder) {
+ parentFoldersMissing++;
+ } else if (![[NSFileManager defaultManager] isWritableFileAtPath:[[[file exportFilePath] stringByDeletingLastPathComponent] stringByExpandingTildeInPath]]) {
+ parentFoldersNotWritable++;
+ }
+ }
+ }
+
+ NSAlert *alert = [[NSAlert alloc] init];
+ [alert setAlertStyle:NSCriticalAlertStyle];
+
+ // If files failed because they already existed, show a OS-like dialog.
+ if (filesAlreadyExisting) {
+
+ // Set up a string for use if files had to be skipped.
+ NSString *additionalErrors = filesFailed ? NSLocalizedString(@"\n\n(In addition, one or more errors occurred while attempting to create the export files: %lu could not be created. These files will be ignored.)", @"Additional export file errors") : @"";
+
+ if (filesAlreadyExisting == 1) {
+ [alert setMessageText:[NSString stringWithFormat:NSLocalizedString(@"“%@” already exists. Do you want to replace it?", @"Export file already exists message"), [[[files objectAtIndex:0] exportFilePath] lastPathComponent]]];
+ [alert setInformativeText:[NSString stringWithFormat:@"%@%@", NSLocalizedString(@"A file with the same name already exists in the target folder. Replacing it will overwrite its current contents.", @"Export file already exists explanatory text"), additionalErrors]];
+ }
+ else if (filesAlreadyExisting == [exportFiles count]) {
+ [alert setMessageText:[NSString stringWithFormat:NSLocalizedString(@"All the export files already exist. Do you want to replace them?", @"All export files already exist message")]];
+ [alert setInformativeText:[NSString stringWithFormat:@"%@%@", NSLocalizedString(@"Files with the same names already exist in the target folder. Replacing them will overwrite their current contents.", @"All export files already exist explanatory text"), additionalErrors]];
+ }
+ else {
+ [alert setMessageText:[NSString stringWithFormat:NSLocalizedString(@"%lu files already exist. Do you want to replace them?", @"Export file already exists message"), filesAlreadyExisting]];
+ [alert setInformativeText:[NSString stringWithFormat:@"%@%@", [NSString stringWithFormat:NSLocalizedString(@"%lu files with the same names already exist in the target folder. Replacing them will overwrite their current contents.", @"Some export files already exist explanatory text"), filesAlreadyExisting], additionalErrors]];
+ }
+
+ [alert addButtonWithTitle:NSLocalizedString(@"Replace", @"Replace button")];
+ [[[alert buttons] objectAtIndex:0] setTag:SPExportErrorReplaceFiles];
+ [[[alert buttons] objectAtIndex:0] setKeyEquivalent:@"r"];
+ [[[alert buttons] objectAtIndex:0] setKeyEquivalentModifierMask:NSCommandKeyMask];
+
+ [alert addButtonWithTitle:NSLocalizedString(@"Cancel", @"cancel button")];
+ [[[alert buttons] objectAtIndex:1] setTag:SPExportErrorCancelExport];
+ [[[alert buttons] objectAtIndex:1] setKeyEquivalent:@"\r"];
+
+ if ((filesAlreadyExisting + filesFailed) != [exportFiles count]) {
+ [alert addButtonWithTitle:NSLocalizedString(@"Skip existing", @"skip existing button")];
+ [[[alert buttons] objectAtIndex:2] setTag:SPExportErrorSkipErrorFiles];
+ [[[alert buttons] objectAtIndex:2] setKeyEquivalent:@"s"];
+ [[[alert buttons] objectAtIndex:2] setKeyEquivalentModifierMask:NSCommandKeyMask];
+ }
+ }
+ // If one or multiple files failed, but only due to unhandled errors, show a short dialog
+ else {
+ if (filesFailed == 1) {
+ [alert setMessageText:[NSString stringWithFormat:NSLocalizedString(@"“%@” could not be created", @"Export file creation error title"), [[[files objectAtIndex:0] exportFilePath] lastPathComponent]]];
+ if (parentFoldersMissing) {
+ [alert setInformativeText:NSLocalizedString(@"The target export folder no longer exists. Please select a new export location and try again.", @"Export folder missing explanatory text")];
+ } else if (parentFoldersNotWritable) {
+ [alert setInformativeText:NSLocalizedString(@"The target export folder is not writable. Please select a new export location and try again.", @"Export folder not writable explanatory text")];
+ } else {
+ [alert setInformativeText:NSLocalizedString(@"An unhandled error occurred when attempting to create the export file. Please check the details and try again.", @"Export file creation error explanatory text")];
+ }
+ }
+ else if (filesFailed == [exportFiles count]) {
+ [alert setMessageText:[NSString stringWithFormat:NSLocalizedString(@"No files could be created", @"All export files creation error title")]];
+ if (parentFoldersMissing == [exportFiles count]) {
+ [alert setInformativeText:NSLocalizedString(@"The target export folder no longer exists. Please select a new export location and try again.", @"Export folder missing explanatory text")];
+ } else if (parentFoldersMissing) {
+ [alert setInformativeText:NSLocalizedString(@"Some of the target export folders no longer exist. Please select a new export location and try again.", @"Some export folders missing explanatory text")];
+ } else if (parentFoldersNotWritable) {
+ [alert setInformativeText:NSLocalizedString(@"Some of the target export folders are not writable. Please select a new export location and try again.", @"Some export folders not writable explanatory text")];
+ } else {
+ [alert setInformativeText:NSLocalizedString(@"An unhandled error occurred when attempting to create each of the export files. Please check the details and try again.", @"All export files creation error explanatory text")];
+ }
+ }
+ else {
+ [alert setMessageText:[NSString stringWithFormat:NSLocalizedString(@"%lu files could not be created", @"Export files creation error title"), filesFailed]];
+ if (parentFoldersMissing) {
+ [alert setInformativeText:[NSString stringWithFormat:NSLocalizedString(@"%lu of the export files could not be created because their target export folder no longer exists; please select a new export location and try again.", @"Export folder missing for some files explanatory text"), parentFoldersMissing]];
+ } else if (parentFoldersNotWritable) {
+ [alert setInformativeText:[NSString stringWithFormat:NSLocalizedString(@"%lu of the export files could not be created because their target export folder is not writable; please select a new export location and try again.", @"Export folder not writable for some files explanatory text"), parentFoldersNotWritable]];
+ } else {
+ [alert setInformativeText:[NSString stringWithFormat:NSLocalizedString(@"An unhandled error occurred when attempting to create %lu of the export files. Please check the details and try again.", @"Export files creation error explanatory text"), filesFailed]];
+ }
+ }
+
+ [alert addButtonWithTitle:NSLocalizedString(@"Cancel", @"cancel button")];
+ [[[alert buttons] objectAtIndex:0] setTag:SPExportErrorCancelExport];
+
+ if (filesFailed != [exportFiles count]) {
+ [alert addButtonWithTitle:NSLocalizedString(@"Skip problems", @"skip problems button")];
+ [[[alert buttons] objectAtIndex:1] setTag:SPExportErrorSkipErrorFiles];
+ [[[alert buttons] objectAtIndex:1] setKeyEquivalent:@"s"];
+ [[[alert buttons] objectAtIndex:1] setKeyEquivalentModifierMask:NSCommandKeyMask];
+ }
+ }
+
+ [self _hideExportProgress];
+
+ [alert beginSheetModalForWindow:[tableDocumentInstance parentWindow] modalDelegate:self didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:files];
+ [alert autorelease];
+}
+
+/**
+ * NSAlert didEnd method.
+ */
+- (void)alertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo
+{
+ NSArray *files = (NSArray *)contextInfo;
+
+ // Ignore the files that exist and remove the associated exporters
+ if (returnCode == SPExportErrorSkipErrorFiles) {
+
+ for (SPExportFile *file in files) {
+
+ // Use a numerically controlled loop to avoid mutating the collection while enumerating
+ NSUInteger i;
+ for (i = 0; i < [exporters count]; i++) {
+ SPExporter *exporter = [exporters objectAtIndex:i];
+ if ([[exporter exportOutputFile] isEqualTo:file]) {
+ [exporters removeObjectAtIndex:i];
+ i--;
+ }
+ }
+ }
+
+ [files release];
+
+ // If we're now left with no exporters, cancel the export operation
+ if ([exporters count] == 0) {
+ [exportFiles removeAllObjects];
+
+ // Trigger restoration of the export interface
+ [self performSelector:@selector(_reopenExportSheet) withObject:nil afterDelay:0.1];
+ }
+ else {
+ // Start the export after a short delay to give this sheet a chance to close
+ [self performSelector:@selector(startExport) withObject:nil afterDelay:0.1];
+ }
+ }
+ // Overwrite the files and continue
+ else if (returnCode == SPExportErrorReplaceFiles) {
+
+ for (SPExportFile *file in files)
+ {
+ if ([file exportFileHandleStatus] == SPExportFileHandleExists) {
+
+ if ([file createExportFileHandle:YES] == SPExportFileHandleCreated) {
+ [file setCompressionFormat:(SPFileCompressionFormat)[exportOutputCompressionFormatPopupButton indexOfSelectedItem]];
+
+ if ([file exportFileNeedsCSVHeader]) {
+ [self writeCSVHeaderToExportFile:file];
+ }
+ else if ([file exportFileNeedsXMLHeader]) {
+ [self writeXMLHeaderToExportFile:file];
+ }
+ }
+ }
+ }
+
+ [files release];
+
+ // Start the export after a short delay to give this sheet a chance to close
+ [self performSelector:@selector(startExport) withObject:nil afterDelay:0.1];
+
+ }
+ // Cancel the entire export operation
+ else if (returnCode == SPExportErrorCancelExport) {
+
+ // Loop the cached export files and remove those we've already created
+ for (SPExportFile *file in exportFiles)
+ {
+ [file delete];
+ }
+
+ [files release];
+
+ // Finally get rid of all the exporters and files
+ [exportFiles removeAllObjects];
+ [exporters removeAllObjects];
+
+ // Trigger restoration of the export interface
+ [self performSelector:@selector(_reopenExportSheet) withObject:nil afterDelay:0.1];
+ }
+}
+
+/**
+ * Re-open the export sheet without resetting the interface - for use on error.
+ */
+- (void)_reopenExportSheet
+{
+ [NSApp beginSheet:[self window]
+ modalForWindow:[tableDocumentInstance parentWindow]
+ modalDelegate:self
+ didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:)
+ contextInfo:nil];
+}
+
+#pragma mark - SPExportFilenameUtilities
+
+/**
+ * Updates the displayed export filename, either custom or default.
+ */
+- (void)updateDisplayedExportFilename
+{
+ NSString *filename = @"";
+
+ if ([[exportCustomFilenameTokenField stringValue] length] > 0) {
+
+ // Get the current export file extension
+ NSString *extension = [self currentDefaultExportFileExtension];
+
+ //note that there will be no tableName if the export is done from a query result without a database selected (or empty).
+ filename = [self expandCustomFilenameFormatUsingTableName:[[tablesListInstance tables] objectOrNilAtIndex:1]];
+
+
+ if (![[self customFilenamePathExtension] length] && [extension length] > 0) filename = [filename stringByAppendingPathExtension:extension];
+ }
+ else {
+ filename = [self generateDefaultExportFilename];
+ }
+
+ [exportCustomFilenameViewLabelButton setTitle:[NSString stringWithFormat:NSLocalizedString(@"Customize Filename (%@)", @"customize file name label"), filename]];
+}
+
+- (NSString *)customFilenamePathExtension
+{
+ NSMutableString *flatted = [NSMutableString string];
+
+ // This time we replace every token with "/a". This has the following effect:
+ // "{host}.{database}" -> "/a./a" -> extension=""
+ // "{database}_{date}.sql" -> "/a_/a.sql" -> extension="sql"
+ // That seems to be the easiest way to let NSString correctly determine if an extension is present
+ for (id filenamePart in [exportCustomFilenameTokenField objectValue])
+ {
+ if([filenamePart isKindOfClass:[NSString class]])
+ [flatted appendString:filenamePart];
+ else if([filenamePart isKindOfClass:[SPExportFileNameTokenObject class]])
+ [flatted appendString:@"/a"];
+ else
+ [NSException raise:NSInternalInconsistencyException format:@"unknown object in token list: %@",filenamePart];
+ }
+
+ return [flatted pathExtension];
+}
+
+- (BOOL)isTableTokenAllowed
+{
+ NSUInteger i = 0;
+ BOOL removeTable = NO;
+
+ BOOL isSQL = exportType == SPSQLExport;
+ BOOL isCSV = exportType == SPCSVExport;
+ BOOL isDot = exportType == SPDotExport;
+ BOOL isXML = exportType == SPXMLExport;
+
+ // Determine whether to remove the table from the tokens list
+ if (exportSource == SPQueryExport || isDot) {
+ removeTable = YES;
+ }
+ else if (isSQL || isCSV || isXML) {
+ for (NSArray *table in tables)
+ {
+ if ([NSArrayObjectAtIndex(table, 2) boolValue]) {
+ i++;
+ if (i == 2) break;
+ }
+ }
+
+ if (i > 1) {
+ removeTable = isSQL ? YES : ![exportFilePerTableCheck state];
+ }
+ }
+
+ return (removeTable == NO);
+}
+
+/**
+ * Updates the available export filename tokens based on the currently selected options.
+ */
+- (void)updateAvailableExportFilenameTokens
+{
+ SPExportFileNameTokenObject *tableObject;
+ NSMutableArray *exportTokens = [NSMutableArray arrayWithObjects:
+ [SPExportFileNameTokenObject tokenWithId:SPFileNameDatabaseTokenName],
+ [SPExportFileNameTokenObject tokenWithId:SPFileNameHostTokenName],
+ [SPExportFileNameTokenObject tokenWithId:SPFileNameDateTokenName],
+ [SPExportFileNameTokenObject tokenWithId:SPFileNameYearTokenName],
+ [SPExportFileNameTokenObject tokenWithId:SPFileNameMonthTokenName],
+ [SPExportFileNameTokenObject tokenWithId:SPFileNameDayTokenName],
+ [SPExportFileNameTokenObject tokenWithId:SPFileNameTimeTokenName],
+ [SPExportFileNameTokenObject tokenWithId:SPFileName24HourTimeTokenName],
+ [SPExportFileNameTokenObject tokenWithId:SPFileNameFavoriteTokenName],
+ (tableObject = [SPExportFileNameTokenObject tokenWithId:SPFileNameTableTokenName]),
+ nil
+ ];
+
+ if (![self isTableTokenAllowed]) {
+ [exportTokens removeObject:tableObject];
+ NSArray *tokenParts = [exportCustomFilenameTokenField objectValue];
+
+ for (id token in tokenParts)
+ {
+ if([token isEqual:tableObject]) {
+ NSMutableArray *newTokens = [NSMutableArray arrayWithArray:tokenParts];
+
+ [newTokens removeObject:tableObject]; //removes all occurances
+
+ [exportCustomFilenameTokenField setObjectValue:newTokens];
+ break;
+ }
+ }
+ }
+
+ [exportCustomFilenameTokenPool setObjectValue:exportTokens];
+ //update preview name as programmatically changing the exportCustomFilenameTokenField does not fire a notification
+ [self updateDisplayedExportFilename];
+}
+
+- (NSArray *)currentAllowedExportFilenameTokens
+{
+ NSArray *mixed = [exportCustomFilenameTokenPool objectValue];
+ NSMutableArray *tokens = [NSMutableArray arrayWithCapacity:[mixed count]]; // ...or less
+
+ for (id obj in mixed) {
+ if([obj isKindOfClass:[SPExportFileNameTokenObject class]]) [tokens addObject:obj];
+ }
+
+ return tokens;
+}
+
+/**
+ * Generates the default export filename based on the selected export options.
+ *
+ * @return The default filename.
+ */
+- (NSString *)generateDefaultExportFilename
+{
+ NSString *filename = @"";
+ NSString *extension = [self currentDefaultExportFileExtension];
+
+ // Determine what the file name should be
+ switch (exportSource)
+ {
+ case SPFilteredExport:
+ filename = [NSString stringWithFormat:@"%@_view", [tableDocumentInstance table]];
+ break;
+ case SPQueryExport:
+ filename = @"query_result";
+ break;
+ case SPTableExport:
+ filename = [NSString stringWithFormat:@"%@_%@", [tableDocumentInstance database], [[NSDate date] descriptionWithCalendarFormat:@"%Y-%m-%d" timeZone:nil locale:nil]];
+ break;
+ }
+
+ return ([extension length] > 0) ? [filename stringByAppendingPathExtension:extension] : filename;
+}
+
+/**
+ * Returns the current default export file extension based on the selected export type.
+ *
+ * @return The default filename extension.
+ */
+- (NSString *)currentDefaultExportFileExtension
+{
+ NSString *extension = @"";
+
+ switch (exportType) {
+ case SPSQLExport:
+ extension = SPFileExtensionSQL;
+ break;
+ case SPCSVExport:
+ // If the tab character (\t) is selected as the feild separator return the extension as .tsv
+ extension = ([exportCSVFieldsTerminatedField indexOfSelectedItem] == 2) ? @"tsv" : @"csv";
+ break;
+ case SPXMLExport:
+ extension = @"xml";
+ break;
+ case SPDotExport:
+ extension = @"dot";
+ break;
+ case SPPDFExport:
+ case SPHTMLExport:
+ case SPExcelExport:
+ default:
+ [NSException raise:NSInvalidArgumentException format:@"unsupported exportType=%lu",exportType];
+ return nil;
+ }
+
+ if ([exportOutputCompressionFormatPopupButton indexOfSelectedItem] != SPNoCompression) {
+
+ SPFileCompressionFormat compressionFormat = (SPFileCompressionFormat)[exportOutputCompressionFormatPopupButton indexOfSelectedItem];
+
+ if ([extension length] > 0) {
+ extension = [extension stringByAppendingPathExtension:(compressionFormat == SPGzipCompression) ? @"gz" : @"bz2"];
+ }
+ else {
+ extension = (compressionFormat == SPGzipCompression) ? @"gz" : @"bz2";
+ }
+ }
+
+ return extension;
+}
+
+/**
+ * Expands the custom filename format based on the selected tokens.
+ * Uses the current custom filename field as a data source.
+ *
+ * @param table A table name to be used within the expanded filename.
+ * Can be nil.
+ *
+ * @return The expanded filename.
+ */
+- (NSString *)expandCustomFilenameFormatUsingTableName:(NSString *)table
+{
+ NSMutableString *string = [NSMutableString string];
+
+ NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
+ [dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4];
+
+ // Walk through the token field, appending token replacements or strings
+ NSArray *representedFilenameParts = [exportCustomFilenameTokenField objectValue];
+
+ for (id filenamePart in representedFilenameParts)
+ {
+ if ([filenamePart isKindOfClass:[SPExportFileNameTokenObject class]]) {
+ NSString *tokenContent = [filenamePart tokenId];
+
+ if ([tokenContent isEqualToString:SPFileNameHostTokenName]) {
+ [string appendStringOrNil:[tableDocumentInstance host]];
+
+ }
+ else if ([tokenContent isEqualToString:SPFileNameDatabaseTokenName]) {
+ [string appendStringOrNil:[tableDocumentInstance database]];
+
+ }
+ else if ([tokenContent isEqualToString:SPFileNameTableTokenName]) {
+ [string appendStringOrNil:table];
+ }
+ else if ([tokenContent isEqualToString:SPFileNameDateTokenName]) {
+ [dateFormatter setDateStyle:NSDateFormatterShortStyle];
+ [dateFormatter setTimeStyle:NSDateFormatterNoStyle];
+ [string appendString:[dateFormatter stringFromDate:[NSDate date]]];
+
+ }
+ else if ([tokenContent isEqualToString:SPFileNameYearTokenName]) {
+ [string appendString:[[NSDate date] descriptionWithCalendarFormat:@"%Y" timeZone:nil locale:nil]];
+
+ }
+ else if ([tokenContent isEqualToString:SPFileNameMonthTokenName]) {
+ [string appendString:[[NSDate date] descriptionWithCalendarFormat:@"%m" timeZone:nil locale:nil]];
+
+ }
+ else if ([tokenContent isEqualToString:SPFileNameDayTokenName]) {
+ [string appendString:[[NSDate date] descriptionWithCalendarFormat:@"%d" timeZone:nil locale:nil]];
+
+ }
+ else if ([tokenContent isEqualToString:SPFileNameTimeTokenName]) {
+ [dateFormatter setDateStyle:NSDateFormatterNoStyle];
+ [dateFormatter setTimeStyle:NSDateFormatterShortStyle];
+ [string appendString:[dateFormatter stringFromDate:[NSDate date]]];
+ }
+ else if ([tokenContent isEqualToString:SPFileName24HourTimeTokenName]) {
+ [string appendString:[[NSDate date] descriptionWithCalendarFormat:@"%H:%M:%S" timeZone:nil locale:nil]];
+ }
+ else if ([tokenContent isEqualToString:SPFileNameFavoriteTokenName]) {
+ [string appendStringOrNil:[tableDocumentInstance name]];
+ }
+ }
+ else {
+ [string appendString:filenamePart];
+ }
+ }
+
+ // Replace colons with hyphens
+ [string replaceOccurrencesOfString:@":"
+ withString:@"-"
+ options:NSLiteralSearch
+ range:NSMakeRange(0, [string length])];
+
+ // Replace forward slashes with hyphens
+ [string replaceOccurrencesOfString:@"/"
+ withString:@"-"
+ options:NSLiteralSearch
+ range:NSMakeRange(0, [string length])];
+
+ [dateFormatter release];
+
+ // Don't allow empty strings - if an empty string resulted, revert to the default string
+ if (![string length]) [string setString:[self generateDefaultExportFilename]];
+
+ return string;
+}
+
+#pragma mark - SPExportInterfaceController
+
+/**
+ * Resizes the export window's height by the supplied delta, while retaining the position of
+ * all interface controls to accommodate the custom filename view.
+ *
+ * @param delta The height delta for which the height should be adjusted for.
+ */
+- (void)_resizeWindowForCustomFilenameViewByHeightDelta:(NSInteger)delta
+{
+ NSUInteger popUpMask = [exportInputPopUpButton autoresizingMask];
+ NSUInteger fileCheckMask = [exportFilePerTableCheck autoresizingMask];
+ NSUInteger scrollMask = [exportTablelistScrollView autoresizingMask];
+ NSUInteger buttonBarMask = [exportTableListButtonBar autoresizingMask];
+ NSUInteger buttonMask = [exportCustomFilenameViewButton autoresizingMask];
+ NSUInteger textFieldMask = [exportCustomFilenameViewLabelButton autoresizingMask];
+ NSUInteger customFilenameViewMask = [exportCustomFilenameView autoresizingMask];
+ NSUInteger tabBarMask = [exportOptionsTabBar autoresizingMask];
+
+ NSRect frame = [[self window] frame];
+
+ if (frame.size.height > 600 && delta > heightOffset1) {
+ frame.origin.y += [exportCustomFilenameView frame].size.height;
+ frame.size.height -= [exportCustomFilenameView frame].size.height;
+
+ [[self window] setFrame:frame display:YES animate:YES];
+ }
+
+ [exportInputPopUpButton setAutoresizingMask:NSViewNotSizable | NSViewMaxYMargin];
+ [exportFilePerTableCheck setAutoresizingMask:NSViewNotSizable | NSViewMaxYMargin];
+ [exportTablelistScrollView setAutoresizingMask:NSViewNotSizable | NSViewMaxYMargin];
+ [exportTableListButtonBar setAutoresizingMask:NSViewNotSizable | NSViewMaxYMargin];
+ [exportOptionsTabBar setAutoresizingMask:NSViewNotSizable | NSViewMaxYMargin];
+ [exportCustomFilenameViewButton setAutoresizingMask:NSViewNotSizable | NSViewMinYMargin];
+ [exportCustomFilenameViewLabelButton setAutoresizingMask:NSViewNotSizable | NSViewMinYMargin];
+ [exportCustomFilenameView setAutoresizingMask:NSViewNotSizable | NSViewMinYMargin];
+
+ NSInteger newMinHeight = (windowMinHeigth - heightOffset1 + delta < windowMinHeigth) ? windowMinHeigth : windowMinHeigth - heightOffset1 + delta;
+
+ [[self window] setMinSize:NSMakeSize(windowMinWidth, newMinHeight)];
+
+ frame.origin.y += heightOffset1;
+ frame.size.height -= heightOffset1;
+
+ heightOffset1 = delta;
+
+ frame.origin.y -= heightOffset1;
+ frame.size.height += heightOffset1;
+
+ [[self window] setFrame:frame display:YES animate:YES];
+
+ [exportInputPopUpButton setAutoresizingMask:popUpMask];
+ [exportFilePerTableCheck setAutoresizingMask:fileCheckMask];
+ [exportTablelistScrollView setAutoresizingMask:scrollMask];
+ [exportTableListButtonBar setAutoresizingMask:buttonBarMask];
+ [exportCustomFilenameViewButton setAutoresizingMask:buttonMask];
+ [exportCustomFilenameViewLabelButton setAutoresizingMask:textFieldMask];
+ [exportCustomFilenameView setAutoresizingMask:customFilenameViewMask];
+ [exportOptionsTabBar setAutoresizingMask:tabBarMask];
+}
+
+/**
+ * Resizes the export window's height by the supplied delta, while retaining the position of
+ * all interface controls to accommodate the advanced options view.
+ *
+ * @param delta The height delta for which the height should be adjusted for.
+ */
+- (void)_resizeWindowForAdvancedOptionsViewByHeightDelta:(NSInteger)delta
+{
+ NSUInteger scrollMask = [exportTablelistScrollView autoresizingMask];
+ NSUInteger buttonBarMask = [exportTableListButtonBar autoresizingMask];
+ NSUInteger tabBarMask = [exportTypeTabBar autoresizingMask];
+ NSUInteger optionsTabBarMask = [exportOptionsTabBar autoresizingMask];
+ NSUInteger buttonMask = [exportAdvancedOptionsViewButton autoresizingMask];
+ NSUInteger textFieldMask = [exportAdvancedOptionsViewLabelButton autoresizingMask];
+ NSUInteger advancedViewMask = [exportAdvancedOptionsView autoresizingMask];
+
+ NSRect frame = [[self window] frame];
+
+ if (frame.size.height > 600 && delta > heightOffset2) {
+ frame.origin.y += [exportAdvancedOptionsView frame].size.height;
+ frame.size.height -= [exportAdvancedOptionsView frame].size.height;
+
+ [[self window] setFrame:frame display:YES animate:YES];
+ }
+
+ [exportTablelistScrollView setAutoresizingMask:NSViewNotSizable | NSViewMinYMargin];
+ [exportTableListButtonBar setAutoresizingMask:NSViewNotSizable | NSViewMinYMargin];
+ [exportTypeTabBar setAutoresizingMask:NSViewNotSizable | NSViewMinYMargin];
+ [exportOptionsTabBar setAutoresizingMask:NSViewNotSizable | NSViewMinYMargin];
+ [exportAdvancedOptionsViewButton setAutoresizingMask:NSViewNotSizable | NSViewMinYMargin];
+ [exportAdvancedOptionsViewLabelButton setAutoresizingMask:NSViewNotSizable | NSViewMinYMargin];
+ [exportAdvancedOptionsView setAutoresizingMask:NSViewNotSizable | NSViewMinYMargin];
+
+ NSInteger newMinHeight = (windowMinHeigth - heightOffset2 + delta < windowMinHeigth) ? windowMinHeigth : windowMinHeigth - heightOffset2 + delta;
+
+ [[self window] setMinSize:NSMakeSize(windowMinWidth, newMinHeight)];
+
+ frame.origin.y += heightOffset2;
+ frame.size.height -= heightOffset2;
+
+ heightOffset2 = delta;
+
+ frame.origin.y -= heightOffset2;
+ frame.size.height += heightOffset2;
+
+ [[self window] setFrame:frame display:YES animate:YES];
+
+ [exportTablelistScrollView setAutoresizingMask:scrollMask];
+ [exportTableListButtonBar setAutoresizingMask:buttonBarMask];
+ [exportTypeTabBar setAutoresizingMask:tabBarMask];
+ [exportOptionsTabBar setAutoresizingMask:optionsTabBarMask];
+ [exportAdvancedOptionsViewButton setAutoresizingMask:buttonMask];
+ [exportAdvancedOptionsViewLabelButton setAutoresizingMask:textFieldMask];
+ [exportAdvancedOptionsView setAutoresizingMask:advancedViewMask];
+}
+
+#pragma mark - SPExportControllerDelegate
+
+#pragma mark Table view datasource methods
+
+- (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView;
+{
+ return [tables count];
+}
+
+- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)rowIndex
+{
+ return NSArrayObjectAtIndex([tables objectAtIndex:rowIndex], [exportTableList columnWithIdentifier:[tableColumn identifier]]);
+}
+
+- (void)tableView:(NSTableView *)tableView setObjectValue:(id)anObject forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)rowIndex
+{
+ [[tables objectAtIndex:rowIndex] replaceObjectAtIndex:[exportTableList columnWithIdentifier:[tableColumn identifier]] withObject:anObject];
+
+ [self updateAvailableExportFilenameTokens];
+ [self _toggleExportButtonOnBackgroundThread];
+ [self _updateExportFormatInformation];
+}
+
+#pragma mark -
+#pragma mark Table view delegate methods
+
+- (BOOL)tableView:(NSTableView *)tableView shouldTrackCell:(NSCell *)cell forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)rowIndex
+{
+ return (tableView == exportTableList);
+}
+
+- (void)tableView:(NSTableView *)tableView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)rowIndex
+{
+ [cell setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];
+}
+
+#pragma mark -
+#pragma mark Tabview delegate methods
+
+- (void)tabView:(NSTabView *)tabView didSelectTabViewItem:(NSTabViewItem *)tabViewItem
+{
+ [tabViewItem setView:exporterView];
+
+ [self _switchTab];
+}
+
+#pragma mark -
+#pragma mark Token field delegate methods
+
+/**
+ * Use the default token style for matched tokens, plain text for all other text.
+ */
+- (NSTokenStyle)tokenField:(NSTokenField *)tokenField styleForRepresentedObject:(id)representedObject
+{
+ if (IS_TOKEN(representedObject)) return NSDefaultTokenStyle;
+
+ return NSPlainTextTokenStyle;
+}
+
+- (BOOL)tokenField:(NSTokenField *)tokenField writeRepresentedObjects:(NSArray *)objects toPasteboard:(NSPasteboard *)pboard
+{
+ NSMutableArray *mixed = [NSMutableArray arrayWithCapacity:[objects count]];
+ NSMutableString *flatted = [NSMutableString string];
+
+ for(id item in objects) {
+ if(IS_TOKEN(item)) {
+ [mixed addObject:@{@"tokenId": [item tokenId]}];
+ [flatted appendFormat:@"{%@}",[item tokenId]];
+ }
+ else if(IS_STRING(item)) {
+ [mixed addObject:item];
+ [flatted appendString:item];
+ }
+ else {
+ [NSException raise:NSInternalInconsistencyException format:@"tokenField %@ contains unexpected object %@",tokenField,item];
+ }
+ }
+
+ [pboard setString:flatted forType:NSPasteboardTypeString];
+ [pboard setPropertyList:mixed forType:SPExportCustomFileNameTokenPlistType];
+ return YES;
+}
+
+- (NSArray *)tokenField:(NSTokenField *)tokenField readFromPasteboard:(NSPasteboard *)pboard
+{
+ NSArray *items = [pboard propertyListForType:SPExportCustomFileNameTokenPlistType];
+ // if we have our preferred object type use it
+ if(items) {
+ NSMutableArray *res = [NSMutableArray arrayWithCapacity:[items count]];
+ for (id item in items) {
+ if (IS_STRING(item)) {
+ [res addObject:item];
+ }
+ else if([item isKindOfClass:[NSDictionary class]]) {
+ NSString *name = [item objectForKey:@"tokenId"];
+ if(name) {
+ SPExportFileNameTokenObject *tok = [SPExportFileNameTokenObject tokenWithId:name];
+ [res addObject:tok];
+ }
+ }
+ else {
+ [NSException raise:NSInternalInconsistencyException format:@"pasteboard %@ contains unexpected object %@",pboard,item];
+ }
+ }
+ return res;
+ }
+ // if the string came from another app, paste it literal, tokenfield will take care of any conversions
+ NSString *raw = [pboard stringForType:NSPasteboardTypeString];
+ if(raw) {
+ return @[[raw stringByReplacingCharactersInSet:[NSCharacterSet newlineCharacterSet] withString:@" "]];
+ }
+
+ return nil;
+}
+
+/**
+ * Take the default suggestion of new tokens - all untokenized text, as no tokenizing character is set - and
+ * split/recombine strings that contain tokens. This preserves all supplied characters and allows tokens to be typed.
+ */
+- (NSArray *)tokenField:(NSTokenField *)tokenField shouldAddObjects:(NSArray *)tokens atIndex:(NSUInteger)index
+{
+ return [self _updateTokensForMixedContent:tokens];
+}
+
+- (NSString *)tokenField:(NSTokenField *)tokenField displayStringForRepresentedObject:(id)representedObject
+{
+ if (IS_TOKEN(representedObject)) {
+ return [localizedTokenNames objectForKey:[(SPExportFileNameTokenObject *)representedObject tokenId]];
+ }
+
+ return representedObject;
+}
+
+/**
+ * Return the editing string untouched - implementing this method prevents whitespace trimming.
+ */
+- (id)tokenField:(NSTokenField *)tokenField representedObjectForEditingString:(NSString *)editingString
+{
+ return editingString;
+}
+
+/**
+ * During text entry into the token field, update the displayed filename and also
+ * trigger tokenization after a short delay.
+ */
+- (void)controlTextDidChange:(NSNotification *)notification
+{
+ // this method can either be called by typing, or by copy&paste.
+ // In the latter case tokenization will already be done by now.
+ if ([notification object] == exportCustomFilenameTokenField) {
+ [self updateDisplayedExportFilename];
+ [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(_tokenizeCustomFilenameTokenField) object:nil];
+ // do not queue a call if the key causing this change was the return key.
+ // This is to prevent a loop with _tokenizeCustomFilenameTokenField.
+ if([[NSApp currentEvent] type] != NSKeyDown || [[NSApp currentEvent] keyCode] != 0x24) {
+ [self performSelector:@selector(_tokenizeCustomFilenameTokenField) withObject:nil afterDelay:0.5];
+ }
+ }
+}
+
+#pragma mark -
+#pragma mark Combo box delegate methods
+
+- (void)comboBoxSelectionDidChange:(NSNotification *)notification
+{
+ if ([notification object] == exportCSVFieldsTerminatedField) {
+ [self updateDisplayedExportFilename];
+ }
+}
+
+#pragma mark -
+
+/**
+ * Takes a mixed array of strings and tokens and converts
+ * any valid tokens inside the strings into real tokens
+ */
+- (NSArray *)_updateTokensForMixedContent:(NSArray *)tokens
+{
+ //if two consecutive tokens are strings, merge them
+ NSMutableArray *mergedTokens = [NSMutableArray array];
+ for (id inputToken in tokens)
+ {
+ if(IS_TOKEN(inputToken)) {
+ [mergedTokens addObject:inputToken];
+ }
+ else if(IS_STRING(inputToken)) {
+ id prev = [mergedTokens lastObject];
+ if(IS_STRING(prev)) {
+ [mergedTokens removeLastObject];
+ [mergedTokens addObject:[prev stringByAppendingString:inputToken]];
+ }
+ else {
+ [mergedTokens addObject:inputToken];
+ }
+ }
+ }
+
+ // create a mapping dict of tokenId => token
+ NSMutableDictionary *replacement = [NSMutableDictionary dictionary];
+ for (SPExportFileNameTokenObject *realToken in [exportCustomFilenameTokenPool objectValue]) {
+ NSString *serializedName = [NSString stringWithFormat:@"{%@}",[realToken tokenId]];
+ [replacement setObject:realToken forKey:serializedName];
+ }
+
+ //now we can look for real tokens to convert inside the strings
+ NSMutableArray *processedTokens = [NSMutableArray array];
+ for (id token in mergedTokens) {
+ if(IS_TOKEN(token)) {
+ [processedTokens addObject:token];
+ continue;
+ }
+
+ NSString *remainder = token;
+ while(true) {
+ NSRange openCurl = [remainder rangeOfString:@"{"];
+ if(openCurl.location == NSNotFound) {
+ break;
+ }
+ NSString *before = [remainder substringToIndex:openCurl.location];
+ if([before length]) {
+ [processedTokens addObject:before];
+ }
+ remainder = [remainder substringFromIndex:openCurl.location];
+ NSRange closeCurl = [remainder rangeOfString:@"}"];
+ if(closeCurl.location == NSNotFound) {
+ break; //we've hit an unterminated token
+ }
+ NSString *tokenString = [remainder substringToIndex:closeCurl.location+1];
+ SPExportFileNameTokenObject *tokenObject = [replacement objectForKey:tokenString];
+ if(tokenObject) {
+ [processedTokens addObject:tokenObject];
+ }
+ else {
+ [processedTokens addObject:tokenString]; // no token with this name, add it as string
+ }
+ remainder = [remainder substringFromIndex:closeCurl.location+1];
+ }
+ if([remainder length]) {
+ [processedTokens addObject:remainder];
+ }
+ }
+
+ return processedTokens;
+}
+
+- (void)_tokenizeCustomFilenameTokenField
+{
+ // if we are currently inside or at the end of a string segment we can
+ // call for tokenization to happen by simulating a return press
+
+ if ([exportCustomFilenameTokenField currentEditor] == nil) return;
+
+ NSRange selectedRange = [[exportCustomFilenameTokenField currentEditor] selectedRange];
+
+ if (selectedRange.location == NSNotFound) return;
+ if (selectedRange.location == 0) return; // the beginning of the field is not valid for tokenization
+ if (selectedRange.length > 0) return;
+
+ NSUInteger start = 0;
+ for(id obj in [exportCustomFilenameTokenField objectValue]) {
+ NSUInteger length;
+ BOOL isText = NO;
+ if(IS_STRING(obj)) {
+ length = [obj length];
+ isText = YES;
+ }
+ else if(IS_TOKEN(obj)) {
+ length = 1; // tokens are seen as one char by the textview
+ }
+ else {
+ [NSException raise:NSInternalInconsistencyException format:@"Unknown object type in token field: %@",obj];
+ }
+ NSUInteger end = start+length;
+ if(selectedRange.location >= start && selectedRange.location <= end) {
+ if(!isText) return; // cursor is at the end of a token
+ break;
+ }
+ start += length;
+ }
+
+ // All conditions met - synthesize the return key to trigger tokenization.
+ NSEvent *tokenizingEvent = [NSEvent keyEventWithType:NSKeyDown
+ location:NSMakePoint(0,0)
+ modifierFlags:0
+ timestamp:0
+ windowNumber:[[exportCustomFilenameTokenField window] windowNumber]
+ context:[NSGraphicsContext currentContext]
+ characters:@""
+ charactersIgnoringModifiers:@""
+ isARepeat:NO
+ keyCode:0x24];
+
+ [NSApp postEvent:tokenizingEvent atStart:NO];
+}
+
+#pragma mark - SPExportSettingsPersistence
+
+#define NAMEOF(x) case x: return @#x
+#define VALUEOF(x,y,dst) if([y isEqualToString:@#x]) { *dst = x; return YES; }
+
++ (NSString *)describeExportSource:(SPExportSource)es
+{
+ switch (es) {
+ NAMEOF(SPFilteredExport);
+ NAMEOF(SPQueryExport);
+ NAMEOF(SPTableExport);
+ }
+ return nil;
+}
+
++ (BOOL)copyExportSourceForDescription:(NSString *)esd to:(SPExportSource *)dst
+{
+ VALUEOF(SPFilteredExport, esd,dst);
+ VALUEOF(SPQueryExport, esd,dst);
+ VALUEOF(SPTableExport, esd,dst);
+ return NO;
+}
+
++ (NSString *)describeExportType:(SPExportType)et
+{
+ switch (et) {
+ NAMEOF(SPSQLExport);
+ NAMEOF(SPCSVExport);
+ NAMEOF(SPXMLExport);
+ NAMEOF(SPDotExport);
+ NAMEOF(SPPDFExport);
+ NAMEOF(SPHTMLExport);
+ NAMEOF(SPExcelExport);
+ NAMEOF(SPAnyExportType);
+ }
+ return nil;
+}
+
++ (BOOL)copyExportTypeForDescription:(NSString *)etd to:(SPExportType *)dst
+{
+ VALUEOF(SPSQLExport, etd, dst);
+ VALUEOF(SPCSVExport, etd, dst);
+ VALUEOF(SPXMLExport, etd, dst);
+ VALUEOF(SPDotExport, etd, dst);
+ //VALUEOF(SPPDFExport, etd, dst);
+ //VALUEOF(SPHTMLExport, etd, dst);
+ //VALUEOF(SPExcelExport, etd, dst);
+ return NO;
+}
+
++ (NSString *)describeCompressionFormat:(SPFileCompressionFormat)cf
+{
+ switch (cf) {
+ NAMEOF(SPNoCompression);
+ NAMEOF(SPGzipCompression);
+ NAMEOF(SPBzip2Compression);
+ }
+ return nil;
+}
+
++ (BOOL)copyCompressionFormatForDescription:(NSString *)cfd to:(SPFileCompressionFormat *)dst
+{
+ VALUEOF(SPNoCompression, cfd, dst);
+ VALUEOF(SPGzipCompression, cfd, dst);
+ VALUEOF(SPBzip2Compression, cfd, dst);
+ return NO;
+}
+
++ (NSString *)describeXMLExportFormat:(SPXMLExportFormat)xf
+{
+ switch (xf) {
+ NAMEOF(SPXMLExportMySQLFormat);
+ NAMEOF(SPXMLExportPlainFormat);
+ }
+ return nil;
+}
+
++ (BOOL)copyXMLExportFormatForDescription:(NSString *)xfd to:(SPXMLExportFormat *)dst
+{
+ VALUEOF(SPXMLExportMySQLFormat, xfd, dst);
+ VALUEOF(SPXMLExportPlainFormat, xfd, dst);
+ return NO;
+}
+
++ (NSString *)describeSQLExportInsertDivider:(SPSQLExportInsertDivider)eid
+{
+ switch (eid) {
+ NAMEOF(SPSQLInsertEveryNDataBytes);
+ NAMEOF(SPSQLInsertEveryNRows);
+ }
+ return nil;
+}
+
++ (BOOL)copySQLExportInsertDividerForDescription:(NSString *)eidd to:(SPSQLExportInsertDivider *)dst
+{
+ VALUEOF(SPSQLInsertEveryNDataBytes, eidd, dst);
+ VALUEOF(SPSQLInsertEveryNRows, eidd, dst);
+ return NO;
+}
+
+#undef NAMEOF
+#undef VALUEOF
+
+- (IBAction)importCurrentSettings:(id)sender
+{
+ //show open file dialog
+ NSOpenPanel *panel = [NSOpenPanel openPanel];
+
+ [panel setAllowedFileTypes:@[SPFileExtensionDefault]];
+ [panel setAllowsOtherFileTypes:YES];
+
+ [panel beginSheetModalForWindow:[self window] completionHandler:^(NSInteger result) {
+ if(result != NSFileHandlingPanelOKButton) return;
+
+ [panel orderOut:nil]; // Panel is still on screen. Hide it first. (This is Apple's recommended way)
+
+ NSError *err = nil;
+ NSData *plist = [NSData dataWithContentsOfURL:[panel URL]
+ options:0
+ error:&err];
+
+ NSDictionary *settings = nil;
+ if(!err) {
+ settings = [NSPropertyListSerialization propertyListWithData:plist
+ options:NSPropertyListImmutable
+ format:NULL
+ error:&err];
+ }
+
+ if(!err) {
+ [self applySettingsFromDictionary:settings error:&err];
+ if(!err) return;
+ }
+
+ // give an explanation for some errors
+ if([[err domain] isEqualToString:SPErrorDomain]) {
+ if([err code] == SPErrorWrongTypeOrNil) {
+ NSDictionary *info = @{
+ NSLocalizedDescriptionKey: NSLocalizedString(@"Invalid file supplied!", @"export : import settings : file error title"),
+ NSLocalizedRecoverySuggestionErrorKey: NSLocalizedString(@"The selected file is either not a valid SPF file or severely corrupted.", @"export : import settings : file error description"),
+ };
+ err = [NSError errorWithDomain:[err domain] code:[err code] userInfo:info];
+ }
+ else if([err code] == SPErrorWrongContentType) {
+ NSDictionary *info = @{
+ NSLocalizedDescriptionKey: NSLocalizedString(@"Wrong SPF content type!", @"export : import settings : spf content type error title"),
+ NSLocalizedRecoverySuggestionErrorKey: [NSString stringWithFormat:NSLocalizedString(@"The selected file contains data of type “%1$@”, but type “%2$@” is needed. Please choose a different file.", @"export : import settings : spf content type error description"),[[err userInfo] objectForKey:@"isType"],[[err userInfo] objectForKey:@"expectedType"]],
+ };
+ err = [NSError errorWithDomain:[err domain] code:[err code] userInfo:info];
+ }
+ }
+
+ NSAlert *alert = [NSAlert alertWithError:err];
+ [alert setAlertStyle:NSCriticalAlertStyle];
+ [alert runModal];
+ }];
+}
+
+- (IBAction)exportCurrentSettings:(id)sender
+{
+ //show save file dialog
+ NSSavePanel *panel = [NSSavePanel savePanel];
+
+ [panel setAllowedFileTypes:@[SPFileExtensionDefault]];
+
+ [panel setExtensionHidden:NO];
+ [panel setAllowsOtherFileTypes:NO];
+ [panel setCanSelectHiddenExtension:YES];
+ [panel setCanCreateDirectories:YES];
+
+ [panel beginSheetModalForWindow:[self window] completionHandler:^(NSInteger returnCode) {
+ if(returnCode != NSFileHandlingPanelOKButton) return;
+
+ // Panel is still on screen. Hide it first. (This is Apple's recommended way)
+ [panel orderOut:nil];
+
+ NSError *err = nil;
+ NSData *plist = [NSPropertyListSerialization dataWithPropertyList:[self currentSettingsAsDictionary]
+ format:NSPropertyListXMLFormat_v1_0
+ options:0
+ error:&err];
+ if(!err) {
+ [plist writeToURL:[panel URL] options:NSAtomicWrite error:&err];
+ if(!err) return;
+ }
+
+ NSAlert *alert = [NSAlert alertWithError:err];
+ [alert setAlertStyle:NSCriticalAlertStyle];
+ [alert runModal];
+ }];
+}
+
+- (NSArray *)currentCustomFilenameAsArray
+{
+ NSArray *tokenListIn = [exportCustomFilenameTokenField objectValue];
+ NSMutableArray *tokenListOut = [NSMutableArray arrayWithCapacity:[tokenListIn count]];
+
+ for (id obj in tokenListIn) {
+ if([obj isKindOfClass:[NSString class]]) {
+ [tokenListOut addObject:obj];
+ }
+ else if([obj isKindOfClass:[SPExportFileNameTokenObject class]]) {
+ NSDictionary *tokenProperties = @{@"tokenId": [obj tokenId]};
+ // in the future the dict can be used to store per-token settings
+ [tokenListOut addObject:tokenProperties];
+ }
+ else {
+ SPLog(@"unknown object in token list: %@",obj);
+ }
+ }
+
+ return tokenListOut;
+}
+
+- (void)setCustomFilenameFromArray:(NSArray *)tokenList
+{
+ NSMutableArray *tokenListOut = [NSMutableArray arrayWithCapacity:[tokenList count]];
+ NSArray *allowedTokens = [self currentAllowedExportFilenameTokens];
+
+ for (id obj in tokenList) {
+ if([obj isKindOfClass:[NSString class]]) {
+ [tokenListOut addObject:obj];
+ }
+ else if([obj isKindOfClass:[NSDictionary class]]) {
+ //there must be at least a non-empty tokenId that is also in the token pool
+ NSString *tokenId = [obj objectForKey:@"tokenId"];
+ if([tokenId length]) {
+ SPExportFileNameTokenObject *token = [SPExportFileNameTokenObject tokenWithId:tokenId];
+ if([allowedTokens containsObject:token]) {
+ [tokenListOut addObject:token];
+ continue;
+ }
+ }
+ SPLog(@"Ignoring an invalid or unknown token with tokenId=%@",tokenId);
+ }
+ else {
+ SPLog(@"unknown object in import token list: %@",obj);
+ }
+ }
+
+ [exportCustomFilenameTokenField setObjectValue:tokenListOut];
+
+ [self updateDisplayedExportFilename];
+}
+
+- (NSDictionary *)currentSettingsAsDictionary
+{
+ NSMutableDictionary *root = [NSMutableDictionary dictionary];
+
+ [root setObject:SPFExportSettingsContentType forKey:SPFFormatKey];
+ [root setObject:@1 forKey:SPFVersionKey];
+
+ [root setObject:[exportPathField stringValue] forKey:@"exportPath"];
+
+ [root setObject:[[self class] describeExportSource:exportSource] forKey:@"exportSource"];
+ [root setObject:[[self class] describeExportType:exportType] forKey:@"exportType"];
+
+ if([[exportCustomFilenameTokenField stringValue] length] > 0) {
+ [root setObject:[self currentCustomFilenameAsArray] forKey:@"customFilename"];
+ }
+
+ [root setObject:[self exporterSettings] forKey:@"settings"];
+
+ if(exportSource == SPTableExport) {
+ NSMutableDictionary *perObjectSettings = [NSMutableDictionary dictionaryWithCapacity:[tables count]];
+
+ for (NSMutableArray *table in tables) {
+ NSString *key = [table objectAtIndex:0];
+ id settings = [self exporterSpecificSettingsForSchemaObject:key ofType:SPTableTypeTable];
+ if(settings)
+ [perObjectSettings setObject:settings forKey:key];
+ }
+
+ [root setObject:perObjectSettings forKey:@"schemaObjects"];
+ }
+
+ [root setObject:IsOn(exportProcessLowMemoryButton) forKey:@"lowMemoryStreaming"];
+ [root setObject:[[self class] describeCompressionFormat:(SPFileCompressionFormat)[exportOutputCompressionFormatPopupButton indexOfSelectedItem]] forKey:@"compressionFormat"];
+
+ return root;
+}
+
+- (BOOL)applySettingsFromDictionary:(NSDictionary *)dict error:(NSError **)err
+{
+ //check for dict/nil
+ if(![dict isKindOfClass:[NSDictionary class]]) {
+ if(err) {
+ *err = [NSError errorWithDomain:SPErrorDomain
+ code:SPErrorWrongTypeOrNil
+ userInfo:nil]; // we don't know where data came from, so we can't provide meaningful help to the user
+ }
+ return NO;
+ }
+
+ //check for export settings
+ NSString *ctype = [dict objectForKey:SPFFormatKey];
+ if (![SPFExportSettingsContentType isEqualToString:ctype]) {
+ if(err) {
+ NSDictionary *errInfo = @{
+ @"isType": ctype,
+ @"expectedType": SPFExportSettingsContentType
+ };
+ *err = [NSError errorWithDomain:SPErrorDomain
+ code:SPErrorWrongContentType
+ userInfo:errInfo];
+ }
+ return NO;
+ }
+
+ //check for version
+ NSInteger version = [[dict objectForKey:SPFVersionKey] integerValue];
+ if(version != 1) {
+ if(err) {
+ NSDictionary *errInfo = @{
+ @"isVersion": @(version),
+ NSLocalizedDescriptionKey: NSLocalizedString(@"Unsupported version for export settings!", @"export : import settings : file version error title"),
+ NSLocalizedRecoverySuggestionErrorKey: [NSString stringWithFormat:NSLocalizedString(@"The selected export settings were stored with version\u00A0%1$ld, but only settings with the following versions can be imported: %2$@.\n\nEither save the settings in a backwards compatible way or update your version of Sequel Pro.", @"export : import settings : file version error description ($1 = is version, $2 = list of supported versions); note: the u00A0 is a non-breaking space, do not add more whitespace."),version,@"1"],
+ };
+ *err = [NSError errorWithDomain:SPErrorDomain
+ code:SPErrorWrongContentVersion
+ userInfo:errInfo];
+ }
+ return NO;
+ }
+
+ //ok, we can try to import that...
+
+ [exporters removeAllObjects];
+ [exportFiles removeAllObjects];
+
+ id o;
+ if((o = [dict objectForKey:@"exportPath"])) [exportPathField setStringValue:o];
+
+ SPExportType et;
+ if((o = [dict objectForKey:@"exportType"]) && [[self class] copyExportTypeForDescription:o to:&et]) {
+ [exportTypeTabBar selectTabViewItemAtIndex:et];
+ }
+
+ //exportType should be changed first, as exportSource depends on it
+ SPExportSource es;
+ if((o = [dict objectForKey:@"exportSource"]) && [[self class] copyExportSourceForDescription:o to:&es]) {
+ [self setExportInput:es]; //try to set it. might fail e.g. if the settings were saved with "query result" but right now no custom query result exists
+ }
+
+ // set exporter specific settings
+ [self applyExporterSettings:[dict objectForKey:@"settings"]];
+
+ // load schema object settings
+ if(exportSource == SPTableExport) {
+ NSDictionary *perObjectSettings = [dict objectForKey:@"schemaObjects"];
+
+ for (NSString *table in [perObjectSettings allKeys]) {
+ id settings = [perObjectSettings objectForKey:table];
+ [self applyExporterSpecificSettings:settings forSchemaObject:table ofType:SPTableTypeTable];
+ }
+
+ [exportTableList reloadData];
+ }
+
+ if((o = [dict objectForKey:@"lowMemoryStreaming"])) [exportProcessLowMemoryButton setState:([o boolValue] ? NSOnState : NSOffState)];
+
+ SPFileCompressionFormat cf;
+ if((o = [dict objectForKey:@"compressionFormat"]) && [[self class] copyCompressionFormatForDescription:o to:&cf]) [exportOutputCompressionFormatPopupButton selectItemAtIndex:cf];
+
+ // might have changed
+ [self _updateExportAdvancedOptionsLabel];
+
+ // token pool is only valid once the schema object selection is done
+ [self updateAvailableExportFilenameTokens];
+ if((o = [dict objectForKey:@"customFilename"]) && [o isKindOfClass:[NSArray class]]) [self setCustomFilenameFromArray:o];
+
+ return YES;
+}
+
+- (NSDictionary *)exporterSettings
+{
+ switch (exportType) {
+ case SPCSVExport:
+ return [self csvSettings];
+ case SPSQLExport:
+ return [self sqlSettings];
+ case SPXMLExport:
+ return [self xmlSettings];
+ case SPDotExport:
+ return [self dotSettings];
+ case SPExcelExport:
+ case SPHTMLExport:
+ case SPPDFExport:
+ default:
+ @throw [NSException exceptionWithName:NSInternalInconsistencyException
+ reason:@"exportType not implemented!"
+ userInfo:@{@"exportType": @(exportType)}];
+ }
+}
+
+- (void)applyExporterSettings:(NSDictionary *)settings
+{
+ switch (exportType) {
+ case SPCSVExport:
+ return [self applyCsvSettings:settings];
+ case SPSQLExport:
+ return [self applySqlSettings:settings];
+ case SPXMLExport:
+ return [self applyXmlSettings:settings];
+ case SPDotExport:
+ return [self applyDotSettings:settings];
+ case SPExcelExport:
+ case SPHTMLExport:
+ case SPPDFExport:
+ default:
+ @throw [NSException exceptionWithName:NSInternalInconsistencyException
+ reason:@"exportType not implemented!"
+ userInfo:@{@"exportType": @(exportType)}];
+ }
+}
+
+- (NSDictionary *)csvSettings
+{
+ return @{
+ @"exportToMultipleFiles": IsOn(exportFilePerTableCheck),
+ @"CSVIncludeFieldNames": IsOn(exportCSVIncludeFieldNamesCheck),
+ @"CSVFieldsTerminated": [exportCSVFieldsTerminatedField stringValue],
+ @"CSVFieldsWrapped": [exportCSVFieldsWrappedField stringValue],
+ @"CSVLinesTerminated": [exportCSVLinesTerminatedField stringValue],
+ @"CSVFieldsEscaped": [exportCSVFieldsEscapedField stringValue],
+ @"CSVNULLValuesAsText": [exportCSVNULLValuesAsTextField stringValue]
+ };
+}
+
+- (void)applyCsvSettings:(NSDictionary *)settings
+{
+ id o;
+ if((o = [settings objectForKey:@"exportToMultipleFiles"])) SetOnOff(o,exportFilePerTableCheck);
+ [self toggleNewFilePerTable:nil];
+
+ if((o = [settings objectForKey:@"CSVIncludeFieldNames"])) SetOnOff(o, exportCSVIncludeFieldNamesCheck);
+ if((o = [settings objectForKey:@"CSVFieldsTerminated"])) [exportCSVFieldsTerminatedField setStringValue:o];
+ if((o = [settings objectForKey:@"CSVFieldsWrapped"])) [exportCSVFieldsWrappedField setStringValue:o];
+ if((o = [settings objectForKey:@"CSVLinesTerminated"])) [exportCSVLinesTerminatedField setStringValue:o];
+ if((o = [settings objectForKey:@"CSVFieldsEscaped"])) [exportCSVFieldsEscapedField setStringValue:o];
+ if((o = [settings objectForKey:@"CSVNULLValuesAsText"])) [exportCSVNULLValuesAsTextField setStringValue:o];
+}
+
+- (NSDictionary *)dotSettings
+{
+ return @{@"DotForceLowerTableNames": IsOn(exportDotForceLowerTableNamesCheck)};
+}
+
+- (void)applyDotSettings:(NSDictionary *)settings
+{
+ id o;
+ if((o = [settings objectForKey:@"DotForceLowerTableNames"])) SetOnOff(o, exportDotForceLowerTableNamesCheck);
+}
+
+- (NSDictionary *)xmlSettings
+{
+ return @{
+ @"exportToMultipleFiles": IsOn(exportFilePerTableCheck),
+ @"XMLFormat": [[self class] describeXMLExportFormat:(SPXMLExportFormat)[exportXMLFormatPopUpButton indexOfSelectedItem]],
+ @"XMLOutputIncludeStructure": IsOn(exportXMLIncludeStructure),
+ @"XMLOutputIncludeContent": IsOn(exportXMLIncludeContent),
+ @"XMLNULLString": [exportXMLNULLValuesAsTextField stringValue]
+ };
+}
+
+- (void)applyXmlSettings:(NSDictionary *)settings
+{
+ id o;
+ SPXMLExportFormat xmlf;
+ if((o = [settings objectForKey:@"exportToMultipleFiles"])) SetOnOff(o, exportFilePerTableCheck);
+ [self toggleNewFilePerTable:nil];
+
+ if((o = [settings objectForKey:@"XMLFormat"]) && [[self class] copyXMLExportFormatForDescription:o to:&xmlf]) [exportXMLFormatPopUpButton selectItemAtIndex:xmlf];
+ if((o = [settings objectForKey:@"XMLOutputIncludeStructure"])) SetOnOff(o, exportXMLIncludeStructure);
+ if((o = [settings objectForKey:@"XMLOutputIncludeContent"])) SetOnOff(o, exportXMLIncludeContent);
+ if((o = [settings objectForKey:@"XMLNULLString"])) [exportXMLNULLValuesAsTextField setStringValue:o];
+
+ [self toggleXMLOutputFormat:exportXMLFormatPopUpButton];
+}
+
+- (NSDictionary *)sqlSettings
+{
+ BOOL includeStructure = ([exportSQLIncludeStructureCheck state] == NSOnState);
+
+ NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:@{
+ @"SQLIncludeStructure": IsOn(exportSQLIncludeStructureCheck),
+ @"SQLIncludeContent": IsOn(exportSQLIncludeContentCheck),
+ @"SQLIncludeErrors": IsOn(exportSQLIncludeErrorsCheck),
+ @"SQLIncludeDROP": IsOn(exportSQLIncludeDropSyntaxCheck),
+ @"SQLUseUTF8BOM": IsOn(exportUseUTF8BOMButton),
+ @"SQLBLOBFieldsAsHex": IsOn(exportSQLBLOBFieldsAsHexCheck),
+ @"SQLInsertNValue": @([exportSQLInsertNValueTextField integerValue]),
+ @"SQLInsertDivider": [[self class] describeSQLExportInsertDivider:(SPSQLExportInsertDivider)[exportSQLInsertDividerPopUpButton indexOfSelectedItem]]
+ }];
+
+ if(includeStructure) {
+ [dict addEntriesFromDictionary:@{
+ @"SQLIncludeAutoIncrementValue": IsOn(exportSQLIncludeAutoIncrementValueButton),
+ @"SQLIncludeDropSyntax": IsOn(exportSQLIncludeDropSyntaxCheck)
+ }];
+ }
+
+ return dict;
+}
+
+- (void)applySqlSettings:(NSDictionary *)settings
+{
+ id o;
+ SPSQLExportInsertDivider div;
+
+ if((o = [settings objectForKey:@"SQLIncludeContent"])) SetOnOff(o, exportSQLIncludeContentCheck);
+ [self toggleSQLIncludeContent:exportSQLIncludeContentCheck];
+
+ if((o = [settings objectForKey:@"SQLIncludeDROP"])) SetOnOff(o, exportSQLIncludeDropSyntaxCheck);
+ [self toggleSQLIncludeDropSyntax:exportSQLIncludeDropSyntaxCheck];
+
+ if((o = [settings objectForKey:@"SQLIncludeStructure"])) SetOnOff(o, exportSQLIncludeStructureCheck);
+ [self toggleSQLIncludeStructure:exportSQLIncludeStructureCheck];
+
+ if((o = [settings objectForKey:@"SQLIncludeErrors"])) SetOnOff(o, exportSQLIncludeErrorsCheck);
+ if((o = [settings objectForKey:@"SQLUseUTF8BOM"])) SetOnOff(o, exportUseUTF8BOMButton);
+ if((o = [settings objectForKey:@"SQLBLOBFieldsAsHex"])) SetOnOff(o, exportSQLBLOBFieldsAsHexCheck);
+ if((o = [settings objectForKey:@"SQLInsertNValue"])) [exportSQLInsertNValueTextField setIntegerValue:[o integerValue]];
+ if((o = [settings objectForKey:@"SQLInsertDivider"]) && [[self class] copySQLExportInsertDividerForDescription:o to:&div]) [exportSQLInsertDividerPopUpButton selectItemAtIndex:div];
+
+ if([exportSQLIncludeStructureCheck state] == NSOnState) {
+ if((o = [settings objectForKey:@"SQLIncludeAutoIncrementValue"])) SetOnOff(o, exportSQLIncludeAutoIncrementValueButton);
+ if((o = [settings objectForKey:@"SQLIncludeDropSyntax"])) SetOnOff(o, exportSQLIncludeDropSyntaxCheck);
+ }
+}
+
+- (id)exporterSpecificSettingsForSchemaObject:(NSString *)name ofType:(SPTableType)type
+{
+ switch (exportType) {
+ case SPCSVExport:
+ return [self csvSpecificSettingsForSchemaObject:name ofType:type];
+ case SPSQLExport:
+ return [self sqlSpecificSettingsForSchemaObject:name ofType:type];
+ case SPXMLExport:
+ return [self xmlSpecificSettingsForSchemaObject:name ofType:type];
+ case SPDotExport:
+ return [self dotSpecificSettingsForSchemaObject:name ofType:type];
+ case SPExcelExport:
+ case SPHTMLExport:
+ case SPPDFExport:
+ default:
+ @throw [NSException exceptionWithName:NSInternalInconsistencyException
+ reason:@"exportType not implemented!"
+ userInfo:@{@"exportType": @(exportType)}];
+ }
+}
+
+- (void)applyExporterSpecificSettings:(id)settings forSchemaObject:(NSString *)name ofType:(SPTableType)type
+{
+ switch (exportType) {
+ case SPCSVExport:
+ return [self applyCsvSpecificSettings:settings forSchemaObject:name ofType:type];
+ case SPSQLExport:
+ return [self applySqlSpecificSettings:settings forSchemaObject:name ofType:type];
+ case SPXMLExport:
+ return [self applyXmlSpecificSettings:settings forSchemaObject:name ofType:type];
+ case SPDotExport:
+ return [self applyDotSpecificSettings:settings forSchemaObject:name ofType:type];
+ case SPExcelExport:
+ case SPHTMLExport:
+ case SPPDFExport:
+ default:
+ @throw [NSException exceptionWithName:NSInternalInconsistencyException
+ reason:@"exportType not implemented!"
+ userInfo:@{@"exportType": @(exportType)}];
+ }
+}
+
+- (id)dotSpecificSettingsForSchemaObject:(NSString *)name ofType:(SPTableType)type
+{
+ // Dot is a graph of the whole database - nothing to pick from
+ return nil;
+}
+
+- (void)applyDotSpecificSettings:(id)settings forSchemaObject:(NSString *)name ofType:(SPTableType)type
+{
+ //should never be called
+}
+
+- (id)xmlSpecificSettingsForSchemaObject:(NSString *)name ofType:(SPTableType)type
+{
+ // XML per table setting is only yes/no
+ if(type == SPTableTypeTable) {
+ // we have to look through the table views' rows to find the current checkbox value...
+ for (NSArray *table in tables) {
+ if([[table objectAtIndex:0] isEqualTo:name]) {
+ return @([[table objectAtIndex:2] boolValue]);
+ }
+ }
+ }
+ return nil;
+}
+
+- (void)applyXmlSpecificSettings:(id)settings forSchemaObject:(NSString *)name ofType:(SPTableType)type
+{
+ // XML per table setting is only yes/no
+ if(type == SPTableTypeTable) {
+ // we have to look through the table views' rows to find the appropriate table...
+ for (NSMutableArray *table in tables) {
+ if([[table objectAtIndex:0] isEqualTo:name]) {
+ [table replaceObjectAtIndex:2 withObject:@([settings boolValue])];
+ return;
+ }
+ }
+ }
+}
+
+- (id)csvSpecificSettingsForSchemaObject:(NSString *)name ofType:(SPTableType)type
+{
+ // CSV per table setting is only yes/no
+ if(type == SPTableTypeTable) {
+ // we have to look through the table views rows to find the current checkbox value...
+ for (NSArray *table in tables) {
+ if([[table objectAtIndex:0] isEqualTo:name]) {
+ return @([[table objectAtIndex:2] boolValue]);
+ }
+ }
+ }
+ return nil;
+}
+
+- (void)applyCsvSpecificSettings:(id)settings forSchemaObject:(NSString *)name ofType:(SPTableType)type
+{
+ // CSV per table setting is only yes/no
+ if(type == SPTableTypeTable) {
+ // we have to look through the table views' rows to find the appropriate table...
+ for (NSMutableArray *table in tables) {
+ if([[table objectAtIndex:0] isEqualTo:name]) {
+ [table replaceObjectAtIndex:2 withObject:@([settings boolValue])];
+ return;
+ }
+ }
+ }
+}
+
+- (id)sqlSpecificSettingsForSchemaObject:(NSString *)name ofType:(SPTableType)type
+{
+ BOOL structure = ([exportSQLIncludeStructureCheck state] == NSOnState);
+ BOOL content = ([exportSQLIncludeContentCheck state] == NSOnState);
+ BOOL drop = ([exportSQLIncludeDropSyntaxCheck state] == NSOnState);
+
+ // SQL allows per table setting of structure/content/drop table
+ if(type == SPTableTypeTable) {
+ // we have to look through the table views rows to find the current checkbox value...
+ for (NSArray *table in tables) {
+ if([[table objectAtIndex:0] isEqualTo:name]) {
+ NSMutableArray *flags = [NSMutableArray arrayWithCapacity:3];
+
+ if (structure && [[table objectAtIndex:1] boolValue]) {
+ [flags addObject:@"structure"];
+ }
+
+ if (content && [[table objectAtIndex:2] boolValue]) {
+ [flags addObject:@"content"];
+ }
+
+ if (drop && [[table objectAtIndex:3] boolValue]) {
+ [flags addObject:@"drop"];
+ }
+
+ return flags;
+ }
+ }
+ }
+ return nil;
+}
+
+- (void)applySqlSpecificSettings:(id)settings forSchemaObject:(NSString *)name ofType:(SPTableType)type
+{
+ BOOL structure = ([exportSQLIncludeStructureCheck state] == NSOnState);
+ BOOL content = ([exportSQLIncludeContentCheck state] == NSOnState);
+ BOOL drop = ([exportSQLIncludeDropSyntaxCheck state] == NSOnState);
+
+ // SQL allows per table setting of structure/content/drop table
+ if(type == SPTableTypeTable) {
+ // we have to look through the table views' rows to find the appropriate table...
+ for (NSMutableArray *table in tables) {
+ if([[table objectAtIndex:0] isEqualTo:name]) {
+ NSArray *flags = settings;
+
+ [table replaceObjectAtIndex:1 withObject:@((structure && [flags containsObject:@"structure"]))];
+ [table replaceObjectAtIndex:2 withObject:@((content && [flags containsObject:@"content"]))];
+ [table replaceObjectAtIndex:3 withObject:@((drop && [flags containsObject:@"drop"]))];
+ return;
+ }
+ }
+ }
+}
+
+#pragma mark - SPCSVExporterDelegate
+
+- (void)csvExportProcessWillBegin:(SPCSVExporter *)exporter
+{
+ [exportProgressText displayIfNeeded];
+
+ [exportProgressIndicator setIndeterminate:YES];
+ [exportProgressIndicator setUsesThreadedAnimation:YES];
+ [exportProgressIndicator startAnimation:self];
+
+ // Only update the progress text if this is a table export
+ if (exportSource == SPTableExport) {
+ // Update the current table export index
+ currentTableExportIndex = (exportTableCount - [exporters count]);
+
+ [exportProgressText setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Table %lu of %lu (%@): Fetching data...", @"export label showing that the app is fetching data for a specific table"), currentTableExportIndex, exportTableCount, [exporter csvTableName]]];
+ }
+ else {
+ [exportProgressText setStringValue:NSLocalizedString(@"Fetching data...", @"export label showing that the app is fetching data")];
+ }
+
+ [exportProgressText displayIfNeeded];
+}
+
+- (void)csvExportProcessComplete:(SPCSVExporter *)exporter
+{
+ NSUInteger exportCount = [exporters count];
+
+ // If required add the next exporter to the operation queue
+ if ((exportCount > 0) && (exportSource == SPTableExport)) {
+
+ // If we're only exporting to a single file then write a header for the next table
+ if (!exportToMultipleFiles) {
+
+ // If we're exporting multiple tables to a single file then append some space and the next table's
+ // name, but only if there is at least 2 exportes left.
+ [[exporter exportOutputFile] writeData:[[NSString stringWithFormat:@"%@%@%@ %@%@%@",
+ [exporter csvLineEndingString],
+ [exporter csvLineEndingString],
+ NSLocalizedString(@"Table", @"csv export table heading"),
+ [(SPCSVExporter *)[exporters objectAtIndex:0] csvTableName],
+ [exporter csvLineEndingString],
+ [exporter csvLineEndingString]] dataUsingEncoding:[exporter exportOutputEncoding]]];
+ }
+ // Otherwise close the file handle of the exporter that just finished
+ // ensuring it's data is written to disk.
+ else {
+ [[exporter exportOutputFile] close];
+ }
+
+ [operationQueue addOperation:[exporters objectAtIndex:0]];
+
+ // Remove the exporter we just added to the operation queue from our list of exporters
+ // so we know it's already been done.
+ [exporters removeObjectAtIndex:0];
+ }
+ // Otherwise if the exporter list is empty, close the progress sheet
+ else {
+ // Close the last exporter's file handle
+ [[exporter exportOutputFile] close];
+
+ [self exportEnded];
+ }
+}
+
+- (void)csvExportProcessWillBeginWritingData:(SPCSVExporter *)exporter
+{
+ // Only update the progress text if this is a table export
+ if (exportSource == SPTableExport) {
+ [exportProgressText setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Table %lu of %lu (%@): Writing data...", @"export label showing app if writing data for a specific table"), currentTableExportIndex, exportTableCount, [exporter csvTableName]]];
+ }
+ else {
+ [exportProgressText setStringValue:NSLocalizedString(@"Writing data...", @"export label showing app is writing data")];
+ }
+
+ [exportProgressText displayIfNeeded];
+
+ [exportProgressIndicator stopAnimation:self];
+ [exportProgressIndicator setUsesThreadedAnimation:NO];
+ [exportProgressIndicator setIndeterminate:NO];
+ [exportProgressIndicator setDoubleValue:0];
+}
+
+- (void)csvExportProcessProgressUpdated:(SPCSVExporter *)exporter
+{
+ [exportProgressIndicator setDoubleValue:[exporter exportProgressValue]];
+}
+
+#pragma mark - SPSQLExporterDelegate
+
+- (void)sqlExportProcessWillBegin:(SPSQLExporter *)exporter
+{
+ [exportProgressTitle setStringValue:NSLocalizedString(@"Exporting SQL", @"text showing that the application is exporting SQL")];
+ [exportProgressText setStringValue:NSLocalizedString(@"Dumping...", @"text showing that app is writing dump")];
+
+ [exportProgressTitle displayIfNeeded];
+ [exportProgressText displayIfNeeded];
+}
+
+- (void)sqlExportProcessComplete:(SPSQLExporter *)exporter
+{
+ [self exportEnded];
+
+ // Check for errors and display the errors sheet if necessary
+ if ([exporter didExportErrorsOccur]) {
+ [self openExportErrorsSheetWithString:[exporter sqlExportErrors]];
+ }
+}
+
+- (void)sqlExportProcessProgressUpdated:(SPSQLExporter *)exporter
+{
+ if ([exportProgressIndicator doubleValue] == 0) {
+ [exportProgressIndicator stopAnimation:self];
+ [exportProgressIndicator setIndeterminate:NO];
+ }
+
+ [exportProgressIndicator setDoubleValue:[exporter exportProgressValue]];
+}
+
+- (void)sqlExportProcessWillBeginFetchingData:(SPSQLExporter *)exporter
+{
+ [exportProgressText setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Table %lu of %lu (%@): Fetching data...", @"export label showing that the app is fetching data for a specific table"), [exporter sqlCurrentTableExportIndex], exportTableCount, [exporter sqlExportCurrentTable]]];
+
+ [exportProgressIndicator startAnimation:self];
+ [exportProgressIndicator setUsesThreadedAnimation:YES];
+ [exportProgressIndicator setIndeterminate:YES];
+ [exportProgressIndicator setDoubleValue:0];
+}
+
+- (void)sqlExportProcessWillBeginWritingData:(SPSQLExporter *)exporter
+{
+ [exportProgressText setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Table %lu of %lu (%@): Writing data...", @"export label showing app if writing data for a specific table"), [exporter sqlCurrentTableExportIndex], exportTableCount, [exporter sqlExportCurrentTable]]];
+}
+
+#pragma mark - SPXMLExporterDelegate
+
+- (void)xmlExportProcessWillBegin:(SPXMLExporter *)exporter
+{
+ [exportProgressText displayIfNeeded];
+
+ [exportProgressIndicator setIndeterminate:YES];
+ [exportProgressIndicator setUsesThreadedAnimation:YES];
+ [exportProgressIndicator startAnimation:self];
+
+ // Only update the progress text if this is a table export
+ if (exportSource == SPTableExport) {
+
+ // Update the current table export index
+ currentTableExportIndex = (exportTableCount - [exporters count]);
+
+ [exportProgressText setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Table %lu of %lu (%@): Fetching data...", @"export label showing that the app is fetching data for a specific table"), currentTableExportIndex, exportTableCount, [exporter xmlTableName]]];
+ }
+ else {
+ [exportProgressText setStringValue:NSLocalizedString(@"Fetching data...", @"export label showing that the app is fetching data")];
+ }
+
+ [exportProgressText displayIfNeeded];
+}
+
+- (void)xmlExportProcessComplete:(SPXMLExporter *)exporter
+{
+ NSUInteger exportCount = [exporters count];
+
+ // If required add the next exporter to the operation queue
+ if ((exportCount > 0) && (exportSource == SPTableExport)) {
+
+ // If we're exporting to multiple files then close the file handle of the exporter
+ // that just finished, ensuring its data is written to disk.
+ if (exportToMultipleFiles) {
+ NSString *string = @"";
+
+ if ([exporter xmlFormat] == SPXMLExportMySQLFormat) {
+ string = (exportSource == SPTableExport) ? @"</database>\n</mysqldump>\n" : @"</resultset>\n";;
+ }
+ else if ([exporter xmlFormat] == SPXMLExportPlainFormat) {
+ string = [NSString stringWithFormat:@"</%@>\n", [[tableDocumentInstance database] HTMLEscapeString]];
+ }
+
+ [[exporter exportOutputFile] writeData:[string dataUsingEncoding:[connection stringEncoding]]];
+ [[exporter exportOutputFile] close];
+ }
+
+ [operationQueue addOperation:[exporters objectAtIndex:0]];
+
+ // Remove the exporter we just added to the operation queue from our list of exporters
+ // so we know it's already been done.
+ [exporters removeObjectAtIndex:0];
+ }
+ // Otherwise if the exporter list is empty, close the progress sheet
+ else {
+ NSString *string = @"";
+
+ if ([exporter xmlFormat] == SPXMLExportMySQLFormat) {
+ string = (exportSource == SPTableExport) ? @"</database>\n</mysqldump>\n" : @"</resultset>\n";;
+ }
+ else if ([exporter xmlFormat] == SPXMLExportPlainFormat) {
+ string = [NSString stringWithFormat:@"</%@>\n", [[tableDocumentInstance database] HTMLEscapeString]];
+ }
+
+ [[exporter exportOutputFile] writeData:[string dataUsingEncoding:[connection stringEncoding]]];
+ [[exporter exportOutputFile] close];
+
+ [self exportEnded];
+ }
+}
+
+- (void)xmlExportProcessProgressUpdated:(SPXMLExporter *)exporter
+{
+ [[exportProgressIndicator onMainThread] setDoubleValue:[exporter exportProgressValue]];
+}
+
+- (void)xmlExportProcessWillBeginWritingData:(SPXMLExporter *)exporter
+{
+ // Only update the progress text if this is a table export
+ if (exportSource == SPTableExport) {
+ [exportProgressText setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Table %lu of %lu (%@): Writing data...", @"export label showing app if writing data for a specific table"), currentTableExportIndex, exportTableCount, [exporter xmlTableName]]];
+ }
+ else {
+ [exportProgressText setStringValue:NSLocalizedString(@"Writing data...", @"export label showing app is writing data")];
+ }
+
+ [exportProgressText displayIfNeeded];
+
+ [exportProgressIndicator stopAnimation:self];
+ [exportProgressIndicator setUsesThreadedAnimation:NO];
+ [exportProgressIndicator setIndeterminate:NO];
+ [exportProgressIndicator setDoubleValue:0];
+}
+
+#pragma mark - SPDotExporterDelegate
+
+- (void)dotExportProcessWillBegin:(SPDotExporter *)exporter
+{
+ [exportProgressTitle setStringValue:NSLocalizedString(@"Exporting Dot File", @"text showing that the application is exporting a Dot file")];
+ [exportProgressText setStringValue:NSLocalizedString(@"Dumping...", @"text showing that app is writing dump")];
+
+ [exportProgressTitle displayIfNeeded];
+ [exportProgressText displayIfNeeded];
+ [exportProgressIndicator stopAnimation:self];
+ [exportProgressIndicator setIndeterminate:NO];
+}
+
+- (void)dotExportProcessComplete:(SPDotExporter *)exporter
+{
+ [self exportEnded];
+}
+
+- (void)dotExportProcessProgressUpdated:(SPDotExporter *)exporter
+{
+ [exportProgressIndicator setDoubleValue:[exporter exportProgressValue]];
+}
+
+- (void)dotExportProcessWillBeginFetchingData:(SPDotExporter *)exporter forTableWithIndex:(NSUInteger)tableIndex
+{
+ // Update the current table export index
+ currentTableExportIndex = tableIndex;
+
+ [exportProgressText setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Table %lu of %lu (%@): Fetching data...", @"export label showing that the app is fetching data for a specific table"), currentTableExportIndex, exportTableCount, [exporter dotExportCurrentTable]]];
+
+ [exportProgressText displayIfNeeded];
+}
+
+- (void)dotExportProcessWillBeginFetchingRelationsData:(SPDotExporter *)exporter
+{
+ [exportProgressText setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Table %lu of %lu (%@): Fetching relations data...", @"export label showing app is fetching relations data for a specific table"), currentTableExportIndex, exportTableCount, [exporter dotExportCurrentTable]]];
+
+ [exportProgressText displayIfNeeded];
+ [exportProgressIndicator setIndeterminate:YES];
+ [exportProgressIndicator setUsesThreadedAnimation:YES];
+ [exportProgressIndicator startAnimation:self];
+}
+
+#pragma mark - SPPDFExporterDelegate
+
+- (void)pdfExportProcessWillBegin:(SPPDFExporter *)exporter
+{
+}
+
+- (void)pdfExportProcessComplete:(SPPDFExporter *)exporter
+{
+ [self exportEnded];
+}
+
+- (void)pdfExportProcessWillBeginWritingData:(SPPDFExporter *)exporter
+{
+}
+
+#pragma mark - SPHTMLExporterDelegate
+
+- (void)htmlExportProcessWillBegin:(SPHTMLExporter *)exporter
+{
+}
+
+- (void)htmlExportProcessComplete:(SPHTMLExporter *)exporter
+{
+ [self exportEnded];
+}
+
+- (void)htmlExportProcessWillBeginWritingData:(SPHTMLExporter *)exporter
+{
+}
+
#pragma mark -
- (void)dealloc
@@ -1090,3 +3755,25 @@ set_input:
}
@end
+
+#pragma mark -
+
+BOOL IS_TOKEN(id x)
+{
+ return [x isKindOfClass:[SPExportFileNameTokenObject class]];
+}
+
+BOOL IS_STRING(id x)
+{
+ return [x isKindOfClass:[NSString class]];
+}
+
+NSNumber *IsOn(id obj)
+{
+ return (([obj state] == NSOnState)? @YES : @NO);
+}
+
+void SetOnOff(NSNumber *ref,id obj)
+{
+ [obj setState:([ref boolValue] ? NSOnState : NSOffState)];
+}
diff --git a/Source/SPExportControllerDelegate.h b/Source/SPExportControllerDelegate.h
deleted file mode 100644
index 69be91d4..00000000
--- a/Source/SPExportControllerDelegate.h
+++ /dev/null
@@ -1,42 +0,0 @@
-//
-// SPExportControllerDelegate.h
-// sequel-pro
-//
-// Created by Stuart Connolly (stuconnolly.com) on October 23, 2010.
-// Copyright (c) 2010 Stuart Connolly. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person
-// obtaining a copy of this software and associated documentation
-// files (the "Software"), to deal in the Software without
-// restriction, including without limitation the rights to use,
-// copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following
-// conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-// OTHER DEALINGS IN THE SOFTWARE.
-//
-// More info at <https://github.com/sequelpro/sequelpro>
-
-#import "SPExportController.h"
-
-/**
- * @category SPExportControllerDelegate SPExportControllerDelegate.h
- *
- * @author Stuart Connolly http://stuconnolly.com/
- *
- * Export controller delegate category.
- */
-@interface SPExportController (SPExportControllerDelegate)
-
-@end
diff --git a/Source/SPExportControllerDelegate.m b/Source/SPExportControllerDelegate.m
deleted file mode 100644
index 8c020fc3..00000000
--- a/Source/SPExportControllerDelegate.m
+++ /dev/null
@@ -1,359 +0,0 @@
-//
-// SPExportControllerDelegate.m
-// sequel-pro
-//
-// Created by Stuart Connolly (stuconnolly.com) on October 23, 2010.
-// Copyright (c) 2010 Stuart Connolly. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person
-// obtaining a copy of this software and associated documentation
-// files (the "Software"), to deal in the Software without
-// restriction, including without limitation the rights to use,
-// copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following
-// conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-// OTHER DEALINGS IN THE SOFTWARE.
-//
-// More info at <https://github.com/sequelpro/sequelpro>
-
-#import "SPExportControllerDelegate.h"
-#import "SPExportFilenameUtilities.h"
-#import "SPExportFileNameTokenObject.h"
-
-static inline BOOL IS_TOKEN(id x);
-static inline BOOL IS_STRING(id x);
-
-// Defined to suppress warnings
-@interface SPExportController (SPExportControllerPrivateAPI)
-
-- (void)_toggleExportButtonOnBackgroundThread;
-- (void)_toggleSQLExportTableNameTokenAvailability;
-- (void)_updateExportFormatInformation;
-- (void)_switchTab;
-- (NSArray *)_updateTokensForMixedContent:(NSArray *)tokens;
-- (void)_tokenizeCustomFilenameTokenField;
-
-@end
-
-@implementation SPExportController (SPExportControllerDelegate)
-
-#pragma mark -
-#pragma mark Table view datasource methods
-
-- (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView;
-{
- return [tables count];
-}
-
-- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)rowIndex
-{
- return NSArrayObjectAtIndex([tables objectAtIndex:rowIndex], [exportTableList columnWithIdentifier:[tableColumn identifier]]);
-}
-
-- (void)tableView:(NSTableView *)tableView setObjectValue:(id)anObject forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)rowIndex
-{
- [[tables objectAtIndex:rowIndex] replaceObjectAtIndex:[exportTableList columnWithIdentifier:[tableColumn identifier]] withObject:anObject];
-
- [self updateAvailableExportFilenameTokens];
- [self _toggleExportButtonOnBackgroundThread];
- [self _updateExportFormatInformation];
-}
-
-#pragma mark -
-#pragma mark Table view delegate methods
-
-- (BOOL)tableView:(NSTableView *)tableView shouldTrackCell:(NSCell *)cell forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)rowIndex
-{
- return (tableView == exportTableList);
-}
-
-- (void)tableView:(NSTableView *)tableView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)rowIndex
-{
- [cell setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];
-}
-
-#pragma mark -
-#pragma mark Tabview delegate methods
-
-- (void)tabView:(NSTabView *)tabView didSelectTabViewItem:(NSTabViewItem *)tabViewItem
-{
- [tabViewItem setView:exporterView];
-
- [self _switchTab];
-}
-
-#pragma mark -
-#pragma mark Token field delegate methods
-
-/**
- * Use the default token style for matched tokens, plain text for all other text.
- */
-- (NSTokenStyle)tokenField:(NSTokenField *)tokenField styleForRepresentedObject:(id)representedObject
-{
- if (IS_TOKEN(representedObject)) return NSDefaultTokenStyle;
-
- return NSPlainTextTokenStyle;
-}
-
-- (BOOL)tokenField:(NSTokenField *)tokenField writeRepresentedObjects:(NSArray *)objects toPasteboard:(NSPasteboard *)pboard
-{
- NSMutableArray *mixed = [NSMutableArray arrayWithCapacity:[objects count]];
- NSMutableString *flatted = [NSMutableString string];
-
- for(id item in objects) {
- if(IS_TOKEN(item)) {
- [mixed addObject:@{@"tokenId": [item tokenId]}];
- [flatted appendFormat:@"{%@}",[item tokenId]];
- }
- else if(IS_STRING(item)) {
- [mixed addObject:item];
- [flatted appendString:item];
- }
- else {
- [NSException raise:NSInternalInconsistencyException format:@"tokenField %@ contains unexpected object %@",tokenField,item];
- }
- }
-
- [pboard setString:flatted forType:NSPasteboardTypeString];
- [pboard setPropertyList:mixed forType:SPExportCustomFileNameTokenPlistType];
- return YES;
-}
-
-- (NSArray *)tokenField:(NSTokenField *)tokenField readFromPasteboard:(NSPasteboard *)pboard
-{
- NSArray *items = [pboard propertyListForType:SPExportCustomFileNameTokenPlistType];
- // if we have our preferred object type use it
- if(items) {
- NSMutableArray *res = [NSMutableArray arrayWithCapacity:[items count]];
- for (id item in items) {
- if (IS_STRING(item)) {
- [res addObject:item];
- }
- else if([item isKindOfClass:[NSDictionary class]]) {
- NSString *name = [item objectForKey:@"tokenId"];
- if(name) {
- SPExportFileNameTokenObject *tok = [SPExportFileNameTokenObject tokenWithId:name];
- [res addObject:tok];
- }
- }
- else {
- [NSException raise:NSInternalInconsistencyException format:@"pasteboard %@ contains unexpected object %@",pboard,item];
- }
- }
- return res;
- }
- // if the string came from another app, paste it literal, tokenfield will take care of any conversions
- NSString *raw = [pboard stringForType:NSPasteboardTypeString];
- if(raw) {
- return @[[raw stringByReplacingCharactersInSet:[NSCharacterSet newlineCharacterSet] withString:@" "]];
- }
-
- return nil;
-}
-
-/**
- * Take the default suggestion of new tokens - all untokenized text, as no tokenizing character is set - and
- * split/recombine strings that contain tokens. This preserves all supplied characters and allows tokens to be typed.
- */
-- (NSArray *)tokenField:(NSTokenField *)tokenField shouldAddObjects:(NSArray *)tokens atIndex:(NSUInteger)index
-{
- return [self _updateTokensForMixedContent:tokens];
-}
-
-- (NSString *)tokenField:(NSTokenField *)tokenField displayStringForRepresentedObject:(id)representedObject
-{
- if (IS_TOKEN(representedObject)) {
- return [localizedTokenNames objectForKey:[(SPExportFileNameTokenObject *)representedObject tokenId]];
- }
-
- return representedObject;
-}
-
-/**
- * Return the editing string untouched - implementing this method prevents whitespace trimming.
- */
-- (id)tokenField:(NSTokenField *)tokenField representedObjectForEditingString:(NSString *)editingString
-{
- return editingString;
-}
-
-/**
- * During text entry into the token field, update the displayed filename and also
- * trigger tokenization after a short delay.
- */
-- (void)controlTextDidChange:(NSNotification *)notification
-{
- // this method can either be called by typing, or by copy&paste.
- // In the latter case tokenization will already be done by now.
- if ([notification object] == exportCustomFilenameTokenField) {
- [self updateDisplayedExportFilename];
- [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(_tokenizeCustomFilenameTokenField) object:nil];
- // do not queue a call if the key causing this change was the return key.
- // This is to prevent a loop with _tokenizeCustomFilenameTokenField.
- if([[NSApp currentEvent] type] != NSKeyDown || [[NSApp currentEvent] keyCode] != 0x24) {
- [self performSelector:@selector(_tokenizeCustomFilenameTokenField) withObject:nil afterDelay:0.5];
- }
- }
-}
-
-#pragma mark -
-#pragma mark Combo box delegate methods
-
-- (void)comboBoxSelectionDidChange:(NSNotification *)notification
-{
- if ([notification object] == exportCSVFieldsTerminatedField) {
- [self updateDisplayedExportFilename];
- }
-}
-
-#pragma mark -
-
-/**
- * Takes a mixed array of strings and tokens and converts
- * any valid tokens inside the strings into real tokens
- */
-- (NSArray *)_updateTokensForMixedContent:(NSArray *)tokens
-{
- //if two consecutive tokens are strings, merge them
- NSMutableArray *mergedTokens = [NSMutableArray array];
- for (id inputToken in tokens)
- {
- if(IS_TOKEN(inputToken)) {
- [mergedTokens addObject:inputToken];
- }
- else if(IS_STRING(inputToken)) {
- id prev = [mergedTokens lastObject];
- if(IS_STRING(prev)) {
- [mergedTokens removeLastObject];
- [mergedTokens addObject:[prev stringByAppendingString:inputToken]];
- }
- else {
- [mergedTokens addObject:inputToken];
- }
- }
- }
-
- // create a mapping dict of tokenId => token
- NSMutableDictionary *replacement = [NSMutableDictionary dictionary];
- for (SPExportFileNameTokenObject *realToken in [exportCustomFilenameTokenPool objectValue]) {
- NSString *serializedName = [NSString stringWithFormat:@"{%@}",[realToken tokenId]];
- [replacement setObject:realToken forKey:serializedName];
- }
-
- //now we can look for real tokens to convert inside the strings
- NSMutableArray *processedTokens = [NSMutableArray array];
- for (id token in mergedTokens) {
- if(IS_TOKEN(token)) {
- [processedTokens addObject:token];
- continue;
- }
-
- NSString *remainder = token;
- while(true) {
- NSRange openCurl = [remainder rangeOfString:@"{"];
- if(openCurl.location == NSNotFound) {
- break;
- }
- NSString *before = [remainder substringToIndex:openCurl.location];
- if([before length]) {
- [processedTokens addObject:before];
- }
- remainder = [remainder substringFromIndex:openCurl.location];
- NSRange closeCurl = [remainder rangeOfString:@"}"];
- if(closeCurl.location == NSNotFound) {
- break; //we've hit an unterminated token
- }
- NSString *tokenString = [remainder substringToIndex:closeCurl.location+1];
- SPExportFileNameTokenObject *tokenObject = [replacement objectForKey:tokenString];
- if(tokenObject) {
- [processedTokens addObject:tokenObject];
- }
- else {
- [processedTokens addObject:tokenString]; // no token with this name, add it as string
- }
- remainder = [remainder substringFromIndex:closeCurl.location+1];
- }
- if([remainder length]) {
- [processedTokens addObject:remainder];
- }
- }
-
- return processedTokens;
-}
-
-- (void)_tokenizeCustomFilenameTokenField
-{
- // if we are currently inside or at the end of a string segment we can
- // call for tokenization to happen by simulating a return press
-
- if ([exportCustomFilenameTokenField currentEditor] == nil) return;
-
- NSRange selectedRange = [[exportCustomFilenameTokenField currentEditor] selectedRange];
-
- if (selectedRange.location == NSNotFound) return;
- if (selectedRange.location == 0) return; // the beginning of the field is not valid for tokenization
- if (selectedRange.length > 0) return;
-
- NSUInteger start = 0;
- for(id obj in [exportCustomFilenameTokenField objectValue]) {
- NSUInteger length;
- BOOL isText = NO;
- if(IS_STRING(obj)) {
- length = [obj length];
- isText = YES;
- }
- else if(IS_TOKEN(obj)) {
- length = 1; // tokens are seen as one char by the textview
- }
- else {
- [NSException raise:NSInternalInconsistencyException format:@"Unknown object type in token field: %@",obj];
- }
- NSUInteger end = start+length;
- if(selectedRange.location >= start && selectedRange.location <= end) {
- if(!isText) return; // cursor is at the end of a token
- break;
- }
- start += length;
- }
-
- // All conditions met - synthesize the return key to trigger tokenization.
- NSEvent *tokenizingEvent = [NSEvent keyEventWithType:NSKeyDown
- location:NSMakePoint(0,0)
- modifierFlags:0
- timestamp:0
- windowNumber:[[exportCustomFilenameTokenField window] windowNumber]
- context:[NSGraphicsContext currentContext]
- characters:@""
- charactersIgnoringModifiers:@""
- isARepeat:NO
- keyCode:0x24];
-
- [NSApp postEvent:tokenizingEvent atStart:NO];
-}
-
-@end
-
-#pragma mark -
-
-BOOL IS_TOKEN(id x)
-{
- return [x isKindOfClass:[SPExportFileNameTokenObject class]];
-}
-
-BOOL IS_STRING(id x)
-{
- return [x isKindOfClass:[NSString class]];
-}
-
diff --git a/Source/SPExportFileUtilities.h b/Source/SPExportFileUtilities.h
deleted file mode 100644
index 54c81eb7..00000000
--- a/Source/SPExportFileUtilities.h
+++ /dev/null
@@ -1,49 +0,0 @@
-//
-// SPExportFileUtilities.m
-// sequel-pro
-//
-// Created by Stuart Connolly (stuconnolly.com) on July 30, 2010.
-// Copyright (c) 2010 Stuart Connolly. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person
-// obtaining a copy of this software and associated documentation
-// files (the "Software"), to deal in the Software without
-// restriction, including without limitation the rights to use,
-// copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following
-// conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-// OTHER DEALINGS IN THE SOFTWARE.
-//
-// More info at <https://github.com/sequelpro/sequelpro>
-
-#import "SPExportController.h"
-
-@class SPExportFile;
-
-/**
- * @category SPExportFileUtilities SPExportFileUtilities.h
- *
- * @author Stuart Connolly http://stuconnolly.com/
- *
- * Export file utilities category.
- */
-@interface SPExportController (SPExportFileUtilities)
-
-- (void)writeCSVHeaderToExportFile:(SPExportFile *)file;
-- (void)writeXMLHeaderToExportFile:(SPExportFile *)file;
-
-- (void)errorCreatingExportFileHandles:(NSArray *)files;
-
-@end
diff --git a/Source/SPExportFileUtilities.m b/Source/SPExportFileUtilities.m
deleted file mode 100644
index f9a6639e..00000000
--- a/Source/SPExportFileUtilities.m
+++ /dev/null
@@ -1,372 +0,0 @@
-//
-// SPExportFileUtilities.m
-// sequel-pro
-//
-// Created by Stuart Connolly (stuconnolly.com) on July 30, 2010.
-// Copyright (c) 2010 Stuart Connolly. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person
-// obtaining a copy of this software and associated documentation
-// files (the "Software"), to deal in the Software without
-// restriction, including without limitation the rights to use,
-// copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following
-// conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-// OTHER DEALINGS IN THE SOFTWARE.
-//
-// More info at <https://github.com/sequelpro/sequelpro>
-
-#import "SPExportFileUtilities.h"
-#import "SPExportInitializer.h"
-#import "SPExporter.h"
-#import "SPExportFile.h"
-#import "SPDatabaseDocument.h"
-#import "SPCustomQuery.h"
-#import "SPTableContent.h"
-#import "SPExportController+SharedPrivateAPI.h"
-
-#import <SPMySQL/SPMySQL.h>
-
-typedef enum
-{
- SPExportErrorCancelExport = 0,
- SPExportErrorReplaceFiles = 1,
- SPExportErrorSkipErrorFiles = 2
-}
-SPExportErrorChoice;
-
-@interface SPExportController (SPExportFileUtilitiesPrivateAPI)
-- (void)_reopenExportSheet;
-@end
-
-@implementation SPExportController (SPExportFileUtilitiesPrivateAPI)
-
-/**
- * Writes the CSV file header to the supplied export file.
- *
- * @param file The export file to write the header to.
- */
-- (void)writeCSVHeaderToExportFile:(SPExportFile *)file
-{
- NSMutableString *lineEnding = [NSMutableString stringWithString:[exportCSVLinesTerminatedField stringValue]];
-
- // Escape tabs, line endings and carriage returns
- [lineEnding replaceOccurrencesOfString:@"\\t" withString:@"\t"
- options:NSLiteralSearch
- range:NSMakeRange(0, [lineEnding length])];
-
-
- [lineEnding replaceOccurrencesOfString:@"\\n" withString:@"\n"
- options:NSLiteralSearch
- range:NSMakeRange(0, [lineEnding length])];
-
- [lineEnding replaceOccurrencesOfString:@"\\r" withString:@"\r"
- options:NSLiteralSearch
- range:NSMakeRange(0, [lineEnding length])];
-
- // Write the file header and the first table name
- [file writeData:[[NSMutableString stringWithFormat:@"%@: %@ %@: %@ %@: %@%@%@%@ %@%@%@",
- NSLocalizedString(@"Host", @"export header host label"),
- [tableDocumentInstance host],
- NSLocalizedString(@"Database", @"export header database label"),
- [tableDocumentInstance database],
- NSLocalizedString(@"Generation Time", @"export header generation time label"),
- [NSDate date],
- lineEnding,
- lineEnding,
- NSLocalizedString(@"Table", @"csv export table heading"),
- [[tables objectAtIndex:0] objectAtIndex:0],
- lineEnding,
- lineEnding] dataUsingEncoding:[connection stringEncoding]]];
-}
-
-/**
- * Writes the XML file header to the supplied export file.
- *
- * @param file The export file to write the header to.
- */
-- (void)writeXMLHeaderToExportFile:(SPExportFile *)file
-{
- NSMutableString *header = [NSMutableString string];
-
- [header setString:@"<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n\n"];
- [header appendString:@"<!--\n-\n"];
- [header appendString:@"- Sequel Pro XML dump\n"];
- [header appendFormat:@"- %@ %@\n-\n", NSLocalizedString(@"Version", @"export header version label"), [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]];
- [header appendFormat:@"- %@\n- %@\n-\n", SPLOCALIZEDURL_HOMEPAGE, SPDevURL];
- [header appendFormat:@"- %@: %@ (MySQL %@)\n", NSLocalizedString(@"Host", @"export header host label"), [tableDocumentInstance host], [tableDocumentInstance mySQLVersion]];
- [header appendFormat:@"- %@: %@\n", NSLocalizedString(@"Database", @"export header database label"), [tableDocumentInstance database]];
- [header appendFormat:@"- %@ Time: %@\n", NSLocalizedString(@"Generation Time", @"export header generation time label"), [NSDate date]];
- [header appendString:@"-\n-->\n\n"];
-
- if ([exportXMLFormatPopUpButton indexOfSelectedItem] == SPXMLExportMySQLFormat) {
-
- NSString *tag;
-
- if (exportSource == SPTableExport) {
- tag = [NSString stringWithFormat:@"<mysqldump xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n<database name=\"%@\">\n\n", [tableDocumentInstance database]];
- }
- else {
- tag = [NSString stringWithFormat:@"<resultset statement=\"%@\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n\n", (exportSource == SPFilteredExport) ? [tableContentInstance usedQuery] : [customQueryInstance usedQuery]];
- }
-
- [header appendString:tag];
- }
- else {
- [header appendFormat:@"<%@>\n\n", [[tableDocumentInstance database] HTMLEscapeString]];
- }
-
- [file writeData:[header dataUsingEncoding:NSUTF8StringEncoding]];
-}
-
-/**
- * Indicates that one or more errors occurred while attempting to create the export file handles. Asks the
- * user how to proceed.
- *
- * @param files An array of export files (SPExportFile) that failed to be created.
- */
-- (void)errorCreatingExportFileHandles:(NSArray *)files
-{
- // We don't know where "files" came from, but we know 2 things:
- // - NSAlert will NOT retain it as contextInfo
- // - This method continues execution after [alert beginSheet:...], thus even if files was retained before, it could be released before the alert ends
- [files retain];
-
- // Get the number of files that already exist as well as couldn't be created because of other reasons
- NSUInteger filesAlreadyExisting = 0;
- NSUInteger parentFoldersMissing = 0;
- NSUInteger parentFoldersNotWritable = 0;
- NSUInteger filesFailed = 0;
-
- for (SPExportFile *file in files)
- {
- if ([file exportFileHandleStatus] == SPExportFileHandleExists) {
- filesAlreadyExisting++;
- }
- // For file handles that we failed to create for some unknown reason, ignore them and remove any
- // exporters that are associated with them.
- else if ([file exportFileHandleStatus] == SPExportFileHandleFailed) {
-
- filesFailed++;
-
- NSMutableArray *exportersToRemove = [[NSMutableArray alloc] init];
-
- for (SPExporter *exporter in exporters)
- {
- if ([[exporter exportOutputFile] isEqualTo:file]) {
- [exportersToRemove addObject:exporter];
- }
- }
-
- [exporters removeObjectsInArray:exportersToRemove];
-
- [exportersToRemove release];
-
- // Check the parent folder to see if it still is present
- BOOL parentIsFolder = NO;
- if (![[NSFileManager defaultManager] fileExistsAtPath:[[[file exportFilePath] stringByDeletingLastPathComponent] stringByExpandingTildeInPath] isDirectory:&parentIsFolder] || !parentIsFolder) {
- parentFoldersMissing++;
- } else if (![[NSFileManager defaultManager] isWritableFileAtPath:[[[file exportFilePath] stringByDeletingLastPathComponent] stringByExpandingTildeInPath]]) {
- parentFoldersNotWritable++;
- }
- }
- }
-
- NSAlert *alert = [[NSAlert alloc] init];
- [alert setAlertStyle:NSCriticalAlertStyle];
-
- // If files failed because they already existed, show a OS-like dialog.
- if (filesAlreadyExisting) {
-
- // Set up a string for use if files had to be skipped.
- NSString *additionalErrors = filesFailed ? NSLocalizedString(@"\n\n(In addition, one or more errors occurred while attempting to create the export files: %lu could not be created. These files will be ignored.)", @"Additional export file errors") : @"";
-
- if (filesAlreadyExisting == 1) {
- [alert setMessageText:[NSString stringWithFormat:NSLocalizedString(@"“%@” already exists. Do you want to replace it?", @"Export file already exists message"), [[[files objectAtIndex:0] exportFilePath] lastPathComponent]]];
- [alert setInformativeText:[NSString stringWithFormat:@"%@%@", NSLocalizedString(@"A file with the same name already exists in the target folder. Replacing it will overwrite its current contents.", @"Export file already exists explanatory text"), additionalErrors]];
- }
- else if (filesAlreadyExisting == [exportFiles count]) {
- [alert setMessageText:[NSString stringWithFormat:NSLocalizedString(@"All the export files already exist. Do you want to replace them?", @"All export files already exist message")]];
- [alert setInformativeText:[NSString stringWithFormat:@"%@%@", NSLocalizedString(@"Files with the same names already exist in the target folder. Replacing them will overwrite their current contents.", @"All export files already exist explanatory text"), additionalErrors]];
- }
- else {
- [alert setMessageText:[NSString stringWithFormat:NSLocalizedString(@"%lu files already exist. Do you want to replace them?", @"Export file already exists message"), filesAlreadyExisting]];
- [alert setInformativeText:[NSString stringWithFormat:@"%@%@", [NSString stringWithFormat:NSLocalizedString(@"%lu files with the same names already exist in the target folder. Replacing them will overwrite their current contents.", @"Some export files already exist explanatory text"), filesAlreadyExisting], additionalErrors]];
- }
-
- [alert addButtonWithTitle:NSLocalizedString(@"Replace", @"Replace button")];
- [[[alert buttons] objectAtIndex:0] setTag:SPExportErrorReplaceFiles];
- [[[alert buttons] objectAtIndex:0] setKeyEquivalent:@"r"];
- [[[alert buttons] objectAtIndex:0] setKeyEquivalentModifierMask:NSCommandKeyMask];
-
- [alert addButtonWithTitle:NSLocalizedString(@"Cancel", @"cancel button")];
- [[[alert buttons] objectAtIndex:1] setTag:SPExportErrorCancelExport];
- [[[alert buttons] objectAtIndex:1] setKeyEquivalent:@"\r"];
-
- if ((filesAlreadyExisting + filesFailed) != [exportFiles count]) {
- [alert addButtonWithTitle:NSLocalizedString(@"Skip existing", @"skip existing button")];
- [[[alert buttons] objectAtIndex:2] setTag:SPExportErrorSkipErrorFiles];
- [[[alert buttons] objectAtIndex:2] setKeyEquivalent:@"s"];
- [[[alert buttons] objectAtIndex:2] setKeyEquivalentModifierMask:NSCommandKeyMask];
- }
- }
- // If one or multiple files failed, but only due to unhandled errors, show a short dialog
- else {
- if (filesFailed == 1) {
- [alert setMessageText:[NSString stringWithFormat:NSLocalizedString(@"“%@” could not be created", @"Export file creation error title"), [[[files objectAtIndex:0] exportFilePath] lastPathComponent]]];
- if (parentFoldersMissing) {
- [alert setInformativeText:NSLocalizedString(@"The target export folder no longer exists. Please select a new export location and try again.", @"Export folder missing explanatory text")];
- } else if (parentFoldersNotWritable) {
- [alert setInformativeText:NSLocalizedString(@"The target export folder is not writable. Please select a new export location and try again.", @"Export folder not writable explanatory text")];
- } else {
- [alert setInformativeText:NSLocalizedString(@"An unhandled error occurred when attempting to create the export file. Please check the details and try again.", @"Export file creation error explanatory text")];
- }
- }
- else if (filesFailed == [exportFiles count]) {
- [alert setMessageText:[NSString stringWithFormat:NSLocalizedString(@"No files could be created", @"All export files creation error title")]];
- if (parentFoldersMissing == [exportFiles count]) {
- [alert setInformativeText:NSLocalizedString(@"The target export folder no longer exists. Please select a new export location and try again.", @"Export folder missing explanatory text")];
- } else if (parentFoldersMissing) {
- [alert setInformativeText:NSLocalizedString(@"Some of the target export folders no longer exist. Please select a new export location and try again.", @"Some export folders missing explanatory text")];
- } else if (parentFoldersNotWritable) {
- [alert setInformativeText:NSLocalizedString(@"Some of the target export folders are not writable. Please select a new export location and try again.", @"Some export folders not writable explanatory text")];
- } else {
- [alert setInformativeText:NSLocalizedString(@"An unhandled error occurred when attempting to create each of the export files. Please check the details and try again.", @"All export files creation error explanatory text")];
- }
- }
- else {
- [alert setMessageText:[NSString stringWithFormat:NSLocalizedString(@"%lu files could not be created", @"Export files creation error title"), filesFailed]];
- if (parentFoldersMissing) {
- [alert setInformativeText:[NSString stringWithFormat:NSLocalizedString(@"%lu of the export files could not be created because their target export folder no longer exists; please select a new export location and try again.", @"Export folder missing for some files explanatory text"), parentFoldersMissing]];
- } else if (parentFoldersNotWritable) {
- [alert setInformativeText:[NSString stringWithFormat:NSLocalizedString(@"%lu of the export files could not be created because their target export folder is not writable; please select a new export location and try again.", @"Export folder not writable for some files explanatory text"), parentFoldersNotWritable]];
- } else {
- [alert setInformativeText:[NSString stringWithFormat:NSLocalizedString(@"An unhandled error occurred when attempting to create %lu of the export files. Please check the details and try again.", @"Export files creation error explanatory text"), filesFailed]];
- }
- }
-
- [alert addButtonWithTitle:NSLocalizedString(@"Cancel", @"cancel button")];
- [[[alert buttons] objectAtIndex:0] setTag:SPExportErrorCancelExport];
-
- if (filesFailed != [exportFiles count]) {
- [alert addButtonWithTitle:NSLocalizedString(@"Skip problems", @"skip problems button")];
- [[[alert buttons] objectAtIndex:1] setTag:SPExportErrorSkipErrorFiles];
- [[[alert buttons] objectAtIndex:1] setKeyEquivalent:@"s"];
- [[[alert buttons] objectAtIndex:1] setKeyEquivalentModifierMask:NSCommandKeyMask];
- }
- }
-
- [self _hideExportProgress];
-
- [alert beginSheetModalForWindow:[tableDocumentInstance parentWindow] modalDelegate:self didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:files];
- [alert autorelease];
-}
-
-/**
- * NSAlert didEnd method.
- */
-- (void)alertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo
-{
- NSArray *files = (NSArray *)contextInfo;
-
- // Ignore the files that exist and remove the associated exporters
- if (returnCode == SPExportErrorSkipErrorFiles) {
-
- for (SPExportFile *file in files) {
-
- // Use a numerically controlled loop to avoid mutating the collection while enumerating
- NSUInteger i;
- for (i = 0; i < [exporters count]; i++) {
- SPExporter *exporter = [exporters objectAtIndex:i];
- if ([[exporter exportOutputFile] isEqualTo:file]) {
- [exporters removeObjectAtIndex:i];
- i--;
- }
- }
- }
-
- [files release];
-
- // If we're now left with no exporters, cancel the export operation
- if ([exporters count] == 0) {
- [exportFiles removeAllObjects];
-
- // Trigger restoration of the export interface
- [self performSelector:@selector(_reopenExportSheet) withObject:nil afterDelay:0.1];
- }
- else {
- // Start the export after a short delay to give this sheet a chance to close
- [self performSelector:@selector(startExport) withObject:nil afterDelay:0.1];
- }
- }
- // Overwrite the files and continue
- else if (returnCode == SPExportErrorReplaceFiles) {
-
- for (SPExportFile *file in files)
- {
- if ([file exportFileHandleStatus] == SPExportFileHandleExists) {
-
- if ([file createExportFileHandle:YES] == SPExportFileHandleCreated) {
- [file setCompressionFormat:(SPFileCompressionFormat)[exportOutputCompressionFormatPopupButton indexOfSelectedItem]];
-
- if ([file exportFileNeedsCSVHeader]) {
- [self writeCSVHeaderToExportFile:file];
- }
- else if ([file exportFileNeedsXMLHeader]) {
- [self writeXMLHeaderToExportFile:file];
- }
- }
- }
- }
-
- [files release];
-
- // Start the export after a short delay to give this sheet a chance to close
- [self performSelector:@selector(startExport) withObject:nil afterDelay:0.1];
-
- }
- // Cancel the entire export operation
- else if (returnCode == SPExportErrorCancelExport) {
-
- // Loop the cached export files and remove those we've already created
- for (SPExportFile *file in exportFiles)
- {
- [file delete];
- }
-
- [files release];
-
- // Finally get rid of all the exporters and files
- [exportFiles removeAllObjects];
- [exporters removeAllObjects];
-
- // Trigger restoration of the export interface
- [self performSelector:@selector(_reopenExportSheet) withObject:nil afterDelay:0.1];
- }
-}
-
-/**
- * Re-open the export sheet without resetting the interface - for use on error.
- */
-- (void)_reopenExportSheet
-{
- [NSApp beginSheet:[self window]
- modalForWindow:[tableDocumentInstance parentWindow]
- modalDelegate:self
- didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:)
- contextInfo:nil];
-}
-
-@end
diff --git a/Source/SPExportFilenameUtilities.h b/Source/SPExportFilenameUtilities.h
deleted file mode 100644
index b0ba9763..00000000
--- a/Source/SPExportFilenameUtilities.h
+++ /dev/null
@@ -1,51 +0,0 @@
-//
-// SPExportFilenameUtilities.h
-// sequel-pro
-//
-// Created by Stuart Connolly (stuconnolly.com) on July 25, 2010.
-// Copyright (c) 2010 Stuart Connolly. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person
-// obtaining a copy of this software and associated documentation
-// files (the "Software"), to deal in the Software without
-// restriction, including without limitation the rights to use,
-// copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following
-// conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-// OTHER DEALINGS IN THE SOFTWARE.
-//
-// More info at <https://github.com/sequelpro/sequelpro>
-
-#import "SPExportController.h"
-
-/**
- * @category SPExportFilenameUtilities SPExportFilenameUtilities.h
- *
- * @author Stuart Connolly http://stuconnolly.com/
- *
- * Export filename utilities category.
- */
-@interface SPExportController (SPExportFilenameUtilities)
-
-- (void)updateDisplayedExportFilename;
-- (void)updateAvailableExportFilenameTokens;
-- (NSArray *)currentAllowedExportFilenameTokens;
-- (NSString *)generateDefaultExportFilename;
-- (NSString *)currentDefaultExportFileExtension;
-- (NSString *)expandCustomFilenameFormatUsingTableName:(NSString *)table;
-- (NSString *)customFilenamePathExtension;
-- (BOOL)isTableTokenAllowed;
-
-@end
diff --git a/Source/SPExportFilenameUtilities.m b/Source/SPExportFilenameUtilities.m
deleted file mode 100644
index c064d363..00000000
--- a/Source/SPExportFilenameUtilities.m
+++ /dev/null
@@ -1,332 +0,0 @@
-//
-// SPExportFilenameUtilities.m
-// sequel-pro
-//
-// Created by Stuart Connolly (stuconnolly.com) on July 25, 2010.
-// Copyright (c) 2010 Stuart Connolly. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person
-// obtaining a copy of this software and associated documentation
-// files (the "Software"), to deal in the Software without
-// restriction, including without limitation the rights to use,
-// copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following
-// conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-// OTHER DEALINGS IN THE SOFTWARE.
-//
-// More info at <https://github.com/sequelpro/sequelpro>
-
-#import "SPExportFilenameUtilities.h"
-#import "SPTablesList.h"
-#import "SPDatabaseDocument.h"
-#import "SPExportFileNameTokenObject.h"
-
-@implementation SPExportController (SPExportFilenameUtilities)
-
-/**
- * Updates the displayed export filename, either custom or default.
- */
-- (void)updateDisplayedExportFilename
-{
- NSString *filename = @"";
-
- if ([[exportCustomFilenameTokenField stringValue] length] > 0) {
-
- // Get the current export file extension
- NSString *extension = [self currentDefaultExportFileExtension];
-
- //note that there will be no tableName if the export is done from a query result without a database selected (or empty).
- filename = [self expandCustomFilenameFormatUsingTableName:[[tablesListInstance tables] objectOrNilAtIndex:1]];
-
-
- if (![[self customFilenamePathExtension] length] && [extension length] > 0) filename = [filename stringByAppendingPathExtension:extension];
- }
- else {
- filename = [self generateDefaultExportFilename];
- }
-
- [exportCustomFilenameViewLabelButton setTitle:[NSString stringWithFormat:NSLocalizedString(@"Customize Filename (%@)", @"customize file name label"), filename]];
-}
-
-- (NSString *)customFilenamePathExtension
-{
- NSMutableString *flatted = [NSMutableString string];
-
- // This time we replace every token with "/a". This has the following effect:
- // "{host}.{database}" -> "/a./a" -> extension=""
- // "{database}_{date}.sql" -> "/a_/a.sql" -> extension="sql"
- // That seems to be the easiest way to let NSString correctly determine if an extension is present
- for (id filenamePart in [exportCustomFilenameTokenField objectValue])
- {
- if([filenamePart isKindOfClass:[NSString class]])
- [flatted appendString:filenamePart];
- else if([filenamePart isKindOfClass:[SPExportFileNameTokenObject class]])
- [flatted appendString:@"/a"];
- else
- [NSException raise:NSInternalInconsistencyException format:@"unknown object in token list: %@",filenamePart];
- }
-
- return [flatted pathExtension];
-}
-
-- (BOOL)isTableTokenAllowed
-{
- NSUInteger i = 0;
- BOOL removeTable = NO;
-
- BOOL isSQL = exportType == SPSQLExport;
- BOOL isCSV = exportType == SPCSVExport;
- BOOL isDot = exportType == SPDotExport;
- BOOL isXML = exportType == SPXMLExport;
-
- // Determine whether to remove the table from the tokens list
- if (exportSource == SPQueryExport || isDot) {
- removeTable = YES;
- }
- else if (isSQL || isCSV || isXML) {
- for (NSArray *table in tables)
- {
- if ([NSArrayObjectAtIndex(table, 2) boolValue]) {
- i++;
- if (i == 2) break;
- }
- }
-
- if (i > 1) {
- removeTable = isSQL ? YES : ![exportFilePerTableCheck state];
- }
- }
-
- return (removeTable == NO);
-}
-
-/**
- * Updates the available export filename tokens based on the currently selected options.
- */
-- (void)updateAvailableExportFilenameTokens
-{
- SPExportFileNameTokenObject *tableObject;
- NSMutableArray *exportTokens = [NSMutableArray arrayWithObjects:
- [SPExportFileNameTokenObject tokenWithId:SPFileNameDatabaseTokenName],
- [SPExportFileNameTokenObject tokenWithId:SPFileNameHostTokenName],
- [SPExportFileNameTokenObject tokenWithId:SPFileNameDateTokenName],
- [SPExportFileNameTokenObject tokenWithId:SPFileNameYearTokenName],
- [SPExportFileNameTokenObject tokenWithId:SPFileNameMonthTokenName],
- [SPExportFileNameTokenObject tokenWithId:SPFileNameDayTokenName],
- [SPExportFileNameTokenObject tokenWithId:SPFileNameTimeTokenName],
- [SPExportFileNameTokenObject tokenWithId:SPFileName24HourTimeTokenName],
- [SPExportFileNameTokenObject tokenWithId:SPFileNameFavoriteTokenName],
- (tableObject = [SPExportFileNameTokenObject tokenWithId:SPFileNameTableTokenName]),
- nil
- ];
-
- if (![self isTableTokenAllowed]) {
- [exportTokens removeObject:tableObject];
- NSArray *tokenParts = [exportCustomFilenameTokenField objectValue];
-
- for (id token in tokenParts)
- {
- if([token isEqual:tableObject]) {
- NSMutableArray *newTokens = [NSMutableArray arrayWithArray:tokenParts];
-
- [newTokens removeObject:tableObject]; //removes all occurances
-
- [exportCustomFilenameTokenField setObjectValue:newTokens];
- break;
- }
- }
- }
-
- [exportCustomFilenameTokenPool setObjectValue:exportTokens];
- //update preview name as programmatically changing the exportCustomFilenameTokenField does not fire a notification
- [self updateDisplayedExportFilename];
-}
-
-- (NSArray *)currentAllowedExportFilenameTokens
-{
- NSArray *mixed = [exportCustomFilenameTokenPool objectValue];
- NSMutableArray *tokens = [NSMutableArray arrayWithCapacity:[mixed count]]; // ...or less
-
- for (id obj in mixed) {
- if([obj isKindOfClass:[SPExportFileNameTokenObject class]]) [tokens addObject:obj];
- }
-
- return tokens;
-}
-
-/**
- * Generates the default export filename based on the selected export options.
- *
- * @return The default filename.
- */
-- (NSString *)generateDefaultExportFilename
-{
- NSString *filename = @"";
- NSString *extension = [self currentDefaultExportFileExtension];
-
- // Determine what the file name should be
- switch (exportSource)
- {
- case SPFilteredExport:
- filename = [NSString stringWithFormat:@"%@_view", [tableDocumentInstance table]];
- break;
- case SPQueryExport:
- filename = @"query_result";
- break;
- case SPTableExport:
- filename = [NSString stringWithFormat:@"%@_%@", [tableDocumentInstance database], [[NSDate date] descriptionWithCalendarFormat:@"%Y-%m-%d" timeZone:nil locale:nil]];
- break;
- }
-
- return ([extension length] > 0) ? [filename stringByAppendingPathExtension:extension] : filename;
-}
-
-/**
- * Returns the current default export file extension based on the selected export type.
- *
- * @return The default filename extension.
- */
-- (NSString *)currentDefaultExportFileExtension
-{
- NSString *extension = @"";
-
- switch (exportType) {
- case SPSQLExport:
- extension = SPFileExtensionSQL;
- break;
- case SPCSVExport:
- // If the tab character (\t) is selected as the feild separator return the extension as .tsv
- extension = ([exportCSVFieldsTerminatedField indexOfSelectedItem] == 2) ? @"tsv" : @"csv";
- break;
- case SPXMLExport:
- extension = @"xml";
- break;
- case SPDotExport:
- extension = @"dot";
- break;
- case SPPDFExport:
- case SPHTMLExport:
- case SPExcelExport:
- default:
- [NSException raise:NSInvalidArgumentException format:@"unsupported exportType=%lu",exportType];
- return nil;
- }
-
- if ([exportOutputCompressionFormatPopupButton indexOfSelectedItem] != SPNoCompression) {
-
- SPFileCompressionFormat compressionFormat = (SPFileCompressionFormat)[exportOutputCompressionFormatPopupButton indexOfSelectedItem];
-
- if ([extension length] > 0) {
- extension = [extension stringByAppendingPathExtension:(compressionFormat == SPGzipCompression) ? @"gz" : @"bz2"];
- }
- else {
- extension = (compressionFormat == SPGzipCompression) ? @"gz" : @"bz2";
- }
- }
-
- return extension;
-}
-
-/**
- * Expands the custom filename format based on the selected tokens.
- * Uses the current custom filename field as a data source.
- *
- * @param table A table name to be used within the expanded filename.
- * Can be nil.
- *
- * @return The expanded filename.
- */
-- (NSString *)expandCustomFilenameFormatUsingTableName:(NSString *)table
-{
- NSMutableString *string = [NSMutableString string];
-
- NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
- [dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4];
-
- // Walk through the token field, appending token replacements or strings
- NSArray *representedFilenameParts = [exportCustomFilenameTokenField objectValue];
-
- for (id filenamePart in representedFilenameParts)
- {
- if ([filenamePart isKindOfClass:[SPExportFileNameTokenObject class]]) {
- NSString *tokenContent = [filenamePart tokenId];
-
- if ([tokenContent isEqualToString:SPFileNameHostTokenName]) {
- [string appendStringOrNil:[tableDocumentInstance host]];
-
- }
- else if ([tokenContent isEqualToString:SPFileNameDatabaseTokenName]) {
- [string appendStringOrNil:[tableDocumentInstance database]];
-
- }
- else if ([tokenContent isEqualToString:SPFileNameTableTokenName]) {
- [string appendStringOrNil:table];
- }
- else if ([tokenContent isEqualToString:SPFileNameDateTokenName]) {
- [dateFormatter setDateStyle:NSDateFormatterShortStyle];
- [dateFormatter setTimeStyle:NSDateFormatterNoStyle];
- [string appendString:[dateFormatter stringFromDate:[NSDate date]]];
-
- }
- else if ([tokenContent isEqualToString:SPFileNameYearTokenName]) {
- [string appendString:[[NSDate date] descriptionWithCalendarFormat:@"%Y" timeZone:nil locale:nil]];
-
- }
- else if ([tokenContent isEqualToString:SPFileNameMonthTokenName]) {
- [string appendString:[[NSDate date] descriptionWithCalendarFormat:@"%m" timeZone:nil locale:nil]];
-
- }
- else if ([tokenContent isEqualToString:SPFileNameDayTokenName]) {
- [string appendString:[[NSDate date] descriptionWithCalendarFormat:@"%d" timeZone:nil locale:nil]];
-
- }
- else if ([tokenContent isEqualToString:SPFileNameTimeTokenName]) {
- [dateFormatter setDateStyle:NSDateFormatterNoStyle];
- [dateFormatter setTimeStyle:NSDateFormatterShortStyle];
- [string appendString:[dateFormatter stringFromDate:[NSDate date]]];
- }
- else if ([tokenContent isEqualToString:SPFileName24HourTimeTokenName]) {
- [string appendString:[[NSDate date] descriptionWithCalendarFormat:@"%H:%M:%S" timeZone:nil locale:nil]];
- }
- else if ([tokenContent isEqualToString:SPFileNameFavoriteTokenName]) {
- [string appendStringOrNil:[tableDocumentInstance name]];
- }
- }
- else {
- [string appendString:filenamePart];
- }
- }
-
- // Replace colons with hyphens
- [string replaceOccurrencesOfString:@":"
- withString:@"-"
- options:NSLiteralSearch
- range:NSMakeRange(0, [string length])];
-
- // Replace forward slashes with hyphens
- [string replaceOccurrencesOfString:@"/"
- withString:@"-"
- options:NSLiteralSearch
- range:NSMakeRange(0, [string length])];
-
- [dateFormatter release];
-
- // Don't allow empty strings - if an empty string resulted, revert to the default string
- if (![string length]) [string setString:[self generateDefaultExportFilename]];
-
- return string;
-}
-
-@end
diff --git a/Source/SPExportInitializer.h b/Source/SPExportInitializer.h
deleted file mode 100644
index e8cfec73..00000000
--- a/Source/SPExportInitializer.h
+++ /dev/null
@@ -1,54 +0,0 @@
-//
-// SPExportInitializer.h
-// sequel-pro
-//
-// Created by Stuart Connolly (stuconnolly.com) on March 31, 2010.
-// Copyright (c) 2010 Stuart Connolly. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person
-// obtaining a copy of this software and associated documentation
-// files (the "Software"), to deal in the Software without
-// restriction, including without limitation the rights to use,
-// copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following
-// conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-// OTHER DEALINGS IN THE SOFTWARE.
-//
-// More info at <https://github.com/sequelpro/sequelpro>
-
-#import "SPExportController.h"
-
-@class SPCSVExporter;
-@class SPXMLExporter;
-
-/**
- * @category SPExportInitializer SPExportInitializer.h
- *
- * @author Stuart Connolly http://stuconnolly.com/
- *
- * Export initializer category.
- */
-@interface SPExportController (SPExportInitializer)
-
-- (void)startExport;
-- (void)exportEnded;
-- (void)initializeExportUsingSelectedOptions;
-
-- (void)exportTables:(NSArray *)exportTables orDataArray:(NSArray *)dataArray;
-
-- (SPCSVExporter *)initializeCSVExporterForTable:(NSString *)table orDataArray:(NSArray *)dataArray;
-- (SPXMLExporter *)initializeXMLExporterForTable:(NSString *)table orDataArray:(NSArray *)dataArray;
-
-@end
diff --git a/Source/SPExportInitializer.m b/Source/SPExportInitializer.m
deleted file mode 100644
index 9269cac8..00000000
--- a/Source/SPExportInitializer.m
+++ /dev/null
@@ -1,611 +0,0 @@
-//
-// SPExportInitializer.m
-// sequel-pro
-//
-// Created by Stuart Connolly (stuconnolly.com) on March 31, 2010.
-// Copyright (c) 2010 Stuart Connolly. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person
-// obtaining a copy of this software and associated documentation
-// files (the "Software"), to deal in the Software without
-// restriction, including without limitation the rights to use,
-// copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following
-// conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-// OTHER DEALINGS IN THE SOFTWARE.
-//
-// More info at <https://github.com/sequelpro/sequelpro>
-
-#import "SPExportInitializer.h"
-#import "SPTableData.h"
-#import "SPDatabaseDocument.h"
-#import "SPTablesList.h"
-#import "SPGrowlController.h"
-#import "SPDatabaseDocument.h"
-#import "SPCustomQuery.h"
-#import "SPAlertSheets.h"
-#import "SPTableContent.h"
-#import "SPCSVExporter.h"
-#import "SPSQLExporter.h"
-#import "SPXMLExporter.h"
-#import "SPDotExporter.h"
-#import "SPExportFile.h"
-#import "SPExportFileUtilities.h"
-#import "SPExportFilenameUtilities.h"
-#import "SPExportFileNameTokenObject.h"
-#import "SPConnectionControllerDelegateProtocol.h"
-#import "SPExportController+SharedPrivateAPI.h"
-#import "SPSQLExporterDelegate.h"
-
-#import <SPMySQL/SPMySQL.h>
-
-@implementation SPExportController (SPExportInitializer)
-
-/**
- * Starts the export process by placing the first exporter on the operation queue. Also opens the progress
- * sheet if it's not already visible.
- */
-- (void)startExport
-{
- // Start progress indicator
- [exportProgressTitle setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Exporting %@", @"text showing that the application is importing a supplied format"), exportTypeLabel]];
- [exportProgressText setStringValue:NSLocalizedString(@"Writing...", @"text showing that app is writing text file")];
-
- [exportProgressIndicator setUsesThreadedAnimation:NO];
- [exportProgressIndicator setIndeterminate:NO];
- [exportProgressIndicator setDoubleValue:0];
-
- // If it's not already displayed, open the progress sheet
- if (![exportProgressWindow isVisible]) {
- [NSApp beginSheet:exportProgressWindow
- modalForWindow:[tableDocumentInstance parentWindow]
- modalDelegate:self
- didEndSelector:nil
- contextInfo:nil];
- }
-
- // cache the current connection encoding so the exporter can do what it wants.
- previousConnectionEncoding = [[NSString alloc] initWithString:[connection encoding]];
- previousConnectionEncodingViaLatin1 = [connection encodingUsesLatin1Transport];
-
- // Add the first exporter to the operation queue
- [operationQueue addOperation:[exporters objectAtIndex:0]];
-
- // Remove the exporter we just added to the operation queue from our list of exporters
- // so we know it's already been done.
- [exporters removeObjectAtIndex:0];
-}
-
-/**
- * @see _queueIsEmptyAfterCancelling:
- */
-- (void)exportEnded
-{
- [self _hideExportProgress];
-
- // Restore query mode
- [tableDocumentInstance setQueryMode:SPInterfaceQueryMode];
-
- // Display Growl notification
- [self displayExportFinishedGrowlNotification];
-
- // Restore the connection encoding to it's pre-export value
- [tableDocumentInstance setConnectionEncoding:[NSString stringWithFormat:@"%@%@", previousConnectionEncoding, (previousConnectionEncodingViaLatin1) ? @"-" : @""] reloadingViews:NO];
-}
-
-/**
- * Initializes the export process by analysing the selected criteria.
- */
-- (void)initializeExportUsingSelectedOptions
-{
- NSArray *dataArray = nil;
-
- // Get rid of the cached connection encoding
- if (previousConnectionEncoding) SPClear(previousConnectionEncoding);
-
- createCustomFilename = ([[exportCustomFilenameTokenField stringValue] length] > 0);
-
- NSMutableArray *exportTables = [NSMutableArray array];
-
- // Set whether or not we are to export to multiple files
- [self setExportToMultipleFiles:[exportFilePerTableCheck state]];
-
- // Get the data depending on the source
- switch (exportSource)
- {
- case SPFilteredExport:
- dataArray = [tableContentInstance currentDataResultWithNULLs:YES hideBLOBs:NO];
- break;
- case SPQueryExport:
- dataArray = [customQueryInstance currentDataResultWithNULLs:YES truncateDataFields:NO];
- break;
- case SPTableExport:
- // Create an array of tables to export
- for (NSMutableArray *table in tables)
- {
- if (exportType == SPSQLExport) {
- if ([[table objectAtIndex:1] boolValue] || [[table objectAtIndex:2] boolValue] || [[table objectAtIndex:3] boolValue]) {
-
- // Check the overall export settings
- if ([[table objectAtIndex:1] boolValue] && (![exportSQLIncludeStructureCheck state])) {
- [table replaceObjectAtIndex:1 withObject:@NO];
- }
-
- if ([[table objectAtIndex:2] boolValue] && (![exportSQLIncludeContentCheck state])) {
- [table replaceObjectAtIndex:2 withObject:@NO];
- }
-
- if ([[table objectAtIndex:3] boolValue] && (![exportSQLIncludeDropSyntaxCheck state])) {
- [table replaceObjectAtIndex:3 withObject:@NO];
- }
-
- [exportTables addObject:table];
- }
- }
- else if (exportType == SPDotExport) {
- [exportTables addObject:[table objectAtIndex:0]];
- }
- else {
- if ([[table objectAtIndex:2] boolValue]) {
- [exportTables addObject:[table objectAtIndex:0]];
- }
- }
- }
-
- break;
- }
-
- // Set the export type label
- switch (exportType)
- {
- case SPSQLExport:
- exportTypeLabel = @"SQL";
- break;
- case SPCSVExport:
- exportTypeLabel = @"CSV";
- break;
- case SPXMLExport:
- exportTypeLabel = @"XML";
- break;
- case SPDotExport:
- exportTypeLabel = @"Dot";
- break;
- case SPPDFExport:
- case SPHTMLExport:
- case SPExcelExport:
- default:
- [NSException raise:NSInvalidArgumentException format:@"unsupported exportType=%lu",exportType];
- return;
- }
-
- // Begin the export based on the source
- switch (exportSource)
- {
- case SPFilteredExport:
- case SPQueryExport:
- [self exportTables:nil orDataArray:dataArray];
- break;
- case SPTableExport:
- [self exportTables:exportTables orDataArray:nil];
- break;
- }
-}
-
-/**
- * Exports the contents of the supplied array of tables or data array.
- *
- * Note that at least one of these parameters must not be nil.
- *
- * @param exportTables An array of table/view names to be exported (can be nil).
- * @param dataArray A MySQL result set array to be exported (can be nil).
- */
-- (void)exportTables:(NSArray *)exportTables orDataArray:(NSArray *)dataArray
-{
- BOOL singleFileHandleSet = NO;
- SPExportFile *singleExportFile = nil, *file = nil;
-
- // Change query logging mode
- [tableDocumentInstance setQueryMode:SPImportExportQueryMode];
-
- // Start the notification timer to allow notifications to be shown even if frontmost for long queries
- [[SPGrowlController sharedGrowlController] setVisibilityForNotificationName:@"Export Finished"];
-
- // Setup the progress sheet
- [exportProgressTitle setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Exporting %@", @"text showing that the application is importing a supplied format"), exportTypeLabel]];
- [exportProgressText setStringValue:NSLocalizedString(@"Initializing...", @"initializing export label")];
-
- [exportProgressIndicator setIndeterminate:YES];
- [exportProgressIndicator setUsesThreadedAnimation:YES];
-
- // Open the progress sheet
- [NSApp beginSheet:exportProgressWindow
- modalForWindow:[tableDocumentInstance parentWindow]
- modalDelegate:self
- didEndSelector:nil
- contextInfo:nil];
-
- // CSV export
- if (exportType == SPCSVExport) {
-
- SPCSVExporter *csvExporter = nil;
-
- // If the user has selected to only export to a single file or this is a filtered or custom query
- // export, create the single file now and assign it to all subsequently created exporters.
- if ((![self exportToMultipleFiles]) || (exportSource == SPFilteredExport) || (exportSource == SPQueryExport)) {
- NSString *selectedTableName = nil;
-
- if (exportSource == SPTableExport && [exportTables count] == 1) selectedTableName = [exportTables objectAtIndex:0];
-
- [exportFilename setString:createCustomFilename ? [self expandCustomFilenameFormatUsingTableName:selectedTableName] : [self generateDefaultExportFilename]];
-
- // Only append the extension if necessary
- if (![[exportFilename pathExtension] length]) {
- [exportFilename setString:[exportFilename stringByAppendingPathExtension:[self currentDefaultExportFileExtension]]];
- }
-
- singleExportFile = [SPExportFile exportFileAtPath:[[exportPathField stringValue] stringByAppendingPathComponent:exportFilename]];
- }
-
- // Start the export process depending on the data source
- if (exportSource == SPTableExport) {
-
- // Cache the number of tables being exported
- exportTableCount = [exportTables count];
-
- // Loop through the tables, creating an exporter for each
- for (NSString *table in exportTables)
- {
- csvExporter = [self initializeCSVExporterForTable:table orDataArray:nil];
-
- // If required create a single file handle for all CSV exports
- if (![self exportToMultipleFiles]) {
- if (!singleFileHandleSet) {
- [singleExportFile setExportFileNeedsCSVHeader:YES];
-
- [exportFiles addObject:singleExportFile];
-
- singleFileHandleSet = YES;
- }
-
- [csvExporter setExportOutputFile:singleExportFile];
- }
-
- [exporters addObject:csvExporter];
- }
- }
- else {
- csvExporter = [self initializeCSVExporterForTable:nil orDataArray:dataArray];
-
- [exportFiles addObject:singleExportFile];
-
- [csvExporter setExportOutputFile:singleExportFile];
-
- [exporters addObject:csvExporter];
- }
- }
- // SQL export
- else if (exportType == SPSQLExport) {
-
- // Cache the number of tables being exported
- exportTableCount = [exportTables count];
-
- SPSQLExporter *sqlExporter = [[SPSQLExporter alloc] initWithDelegate:self];
-
- [sqlExporter setSqlDatabaseHost:[tableDocumentInstance host]];
- [sqlExporter setSqlDatabaseName:[tableDocumentInstance database]];
- [sqlExporter setSqlDatabaseVersion:[tableDocumentInstance mySQLVersion]];
-
- [sqlExporter setSqlOutputIncludeUTF8BOM:[exportUseUTF8BOMButton state]];
- [sqlExporter setSqlOutputEncodeBLOBasHex:[exportSQLBLOBFieldsAsHexCheck state]];
- [sqlExporter setSqlOutputIncludeErrors:[exportSQLIncludeErrorsCheck state]];
- [sqlExporter setSqlOutputIncludeAutoIncrement:([exportSQLIncludeStructureCheck state] && [exportSQLIncludeAutoIncrementValueButton state])];
-
- [sqlExporter setSqlInsertAfterNValue:[exportSQLInsertNValueTextField integerValue]];
- [sqlExporter setSqlInsertDivider:[exportSQLInsertDividerPopUpButton indexOfSelectedItem]];
-
- [sqlExporter setSqlExportTables:exportTables];
-
- // Create custom filename if required
- NSString *selectedTableName = (exportSource == SPTableExport && [exportTables count] == 1)? [[exportTables objectAtIndex:0] objectAtIndex:0] : nil;
- [exportFilename setString:(createCustomFilename) ? [self expandCustomFilenameFormatUsingTableName:selectedTableName] : [self generateDefaultExportFilename]];
-
- // Only append the extension if necessary
- if (![[exportFilename pathExtension] length]) {
- [exportFilename setString:[exportFilename stringByAppendingPathExtension:[self currentDefaultExportFileExtension]]];
- }
-
- file = [SPExportFile exportFileAtPath:[[exportPathField stringValue] stringByAppendingPathComponent:exportFilename]];
-
- [exportFiles addObject:file];
-
- [sqlExporter setExportOutputFile:file];
-
- [exporters addObject:sqlExporter];
-
- [sqlExporter release];
- }
- // XML export
- else if (exportType == SPXMLExport) {
-
- SPXMLExporter *xmlExporter = nil;
-
- // If the user has selected to only export to a single file or this is a filtered or custom query
- // export, create the single file now and assign it to all subsequently created exporters.
- if ((![self exportToMultipleFiles]) || (exportSource == SPFilteredExport) || (exportSource == SPQueryExport)) {
- NSString *selectedTableName = nil;
- if (exportSource == SPTableExport && [exportTables count] == 1) selectedTableName = [exportTables objectAtIndex:0];
-
- [exportFilename setString:(createCustomFilename) ? [self expandCustomFilenameFormatUsingTableName:selectedTableName] : [self generateDefaultExportFilename]];
-
- // Only append the extension if necessary
- if (![[exportFilename pathExtension] length]) {
- [exportFilename setString:[exportFilename stringByAppendingPathExtension:[self currentDefaultExportFileExtension]]];
- }
-
- singleExportFile = [SPExportFile exportFileAtPath:[[exportPathField stringValue] stringByAppendingPathComponent:exportFilename]];
- }
-
- // Start the export process depending on the data source
- if (exportSource == SPTableExport) {
-
- // Cache the number of tables being exported
- exportTableCount = [exportTables count];
-
- // Loop through the tables, creating an exporter for each
- for (NSString *table in exportTables)
- {
- xmlExporter = [self initializeXMLExporterForTable:table orDataArray:nil];
-
- // If required create a single file handle for all XML exports
- if (![self exportToMultipleFiles]) {
- if (!singleFileHandleSet) {
- [singleExportFile setExportFileNeedsXMLHeader:YES];
-
- [exportFiles addObject:singleExportFile];
-
- singleFileHandleSet = YES;
- }
-
- [xmlExporter setExportOutputFile:singleExportFile];
- }
-
- [exporters addObject:xmlExporter];
- }
- }
- else {
- xmlExporter = [self initializeXMLExporterForTable:nil orDataArray:dataArray];
-
- [singleExportFile setExportFileNeedsXMLHeader:YES];
-
- [exportFiles addObject:singleExportFile];
-
- [xmlExporter setExportOutputFile:singleExportFile];
-
- [exporters addObject:xmlExporter];
- }
- }
- // Dot export
- else if (exportType == SPDotExport) {
-
- // Cache the number of tables being exported
- exportTableCount = [exportTables count];
-
- SPDotExporter *dotExporter = [[SPDotExporter alloc] initWithDelegate:self];
-
- [dotExporter setDotTableData:tableDataInstance];
- [dotExporter setDotForceLowerTableNames:[exportDotForceLowerTableNamesCheck state]];
- [dotExporter setDotDatabaseHost:[tableDocumentInstance host]];
- [dotExporter setDotDatabaseName:[tableDocumentInstance database]];
- [dotExporter setDotDatabaseVersion:[tableDocumentInstance mySQLVersion]];
-
- [dotExporter setDotExportTables:exportTables];
-
- // Create custom filename if required
- if (createCustomFilename) {
- [exportFilename setString:[self expandCustomFilenameFormatUsingTableName:nil]];
- }
- else {
- [exportFilename setString:[tableDocumentInstance database]];
- }
-
- // Only append the extension if necessary
- if (![[exportFilename pathExtension] length]) {
- [exportFilename setString:[exportFilename stringByAppendingPathExtension:[self currentDefaultExportFileExtension]]];
- }
-
- file = [SPExportFile exportFileAtPath:[[exportPathField stringValue] stringByAppendingPathComponent:exportFilename]];
-
- [exportFiles addObject:file];
-
- [dotExporter setExportOutputFile:file];
-
- [exporters addObject:dotExporter];
-
- [dotExporter release];
- }
-
- // For each of the created exporters, set their generic properties
- for (SPExporter *exporter in exporters)
- {
- [exporter setConnection:connection];
- [exporter setServerSupport:[self serverSupport]];
- [exporter setExportOutputEncoding:[connection stringEncoding]];
- [exporter setExportMaxProgress:(NSInteger)[exportProgressIndicator bounds].size.width];
- [exporter setExportUsingLowMemoryBlockingStreaming:([exportProcessLowMemoryButton state] == NSOnState)];
- [exporter setExportOutputCompressionFormat:(SPFileCompressionFormat)[exportOutputCompressionFormatPopupButton indexOfSelectedItem]];
- [exporter setExportOutputCompressFile:([exportOutputCompressionFormatPopupButton indexOfSelectedItem] != SPNoCompression)];
- }
-
- NSMutableArray *problemFiles = [[NSMutableArray alloc] init];
-
- // Create the actual file handles while dealing with errors (e.g. file already exists, etc) during creation
- for (SPExportFile *exportFile in exportFiles)
- {
- if ([exportFile createExportFileHandle:NO] == SPExportFileHandleCreated) {
-
- [exportFile setCompressionFormat:(SPFileCompressionFormat)[exportOutputCompressionFormatPopupButton indexOfSelectedItem]];
-
- if ([exportFile exportFileNeedsCSVHeader]) {
- [self writeCSVHeaderToExportFile:exportFile];
- }
- else if ([exportFile exportFileNeedsXMLHeader]) {
- [self writeXMLHeaderToExportFile:exportFile];
- }
- }
- else {
- [problemFiles addObject:exportFile];
- }
- }
-
- // Deal with any file handles that we failed to create for whatever reason
- if ([problemFiles count] > 0) {
- [self errorCreatingExportFileHandles:problemFiles];
- }
- else {
- [self startExport];
- }
-
- [problemFiles release];
-}
-
-/**
- * Initialises a CSV exporter for the supplied table name or data array.
- *
- * @param table The table name for which the exporter should be cerated for (can be nil).
- * @param dataArray The MySQL result data array for which the exporter should be created for (can be nil).
- */
-- (SPCSVExporter *)initializeCSVExporterForTable:(NSString *)table orDataArray:(NSArray *)dataArray
-{
- SPCSVExporter *csvExporter = [[SPCSVExporter alloc] initWithDelegate:self];
-
- // Depeding on the export source, set the table name or data array
- if (exportSource == SPTableExport) {
- [csvExporter setCsvTableName:table];
- }
- else {
- [csvExporter setCsvDataArray:dataArray];
- }
-
- [csvExporter setCsvTableData:tableDataInstance];
- [csvExporter setCsvOutputFieldNames:[exportCSVIncludeFieldNamesCheck state]];
- [csvExporter setCsvFieldSeparatorString:[exportCSVFieldsTerminatedField stringValue]];
- [csvExporter setCsvEnclosingCharacterString:[exportCSVFieldsWrappedField stringValue]];
- [csvExporter setCsvLineEndingString:[exportCSVLinesTerminatedField stringValue]];
- [csvExporter setCsvEscapeString:[exportCSVFieldsEscapedField stringValue]];
- [csvExporter setCsvNULLString:[exportCSVNULLValuesAsTextField stringValue]];
-
- // If required create separate files
- if (exportSource == SPTableExport && [self exportToMultipleFiles]) {
-
- if (createCustomFilename) {
-
- // Create custom filename based on the selected format
- [exportFilename setString:[self expandCustomFilenameFormatUsingTableName:table]];
-
- // If the user chose to use a custom filename format and we exporting to multiple files, make
- // sure the table name is included to ensure the output files are unique.
- if (exportTableCount > 1) {
- BOOL tableNameInTokens = NO;
- NSArray *representedObjects = [exportCustomFilenameTokenField objectValue];
- for (id representedObject in representedObjects) {
- if ([representedObject isKindOfClass:[SPExportFileNameTokenObject class]] && [[representedObject tokenId] isEqualToString:SPFileNameTableTokenName]) tableNameInTokens = YES;
- }
- [exportFilename setString:(tableNameInTokens ? exportFilename : [exportFilename stringByAppendingFormat:@"_%@", table])];
- }
- }
- else {
- [exportFilename setString:(dataArray) ? [tableDocumentInstance database] : table];
- }
-
- // Only append the extension if necessary
- if (![[exportFilename pathExtension] length]) {
- [exportFilename setString:[exportFilename stringByAppendingPathExtension:[self currentDefaultExportFileExtension]]];
- }
-
- SPExportFile *file = [SPExportFile exportFileAtPath:[[exportPathField stringValue] stringByAppendingPathComponent:exportFilename]];
-
- [exportFiles addObject:file];
-
- [csvExporter setExportOutputFile:file];
- }
-
- return [csvExporter autorelease];
-}
-
-/**
- * Initialises a XML exporter for the supplied table name or data array.
- *
- * @param table The table name for which the exporter should be cerated for (can be nil).
- * @param dataArray The MySQL result data array for which the exporter should be created for (can be nil).
- */
-- (SPXMLExporter *)initializeXMLExporterForTable:(NSString *)table orDataArray:(NSArray *)dataArray
-{
- SPXMLExporter *xmlExporter = [[SPXMLExporter alloc] initWithDelegate:self];
-
- // if required set the data array
- if (exportSource != SPTableExport) {
- [xmlExporter setXmlDataArray:dataArray];
- }
-
- // Regardless of the export source, set exporter's table name as it's used in the output
- // of table and table content exports.
- [xmlExporter setXmlTableName:table];
-
- [xmlExporter setXmlFormat:[exportXMLFormatPopUpButton indexOfSelectedItem]];
- [xmlExporter setXmlOutputIncludeStructure:[exportXMLIncludeStructure state]];
- [xmlExporter setXmlOutputIncludeContent:[exportXMLIncludeContent state]];
- [xmlExporter setXmlNULLString:[exportXMLNULLValuesAsTextField stringValue]];
-
- // If required create separate files
- if ((exportSource == SPTableExport) && exportToMultipleFiles && (exportTableCount > 0)) {
-
- if (createCustomFilename) {
-
- // Create custom filename based on the selected format
- [exportFilename setString:[self expandCustomFilenameFormatUsingTableName:table]];
-
- // If the user chose to use a custom filename format and we exporting to multiple files, make
- // sure the table name is included to ensure the output files are unique.
- if (exportTableCount > 1) {
- BOOL tableNameInTokens = NO;
- NSArray *representedObjects = [exportCustomFilenameTokenField objectValue];
- for (id representedObject in representedObjects) {
- if ([representedObject isKindOfClass:[SPExportFileNameTokenObject class]] && [[representedObject tokenId] isEqualToString:SPFileNameTableTokenName]) tableNameInTokens = YES;
- }
- [exportFilename setString:(tableNameInTokens ? exportFilename : [exportFilename stringByAppendingFormat:@"_%@", table])];
- }
- }
- else {
- [exportFilename setString:(dataArray) ? [tableDocumentInstance database] : table];
- }
-
- // Only append the extension if necessary
- if (![[exportFilename pathExtension] length]) {
- [exportFilename setString:[exportFilename stringByAppendingPathExtension:[self currentDefaultExportFileExtension]]];
- }
-
- SPExportFile *file = [SPExportFile exportFileAtPath:[[exportPathField stringValue] stringByAppendingPathComponent:exportFilename]];
-
- [file setExportFileNeedsXMLHeader:YES];
-
- [exportFiles addObject:file];
-
- [xmlExporter setExportOutputFile:file];
- }
-
- return [xmlExporter autorelease];
-}
-
-@end
diff --git a/Source/SPExportInterfaceController.h b/Source/SPExportInterfaceController.h
deleted file mode 100644
index 8205f99b..00000000
--- a/Source/SPExportInterfaceController.h
+++ /dev/null
@@ -1,42 +0,0 @@
-//
-// SPExportInterfaceController.h
-// sequel-pro
-//
-// Created by Stuart Connolly (stuconnolly.com) on March 31, 2012.
-// Copyright (c) 2012 Stuart Connolly. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person
-// obtaining a copy of this software and associated documentation
-// files (the "Software"), to deal in the Software without
-// restriction, including without limitation the rights to use,
-// copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following
-// conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-// OTHER DEALINGS IN THE SOFTWARE.
-//
-// More info at <https://github.com/sequelpro/sequelpro>
-
-#import "SPExportController.h"
-
-/**
- * @category SPExportInterfaceController SPExportInterfaceController.h
- *
- * @author Stuart Connolly http://stuconnolly.com/
- *
- * Export interface category.
- */
-@interface SPExportController (SPExportInterfaceController)
-
-@end
diff --git a/Source/SPExportInterfaceController.m b/Source/SPExportInterfaceController.m
deleted file mode 100644
index 0011a0a8..00000000
--- a/Source/SPExportInterfaceController.m
+++ /dev/null
@@ -1,150 +0,0 @@
-//
-// SPExportInterfaceController.m
-// sequel-pro
-//
-// Created by Stuart Connolly (stuconnolly.com) on March 31, 2012.
-// Copyright (c) 2012 Stuart Connolly. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person
-// obtaining a copy of this software and associated documentation
-// files (the "Software"), to deal in the Software without
-// restriction, including without limitation the rights to use,
-// copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following
-// conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-// OTHER DEALINGS IN THE SOFTWARE.
-//
-// More info at <https://github.com/sequelpro/sequelpro>
-
-#import "SPExportInterfaceController.h"
-
-@implementation SPExportController (SPExportInterfaceController)
-
-/**
- * Resizes the export window's height by the supplied delta, while retaining the position of
- * all interface controls to accommodate the custom filename view.
- *
- * @param delta The height delta for which the height should be adjusted for.
- */
-- (void)_resizeWindowForCustomFilenameViewByHeightDelta:(NSInteger)delta
-{
- NSUInteger popUpMask = [exportInputPopUpButton autoresizingMask];
- NSUInteger fileCheckMask = [exportFilePerTableCheck autoresizingMask];
- NSUInteger scrollMask = [exportTablelistScrollView autoresizingMask];
- NSUInteger buttonBarMask = [exportTableListButtonBar autoresizingMask];
- NSUInteger buttonMask = [exportCustomFilenameViewButton autoresizingMask];
- NSUInteger textFieldMask = [exportCustomFilenameViewLabelButton autoresizingMask];
- NSUInteger customFilenameViewMask = [exportCustomFilenameView autoresizingMask];
- NSUInteger tabBarMask = [exportOptionsTabBar autoresizingMask];
-
- NSRect frame = [[self window] frame];
-
- if (frame.size.height > 600 && delta > heightOffset1) {
- frame.origin.y += [exportCustomFilenameView frame].size.height;
- frame.size.height -= [exportCustomFilenameView frame].size.height;
-
- [[self window] setFrame:frame display:YES animate:YES];
- }
-
- [exportInputPopUpButton setAutoresizingMask:NSViewNotSizable | NSViewMaxYMargin];
- [exportFilePerTableCheck setAutoresizingMask:NSViewNotSizable | NSViewMaxYMargin];
- [exportTablelistScrollView setAutoresizingMask:NSViewNotSizable | NSViewMaxYMargin];
- [exportTableListButtonBar setAutoresizingMask:NSViewNotSizable | NSViewMaxYMargin];
- [exportOptionsTabBar setAutoresizingMask:NSViewNotSizable | NSViewMaxYMargin];
- [exportCustomFilenameViewButton setAutoresizingMask:NSViewNotSizable | NSViewMinYMargin];
- [exportCustomFilenameViewLabelButton setAutoresizingMask:NSViewNotSizable | NSViewMinYMargin];
- [exportCustomFilenameView setAutoresizingMask:NSViewNotSizable | NSViewMinYMargin];
-
- NSInteger newMinHeight = (windowMinHeigth - heightOffset1 + delta < windowMinHeigth) ? windowMinHeigth : windowMinHeigth - heightOffset1 + delta;
-
- [[self window] setMinSize:NSMakeSize(windowMinWidth, newMinHeight)];
-
- frame.origin.y += heightOffset1;
- frame.size.height -= heightOffset1;
-
- heightOffset1 = delta;
-
- frame.origin.y -= heightOffset1;
- frame.size.height += heightOffset1;
-
- [[self window] setFrame:frame display:YES animate:YES];
-
- [exportInputPopUpButton setAutoresizingMask:popUpMask];
- [exportFilePerTableCheck setAutoresizingMask:fileCheckMask];
- [exportTablelistScrollView setAutoresizingMask:scrollMask];
- [exportTableListButtonBar setAutoresizingMask:buttonBarMask];
- [exportCustomFilenameViewButton setAutoresizingMask:buttonMask];
- [exportCustomFilenameViewLabelButton setAutoresizingMask:textFieldMask];
- [exportCustomFilenameView setAutoresizingMask:customFilenameViewMask];
- [exportOptionsTabBar setAutoresizingMask:tabBarMask];
-}
-
-/**
- * Resizes the export window's height by the supplied delta, while retaining the position of
- * all interface controls to accommodate the advanced options view.
- *
- * @param delta The height delta for which the height should be adjusted for.
- */
-- (void)_resizeWindowForAdvancedOptionsViewByHeightDelta:(NSInteger)delta
-{
- NSUInteger scrollMask = [exportTablelistScrollView autoresizingMask];
- NSUInteger buttonBarMask = [exportTableListButtonBar autoresizingMask];
- NSUInteger tabBarMask = [exportTypeTabBar autoresizingMask];
- NSUInteger optionsTabBarMask = [exportOptionsTabBar autoresizingMask];
- NSUInteger buttonMask = [exportAdvancedOptionsViewButton autoresizingMask];
- NSUInteger textFieldMask = [exportAdvancedOptionsViewLabelButton autoresizingMask];
- NSUInteger advancedViewMask = [exportAdvancedOptionsView autoresizingMask];
-
- NSRect frame = [[self window] frame];
-
- if (frame.size.height > 600 && delta > heightOffset2) {
- frame.origin.y += [exportAdvancedOptionsView frame].size.height;
- frame.size.height -= [exportAdvancedOptionsView frame].size.height;
-
- [[self window] setFrame:frame display:YES animate:YES];
- }
-
- [exportTablelistScrollView setAutoresizingMask:NSViewNotSizable | NSViewMinYMargin];
- [exportTableListButtonBar setAutoresizingMask:NSViewNotSizable | NSViewMinYMargin];
- [exportTypeTabBar setAutoresizingMask:NSViewNotSizable | NSViewMinYMargin];
- [exportOptionsTabBar setAutoresizingMask:NSViewNotSizable | NSViewMinYMargin];
- [exportAdvancedOptionsViewButton setAutoresizingMask:NSViewNotSizable | NSViewMinYMargin];
- [exportAdvancedOptionsViewLabelButton setAutoresizingMask:NSViewNotSizable | NSViewMinYMargin];
- [exportAdvancedOptionsView setAutoresizingMask:NSViewNotSizable | NSViewMinYMargin];
-
- NSInteger newMinHeight = (windowMinHeigth - heightOffset2 + delta < windowMinHeigth) ? windowMinHeigth : windowMinHeigth - heightOffset2 + delta;
-
- [[self window] setMinSize:NSMakeSize(windowMinWidth, newMinHeight)];
-
- frame.origin.y += heightOffset2;
- frame.size.height -= heightOffset2;
-
- heightOffset2 = delta;
-
- frame.origin.y -= heightOffset2;
- frame.size.height += heightOffset2;
-
- [[self window] setFrame:frame display:YES animate:YES];
-
- [exportTablelistScrollView setAutoresizingMask:scrollMask];
- [exportTableListButtonBar setAutoresizingMask:buttonBarMask];
- [exportTypeTabBar setAutoresizingMask:tabBarMask];
- [exportOptionsTabBar setAutoresizingMask:optionsTabBarMask];
- [exportAdvancedOptionsViewButton setAutoresizingMask:buttonMask];
- [exportAdvancedOptionsViewLabelButton setAutoresizingMask:textFieldMask];
- [exportAdvancedOptionsView setAutoresizingMask:advancedViewMask];
-}
-
-@end
diff --git a/Source/SPExportSettingsPersistence.h b/Source/SPExportSettingsPersistence.h
deleted file mode 100644
index 41609125..00000000
--- a/Source/SPExportSettingsPersistence.h
+++ /dev/null
@@ -1,64 +0,0 @@
-//
-// SPExportSettingsPersistence.h
-// sequel-pro
-//
-// Created by Max Lohrmann on 09.10.15.
-// Copyright (c) 2015 Max Lohrmann. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person
-// obtaining a copy of this software and associated documentation
-// files (the "Software"), to deal in the Software without
-// restriction, including without limitation the rights to use,
-// copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following
-// conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-// OTHER DEALINGS IN THE SOFTWARE.
-//
-// More info at <https://github.com/sequelpro/sequelpro>
-
-#import <Foundation/Foundation.h>
-#import "SPExportController.h"
-
-@interface SPExportController (SPExportSettingsPersistence)
-
-- (IBAction)exportCurrentSettings:(id)sender;
-- (IBAction)importCurrentSettings:(id)sender;
-
-/**
- * @return The current settings as a dictionary which can be serialized
- */
-- (NSDictionary *)currentSettingsAsDictionary;
-
-/** Overwrite current export settings with those defined in dict
- * @param dict The new settings to apply (passing nil is an error.)
- * @param err Errors while applying (will mostly be about invalid format, type)
- * Can pass NULL, if not interested in details.
- * Will NOT be changed unless the method also returns NO
- * @return success
- */
-- (BOOL)applySettingsFromDictionary:(NSDictionary *)dict error:(NSError **)err;
-
-/**
- * @return A serialized form of the "custom filename" field
- */
-- (NSArray *)currentCustomFilenameAsArray;
-
-/**
- * @param tokenList A serialized form of the "custom filename" field
- * @see currentCustomFilenameAsArray
- */
-- (void)setCustomFilenameFromArray:(NSArray *)tokenList;
-
-@end
diff --git a/Source/SPExportSettingsPersistence.m b/Source/SPExportSettingsPersistence.m
deleted file mode 100644
index 33118e84..00000000
--- a/Source/SPExportSettingsPersistence.m
+++ /dev/null
@@ -1,803 +0,0 @@
-//
-// SPExportSettingsPersistence.m
-// sequel-pro
-//
-// Created by Max Lohrmann on 09.10.15.
-// Copyright (c) 2015 Max Lohrmann. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person
-// obtaining a copy of this software and associated documentation
-// files (the "Software"), to deal in the Software without
-// restriction, including without limitation the rights to use,
-// copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following
-// conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-// OTHER DEALINGS IN THE SOFTWARE.
-//
-// More info at <https://github.com/sequelpro/sequelpro>
-
-#import "SPExportSettingsPersistence.h"
-#import "SPExportFileNameTokenObject.h"
-#import "SPExportFilenameUtilities.h"
-#import "SPExportController+SharedPrivateAPI.h"
-
-/**
- * converts a ([obj state] == NSOnState) to @YES / @NO
- * (because doing @([obj state] == NSOnState) will result in an integer 0/1)
- */
-static inline NSNumber *IsOn(id obj);
-/**
- * Sets the state of obj to NSOnState or NSOffState based on the value of ref
- */
-static inline void SetOnOff(NSNumber *ref,id obj);
-
-@interface SPExportController (Private)
-
-- (void)_updateExportAdvancedOptionsLabel;
-
-@end
-
-@interface SPExportController (SPExportSettingsPersistence_Private)
-
-// those methods will convert the name of a C enum constant to a NSString
-+ (NSString *)describeExportSource:(SPExportSource)es;
-+ (NSString *)describeExportType:(SPExportType)et;
-+ (NSString *)describeCompressionFormat:(SPFileCompressionFormat)cf;
-+ (NSString *)describeXMLExportFormat:(SPXMLExportFormat)xf;
-+ (NSString *)describeSQLExportInsertDivider:(SPSQLExportInsertDivider)eid;
-
-// these will store the C enum constant named by NSString in dst and return YES,
-// if a valid mapping exists. Otherwise will just return NO and not modify dst.
-+ (BOOL)copyExportSourceForDescription:(NSString *)esd to:(SPExportSource *)dst;
-+ (BOOL)copyCompressionFormatForDescription:(NSString *)esd to:(SPFileCompressionFormat *)dst;
-+ (BOOL)copyExportTypeForDescription:(NSString *)esd to:(SPExportType *)dst;
-+ (BOOL)copyXMLExportFormatForDescription:(NSString *)xfd to:(SPXMLExportFormat *)dst;
-+ (BOOL)copySQLExportInsertDividerForDescription:(NSString *)xfd to:(SPSQLExportInsertDivider *)dst;
-
-- (NSDictionary *)exporterSettings;
-- (NSDictionary *)csvSettings;
-- (NSDictionary *)dotSettings;
-- (NSDictionary *)xmlSettings;
-- (NSDictionary *)sqlSettings;
-
-- (void)applyExporterSettings:(NSDictionary *)settings;
-- (void)applyCsvSettings:(NSDictionary *)settings;
-- (void)applyDotSettings:(NSDictionary *)settings;
-- (void)applyXmlSettings:(NSDictionary *)settings;
-- (void)applySqlSettings:(NSDictionary *)settings;
-
-- (id)exporterSpecificSettingsForSchemaObject:(NSString *)name ofType:(SPTableType)type;
-- (id)dotSpecificSettingsForSchemaObject:(NSString *)name ofType:(SPTableType)type;
-- (id)xmlSpecificSettingsForSchemaObject:(NSString *)name ofType:(SPTableType)type;
-- (id)csvSpecificSettingsForSchemaObject:(NSString *)name ofType:(SPTableType)type;
-- (id)sqlSpecificSettingsForSchemaObject:(NSString *)name ofType:(SPTableType)type;
-
-- (void)applyExporterSpecificSettings:(id)settings forSchemaObject:(NSString *)name ofType:(SPTableType)type;
-- (void)applyDotSpecificSettings:(id)settings forSchemaObject:(NSString *)name ofType:(SPTableType)type;
-- (void)applyXmlSpecificSettings:(id)settings forSchemaObject:(NSString *)name ofType:(SPTableType)type;
-- (void)applyCsvSpecificSettings:(id)settings forSchemaObject:(NSString *)name ofType:(SPTableType)type;
-- (void)applySqlSpecificSettings:(id)settings forSchemaObject:(NSString *)name ofType:(SPTableType)type;
-
-@end
-
-#pragma mark -
-
-@implementation SPExportController (SPExportSettingsPersistence)
-
-#define NAMEOF(x) case x: return @#x
-#define VALUEOF(x,y,dst) if([y isEqualToString:@#x]) { *dst = x; return YES; }
-
-+ (NSString *)describeExportSource:(SPExportSource)es
-{
- switch (es) {
- NAMEOF(SPFilteredExport);
- NAMEOF(SPQueryExport);
- NAMEOF(SPTableExport);
- }
- return nil;
-}
-
-+ (BOOL)copyExportSourceForDescription:(NSString *)esd to:(SPExportSource *)dst
-{
- VALUEOF(SPFilteredExport, esd,dst);
- VALUEOF(SPQueryExport, esd,dst);
- VALUEOF(SPTableExport, esd,dst);
- return NO;
-}
-
-+ (NSString *)describeExportType:(SPExportType)et
-{
- switch (et) {
- NAMEOF(SPSQLExport);
- NAMEOF(SPCSVExport);
- NAMEOF(SPXMLExport);
- NAMEOF(SPDotExport);
- NAMEOF(SPPDFExport);
- NAMEOF(SPHTMLExport);
- NAMEOF(SPExcelExport);
- NAMEOF(SPAnyExportType);
- }
- return nil;
-}
-
-+ (BOOL)copyExportTypeForDescription:(NSString *)etd to:(SPExportType *)dst
-{
- VALUEOF(SPSQLExport, etd, dst);
- VALUEOF(SPCSVExport, etd, dst);
- VALUEOF(SPXMLExport, etd, dst);
- VALUEOF(SPDotExport, etd, dst);
- //VALUEOF(SPPDFExport, etd, dst);
- //VALUEOF(SPHTMLExport, etd, dst);
- //VALUEOF(SPExcelExport, etd, dst);
- return NO;
-}
-
-+ (NSString *)describeCompressionFormat:(SPFileCompressionFormat)cf
-{
- switch (cf) {
- NAMEOF(SPNoCompression);
- NAMEOF(SPGzipCompression);
- NAMEOF(SPBzip2Compression);
- }
- return nil;
-}
-
-+ (BOOL)copyCompressionFormatForDescription:(NSString *)cfd to:(SPFileCompressionFormat *)dst
-{
- VALUEOF(SPNoCompression, cfd, dst);
- VALUEOF(SPGzipCompression, cfd, dst);
- VALUEOF(SPBzip2Compression, cfd, dst);
- return NO;
-}
-
-+ (NSString *)describeXMLExportFormat:(SPXMLExportFormat)xf
-{
- switch (xf) {
- NAMEOF(SPXMLExportMySQLFormat);
- NAMEOF(SPXMLExportPlainFormat);
- }
- return nil;
-}
-
-+ (BOOL)copyXMLExportFormatForDescription:(NSString *)xfd to:(SPXMLExportFormat *)dst
-{
- VALUEOF(SPXMLExportMySQLFormat, xfd, dst);
- VALUEOF(SPXMLExportPlainFormat, xfd, dst);
- return NO;
-}
-
-+ (NSString *)describeSQLExportInsertDivider:(SPSQLExportInsertDivider)eid
-{
- switch (eid) {
- NAMEOF(SPSQLInsertEveryNDataBytes);
- NAMEOF(SPSQLInsertEveryNRows);
- }
- return nil;
-}
-
-+ (BOOL)copySQLExportInsertDividerForDescription:(NSString *)eidd to:(SPSQLExportInsertDivider *)dst
-{
- VALUEOF(SPSQLInsertEveryNDataBytes, eidd, dst);
- VALUEOF(SPSQLInsertEveryNRows, eidd, dst);
- return NO;
-}
-
-#undef NAMEOF
-#undef VALUEOF
-
-- (IBAction)importCurrentSettings:(id)sender
-{
- //show open file dialog
- NSOpenPanel *panel = [NSOpenPanel openPanel];
-
- [panel setAllowedFileTypes:@[SPFileExtensionDefault]];
- [panel setAllowsOtherFileTypes:YES];
-
- [panel beginSheetModalForWindow:[self window] completionHandler:^(NSInteger result) {
- if(result != NSFileHandlingPanelOKButton) return;
-
- [panel orderOut:nil]; // Panel is still on screen. Hide it first. (This is Apple's recommended way)
-
- NSError *err = nil;
- NSData *plist = [NSData dataWithContentsOfURL:[panel URL]
- options:0
- error:&err];
-
- NSDictionary *settings = nil;
- if(!err) {
- settings = [NSPropertyListSerialization propertyListWithData:plist
- options:NSPropertyListImmutable
- format:NULL
- error:&err];
- }
-
- if(!err) {
- [self applySettingsFromDictionary:settings error:&err];
- if(!err) return;
- }
-
- // give an explanation for some errors
- if([[err domain] isEqualToString:SPErrorDomain]) {
- if([err code] == SPErrorWrongTypeOrNil) {
- NSDictionary *info = @{
- NSLocalizedDescriptionKey: NSLocalizedString(@"Invalid file supplied!", @"export : import settings : file error title"),
- NSLocalizedRecoverySuggestionErrorKey: NSLocalizedString(@"The selected file is either not a valid SPF file or severely corrupted.", @"export : import settings : file error description"),
- };
- err = [NSError errorWithDomain:[err domain] code:[err code] userInfo:info];
- }
- else if([err code] == SPErrorWrongContentType) {
- NSDictionary *info = @{
- NSLocalizedDescriptionKey: NSLocalizedString(@"Wrong SPF content type!", @"export : import settings : spf content type error title"),
- NSLocalizedRecoverySuggestionErrorKey: [NSString stringWithFormat:NSLocalizedString(@"The selected file contains data of type “%1$@”, but type “%2$@” is needed. Please choose a different file.", @"export : import settings : spf content type error description"),[[err userInfo] objectForKey:@"isType"],[[err userInfo] objectForKey:@"expectedType"]],
- };
- err = [NSError errorWithDomain:[err domain] code:[err code] userInfo:info];
- }
- }
-
- NSAlert *alert = [NSAlert alertWithError:err];
- [alert setAlertStyle:NSCriticalAlertStyle];
- [alert runModal];
- }];
-}
-
-- (IBAction)exportCurrentSettings:(id)sender
-{
- //show save file dialog
- NSSavePanel *panel = [NSSavePanel savePanel];
-
- [panel setAllowedFileTypes:@[SPFileExtensionDefault]];
-
- [panel setExtensionHidden:NO];
- [panel setAllowsOtherFileTypes:NO];
- [panel setCanSelectHiddenExtension:YES];
- [panel setCanCreateDirectories:YES];
-
- [panel beginSheetModalForWindow:[self window] completionHandler:^(NSInteger returnCode) {
- if(returnCode != NSFileHandlingPanelOKButton) return;
-
- // Panel is still on screen. Hide it first. (This is Apple's recommended way)
- [panel orderOut:nil];
-
- NSError *err = nil;
- NSData *plist = [NSPropertyListSerialization dataWithPropertyList:[self currentSettingsAsDictionary]
- format:NSPropertyListXMLFormat_v1_0
- options:0
- error:&err];
- if(!err) {
- [plist writeToURL:[panel URL] options:NSAtomicWrite error:&err];
- if(!err) return;
- }
-
- NSAlert *alert = [NSAlert alertWithError:err];
- [alert setAlertStyle:NSCriticalAlertStyle];
- [alert runModal];
- }];
-}
-
-- (NSArray *)currentCustomFilenameAsArray
-{
- NSArray *tokenListIn = [exportCustomFilenameTokenField objectValue];
- NSMutableArray *tokenListOut = [NSMutableArray arrayWithCapacity:[tokenListIn count]];
-
- for (id obj in tokenListIn) {
- if([obj isKindOfClass:[NSString class]]) {
- [tokenListOut addObject:obj];
- }
- else if([obj isKindOfClass:[SPExportFileNameTokenObject class]]) {
- NSDictionary *tokenProperties = @{@"tokenId": [obj tokenId]};
- // in the future the dict can be used to store per-token settings
- [tokenListOut addObject:tokenProperties];
- }
- else {
- SPLog(@"unknown object in token list: %@",obj);
- }
- }
-
- return tokenListOut;
-}
-
-- (void)setCustomFilenameFromArray:(NSArray *)tokenList
-{
- NSMutableArray *tokenListOut = [NSMutableArray arrayWithCapacity:[tokenList count]];
- NSArray *allowedTokens = [self currentAllowedExportFilenameTokens];
-
- for (id obj in tokenList) {
- if([obj isKindOfClass:[NSString class]]) {
- [tokenListOut addObject:obj];
- }
- else if([obj isKindOfClass:[NSDictionary class]]) {
- //there must be at least a non-empty tokenId that is also in the token pool
- NSString *tokenId = [obj objectForKey:@"tokenId"];
- if([tokenId length]) {
- SPExportFileNameTokenObject *token = [SPExportFileNameTokenObject tokenWithId:tokenId];
- if([allowedTokens containsObject:token]) {
- [tokenListOut addObject:token];
- continue;
- }
- }
- SPLog(@"Ignoring an invalid or unknown token with tokenId=%@",tokenId);
- }
- else {
- SPLog(@"unknown object in import token list: %@",obj);
- }
- }
-
- [exportCustomFilenameTokenField setObjectValue:tokenListOut];
-
- [self updateDisplayedExportFilename];
-}
-
-- (NSDictionary *)currentSettingsAsDictionary
-{
- NSMutableDictionary *root = [NSMutableDictionary dictionary];
-
- [root setObject:SPFExportSettingsContentType forKey:SPFFormatKey];
- [root setObject:@1 forKey:SPFVersionKey];
-
- [root setObject:[exportPathField stringValue] forKey:@"exportPath"];
-
- [root setObject:[[self class] describeExportSource:exportSource] forKey:@"exportSource"];
- [root setObject:[[self class] describeExportType:exportType] forKey:@"exportType"];
-
- if([[exportCustomFilenameTokenField stringValue] length] > 0) {
- [root setObject:[self currentCustomFilenameAsArray] forKey:@"customFilename"];
- }
-
- [root setObject:[self exporterSettings] forKey:@"settings"];
-
- if(exportSource == SPTableExport) {
- NSMutableDictionary *perObjectSettings = [NSMutableDictionary dictionaryWithCapacity:[tables count]];
-
- for (NSMutableArray *table in tables) {
- NSString *key = [table objectAtIndex:0];
- id settings = [self exporterSpecificSettingsForSchemaObject:key ofType:SPTableTypeTable];
- if(settings)
- [perObjectSettings setObject:settings forKey:key];
- }
-
- [root setObject:perObjectSettings forKey:@"schemaObjects"];
- }
-
- [root setObject:IsOn(exportProcessLowMemoryButton) forKey:@"lowMemoryStreaming"];
- [root setObject:[[self class] describeCompressionFormat:(SPFileCompressionFormat)[exportOutputCompressionFormatPopupButton indexOfSelectedItem]] forKey:@"compressionFormat"];
-
- return root;
-}
-
-- (BOOL)applySettingsFromDictionary:(NSDictionary *)dict error:(NSError **)err
-{
- //check for dict/nil
- if(![dict isKindOfClass:[NSDictionary class]]) {
- if(err) {
- *err = [NSError errorWithDomain:SPErrorDomain
- code:SPErrorWrongTypeOrNil
- userInfo:nil]; // we don't know where data came from, so we can't provide meaningful help to the user
- }
- return NO;
- }
-
- //check for export settings
- NSString *ctype = [dict objectForKey:SPFFormatKey];
- if (![SPFExportSettingsContentType isEqualToString:ctype]) {
- if(err) {
- NSDictionary *errInfo = @{
- @"isType": ctype,
- @"expectedType": SPFExportSettingsContentType
- };
- *err = [NSError errorWithDomain:SPErrorDomain
- code:SPErrorWrongContentType
- userInfo:errInfo];
- }
- return NO;
- }
-
- //check for version
- NSInteger version = [[dict objectForKey:SPFVersionKey] integerValue];
- if(version != 1) {
- if(err) {
- NSDictionary *errInfo = @{
- @"isVersion": @(version),
- NSLocalizedDescriptionKey: NSLocalizedString(@"Unsupported version for export settings!", @"export : import settings : file version error title"),
- NSLocalizedRecoverySuggestionErrorKey: [NSString stringWithFormat:NSLocalizedString(@"The selected export settings were stored with version\u00A0%1$ld, but only settings with the following versions can be imported: %2$@.\n\nEither save the settings in a backwards compatible way or update your version of Sequel Pro.", @"export : import settings : file version error description ($1 = is version, $2 = list of supported versions); note: the u00A0 is a non-breaking space, do not add more whitespace."),version,@"1"],
- };
- *err = [NSError errorWithDomain:SPErrorDomain
- code:SPErrorWrongContentVersion
- userInfo:errInfo];
- }
- return NO;
- }
-
- //ok, we can try to import that...
-
- [exporters removeAllObjects];
- [exportFiles removeAllObjects];
-
- id o;
- if((o = [dict objectForKey:@"exportPath"])) [exportPathField setStringValue:o];
-
- SPExportType et;
- if((o = [dict objectForKey:@"exportType"]) && [[self class] copyExportTypeForDescription:o to:&et]) {
- [exportTypeTabBar selectTabViewItemAtIndex:et];
- }
-
- //exportType should be changed first, as exportSource depends on it
- SPExportSource es;
- if((o = [dict objectForKey:@"exportSource"]) && [[self class] copyExportSourceForDescription:o to:&es]) {
- [self setExportInput:es]; //try to set it. might fail e.g. if the settings were saved with "query result" but right now no custom query result exists
- }
-
- // set exporter specific settings
- [self applyExporterSettings:[dict objectForKey:@"settings"]];
-
- // load schema object settings
- if(exportSource == SPTableExport) {
- NSDictionary *perObjectSettings = [dict objectForKey:@"schemaObjects"];
-
- for (NSString *table in [perObjectSettings allKeys]) {
- id settings = [perObjectSettings objectForKey:table];
- [self applyExporterSpecificSettings:settings forSchemaObject:table ofType:SPTableTypeTable];
- }
-
- [exportTableList reloadData];
- }
-
- if((o = [dict objectForKey:@"lowMemoryStreaming"])) [exportProcessLowMemoryButton setState:([o boolValue] ? NSOnState : NSOffState)];
-
- SPFileCompressionFormat cf;
- if((o = [dict objectForKey:@"compressionFormat"]) && [[self class] copyCompressionFormatForDescription:o to:&cf]) [exportOutputCompressionFormatPopupButton selectItemAtIndex:cf];
-
- // might have changed
- [self _updateExportAdvancedOptionsLabel];
-
- // token pool is only valid once the schema object selection is done
- [self updateAvailableExportFilenameTokens];
- if((o = [dict objectForKey:@"customFilename"]) && [o isKindOfClass:[NSArray class]]) [self setCustomFilenameFromArray:o];
-
- return YES;
-}
-
-- (NSDictionary *)exporterSettings
-{
- switch (exportType) {
- case SPCSVExport:
- return [self csvSettings];
- case SPSQLExport:
- return [self sqlSettings];
- case SPXMLExport:
- return [self xmlSettings];
- case SPDotExport:
- return [self dotSettings];
- case SPExcelExport:
- case SPHTMLExport:
- case SPPDFExport:
- default:
- @throw [NSException exceptionWithName:NSInternalInconsistencyException
- reason:@"exportType not implemented!"
- userInfo:@{@"exportType": @(exportType)}];
- }
-}
-
-- (void)applyExporterSettings:(NSDictionary *)settings
-{
- switch (exportType) {
- case SPCSVExport:
- return [self applyCsvSettings:settings];
- case SPSQLExport:
- return [self applySqlSettings:settings];
- case SPXMLExport:
- return [self applyXmlSettings:settings];
- case SPDotExport:
- return [self applyDotSettings:settings];
- case SPExcelExport:
- case SPHTMLExport:
- case SPPDFExport:
- default:
- @throw [NSException exceptionWithName:NSInternalInconsistencyException
- reason:@"exportType not implemented!"
- userInfo:@{@"exportType": @(exportType)}];
- }
-}
-
-- (NSDictionary *)csvSettings
-{
- return @{
- @"exportToMultipleFiles": IsOn(exportFilePerTableCheck),
- @"CSVIncludeFieldNames": IsOn(exportCSVIncludeFieldNamesCheck),
- @"CSVFieldsTerminated": [exportCSVFieldsTerminatedField stringValue],
- @"CSVFieldsWrapped": [exportCSVFieldsWrappedField stringValue],
- @"CSVLinesTerminated": [exportCSVLinesTerminatedField stringValue],
- @"CSVFieldsEscaped": [exportCSVFieldsEscapedField stringValue],
- @"CSVNULLValuesAsText": [exportCSVNULLValuesAsTextField stringValue]
- };
-}
-
-- (void)applyCsvSettings:(NSDictionary *)settings
-{
- id o;
- if((o = [settings objectForKey:@"exportToMultipleFiles"])) SetOnOff(o,exportFilePerTableCheck);
- [self toggleNewFilePerTable:nil];
-
- if((o = [settings objectForKey:@"CSVIncludeFieldNames"])) SetOnOff(o, exportCSVIncludeFieldNamesCheck);
- if((o = [settings objectForKey:@"CSVFieldsTerminated"])) [exportCSVFieldsTerminatedField setStringValue:o];
- if((o = [settings objectForKey:@"CSVFieldsWrapped"])) [exportCSVFieldsWrappedField setStringValue:o];
- if((o = [settings objectForKey:@"CSVLinesTerminated"])) [exportCSVLinesTerminatedField setStringValue:o];
- if((o = [settings objectForKey:@"CSVFieldsEscaped"])) [exportCSVFieldsEscapedField setStringValue:o];
- if((o = [settings objectForKey:@"CSVNULLValuesAsText"])) [exportCSVNULLValuesAsTextField setStringValue:o];
-}
-
-- (NSDictionary *)dotSettings
-{
- return @{@"DotForceLowerTableNames": IsOn(exportDotForceLowerTableNamesCheck)};
-}
-
-- (void)applyDotSettings:(NSDictionary *)settings
-{
- id o;
- if((o = [settings objectForKey:@"DotForceLowerTableNames"])) SetOnOff(o, exportDotForceLowerTableNamesCheck);
-}
-
-- (NSDictionary *)xmlSettings
-{
- return @{
- @"exportToMultipleFiles": IsOn(exportFilePerTableCheck),
- @"XMLFormat": [[self class] describeXMLExportFormat:(SPXMLExportFormat)[exportXMLFormatPopUpButton indexOfSelectedItem]],
- @"XMLOutputIncludeStructure": IsOn(exportXMLIncludeStructure),
- @"XMLOutputIncludeContent": IsOn(exportXMLIncludeContent),
- @"XMLNULLString": [exportXMLNULLValuesAsTextField stringValue]
- };
-}
-
-- (void)applyXmlSettings:(NSDictionary *)settings
-{
- id o;
- SPXMLExportFormat xmlf;
- if((o = [settings objectForKey:@"exportToMultipleFiles"])) SetOnOff(o, exportFilePerTableCheck);
- [self toggleNewFilePerTable:nil];
-
- if((o = [settings objectForKey:@"XMLFormat"]) && [[self class] copyXMLExportFormatForDescription:o to:&xmlf]) [exportXMLFormatPopUpButton selectItemAtIndex:xmlf];
- if((o = [settings objectForKey:@"XMLOutputIncludeStructure"])) SetOnOff(o, exportXMLIncludeStructure);
- if((o = [settings objectForKey:@"XMLOutputIncludeContent"])) SetOnOff(o, exportXMLIncludeContent);
- if((o = [settings objectForKey:@"XMLNULLString"])) [exportXMLNULLValuesAsTextField setStringValue:o];
-
- [self toggleXMLOutputFormat:exportXMLFormatPopUpButton];
-}
-
-- (NSDictionary *)sqlSettings
-{
- BOOL includeStructure = ([exportSQLIncludeStructureCheck state] == NSOnState);
-
- NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:@{
- @"SQLIncludeStructure": IsOn(exportSQLIncludeStructureCheck),
- @"SQLIncludeContent": IsOn(exportSQLIncludeContentCheck),
- @"SQLIncludeErrors": IsOn(exportSQLIncludeErrorsCheck),
- @"SQLIncludeDROP": IsOn(exportSQLIncludeDropSyntaxCheck),
- @"SQLUseUTF8BOM": IsOn(exportUseUTF8BOMButton),
- @"SQLBLOBFieldsAsHex": IsOn(exportSQLBLOBFieldsAsHexCheck),
- @"SQLInsertNValue": @([exportSQLInsertNValueTextField integerValue]),
- @"SQLInsertDivider": [[self class] describeSQLExportInsertDivider:(SPSQLExportInsertDivider)[exportSQLInsertDividerPopUpButton indexOfSelectedItem]]
- }];
-
- if(includeStructure) {
- [dict addEntriesFromDictionary:@{
- @"SQLIncludeAutoIncrementValue": IsOn(exportSQLIncludeAutoIncrementValueButton),
- @"SQLIncludeDropSyntax": IsOn(exportSQLIncludeDropSyntaxCheck)
- }];
- }
-
- return dict;
-}
-
-- (void)applySqlSettings:(NSDictionary *)settings
-{
- id o;
- SPSQLExportInsertDivider div;
-
- if((o = [settings objectForKey:@"SQLIncludeContent"])) SetOnOff(o, exportSQLIncludeContentCheck);
- [self toggleSQLIncludeContent:exportSQLIncludeContentCheck];
-
- if((o = [settings objectForKey:@"SQLIncludeDROP"])) SetOnOff(o, exportSQLIncludeDropSyntaxCheck);
- [self toggleSQLIncludeDropSyntax:exportSQLIncludeDropSyntaxCheck];
-
- if((o = [settings objectForKey:@"SQLIncludeStructure"])) SetOnOff(o, exportSQLIncludeStructureCheck);
- [self toggleSQLIncludeStructure:exportSQLIncludeStructureCheck];
-
- if((o = [settings objectForKey:@"SQLIncludeErrors"])) SetOnOff(o, exportSQLIncludeErrorsCheck);
- if((o = [settings objectForKey:@"SQLUseUTF8BOM"])) SetOnOff(o, exportUseUTF8BOMButton);
- if((o = [settings objectForKey:@"SQLBLOBFieldsAsHex"])) SetOnOff(o, exportSQLBLOBFieldsAsHexCheck);
- if((o = [settings objectForKey:@"SQLInsertNValue"])) [exportSQLInsertNValueTextField setIntegerValue:[o integerValue]];
- if((o = [settings objectForKey:@"SQLInsertDivider"]) && [[self class] copySQLExportInsertDividerForDescription:o to:&div]) [exportSQLInsertDividerPopUpButton selectItemAtIndex:div];
-
- if([exportSQLIncludeStructureCheck state] == NSOnState) {
- if((o = [settings objectForKey:@"SQLIncludeAutoIncrementValue"])) SetOnOff(o, exportSQLIncludeAutoIncrementValueButton);
- if((o = [settings objectForKey:@"SQLIncludeDropSyntax"])) SetOnOff(o, exportSQLIncludeDropSyntaxCheck);
- }
-}
-
-- (id)exporterSpecificSettingsForSchemaObject:(NSString *)name ofType:(SPTableType)type
-{
- switch (exportType) {
- case SPCSVExport:
- return [self csvSpecificSettingsForSchemaObject:name ofType:type];
- case SPSQLExport:
- return [self sqlSpecificSettingsForSchemaObject:name ofType:type];
- case SPXMLExport:
- return [self xmlSpecificSettingsForSchemaObject:name ofType:type];
- case SPDotExport:
- return [self dotSpecificSettingsForSchemaObject:name ofType:type];
- case SPExcelExport:
- case SPHTMLExport:
- case SPPDFExport:
- default:
- @throw [NSException exceptionWithName:NSInternalInconsistencyException
- reason:@"exportType not implemented!"
- userInfo:@{@"exportType": @(exportType)}];
- }
-}
-
-- (void)applyExporterSpecificSettings:(id)settings forSchemaObject:(NSString *)name ofType:(SPTableType)type
-{
- switch (exportType) {
- case SPCSVExport:
- return [self applyCsvSpecificSettings:settings forSchemaObject:name ofType:type];
- case SPSQLExport:
- return [self applySqlSpecificSettings:settings forSchemaObject:name ofType:type];
- case SPXMLExport:
- return [self applyXmlSpecificSettings:settings forSchemaObject:name ofType:type];
- case SPDotExport:
- return [self applyDotSpecificSettings:settings forSchemaObject:name ofType:type];
- case SPExcelExport:
- case SPHTMLExport:
- case SPPDFExport:
- default:
- @throw [NSException exceptionWithName:NSInternalInconsistencyException
- reason:@"exportType not implemented!"
- userInfo:@{@"exportType": @(exportType)}];
- }
-}
-
-- (id)dotSpecificSettingsForSchemaObject:(NSString *)name ofType:(SPTableType)type
-{
- // Dot is a graph of the whole database - nothing to pick from
- return nil;
-}
-
-- (void)applyDotSpecificSettings:(id)settings forSchemaObject:(NSString *)name ofType:(SPTableType)type
-{
- //should never be called
-}
-
-- (id)xmlSpecificSettingsForSchemaObject:(NSString *)name ofType:(SPTableType)type
-{
- // XML per table setting is only yes/no
- if(type == SPTableTypeTable) {
- // we have to look through the table views' rows to find the current checkbox value...
- for (NSArray *table in tables) {
- if([[table objectAtIndex:0] isEqualTo:name]) {
- return @([[table objectAtIndex:2] boolValue]);
- }
- }
- }
- return nil;
-}
-
-- (void)applyXmlSpecificSettings:(id)settings forSchemaObject:(NSString *)name ofType:(SPTableType)type
-{
- // XML per table setting is only yes/no
- if(type == SPTableTypeTable) {
- // we have to look through the table views' rows to find the appropriate table...
- for (NSMutableArray *table in tables) {
- if([[table objectAtIndex:0] isEqualTo:name]) {
- [table replaceObjectAtIndex:2 withObject:@([settings boolValue])];
- return;
- }
- }
- }
-}
-
-- (id)csvSpecificSettingsForSchemaObject:(NSString *)name ofType:(SPTableType)type
-{
- // CSV per table setting is only yes/no
- if(type == SPTableTypeTable) {
- // we have to look through the table views rows to find the current checkbox value...
- for (NSArray *table in tables) {
- if([[table objectAtIndex:0] isEqualTo:name]) {
- return @([[table objectAtIndex:2] boolValue]);
- }
- }
- }
- return nil;
-}
-
-- (void)applyCsvSpecificSettings:(id)settings forSchemaObject:(NSString *)name ofType:(SPTableType)type
-{
- // CSV per table setting is only yes/no
- if(type == SPTableTypeTable) {
- // we have to look through the table views' rows to find the appropriate table...
- for (NSMutableArray *table in tables) {
- if([[table objectAtIndex:0] isEqualTo:name]) {
- [table replaceObjectAtIndex:2 withObject:@([settings boolValue])];
- return;
- }
- }
- }
-}
-
-- (id)sqlSpecificSettingsForSchemaObject:(NSString *)name ofType:(SPTableType)type
-{
- BOOL structure = ([exportSQLIncludeStructureCheck state] == NSOnState);
- BOOL content = ([exportSQLIncludeContentCheck state] == NSOnState);
- BOOL drop = ([exportSQLIncludeDropSyntaxCheck state] == NSOnState);
-
- // SQL allows per table setting of structure/content/drop table
- if(type == SPTableTypeTable) {
- // we have to look through the table views rows to find the current checkbox value...
- for (NSArray *table in tables) {
- if([[table objectAtIndex:0] isEqualTo:name]) {
- NSMutableArray *flags = [NSMutableArray arrayWithCapacity:3];
-
- if (structure && [[table objectAtIndex:1] boolValue]) {
- [flags addObject:@"structure"];
- }
-
- if (content && [[table objectAtIndex:2] boolValue]) {
- [flags addObject:@"content"];
- }
-
- if (drop && [[table objectAtIndex:3] boolValue]) {
- [flags addObject:@"drop"];
- }
-
- return flags;
- }
- }
- }
- return nil;
-}
-
-- (void)applySqlSpecificSettings:(id)settings forSchemaObject:(NSString *)name ofType:(SPTableType)type
-{
- BOOL structure = ([exportSQLIncludeStructureCheck state] == NSOnState);
- BOOL content = ([exportSQLIncludeContentCheck state] == NSOnState);
- BOOL drop = ([exportSQLIncludeDropSyntaxCheck state] == NSOnState);
-
- // SQL allows per table setting of structure/content/drop table
- if(type == SPTableTypeTable) {
- // we have to look through the table views' rows to find the appropriate table...
- for (NSMutableArray *table in tables) {
- if([[table objectAtIndex:0] isEqualTo:name]) {
- NSArray *flags = settings;
-
- [table replaceObjectAtIndex:1 withObject:@((structure && [flags containsObject:@"structure"]))];
- [table replaceObjectAtIndex:2 withObject:@((content && [flags containsObject:@"content"]))];
- [table replaceObjectAtIndex:3 withObject:@((drop && [flags containsObject:@"drop"]))];
- return;
- }
- }
- }
-}
-
-@end
-
-#pragma mark -
-
-NSNumber *IsOn(id obj)
-{
- return (([obj state] == NSOnState)? @YES : @NO);
-}
-
-void SetOnOff(NSNumber *ref,id obj)
-{
- [obj setState:([ref boolValue] ? NSOnState : NSOffState)];
-}
diff --git a/Source/SPFieldMapperController.m b/Source/SPFieldMapperController.m
index ee80174a..4dbf8aa9 100644
--- a/Source/SPFieldMapperController.m
+++ b/Source/SPFieldMapperController.m
@@ -52,7 +52,7 @@ static NSString *SPTableViewSqlColumnID = @"sql";
static NSUInteger SPSourceColumnTypeText = 0;
static NSUInteger SPSourceColumnTypeInteger = 1;
-@interface SPFieldMapperController (Private)
+@interface SPFieldMapperController ()
- (void)_setupFieldMappingPopUpMenus;
@end
diff --git a/Source/SPHTMLExporterDelegate.h b/Source/SPHTMLExporterDelegate.h
deleted file mode 100644
index a206839b..00000000
--- a/Source/SPHTMLExporterDelegate.h
+++ /dev/null
@@ -1,43 +0,0 @@
-//
-// SPHTMLExporterDelegate.h
-// sequel-pro
-//
-// Created by Stuart Connolly (stuconnolly.com) on April 24, 2010.
-// Copyright (c) 2010 Stuart Connolly. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person
-// obtaining a copy of this software and associated documentation
-// files (the "Software"), to deal in the Software without
-// restriction, including without limitation the rights to use,
-// copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following
-// conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-// OTHER DEALINGS IN THE SOFTWARE.
-//
-// More info at <https://github.com/sequelpro/sequelpro>
-
-#import "SPExportController.h"
-#import "SPHTMLExporterProtocol.h"
-
-/**
- * @category SPHTMLExporterDelegate SPHTMLExporterDelegate.h
- *
- * @author Stuart Connolly http://stuconnolly.com/
- *
- * HTML exporter delegate category.
- */
-@interface SPExportController (SPHTMLExporterDelegate) <SPHTMLExporterProtocol>
-
-@end
diff --git a/Source/SPHTMLExporterDelegate.m b/Source/SPHTMLExporterDelegate.m
deleted file mode 100644
index 0d69f651..00000000
--- a/Source/SPHTMLExporterDelegate.m
+++ /dev/null
@@ -1,49 +0,0 @@
-//
-// SPHTMLExporterDelegate.m
-// sequel-pro
-//
-// Created by Stuart Connolly (stuconnolly.com) on April 24, 2010.
-// Copyright (c) 2010 Stuart Connolly. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person
-// obtaining a copy of this software and associated documentation
-// files (the "Software"), to deal in the Software without
-// restriction, including without limitation the rights to use,
-// copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following
-// conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-// OTHER DEALINGS IN THE SOFTWARE.
-//
-// More info at <https://github.com/sequelpro/sequelpro>
-
-#import "SPHTMLExporterDelegate.h"
-#import "SPExportInitializer.h"
-
-@implementation SPExportController (SPHTMLExporterDelegate)
-
-- (void)htmlExportProcessWillBegin:(SPHTMLExporter *)exporter
-{
-}
-
-- (void)htmlExportProcessComplete:(SPHTMLExporter *)exporter
-{
- [self exportEnded];
-}
-
-- (void)htmlExportProcessWillBeginWritingData:(SPHTMLExporter *)exporter
-{
-}
-
-@end
diff --git a/Source/SPPDFExporterDelegate.h b/Source/SPPDFExporterDelegate.h
deleted file mode 100644
index a44b1fa8..00000000
--- a/Source/SPPDFExporterDelegate.h
+++ /dev/null
@@ -1,43 +0,0 @@
-//
-// SPPDFExporterDelegate.h
-// sequel-pro
-//
-// Created by Stuart Connolly (stuconnolly.com) on April 24, 2010.
-// Copyright (c) 2010 Stuart Connolly. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person
-// obtaining a copy of this software and associated documentation
-// files (the "Software"), to deal in the Software without
-// restriction, including without limitation the rights to use,
-// copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following
-// conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-// OTHER DEALINGS IN THE SOFTWARE.
-//
-// More info at <https://github.com/sequelpro/sequelpro>
-
-#import "SPExportController.h"
-#import "SPPDFExporterProtocol.h"
-
-/**
- * @category SPPDFExporterDelegate SPPDFExporterDelegate.h
- *
- * @author Stuart Connolly http://stuconnolly.com/
- *
- * PDF exporter delegate category.
- */
-@interface SPExportController (SPPDFExporterDelegate) <SPPDFExporterProtocol>
-
-@end
diff --git a/Source/SPPDFExporterDelegate.m b/Source/SPPDFExporterDelegate.m
deleted file mode 100644
index b6b6eef7..00000000
--- a/Source/SPPDFExporterDelegate.m
+++ /dev/null
@@ -1,49 +0,0 @@
-//
-// SPPDFExporterDelegate.m
-// sequel-pro
-//
-// Created by Stuart Connolly (stuconnolly.com) on April 24, 2010.
-// Copyright (c) 2010 Stuart Connolly. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person
-// obtaining a copy of this software and associated documentation
-// files (the "Software"), to deal in the Software without
-// restriction, including without limitation the rights to use,
-// copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following
-// conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-// OTHER DEALINGS IN THE SOFTWARE.
-//
-// More info at <https://github.com/sequelpro/sequelpro>
-
-#import "SPPDFExporterDelegate.h"
-#import "SPExportInitializer.h"
-
-@implementation SPExportController (SPPDFExporterDelegate)
-
-- (void)pdfExportProcessWillBegin:(SPPDFExporter *)exporter
-{
-}
-
-- (void)pdfExportProcessComplete:(SPPDFExporter *)exporter
-{
- [self exportEnded];
-}
-
-- (void)pdfExportProcessWillBeginWritingData:(SPPDFExporter *)exporter
-{
-}
-
-@end
diff --git a/Source/SPProcessListController.m b/Source/SPProcessListController.m
index eb22d484..a256835c 100644
--- a/Source/SPProcessListController.m
+++ b/Source/SPProcessListController.m
@@ -45,7 +45,7 @@ static NSString *SPTableViewIDColumnIdentifier = @"Id";
static NSString * const SPKillModeKey = @"SPKillMode";
static NSString * const SPKillIdKey = @"SPKillId";
-@interface SPProcessListController (PrivateAPI)
+@interface SPProcessListController ()
- (void)_processListRefreshed;
- (void)_startAutoRefreshTimer;
@@ -803,6 +803,70 @@ static NSString * const SPKillIdKey = @"SPKillId";
[prefs removeObserver:self forKeyPath:SPDisplayTableViewVerticalGridlines];
}
+#pragma mark - SPProcessListControllerDataSource
+
+#pragma mark Tableview delegate methods
+
+/**
+ * Table view delegate method. Returns the number of rows in the table veiw.
+ */
+- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
+{
+ return [processesFiltered count];
+}
+
+/**
+ * Table view delegate method. Returns the specific object for the request column and row.
+ */
+- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
+{
+ id object = ((NSUInteger)row < [processesFiltered count]) ? [[processesFiltered objectAtIndex:row] valueForKey:[tableColumn identifier]] : @"";
+
+ if ([object isNSNull]) {
+ return [prefs stringForKey:SPNullValue];
+ }
+
+ // If the string is exactly 100 characters long, and FULL process lists are not enabled, it's a safe
+ // bet that the string is truncated
+ if (!showFullProcessList && [object isKindOfClass:[NSString class]] && [(NSString *)object length] == 100) {
+ return [object stringByAppendingString:@"…"];
+ }
+
+ return object;
+}
+
+/**
+ * Table view delegate method. Called when the user changes the sort by column.
+ */
+- (void)tableView:(NSTableView *)tableView sortDescriptorsDidChange:(NSArray *)oldDescriptors
+{
+ [processesFiltered sortUsingDescriptors:[tableView sortDescriptors]];
+
+ [tableView reloadData];
+}
+
+/**
+ * Table view delegate method. Called whenever the user changes a column width.
+ */
+- (void)tableViewColumnDidResize:(NSNotification *)notification
+{
+ NSTableColumn *column = [[notification userInfo] objectForKey:@"NSTableColumn"];
+
+ // Get the existing table column widths dictionary if it exists
+ NSMutableDictionary *tableColumnWidths = ([prefs objectForKey:SPProcessListTableColumnWidths]) ?
+ [NSMutableDictionary dictionaryWithDictionary:[prefs objectForKey:SPProcessListTableColumnWidths]] :
+ [NSMutableDictionary dictionary];
+
+ // Save column size
+ NSString *columnName = [[column headerCell] stringValue];
+
+ if (columnName) {
+ [tableColumnWidths setObject:[NSNumber numberWithDouble:[column width]] forKey:columnName];
+
+ [prefs setObject:tableColumnWidths forKey:SPProcessListTableColumnWidths];
+ }
+}
+
#pragma mark -
- (void)dealloc
diff --git a/Source/SPProcessListControllerDataSource.h b/Source/SPProcessListControllerDataSource.h
deleted file mode 100644
index 0934d591..00000000
--- a/Source/SPProcessListControllerDataSource.h
+++ /dev/null
@@ -1,33 +0,0 @@
-//
-// SPProcessListControllerDataSource.h
-// sequel-pro
-//
-// Created by Stuart Connolly (stuconnolly.com) on April 3, 2013.
-// Copyright (c) 2013 Stuart Connolly. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person
-// obtaining a copy of this software and associated documentation
-// files (the "Software"), to deal in the Software without
-// restriction, including without limitation the rights to use,
-// copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following
-// conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-// OTHER DEALINGS IN THE SOFTWARE.
-
-#import "SPProcessListController.h"
-
-@interface SPProcessListController (SPProcessListControllerDataSource)
-
-@end
diff --git a/Source/SPProcessListControllerDataSource.m b/Source/SPProcessListControllerDataSource.m
deleted file mode 100644
index 7306e382..00000000
--- a/Source/SPProcessListControllerDataSource.m
+++ /dev/null
@@ -1,96 +0,0 @@
-//
-// SPProcessListControllerDataSource.m
-// sequel-pro
-//
-// Created by Stuart Connolly (stuconnolly.com) on April 3, 2013.
-// Copyright (c) 2013 Stuart Connolly. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person
-// obtaining a copy of this software and associated documentation
-// files (the "Software"), to deal in the Software without
-// restriction, including without limitation the rights to use,
-// copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following
-// conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-// OTHER DEALINGS IN THE SOFTWARE.
-
-#import "SPProcessListControllerDataSource.h"
-
-@implementation SPProcessListController (SPProcessListControllerDataSource)
-
-#pragma mark -
-#pragma mark Tableview delegate methods
-
-/**
- * Table view delegate method. Returns the number of rows in the table veiw.
- */
-- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
-{
- return [processesFiltered count];
-}
-
-/**
- * Table view delegate method. Returns the specific object for the request column and row.
- */
-- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
-{
- id object = ((NSUInteger)row < [processesFiltered count]) ? [[processesFiltered objectAtIndex:row] valueForKey:[tableColumn identifier]] : @"";
-
- if ([object isNSNull]) {
- return [prefs stringForKey:SPNullValue];
- }
-
- // If the string is exactly 100 characters long, and FULL process lists are not enabled, it's a safe
- // bet that the string is truncated
- if (!showFullProcessList && [object isKindOfClass:[NSString class]] && [(NSString *)object length] == 100) {
- return [object stringByAppendingString:@"…"];
- }
-
- return object;
-}
-
-/**
- * Table view delegate method. Called when the user changes the sort by column.
- */
-- (void)tableView:(NSTableView *)tableView sortDescriptorsDidChange:(NSArray *)oldDescriptors
-{
- [processesFiltered sortUsingDescriptors:[tableView sortDescriptors]];
-
- [tableView reloadData];
-}
-
-/**
- * Table view delegate method. Called whenever the user changes a column width.
- */
-- (void)tableViewColumnDidResize:(NSNotification *)notification
-{
- NSTableColumn *column = [[notification userInfo] objectForKey:@"NSTableColumn"];
-
- // Get the existing table column widths dictionary if it exists
- NSMutableDictionary *tableColumnWidths = ([prefs objectForKey:SPProcessListTableColumnWidths]) ?
- [NSMutableDictionary dictionaryWithDictionary:[prefs objectForKey:SPProcessListTableColumnWidths]] :
- [NSMutableDictionary dictionary];
-
- // Save column size
- NSString *columnName = [[column headerCell] stringValue];
-
- if (columnName) {
- [tableColumnWidths setObject:[NSNumber numberWithDouble:[column width]] forKey:columnName];
-
- [prefs setObject:tableColumnWidths forKey:SPProcessListTableColumnWidths];
- }
-}
-
-@end
diff --git a/Source/SPSQLExporterDelegate.h b/Source/SPSQLExporterDelegate.h
deleted file mode 100644
index a4a3e1cb..00000000
--- a/Source/SPSQLExporterDelegate.h
+++ /dev/null
@@ -1,43 +0,0 @@
-//
-// SPSQLExporterDelegate.h
-// sequel-pro
-//
-// Created by Stuart Connolly (stuconnolly.com) on March 28, 2010.
-// Copyright (c) 2010 Stuart Connolly. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person
-// obtaining a copy of this software and associated documentation
-// files (the "Software"), to deal in the Software without
-// restriction, including without limitation the rights to use,
-// copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following
-// conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-// OTHER DEALINGS IN THE SOFTWARE.
-//
-// More info at <https://github.com/sequelpro/sequelpro>
-
-#import "SPExportController.h"
-#import "SPSQLExporterProtocol.h"
-
-/**
- * @category SPSQLExporterDelegate SPSQLExporterDelegate.h
- *
- * @author Stuart Connolly http://stuconnolly.com/
- *
- * SQL exporter delegate category.
- */
-@interface SPExportController (SPSQLExporterDelegate) <SPSQLExporterProtocol>
-
-@end
diff --git a/Source/SPSQLExporterDelegate.m b/Source/SPSQLExporterDelegate.m
deleted file mode 100644
index 09e87cf8..00000000
--- a/Source/SPSQLExporterDelegate.m
+++ /dev/null
@@ -1,82 +0,0 @@
-//
-// SPSQLExporterDelegate.m
-// sequel-pro
-//
-// Created by Stuart Connolly (stuconnolly.com) on March 28, 2010.
-// Copyright (c) 2010 Stuart Connolly. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person
-// obtaining a copy of this software and associated documentation
-// files (the "Software"), to deal in the Software without
-// restriction, including without limitation the rights to use,
-// copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following
-// conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-// OTHER DEALINGS IN THE SOFTWARE.
-//
-// More info at <https://github.com/sequelpro/sequelpro>
-
-#import "SPSQLExporterDelegate.h"
-#import "SPSQLExporter.h"
-#import "SPDatabaseDocument.h"
-#import "SPExportInitializer.h"
-
-@implementation SPExportController (SPSQLExporterDelegate)
-
-- (void)sqlExportProcessWillBegin:(SPSQLExporter *)exporter
-{
- [exportProgressTitle setStringValue:NSLocalizedString(@"Exporting SQL", @"text showing that the application is exporting SQL")];
- [exportProgressText setStringValue:NSLocalizedString(@"Dumping...", @"text showing that app is writing dump")];
-
- [exportProgressTitle displayIfNeeded];
- [exportProgressText displayIfNeeded];
-}
-
-- (void)sqlExportProcessComplete:(SPSQLExporter *)exporter
-{
- [self exportEnded];
-
- // Check for errors and display the errors sheet if necessary
- if ([exporter didExportErrorsOccur]) {
- [self openExportErrorsSheetWithString:[exporter sqlExportErrors]];
- }
-}
-
-- (void)sqlExportProcessProgressUpdated:(SPSQLExporter *)exporter
-{
- if ([exportProgressIndicator doubleValue] == 0) {
- [exportProgressIndicator stopAnimation:self];
- [exportProgressIndicator setIndeterminate:NO];
- }
-
- [exportProgressIndicator setDoubleValue:[exporter exportProgressValue]];
-}
-
-- (void)sqlExportProcessWillBeginFetchingData:(SPSQLExporter *)exporter
-{
- [exportProgressText setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Table %lu of %lu (%@): Fetching data...", @"export label showing that the app is fetching data for a specific table"), [exporter sqlCurrentTableExportIndex], exportTableCount, [exporter sqlExportCurrentTable]]];
-
- [exportProgressIndicator startAnimation:self];
- [exportProgressIndicator setUsesThreadedAnimation:YES];
- [exportProgressIndicator setIndeterminate:YES];
- [exportProgressIndicator setDoubleValue:0];
-}
-
-- (void)sqlExportProcessWillBeginWritingData:(SPSQLExporter *)exporter
-{
- [exportProgressText setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Table %lu of %lu (%@): Writing data...", @"export label showing app if writing data for a specific table"), [exporter sqlCurrentTableExportIndex], exportTableCount, [exporter sqlExportCurrentTable]]];
-}
-
-@end
diff --git a/Source/SPTableData.m b/Source/SPTableData.m
index a0bfa7ff..c065d4d1 100644
--- a/Source/SPTableData.m
+++ b/Source/SPTableData.m
@@ -39,7 +39,7 @@
#import <pthread.h>
#import <SPMySQL/SPMySQL.h>
-@interface SPTableData (PrivateAPI)
+@interface SPTableData ()
- (void)_loopWhileWorking;
- (NSDictionary *)parseCreateStatement:(NSString *)tableDef ofType:(NSString *)tableType;
diff --git a/Source/SPXMLExporterDelegate.h b/Source/SPXMLExporterDelegate.h
deleted file mode 100644
index 606235e1..00000000
--- a/Source/SPXMLExporterDelegate.h
+++ /dev/null
@@ -1,43 +0,0 @@
-//
-// SPXMLExporterDelegate.h
-// sequel-pro
-//
-// Created by Stuart Connolly (stuconnolly.com) on April 6, 2010.
-// Copyright (c) 2010 Stuart Connolly. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person
-// obtaining a copy of this software and associated documentation
-// files (the "Software"), to deal in the Software without
-// restriction, including without limitation the rights to use,
-// copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following
-// conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-// OTHER DEALINGS IN THE SOFTWARE.
-//
-// More info at <https://github.com/sequelpro/sequelpro>
-
-#import "SPExportController.h"
-#import "SPXMLExporterProtocol.h"
-
-/**
- * @category SPXMLExporterDelegate SPXMLExporterDelegate.h
- *
- * @author Stuart Connolly http://stuconnolly.com/
- *
- * XML exporter delegate category.
- */
-@interface SPExportController (SPXMLExporterDelegate) <SPXMLExporterProtocol>
-
-@end
diff --git a/Source/SPXMLExporterDelegate.m b/Source/SPXMLExporterDelegate.m
deleted file mode 100644
index 80d5d0ca..00000000
--- a/Source/SPXMLExporterDelegate.m
+++ /dev/null
@@ -1,134 +0,0 @@
-//
-// SPXMLExporterDelegate.h
-// sequel-pro
-//
-// Created by Stuart Connolly (stuconnolly.com) on April 6, 2010.
-// Copyright (c) 2010 Stuart Connolly. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person
-// obtaining a copy of this software and associated documentation
-// files (the "Software"), to deal in the Software without
-// restriction, including without limitation the rights to use,
-// copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following
-// conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-// OTHER DEALINGS IN THE SOFTWARE.
-//
-// More info at <https://github.com/sequelpro/sequelpro>
-
-#import "SPXMLExporterDelegate.h"
-#import "SPXMLExporter.h"
-#import "SPDatabaseDocument.h"
-#import "SPExportFile.h"
-#import "SPExportInitializer.h"
-
-#import <SPMySQL/SPMySQL.h>
-
-@implementation SPExportController (SPXMLExporterDelegate)
-
-- (void)xmlExportProcessWillBegin:(SPXMLExporter *)exporter
-{
- [exportProgressText displayIfNeeded];
-
- [exportProgressIndicator setIndeterminate:YES];
- [exportProgressIndicator setUsesThreadedAnimation:YES];
- [exportProgressIndicator startAnimation:self];
-
- // Only update the progress text if this is a table export
- if (exportSource == SPTableExport) {
-
- // Update the current table export index
- currentTableExportIndex = (exportTableCount - [exporters count]);
-
- [exportProgressText setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Table %lu of %lu (%@): Fetching data...", @"export label showing that the app is fetching data for a specific table"), currentTableExportIndex, exportTableCount, [exporter xmlTableName]]];
- }
- else {
- [exportProgressText setStringValue:NSLocalizedString(@"Fetching data...", @"export label showing that the app is fetching data")];
- }
-
- [exportProgressText displayIfNeeded];
-}
-
-- (void)xmlExportProcessComplete:(SPXMLExporter *)exporter
-{
- NSUInteger exportCount = [exporters count];
-
- // If required add the next exporter to the operation queue
- if ((exportCount > 0) && (exportSource == SPTableExport)) {
-
- // If we're exporting to multiple files then close the file handle of the exporter
- // that just finished, ensuring its data is written to disk.
- if (exportToMultipleFiles) {
- NSString *string = @"";
-
- if ([exporter xmlFormat] == SPXMLExportMySQLFormat) {
- string = (exportSource == SPTableExport) ? @"</database>\n</mysqldump>\n" : @"</resultset>\n";;
- }
- else if ([exporter xmlFormat] == SPXMLExportPlainFormat) {
- string = [NSString stringWithFormat:@"</%@>\n", [[tableDocumentInstance database] HTMLEscapeString]];
- }
-
- [[exporter exportOutputFile] writeData:[string dataUsingEncoding:[connection stringEncoding]]];
- [[exporter exportOutputFile] close];
- }
-
- [operationQueue addOperation:[exporters objectAtIndex:0]];
-
- // Remove the exporter we just added to the operation queue from our list of exporters
- // so we know it's already been done.
- [exporters removeObjectAtIndex:0];
- }
- // Otherwise if the exporter list is empty, close the progress sheet
- else {
- NSString *string = @"";
-
- if ([exporter xmlFormat] == SPXMLExportMySQLFormat) {
- string = (exportSource == SPTableExport) ? @"</database>\n</mysqldump>\n" : @"</resultset>\n";;
- }
- else if ([exporter xmlFormat] == SPXMLExportPlainFormat) {
- string = [NSString stringWithFormat:@"</%@>\n", [[tableDocumentInstance database] HTMLEscapeString]];
- }
-
- [[exporter exportOutputFile] writeData:[string dataUsingEncoding:[connection stringEncoding]]];
- [[exporter exportOutputFile] close];
-
- [self exportEnded];
- }
-}
-
-- (void)xmlExportProcessProgressUpdated:(SPXMLExporter *)exporter
-{
- [[exportProgressIndicator onMainThread] setDoubleValue:[exporter exportProgressValue]];
-}
-
-- (void)xmlExportProcessWillBeginWritingData:(SPXMLExporter *)exporter
-{
- // Only update the progress text if this is a table export
- if (exportSource == SPTableExport) {
- [exportProgressText setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Table %lu of %lu (%@): Writing data...", @"export label showing app if writing data for a specific table"), currentTableExportIndex, exportTableCount, [exporter xmlTableName]]];
- }
- else {
- [exportProgressText setStringValue:NSLocalizedString(@"Writing data...", @"export label showing app is writing data")];
- }
-
- [exportProgressText displayIfNeeded];
-
- [exportProgressIndicator stopAnimation:self];
- [exportProgressIndicator setUsesThreadedAnimation:NO];
- [exportProgressIndicator setIndeterminate:NO];
- [exportProgressIndicator setDoubleValue:0];
-}
-
-@end