aboutsummaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
Diffstat (limited to 'Source')
-rw-r--r--Source/SPHistoryController.h59
-rw-r--r--Source/SPHistoryController.m256
-rw-r--r--Source/TableDocument.h2
-rw-r--r--Source/TableDocument.m18
-rw-r--r--Source/TablesList.h2
-rw-r--r--Source/TablesList.m2
6 files changed, 338 insertions, 1 deletions
diff --git a/Source/SPHistoryController.h b/Source/SPHistoryController.h
new file mode 100644
index 00000000..110ebea3
--- /dev/null
+++ b/Source/SPHistoryController.h
@@ -0,0 +1,59 @@
+//
+// $Id: SPFieldEditorController.h 802 2009-06-03 20:46:57Z bibiko $
+//
+// SPHistoryController.h
+// sequel-pro
+//
+// Created by Rowan Beentje on July 23, 2009
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// More info at <http://code.google.com/p/sequel-pro/>
+
+#import <Cocoa/Cocoa.h>
+
+@class TableDocument;
+
+enum sphistory_view_types
+{
+ SP_VIEW_STRUCTURE = 0,
+ SP_VIEW_CONTENT = 1,
+ SP_VIEW_CUSTOMQUERY = 2,
+ SP_VIEW_STATUS = 3,
+ SP_VIEW_RELATIONS = 4
+};
+
+@interface SPHistoryController : NSObject {
+ IBOutlet TableDocument *theDocument;
+ IBOutlet NSSegmentedControl *historyControl;
+
+ NSMutableArray *history;
+ unsigned int historyPosition;
+ BOOL restoringHistoryState;
+}
+
+// Interface interaction
+- (void) updateToolbarItem;
+- (IBAction) historyControlClicked:(NSSegmentedControl *)theControl;
+- (unsigned int) currentlySelectedView;
+
+// Adding or updating history entries
+- (void) updateHistoryEntries;
+
+// Loading history entries
+- (void) loadEntryAtPosition:(unsigned int)position;
+- (void) abortEntryLoad;
+
+@end
diff --git a/Source/SPHistoryController.m b/Source/SPHistoryController.m
new file mode 100644
index 00000000..fc6e03b9
--- /dev/null
+++ b/Source/SPHistoryController.m
@@ -0,0 +1,256 @@
+//
+// $Id: SPFieldEditorController.h 802 2009-06-03 20:46:57Z bibiko $
+//
+// SPHistoryController.h
+// sequel-pro
+//
+// Created by Rowan Beentje on July 23, 2009
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// More info at <http://code.google.com/p/sequel-pro/>
+
+#import "TableDocument.h"
+#import "TablesList.h"
+#import "SPHistoryController.h"
+
+
+@implementation SPHistoryController
+
+#pragma mark Setup and teardown
+
+/**
+ * Initialise by creating a blank history array
+ */
+- (id) init
+{
+ if (self = [super init]) {
+ history = [[NSMutableArray alloc] init];
+ historyPosition = NSNotFound;
+ restoringHistoryState = NO;
+ }
+ return self;
+}
+
+- (void) dealloc
+{
+ [history release];
+ [super dealloc];
+}
+
+#pragma mark -
+#pragma mark Interface interaction
+
+/**
+ * Updates the toolbar item to reflect the current history state and position
+ */
+- (void) updateToolbarItem
+{
+ BOOL backEnabled = NO;
+ BOOL forwardEnabled = NO;
+
+ // Set the active state of the segments if appropriate
+ if ([history count] && historyPosition > 0) backEnabled = YES;
+ if ([history count] && historyPosition + 1 < [history count]) forwardEnabled = YES;
+
+ [historyControl setEnabled:backEnabled forSegment:0];
+ [historyControl setEnabled:forwardEnabled forSegment:1];
+}
+
+/**
+ * Trigger a navigation action in response to a click
+ */
+- (IBAction) historyControlClicked:(NSSegmentedControl *)theControl
+{
+ switch ([theControl selectedSegment]) {
+
+ // Back button clicked:
+ case 0:
+ if (historyPosition == NSNotFound || !historyPosition) return;
+ [self loadEntryAtPosition:historyPosition - 1];
+ break;
+
+ // Forward button clicked:
+ case 1:
+ if (historyPosition == NSNotFound || historyPosition + 1 >= [history count]) return;
+ [self loadEntryAtPosition:historyPosition + 1];
+ break;
+ }
+}
+
+/**
+ * Retrieve the view that is currently selected from the database
+ */
+- (unsigned int) currentlySelectedView
+{
+ unsigned int theView = NSNotFound;
+
+ NSString *viewName = [[[theDocument valueForKey:@"tableTabView"] selectedTabViewItem] identifier];
+ if ([viewName isEqualToString:@"source"]) {
+ theView = SP_VIEW_STRUCTURE;
+ } else if ([viewName isEqualToString:@"content"]) {
+ theView = SP_VIEW_CONTENT;
+ } else if ([viewName isEqualToString:@"customQuery"]) {
+ theView = SP_VIEW_CUSTOMQUERY;
+ } else if ([viewName isEqualToString:@"status"]) {
+ theView = SP_VIEW_STATUS;
+ } else if ([viewName isEqualToString:@"relations"]) {
+ theView = SP_VIEW_RELATIONS;
+ }
+
+ return theView;
+}
+
+#pragma mark -
+#pragma mark Adding or updating history entries
+
+/**
+ * Call to store or update a history item for the document state. Checks against
+ * the latest stored details; if they match, a new history item is not created.
+ * This should therefore be called without worry of duplicates.
+ */
+- (void) updateHistoryEntries
+{
+
+ // Don't modify anything if we're in the process of restoring an old history state
+ if (restoringHistoryState) return;
+
+ // Work out the current document details
+ NSString *theDatabase = [theDocument database];
+ NSString *theTable = [theDocument table];
+ unsigned int theView = [self currentlySelectedView];
+
+ // Check for a duplicate against the current entry
+ if (historyPosition != NSNotFound) {
+ NSDictionary *currentHistoryItem = [history objectAtIndex:historyPosition];
+ if ([[currentHistoryItem objectForKey:@"database"] isEqualToString:theDatabase]
+ && [[currentHistoryItem objectForKey:@"table"] isEqualToString:theTable]
+ && [[currentHistoryItem objectForKey:@"view"] intValue] == theView)
+ {
+ return;
+ }
+ }
+
+ // If there's any items after the current history position, remove them
+ if (historyPosition != NSNotFound && historyPosition < [history count] - 1) {
+ [history removeObjectsInRange:NSMakeRange(historyPosition + 1, [history count] - historyPosition - 1)];
+
+ // Special case: if the last history item is currently active, and has no table,
+ // but the new selection does - delete the last entry, in order to replace it.
+ // This improves history flow.
+ } else if (historyPosition != NSNotFound && historyPosition == [history count] - 1
+ && [[[history objectAtIndex:historyPosition] objectForKey:@"database"] isEqualToString:theDatabase]
+ && ![[history objectAtIndex:historyPosition] objectForKey:@"table"])
+ {
+ [history removeLastObject];
+ }
+
+ // Construct and add the new history entry
+ NSMutableDictionary *newEntry = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+ theDatabase, @"database",
+ theTable, @"table",
+ [NSNumber numberWithInt:theView], @"view",
+ nil];
+ [history addObject:newEntry];
+ historyPosition = [history count] - 1;
+ [self updateToolbarItem];
+}
+
+#pragma mark -
+#pragma mark Loading history entries
+
+/**
+ * Load a history entry and attempt to return the interface to that state.
+ */
+- (void) loadEntryAtPosition:(unsigned int)position
+{
+
+ // Sanity check the input
+ if (position == NSNotFound || position < 0 || position >= [history count]) {
+ NSBeep();
+ return;
+ }
+
+ restoringHistoryState = YES;
+
+ // Update the position and extract the history entry
+ historyPosition = position;
+ NSDictionary *historyEntry = [history objectAtIndex:historyPosition];
+
+ // Check and set the database
+ if (![[theDocument database] isEqualToString:[historyEntry objectForKey:@"database"]]) {
+ NSPopUpButton *chooseDatabaseButton = [theDocument valueForKey:@"chooseDatabaseButton"];
+ [chooseDatabaseButton selectItemWithTitle:[historyEntry objectForKey:@"database"]];
+ [theDocument chooseDatabase:self];
+ if (![[theDocument database] isEqualToString:[historyEntry objectForKey:@"database"]]) {
+ return [self abortEntryLoad];
+ }
+ }
+
+ // Check and set the table
+ if ([historyEntry objectForKey:@"table"] && ![[theDocument table] isEqualToString:[historyEntry objectForKey:@"table"]]) {
+ TablesList *tablesListInstance = [theDocument valueForKey:@"tablesListInstance"];
+ NSArray *tables = [tablesListInstance tables];
+ if ([tables indexOfObject:[historyEntry objectForKey:@"table"]] == NSNotFound) {
+ return [self abortEntryLoad];
+ }
+ [[tablesListInstance valueForKey:@"tablesListView"] selectRowIndexes:[NSIndexSet indexSetWithIndex:[tables indexOfObject:[historyEntry objectForKey:@"table"]]] byExtendingSelection:NO];
+ if (![[theDocument table] isEqualToString:[historyEntry objectForKey:@"table"]]) {
+ return [self abortEntryLoad];
+ }
+ } else if (![historyEntry objectForKey:@"table"] && [theDocument table]) {
+ TablesList *tablesListInstance = [theDocument valueForKey:@"tablesListInstance"];
+ [[tablesListInstance valueForKey:@"tablesListView"] deselectAll:self];
+ }
+
+ // Check and set the view
+ if ([self currentlySelectedView] != [[historyEntry objectForKey:@"view"] intValue]) {
+ switch ([[historyEntry objectForKey:@"view"] intValue]) {
+ case SP_VIEW_STRUCTURE:
+ [theDocument viewStructure:self];
+ break;
+ case SP_VIEW_CONTENT:
+ [theDocument viewContent:self];
+ break;
+ case SP_VIEW_CUSTOMQUERY:
+ [theDocument viewQuery:self];
+ break;
+ case SP_VIEW_STATUS:
+ [theDocument viewStatus:self];
+ break;
+ case SP_VIEW_RELATIONS:
+ [theDocument viewRelations:self];
+ break;
+ }
+ if ([self currentlySelectedView] != [[historyEntry objectForKey:@"view"] intValue]) {
+ return [self abortEntryLoad];
+ }
+ }
+
+ restoringHistoryState = NO;
+ [self updateToolbarItem];
+}
+
+/**
+ * Convenience method for aborting history load - could at some point
+ * clean up the history list, show an alert, etc
+ */
+- (void) abortEntryLoad
+{
+ NSBeep();
+ restoringHistoryState = NO;
+}
+
+@end
diff --git a/Source/TableDocument.h b/Source/TableDocument.h
index 5cd9dc6c..97da96f9 100644
--- a/Source/TableDocument.h
+++ b/Source/TableDocument.h
@@ -46,6 +46,7 @@
IBOutlet id tableDataInstance;
IBOutlet id extendedTableInfoInstance;
IBOutlet id databaseDataInstance;
+ IBOutlet id spHistoryControllerInstance;
IBOutlet id spExportControllerInstance;
IBOutlet id tableWindow;
@@ -64,6 +65,7 @@
IBOutlet id databaseEncodingButton;
IBOutlet id addDatabaseButton;
IBOutlet id chooseDatabaseButton;
+ IBOutlet id historyControl;
IBOutlet id variablesTableView;
IBOutlet NSTabView *tableTabView;
diff --git a/Source/TableDocument.m b/Source/TableDocument.m
index 00c31a15..76e0337b 100644
--- a/Source/TableDocument.m
+++ b/Source/TableDocument.m
@@ -43,6 +43,7 @@
#import "MainController.h"
#import "SPExtendedTableInfo.h"
#import "SPConnectionController.h"
+#import "SPHistoryController.h"
#import "SPPreferenceController.h"
#import "SPPrintAccessory.h"
#import "QLPreviewPanel.h"
@@ -168,6 +169,7 @@
if ([connectionController database] && ![[connectionController database] isEqualToString:@""]) {
if (selectedDatabase) [selectedDatabase release], selectedDatabase = nil;
selectedDatabase = [[NSString alloc] initWithString:[connectionController database]];
+ [spHistoryControllerInstance updateHistoryEntries];
}
// Update the database list
@@ -416,6 +418,9 @@
[tablesListInstance setConnection:mySQLConnection];
[tableDumpInstance setConnection:mySQLConnection];
[tableWindow setTitle:[NSString stringWithFormat:@"(MySQL %@) %@/%@", mySQLVersion, [self name], [self database]]];
+
+ // Add a history entry
+ [spHistoryControllerInstance updateHistoryEntries];
}
/**
@@ -1550,6 +1555,7 @@
[tableTabView selectTabViewItemAtIndex:0];
[mainToolbar setSelectedItemIdentifier:@"SwitchToTableStructureToolbarItemIdentifier"];
+ [spHistoryControllerInstance updateHistoryEntries];
}
- (IBAction)viewContent:(id)sender
@@ -1563,6 +1569,7 @@
[tableTabView selectTabViewItemAtIndex:1];
[mainToolbar setSelectedItemIdentifier:@"SwitchToTableContentToolbarItemIdentifier"];
+ [spHistoryControllerInstance updateHistoryEntries];
}
- (IBAction)viewQuery:(id)sender
@@ -1583,6 +1590,7 @@
[tableTabView selectTabViewItemAtIndex:2];
[mainToolbar setSelectedItemIdentifier:@"SwitchToRunQueryToolbarItemIdentifier"];
+ [spHistoryControllerInstance updateHistoryEntries];
// Set the focus on the text field if no query has been run
if (![[customQueryTextView string] length]) [tableWindow makeFirstResponder:customQueryTextView];
@@ -1606,6 +1614,7 @@
[tableTabView selectTabViewItemAtIndex:3];
[mainToolbar setSelectedItemIdentifier:@"SwitchToTableInfoToolbarItemIdentifier"];
+ [spHistoryControllerInstance updateHistoryEntries];
}
- (IBAction)viewRelations:(id)sender
@@ -1626,6 +1635,7 @@
[tableTabView selectTabViewItemAtIndex:4];
[mainToolbar setSelectedItemIdentifier:@"SwitchToTableRelationsToolbarItemIdentifier"];
+ [spHistoryControllerInstance updateHistoryEntries];
}
@@ -1751,7 +1761,12 @@
chooseDatabaseToolbarItem = toolbarItem;
[self updateChooseDatabaseToolbarItemWidth];
}
-
+
+ } else if ([itemIdentifier isEqualToString:@"HistoryNavigationToolbarItemIdentifier"]) {
+ [toolbarItem setLabel:NSLocalizedString(@"History", @"toolbar item for navigation history")];
+ [toolbarItem setPaletteLabel:[toolbarItem label]];
+ [toolbarItem setView:historyControl];
+
} else if ([itemIdentifier isEqualToString:@"ToggleConsoleIdentifier"]) {
//set the text label to be displayed in the toolbar and customization palette
[toolbarItem setPaletteLabel:NSLocalizedString(@"Show/Hide Console", @"toolbar item for show/hide console")];
@@ -1847,6 +1862,7 @@
{
return [NSArray arrayWithObjects:
@"DatabaseSelectToolbarItemIdentifier",
+ @"HistoryNavigationToolbarItemIdentifier",
@"ToggleConsoleIdentifier",
@"ClearConsoleIdentifier",
@"FlushPrivilegesIdentifier",
diff --git a/Source/TablesList.h b/Source/TablesList.h
index 68578010..250f451f 100644
--- a/Source/TablesList.h
+++ b/Source/TablesList.h
@@ -25,6 +25,7 @@
#import <Cocoa/Cocoa.h>
#import <MCPKit/MCPKit.h>
+#import "SPHistoryController.h"
enum sp_table_types
{
@@ -54,6 +55,7 @@ enum sp_table_types
IBOutlet id tableDataInstance;
IBOutlet id extendedTableInfoInstance;
IBOutlet id databaseDataInstance;
+ IBOutlet SPHistoryController *spHistoryControllerInstance;
IBOutlet id tableWindow;
IBOutlet id copyTableSheet;
diff --git a/Source/TablesList.m b/Source/TablesList.m
index e5f4a35d..6d611306 100644
--- a/Source/TablesList.m
+++ b/Source/TablesList.m
@@ -1297,6 +1297,8 @@
[tableWindow setTitle:[NSString stringWithFormat:@"(MySQL %@) %@/%@", [tableDocumentInstance mySQLVersion],
[tableDocumentInstance name], [tableDocumentInstance database]]];
}
+
+ [spHistoryControllerInstance updateHistoryEntries];
}
#pragma mark -