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.
This commit is contained in:
Virgil Dupras 2013-10-12 13:54:13 -04:00
parent 2fdfacb34e
commit 33d9569427
10 changed files with 92 additions and 50 deletions

View File

@ -1,7 +1,7 @@
import logging import logging
from objp.util import pyref, dontwrap 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 from cocoa.inter import PyFairware, FairwareView
class DupeGuruView(FairwareView): class DupeGuruView(FairwareView):
@ -17,8 +17,7 @@ class PyDupeGuruBase(PyFairware):
install_exception_hook() install_exception_hook()
install_cocoa_logger() install_cocoa_logger()
patch_threaded_job_performer() patch_threaded_job_performer()
appdata = proxy.getAppdataPath() self.model = modelclass(self)
self.model = modelclass(self, appdata)
#---Sub-proxies #---Sub-proxies
def detailsPanel(self) -> pyref: def detailsPanel(self) -> pyref:
@ -144,14 +143,6 @@ class PyDupeGuruBase(PyFairware):
self.model.options['copymove_dest_type'] = copymove_dest_type self.model.options['copymove_dest_type'] = copymove_dest_type
#--- model --> view #--- model --> view
@dontwrap
def open_path(self, path):
proxy.openPath_(str(path))
@dontwrap
def reveal_path(self, path):
proxy.revealPath_(str(path))
@dontwrap @dontwrap
def ask_yes_no(self, prompt): def ask_yes_no(self, prompt):
return self.callback.askYesNoWithPrompt_(prompt) return self.callback.askYesNoWithPrompt_(prompt)

View File

@ -294,10 +294,6 @@ class PyBaseApp(PyGUIObject):
def set_default(self, key_name, value): def set_default(self, key_name, value):
proxy.setPrefValue_value_(key_name, value) proxy.setPrefValue_value_(key_name, value)
@dontwrap
def open_url(self, url):
proxy.openURL_(url)
@dontwrap @dontwrap
def show_message(self, msg): def show_message(self, msg):
self.callback.showMessage_(msg) self.callback.showMessage_(msg)

View File

@ -25,6 +25,7 @@ from hscommon.util import (delete_if_empty, first, escape, nonone, format_time_d
rem_file_ext) rem_file_ext)
from hscommon.trans import tr from hscommon.trans import tr
from hscommon.plat import ISWINDOWS from hscommon.plat import ISWINDOWS
from hscommon import desktop
from . import directories, results, scanner, export, fs from . import directories, results, scanner, export, fs
from .gui.deletion_options import DeletionOptions from .gui.deletion_options import DeletionOptions
@ -123,8 +124,6 @@ class DupeGuru(RegistrableApplication, Broadcaster):
Instance of :mod:`meta-gui <core.gui>` table listing the results from :attr:`results` Instance of :mod:`meta-gui <core.gui>` table listing the results from :attr:`results`
""" """
#--- View interface #--- View interface
# open_path(path)
# reveal_path(path)
# ask_yes_no(prompt) --> bool # ask_yes_no(prompt) --> bool
# show_results_window() # show_results_window()
# show_problem_dialog() # show_problem_dialog()
@ -135,13 +134,13 @@ class DupeGuru(RegistrableApplication, Broadcaster):
PROMPT_NAME = "dupeGuru" PROMPT_NAME = "dupeGuru"
DEMO_LIMITATION = tr("will only be able to delete, move or copy 10 duplicates at once") 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): if view.get_default(DEBUG_MODE_PREFERENCE):
logging.getLogger().setLevel(logging.DEBUG) logging.getLogger().setLevel(logging.DEBUG)
logging.debug("Debug mode enabled") logging.debug("Debug mode enabled")
RegistrableApplication.__init__(self, view, appid=1) RegistrableApplication.__init__(self, view, appid=1)
Broadcaster.__init__(self) Broadcaster.__init__(self)
self.appdata = appdata self.appdata = desktop.special_folder_path(desktop.SpecialFolder.AppData)
if not op.exists(self.appdata): if not op.exists(self.appdata):
os.makedirs(self.appdata) os.makedirs(self.appdata)
self.directories = directories.Directories() self.directories = directories.Directories()
@ -440,7 +439,7 @@ class DupeGuru(RegistrableApplication, Broadcaster):
def export_to_xhtml(self): def export_to_xhtml(self):
colnames, rows = self._get_export_data() colnames, rows = self._get_export_data()
export_path = export.export_to_xhtml(colnames, rows) export_path = export.export_to_xhtml(colnames, rows)
self.view.open_path(export_path) desktop.open_path(export_path)
def export_to_csv(self): def export_to_csv(self):
dest_file = self.view.select_dest_file(tr("Select a destination for your exported CSV"), 'csv') 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): if not self.view.ask_yes_no(MSG_MANY_FILES_TO_OPEN):
return return
for dupe in self.selected_dupes: for dupe in self.selected_dupes:
self.view.open_path(dupe.path) desktop.open_path(dupe.path)
def purge_ignore_list(self): def purge_ignore_list(self):
self.scanner.ignore_list.Filter(lambda f,s:op.exists(f) and op.exists(s)) 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): def reveal_selected(self):
if self.selected_dupes: if self.selected_dupes:
self.view.reveal_path(self.selected_dupes[0].path) desktop.reveal_path(self.selected_dupes[0].path)
def save(self): def save(self):
if not op.exists(self.appdata): if not op.exists(self.appdata):

View File

@ -6,6 +6,8 @@
# which should be included with this package. The terms are also available at # which should be included with this package. The terms are also available at
# http://www.hardcoded.net/licenses/bsd_license # http://www.hardcoded.net/licenses/bsd_license
from hscommon import desktop
from .problem_table import ProblemTable from .problem_table import ProblemTable
class ProblemDialog: class ProblemDialog:
@ -20,7 +22,7 @@ class ProblemDialog:
def reveal_selected_dupe(self): def reveal_selected_dupe(self):
if self._selected_dupe is not None: 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): def select_dupe(self, dupe):
self._selected_dupe = dupe self._selected_dupe = dupe

View File

@ -16,8 +16,8 @@ class DupeGuru(DupeGuruBase):
METADATA_TO_READ = ['size', 'mtime', 'duration', 'bitrate', 'samplerate', 'title', 'artist', METADATA_TO_READ = ['size', 'mtime', 'duration', 'bitrate', 'samplerate', 'title', 'artist',
'album', 'genre', 'year', 'track', 'comment'] 'album', 'genre', 'year', 'track', 'comment']
def __init__(self, view, appdata): def __init__(self, view):
DupeGuruBase.__init__(self, view, appdata) DupeGuruBase.__init__(self, view)
self.scanner = scanner.ScannerME() self.scanner = scanner.ScannerME()
self.directories.fileclasses = [fs.MusicFile] self.directories.fileclasses = [fs.MusicFile]

View File

@ -18,8 +18,8 @@ class DupeGuru(DupeGuruBase):
NAME = __appname__ NAME = __appname__
METADATA_TO_READ = ['size', 'mtime', 'dimensions', 'exif_timestamp'] METADATA_TO_READ = ['size', 'mtime', 'dimensions', 'exif_timestamp']
def __init__(self, view, appdata): def __init__(self, view):
DupeGuruBase.__init__(self, view, appdata) DupeGuruBase.__init__(self, view)
self.scanner = ScannerPE() self.scanner = ScannerPE()
self.scanner.cache_path = op.join(self.appdata, 'cached_pictures.db') self.scanner.cache_path = op.join(self.appdata, 'cached_pictures.db')

View File

@ -14,8 +14,8 @@ class DupeGuru(DupeGuruBase):
NAME = __appname__ NAME = __appname__
METADATA_TO_READ = ['size', 'mtime'] METADATA_TO_READ = ['size', 'mtime']
def __init__(self, view, appdata): def __init__(self, view):
DupeGuruBase.__init__(self, view, appdata) DupeGuruBase.__init__(self, view)
self.directories.fileclasses = [fs.File] self.directories.fileclasses = [fs.File]
self.directories.folderclass = fs.Folder self.directories.folderclass = fs.Folder

67
hscommon/desktop.py Normal file
View File

@ -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!")

View File

@ -9,6 +9,7 @@
import re import re
from hashlib import md5 from hashlib import md5
from . import desktop
from .trans import trget from .trans import trget
tr = trget('hscommon') tr = trget('hscommon')
@ -47,7 +48,6 @@ class RegistrableApplication:
# setup_as_registered() # setup_as_registered()
# show_message(msg) # show_message(msg)
# show_demo_nag(prompt) # show_demo_nag(prompt)
# open_url(url)
PROMPT_NAME = "<undefined>" PROMPT_NAME = "<undefined>"
DEMO_LIMITATION = "<undefined>" DEMO_LIMITATION = "<undefined>"
@ -154,13 +154,13 @@ class RegistrableApplication:
pass pass
def contribute(self): def contribute(self):
self.view.open_url("http://open.hardcoded.net/contribute/") desktop.open_url("http://open.hardcoded.net/contribute/")
def buy(self): 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): def about_fairware(self):
self.view.open_url("http://open.hardcoded.net/about/") desktop.open_url("http://open.hardcoded.net/about/")
@property @property
def should_show_fairware_reminder(self): def should_show_fairware_reminder(self):

View File

@ -7,7 +7,6 @@
# http://www.hardcoded.net/licenses/bsd_license # http://www.hardcoded.net/licenses/bsd_license
import sys import sys
import os
import os.path as op import os.path as op
from PyQt4.QtCore import QTimer, QObject, QCoreApplication, QUrl, QProcess, SIGNAL, pyqtSignal 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.trans import trget
from hscommon.plat import ISLINUX from hscommon.plat import ISLINUX
from hscommon import desktop
from qtlib.about_box import AboutBox from qtlib.about_box import AboutBox
from qtlib.recent import Recent from qtlib.recent import Recent
from qtlib.reg import Registration from qtlib.reg import Registration
from qtlib.util import createActions, getAppData from qtlib.util import createActions
from qtlib.progress_window import ProgressWindow from qtlib.progress_window import ProgressWindow
from . import platform from . import platform
@ -46,7 +46,7 @@ class DupeGuru(QObject):
QObject.__init__(self) QObject.__init__(self)
self.prefs = self.PREFERENCES_CLASS() self.prefs = self.PREFERENCES_CLASS()
self.prefs.load() self.prefs.load()
self.model = self.MODELCLASS(view=self, appdata=getAppData()) self.model = self.MODELCLASS(view=self)
self._setup() self._setup()
self.prefsChanged.emit(self.prefs) self.prefsChanged.emit(self.prefs)
@ -154,7 +154,7 @@ class DupeGuru(QObject):
def openDebugLogTriggered(self): def openDebugLogTriggered(self):
debugLogPath = op.join(self.model.appdata, 'debug.log') debugLogPath = op.join(self.model.appdata, 'debug.log')
self.open_path(debugLogPath) desktop.open_path(debugLogPath)
def preferencesTriggered(self): def preferencesTriggered(self):
self.preferences_dialog.load() self.preferences_dialog.load()
@ -181,15 +181,6 @@ class DupeGuru(QObject):
QDesktopServices.openUrl(url) QDesktopServices.openUrl(url)
#--- model --> view #--- 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): def get_default(self, key):
return self.prefs.get_value(key) return self.prefs.get_value(key)
@ -212,10 +203,6 @@ class DupeGuru(QObject):
def ask_yes_no(self, prompt): def ask_yes_no(self, prompt):
return self.confirm('', prompt) return self.confirm('', prompt)
def open_url(self, url):
url = QUrl(url)
QDesktopServices.openUrl(url)
def show_results_window(self): def show_results_window(self):
self.showResultsWindow() self.showResultsWindow()