diff --git a/base/qt/app.py b/base/qt/app.py index fc471a90..9a94b540 100644 --- a/base/qt/app.py +++ b/base/qt/app.py @@ -9,8 +9,6 @@ import logging import os.path as op -import sys -import traceback from PyQt4.QtCore import Qt, QTimer, QObject, QCoreApplication, QUrl, SIGNAL from PyQt4.QtGui import QProgressDialog, QDesktopServices, QFileDialog, QDialog, QMessageBox @@ -22,16 +20,14 @@ from hsutil.reg import RegistrationRequired from dupeguru.app import (DupeGuru as DupeGuruBase, JOB_SCAN, JOB_LOAD, JOB_MOVE, JOB_COPY, JOB_DELETE) -if sys.platform == 'win32': - from .win import recycle_file -else: - logging.warning("Unsupported Platform!!!") +from qtlib.progress import Progress -from main_window import MainWindow -from directories_dialog import DirectoriesDialog -from about_box import AboutBox -from reg import Registration -from error_report_dialog import ErrorReportDialog +from . import platform + +from .main_window import MainWindow +from .directories_dialog import DirectoriesDialog +from .about_box import AboutBox +from .reg import Registration JOBID2TITLE = { JOB_SCAN: "Scanning for duplicates", @@ -41,47 +37,6 @@ JOBID2TITLE = { JOB_DELETE: "Sending files to the recycle bin", } -class Progress(QProgressDialog, job.ThreadedJobPerformer): - def __init__(self, parent): - flags = Qt.CustomizeWindowHint | Qt.WindowTitleHint | Qt.WindowSystemMenuHint - QProgressDialog.__init__(self, '', u"Cancel", 0, 100, parent, flags) - self.setModal(True) - self.setAutoReset(False) - self.setAutoClose(False) - self._timer = QTimer() - self._jobid = '' - self.connect(self._timer, SIGNAL('timeout()'), self.updateProgress) - - def updateProgress(self): - # the values might change before setValue happens - last_progress = self.last_progress - last_desc = self.last_desc - if not self._job_running or last_progress is None: - self._timer.stop() - self.close() - self.emit(SIGNAL('finished(QString)'), self._jobid) - if self._last_error is not None: - s = ''.join(traceback.format_exception(*self._last_error)) - dialog = ErrorReportDialog(self.parent(), s) - dialog.exec_() - return - if self.wasCanceled(): - self.job_cancelled = True - return - if last_desc: - self.setLabelText(last_desc) - self.setValue(last_progress) - - def run(self, jobid, title, target, args=()): - self._jobid = jobid - self.reset() - self.setLabelText('') - self.run_threaded(target, args) - self.setWindowTitle(title) - self.show() - self._timer.start(500) - - def demo_method(method): def wrapper(self, *args, **kwargs): try: @@ -154,7 +109,7 @@ class DupeGuru(DupeGuruBase, QObject): #--- Override @staticmethod def _recycle_dupe(dupe): - recycle_file(dupe.path) + platform.recycle_file(dupe.path) def _start_job(self, jobid, func): title = JOBID2TITLE[jobid] diff --git a/base/qt/directories_model.py b/base/qt/directories_model.py index bf2f86e3..ac77fa0c 100644 --- a/base/qt/directories_model.py +++ b/base/qt/directories_model.py @@ -7,10 +7,10 @@ # which should be included with this package. The terms are also available at # http://www.hardcoded.net/licenses/hs_license -from PyQt4.QtCore import QVariant, QModelIndex, Qt, QRect, QEvent, QPoint +from PyQt4.QtCore import QModelIndex, Qt, QRect, QEvent, QPoint from PyQt4.QtGui import QComboBox, QStyledItemDelegate, QMouseEvent, QApplication, QBrush -from tree_model import TreeNode, TreeModel +from qtlib.tree_model import TreeNode, TreeModel HEADERS = ['Name', 'State'] STATES = ['Normal', 'Reference', 'Excluded'] @@ -22,8 +22,7 @@ class DirectoriesDelegate(QStyledItemDelegate): return editor def setEditorData(self, editor, index): - value, ok = index.model().data(index, Qt.EditRole).toInt() - assert ok + value = index.model().data(index, Qt.EditRole) editor.setCurrentIndex(value); press = QMouseEvent(QEvent.MouseButtonPress, QPoint(0, 0), Qt.LeftButton, Qt.LeftButton, Qt.NoModifier) release = QMouseEvent(QEvent.MouseButtonRelease, QPoint(0, 0), Qt.LeftButton, Qt.LeftButton, Qt.NoModifier) @@ -32,7 +31,7 @@ class DirectoriesDelegate(QStyledItemDelegate): # editor.showPopup() # this causes a weird glitch. the ugly workaround is above. def setModelData(self, editor, model, index): - value = QVariant(editor.currentIndex()) + value = editor.currentIndex() model.setData(index, value, Qt.EditRole) def updateEditorGeometry(self, editor, option, index): @@ -40,16 +39,15 @@ class DirectoriesDelegate(QStyledItemDelegate): class DirectoryNode(TreeNode): - def __init__(self, parent, ref, row): - TreeNode.__init__(self, parent, row) + def __init__(self, model, parent, ref, row): + TreeNode.__init__(self, model, parent, row) self.ref = ref - def _get_children(self): - children = [] - for index, directory in enumerate(self.ref.dirs): - node = DirectoryNode(self, directory, index) - children.append(node) - return children + def _createNode(self, ref, row): + return DirectoryNode(self.model, self, ref, row) + + def _getChildren(self): + return self.ref.dirs class DirectoriesModel(TreeModel): @@ -57,33 +55,33 @@ class DirectoriesModel(TreeModel): self._dirs = app.directories TreeModel.__init__(self) - def _root_nodes(self): - nodes = [] - for index, directory in enumerate(self._dirs): - nodes.append(DirectoryNode(None, directory, index)) - return nodes + def _createNode(self, ref, row): + return DirectoryNode(self, None, ref, row) + + def _getChildren(self): + return self._dirs def columnCount(self, parent): return 2 def data(self, index, role): if not index.isValid(): - return QVariant() + return None node = index.internalPointer() if role == Qt.DisplayRole: if index.column() == 0: - return QVariant(node.ref.name) + return node.ref.name else: - return QVariant(STATES[self._dirs.get_state(node.ref.path)]) + return STATES[self._dirs.get_state(node.ref.path)] elif role == Qt.EditRole and index.column() == 1: - return QVariant(self._dirs.get_state(node.ref.path)) + return self._dirs.get_state(node.ref.path) elif role == Qt.ForegroundRole: state = self._dirs.get_state(node.ref.path) if state == 1: - return QVariant(QBrush(Qt.blue)) + return QBrush(Qt.blue) elif state == 2: - return QVariant(QBrush(Qt.red)) - return QVariant() + return QBrush(Qt.red) + return None def flags(self, index): if not index.isValid(): @@ -96,15 +94,13 @@ class DirectoriesModel(TreeModel): def headerData(self, section, orientation, role): if orientation == Qt.Horizontal: if role == Qt.DisplayRole and section < len(HEADERS): - return QVariant(HEADERS[section]) - return QVariant() + return HEADERS[section] + return None def setData(self, index, value, role): if not index.isValid() or role != Qt.EditRole or index.column() != 1: return False node = index.internalPointer() - state, ok = value.toInt() - assert ok - self._dirs.set_state(node.ref.path, state) + self._dirs.set_state(node.ref.path, value) return True diff --git a/base/qt/error_report_dialog.py b/base/qt/error_report_dialog.py deleted file mode 100644 index ec4a5677..00000000 --- a/base/qt/error_report_dialog.py +++ /dev/null @@ -1,27 +0,0 @@ -# Created By: Virgil Dupras -# Created On: 2009-05-23 -# $Id$ -# Copyright 2009 Hardcoded Software (http://www.hardcoded.net) -# -# This software is licensed under the "HS" 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/hs_license - -from PyQt4.QtCore import Qt, QUrl -from PyQt4.QtGui import QDialog, QDesktopServices - -from error_report_dialog_ui import Ui_ErrorReportDialog - -class ErrorReportDialog(QDialog, Ui_ErrorReportDialog): - def __init__(self, parent, error): - flags = Qt.CustomizeWindowHint | Qt.WindowTitleHint | Qt.WindowSystemMenuHint - QDialog.__init__(self, parent, flags) - self.setupUi(self) - self.errorTextEdit.setPlainText(error) - - def accept(self): - text = self.errorTextEdit.toPlainText() - url = QUrl("mailto:support@hardcoded.net?SUBJECT=Error Report&BODY=%s" % text) - QDesktopServices.openUrl(url) - QDialog.accept(self) - diff --git a/base/qt/error_report_dialog.ui b/base/qt/error_report_dialog.ui deleted file mode 100644 index 0974dd2f..00000000 --- a/base/qt/error_report_dialog.ui +++ /dev/null @@ -1,117 +0,0 @@ - - - ErrorReportDialog - - - - 0 - 0 - 553 - 349 - - - - Error Report - - - - - - Something went wrong. Would you like to send the error report to Hardcoded Software? - - - true - - - - - - - true - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 110 - 0 - - - - Don't Send - - - - - - - - 110 - 0 - - - - Send - - - true - - - - - - - - - - - sendButton - clicked() - ErrorReportDialog - accept() - - - 485 - 320 - - - 276 - 174 - - - - - dontSendButton - clicked() - ErrorReportDialog - reject() - - - 373 - 320 - - - 276 - 174 - - - - - diff --git a/base/qt/platform.py b/base/qt/platform.py new file mode 100644 index 00000000..c0668794 --- /dev/null +++ b/base/qt/platform.py @@ -0,0 +1,17 @@ +# -*- coding: utf-8 -*- +# Created By: Virgil Dupras +# Created On: 2009-09-27 +# $Id$ +# Copyright 2009 Hardcoded Software (http://www.hardcoded.net) +# +# This software is licensed under the "HS" 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/hs_license + +import logging +import sys + +if sys.platform == 'win32': + from platform_win import * +else: + logging.warning("Unsupported Platform!!") \ No newline at end of file diff --git a/base/qt/win/__init__.py b/base/qt/platform_win.py similarity index 100% rename from base/qt/win/__init__.py rename to base/qt/platform_win.py diff --git a/base/qt/results_model.py b/base/qt/results_model.py index 3ec8a095..ccd84f7b 100644 --- a/base/qt/results_model.py +++ b/base/qt/results_model.py @@ -7,30 +7,29 @@ # which should be included with this package. The terms are also available at # http://www.hardcoded.net/licenses/hs_license -from PyQt4.QtCore import SIGNAL, Qt, QAbstractItemModel, QVariant, QModelIndex, QRect +from PyQt4.QtCore import SIGNAL, Qt, QAbstractItemModel, QModelIndex, QRect from PyQt4.QtGui import QBrush, QStyledItemDelegate, QFont, QTreeView, QColor -from tree_model import TreeNode, TreeModel +from qtlib.tree_model import TreeNode, TreeModel class ResultNode(TreeNode): def __init__(self, model, parent, row, dupe, group): - TreeNode.__init__(self, parent, row) - self.model = model + TreeNode.__init__(self, model, parent, row) self.dupe = dupe self.group = group self._normalData = None self._deltaData = None - def _get_children(self): - children = [] - if self.dupe is self.group.ref: - for index, dupe in enumerate(self.group.dupes): - children.append(ResultNode(self.model, self, index, dupe, self.group)) - return children + def _createNode(self, ref, row): + return ResultNode(self.model, self, row, ref, self.group) - def reset(self): + def _getChildren(self): + return self.group.dupes if self.dupe is self.group.ref else [] + + def invalidate(self): self._normalData = None self._deltaData = None + TreeNode.invalidate(self) @property def normalData(self): @@ -65,40 +64,41 @@ class ResultsModel(TreeModel): self._power_marker = False TreeModel.__init__(self) - def _root_nodes(self): - nodes = [] + def _createNode(self, ref, row): if self.power_marker: - for index, dupe in enumerate(self._results.dupes): - group = self._results.get_group_of_duplicate(dupe) - nodes.append(ResultNode(self, None, index, dupe, group)) + # ref is a dupe + group = self._results.get_group_of_duplicate(ref) + return ResultNode(self, None, row, ref, group) else: - for index, group in enumerate(self._results.groups): - nodes.append(ResultNode(self, None, index, group.ref, group)) - return nodes + # ref is a group + return ResultNode(self, None, row, ref.ref, ref) + + def _getChildren(self): + return self._results.dupes if self.power_marker else self._results.groups def columnCount(self, parent): return len(self._data.COLUMNS) def data(self, index, role): if not index.isValid(): - return QVariant() + return None node = index.internalPointer() if role == Qt.DisplayRole: data = node.deltaData if self.delta else node.normalData - return QVariant(data[index.column()]) + return data[index.column()] elif role == Qt.CheckStateRole: if index.column() == 0 and node.dupe is not node.group.ref: state = Qt.Checked if self._results.is_marked(node.dupe) else Qt.Unchecked - return QVariant(state) + return state elif role == Qt.ForegroundRole: if node.dupe is node.group.ref or node.dupe.is_ref: - return QVariant(QBrush(Qt.blue)) + return QBrush(Qt.blue) elif self.delta and index.column() in self._delta_columns: - return QVariant(QBrush(QColor(255, 142, 40))) # orange + return QBrush(QColor(255, 142, 40)) # orange elif role == Qt.EditRole: if index.column() == 0: - return QVariant(node.normalData[index.column()]) - return QVariant() + return node.normalData[index.column()] + return None def dupesForIndexes(self, indexes): nodes = [index.internalPointer() for index in indexes] @@ -138,9 +138,8 @@ class ResultsModel(TreeModel): def headerData(self, section, orientation, role): if orientation == Qt.Horizontal and role == Qt.DisplayRole and section < len(self._data.COLUMNS): - return QVariant(self._data.COLUMNS[section]['display']) - - return QVariant() + return self._data.COLUMNS[section]['display'] + return None def setData(self, index, value, role): if not index.isValid(): diff --git a/base/qt/tree_model.py b/base/qt/tree_model.py deleted file mode 100644 index d102fac7..00000000 --- a/base/qt/tree_model.py +++ /dev/null @@ -1,68 +0,0 @@ -# Created By: Virgil Dupras -# Created On: 2009-05-04 -# $Id$ -# Copyright 2009 Hardcoded Software (http://www.hardcoded.net) -# -# This software is licensed under the "HS" 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/hs_license - -from PyQt4.QtCore import Qt, QAbstractItemModel, QVariant, QModelIndex - -class TreeNode(object): - def __init__(self, parent, row): - self.parent = parent - self.row = row - self._children = None - - def _get_children(self): - raise NotImplementedError() - - @property - def children(self): - if self._children is None: - self._children = self._get_children() - return self._children - - -class TreeModel(QAbstractItemModel): - def __init__(self): - QAbstractItemModel.__init__(self) - self._nodes = None - - def _root_nodes(self): - raise NotImplementedError() - - def index(self, row, column, parent): - if not self.nodes: - return QModelIndex() - if not parent.isValid(): - return self.createIndex(row, column, self.nodes[row]) - node = parent.internalPointer() - return self.createIndex(row, column, node.children[row]) - - def parent(self, index): - if not index.isValid(): - return QModelIndex() - node = index.internalPointer() - if node.parent is None: - return QModelIndex() - else: - return self.createIndex(node.parent.row, 0, node.parent) - - def reset(self): - self._nodes = None - QAbstractItemModel.reset(self) - - def rowCount(self, parent): - if not parent.isValid(): - return len(self.nodes) - node = parent.internalPointer() - return len(node.children) - - @property - def nodes(self): - if self._nodes is None: - self._nodes = self._root_nodes() - return self._nodes -