mirror of
				https://github.com/arsenetar/dupeguru.git
				synced 2025-09-11 17:58:17 +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