diff options
author | Bibiko <bibiko@eva.mpg.de> | 2009-09-28 10:41:24 +0000 |
---|---|---|
committer | Bibiko <bibiko@eva.mpg.de> | 2009-09-28 10:41:24 +0000 |
commit | 020cfd249c9022a2b84ae64786cdcbed42102217 (patch) | |
tree | 9ca5cde48ed30641427fb14b3b9cd97de581ac38 | |
parent | cc0c0a7842e3bff325fa29c71f5115361981797d (diff) | |
download | sequelpro-020cfd249c9022a2b84ae64786cdcbed42102217.tar.gz sequelpro-020cfd249c9022a2b84ae64786cdcbed42102217.tar.bz2 sequelpro-020cfd249c9022a2b84ae64786cdcbed42102217.zip |
• rewrote the content filter logic:
- all default filters come from "ContentFilters.plist" which can be localized
main structure:
<plist>
<dict>
<key>number</key>
<array/>
<key>string</key>
<array/>
<key>date</key>
<array/>
</dict>
</plist>
filter item structure: [ ${} is a place holder for an argument ]
<dict>
<key>MenuLabel</key>
<string>BETWEEN</string>
<key>Tooltip>
<string>a tooltip</string>
<key>NumberOfArguments</key>
<integer>2</integer>
<key>ConjunctionLabels</key>
<array>
<string>AND</string>
</array>
<key>Clause</key>
<string>BETWEEN '${}' AND '${}'</string>
</dict>
- if NumberOfArguments == 0 then start filtering automatically
- now one can save his/her own filters in SP's preferences.plist (GUI follows soon)
- fixed issue for filters requiring two arguments that pressing RETURN if one is in the second argument input field invokes "Filter"
- added string operators: "IS EMPTY" and "IS NOT EMPTY"
- fixed issue that now one is able to look for eg \n in string fields
-rw-r--r-- | Interfaces/English.lproj/DBView.xib | 90 | ||||
-rw-r--r-- | Resources/English.lproj/ContentFilters.plist | 270 | ||||
-rw-r--r-- | Resources/PreferenceDefaults.plist | 9 | ||||
-rw-r--r-- | Source/TableContent.h | 2 | ||||
-rw-r--r-- | Source/TableContent.m | 363 |
5 files changed, 499 insertions, 235 deletions
diff --git a/Interfaces/English.lproj/DBView.xib b/Interfaces/English.lproj/DBView.xib index c74c3c18..f74d906d 100644 --- a/Interfaces/English.lproj/DBView.xib +++ b/Interfaces/English.lproj/DBView.xib @@ -23,13 +23,13 @@ </object> <object class="NSMutableArray" key="IBDocument.EditedObjectIDs"> <bool key="EncodedWithXMLCoder">YES</bool> - <integer value="231"/> + <integer value="27"/> </object> <object class="NSArray" key="IBDocument.PluginDependencies"> <bool key="EncodedWithXMLCoder">YES</bool> <string>com.brandonwalkin.BWToolkit</string> - <string>com.apple.WebKitIBPlugin</string> <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <string>com.apple.WebKitIBPlugin</string> </object> <object class="NSMutableDictionary" key="IBDocument.Metadata"> <bool key="EncodedWithXMLCoder">YES</bool> @@ -59,7 +59,7 @@ <string key="NSWindowTitle">Connecting...</string> <string key="NSWindowClass">NSWindow</string> <string key="NSViewClass">View</string> - <string key="NSWindowContentMaxSize">{3.40282e+38, 3.40282e+38}</string> + <string key="NSWindowContentMaxSize">{1.79769e+308, 1.79769e+308}</string> <string key="NSWindowContentMinSize">{780, 480}</string> <object class="NSView" key="NSWindowView" id="579726586"> <reference key="NSNextResponder"/> @@ -310,7 +310,7 @@ <string key="NSColorName">controlColor</string> <object class="NSColor" key="NSColor" id="1001122760"> <int key="NSColorSpace">3</int> - <bytes key="NSWhite">MC42NjY2NjY2ODY1AA</bytes> + <bytes key="NSWhite">MC42NjY2NjY2NjY3AA</bytes> </object> </object> <reference key="NSTextColor" ref="454249633"/> @@ -815,7 +815,7 @@ <object class="NSTabViewItem" id="831053945"> <string key="NSIdentifier">source</string> <object class="NSView" key="NSView" id="461236772"> - <reference key="NSNextResponder" ref="714795046"/> + <nil key="NSNextResponder"/> <int key="NSvFlags">256</int> <object class="NSMutableArray" key="NSSubviews"> <bool key="EncodedWithXMLCoder">YES</bool> @@ -2073,7 +2073,6 @@ </object> </object> <string key="NSFrame">{{10, 7}, {700, 544}}</string> - <reference key="NSSuperview" ref="714795046"/> </object> <string key="NSLabel">Structure</string> <reference key="NSColor" ref="62854682"/> @@ -2082,7 +2081,7 @@ <object class="NSTabViewItem" id="624106058"> <string key="NSIdentifier">content</string> <object class="NSView" key="NSView" id="1013108064"> - <nil key="NSNextResponder"/> + <reference key="NSNextResponder" ref="714795046"/> <int key="NSvFlags">256</int> <object class="NSMutableArray" key="NSSubviews"> <bool key="EncodedWithXMLCoder">YES</bool> @@ -2542,7 +2541,7 @@ <object class="NSPopUpButton" id="830088955"> <reference key="NSNextResponder" ref="894187833"/> <int key="NSvFlags">266</int> - <string key="NSFrame">{{54, 3}, {102, 20}}</string> + <string key="NSFrame">{{51, 3}, {102, 20}}</string> <reference key="NSSuperview" ref="894187833"/> <bool key="NSEnabled">YES</bool> <object class="NSPopUpButtonCell" key="NSCell" id="376863254"> @@ -2590,7 +2589,7 @@ <object class="NSPopUpButton" id="744029762"> <reference key="NSNextResponder" ref="894187833"/> <int key="NSvFlags">265</int> - <string key="NSFrame">{{161, 0}, {89, 25}}</string> + <string key="NSFrame">{{158, 0}, {95, 25}}</string> <reference key="NSSuperview" ref="894187833"/> <bool key="NSEnabled">YES</bool> <object class="NSPopUpButtonCell" key="NSCell" id="105542136"> @@ -2843,6 +2842,8 @@ <int key="NSPeriodicInterval">75</int> </object> <int key="NSMaximumRecents">255</int> + <bool key="NSSendsWholeSearchString">YES</bool> + <bytes key="NSSearchFieldFlags">CAAAAA</bytes> </object> </object> </object> @@ -2858,6 +2859,7 @@ </object> </object> <string key="NSFrame">{{10, 7}, {700, 544}}</string> + <reference key="NSSuperview" ref="714795046"/> </object> <string key="NSLabel">Content</string> <reference key="NSColor" ref="62854682"/> @@ -4759,14 +4761,14 @@ <reference key="NSTabView" ref="714795046"/> </object> </object> - <reference key="NSSelectedTabViewItem" ref="831053945"/> + <reference key="NSSelectedTabViewItem" ref="624106058"/> <reference key="NSFont" ref="26"/> <int key="NSTvFlags">134217731</int> <bool key="NSAllowTruncatedLabels">YES</bool> <bool key="NSDrawsBackground">YES</bool> <object class="NSMutableArray" key="NSSubviews"> <bool key="EncodedWithXMLCoder">YES</bool> - <reference ref="461236772"/> + <reference ref="1013108064"/> </object> </object> </object> @@ -4786,7 +4788,7 @@ </object> <string key="NSScreenRect">{{0, 0}, {1920, 1178}}</string> <string key="NSMinSize">{780, 502}</string> - <string key="NSMaxSize">{3.40282e+38, 3.40282e+38}</string> + <string key="NSMaxSize">{1.79769e+308, 1.79769e+308}</string> <string key="NSFrameAutosaveName"/> </object> <object class="NSWindowTemplate" id="554105051"> @@ -5957,7 +5959,7 @@ <object class="NSMutableString" key="NSViewClass"> <characters key="NS.bytes">View</characters> </object> - <string key="NSWindowContentMaxSize">{3.40282e+38, 3.40282e+38}</string> + <string key="NSWindowContentMaxSize">{1.79769e+308, 1.79769e+308}</string> <string key="NSWindowContentMinSize">{213, 107}</string> <object class="NSView" key="NSWindowView" id="329225443"> <nil key="NSNextResponder"/> @@ -6236,7 +6238,7 @@ </object> <string key="NSScreenRect">{{0, 0}, {1440, 878}}</string> <string key="NSMinSize">{213, 129}</string> - <string key="NSMaxSize">{3.40282e+38, 3.40282e+38}</string> + <string key="NSMaxSize">{1.79769e+308, 1.79769e+308}</string> </object> <object class="NSWindowTemplate" id="734744289"> <int key="NSWindowStyleMask">1</int> @@ -6248,7 +6250,7 @@ <object class="NSMutableString" key="NSViewClass"> <characters key="NS.bytes">View</characters> </object> - <string key="NSWindowContentMaxSize">{3.40282e+38, 3.40282e+38}</string> + <string key="NSWindowContentMaxSize">{1.79769e+308, 1.79769e+308}</string> <string key="NSWindowContentMinSize">{213, 107}</string> <object class="NSView" key="NSWindowView" id="234287744"> <nil key="NSNextResponder"/> @@ -6404,7 +6406,7 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string> </object> <string key="NSScreenRect">{{0, 0}, {1440, 878}}</string> <string key="NSMinSize">{213, 129}</string> - <string key="NSMaxSize">{3.40282e+38, 3.40282e+38}</string> + <string key="NSMaxSize">{1.79769e+308, 1.79769e+308}</string> </object> <object class="NSWindowTemplate" id="787219800"> <int key="NSWindowStyleMask">1</int> @@ -6414,7 +6416,7 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string> <string key="NSWindowTitle">New Relation</string> <string key="NSWindowClass">NSPanel</string> <nil key="NSViewClass"/> - <string key="NSWindowContentMaxSize">{3.40282e+38, 3.40282e+38}</string> + <string key="NSWindowContentMaxSize">{1.79769e+308, 1.79769e+308}</string> <object class="NSView" key="NSWindowView" id="842408319"> <nil key="NSNextResponder"/> <int key="NSvFlags">256</int> @@ -7015,7 +7017,7 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string> <string key="NSFrameSize">{302, 307}</string> </object> <string key="NSScreenRect">{{0, 0}, {1440, 878}}</string> - <string key="NSMaxSize">{3.40282e+38, 3.40282e+38}</string> + <string key="NSMaxSize">{1.79769e+308, 1.79769e+308}</string> </object> <object class="NSWindowTemplate" id="1066802919"> <int key="NSWindowStyleMask">3</int> @@ -7027,7 +7029,7 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string> <object class="NSMutableString" key="NSViewClass"> <characters key="NS.bytes">View</characters> </object> - <string key="NSWindowContentMaxSize">{3.40282e+38, 3.40282e+38}</string> + <string key="NSWindowContentMaxSize">{1.79769e+308, 1.79769e+308}</string> <string key="NSWindowContentMinSize">{213, 50}</string> <object class="NSView" key="NSWindowView" id="525490268"> <nil key="NSNextResponder"/> @@ -7147,7 +7149,7 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string> </object> <string key="NSScreenRect">{{0, 0}, {1920, 1178}}</string> <string key="NSMinSize">{213, 72}</string> - <string key="NSMaxSize">{3.40282e+38, 3.40282e+38}</string> + <string key="NSMaxSize">{1.79769e+308, 1.79769e+308}</string> </object> <object class="NSWindowTemplate" id="553728448"> <int key="NSWindowStyleMask">9</int> @@ -7159,7 +7161,7 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string> <object class="NSMutableString" key="NSViewClass"> <characters key="NS.bytes">View</characters> </object> - <string key="NSWindowContentMaxSize">{3.40282e+38, 3.40282e+38}</string> + <string key="NSWindowContentMaxSize">{1.79769e+308, 1.79769e+308}</string> <string key="NSWindowContentMinSize">{213, 107}</string> <object class="NSView" key="NSWindowView" id="1052076676"> <nil key="NSNextResponder"/> @@ -7294,7 +7296,7 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string> </object> <string key="NSScreenRect">{{0, 0}, {1440, 878}}</string> <string key="NSMinSize">{213, 129}</string> - <string key="NSMaxSize">{3.40282e+38, 3.40282e+38}</string> + <string key="NSMaxSize">{1.79769e+308, 1.79769e+308}</string> </object> <object class="NSWindowTemplate" id="202784209"> <int key="NSWindowStyleMask">15</int> @@ -7306,7 +7308,7 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string> <object class="NSMutableString" key="NSViewClass"> <characters key="NS.bytes">View</characters> </object> - <string key="NSWindowContentMaxSize">{3.40282e+38, 3.40282e+38}</string> + <string key="NSWindowContentMaxSize">{1.79769e+308, 1.79769e+308}</string> <string key="NSWindowContentMinSize">{350, 200}</string> <object class="NSView" key="NSWindowView" id="226131408"> <nil key="NSNextResponder"/> @@ -7610,7 +7612,7 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string> </object> <string key="NSScreenRect">{{0, 0}, {1440, 878}}</string> <string key="NSMinSize">{350, 222}</string> - <string key="NSMaxSize">{3.40282e+38, 3.40282e+38}</string> + <string key="NSMaxSize">{1.79769e+308, 1.79769e+308}</string> </object> <object class="NSWindowTemplate" id="135079060"> <int key="NSWindowStyleMask">8219</int> @@ -7620,7 +7622,7 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string> <string key="NSWindowTitle">Create Table Syntax</string> <string key="NSWindowClass">NSPanel</string> <nil key="NSViewClass"/> - <string key="NSWindowContentMaxSize">{3.40282e+38, 3.40282e+38}</string> + <string key="NSWindowContentMaxSize">{1.79769e+308, 1.79769e+308}</string> <string key="NSWindowContentMinSize">{120, 100}</string> <object class="NSView" key="NSWindowView" id="661948784"> <nil key="NSNextResponder"/> @@ -7680,9 +7682,9 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string> </object> <object class="NSMutableArray" key="dict.values"> <bool key="EncodedWithXMLCoder">YES</bool> - <object class="NSColor" id="929581604"> + <object class="NSColor" id="1029043619"> <int key="NSColorSpace">1</int> - <bytes key="NSRGB">MC45MDE5NjA3OTAyIDAuOTAxOTYwNzkwMiAwLjkwMTk2MDc5MDIAA</bytes> + <bytes key="NSRGB">MC45MDE5NjA3OSAwLjkwMTk2MDc5IDAuOTAxOTYwNzkAA</bytes> </object> <object class="NSFont" id="188091016"> <string key="NSName">LucidaGrande</string> @@ -7803,7 +7805,7 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string> </object> <object class="NSMutableArray" key="dict.values"> <bool key="EncodedWithXMLCoder">YES</bool> - <reference ref="929581604"/> + <reference ref="1029043619"/> <object class="NSFont" id="25"> <string key="NSName">LucidaGrande-Bold</string> <double key="NSSize">10</double> @@ -7923,7 +7925,7 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string> <int key="NSArrowsLoc">2</int> <reference key="NSTarget" ref="992507944"/> <string key="NSAction">_doScroller:</string> - <double key="NSPercent">0.84027779102325439</double> + <double key="NSPercent">0.84027777777777779</double> </object> <object class="NSScroller" id="655849727"> <reference key="NSNextResponder" ref="992507944"/> @@ -7950,7 +7952,7 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string> </object> <string key="NSScreenRect">{{0, 0}, {1440, 878}}</string> <string key="NSMinSize">{120, 119}</string> - <string key="NSMaxSize">{3.40282e+38, 3.40282e+38}</string> + <string key="NSMaxSize">{1.79769e+308, 1.79769e+308}</string> <string key="NSFrameAutosaveName">createTableSyntaxWindow</string> </object> <object class="NSWindowTemplate" id="466147946"> @@ -7963,7 +7965,7 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string> <object class="NSMutableString" key="NSViewClass"> <characters key="NS.bytes">View</characters> </object> - <string key="NSWindowContentMaxSize">{3.40282e+38, 3.40282e+38}</string> + <string key="NSWindowContentMaxSize">{1.79769e+308, 1.79769e+308}</string> <string key="NSWindowContentMinSize">{213, 107}</string> <object class="NSView" key="NSWindowView" id="860968037"> <nil key="NSNextResponder"/> @@ -8112,7 +8114,7 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string> </object> <string key="NSScreenRect">{{0, 0}, {1440, 878}}</string> <string key="NSMinSize">{213, 129}</string> - <string key="NSMaxSize">{3.40282e+38, 3.40282e+38}</string> + <string key="NSMaxSize">{1.79769e+308, 1.79769e+308}</string> </object> <object class="NSWindowTemplate" id="78186995"> <int key="NSWindowStyleMask">31</int> @@ -8122,7 +8124,7 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string> <string key="NSWindowTitle">MySQL Help</string> <string key="NSWindowClass">NSPanel</string> <nil key="NSViewClass"/> - <string key="NSWindowContentMaxSize">{3.40282e+38, 3.40282e+38}</string> + <string key="NSWindowContentMaxSize">{1.79769e+308, 1.79769e+308}</string> <string key="NSWindowContentMinSize">{351, 120}</string> <object class="NSView" key="NSWindowView" id="539508428"> <nil key="NSNextResponder"/> @@ -8516,7 +8518,7 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string> </object> <string key="NSScreenRect">{{0, 0}, {1280, 1002}}</string> <string key="NSMinSize">{351, 136}</string> - <string key="NSMaxSize">{3.40282e+38, 3.40282e+38}</string> + <string key="NSMaxSize">{1.79769e+308, 1.79769e+308}</string> <string key="NSFrameAutosaveName">MYSQL_HELP_WINDOW</string> </object> <object class="NSWindowTemplate" id="176945499"> @@ -8529,7 +8531,7 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string> <object class="NSMutableString" key="NSViewClass"> <characters key="NS.bytes">View</characters> </object> - <string key="NSWindowContentMaxSize">{3.40282e+38, 3.40282e+38}</string> + <string key="NSWindowContentMaxSize">{1.79769e+308, 1.79769e+308}</string> <string key="NSWindowContentMinSize">{350, 250}</string> <object class="NSView" key="NSWindowView" id="1024486775"> <nil key="NSNextResponder"/> @@ -8916,7 +8918,7 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string> </object> <string key="NSScreenRect">{{0, 0}, {1920, 1178}}</string> <string key="NSMinSize">{350, 272}</string> - <string key="NSMaxSize">{3.40282e+38, 3.40282e+38}</string> + <string key="NSMaxSize">{1.79769e+308, 1.79769e+308}</string> </object> <object class="NSWindowTemplate" id="434046103"> <int key="NSWindowStyleMask">9</int> @@ -9049,7 +9051,7 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string> <string key="NSWindowTitle">Secure Text Input Sheet</string> <string key="NSWindowClass">NSPanel</string> <nil key="NSViewClass"/> - <string key="NSWindowContentMaxSize">{3.40282e+38, 3.40282e+38}</string> + <string key="NSWindowContentMaxSize">{1.79769e+308, 1.79769e+308}</string> <object class="NSView" key="NSWindowView" id="978976687"> <nil key="NSNextResponder"/> <int key="NSvFlags">256</int> @@ -9153,7 +9155,7 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string> <string key="NSFrameSize">{338, 138}</string> </object> <string key="NSScreenRect">{{0, 0}, {1280, 778}}</string> - <string key="NSMaxSize">{3.40282e+38, 3.40282e+38}</string> + <string key="NSMaxSize">{1.79769e+308, 1.79769e+308}</string> </object> <object class="NSCustomView" id="139279766"> <nil key="NSNextResponder"/> @@ -11549,7 +11551,7 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string> <string key="NSColorName">disabledControlTextColor</string> <object class="NSColor" key="NSColor"> <int key="NSColorSpace">3</int> - <bytes key="NSWhite">MC4zMzMzMzMzNDMzAA</bytes> + <bytes key="NSWhite">MC4zMzMzMzMzMzMzAA</bytes> </object> </object> </object> @@ -15676,6 +15678,14 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string> </object> <int key="connectionID">6534</int> </object> + <object class="IBConnectionRecord"> + <object class="IBActionConnection" key="connection"> + <string key="label">filterTable:</string> + <reference key="source" ref="392169872"/> + <reference key="destination" ref="538700903"/> + </object> + <int key="connectionID">6536</int> + </object> </object> <object class="IBMutableOrderedSet" key="objectRecords"> <object class="NSArray" key="orderedObjects"> @@ -25455,7 +25465,7 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string> </object> </object> <nil key="sourceID"/> - <int key="maxID">6534</int> + <int key="maxID">6536</int> </object> <object class="IBClassDescriber" key="IBDocument.Classes"> <object class="NSMutableArray" key="referencedPartialClassDescriptions"> diff --git a/Resources/English.lproj/ContentFilters.plist b/Resources/English.lproj/ContentFilters.plist index 4768f16b..2f52c6af 100644 --- a/Resources/English.lproj/ContentFilters.plist +++ b/Resources/English.lproj/ContentFilters.plist @@ -1,7 +1,269 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> -<plist version="1.0"> +<?xml version='1.0' encoding='UTF-8'?> +<!DOCTYPE plist PUBLIC '-//Apple//DTD PLIST 1.0//EN' 'http://www.apple.com/DTDs/PropertyList-1.0.dtd'> +<plist version='1.0'> <dict> - + <key>number</key> + <array> + <dict> + <key>MenuLabel</key> + <string>=</string> + <key>NumberOfArguments</key> + <integer>1</integer> + <key>Clause</key> + <string>= '${}'</string> + </dict> + <dict> + <key>MenuLabel</key> + <string>≠</string> + <key>NumberOfArguments</key> + <integer>1</integer> + <key>Clause</key> + <string>!= '${}'</string> + </dict> + <dict> + <key>MenuLabel</key> + <string>></string> + <key>NumberOfArguments</key> + <integer>1</integer> + <key>Clause</key> + <string>> '${}'</string> + </dict> + <dict> + <key>MenuLabel</key> + <string><</string> + <key>NumberOfArguments</key> + <integer>1</integer> + <key>Clause</key> + <string>< '${}'</string> + </dict> + <dict> + <key>MenuLabel</key> + <string>≥</string> + <key>NumberOfArguments</key> + <integer>1</integer> + <key>Clause</key> + <string>>= '${}'</string> + </dict> + <dict> + <key>MenuLabel</key> + <string>≤</string> + <key>NumberOfArguments</key> + <integer>1</integer> + <key>Clause</key> + <string><= '${}'</string> + </dict> + <dict> + <key>MenuLabel</key> + <string>IN</string> + <key>NumberOfArguments</key> + <integer>1</integer> + <key>Clause</key> + <string>IN (${})</string> + </dict> + <dict> + <key>MenuLabel</key> + <string>LIKE</string> + <key>NumberOfArguments</key> + <integer>1</integer> + <key>Clause</key> + <string>LIKE '${}'</string> + </dict> + <dict> + <key>MenuLabel</key> + <string>BETWEEN</string> + <key>NumberOfArguments</key> + <integer>2</integer> + <key>ConjunctionLabels</key> + <array> + <string>AND</string> + </array> + <key>Clause</key> + <string>BETWEEN '${}' AND '${}'</string> + </dict> + <dict> + <key>MenuLabel</key> + <string>IS NULL</string> + <key>NumberOfArguments</key> + <integer>0</integer> + <key>Clause</key> + <string>IS NULL</string> + </dict> + <dict> + <key>MenuLabel</key> + <string>IS NOT NULL</string> + <key>NumberOfArguments</key> + <integer>0</integer> + <key>Clause</key> + <string>IS NOT NULL</string> + </dict> + </array> + <key>string</key> + <array> + <dict> + <key>MenuLabel</key> + <string>IS</string> + <key>NumberOfArguments</key> + <integer>1</integer> + <key>Clause</key> + <string>LIKE '${}'</string> + </dict> + <dict> + <key>MenuLabel</key> + <string>IS NOT</string> + <key>NumberOfArguments</key> + <integer>1</integer> + <key>Clause</key> + <string>NOT LIKE '${}'</string> + </dict> + <dict> + <key>MenuLabel</key> + <string>contains</string> + <key>NumberOfArguments</key> + <integer>1</integer> + <key>Clause</key> + <string>LIKE '%${}%'</string> + </dict> + <dict> + <key>MenuLabel</key> + <string>contains not</string> + <key>NumberOfArguments</key> + <integer>1</integer> + <key>Clause</key> + <string>NOT LIKE '%${}%'</string> + </dict> + <dict> + <key>MenuLabel</key> + <string>IN</string> + <key>NumberOfArguments</key> + <integer>1</integer> + <key>Clause</key> + <string>IN (${})</string> + <key>Tooltip</key> + <string>Do quote strings manually.</string> + </dict> + <dict> + <key>MenuLabel</key> + <string>BETWEEN</string> + <key>NumberOfArguments</key> + <integer>2</integer> + <key>ConjunctionLabels</key> + <array> + <string>AND</string> + </array> + <key>Clause</key> + <string>BETWEEN '${}' AND '${}'</string> + </dict> + <dict> + <key>MenuLabel</key> + <string>IS NULL</string> + <key>NumberOfArguments</key> + <integer>0</integer> + <key>Clause</key> + <string>IS NULL</string> + </dict> + <dict> + <key>MenuLabel</key> + <string>IS NOT NULL</string> + <key>NumberOfArguments</key> + <integer>0</integer> + <key>Clause</key> + <string>IS NOT NULL</string> + </dict> + <dict> + <key>MenuLabel</key> + <string>IS EMPTY</string> + <key>NumberOfArguments</key> + <integer>0</integer> + <key>Clause</key> + <string>LIKE ''</string> + </dict> + <dict> + <key>MenuLabel</key> + <string>IS NOT EMPTY</string> + <key>NumberOfArguments</key> + <integer>0</integer> + <key>Clause</key> + <string>NOT LIKE ''</string> + </dict> + </array> + <key>date</key> + <array> + <dict> + <key>MenuLabel</key> + <string>IS</string> + <key>NumberOfArguments</key> + <integer>1</integer> + <key>Clause</key> + <string>= '${}'</string> + </dict> + <dict> + <key>MenuLabel</key> + <string>IS NOT</string> + <key>NumberOfArguments</key> + <integer>1</integer> + <key>Clause</key> + <string>!= '${}'</string> + </dict> + <dict> + <key>MenuLabel</key> + <string>is after</string> + <key>NumberOfArguments</key> + <integer>1</integer> + <key>Clause</key> + <string>> '${}'</string> + </dict> + <dict> + <key>MenuLabel</key> + <string>is before</string> + <key>NumberOfArguments</key> + <integer>1</integer> + <key>Clause</key> + <string>< '${}'</string> + </dict> + <dict> + <key>MenuLabel</key> + <string>is after or equal to</string> + <key>NumberOfArguments</key> + <integer>1</integer> + <key>Clause</key> + <string>>= '${}'</string> + </dict> + <dict> + <key>MenuLabel</key> + <string>is before or equal to</string> + <key>NumberOfArguments</key> + <integer>1</integer> + <key>Clause</key> + <string><= '${}'</string> + </dict> + <dict> + <key>MenuLabel</key> + <string>BETWEEN</string> + <key>NumberOfArguments</key> + <integer>2</integer> + <key>ConjunctionLabels</key> + <array> + <string>AND</string> + </array> + <key>Clause</key> + <string>BETWEEN '${}' AND '${}'</string> + </dict> + <dict> + <key>MenuLabel</key> + <string>IS NULL</string> + <key>NumberOfArguments</key> + <integer>0</integer> + <key>Clause</key> + <string>IS NULL</string> + </dict> + <dict> + <key>MenuLabel</key> + <string>IS NOT NULL</string> + <key>NumberOfArguments</key> + <integer>0</integer> + <key>Clause</key> + <string>IS NOT NULL</string> + </dict> + </array> </dict> </plist> diff --git a/Resources/PreferenceDefaults.plist b/Resources/PreferenceDefaults.plist index 33964fbb..e6b1c52e 100644 --- a/Resources/PreferenceDefaults.plist +++ b/Resources/PreferenceDefaults.plist @@ -109,6 +109,13 @@ <key>QuickLookTypes</key> <array/> <key>ContentFilters</key> - <array/> + <dict> + <key>number</key> + <array/> + <key>string</key> + <array/> + <key>date</key> + <array/> + </dict> </dict> </plist> diff --git a/Source/TableContent.h b/Source/TableContent.h index 75b342f6..a498189b 100644 --- a/Source/TableContent.h +++ b/Source/TableContent.h @@ -67,6 +67,8 @@ NSUserDefaults *prefs; int currentlyEditingRow, maxNumRows; + NSMutableDictionary *contentFilters; + BOOL sortColumnToRestoreIsAsc; NSString *sortColumnToRestore; unsigned int limitStartPositionToRestore; diff --git a/Source/TableContent.m b/Source/TableContent.m index 19cb1dcf..ed9cf237 100644 --- a/Source/TableContent.m +++ b/Source/TableContent.m @@ -44,6 +44,8 @@ #import "QLPreviewPanel.h" #import "SPFieldEditorController.h" #import "SPTooltip.h" +#import "RegexKitLite.h" + @implementation TableContent @@ -82,6 +84,22 @@ prefs = [NSUserDefaults standardUserDefaults]; usedQuery = [[NSString alloc] initWithString:@""]; + + // Init default filters for Content Browser + contentFilters = nil; + NSError *readError = nil; + NSString *convError = nil; + NSPropertyListFormat format; + NSData *defaultFilterData = [NSData dataWithContentsOfFile:[NSBundle pathForResource:@"ContentFilters.plist" ofType:nil inDirectory:[[NSBundle mainBundle] bundlePath]] + options:NSMappedRead error:&readError]; + contentFilters = [[NSMutableDictionary alloc] init]; + [contentFilters setDictionary:[NSPropertyListSerialization propertyListFromData:defaultFilterData + mutabilityOption:NSPropertyListMutableContainersAndLeaves format:&format errorDescription:&convError]]; + if(contentFilters == nil || readError != nil || convError != nil) { + NSLog(@"Error while reading 'ContentFilters.plist':\n%@\n%@", [readError localizedDescription], convError); + NSBeep(); + } + } return self; @@ -495,185 +513,109 @@ */ - (NSString *)tableFilterString { - BOOL doQuote = YES; - BOOL ignoreArgument = NO; + NSString *filterString; - NSString *compareOperator = @""; - int tag = [[compareField selectedItem] tag]; - - // Filter arguments + + if(contentFilters == nil) { + NSLog(@"Fatal error while retrieving content filters. No filters found."); + NSBeep(); + return nil; + } + + // Current selected filter type + if(![contentFilters objectForKey:compareType]) { + NSLog(@"Error while retrieving filters. Filter type “%@” unknown.", compareType); + NSBeep(); + return nil; + } + NSDictionary *filter = [[contentFilters objectForKey:compareType] objectAtIndex:[[compareField selectedItem] tag]]; + + if(![filter objectForKey:@"Clause"] || ![filter objectForKey:@"NumberOfArguments"]) { + NSLog(@"Error while retrieving filter clause. No “Clause” or/and “NumberOfArguments” key found."); + NSBeep(); + return nil; + } + + NSUInteger numberOfArguments = [[filter objectForKey:@"NumberOfArguments"] intValue]; + + // argument if Filter requires only one argument NSMutableString *argument = [[NSMutableString alloc] initWithString:[argumentField stringValue]]; - NSString *firstBetweenArgument = [firstBetweenField stringValue]; - NSString *secondBetweenArgument = [secondBetweenField stringValue]; - // If the filter field is empty and the selected filter is not looking - // for NULLs or NOT NULLs, then no filtering is required - return nil. - if (([argument length] == 0) && (![[[compareField selectedItem] title] hasSuffix:@"NULL"]) && (![[[compareField selectedItem] title] isEqualToString:@"BETWEEN"])) { + // If the filter field is empty and the selected filter does not require + // only one argument, then no filtering is required - return nil. + if (![argument length] && numberOfArguments == 1) { [argument release]; return nil; } - - // If we are using the BETWEEN operator and either of the argument fields are empty return nil. - if ([[[compareField selectedItem] title] isEqualToString:@"BETWEEN"]) { + + // arguments if Filter requires two arguments + NSMutableString *firstBetweenArgument = [[NSMutableString alloc] initWithString:[firstBetweenField stringValue]]; + NSMutableString *secondBetweenArgument = [[NSMutableString alloc] initWithString:[secondBetweenField stringValue]]; + + // If filter requires two arguments and either of the argument fields are empty + // return nil. + if (numberOfArguments == 2) { if (([firstBetweenArgument length] == 0) || ([secondBetweenArgument length] == 0)) { + [argument release]; + [firstBetweenArgument release]; + [secondBetweenArgument release]; return nil; } } - // Construct the filter string - if (![compareType isEqualToString:@""]) { - if ([compareType isEqualToString:@"string"]) { - // String comparision - switch (tag) { - case 0: - compareOperator = @"LIKE"; - break; - case 1: - compareOperator = @"NOT LIKE"; - break; - case 2: - compareOperator = @"LIKE"; - [argument setString:[[@"%" stringByAppendingString:argument] stringByAppendingString:@"%"]]; - break; - case 3: - compareOperator = @"NOT LIKE"; - [argument setString:[[@"%" stringByAppendingString:argument] stringByAppendingString:@"%"]]; - break; - case 4: - compareOperator = @"IN"; - doQuote = NO; - [argument setString:[[@"(" stringByAppendingString:argument] stringByAppendingString:@")"]]; - break; - case 5: - compareOperator = @"BETWEEN"; - doQuote = NO; - [argument setString:[NSString stringWithFormat:@"'%@' AND '%@'", [firstBetweenField stringValue], [secondBetweenField stringValue]]]; - break; - case 6: - compareOperator = @"IS NULL"; - doQuote = NO; - ignoreArgument = YES; - break; - case 7: - compareOperator = @"IS NOT NULL"; - doQuote = NO; - ignoreArgument = YES; - break; - } - } - else if ([compareType isEqualToString:@"number"]) { - // Numeric comparision - switch (tag) { - case 0: - compareOperator = @"="; - break; - case 1: - compareOperator = @"!="; - break; - case 2: - compareOperator = @">"; - break; - case 3: - compareOperator = @"<"; - break; - case 4: - compareOperator = @">="; - break; - case 5: - compareOperator = @"<="; - break; - case 6: - compareOperator = @"IN"; - doQuote = NO; - [argument setString:[[@"(" stringByAppendingString:argument] stringByAppendingString:@")"]]; - break; - case 7: - compareOperator = @"LIKE"; - doQuote = YES; - ignoreArgument = YES; - break; - case 8: - compareOperator = @"BETWEEN"; - doQuote = NO; - [argument setString:[NSString stringWithFormat:@"'%@' AND '%@'", [firstBetweenField stringValue], [secondBetweenField stringValue]]]; - break; - case 9: - compareOperator = @"IS NULL"; - doQuote = NO; - ignoreArgument = YES; - break; - case 10: - compareOperator = @"IS NOT NULL"; - doQuote = NO; - ignoreArgument = YES; - break; - } - } - else if ([compareType isEqualToString:@"date"]) { - // Date comparision - switch (tag) { - case 0: - compareOperator = @"="; - break; - case 1: - compareOperator = @"!="; - break; - case 2: - compareOperator = @">"; - break; - case 3: - compareOperator = @"<"; - break; - case 4: - compareOperator = @">="; - break; - case 5: - compareOperator = @"<="; - break; - case 6: - compareOperator = @"BETWEEN"; - doQuote = NO; - [argument setString:[NSString stringWithFormat:@"'%@' AND '%@'", [firstBetweenField stringValue], [secondBetweenField stringValue]]]; - break; - case 7: - compareOperator = @"IS NULL"; - doQuote = NO; - ignoreArgument = YES; - break; - case 8: - compareOperator = @"IS NOT NULL"; - doQuote = NO; - ignoreArgument = YES; - break; - } - } - else { - doQuote = NO; - ignoreArgument = YES; - NSLog(@"ERROR: unknown comparison type %@", compareType); + // Retrieve actual WHERE clause + NSMutableString *clause = [[NSMutableString alloc] init]; + [clause setString:[filter objectForKey:@"Clause"]]; + + // Escape % sign + [clause replaceOccurrencesOfRegex:@"%"withString:@"%%"]; + [clause flushCachedRegexData]; + + // Replace placeholder ${} by %@ + NSRange matchedRange; + NSString *re = @"(?<!\\\\)\\$\\{.*?\\}"; + if([clause isMatchedByRegex:re]) { + while([clause isMatchedByRegex:re]) { + matchedRange = [clause rangeOfRegex:re]; + [clause replaceCharactersInRange:matchedRange withString:@"%@"]; + [clause flushCachedRegexData]; } - - if (doQuote) { - int i; - - // Escape special characters - for (i = 0 ; i < [argument length]; i++) { - if ([argument characterAtIndex:i] == '\\') { - [argument insertString:@"\\" atIndex:i]; - i++; - } + } + + // Check number of placeholders and given 'NumberOfArguments' + if([clause replaceOccurrencesOfString:@"%@" withString:@"%@" options:NSLiteralSearch range:NSMakeRange(0, [clause length])] != numberOfArguments) { + NSLog(@"Error while setting filter string. “NumberOfArguments” differs from the number of arguments specified in “Clause”."); + NSBeep(); + [argument release]; + [firstBetweenArgument release]; + [secondBetweenArgument release]; + [clause release]; + return nil; + } + + // Construct the filter string according the required number of arguments + if (numberOfArguments == 2) { + filterString = [NSString stringWithFormat:@"%@ %@", + [[fieldField titleOfSelectedItem] backtickQuotedString], + [NSString stringWithFormat:clause, firstBetweenArgument, secondBetweenArgument]]; + } else if (numberOfArguments == 1) { + filterString = [NSString stringWithFormat:@"%@ %@", + [[fieldField titleOfSelectedItem] backtickQuotedString], + [NSString stringWithFormat:clause, argument]]; + } else { + filterString = [NSString stringWithFormat:@"%@ %@", + [[fieldField titleOfSelectedItem] backtickQuotedString], + [filter objectForKey:@"Clause"]]; + if(numberOfArguments > 2) { + NSLog(@"Filter with more than 2 arguments is not yet supported."); + NSBeep(); } - - [argument setString:[mySQLConnection prepareString:argument]]; - - filterString = [NSString stringWithFormat:@"%@ %@ \"%@\"", [[fieldField titleOfSelectedItem] backtickQuotedString], compareOperator, argument]; - } - else { - filterString = [NSString stringWithFormat:@"%@ %@ %@", [[fieldField titleOfSelectedItem] backtickQuotedString], compareOperator, (ignoreArgument) ? @"" : argument]; - } } - + [argument release]; + [firstBetweenArgument release]; + [secondBetweenArgument release]; + [clause release]; // Return the filter string return filterString; @@ -779,27 +721,41 @@ */ - (IBAction)toggleFilterField:(id)sender { - NSString *filter = [[compareField selectedItem] title]; - - if ([filter isEqualToString:@"BETWEEN"]) { + + NSDictionary *filter = [[contentFilters objectForKey:compareType] objectAtIndex:[[compareField selectedItem] tag]]; + if ([[filter objectForKey:@"NumberOfArguments"] intValue] == 2) { [argumentField setHidden:YES]; + + if([filter objectForKey:@"ConjunctionLabels"] && [[filter objectForKey:@"ConjunctionLabels"] count] == 1) + [betweenTextField setStringValue:[[filter objectForKey:@"ConjunctionLabels"] objectAtIndex:0]]; [betweenTextField setHidden:NO]; [firstBetweenField setHidden:NO]; [secondBetweenField setHidden:NO]; + [firstBetweenField setEnabled:YES]; [secondBetweenField setEnabled:YES]; [firstBetweenField selectText:self]; } - else { + else if ([[filter objectForKey:@"NumberOfArguments"] intValue] == 1){ [argumentField setHidden:NO]; + [argumentField setEnabled:YES]; + [argumentField selectText:self]; + [betweenTextField setHidden:YES]; [firstBetweenField setHidden:YES]; [secondBetweenField setHidden:YES]; - [argumentField selectText:self]; } + else { + [argumentField setHidden:NO]; + [argumentField setEnabled:NO]; - // If the user is filtering for NULLs then disable the filter field, otherwise enable it. - [argumentField setEnabled:(![[[compareField selectedItem] title] hasSuffix:@"NULL"])]; + [betweenTextField setHidden:YES]; + [firstBetweenField setHidden:YES]; + [secondBetweenField setHidden:YES]; + + // Start search if no argument is required + [self filterTable:self]; + } } @@ -1114,18 +1070,23 @@ */ - (IBAction)setCompareTypes:(id)sender { - NSArray *stringTypes = [NSArray arrayWithObjects:NSLocalizedString(@"IS", @"popup menuitem for field IS value"), NSLocalizedString(@"IS NOT", @"popup menuitem for field IS NOT value"), NSLocalizedString(@"contains", @"popup menuitem for field CONTAINS value"), NSLocalizedString(@"contains not", @"popup menuitem for field CONTAINS NOT value"), @"IN", @"BETWEEN", nil]; - NSArray *numberTypes = [NSArray arrayWithObjects:@"=", @"≠", @">", @"<", @"≥", @"≤", @"IN", @"LIKE", @"BETWEEN", nil]; - NSArray *dateTypes = [NSArray arrayWithObjects:NSLocalizedString(@"IS", @"popup menuitem for field IS value"), NSLocalizedString(@"IS NOT", @"popup menuitem for field IS NOT value"), NSLocalizedString(@"is after", @"popup menuitem for field AFTER DATE value"), NSLocalizedString(@"is before", @"popup menuitem for field BEFORE DATE value"), NSLocalizedString(@"is after or equal to", @"popup menuitem for field AFTER OR EQUAL TO value"), NSLocalizedString(@"is before or equal to", @"popup menuitem for field BEFORE OR EQUAL TO value"), @"BETWEEN", nil]; + + if(contentFilters == nil + || ![contentFilters objectForKey:@"number"] + || ![contentFilters objectForKey:@"string"] + || ![contentFilters objectForKey:@"date"]) { + NSLog(@"Error while setting filter types."); + NSBeep(); + return; + } + NSString *fieldTypeGrouping = [NSString stringWithString:[[tableDataInstance columnWithName:[[fieldField selectedItem] title]] objectForKey:@"typegrouping"]]; - - int i; - + [compareField removeAllItems]; if ( [fieldTypeGrouping isEqualToString:@"date"] ) { - [compareField addItemsWithTitles:dateTypes]; compareType = @"date"; + /* if ([fieldType isEqualToString:@"timestamp"]) { [argumentField setFormatter:[[NSDateFormatter alloc] @@ -1147,34 +1108,56 @@ // TODO: A bug in the framework previously meant enum fields had to be treated as string fields for the purposes // of comparison - this can now be split out to support additional comparison fucntionality if desired. - } else if ([fieldTypeGrouping isEqualToString:@"string"] || [fieldTypeGrouping isEqualToString:@"binary"] + } else if ([fieldTypeGrouping isEqualToString:@"string"] || [fieldTypeGrouping isEqualToString:@"binary"] || [fieldTypeGrouping isEqualToString:@"textdata"] || [fieldTypeGrouping isEqualToString:@"blobdata"] || [fieldTypeGrouping isEqualToString:@"enum"]) { - [compareField addItemsWithTitles:stringTypes]; + compareType = @"string"; - // [argumentField setFormatter:nil]; + // [argumentField setFormatter:nil]; + } else if ([fieldTypeGrouping isEqualToString:@"bit"] || [fieldTypeGrouping isEqualToString:@"integer"] || [fieldTypeGrouping isEqualToString:@"float"]) { - [compareField addItemsWithTitles:numberTypes]; compareType = @"number"; - // [argumentField setFormatter:numberFormatter]; + // [argumentField setFormatter:numberFormatter]; + } else { + compareType = @""; + NSBeep(); NSLog(@"ERROR: unknown type for comparision: %@, in %@", [[tableDataInstance columnWithName:[[fieldField selectedItem] title]] objectForKey:@"type"], fieldTypeGrouping); } // Add IS NULL and IS NOT NULL as they should always be available - [compareField addItemWithTitle:@"IS NULL"]; - [compareField addItemWithTitle:@"IS NOT NULL"]; - - for ( i = 0 ; i < [compareField numberOfItems] ; i++ ) { - [[compareField itemAtIndex:i] setTag:i]; - } + // [compareField addItemWithTitle:@"IS NULL"]; + // [compareField addItemWithTitle:@"IS NOT NULL"]; + + // Load user-defined content filters + if([prefs objectForKey:@"ContentFilters"] + && [contentFilters objectForKey:compareType] + && [[prefs objectForKey:@"ContentFilters"] objectForKey:compareType]) + { + [[contentFilters objectForKey:compareType] addObjectsFromArray:[[prefs objectForKey:@"ContentFilters"] objectForKey:compareType]]; + } + + // Rebuild operator popup menu + NSUInteger i = 0; + NSMenu *menu = [compareField menu]; + if([contentFilters objectForKey:compareType]) + for(id filter in [contentFilters objectForKey:compareType]) { + NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:([filter objectForKey:@"MenuLabel"])?[filter objectForKey:@"MenuLabel"]:@"not specified" action:NULL keyEquivalent:@""]; + if([filter objectForKey:@"Tooltip"]) + [item setToolTip:[filter objectForKey:@"Tooltip"]]; + [item setTag:i]; + [menu addItem:item]; + [item release]; + i++; + } // Update the argumentField enabled state [self toggleFilterField:self]; // set focus on argumentField [argumentField selectText:self]; + } - (IBAction)stepLimitRows:(id)sender @@ -2400,7 +2383,7 @@ [tableValues release]; [dataColumns release]; [oldRow release]; - // if (editData) [editData release]; + if (contentFilters) [contentFilters release]; if (keys) [keys release]; if (sortCol) [sortCol release]; [usedQuery release]; |