aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrowanbeentje <rowan@beent.je>2012-07-23 00:35:01 +0000
committerrowanbeentje <rowan@beent.je>2012-07-23 00:35:01 +0000
commitea1516eeb991cedd2ea8d86d65fef4b102996b2b (patch)
treed2c128b5ad0f68b974e3c5e2a44c1c49fd33ce7f
parent78b52f5a0cea1fc1d0c944f5408e7ef41d0ca2d6 (diff)
downloadsequelpro-ea1516eeb991cedd2ea8d86d65fef4b102996b2b.tar.gz
sequelpro-ea1516eeb991cedd2ea8d86d65fef4b102996b2b.tar.bz2
sequelpro-ea1516eeb991cedd2ea8d86d65fef4b102996b2b.zip
- Add a new SPSplitView class, intended to replace all BWSplitViews and so allow us to remove BWToolKit. Supports constraints and animated collapsible subviews configured in code, fixes crashes and exceptions if a window is closed while animations are taking place or scheduled to take place.
- Replace the two vertical splitters in the table list (the filter splitter, and the table info splitter) with SPSplitView implementations as a test - Add a helper method in the new SPDateAdditions
-rw-r--r--Interfaces/English.lproj/DBView.xib443
-rw-r--r--Resources/English.lproj/Localizable.stringsbin232178 -> 231846 bytes
-rw-r--r--Source/SPConnectionHandler.m2
-rw-r--r--Source/SPDatabaseDocument.h2
-rw-r--r--Source/SPDatabaseDocument.m21
-rw-r--r--Source/SPDateAdditions.h37
-rw-r--r--Source/SPDateAdditions.m53
-rw-r--r--Source/SPSplitView.h71
-rw-r--r--Source/SPSplitView.m1094
-rw-r--r--Source/SPTableInfo.h1
-rw-r--r--Source/SPTablesList.h9
-rw-r--r--Source/SPTablesList.m71
-rw-r--r--sequel-pro.xcodeproj/project.pbxproj12
13 files changed, 1515 insertions, 301 deletions
diff --git a/Interfaces/English.lproj/DBView.xib b/Interfaces/English.lproj/DBView.xib
index 1d553921..155a42f8 100644
--- a/Interfaces/English.lproj/DBView.xib
+++ b/Interfaces/English.lproj/DBView.xib
@@ -23,8 +23,8 @@
</object>
<object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
<bool key="EncodedWithXMLCoder">YES</bool>
+ <integer value="6266"/>
<integer value="5323"/>
- <integer value="6033"/>
</object>
<object class="NSArray" key="IBDocument.PluginDependencies">
<bool key="EncodedWithXMLCoder">YES</bool>
@@ -57,7 +57,7 @@
<int key="NSvFlags">274</int>
<object class="NSMutableArray" key="NSSubviews">
<bool key="EncodedWithXMLCoder">YES</bool>
- <object class="BWCustomView" id="1053680279">
+ <object class="NSView" id="1053680279">
<reference key="NSNextResponder" ref="162770193"/>
<int key="NSvFlags">272</int>
<object class="NSMutableArray" key="NSSubviews">
@@ -348,20 +348,20 @@
<reference key="NSSuperview" ref="28219887"/>
<bool key="NSEnabled">YES</bool>
<object class="BWAnchoredButtonCell" key="NSCell" id="708016222">
- <int key="NSCellFlags">-2080244224</int>
+ <int key="NSCellFlags">67239424</int>
<int key="NSCellFlags2">134348800</int>
<string key="NSContents"/>
<reference key="NSSupport" ref="26"/>
<reference key="NSControlView" ref="57416393"/>
<int key="NSButtonFlags">-926662401</int>
<int key="NSButtonFlags2">163</int>
- <object class="NSCustomResource" key="NSNormalImage" id="230512564">
+ <object class="NSCustomResource" key="NSNormalImage" id="367969719">
<string key="NSClassName">NSImage</string>
- <string key="NSResourceName">button_pane_show_icon</string>
+ <string key="NSResourceName">button_pane_hide_icon</string>
</object>
- <object class="NSCustomResource" key="NSAlternateImage" id="6531">
+ <object class="NSCustomResource" key="NSAlternateImage" id="359449987">
<string key="NSClassName">NSImage</string>
- <string key="NSResourceName">button_pane_hide_icon</string>
+ <string key="NSResourceName">button_pane_show_icon</string>
</object>
<string key="NSAlternateContents"/>
<string key="NSKeyEquivalent"/>
@@ -377,104 +377,26 @@
<bool key="BWABBHandleIsRightAligned">NO</bool>
<int key="BWABBSelectedIndex">0</int>
</object>
- <object class="BWSplitView" id="298095498">
+ <object class="NSSplitView" id="298095498">
<reference key="NSNextResponder" ref="1053680279"/>
<int key="NSvFlags">274</int>
<object class="NSMutableArray" key="NSSubviews">
<bool key="EncodedWithXMLCoder">YES</bool>
- <object class="BWCustomView" id="131633443">
+ <object class="NSView" id="131633443">
<reference key="NSNextResponder" ref="298095498"/>
<int key="NSvFlags">274</int>
<object class="NSMutableArray" key="NSSubviews">
<bool key="EncodedWithXMLCoder">YES</bool>
- <object class="BWSplitView" id="213762440">
+ <object class="NSSplitView" id="213762440">
<reference key="NSNextResponder" ref="131633443"/>
<int key="NSvFlags">274</int>
<object class="NSMutableArray" key="NSSubviews">
<bool key="EncodedWithXMLCoder">YES</bool>
- <object class="BWCustomView" id="801427893">
+ <object class="NSView" id="801427893">
<reference key="NSNextResponder" ref="213762440"/>
- <int key="NSvFlags">288</int>
+ <int key="NSvFlags">258</int>
<object class="NSMutableArray" key="NSSubviews">
<bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSSearchField" id="727834078">
- <reference key="NSNextResponder" ref="801427893"/>
- <int key="NSvFlags">290</int>
- <string key="NSFrame">{{5, 2}, {204, 19}}</string>
- <reference key="NSSuperview" ref="801427893"/>
- <bool key="NSEnabled">YES</bool>
- <object class="NSSearchFieldCell" key="NSCell" id="134854992">
- <int key="NSCellFlags">343014976</int>
- <int key="NSCellFlags2">268567552</int>
- <string key="NSContents"/>
- <reference key="NSSupport" ref="26"/>
- <reference key="NSControlView" ref="727834078"/>
- <bool key="NSDrawsBackground">YES</bool>
- <int key="NSTextBezelStyle">1</int>
- <object class="NSColor" key="NSBackgroundColor" id="480189472">
- <int key="NSColorSpace">6</int>
- <string key="NSCatalogName">System</string>
- <string key="NSColorName">textBackgroundColor</string>
- <object class="NSColor" key="NSColor" id="449903125">
- <int key="NSColorSpace">3</int>
- <bytes key="NSWhite">MQA</bytes>
- </object>
- </object>
- <object class="NSColor" key="NSTextColor" id="454249633">
- <int key="NSColorSpace">6</int>
- <string key="NSCatalogName">System</string>
- <string key="NSColorName">controlTextColor</string>
- <object class="NSColor" key="NSColor" id="304829493">
- <int key="NSColorSpace">3</int>
- <bytes key="NSWhite">MAA</bytes>
- </object>
- </object>
- <object class="NSButtonCell" key="NSSearchButtonCell">
- <int key="NSCellFlags">130560</int>
- <int key="NSCellFlags2">0</int>
- <string key="NSContents">search</string>
- <reference key="NSControlView" ref="727834078"/>
- <string key="NSAction">_searchFieldSearch:</string>
- <reference key="NSTarget" ref="134854992"/>
- <int key="NSButtonFlags">138690815</int>
- <int key="NSButtonFlags2">0</int>
- <string key="NSKeyEquivalent"/>
- <int key="NSPeriodicDelay">400</int>
- <int key="NSPeriodicInterval">75</int>
- </object>
- <object class="NSButtonCell" key="NSCancelButtonCell">
- <int key="NSCellFlags">130560</int>
- <int key="NSCellFlags2">0</int>
- <string key="NSContents">clear</string>
- <object class="NSMutableArray" key="NSAccessibilityOverriddenAttributes">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSMutableDictionary">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>AXDescription</string>
- <string>NSAccessibilityEncodedAttributesValueType</string>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>cancel</string>
- <integer value="1"/>
- </object>
- </object>
- </object>
- <reference key="NSControlView" ref="727834078"/>
- <string key="NSAction">_searchFieldCancel:</string>
- <reference key="NSTarget" ref="134854992"/>
- <int key="NSButtonFlags">138690815</int>
- <int key="NSButtonFlags2">0</int>
- <string key="NSKeyEquivalent"/>
- <int key="NSPeriodicDelay">400</int>
- <int key="NSPeriodicInterval">75</int>
- </object>
- <int key="NSMaximumRecents">255</int>
- <bytes key="NSSearchFieldFlags">CAAAAA</bytes>
- </object>
- </object>
<object class="NSScrollView" id="607475905">
<reference key="NSNextResponder" ref="801427893"/>
<int key="NSvFlags">4386</int>
@@ -515,7 +437,10 @@
<int key="NSColorSpace">6</int>
<string key="NSCatalogName">System</string>
<string key="NSColorName">headerTextColor</string>
- <reference key="NSColor" ref="304829493"/>
+ <object class="NSColor" key="NSColor" id="304829493">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MAA</bytes>
+ </object>
</object>
</object>
<object class="NSTextFieldCell" key="NSDataCell" id="849848233">
@@ -533,7 +458,12 @@
<bytes key="NSWhite">MC42NjY2NjY2NjY3AA</bytes>
</object>
</object>
- <reference key="NSTextColor" ref="454249633"/>
+ <object class="NSColor" key="NSTextColor" id="454249633">
+ <int key="NSColorSpace">6</int>
+ <string key="NSCatalogName">System</string>
+ <string key="NSColorName">controlTextColor</string>
+ <reference key="NSColor" ref="304829493"/>
+ </object>
</object>
<int key="NSResizingMask">3</int>
<bool key="NSIsResizeable">YES</bool>
@@ -620,14 +550,83 @@
<reference key="NSContentView" ref="494991824"/>
<bytes key="NSScrollAmts">QSAAAEEgAABBmAAAQZgAAA</bytes>
</object>
+ <object class="NSSearchField" id="727834078">
+ <reference key="NSNextResponder" ref="801427893"/>
+ <int key="NSvFlags">290</int>
+ <string key="NSFrame">{{5, 2}, {204, 19}}</string>
+ <reference key="NSSuperview" ref="801427893"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSSearchFieldCell" key="NSCell" id="134854992">
+ <int key="NSCellFlags">343014976</int>
+ <int key="NSCellFlags2">268567552</int>
+ <string key="NSContents"/>
+ <reference key="NSSupport" ref="26"/>
+ <reference key="NSControlView" ref="727834078"/>
+ <bool key="NSDrawsBackground">YES</bool>
+ <int key="NSTextBezelStyle">1</int>
+ <object class="NSColor" key="NSBackgroundColor" id="480189472">
+ <int key="NSColorSpace">6</int>
+ <string key="NSCatalogName">System</string>
+ <string key="NSColorName">textBackgroundColor</string>
+ <object class="NSColor" key="NSColor" id="449903125">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MQA</bytes>
+ </object>
+ </object>
+ <reference key="NSTextColor" ref="454249633"/>
+ <object class="NSButtonCell" key="NSSearchButtonCell">
+ <int key="NSCellFlags">130560</int>
+ <int key="NSCellFlags2">0</int>
+ <string key="NSContents">search</string>
+ <reference key="NSControlView" ref="727834078"/>
+ <string key="NSAction">_searchFieldSearch:</string>
+ <reference key="NSTarget" ref="134854992"/>
+ <int key="NSButtonFlags">138690815</int>
+ <int key="NSButtonFlags2">0</int>
+ <string key="NSKeyEquivalent"/>
+ <int key="NSPeriodicDelay">400</int>
+ <int key="NSPeriodicInterval">75</int>
+ </object>
+ <object class="NSButtonCell" key="NSCancelButtonCell">
+ <int key="NSCellFlags">130560</int>
+ <int key="NSCellFlags2">0</int>
+ <string key="NSContents">clear</string>
+ <object class="NSMutableArray" key="NSAccessibilityOverriddenAttributes">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMutableDictionary">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>AXDescription</string>
+ <string>NSAccessibilityEncodedAttributesValueType</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>cancel</string>
+ <integer value="1"/>
+ </object>
+ </object>
+ </object>
+ <reference key="NSControlView" ref="727834078"/>
+ <string key="NSAction">_searchFieldCancel:</string>
+ <reference key="NSTarget" ref="134854992"/>
+ <int key="NSButtonFlags">138690815</int>
+ <int key="NSButtonFlags2">0</int>
+ <string key="NSKeyEquivalent"/>
+ <int key="NSPeriodicDelay">400</int>
+ <int key="NSPeriodicInterval">75</int>
+ </object>
+ <int key="NSMaximumRecents">255</int>
+ <bytes key="NSSearchFieldFlags">CAAAAA</bytes>
+ </object>
+ </object>
</object>
<string key="NSFrameSize">{214, 26}</string>
<reference key="NSSuperview" ref="213762440"/>
- <string key="NSClassName">NSView</string>
</object>
- <object class="BWCustomView" id="1017775084">
+ <object class="NSView" id="1017775084">
<reference key="NSNextResponder" ref="213762440"/>
- <int key="NSvFlags">272</int>
+ <int key="NSvFlags">274</int>
<object class="NSMutableArray" key="NSSubviews">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSScrollView" id="233472824">
@@ -747,44 +746,17 @@
</object>
<string key="NSFrame">{{0, 27}, {214, 352}}</string>
<reference key="NSSuperview" ref="213762440"/>
- <string key="NSClassName">NSView</string>
</object>
</object>
<string key="NSFrameSize">{214, 379}</string>
<reference key="NSSuperview" ref="131633443"/>
<int key="NSDividerStyle">2</int>
- <object class="NSColor" key="BWSVColor">
- <int key="NSColorSpace">6</int>
- <string key="NSCatalogName">System</string>
- <string key="NSColorName">_sourceListBackgroundColor</string>
- <reference key="NSColor" ref="899084452"/>
- </object>
- <bool key="BWSVColorIsEnabled">YES</bool>
- <object class="NSMutableDictionary" key="BWSVMinValues">
- <integer value="0" key="NS.key.0"/>
- <integer value="26" key="NS.object.0"/>
- </object>
- <object class="NSMutableDictionary" key="BWSVMaxValues">
- <integer value="0" key="NS.key.0"/>
- <integer value="26" key="NS.object.0"/>
- </object>
- <object class="NSMutableDictionary" key="BWSVMinUnits">
- <integer value="0" key="NS.key.0"/>
- <integer value="0" key="NS.object.0"/>
- </object>
- <object class="NSMutableDictionary" key="BWSVMaxUnits">
- <integer value="0" key="NS.key.0"/>
- <integer value="0" key="NS.object.0"/>
- </object>
- <int key="BWSVCollapsiblePopupSelection">1</int>
- <bool key="BWSVDividerCanCollapse">NO</bool>
</object>
</object>
<string key="NSFrameSize">{214, 379}</string>
<reference key="NSSuperview" ref="298095498"/>
- <string key="NSClassName">NSView</string>
</object>
- <object class="BWCustomView" id="192579410">
+ <object class="NSView" id="192579410">
<reference key="NSNextResponder" ref="298095498"/>
<int key="NSvFlags">258</int>
<object class="NSMutableArray" key="NSSubviews">
@@ -1019,57 +991,17 @@
</object>
<string key="NSFrame">{{0, 380}, {214, 145}}</string>
<reference key="NSSuperview" ref="298095498"/>
- <string key="NSClassName">NSView</string>
</object>
</object>
<string key="NSFrame">{{0, 24}, {214, 525}}</string>
<reference key="NSSuperview" ref="1053680279"/>
<int key="NSDividerStyle">2</int>
- <reference key="BWSVColor" ref="304829493"/>
- <bool key="BWSVColorIsEnabled">NO</bool>
- <object class="NSMutableDictionary" key="BWSVMinValues">
- <integer value="1" key="NS.key.0"/>
- <integer value="0" key="NS.object.0"/>
- </object>
- <object class="NSMutableDictionary" key="BWSVMaxValues">
- <integer value="1" key="NS.key.0"/>
- <integer value="145" key="NS.object.0"/>
- </object>
- <object class="NSMutableDictionary" key="BWSVMinUnits">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <integer value="0"/>
- <integer value="1"/>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <integer value="0"/>
- <integer value="0"/>
- </object>
- </object>
- <object class="NSMutableDictionary" key="BWSVMaxUnits">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <integer value="0"/>
- <integer value="1"/>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <integer value="0"/>
- <integer value="0"/>
- </object>
- </object>
- <int key="BWSVCollapsiblePopupSelection">2</int>
- <bool key="BWSVDividerCanCollapse">NO</bool>
</object>
</object>
<string key="NSFrameSize">{214, 549}</string>
<reference key="NSSuperview" ref="162770193"/>
- <string key="NSClassName">NSView</string>
</object>
- <object class="BWCustomView" id="882258892">
+ <object class="NSView" id="882258892">
<reference key="NSNextResponder" ref="162770193"/>
<int key="NSvFlags">274</int>
<object class="NSMutableArray" key="NSSubviews">
@@ -3335,8 +3267,8 @@
<reference key="NSControlView" ref="1006311058"/>
<int key="NSButtonFlags">-926662401</int>
<int key="NSButtonFlags2">163</int>
- <reference key="NSNormalImage" ref="230512564"/>
- <reference key="NSAlternateImage" ref="6531"/>
+ <reference key="NSNormalImage" ref="359449987"/>
+ <reference key="NSAlternateImage" ref="367969719"/>
<string key="NSAlternateContents"/>
<string key="NSKeyEquivalent"/>
<int key="NSPeriodicDelay">200</int>
@@ -3475,7 +3407,7 @@
<int key="NSvFlags">274</int>
<object class="NSMutableArray" key="NSSubviews">
<bool key="EncodedWithXMLCoder">YES</bool>
- <object class="BWCustomView" id="940311190">
+ <object class="NSView" id="940311190">
<reference key="NSNextResponder" ref="515194087"/>
<int key="NSvFlags">272</int>
<object class="NSMutableArray" key="NSSubviews">
@@ -4413,9 +4345,8 @@
</object>
<string key="NSFrameSize">{696, 395}</string>
<reference key="NSSuperview" ref="515194087"/>
- <string key="NSClassName">NSView</string>
</object>
- <object class="BWCustomView" id="1028777476">
+ <object class="NSView" id="1028777476">
<reference key="NSNextResponder" ref="515194087"/>
<int key="NSvFlags">274</int>
<object class="NSMutableArray" key="NSSubviews">
@@ -4611,7 +4542,6 @@
</object>
<string key="NSFrame">{{0, 396}, {696, 111}}</string>
<reference key="NSSuperview" ref="515194087"/>
- <string key="NSClassName">NSView</string>
</object>
</object>
<string key="NSFrame">{{6, 34}, {696, 507}}</string>
@@ -6464,7 +6394,6 @@
</object>
<string key="NSFrame">{{215, 0}, {728, 549}}</string>
<reference key="NSSuperview" ref="162770193"/>
- <string key="NSClassName">NSView</string>
</object>
</object>
<string key="NSFrameSize">{943, 549}</string>
@@ -10054,7 +9983,7 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string>
<int key="NSvFlags">274</int>
<object class="NSMutableArray" key="NSSubviews">
<bool key="EncodedWithXMLCoder">YES</bool>
- <object class="BWCustomView" id="40644394">
+ <object class="NSView" id="40644394">
<reference key="NSNextResponder" ref="80390753"/>
<int key="NSvFlags">272</int>
<object class="NSMutableArray" key="NSSubviews">
@@ -10198,9 +10127,8 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string>
</object>
<string key="NSFrameSize">{482, 106}</string>
<reference key="NSSuperview" ref="80390753"/>
- <string key="NSClassName">NSView</string>
</object>
- <object class="BWCustomView" id="317678649">
+ <object class="NSView" id="317678649">
<reference key="NSNextResponder" ref="80390753"/>
<int key="NSvFlags">272</int>
<object class="NSMutableArray" key="NSSubviews">
@@ -10347,7 +10275,6 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string>
</object>
<string key="NSFrame">{{0, 107}, {482, 108}}</string>
<reference key="NSSuperview" ref="80390753"/>
- <string key="NSClassName">NSView</string>
</object>
</object>
<string key="NSFrame">{{-1, 55}, {482, 215}}</string>
@@ -13671,22 +13598,6 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string>
</object>
<object class="IBConnectionRecord">
<object class="IBOutletConnection" key="connection">
- <string key="label">tableInfoCollapseButton</string>
- <reference key="source" ref="438574515"/>
- <reference key="destination" ref="57416393"/>
- </object>
- <int key="connectionID">6259</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBOutletConnection" key="connection">
- <string key="label">tableListSplitter</string>
- <reference key="source" ref="427689665"/>
- <reference key="destination" ref="213762440"/>
- </object>
- <int key="connectionID">6269</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBOutletConnection" key="connection">
<string key="label">tableListFilterSplitView</string>
<reference key="source" ref="438574515"/>
<reference key="destination" ref="213762440"/>
@@ -13695,14 +13606,6 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string>
</object>
<object class="IBConnectionRecord">
<object class="IBOutletConnection" key="connection">
- <string key="label">delegate</string>
- <reference key="source" ref="213762440"/>
- <reference key="destination" ref="427689665"/>
- </object>
- <int key="connectionID">6283</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBOutletConnection" key="connection">
<string key="label">listFilterField</string>
<reference key="source" ref="438574515"/>
<reference key="destination" ref="727834078"/>
@@ -16528,14 +16431,6 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string>
</object>
<object class="IBConnectionRecord">
<object class="IBOutletConnection" key="connection">
- <string key="label">containerView</string>
- <reference key="source" ref="622219357"/>
- <reference key="destination" ref="192579410"/>
- </object>
- <int key="connectionID">7714</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBOutletConnection" key="connection">
<string key="label">delegate</string>
<reference key="source" ref="78186995"/>
<reference key="destination" ref="601471102"/>
@@ -16742,6 +16637,22 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string>
</object>
<int key="connectionID">7839</int>
</object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">collapseToggleButton</string>
+ <reference key="source" ref="298095498"/>
+ <reference key="destination" ref="57416393"/>
+ </object>
+ <int key="connectionID">7840</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">delegate</string>
+ <reference key="source" ref="213762440"/>
+ <reference key="destination" ref="438574515"/>
+ </object>
+ <int key="connectionID">7841</int>
+ </object>
</object>
<object class="IBMutableOrderedSet" key="objectRecords">
<object class="NSArray" key="orderedObjects">
@@ -24039,6 +23950,7 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string>
<string>6024.IBPluginDependency</string>
<string>6027.IBPluginDependency</string>
<string>6028.IBPluginDependency</string>
+ <string>6032.CustomClassName</string>
<string>6032.IBPluginDependency</string>
<string>6033.IBPluginDependency</string>
<string>6034.IBPluginDependency</string>
@@ -24120,6 +24032,7 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string>
<string>6240.IBPluginDependency</string>
<string>6241.IBPluginDependency</string>
<string>6242.IBPluginDependency</string>
+ <string>6265.CustomClassName</string>
<string>6265.IBPluginDependency</string>
<string>6266.IBPluginDependency</string>
<string>6267.IBPluginDependency</string>
@@ -25614,6 +25527,7 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string>
<string>com.brandonwalkin.BWToolkit</string>
<string>com.brandonwalkin.BWToolkit</string>
<string>com.brandonwalkin.BWToolkit</string>
+ <string>SPSplitView</string>
<string>com.brandonwalkin.BWToolkit</string>
<string>com.brandonwalkin.BWToolkit</string>
<string>com.brandonwalkin.BWToolkit</string>
@@ -25774,6 +25688,7 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>SPSplitView</string>
<string>com.brandonwalkin.BWToolkit</string>
<string>com.brandonwalkin.BWToolkit</string>
<string>com.brandonwalkin.BWToolkit</string>
@@ -26780,7 +26695,7 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string>
</object>
</object>
<nil key="sourceID"/>
- <int key="maxID">7839</int>
+ <int key="maxID">7841</int>
</object>
<object class="IBClassDescriber" key="IBDocument.Classes">
<object class="NSMutableArray" key="referencedPartialClassDescriptions">
@@ -28435,10 +28350,8 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string>
<string>tableContentInstance</string>
<string>tableDataInstance</string>
<string>tableDumpInstance</string>
- <string>tableInfoCollapseButton</string>
<string>tableInfoScrollView</string>
<string>tableInfoTable</string>
- <string>tableListSplitter</string>
<string>tableRelationsInstance</string>
<string>tableSourceInstance</string>
<string>tableTabView</string>
@@ -28508,10 +28421,8 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string>
<string>SPTableContent</string>
<string>SPTableData</string>
<string>id</string>
- <string>NSButton</string>
<string>NSScrollView</string>
<string>NSTableView</string>
- <string>NSSplitView</string>
<string>id</string>
<string>SPTableStructure</string>
<string>NSTabView</string>
@@ -28584,10 +28495,8 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string>
<string>tableContentInstance</string>
<string>tableDataInstance</string>
<string>tableDumpInstance</string>
- <string>tableInfoCollapseButton</string>
<string>tableInfoScrollView</string>
<string>tableInfoTable</string>
- <string>tableListSplitter</string>
<string>tableRelationsInstance</string>
<string>tableSourceInstance</string>
<string>tableTabView</string>
@@ -28817,10 +28726,6 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string>
<string key="candidateClassName">id</string>
</object>
<object class="IBToOneOutletInfo">
- <string key="name">tableInfoCollapseButton</string>
- <string key="candidateClassName">NSButton</string>
- </object>
- <object class="IBToOneOutletInfo">
<string key="name">tableInfoScrollView</string>
<string key="candidateClassName">NSScrollView</string>
</object>
@@ -28829,10 +28734,6 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string>
<string key="candidateClassName">NSTableView</string>
</object>
<object class="IBToOneOutletInfo">
- <string key="name">tableListSplitter</string>
- <string key="candidateClassName">NSSplitView</string>
- </object>
- <object class="IBToOneOutletInfo">
<string key="name">tableRelationsInstance</string>
<string key="candidateClassName">id</string>
</object>
@@ -30619,6 +30520,57 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string>
</object>
</object>
<object class="IBPartialClassDescription">
+ <string key="className">SPSplitView</string>
+ <string key="superclassName">NSSplitView</string>
+ <object class="NSMutableDictionary" key="actions">
+ <string key="NS.key.0">toggleCollapse:</string>
+ <string key="NS.object.0">id</string>
+ </object>
+ <object class="NSMutableDictionary" key="actionInfosByName">
+ <string key="NS.key.0">toggleCollapse:</string>
+ <object class="IBActionInfo" key="NS.object.0">
+ <string key="name">toggleCollapse:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="outlets">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>additionalDragHandleView</string>
+ <string>collapseToggleButton</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>NSView</string>
+ <string>NSButton</string>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="toOneOutletInfosByName">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>additionalDragHandleView</string>
+ <string>collapseToggleButton</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBToOneOutletInfo">
+ <string key="name">additionalDragHandleView</string>
+ <string key="candidateClassName">NSView</string>
+ </object>
+ <object class="IBToOneOutletInfo">
+ <string key="name">collapseToggleButton</string>
+ <string key="candidateClassName">NSButton</string>
+ </object>
+ </object>
+ </object>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">Source/SPSplitView.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
<string key="className">SPTableContent</string>
<string key="superclassName">NSObject</string>
<object class="NSMutableDictionary" key="actions">
@@ -31137,7 +31089,6 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string>
<object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>activitiesTable</string>
- <string>containerView</string>
<string>infoTable</string>
<string>tableDataInstance</string>
<string>tableDocumentInstance</string>
@@ -31148,7 +31099,6 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>NSTableView</string>
- <string>NSView</string>
<string>id</string>
<string>id</string>
<string>id</string>
@@ -31162,7 +31112,6 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string>
<object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>activitiesTable</string>
- <string>containerView</string>
<string>infoTable</string>
<string>tableDataInstance</string>
<string>tableDocumentInstance</string>
@@ -31177,10 +31126,6 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string>
<string key="candidateClassName">NSTableView</string>
</object>
<object class="IBToOneOutletInfo">
- <string key="name">containerView</string>
- <string key="candidateClassName">NSView</string>
- </object>
- <object class="IBToOneOutletInfo">
<string key="name">infoTable</string>
<string key="candidateClassName">id</string>
</object>
@@ -31461,7 +31406,6 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string>
<string>addField:</string>
<string>closeSheet:</string>
<string>duplicateField:</string>
- <string>reloadTable:</string>
<string>removeField:</string>
<string>resetAutoIncrement:</string>
<string>showOptimizedFieldType:</string>
@@ -31476,7 +31420,6 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string>
<string>id</string>
<string>id</string>
<string>id</string>
- <string>id</string>
<string>NSMenuItem</string>
<string>id</string>
</object>
@@ -31488,7 +31431,6 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string>
<string>addField:</string>
<string>closeSheet:</string>
<string>duplicateField:</string>
- <string>reloadTable:</string>
<string>removeField:</string>
<string>resetAutoIncrement:</string>
<string>showOptimizedFieldType:</string>
@@ -31510,10 +31452,6 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string>
<string key="candidateClassName">id</string>
</object>
<object class="IBActionInfo">
- <string key="name">reloadTable:</string>
- <string key="candidateClassName">id</string>
- </object>
- <object class="IBActionInfo">
<string key="name">removeField:</string>
<string key="candidateClassName">id</string>
</object>
@@ -31756,6 +31694,24 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string>
</object>
<object class="IBPartialClassDescription">
<string key="className">SPTableStructure</string>
+ <object class="NSMutableDictionary" key="actions">
+ <string key="NS.key.0">reloadTable:</string>
+ <string key="NS.object.0">id</string>
+ </object>
+ <object class="NSMutableDictionary" key="actionInfosByName">
+ <string key="NS.key.0">reloadTable:</string>
+ <object class="IBActionInfo" key="NS.object.0">
+ <string key="name">reloadTable:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ </object>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">Source/SPTableStructureLoading.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">SPTableStructure</string>
<string key="superclassName">NSObject</string>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBUserSource</string>
@@ -32105,7 +32061,6 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string>
<string>tableDocumentInstance</string>
<string>tableDumpInstance</string>
<string>tableEncodingButton</string>
- <string>tableInfoCollapseButton</string>
<string>tableInfoInstance</string>
<string>tableListFilterSplitView</string>
<string>tableListSplitView</string>
@@ -32158,10 +32113,9 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string>
<string>SPDatabaseDocument</string>
<string>id</string>
<string>id</string>
- <string>NSButton</string>
<string>id</string>
- <string>NSSplitView</string>
- <string>NSSplitView</string>
+ <string>SPSplitView</string>
+ <string>SPSplitView</string>
<string>id</string>
<string>id</string>
<string>SPTableStructure</string>
@@ -32214,7 +32168,6 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string>
<string>tableDocumentInstance</string>
<string>tableDumpInstance</string>
<string>tableEncodingButton</string>
- <string>tableInfoCollapseButton</string>
<string>tableInfoInstance</string>
<string>tableListFilterSplitView</string>
<string>tableListSplitView</string>
@@ -32370,20 +32323,16 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string>
<string key="candidateClassName">id</string>
</object>
<object class="IBToOneOutletInfo">
- <string key="name">tableInfoCollapseButton</string>
- <string key="candidateClassName">NSButton</string>
- </object>
- <object class="IBToOneOutletInfo">
<string key="name">tableInfoInstance</string>
<string key="candidateClassName">id</string>
</object>
<object class="IBToOneOutletInfo">
<string key="name">tableListFilterSplitView</string>
- <string key="candidateClassName">NSSplitView</string>
+ <string key="candidateClassName">SPSplitView</string>
</object>
<object class="IBToOneOutletInfo">
<string key="name">tableListSplitView</string>
- <string key="candidateClassName">NSSplitView</string>
+ <string key="candidateClassName">SPSplitView</string>
</object>
<object class="IBToOneOutletInfo">
<string key="name">tableNameField</string>
diff --git a/Resources/English.lproj/Localizable.strings b/Resources/English.lproj/Localizable.strings
index ae7913fd..3bc0d800 100644
--- a/Resources/English.lproj/Localizable.strings
+++ b/Resources/English.lproj/Localizable.strings
Binary files differ
diff --git a/Source/SPConnectionHandler.m b/Source/SPConnectionHandler.m
index 77e3550f..bdd57a2c 100644
--- a/Source/SPConnectionHandler.m
+++ b/Source/SPConnectionHandler.m
@@ -71,7 +71,7 @@ static NSString *SPLocalhostAddress = @"127.0.0.1";
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
mySQLConnection = [[SPMySQLConnection alloc] init];
-
+
// Set up shared details
[mySQLConnection setUsername:[self user]];
diff --git a/Source/SPDatabaseDocument.h b/Source/SPDatabaseDocument.h
index 12f00863..0dd389b8 100644
--- a/Source/SPDatabaseDocument.h
+++ b/Source/SPDatabaseDocument.h
@@ -123,8 +123,6 @@ SPDatabaseData, SPTablesList, SPTableStructure, SPTableContent, SPTableData, SPS
IBOutlet NSTabView *tableTabView;
IBOutlet NSTableView *tableInfoTable;
- IBOutlet NSButton *tableInfoCollapseButton;
- IBOutlet NSSplitView *tableListSplitter;
IBOutlet NSSplitView *contentViewSplitter;
IBOutlet id sidebarGrabber;
diff --git a/Source/SPDatabaseDocument.m b/Source/SPDatabaseDocument.m
index 5f7cb49a..0cfec364 100644
--- a/Source/SPDatabaseDocument.m
+++ b/Source/SPDatabaseDocument.m
@@ -528,10 +528,7 @@ static NSString *SPRenameDatabaseAction = @"SPRenameDatabase";
// Set focus to table list filter field if visible
// otherwise set focus to Table List view
- if ([[tablesListInstance tables] count] > 20)
- [parentWindow makeFirstResponder:listFilterField];
- else
- [parentWindow makeFirstResponder:[tablesListInstance valueForKeyPath:@"tablesListView"]];
+ [self focusOnTableListFilter:self];
if (spfSession != nil) {
@@ -2296,7 +2293,7 @@ static NSString *SPRenameDatabaseAction = @"SPRenameDatabase";
*/
- (IBAction)focusOnTableListFilter:(id)sender
{
- [tablesListInstance performSelector:@selector(makeTableListFilterHaveFocus) withObject:nil afterDelay:0.1];
+ [[tablesListInstance onMainThread] performSelector:@selector(makeTableListFilterHaveFocus) withObject:nil afterDelay:0.25];
}
/**
@@ -5575,13 +5572,6 @@ static NSString *SPRenameDatabaseAction = @"SPRenameDatabase";
#pragma mark -
#pragma mark SplitView delegate methods
#ifndef SP_REFACTOR /* SplitView delegate methods */
-/**
- * tells the splitView that it can collapse views
- */
-- (BOOL)splitView:(NSSplitView *)sender canCollapseSubview:(NSView *)subview
-{
- return subview == [[tableInfoTable superview] superview];
-}
- (void)splitViewDidResizeSubviews:(NSNotification *)notification
{
@@ -6071,12 +6061,7 @@ static NSString *SPRenameDatabaseAction = @"SPRenameDatabase";
// Set focus to table list filter field if visible
// otherwise set focus to Table List view
- if ([[tablesListInstance tables] count] > 20) {
- [[parentWindow onMainThread] makeFirstResponder:listFilterField];
- }
- else {
- [[parentWindow onMainThread] makeFirstResponder:[tablesListInstance valueForKeyPath:@"tablesListView"]];
- }
+ [self focusOnTableListFilter:self];
#endif
}
diff --git a/Source/SPDateAdditions.h b/Source/SPDateAdditions.h
new file mode 100644
index 00000000..cacb11c4
--- /dev/null
+++ b/Source/SPDateAdditions.h
@@ -0,0 +1,37 @@
+//
+// $Id$
+//
+// SPDateAdditions.h
+// sequel-pro
+//
+// Created by Rowan Beentje (rowan.beent.je) on July 9, 2012
+// Copyright (c) 2012 Rowan Beentje. 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 <http://code.google.com/p/sequel-pro/>
+
+@interface NSDate (SPDateAdditions)
+
++ (double)monotonicTimeInterval;
+
+@end
diff --git a/Source/SPDateAdditions.m b/Source/SPDateAdditions.m
new file mode 100644
index 00000000..e486125a
--- /dev/null
+++ b/Source/SPDateAdditions.m
@@ -0,0 +1,53 @@
+//
+// $Id$
+//
+// SPDateAdditions.m
+// sequel-pro
+//
+// Created by Rowan Beentje (rowan.beent.je) on February 22, 2012
+// Copyright (c) 2012 Rowan Beentje. 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 <http://code.google.com/p/sequel-pro/>
+
+#include <mach/mach_time.h>
+
+@implementation NSDate (SPDateAdditions)
+
+/**
+ * Retrieve a monotonic time for timing purposes: a value of a number of seconds
+ * which can be use for relative time comparison in a monotonic sense, eg in a
+ * particular session this value will only ever increase linearly.
+ * This differs from (for example) unix epoch timestamps or dates, which can change
+ * when the system time changes or synchs, but should never be used for absolute time
+ * as it is based on the elapsed time since the system booted.
+ */
++ (double)monotonicTimeInterval
+{
+ uint64_t elapsedTime_t = mach_absolute_time();
+ Nanoseconds nanosecondsElapsed = AbsoluteToNanoseconds(*(AbsoluteTime *)&(elapsedTime_t));
+
+ return (((double)UnsignedWideToUInt64(nanosecondsElapsed)) * 1e-9);
+}
+
+@end
diff --git a/Source/SPSplitView.h b/Source/SPSplitView.h
new file mode 100644
index 00000000..14ea1ee2
--- /dev/null
+++ b/Source/SPSplitView.h
@@ -0,0 +1,71 @@
+//
+// $Id$
+//
+// SPSplitView.h
+// sequel-pro
+//
+// Created by Rowan Beentje on April 25, 2012
+// Copyright (c) 2012 Rowan Beentje. 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 <http://code.google.com/p/sequel-pro/>
+
+#import <AppKit/NSSplitView.h>
+
+@class SPSplitViewAnimationRetainCycleBypass;
+
+@interface SPSplitView : NSSplitView {
+ NSObject *delegate;
+
+ IBOutlet NSButton *collapseToggleButton;
+ IBOutlet NSView *additionalDragHandleView;
+
+ NSUInteger collapsibleSubviewIndex;
+ BOOL collapsibleSubviewCollapsed;
+
+ double animationStartTime;
+ double animationDuration;
+ NSTimer *animationTimer;
+ SPSplitViewAnimationRetainCycleBypass *animationRetainCycleBypassObject;
+ float animationStartSize;
+ float animationTargetSize;
+
+ NSMutableArray *viewMinimumSizes;
+ NSMutableArray *viewMaximumSizes;
+}
+
+// Collapsing/expanding
+- (void)setCollapsibleSubviewIndex:(NSUInteger)subviewIndex;
+- (void)setToggleCollapseButton:(NSButton *)aButton;
+- (BOOL)isCollapsibleSubviewCollapsed;
+- (IBAction)toggleCollapse:(id)sender;
+- (void)setCollapsibleSubviewCollapsed:(BOOL)shouldCollapse animate:(BOOL)shouldAnimate;
+
+// Additional drag handle
+- (void)setAdditionalDragHandleView:(NSView *)aView;
+
+// Constraints
+- (void)setMinSize:(CGFloat)newMinSize ofSubviewAtIndex:(NSUInteger)subviewIndex;
+- (void)setMaxSize:(CGFloat)newMaxSize ofSubviewAtIndex:(NSUInteger)subviewIndex;
+
+@end
diff --git a/Source/SPSplitView.m b/Source/SPSplitView.m
new file mode 100644
index 00000000..87392712
--- /dev/null
+++ b/Source/SPSplitView.m
@@ -0,0 +1,1094 @@
+//
+// $Id$
+//
+// SPSplitView.m
+// sequel-pro
+//
+// Created by Rowan Beentje on April 25, 2012
+// Copyright (c) 2012 Rowan Beentje. 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 <http://code.google.com/p/sequel-pro/>
+
+#import "SPSplitView.h"
+#import "SPDateAdditions.h"
+
+@interface SPSplitView (Private_API)
+
+- (void)_initCustomProperties;
+- (void)_ensureDefaultSubviewSizesToIndex:(NSUInteger)anIndex;
+
+- (NSArray *)_suggestedSizesForTargetSize:(CGFloat)targetSize respectingSpringsAndStruts:(BOOL)respectStruts respectingConstraints:(BOOL)respectConstraints;
+
+- (CGFloat)_startPositionOfView:(NSView *)aView;
+- (CGFloat)_lengthOfView:(NSView *)aView;
+- (void)_setStartPosition:(CGFloat)newOrigin ofView:(NSView *)aView;
+- (void)_setLength:(CGFloat)newLength ofView:(NSView *)aView;
+
+- (BOOL)_isViewResizable:(NSView *)aView;
+@end
+
+@interface SPSplitViewHelperView : NSView
+{
+ NSView *wrappedView;
+}
+
+- (id)initReplacingView:(NSView *)aView;
+- (void)restoreOriginalView;
+
+@end
+
+@interface SPSplitViewAnimationRetainCycleBypass : NSObject
+{
+ SPSplitView *parentSplitView;
+}
+
+- (id)initWithParent:(SPSplitView *)aSplitView;
+- (void)_animationStep:(NSTimer *)aTimer;
+
+@end
+
+
+@implementation SPSplitView
+
+#pragma mark -
+#pragma mark Setup and teardown
+
+- (id)initWithFrame:(NSRect)frameRect
+{
+ if ((self = [super initWithFrame:frameRect])) {
+ [self _initCustomProperties];
+ }
+ return self;
+}
+
+- (id)initWithCoder:(NSCoder *)coder
+{
+ if ((self = [super initWithCoder:coder])) {
+ [self _initCustomProperties];
+ }
+ return self;
+}
+
+- (void)awakeFromNib
+{
+ [super awakeFromNib];
+
+ delegate = [super delegate];
+ [super setDelegate:self];
+
+ [self adjustSubviews];
+
+ [collapseToggleButton setState:(collapsibleSubviewCollapsed?NSOnState:NSOffState)];
+}
+
+- (void)dealloc
+{
+ [viewMinimumSizes release];
+ [viewMaximumSizes release];
+
+ if (animationTimer) [animationTimer invalidate], [animationTimer release], animationTimer = nil;
+ if (animationRetainCycleBypassObject) [animationRetainCycleBypassObject release], animationRetainCycleBypassObject = nil;
+
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ [super dealloc];
+}
+
+#pragma mark -
+#pragma mark Collapsible subview management
+
+/**
+ * Set the index of the collapsible subview; pass in NSNotFound as the index
+ * to unset an existing subview.
+ */
+- (void)setCollapsibleSubviewIndex:(NSUInteger)subviewIndex
+{
+ if (collapsibleSubviewIndex == subviewIndex) {
+ return;
+ }
+
+ if (subviewIndex > [[self subviews] count]) {
+ [NSException raise:NSInternalInconsistencyException format:@"Specified a collpasible subview index which doesn't exist"];
+ }
+
+ // If an existing collapsible subview exists, and the view is collapsed,
+ // expand the old view before proceeding
+ if (collapsibleSubviewIndex != NSNotFound && collapsibleSubviewCollapsed) {
+ [self setCollapsibleSubviewCollapsed:NO animate:NO];
+ }
+
+ collapsibleSubviewIndex = subviewIndex;
+ [collapseToggleButton setState:NSOffState];
+ collapsibleSubviewCollapsed = NO;
+}
+
+/**
+ * Set a button which controls the state of the collapsible subview; if this is set,
+ * the button state will automatically be set as the subview collapses or expands.
+ * This can also be set using the IBOutlet.
+ */
+- (void)setToggleCollapseButton:(NSButton *)aButton
+{
+ collapseToggleButton = aButton;
+ [collapseToggleButton setState:(collapsibleSubviewCollapsed?NSOnState:NSOffState)];
+}
+
+/**
+ * Return whether the collapsible subview is collapsed or collapsing.
+ */
+- (BOOL)isCollapsibleSubviewCollapsed
+{
+ if (collapsibleSubviewIndex == NSNotFound) {
+ return NO;
+ }
+
+ return collapsibleSubviewCollapsed;
+}
+
+/**
+ * Return whether the specified subview is collapsed, overriding the original method for
+ * the collapsible subview set on this object; note that for the subview collapsible by
+ * this class, YES is returned only if the subview is fully collapsed, not when animating.
+ */
+- (BOOL)isSubviewCollapsed:(NSView *)subview
+{
+ NSUInteger subviewIndex = [[self subviews] indexOfObject:subview];
+ if (collapsibleSubviewIndex == NSNotFound || subviewIndex != collapsibleSubviewIndex) {
+ return [super isSubviewCollapsed:subview];
+ }
+
+ return collapsibleSubviewCollapsed && !animationTimer;
+}
+
+/**
+ * Toggle the collapse state, using animation.
+ */
+- (IBAction)toggleCollapse:(id)sender
+{
+ [self setCollapsibleSubviewCollapsed:!collapsibleSubviewCollapsed animate:YES];
+}
+
+/**
+ * Trigger a collapsible subview collapse or expand, optionally animating the transition.
+ * This is the master collapse/expand method, called by any other methods to perform the work.
+ */
+- (void)setCollapsibleSubviewCollapsed:(BOOL)shouldCollapse animate:(BOOL)shouldAnimate
+{
+ if (collapsibleSubviewIndex == NSNotFound || shouldCollapse == collapsibleSubviewCollapsed) {
+ return;
+ }
+
+ collapsibleSubviewCollapsed = shouldCollapse;
+ [collapseToggleButton setState:(shouldCollapse?NSOnState:NSOffState)];
+
+ NSView *viewToAnimate = [[self subviews] objectAtIndex:collapsibleSubviewIndex];
+ animationStartSize = [self _lengthOfView:viewToAnimate];
+
+ if (shouldCollapse) {
+
+ // If collapsing, ensure the original view is wrapped in a helper view to avoid
+ // animation resizes of the contained view. (Uncollapses will already be wrapped.)
+ if (![viewToAnimate isMemberOfClass:[SPSplitViewHelperView class]]) {
+ [[[SPSplitViewHelperView alloc] initReplacingView:viewToAnimate] autorelease];
+ viewToAnimate = [[self subviews] objectAtIndex:collapsibleSubviewIndex];
+ }
+
+ animationTargetSize = 0;
+ } else {
+ animationTargetSize = [self _lengthOfView:[[viewToAnimate subviews] objectAtIndex:0]];
+ }
+
+ // If not animating, update the view at once
+ if (!shouldAnimate) {
+ [self adjustSubviews];
+
+ // Otherwise, start an animation.
+ } else {
+ if (animationTimer) [animationTimer invalidate], [animationTimer release], animationTimer = nil;
+ if (animationRetainCycleBypassObject) [animationRetainCycleBypassObject release], animationRetainCycleBypassObject = nil;
+ animationStartTime = [NSDate monotonicTimeInterval];
+
+ // Determine the animation length, in seconds, starting with a quarter of a second
+ animationDuration = 0.25f;
+
+ // Make it a slow animation if appropriate
+ if ([[NSApp currentEvent] type] == NSLeftMouseUp && [[NSApp currentEvent] modifierFlags] & NSShiftKeyMask) {
+ animationDuration *= 10;
+ }
+
+ // Modify the duration by the proportion of any interrupted animation
+ CGFloat fullViewSize = [self _lengthOfView:[[viewToAnimate subviews] objectAtIndex:0]];
+ if (shouldCollapse) {
+ animationDuration *= animationStartSize / fullViewSize;
+ } else {
+ animationDuration *= (animationTargetSize - animationStartSize) / fullViewSize;
+ }
+
+ // Create an object to avoid NSTimer retain cycles
+ animationRetainCycleBypassObject = [[SPSplitViewAnimationRetainCycleBypass alloc] initWithParent:self];
+
+ // Start an animation at 30fps
+ animationTimer = [[NSTimer timerWithTimeInterval:(1.f/30.f) target:animationRetainCycleBypassObject selector:@selector(_animationStep:) userInfo:nil repeats:YES] retain];
+ [[NSRunLoop currentRunLoop] addTimer:animationTimer forMode:NSRunLoopCommonModes];
+ }
+}
+
+#pragma mark -
+#pragma mark Additional drag handle view
+
+/**
+ * Set an additional view, the frame rect of which will be used to provide an additional
+ * drag handle to reposition the *first* divider.
+ * This can also be set using the IBOutlet.
+ */
+- (void)setAdditionalDragHandleView:(NSView *)aView
+{
+ if ([aView window] != [self window]) {
+ [NSException raise:NSInternalInconsistencyException format:@"Additional drag handle must be in the same window as the split view"];
+ }
+
+ additionalDragHandleView = aView;
+}
+
+#pragma mark -
+#pragma mark Constraint management
+
+/**
+ * Set the minimum size of a view at the specified index. Note that indexes cannot be kept
+ * in sync with subsequent view deletions/additions, so these will continue to apply to the
+ * specified index and not the view originally at that index.
+ */
+- (void)setMinSize:(CGFloat)newMinSize ofSubviewAtIndex:(NSUInteger)subviewIndex
+{
+ [self _ensureDefaultSubviewSizesToIndex:subviewIndex];
+
+ // Verify against the max size
+ if (newMinSize > [[viewMaximumSizes objectAtIndex:subviewIndex] floatValue]) {
+ [NSException raise:NSInternalInconsistencyException format:@"Minimum size for a subview specified as larger than the maximum size"];
+ }
+
+ [viewMinimumSizes replaceObjectAtIndex:subviewIndex withObject:[NSNumber numberWithFloat:newMinSize]];
+}
+
+/**
+ * Set the minimum size of a view at the specified index. Note that indexes cannot be kept
+ * in sync with subsequent view deletions/additions, so these will continue to apply to the
+ * specified index and not the view originally at that index.
+ */
+- (void)setMaxSize:(CGFloat)newMaxSize ofSubviewAtIndex:(NSUInteger)subviewIndex
+{
+ [self _ensureDefaultSubviewSizesToIndex:subviewIndex];
+
+ // Verify against the max size
+ if (newMaxSize < [[viewMinimumSizes objectAtIndex:subviewIndex] floatValue]) {
+ [NSException raise:NSInternalInconsistencyException format:@"Maximum size for a subview specified as smaller than the minimum size"];
+ }
+
+ [viewMaximumSizes replaceObjectAtIndex:subviewIndex withObject:[NSNumber numberWithFloat:newMaxSize]];
+}
+
+#pragma mark -
+#pragma mark Sizing
+
+/**
+ * adjustSubviews adjusts the sizes of the subviews so they fill up the splitview fully.
+ * With no constraints and no collapsible subviews, all the subviews are resized
+ * proportionally; however this override method handles constraints and collapsible subviews,
+ * as well as animating collapses when driven by a timer.
+ *
+ * When resizing starts, non-resizable subviews are first left at their default sizes,
+ * and other views are resized proportionally. If those views hit constraints set on the
+ * object via setMinSize: or setMaxSize:, the constraints are respected, and other views
+ * continue to be resized.
+ *
+ * If that resize process cannot cope with the size change, non-resizable subviews are
+ * resized, respecting constraints set via setMinSize: or setMaxSize:.
+ *
+ * If all constraints are hit, then resizing will start to exceed the constraints.
+ */
+- (void)adjustSubviews
+{
+ CGFloat totalAvailableSize = [self _lengthOfView:self];
+ NSUInteger i, viewCount = [[self subviews] count];
+
+ // Amend the total length by non-hidden dividers
+ for (i = 0; i < viewCount - 1; i++) {
+ if (![self splitView:self shouldHideDividerAtIndex:i]) {
+ totalAvailableSize -= [self dividerThickness];
+ }
+ }
+
+ // Start by checking for valid sizes complying with all constraints
+ NSArray *viewSizes = [self _suggestedSizesForTargetSize:totalAvailableSize respectingSpringsAndStruts:YES respectingConstraints:YES];
+
+ // If that didn't produce a valid result, allow resizing of non-resizable views
+ if (!viewSizes) {
+ viewSizes = [self _suggestedSizesForTargetSize:totalAvailableSize respectingSpringsAndStruts:NO respectingConstraints:YES];
+ }
+
+ // If that still didn't produce a valid result, resort to resizing all views
+ if (!viewSizes) {
+ viewSizes = [self _suggestedSizesForTargetSize:totalAvailableSize respectingSpringsAndStruts:NO respectingConstraints:NO];
+ }
+
+ // Safety check
+ if ([viewSizes count] < [[self subviews] count]) {
+ [super adjustSubviews];
+ return;
+ }
+
+ CGFloat splitViewBreadth;
+ if ([self isVertical]) {
+ splitViewBreadth = [self frame].size.height;
+ } else {
+ splitViewBreadth = [self frame].size.width;
+ }
+
+ // Apply the size changes to the views.
+ CGFloat originPosition = 0;
+ for (i = 0; i < viewCount; i++) {
+ NSView *eachSubview = [[self subviews] objectAtIndex:i];
+ CGFloat viewSize = [[viewSizes objectAtIndex:i] floatValue];
+ NSRect viewFrame = [eachSubview frame];
+
+ if ([self isVertical]) {
+ viewFrame.origin.x = roundf(originPosition);
+ viewFrame.size.width = roundf(viewSize);
+ viewFrame.size.height = splitViewBreadth;
+ } else {
+ viewFrame.origin.y = roundf(originPosition);
+ viewFrame.size.width = splitViewBreadth;
+ viewFrame.size.height = roundf(viewSize);
+ }
+
+ [eachSubview setFrame:viewFrame];
+
+ originPosition += viewSize;
+
+ if ((i + 1) < viewCount && ![self splitView:self shouldHideDividerAtIndex:(i + 1)]) {
+ originPosition += [self dividerThickness];
+ }
+ }
+
+ // Invalidate the cursor rects
+ [[self window] invalidateCursorRectsForView:self];
+}
+
+#pragma mark -
+#pragma mark Delegate method overrides
+
+/**
+ * Handle requests to collapse a particular subview. If a subview is collapsible,
+ * by default this will return YES for that subview and NO for all others.
+ * The delegate can override this if necessary.
+ */
+- (BOOL)splitView:(NSSplitView *)splitView canCollapseSubview:(NSView *)subview
+{
+ if ([delegate respondsToSelector:@selector(splitView:canCollapseSubview:)]) {
+ return [delegate splitView:splitView canCollapseSubview:subview];
+ }
+
+ if (collapsibleSubviewIndex != NSNotFound && [[self subviews] objectAtIndex:collapsibleSubviewIndex] == subview) {
+ return YES;
+ }
+
+ return NO;
+}
+
+/**
+ * Handle requests as to whether a subview should be collapsed as a result of
+ * a double-click on a divider. If a subview is collapsible, by default this
+ * will return NO, but an animated collapse/expand will be triggered instead to
+ * perform the same action with animation.
+ * The delegate can override this if necessary.
+ */
+- (BOOL)splitView:(NSSplitView *)splitView shouldCollapseSubview:(NSView *)subview forDoubleClickOnDividerAtIndex:(NSInteger)dividerIndex
+{
+ if ([delegate respondsToSelector:@selector(splitView:shouldCollapseSubview:forDoubleClickOnDividerAtIndex:)]) {
+ return [delegate splitView:splitView shouldCollapseSubview:subview forDoubleClickOnDividerAtIndex:dividerIndex];
+ }
+
+ // If there's no collapsible subview, don't allow collapse
+ if (collapsibleSubviewIndex == NSNotFound) {
+ return NO;
+ }
+
+ // Ensure the divider is adjacent to the collapsible view
+ if ((NSUInteger)dividerIndex != collapsibleSubviewIndex && (NSUInteger)dividerIndex != (collapsibleSubviewIndex - 1)) {
+ return NO;
+ }
+
+ // Trigger an animated collapse and prevent the original collapse
+ [self setCollapsibleSubviewCollapsed:YES animate:YES];
+ return NO;
+}
+
+/**
+ * While the collapsible subview is collapsed, hide the adjacent divider.
+ *
+ * Forwards requests on to the original delegate to allow overrides.
+ */
+- (BOOL)splitView:(NSSplitView *)splitView shouldHideDividerAtIndex:(NSInteger)dividerIndex
+{
+ if ([delegate respondsToSelector:@selector(splitView:shouldHideDividerAtIndex:)]) {
+ return [delegate splitView:splitView shouldHideDividerAtIndex:dividerIndex];
+ }
+
+ // If there's no collapsible subview, or it's not hidden, don't hide any dividers
+ if (!collapsibleSubviewCollapsed || collapsibleSubviewIndex == NSNotFound) {
+ return NO;
+ }
+
+ // Only hide one divider adjacent to the collapsible view
+ if ((collapsibleSubviewIndex == 0 && dividerIndex > 0) || (collapsibleSubviewIndex > 0 && (NSUInteger)(dividerIndex + 1) != collapsibleSubviewIndex)) {
+ return NO;
+ }
+
+ // If the collapsible subview is fully collapsed, hide the divider
+ if (!animationTimer) {
+ return YES;
+ }
+
+ return NO;
+}
+
+/**
+ * Handle delegate requests for a minimum size for the splitview above or to the left of
+ * the supplied divider index, using the minimum constraints supplied via setMinSize: if
+ * present.
+ *
+ * Only the two views adjacent to the supplied divider index are currently considered.
+ *
+ * Forwards requests on to the original delegate to allow overrides.
+ */
+- (CGFloat)splitView:(NSSplitView *)splitView constrainMinCoordinate:(CGFloat)proposedMinimumPosition ofSubviewAt:(NSInteger)dividerIndex
+{
+ if ([delegate respondsToSelector:@selector(splitView:constrainMinCoordinate:ofSubviewAt:)]) {
+ return [delegate splitView:splitView constrainMinCoordinate:proposedMinimumPosition ofSubviewAt:dividerIndex];
+ }
+
+ NSView *aView;
+ CGFloat preMinPosition = 0, postMaxPosition = 0;
+
+ [self _ensureDefaultSubviewSizesToIndex:(dividerIndex + 1)];
+
+ // If the preceeding view is not resizable, treat it as fixed position
+ aView = [[self subviews] objectAtIndex:dividerIndex];
+ if (![self _isViewResizable:aView]) {
+ preMinPosition = [self _startPositionOfView:aView] + [self _lengthOfView:aView];
+ } else {
+
+ // Check the minimum size of the preceeding view
+ CGFloat preMinSize = [[viewMinimumSizes objectAtIndex:dividerIndex] floatValue];
+ if (preMinSize) {
+ preMinPosition = [self _startPositionOfView:aView] + preMinSize;
+ }
+ }
+
+ // If the following view is not resizable, treat it as fixed position
+ aView = [[self subviews] objectAtIndex:(dividerIndex + 1)];
+ if (![self _isViewResizable:aView]) {
+ postMaxPosition = [self _startPositionOfView:aView] - [self dividerThickness];
+ } else {
+
+ // Check the maximum size of the following view
+ CGFloat postMaxSize = [[viewMaximumSizes objectAtIndex:(dividerIndex + 1)] floatValue];
+ if (postMaxSize != FLT_MAX) {
+ postMaxPosition = [self _startPositionOfView:aView] + [self _lengthOfView:aView] - postMaxSize - [self dividerThickness];
+ }
+ }
+
+ CGFloat suggestedMinimum = fmaxf(preMinPosition, postMaxPosition);
+ if (suggestedMinimum > proposedMinimumPosition) {
+ return suggestedMinimum;
+ }
+
+ return proposedMinimumPosition;
+}
+
+/**
+ * Handle delegate requests for a maximum size for the splitview above or to the left of
+ * the supplied divider index, using the maximum constraints supplied via setMaxSize: if
+ * present.
+ *
+ * Only the two views adjacent to the supplied divider index are currently considered.
+ *
+ * Forwards requests on to the original delegate to allow overrides.
+ */
+- (CGFloat)splitView:(NSSplitView *)splitView constrainMaxCoordinate:(CGFloat)proposedMaximumPosition ofSubviewAt:(NSInteger)dividerIndex
+{
+ if ([delegate respondsToSelector:@selector(splitView:constrainMaxCoordinate:ofSubviewAt:)]) {
+ return [delegate splitView:splitView constrainMaxCoordinate:proposedMaximumPosition ofSubviewAt:dividerIndex];
+ }
+
+ NSView *aView;
+ CGFloat preMaxPosition = FLT_MAX, postMinPosition = FLT_MAX;
+
+ [self _ensureDefaultSubviewSizesToIndex:(dividerIndex + 1)];
+
+ // If the preceeding view is not resizable, treat it as fixed position
+ aView = [[self subviews] objectAtIndex:dividerIndex];
+ if (![self _isViewResizable:aView]) {
+ preMaxPosition = [self _startPositionOfView:aView] + [self _lengthOfView:aView];
+ } else {
+
+ // Check the maximum size of the preceeding view
+ CGFloat preMaxSize = [[viewMaximumSizes objectAtIndex:dividerIndex] floatValue];
+ if (preMaxSize != FLT_MAX) {
+ preMaxPosition = [self _startPositionOfView:aView] + preMaxSize;
+ }
+ }
+
+ // If the following view is not resizable, treat it as fixed position
+ aView = [[self subviews] objectAtIndex:(dividerIndex + 1)];
+ if (![self _isViewResizable:aView]) {
+ postMinPosition = [self _startPositionOfView:aView] - [self dividerThickness];
+ } else {
+
+ // Check the minimum size of the following view
+ CGFloat postMinSize = [[viewMinimumSizes objectAtIndex:(dividerIndex + 1)] floatValue];
+ if (postMinSize) {
+ postMinPosition = [self _startPositionOfView:aView] + [self _lengthOfView:aView] - postMinSize - [self dividerThickness];
+ }
+ }
+
+ CGFloat suggestedMaximum = fminf(preMaxPosition, postMinPosition);
+ if (suggestedMaximum < proposedMaximumPosition) {
+ return suggestedMaximum;
+ }
+
+ return proposedMaximumPosition;
+}
+
+/**
+ * If an additional drag handle is set - in the nib or in code - return its rect as an
+ * additional effective rect.
+ *
+ * Forwards requests on to the original delegate to allow overrides.
+ */
+- (NSRect)splitView:(NSSplitView *)splitView additionalEffectiveRectOfDividerAtIndex:(NSInteger)dividerIndex
+{
+ if ([delegate respondsToSelector:@selector(splitView:additionalEffectiveRectOfDividerAtIndex:)]) {
+ return [delegate splitView:splitView additionalEffectiveRectOfDividerAtIndex:dividerIndex];
+ }
+
+ // If a view is set, return its frame in the splitview coordinate system
+ if (additionalDragHandleView) {
+ NSRect dragRect = [additionalDragHandleView frame];
+ dragRect.origin = [self convertPoint:dragRect.origin fromView:[additionalDragHandleView superview]];
+ return dragRect;
+ }
+
+ return NSZeroRect;
+}
+
+/**
+ * Listen to view resize delegate notifications, to track collapses triggered by dragging
+ * a view to zero size.
+ *
+ * Also forwards the event on to the delegate for further handling.
+ */
+- (void)splitViewDidResizeSubviews:(NSNotification *)notification
+{
+
+ // If the collapsible subview was collapsed using (for example) a drag,
+ // track the collapse correctly.
+ if (collapsibleSubviewIndex != NSNotFound && !collapsibleSubviewCollapsed) {
+ if ([[[self subviews] objectAtIndex:collapsibleSubviewIndex] isHidden]) {
+ [[[self subviews] objectAtIndex:collapsibleSubviewIndex] setHidden:NO];
+ [self setCollapsibleSubviewCollapsed:YES animate:NO];
+ }
+ }
+
+ // Do the same for expansions
+ if (collapsibleSubviewIndex != NSNotFound && collapsibleSubviewCollapsed) {
+ if (!animationTimer && [self _lengthOfView:[[self subviews] objectAtIndex:collapsibleSubviewIndex]]) {
+ [self setCollapsibleSubviewCollapsed:NO animate:NO];
+ }
+ }
+
+ if ([delegate respondsToSelector:@selector(splitViewDidResizeSubviews:)]) {
+ [delegate splitViewDidResizeSubviews:notification];
+ }
+}
+
+#pragma mark -
+#pragma mark Delegate method forwarding
+
+- (CGFloat)splitView:(NSSplitView *)splitView constrainSplitPosition:(CGFloat)proposedPosition ofSubviewAt:(NSInteger)dividerIndex
+{
+ if ([delegate respondsToSelector:@selector(splitView:constrainSplitPosition:ofSubviewAt:)]) {
+ return [delegate splitView:splitView constrainSplitPosition:proposedPosition ofSubviewAt:dividerIndex];
+ }
+
+ return proposedPosition;
+}
+
+- (NSRect)splitView:(NSSplitView *)splitView effectiveRect:(NSRect)proposedEffectiveRect forDrawnRect:(NSRect)drawnRect ofDividerAtIndex:(NSInteger)dividerIndex
+{
+ if ([delegate respondsToSelector:@selector(splitView:effectiveRect:forDrawnRect:ofDividerAtIndex:)]) {
+ return [delegate splitView:splitView effectiveRect:proposedEffectiveRect forDrawnRect:drawnRect ofDividerAtIndex:dividerIndex];
+ }
+
+ return proposedEffectiveRect;
+}
+
+- (BOOL)splitView:(NSSplitView *)splitView shouldAdjustSizeOfSubview:(NSView *)view
+{
+ if ([delegate respondsToSelector:@selector(splitView:shouldAdjustSizeOfSubview:)]) {
+ return [(id)delegate splitView:splitView shouldAdjustSizeOfSubview:view];
+ }
+
+ return YES;
+}
+
+- (void)splitView:(NSSplitView *)splitView resizeSubviewsWithOldSize:(NSSize)oldSize
+{
+ if ([delegate respondsToSelector:@selector(splitView:resizeSubviewsWithOldSize:)]) {
+ return [delegate splitView:splitView resizeSubviewsWithOldSize:oldSize];
+ }
+
+ return [self adjustSubviews];
+}
+
+- (void)splitViewWillResizeSubviews:(NSNotification *)notification
+{
+ if ([delegate respondsToSelector:@selector(splitViewWillResizeSubviews:)]) {
+ [delegate splitViewWillResizeSubviews:notification];
+ }
+}
+
+@end
+
+#pragma mark -
+#pragma mark Private API
+
+@implementation SPSplitView (Private_API)
+
+- (void)_initCustomProperties
+{
+ collapseToggleButton = nil;
+ additionalDragHandleView = nil;
+
+ collapsibleSubviewIndex = NSNotFound;
+ collapsibleSubviewCollapsed = NO;
+
+ animationStartTime = 0;
+ animationTimer = nil;
+ animationRetainCycleBypassObject = nil;
+
+ // Set up the maximum and minimum length arrays. Note that because there are no
+ // notifications for subviews being removed, these cannot be kept in sync with the
+ // actual view count - so these are only set via index, not view, and length-checked
+ // on every use for safety.
+ NSUInteger l = [[self subviews] count];
+ viewMinimumSizes = [[NSMutableArray alloc] initWithCapacity:l];
+ viewMaximumSizes = [[NSMutableArray alloc] initWithCapacity:l];
+ [self _ensureDefaultSubviewSizesToIndex:l-1];
+}
+
+/**
+ * Add default sizing information for a new subview up to at least a specified index;
+ * no maximum or minimum sizes for the subviews, but ensuring the arrays are set up.
+ */
+- (void)_ensureDefaultSubviewSizesToIndex:(NSUInteger)anIndex
+{
+ if ([viewMinimumSizes count] > anIndex) {
+ return;
+ }
+
+ for (NSUInteger i = [viewMinimumSizes count]; i <= anIndex; i++) {
+ [viewMinimumSizes addObject:[NSNumber numberWithFloat:0]];
+ [viewMaximumSizes addObject:[NSNumber numberWithFloat:FLT_MAX]];
+ }
+}
+
+#pragma mark -
+
+/**
+ * Generate an array of suggested view lengths along the split view lengthwise axis,
+ * respecting spring/strut or min/max size constraints as appropriate.
+ * If the supplied constraints cannot be respected, returns nil.
+ */
+- (NSArray *)_suggestedSizesForTargetSize:(CGFloat)targetSize respectingSpringsAndStruts:(BOOL)respectStruts respectingConstraints:(BOOL)respectConstraints
+{
+ NSUInteger i;
+ NSUInteger subviewCount = [[self subviews] count];
+ NSView *eachSubview;
+ BOOL viewIsAnimating;
+ float viewLength, sizeDifference, totalGive, changedLength;
+ float totalCurrentSize = 0;
+ float resizeProportionTotal = 1.f;
+ float *originalSizes = malloc(subviewCount * sizeof(float));
+ float *minSizes = malloc(subviewCount * sizeof(float));
+ float *maxSizes = malloc(subviewCount * sizeof(float));
+ BOOL *sizesCalculated;
+ float *resizeProportions;
+ NSMutableArray *outputSizes = [NSMutableArray arrayWithCapacity:subviewCount];
+
+ [self _ensureDefaultSubviewSizesToIndex:(subviewCount + 1)];
+
+ // Step through all the views, first getting a list of their initial sizes, as well as
+ // performing any animation-related cleanup
+ for (i = 0; i < subviewCount; i++) {
+ eachSubview = [[self subviews] objectAtIndex:i];
+ viewLength = [self _lengthOfView:eachSubview];
+ viewIsAnimating = (i == collapsibleSubviewIndex && animationTimer);
+
+ // Determine the min and max sizes for this view.
+ if (i == collapsibleSubviewIndex && collapsibleSubviewCollapsed && !viewIsAnimating) {
+ minSizes[i] = 0.f;
+ maxSizes[i] = 0.f;
+ } else if (i == collapsibleSubviewIndex && !viewLength && animationTargetSize && [eachSubview isKindOfClass:[SPSplitViewHelperView class]]) {
+ minSizes[i] = animationTargetSize;
+ maxSizes[i] = animationTargetSize;
+ } else if (respectStruts && ![self _isViewResizable:eachSubview]) {
+ minSizes[i] = viewLength;
+ maxSizes[i] = viewLength;
+ } else if (respectConstraints) {
+ minSizes[i] = [[viewMinimumSizes objectAtIndex:i] floatValue];
+ maxSizes[i] = [[viewMaximumSizes objectAtIndex:i] floatValue];
+ } else {
+ minSizes[i] = 0.f;
+ maxSizes[i] = FLT_MAX;
+ }
+
+ // If this isn't the collapsible subview, or if there's no collapse animation, measure
+ // the view and continue.
+ if (!viewIsAnimating) {
+ originalSizes[i] = viewLength;
+ totalCurrentSize += viewLength;
+ [outputSizes addObject:[NSNumber numberWithFloat:viewLength]];
+ continue;
+ }
+
+ // The collapsible subview is collapsing or uncollapsing. Prepare to update the sizes...
+ double currentTime = [NSDate monotonicTimeInterval];
+ float animationProgress = (float)((currentTime - animationStartTime) / animationDuration);
+ if (animationProgress > 1) animationProgress = 1;
+
+ // If the animation has reached the end, ensure completion tasks are run
+ if (animationProgress == 1) {
+ if (animationTimer) [animationTimer invalidate], [animationTimer release], animationTimer = nil;
+ if (animationRetainCycleBypassObject) [animationRetainCycleBypassObject release], animationRetainCycleBypassObject = nil;
+
+ // If uncollapsing, restore the original view and remove the helper
+ if (!collapsibleSubviewCollapsed) {
+ [(SPSplitViewHelperView *)eachSubview restoreOriginalView];
+ }
+ }
+
+ // Calculate the size for this point in the animation
+ if (collapsibleSubviewCollapsed) {
+ viewLength = animationStartSize * (1 - animationProgress);
+ } else {
+ viewLength = animationStartSize + ((animationTargetSize - animationStartSize) * animationProgress);
+ }
+ viewLength = roundf(viewLength);
+
+ // Max and min should always be clamped to the animated view size
+ minSizes[i] = viewLength;
+ maxSizes[i] = viewLength;
+
+ // Insert the modified view size
+ totalCurrentSize += viewLength;
+ originalSizes[i] = viewLength;
+ [outputSizes addObject:[NSNumber numberWithFloat:viewLength]];
+ }
+
+ sizeDifference = targetSize - totalCurrentSize;
+
+ // Compare the min/max lengths to the target length and see if there's sufficient give
+ // as well as working out the resize proportions
+ totalGive = 0;
+ for (i = 0; i < subviewCount; i++) {
+ if (sizeDifference > 0) {
+ if (maxSizes[i] == FLT_MAX) {
+ totalGive = FLT_MAX;
+ break;
+ }
+ totalGive += maxSizes[i] - originalSizes[i];
+ } else {
+ totalGive += originalSizes[i] - minSizes[i];
+ }
+ }
+
+ // If there isn't sufficient give, return nil to allow a retry with fewer constraints
+ if (totalGive < fabsf(sizeDifference)) {
+ free(originalSizes);
+ free(minSizes);
+ free(maxSizes);
+ return nil;
+ }
+
+ // Set up some arrays for fast lookups
+ sizesCalculated = malloc(subviewCount * sizeof(BOOL));
+ resizeProportions = malloc(subviewCount * sizeof(float));
+
+ // Prepopulate them
+ for (i = 0; i < subviewCount; i++) {
+ sizesCalculated[i] = NO;
+ if (!totalCurrentSize) {
+ resizeProportions[i] = 0.f;
+ } else {
+ resizeProportions[i] = originalSizes[i] / totalCurrentSize;
+ }
+ }
+
+ // In a loop, determine whether any constraints would be hit, and if so, match them
+ // and update remaining proportions.
+ BOOL iteratingConstraints = YES;
+ while (iteratingConstraints) {
+ iteratingConstraints = NO;
+ for (i = 0; i < subviewCount; i++) {
+ if (sizesCalculated[i]) continue;
+
+ // Check whether the size constraints are reached for this view. If so, record the
+ // limited view size, and break the loop.
+ viewLength = originalSizes[i] + (sizeDifference * resizeProportions[i]/resizeProportionTotal);
+ if (viewLength > maxSizes[i] || viewLength < minSizes[i]) {
+
+ // Track the change in size, if any
+ if (viewLength > maxSizes[i]) {
+ changedLength = maxSizes[i];
+ } else {
+ changedLength = minSizes[i];
+ }
+ sizeDifference = sizeDifference + originalSizes[i] - changedLength;
+
+ // Alter the overall proportion total modifier
+ resizeProportionTotal -= resizeProportions[i];
+
+ // Amend the output size and prepare to re-loop from the start
+ [outputSizes replaceObjectAtIndex:i withObject:[NSNumber numberWithFloat:changedLength]];
+ sizesCalculated[i] = YES;
+ iteratingConstraints = YES;
+ break;
+ }
+ }
+
+ // If, after any changes, all the remaining subview proportions are 0, resize
+ // them equally.
+ BOOL allSubviewsZeroSized = YES;
+ for (i = 0; i < subviewCount; i++) {
+ if (sizesCalculated[i]) continue;
+
+ if (resizeProportions[i] > 0.f) {
+ allSubviewsZeroSized = NO;
+ break;
+ }
+ }
+ if (allSubviewsZeroSized) {
+ resizeProportionTotal = 1.f;
+ for (i = 0; i < subviewCount; i++) {
+ if (sizesCalculated[i]) continue;
+ resizeProportions[i] = 1.f / subviewCount;
+ }
+ }
+ }
+
+ // All constraints have now been dealt with; populate all other output sizes proportionally.
+ for (i = 0; i < subviewCount; i++) {
+ if (sizesCalculated[i]) continue;
+
+ viewLength = originalSizes[i] + (sizeDifference * resizeProportions[i]/resizeProportionTotal);
+ [outputSizes replaceObjectAtIndex:i withObject:[NSNumber numberWithFloat:viewLength]];
+ }
+
+ // Clean up and return
+ free(originalSizes);
+ free(minSizes);
+ free(maxSizes);
+ free(sizesCalculated);
+ free(resizeProportions);
+
+ return outputSizes;
+}
+
+#pragma mark -
+
+/**
+ * Retrieve the start position of a view, using the lengthwise axis of the splitview.
+ */
+- (CGFloat)_startPositionOfView:(NSView *)aView
+{
+ if ([self isVertical]) {
+ return [aView frame].origin.x;
+ }
+ return [aView frame].origin.y;
+}
+
+/**
+ * Retrieve the length of a view, along the lengthwise axis of the splitview.
+ */
+- (CGFloat)_lengthOfView:(NSView *)aView
+{
+ if ([self isVertical]) {
+ return [aView frame].size.width;
+ }
+ return [aView frame].size.height;
+}
+
+/**
+ * Update the start position of a view, using the lengthwise axis of the splitview.
+ */
+- (void)_setStartPosition:(CGFloat)newOrigin ofView:(NSView *)aView
+{
+ if ([self isVertical]) {
+ return [aView setFrameOrigin:NSMakePoint(newOrigin, [aView frame].origin.y)];
+ }
+ return [aView setFrameOrigin:NSMakePoint([aView frame].origin.x, newOrigin)];
+}
+
+/**
+ * Update the length of a view, along the lengthwise axis of the splitview.
+ */
+- (void)_setLength:(CGFloat)newLength ofView:(NSView *)aView
+{
+ if ([self isVertical]) {
+ return [aView setFrameSize:NSMakeSize(newLength, [aView frame].size.height)];
+ }
+ return [aView setFrameSize:NSMakeSize([aView frame].size.width, newLength)];
+}
+
+#pragma mark -
+
+/**
+ * Determine whether the supplied view is defined as resizable along the split view's
+ * lengthwise axis in the xib files - whether springs/struts constrain resizing.
+ */
+- (BOOL)_isViewResizable:(NSView *)aView
+{
+ if ([self isVertical]) {
+ return ([aView autoresizingMask] & NSViewWidthSizable);
+ }
+ return ([aView autoresizingMask] & NSViewHeightSizable);
+}
+
+@end
+
+#pragma mark -
+#pragma mark Animation transition view class
+
+@implementation SPSplitViewHelperView
+
+/**
+ * Initialise the helper view with a specified view; the helper view replaces the
+ * specified view, adding it as a subview to maintain the same appearance, and then
+ * can be animated without affecting the contained view.
+ */
+- (id)initReplacingView:(NSView *)aView
+{
+ self = [super initWithFrame:[aView frame]];
+ if (!self) return nil;
+
+ // Retain the wrapped view while this view exists
+ wrappedView = [aView retain];
+
+ // Copy over the autoresizing mask from the wrapped view to this view, to keep the same
+ // draw appearance during the resize.
+ [self setAutoresizingMask:[wrappedView autoresizingMask]];
+
+ // Set the wrapped view to flexible margin, edge dependent on view ordering
+ if ([[[wrappedView superview] subviews] indexOfObject:wrappedView]) {
+ [wrappedView setAutoresizingMask:NSViewMinXMargin | NSViewMinYMargin];
+ } else {
+ [wrappedView setAutoresizingMask:NSViewMaxXMargin | NSViewMaxYMargin];
+ }
+
+ // Swap the views
+ [[wrappedView superview] replaceSubview:wrappedView with:self];
+ [wrappedView setFrameOrigin:NSMakePoint(0, 0)];
+ [self addSubview:wrappedView];
+
+ return self;
+}
+
+/**
+ * Restore the original view once the animation is complete. This should only
+ * be called when the view height has been restored.
+ */
+- (void)restoreOriginalView
+{
+
+ // Safety checks
+ if (!wrappedView || ![self frame].size.height || ![self frame].size.width) {
+ return;
+ }
+
+ // Check for a first responder to restore, using the "true" first responder for field editors
+ NSResponder *firstResponderToRestore = [[self window] firstResponder];
+ if ([firstResponderToRestore respondsToSelector:@selector(isFieldEditor)] && [(NSText *)firstResponderToRestore isFieldEditor]) {
+ firstResponderToRestore = [(NSText *)firstResponderToRestore delegate];
+ }
+ if (![firstResponderToRestore isKindOfClass:[NSView class]] || ![(NSView *)firstResponderToRestore isDescendantOf:wrappedView]) {
+ firstResponderToRestore = nil;
+ }
+
+ // Restore the view's original resize mark now that the size changes are complete
+ [wrappedView setAutoresizingMask:[self autoresizingMask]];
+
+ // Replace this view with the original wrapped view
+ [wrappedView removeFromSuperview];
+ [[self superview] replaceSubview:self with:wrappedView];
+
+ // Restore the first responder if appropriate
+ if (firstResponderToRestore) {
+ [[self window] makeFirstResponder:firstResponderToRestore];
+ }
+
+ [wrappedView release], wrappedView = nil;
+}
+
+- (void)dealloc
+{
+ if (wrappedView) [wrappedView release], wrappedView = nil;
+
+ [super dealloc];
+}
+
+@end
+
+#pragma mark -
+#pragma mark Retain cycle avoidance class
+
+@implementation SPSplitViewAnimationRetainCycleBypass
+
+- (id)initWithParent:(SPSplitView *)aSplitView
+{
+ self = [super init];
+ if (!self) return nil;
+
+ // Keep a weak link to the parent
+ parentSplitView = aSplitView;
+
+ return self;
+}
+
+- (void)_animationStep:(NSTimer *)aTimer
+{
+ [parentSplitView adjustSubviews];
+}
+
+@end
+
diff --git a/Source/SPTableInfo.h b/Source/SPTableInfo.h
index 48e56e0c..753060e8 100644
--- a/Source/SPTableInfo.h
+++ b/Source/SPTableInfo.h
@@ -33,7 +33,6 @@
IBOutlet NSTableView *activitiesTable;
IBOutlet NSScrollView *tableInfoScrollView;
- IBOutlet NSView *containerView;
NSMutableArray *info;
NSMutableArray *activities;
diff --git a/Source/SPTablesList.h b/Source/SPTablesList.h
index 368880f0..96b15b4c 100644
--- a/Source/SPTablesList.h
+++ b/Source/SPTablesList.h
@@ -24,13 +24,13 @@
// More info at <http://code.google.com/p/sequel-pro/>
@class SPHistoryController, SPTableView, SPMySQLConnection;
-@class SPDatabaseDocument, SPDatabaseData, SPTableStructure, SPTableContent;
+@class SPDatabaseDocument, SPDatabaseData, SPTableStructure, SPTableContent, SPSplitView;
#ifdef SP_REFACTOR
@class SQLSidebarViewController;
#endif
-@interface NSObject (NSSplitView)
+@interface NSObject (BWSplitView)
- (NSView *)collapsibleSubview;
- (IBAction)toggleCollapse:(id)sender;
@@ -83,9 +83,8 @@
IBOutlet id addTableButton;
#ifndef SP_REFACTOR
IBOutlet id truncateTableButton;
- IBOutlet NSSplitView *tableListSplitView;
- IBOutlet NSSplitView *tableListFilterSplitView;
- IBOutlet NSButton *tableInfoCollapseButton;
+ IBOutlet SPSplitView *tableListSplitView;
+ IBOutlet SPSplitView *tableListFilterSplitView;
IBOutlet NSSearchField *listFilterField;
diff --git a/Source/SPTablesList.m b/Source/SPTablesList.m
index 441fdeab..7387044b 100644
--- a/Source/SPTablesList.m
+++ b/Source/SPTablesList.m
@@ -50,6 +50,7 @@
#ifndef SP_REFACTOR /* headers */
#import "SPWindowController.h"
#import "SPAppController.h"
+#import "SPSplitView.h"
#endif
#ifdef SP_REFACTOR
@@ -131,29 +132,18 @@ static NSString *SPDuplicateTable = @"SPDuplicateTable";
- (void)awakeFromNib
{
#ifndef SP_REFACTOR
- // Collapse the table information pane if preference to do so is set
- if ([[[NSUserDefaults standardUserDefaults] objectForKey:SPTableInformationPanelCollapsed] boolValue]
- && [tableListSplitView collapsibleSubview]) {
- [tableInfoCollapseButton setNextState];
- [tableInfoCollapseButton setToolTip:NSLocalizedString(@"Show Table Information",@"Show Table Information")];
- [tableListSplitView setValue:[NSNumber numberWithFloat:[tableListSplitView collapsibleSubview].frame.size.height] forKey:@"uncollapsedSize"];
- [[tableListSplitView collapsibleSubview] setAutoresizesSubviews:NO];
- [[tableListSplitView collapsibleSubview] setFrameSize:NSMakeSize([tableListSplitView collapsibleSubview].frame.size.width, 0)];
- [tableListSplitView setCollapsibleSubviewCollapsed:YES];
- [[tableListSplitView collapsibleSubview] setAutoresizesSubviews:YES];
- }
- else {
- [tableInfoCollapseButton setToolTip:NSLocalizedString(@"Hide Table Information",@"Hide Table Information")];
- }
-
- // Start the table filter list collapsed
- if ([tableListFilterSplitView collapsibleSubview]) {
- [tableListFilterSplitView setValue:[NSNumber numberWithFloat:[tableListFilterSplitView collapsibleSubview].frame.size.height] forKey:@"uncollapsedSize"];
- // Set search bar view to the height of 1 instead of 0 to ensure that the view will be visible
- // after opening a next connection window which has more than 20 tables
- [[tableListFilterSplitView collapsibleSubview] setFrameSize:NSMakeSize([tableListFilterSplitView collapsibleSubview].frame.size.width, 1)];
- [tableListFilterSplitView setCollapsibleSubviewCollapsed:YES];
+
+ // Configure the table information pane
+ [tableListSplitView setCollapsibleSubviewIndex:1];
+
+ // Collapse the pane if the last state was collapsed
+ if ([[[NSUserDefaults standardUserDefaults] objectForKey:SPTableInformationPanelCollapsed] boolValue]) {
+ [tableListSplitView setCollapsibleSubviewCollapsed:YES animate:NO];
}
+
+ // Configure the table list filter, starting it collapsed
+ [tableListFilterSplitView setCollapsibleSubviewIndex:0];
+ [tableListFilterSplitView setCollapsibleSubviewCollapsed:YES animate:NO];
// Disable tab edit behaviour in the tables list
[tablesListView setTabEditingDisabled:YES];
@@ -670,8 +660,7 @@ static NSString *SPDuplicateTable = @"SPDuplicateTable";
{
[tableListSplitView toggleCollapse:sender];
- [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithBool:([tableInfoCollapseButton state] == NSOffState)] forKey:SPTableInformationPanelCollapsed];
- [tableInfoCollapseButton setToolTip:([tableInfoCollapseButton state] == NSOffState) ? NSLocalizedString(@"Show Table Information", @"Show Table Information") : NSLocalizedString(@"Hide Table Information", @"Hide Table Information")];
+ [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithBool:[tableListSplitView isCollapsibleSubviewCollapsed]] forKey:SPTableInformationPanelCollapsed];
}
#endif
@@ -1807,7 +1796,7 @@ static NSString *SPDuplicateTable = @"SPDuplicateTable";
*/
- (void) showFilter
{
- if ([tableListFilterSplitView collapsibleSubviewIsCollapsed]) {
+ if ([tableListFilterSplitView isCollapsibleSubviewCollapsed]) {
[tableListFilterSplitView performSelectorOnMainThread:@selector(toggleCollapse:) withObject:nil waitUntilDone:NO];
}
}
@@ -1818,7 +1807,7 @@ static NSString *SPDuplicateTable = @"SPDuplicateTable";
*/
- (void) hideFilter
{
- if (![tableListFilterSplitView collapsibleSubviewIsCollapsed]) {
+ if (![tableListFilterSplitView isCollapsibleSubviewCollapsed]) {
[tableListFilterSplitView performSelectorOnMainThread:@selector(toggleCollapse:) withObject:nil waitUntilDone:NO];
}
}
@@ -2000,10 +1989,38 @@ static NSString *SPDuplicateTable = @"SPDuplicateTable";
#pragma mark -
#pragma mark SplitView Delegate Methods
+/**
+ * Prevent the table info pane from being resized manually, by making the splitter
+ * not-selectable.
+ */
- (NSRect)splitView:(NSSplitView *)splitView effectiveRect:(NSRect)proposedEffectiveRect forDrawnRect:(NSRect)drawnRect ofDividerAtIndex:(NSInteger)dividerIndex
{
- return (splitView == tableListSplitView ? NSZeroRect : proposedEffectiveRect);
+ if (splitView == (NSSplitView *)tableListSplitView || splitView == (NSSplitView *)tableListFilterSplitView) {
+ return NSZeroRect;
+ }
+
+ return proposedEffectiveRect;
}
+
+/**
+ * Never show the divider bar for the table list filter split view.
+ */
+- (BOOL)splitView:(NSSplitView *)splitView shouldHideDividerAtIndex:(NSInteger)dividerIndex
+{
+ if (splitView == (NSSplitView *)tableListFilterSplitView) {
+ return YES;
+ }
+
+ // Because both the info pane split view and filter view split view use this class
+ // as a delegate, we now have to duplicate some logic in SPSplitView to match the
+ // default behaviour - thanks to the override above.
+ if (splitView == (NSSplitView *)tableListSplitView) {
+ return [tableListSplitView isSubviewCollapsed:[[tableListSplitView subviews] objectAtIndex:1]];
+ }
+
+ return NO;
+}
+
#endif
diff --git a/sequel-pro.xcodeproj/project.pbxproj b/sequel-pro.xcodeproj/project.pbxproj
index 43007b76..7b9b480e 100644
--- a/sequel-pro.xcodeproj/project.pbxproj
+++ b/sequel-pro.xcodeproj/project.pbxproj
@@ -334,6 +334,8 @@
58DC0D5F1293293400B76DA5 /* ShortcutRecorder.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 58DC0D5E1293293400B76DA5 /* ShortcutRecorder.framework */; };
58DC0D7C12932AB200B76DA5 /* ShortcutRecorder.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = 58DC0D5E1293293400B76DA5 /* ShortcutRecorder.framework */; };
58DC10D312A1B8DF00B76DA5 /* SPMenuAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 58DC10D212A1B8DF00B76DA5 /* SPMenuAdditions.m */; };
+ 58DF9F3315AB26C2003B4330 /* SPDateAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 58DF9F3215AB26C2003B4330 /* SPDateAdditions.m */; };
+ 58DF9F7315AB8509003B4330 /* SPSplitView.m in Sources */ = {isa = PBXBuildFile; fileRef = 58DF9F7215AB8509003B4330 /* SPSplitView.m */; };
58E205FC1234FE4F00A97059 /* KeyTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 58E205FB1234FE4F00A97059 /* KeyTemplate.pdf */; };
58FEF16D0F23D66600518E8E /* SPSQLParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 58FEF16C0F23D66600518E8E /* SPSQLParser.m */; };
58FEF57E0F3B4E9700518E8E /* SPTableData.m in Sources */ = {isa = PBXBuildFile; fileRef = 58FEF57D0F3B4E9700518E8E /* SPTableData.m */; };
@@ -1113,6 +1115,10 @@
58DC0D5E1293293400B76DA5 /* ShortcutRecorder.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ShortcutRecorder.framework; path = Frameworks/ShortcutRecorder.framework; sourceTree = "<group>"; };
58DC10D112A1B8DF00B76DA5 /* SPMenuAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SPMenuAdditions.h; sourceTree = "<group>"; };
58DC10D212A1B8DF00B76DA5 /* SPMenuAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SPMenuAdditions.m; sourceTree = "<group>"; };
+ 58DF9F3115AB26C2003B4330 /* SPDateAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SPDateAdditions.h; sourceTree = "<group>"; };
+ 58DF9F3215AB26C2003B4330 /* SPDateAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SPDateAdditions.m; sourceTree = "<group>"; };
+ 58DF9F7115AB8509003B4330 /* SPSplitView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SPSplitView.h; sourceTree = "<group>"; };
+ 58DF9F7215AB8509003B4330 /* SPSplitView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SPSplitView.m; sourceTree = "<group>"; };
58E205FB1234FE4F00A97059 /* KeyTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = KeyTemplate.pdf; sourceTree = "<group>"; };
58FEF16B0F23D66600518E8E /* SPSQLParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SPSQLParser.h; sourceTree = "<group>"; };
58FEF16C0F23D66600518E8E /* SPSQLParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SPSQLParser.m; sourceTree = "<group>"; };
@@ -2005,6 +2011,8 @@
584095181107CB6600260CFD /* SPAlertSheets.m */,
1798F19C15501892004B0AB8 /* SPFlippedView.h */,
1798F19D15501892004B0AB8 /* SPFlippedView.m */,
+ 58DF9F7115AB8509003B4330 /* SPSplitView.h */,
+ 58DF9F7215AB8509003B4330 /* SPSplitView.m */,
58C56EF30F438E120035701E /* SPDataCellFormatter.h */,
58C56EF40F438E120035701E /* SPDataCellFormatter.m */,
BC2898F1125F4488001B50E1 /* SPGeometryDataView.h */,
@@ -2533,6 +2541,8 @@
B57747D80F7A8990003B34F9 /* SPWindowAdditions.m */,
BC2C16D20FEBEDF10003993B /* SPDataAdditions.h */,
BC2C16D30FEBEDF10003993B /* SPDataAdditions.m */,
+ 58DF9F3115AB26C2003B4330 /* SPDateAdditions.h */,
+ 58DF9F3215AB26C2003B4330 /* SPDateAdditions.m */,
582A01E7107C0C170027D42B /* SPNotLoaded.h */,
582A01E8107C0C170027D42B /* SPNotLoaded.m */,
5870868210FA3E9C00D58E1C /* SPDataStorage.h */,
@@ -3249,6 +3259,8 @@
176E14D115570FE300FAF326 /* SPBundleCommandRunner.m in Sources */,
1748D50C15A4444F003562F2 /* SPTableStructureLoading.m in Sources */,
1748D58615A83E54003562F2 /* SPWindowManagement.m in Sources */,
+ 58DF9F3315AB26C2003B4330 /* SPDateAdditions.m in Sources */,
+ 58DF9F7315AB8509003B4330 /* SPSplitView.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};