aboutsummaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
authorMax <dmoagx@users.noreply.github.com>2017-12-28 00:34:42 +0100
committerMax <dmoagx@users.noreply.github.com>2018-01-20 02:42:35 +0100
commitb7830d694092ba3418b803448798f9b7d9687bde (patch)
tree8c2d1b61b7a4d23ac13ca65da9c67f352593e8fe /Source
parente86375a3402b30cf3f28c308ccf63a4ca224ccae (diff)
downloadsequelpro-b7830d694092ba3418b803448798f9b7d9687bde.tar.gz
sequelpro-b7830d694092ba3418b803448798f9b7d9687bde.tar.bz2
sequelpro-b7830d694092ba3418b803448798f9b7d9687bde.zip
Merge SPDatabaseDocument (part of #2789)
Diffstat (limited to 'Source')
-rw-r--r--Source/SPAppController.m1
-rw-r--r--Source/SPConnectionController.m1
-rw-r--r--Source/SPConnectionControllerInitializer.m2
-rw-r--r--Source/SPConnectionDelegate.h42
-rw-r--r--Source/SPConnectionDelegate.m209
-rw-r--r--Source/SPCustomQuery.m2
-rw-r--r--Source/SPDataImport.m1
-rw-r--r--Source/SPDatabaseDocument.h43
-rw-r--r--Source/SPDatabaseDocument.m1190
-rw-r--r--Source/SPDatabaseStructure.m1
-rw-r--r--Source/SPDatabaseViewController.h65
-rw-r--r--Source/SPDatabaseViewController.m641
-rw-r--r--Source/SPExportFilenameUtilities.m2
-rw-r--r--Source/SPExtendedTableInfo.m1
-rw-r--r--Source/SPHistoryController.m1
-rw-r--r--Source/SPIndexesController.m1
-rw-r--r--Source/SPNavigatorController.m1
-rw-r--r--Source/SPPrintController.h42
-rw-r--r--Source/SPPrintController.m461
-rw-r--r--Source/SPTableContent.m1
-rw-r--r--Source/SPTableStructure.m1
-rw-r--r--Source/SPTableStructureDelegate.h2
-rw-r--r--Source/SPTableStructureDelegate.m4
-rw-r--r--Source/SPTableStructureLoading.m2
-rw-r--r--Source/SPTablesList.m1
-rw-r--r--Source/SPTextView.m3
-rw-r--r--Source/SPWindowController.m1
27 files changed, 1235 insertions, 1487 deletions
diff --git a/Source/SPAppController.m b/Source/SPAppController.m
index 58080265..a0d4c266 100644
--- a/Source/SPAppController.m
+++ b/Source/SPAppController.m
@@ -50,7 +50,6 @@
#import "SPCopyTable.h"
#import "SPSyntaxParser.h"
#import "SPOSInfo.h"
-#import "SPPrintController.h"
#import <PSMTabBar/PSMTabBarControl.h>
#import <Sparkle/Sparkle.h>
diff --git a/Source/SPConnectionController.m b/Source/SPConnectionController.m
index 1ccde091..96376404 100644
--- a/Source/SPConnectionController.m
+++ b/Source/SPConnectionController.m
@@ -45,7 +45,6 @@
#import "SPFavoritesController.h"
#import "SPFavoriteNode.h"
#import "SPGeneralPreferencePane.h"
-#import "SPDatabaseViewController.h"
#import "SPTreeNode.h"
#import "SPFavoritesExporter.h"
#import "SPFavoritesImporter.h"
diff --git a/Source/SPConnectionControllerInitializer.m b/Source/SPConnectionControllerInitializer.m
index 5254e36d..22e52502 100644
--- a/Source/SPConnectionControllerInitializer.m
+++ b/Source/SPConnectionControllerInitializer.m
@@ -35,7 +35,7 @@
#import "SPTreeNode.h"
#import "SPFavoriteNode.h"
#import "SPGroupNode.h"
-#import "SPDatabaseViewController.h"
+#import "SPDatabaseDocument.h"
#import "SPSplitView.h"
#import "SPFavoriteColorSupport.h"
#import "SPColorSelectorView.h"
diff --git a/Source/SPConnectionDelegate.h b/Source/SPConnectionDelegate.h
deleted file mode 100644
index c786d8ac..00000000
--- a/Source/SPConnectionDelegate.h
+++ /dev/null
@@ -1,42 +0,0 @@
-//
-// SPConnectionDelegate.h
-// sequel-pro
-//
-// Created by Stuart Connolly (stuconnolly.com) on November 13, 2009.
-// Copyright (c) 2009 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 "SPDatabaseDocument.h"
-
-#import <SPMySQL/SPMySQLConnectionDelegate.h>
-
-@interface SPDatabaseDocument (SPConnectionDelegate) <SPMySQLConnectionDelegate>
-
-- (void) closeAndDisconnect;
-
-- (NSString *)keychainPasswordForConnection:(SPMySQLConnection *)connection;
-- (NSString *)keychainPasswordForSSHConnection:(SPMySQLConnection *)connection;
-
-@end
diff --git a/Source/SPConnectionDelegate.m b/Source/SPConnectionDelegate.m
deleted file mode 100644
index 9e5cbd25..00000000
--- a/Source/SPConnectionDelegate.m
+++ /dev/null
@@ -1,209 +0,0 @@
-//
-// SPConnectionDelegate.m
-// sequel-pro
-//
-// Created by Stuart Connolly (stuconnolly.com) on November 13, 2009.
-// Copyright (c) 2009 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 "SPConnectionDelegate.h"
-#import "SPConnectionController.h"
-#import "SPQueryController.h"
-#import "SPKeychain.h"
-#import "SPAlertSheets.h"
-
-#import <SPMySQL/SPMySQLConstants.h>
-
-@implementation SPDatabaseDocument (SPConnectionDelegate)
-
-#pragma mark -
-#pragma mark SPMySQLConnection delegate methods
-
-/**
- * Invoked when the framework is about to perform a query.
- */
-- (void)willQueryString:(NSString *)query connection:(id)connection
-{
-#ifndef SP_CODA
- if ([prefs boolForKey:SPConsoleEnableLogging]) {
- if ((_queryMode == SPInterfaceQueryMode && [prefs boolForKey:SPConsoleEnableInterfaceLogging]) ||
- (_queryMode == SPCustomQueryQueryMode && [prefs boolForKey:SPConsoleEnableCustomQueryLogging]) ||
- (_queryMode == SPImportExportQueryMode && [prefs boolForKey:SPConsoleEnableImportExportLogging]))
- {
- [[SPQueryController sharedQueryController] showMessageInConsole:query connection:[self name] database:[self database]];
- }
- }
-#endif
-}
-
-/**
- * Invoked when the query just executed by the framework resulted in an error.
- */
-- (void)queryGaveError:(NSString *)error connection:(id)connection
-{
-#ifndef SP_CODA
- if ([prefs boolForKey:SPConsoleEnableLogging] && [prefs boolForKey:SPConsoleEnableErrorLogging]) {
- [[SPQueryController sharedQueryController] showErrorInConsole:error connection:[self name] database:[self database]];
- }
-#endif
-}
-
-/**
- * Invoked when the current connection needs a password from the Keychain.
- */
-- (NSString *)keychainPasswordForConnection:(SPMySQLConnection *)connection
-{
- // If no keychain item is available, return an empty password
- if (![connectionController connectionKeychainItemName]) return nil;
-
- // Otherwise, pull the password from the keychain using the details from this connection
- SPKeychain *keychain = [[SPKeychain alloc] init];
-
- NSString *password = [keychain getPasswordForName:[connectionController connectionKeychainItemName] account:[connectionController connectionKeychainItemAccount]];
-
- [keychain release];
-
- return password;
-}
-
-/**
- * Invoked when the current connection needs a ssh password from the Keychain.
- * This isn't actually part of the SPMySQLConnection delegate protocol, but is here
- * due to its similarity to the previous method.
- */
-- (NSString *)keychainPasswordForSSHConnection:(SPMySQLConnection *)connection
-{
- // If no keychain item is available, return an empty password
- if (![connectionController connectionKeychainItemName]) return @"";
-
- // Otherwise, pull the password from the keychain using the details from this connection
- SPKeychain *keychain = [[SPKeychain alloc] init];
-
- NSString *connectionSSHKeychainItemName = [[keychain nameForSSHForFavoriteName:[connectionController name] id:[self keyChainID]] retain];
- NSString *connectionSSHKeychainItemAccount = [[keychain accountForSSHUser:[connectionController sshUser] sshHost:[connectionController sshHost]] retain];
- NSString *sshPassword = [keychain getPasswordForName:connectionSSHKeychainItemName account:connectionSSHKeychainItemAccount];
-
- if (!sshPassword || ![sshPassword length]) {
- sshPassword = @"";
- }
-
- if (connectionSSHKeychainItemName) [connectionSSHKeychainItemName release];
- if (connectionSSHKeychainItemAccount) [connectionSSHKeychainItemAccount release];
-
- [keychain release];
-
- return sshPassword;
-}
-
-/**
- * Invoked when an attempt was made to execute a query on the current connection, but the connection is not
- * actually active.
- */
-- (void)noConnectionAvailable:(id)connection
-{
- SPOnewayAlertSheet(
- NSLocalizedString(@"No connection available", @"no connection available message"),
- [self parentWindow],
- NSLocalizedString(@"An error has occured and there doesn't seem to be a connection available.", @"no connection available informatie message")
- );
-}
-
-/**
- * Invoked when the connection fails and the framework needs to know how to proceed.
- */
-- (SPMySQLConnectionLostDecision)connectionLost:(id)connection
-{
- SPMySQLConnectionLostDecision connectionErrorCode = SPMySQLConnectionLostDisconnect;
-
- // Only display the reconnect dialog if the window is visible
- if ([self parentWindow] && [[self parentWindow] isVisible]) {
-
- // Ensure the window isn't miniaturized
- if ([[self parentWindow] isMiniaturized]) [[self parentWindow] deminiaturize:self];
-
-#ifndef SP_CODA
- // Ensure the window and tab are frontmost
- [self makeKeyDocument];
-#endif
-
- // Display the connection error dialog and wait for the return code
- [NSApp beginSheet:connectionErrorDialog modalForWindow:[self parentWindow] modalDelegate:self didEndSelector:nil contextInfo:nil];
- connectionErrorCode = (SPMySQLConnectionLostDecision)[NSApp runModalForWindow:connectionErrorDialog];
-
- [NSApp endSheet:connectionErrorDialog];
- [connectionErrorDialog orderOut:nil];
-
- // If 'disconnect' was selected, trigger a window close.
- if (connectionErrorCode == SPMySQLConnectionLostDisconnect) {
- [self performSelectorOnMainThread:@selector(closeAndDisconnect) withObject:nil waitUntilDone:YES];
- }
- }
-
- return connectionErrorCode;
-}
-
-/**
- * Invoke to display an informative but non-fatal error directly to the user.
- */
-- (void)showErrorWithTitle:(NSString *)theTitle message:(NSString *)theMessage
-{
- if ([[self parentWindow] isVisible]) {
- SPOnewayAlertSheet(theTitle, [self parentWindow], theMessage);
- }
-}
-
-/**
- * Invoked when user dismisses the error sheet displayed as a result of the current connection being lost.
- */
-- (IBAction)closeErrorConnectionSheet:(id)sender
-{
- [NSApp stopModalWithCode:[sender tag]];
-}
-
-/**
- * Close the connection - should be performed on the main thread.
- */
-- (void) closeAndDisconnect
-{
-#ifndef SP_CODA
- NSWindow *theParentWindow = [self parentWindow];
-
- _isConnected = NO;
-
- if ([[[self parentTabViewItem] tabView] numberOfTabViewItems] == 1) {
- [theParentWindow orderOut:self];
- [theParentWindow setAlphaValue:0.0f];
- [theParentWindow performSelector:@selector(close) withObject:nil afterDelay:1.0];
- }
- else {
- [[[self parentTabViewItem] tabView] performSelector:@selector(removeTabViewItem:) withObject:[self parentTabViewItem] afterDelay:0.5];
- [theParentWindow performSelector:@selector(makeKeyAndOrderFront:) withObject:nil afterDelay:0.6];
- }
-
- [self parentTabDidClose];
-#endif
-}
-
-@end
diff --git a/Source/SPCustomQuery.m b/Source/SPCustomQuery.m
index c14c275d..319b766c 100644
--- a/Source/SPCustomQuery.m
+++ b/Source/SPCustomQuery.m
@@ -66,7 +66,7 @@
#import <pthread.h>
#import <SPMySQL/SPMySQL.h>
-@interface SPCustomQuery (PrivateAPI)
+@interface SPCustomQuery ()
- (id)_resultDataItemAtRow:(NSInteger)row columnIndex:(NSUInteger)column preserveNULLs:(BOOL)preserveNULLs asPreview:(BOOL)asPreview;
+ (NSString *)linkToHelpTopic:(NSString *)aTopic;
diff --git a/Source/SPDataImport.m b/Source/SPDataImport.m
index 4c680801..f8d145a9 100644
--- a/Source/SPDataImport.m
+++ b/Source/SPDataImport.m
@@ -31,7 +31,6 @@
#import "SPDataImport.h"
#import "SPDatabaseDocument.h"
-#import "SPDatabaseViewController.h"
#import "SPTablesList.h"
#import "SPTableStructure.h"
#import "SPDatabaseStructure.h"
diff --git a/Source/SPDatabaseDocument.h b/Source/SPDatabaseDocument.h
index 96c78d1a..de7dd55e 100644
--- a/Source/SPDatabaseDocument.h
+++ b/Source/SPDatabaseDocument.h
@@ -291,7 +291,7 @@
int64_t instanceId;
}
-@property (assign) NSTableView *dbTablesTableView;
+@property (nonatomic, assign) NSTableView *dbTablesTableView;
#ifdef SP_CODA /* ivars */
@property (assign) SPDatabaseData* databaseDataInstance;
@@ -537,4 +537,45 @@
#endif
+#pragma mark - SPDatabaseViewController
+
+// Accessors
+- (NSString *)table;
+- (SPTableType)tableType;
+
+- (BOOL)structureLoaded;
+- (BOOL)contentLoaded;
+- (BOOL)statusLoaded;
+
+#ifndef SP_CODA /* method decls */
+// Tab view control
+- (IBAction)viewStructure:(id)sender;
+- (IBAction)viewContent:(id)sender;
+- (IBAction)viewQuery:(id)sender;
+- (IBAction)viewStatus:(id)sender;
+- (IBAction)viewRelations:(id)sender;
+- (IBAction)viewTriggers:(id)sender;
+#endif
+
+- (void)setStructureRequiresReload:(BOOL)reload;
+- (void)setContentRequiresReload:(BOOL)reload;
+- (void)setStatusRequiresReload:(BOOL)reload;
+- (void)setRelationsRequiresReload:(BOOL)reload;
+
+// Table control
+- (void)loadTable:(NSString *)aTable ofType:(SPTableType)aTableType;
+
+#ifndef SP_CODA /* method decls */
+- (NSView *)databaseView;
+#endif
+
+#pragma mark - SPPrintController
+
+- (void)startPrintDocumentOperation;
+- (void)generateHTMLForPrinting;
+- (void)generateTableInfoHTMLForPrinting;
+
+- (NSArray *)columnNames;
+- (NSMutableDictionary *)connectionInformation;
+
@end
diff --git a/Source/SPDatabaseDocument.m b/Source/SPDatabaseDocument.m
index a82632d0..d591121d 100644
--- a/Source/SPDatabaseDocument.m
+++ b/Source/SPDatabaseDocument.m
@@ -34,7 +34,6 @@
#import "SPConnectionHandler.h"
#import "SPConnectionControllerInitializer.h"
#import "SPTablesList.h"
-#import "SPTableStructure.h"
#import "SPDatabaseStructure.h"
#import "SPFileHandle.h"
#import "SPKeychain.h"
@@ -54,7 +53,6 @@
#import "SPTableData.h"
#import "SPDatabaseData.h"
#import "SPDatabaseStructure.h"
-#import "SPAppController.h"
#import "SPExtendedTableInfo.h"
#import "SPHistoryController.h"
#import "SPPreferenceController.h"
@@ -72,9 +70,6 @@
#import "SPCopyTable.h"
#import "SPServerSupport.h"
#import "SPTooltip.h"
-#import "SPDatabaseViewController.h"
-#import "SPBundleHTMLOutputController.h"
-#import "SPConnectionDelegate.h"
#import "SPThreadAdditions.h"
#import "RegexKitLite.h"
#import "SPTextView.h"
@@ -83,6 +78,18 @@
#import "SPGotoDatabaseController.h"
#import "SPFunctions.h"
#import "SPCreateDatabaseInfo.h"
+#ifndef SP_CODA /* headers */
+#import "SPAppController.h"
+#import "SPBundleHTMLOutputController.h"
+#endif
+#import "SPTableTriggers.h"
+#ifdef SP_CODA /* headers */
+#import "SPTableStructure.h"
+#import "SPTableStructureLoading.h"
+#endif
+#import "SPPrintAccessory.h"
+#import "MGTemplateEngine.h"
+#import "ICUTemplateMatcher.h"
#import <SPMySQL/SPMySQL.h>
@@ -108,6 +115,18 @@ static int64_t SPDatabaseDocumentInstanceCounter = 0;
- (void)_addPreferenceObservers;
- (void)_removePreferenceObservers;
+#pragma mark - SPDatabaseViewControllerPrivateAPI
+
+- (void)_loadTabTask:(NSNumber *)tabViewItemIndexNumber;
+- (void)_loadTableTask;
+
+#pragma mark - SPConnectionDelegate
+
+- (void) closeAndDisconnect;
+
+- (NSString *)keychainPasswordForConnection:(SPMySQLConnection *)connection;
+- (NSString *)keychainPasswordForSSHConnection:(SPMySQLConnection *)connection;
+
@end
@implementation SPDatabaseDocument
@@ -121,6 +140,7 @@ static int64_t SPDatabaseDocumentInstanceCounter = 0;
@synthesize databaseStructureRetrieval;
@synthesize processID;
@synthesize instanceId;
+@synthesize dbTablesTableView = dbTablesTableView;
#pragma mark -
@@ -6524,6 +6544,1166 @@ static int64_t SPDatabaseDocumentInstanceCounter = 0;
[prefs removeObserver:[SPQueryController sharedQueryController] forKeyPath:SPDisplayTableViewVerticalGridlines];
}
+#pragma mark - SPDatabaseViewController
+
+#pragma mark Getters
+
+#ifndef SP_CODA /* getters */
+/**
+ * Returns the master database view, containing the tables list and views for
+ * table setup and contents.
+ */
+- (NSView *)databaseView
+{
+ return parentView;
+}
+#endif
+
+/**
+ * Returns the name of the currently selected table/view/procedure/function.
+ */
+- (NSString *)table
+{
+ return selectedTableName;
+}
+
+/**
+ * Returns the currently selected table type, or -1 if no table or multiple tables are selected
+ */
+- (SPTableType)tableType
+{
+ return selectedTableType;
+}
+
+/**
+ * Returns YES if table source has already been loaded
+ */
+- (BOOL)structureLoaded
+{
+ return structureLoaded;
+}
+
+/**
+ * Returns YES if table content has already been loaded
+ */
+- (BOOL)contentLoaded
+{
+ return contentLoaded;
+}
+
+/**
+ * Returns YES if table status has already been loaded
+ */
+- (BOOL)statusLoaded
+{
+ return statusLoaded;
+}
+
+#ifndef SP_CODA /* toolbar ibactions */
+
+#pragma mark -
+#pragma mark Tab view control and delegate methods
+
+//WARNING: Might be called from code in background threads
+- (IBAction)viewStructure:(id)sender
+{
+ // Cancel the selection if currently editing a view and unable to save
+ if (![[self onMainThread] couldCommitCurrentViewActions]) {
+ [[mainToolbar onMainThread] setSelectedItemIdentifier:*SPViewModeToMainToolbarMap[[prefs integerForKey:SPLastViewMode]]];
+ return;
+ }
+
+ [[tableTabView onMainThread] selectTabViewItemAtIndex:0];
+ [[mainToolbar onMainThread] setSelectedItemIdentifier:SPMainToolbarTableStructure];
+ [spHistoryControllerInstance updateHistoryEntries];
+
+ [prefs setInteger:SPStructureViewMode forKey:SPLastViewMode];
+}
+
+- (IBAction)viewContent:(id)sender
+{
+ // Cancel the selection if currently editing a view and unable to save
+ if (![self couldCommitCurrentViewActions]) {
+ [mainToolbar setSelectedItemIdentifier:*SPViewModeToMainToolbarMap[[prefs integerForKey:SPLastViewMode]]];
+ return;
+ }
+
+ [tableTabView selectTabViewItemAtIndex:1];
+ [mainToolbar setSelectedItemIdentifier:SPMainToolbarTableContent];
+ [spHistoryControllerInstance updateHistoryEntries];
+
+ [prefs setInteger:SPContentViewMode forKey:SPLastViewMode];
+}
+
+- (IBAction)viewQuery:(id)sender
+{
+ // Cancel the selection if currently editing a view and unable to save
+ if (![self couldCommitCurrentViewActions]) {
+ [mainToolbar setSelectedItemIdentifier:*SPViewModeToMainToolbarMap[[prefs integerForKey:SPLastViewMode]]];
+ return;
+ }
+
+ [tableTabView selectTabViewItemAtIndex:2];
+ [mainToolbar setSelectedItemIdentifier:SPMainToolbarCustomQuery];
+ [spHistoryControllerInstance updateHistoryEntries];
+
+ // Set the focus on the text field
+ [parentWindow makeFirstResponder:customQueryTextView];
+
+ [prefs setInteger:SPQueryEditorViewMode forKey:SPLastViewMode];
+}
+
+- (IBAction)viewStatus:(id)sender
+{
+ // Cancel the selection if currently editing a view and unable to save
+ if (![self couldCommitCurrentViewActions]) {
+ [mainToolbar setSelectedItemIdentifier:*SPViewModeToMainToolbarMap[[prefs integerForKey:SPLastViewMode]]];
+ return;
+ }
+
+ [tableTabView selectTabViewItemAtIndex:3];
+ [mainToolbar setSelectedItemIdentifier:SPMainToolbarTableInfo];
+ [spHistoryControllerInstance updateHistoryEntries];
+
+ if ([[self table] length]) {
+ [extendedTableInfoInstance loadTable:[self table]];
+ }
+
+ [parentWindow makeFirstResponder:[extendedTableInfoInstance valueForKeyPath:@"tableCreateSyntaxTextView"]];
+
+ [prefs setInteger:SPTableInfoViewMode forKey:SPLastViewMode];
+}
+
+- (IBAction)viewRelations:(id)sender
+{
+ // Cancel the selection if currently editing a view and unable to save
+ if (![self couldCommitCurrentViewActions]) {
+ [mainToolbar setSelectedItemIdentifier:*SPViewModeToMainToolbarMap[[prefs integerForKey:SPLastViewMode]]];
+ return;
+ }
+
+ [tableTabView selectTabViewItemAtIndex:4];
+ [mainToolbar setSelectedItemIdentifier:SPMainToolbarTableRelations];
+ [spHistoryControllerInstance updateHistoryEntries];
+
+ [prefs setInteger:SPRelationsViewMode forKey:SPLastViewMode];
+}
+
+- (IBAction)viewTriggers:(id)sender
+{
+ // Cancel the selection if currently editing a view and unable to save
+ if (![self couldCommitCurrentViewActions]) {
+ [mainToolbar setSelectedItemIdentifier:*SPViewModeToMainToolbarMap[[prefs integerForKey:SPLastViewMode]]];
+ return;
+ }
+
+ [tableTabView selectTabViewItemAtIndex:5];
+ [mainToolbar setSelectedItemIdentifier:SPMainToolbarTableTriggers];
+ [spHistoryControllerInstance updateHistoryEntries];
+
+ [prefs setInteger:SPTriggersViewMode forKey:SPLastViewMode];
+}
+#endif
+
+/**
+ * Mark the structure tab for refresh when it's next switched to,
+ * or reload the view if it's currently active
+ */
+- (void)setStructureRequiresReload:(BOOL)reload
+{
+ BOOL reloadRequired = reload;
+
+#ifndef SP_CODA
+ if ([self currentlySelectedView] == SPTableViewStructure) {
+ reloadRequired = NO;
+ }
+#endif
+
+ if (reloadRequired && selectedTableName) {
+ [tableSourceInstance loadTable:selectedTableName];
+ }
+ else {
+ structureLoaded = !reload;
+ }
+}
+
+/**
+ * Mark the content tab for refresh when it's next switched to,
+ * or reload the view if it's currently active
+ */
+- (void)setContentRequiresReload:(BOOL)reload
+{
+ if (reload && selectedTableName
+#ifndef SP_CODA /* check which tab is selected */
+ && [self currentlySelectedView] == SPTableViewContent
+#endif
+ ) {
+ [tableContentInstance loadTable:selectedTableName];
+ }
+ else {
+ contentLoaded = !reload;
+ }
+}
+
+/**
+ * Mark the extended tab info for refresh when it's next switched to,
+ * or reload the view if it's currently active
+ */
+- (void)setStatusRequiresReload:(BOOL)reload
+{
+ if (reload && selectedTableName
+#ifndef SP_CODA /* check which tab is selected */
+ && [self currentlySelectedView] == SPTableViewStatus
+#endif
+ ) {
+ [[extendedTableInfoInstance onMainThread] loadTable:selectedTableName];
+ }
+ else {
+ statusLoaded = !reload;
+ }
+}
+
+/**
+ * Mark the relations tab for refresh when it's next switched to,
+ * or reload the view if it's currently active
+ */
+- (void)setRelationsRequiresReload:(BOOL)reload
+{
+ if (reload && selectedTableName
+#ifndef SP_CODA /* check which tab is selected */
+ && [self currentlySelectedView] == SPTableViewRelations
+#endif
+ ) {
+ [[tableRelationsInstance onMainThread] refreshRelations:self];
+ }
+ else {
+ relationsLoaded = !reload;
+ }
+}
+
+#ifndef SP_CODA /* !!! respond to tab change */
+/**
+ * Triggers a task to update the newly selected tab view, ensuring
+ * the data is fully loaded and up-to-date.
+ */
+- (void)tabView:(NSTabView *)aTabView didSelectTabViewItem:(NSTabViewItem *)tabViewItem
+{
+ [self startTaskWithDescription:[NSString stringWithFormat:NSLocalizedString(@"Loading %@...", @"Loading table task string"), [self table]]];
+
+ // We can't pass aTabView or tabViewItem UI objects to a bg thread, but since the change should already
+ // be done in *did*SelectTabViewItem we can just ask the tab view for the current selection index and use that
+ SPTableViewType newView = [self currentlySelectedView];
+
+ if ([NSThread isMainThread]) {
+ [NSThread detachNewThreadWithName:SPCtxt(@"SPDatabaseDocument view load task",self)
+ target:self
+ selector:@selector(_loadTabTask:)
+ object:@(newView)];
+ }
+ else {
+ [self _loadTabTask:@(newView)];
+ }
+}
+#endif
+
+#pragma mark -
+#pragma mark Table control
+
+/**
+ * Loads a specified table into the database view, and ensures it's selected in
+ * the tables list. Passing a table name of nil will deselect any currently selected
+ * table, but will leave multiple selections intact.
+ * If this method is supplied with the currently selected name, a reload rather than
+ * a load will be triggered.
+ */
+- (void)loadTable:(NSString *)aTable ofType:(SPTableType)aTableType
+{
+ // Ensure a connection is still present
+ if (![mySQLConnection isConnected]) return;
+
+ // If the supplied table name was nil, clear the views.
+ if (!aTable) {
+
+ // Update the selected table name and type
+ if (selectedTableName) SPClear(selectedTableName);
+
+ selectedTableType = SPTableTypeNone;
+
+ // Clear the views
+ [[tablesListInstance onMainThread] setSelectionState:nil];
+ [tableSourceInstance loadTable:nil];
+ [tableContentInstance loadTable:nil];
+#ifndef SP_CODA /* [extendedTableInfoInstance loadTable:] */
+ [[extendedTableInfoInstance onMainThread] loadTable:nil];
+ [[tableTriggersInstance onMainThread] resetInterface];
+ [[tableRelationsInstance onMainThread] refreshRelations:self];
+#endif
+ structureLoaded = NO;
+ contentLoaded = NO;
+ statusLoaded = NO;
+ triggersLoaded = NO;
+ relationsLoaded = NO;
+
+#ifndef SP_CODA
+ // Update the window title
+ [self updateWindowTitle:self];
+
+ // Add a history entry
+ [spHistoryControllerInstance updateHistoryEntries];
+#endif
+
+ // Notify listeners of the table change
+ [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadWithName:SPTableChangedNotification object:self];
+
+ return;
+ }
+
+ BOOL isReloading = (selectedTableName && [selectedTableName isEqualToString:aTable]);
+
+ // Store the new name
+ if (selectedTableName) [selectedTableName release];
+
+ selectedTableName = [[NSString alloc] initWithString:aTable];
+ selectedTableType = aTableType;
+
+ // Start a task
+ if (isReloading) {
+ [self startTaskWithDescription:NSLocalizedString(@"Reloading...", @"Reloading table task string")];
+ }
+ else {
+ [self startTaskWithDescription:[NSString stringWithFormat:NSLocalizedString(@"Loading %@...", @"Loading table task string"), aTable]];
+ }
+
+ // Update the tables list interface - also updates menus to reflect the selected table type
+ [[tablesListInstance onMainThread] setSelectionState:[NSDictionary dictionaryWithObjectsAndKeys:aTable, @"name", [NSNumber numberWithInteger:aTableType], @"type", nil]];
+
+ // If on the main thread, fire up a thread to deal with view changes and data loading;
+ // if already on a background thread, make the changes on the existing thread.
+ if ([NSThread isMainThread]) {
+ [NSThread detachNewThreadWithName:SPCtxt(@"SPDatabaseDocument table load task",self)
+ target:self
+ selector:@selector(_loadTableTask)
+ object:nil];
+ }
+ else {
+ [self _loadTableTask];
+ }
+}
+
+/**
+ * In a threaded task, ensure that the supplied tab is loaded -
+ * usually as a result of switching to it.
+ */
+- (void)_loadTabTask:(NSNumber *)tabViewItemIndexNumber
+{
+ NSAutoreleasePool *tabLoadPool = [[NSAutoreleasePool alloc] init];
+
+ // If anything other than a single table or view is selected, don't proceed.
+ if (![self table] || ([tablesListInstance tableType] != SPTableTypeTable && [tablesListInstance tableType] != SPTableTypeView))
+ {
+ [self endTask];
+ [tabLoadPool drain];
+ return;
+ }
+
+ // Get the tab view index and ensure the associated view is loaded
+ SPTableViewType selectedTabViewIndex = [tabViewItemIndexNumber integerValue];
+
+ switch (selectedTabViewIndex) {
+ case SPTableViewStructure:
+ if (!structureLoaded) {
+ [tableSourceInstance loadTable:selectedTableName];
+ structureLoaded = YES;
+ }
+ break;
+ case SPTableViewContent:
+ if (!contentLoaded) {
+ [tableContentInstance loadTable:selectedTableName];
+ contentLoaded = YES;
+ }
+ break;
+#ifndef SP_CODA /* case SPTableViewStatus: case SPTableViewTriggers: */
+ case SPTableViewStatus:
+ if (!statusLoaded) {
+ [[extendedTableInfoInstance onMainThread] loadTable:selectedTableName];
+ statusLoaded = YES;
+ }
+ break;
+ case SPTableViewTriggers:
+ if (!triggersLoaded) {
+ [[tableTriggersInstance onMainThread] loadTriggers];
+ triggersLoaded = YES;
+ }
+ break;
+ case SPTableViewRelations:
+ if (!relationsLoaded) {
+ [[tableRelationsInstance onMainThread] refreshRelations:self];
+ relationsLoaded = YES;
+ }
+ break;
+#endif
+ }
+
+ [self endTask];
+
+ [tabLoadPool drain];
+}
+
+
+/**
+ * In a threaded task, load the currently selected table/view/proc/function.
+ */
+- (void)_loadTableTask
+{
+ NSAutoreleasePool *loadPool = [[NSAutoreleasePool alloc] init];
+ NSString *tableEncoding = nil;
+
+#ifndef SP_CODA /* Update the window title */
+ // Update the window title
+ [self updateWindowTitle:self];
+#endif
+
+ // Reset table information caches and mark that all loaded views require their data reloading
+ [tableDataInstance resetAllData];
+
+ structureLoaded = NO;
+ contentLoaded = NO;
+ statusLoaded = NO;
+ triggersLoaded = NO;
+ relationsLoaded = NO;
+
+ // Ensure status and details are fetched using UTF8
+ NSString *previousEncoding = [mySQLConnection encoding];
+ BOOL changeEncoding = ![previousEncoding isEqualToString:@"utf8"];
+
+ if (changeEncoding) {
+ [mySQLConnection storeEncodingForRestoration];
+ [mySQLConnection setEncoding:@"utf8"];
+ }
+
+ // Cache status information on the working thread
+ [tableDataInstance updateStatusInformationForCurrentTable];
+
+ // Check the current encoding against the table encoding to see whether
+ // an encoding change and reset is required. This also caches table information on
+ // the working thread.
+ if( selectedTableType == SPTableTypeView || selectedTableType == SPTableTypeTable) {
+
+ // tableEncoding == nil indicates that there was an error while retrieving table data
+ tableEncoding = [tableDataInstance tableEncoding];
+
+ // If encoding is set to Autodetect, update the connection character set encoding
+ // based on the newly selected table's encoding - but only if it differs from the current encoding.
+ if ([[[NSUserDefaults standardUserDefaults] objectForKey:SPDefaultEncoding] intValue] == SPEncodingAutodetect) {
+ if (tableEncoding != nil && ![tableEncoding isEqualToString:previousEncoding]) {
+ [self setConnectionEncoding:tableEncoding reloadingViews:NO];
+ changeEncoding = NO;
+ }
+ }
+ }
+
+ if (changeEncoding) [mySQLConnection restoreStoredEncoding];
+
+ // Notify listeners of the table change now that the state is fully set up.
+ [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadWithName:SPTableChangedNotification object:self];
+
+#ifndef SP_CODA /* [spHistoryControllerInstance restoreViewStates] */
+
+ // Restore view states as appropriate
+ [spHistoryControllerInstance restoreViewStates];
+#endif
+
+ // Load the currently selected view if looking at a table or view
+ if (tableEncoding && (selectedTableType == SPTableTypeView || selectedTableType == SPTableTypeTable))
+ {
+#ifndef SP_CODA /* load everything */
+ NSInteger selectedTabViewIndex = [[self onMainThread] currentlySelectedView];
+
+ switch (selectedTabViewIndex) {
+ case SPTableViewStructure:
+#endif
+ [tableSourceInstance loadTable:selectedTableName];
+ structureLoaded = YES;
+#ifndef SP_CODA /* load everything */
+ break;
+ case SPTableViewContent:
+#endif
+ [tableContentInstance loadTable:selectedTableName];
+ contentLoaded = YES;
+#ifndef SP_CODA /* load everything */
+ break;
+ case SPTableViewStatus:
+ [[extendedTableInfoInstance onMainThread] loadTable:selectedTableName];
+ statusLoaded = YES;
+ break;
+ case SPTableViewTriggers:
+ [[tableTriggersInstance onMainThread] loadTriggers];
+ triggersLoaded = YES;
+ break;
+ case SPTableViewRelations:
+ [[tableRelationsInstance onMainThread] refreshRelations:self];
+ relationsLoaded = YES;
+ break;
+ }
+#endif
+ }
+
+ // Clear any views which haven't been loaded as they weren't visible. Note
+ // that this should be done after reloading visible views, instead of clearing all
+ // views, to reduce UI operations and avoid resetting state unnecessarily.
+ // Some views (eg TableRelations) make use of the SPTableChangedNotification and
+ // so don't require manual clearing.
+ if (!structureLoaded) [tableSourceInstance loadTable:nil];
+ if (!contentLoaded) [tableContentInstance loadTable:nil];
+ if (!statusLoaded) [[extendedTableInfoInstance onMainThread] loadTable:nil];
+ if (!triggersLoaded) [[tableTriggersInstance onMainThread] resetInterface];
+
+ // If the table row counts an inaccurate and require updating, trigger an update - no
+ // action will be performed if not necessary
+ [tableDataInstance updateAccurateNumberOfRowsForCurrentTableForcingUpdate:NO];
+
+#ifndef SP_CODA /* show Create Table syntax */
+ // Update the "Show Create Syntax" window if it's already opened
+ // according to the selected table/view/proc/func
+ if ([[[self onMainThread] getCreateTableSyntaxWindow] isVisible]) {
+ [[self onMainThread] showCreateTableSyntax:self];
+ }
+
+ // Add a history entry
+ [spHistoryControllerInstance updateHistoryEntries];
+#endif
+ // Empty the loading pool and exit the thread
+ [self endTask];
+
+#ifndef SP_CODA /* triggered commands */
+ NSArray *triggeredCommands = [SPAppDelegate bundleCommandsForTrigger:SPBundleTriggerActionTableChanged];
+
+ for(NSString* cmdPath in triggeredCommands)
+ {
+ NSArray *data = [cmdPath componentsSeparatedByString:@"|"];
+ NSMenuItem *aMenuItem = [[[NSMenuItem alloc] init] autorelease];
+ [aMenuItem setTag:0];
+ [aMenuItem setToolTip:[data objectAtIndex:0]];
+
+ // For HTML output check if corresponding window already exists
+ BOOL stopTrigger = NO;
+ if([(NSString*)[data objectAtIndex:2] length]) {
+ BOOL correspondingWindowFound = NO;
+ NSString *uuid = [data objectAtIndex:2];
+ for(id win in [NSApp windows]) {
+ if([[[[win delegate] class] description] isEqualToString:@"SPBundleHTMLOutputController"]) {
+ if([[[win delegate] windowUUID] isEqualToString:uuid]) {
+ correspondingWindowFound = YES;
+ break;
+ }
+ }
+ }
+ if(!correspondingWindowFound) stopTrigger = YES;
+ }
+ if(!stopTrigger) {
+ id firstResponder = [[NSApp keyWindow] firstResponder];
+ if([[data objectAtIndex:1] isEqualToString:SPBundleScopeGeneral]) {
+ [[SPAppDelegate onMainThread] executeBundleItemForApp:aMenuItem];
+ }
+ else if([[data objectAtIndex:1] isEqualToString:SPBundleScopeDataTable]) {
+ if([[[firstResponder class] description] isEqualToString:@"SPCopyTable"])
+ [[firstResponder onMainThread] executeBundleItemForDataTable:aMenuItem];
+ }
+ else if([[data objectAtIndex:1] isEqualToString:SPBundleScopeInputField]) {
+ if([firstResponder isKindOfClass:[NSTextView class]])
+ [[firstResponder onMainThread] executeBundleItemForInputField:aMenuItem];
+ }
+ }
+ }
+#endif
+
+ [loadPool drain];
+}
+
+#pragma mark - SPMySQLConnection delegate methods
+
+/**
+ * Invoked when the framework is about to perform a query.
+ */
+- (void)willQueryString:(NSString *)query connection:(id)connection
+{
+#ifndef SP_CODA
+ if ([prefs boolForKey:SPConsoleEnableLogging]) {
+ if ((_queryMode == SPInterfaceQueryMode && [prefs boolForKey:SPConsoleEnableInterfaceLogging]) ||
+ (_queryMode == SPCustomQueryQueryMode && [prefs boolForKey:SPConsoleEnableCustomQueryLogging]) ||
+ (_queryMode == SPImportExportQueryMode && [prefs boolForKey:SPConsoleEnableImportExportLogging]))
+ {
+ [[SPQueryController sharedQueryController] showMessageInConsole:query connection:[self name] database:[self database]];
+ }
+ }
+#endif
+}
+
+/**
+ * Invoked when the query just executed by the framework resulted in an error.
+ */
+- (void)queryGaveError:(NSString *)error connection:(id)connection
+{
+#ifndef SP_CODA
+ if ([prefs boolForKey:SPConsoleEnableLogging] && [prefs boolForKey:SPConsoleEnableErrorLogging]) {
+ [[SPQueryController sharedQueryController] showErrorInConsole:error connection:[self name] database:[self database]];
+ }
+#endif
+}
+
+/**
+ * Invoked when the current connection needs a password from the Keychain.
+ */
+- (NSString *)keychainPasswordForConnection:(SPMySQLConnection *)connection
+{
+ // If no keychain item is available, return an empty password
+ if (![connectionController connectionKeychainItemName]) return nil;
+
+ // Otherwise, pull the password from the keychain using the details from this connection
+ SPKeychain *keychain = [[SPKeychain alloc] init];
+
+ NSString *password = [keychain getPasswordForName:[connectionController connectionKeychainItemName] account:[connectionController connectionKeychainItemAccount]];
+
+ [keychain release];
+
+ return password;
+}
+
+/**
+ * Invoked when the current connection needs a ssh password from the Keychain.
+ * This isn't actually part of the SPMySQLConnection delegate protocol, but is here
+ * due to its similarity to the previous method.
+ */
+- (NSString *)keychainPasswordForSSHConnection:(SPMySQLConnection *)connection
+{
+ // If no keychain item is available, return an empty password
+ if (![connectionController connectionKeychainItemName]) return @"";
+
+ // Otherwise, pull the password from the keychain using the details from this connection
+ SPKeychain *keychain = [[SPKeychain alloc] init];
+
+ NSString *connectionSSHKeychainItemName = [[keychain nameForSSHForFavoriteName:[connectionController name] id:[self keyChainID]] retain];
+ NSString *connectionSSHKeychainItemAccount = [[keychain accountForSSHUser:[connectionController sshUser] sshHost:[connectionController sshHost]] retain];
+ NSString *sshPassword = [keychain getPasswordForName:connectionSSHKeychainItemName account:connectionSSHKeychainItemAccount];
+
+ if (!sshPassword || ![sshPassword length]) {
+ sshPassword = @"";
+ }
+
+ if (connectionSSHKeychainItemName) [connectionSSHKeychainItemName release];
+ if (connectionSSHKeychainItemAccount) [connectionSSHKeychainItemAccount release];
+
+ [keychain release];
+
+ return sshPassword;
+}
+
+/**
+ * Invoked when an attempt was made to execute a query on the current connection, but the connection is not
+ * actually active.
+ */
+- (void)noConnectionAvailable:(id)connection
+{
+ SPOnewayAlertSheet(
+ NSLocalizedString(@"No connection available", @"no connection available message"),
+ [self parentWindow],
+ NSLocalizedString(@"An error has occured and there doesn't seem to be a connection available.", @"no connection available informatie message")
+ );
+}
+
+/**
+ * Invoked when the connection fails and the framework needs to know how to proceed.
+ */
+- (SPMySQLConnectionLostDecision)connectionLost:(id)connection
+{
+ SPMySQLConnectionLostDecision connectionErrorCode = SPMySQLConnectionLostDisconnect;
+
+ // Only display the reconnect dialog if the window is visible
+ if ([self parentWindow] && [[self parentWindow] isVisible]) {
+
+ // Ensure the window isn't miniaturized
+ if ([[self parentWindow] isMiniaturized]) [[self parentWindow] deminiaturize:self];
+
+#ifndef SP_CODA
+ // Ensure the window and tab are frontmost
+ [self makeKeyDocument];
+#endif
+
+ // Display the connection error dialog and wait for the return code
+ [NSApp beginSheet:connectionErrorDialog modalForWindow:[self parentWindow] modalDelegate:self didEndSelector:nil contextInfo:nil];
+ connectionErrorCode = (SPMySQLConnectionLostDecision)[NSApp runModalForWindow:connectionErrorDialog];
+
+ [NSApp endSheet:connectionErrorDialog];
+ [connectionErrorDialog orderOut:nil];
+
+ // If 'disconnect' was selected, trigger a window close.
+ if (connectionErrorCode == SPMySQLConnectionLostDisconnect) {
+ [self performSelectorOnMainThread:@selector(closeAndDisconnect) withObject:nil waitUntilDone:YES];
+ }
+ }
+
+ return connectionErrorCode;
+}
+
+/**
+ * Invoke to display an informative but non-fatal error directly to the user.
+ */
+- (void)showErrorWithTitle:(NSString *)theTitle message:(NSString *)theMessage
+{
+ if ([[self parentWindow] isVisible]) {
+ SPOnewayAlertSheet(theTitle, [self parentWindow], theMessage);
+ }
+}
+
+/**
+ * Invoked when user dismisses the error sheet displayed as a result of the current connection being lost.
+ */
+- (IBAction)closeErrorConnectionSheet:(id)sender
+{
+ [NSApp stopModalWithCode:[sender tag]];
+}
+
+/**
+ * Close the connection - should be performed on the main thread.
+ */
+- (void) closeAndDisconnect
+{
+#ifndef SP_CODA
+ NSWindow *theParentWindow = [self parentWindow];
+
+ _isConnected = NO;
+
+ if ([[[self parentTabViewItem] tabView] numberOfTabViewItems] == 1) {
+ [theParentWindow orderOut:self];
+ [theParentWindow setAlphaValue:0.0f];
+ [theParentWindow performSelector:@selector(close) withObject:nil afterDelay:1.0];
+ }
+ else {
+ [[[self parentTabViewItem] tabView] performSelector:@selector(removeTabViewItem:) withObject:[self parentTabViewItem] afterDelay:0.5];
+ [theParentWindow performSelector:@selector(makeKeyAndOrderFront:) withObject:nil afterDelay:0.6];
+ }
+
+ [self parentTabDidClose];
+#endif
+}
+
+#pragma mark - SPPrintController
+
+/**
+ * WebView delegate method.
+ */
+- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame
+{
+ // Because we need the webFrame loaded (for preview), we've moved the actual printing here
+ NSPrintInfo *printInfo = [NSPrintInfo sharedPrintInfo];
+
+ NSSize paperSize = [printInfo paperSize];
+ NSRect printableRect = [printInfo imageablePageBounds];
+
+ // Calculate page margins
+ CGFloat marginL = printableRect.origin.x;
+ CGFloat marginR = paperSize.width - (printableRect.origin.x + printableRect.size.width);
+ CGFloat marginB = printableRect.origin.y;
+ CGFloat marginT = paperSize.height - (printableRect.origin.y + printableRect.size.height);
+
+ // Make sure margins are symetric and positive
+ CGFloat marginLR = MAX(0, MAX(marginL, marginR));
+ CGFloat marginTB = MAX(0, MAX(marginT, marginB));
+
+ // Set the margins
+ [printInfo setLeftMargin:marginLR];
+ [printInfo setRightMargin:marginLR];
+ [printInfo setTopMargin:marginTB];
+ [printInfo setBottomMargin:marginTB];
+
+ [printInfo setHorizontalPagination:NSFitPagination];
+ [printInfo setVerticalPagination:NSAutoPagination];
+ [printInfo setVerticallyCentered:NO];
+
+ NSPrintOperation *op = [NSPrintOperation printOperationWithView:[[[printWebView mainFrame] frameView] documentView] printInfo:printInfo];
+
+ // Perform the print operation on a background thread
+ [op setCanSpawnSeparateThread:YES];
+
+ // Add the ability to select the orientation to print panel
+ NSPrintPanel *printPanel = [op printPanel];
+
+ [printPanel setOptions:[printPanel options] + NSPrintPanelShowsOrientation + NSPrintPanelShowsScaling + NSPrintPanelShowsPaperSize];
+
+ SPPrintAccessory *printAccessory = [[SPPrintAccessory alloc] initWithNibName:@"PrintAccessory" bundle:nil];
+
+ [printAccessory setPrintView:printWebView];
+ [printPanel addAccessoryController:printAccessory];
+
+ [[NSPageLayout pageLayout] addAccessoryController:printAccessory];
+ [printAccessory release];
+
+ [op setPrintPanel:printPanel];
+
+ [op runOperationModalForWindow:[self parentWindow]
+ delegate:self
+ didRunSelector:nil
+ contextInfo:nil];
+
+ if ([self isWorking]) [self endTask];
+}
+
+/**
+ * Loads the print document interface. The actual printing is done in the doneLoading delegate.
+ */
+- (IBAction)printDocument:(id)sender
+{
+ // Only display warning for the 'Table Content' view
+ if ([self currentlySelectedView] == SPTableViewContent) {
+
+ NSInteger rowLimit = [prefs integerForKey:SPPrintWarningRowLimit];
+
+ // Result count minus one because the first element is the column names
+ NSInteger resultRows = ([[tableContentInstance currentResult] count] - 1);
+
+ if (resultRows > rowLimit) {
+
+ NSNumberFormatter *numberFormatter = [[[NSNumberFormatter alloc] init] autorelease];
+
+ [numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
+
+ NSAlert *alert = [NSAlert alertWithMessageText:NSLocalizedString(@"Continue to print?", @"continue to print message")
+ defaultButton:NSLocalizedString(@"Print", @"print button")
+ alternateButton:NSLocalizedString(@"Cancel", @"cancel button")
+ otherButton:nil
+ informativeTextWithFormat:NSLocalizedString(@"Are you sure you want to print the current content view of the table '%@'?\n\nIt currently contains %@ rows, which may take a significant amount of time to print.", @"continue to print informative message"), [self table], [numberFormatter stringFromNumber:[NSNumber numberWithLongLong:resultRows]]];
+
+ NSArray *buttons = [alert buttons];
+
+ // Change the alert's cancel button to have the key equivalent of return
+ [[buttons objectAtIndex:0] setKeyEquivalent:@"p"];
+ [[buttons objectAtIndex:0] setKeyEquivalentModifierMask:NSCommandKeyMask];
+ [[buttons objectAtIndex:1] setKeyEquivalent:@"\r"];
+
+ [alert beginSheetModalForWindow:[self parentWindow] modalDelegate:self didEndSelector:@selector(printWarningDidEnd:returnCode:contextInfo:) contextInfo:NULL];
+
+ return;
+ }
+ }
+
+ [self startPrintDocumentOperation];
+}
+
+/**
+ * Called when the print warning dialog is dismissed.
+ */
+- (void)printWarningDidEnd:(id)sheet returnCode:(NSInteger)returnCode contextInfo:(NSString *)contextInfo
+{
+ if (returnCode == NSAlertDefaultReturn) {
+ [self startPrintDocumentOperation];
+ }
+}
+
+/**
+ * Starts tge print document operation by spawning a new thread if required.
+ */
+- (void)startPrintDocumentOperation
+{
+ [self startTaskWithDescription:NSLocalizedString(@"Generating print document...", @"generating print document status message")];
+
+ BOOL isTableInformation = ([self currentlySelectedView] == SPTableViewStatus);
+
+ if ([NSThread isMainThread]) {
+ printThread = [[NSThread alloc] initWithTarget:self selector:(isTableInformation) ? @selector(generateTableInfoHTMLForPrinting) : @selector(generateHTMLForPrinting) object:nil];
+ [printThread setName:@"SPDatabaseDocument document generator"];
+
+ [self enableTaskCancellationWithTitle:NSLocalizedString(@"Cancel", @"cancel button") callbackObject:self callbackFunction:@selector(generateHTMLForPrintingCallback)];
+
+ [printThread start];
+ }
+ else {
+ (isTableInformation) ? [self generateTableInfoHTMLForPrinting] : [self generateHTMLForPrinting];
+ }
+}
+
+/**
+ * HTML generation thread callback method.
+ */
+- (void)generateHTMLForPrintingCallback
+{
+ [self setTaskDescription:NSLocalizedString(@"Cancelling...", @"cancelling task status message")];
+
+ // Cancel the print thread
+ [printThread cancel];
+}
+
+/**
+ * Loads the supplied HTML string in the print WebView.
+ */
+- (void)loadPrintWebViewWithHTMLString:(NSString *)HTMLString
+{
+ [[printWebView mainFrame] loadHTMLString:HTMLString baseURL:nil];
+
+ if (printThread) SPClear(printThread);
+}
+
+/**
+ * Generates the HTML for the current view that is being printed.
+ */
+- (void)generateHTMLForPrinting
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ // Set up template engine with your chosen matcher
+ MGTemplateEngine *engine = [MGTemplateEngine templateEngine];
+
+ [engine setMatcher:[ICUTemplateMatcher matcherWithTemplateEngine:engine]];
+
+ NSMutableDictionary *connection = [self connectionInformation];
+
+ NSString *heading = @"";
+ NSArray *rows, *indexes, *indexColumns = nil;
+
+ NSArray *columns = [self columnNames];
+
+ NSMutableDictionary *printData = [NSMutableDictionary dictionary];
+
+ SPTableViewType view = [self currentlySelectedView];
+
+ // Table source view
+ if (view == SPTableViewStructure) {
+
+ NSDictionary *tableSource = [tableSourceInstance tableSourceForPrinting];
+
+ NSInteger tableType = [tablesListInstance tableType];
+
+ switch (tableType) {
+ case SPTableTypeTable:
+ heading = NSLocalizedString(@"Table Structure", @"table structure print heading");
+ break;
+ case SPTableTypeView:
+ heading = NSLocalizedString(@"View Structure", @"view structure print heading");
+ break;
+ }
+
+ rows = [[NSArray alloc] initWithArray:
+ [[tableSource objectForKey:@"structure"] objectsAtIndexes:
+ [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(1, [[tableSource objectForKey:@"structure"] count] - 1)]]
+ ];
+
+ indexes = [[NSArray alloc] initWithArray:
+ [[tableSource objectForKey:@"indexes"] objectsAtIndexes:
+ [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(1, [[tableSource objectForKey:@"indexes"] count] - 1)]]
+ ];
+
+ indexColumns = [[tableSource objectForKey:@"indexes"] objectAtIndex:0];
+
+ [printData setObject:rows forKey:@"rows"];
+ [printData setObject:indexes forKey:@"indexes"];
+ [printData setObject:indexColumns forKey:@"indexColumns"];
+
+ if ([indexes count]) [printData setObject:@1 forKey:@"hasIndexes"];
+
+ [rows release];
+ [indexes release];
+ }
+ // Table content view
+ else if (view == SPTableViewContent) {
+
+ NSArray *data = [tableContentInstance currentDataResultWithNULLs:NO hideBLOBs:YES];
+
+ heading = NSLocalizedString(@"Table Content", @"table content print heading");
+
+ rows = [[NSArray alloc] initWithArray:
+ [data objectsAtIndexes:
+ [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(1, [data count] - 1)]]
+ ];
+
+ [printData setObject:rows forKey:@"rows"];
+ [connection setValue:[tableContentInstance usedQuery] forKey:@"query"];
+
+ [rows release];
+ }
+ // Custom query view
+ else if (view == SPTableViewCustomQuery) {
+
+ NSArray *data = [customQueryInstance currentResult];
+
+ heading = NSLocalizedString(@"Query Result", @"query result print heading");
+
+ rows = [[NSArray alloc] initWithArray:
+ [data objectsAtIndexes:
+ [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(1, [data count] - 1)]]
+ ];
+
+ [printData setObject:rows forKey:@"rows"];
+ [connection setValue:[customQueryInstance usedQuery] forKey:@"query"];
+
+ [rows release];
+ }
+ // Table relations view
+ else if (view == SPTableViewRelations) {
+
+ NSArray *data = [tableRelationsInstance relationDataForPrinting];
+
+ heading = NSLocalizedString(@"Table Relations", @"toolbar item label for switching to the Table Relations tab");
+
+ rows = [[NSArray alloc] initWithArray:
+ [data objectsAtIndexes:
+ [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(1, ([data count] - 1))]]
+ ];
+
+ [printData setObject:rows forKey:@"rows"];
+
+ [rows release];
+ }
+ // Table triggers view
+ else if (view == SPTableViewTriggers) {
+
+ NSArray *data = [tableTriggersInstance triggerDataForPrinting];
+
+ heading = NSLocalizedString(@"Table Triggers", @"toolbar item label for switching to the Table Triggers tab");
+
+ rows = [[NSArray alloc] initWithArray:
+ [data objectsAtIndexes:
+ [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(1, ([data count] - 1))]]
+ ];
+
+ [printData setObject:rows forKey:@"rows"];
+
+ [rows release];
+ }
+
+ [engine setObject:connection forKey:@"c"];
+
+ [printData setObject:heading forKey:@"heading"];
+ [printData setObject:columns forKey:@"columns"];
+ [printData setObject:([prefs boolForKey:SPUseMonospacedFonts]) ? SPDefaultMonospacedFontName : @"Lucida Grande" forKey:@"font"];
+ [printData setObject:([prefs boolForKey:SPDisplayTableViewVerticalGridlines]) ? @"1px solid #CCCCCC" : @"none" forKey:@"gridlines"];
+
+ NSString *HTMLString = [engine processTemplateInFileAtPath:[[NSBundle mainBundle] pathForResource:SPHTMLPrintTemplate ofType:@"html"] withVariables:printData];
+
+ // Check if the operation has been cancelled
+ if ((printThread != nil) && (![NSThread isMainThread]) && ([printThread isCancelled])) {
+ [self endTask];
+ [pool drain];
+
+ [NSThread exit];
+ return;
+ }
+
+ [self performSelectorOnMainThread:@selector(loadPrintWebViewWithHTMLString:) withObject:HTMLString waitUntilDone:NO];
+
+ [pool drain];
+}
+
+/**
+ * Generates the HTML for the table information view that is to be printed.
+ */
+- (void)generateTableInfoHTMLForPrinting
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ // Set up template engine with your chosen matcher
+ MGTemplateEngine *engine = [MGTemplateEngine templateEngine];
+
+ [engine setMatcher:[ICUTemplateMatcher matcherWithTemplateEngine:engine]];
+
+ NSMutableDictionary *connection = [self connectionInformation];
+ NSMutableDictionary *printData = [NSMutableDictionary dictionary];
+
+ NSString *heading = NSLocalizedString(@"Table Information", @"table information print heading");
+
+ [engine setObject:connection forKey:@"c"];
+ [engine setObject:[[extendedTableInfoInstance onMainThread] tableInformationForPrinting] forKey:@"i"];
+
+ [printData setObject:heading forKey:@"heading"];
+ [printData setObject:[[NSUnarchiver unarchiveObjectWithData:[prefs objectForKey:SPCustomQueryEditorFont]] fontName] forKey:@"font"];
+
+ NSString *HTMLString = [engine processTemplateInFileAtPath:[[NSBundle mainBundle] pathForResource:SPHTMLTableInfoPrintTemplate ofType:@"html"] withVariables:printData];
+
+ // Check if the operation has been cancelled
+ if ((printThread != nil) && (![NSThread isMainThread]) && ([printThread isCancelled])) {
+ [self endTask];
+ [pool drain];
+
+ [NSThread exit];
+ return;
+ }
+
+ [self performSelectorOnMainThread:@selector(loadPrintWebViewWithHTMLString:) withObject:HTMLString waitUntilDone:NO];
+
+ [pool drain];
+}
+
+/**
+ * Returns an array of columns for whichever view is being printed.
+ */
+- (NSArray *)columnNames
+{
+ NSArray *columns = nil;
+
+ SPTableViewType view = [self currentlySelectedView];
+
+ // Table source view
+ if ((view == SPTableViewStructure) && ([[tableSourceInstance tableSourceForPrinting] count] > 0)) {
+
+ columns = [[NSArray alloc] initWithArray:[[[tableSourceInstance tableSourceForPrinting] objectForKey:@"structure"] objectAtIndex:0] copyItems:YES];
+ }
+ // Table content view
+ else if ((view == SPTableViewContent) && ([[tableContentInstance currentResult] count] > 0)) {
+
+ columns = [[NSArray alloc] initWithArray:[[tableContentInstance currentResult] objectAtIndex:0] copyItems:YES];
+ }
+ // Custom query view
+ else if ((view == SPTableViewCustomQuery) && ([[customQueryInstance currentResult] count] > 0)) {
+
+ columns = [[NSArray alloc] initWithArray:[[customQueryInstance currentResult] objectAtIndex:0] copyItems:YES];
+ }
+ // Table relations view
+ else if ((view == SPTableViewRelations) && ([[tableRelationsInstance relationDataForPrinting] count] > 0)) {
+
+ columns = [[NSArray alloc] initWithArray:[[tableRelationsInstance relationDataForPrinting] objectAtIndex:0] copyItems:YES];
+ }
+ // Table triggers view
+ else if ((view == SPTableViewTriggers) && ([[tableTriggersInstance triggerDataForPrinting] count] > 0)) {
+
+ columns = [[NSArray alloc] initWithArray:[[tableTriggersInstance triggerDataForPrinting] objectAtIndex:0] copyItems:YES];
+ }
+
+ if (columns) [columns autorelease];
+
+ return columns;
+}
+
+/**
+ * Generates a dictionary of connection information that is used for printing.
+ */
+- (NSMutableDictionary *)connectionInformation
+{
+ NSString *versionForPrint = [NSString stringWithFormat:@"%@ %@ (%@ %@)",
+ [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"],
+ [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"],
+ NSLocalizedString(@"build", @"build label"),
+ [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"]
+ ];
+
+ NSMutableDictionary *connection = [NSMutableDictionary dictionary];
+
+ if ([[self user] length]) {
+ [connection setValue:[self user] forKey:@"username"];
+ }
+
+ if ([[self table] length]) {
+ [connection setValue:[self table] forKey:@"table"];
+ }
+
+ if ([connectionController port] && [[connectionController port] length]) {
+ [connection setValue:[connectionController port] forKey:@"port"];
+ }
+
+ [connection setValue:[self host] forKey:@"hostname"];
+ [connection setValue:selectedDatabase forKey:@"database"];
+ [connection setValue:versionForPrint forKey:@"version"];
+
+ return connection;
+}
+
#pragma mark -
- (void)dealloc
diff --git a/Source/SPDatabaseStructure.m b/Source/SPDatabaseStructure.m
index fdb78916..477b3986 100644
--- a/Source/SPDatabaseStructure.m
+++ b/Source/SPDatabaseStructure.m
@@ -30,7 +30,6 @@
#import "SPDatabaseStructure.h"
#import "SPDatabaseDocument.h"
-#import "SPConnectionDelegate.h"
#import "SPTablesList.h"
#import "RegexKitLite.h"
#import "SPThreadAdditions.h"
diff --git a/Source/SPDatabaseViewController.h b/Source/SPDatabaseViewController.h
deleted file mode 100644
index aafa0cdd..00000000
--- a/Source/SPDatabaseViewController.h
+++ /dev/null
@@ -1,65 +0,0 @@
-//
-// SPDatabaseViewController.h
-// sequel-pro
-//
-// Created by Rowan Beentje on October 31, 2010.
-// Copyright (c) 2010 Arboreal. 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 "SPDatabaseDocument.h"
-
-@interface SPDatabaseDocument (SPDatabaseViewController)
-
-// Accessors
-- (NSString *)table;
-- (SPTableType)tableType;
-
-- (BOOL)structureLoaded;
-- (BOOL)contentLoaded;
-- (BOOL)statusLoaded;
-
-#ifndef SP_CODA /* method decls */
-// Tab view control
-- (IBAction)viewStructure:(id)sender;
-- (IBAction)viewContent:(id)sender;
-- (IBAction)viewQuery:(id)sender;
-- (IBAction)viewStatus:(id)sender;
-- (IBAction)viewRelations:(id)sender;
-- (IBAction)viewTriggers:(id)sender;
-#endif
-
-- (void)setStructureRequiresReload:(BOOL)reload;
-- (void)setContentRequiresReload:(BOOL)reload;
-- (void)setStatusRequiresReload:(BOOL)reload;
-- (void)setRelationsRequiresReload:(BOOL)reload;
-
-// Table control
-- (void)loadTable:(NSString *)aTable ofType:(SPTableType)aTableType;
-
-#ifndef SP_CODA /* method decls */
-- (NSView *)databaseView;
-#endif
-
-@end
diff --git a/Source/SPDatabaseViewController.m b/Source/SPDatabaseViewController.m
deleted file mode 100644
index 8f0e8c38..00000000
--- a/Source/SPDatabaseViewController.m
+++ /dev/null
@@ -1,641 +0,0 @@
-//
-// SPDatabaseViewController.m
-// sequel-pro
-//
-// Created by Rowan Beentje on October 31, 2010.
-// Copyright (c) 2010 Arboreal. 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>
-
-#ifndef SP_CODA /* headers */
-#import "SPAppController.h"
-#import "SPBundleHTMLOutputController.h"
-#endif
-#import "SPCopyTable.h"
-#import "SPDatabaseViewController.h"
-#import "SPHistoryController.h"
-#import "SPTableContent.h"
-#import "SPTableData.h"
-#import "SPTablesList.h"
-#import "SPTableTriggers.h"
-#import "SPThreadAdditions.h"
-#import "SPTableRelations.h"
-#ifdef SP_CODA /* headers */
-#import "SPTableStructure.h"
-#import "SPTableStructureLoading.h"
-#endif
-
-#import <SPMySQL/SPMySQL.h>
-
-@interface SPDatabaseDocument (SPDatabaseViewControllerPrivateAPI)
-
-- (void)_loadTabTask:(NSNumber *)tabViewItemIndexNumber;
-- (void)_loadTableTask;
-
-@end
-
-@implementation SPDatabaseDocument (SPDatabaseViewController)
-
-#pragma mark -
-#pragma mark Getters
-
-#ifndef SP_CODA /* getters */
-/**
- * Returns the master database view, containing the tables list and views for
- * table setup and contents.
- */
-- (NSView *)databaseView
-{
- return parentView;
-}
-#endif
-
-/**
- * Returns the name of the currently selected table/view/procedure/function.
- */
-- (NSString *)table
-{
- return selectedTableName;
-}
-
-/**
- * Returns the currently selected table type, or -1 if no table or multiple tables are selected
- */
-- (SPTableType)tableType
-{
- return selectedTableType;
-}
-
-/**
- * Returns YES if table source has already been loaded
- */
-- (BOOL)structureLoaded
-{
- return structureLoaded;
-}
-
-/**
- * Returns YES if table content has already been loaded
- */
-- (BOOL)contentLoaded
-{
- return contentLoaded;
-}
-
-/**
- * Returns YES if table status has already been loaded
- */
-- (BOOL)statusLoaded
-{
- return statusLoaded;
-}
-
-#ifndef SP_CODA /* toolbar ibactions */
-
-#pragma mark -
-#pragma mark Tab view control and delegate methods
-
-//WARNING: Might be called from code in background threads
-- (IBAction)viewStructure:(id)sender
-{
- // Cancel the selection if currently editing a view and unable to save
- if (![[self onMainThread] couldCommitCurrentViewActions]) {
- [[mainToolbar onMainThread] setSelectedItemIdentifier:*SPViewModeToMainToolbarMap[[prefs integerForKey:SPLastViewMode]]];
- return;
- }
-
- [[tableTabView onMainThread] selectTabViewItemAtIndex:0];
- [[mainToolbar onMainThread] setSelectedItemIdentifier:SPMainToolbarTableStructure];
- [spHistoryControllerInstance updateHistoryEntries];
-
- [prefs setInteger:SPStructureViewMode forKey:SPLastViewMode];
-}
-
-- (IBAction)viewContent:(id)sender
-{
- // Cancel the selection if currently editing a view and unable to save
- if (![self couldCommitCurrentViewActions]) {
- [mainToolbar setSelectedItemIdentifier:*SPViewModeToMainToolbarMap[[prefs integerForKey:SPLastViewMode]]];
- return;
- }
-
- [tableTabView selectTabViewItemAtIndex:1];
- [mainToolbar setSelectedItemIdentifier:SPMainToolbarTableContent];
- [spHistoryControllerInstance updateHistoryEntries];
-
- [prefs setInteger:SPContentViewMode forKey:SPLastViewMode];
-}
-
-- (IBAction)viewQuery:(id)sender
-{
- // Cancel the selection if currently editing a view and unable to save
- if (![self couldCommitCurrentViewActions]) {
- [mainToolbar setSelectedItemIdentifier:*SPViewModeToMainToolbarMap[[prefs integerForKey:SPLastViewMode]]];
- return;
- }
-
- [tableTabView selectTabViewItemAtIndex:2];
- [mainToolbar setSelectedItemIdentifier:SPMainToolbarCustomQuery];
- [spHistoryControllerInstance updateHistoryEntries];
-
- // Set the focus on the text field
- [parentWindow makeFirstResponder:customQueryTextView];
-
- [prefs setInteger:SPQueryEditorViewMode forKey:SPLastViewMode];
-}
-
-- (IBAction)viewStatus:(id)sender
-{
- // Cancel the selection if currently editing a view and unable to save
- if (![self couldCommitCurrentViewActions]) {
- [mainToolbar setSelectedItemIdentifier:*SPViewModeToMainToolbarMap[[prefs integerForKey:SPLastViewMode]]];
- return;
- }
-
- [tableTabView selectTabViewItemAtIndex:3];
- [mainToolbar setSelectedItemIdentifier:SPMainToolbarTableInfo];
- [spHistoryControllerInstance updateHistoryEntries];
-
- if ([[self table] length]) {
- [extendedTableInfoInstance loadTable:[self table]];
- }
-
- [parentWindow makeFirstResponder:[extendedTableInfoInstance valueForKeyPath:@"tableCreateSyntaxTextView"]];
-
- [prefs setInteger:SPTableInfoViewMode forKey:SPLastViewMode];
-}
-
-- (IBAction)viewRelations:(id)sender
-{
- // Cancel the selection if currently editing a view and unable to save
- if (![self couldCommitCurrentViewActions]) {
- [mainToolbar setSelectedItemIdentifier:*SPViewModeToMainToolbarMap[[prefs integerForKey:SPLastViewMode]]];
- return;
- }
-
- [tableTabView selectTabViewItemAtIndex:4];
- [mainToolbar setSelectedItemIdentifier:SPMainToolbarTableRelations];
- [spHistoryControllerInstance updateHistoryEntries];
-
- [prefs setInteger:SPRelationsViewMode forKey:SPLastViewMode];
-}
-
-- (IBAction)viewTriggers:(id)sender
-{
- // Cancel the selection if currently editing a view and unable to save
- if (![self couldCommitCurrentViewActions]) {
- [mainToolbar setSelectedItemIdentifier:*SPViewModeToMainToolbarMap[[prefs integerForKey:SPLastViewMode]]];
- return;
- }
-
- [tableTabView selectTabViewItemAtIndex:5];
- [mainToolbar setSelectedItemIdentifier:SPMainToolbarTableTriggers];
- [spHistoryControllerInstance updateHistoryEntries];
-
- [prefs setInteger:SPTriggersViewMode forKey:SPLastViewMode];
-}
-#endif
-
-/**
- * Mark the structure tab for refresh when it's next switched to,
- * or reload the view if it's currently active
- */
-- (void)setStructureRequiresReload:(BOOL)reload
-{
- BOOL reloadRequired = reload;
-
-#ifndef SP_CODA
- if ([self currentlySelectedView] == SPTableViewStructure) {
- reloadRequired = NO;
- }
-#endif
-
- if (reloadRequired && selectedTableName) {
- [tableSourceInstance loadTable:selectedTableName];
- }
- else {
- structureLoaded = !reload;
- }
-}
-
-/**
- * Mark the content tab for refresh when it's next switched to,
- * or reload the view if it's currently active
- */
-- (void)setContentRequiresReload:(BOOL)reload
-{
- if (reload && selectedTableName
-#ifndef SP_CODA /* check which tab is selected */
- && [self currentlySelectedView] == SPTableViewContent
-#endif
- ) {
- [tableContentInstance loadTable:selectedTableName];
- }
- else {
- contentLoaded = !reload;
- }
-}
-
-/**
- * Mark the extended tab info for refresh when it's next switched to,
- * or reload the view if it's currently active
- */
-- (void)setStatusRequiresReload:(BOOL)reload
-{
- if (reload && selectedTableName
-#ifndef SP_CODA /* check which tab is selected */
- && [self currentlySelectedView] == SPTableViewStatus
-#endif
- ) {
- [[extendedTableInfoInstance onMainThread] loadTable:selectedTableName];
- }
- else {
- statusLoaded = !reload;
- }
-}
-
-/**
- * Mark the relations tab for refresh when it's next switched to,
- * or reload the view if it's currently active
- */
-- (void)setRelationsRequiresReload:(BOOL)reload
-{
- if (reload && selectedTableName
-#ifndef SP_CODA /* check which tab is selected */
- && [self currentlySelectedView] == SPTableViewRelations
-#endif
- ) {
- [[tableRelationsInstance onMainThread] refreshRelations:self];
- }
- else {
- relationsLoaded = !reload;
- }
-}
-
-#ifndef SP_CODA /* !!! respond to tab change */
-/**
- * Triggers a task to update the newly selected tab view, ensuring
- * the data is fully loaded and up-to-date.
- */
-- (void)tabView:(NSTabView *)aTabView didSelectTabViewItem:(NSTabViewItem *)tabViewItem
-{
- [self startTaskWithDescription:[NSString stringWithFormat:NSLocalizedString(@"Loading %@...", @"Loading table task string"), [self table]]];
-
- // We can't pass aTabView or tabViewItem UI objects to a bg thread, but since the change should already
- // be done in *did*SelectTabViewItem we can just ask the tab view for the current selection index and use that
- SPTableViewType newView = [self currentlySelectedView];
-
- if ([NSThread isMainThread]) {
- [NSThread detachNewThreadWithName:SPCtxt(@"SPDatabaseViewController view load task",self)
- target:self
- selector:@selector(_loadTabTask:)
- object:@(newView)];
- }
- else {
- [self _loadTabTask:@(newView)];
- }
-}
-#endif
-
-#pragma mark -
-#pragma mark Table control
-
-/**
- * Loads a specified table into the database view, and ensures it's selected in
- * the tables list. Passing a table name of nil will deselect any currently selected
- * table, but will leave multiple selections intact.
- * If this method is supplied with the currently selected name, a reload rather than
- * a load will be triggered.
- */
-- (void)loadTable:(NSString *)aTable ofType:(SPTableType)aTableType
-{
- // Ensure a connection is still present
- if (![mySQLConnection isConnected]) return;
-
- // If the supplied table name was nil, clear the views.
- if (!aTable) {
-
- // Update the selected table name and type
- if (selectedTableName) SPClear(selectedTableName);
-
- selectedTableType = SPTableTypeNone;
-
- // Clear the views
- [[tablesListInstance onMainThread] setSelectionState:nil];
- [tableSourceInstance loadTable:nil];
- [tableContentInstance loadTable:nil];
-#ifndef SP_CODA /* [extendedTableInfoInstance loadTable:] */
- [[extendedTableInfoInstance onMainThread] loadTable:nil];
- [[tableTriggersInstance onMainThread] resetInterface];
- [[tableRelationsInstance onMainThread] refreshRelations:self];
-#endif
- structureLoaded = NO;
- contentLoaded = NO;
- statusLoaded = NO;
- triggersLoaded = NO;
- relationsLoaded = NO;
-
-#ifndef SP_CODA
- // Update the window title
- [self updateWindowTitle:self];
-
- // Add a history entry
- [spHistoryControllerInstance updateHistoryEntries];
-#endif
-
- // Notify listeners of the table change
- [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadWithName:SPTableChangedNotification object:self];
-
- return;
- }
-
- BOOL isReloading = (selectedTableName && [selectedTableName isEqualToString:aTable]);
-
- // Store the new name
- if (selectedTableName) [selectedTableName release];
-
- selectedTableName = [[NSString alloc] initWithString:aTable];
- selectedTableType = aTableType;
-
- // Start a task
- if (isReloading) {
- [self startTaskWithDescription:NSLocalizedString(@"Reloading...", @"Reloading table task string")];
- }
- else {
- [self startTaskWithDescription:[NSString stringWithFormat:NSLocalizedString(@"Loading %@...", @"Loading table task string"), aTable]];
- }
-
- // Update the tables list interface - also updates menus to reflect the selected table type
- [[tablesListInstance onMainThread] setSelectionState:[NSDictionary dictionaryWithObjectsAndKeys:aTable, @"name", [NSNumber numberWithInteger:aTableType], @"type", nil]];
-
- // If on the main thread, fire up a thread to deal with view changes and data loading;
- // if already on a background thread, make the changes on the existing thread.
- if ([NSThread isMainThread]) {
- [NSThread detachNewThreadWithName:SPCtxt(@"SPDatabaseViewController table load task",self)
- target:self
- selector:@selector(_loadTableTask)
- object:nil];
- }
- else {
- [self _loadTableTask];
- }
-}
-
-@end
-
-#pragma mark -
-
-@implementation SPDatabaseDocument (SPDatabaseViewControllerPrivateAPI)
-
-/**
- * In a threaded task, ensure that the supplied tab is loaded -
- * usually as a result of switching to it.
- */
-- (void)_loadTabTask:(NSNumber *)tabViewItemIndexNumber
-{
- NSAutoreleasePool *tabLoadPool = [[NSAutoreleasePool alloc] init];
-
- // If anything other than a single table or view is selected, don't proceed.
- if (![self table] || ([tablesListInstance tableType] != SPTableTypeTable && [tablesListInstance tableType] != SPTableTypeView))
- {
- [self endTask];
- [tabLoadPool drain];
- return;
- }
-
- // Get the tab view index and ensure the associated view is loaded
- SPTableViewType selectedTabViewIndex = [tabViewItemIndexNumber integerValue];
-
- switch (selectedTabViewIndex) {
- case SPTableViewStructure:
- if (!structureLoaded) {
- [tableSourceInstance loadTable:selectedTableName];
- structureLoaded = YES;
- }
- break;
- case SPTableViewContent:
- if (!contentLoaded) {
- [tableContentInstance loadTable:selectedTableName];
- contentLoaded = YES;
- }
- break;
-#ifndef SP_CODA /* case SPTableViewStatus: case SPTableViewTriggers: */
- case SPTableViewStatus:
- if (!statusLoaded) {
- [[extendedTableInfoInstance onMainThread] loadTable:selectedTableName];
- statusLoaded = YES;
- }
- break;
- case SPTableViewTriggers:
- if (!triggersLoaded) {
- [[tableTriggersInstance onMainThread] loadTriggers];
- triggersLoaded = YES;
- }
- break;
- case SPTableViewRelations:
- if (!relationsLoaded) {
- [[tableRelationsInstance onMainThread] refreshRelations:self];
- relationsLoaded = YES;
- }
- break;
-#endif
- }
-
- [self endTask];
-
- [tabLoadPool drain];
-}
-
-
-/**
- * In a threaded task, load the currently selected table/view/proc/function.
- */
-- (void)_loadTableTask
-{
- NSAutoreleasePool *loadPool = [[NSAutoreleasePool alloc] init];
- NSString *tableEncoding = nil;
-
-#ifndef SP_CODA /* Update the window title */
- // Update the window title
- [self updateWindowTitle:self];
-#endif
-
- // Reset table information caches and mark that all loaded views require their data reloading
- [tableDataInstance resetAllData];
-
- structureLoaded = NO;
- contentLoaded = NO;
- statusLoaded = NO;
- triggersLoaded = NO;
- relationsLoaded = NO;
-
- // Ensure status and details are fetched using UTF8
- NSString *previousEncoding = [mySQLConnection encoding];
- BOOL changeEncoding = ![previousEncoding isEqualToString:@"utf8"];
-
- if (changeEncoding) {
- [mySQLConnection storeEncodingForRestoration];
- [mySQLConnection setEncoding:@"utf8"];
- }
-
- // Cache status information on the working thread
- [tableDataInstance updateStatusInformationForCurrentTable];
-
- // Check the current encoding against the table encoding to see whether
- // an encoding change and reset is required. This also caches table information on
- // the working thread.
- if( selectedTableType == SPTableTypeView || selectedTableType == SPTableTypeTable) {
-
- // tableEncoding == nil indicates that there was an error while retrieving table data
- tableEncoding = [tableDataInstance tableEncoding];
-
- // If encoding is set to Autodetect, update the connection character set encoding
- // based on the newly selected table's encoding - but only if it differs from the current encoding.
- if ([[[NSUserDefaults standardUserDefaults] objectForKey:SPDefaultEncoding] intValue] == SPEncodingAutodetect) {
- if (tableEncoding != nil && ![tableEncoding isEqualToString:previousEncoding]) {
- [self setConnectionEncoding:tableEncoding reloadingViews:NO];
- changeEncoding = NO;
- }
- }
- }
-
- if (changeEncoding) [mySQLConnection restoreStoredEncoding];
-
- // Notify listeners of the table change now that the state is fully set up.
- [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadWithName:SPTableChangedNotification object:self];
-
-#ifndef SP_CODA /* [spHistoryControllerInstance restoreViewStates] */
-
- // Restore view states as appropriate
- [spHistoryControllerInstance restoreViewStates];
-#endif
-
- // Load the currently selected view if looking at a table or view
- if (tableEncoding && (selectedTableType == SPTableTypeView || selectedTableType == SPTableTypeTable))
- {
-#ifndef SP_CODA /* load everything */
- NSInteger selectedTabViewIndex = [[self onMainThread] currentlySelectedView];
-
- switch (selectedTabViewIndex) {
- case SPTableViewStructure:
-#endif
- [tableSourceInstance loadTable:selectedTableName];
- structureLoaded = YES;
-#ifndef SP_CODA /* load everything */
- break;
- case SPTableViewContent:
-#endif
- [tableContentInstance loadTable:selectedTableName];
- contentLoaded = YES;
-#ifndef SP_CODA /* load everything */
- break;
- case SPTableViewStatus:
- [[extendedTableInfoInstance onMainThread] loadTable:selectedTableName];
- statusLoaded = YES;
- break;
- case SPTableViewTriggers:
- [[tableTriggersInstance onMainThread] loadTriggers];
- triggersLoaded = YES;
- break;
- case SPTableViewRelations:
- [[tableRelationsInstance onMainThread] refreshRelations:self];
- relationsLoaded = YES;
- break;
- }
-#endif
- }
-
- // Clear any views which haven't been loaded as they weren't visible. Note
- // that this should be done after reloading visible views, instead of clearing all
- // views, to reduce UI operations and avoid resetting state unnecessarily.
- // Some views (eg TableRelations) make use of the SPTableChangedNotification and
- // so don't require manual clearing.
- if (!structureLoaded) [tableSourceInstance loadTable:nil];
- if (!contentLoaded) [tableContentInstance loadTable:nil];
- if (!statusLoaded) [[extendedTableInfoInstance onMainThread] loadTable:nil];
- if (!triggersLoaded) [[tableTriggersInstance onMainThread] resetInterface];
-
- // If the table row counts an inaccurate and require updating, trigger an update - no
- // action will be performed if not necessary
- [tableDataInstance updateAccurateNumberOfRowsForCurrentTableForcingUpdate:NO];
-
-#ifndef SP_CODA /* show Create Table syntax */
- // Update the "Show Create Syntax" window if it's already opened
- // according to the selected table/view/proc/func
- if ([[[self onMainThread] getCreateTableSyntaxWindow] isVisible]) {
- [[self onMainThread] showCreateTableSyntax:self];
- }
-
- // Add a history entry
- [spHistoryControllerInstance updateHistoryEntries];
-#endif
- // Empty the loading pool and exit the thread
- [self endTask];
-
-#ifndef SP_CODA /* triggered commands */
- NSArray *triggeredCommands = [SPAppDelegate bundleCommandsForTrigger:SPBundleTriggerActionTableChanged];
-
- for(NSString* cmdPath in triggeredCommands)
- {
- NSArray *data = [cmdPath componentsSeparatedByString:@"|"];
- NSMenuItem *aMenuItem = [[[NSMenuItem alloc] init] autorelease];
- [aMenuItem setTag:0];
- [aMenuItem setToolTip:[data objectAtIndex:0]];
-
- // For HTML output check if corresponding window already exists
- BOOL stopTrigger = NO;
- if([(NSString*)[data objectAtIndex:2] length]) {
- BOOL correspondingWindowFound = NO;
- NSString *uuid = [data objectAtIndex:2];
- for(id win in [NSApp windows]) {
- if([[[[win delegate] class] description] isEqualToString:@"SPBundleHTMLOutputController"]) {
- if([[[win delegate] windowUUID] isEqualToString:uuid]) {
- correspondingWindowFound = YES;
- break;
- }
- }
- }
- if(!correspondingWindowFound) stopTrigger = YES;
- }
- if(!stopTrigger) {
- id firstResponder = [[NSApp keyWindow] firstResponder];
- if([[data objectAtIndex:1] isEqualToString:SPBundleScopeGeneral]) {
- [[SPAppDelegate onMainThread] executeBundleItemForApp:aMenuItem];
- }
- else if([[data objectAtIndex:1] isEqualToString:SPBundleScopeDataTable]) {
- if([[[firstResponder class] description] isEqualToString:@"SPCopyTable"])
- [[firstResponder onMainThread] executeBundleItemForDataTable:aMenuItem];
- }
- else if([[data objectAtIndex:1] isEqualToString:SPBundleScopeInputField]) {
- if([firstResponder isKindOfClass:[NSTextView class]])
- [[firstResponder onMainThread] executeBundleItemForInputField:aMenuItem];
- }
- }
- }
-#endif
-
- [loadPool drain];
-}
-
-@end
diff --git a/Source/SPExportFilenameUtilities.m b/Source/SPExportFilenameUtilities.m
index 17e01e73..c064d363 100644
--- a/Source/SPExportFilenameUtilities.m
+++ b/Source/SPExportFilenameUtilities.m
@@ -30,7 +30,7 @@
#import "SPExportFilenameUtilities.h"
#import "SPTablesList.h"
-#import "SPDatabaseViewController.h"
+#import "SPDatabaseDocument.h"
#import "SPExportFileNameTokenObject.h"
@implementation SPExportController (SPExportFilenameUtilities)
diff --git a/Source/SPExtendedTableInfo.m b/Source/SPExtendedTableInfo.m
index 35a102a9..57d765de 100644
--- a/Source/SPExtendedTableInfo.m
+++ b/Source/SPExtendedTableInfo.m
@@ -34,7 +34,6 @@
#import "RegexKitLite.h"
#import "SPDatabaseData.h"
#import "SPDatabaseDocument.h"
-#import "SPDatabaseViewController.h"
#import "SPTablesList.h"
#import "SPAlertSheets.h"
#import "SPTableStructure.h"
diff --git a/Source/SPHistoryController.m b/Source/SPHistoryController.m
index ec05c4af..2abac6bb 100644
--- a/Source/SPHistoryController.m
+++ b/Source/SPHistoryController.m
@@ -32,7 +32,6 @@
#import "SPTableContent.h"
#import "SPTablesList.h"
#import "SPHistoryController.h"
-#import "SPDatabaseViewController.h"
#import "SPThreadAdditions.h"
@implementation SPHistoryController
diff --git a/Source/SPIndexesController.m b/Source/SPIndexesController.m
index dcf01ccb..661b1b7f 100644
--- a/Source/SPIndexesController.m
+++ b/Source/SPIndexesController.m
@@ -36,7 +36,6 @@
#import "SPDatabaseDocument.h"
#import "SPTablesList.h"
#import "SPTableView.h"
-#import "SPDatabaseViewController.h"
#import "SPTableStructure.h"
#import "SPTableStructureLoading.h"
#import "SPThreadAdditions.h"
diff --git a/Source/SPNavigatorController.m b/Source/SPNavigatorController.m
index 93b4f13d..a7d8b61b 100644
--- a/Source/SPNavigatorController.m
+++ b/Source/SPNavigatorController.m
@@ -39,7 +39,6 @@
#import "SPLogger.h"
#import "SPTooltip.h"
#import "SPAppController.h"
-#import "SPDatabaseViewController.h"
#import "SPDatabaseStructure.h"
#import "SPThreadAdditions.h"
diff --git a/Source/SPPrintController.h b/Source/SPPrintController.h
deleted file mode 100644
index a9780a2d..00000000
--- a/Source/SPPrintController.h
+++ /dev/null
@@ -1,42 +0,0 @@
-//
-// SPPrintController.h
-// sequel-pro
-//
-// Created by Stuart Connolly (stuconnolly.com) on March 11, 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 "SPDatabaseDocument.h"
-
-@interface SPDatabaseDocument (SPPrintController)
-
-- (void)startPrintDocumentOperation;
-- (void)generateHTMLForPrinting;
-- (void)generateTableInfoHTMLForPrinting;
-
-- (NSArray *)columnNames;
-- (NSMutableDictionary *)connectionInformation;
-
-@end
diff --git a/Source/SPPrintController.m b/Source/SPPrintController.m
deleted file mode 100644
index ab2cda9a..00000000
--- a/Source/SPPrintController.m
+++ /dev/null
@@ -1,461 +0,0 @@
-//
-// SPPrintController.m
-// sequel-pro
-//
-// Created by Stuart Connolly (stuconnolly.com) on March 11, 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 "SPPrintController.h"
-#import "SPTableContent.h"
-#import "SPTableStructure.h"
-#import "SPCustomQuery.h"
-#import "SPTableRelations.h"
-#import "SPPrintAccessory.h"
-#import "MGTemplateEngine.h"
-#import "ICUTemplateMatcher.h"
-#import "SPConnectionController.h"
-#import "SPExtendedTableInfo.h"
-#import "SPTableTriggers.h"
-#import "SPDatabaseViewController.h"
-
-@implementation SPDatabaseDocument (SPPrintController)
-
-/**
- * WebView delegate method.
- */
-- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame
-{
- // Because we need the webFrame loaded (for preview), we've moved the actual printing here
- NSPrintInfo *printInfo = [NSPrintInfo sharedPrintInfo];
-
- NSSize paperSize = [printInfo paperSize];
- NSRect printableRect = [printInfo imageablePageBounds];
-
- // Calculate page margins
- CGFloat marginL = printableRect.origin.x;
- CGFloat marginR = paperSize.width - (printableRect.origin.x + printableRect.size.width);
- CGFloat marginB = printableRect.origin.y;
- CGFloat marginT = paperSize.height - (printableRect.origin.y + printableRect.size.height);
-
- // Make sure margins are symetric and positive
- CGFloat marginLR = MAX(0, MAX(marginL, marginR));
- CGFloat marginTB = MAX(0, MAX(marginT, marginB));
-
- // Set the margins
- [printInfo setLeftMargin:marginLR];
- [printInfo setRightMargin:marginLR];
- [printInfo setTopMargin:marginTB];
- [printInfo setBottomMargin:marginTB];
-
- [printInfo setHorizontalPagination:NSFitPagination];
- [printInfo setVerticalPagination:NSAutoPagination];
- [printInfo setVerticallyCentered:NO];
-
- NSPrintOperation *op = [NSPrintOperation printOperationWithView:[[[printWebView mainFrame] frameView] documentView] printInfo:printInfo];
-
- // Perform the print operation on a background thread
- [op setCanSpawnSeparateThread:YES];
-
- // Add the ability to select the orientation to print panel
- NSPrintPanel *printPanel = [op printPanel];
-
- [printPanel setOptions:[printPanel options] + NSPrintPanelShowsOrientation + NSPrintPanelShowsScaling + NSPrintPanelShowsPaperSize];
-
- SPPrintAccessory *printAccessory = [[SPPrintAccessory alloc] initWithNibName:@"PrintAccessory" bundle:nil];
-
- [printAccessory setPrintView:printWebView];
- [printPanel addAccessoryController:printAccessory];
-
- [[NSPageLayout pageLayout] addAccessoryController:printAccessory];
- [printAccessory release];
-
- [op setPrintPanel:printPanel];
-
- [op runOperationModalForWindow:[self parentWindow]
- delegate:self
- didRunSelector:nil
- contextInfo:nil];
-
- if ([self isWorking]) [self endTask];
-}
-
-/**
- * Loads the print document interface. The actual printing is done in the doneLoading delegate.
- */
-- (IBAction)printDocument:(id)sender
-{
- // Only display warning for the 'Table Content' view
- if ([self currentlySelectedView] == SPTableViewContent) {
-
- NSInteger rowLimit = [prefs integerForKey:SPPrintWarningRowLimit];
-
- // Result count minus one because the first element is the column names
- NSInteger resultRows = ([[tableContentInstance currentResult] count] - 1);
-
- if (resultRows > rowLimit) {
-
- NSNumberFormatter *numberFormatter = [[[NSNumberFormatter alloc] init] autorelease];
-
- [numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
-
- NSAlert *alert = [NSAlert alertWithMessageText:NSLocalizedString(@"Continue to print?", @"continue to print message")
- defaultButton:NSLocalizedString(@"Print", @"print button")
- alternateButton:NSLocalizedString(@"Cancel", @"cancel button")
- otherButton:nil
- informativeTextWithFormat:NSLocalizedString(@"Are you sure you want to print the current content view of the table '%@'?\n\nIt currently contains %@ rows, which may take a significant amount of time to print.", @"continue to print informative message"), [self table], [numberFormatter stringFromNumber:[NSNumber numberWithLongLong:resultRows]]];
-
- NSArray *buttons = [alert buttons];
-
- // Change the alert's cancel button to have the key equivalent of return
- [[buttons objectAtIndex:0] setKeyEquivalent:@"p"];
- [[buttons objectAtIndex:0] setKeyEquivalentModifierMask:NSCommandKeyMask];
- [[buttons objectAtIndex:1] setKeyEquivalent:@"\r"];
-
- [alert beginSheetModalForWindow:[self parentWindow] modalDelegate:self didEndSelector:@selector(printWarningDidEnd:returnCode:contextInfo:) contextInfo:NULL];
-
- return;
- }
- }
-
- [self startPrintDocumentOperation];
-}
-
-/**
- * Called when the print warning dialog is dismissed.
- */
-- (void)printWarningDidEnd:(id)sheet returnCode:(NSInteger)returnCode contextInfo:(NSString *)contextInfo
-{
- if (returnCode == NSAlertDefaultReturn) {
- [self startPrintDocumentOperation];
- }
-}
-
-/**
- * Starts tge print document operation by spawning a new thread if required.
- */
-- (void)startPrintDocumentOperation
-{
- [self startTaskWithDescription:NSLocalizedString(@"Generating print document...", @"generating print document status message")];
-
- BOOL isTableInformation = ([self currentlySelectedView] == SPTableViewStatus);
-
- if ([NSThread isMainThread]) {
- printThread = [[NSThread alloc] initWithTarget:self selector:(isTableInformation) ? @selector(generateTableInfoHTMLForPrinting) : @selector(generateHTMLForPrinting) object:nil];
- [printThread setName:@"SPPrintController document generator"];
-
- [self enableTaskCancellationWithTitle:NSLocalizedString(@"Cancel", @"cancel button") callbackObject:self callbackFunction:@selector(generateHTMLForPrintingCallback)];
-
- [printThread start];
- }
- else {
- (isTableInformation) ? [self generateTableInfoHTMLForPrinting] : [self generateHTMLForPrinting];
- }
-}
-
-/**
- * HTML generation thread callback method.
- */
-- (void)generateHTMLForPrintingCallback
-{
- [self setTaskDescription:NSLocalizedString(@"Cancelling...", @"cancelling task status message")];
-
- // Cancel the print thread
- [printThread cancel];
-}
-
-/**
- * Loads the supplied HTML string in the print WebView.
- */
-- (void)loadPrintWebViewWithHTMLString:(NSString *)HTMLString
-{
- [[printWebView mainFrame] loadHTMLString:HTMLString baseURL:nil];
-
- if (printThread) SPClear(printThread);
-}
-
-/**
- * Generates the HTML for the current view that is being printed.
- */
-- (void)generateHTMLForPrinting
-{
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-
- // Set up template engine with your chosen matcher
- MGTemplateEngine *engine = [MGTemplateEngine templateEngine];
-
- [engine setMatcher:[ICUTemplateMatcher matcherWithTemplateEngine:engine]];
-
- NSMutableDictionary *connection = [self connectionInformation];
-
- NSString *heading = @"";
- NSArray *rows, *indexes, *indexColumns = nil;
-
- NSArray *columns = [self columnNames];
-
- NSMutableDictionary *printData = [NSMutableDictionary dictionary];
-
- SPTableViewType view = [self currentlySelectedView];
-
- // Table source view
- if (view == SPTableViewStructure) {
-
- NSDictionary *tableSource = [tableSourceInstance tableSourceForPrinting];
-
- NSInteger tableType = [tablesListInstance tableType];
-
- switch (tableType) {
- case SPTableTypeTable:
- heading = NSLocalizedString(@"Table Structure", @"table structure print heading");
- break;
- case SPTableTypeView:
- heading = NSLocalizedString(@"View Structure", @"view structure print heading");
- break;
- }
-
- rows = [[NSArray alloc] initWithArray:
- [[tableSource objectForKey:@"structure"] objectsAtIndexes:
- [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(1, [[tableSource objectForKey:@"structure"] count] - 1)]]
- ];
-
- indexes = [[NSArray alloc] initWithArray:
- [[tableSource objectForKey:@"indexes"] objectsAtIndexes:
- [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(1, [[tableSource objectForKey:@"indexes"] count] - 1)]]
- ];
-
- indexColumns = [[tableSource objectForKey:@"indexes"] objectAtIndex:0];
-
- [printData setObject:rows forKey:@"rows"];
- [printData setObject:indexes forKey:@"indexes"];
- [printData setObject:indexColumns forKey:@"indexColumns"];
-
- if ([indexes count]) [printData setObject:@1 forKey:@"hasIndexes"];
-
- [rows release];
- [indexes release];
- }
- // Table content view
- else if (view == SPTableViewContent) {
-
- NSArray *data = [tableContentInstance currentDataResultWithNULLs:NO hideBLOBs:YES];
-
- heading = NSLocalizedString(@"Table Content", @"table content print heading");
-
- rows = [[NSArray alloc] initWithArray:
- [data objectsAtIndexes:
- [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(1, [data count] - 1)]]
- ];
-
- [printData setObject:rows forKey:@"rows"];
- [connection setValue:[tableContentInstance usedQuery] forKey:@"query"];
-
- [rows release];
- }
- // Custom query view
- else if (view == SPTableViewCustomQuery) {
-
- NSArray *data = [customQueryInstance currentResult];
-
- heading = NSLocalizedString(@"Query Result", @"query result print heading");
-
- rows = [[NSArray alloc] initWithArray:
- [data objectsAtIndexes:
- [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(1, [data count] - 1)]]
- ];
-
- [printData setObject:rows forKey:@"rows"];
- [connection setValue:[customQueryInstance usedQuery] forKey:@"query"];
-
- [rows release];
- }
- // Table relations view
- else if (view == SPTableViewRelations) {
-
- NSArray *data = [tableRelationsInstance relationDataForPrinting];
-
- heading = NSLocalizedString(@"Table Relations", @"toolbar item label for switching to the Table Relations tab");
-
- rows = [[NSArray alloc] initWithArray:
- [data objectsAtIndexes:
- [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(1, ([data count] - 1))]]
- ];
-
- [printData setObject:rows forKey:@"rows"];
-
- [rows release];
- }
- // Table triggers view
- else if (view == SPTableViewTriggers) {
-
- NSArray *data = [tableTriggersInstance triggerDataForPrinting];
-
- heading = NSLocalizedString(@"Table Triggers", @"toolbar item label for switching to the Table Triggers tab");
-
- rows = [[NSArray alloc] initWithArray:
- [data objectsAtIndexes:
- [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(1, ([data count] - 1))]]
- ];
-
- [printData setObject:rows forKey:@"rows"];
-
- [rows release];
- }
-
- [engine setObject:connection forKey:@"c"];
-
- [printData setObject:heading forKey:@"heading"];
- [printData setObject:columns forKey:@"columns"];
- [printData setObject:([prefs boolForKey:SPUseMonospacedFonts]) ? SPDefaultMonospacedFontName : @"Lucida Grande" forKey:@"font"];
- [printData setObject:([prefs boolForKey:SPDisplayTableViewVerticalGridlines]) ? @"1px solid #CCCCCC" : @"none" forKey:@"gridlines"];
-
- NSString *HTMLString = [engine processTemplateInFileAtPath:[[NSBundle mainBundle] pathForResource:SPHTMLPrintTemplate ofType:@"html"] withVariables:printData];
-
- // Check if the operation has been cancelled
- if ((printThread != nil) && (![NSThread isMainThread]) && ([printThread isCancelled])) {
- [self endTask];
- [pool drain];
-
- [NSThread exit];
- return;
- }
-
- [self performSelectorOnMainThread:@selector(loadPrintWebViewWithHTMLString:) withObject:HTMLString waitUntilDone:NO];
-
- [pool drain];
-}
-
-/**
- * Generates the HTML for the table information view that is to be printed.
- */
-- (void)generateTableInfoHTMLForPrinting
-{
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-
- // Set up template engine with your chosen matcher
- MGTemplateEngine *engine = [MGTemplateEngine templateEngine];
-
- [engine setMatcher:[ICUTemplateMatcher matcherWithTemplateEngine:engine]];
-
- NSMutableDictionary *connection = [self connectionInformation];
- NSMutableDictionary *printData = [NSMutableDictionary dictionary];
-
- NSString *heading = NSLocalizedString(@"Table Information", @"table information print heading");
-
- [engine setObject:connection forKey:@"c"];
- [engine setObject:[[extendedTableInfoInstance onMainThread] tableInformationForPrinting] forKey:@"i"];
-
- [printData setObject:heading forKey:@"heading"];
- [printData setObject:[[NSUnarchiver unarchiveObjectWithData:[prefs objectForKey:SPCustomQueryEditorFont]] fontName] forKey:@"font"];
-
- NSString *HTMLString = [engine processTemplateInFileAtPath:[[NSBundle mainBundle] pathForResource:SPHTMLTableInfoPrintTemplate ofType:@"html"] withVariables:printData];
-
- // Check if the operation has been cancelled
- if ((printThread != nil) && (![NSThread isMainThread]) && ([printThread isCancelled])) {
- [self endTask];
- [pool drain];
-
- [NSThread exit];
- return;
- }
-
- [self performSelectorOnMainThread:@selector(loadPrintWebViewWithHTMLString:) withObject:HTMLString waitUntilDone:NO];
-
- [pool drain];
-}
-
-/**
- * Returns an array of columns for whichever view is being printed.
- */
-- (NSArray *)columnNames
-{
- NSArray *columns = nil;
-
- SPTableViewType view = [self currentlySelectedView];
-
- // Table source view
- if ((view == SPTableViewStructure) && ([[tableSourceInstance tableSourceForPrinting] count] > 0)) {
-
- columns = [[NSArray alloc] initWithArray:[[[tableSourceInstance tableSourceForPrinting] objectForKey:@"structure"] objectAtIndex:0] copyItems:YES];
- }
- // Table content view
- else if ((view == SPTableViewContent) && ([[tableContentInstance currentResult] count] > 0)) {
-
- columns = [[NSArray alloc] initWithArray:[[tableContentInstance currentResult] objectAtIndex:0] copyItems:YES];
- }
- // Custom query view
- else if ((view == SPTableViewCustomQuery) && ([[customQueryInstance currentResult] count] > 0)) {
-
- columns = [[NSArray alloc] initWithArray:[[customQueryInstance currentResult] objectAtIndex:0] copyItems:YES];
- }
- // Table relations view
- else if ((view == SPTableViewRelations) && ([[tableRelationsInstance relationDataForPrinting] count] > 0)) {
-
- columns = [[NSArray alloc] initWithArray:[[tableRelationsInstance relationDataForPrinting] objectAtIndex:0] copyItems:YES];
- }
- // Table triggers view
- else if ((view == SPTableViewTriggers) && ([[tableTriggersInstance triggerDataForPrinting] count] > 0)) {
-
- columns = [[NSArray alloc] initWithArray:[[tableTriggersInstance triggerDataForPrinting] objectAtIndex:0] copyItems:YES];
- }
-
- if (columns) [columns autorelease];
-
- return columns;
-}
-
-/**
- * Generates a dictionary of connection information that is used for printing.
- */
-- (NSMutableDictionary *)connectionInformation
-{
- NSString *versionForPrint = [NSString stringWithFormat:@"%@ %@ (%@ %@)",
- [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"],
- [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"],
- NSLocalizedString(@"build", @"build label"),
- [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"]
- ];
-
- NSMutableDictionary *connection = [NSMutableDictionary dictionary];
-
- if ([[self user] length]) {
- [connection setValue:[self user] forKey:@"username"];
- }
-
- if ([[self table] length]) {
- [connection setValue:[self table] forKey:@"table"];
- }
-
- if ([connectionController port] && [[connectionController port] length]) {
- [connection setValue:[connectionController port] forKey:@"port"];
- }
-
- [connection setValue:[self host] forKey:@"hostname"];
- [connection setValue:selectedDatabase forKey:@"database"];
- [connection setValue:versionForPrint forKey:@"version"];
-
- return connection;
-}
-
-@end
diff --git a/Source/SPTableContent.m b/Source/SPTableContent.m
index 2366cbf0..3735c04c 100644
--- a/Source/SPTableContent.m
+++ b/Source/SPTableContent.m
@@ -55,7 +55,6 @@
#import "SPHistoryController.h"
#import "SPGeometryDataView.h"
#import "SPTextView.h"
-#import "SPDatabaseViewController.h"
#ifndef SP_CODA /* headers */
#import "SPAppController.h"
#import "SPBundleHTMLOutputController.h"
diff --git a/Source/SPTableStructure.m b/Source/SPTableStructure.m
index c1b007c3..4120dbf8 100644
--- a/Source/SPTableStructure.m
+++ b/Source/SPTableStructure.m
@@ -32,7 +32,6 @@
#import "SPTableStructure.h"
#import "SPDatabaseStructure.h"
#import "SPDatabaseDocument.h"
-#import "SPDatabaseViewController.h"
#import "SPTableInfo.h"
#import "SPTablesList.h"
#import "SPTableData.h"
diff --git a/Source/SPTableStructureDelegate.h b/Source/SPTableStructureDelegate.h
index 4e845d6e..2ddf8914 100644
--- a/Source/SPTableStructureDelegate.h
+++ b/Source/SPTableStructureDelegate.h
@@ -1,5 +1,5 @@
//
-// SPConnectionDelegate.h
+// SPTableStructureDelegate.h
// sequel-pro
//
// Created by Stuart Connolly (stuconnolly.com) on October 26, 2010.
diff --git a/Source/SPTableStructureDelegate.m b/Source/SPTableStructureDelegate.m
index 4c6e2db3..88c9673f 100644
--- a/Source/SPTableStructureDelegate.m
+++ b/Source/SPTableStructureDelegate.m
@@ -1,5 +1,5 @@
//
-// SPConnectionDelegate.m
+// SPTableStructureDelegate.m
// sequel-pro
//
// Created by Stuart Connolly (stuconnolly.com) on October 26, 2010.
@@ -31,7 +31,7 @@
#import "SPTableStructureDelegate.h"
#import "SPAlertSheets.h"
#import "SPDatabaseData.h"
-#import "SPDatabaseViewController.h"
+#import "SPDatabaseDocument.h"
#import "SPTableData.h"
#import "SPTableView.h"
#import "SPTableFieldValidation.h"
diff --git a/Source/SPTableStructureLoading.m b/Source/SPTableStructureLoading.m
index b7f8e748..9aec78e7 100644
--- a/Source/SPTableStructureLoading.m
+++ b/Source/SPTableStructureLoading.m
@@ -32,7 +32,7 @@
#import "SPDatabaseData.h"
#import "SPDatabaseStructure.h"
#import "SPTableFieldValidation.h"
-#import "SPDatabaseViewController.h"
+#import "SPDatabaseDocument.h"
#import "SPIndexesController.h"
#import "SPTablesList.h"
#import "SPThreadAdditions.h"
diff --git a/Source/SPTablesList.m b/Source/SPTablesList.m
index 6096b493..eceb57f2 100644
--- a/Source/SPTablesList.m
+++ b/Source/SPTablesList.m
@@ -33,7 +33,6 @@
#import "SPDatabaseDocument.h"
#import "SPTableStructure.h"
#import "SPDatabaseStructure.h"
-#import "SPDatabaseViewController.h"
#import "SPTableContent.h"
#import "SPTableData.h"
#import "SPTableInfo.h"
diff --git a/Source/SPTextView.m b/Source/SPTextView.m
index 36bd005e..7056befd 100644
--- a/Source/SPTextView.m
+++ b/Source/SPTextView.m
@@ -42,7 +42,6 @@
#ifndef SP_CODA /* headers */
#import "SPBundleHTMLOutputController.h"
#endif
-#import "SPDatabaseViewController.h"
#ifndef SP_CODA /* headers */
#import "SPAppController.h"
#endif
@@ -1032,7 +1031,7 @@ static inline NSPoint SPPointOnLine(NSPoint a, NSPoint b, CGFloat t) { return NS
- (IBAction)printDocument:(id)sender
{
- // If Extended Table Info tab is active delegate the print call to the SPPrintController
+ // If Extended Table Info tab is active delegate the print call to the SPDatabaseDocument
// if the user doesn't select anything in self
if([[[[self delegate] class] description] isEqualToString:@"SPExtendedTableInfo"] && ![self selectedRange].length) {
[[(NSObject*)[self delegate] valueForKeyPath:@"tableDocumentInstance"] printDocument:sender];
diff --git a/Source/SPWindowController.m b/Source/SPWindowController.m
index bee91aa4..330d792f 100644
--- a/Source/SPWindowController.m
+++ b/Source/SPWindowController.m
@@ -30,7 +30,6 @@
#import "SPWindowController.h"
#import "SPDatabaseDocument.h"
-#import "SPDatabaseViewController.h"
#import "SPAppController.h"
#import "PSMTabDragAssistant.h"
#import "SPConnectionController.h"