diff --git a/cocoa/base/PyDupeGuru.h b/cocoa/base/PyDupeGuru.h
index 28f830b0..7879caa9 100644
--- a/cocoa/base/PyDupeGuru.h
+++ b/cocoa/base/PyDupeGuru.h
@@ -20,6 +20,7 @@ http://www.hardcoded.net/licenses/hs_license
- (void)clearIgnoreList;
- (void)purgeIgnoreList;
- (NSString *)exportToXHTMLwithColumns:(NSArray *)aColIds;
+- (void)invokeCommand:(NSString *)cmd;
- (NSNumber *)doScan;
diff --git a/cocoa/base/ResultWindow.h b/cocoa/base/ResultWindow.h
index 4bf6bd7f..3df5601c 100644
--- a/cocoa/base/ResultWindow.h
+++ b/cocoa/base/ResultWindow.h
@@ -48,6 +48,7 @@ http://www.hardcoded.net/licenses/hs_license
- (IBAction)exportToXHTML:(id)sender;
- (IBAction)filter:(id)sender;
- (IBAction)ignoreSelected:(id)sender;
+- (IBAction)invokeCustomCommand:(id)sender;
- (IBAction)markAll:(id)sender;
- (IBAction)markInvert:(id)sender;
- (IBAction)markNone:(id)sender;
diff --git a/cocoa/base/ResultWindow.m b/cocoa/base/ResultWindow.m
index fa273c8e..4c60c20d 100644
--- a/cocoa/base/ResultWindow.m
+++ b/cocoa/base/ResultWindow.m
@@ -200,6 +200,13 @@ http://www.hardcoded.net/licenses/hs_license
[py addSelectedToIgnoreList];
}
+- (IBAction)invokeCustomCommand:(id)sender
+{
+ NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+ NSString *cmd = [ud stringForKey:@"CustomCommand"];
+ [py invokeCommand:cmd];
+}
+
- (IBAction)markAll:(id)sender
{
[py markAll];
diff --git a/cocoa/base/xib/MainMenu.xib b/cocoa/base/xib/MainMenu.xib
index 686991fa..ea7f76be 100644
--- a/cocoa/base/xib/MainMenu.xib
+++ b/cocoa/base/xib/MainMenu.xib
@@ -2,18 +2,18 @@
1050
- 10C540
+ 10D573
740
- 1038.25
- 458.00
+ 1038.29
+ 460.00
@@ -2530,6 +2547,7 @@
+
@@ -3066,6 +3084,11 @@
+
+ 1177
+
+
+
@@ -3117,6 +3140,7 @@
1171.IBPluginDependency
1172.IBPluginDependency
1173.IBPluginDependency
+ 1177.IBPluginDependency
134.IBPluginDependency
134.ImportedFromIB2
136.IBPluginDependency
@@ -3355,6 +3379,7 @@
com.apple.InterfaceBuilder.CocoaPlugin
com.apple.InterfaceBuilder.CocoaPlugin
com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
com.apple.InterfaceBuilder.CocoaPlugin
@@ -3374,9 +3399,9 @@
- {{109, 366}, {557, 400}}
+ {{439, 345}, {557, 400}}
com.apple.InterfaceBuilder.CocoaPlugin
- {{109, 366}, {557, 400}}
+ {{439, 345}, {557, 400}}
@@ -3423,7 +3448,7 @@
com.apple.InterfaceBuilder.CocoaPlugin
- {{286, 475}, {361, 293}}
+ {{286, 455}, {361, 313}}
com.apple.InterfaceBuilder.CocoaPlugin
com.apple.InterfaceBuilder.CocoaPlugin
@@ -3561,7 +3586,7 @@
- 1176
+ 1178
@@ -3776,8 +3801,17 @@
ResultWindow
ResultWindowBase
- removeDeadTracks:
- id
+ YES
+
+ YES
+ resetColumnsToDefault:
+ startDuplicateScan:
+
+
+ YES
+ id
+ id
+
IBProjectSource
@@ -3799,6 +3833,7 @@
exportToXHTML:
filter:
ignoreSelected:
+ invokeCustomCommand:
markAll:
markInvert:
markNone:
@@ -3848,6 +3883,7 @@
id
id
id
+ id
@@ -4500,7 +4536,7 @@
YES
- ../../me/dupeguru.xcodeproj
+ ../../se/dupeguru.xcodeproj
3
diff --git a/cocoa/se/xib/Preferences.xib b/cocoa/se/xib/Preferences.xib
index 53e8eca3..93686d93 100644
--- a/cocoa/se/xib/Preferences.xib
+++ b/cocoa/se/xib/Preferences.xib
@@ -2,10 +2,10 @@
1050
- 10C540
+ 10D573
740
- 1038.25
- 458.00
+ 1038.29
+ 460.00
com.apple.InterfaceBuilder.CocoaPlugin
740
@@ -39,16 +39,12 @@
NSApplication
-
- YES
- SUEnableAutomaticChecks
-
YES
3
2
- {{92, 276}, {352, 326}}
+ {{92, 269}, {389, 333}}
1886912512
dupeGuru Preferences
@@ -64,325 +60,21 @@
256
YES
-
-
- 292
- {{120, 247}, {181, 21}}
-
- YES
-
- 67239424
- 0
-
-
-
-
- Helvetica
- 12
- 16
-
-
- 100
- 1
- 80
- 0.0
- 0
- 1
- NO
- NO
-
-
-
-
- 292
- {{122, 230}, {80, 13}}
-
- YES
-
- 67239424
- 272629760
- More results
-
- LucidaGrande
- 10
- 2843
-
-
-
- 6
- System
- controlColor
-
- 3
- MC42NjY2NjY2NjY3AA
-
-
-
- 6
- System
- controlTextColor
-
- 3
- MAA
-
-
-
-
-
-
- 289
- {{219, 230}, {80, 13}}
-
- YES
-
- 67239424
- 71303168
- Fewer results
-
-
-
-
-
-
-
-
- 292
- {{17, 252}, {100, 14}}
-
- YES
-
- 67239424
- 272629760
- Filter hardness:
-
- LucidaGrande
- 11
- 3100
-
-
-
-
-
-
-
-
- 292
- {{20, 293}, {85, 13}}
-
- YES
-
- 67239424
- 272629760
- Scan type:
-
-
-
-
-
-
-
-
-
- 256
- {{18, 206}, {214, 18}}
-
- YES
-
- 67239424
- 0
- Word weighting
-
-
- 1211912703
- 2
-
- NSSwitch
-
-
-
- 200
- 25
-
-
-
-
- 256
- {{18, 166}, {214, 18}}
-
- YES
-
- 67239424
- 0
- Can mix file kind
-
-
- 1211912703
- 2
-
-
-
- 200
- 25
-
-
-
-
- 256
- {{304, 252}, {31, 14}}
-
- YES
-
- 67239424
- -1874853888
-
-
-
-
- YES
-
- YES
- allowsFloats
- attributedStringForZero
- decimalSeparator
- formatterBehavior
- groupingSeparator
- negativeFormat
- positiveFormat
- usesGroupingSeparator
-
-
- YES
-
-
- 0
-
- YES
-
-
- YES
-
-
-
- .
-
- ,
- -0
- 0
-
-
-
- 0
- -0
-
-
-
-
-
-
-
- NaN
-
-
-
- 0
- 0
- YES
- NO
- 1
- AAAAAAAAAAAAAAAAAAAAAA
-
-
-
- .
- ,
- NO
- YES
- YES
-
-
-
-
-
-
256
- {{190, 12}, {148, 32}}
+ {{227, 12}, {148, 32}}
YES
67239424
134217728
Reset to Defaults
-
+
+ LucidaGrande
+ 13
+ 1044
+
-2038284033
1
@@ -395,297 +87,681 @@
25
-
+
- 256
- {{18, 186}, {214, 18}}
+ 12
+ {{13, 40}, {363, 287}}
- YES
-
- 67239424
- 0
- Match similar words
-
-
- 1211912703
- 2
-
-
-
- 200
- 25
-
-
-
-
- 292
- {{20, 67}, {85, 13}}
-
- YES
-
- 67239424
- 272629760
- Copy and Move:
-
-
-
-
-
-
-
-
-
- 256
- {{18, 86}, {283, 18}}
-
- YES
-
- 67239424
- 0
- Automatically check for updates
-
-
- 1211912703
- 2
-
-
-
- 200
- 25
-
-
-
-
- 256
- {{18, 146}, {228, 18}}
-
- YES
-
- 67239424
- 0
- Use regular expressions when filtering
-
-
- 1211912703
- 2
-
-
-
- 200
- 25
-
-
-
-
- 256
- {{18, 126}, {242, 18}}
-
- YES
-
- 67239424
- 0
- Remove empty folders on delete or move
-
-
- 1211912703
- 2
-
-
-
- 200
- 25
-
-
-
-
- 256
- {{18, 106}, {152, 18}}
-
- YES
-
- 67239424
- 0
- Ignore files smaller than
-
-
- 1211912703
- 2
-
-
-
- 200
- 25
-
-
-
-
- 268
- {{176, 104}, {59, 22}}
-
- YES
-
- -1804468671
- -1874852864
-
-
-
-
- YES
-
+
+ YES
+
+ 1
+
+
+ 256
+
YES
- allowsFloats
- formatterBehavior
- locale
- maximumFractionDigits
- numberStyle
- positiveFormat
- roundingIncrement
- usesGroupingSeparator
-
-
- YES
-
-
-
-
+
+
+ 292
+ {{117, 179}, {181, 21}}
+
+ YES
+
+ 67239424
+ 0
+
+
+
+
+ Helvetica
+ 12
+ 16
+
+
+ 100
+ 1
+ 80
+ 0.0
+ 0
+ 1
+ NO
+ NO
+
+
+
+
+ 292
+ {{119, 162}, {80, 13}}
+
+ YES
+
+ 67239424
+ 272629760
+ More results
+
+ LucidaGrande
+ 10
+ 2843
+
+
+
+ 6
+ System
+ controlColor
+
+ 3
+ MC42NjY2NjY2NjY3AA
+
+
+
+ 6
+ System
+ controlTextColor
+
+ 3
+ MAA
+
+
+
+
+
+
+ 289
+ {{216, 162}, {80, 13}}
+
+ YES
+
+ 67239424
+ 71303168
+ Fewer results
+
+
+
+
+
+
+
+
+ 292
+ {{14, 184}, {100, 14}}
+
+ YES
+
+ 67239424
+ 272629760
+ Filter hardness:
+
+ LucidaGrande
+ 11
+ 3100
+
+
+
+
+
+
+
+
+ 292
+ {{17, 225}, {85, 13}}
+
+ YES
+
+ 67239424
+ 272629760
+ Scan type:
+
+
+
+
+
+
+
+
+
+ 256
+ {{15, 138}, {214, 18}}
+
+ YES
+
+ 67239424
+ 0
+ Word weighting
+
+
+ 1211912703
+ 2
+
+ NSSwitch
+
+
+
+ 200
+ 25
+
+
+
+
+ 256
+ {{15, 98}, {214, 18}}
+
+ YES
+
+ 67239424
+ 0
+ Can mix file kind
+
+
+ 1211912703
+ 2
+
+
+
+ 200
+ 25
+
+
+
+
+ 256
+ {{15, 118}, {214, 18}}
+
+ YES
+
+ 67239424
+ 0
+ Match similar words
+
+
+ 1211912703
+ 2
+
+
+
+ 200
+ 25
+
+
+
+
+ 292
+ {{17, 17}, {85, 13}}
+
+ YES
+
+ 67239424
+ 272629760
+ Copy and Move:
+
+
+
+
+
+
+
+
+
+ 256
+ {{15, 36}, {283, 18}}
+
+ YES
+
+ 67239424
+ 0
+ Automatically check for updates
+
+
+ 1211912703
+ 2
+
+
+
+ 200
+ 25
+
+
+
+
+ 256
+ {{15, 76}, {242, 18}}
+
+ YES
+
+ 67239424
+ 0
+ Remove empty folders on delete or move
+
+
+ 1211912703
+ 2
+
+
+
+ 200
+ 25
+
+
+
+
+ 256
+ {{15, 56}, {152, 18}}
+
+ YES
+
+ 67239424
+ 0
+ Ignore files smaller than
+
+
+ 1211912703
+ 2
+
+
+
+ 200
+ 25
+
+
+
+
+ 268
+ {{173, 54}, {59, 22}}
+
+ YES
+
+ -1804468671
+ -1874852864
+
+
+
+
+ YES
+
+ YES
+ allowsFloats
+ formatterBehavior
+ locale
+ maximumFractionDigits
+ numberStyle
+ positiveFormat
+ roundingIncrement
+ usesGroupingSeparator
+
+
+ YES
+
+
+
+
+
+
+
+ #0
+
+
+
+
+ #0
+ #0
+
+
+
+
+
+ NaN
+
+ YES
+
+
+ YES
+
+
+
+
+ 0
+ 0
+ YES
+ NO
+ 1
+ AAAAAAAAAAAAAAAAAAAAAA
+
+
+
+ 3
+ YES
+ YES
+ YES
+
+ .
+ ,
+ NO
+ NO
+ NO
+
+
+ YES
+
+ 6
+ System
+ textBackgroundColor
+
+ 3
+ MQA
+
+
+
+ 6
+ System
+ textColor
+
+
+
+
+
+
+ 292
+ {{240, 56}, {23, 17}}
+
+ YES
+
+ 67239424
+ 272629760
+ KB
+
+
+
+
+
+
+
+
+ 256
+ {{301, 184}, {31, 14}}
+
+ YES
+
+ 67239424
+ -1874853888
+
+
+
+
+ YES
+
+ YES
+ allowsFloats
+ attributedStringForZero
+ decimalSeparator
+ formatterBehavior
+ groupingSeparator
+ negativeFormat
+ positiveFormat
+ usesGroupingSeparator
+
+
+ YES
+
+
+ 0
+
+
+ .
+
+ ,
+ -0
+ 0
+
+
+
+ 0
+ -0
+
+
+
+
+
+
+
+ NaN
+
+
+
+
+
+ .
+ ,
+ NO
+ YES
+ YES
+
+
+
+
+
-
-
- #0
-
-
+ {{10, 33}, {343, 241}}
+
- #0
- #0
-
-
-
-
-
- NaN
-
-
-
-
-
- 3
- YES
- YES
- YES
-
- .
- ,
- NO
- NO
- NO
+ Basic
+
+
-
- YES
-
- 6
- System
- textBackgroundColor
-
- 3
- MQA
+
+ 2
+
+
+ 256
+
+ YES
+
+
+ 256
+ {{15, 222}, {228, 18}}
+
+ YES
+
+ 67239424
+ 0
+ Use regular expressions when filtering
+
+
+ 1211912703
+ 2
+
+
+
+ 200
+ 25
+
+
+
+
+ 292
+ {{14, 199}, {315, 17}}
+
+ YES
+
+ 67239424
+ 272629760
+ Custom command (arguments: %d for dupe, %r for ref):
+
+
+
+
+
+
+
+
+ 266
+ {{17, 169}, {309, 22}}
+
+ YES
+
+ -1804468671
+ 272630784
+
+
+
+ YES
+
+
+
+
+
+ {{10, 33}, {343, 241}}
-
-
- 6
- System
- textColor
-
+ Advanced
+
+
-
-
-
- 292
- {{243, 106}, {23, 17}}
-
- YES
-
- 67239424
- 272629760
- KB
-
-
-
-
+
+
+ 0
+ YES
+ YES
+
+ YES
+
- {352, 326}
+ {389, 333}
{{0, 0}, {1440, 878}}
@@ -864,22 +940,6 @@
113
-
-
- value: values.useRegexpFilter
-
-
-
-
-
- value: values.useRegexpFilter
- value
- values.useRegexpFilter
- 2
-
-
- 114
-
selectedIndex: values.scanType
@@ -976,6 +1036,38 @@
122
+
+
+ value: values.useRegexpFilter
+
+
+
+
+
+ value: values.useRegexpFilter
+ value
+ values.useRegexpFilter
+ 2
+
+
+ 130
+
+
+
+ value: values.CustomCommand
+
+
+
+
+
+ value: values.CustomCommand
+ value
+ values.CustomCommand
+ 2
+
+
+ 140
+
@@ -1025,109 +1117,11 @@
YES
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
- 54
-
-
- YES
-
-
-
-
-
- 55
-
-
- YES
-
-
-
-
-
- 56
-
-
- YES
-
-
-
-
-
- 57
-
-
- YES
-
-
-
-
-
- 58
-
-
- YES
-
-
-
-
-
- 59
-
-
- YES
-
-
-
-
-
- 60
-
-
- YES
-
-
-
-
-
- 61
-
-
- YES
-
-
-
-
-
- 62
-
-
- YES
-
-
-
-
63
@@ -1138,76 +1132,73 @@
- 64
-
+ 86
+
+
+
+
+ 123
+
YES
-
+
+
- 65
-
+ 124
+
YES
-
+
-
+
- 66
-
+ 125
+
YES
-
+
-
+
- 67
-
+ 126
+
YES
-
+
+
+
-
+
- 68
-
+ 127
+
YES
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
- 69
-
-
- YES
-
-
-
-
-
- 70
-
-
- YES
-
-
-
-
-
- 71
-
-
- YES
-
-
-
+
72
@@ -1216,33 +1207,78 @@
YES
-
+
73
+
+ 71
+
+
+ YES
+
+
+
+
74
+
+ 70
+
+
+ YES
+
+
+
+
75
+
+ 69
+
+
+ YES
+
+
+
+
76
+
+ 68
+
+
+ YES
+
+
+
+
77
+
+ 67
+
+
+ YES
+
+
+
+
78
@@ -1257,60 +1293,86 @@
YES
-
+
-
- 80
-
-
-
81
+
+ 80
+
+
+
+
+ 66
+
+
+ YES
+
+
+
+
82
+
+ 65
+
+
+ YES
+
+
+
+
83
- 84
-
+ 62
+
YES
-
+
-
-
-
- 85
-
-
-
-
- 86
-
-
+
87
+
+ 61
+
+
+ YES
+
+
+
+
88
+
+ 60
+
+
+ YES
+
+
+
+
89
@@ -1325,15 +1387,15 @@
YES
-
-
+
+
- 91
-
+ 93
+
@@ -1342,30 +1404,61 @@
- 93
-
+ 91
+
+
+ 59
+
+
+ YES
+
+
+
+
94
- 95
-
-
+ 57
+
+
+ YES
+
+
+
96
+
+ 56
+
+
+ YES
+
+
+
+
97
+
+ 55
+
+
+ YES
+
+
+
+
98
@@ -1380,11 +1473,85 @@
+
+ 54
+
+
+ YES
+
+
+
+
100
+
+ 128
+
+
+ YES
+
+
+
+
+
+ 129
+
+
+
+
+ 133
+
+
+ YES
+
+
+
+
+
+ 134
+
+
+
+
+ 138
+
+
+ YES
+
+
+
+
+
+ 139
+
+
+
+
+ 64
+
+
+ YES
+
+
+
+
+
+ 84
+
+
+ YES
+
+
+
+
+
+ 85
+
+
+
@@ -1393,6 +1560,19 @@
YES
-3.IBPluginDependency
100.IBPluginDependency
+ 123.IBPluginDependency
+ 124.IBPluginDependency
+ 125.IBPluginDependency
+ 126.IBPluginDependency
+ 127.IBPluginDependency
+ 128.IBPluginDependency
+ 128.ImportedFromIB2
+ 129.IBPluginDependency
+ 133.IBPluginDependency
+ 133.ImportedFromIB2
+ 134.IBPluginDependency
+ 138.IBPluginDependency
+ 139.IBPluginDependency
51.IBPluginDependency
51.ImportedFromIB2
52.IBEditorWindowLastContentRect
@@ -1411,8 +1591,6 @@
56.ImportedFromIB2
57.IBPluginDependency
57.ImportedFromIB2
- 58.IBPluginDependency
- 58.ImportedFromIB2
59.IBPluginDependency
59.ImportedFromIB2
60.IBPluginDependency
@@ -1471,7 +1649,6 @@
93.IBPluginDependency
93.ImportedFromIB2
94.IBPluginDependency
- 95.IBPluginDependency
96.IBPluginDependency
97.IBPluginDependency
98.IBPluginDependency
@@ -1484,10 +1661,23 @@
com.apple.InterfaceBuilder.CocoaPlugin
com.apple.InterfaceBuilder.CocoaPlugin
com.apple.InterfaceBuilder.CocoaPlugin
-
- {{88, 519}, {352, 326}}
com.apple.InterfaceBuilder.CocoaPlugin
- {{88, 519}, {352, 326}}
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ {{88, 512}, {389, 333}}
+ com.apple.InterfaceBuilder.CocoaPlugin
+ {{88, 512}, {389, 333}}
{213, 107}
@@ -1530,8 +1720,6 @@
com.apple.InterfaceBuilder.CocoaPlugin
com.apple.InterfaceBuilder.CocoaPlugin
-
- com.apple.InterfaceBuilder.CocoaPlugin
com.apple.InterfaceBuilder.CocoaPlugin
com.apple.InterfaceBuilder.CocoaPlugin
com.apple.InterfaceBuilder.CocoaPlugin
@@ -1564,7 +1752,6 @@
com.apple.InterfaceBuilder.CocoaPlugin
com.apple.InterfaceBuilder.CocoaPlugin
com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
com.apple.InterfaceBuilder.CocoaPlugin
@@ -1586,7 +1773,7 @@
- 122
+ 140
@@ -2044,6 +2231,22 @@
AppKit.framework/Headers/NSSliderCell.h
+
+ NSTabView
+ NSView
+
+ IBFrameworkSource
+ AppKit.framework/Headers/NSTabView.h
+
+
+
+ NSTabViewItem
+ NSObject
+
+ IBFrameworkSource
+ AppKit.framework/Headers/NSTabViewItem.h
+
+
NSTextField
NSControl
diff --git a/core/app.py b/core/app.py
index 296aaea3..00803338 100644
--- a/core/app.py
+++ b/core/app.py
@@ -11,6 +11,7 @@ from __future__ import unicode_literals
import os
import os.path as op
import logging
+import subprocess
from send2trash import send2trash
from hsutil import io, files
@@ -218,6 +219,22 @@ class DupeGuru(RegistrableApplication, Broadcaster):
rows.append(row)
return export.export_to_xhtml(colnames, rows)
+ def invoke_command(self, cmd):
+ """Calls command `cmd` with %d and %r placeholders replaced.
+
+ Using the current selection, %d is replaced with the currently selected dupe and %r is
+ replaced with that dupe's ref file. If there's no selection, the command is not invoked.
+ If the dupe is a ref, %d and %r will be the same.
+ """
+ if not self.selected_dupes:
+ return
+ dupe = self.selected_dupes[0]
+ group = self.results.get_group_of_duplicate(dupe)
+ ref = group.ref
+ cmd = cmd.replace('%d', unicode(dupe.path))
+ cmd = cmd.replace('%r', unicode(ref.path))
+ subprocess.Popen(cmd, shell=True)
+
def load(self):
self._start_job(JOB_LOAD, self._do_load)
self.load_ignore_list()
diff --git a/core/app_cocoa_inter.py b/core/app_cocoa_inter.py
index 0a0a1d68..b5e166eb 100644
--- a/core/app_cocoa_inter.py
+++ b/core/app_cocoa_inter.py
@@ -95,6 +95,9 @@ class PyDupeGuruBase(PyRegistrable):
def revealSelected(self):
self.py.reveal_selected()
+ def invokeCommand_(self, cmd):
+ self.py.invoke_command(cmd)
+
#---Information
def getIgnoreListCount(self):
return len(self.py.scanner.ignore_list)