diff options
author | rowanbeentje <rowan@beent.je> | 2012-07-23 00:35:01 +0000 |
---|---|---|
committer | rowanbeentje <rowan@beent.je> | 2012-07-23 00:35:01 +0000 |
commit | ea1516eeb991cedd2ea8d86d65fef4b102996b2b (patch) | |
tree | d2c128b5ad0f68b974e3c5e2a44c1c49fd33ce7f | |
parent | 78b52f5a0cea1fc1d0c944f5408e7ef41d0ca2d6 (diff) | |
download | sequelpro-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.xib | 443 | ||||
-rw-r--r-- | Resources/English.lproj/Localizable.strings | bin | 232178 -> 231846 bytes | |||
-rw-r--r-- | Source/SPConnectionHandler.m | 2 | ||||
-rw-r--r-- | Source/SPDatabaseDocument.h | 2 | ||||
-rw-r--r-- | Source/SPDatabaseDocument.m | 21 | ||||
-rw-r--r-- | Source/SPDateAdditions.h | 37 | ||||
-rw-r--r-- | Source/SPDateAdditions.m | 53 | ||||
-rw-r--r-- | Source/SPSplitView.h | 71 | ||||
-rw-r--r-- | Source/SPSplitView.m | 1094 | ||||
-rw-r--r-- | Source/SPTableInfo.h | 1 | ||||
-rw-r--r-- | Source/SPTablesList.h | 9 | ||||
-rw-r--r-- | Source/SPTablesList.m | 71 | ||||
-rw-r--r-- | sequel-pro.xcodeproj/project.pbxproj | 12 |
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 Binary files differindex ae7913fd..3bc0d800 100644 --- a/Resources/English.lproj/Localizable.strings +++ b/Resources/English.lproj/Localizable.strings 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; }; |