The directories dialog is now the main window. There's probably many glitches left to fix due to that change, but the basic functionalities are there.

--HG--
rename : qt/base/main_window.py => qt/base/result_window.py
rename : qt/pe/main_window.py => qt/pe/result_window.py
This commit is contained in:
Virgil Dupras 2011-01-15 16:29:35 +01:00
parent 30eb26af7d
commit d51f5184d7
7 changed files with 251 additions and 225 deletions

View File

@ -6,14 +6,12 @@
# which should be included with this package. The terms are also available at
# http://www.hardcoded.net/licenses/bsd_license
import logging
import os
import os.path as op
from PyQt4.QtCore import QTimer, QObject, QCoreApplication, QUrl, SIGNAL, pyqtSignal
from PyQt4.QtGui import QDesktopServices, QFileDialog, QDialog, QMessageBox
from PyQt4.QtCore import QTimer, QObject, QCoreApplication, QUrl, QProcess, SIGNAL, pyqtSignal
from PyQt4.QtGui import QDesktopServices, QFileDialog, QDialog, QMessageBox, QApplication
from jobprogress import job
from jobprogress.qt import Progress
@ -21,13 +19,14 @@ from jobprogress.qt import Progress
from core.app import DupeGuru as DupeGuruBase, JOB_SCAN, JOB_LOAD, JOB_MOVE, JOB_COPY, JOB_DELETE
from qtlib.about_box import AboutBox
from qtlib.recent import Recent
from qtlib.reg import Registration
from . import platform
from .main_window import MainWindow
from .result_window import ResultWindow
from .directories_dialog import DirectoriesDialog
from .problem_dialog import ProblemDialog
from .util import createActions
JOBID2TITLE = {
JOB_SCAN: "Scanning for duplicates",
@ -54,16 +53,20 @@ class DupeGuru(DupeGuruBase, QObject):
#--- Private
def _setup(self):
self._setupActions()
self.prefs = self._create_preferences()
self.prefs.load()
self._update_options()
self.main_window = self._create_main_window()
self._progress = Progress(self.main_window)
self.directories_dialog = DirectoriesDialog(self.main_window, self)
self.details_dialog = self._create_details_dialog(self.main_window)
self.problemDialog = ProblemDialog(parent=self.main_window, app=self)
self.preferences_dialog = self._create_preferences_dialog(self.main_window)
self.about_box = AboutBox(self.main_window, self)
self.resultWindow = self._create_result_window()
self._progress = Progress(self.resultWindow)
self.directories_dialog = DirectoriesDialog(self.resultWindow, self)
self.details_dialog = self._create_details_dialog(self.resultWindow)
self.problemDialog = ProblemDialog(parent=self.resultWindow, app=self)
self.preferences_dialog = self._create_preferences_dialog(self.resultWindow)
self.about_box = AboutBox(self.resultWindow, self)
self.recentResults = Recent(self, self.directories_dialog.menuLoadRecent, 'recentResults')
self.recentResults.mustOpenItem.connect(self.load_from)
self.reg = Registration(self)
self.set_registration(self.prefs.registration_code, self.prefs.registration_email)
@ -73,19 +76,30 @@ class DupeGuru(DupeGuruBase, QObject):
# 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)
if self.prefs.mainWindowIsMaximized:
self.main_window.showMaximized()
else:
self.main_window.show()
self.directories_dialog.show()
self.load()
self.connect(QCoreApplication.instance(), SIGNAL('aboutToQuit()'), self.application_will_terminate)
self.connect(self._progress, SIGNAL('finished(QString)'), self.job_finished)
def _setupActions(self):
# Setup actions that are common to both the directory dialog and the results window.
# (name, shortcut, icon, desc, func)
ACTIONS = [
('actionQuit', 'Ctrl+Q', '', "Quit", self.quitTriggered),
('actionPreferences', 'Ctrl+5', 'preferences', "Preferences", self.preferencesTriggered),
('actionShowHelp', 'F1', '', "dupeGuru Help", self.showHelpTriggered),
('actionAbout', '', '', "About dupeGuru", self.showAboutBoxTriggered),
('actionRegister', '', '', "Register dupeGuru", self.registerTriggered),
('actionCheckForUpdate', '', '', "Check for Update", self.checkForUpdateTriggered),
('actionOpenDebugLog', '', '', "Open Debug Log", self.openDebugLogTriggered),
]
createActions(ACTIONS, self)
def _setup_as_registered(self):
self.prefs.registration_code = self.registration_code
self.prefs.registration_email = self.registration_email
self.main_window.actionRegister.setVisible(False)
self.actionRegister.setVisible(False)
self.about_box.registerButton.hide()
self.about_box.registeredEmailLabel.setText(self.prefs.registration_email)
@ -99,8 +113,8 @@ class DupeGuru(DupeGuruBase, QObject):
def _create_details_dialog(self, parent):
raise NotImplementedError()
def _create_main_window(self):
return MainWindow(app=self)
def _create_result_window(self):
return ResultWindow(app=self)
def _create_preferences(self):
raise NotImplementedError()
@ -126,7 +140,7 @@ class DupeGuru(DupeGuruBase, QObject):
self._progress.run(jobid, title, func, args=args)
except job.JobInProgressError:
msg = "A previous action is still hanging in there. You can't start a new one yet. Wait a few seconds, then try again."
QMessageBox.information(self.main_window, 'Action in progress', msg)
QMessageBox.information(self.resultWindow, 'Action in progress', msg)
def add_selected_to_ignore_list(self):
dupes = self.without_ref(self.selected_dupes)
@ -134,14 +148,14 @@ class DupeGuru(DupeGuruBase, QObject):
return
title = "Add to Ignore List"
msg = "All selected {0} matches are going to be ignored in all subsequent scans. Continue?".format(len(dupes))
if self.main_window._confirm(title, msg):
if self.confirm(title, msg):
DupeGuruBase.add_selected_to_ignore_list(self)
def copy_or_move_marked(self, copy):
opname = 'copy' if copy else 'move'
title = "Select a directory to {0} marked files to".format(opname)
flags = QFileDialog.ShowDirsOnly
destination = str(QFileDialog.getExistingDirectory(self.main_window, title, '', flags))
destination = str(QFileDialog.getExistingDirectory(self.resultWindow, title, '', flags))
if not destination:
return
recreate_path = self.prefs.destination_type
@ -153,46 +167,32 @@ class DupeGuru(DupeGuruBase, QObject):
return
title = "Remove duplicates"
msg = "You are about to remove {0} files from results. Continue?".format(len(dupes))
if self.main_window._confirm(title, msg):
if self.confirm(title, msg):
DupeGuruBase.remove_selected(self)
#--- Public
def askForRegCode(self):
self.reg.ask_for_code()
def confirm(self, title, msg, default_button=QMessageBox.Yes):
active = QApplication.activeWindow()
buttons = QMessageBox.Yes | QMessageBox.No
answer = QMessageBox.question(active, title, msg, buttons, default_button)
return answer == QMessageBox.Yes
def invokeCustomCommand(self):
cmd = self.prefs.custom_command
if cmd:
self.invoke_command(cmd)
else:
msg = "You have no custom command set up. Please, set it up in your preferences."
QMessageBox.warning(self.main_window, 'Custom Command', msg)
def openDebugLog(self):
debugLogPath = op.join(self.appdata, 'debug.log')
self._open_path(debugLogPath)
def show_about_box(self):
self.about_box.show()
QMessageBox.warning(self.resultWindow, 'Custom Command', msg)
def show_details(self):
self.details_dialog.show()
def show_directories(self):
self.directories_dialog.show()
def show_help(self):
base_path = platform.HELP_PATH.format(self.EDITION)
url = QUrl.fromLocalFile(op.abspath(op.join(base_path, 'index.html')))
QDesktopServices.openUrl(url)
def show_preferences(self):
self.preferences_dialog.load()
result = self.preferences_dialog.exec_()
if result == QDialog.Accepted:
self.preferences_dialog.save()
self.prefs.save()
self._update_options()
def showResultsWindow(self):
self.resultWindow.show()
#--- Signals
willSavePrefs = pyqtSignal()
@ -203,6 +203,9 @@ class DupeGuru(DupeGuruBase, QObject):
self.prefs.save()
self.save()
def checkForUpdateTriggered(self):
QProcess.execute('updater.exe', ['/checknow'])
def job_finished(self, jobid):
self._job_completed(jobid)
if jobid in (JOB_MOVE, JOB_COPY, JOB_DELETE):
@ -210,10 +213,40 @@ class DupeGuru(DupeGuruBase, QObject):
self.problemDialog.show()
else:
msg = "All files were processed successfully."
QMessageBox.information(self.main_window, 'Operation Complete', msg)
QMessageBox.information(self.resultWindow, 'Operation Complete', msg)
elif jobid == JOB_SCAN:
if not self.results.groups:
title = "Scanning complete"
title = "Scan complete"
msg = "No duplicates found."
QMessageBox.information(self.main_window, title, msg)
QMessageBox.information(self.resultWindow, title, msg)
else:
self.showResultsWindow()
elif jobid == JOB_LOAD:
self.showResultsWindow()
def openDebugLogTriggered(self):
debugLogPath = op.join(self.appdata, 'debug.log')
self._open_path(debugLogPath)
def preferencesTriggered(self):
self.preferences_dialog.load()
result = self.preferences_dialog.exec_()
if result == QDialog.Accepted:
self.preferences_dialog.save()
self.prefs.save()
self._update_options()
def quitTriggered(self):
self.directories_dialog.close()
def registerTriggered(self):
self.reg.ask_for_code()
def showAboutBoxTriggered(self):
self.about_box.show()
def showHelpTriggered(self):
base_path = platform.HELP_PATH.format(self.EDITION)
url = QUrl.fromLocalFile(op.abspath(op.join(base_path, 'index.html')))
QDesktopServices.openUrl(url)

View File

@ -6,17 +6,20 @@
# which should be included with this package. The terms are also available at
# http://www.hardcoded.net/licenses/bsd_license
from PyQt4.QtCore import SIGNAL, Qt, QSize
from PyQt4.QtGui import (QDialog, QFileDialog, QHeaderView, QVBoxLayout, QHBoxLayout, QTreeView,
QAbstractItemView, QSpacerItem, QSizePolicy, QPushButton, QApplication)
from PyQt4.QtCore import QSize, QRect
from PyQt4.QtGui import (QWidget, QFileDialog, QHeaderView, QVBoxLayout, QHBoxLayout, QTreeView,
QAbstractItemView, QSpacerItem, QSizePolicy, QPushButton, QApplication, QMessageBox, QMainWindow,
QMenuBar, QMenu)
from core.app import NoScannableFileError
from . import platform
from .directories_model import DirectoriesModel, DirectoriesDelegate
from .util import createActions
class DirectoriesDialog(QDialog):
class DirectoriesDialog(QMainWindow):
def __init__(self, parent, app):
flags = Qt.CustomizeWindowHint | Qt.WindowTitleHint | Qt.WindowSystemMenuHint
QDialog.__init__(self, parent, flags)
QMainWindow.__init__(self, None)
self.app = app
self.lastAddedFolder = platform.INITIAL_FOLDER_IN_DIALOGS
self.directoriesModel = DirectoriesModel(self.app)
@ -24,21 +27,61 @@ class DirectoriesDialog(QDialog):
self._setupUi()
self._updateRemoveButton()
self.connect(self.doneButton, SIGNAL('clicked()'), self.doneButtonClicked)
self.connect(self.addButton, SIGNAL('clicked()'), self.addButtonClicked)
self.connect(self.removeButton, SIGNAL('clicked()'), self.removeButtonClicked)
self.connect(self.treeView.selectionModel(), SIGNAL('selectionChanged(QItemSelection,QItemSelection)'), self.selectionChanged)
self.scanButton.clicked.connect(self.scanButtonClicked)
self.addButton.clicked.connect(self.addButtonClicked)
self.removeButton.clicked.connect(self.removeButtonClicked)
self.treeView.selectionModel().selectionChanged.connect(self.selectionChanged)
self.app.willSavePrefs.connect(self.appWillSavePrefs)
def _setupActions(self):
# (name, shortcut, icon, desc, func)
ACTIONS = [
('actionLoadResults', 'Ctrl+L', '', "Load Results...", self.loadResultsTriggered),
('actionShowResultsWindow', '', '', "Results Window", self.app.showResultsWindow),
]
createActions(ACTIONS, self)
def _setupMenu(self):
self.menubar = QMenuBar(self)
self.menubar.setGeometry(QRect(0, 0, 42, 22))
self.menuFile = QMenu(self.menubar)
self.menuFile.setTitle("File")
self.menuView = QMenu(self.menubar)
self.menuView.setTitle("View")
self.menuHelp = QMenu(self.menubar)
self.menuHelp.setTitle("Help")
self.menuLoadRecent = QMenu(self.menuFile)
self.menuLoadRecent.setTitle("Load Recent Results")
self.setMenuBar(self.menubar)
self.menuFile.addAction(self.actionLoadResults)
self.menuFile.addAction(self.menuLoadRecent.menuAction())
self.menuFile.addSeparator()
self.menuFile.addAction(self.app.actionQuit)
self.menuView.addAction(self.app.actionPreferences)
self.menuView.addAction(self.actionShowResultsWindow)
self.menuHelp.addAction(self.app.actionShowHelp)
self.menuHelp.addAction(self.app.actionRegister)
self.menuHelp.addAction(self.app.actionCheckForUpdate)
self.menuHelp.addAction(self.app.actionOpenDebugLog)
self.menuHelp.addAction(self.app.actionAbout)
self.menubar.addAction(self.menuFile.menuAction())
self.menubar.addAction(self.menuView.menuAction())
self.menubar.addAction(self.menuHelp.menuAction())
def _setupUi(self):
self.setWindowTitle("Directories")
self.setWindowTitle(self.app.NAME)
self.resize(420, 338)
self.verticalLayout = QVBoxLayout(self)
self.treeView = QTreeView(self)
self.centralwidget = QWidget(self)
self.verticalLayout = QVBoxLayout(self.centralwidget)
self.treeView = QTreeView(self.centralwidget)
self.treeView.setItemDelegate(self.directoriesDelegate)
self.treeView.setModel(self.directoriesModel)
self.treeView.setAcceptDrops(True)
self.treeView.setEditTriggers(QAbstractItemView.DoubleClicked|QAbstractItemView.EditKeyPressed|QAbstractItemView.SelectedClicked)
triggers = QAbstractItemView.DoubleClicked|QAbstractItemView.EditKeyPressed\
|QAbstractItemView.SelectedClicked
self.treeView.setEditTriggers(triggers)
self.treeView.setDragDropOverwriteMode(True)
self.treeView.setDragDropMode(QAbstractItemView.DropOnly)
self.treeView.setUniformRowHeights(True)
@ -51,31 +94,35 @@ class DirectoriesDialog(QDialog):
self.horizontalLayout = QHBoxLayout()
spacerItem = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
self.horizontalLayout.addItem(spacerItem)
self.removeButton = QPushButton(self)
self.removeButton = QPushButton(self.centralwidget)
self.removeButton.setText("Remove")
self.removeButton.setShortcut("Del")
self.removeButton.setMinimumSize(QSize(91, 0))
self.removeButton.setMaximumSize(QSize(16777215, 32))
self.horizontalLayout.addWidget(self.removeButton)
self.addButton = QPushButton(self)
self.addButton = QPushButton(self.centralwidget)
self.addButton.setText("Add")
self.addButton.setMinimumSize(QSize(91, 0))
self.addButton.setMaximumSize(QSize(16777215, 32))
self.horizontalLayout.addWidget(self.addButton)
spacerItem1 = QSpacerItem(40, 20, QSizePolicy.Fixed, QSizePolicy.Minimum)
self.horizontalLayout.addItem(spacerItem1)
self.doneButton = QPushButton(self)
self.doneButton.setText("Done")
self.scanButton = QPushButton(self.centralwidget)
self.scanButton.setText("Scan")
sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.doneButton.sizePolicy().hasHeightForWidth())
self.doneButton.setSizePolicy(sizePolicy)
self.doneButton.setMinimumSize(QSize(91, 0))
self.doneButton.setMaximumSize(QSize(16777215, 32))
self.doneButton.setDefault(True)
self.horizontalLayout.addWidget(self.doneButton)
sizePolicy.setHeightForWidth(self.scanButton.sizePolicy().hasHeightForWidth())
self.scanButton.setSizePolicy(sizePolicy)
self.scanButton.setMinimumSize(QSize(91, 0))
self.scanButton.setMaximumSize(QSize(16777215, 32))
self.scanButton.setDefault(True)
self.horizontalLayout.addWidget(self.scanButton)
self.verticalLayout.addLayout(self.horizontalLayout)
self.setCentralWidget(self.centralwidget)
self._setupActions()
self._setupMenu()
if self.app.prefs.directoriesWindowRect is not None:
self.setGeometry(self.app.prefs.directoriesWindowRect)
@ -90,6 +137,17 @@ class DirectoriesDialog(QDialog):
node = index.internalPointer()
# label = 'Remove' if node.parent is None else 'Exclude'
#--- QWidget overrides
def closeEvent(self, event):
event.accept()
if self.app.results.is_modified:
title = "Unsaved results"
msg = "You have unsaved results, do you really want to quit?"
if not self.app.confirm(title, msg):
event.ignore()
if event.isAccepted():
QApplication.quit()
#--- Events
def addButtonClicked(self):
title = "Select a directory to add to the scanning list"
@ -103,8 +161,13 @@ class DirectoriesDialog(QDialog):
def appWillSavePrefs(self):
self.app.prefs.directoriesWindowRect = self.geometry()
def doneButtonClicked(self):
self.hide()
def loadResultsTriggered(self):
title = "Select a results file to load"
files = "dupeGuru Results (*.dupeguru)"
destination = QFileDialog.getOpenFileName(self, title, '', files)
if destination:
self.app.load_from(destination)
self.app.recentResults.insertItem(destination)
def removeButtonClicked(self):
indexes = self.treeView.selectedIndexes()
@ -116,6 +179,18 @@ class DirectoriesDialog(QDialog):
row = index.row()
self.app.remove_directory(row)
def scanButtonClicked(self):
title = "Start a new scan"
if len(self.app.results.groups) > 0:
msg = "Are you sure you want to start a new duplicate scan?"
if not self.app.confirm(title, msg):
return
try:
self.app.start_scanning()
except NoScannableFileError:
msg = "The selected directories contain no scannable file."
QMessageBox.warning(self, title, msg)
def selectionChanged(self, selected, deselected):
self._updateRemoveButton()

View File

@ -36,8 +36,8 @@ class Preferences(PreferencesBase):
self.columns_width[index] = width
self.columns_visible = get('ColumnsVisible', self.columns_visible)
self.mainWindowIsMaximized = get('MainWindowIsMaximized', self.mainWindowIsMaximized)
self.mainWindowRect = self.get_rect('MainWindowRect', self.mainWindowRect)
self.resultWindowIsMaximized = get('ResultWindowIsMaximized', self.resultWindowIsMaximized)
self.resultWindowRect = self.get_rect('ResultWindowRect', self.resultWindowRect)
self.detailsWindowRect = self.get_rect('DetailsWindowRect', self.detailsWindowRect)
self.directoriesWindowRect = self.get_rect('DirectoriesWindowRect', self.directoriesWindowRect)
self.recentResults = get('RecentResults', self.recentResults)
@ -59,8 +59,8 @@ class Preferences(PreferencesBase):
self.destination_type = 1
self.custom_command = ''
self.mainWindowIsMaximized = False
self.mainWindowRect = None
self.resultWindowIsMaximized = False
self.resultWindowRect = None
self.detailsWindowRect = None
self.directoriesWindowRect = None
self.recentResults = []
@ -89,8 +89,8 @@ class Preferences(PreferencesBase):
set_('ColumnsWidth', self.columns_width)
set_('ColumnsVisible', self.columns_visible)
set_('MainWindowIsMaximized', self.mainWindowIsMaximized)
self.set_rect('MainWindowRect', self.mainWindowRect)
set_('ResultWindowIsMaximized', self.resultWindowIsMaximized)
self.set_rect('ResultWindowRect', self.resultWindowRect)
self.set_rect('DetailsWindowRect', self.detailsWindowRect)
self.set_rect('DirectoriesWindowRect', self.directoriesWindowRect)
set_('RecentResults', self.recentResults)

View File

@ -8,21 +8,18 @@
import sys
from PyQt4.QtCore import Qt, QCoreApplication, QProcess, SIGNAL, QUrl, QRect
from PyQt4.QtGui import (QMainWindow, QMenu, QPixmap, QIcon, QToolButton, QLabel, QHeaderView,
QMessageBox, QInputDialog, QLineEdit, QDesktopServices, QFileDialog, QAction, QMenuBar,
QToolBar, QWidget, QVBoxLayout, QAbstractItemView, QStatusBar)
from PyQt4.QtCore import Qt, SIGNAL, QUrl, QRect
from PyQt4.QtGui import (QMainWindow, QMenu, QPixmap, QIcon, QLabel, QHeaderView, QMessageBox,
QInputDialog, QLineEdit, QDesktopServices, QFileDialog, QMenuBar, QWidget, QVBoxLayout,
QAbstractItemView, QStatusBar)
from hscommon.util import nonone
from qtlib.recent import Recent
from core.app import NoScannableFileError
from . import dg_rc
from .results_model import ResultsModel, ResultsView
from .stats_label import StatsLabel
from .util import createActions
class MainWindow(QMainWindow):
class ResultWindow(QMainWindow):
def __init__(self, app):
QMainWindow.__init__(self, None)
self.app = app
@ -41,11 +38,8 @@ class MainWindow(QMainWindow):
def _setupActions(self):
# (name, shortcut, icon, desc, func)
ACTIONS = [
('actionScan', 'Ctrl+T', self.app.LOGO_NAME, "Start Scan", self.scanTriggered),
('actionDirectories', 'Ctrl+4', 'folder', "Directories", self.directoriesTriggered),
('actionDetails', 'Ctrl+3', 'details', "Details", self.detailsTriggered),
('actionActions', '', 'actions', "Actions", self.actionsTriggered),
('actionPreferences', 'Ctrl+5', 'preferences', "Preferences", self.preferencesTriggered),
('actionDelta', 'Ctrl+2', 'delta', "Delta Values", self.deltaTriggered),
('actionPowerMarker', 'Ctrl+1', 'power_marker', "Power Marker", self.powerMarkerTriggered),
('actionDeleteMarked', 'Ctrl+D', '', "Send Marked to Recycle Bin", self.deleteTriggered),
@ -64,28 +58,13 @@ class MainWindow(QMainWindow):
('actionInvertMarking', 'Ctrl+Alt+A', '', "Invert Marking", self.markInvertTriggered),
('actionMarkSelected', '', '', "Mark Selected", self.markSelectedTriggered),
('actionClearIgnoreList', '', '', "Clear Ignore List", self.clearIgnoreListTriggered),
('actionQuit', 'Ctrl+Q', '', "Quit", self.close),
('actionApplyFilter', 'Ctrl+F', '', "Apply Filter", self.applyFilterTriggered),
('actionCancelFilter', 'Ctrl+Shift+F', '', "Cancel Filter", self.cancelFilterTriggered),
('actionShowHelp', 'F1', '', "dupeGuru Help", self.showHelpTriggered),
('actionAbout', '', '', "About dupeGuru", self.aboutTriggered),
('actionRegister', '', '', "Register dupeGuru", self.registerTrigerred),
('actionCheckForUpdate', '', '', "Check for Update", self.checkForUpdateTriggered),
('actionExport', '', '', "Export To HTML", self.exportTriggered),
('actionLoadResults', 'Ctrl+L', '', "Load Results...", self.loadResultsTriggered),
('actionSaveResults', 'Ctrl+S', '', "Save Results...", self.saveResultsTriggered),
('actionOpenDebugLog', '', '', "Open Debug Log", self.openDebugLogTriggered),
('actionInvokeCustomCommand', 'Ctrl+I', '', "Invoke Custom Command", self.app.invokeCustomCommand),
]
for name, shortcut, icon, desc, func in ACTIONS:
action = QAction(self)
if icon:
action.setIcon(QIcon(QPixmap(':/' + icon)))
if shortcut:
action.setShortcut(shortcut)
action.setText(desc)
action.triggered.connect(func)
setattr(self, name, action)
createActions(ACTIONS, self)
self.actionDelta.setCheckable(True)
self.actionPowerMarker.setCheckable(True)
@ -100,14 +79,10 @@ class MainWindow(QMainWindow):
self.menuActions.setTitle("Actions")
self.menuColumns = QMenu(self.menubar)
self.menuColumns.setTitle("Columns")
self.menuModes = QMenu(self.menubar)
self.menuModes.setTitle("Modes")
self.menuWindow = QMenu(self.menubar)
self.menuWindow.setTitle("Windows")
self.menuView = QMenu(self.menubar)
self.menuView.setTitle("View")
self.menuHelp = QMenu(self.menubar)
self.menuHelp.setTitle("Help")
self.menuLoadRecent = QMenu(self.menuFile)
self.menuLoadRecent.setTitle("Load Recent Results")
self.setMenuBar(self.menubar)
self.menuActions.addAction(self.actionDeleteMarked)
@ -131,32 +106,27 @@ class MainWindow(QMainWindow):
self.menuMark.addAction(self.actionMarkNone)
self.menuMark.addAction(self.actionInvertMarking)
self.menuMark.addAction(self.actionMarkSelected)
self.menuModes.addAction(self.actionPowerMarker)
self.menuModes.addAction(self.actionDelta)
self.menuWindow.addAction(self.actionDetails)
self.menuWindow.addAction(self.actionDirectories)
self.menuWindow.addAction(self.actionPreferences)
self.menuHelp.addAction(self.actionShowHelp)
self.menuHelp.addAction(self.actionRegister)
self.menuHelp.addAction(self.actionCheckForUpdate)
self.menuHelp.addAction(self.actionOpenDebugLog)
self.menuHelp.addAction(self.actionAbout)
self.menuFile.addAction(self.actionScan)
self.menuFile.addSeparator()
self.menuFile.addAction(self.actionLoadResults)
self.menuFile.addAction(self.menuLoadRecent.menuAction())
self.menuView.addAction(self.actionPowerMarker)
self.menuView.addAction(self.actionDelta)
self.menuView.addSeparator()
self.menuView.addAction(self.actionDetails)
self.menuView.addAction(self.app.actionPreferences)
self.menuHelp.addAction(self.app.actionShowHelp)
self.menuHelp.addAction(self.app.actionRegister)
self.menuHelp.addAction(self.app.actionCheckForUpdate)
self.menuHelp.addAction(self.app.actionOpenDebugLog)
self.menuHelp.addAction(self.app.actionAbout)
self.menuFile.addAction(self.actionSaveResults)
self.menuFile.addAction(self.actionExport)
self.menuFile.addAction(self.actionClearIgnoreList)
self.menuFile.addSeparator()
self.menuFile.addAction(self.actionQuit)
self.menuFile.addAction(self.app.actionQuit)
self.menubar.addAction(self.menuFile.menuAction())
self.menubar.addAction(self.menuMark.menuAction())
self.menubar.addAction(self.menuActions.menuAction())
self.menubar.addAction(self.menuColumns.menuAction())
self.menubar.addAction(self.menuModes.menuAction())
self.menubar.addAction(self.menuWindow.menuAction())
self.menubar.addAction(self.menuView.menuAction())
self.menubar.addAction(self.menuHelp.menuAction())
# Columns menu
@ -190,27 +160,8 @@ class MainWindow(QMainWindow):
actionMenu.addAction(self.actionRenameSelected)
self.actionActions.setMenu(actionMenu)
def _setupToolbar(self):
self.toolBar = QToolBar(self)
self.toolBar.setMovable(False)
self.toolBar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
self.toolBar.setFloatable(False)
self.addToolBar(Qt.ToolBarArea(Qt.TopToolBarArea), self.toolBar)
self.toolBar.addAction(self.actionScan)
button = QToolButton(self.toolBar)
button.setDefaultAction(self.actionActions.menu().menuAction())
button.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
self.actionsButton = button
self.toolBar.addWidget(button)
self.toolBar.addAction(self.actionDirectories)
self.toolBar.addAction(self.actionDetails)
self.toolBar.addAction(self.actionPreferences)
self.toolBar.addAction(self.actionDelta)
self.toolBar.addAction(self.actionPowerMarker)
def _setupUi(self):
self.setWindowTitle(QCoreApplication.instance().applicationName())
self.setWindowTitle("dupeGuru Results")
self.resize(630, 514)
self.centralwidget = QWidget(self)
self.verticalLayout_2 = QVBoxLayout(self.centralwidget)
@ -230,17 +181,16 @@ class MainWindow(QMainWindow):
self.setCentralWidget(self.centralwidget)
self._setupActions()
self._setupMenu()
self._setupToolbar()
self.recentResults = Recent(self.app, self.menuLoadRecent, 'recentResults')
self.recentResults.mustOpenItem.connect(self.app.load_from)
self.statusbar = QStatusBar(self)
self.statusbar.setSizeGripEnabled(True)
self.setStatusBar(self.statusbar)
self.statusLabel = QLabel(self)
self.statusbar.addPermanentWidget(self.statusLabel, 1)
if self.app.prefs.mainWindowRect is not None and not self.app.prefs.mainWindowIsMaximized:
self.setGeometry(self.app.prefs.mainWindowRect)
if self.app.prefs.resultWindowIsMaximized:
self.setWindowState(self.windowState() | Qt.WindowMaximized)
if self.app.prefs.resultWindowRect is not None and not self.app.prefs.resultWindowIsMaximized:
self.setGeometry(self.app.prefs.resultWindowRect)
# Platform-specific setup
if sys.platform == 'linux2':
@ -249,11 +199,6 @@ class MainWindow(QMainWindow):
self.actionHardlinkMarked.setVisible(False)
#--- Private
def _confirm(self, title, msg, default_button=QMessageBox.Yes):
buttons = QMessageBox.Yes | QMessageBox.No
answer = QMessageBox.question(self, title, msg, buttons, default_button)
return answer == QMessageBox.Yes
def _load_columns(self):
h = self.resultsView.horizontalHeader()
h.setResizeMode(QHeaderView.Interactive)
@ -270,19 +215,7 @@ class MainWindow(QMainWindow):
colid = action.column_index
action.setChecked(not h.isSectionHidden(colid))
#--- QWidget overrides
def closeEvent(self, event):
event.accept()
if self.app.results.is_modified:
title = "Unsaved results"
msg = "You have unsaved results, do you really want to quit?"
if not self._confirm(title, msg):
event.ignore()
#--- Actions
def aboutTriggered(self):
self.app.show_about_box()
def actionsTriggered(self):
self.actionsButton.showMenu()
@ -303,9 +236,6 @@ class MainWindow(QMainWindow):
def cancelFilterTriggered(self):
self.app.apply_filter('')
def checkForUpdateTriggered(self):
QProcess.execute('updater.exe', ['/checknow'])
def clearIgnoreListTriggered(self):
title = "Clear Ignore List"
count = len(self.app.scanner.ignore_list)
@ -313,7 +243,7 @@ class MainWindow(QMainWindow):
QMessageBox.information(self, title, "Nothing to clear.")
return
msg = "Do you really want to remove all {0} items from the ignore list?".format(count)
if self._confirm(title, msg, QMessageBox.No):
if self.app.confirm(title, msg, QMessageBox.No):
self.app.scanner.ignore_list.Clear()
QMessageBox.information(self, title, "Ignore list cleared.")
@ -326,7 +256,7 @@ class MainWindow(QMainWindow):
return
title = "Delete duplicates"
msg = "You are about to send {0} files to the recycle bin. Continue?".format(count)
if self._confirm(title, msg):
if self.app.confirm(title, msg):
self.app.delete_marked()
def deltaTriggered(self):
@ -335,9 +265,6 @@ class MainWindow(QMainWindow):
def detailsTriggered(self):
self.app.show_details()
def directoriesTriggered(self):
self.app.show_directories()
def exportTriggered(self):
h = self.resultsView.horizontalHeader()
column_ids = []
@ -354,17 +281,9 @@ class MainWindow(QMainWindow):
return
title = "Delete and hardlink duplicates"
msg = "You are about to send {0} files to the trash and hardlink them afterwards. Continue?".format(count)
if self._confirm(title, msg):
if self.app.confirm(title, msg):
self.app.delete_marked(replace_with_hardlinks=True)
def loadResultsTriggered(self):
title = "Select a results file to load"
files = "dupeGuru Results (*.dupeguru)"
destination = QFileDialog.getOpenFileName(self, title, '', files)
if destination:
self.app.load_from(destination)
self.recentResults.insertItem(destination)
def makeReferenceTriggered(self):
self.app.make_selected_reference()
@ -383,9 +302,6 @@ class MainWindow(QMainWindow):
def moveTriggered(self):
self.app.copy_or_move_marked(False)
def openDebugLogTriggered(self):
self.app.openDebugLog()
def openTriggered(self):
self.app.open_selected()
@ -395,16 +311,13 @@ class MainWindow(QMainWindow):
def preferencesTriggered(self):
self.app.show_preferences()
def registerTrigerred(self):
self.app.reg.ask_for_code()
def removeMarkedTriggered(self):
count = self.app.results.mark_count
if not count:
return
title = "Remove duplicates"
msg = "You are about to remove {0} files from results. Continue?".format(count)
if self._confirm(title, msg):
if self.app.confirm(title, msg):
self.app.remove_marked()
def removeSelectedTriggered(self):
@ -422,23 +335,7 @@ class MainWindow(QMainWindow):
destination = QFileDialog.getSaveFileName(self, title, '', files)
if destination:
self.app.save_as(destination)
self.recentResults.insertItem(destination)
def scanTriggered(self):
title = "Start a new scan"
if len(self.app.results.groups) > 0:
msg = "Are you sure you want to start a new duplicate scan?"
if not self._confirm(title, msg):
return
try:
self.app.start_scanning()
except NoScannableFileError:
msg = "The selected directories contain no scannable file."
QMessageBox.warning(self, title, msg)
self.app.show_directories()
def showHelpTriggered(self):
self.app.show_help()
self.app.recentResults.insertItem(destination)
#--- Events
def appWillSavePrefs(self):
@ -451,8 +348,8 @@ class MainWindow(QMainWindow):
visible.append(not h.isSectionHidden(i))
prefs.columns_width = widths
prefs.columns_visible = visible
prefs.mainWindowIsMaximized = self.isMaximized()
prefs.mainWindowRect = self.geometry()
prefs.resultWindowIsMaximized = self.isMaximized()
prefs.resultWindowRect = self.geometry()
def columnToggled(self, action):
colid = action.column_index

21
qt/base/util.py Normal file
View File

@ -0,0 +1,21 @@
# Created By: Virgil Dupras
# Created On: 2011-01-15
# Copyright 2011 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
from PyQt4.QtGui import QPixmap, QIcon, QAction
def createActions(actions, target):
# actions = [(name, shortcut, icon, desc, func)]
for name, shortcut, icon, desc, func in actions:
action = QAction(target)
if icon:
action.setIcon(QIcon(QPixmap(':/' + icon)))
if shortcut:
action.setShortcut(shortcut)
action.setText(desc)
action.triggered.connect(func)
setattr(target, name, action)

View File

@ -20,7 +20,7 @@ from core_pe.scanner import ScannerPE
from ..base.app import DupeGuru as DupeGuruBase
from .block import getblocks
from .details_dialog import DetailsDialog
from .main_window import MainWindow
from .result_window import ResultWindow
from .preferences import Preferences
from .preferences_dialog import PreferencesDialog
@ -79,8 +79,8 @@ class DupeGuru(DupeGuruBase):
def _create_details_dialog(self, parent):
return DetailsDialog(parent, self)
def _create_main_window(self):
return MainWindow(app=self)
def _create_result_window(self):
return ResultWindow(app=self)
def _create_preferences(self):
return Preferences()

View File

@ -9,11 +9,11 @@
from PyQt4.QtCore import SIGNAL
from PyQt4.QtGui import QMessageBox, QAction
from ..base.main_window import MainWindow as MainWindowBase
from ..base.result_window import ResultWindow as ResultWindowBase
class MainWindow(MainWindowBase):
class ResultWindow(ResultWindowBase):
def _setupUi(self):
MainWindowBase._setupUi(self)
ResultWindowBase._setupUi(self)
self.actionClearPictureCache = QAction("Clear Picture Cache", self)
self.menuFile.insertAction(self.actionClearIgnoreList, self.actionClearPictureCache)
self.connect(self.actionClearPictureCache, SIGNAL("triggered()"), self.clearPictureCacheTriggered)
@ -21,7 +21,7 @@ class MainWindow(MainWindowBase):
def clearPictureCacheTriggered(self):
title = "Clear Picture Cache"
msg = "Do you really want to remove all your cached picture analysis?"
if self._confirm(title, msg, QMessageBox.No):
if self.app.confirm(title, msg, QMessageBox.No):
self.app.scanner.clear_picture_cache()
QMessageBox.information(self, title, "Picture cache cleared.")