From 33d95694275233b7df0a1d253888f7a9eff39941 Mon Sep 17 00:00:00 2001 From: Virgil Dupras Date: Sat, 12 Oct 2013 13:54:13 -0400 Subject: [PATCH] Refactoring: Created hscommon.desktop This unit hosts previously awkward UI view methods which weren't related to the view itself, but to the current desktop environment. These functions are now at their appropriate place. --- cocoa/inter/app.py | 13 ++------ cocoalib/cocoa/inter.py | 4 --- core/app.py | 13 ++++---- core/gui/problem_dialog.py | 4 ++- core_me/app.py | 4 +-- core_pe/app.py | 4 +-- core_se/app.py | 4 +-- hscommon/desktop.py | 67 ++++++++++++++++++++++++++++++++++++++ hscommon/reg.py | 8 ++--- qt/base/app.py | 21 +++--------- 10 files changed, 92 insertions(+), 50 deletions(-) create mode 100644 hscommon/desktop.py diff --git a/cocoa/inter/app.py b/cocoa/inter/app.py index 51768c74..be331357 100644 --- a/cocoa/inter/app.py +++ b/cocoa/inter/app.py @@ -1,7 +1,7 @@ import logging from objp.util import pyref, dontwrap -from cocoa import install_exception_hook, install_cocoa_logger, patch_threaded_job_performer, proxy +from cocoa import install_exception_hook, install_cocoa_logger, patch_threaded_job_performer from cocoa.inter import PyFairware, FairwareView class DupeGuruView(FairwareView): @@ -17,8 +17,7 @@ class PyDupeGuruBase(PyFairware): install_exception_hook() install_cocoa_logger() patch_threaded_job_performer() - appdata = proxy.getAppdataPath() - self.model = modelclass(self, appdata) + self.model = modelclass(self) #---Sub-proxies def detailsPanel(self) -> pyref: @@ -144,14 +143,6 @@ class PyDupeGuruBase(PyFairware): self.model.options['copymove_dest_type'] = copymove_dest_type #--- model --> view - @dontwrap - def open_path(self, path): - proxy.openPath_(str(path)) - - @dontwrap - def reveal_path(self, path): - proxy.revealPath_(str(path)) - @dontwrap def ask_yes_no(self, prompt): return self.callback.askYesNoWithPrompt_(prompt) diff --git a/cocoalib/cocoa/inter.py b/cocoalib/cocoa/inter.py index 625f2c5f..e140d26a 100644 --- a/cocoalib/cocoa/inter.py +++ b/cocoalib/cocoa/inter.py @@ -294,10 +294,6 @@ class PyBaseApp(PyGUIObject): def set_default(self, key_name, value): proxy.setPrefValue_value_(key_name, value) - @dontwrap - def open_url(self, url): - proxy.openURL_(url) - @dontwrap def show_message(self, msg): self.callback.showMessage_(msg) diff --git a/core/app.py b/core/app.py index e72313cc..096b7fca 100644 --- a/core/app.py +++ b/core/app.py @@ -25,6 +25,7 @@ from hscommon.util import (delete_if_empty, first, escape, nonone, format_time_d rem_file_ext) from hscommon.trans import tr from hscommon.plat import ISWINDOWS +from hscommon import desktop from . import directories, results, scanner, export, fs from .gui.deletion_options import DeletionOptions @@ -123,8 +124,6 @@ class DupeGuru(RegistrableApplication, Broadcaster): Instance of :mod:`meta-gui ` table listing the results from :attr:`results` """ #--- View interface - # open_path(path) - # reveal_path(path) # ask_yes_no(prompt) --> bool # show_results_window() # show_problem_dialog() @@ -135,13 +134,13 @@ class DupeGuru(RegistrableApplication, Broadcaster): PROMPT_NAME = "dupeGuru" DEMO_LIMITATION = tr("will only be able to delete, move or copy 10 duplicates at once") - def __init__(self, view, appdata): + def __init__(self, view): if view.get_default(DEBUG_MODE_PREFERENCE): logging.getLogger().setLevel(logging.DEBUG) logging.debug("Debug mode enabled") RegistrableApplication.__init__(self, view, appid=1) Broadcaster.__init__(self) - self.appdata = appdata + self.appdata = desktop.special_folder_path(desktop.SpecialFolder.AppData) if not op.exists(self.appdata): os.makedirs(self.appdata) self.directories = directories.Directories() @@ -440,7 +439,7 @@ class DupeGuru(RegistrableApplication, Broadcaster): def export_to_xhtml(self): colnames, rows = self._get_export_data() export_path = export.export_to_xhtml(colnames, rows) - self.view.open_path(export_path) + desktop.open_path(export_path) def export_to_csv(self): dest_file = self.view.select_dest_file(tr("Select a destination for your exported CSV"), 'csv') @@ -557,7 +556,7 @@ class DupeGuru(RegistrableApplication, Broadcaster): if not self.view.ask_yes_no(MSG_MANY_FILES_TO_OPEN): return for dupe in self.selected_dupes: - self.view.open_path(dupe.path) + desktop.open_path(dupe.path) def purge_ignore_list(self): self.scanner.ignore_list.Filter(lambda f,s:op.exists(f) and op.exists(s)) @@ -620,7 +619,7 @@ class DupeGuru(RegistrableApplication, Broadcaster): def reveal_selected(self): if self.selected_dupes: - self.view.reveal_path(self.selected_dupes[0].path) + desktop.reveal_path(self.selected_dupes[0].path) def save(self): if not op.exists(self.appdata): diff --git a/core/gui/problem_dialog.py b/core/gui/problem_dialog.py index d458c022..9271ae83 100644 --- a/core/gui/problem_dialog.py +++ b/core/gui/problem_dialog.py @@ -6,6 +6,8 @@ # which should be included with this package. The terms are also available at # http://www.hardcoded.net/licenses/bsd_license +from hscommon import desktop + from .problem_table import ProblemTable class ProblemDialog: @@ -20,7 +22,7 @@ class ProblemDialog: def reveal_selected_dupe(self): if self._selected_dupe is not None: - self.app.view.reveal_path(self._selected_dupe.path) + desktop.reveal_path(self._selected_dupe.path) def select_dupe(self, dupe): self._selected_dupe = dupe diff --git a/core_me/app.py b/core_me/app.py index eb9124da..a49499ea 100644 --- a/core_me/app.py +++ b/core_me/app.py @@ -16,8 +16,8 @@ class DupeGuru(DupeGuruBase): METADATA_TO_READ = ['size', 'mtime', 'duration', 'bitrate', 'samplerate', 'title', 'artist', 'album', 'genre', 'year', 'track', 'comment'] - def __init__(self, view, appdata): - DupeGuruBase.__init__(self, view, appdata) + def __init__(self, view): + DupeGuruBase.__init__(self, view) self.scanner = scanner.ScannerME() self.directories.fileclasses = [fs.MusicFile] diff --git a/core_pe/app.py b/core_pe/app.py index 05b871b2..05927096 100644 --- a/core_pe/app.py +++ b/core_pe/app.py @@ -18,8 +18,8 @@ class DupeGuru(DupeGuruBase): NAME = __appname__ METADATA_TO_READ = ['size', 'mtime', 'dimensions', 'exif_timestamp'] - def __init__(self, view, appdata): - DupeGuruBase.__init__(self, view, appdata) + def __init__(self, view): + DupeGuruBase.__init__(self, view) self.scanner = ScannerPE() self.scanner.cache_path = op.join(self.appdata, 'cached_pictures.db') diff --git a/core_se/app.py b/core_se/app.py index 42d80d9b..cacd2e7d 100644 --- a/core_se/app.py +++ b/core_se/app.py @@ -14,8 +14,8 @@ class DupeGuru(DupeGuruBase): NAME = __appname__ METADATA_TO_READ = ['size', 'mtime'] - def __init__(self, view, appdata): - DupeGuruBase.__init__(self, view, appdata) + def __init__(self, view): + DupeGuruBase.__init__(self, view) self.directories.fileclasses = [fs.File] self.directories.folderclass = fs.Folder diff --git a/hscommon/desktop.py b/hscommon/desktop.py new file mode 100644 index 00000000..ea5d707f --- /dev/null +++ b/hscommon/desktop.py @@ -0,0 +1,67 @@ +# Created By: Virgil Dupras +# Created On: 2013-10-12 +# Copyright 2013 Hardcoded Software (http://www.hardcoded.net) +# +# This software is licensed under the "BSD" License as described in the "LICENSE" file, +# which should be included with this package. The terms are also available at +# http://www.hardcoded.net/licenses/bsd_license + +class SpecialFolder: + AppData = 1 + Cache = 2 + +def open_url(url): + """Open ``url`` with the default browser. + """ + _open_url(url) + +def open_path(path): + """Open ``path`` with its associated application. + """ + _open_path(str(path)) + +def reveal_path(path): + """Open the folder containing ``path`` with the default file browser. + """ + _reveal_path(str(path)) + +def special_folder_path(special_folder): + """Returns the path of ``special_folder``. + + ``special_folder`` is a SpecialFolder.* const. + """ + return _special_folder_path(special_folder) + +try: + from cocoa import proxy + _open_url = proxy.openURL_ + _open_path = proxy.openPath_ + _reveal_path = proxy.revealPath_ + + def _special_folder_path(special_folder): + if special_folder == SpecialFolder.Cache: + return proxy.getCachePath() + else: + return proxy.getAppdataPath() + +except ImportError: + try: + from PyQt4.QtCore import QUrl + from PyQt4.QtGui import QDesktopServices + import os.path as op + def _open_path(path): + url = QUrl.fromLocalFile(str(path)) + QDesktopServices.openUrl(url) + + def _reveal_path(path): + _open_path(op.dirname(str(path))) + + def _special_folder_path(special_folder): + if special_folder == SpecialFolder.Cache: + qtfolder = QDesktopServices.CacheLocation + else: + qtfolder = QDesktopServices.DataLocation + return str(QDesktopServices.storageLocation(qtfolder)) + + except ImportError: + raise Exception("Can't setup desktop functions!") diff --git a/hscommon/reg.py b/hscommon/reg.py index 3b5a57e0..98e84d56 100644 --- a/hscommon/reg.py +++ b/hscommon/reg.py @@ -9,6 +9,7 @@ import re from hashlib import md5 +from . import desktop from .trans import trget tr = trget('hscommon') @@ -47,7 +48,6 @@ class RegistrableApplication: # setup_as_registered() # show_message(msg) # show_demo_nag(prompt) - # open_url(url) PROMPT_NAME = "" DEMO_LIMITATION = "" @@ -154,13 +154,13 @@ class RegistrableApplication: pass def contribute(self): - self.view.open_url("http://open.hardcoded.net/contribute/") + desktop.open_url("http://open.hardcoded.net/contribute/") def buy(self): - self.view.open_url("http://www.hardcoded.net/purchase.htm") + desktop.open_url("http://www.hardcoded.net/purchase.htm") def about_fairware(self): - self.view.open_url("http://open.hardcoded.net/about/") + desktop.open_url("http://open.hardcoded.net/about/") @property def should_show_fairware_reminder(self): diff --git a/qt/base/app.py b/qt/base/app.py index 01de41aa..f4d6b378 100644 --- a/qt/base/app.py +++ b/qt/base/app.py @@ -7,7 +7,6 @@ # http://www.hardcoded.net/licenses/bsd_license import sys -import os import os.path as op from PyQt4.QtCore import QTimer, QObject, QCoreApplication, QUrl, QProcess, SIGNAL, pyqtSignal @@ -15,11 +14,12 @@ from PyQt4.QtGui import QDesktopServices, QFileDialog, QDialog, QMessageBox, QAp from hscommon.trans import trget from hscommon.plat import ISLINUX +from hscommon import desktop from qtlib.about_box import AboutBox from qtlib.recent import Recent from qtlib.reg import Registration -from qtlib.util import createActions, getAppData +from qtlib.util import createActions from qtlib.progress_window import ProgressWindow from . import platform @@ -46,7 +46,7 @@ class DupeGuru(QObject): QObject.__init__(self) self.prefs = self.PREFERENCES_CLASS() self.prefs.load() - self.model = self.MODELCLASS(view=self, appdata=getAppData()) + self.model = self.MODELCLASS(view=self) self._setup() self.prefsChanged.emit(self.prefs) @@ -154,7 +154,7 @@ class DupeGuru(QObject): def openDebugLogTriggered(self): debugLogPath = op.join(self.model.appdata, 'debug.log') - self.open_path(debugLogPath) + desktop.open_path(debugLogPath) def preferencesTriggered(self): self.preferences_dialog.load() @@ -181,15 +181,6 @@ class DupeGuru(QObject): 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 get_default(self, key): return self.prefs.get_value(key) @@ -212,10 +203,6 @@ class DupeGuru(QObject): def ask_yes_no(self, prompt): return self.confirm('', prompt) - def open_url(self, url): - url = QUrl(url) - QDesktopServices.openUrl(url) - def show_results_window(self): self.showResultsWindow()