1
0
mirror of https://github.com/arsenetar/dupeguru.git synced 2024-10-19 00:55:58 +00:00
dupeguru/cocoa/inter/app.py
Virgil Dupras 721591d3e3 Added a Deletion Options dialog that pops up when Send to Trash is triggered.
It offers hardlink and direct deletion options. This new feature supersedes the old "Send to Trash and Hardlink" menu item, which was removed.
2012-05-30 12:10:56 -04:00

220 lines
6.4 KiB
Python

import logging
from objp.util import pyref, dontwrap
from jobprogress import job
import cocoa
from cocoa import install_exception_hook, proxy
from cocoa.inter import PyFairware, FairwareView
from hscommon.trans import trget
from core.app import JobType
tr = trget('ui')
JOBID2TITLE = {
JobType.Scan: tr("Scanning for duplicates"),
JobType.Load: tr("Loading"),
JobType.Move: tr("Moving"),
JobType.Copy: tr("Copying"),
JobType.Delete: tr("Sending to Trash"),
}
class DupeGuruView(FairwareView):
def askYesNoWithPrompt_(self, prompt: str) -> bool: pass
def showProblemDialog(self): pass
def selectDestFolderWithPrompt_(self, prompt: str) -> str: pass
class PyDupeGuruBase(PyFairware):
FOLLOW_PROTOCOLS = ['Worker']
@dontwrap
def _init(self, modelclass):
logging.basicConfig(level=logging.WARNING, format='%(levelname)s %(message)s')
install_exception_hook()
appdata = proxy.getAppdataPath()
self.model = modelclass(self, appdata)
self.progress = cocoa.ThreadedJobPerformer()
#---Sub-proxies
def detailsPanel(self) -> pyref:
return self.model.details_panel
def directoryTree(self) -> pyref:
return self.model.directory_tree
def problemDialog(self) -> pyref:
return self.model.problem_dialog
def statsLabel(self) -> pyref:
return self.model.stats_label
def resultTable(self) -> pyref:
return self.model.result_table
def ignoreListDialog(self) -> pyref:
return self.model.ignore_list_dialog
def deletionOptions(self) -> pyref:
return self.model.deletion_options
#---Directories
def addDirectory_(self, directory: str) -> int:
return self.model.add_directory(directory)
#---Results
def doScan(self):
self.model.start_scanning()
def exportToXHTML(self) -> str:
return self.model.export_to_xhtml()
def loadSession(self):
self.model.load()
def loadResultsFrom_(self, filename: str):
self.model.load_from(filename)
def markAll(self):
self.model.mark_all()
def markNone(self):
self.model.mark_none()
def markInvert(self):
self.model.mark_invert()
def purgeIgnoreList(self):
self.model.purge_ignore_list()
def toggleSelectedMark(self):
self.model.toggle_selected_mark_state()
def saveSession(self):
self.model.save()
def saveResultsAs_(self, filename: str):
self.model.save_as(filename)
#---Actions
def addSelectedToIgnoreList(self):
self.model.add_selected_to_ignore_list()
def deleteMarked(self):
self.model.delete_marked()
def applyFilter_(self, filter: str):
self.model.apply_filter(filter)
def makeSelectedReference(self):
self.model.make_selected_reference()
def copyMarked(self):
self.model.copy_or_move_marked(copy=True)
def moveMarked(self):
self.model.copy_or_move_marked(copy=False)
def openSelected(self):
self.model.open_selected()
def removeMarked(self):
self.model.remove_marked()
def removeSelected(self):
self.model.remove_selected()
def revealSelected(self):
self.model.reveal_selected()
def invokeCustomCommand(self):
self.model.invoke_custom_command()
def showIgnoreList(self):
self.model.ignore_list_dialog.show()
#---Information
def resultsAreModified(self) -> bool:
return self.model.results.is_modified
#---Properties
def setMixFileKind_(self, mix_file_kind: bool):
self.model.scanner.mix_file_kind = mix_file_kind
def setEscapeFilterRegexp_(self, escape_filter_regexp: bool):
self.model.options['escape_filter_regexp'] = escape_filter_regexp
def setRemoveEmptyFolders_(self, remove_empty_folders: bool):
self.model.options['clean_empty_dirs'] = remove_empty_folders
def setIgnoreHardlinkMatches_(self, ignore_hardlink_matches: bool):
self.model.options['ignore_hardlink_matches'] = ignore_hardlink_matches
def setCopyMoveDestType_(self, copymove_dest_type: int):
self.model.options['copymove_dest_type'] = copymove_dest_type
#---Worker
def getJobProgress(self) -> object: # NSNumber
try:
return self.progress.last_progress
except AttributeError:
# I have *no idea* why this can possible happen (last_progress is always set by
# create_job() *before* any threaded job notification, which shows the progress panel,
# is sent), but it happens anyway, so there we go. ref: #106
return -1
def getJobDesc(self) -> str:
try:
return self.progress.last_desc
except AttributeError:
# see getJobProgress
return ''
def cancelJob(self):
self.progress.job_cancelled = True
def jobCompleted_(self, jobid: str):
result = self.model._job_completed(jobid, self.progress.last_error)
if not result:
self.progress.reraise_if_error()
#--- model --> view
@dontwrap
def open_path(self, path):
proxy.openPath_(str(path))
@dontwrap
def reveal_path(self, path):
proxy.revealPath_(str(path))
@dontwrap
def start_job(self, jobid, func, args=()):
try:
j = self.progress.create_job()
args = tuple([j] + list(args))
self.progress.run_threaded(func, args=args)
except job.JobInProgressError:
proxy.postNotification_userInfo_('JobInProgress', None)
else:
ud = {'desc': JOBID2TITLE[jobid], 'jobid':jobid}
proxy.postNotification_userInfo_('JobStarted', ud)
@dontwrap
def ask_yes_no(self, prompt):
return self.callback.askYesNoWithPrompt_(prompt)
@dontwrap
def show_results_window(self):
# Not needed yet because our progress dialog is shown as a sheet of the results window,
# which causes it to be already visible when the scan/load ends.
# XXX Make progress sheet be a child of the folder selection window.
pass
@dontwrap
def show_problem_dialog(self):
self.callback.showProblemDialog()
@dontwrap
def select_dest_folder(self, prompt):
return self.callback.selectDestFolderWithPrompt_(prompt)