mirror of
https://github.com/arsenetar/dupeguru.git
synced 2025-03-10 05:34:36 +00:00
Decoupled app in core.app from apps in qt.app and core.app_cocoa. Instead of subclassing it, they now hold a reference to it while fulfilling the role of core.app's "view".
This commit is contained in:
parent
841b249b67
commit
f730f4f55a
50
core/app.py
50
core/app.py
@ -41,7 +41,16 @@ class DestType:
|
||||
Absolute = 2
|
||||
|
||||
class DupeGuru(RegistrableApplication, Broadcaster):
|
||||
def __init__(self, data_module, appdata):
|
||||
#--- View interface
|
||||
# open_path(path)
|
||||
# reveal_path(path)
|
||||
# start_job(jobid, func, *args) ( func(j, *args) )
|
||||
# get_default(key_name, fallback_value=None)
|
||||
# set_default(key_name, value)
|
||||
# show_extra_fairware_reminder()
|
||||
|
||||
def __init__(self, view, data_module, appdata):
|
||||
self.view = view
|
||||
if self.get_default(DEBUG_MODE_PREFERENCE, False):
|
||||
logging.getLogger().setLevel(logging.DEBUG)
|
||||
logging.debug("Debug mode enabled")
|
||||
@ -122,14 +131,6 @@ class DupeGuru(RegistrableApplication, Broadcaster):
|
||||
if jobid in {JOB_COPY, JOB_MOVE, JOB_DELETE}:
|
||||
self.notify('problems_changed')
|
||||
|
||||
@staticmethod
|
||||
def _open_path(path):
|
||||
raise NotImplementedError()
|
||||
|
||||
@staticmethod
|
||||
def _reveal_path(path):
|
||||
raise NotImplementedError()
|
||||
|
||||
@staticmethod
|
||||
def _remove_hardlink_dupes(files):
|
||||
seen_inodes = set()
|
||||
@ -151,19 +152,6 @@ class DupeGuru(RegistrableApplication, Broadcaster):
|
||||
self.selected_dupes = dupes
|
||||
self.notify('dupes_selected')
|
||||
|
||||
def _start_job(self, jobid, func, *args):
|
||||
# func(j, *args)
|
||||
raise NotImplementedError()
|
||||
|
||||
def _get_default(self, key_name, fallback_value=None):
|
||||
raise NotImplementedError()
|
||||
|
||||
def _set_default(self, key_name, value):
|
||||
raise NotImplementedError()
|
||||
|
||||
def _show_extra_fairware_reminder(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
#--- Public
|
||||
def add_directory(self, d):
|
||||
try:
|
||||
@ -194,7 +182,7 @@ class DupeGuru(RegistrableApplication, Broadcaster):
|
||||
|
||||
def show_extra_fairware_reminder_if_needed(self):
|
||||
if self.results.mark_count > 100 and self.should_show_fairware_reminder:
|
||||
self._show_extra_fairware_reminder()
|
||||
self.view.show_extra_fairware_reminder()
|
||||
|
||||
def clean_empty_dirs(self, path):
|
||||
if self.options['clean_empty_dirs']:
|
||||
@ -234,11 +222,11 @@ class DupeGuru(RegistrableApplication, Broadcaster):
|
||||
|
||||
self.show_extra_fairware_reminder_if_needed()
|
||||
jobid = JOB_COPY if copy else JOB_MOVE
|
||||
self._start_job(jobid, do)
|
||||
self.view.start_job(jobid, do)
|
||||
|
||||
def delete_marked(self, replace_with_hardlinks=False):
|
||||
self.show_extra_fairware_reminder_if_needed()
|
||||
self._start_job(JOB_DELETE, self._do_delete, replace_with_hardlinks)
|
||||
self.view.start_job(JOB_DELETE, self._do_delete, replace_with_hardlinks)
|
||||
|
||||
def export_to_xhtml(self, column_ids):
|
||||
column_ids = [colid for colid in column_ids if colid.isdigit()]
|
||||
@ -288,7 +276,7 @@ class DupeGuru(RegistrableApplication, Broadcaster):
|
||||
def load_from(self, filename):
|
||||
def do(j):
|
||||
self.results.load_from_xml(filename, self._get_file, j)
|
||||
self._start_job(JOB_LOAD, do)
|
||||
self.view.start_job(JOB_LOAD, do)
|
||||
|
||||
def make_selected_reference(self):
|
||||
dupes = self.without_ref(self.selected_dupes)
|
||||
@ -321,7 +309,7 @@ class DupeGuru(RegistrableApplication, Broadcaster):
|
||||
|
||||
def open_selected(self):
|
||||
if self.selected_dupes:
|
||||
self._open_path(self.selected_dupes[0].path)
|
||||
self.view.open_path(self.selected_dupes[0].path)
|
||||
|
||||
def purge_ignore_list(self):
|
||||
self.scanner.ignore_list.Filter(lambda f,s:op.exists(f) and op.exists(s))
|
||||
@ -360,7 +348,7 @@ class DupeGuru(RegistrableApplication, Broadcaster):
|
||||
|
||||
def reveal_selected(self):
|
||||
if self.selected_dupes:
|
||||
self._reveal_path(self.selected_dupes[0].path)
|
||||
self.view.reveal_path(self.selected_dupes[0].path)
|
||||
|
||||
def save(self):
|
||||
if not op.exists(self.appdata):
|
||||
@ -388,7 +376,7 @@ class DupeGuru(RegistrableApplication, Broadcaster):
|
||||
raise NoScannableFileError()
|
||||
self.results.groups = []
|
||||
self._results_changed()
|
||||
self._start_job(JOB_SCAN, do)
|
||||
self.view.start_job(JOB_SCAN, do)
|
||||
|
||||
def toggle_selected_mark_state(self):
|
||||
for dupe in self.selected_dupes:
|
||||
@ -399,7 +387,7 @@ class DupeGuru(RegistrableApplication, Broadcaster):
|
||||
return [dupe for dupe in dupes if self.results.get_group_of_duplicate(dupe).ref is not dupe]
|
||||
|
||||
def get_default(self, key, fallback_value=None):
|
||||
result = nonone(self._get_default(key), fallback_value)
|
||||
result = nonone(self.view.get_default(key), fallback_value)
|
||||
if fallback_value is not None and not isinstance(result, type(fallback_value)):
|
||||
# we don't want to end up with garbage values from the prefs
|
||||
try:
|
||||
@ -409,7 +397,7 @@ class DupeGuru(RegistrableApplication, Broadcaster):
|
||||
return result
|
||||
|
||||
def set_default(self, key, value):
|
||||
self._set_default(key, value)
|
||||
self.view.set_default(key, value)
|
||||
|
||||
#--- Properties
|
||||
@property
|
||||
|
@ -27,46 +27,51 @@ JOBID2TITLE = {
|
||||
app.JOB_DELETE: tr("Sending to Trash"),
|
||||
}
|
||||
|
||||
class DupeGuru(app.DupeGuru):
|
||||
def __init__(self, data_module, appdata_subdir):
|
||||
logging.basicConfig(level=logging.WARNING, format='%(levelname)s %(message)s')
|
||||
install_exception_hook()
|
||||
appsupport = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, True)[0]
|
||||
appdata = op.join(appsupport, appdata_subdir)
|
||||
app.DupeGuru.__init__(self, data_module, appdata)
|
||||
self.progress = cocoa.ThreadedJobPerformer()
|
||||
class DupeGuruView:
|
||||
def __init__(self, app):
|
||||
self.app = app
|
||||
|
||||
#--- Override
|
||||
@staticmethod
|
||||
def _open_path(path):
|
||||
def open_path(path):
|
||||
NSWorkspace.sharedWorkspace().openFile_(str(path))
|
||||
|
||||
@staticmethod
|
||||
def _reveal_path(path):
|
||||
def reveal_path(path):
|
||||
NSWorkspace.sharedWorkspace().selectFile_inFileViewerRootedAtPath_(str(path), '')
|
||||
|
||||
def _start_job(self, jobid, func, *args):
|
||||
def start_job(self, jobid, func, *args):
|
||||
try:
|
||||
j = self.progress.create_job()
|
||||
j = self.app.progress.create_job()
|
||||
args = tuple([j] + list(args))
|
||||
self.progress.run_threaded(func, args=args)
|
||||
self.app.progress.run_threaded(func, args=args)
|
||||
except job.JobInProgressError:
|
||||
NSNotificationCenter.defaultCenter().postNotificationName_object_('JobInProgress', self)
|
||||
else:
|
||||
ud = {'desc': JOBID2TITLE[jobid], 'jobid':jobid}
|
||||
NSNotificationCenter.defaultCenter().postNotificationName_object_userInfo_('JobStarted', self, ud)
|
||||
|
||||
def _get_default(self, key_name):
|
||||
def get_default(self, key_name):
|
||||
raw = NSUserDefaults.standardUserDefaults().objectForKey_(key_name)
|
||||
result = pythonify(raw)
|
||||
return result
|
||||
|
||||
def _set_default(self, key_name, value):
|
||||
def set_default(self, key_name, value):
|
||||
NSUserDefaults.standardUserDefaults().setObject_forKey_(value, key_name)
|
||||
|
||||
def _show_extra_fairware_reminder(self):
|
||||
def show_extra_fairware_reminder(self):
|
||||
NSNotificationCenter.defaultCenter().postNotificationName_object_userInfo_('ShowExtraFairwareReminder', self, None)
|
||||
|
||||
|
||||
class DupeGuru(app.DupeGuru):
|
||||
def __init__(self, data_module, appdata_subdir):
|
||||
logging.basicConfig(level=logging.WARNING, format='%(levelname)s %(message)s')
|
||||
install_exception_hook()
|
||||
view = DupeGuruView(self)
|
||||
appsupport = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, True)[0]
|
||||
appdata = op.join(appsupport, appdata_subdir)
|
||||
app.DupeGuru.__init__(self, view, data_module, appdata)
|
||||
self.progress = cocoa.ThreadedJobPerformer()
|
||||
|
||||
#--- Public
|
||||
def start_scanning(self):
|
||||
self._select_dupes([])
|
||||
|
114
qt/base/app.py
114
qt/base/app.py
@ -19,7 +19,7 @@ from jobprogress import job
|
||||
from jobprogress.qt import Progress
|
||||
from hscommon.trans import tr, trmsg
|
||||
|
||||
from core.app import DupeGuru as DupeGuruBase, JOB_SCAN, JOB_LOAD, JOB_MOVE, JOB_COPY, JOB_DELETE
|
||||
from core.app import DupeGuru as DupeGuruModel, JOB_SCAN, JOB_LOAD, JOB_MOVE, JOB_COPY, JOB_DELETE
|
||||
|
||||
from qtlib.about_box import AboutBox
|
||||
from qtlib.recent import Recent
|
||||
@ -45,11 +45,12 @@ class SysWrapper(io.IOBase):
|
||||
if s.strip(): # don't log empty stuff
|
||||
logging.warning(s)
|
||||
|
||||
class DupeGuru(DupeGuruBase, QObject):
|
||||
class DupeGuru(QObject):
|
||||
LOGO_NAME = '<replace this>'
|
||||
NAME = '<replace this>'
|
||||
|
||||
def __init__(self, data_module):
|
||||
QObject.__init__(self)
|
||||
appdata = str(QDesktopServices.storageLocation(QDesktopServices.DataLocation))
|
||||
if not op.exists(appdata):
|
||||
os.makedirs(appdata)
|
||||
@ -62,8 +63,7 @@ class DupeGuru(DupeGuruBase, QObject):
|
||||
sys.stdout = SysWrapper()
|
||||
self.prefs = self._create_preferences()
|
||||
self.prefs.load()
|
||||
DupeGuruBase.__init__(self, data_module, appdata)
|
||||
QObject.__init__(self)
|
||||
self.model = DupeGuruModel(view=self, data_module=data_module, appdata=appdata)
|
||||
self._setup()
|
||||
|
||||
#--- Private
|
||||
@ -71,7 +71,7 @@ class DupeGuru(DupeGuruBase, QObject):
|
||||
self._setupActions()
|
||||
self._update_options()
|
||||
self.recentResults = Recent(self, 'recentResults')
|
||||
self.recentResults.mustOpenItem.connect(self.load_from)
|
||||
self.recentResults.mustOpenItem.connect(self.model.load_from)
|
||||
self.resultWindow = self._create_result_window()
|
||||
self._progress = Progress(self.resultWindow)
|
||||
self.directories_dialog = DirectoriesDialog(self.resultWindow, self)
|
||||
@ -81,16 +81,16 @@ class DupeGuru(DupeGuruBase, QObject):
|
||||
self.about_box = AboutBox(self.resultWindow, self)
|
||||
|
||||
|
||||
self.reg = Registration(self)
|
||||
self.set_registration(self.prefs.registration_code, self.prefs.registration_email)
|
||||
if self.should_show_fairware_reminder:
|
||||
self.reg = Registration(self.model)
|
||||
self.model.set_registration(self.prefs.registration_code, self.prefs.registration_email)
|
||||
if self.model.should_show_fairware_reminder:
|
||||
# The timer scheme is because if the nag is not shown before the application is
|
||||
# completely initialized, the nag will be shown before the app shows up in the task bar
|
||||
# In some circumstances, the nag is hidden by other window, which may make the user think
|
||||
# that the application haven't launched.
|
||||
QTimer.singleShot(0, self.reg.show_nag)
|
||||
self.directories_dialog.show()
|
||||
self.load()
|
||||
self.model.load()
|
||||
|
||||
self.connect(QCoreApplication.instance(), SIGNAL('aboutToQuit()'), self.application_will_terminate)
|
||||
self.connect(self._progress, SIGNAL('finished(QString)'), self.job_finished)
|
||||
@ -120,10 +120,10 @@ class DupeGuru(DupeGuruBase, QObject):
|
||||
self.about_box.registeredEmailLabel.setText(self.prefs.registration_email)
|
||||
|
||||
def _update_options(self):
|
||||
self.scanner.mix_file_kind = self.prefs.mix_file_kind
|
||||
self.options['escape_filter_regexp'] = self.prefs.use_regexp
|
||||
self.options['clean_empty_dirs'] = self.prefs.remove_empty_folders
|
||||
self.options['ignore_hardlink_matches'] = self.prefs.ignore_hardlink_matches
|
||||
self.model.scanner.mix_file_kind = self.prefs.mix_file_kind
|
||||
self.model.options['escape_filter_regexp'] = self.prefs.use_regexp
|
||||
self.model.options['clean_empty_dirs'] = self.prefs.remove_empty_folders
|
||||
self.model.options['ignore_hardlink_matches'] = self.prefs.ignore_hardlink_matches
|
||||
|
||||
#--- Virtual
|
||||
def _create_details_dialog(self, parent):
|
||||
@ -138,44 +138,15 @@ class DupeGuru(DupeGuruBase, QObject):
|
||||
def _create_preferences_dialog(self, parent):
|
||||
raise NotImplementedError()
|
||||
|
||||
#--- Override
|
||||
@staticmethod
|
||||
def _open_path(path):
|
||||
url = QUrl.fromLocalFile(str(path))
|
||||
QDesktopServices.openUrl(url)
|
||||
|
||||
@staticmethod
|
||||
def _reveal_path(path):
|
||||
DupeGuru._open_path(path[:-1])
|
||||
|
||||
def _start_job(self, jobid, func, *args):
|
||||
title = JOBID2TITLE[jobid]
|
||||
try:
|
||||
j = self._progress.create_job()
|
||||
args = tuple([j] + list(args))
|
||||
self._progress.run(jobid, title, func, args=args)
|
||||
except job.JobInProgressError:
|
||||
msg = trmsg("TaskHangingMsg")
|
||||
QMessageBox.information(self.resultWindow, 'Action in progress', msg)
|
||||
|
||||
def _get_default(self, key):
|
||||
return self.prefs.get_value(key)
|
||||
|
||||
def _set_default(self, key, value):
|
||||
self.prefs.set_value(key, value)
|
||||
|
||||
def _show_extra_fairware_reminder(self):
|
||||
dialog = ExtraFairwareReminder(self.directories_dialog, self)
|
||||
dialog.exec_()
|
||||
|
||||
#--- Public
|
||||
def add_selected_to_ignore_list(self):
|
||||
dupes = self.without_ref(self.selected_dupes)
|
||||
dupes = self.model.without_ref(self.model.selected_dupes)
|
||||
if not dupes:
|
||||
return
|
||||
title = tr("Add to Ignore List")
|
||||
msg = trmsg("IgnoreConfirmMsg").format(len(dupes))
|
||||
if self.confirm(title, msg):
|
||||
DupeGuruBase.add_selected_to_ignore_list(self)
|
||||
self.model.add_selected_to_ignore_list(self)
|
||||
|
||||
def copy_or_move_marked(self, copy):
|
||||
opname = tr("copy") if copy else tr("move")
|
||||
@ -185,18 +156,17 @@ class DupeGuru(DupeGuruBase, QObject):
|
||||
if not destination:
|
||||
return
|
||||
recreate_path = self.prefs.destination_type
|
||||
DupeGuruBase.copy_or_move_marked(self, copy, destination, recreate_path)
|
||||
self.model.copy_or_move_marked(self, copy, destination, recreate_path)
|
||||
|
||||
def remove_selected(self):
|
||||
dupes = self.without_ref(self.selected_dupes)
|
||||
dupes = self.model.without_ref(self.model.selected_dupes)
|
||||
if not dupes:
|
||||
return
|
||||
title = tr("Remove duplicates")
|
||||
msg = trmsg("FileRemovalConfirmMsg").format(len(dupes))
|
||||
if self.confirm(title, msg):
|
||||
DupeGuruBase.remove_selected(self)
|
||||
self.model.remove_selected(self)
|
||||
|
||||
#--- Public
|
||||
def askForRegCode(self):
|
||||
self.reg.ask_for_code()
|
||||
|
||||
@ -209,7 +179,7 @@ class DupeGuru(DupeGuruBase, QObject):
|
||||
def invokeCustomCommand(self):
|
||||
cmd = self.prefs.custom_command
|
||||
if cmd:
|
||||
self.invoke_command(cmd)
|
||||
self.model.invoke_command(cmd)
|
||||
else:
|
||||
msg = trmsg("NoCustomCommandMsg")
|
||||
QMessageBox.warning(self.resultWindow, tr("Custom Command"), msg)
|
||||
@ -227,21 +197,21 @@ class DupeGuru(DupeGuruBase, QObject):
|
||||
def application_will_terminate(self):
|
||||
self.willSavePrefs.emit()
|
||||
self.prefs.save()
|
||||
self.save()
|
||||
self.model.save()
|
||||
|
||||
def checkForUpdateTriggered(self):
|
||||
QProcess.execute('updater.exe', ['/checknow'])
|
||||
|
||||
def job_finished(self, jobid):
|
||||
self._job_completed(jobid)
|
||||
self.model._job_completed(jobid)
|
||||
if jobid in (JOB_MOVE, JOB_COPY, JOB_DELETE):
|
||||
if self.results.problems:
|
||||
if self.model.results.problems:
|
||||
self.problemDialog.show()
|
||||
else:
|
||||
msg = trmsg("OperationSuccessMsg")
|
||||
QMessageBox.information(self.resultWindow, tr("Operation Complete"), msg)
|
||||
elif jobid == JOB_SCAN:
|
||||
if not self.results.groups:
|
||||
if not self.model.results.groups:
|
||||
title = tr("Scan complete")
|
||||
msg = trmsg("NoDuplicateFoundMsg")
|
||||
QMessageBox.information(self.resultWindow, title, msg)
|
||||
@ -251,12 +221,12 @@ class DupeGuru(DupeGuruBase, QObject):
|
||||
self.showResultsWindow()
|
||||
|
||||
def openDebugLogTriggered(self):
|
||||
debugLogPath = op.join(self.appdata, 'debug.log')
|
||||
self._open_path(debugLogPath)
|
||||
debugLogPath = op.join(self.model.appdata, 'debug.log')
|
||||
self.open_path(debugLogPath)
|
||||
|
||||
def preferencesTriggered(self):
|
||||
self.preferences_dialog.load()
|
||||
result = self.preferences_dialog.exec_()
|
||||
result = self.preferences_dialog.exec()
|
||||
if result == QDialog.Accepted:
|
||||
self.preferences_dialog.save()
|
||||
self.prefs.save()
|
||||
@ -276,3 +246,33 @@ class DupeGuru(DupeGuruBase, QObject):
|
||||
url = QUrl.fromLocalFile(op.abspath(op.join(base_path, 'index.html')))
|
||||
QDesktopServices.openUrl(url)
|
||||
|
||||
#--- model --> view
|
||||
@staticmethod
|
||||
def open_path(path):
|
||||
url = QUrl.fromLocalFile(str(path))
|
||||
QDesktopServices.openUrl(url)
|
||||
|
||||
@staticmethod
|
||||
def reveal_path(path):
|
||||
DupeGuru.open_path(path[:-1])
|
||||
|
||||
def start_job(self, jobid, func, *args):
|
||||
title = JOBID2TITLE[jobid]
|
||||
try:
|
||||
j = self._progress.create_job()
|
||||
args = tuple([j] + list(args))
|
||||
self._progress.run(jobid, title, func, args=args)
|
||||
except job.JobInProgressError:
|
||||
msg = trmsg("TaskHangingMsg")
|
||||
QMessageBox.information(self.resultWindow, 'Action in progress', msg)
|
||||
|
||||
def get_default(self, key):
|
||||
return self.prefs.get_value(key)
|
||||
|
||||
def set_default(self, key, value):
|
||||
self.prefs.set_value(key, value)
|
||||
|
||||
def show_extra_fairware_reminder(self):
|
||||
dialog = ExtraFairwareReminder(self.directories_dialog, self)
|
||||
dialog.exec()
|
||||
|
||||
|
@ -18,7 +18,7 @@ class DetailsDialog(QDialog):
|
||||
def __init__(self, parent, app):
|
||||
QDialog.__init__(self, parent, Qt.Tool)
|
||||
self.app = app
|
||||
self.model = DetailsPanel(self, app)
|
||||
self.model = DetailsPanel(self, app.model)
|
||||
self._setupUi()
|
||||
if self.app.prefs.detailsWindowRect is not None:
|
||||
self.setGeometry(self.app.prefs.detailsWindowRect)
|
||||
|
@ -45,7 +45,7 @@ class DirectoriesDialog(QMainWindow):
|
||||
self.treeView.selectionModel().selectionChanged.connect(self.selectionChanged)
|
||||
self.app.recentResults.itemsChanged.connect(self._updateLoadResultsButton)
|
||||
self.recentFolders.itemsChanged.connect(self._updateAddButton)
|
||||
self.recentFolders.mustOpenItem.connect(self.app.add_directory)
|
||||
self.recentFolders.mustOpenItem.connect(self.app.model.add_directory)
|
||||
self.directoriesModel.foldersAdded.connect(self.directoriesModelAddedFolders)
|
||||
self.app.willSavePrefs.connect(self.appWillSavePrefs)
|
||||
|
||||
@ -170,7 +170,7 @@ class DirectoriesDialog(QMainWindow):
|
||||
#--- QWidget overrides
|
||||
def closeEvent(self, event):
|
||||
event.accept()
|
||||
if self.app.results.is_modified:
|
||||
if self.app.model.results.is_modified:
|
||||
title = tr("Unsaved results")
|
||||
msg = trmsg("ReallyWantToQuitMsg")
|
||||
if not self.app.confirm(title, msg):
|
||||
@ -186,7 +186,7 @@ class DirectoriesDialog(QMainWindow):
|
||||
if not dirpath:
|
||||
return
|
||||
self.lastAddedFolder = dirpath
|
||||
self.app.add_directory(dirpath)
|
||||
self.app.model.add_directory(dirpath)
|
||||
self.recentFolders.insertItem(dirpath)
|
||||
|
||||
def appWillSavePrefs(self):
|
||||
@ -201,7 +201,7 @@ class DirectoriesDialog(QMainWindow):
|
||||
files = ';;'.join([tr("dupeGuru Results (*.dupeguru)"), tr("All Files (*.*)")])
|
||||
destination = QFileDialog.getOpenFileName(self, title, '', files)
|
||||
if destination:
|
||||
self.app.load_from(destination)
|
||||
self.app.model.load_from(destination)
|
||||
self.app.recentResults.insertItem(destination)
|
||||
|
||||
def removeFolderButtonClicked(self):
|
||||
@ -212,16 +212,16 @@ class DirectoriesDialog(QMainWindow):
|
||||
node = index.internalPointer()
|
||||
if node.parent is None:
|
||||
row = index.row()
|
||||
self.app.remove_directory(row)
|
||||
self.app.model.remove_directory(row)
|
||||
|
||||
def scanButtonClicked(self):
|
||||
title = tr("Start a new scan")
|
||||
if self.app.results.is_modified:
|
||||
if self.app.model.results.is_modified:
|
||||
msg = trmsg("ReallyWantToContinueMsg")
|
||||
if not self.app.confirm(title, msg):
|
||||
return
|
||||
try:
|
||||
self.app.start_scanning()
|
||||
self.app.model.start_scanning()
|
||||
except NoScannableFileError:
|
||||
msg = trmsg("NoScannableFileMsg")
|
||||
QMessageBox.warning(self, title, msg)
|
||||
|
@ -60,7 +60,7 @@ class DirectoriesDelegate(QStyledItemDelegate):
|
||||
class DirectoriesModel(TreeModel):
|
||||
def __init__(self, app):
|
||||
TreeModel.__init__(self)
|
||||
self.model = DirectoryTree(self, app)
|
||||
self.model = DirectoryTree(self, app.model)
|
||||
self.model.connect()
|
||||
|
||||
def _createNode(self, ref, row):
|
||||
|
@ -55,7 +55,7 @@ class PrioritizeDialog(QDialog):
|
||||
QDialog.__init__(self, parent, flags)
|
||||
self.app = app
|
||||
self._setupUi()
|
||||
self.model = PrioritizeDialogModel(view=self, app=app)
|
||||
self.model = PrioritizeDialogModel(view=self, app=app.model)
|
||||
self.categoryList = ComboboxModel(model=self.model.category_list, view=self.categoryCombobox)
|
||||
self.criteriaList = ListviewModel(model=self.model.criteria_list, view=self.criteriaListView)
|
||||
self.prioritizationList = PrioritizationList(model=self.model.prioritization_list, view=self.prioritizationListView)
|
||||
|
@ -20,7 +20,7 @@ class ProblemDialog(QDialog):
|
||||
QDialog.__init__(self, parent, flags)
|
||||
self.app = app
|
||||
self._setupUi()
|
||||
self.model = ProblemDialogModel(view=self, app=app)
|
||||
self.model = ProblemDialogModel(view=self, app=app.model)
|
||||
self.table = ProblemTable(problem_dialog=self, view=self.tableView)
|
||||
self.model.connect()
|
||||
self.table.model.connect()
|
||||
|
@ -140,7 +140,7 @@ class ResultWindow(QMainWindow):
|
||||
# Columns menu
|
||||
menu = self.menuColumns
|
||||
self._column_actions = []
|
||||
for index, column in enumerate(self.app.data.COLUMNS):
|
||||
for index, column in enumerate(self.app.model.data.COLUMNS):
|
||||
action = menu.addAction(column.display)
|
||||
action.setCheckable(True)
|
||||
action.column_index = index
|
||||
@ -224,7 +224,7 @@ class ResultWindow(QMainWindow):
|
||||
self.actionsButton.showMenu()
|
||||
|
||||
def addToIgnoreListTriggered(self):
|
||||
self.app.add_selected_to_ignore_list()
|
||||
self.app.model.add_selected_to_ignore_list()
|
||||
|
||||
def applyFilterTriggered(self):
|
||||
title = tr("Apply Filter")
|
||||
@ -234,34 +234,34 @@ class ResultWindow(QMainWindow):
|
||||
if not ok:
|
||||
return
|
||||
answer = str(answer)
|
||||
self.app.apply_filter(answer)
|
||||
self.app.model.apply_filter(answer)
|
||||
self._last_filter = answer
|
||||
|
||||
def cancelFilterTriggered(self):
|
||||
self.app.apply_filter('')
|
||||
self.app.model.apply_filter('')
|
||||
|
||||
def clearIgnoreListTriggered(self):
|
||||
title = tr("Clear Ignore List")
|
||||
count = len(self.app.scanner.ignore_list)
|
||||
count = len(self.app.model.scanner.ignore_list)
|
||||
if not count:
|
||||
QMessageBox.information(self, title, trmsg("NothingToClearMsg"))
|
||||
return
|
||||
msg = trmsg("ClearIgnoreListConfirmMsg").format(count)
|
||||
if self.app.confirm(title, msg, QMessageBox.No):
|
||||
self.app.scanner.ignore_list.Clear()
|
||||
self.app.model.scanner.ignore_list.Clear()
|
||||
QMessageBox.information(self, title, trmsg("IgnoreListClearedMsg"))
|
||||
|
||||
def copyTriggered(self):
|
||||
self.app.copy_or_move_marked(True)
|
||||
self.app.model.copy_or_move_marked(True)
|
||||
|
||||
def deleteTriggered(self):
|
||||
count = self.app.results.mark_count
|
||||
count = self.app.model.results.mark_count
|
||||
if not count:
|
||||
return
|
||||
title = tr("Delete duplicates")
|
||||
msg = trmsg("SendToTrashConfirmMsg").format(count)
|
||||
if self.app.confirm(title, msg):
|
||||
self.app.delete_marked()
|
||||
self.app.model.delete_marked()
|
||||
|
||||
def deltaTriggered(self):
|
||||
self.resultsModel.delta_values = self.actionDelta.isChecked()
|
||||
@ -272,42 +272,42 @@ class ResultWindow(QMainWindow):
|
||||
def exportTriggered(self):
|
||||
h = self.resultsView.horizontalHeader()
|
||||
column_ids = []
|
||||
for i in range(len(self.app.data.COLUMNS)):
|
||||
for i in range(len(self.app.model.data.COLUMNS)):
|
||||
if not h.isSectionHidden(i):
|
||||
column_ids.append(str(i))
|
||||
exported_path = self.app.export_to_xhtml(column_ids)
|
||||
exported_path = self.app.model.export_to_xhtml(column_ids)
|
||||
url = QUrl.fromLocalFile(exported_path)
|
||||
QDesktopServices.openUrl(url)
|
||||
|
||||
def hardlinkTriggered(self):
|
||||
count = self.app.results.mark_count
|
||||
count = self.app.model.results.mark_count
|
||||
if not count:
|
||||
return
|
||||
title = tr("Delete and hardlink duplicates")
|
||||
msg = trmsg("HardlinkConfirmMsg").format(count)
|
||||
if self.app.confirm(title, msg):
|
||||
self.app.delete_marked(replace_with_hardlinks=True)
|
||||
self.app.model.delete_marked(replace_with_hardlinks=True)
|
||||
|
||||
def makeReferenceTriggered(self):
|
||||
self.app.make_selected_reference()
|
||||
self.app.model.make_selected_reference()
|
||||
|
||||
def markAllTriggered(self):
|
||||
self.app.mark_all()
|
||||
self.app.model.mark_all()
|
||||
|
||||
def markInvertTriggered(self):
|
||||
self.app.mark_invert()
|
||||
self.app.model.mark_invert()
|
||||
|
||||
def markNoneTriggered(self):
|
||||
self.app.mark_none()
|
||||
self.app.model.mark_none()
|
||||
|
||||
def markSelectedTriggered(self):
|
||||
self.app.toggle_selected_mark_state()
|
||||
self.app.model.toggle_selected_mark_state()
|
||||
|
||||
def moveTriggered(self):
|
||||
self.app.copy_or_move_marked(False)
|
||||
self.app.model.copy_or_move_marked(False)
|
||||
|
||||
def openTriggered(self):
|
||||
self.app.open_selected()
|
||||
self.app.model.open_selected()
|
||||
|
||||
def powerMarkerTriggered(self):
|
||||
self.resultsModel.power_marker = self.actionPowerMarker.isChecked()
|
||||
@ -316,16 +316,16 @@ class ResultWindow(QMainWindow):
|
||||
self.app.show_preferences()
|
||||
|
||||
def removeMarkedTriggered(self):
|
||||
count = self.app.results.mark_count
|
||||
count = self.app.model.results.mark_count
|
||||
if not count:
|
||||
return
|
||||
title = tr("Remove duplicates")
|
||||
msg = trmsg("FileRemovalConfirmMsg").format(count)
|
||||
if self.app.confirm(title, msg):
|
||||
self.app.remove_marked()
|
||||
self.app.model.remove_marked()
|
||||
|
||||
def removeSelectedTriggered(self):
|
||||
self.app.remove_selected()
|
||||
self.app.model.remove_selected()
|
||||
|
||||
def renameTriggered(self):
|
||||
self.resultsView.edit(self.resultsView.selectionModel().currentIndex())
|
||||
@ -337,7 +337,7 @@ class ResultWindow(QMainWindow):
|
||||
dlg.model.perform_reprioritization()
|
||||
|
||||
def revealTriggered(self):
|
||||
self.app.reveal_selected()
|
||||
self.app.model.reveal_selected()
|
||||
|
||||
def saveResultsTriggered(self):
|
||||
title = trmsg("SelectResultToSaveMsg")
|
||||
@ -346,7 +346,7 @@ class ResultWindow(QMainWindow):
|
||||
if destination:
|
||||
if not destination.endswith('.dupeguru'):
|
||||
destination = '{}.dupeguru'.format(destination)
|
||||
self.app.save_as(destination)
|
||||
self.app.model.save_as(destination)
|
||||
self.app.recentResults.insertItem(destination)
|
||||
|
||||
#--- Events
|
||||
@ -355,7 +355,7 @@ class ResultWindow(QMainWindow):
|
||||
h = self.resultsView.horizontalHeader()
|
||||
widths = []
|
||||
visible = []
|
||||
for i in range(len(self.app.data.COLUMNS)):
|
||||
for i in range(len(self.app.model.data.COLUMNS)):
|
||||
widths.append(h.sectionSize(i))
|
||||
visible.append(not h.isSectionHidden(i))
|
||||
prefs.columns_width = widths
|
||||
@ -377,8 +377,8 @@ class ResultWindow(QMainWindow):
|
||||
self.actionActions.menu().exec_(event.globalPos())
|
||||
|
||||
def resultsDoubleClicked(self):
|
||||
self.app.open_selected()
|
||||
self.app.model.open_selected()
|
||||
|
||||
def resultsSpacePressed(self):
|
||||
self.app.toggle_selected_mark_state()
|
||||
self.app.model.toggle_selected_mark_state()
|
||||
|
||||
|
@ -15,10 +15,10 @@ from core.gui.result_table import ResultTable as ResultTableModel
|
||||
|
||||
class ResultsModel(Table):
|
||||
def __init__(self, app, view):
|
||||
model = ResultTableModel(self, app)
|
||||
model = ResultTableModel(self, app.model)
|
||||
self._app = app
|
||||
self._data = app.data
|
||||
self._delta_columns = app.data.DELTA_COLUMNS
|
||||
self._data = app.model.data
|
||||
self._delta_columns = app.model.data.DELTA_COLUMNS
|
||||
Table.__init__(self, model, view)
|
||||
self.model.connect()
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Created By: Virgil Dupras
|
||||
# Created On: 2010-02-12
|
||||
# Copyright 2011 Hardcoded Software (http://www.hardcoded.net)
|
||||
@ -12,7 +11,7 @@ from core.gui.stats_label import StatsLabel as StatsLabelModel
|
||||
class StatsLabel(object):
|
||||
def __init__(self, app, view):
|
||||
self.view = view
|
||||
self.model = StatsLabelModel(self, app)
|
||||
self.model = StatsLabelModel(self, app.model)
|
||||
self.model.connect()
|
||||
|
||||
def refresh(self):
|
||||
|
14
qt/me/app.py
14
qt/me/app.py
@ -22,16 +22,16 @@ class DupeGuru(DupeGuruBase):
|
||||
DupeGuruBase.__init__(self, data)
|
||||
|
||||
def _setup(self):
|
||||
self.scanner = scanner.ScannerME()
|
||||
self.directories.fileclasses = [fs.MusicFile]
|
||||
self.model.scanner = scanner.ScannerME()
|
||||
self.model.directories.fileclasses = [fs.MusicFile]
|
||||
DupeGuruBase._setup(self)
|
||||
|
||||
def _update_options(self):
|
||||
DupeGuruBase._update_options(self)
|
||||
self.scanner.min_match_percentage = self.prefs.filter_hardness
|
||||
self.scanner.scan_type = self.prefs.scan_type
|
||||
self.scanner.word_weighting = self.prefs.word_weighting
|
||||
self.scanner.match_similar_words = self.prefs.match_similar
|
||||
self.model.scanner.min_match_percentage = self.prefs.filter_hardness
|
||||
self.model.scanner.scan_type = self.prefs.scan_type
|
||||
self.model.scanner.word_weighting = self.prefs.word_weighting
|
||||
self.model.scanner.match_similar_words = self.prefs.match_similar
|
||||
scanned_tags = set()
|
||||
if self.prefs.scan_tag_track:
|
||||
scanned_tags.add('track')
|
||||
@ -45,7 +45,7 @@ class DupeGuru(DupeGuruBase):
|
||||
scanned_tags.add('genre')
|
||||
if self.prefs.scan_tag_year:
|
||||
scanned_tags.add('year')
|
||||
self.scanner.scanned_tags = scanned_tags
|
||||
self.model.scanner.scanned_tags = scanned_tags
|
||||
|
||||
def _create_details_dialog(self, parent):
|
||||
return DetailsDialog(parent, self)
|
||||
|
12
qt/pe/app.py
12
qt/pe/app.py
@ -74,16 +74,16 @@ class DupeGuru(DupeGuruBase):
|
||||
DupeGuruBase.__init__(self, data_pe)
|
||||
|
||||
def _setup(self):
|
||||
self.scanner = ScannerPE()
|
||||
self.directories.fileclasses = [File]
|
||||
self.scanner.cache_path = op.join(self.appdata, 'cached_pictures.db')
|
||||
self.model.scanner = ScannerPE()
|
||||
self.model.directories.fileclasses = [File]
|
||||
self.model.scanner.cache_path = op.join(self.model.appdata, 'cached_pictures.db')
|
||||
DupeGuruBase._setup(self)
|
||||
|
||||
def _update_options(self):
|
||||
DupeGuruBase._update_options(self)
|
||||
self.scanner.scan_type = self.prefs.scan_type
|
||||
self.scanner.match_scaled = self.prefs.match_scaled
|
||||
self.scanner.threshold = self.prefs.filter_hardness
|
||||
self.model.scanner.scan_type = self.prefs.scan_type
|
||||
self.model.scanner.match_scaled = self.prefs.match_scaled
|
||||
self.model.scanner.threshold = self.prefs.filter_hardness
|
||||
|
||||
def _create_details_dialog(self, parent):
|
||||
return DetailsDialog(parent, self)
|
||||
|
@ -60,10 +60,10 @@ class DetailsDialog(DetailsDialogBase):
|
||||
self.verticalLayout.addWidget(self.tableView)
|
||||
|
||||
def _update(self):
|
||||
if not self.app.selected_dupes:
|
||||
if not self.app.model.selected_dupes:
|
||||
return
|
||||
dupe = self.app.selected_dupes[0]
|
||||
group = self.app.results.get_group_of_duplicate(dupe)
|
||||
dupe = self.app.model.selected_dupes[0]
|
||||
group = self.app.model.results.get_group_of_duplicate(dupe)
|
||||
ref = group.ref
|
||||
|
||||
self.selectedPixmap = QPixmap(str(dupe.path))
|
||||
|
10
qt/se/app.py
10
qt/se/app.py
@ -37,12 +37,12 @@ class DupeGuru(DupeGuruBase):
|
||||
|
||||
def _update_options(self):
|
||||
DupeGuruBase._update_options(self)
|
||||
self.scanner.min_match_percentage = self.prefs.filter_hardness
|
||||
self.scanner.scan_type = self.prefs.scan_type
|
||||
self.scanner.word_weighting = self.prefs.word_weighting
|
||||
self.scanner.match_similar_words = self.prefs.match_similar
|
||||
self.model.scanner.min_match_percentage = self.prefs.filter_hardness
|
||||
self.model.scanner.scan_type = self.prefs.scan_type
|
||||
self.model.scanner.word_weighting = self.prefs.word_weighting
|
||||
self.model.scanner.match_similar_words = self.prefs.match_similar
|
||||
threshold = self.prefs.small_file_threshold if self.prefs.ignore_small_files else 0
|
||||
self.scanner.size_threshold = threshold * 1024 # threshold is in KB. the scanner wants bytes
|
||||
self.model.scanner.size_threshold = threshold * 1024 # threshold is in KB. the scanner wants bytes
|
||||
|
||||
def _create_details_dialog(self, parent):
|
||||
return DetailsDialog(parent, self)
|
||||
|
Loading…
x
Reference in New Issue
Block a user