aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMax <post@wickenrode.com>2014-10-12 22:41:36 +0200
committerMax <post@wickenrode.com>2014-10-12 22:41:36 +0200
commit0e4ad8eb9cddbbd755d55bb50f7707f1e8160121 (patch)
tree72c584ec63ee53895ffa99bc35240fa92d8f0b8c
parentf9ed97815c219939e7bc05eb92da62f508210a18 (diff)
downloadsequelpro-0e4ad8eb9cddbbd755d55bb50f7707f1e8160121.tar.gz
sequelpro-0e4ad8eb9cddbbd755d55bb50f7707f1e8160121.tar.bz2
sequelpro-0e4ad8eb9cddbbd755d55bb50f7707f1e8160121.zip
Add a "Go to Database" dialog
The dialog enables * searching for a database by name (substring matching), * using C&P to select databases * navigating to databases not in the database dropdown * faster keyboard-based navigation
-rw-r--r--Interfaces/English.lproj/GotoDatabaseDialog.xib117
-rw-r--r--Interfaces/English.lproj/MainMenu.xib105
-rw-r--r--Source/SPDatabaseDocument.h3
-rw-r--r--Source/SPDatabaseDocument.m19
-rw-r--r--Source/SPGotoDatabaseController.h86
-rw-r--r--Source/SPGotoDatabaseController.m223
-rw-r--r--sequel-pro.xcodeproj/project.pbxproj10
7 files changed, 504 insertions, 59 deletions
diff --git a/Interfaces/English.lproj/GotoDatabaseDialog.xib b/Interfaces/English.lproj/GotoDatabaseDialog.xib
new file mode 100644
index 00000000..310b74b0
--- /dev/null
+++ b/Interfaces/English.lproj/GotoDatabaseDialog.xib
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="5056" systemVersion="13E28" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
+ <dependencies>
+ <deployment defaultVersion="1060" identifier="macosx"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="5056"/>
+ </dependencies>
+ <objects>
+ <customObject id="-2" userLabel="File's Owner" customClass="SPGotoDatabaseController">
+ <connections>
+ <outlet property="cancelButton" destination="44U-6X-ZGG" id="dkD-wk-aid"/>
+ <outlet property="databaseListView" destination="cDW-lq-Q6e" id="aXN-gQ-VPQ"/>
+ <outlet property="okButton" destination="Qwd-4g-Aav" id="lhQ-gz-P3m"/>
+ <outlet property="searchField" destination="7dG-5r-Xs2" id="jrs-Y3-ixn"/>
+ <outlet property="window" destination="QvC-M9-y7g" id="3iD-lu-WNH"/>
+ </connections>
+ </customObject>
+ <customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
+ <customObject id="-3" userLabel="Application"/>
+ <window title="Go to Database" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" restorable="NO" oneShot="NO" releasedWhenClosed="NO" showsToolbarButton="NO" visibleAtLaunch="NO" animationBehavior="default" id="QvC-M9-y7g">
+ <windowStyleMask key="styleMask" titled="YES"/>
+ <rect key="contentRect" x="196" y="240" width="480" height="280"/>
+ <rect key="screenRect" x="0.0" y="0.0" width="1920" height="1178"/>
+ <value key="minSize" type="size" width="480" height="280"/>
+ <view key="contentView" id="EiT-Mj-1SZ">
+ <rect key="frame" x="0.0" y="0.0" width="480" height="280"/>
+ <autoresizingMask key="autoresizingMask"/>
+ <subviews>
+ <button verticalHuggingPriority="750" id="Qwd-4g-Aav">
+ <rect key="frame" x="407" y="13" width="59" height="32"/>
+ <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
+ <buttonCell key="cell" type="push" title="OK" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="K2E-vc-mDT">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+ <font key="font" metaFont="system"/>
+ <string key="keyEquivalent" base64-UTF8="YES">
+DQ
+</string>
+ </buttonCell>
+ <connections>
+ <action selector="okClicked:" target="-2" id="yNe-4p-Qs8"/>
+ </connections>
+ </button>
+ <button verticalHuggingPriority="750" id="44U-6X-ZGG">
+ <rect key="frame" x="14" y="13" width="82" height="32"/>
+ <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+ <buttonCell key="cell" type="push" title="Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="6cJ-4a-khl">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+ <font key="font" metaFont="system"/>
+ <string key="keyEquivalent" base64-UTF8="YES">
+Gw
+</string>
+ </buttonCell>
+ <connections>
+ <action selector="cancelClicked:" target="-2" id="HtW-wh-O9q"/>
+ </connections>
+ </button>
+ <searchField verticalHuggingPriority="750" id="7dG-5r-Xs2">
+ <rect key="frame" x="20" y="238" width="440" height="22"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
+ <searchFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" borderStyle="bezel" placeholderString="Database Name" usesSingleLineMode="YES" bezelStyle="round" sendsSearchStringImmediately="YES" id="3iD-8e-Wt2">
+ <font key="font" metaFont="system"/>
+ <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
+ </searchFieldCell>
+ <connections>
+ <action selector="searchChanged:" target="-2" id="keN-UZ-6QR"/>
+ <outlet property="delegate" destination="-2" id="DIs-zq-6Cv"/>
+ </connections>
+ </searchField>
+ <scrollView focusRingType="none" autohidesScrollers="YES" horizontalLineScroll="19" horizontalPageScroll="10" verticalLineScroll="19" verticalPageScroll="10" usesPredominantAxisScrolling="NO" id="LoZ-sS-bTj">
+ <rect key="frame" x="20" y="50" width="440" height="180"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <clipView key="contentView" id="ip2-JF-i6U">
+ <rect key="frame" x="1" y="1" width="438" height="178"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <subviews>
+ <tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" selectionHighlightStyle="sourceList" alternatingRowBackgroundColors="YES" columnReordering="NO" columnResizing="NO" multipleSelection="NO" autosaveColumns="NO" typeSelect="NO" id="cDW-lq-Q6e">
+ <rect key="frame" x="0.0" y="0.0" width="438" height="178"/>
+ <autoresizingMask key="autoresizingMask"/>
+ <size key="intercellSpacing" width="3" height="2"/>
+ <color key="backgroundColor" name="_sourceListBackgroundColor" catalog="System" colorSpace="catalog"/>
+ <color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
+ <tableColumns>
+ <tableColumn editable="NO" width="435" minWidth="40" maxWidth="1000" id="Ift-DE-ytF">
+ <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left" title="Database">
+ <font key="font" metaFont="smallSystem"/>
+ <color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" white="0.33333298560000002" alpha="1" colorSpace="calibratedWhite"/>
+ </tableHeaderCell>
+ <textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" refusesFirstResponder="YES" alignment="left" title="Text Cell" id="mE5-9u-hCv">
+ <font key="font" metaFont="system"/>
+ <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ <tableColumnResizingMask key="resizingMask" resizeWithTable="YES"/>
+ </tableColumn>
+ </tableColumns>
+ <connections>
+ <outlet property="dataSource" destination="-2" id="O6w-uT-xK7"/>
+ </connections>
+ </tableView>
+ </subviews>
+ <color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
+ </clipView>
+ <scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="YES" id="H6G-xb-0Tc">
+ <rect key="frame" x="1" y="164" width="423" height="15"/>
+ <autoresizingMask key="autoresizingMask"/>
+ </scroller>
+ <scroller key="verticalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="NO" id="GxF-Wp-RA1">
+ <rect key="frame" x="424" y="17" width="15" height="147"/>
+ <autoresizingMask key="autoresizingMask"/>
+ </scroller>
+ </scrollView>
+ </subviews>
+ </view>
+ </window>
+ </objects>
+</document>
diff --git a/Interfaces/English.lproj/MainMenu.xib b/Interfaces/English.lproj/MainMenu.xib
index f8d24d80..a8639839 100644
--- a/Interfaces/English.lproj/MainMenu.xib
+++ b/Interfaces/English.lproj/MainMenu.xib
@@ -1227,6 +1227,25 @@
<object class="NSMenu" key="NSSubmenu" id="762880388">
<string key="NSTitle">Database</string>
<array class="NSMutableArray" key="NSMenuItems">
+ <object class="NSMenuItem" id="859280893">
+ <reference key="NSMenu" ref="762880388"/>
+ <string key="NSTitle">Go to Database…</string>
+ <string key="NSKeyEquiv">d</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="325032718"/>
+ <reference key="NSMixedImage" ref="674471825"/>
+ </object>
+ <object class="NSMenuItem" id="346403677">
+ <reference key="NSMenu" ref="762880388"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="325032718"/>
+ <reference key="NSMixedImage" ref="674471825"/>
+ </object>
<object class="NSMenuItem" id="838091116">
<reference key="NSMenu" ref="762880388"/>
<string key="NSTitle">Add Database...</string>
@@ -3151,6 +3170,14 @@
<string key="id">BUY-hF-nKy</string>
</object>
<object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">showGotoDatabase:</string>
+ <reference key="source" ref="1005713010"/>
+ <reference key="destination" ref="859280893"/>
+ </object>
+ <string key="id">jS0-aP-Y7o</string>
+ </object>
+ <object class="IBConnectionRecord">
<object class="IBOutletConnection" key="connection">
<string key="label">delegate</string>
<reference key="source" ref="524643114"/>
@@ -4145,6 +4172,8 @@
<reference ref="1042638490"/>
<reference ref="1060677288"/>
<reference ref="607642194"/>
+ <reference ref="859280893"/>
+ <reference ref="346403677"/>
</array>
<reference key="parent" ref="19149132"/>
</object>
@@ -4733,6 +4762,16 @@
<reference key="object" ref="221903071"/>
<reference key="parent" ref="781540470"/>
</object>
+ <object class="IBObjectRecord">
+ <string key="id">8MG-hk-1qS</string>
+ <reference key="object" ref="859280893"/>
+ <reference key="parent" ref="762880388"/>
+ </object>
+ <object class="IBObjectRecord">
+ <string key="id">Yzp-Qk-v7Y</string>
+ <reference key="object" ref="346403677"/>
+ <reference key="parent" ref="762880388"/>
+ </object>
</array>
</object>
<dictionary class="NSMutableDictionary" key="flattenedProperties">
@@ -5266,6 +5305,7 @@
<boolean value="NO" key="864.showNotes"/>
<string key="865.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<boolean value="NO" key="865.showNotes"/>
+ <string key="8MG-hk-1qS.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="906.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<boolean value="NO" key="906.showNotes"/>
<string key="908.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
@@ -5362,6 +5402,7 @@
</object>
<string key="998.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<boolean value="NO" key="998.showNotes"/>
+ <string key="Yzp-Qk-v7Y.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="nXE-rI-RyI.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
</dictionary>
<dictionary class="NSMutableDictionary" key="unlocalizedProperties"/>
@@ -5372,47 +5413,6 @@
<object class="IBClassDescriber" key="IBDocument.Classes">
<array class="NSMutableArray" key="referencedPartialClassDescriptions">
<object class="IBPartialClassDescription">
- <string key="className">NSDocument</string>
- <dictionary class="NSMutableDictionary" key="actions">
- <string key="printDocument:">id</string>
- <string key="revertDocumentToSaved:">id</string>
- <string key="runPageLayout:">id</string>
- <string key="saveDocument:">id</string>
- <string key="saveDocumentAs:">id</string>
- <string key="saveDocumentTo:">id</string>
- </dictionary>
- <dictionary class="NSMutableDictionary" key="actionInfosByName">
- <object class="IBActionInfo" key="printDocument:">
- <string key="name">printDocument:</string>
- <string key="candidateClassName">id</string>
- </object>
- <object class="IBActionInfo" key="revertDocumentToSaved:">
- <string key="name">revertDocumentToSaved:</string>
- <string key="candidateClassName">id</string>
- </object>
- <object class="IBActionInfo" key="runPageLayout:">
- <string key="name">runPageLayout:</string>
- <string key="candidateClassName">id</string>
- </object>
- <object class="IBActionInfo" key="saveDocument:">
- <string key="name">saveDocument:</string>
- <string key="candidateClassName">id</string>
- </object>
- <object class="IBActionInfo" key="saveDocumentAs:">
- <string key="name">saveDocumentAs:</string>
- <string key="candidateClassName">id</string>
- </object>
- <object class="IBActionInfo" key="saveDocumentTo:">
- <string key="name">saveDocumentTo:</string>
- <string key="candidateClassName">id</string>
- </object>
- </dictionary>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">./Classes/NSDocument.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
<string key="className">NSTextView</string>
<dictionary class="NSMutableDictionary" key="actions">
<string key="doDecomposedStringWithCanonicalMapping:">id</string>
@@ -6877,6 +6877,7 @@
<string key="setDatabases:">id</string>
<string key="showCreateTableSyntax:">id</string>
<string key="showFilterTable:">id</string>
+ <string key="showGotoDatabase:">id</string>
<string key="showMySQLHelp:">id</string>
<string key="showNavigator:">id</string>
<string key="showServerProcesses:">id</string>
@@ -7044,6 +7045,10 @@
<string key="name">showFilterTable:</string>
<string key="candidateClassName">id</string>
</object>
+ <object class="IBActionInfo" key="showGotoDatabase:">
+ <string key="name">showGotoDatabase:</string>
+ <string key="candidateClassName">id</string>
+ </object>
<object class="IBActionInfo" key="showMySQLHelp:">
<string key="name">showMySQLHelp:</string>
<string key="candidateClassName">id</string>
@@ -9728,24 +9733,6 @@
<string key="minorKey">./Classes/SUUpdater.h</string>
</object>
</object>
- <object class="IBPartialClassDescription">
- <string key="className">WebView</string>
- <object class="NSMutableDictionary" key="actions">
- <string key="NS.key.0">reloadFromOrigin:</string>
- <string key="NS.object.0">id</string>
- </object>
- <object class="NSMutableDictionary" key="actionInfosByName">
- <string key="NS.key.0">reloadFromOrigin:</string>
- <object class="IBActionInfo" key="NS.object.0">
- <string key="name">reloadFromOrigin:</string>
- <string key="candidateClassName">id</string>
- </object>
- </object>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">./Classes/WebView.h</string>
- </object>
- </object>
</array>
</object>
<int key="IBDocument.localizationMode">0</int>
diff --git a/Source/SPDatabaseDocument.h b/Source/SPDatabaseDocument.h
index 218f3bc7..a67619e8 100644
--- a/Source/SPDatabaseDocument.h
+++ b/Source/SPDatabaseDocument.h
@@ -55,6 +55,7 @@
@class SPDatabaseStructure;
@class SPMySQLConnection;
@class SPCharsetCollationHelper;
+@class SPGotoDatabaseController;
#import "SPDatabaseContentViewDelegate.h"
#import "SPConnectionControllerDelegateProtocol.h"
@@ -280,6 +281,7 @@
BOOL windowTitleStatusViewIsVisible;
#endif
SPDatabaseStructure *databaseStructureRetrieval;
+ SPGotoDatabaseController *gotoDatabaseController;
}
#ifdef SP_CODA /* ivars */
@@ -352,6 +354,7 @@
- (IBAction)showServerVariables:(id)sender;
- (IBAction)showServerProcesses:(id)sender;
- (IBAction)openCurrentConnectionInNewWindow:(id)sender;
+- (IBAction)showGotoDatabase:(id)sender;
#endif
- (NSArray *)allDatabaseNames;
- (NSArray *)allSystemDatabaseNames;
diff --git a/Source/SPDatabaseDocument.m b/Source/SPDatabaseDocument.m
index 330716c3..9a736f90 100644
--- a/Source/SPDatabaseDocument.m
+++ b/Source/SPDatabaseDocument.m
@@ -109,6 +109,7 @@ enum {
#endif
#import "SPCharsetCollationHelper.h"
+#import "SPGotoDatabaseController.h"
#import <SPMySQL/SPMySQL.h>
@@ -206,6 +207,7 @@ static NSString *SPAlterDatabaseAction = @"SPAlterDatabase";
mySQLVersion = nil;
allDatabases = nil;
allSystemDatabases = nil;
+ gotoDatabaseController = nil;
#ifndef SP_CODA /* init ivars */
mainToolbar = nil;
@@ -1131,6 +1133,22 @@ static NSString *SPAlterDatabaseAction = @"SPAlterDatabase";
return [[SPNavigatorController sharedNavigatorController] allSchemaKeysForConnection:[self connectionID]];
}
+- (IBAction)showGotoDatabase:(id)sender
+{
+ if(!gotoDatabaseController) {
+ gotoDatabaseController = [[SPGotoDatabaseController alloc] init];
+ }
+
+ NSMutableArray *dbList = [[NSMutableArray alloc] init];
+ [dbList addObjectsFromArray:[self allSystemDatabaseNames]];
+ [dbList addObjectsFromArray:[self allDatabaseNames]];
+ [gotoDatabaseController setDatabaseList:[dbList autorelease]];
+
+ if([gotoDatabaseController runModal]) {
+ [self selectDatabase:[gotoDatabaseController selectedDatabase] item:nil];
+ }
+}
+
#ifndef SP_CODA /* console and navigator methods */
#pragma mark -
@@ -6269,6 +6287,7 @@ static NSString *SPAlterDatabaseAction = @"SPAlterDatabase";
[allDatabases release];
[allSystemDatabases release];
+ [gotoDatabaseController release];
#ifndef SP_CODA /* dealloc ivars */
[undoManager release];
[printWebView release];
diff --git a/Source/SPGotoDatabaseController.h b/Source/SPGotoDatabaseController.h
new file mode 100644
index 00000000..99dfc289
--- /dev/null
+++ b/Source/SPGotoDatabaseController.h
@@ -0,0 +1,86 @@
+//
+// GotoDatbaseController.h
+// sequel-pro
+//
+// Created by Max Lohrmann on 12.10.14.
+// Copyright (c) 2014 Max Lohrmann. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+//
+// More info at <https://github.com/sequelpro/sequelpro>
+
+#import <Cocoa/Cocoa.h>
+@class SPDatabaseDocument;
+
+/**
+ * This class provides a dialog with a single-column table view and a
+ * search field. It can be used for finding databases by name and/or faster,
+ * keyboard-based navigation between databases. The dialog also enables
+ * jumping to a database by C&P-ing its full name.
+ */
+@interface SPGotoDatabaseController : NSWindowController <NSTableViewDataSource,NSControlTextEditingDelegate> {
+ IBOutlet NSSearchField *searchField;
+ IBOutlet NSButton *okButton;
+ IBOutlet NSButton *cancelButton;
+ IBOutlet NSTableView *databaseListView;
+
+ NSMutableArray *unfilteredList;
+ NSMutableArray *filteredList;
+ BOOL isFiltered;
+}
+
+/**
+ * Specifies whether custom names (i.e. names that were not in the list supplied
+ * by setDatabaseList:) will be allowed. This is useful if it has to be assumed
+ * that the list of databases is not exhaustive (eg. databases added after fetching
+ * the database list).
+ */
+@property BOOL allowCustomNames;
+
+/**
+ * Set the list of databases the user can pick from.
+ * @param list An array of NSStrings
+ *
+ * This method must be called before runModal. The list will not be updated
+ * when the dialog is on screen.
+ */
+- (void)setDatabaseList:(NSArray *)list;
+
+/**
+ * Retrieve the user selection.
+ * @return The selected database or nil, if there is no selection
+ *
+ * This method retrieves the database selected by the user. Note that this is
+ * not neccesarily one of the objects which were passed in, if allowCustomNames
+ * is enabled. The return value of this function is undefined after calling
+ * setDatabaseList:!
+ */
+- (NSString *)selectedDatabase;
+
+/**
+ * Starts displaying the dialog as application modal.
+ * @return YES if the user pressed "OK", NO otherwise
+ *
+ * This method will only return once the dialog was closed again.
+ */
+- (BOOL)runModal;
+@end
diff --git a/Source/SPGotoDatabaseController.m b/Source/SPGotoDatabaseController.m
new file mode 100644
index 00000000..0c6cbef0
--- /dev/null
+++ b/Source/SPGotoDatabaseController.m
@@ -0,0 +1,223 @@
+//
+// GotoDatbaseController.m
+// sequel-pro
+//
+// Created by Max Lohrmann on 12.10.14.
+// Copyright (c) 2014 Max Lohrmann. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+//
+// More info at <https://github.com/sequelpro/sequelpro>
+
+#import "SPGotoDatabaseController.h"
+#import "SPDatabaseDocument.h"
+
+@interface SPGotoDatabaseController (Private)
+- (void)_buildHightlightedFilterList:(NSString *)filter didFindExactMatch:(BOOL *)exactMatch;
+
+- (IBAction)okClicked:(id)sender;
+- (IBAction)cancelClicked:(id)sender;
+- (IBAction)searchChanged:(id)sender;
+@end
+
+@implementation SPGotoDatabaseController
+
+- (id)init
+{
+ self = [super initWithWindowNibName:@"GotoDatabaseDialog"];
+ if (self) {
+ unfilteredList = [[NSMutableArray alloc] init];
+ filteredList = [[NSMutableArray alloc] init];
+ isFiltered = NO;
+ [self setAllowCustomNames:YES];
+ }
+ return self;
+}
+
+#pragma mark -
+#pragma mark IBAction
+
+- (IBAction)okClicked:(id)sender
+{
+ [NSApp stopModalWithCode:YES];
+ [[self window] orderOut:nil];
+}
+
+- (IBAction)cancelClicked:(id)sender
+{
+ [NSApp stopModalWithCode:NO];
+ [[self window] orderOut:nil];
+}
+
+- (IBAction)searchChanged:(id)sender
+{
+ [filteredList removeAllObjects];
+ NSString *newFilter = [searchField stringValue];
+ if(!newFilter || [newFilter isEqualToString:@""]) {
+ isFiltered = NO;
+ }
+ else {
+ isFiltered = YES;
+ BOOL exactMatch = NO;
+ [self _buildHightlightedFilterList:newFilter didFindExactMatch:&exactMatch];
+ //always add the search string to the end of the list (in case the user
+ //wants to switch to a DB not in the list) unless there was an exact match
+ if([self allowCustomNames] && !exactMatch) {
+ NSMutableAttributedString *searchValue = [[NSMutableAttributedString alloc] initWithString:newFilter];
+ [searchValue applyFontTraits:NSItalicFontMask range:NSMakeRange(0, [newFilter length])];
+ [filteredList addObject:[searchValue autorelease]];
+ }
+ }
+ [databaseListView reloadData];
+ //ensure we have a selection
+ if([databaseListView selectedRow] < 0)
+ [databaseListView selectRowIndexes:[NSIndexSet indexSetWithIndex:0] byExtendingSelection:NO];
+
+ [okButton setEnabled:([databaseListView selectedRow] >= 0)];
+}
+
+#pragma mark -
+#pragma mark Public
+
+- (NSString *)selectedDatabase {
+ NSInteger row = [databaseListView selectedRow];
+ id attrValue;
+ if(isFiltered) {
+ attrValue = [filteredList objectOrNilAtIndex:row];
+ }
+ else {
+ attrValue = [unfilteredList objectOrNilAtIndex:row];
+ }
+ if([attrValue isKindOfClass:[NSAttributedString class]])
+ return [attrValue string];
+ return attrValue;
+}
+
+- (void)setDatabaseList:(NSArray *)list
+{
+ //update list of databases
+ [unfilteredList removeAllObjects];
+ [unfilteredList addObjectsFromArray:list];
+}
+
+- (BOOL)runModal
+{
+ //NSWindowController is lazy with loading nibs
+ [self window];
+
+ //reset the search field
+ [searchField setStringValue:@""];
+ [self searchChanged:nil];
+ //give focus to search field
+ [[self window] makeFirstResponder:searchField];
+ //start modal dialog
+ return [NSApp runModalForWindow:[self window]];
+}
+
+#pragma mark -
+#pragma mark Private
+
+- (void)_buildHightlightedFilterList:(NSString *)filter didFindExactMatch:(BOOL *)exactMatch
+{
+ NSDictionary *attrs = [[NSDictionary alloc] initWithObjectsAndKeys:
+ [NSColor colorWithCalibratedRed:249/255.0 green:247/255.0 blue:62/255.0 alpha:0.5],NSBackgroundColorAttributeName,
+ [NSColor colorWithCalibratedRed:180/255.0 green:164/255.0 blue:31/255.0 alpha:1.0],NSUnderlineColorAttributeName,
+ [NSNumber numberWithInt:NSUnderlineStyleSingle],NSUnderlineStyleAttributeName,
+ nil];
+
+ for(NSString *db in unfilteredList) {
+ NSRange match = [db rangeOfString:filter];
+ if(match.location == NSNotFound)
+ continue;
+ //check for exact match?
+ if(exactMatch && !*exactMatch) {
+ if(match.location == 0 && match.length == [db length])
+ *exactMatch = YES;
+ }
+
+ NSMutableAttributedString *attrMatch = [[NSMutableAttributedString alloc] initWithString:db];
+ [attrMatch setAttributes:attrs range:match];
+ [filteredList addObject:[attrMatch autorelease]];
+ }
+
+ [attrs release];
+}
+
+#pragma mark -
+#pragma mark NSTableViewDataSource
+
+- (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView
+{
+ if(!isFiltered) {
+ return [unfilteredList count];
+ }
+ else {
+ return [filteredList count];
+ }
+}
+
+- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex
+{
+ if(!isFiltered)
+ return [unfilteredList objectAtIndex:rowIndex];
+ else
+ return [filteredList objectAtIndex:rowIndex];
+}
+
+#pragma mark -
+#pragma mark NSControlTextEditingDelegate
+
+- (BOOL)control:(NSControl *)control textView:(NSTextView *)fieldEditor doCommandBySelector:(SEL)commandSelector
+{
+ //the ESC key will usually clear the search field. we want to close the dialog
+ if(commandSelector == @selector(cancelOperation:)) {
+ [cancelButton performClick:control];
+ return YES;
+ }
+ //arrow down/up will usually go to start/end of the text field. we want to change the selected table row.
+ if(commandSelector == @selector(moveDown:)) {
+ [databaseListView selectRowIndexes:[NSIndexSet indexSetWithIndex:([databaseListView selectedRow]+1)] byExtendingSelection:NO];
+ return YES;
+ }
+ if(commandSelector == @selector(moveUp:)) {
+ [databaseListView selectRowIndexes:[NSIndexSet indexSetWithIndex:([databaseListView selectedRow]-1)] byExtendingSelection:NO];
+ return YES;
+ }
+ //forward return to OK button (enter will not be caught by search field)
+ if(commandSelector == @selector(insertNewline:)) {
+ [okButton performClick:control];
+ return YES;
+ }
+
+ return NO;
+}
+
+#pragma mark -
+
+- (void)dealloc
+{
+ [unfilteredList release], unfilteredList = nil;
+ [filteredList release], filteredList = nil;
+ [super dealloc];
+}
+
+@end
diff --git a/sequel-pro.xcodeproj/project.pbxproj b/sequel-pro.xcodeproj/project.pbxproj
index 073ad76f..0014bc2f 100644
--- a/sequel-pro.xcodeproj/project.pbxproj
+++ b/sequel-pro.xcodeproj/project.pbxproj
@@ -179,6 +179,8 @@
4DECC48F0EC2B436008D359E /* Sparkle.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = 4DECC3320EC2A170008D359E /* Sparkle.framework */; };
4DECC4910EC2B436008D359E /* Growl.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = 4DECC3340EC2A170008D359E /* Growl.framework */; };
501B1D181728A3DA0017C92E /* SPCharsetCollationHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 501B1D171728A3DA0017C92E /* SPCharsetCollationHelper.m */; };
+ 50A9F8AD19EAD4860053E571 /* GotoDatabaseDialog.xib in Resources */ = {isa = PBXBuildFile; fileRef = 50A9F8AC19EAD4860053E571 /* GotoDatabaseDialog.xib */; };
+ 50A9F8B119EAD4B90053E571 /* SPGotoDatabaseController.m in Sources */ = {isa = PBXBuildFile; fileRef = 50A9F8B019EAD4B90053E571 /* SPGotoDatabaseController.m */; };
50E217B318174246009D3580 /* SPColorSelectorView.m in Sources */ = {isa = PBXBuildFile; fileRef = 50E217B218174246009D3580 /* SPColorSelectorView.m */; };
50E217B618174280009D3580 /* SPFavoriteColorSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = 50E217B518174280009D3580 /* SPFavoriteColorSupport.m */; };
5806B76411A991EC00813A88 /* SPDocumentController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5806B76311A991EC00813A88 /* SPDocumentController.m */; };
@@ -879,6 +881,9 @@
4DECC3340EC2A170008D359E /* Growl.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Growl.framework; path = Frameworks/Growl.framework; sourceTree = "<group>"; };
501B1D161728A3DA0017C92E /* SPCharsetCollationHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SPCharsetCollationHelper.h; sourceTree = "<group>"; };
501B1D171728A3DA0017C92E /* SPCharsetCollationHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SPCharsetCollationHelper.m; sourceTree = "<group>"; };
+ 50A9F8AC19EAD4860053E571 /* GotoDatabaseDialog.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = GotoDatabaseDialog.xib; path = English.lproj/GotoDatabaseDialog.xib; sourceTree = "<group>"; };
+ 50A9F8AF19EAD4B90053E571 /* SPGotoDatabaseController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SPGotoDatabaseController.h; sourceTree = "<group>"; };
+ 50A9F8B019EAD4B90053E571 /* SPGotoDatabaseController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SPGotoDatabaseController.m; sourceTree = "<group>"; };
50E217B118174246009D3580 /* SPColorSelectorView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SPColorSelectorView.h; sourceTree = "<group>"; };
50E217B218174246009D3580 /* SPColorSelectorView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SPColorSelectorView.m; sourceTree = "<group>"; };
50E217B418174280009D3580 /* SPFavoriteColorSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SPFavoriteColorSupport.h; sourceTree = "<group>"; };
@@ -1583,6 +1588,8 @@
17846B9D170C95D800414499 /* Process List */,
17381853151FB29C0078FFE2 /* User Manager */,
1713C73D140D88D400CFD461 /* Query Controller */,
+ 50A9F8AF19EAD4B90053E571 /* SPGotoDatabaseController.h */,
+ 50A9F8B019EAD4B90053E571 /* SPGotoDatabaseController.m */,
);
name = "Subview Controllers";
sourceTree = "<group>";
@@ -2202,6 +2209,7 @@
1792C13010AD752100ABE758 /* DatabaseServerVariables.xib */,
58C3507310B9ADEA00D37E14 /* ContentPaginationView.xib */,
17A7773611C52E61001E27B4 /* IndexesView.xib */,
+ 50A9F8AC19EAD4860053E571 /* GotoDatabaseDialog.xib */,
);
path = Interfaces;
sourceTree = "<group>";
@@ -2914,6 +2922,7 @@
C9AD7C7C1676158C00234EEE /* toolbar-switch-to-sql@2x.png in Resources */,
C9AD7C7F167619B400234EEE /* button_refresh.png in Resources */,
C9AD7C80167619B400234EEE /* button_refresh@2x.png in Resources */,
+ 50A9F8AD19EAD4860053E571 /* GotoDatabaseDialog.xib in Resources */,
C9AD7C8316761B3300234EEE /* button_action.png in Resources */,
C9AD7C8416761B3300234EEE /* button_action@2x.png in Resources */,
C9AD7C891676204300234EEE /* button_info_pane_hide.png in Resources */,
@@ -3085,6 +3094,7 @@
17E6415A0EF01EF6001BC333 /* SPDatabaseDocument.m in Sources */,
17E6415B0EF01EF6001BC333 /* SPDataImport.m in Sources */,
17E6415C0EF01EF6001BC333 /* SPTableStructure.m in Sources */,
+ 50A9F8B119EAD4B90053E571 /* SPGotoDatabaseController.m in Sources */,
17E641640EF01F15001BC333 /* SPTableInfo.m in Sources */,
17E641650EF01F15001BC333 /* SPTablesList.m in Sources */,
17E6416C0EF01F37001BC333 /* ImageAndTextCell.m in Sources */,