diff --git a/cocoa/base/PyDupeGuru.h b/cocoa/base/PyDupeGuru.h
index 7879caa9..ebe1a325 100644
--- a/cocoa/base/PyDupeGuru.h
+++ b/cocoa/base/PyDupeGuru.h
@@ -14,7 +14,9 @@ http://www.hardcoded.net/licenses/hs_license
- (NSNumber *)addDirectory:(NSString *)name;
- (void)removeDirectory:(NSNumber *)index;
- (void)loadResults;
+- (void)loadResultsFrom:(NSString *)filename;
- (void)saveResults;
+- (void)saveResultsAs:(NSString *)filename;
- (void)loadIgnoreList;
- (void)saveIgnoreList;
- (void)clearIgnoreList;
diff --git a/cocoa/base/ResultWindow.h b/cocoa/base/ResultWindow.h
index 3df5601c..7eee7ce9 100644
--- a/cocoa/base/ResultWindow.h
+++ b/cocoa/base/ResultWindow.h
@@ -49,6 +49,7 @@ http://www.hardcoded.net/licenses/hs_license
- (IBAction)filter:(id)sender;
- (IBAction)ignoreSelected:(id)sender;
- (IBAction)invokeCustomCommand:(id)sender;
+- (IBAction)loadResults:(id)sender;
- (IBAction)markAll:(id)sender;
- (IBAction)markInvert:(id)sender;
- (IBAction)markNone:(id)sender;
@@ -61,6 +62,7 @@ http://www.hardcoded.net/licenses/hs_license
- (IBAction)renameSelected:(id)sender;
- (IBAction)resetColumnsToDefault:(id)sender;
- (IBAction)revealSelected:(id)sender;
+- (IBAction)saveResults:(id)sender;
- (IBAction)showPreferencesPanel:(id)sender;
- (IBAction)startDuplicateScan:(id)sender;
- (IBAction)switchSelected:(id)sender;
diff --git a/cocoa/base/ResultWindow.m b/cocoa/base/ResultWindow.m
index 1d7dc9b9..0312d852 100644
--- a/cocoa/base/ResultWindow.m
+++ b/cocoa/base/ResultWindow.m
@@ -212,6 +212,21 @@ http://www.hardcoded.net/licenses/hs_license
}
}
+- (IBAction)loadResults:(id)sender
+{
+ NSOpenPanel *op = [NSOpenPanel openPanel];
+ [op setCanChooseFiles:YES];
+ [op setCanChooseDirectories:NO];
+ [op setCanCreateDirectories:NO];
+ [op setAllowsMultipleSelection:NO];
+ [op setAllowedFileTypes:[NSArray arrayWithObject:@"dupeguru"]];
+ [op setTitle:@"Select a results file to load"];
+ if ([op runModal] == NSOKButton) {
+ NSString *filename = [[op filenames] objectAtIndex:0];
+ [py loadResultsFrom:filename];
+ }
+}
+
- (IBAction)markAll:(id)sender
{
[py markAll];
@@ -303,6 +318,17 @@ http://www.hardcoded.net/licenses/hs_license
[preferencesPanel showWindow:sender];
}
+- (IBAction)saveResults:(id)sender
+{
+ NSSavePanel *sp = [NSSavePanel savePanel];
+ [sp setCanCreateDirectories:YES];
+ [sp setAllowedFileTypes:[NSArray arrayWithObject:@"dupeguru"]];
+ [sp setTitle:@"Select a file to save your results to"];
+ if ([sp runModal] == NSOKButton) {
+ [py saveResultsAs:[sp filename]];
+ }
+}
+
- (IBAction)startDuplicateScan:(id)sender
{
// Virtual
diff --git a/cocoa/base/xib/MainMenu.xib b/cocoa/base/xib/MainMenu.xib
index ea7f76be..26a70c66 100644
--- a/cocoa/base/xib/MainMenu.xib
+++ b/cocoa/base/xib/MainMenu.xib
@@ -2,18 +2,17 @@
1050
- 10D573
- 740
+ 10F569
+ 788
1038.29
- 460.00
+ 461.00
@@ -3113,6 +3195,7 @@
1028.ImportedFromIB2
103.IBPluginDependency
103.ImportedFromIB2
+ 106.IBEditorWindowLastContentRect
106.IBPluginDependency
106.ImportedFromIB2
111.IBPluginDependency
@@ -3141,6 +3224,11 @@
1172.IBPluginDependency
1173.IBPluginDependency
1177.IBPluginDependency
+ 1203.IBPluginDependency
+ 1204.IBEditorWindowLastContentRect
+ 1204.IBPluginDependency
+ 1205.IBPluginDependency
+ 1206.IBPluginDependency
134.IBPluginDependency
134.ImportedFromIB2
136.IBPluginDependency
@@ -3177,6 +3265,7 @@
222.ImportedFromIB2
23.IBPluginDependency
23.ImportedFromIB2
+ 24.IBEditorWindowLastContentRect
24.IBPluginDependency
24.ImportedFromIB2
29.IBEditorWindowLastContentRect
@@ -3314,6 +3403,7 @@
955.ImportedFromIB2
959.IBPluginDependency
959.ImportedFromIB2
+ 960.IBEditorWindowLastContentRect
960.IBPluginDependency
960.ImportedFromIB2
961.IBPluginDependency
@@ -3322,6 +3412,7 @@
962.ImportedFromIB2
965.IBPluginDependency
965.ImportedFromIB2
+ 966.IBEditorWindowLastContentRect
966.IBPluginDependency
966.ImportedFromIB2
985.IBPluginDependency
@@ -3351,6 +3442,7 @@
com.apple.InterfaceBuilder.CocoaPlugin
+ {{602, 725}, {196, 43}}
com.apple.InterfaceBuilder.CocoaPlugin
com.apple.InterfaceBuilder.CocoaPlugin
@@ -3368,7 +3460,7 @@
com.apple.InterfaceBuilder.CocoaPlugin
- {{79, 766}, {617, 0}}
+ {{409, 745}, {617, 0}}
com.apple.InterfaceBuilder.CocoaPlugin
com.apple.InterfaceBuilder.CocoaPlugin
com.apple.InterfaceBuilder.CocoaPlugin
@@ -3380,6 +3472,11 @@
com.apple.InterfaceBuilder.CocoaPlugin
com.apple.InterfaceBuilder.CocoaPlugin
com.apple.InterfaceBuilder.CocoaPlugin
+ {{242, 705}, {258, 63}}
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
com.apple.InterfaceBuilder.CocoaPlugin
@@ -3415,9 +3512,10 @@
com.apple.InterfaceBuilder.CocoaPlugin
+ {{531, 625}, {193, 143}}
com.apple.InterfaceBuilder.CocoaPlugin
- {{140, 768}, {481, 20}}
+ {{140, 768}, {523, 20}}
com.apple.InterfaceBuilder.CocoaPlugin
com.apple.InterfaceBuilder.CocoaPlugin
@@ -3448,7 +3546,7 @@
com.apple.InterfaceBuilder.CocoaPlugin
- {{286, 455}, {361, 313}}
+ {{328, 475}, {361, 293}}
com.apple.InterfaceBuilder.CocoaPlugin
com.apple.InterfaceBuilder.CocoaPlugin
@@ -3468,7 +3566,7 @@
com.apple.InterfaceBuilder.CocoaPlugin
- {{355, 762}, {64, 6}}
+ {{397, 762}, {64, 6}}
com.apple.InterfaceBuilder.CocoaPlugin
{{182, 609}, {331, 133}}
@@ -3552,6 +3650,7 @@
com.apple.InterfaceBuilder.CocoaPlugin
+ {{475, 725}, {167, 43}}
com.apple.InterfaceBuilder.CocoaPlugin
com.apple.InterfaceBuilder.CocoaPlugin
@@ -3560,6 +3659,7 @@
com.apple.InterfaceBuilder.CocoaPlugin
+ {{284, 615}, {188, 153}}
com.apple.InterfaceBuilder.CocoaPlugin
com.apple.InterfaceBuilder.CocoaPlugin
@@ -3586,7 +3686,7 @@
- 1178
+ 1208
@@ -3607,6 +3707,25 @@
id
+
+ YES
+
+ YES
+ openWebsite:
+ toggleDirectories:
+
+
+ YES
+
+ openWebsite:
+ id
+
+
+ toggleDirectories:
+ id
+
+
+
IBProjectSource
AppDelegate.h
@@ -3619,6 +3738,13 @@
unlockApp:
id
+
+ unlockApp:
+
+ unlockApp:
+ id
+
+
YES
@@ -3634,6 +3760,30 @@
NSMenuItem
+
+ YES
+
+ YES
+ py
+ recentDirectories
+ unlockMenuItem
+
+
+ YES
+
+ py
+ PyDupeGuru
+
+
+ recentDirectories
+ RecentDirectories
+
+
+ unlockMenuItem
+ NSMenuItem
+
+
+
IBUserSource
@@ -3646,6 +3796,13 @@
unlockApp:
id
+
+ unlockApp:
+
+ unlockApp:
+ id
+
+
YES
@@ -3663,6 +3820,35 @@
NSMenuItem
+
+ YES
+
+ YES
+ py
+ recentDirectories
+ result
+ unlockMenuItem
+
+
+ YES
+
+ py
+ PyDupeGuruBase
+
+
+ recentDirectories
+ RecentDirectories
+
+
+ result
+ ResultWindowBase
+
+
+ unlockMenuItem
+ NSMenuItem
+
+
+
IBProjectSource
../base/AppDelegate.h
@@ -3771,6 +3957,25 @@
id
+
+ YES
+
+ YES
+ clearMenu:
+ menuClick:
+
+
+ YES
+
+ clearMenu:
+ id
+
+
+ menuClick:
+ id
+
+
+
YES
@@ -3784,6 +3989,25 @@
NSMenu
+
+ YES
+
+ YES
+ delegate
+ menu
+
+
+ YES
+
+ delegate
+ id
+
+
+ menu
+ NSMenu
+
+
+
IBProjectSource
../RecentDirectories.h
@@ -3813,6 +4037,25 @@
id
+
+ YES
+
+ YES
+ resetColumnsToDefault:
+ startDuplicateScan:
+
+
+ YES
+
+ resetColumnsToDefault:
+ id
+
+
+ startDuplicateScan:
+ id
+
+
+
IBProjectSource
ResultWindow.h
@@ -3834,6 +4077,7 @@
filter:
ignoreSelected:
invokeCustomCommand:
+ loadResults:
markAll:
markInvert:
markNone:
@@ -3846,6 +4090,7 @@
renameSelected:
resetColumnsToDefault:
revealSelected:
+ saveResults:
showPreferencesPanel:
startDuplicateScan:
switchSelected:
@@ -3884,6 +4129,167 @@
id
id
id
+ id
+ id
+
+
+
+ YES
+
+ YES
+ changeDelta:
+ changePowerMarker:
+ clearIgnoreList:
+ copyMarked:
+ deleteMarked:
+ exportToXHTML:
+ filter:
+ ignoreSelected:
+ invokeCustomCommand:
+ loadResults:
+ markAll:
+ markInvert:
+ markNone:
+ markSelected:
+ moveMarked:
+ openClicked:
+ openSelected:
+ removeMarked:
+ removeSelected:
+ renameSelected:
+ resetColumnsToDefault:
+ revealSelected:
+ saveResults:
+ showPreferencesPanel:
+ startDuplicateScan:
+ switchSelected:
+ toggleColumn:
+ toggleDelta:
+ toggleDetailsPanel:
+ togglePowerMarker:
+
+
+ YES
+
+ changeDelta:
+ id
+
+
+ changePowerMarker:
+ id
+
+
+ clearIgnoreList:
+ id
+
+
+ copyMarked:
+ id
+
+
+ deleteMarked:
+ id
+
+
+ exportToXHTML:
+ id
+
+
+ filter:
+ id
+
+
+ ignoreSelected:
+ id
+
+
+ invokeCustomCommand:
+ id
+
+
+ loadResults:
+ id
+
+
+ markAll:
+ id
+
+
+ markInvert:
+ id
+
+
+ markNone:
+ id
+
+
+ markSelected:
+ id
+
+
+ moveMarked:
+ id
+
+
+ openClicked:
+ id
+
+
+ openSelected:
+ id
+
+
+ removeMarked:
+ id
+
+
+ removeSelected:
+ id
+
+
+ renameSelected:
+ id
+
+
+ resetColumnsToDefault:
+ id
+
+
+ revealSelected:
+ id
+
+
+ saveResults:
+ id
+
+
+ showPreferencesPanel:
+ id
+
+
+ startDuplicateScan:
+ id
+
+
+ switchSelected:
+ id
+
+
+ toggleColumn:
+ id
+
+
+ toggleDelta:
+ id
+
+
+ toggleDetailsPanel:
+ id
+
+
+ togglePowerMarker:
+ id
+
@@ -3911,6 +4317,55 @@
NSTextField
+
+ YES
+
+ YES
+ app
+ columnsMenu
+ deltaSwitch
+ filterField
+ matches
+ pmSwitch
+ py
+ stats
+
+
+ YES
+
+ app
+ id
+
+
+ columnsMenu
+ NSMenu
+
+
+ deltaSwitch
+ NSSegmentedControl
+
+
+ filterField
+ NSSearchField
+
+
+ matches
+ HSOutlineView
+
+
+ pmSwitch
+ NSSegmentedControl
+
+
+ py
+ PyDupeGuruBase
+
+
+ stats
+ NSTextField
+
+
+
IBProjectSource
../base/ResultWindow.h
@@ -4502,6 +4957,13 @@
showWindow:
id
+
+ showWindow:
+
+ showWindow:
+ id
+
+
IBFrameworkSource
AppKit.framework/Headers/NSWindowController.h
@@ -4514,15 +4976,30 @@
checkForUpdates:
id
+
+ checkForUpdates:
+
+ checkForUpdates:
+ id
+
+
delegate
id
+
+ delegate
+
+ delegate
+ id
+
+
0
+ IBCocoaFramework
com.apple.InterfaceBuilder.CocoaPlugin.macosx
@@ -4538,5 +5015,28 @@
YES
../../se/dupeguru.xcodeproj
3
+
+ YES
+
+ YES
+ NSActionTemplate
+ NSApplicationIcon
+ NSMenuCheckmark
+ NSMenuMixedState
+ details32
+ folder32
+ preferences32
+
+
+ YES
+ {15, 15}
+ {128, 128}
+ {9, 8}
+ {7, 2}
+ {48, 48}
+ {32, 32}
+ {32, 32}
+
+
diff --git a/core/app.py b/core/app.py
index 75d36273..b46e6c9a 100644
--- a/core/app.py
+++ b/core/app.py
@@ -244,6 +244,11 @@ class DupeGuru(RegistrableApplication, Broadcaster):
self._start_job(JOB_LOAD, self._do_load)
self.load_ignore_list()
+ def load_from(self, filename):
+ def do(j):
+ self.results.load_from_xml(filename, self._get_file, j)
+ self._start_job(JOB_LOAD, do)
+
def load_ignore_list(self):
p = op.join(self.appdata, 'ignore_list.xml')
self.scanner.ignore_list.load_from_xml(p)
@@ -322,6 +327,11 @@ class DupeGuru(RegistrableApplication, Broadcaster):
if self.results.is_modified:
self.results.save_to_xml(op.join(self.appdata, 'last_results.xml'))
+ def save_as(self, filename):
+ self.results.save_to_xml(filename)
+ # It's not because we saved it here that we don't want to save it in appdata when we quit
+ self.results.is_modified = True
+
def save_ignore_list(self):
if not op.exists(self.appdata):
os.makedirs(self.appdata)
diff --git a/core/app_cocoa_inter.py b/core/app_cocoa_inter.py
index 75ba44c6..29b535f6 100644
--- a/core/app_cocoa_inter.py
+++ b/core/app_cocoa_inter.py
@@ -46,6 +46,9 @@ class PyDupeGuruBase(PyRegistrable):
def loadResults(self):
self.py.load()
+ def loadResultsFrom_(self, filename):
+ self.py.load_from(filename)
+
def markAll(self):
self.py.mark_all()
@@ -67,6 +70,9 @@ class PyDupeGuruBase(PyRegistrable):
def saveResults(self):
self.py.save()
+ def saveResultsAs_(self, filename):
+ self.py.save_as(filename)
+
#---Actions
def addSelectedToIgnoreList(self):
self.py.add_selected_to_ignore_list()
diff --git a/core_pe/app_cocoa.py b/core_pe/app_cocoa.py
index f56a6773..10dd2c30 100644
--- a/core_pe/app_cocoa.py
+++ b/core_pe/app_cocoa.py
@@ -164,10 +164,6 @@ class DupeGuruPE(app_cocoa.DupeGuru):
else:
app_cocoa.DupeGuru._do_delete_dupe(self, dupe)
- def _do_load(self, j):
- self.directories.load_from_file(op.join(self.appdata, 'last_directories.xml'))
- self.results.load_from_xml(op.join(self.appdata, 'last_results.xml'), self._get_file, j)
-
def _get_file(self, str_path):
p = Path(str_path)
if (self.directories.iphoto_libpath is not None) and (p in self.directories.iphoto_libpath[:-1]):
diff --git a/qt/base/main_window.py b/qt/base/main_window.py
index 7ee74f88..8382a857 100644
--- a/qt/base/main_window.py
+++ b/qt/base/main_window.py
@@ -10,7 +10,7 @@ import sys
from PyQt4.QtCore import Qt, QCoreApplication, QProcess, SIGNAL, QUrl
from PyQt4.QtGui import (QMainWindow, QMenu, QPixmap, QIcon, QToolButton, QLabel, QHeaderView,
- QMessageBox, QInputDialog, QLineEdit, QDesktopServices)
+ QMessageBox, QInputDialog, QLineEdit, QDesktopServices, QFileDialog)
from hsutil.misc import nonone
@@ -37,7 +37,13 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.connect(QCoreApplication.instance(), SIGNAL('aboutToQuit()'), self.application_will_terminate)
self.connect(self.resultsView, SIGNAL('doubleClicked()'), self.resultsDoubleClicked)
self.connect(self.resultsView, SIGNAL('spacePressed()'), self.resultsSpacePressed)
+
+ # Actions (the vast majority of them are connected in the UI file, but I'm trying to
+ # phase away from those, and these connections are harder to maintain than through simple
+ # code
self.actionInvokeCustomCommand.triggered.connect(self.app.invokeCustomCommand)
+ self.actionLoadResults.triggered.connect(self.loadResultsTriggered)
+ self.actionSaveResults.triggered.connect(self.saveResultsTriggered)
def _setupUi(self):
self.setupUi(self)
@@ -196,7 +202,14 @@ class MainWindow(QMainWindow, Ui_MainWindow):
exported_path = self.app.export_to_xhtml(column_ids)
url = QUrl.fromLocalFile(exported_path)
QDesktopServices.openUrl(url)
-
+
+ def loadResultsTriggered(self):
+ title = "Select a results file to load"
+ files = "dupeGuru Results (*.dupeguru)"
+ destination = QFileDialog.getOpenFileName(self, title, '', files)
+ if destination:
+ self.app.load_from(destination)
+
def makeReferenceTriggered(self):
self.app.make_selected_reference()
@@ -248,6 +261,13 @@ class MainWindow(QMainWindow, Ui_MainWindow):
def revealTriggered(self):
self.app.reveal_selected()
+ def saveResultsTriggered(self):
+ title = "Select a file to save your results to"
+ files = "dupeGuru Results (*.dupeguru)"
+ destination = QFileDialog.getSaveFileName(self, title, '', files)
+ if destination:
+ self.app.save_as(destination)
+
def scanTriggered(self):
title = "Start a new scan"
if len(self.app.results.groups) > 0:
diff --git a/qt/base/main_window.ui b/qt/base/main_window.ui
index 7d443b43..971425d3 100644
--- a/qt/base/main_window.ui
+++ b/qt/base/main_window.ui
@@ -126,6 +126,8 @@
+
+
@@ -183,7 +185,7 @@
Start scanning for duplicates
- Ctrl+S
+ Ctrl+T
@@ -427,6 +429,22 @@
Export To XHTML
+
+
+ Load Results...
+
+
+ Ctrl+L
+
+
+
+
+ Save Results...
+
+
+ Ctrl+S
+
+
Open Debug Log