1
0
mirror of https://github.com/arsenetar/dupeguru.git synced 2026-01-22 22:51:39 +00:00

[#194 state:fixed] Added the "Replace with symlink" deletion option.

This commit is contained in:
Virgil Dupras
2012-08-01 12:36:23 -04:00
parent 5247ac8abd
commit 5a5a74d0e1
9 changed files with 71 additions and 53 deletions

View File

@@ -15,12 +15,14 @@ http://www.hardcoded.net/licenses/bsd_license
PyDeletionOptions *model;
NSTextField *messageTextField;
NSButton *hardlinkButton;
NSButton *linkButton;
NSMatrix *linkTypeRadio;
NSButton *directButton;
}
@property (readwrite, retain) NSTextField *messageTextField;
@property (readwrite, retain) NSButton *hardlinkButton;
@property (readwrite, retain) NSButton *linkButton;
@property (readwrite, retain) NSMatrix *linkTypeRadio;
@property (readwrite, retain) NSButton *directButton;
- (id)initWithPyRef:(PyObject *)aPyRef;

View File

@@ -13,7 +13,8 @@ http://www.hardcoded.net/licenses/bsd_license
@implementation DeletionOptions
@synthesize messageTextField;
@synthesize hardlinkButton;
@synthesize linkButton;
@synthesize linkTypeRadio;
@synthesize directButton;
- (id)initWithPyRef:(PyObject *)aPyRef
@@ -33,7 +34,8 @@ http://www.hardcoded.net/licenses/bsd_license
- (void)updateOptions
{
[model setHardlink:[hardlinkButton state] == NSOnState];
[model setLinkDeleted:[linkButton state] == NSOnState];
[model setUseHardlinks:[linkTypeRadio selectedColumn] == 1];
[model setDirect:[directButton state] == NSOnState];
}
@@ -55,8 +57,9 @@ http://www.hardcoded.net/licenses/bsd_license
- (BOOL)show
{
[hardlinkButton setState:NSOffState];
[linkButton setState:NSOffState];
[directButton setState:NSOffState];
[linkTypeRadio selectCellAtRow:0 column:0];
NSInteger r = [NSApp runModalForWindow:[self window]];
[[self window] close];
return r == NSOKButton;

View File

@@ -1,47 +1,49 @@
ownerclass = 'DeletionOptions'
ownerimport = 'DeletionOptions.h'
result = Window(450, 215, "Deletion Options")
result = Window(450, 240, "Deletion Options")
messageLabel = Label(result, "")
hardlinkCheckbox = Checkbox(result, "Hardlink deleted files")
hardlinkLabel = Label(result, "After having deleted a duplicate, place a hardlink targeting the "
linkCheckbox = Checkbox(result, "Link deleted files")
linkLabel = Label(result, "After having deleted a duplicate, place a link targeting the "
"reference file to replace the deleted file.")
linkTypeChoice = RadioButtons(result, ["Symlink", "Hardlink"], columns=2)
directCheckbox = Checkbox(result, "Directly delete files")
directLabel = Label(result, "Instead of sending files to trash, delete them directly. This option "
"is usually used as a workaround when the normal deletion method doesn't work.")
proceedButton = Button(result, "Proceed")
cancelButton = Button(result, "Cancel")
owner.hardlinkButton = hardlinkCheckbox
owner.linkButton = linkCheckbox
owner.linkTypeRadio = linkTypeChoice
owner.directButton = directCheckbox
owner.messageTextField = messageLabel
result.canMinimize = False
result.canResize = False
hardlinkLabel.controlSize = const.NSSmallControlSize
directLabel.controlSize = const.NSSmallControlSize
linkLabel.controlSize = ControlSize.Small
directLabel.controlSize = ControlSize.Small
linkTypeChoice.controlSize = ControlSize.Small
proceedButton.keyEquivalent = '\\r'
cancelButton.keyEquivalent = '\\e'
hardlinkCheckbox.action = directCheckbox.action = Action(owner, 'updateOptions')
linkCheckbox.action = directCheckbox.action = linkTypeChoice.action = Action(owner, 'updateOptions')
proceedButton.action = Action(owner, 'proceed')
cancelButton.action = Action(owner, 'cancel')
hardlinkLabel.height *= 2 # 2 lines
linkLabel.height *= 2 # 2 lines
directLabel.height *= 3 # 3 lines
proceedButton.width = 92
cancelButton.width = 92
messageLabel.packToCorner(Pack.UpperLeft)
hardlinkCheckbox.packRelativeTo(messageLabel, Pack.Below)
hardlinkLabel.packRelativeTo(hardlinkCheckbox, Pack.Below)
directCheckbox.packRelativeTo(hardlinkLabel, Pack.Below)
directLabel.packRelativeTo(directCheckbox, Pack.Below)
for view in (messageLabel, hardlinkCheckbox, hardlinkLabel, directCheckbox, directLabel):
view.fill(Pack.Right)
proceedButton.packToCorner(Pack.LowerRight)
cancelButton.packRelativeTo(proceedButton, Pack.Left)
mainLayout = VLayout([messageLabel, linkCheckbox, linkLabel, linkTypeChoice, directCheckbox,
directLabel])
mainLayout.packToCorner(Pack.UpperLeft)
mainLayout.fill(Pack.Right)
buttonLayout = HLayout([cancelButton, proceedButton])
buttonLayout.packToCorner(Pack.LowerRight)
# indent the labels under checkboxes a little bit to the right
for label in (hardlinkLabel, directLabel):
label.x += 20
label.width -= 20
for indentedView in (linkLabel, directLabel, linkTypeChoice):
indentedView.x += 20
indentedView.width -= 20
# We actually don't want the link choice radio buttons to take all the width, it looks weird.
linkTypeChoice.width = 170

View File

@@ -151,12 +151,12 @@ class DupeGuruME(DupeGuruBase):
self.directories = Directories(fileclasses=self.directories.fileclasses)
self.dead_tracks = []
def _do_delete(self, j, replace_with_hardlinks, direct_deletion):
def _do_delete(self, j, *args):
# XXX If I read correctly, Python 3.3 will allow us to go fetch inner function easily, so
# we'll be able to replace "op" below with DupeGuruBase._do_delete.op.
def op(dupe):
j.add_progress()
return self._do_delete_dupe(dupe, replace_with_hardlinks, direct_deletion)
return self._do_delete_dupe(dupe, *args)
marked = [dupe for dupe in self.results.dupes if self.results.is_marked(dupe)]
j.start_job(self.results.mark_count, tr("Sending dupes to the Trash"))
@@ -169,10 +169,10 @@ class DupeGuruME(DupeGuruBase):
pass
self.results.perform_on_marked(op, True)
def _do_delete_dupe(self, dupe, replace_with_hardlinks, direct_deletion):
def _do_delete_dupe(self, dupe, *args):
if isinstance(dupe, ITunesSong):
dupe.remove_from_library()
DupeGuruBase._do_delete_dupe(self, dupe, replace_with_hardlinks, direct_deletion)
DupeGuruBase._do_delete_dupe(self, dupe, *args)
def _create_file(self, path):
if (self.directories.itunes_libpath is not None) and (path in self.directories.itunes_libpath[:-1]):

View File

@@ -176,10 +176,10 @@ class DupeGuruPE(DupeGuruBase):
DupeGuruBase.__init__(self, view, appdata)
self.directories = Directories()
def _do_delete(self, j, replace_with_hardlinks, direct_deletion):
def _do_delete(self, j, *args):
def op(dupe):
j.add_progress()
return self._do_delete_dupe(dupe, replace_with_hardlinks, direct_deletion)
return self._do_delete_dupe(dupe, *args)
self.deleted_aperture_photos = False
marked = [dupe for dupe in self.results.dupes if self.results.is_marked(dupe)]
@@ -202,7 +202,7 @@ class DupeGuruPE(DupeGuruBase):
pass
self.results.perform_on_marked(op, True)
def _do_delete_dupe(self, dupe, replace_with_hardlinks, direct_deletion):
def _do_delete_dupe(self, dupe, *args):
if isinstance(dupe, IPhoto):
try:
a = app('iPhoto')
@@ -244,7 +244,7 @@ class DupeGuruPE(DupeGuruBase):
except (CommandError, RuntimeError) as e:
raise EnvironmentError(str(e))
else:
DupeGuruBase._do_delete_dupe(self, dupe, replace_with_hardlinks, direct_deletion)
DupeGuruBase._do_delete_dupe(self, dupe, *args)
def _create_file(self, path):
if (self.directories.iphoto_libpath is not None) and (path in self.directories.iphoto_libpath[:-1]):

View File

@@ -13,8 +13,11 @@ class DeletionOptionsView(GUIObjectView):
def show(self) -> bool: pass
class PyDeletionOptions(PyGUIObject):
def setHardlink_(self, hardlink: bool):
self.model.hardlink = hardlink
def setLinkDeleted_(self, link_deleted: bool):
self.model.link_deleted = link_deleted
def setUseHardlinks_(self, use_hardlinks: bool):
self.model.use_hardlinks = use_hardlinks
def setDirect_(self, direct: bool):
self.model.direct = direct