mirror of
https://github.com/arsenetar/dupeguru.git
synced 2026-01-22 14:41:39 +00:00
Added tox configuration
... and fixed pep8 warnings. There's a lot of them that are still ignored, but that's because it's too much of a step to take at once.
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
# Created By: Virgil Dupras
|
||||
# Created On: 2009-04-25
|
||||
# Copyright 2014 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
|
||||
#
|
||||
# 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
|
||||
|
||||
import sys
|
||||
@@ -14,13 +14,12 @@ from PyQt5.QtGui import QDesktopServices
|
||||
from PyQt5.QtWidgets import QApplication, QFileDialog, QDialog, QMessageBox
|
||||
|
||||
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.util import createActions
|
||||
from qtlib.progress_window import ProgressWindow
|
||||
from qtlib.progress_window import ProgressWindow
|
||||
|
||||
from . import platform
|
||||
from .result_window import ResultWindow
|
||||
@@ -35,13 +34,13 @@ class DupeGuru(QObject):
|
||||
MODELCLASS = None
|
||||
LOGO_NAME = '<replace this>'
|
||||
NAME = '<replace this>'
|
||||
|
||||
|
||||
DETAILS_DIALOG_CLASS = None
|
||||
RESULT_WINDOW_CLASS = ResultWindow
|
||||
RESULT_MODEL_CLASS = None
|
||||
PREFERENCES_CLASS = None
|
||||
PREFERENCES_DIALOG_CLASS = None
|
||||
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self.prefs = self.PREFERENCES_CLASS()
|
||||
@@ -49,7 +48,7 @@ class DupeGuru(QObject):
|
||||
self.model = self.MODELCLASS(view=self)
|
||||
self._setup()
|
||||
self.prefsChanged.emit(self.prefs)
|
||||
|
||||
|
||||
#--- Private
|
||||
def _setup(self):
|
||||
self._setupActions()
|
||||
@@ -58,24 +57,24 @@ class DupeGuru(QObject):
|
||||
self.recentResults.mustOpenItem.connect(self.model.load_from)
|
||||
self.directories_dialog = DirectoriesDialog(self)
|
||||
self.resultWindow = self.RESULT_WINDOW_CLASS(self.directories_dialog, self)
|
||||
self.progress_window = ProgressWindow(self.resultWindow, self.model.progress_window)
|
||||
self.progress_window = ProgressWindow(self.resultWindow, self.model.progress_window)
|
||||
self.details_dialog = self.DETAILS_DIALOG_CLASS(self.resultWindow, self)
|
||||
self.problemDialog = ProblemDialog(parent=self.resultWindow, model=self.model.problem_dialog)
|
||||
self.ignoreListDialog = IgnoreListDialog(parent=self.resultWindow, model=self.model.ignore_list_dialog)
|
||||
self.deletionOptions = DeletionOptions(parent=self.resultWindow, model=self.model.deletion_options)
|
||||
self.preferences_dialog = self.PREFERENCES_DIALOG_CLASS(self.resultWindow, self)
|
||||
self.about_box = AboutBox(self.resultWindow, self)
|
||||
|
||||
|
||||
self.directories_dialog.show()
|
||||
self.model.load()
|
||||
|
||||
# The timer scheme is because if the nag is not shown before the application is
|
||||
|
||||
# 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.finishedLaunching)
|
||||
QCoreApplication.instance().aboutToQuit.connect(self.application_will_terminate)
|
||||
|
||||
|
||||
def _setupActions(self):
|
||||
# Setup actions that are common to both the directory dialog and the results window.
|
||||
# (name, shortcut, icon, desc, func)
|
||||
@@ -88,61 +87,61 @@ class DupeGuru(QObject):
|
||||
('actionOpenDebugLog', '', '', tr("Open Debug Log"), self.openDebugLogTriggered),
|
||||
]
|
||||
createActions(ACTIONS, self)
|
||||
|
||||
|
||||
def _update_options(self):
|
||||
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
|
||||
self.model.options['copymove_dest_type'] = self.prefs.destination_type
|
||||
|
||||
|
||||
#--- Public
|
||||
def add_selected_to_ignore_list(self):
|
||||
self.model.add_selected_to_ignore_list()
|
||||
|
||||
|
||||
def remove_selected(self):
|
||||
self.model.remove_selected(self)
|
||||
|
||||
|
||||
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):
|
||||
self.model.invoke_custom_command()
|
||||
|
||||
|
||||
def show_details(self):
|
||||
self.details_dialog.show()
|
||||
|
||||
|
||||
def showResultsWindow(self):
|
||||
self.resultWindow.show()
|
||||
|
||||
|
||||
#--- Signals
|
||||
willSavePrefs = pyqtSignal()
|
||||
prefsChanged = pyqtSignal(object)
|
||||
|
||||
|
||||
#--- Events
|
||||
def finishedLaunching(self):
|
||||
if sys.getfilesystemencoding() == 'ascii':
|
||||
# No need to localize this, it's a debugging message.
|
||||
msg = "Something is wrong with the way your system locale is set. If the files you're "\
|
||||
"scanning have accented letters, you'll probably get a crash. It is advised that "\
|
||||
"you set your system locale properly."
|
||||
"scanning have accented letters, you'll probably get a crash. It is advised that "\
|
||||
"you set your system locale properly."
|
||||
QMessageBox.warning(self.directories_dialog, "Wrong Locale", msg)
|
||||
|
||||
|
||||
def application_will_terminate(self):
|
||||
self.willSavePrefs.emit()
|
||||
self.prefs.save()
|
||||
self.model.save()
|
||||
|
||||
|
||||
def ignoreListTriggered(self):
|
||||
self.model.ignore_list_dialog.show()
|
||||
|
||||
|
||||
def openDebugLogTriggered(self):
|
||||
debugLogPath = op.join(self.model.appdata, 'debug.log')
|
||||
desktop.open_path(debugLogPath)
|
||||
|
||||
|
||||
def preferencesTriggered(self):
|
||||
self.preferences_dialog.load()
|
||||
result = self.preferences_dialog.exec()
|
||||
@@ -151,42 +150,42 @@ class DupeGuru(QObject):
|
||||
self.prefs.save()
|
||||
self._update_options()
|
||||
self.prefsChanged.emit(self.prefs)
|
||||
|
||||
|
||||
def quitTriggered(self):
|
||||
self.directories_dialog.close()
|
||||
|
||||
|
||||
def showAboutBoxTriggered(self):
|
||||
self.about_box.show()
|
||||
|
||||
|
||||
def showHelpTriggered(self):
|
||||
base_path = platform.HELP_PATH
|
||||
url = QUrl.fromLocalFile(op.abspath(op.join(base_path, 'index.html')))
|
||||
QDesktopServices.openUrl(url)
|
||||
|
||||
|
||||
#--- model --> view
|
||||
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_message(self, msg):
|
||||
window = QApplication.activeWindow()
|
||||
QMessageBox.information(window, '', msg)
|
||||
|
||||
|
||||
def ask_yes_no(self, prompt):
|
||||
return self.confirm('', prompt)
|
||||
|
||||
|
||||
def show_results_window(self):
|
||||
self.showResultsWindow()
|
||||
|
||||
|
||||
def show_problem_dialog(self):
|
||||
self.problemDialog.show()
|
||||
|
||||
|
||||
def select_dest_folder(self, prompt):
|
||||
flags = QFileDialog.ShowDirsOnly
|
||||
return QFileDialog.getExistingDirectory(self.resultWindow, prompt, '', flags)
|
||||
|
||||
|
||||
def select_dest_file(self, prompt, extension):
|
||||
files = tr("{} file (*.{})").format(extension.upper(), extension)
|
||||
destination, chosen_filter = QFileDialog.getSaveFileName(self.resultWindow, prompt, '', files)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# cxfreeze has some problems detecting all dependencies.
|
||||
# This modules explicitly import those problematic modules.
|
||||
# flake8: noqa
|
||||
|
||||
import xml.etree.ElementPath
|
||||
import gzip
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
# Created By: Virgil Dupras
|
||||
# Created On: 2012-05-30
|
||||
# Copyright 2014 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
|
||||
#
|
||||
# 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 PyQt5.QtCore import Qt
|
||||
@@ -21,11 +21,11 @@ class DeletionOptions(QDialog):
|
||||
self.model = model
|
||||
self._setupUi()
|
||||
self.model.view = self
|
||||
|
||||
|
||||
self.linkCheckbox.stateChanged.connect(self.linkCheckboxChanged)
|
||||
self.buttonBox.accepted.connect(self.accept)
|
||||
self.buttonBox.rejected.connect(self.reject)
|
||||
|
||||
|
||||
def _setupUi(self):
|
||||
self.setWindowTitle(tr("Deletion Options"))
|
||||
self.resize(400, 270)
|
||||
@@ -34,8 +34,10 @@ class DeletionOptions(QDialog):
|
||||
self.verticalLayout.addWidget(self.msgLabel)
|
||||
self.linkCheckbox = QCheckBox(tr("Link deleted files"))
|
||||
self.verticalLayout.addWidget(self.linkCheckbox)
|
||||
text = tr("After having deleted a duplicate, place a link targeting the reference file "
|
||||
"to replace the deleted file.")
|
||||
text = tr(
|
||||
"After having deleted a duplicate, place a link targeting the reference file "
|
||||
"to replace the deleted file."
|
||||
)
|
||||
self.linkMessageLabel = QLabel(text)
|
||||
self.linkMessageLabel.setWordWrap(True)
|
||||
self.verticalLayout.addWidget(self.linkMessageLabel)
|
||||
@@ -46,8 +48,10 @@ class DeletionOptions(QDialog):
|
||||
self.linkCheckbox.setText(self.linkCheckbox.text() + tr(" (unsupported)"))
|
||||
self.directCheckbox = QCheckBox(tr("Directly delete files"))
|
||||
self.verticalLayout.addWidget(self.directCheckbox)
|
||||
text = tr("Instead of sending files to trash, delete them directly. This option is usually "
|
||||
"used as a workaround when the normal deletion method doesn't work.")
|
||||
text = tr(
|
||||
"Instead of sending files to trash, delete them directly. This option is usually "
|
||||
"used as a workaround when the normal deletion method doesn't work."
|
||||
)
|
||||
self.directMessageLabel = QLabel(text)
|
||||
self.directMessageLabel.setWordWrap(True)
|
||||
self.verticalLayout.addWidget(self.directMessageLabel)
|
||||
@@ -55,15 +59,15 @@ class DeletionOptions(QDialog):
|
||||
self.buttonBox.addButton(tr("Proceed"), QDialogButtonBox.AcceptRole)
|
||||
self.buttonBox.addButton(tr("Cancel"), QDialogButtonBox.RejectRole)
|
||||
self.verticalLayout.addWidget(self.buttonBox)
|
||||
|
||||
|
||||
#--- Signals
|
||||
def linkCheckboxChanged(self, changed: int):
|
||||
self.model.link_deleted = bool(changed)
|
||||
|
||||
|
||||
#--- model --> view
|
||||
def update_msg(self, msg: str):
|
||||
self.msgLabel.setText(msg)
|
||||
|
||||
|
||||
def show(self):
|
||||
self.linkCheckbox.setChecked(self.model.link_deleted)
|
||||
self.linkTypeRadio.selected_index = 1 if self.model.use_hardlinks else 0
|
||||
@@ -73,7 +77,7 @@ class DeletionOptions(QDialog):
|
||||
self.model.use_hardlinks = self.linkTypeRadio.selected_index == 1
|
||||
self.model.direct = self.directCheckbox.isChecked()
|
||||
return result == QDialog.Accepted
|
||||
|
||||
|
||||
def set_hardlink_option_enabled(self, is_enabled: bool):
|
||||
self.linkTypeRadio.setEnabled(is_enabled)
|
||||
|
||||
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
# Created By: Virgil Dupras
|
||||
# Created On: 2009-04-25
|
||||
# Copyright 2014 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
|
||||
#
|
||||
# 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 PyQt5.QtCore import QRect
|
||||
from PyQt5.QtWidgets import (QWidget, QFileDialog, QHeaderView, QVBoxLayout, QHBoxLayout, QTreeView,
|
||||
from PyQt5.QtWidgets import (
|
||||
QWidget, QFileDialog, QHeaderView, QVBoxLayout, QHBoxLayout, QTreeView,
|
||||
QAbstractItemView, QSpacerItem, QSizePolicy, QPushButton, QMainWindow, QMenuBar, QMenu, QLabel,
|
||||
QApplication)
|
||||
QApplication
|
||||
)
|
||||
from PyQt5.QtGui import QPixmap, QIcon
|
||||
|
||||
from hscommon.trans import trget
|
||||
@@ -39,7 +41,7 @@ class DirectoriesDialog(QMainWindow):
|
||||
self._updateRemoveButton()
|
||||
self._updateLoadResultsButton()
|
||||
self._setupBindings()
|
||||
|
||||
|
||||
def _setupBindings(self):
|
||||
self.scanButton.clicked.connect(self.scanButtonClicked)
|
||||
self.loadResultsButton.clicked.connect(self.actionLoadResults.trigger)
|
||||
@@ -51,7 +53,7 @@ class DirectoriesDialog(QMainWindow):
|
||||
self.recentFolders.mustOpenItem.connect(self.app.model.add_directory)
|
||||
self.directoriesModel.foldersAdded.connect(self.directoriesModelAddedFolders)
|
||||
self.app.willSavePrefs.connect(self.appWillSavePrefs)
|
||||
|
||||
|
||||
def _setupActions(self):
|
||||
# (name, shortcut, icon, desc, func)
|
||||
ACTIONS = [
|
||||
@@ -60,7 +62,7 @@ class DirectoriesDialog(QMainWindow):
|
||||
('actionAddFolder', '', '', tr("Add Folder..."), self.addFolderTriggered),
|
||||
]
|
||||
createActions(ACTIONS, self)
|
||||
|
||||
|
||||
def _setupMenu(self):
|
||||
self.menubar = QMenuBar(self)
|
||||
self.menubar.setGeometry(QRect(0, 0, 42, 22))
|
||||
@@ -73,7 +75,7 @@ class DirectoriesDialog(QMainWindow):
|
||||
self.menuLoadRecent = QMenu(self.menuFile)
|
||||
self.menuLoadRecent.setTitle(tr("Load Recent Results"))
|
||||
self.setMenuBar(self.menubar)
|
||||
|
||||
|
||||
self.menuFile.addAction(self.actionLoadResults)
|
||||
self.menuFile.addAction(self.menuLoadRecent.menuAction())
|
||||
self.menuFile.addSeparator()
|
||||
@@ -84,21 +86,21 @@ class DirectoriesDialog(QMainWindow):
|
||||
self.menuHelp.addAction(self.app.actionShowHelp)
|
||||
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())
|
||||
|
||||
|
||||
# Recent folders menu
|
||||
self.menuRecentFolders = QMenu()
|
||||
self.menuRecentFolders.addAction(self.actionAddFolder)
|
||||
self.menuRecentFolders.addSeparator()
|
||||
|
||||
|
||||
# Recent results menu
|
||||
self.menuRecentResults = QMenu()
|
||||
self.menuRecentResults.addAction(self.actionLoadResults)
|
||||
self.menuRecentResults.addSeparator()
|
||||
|
||||
|
||||
def _setupUi(self):
|
||||
self.setWindowTitle(self.app.NAME)
|
||||
self.resize(420, 338)
|
||||
@@ -110,8 +112,8 @@ class DirectoriesDialog(QMainWindow):
|
||||
self.treeView.setSelectionMode(QAbstractItemView.ExtendedSelection)
|
||||
self.treeView.setSelectionBehavior(QAbstractItemView.SelectRows)
|
||||
self.treeView.setAcceptDrops(True)
|
||||
triggers = 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)
|
||||
@@ -136,41 +138,41 @@ class DirectoriesDialog(QMainWindow):
|
||||
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)
|
||||
else:
|
||||
moveToScreenCenter(self)
|
||||
|
||||
|
||||
def _setupColumns(self):
|
||||
header = self.treeView.header()
|
||||
header.setStretchLastSection(False)
|
||||
header.setSectionResizeMode(0, QHeaderView.Stretch)
|
||||
header.setSectionResizeMode(1, QHeaderView.Fixed)
|
||||
header.resizeSection(1, 100)
|
||||
|
||||
|
||||
def _updateAddButton(self):
|
||||
if self.recentFolders.isEmpty():
|
||||
self.addFolderButton.setMenu(None)
|
||||
else:
|
||||
self.addFolderButton.setMenu(self.menuRecentFolders)
|
||||
|
||||
|
||||
def _updateRemoveButton(self):
|
||||
indexes = self.treeView.selectedIndexes()
|
||||
if not indexes:
|
||||
self.removeFolderButton.setEnabled(False)
|
||||
return
|
||||
self.removeFolderButton.setEnabled(True)
|
||||
|
||||
|
||||
def _updateLoadResultsButton(self):
|
||||
if self.app.recentResults.isEmpty():
|
||||
self.loadResultsButton.setMenu(None)
|
||||
else:
|
||||
self.loadResultsButton.setMenu(self.menuRecentResults)
|
||||
|
||||
|
||||
#--- QWidget overrides
|
||||
def closeEvent(self, event):
|
||||
event.accept()
|
||||
@@ -181,7 +183,7 @@ class DirectoriesDialog(QMainWindow):
|
||||
event.ignore()
|
||||
if event.isAccepted():
|
||||
QApplication.quit()
|
||||
|
||||
|
||||
#--- Events
|
||||
def addFolderTriggered(self):
|
||||
title = tr("Select a folder to add to the scanning list")
|
||||
@@ -192,14 +194,14 @@ class DirectoriesDialog(QMainWindow):
|
||||
self.lastAddedFolder = dirpath
|
||||
self.app.model.add_directory(dirpath)
|
||||
self.recentFolders.insertItem(dirpath)
|
||||
|
||||
|
||||
def appWillSavePrefs(self):
|
||||
self.app.prefs.directoriesWindowRect = self.geometry()
|
||||
|
||||
|
||||
def directoriesModelAddedFolders(self, folders):
|
||||
for folder in folders:
|
||||
self.recentFolders.insertItem(folder)
|
||||
|
||||
|
||||
def loadResultsTriggered(self):
|
||||
title = tr("Select a results file to load")
|
||||
files = ';;'.join([tr("dupeGuru Results (*.dupeguru)"), tr("All Files (*.*)")])
|
||||
@@ -207,10 +209,10 @@ class DirectoriesDialog(QMainWindow):
|
||||
if destination:
|
||||
self.app.model.load_from(destination)
|
||||
self.app.recentResults.insertItem(destination)
|
||||
|
||||
|
||||
def removeFolderButtonClicked(self):
|
||||
self.directoriesModel.model.remove_selected()
|
||||
|
||||
|
||||
def scanButtonClicked(self):
|
||||
if self.app.model.results.is_modified:
|
||||
title = tr("Start a new scan")
|
||||
@@ -218,17 +220,17 @@ class DirectoriesDialog(QMainWindow):
|
||||
if not self.app.confirm(title, msg):
|
||||
return
|
||||
self.app.model.start_scanning()
|
||||
|
||||
|
||||
def selectionChanged(self, selected, deselected):
|
||||
self._updateRemoveButton()
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
from . import dg_rc
|
||||
from . import dg_rc # NOQA
|
||||
from ..testapp import TestApp
|
||||
app = QApplication([])
|
||||
dgapp = TestApp()
|
||||
dialog = DirectoriesDialog(None, dgapp)
|
||||
dialog.show()
|
||||
sys.exit(app.exec_())
|
||||
sys.exit(app.exec_())
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
# Created By: Virgil Dupras
|
||||
# Created On: 2009-04-25
|
||||
# Copyright 2014 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
|
||||
#
|
||||
# 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
|
||||
|
||||
import urllib.parse
|
||||
|
||||
from PyQt5.QtCore import pyqtSignal, Qt, QRect, QUrl, QModelIndex, QItemSelection
|
||||
from PyQt5.QtWidgets import (QComboBox, QStyledItemDelegate, QStyle, QStyleOptionComboBox,
|
||||
QStyleOptionViewItem, QApplication)
|
||||
from PyQt5.QtWidgets import (
|
||||
QComboBox, QStyledItemDelegate, QStyle, QStyleOptionComboBox,
|
||||
QStyleOptionViewItem, QApplication
|
||||
)
|
||||
from PyQt5.QtGui import QBrush
|
||||
|
||||
from hscommon.trans import trget
|
||||
@@ -23,10 +25,10 @@ STATES = [tr("Normal"), tr("Reference"), tr("Excluded")]
|
||||
|
||||
class DirectoriesDelegate(QStyledItemDelegate):
|
||||
def createEditor(self, parent, option, index):
|
||||
editor = QComboBox(parent);
|
||||
editor = QComboBox(parent)
|
||||
editor.addItems(STATES)
|
||||
return editor
|
||||
|
||||
|
||||
def paint(self, painter, option, index):
|
||||
self.initStyleOption(option, index)
|
||||
# No idea why, but this cast is required if we want to have access to the V4 valuess
|
||||
@@ -44,19 +46,19 @@ class DirectoriesDelegate(QStyledItemDelegate):
|
||||
painter.drawText(rect, Qt.AlignLeft, option.text)
|
||||
else:
|
||||
super().paint(painter, option, index)
|
||||
|
||||
|
||||
def setEditorData(self, editor, index):
|
||||
value = index.model().data(index, Qt.EditRole)
|
||||
editor.setCurrentIndex(value);
|
||||
editor.setCurrentIndex(value)
|
||||
editor.showPopup()
|
||||
|
||||
|
||||
def setModelData(self, editor, model, index):
|
||||
value = editor.currentIndex()
|
||||
model.setData(index, value, Qt.EditRole)
|
||||
|
||||
|
||||
def updateEditorGeometry(self, editor, option, index):
|
||||
editor.setGeometry(option.rect)
|
||||
|
||||
|
||||
|
||||
class DirectoriesModel(TreeModel):
|
||||
def __init__(self, model, view, **kwargs):
|
||||
@@ -65,18 +67,18 @@ class DirectoriesModel(TreeModel):
|
||||
self.model.view = self
|
||||
self.view = view
|
||||
self.view.setModel(self)
|
||||
|
||||
|
||||
self.view.selectionModel().selectionChanged[(QItemSelection, QItemSelection)].connect(self.selectionChanged)
|
||||
|
||||
|
||||
def _createNode(self, ref, row):
|
||||
return RefNode(self, None, ref, row)
|
||||
|
||||
|
||||
def _getChildren(self):
|
||||
return list(self.model)
|
||||
|
||||
|
||||
def columnCount(self, parent=QModelIndex()):
|
||||
return 2
|
||||
|
||||
|
||||
def data(self, index, role):
|
||||
if not index.isValid():
|
||||
return None
|
||||
@@ -96,7 +98,7 @@ class DirectoriesModel(TreeModel):
|
||||
elif state == 2:
|
||||
return QBrush(Qt.red)
|
||||
return None
|
||||
|
||||
|
||||
def dropMimeData(self, mimeData, action, row, column, parentIndex):
|
||||
# the data in mimeData is urlencoded **in utf-8**!!! What we do is to decode, the mime data
|
||||
# with 'ascii', which works since it's urlencoded. Then, we pass that to urllib.
|
||||
@@ -111,7 +113,7 @@ class DirectoriesModel(TreeModel):
|
||||
self.foldersAdded.emit(paths)
|
||||
self.reset()
|
||||
return True
|
||||
|
||||
|
||||
def flags(self, index):
|
||||
if not index.isValid():
|
||||
return Qt.ItemIsEnabled | Qt.ItemIsDropEnabled
|
||||
@@ -119,16 +121,16 @@ class DirectoriesModel(TreeModel):
|
||||
if index.column() == 1:
|
||||
result |= Qt.ItemIsEditable
|
||||
return result
|
||||
|
||||
|
||||
def headerData(self, section, orientation, role):
|
||||
if orientation == Qt.Horizontal:
|
||||
if role == Qt.DisplayRole and section < len(HEADERS):
|
||||
return HEADERS[section]
|
||||
return None
|
||||
|
||||
|
||||
def mimeTypes(self):
|
||||
return ['text/uri-list']
|
||||
|
||||
|
||||
def setData(self, index, value, role):
|
||||
if not index.isValid() or role != Qt.EditRole or index.column() != 1:
|
||||
return False
|
||||
@@ -136,24 +138,24 @@ class DirectoriesModel(TreeModel):
|
||||
ref = node.ref
|
||||
ref.state = value
|
||||
return True
|
||||
|
||||
|
||||
def supportedDropActions(self):
|
||||
# Normally, the correct action should be ActionLink, but the drop doesn't work. It doesn't
|
||||
# work with ActionMove either. So screw that, and accept anything.
|
||||
return Qt.ActionMask
|
||||
|
||||
|
||||
#--- Events
|
||||
def selectionChanged(self, selected, deselected):
|
||||
newNodes = [modelIndex.internalPointer().ref for modelIndex in self.view.selectionModel().selectedRows()]
|
||||
self.model.selected_nodes = newNodes
|
||||
|
||||
|
||||
#--- Signals
|
||||
foldersAdded = pyqtSignal(list)
|
||||
|
||||
|
||||
#--- model --> view
|
||||
def refresh(self):
|
||||
self.reset()
|
||||
|
||||
|
||||
def refresh_states(self):
|
||||
self.refreshData()
|
||||
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
# Created By: Virgil Dupras
|
||||
# Created On: 2012-03-13
|
||||
# Copyright 2014 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
|
||||
#
|
||||
# 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 PyQt5.QtCore import Qt
|
||||
@@ -23,11 +23,11 @@ class IgnoreListDialog(QDialog):
|
||||
self.model = model
|
||||
self.model.view = self
|
||||
self.table = IgnoreListTable(self.model.ignore_list_table, view=self.tableView)
|
||||
|
||||
|
||||
self.removeSelectedButton.clicked.connect(self.model.remove_selected)
|
||||
self.clearButton.clicked.connect(self.model.clear)
|
||||
self.closeButton.clicked.connect(self.accept)
|
||||
|
||||
|
||||
def _setupUi(self):
|
||||
self.setWindowTitle(tr("Ignore List"))
|
||||
self.resize(540, 330)
|
||||
@@ -45,10 +45,14 @@ class IgnoreListDialog(QDialog):
|
||||
self.removeSelectedButton = QPushButton(tr("Remove Selected"))
|
||||
self.clearButton = QPushButton(tr("Clear"))
|
||||
self.closeButton = QPushButton(tr("Close"))
|
||||
self.verticalLayout.addLayout(horizontalWrap([self.removeSelectedButton, self.clearButton,
|
||||
None, self.closeButton]))
|
||||
|
||||
self.verticalLayout.addLayout(
|
||||
horizontalWrap([
|
||||
self.removeSelectedButton, self.clearButton,
|
||||
None, self.closeButton
|
||||
])
|
||||
)
|
||||
|
||||
#--- model --> view
|
||||
def show(self):
|
||||
super().show()
|
||||
|
||||
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
# Created By: Virgil Dupras
|
||||
# Created On: 2011-01-21
|
||||
# Copyright 2014 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
|
||||
#
|
||||
# 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 PyQt5.QtCore import Qt, QSize
|
||||
from PyQt5.QtWidgets import (QDialog, QDialogButtonBox, QVBoxLayout, QHBoxLayout, QLabel, QComboBox,
|
||||
QSlider, QSizePolicy, QSpacerItem, QCheckBox, QLineEdit, QMessageBox, QSpinBox)
|
||||
from PyQt5.QtWidgets import (
|
||||
QDialog, QDialogButtonBox, QVBoxLayout, QHBoxLayout, QLabel, QComboBox,
|
||||
QSlider, QSizePolicy, QSpacerItem, QCheckBox, QLineEdit, QMessageBox, QSpinBox
|
||||
)
|
||||
|
||||
from hscommon.plat import ISOSX, ISLINUX
|
||||
from hscommon.trans import trget
|
||||
@@ -25,12 +27,12 @@ class PreferencesDialogBase(QDialog):
|
||||
super().__init__(parent, flags, **kwargs)
|
||||
self.app = app
|
||||
self._setupUi()
|
||||
|
||||
|
||||
self.filterHardnessSlider.valueChanged['int'].connect(self.filterHardnessLabel.setNum)
|
||||
self.buttonBox.clicked.connect(self.buttonClicked)
|
||||
self.buttonBox.accepted.connect(self.accept)
|
||||
self.buttonBox.rejected.connect(self.reject)
|
||||
|
||||
|
||||
def _setupScanTypeBox(self, labels):
|
||||
self.scanTypeHLayout = QHBoxLayout()
|
||||
self.scanTypeLabel = QLabel(self)
|
||||
@@ -43,7 +45,7 @@ class PreferencesDialogBase(QDialog):
|
||||
self.scanTypeComboBox.addItem(label)
|
||||
self.scanTypeHLayout.addWidget(self.scanTypeComboBox)
|
||||
self.widgetsVLayout.addLayout(self.scanTypeHLayout)
|
||||
|
||||
|
||||
def _setupFilterHardnessBox(self):
|
||||
self.filterHardnessHLayout = QHBoxLayout()
|
||||
self.filterHardnessLabel = QLabel(self)
|
||||
@@ -82,7 +84,7 @@ class PreferencesDialogBase(QDialog):
|
||||
self.filterHardnessHLayoutSub2.addWidget(self.fewerResultsLabel)
|
||||
self.filterHardnessVLayout.addLayout(self.filterHardnessHLayoutSub2)
|
||||
self.filterHardnessHLayout.addLayout(self.filterHardnessVLayout)
|
||||
|
||||
|
||||
def _setupBottomPart(self):
|
||||
# The bottom part of the pref panel is always the same in all editions.
|
||||
self.fontSizeLabel = QLabel(tr("Font size:"))
|
||||
@@ -107,18 +109,18 @@ class PreferencesDialogBase(QDialog):
|
||||
self.widgetsVLayout.addWidget(self.customCommandLabel)
|
||||
self.customCommandEdit = QLineEdit(self)
|
||||
self.widgetsVLayout.addWidget(self.customCommandEdit)
|
||||
|
||||
|
||||
def _setupAddCheckbox(self, name, label, parent=None):
|
||||
if parent is None:
|
||||
parent = self
|
||||
cb = QCheckBox(parent)
|
||||
cb.setText(label)
|
||||
setattr(self, name, cb)
|
||||
|
||||
|
||||
def _setupPreferenceWidgets(self):
|
||||
# Edition-specific
|
||||
pass
|
||||
|
||||
|
||||
def _setupUi(self):
|
||||
self.setWindowTitle(tr("Preferences"))
|
||||
self.resize(304, 263)
|
||||
@@ -134,15 +136,15 @@ class PreferencesDialogBase(QDialog):
|
||||
if (not ISOSX) and (not ISLINUX):
|
||||
self.mainVLayout.removeWidget(self.ignoreHardlinkMatches)
|
||||
self.ignoreHardlinkMatches.setHidden(True)
|
||||
|
||||
|
||||
def _load(self, prefs, setchecked):
|
||||
# Edition-specific
|
||||
pass
|
||||
|
||||
|
||||
def _save(self, prefs, ischecked):
|
||||
# Edition-specific
|
||||
pass
|
||||
|
||||
|
||||
def load(self, prefs=None):
|
||||
if prefs is None:
|
||||
prefs = self.app.prefs
|
||||
@@ -163,7 +165,7 @@ class PreferencesDialogBase(QDialog):
|
||||
langindex = 0
|
||||
self.languageComboBox.setCurrentIndex(langindex)
|
||||
self._load(prefs, setchecked)
|
||||
|
||||
|
||||
def save(self):
|
||||
prefs = self.app.prefs
|
||||
prefs.filter_hardness = self.filterHardnessSlider.value()
|
||||
@@ -184,9 +186,10 @@ class PreferencesDialogBase(QDialog):
|
||||
QMessageBox.information(self, "", tr("dupeGuru has to restart for language changes to take effect."))
|
||||
self.app.prefs.language = lang
|
||||
self._save(prefs, ischecked)
|
||||
|
||||
|
||||
#--- Events
|
||||
def buttonClicked(self, button):
|
||||
role = self.buttonBox.buttonRole(button)
|
||||
if role == QDialogButtonBox.ResetRole:
|
||||
self.resetToDefaults()
|
||||
self.resetToDefaults()
|
||||
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
# Created By: Virgil Dupras
|
||||
# Created On: 2011-09-06
|
||||
# Copyright 2014 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
|
||||
#
|
||||
# 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 PyQt5.QtCore import Qt, QMimeData, QByteArray
|
||||
from PyQt5.QtWidgets import (QDialog, QVBoxLayout, QHBoxLayout, QPushButton, QComboBox, QListView,
|
||||
QDialogButtonBox, QAbstractItemView, QLabel, QStyle, QSplitter, QWidget, QSizePolicy)
|
||||
from PyQt5.QtWidgets import (
|
||||
QDialog, QVBoxLayout, QHBoxLayout, QPushButton, QComboBox, QListView,
|
||||
QDialogButtonBox, QAbstractItemView, QLabel, QStyle, QSplitter, QWidget, QSizePolicy
|
||||
)
|
||||
|
||||
from hscommon.trans import trget
|
||||
from qtlib.selectable_list import ComboboxModel, ListviewModel
|
||||
@@ -24,7 +26,7 @@ class PrioritizationList(ListviewModel):
|
||||
if not index.isValid():
|
||||
return Qt.ItemIsEnabled | Qt.ItemIsDropEnabled
|
||||
return Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsDragEnabled
|
||||
|
||||
|
||||
#--- Drag & Drop
|
||||
def dropMimeData(self, mimeData, action, row, column, parentIndex):
|
||||
if not mimeData.hasFormat(MIME_INDEXES):
|
||||
@@ -37,17 +39,17 @@ class PrioritizationList(ListviewModel):
|
||||
indexes = list(map(int, strMimeData.split(',')))
|
||||
self.model.move_indexes(indexes, row)
|
||||
return True
|
||||
|
||||
|
||||
def mimeData(self, indexes):
|
||||
rows = {str(index.row()) for index in indexes}
|
||||
data = ','.join(rows)
|
||||
mimeData = QMimeData()
|
||||
mimeData.setData(MIME_INDEXES, QByteArray(data.encode()))
|
||||
return mimeData
|
||||
|
||||
|
||||
def mimeTypes(self):
|
||||
return [MIME_INDEXES]
|
||||
|
||||
|
||||
def supportedDropActions(self):
|
||||
return Qt.MoveAction
|
||||
|
||||
@@ -59,9 +61,11 @@ class PrioritizeDialog(QDialog):
|
||||
self.model = PrioritizeDialogModel(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)
|
||||
self.prioritizationList = PrioritizationList(
|
||||
model=self.model.prioritization_list, view=self.prioritizationListView
|
||||
)
|
||||
self.model.view = self
|
||||
|
||||
|
||||
self.addCriteriaButton.clicked.connect(self.model.add_selected)
|
||||
self.removeCriteriaButton.clicked.connect(self.model.remove_selected)
|
||||
self.buttonBox.accepted.connect(self.accept)
|
||||
@@ -70,11 +74,13 @@ class PrioritizeDialog(QDialog):
|
||||
def _setupUi(self):
|
||||
self.setWindowTitle(tr("Re-Prioritize duplicates"))
|
||||
self.resize(700, 400)
|
||||
|
||||
|
||||
#widgets
|
||||
msg = tr("Add criteria to the right box and click OK to send the dupes that correspond the "
|
||||
msg = tr(
|
||||
"Add criteria to the right box and click OK to send the dupes that correspond the "
|
||||
"best to these criteria to their respective group's "
|
||||
"reference position. Read the help file for more information.")
|
||||
"reference position. Read the help file for more information."
|
||||
)
|
||||
self.promptLabel = QLabel(msg)
|
||||
self.promptLabel.setWordWrap(True)
|
||||
self.categoryCombobox = QComboBox()
|
||||
@@ -88,7 +94,7 @@ class PrioritizeDialog(QDialog):
|
||||
self.prioritizationListView.setSelectionBehavior(QAbstractItemView.SelectRows)
|
||||
self.buttonBox = QDialogButtonBox()
|
||||
self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel|QDialogButtonBox.Ok)
|
||||
|
||||
|
||||
# layout
|
||||
self.mainLayout = QVBoxLayout(self)
|
||||
self.mainLayout.addWidget(self.promptLabel)
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
# Created By: Virgil Dupras
|
||||
# Created On: 2010-04-12
|
||||
# Copyright 2014 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
|
||||
#
|
||||
# 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 PyQt5.QtCore import Qt
|
||||
from PyQt5.QtWidgets import (QDialog, QVBoxLayout, QHBoxLayout, QPushButton, QSpacerItem, QSizePolicy,
|
||||
QLabel, QTableView, QAbstractItemView, QApplication)
|
||||
from PyQt5.QtWidgets import (
|
||||
QDialog, QVBoxLayout, QHBoxLayout, QPushButton, QSpacerItem, QSizePolicy,
|
||||
QLabel, QTableView, QAbstractItemView, QApplication
|
||||
)
|
||||
|
||||
from hscommon.trans import trget
|
||||
from .problem_table import ProblemTable
|
||||
@@ -23,18 +25,20 @@ class ProblemDialog(QDialog):
|
||||
self.model = model
|
||||
self.model.view = self
|
||||
self.table = ProblemTable(self.model.problem_table, view=self.tableView)
|
||||
|
||||
|
||||
self.revealButton.clicked.connect(self.model.reveal_selected_dupe)
|
||||
self.closeButton.clicked.connect(self.accept)
|
||||
|
||||
|
||||
def _setupUi(self):
|
||||
self.setWindowTitle(tr("Problems!"))
|
||||
self.resize(413, 323)
|
||||
self.verticalLayout = QVBoxLayout(self)
|
||||
self.label = QLabel(self)
|
||||
msg = tr("There were problems processing some (or all) of the files. The cause of "
|
||||
msg = tr(
|
||||
"There were problems processing some (or all) of the files. The cause of "
|
||||
"these problems are described in the table below. Those files were not "
|
||||
"removed from your results.")
|
||||
"removed from your results."
|
||||
)
|
||||
self.label.setText(msg)
|
||||
self.label.setWordWrap(True)
|
||||
self.verticalLayout.addWidget(self.label)
|
||||
@@ -58,7 +62,7 @@ class ProblemDialog(QDialog):
|
||||
self.closeButton.setDefault(True)
|
||||
self.horizontalLayout.addWidget(self.closeButton)
|
||||
self.verticalLayout.addLayout(self.horizontalLayout)
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
@@ -67,4 +71,4 @@ if __name__ == '__main__':
|
||||
dgapp = TestApp()
|
||||
dialog = ProblemDialog(None, dgapp)
|
||||
dialog.show()
|
||||
sys.exit(app.exec_())
|
||||
sys.exit(app.exec_())
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
# Created By: Virgil Dupras
|
||||
# Created On: 2009-04-25
|
||||
# Copyright 2014 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
|
||||
#
|
||||
# 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 PyQt5.QtCore import Qt, QRect
|
||||
from PyQt5.QtWidgets import (QMainWindow, QMenu, QLabel, QFileDialog, QMenuBar, QWidget,
|
||||
QVBoxLayout, QAbstractItemView, QStatusBar, QDialog, QPushButton, QCheckBox)
|
||||
from PyQt5.QtWidgets import (
|
||||
QMainWindow, QMenu, QLabel, QFileDialog, QMenuBar, QWidget,
|
||||
QVBoxLayout, QAbstractItemView, QStatusBar, QDialog, QPushButton, QCheckBox
|
||||
)
|
||||
|
||||
from hscommon.trans import trget
|
||||
from qtlib.util import moveToScreenCenter, horizontalWrap, createActions
|
||||
@@ -28,7 +30,7 @@ class ResultWindow(QMainWindow):
|
||||
self.resultsModel = app.RESULT_MODEL_CLASS(self.app, self.resultsView)
|
||||
self.stats = StatsLabel(app.model.stats_label, self.statusLabel)
|
||||
self._update_column_actions_status()
|
||||
|
||||
|
||||
self.menuColumns.triggered.connect(self.columnToggled)
|
||||
self.resultsView.doubleClicked.connect(self.resultsDoubleClicked)
|
||||
self.resultsView.spacePressed.connect(self.resultsSpacePressed)
|
||||
@@ -37,7 +39,7 @@ class ResultWindow(QMainWindow):
|
||||
self.deltaValuesCheckBox.stateChanged.connect(self.deltaTriggered)
|
||||
self.searchEdit.searchChanged.connect(self.searchChanged)
|
||||
self.app.willSavePrefs.connect(self.appWillSavePrefs)
|
||||
|
||||
|
||||
def _setupActions(self):
|
||||
# (name, shortcut, icon, desc, func)
|
||||
ACTIONS = [
|
||||
@@ -50,11 +52,23 @@ class ResultWindow(QMainWindow):
|
||||
('actionCopyMarked', 'Ctrl+Shift+M', '', tr("Copy Marked to..."), self.copyTriggered),
|
||||
('actionRemoveMarked', 'Ctrl+R', '', tr("Remove Marked from Results"), self.removeMarkedTriggered),
|
||||
('actionReprioritize', '', '', tr("Re-Prioritize Results..."), self.reprioritizeTriggered),
|
||||
('actionRemoveSelected', 'Ctrl+Del', '', tr("Remove Selected from Results"), self.removeSelectedTriggered),
|
||||
('actionIgnoreSelected', 'Ctrl+Shift+Del', '', tr("Add Selected to Ignore List"), self.addToIgnoreListTriggered),
|
||||
('actionMakeSelectedReference', 'Ctrl+Space', '', tr("Make Selected into Reference"), self.app.model.make_selected_reference),
|
||||
(
|
||||
'actionRemoveSelected', 'Ctrl+Del', '',
|
||||
tr("Remove Selected from Results"), self.removeSelectedTriggered
|
||||
),
|
||||
(
|
||||
'actionIgnoreSelected', 'Ctrl+Shift+Del', '',
|
||||
tr("Add Selected to Ignore List"), self.addToIgnoreListTriggered
|
||||
),
|
||||
(
|
||||
'actionMakeSelectedReference', 'Ctrl+Space', '',
|
||||
tr("Make Selected into Reference"), self.app.model.make_selected_reference
|
||||
),
|
||||
('actionOpenSelected', 'Ctrl+O', '', tr("Open Selected with Default Application"), self.openTriggered),
|
||||
('actionRevealSelected', 'Ctrl+Shift+O', '', tr("Open Containing Folder of Selected"), self.revealTriggered),
|
||||
(
|
||||
'actionRevealSelected', 'Ctrl+Shift+O', '',
|
||||
tr("Open Containing Folder of Selected"), self.revealTriggered
|
||||
),
|
||||
('actionRenameSelected', 'F2', '', tr("Rename Selected"), self.renameTriggered),
|
||||
('actionMarkAll', 'Ctrl+A', '', tr("Mark All"), self.markAllTriggered),
|
||||
('actionMarkNone', 'Ctrl+Shift+A', '', tr("Mark None"), self.markNoneTriggered),
|
||||
@@ -68,7 +82,7 @@ class ResultWindow(QMainWindow):
|
||||
createActions(ACTIONS, self)
|
||||
self.actionDelta.setCheckable(True)
|
||||
self.actionPowerMarker.setCheckable(True)
|
||||
|
||||
|
||||
def _setupMenu(self):
|
||||
self.menubar = QMenuBar()
|
||||
self.menubar.setGeometry(QRect(0, 0, 630, 22))
|
||||
@@ -85,7 +99,7 @@ class ResultWindow(QMainWindow):
|
||||
self.menuHelp = QMenu(self.menubar)
|
||||
self.menuHelp.setTitle(tr("Help"))
|
||||
self.setMenuBar(self.menubar)
|
||||
|
||||
|
||||
self.menuActions.addAction(self.actionDeleteMarked)
|
||||
self.menuActions.addAction(self.actionMoveMarked)
|
||||
self.menuActions.addAction(self.actionCopyMarked)
|
||||
@@ -118,14 +132,14 @@ class ResultWindow(QMainWindow):
|
||||
self.menuFile.addAction(self.actionExportToCSV)
|
||||
self.menuFile.addSeparator()
|
||||
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.menuView.menuAction())
|
||||
self.menubar.addAction(self.menuHelp.menuAction())
|
||||
|
||||
|
||||
# Columns menu
|
||||
menu = self.menuColumns
|
||||
self._column_actions = []
|
||||
@@ -138,7 +152,7 @@ class ResultWindow(QMainWindow):
|
||||
menu.addSeparator()
|
||||
action = menu.addAction(tr("Reset to Defaults"))
|
||||
action.item_index = -1
|
||||
|
||||
|
||||
# Action menu
|
||||
actionMenu = QMenu(tr("Actions"), self.menubar)
|
||||
actionMenu.addAction(self.actionDeleteMarked)
|
||||
@@ -156,7 +170,7 @@ class ResultWindow(QMainWindow):
|
||||
actionMenu.addAction(self.actionRenameSelected)
|
||||
self.actionActions.setMenu(actionMenu)
|
||||
self.actionsButton.setMenu(self.actionActions.menu())
|
||||
|
||||
|
||||
def _setupUi(self):
|
||||
self.setWindowTitle(tr("{} Results").format(self.app.NAME))
|
||||
self.resize(630, 514)
|
||||
@@ -170,8 +184,10 @@ class ResultWindow(QMainWindow):
|
||||
self.deltaValuesCheckBox = QCheckBox(tr("Delta Values"))
|
||||
self.searchEdit = SearchEdit()
|
||||
self.searchEdit.setMaximumWidth(300)
|
||||
self.horizontalLayout = horizontalWrap([self.actionsButton, self.detailsButton,
|
||||
self.dupesOnlyCheckBox, self.deltaValuesCheckBox, None, self.searchEdit, 8])
|
||||
self.horizontalLayout = horizontalWrap([
|
||||
self.actionsButton, self.detailsButton,
|
||||
self.dupesOnlyCheckBox, self.deltaValuesCheckBox, None, self.searchEdit, 8
|
||||
])
|
||||
self.horizontalLayout.setSpacing(8)
|
||||
self.verticalLayout.addLayout(self.horizontalLayout)
|
||||
self.resultsView = ResultsView(self.centralwidget)
|
||||
@@ -193,7 +209,7 @@ class ResultWindow(QMainWindow):
|
||||
self.setStatusBar(self.statusbar)
|
||||
self.statusLabel = QLabel(self)
|
||||
self.statusbar.addPermanentWidget(self.statusLabel, 1)
|
||||
|
||||
|
||||
if self.app.prefs.resultWindowIsMaximized:
|
||||
self.setWindowState(self.windowState() | Qt.WindowMaximized)
|
||||
else:
|
||||
@@ -201,85 +217,85 @@ class ResultWindow(QMainWindow):
|
||||
self.setGeometry(self.app.prefs.resultWindowRect)
|
||||
else:
|
||||
moveToScreenCenter(self)
|
||||
|
||||
|
||||
#--- Private
|
||||
def _update_column_actions_status(self):
|
||||
# Update menu checked state
|
||||
menu_items = self.app.model.result_table.columns.menu_items()
|
||||
for action, (display, visible) in zip(self._column_actions, menu_items):
|
||||
action.setChecked(visible)
|
||||
|
||||
|
||||
#--- Actions
|
||||
def actionsTriggered(self):
|
||||
self.actionsButton.showMenu()
|
||||
|
||||
|
||||
def addToIgnoreListTriggered(self):
|
||||
self.app.model.add_selected_to_ignore_list()
|
||||
|
||||
|
||||
def copyTriggered(self):
|
||||
self.app.model.copy_or_move_marked(True)
|
||||
|
||||
|
||||
def deleteTriggered(self):
|
||||
self.app.model.delete_marked()
|
||||
|
||||
|
||||
def deltaTriggered(self, state=None):
|
||||
# The sender can be either the action or the checkbox, but both have a isChecked() method.
|
||||
self.resultsModel.delta_values = self.sender().isChecked()
|
||||
self.actionDelta.setChecked(self.resultsModel.delta_values)
|
||||
self.deltaValuesCheckBox.setChecked(self.resultsModel.delta_values)
|
||||
|
||||
|
||||
def detailsTriggered(self):
|
||||
self.app.show_details()
|
||||
|
||||
|
||||
def markAllTriggered(self):
|
||||
self.app.model.mark_all()
|
||||
|
||||
|
||||
def markInvertTriggered(self):
|
||||
self.app.model.mark_invert()
|
||||
|
||||
|
||||
def markNoneTriggered(self):
|
||||
self.app.model.mark_none()
|
||||
|
||||
|
||||
def markSelectedTriggered(self):
|
||||
self.app.model.toggle_selected_mark_state()
|
||||
|
||||
|
||||
def moveTriggered(self):
|
||||
self.app.model.copy_or_move_marked(False)
|
||||
|
||||
|
||||
def openTriggered(self):
|
||||
self.app.model.open_selected()
|
||||
|
||||
|
||||
def powerMarkerTriggered(self, state=None):
|
||||
# see deltaTriggered
|
||||
self.resultsModel.power_marker = self.sender().isChecked()
|
||||
self.actionPowerMarker.setChecked(self.resultsModel.power_marker)
|
||||
self.dupesOnlyCheckBox.setChecked(self.resultsModel.power_marker)
|
||||
|
||||
|
||||
def preferencesTriggered(self):
|
||||
self.app.show_preferences()
|
||||
|
||||
|
||||
def removeMarkedTriggered(self):
|
||||
self.app.model.remove_marked()
|
||||
|
||||
|
||||
def removeSelectedTriggered(self):
|
||||
self.app.model.remove_selected()
|
||||
|
||||
|
||||
def renameTriggered(self):
|
||||
index = self.resultsView.selectionModel().currentIndex()
|
||||
# Our index is the current row, with column set to 0. Our filename column is 1 and that's
|
||||
# what we want.
|
||||
index = index.sibling(index.row(), 1)
|
||||
self.resultsView.edit(index)
|
||||
|
||||
|
||||
def reprioritizeTriggered(self):
|
||||
dlg = PrioritizeDialog(self, self.app)
|
||||
result = dlg.exec()
|
||||
if result == QDialog.Accepted:
|
||||
dlg.model.perform_reprioritization()
|
||||
|
||||
|
||||
def revealTriggered(self):
|
||||
self.app.model.reveal_selected()
|
||||
|
||||
|
||||
def saveResultsTriggered(self):
|
||||
title = tr("Select a file to save your results to")
|
||||
files = tr("dupeGuru Results (*.dupeguru)")
|
||||
@@ -289,13 +305,13 @@ class ResultWindow(QMainWindow):
|
||||
destination = '{}.dupeguru'.format(destination)
|
||||
self.app.model.save_as(destination)
|
||||
self.app.recentResults.insertItem(destination)
|
||||
|
||||
|
||||
#--- Events
|
||||
def appWillSavePrefs(self):
|
||||
prefs = self.app.prefs
|
||||
prefs.resultWindowIsMaximized = self.isMaximized()
|
||||
prefs.resultWindowRect = self.geometry()
|
||||
|
||||
|
||||
def columnToggled(self, action):
|
||||
index = action.item_index
|
||||
if index == -1:
|
||||
@@ -304,16 +320,16 @@ class ResultWindow(QMainWindow):
|
||||
else:
|
||||
visible = self.app.model.result_table.columns.toggle_menu_item(index)
|
||||
action.setChecked(visible)
|
||||
|
||||
|
||||
def contextMenuEvent(self, event):
|
||||
self.actionActions.menu().exec_(event.globalPos())
|
||||
|
||||
|
||||
def resultsDoubleClicked(self, modelIndex):
|
||||
self.app.model.open_selected()
|
||||
|
||||
|
||||
def resultsSpacePressed(self):
|
||||
self.app.model.toggle_selected_mark_state()
|
||||
|
||||
|
||||
def searchChanged(self):
|
||||
self.app.model.apply_filter(self.searchEdit.text())
|
||||
|
||||
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
# Created By: Virgil Dupras
|
||||
# Created On: 2009-04-29
|
||||
# Copyright 2014 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
|
||||
#
|
||||
# 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
|
||||
|
||||
import sys
|
||||
from PyQt5.QtCore import QSize
|
||||
from PyQt5.QtWidgets import (QVBoxLayout, QHBoxLayout, QLabel, QSizePolicy, QSpacerItem, QWidget,
|
||||
QApplication)
|
||||
from PyQt5.QtWidgets import (
|
||||
QVBoxLayout, QHBoxLayout, QLabel, QSizePolicy, QSpacerItem, QWidget,
|
||||
QApplication
|
||||
)
|
||||
|
||||
from hscommon.trans import trget
|
||||
from core.scanner import ScanType
|
||||
@@ -31,9 +33,9 @@ SCAN_TYPE_ORDER = [
|
||||
class PreferencesDialog(PreferencesDialogBase):
|
||||
def __init__(self, parent, app):
|
||||
PreferencesDialogBase.__init__(self, parent, app)
|
||||
|
||||
|
||||
self.scanTypeComboBox.currentIndexChanged[int].connect(self.scanTypeChanged)
|
||||
|
||||
|
||||
def _setupPreferenceWidgets(self):
|
||||
scanTypeLabels = [
|
||||
tr("Filename"),
|
||||
@@ -87,7 +89,7 @@ class PreferencesDialog(PreferencesDialogBase):
|
||||
self._setupAddCheckbox('debugModeBox', tr("Debug mode (restart required)"))
|
||||
self.widgetsVLayout.addWidget(self.debugModeBox)
|
||||
self._setupBottomPart()
|
||||
|
||||
|
||||
def _load(self, prefs, setchecked):
|
||||
scan_type_index = SCAN_TYPE_ORDER.index(prefs.scan_type)
|
||||
self.scanTypeComboBox.setCurrentIndex(scan_type_index)
|
||||
@@ -99,7 +101,7 @@ class PreferencesDialog(PreferencesDialogBase):
|
||||
setchecked(self.tagYearBox, prefs.scan_tag_year)
|
||||
setchecked(self.matchSimilarBox, prefs.match_similar)
|
||||
setchecked(self.wordWeightingBox, prefs.word_weighting)
|
||||
|
||||
|
||||
def _save(self, prefs, ischecked):
|
||||
prefs.scan_type = SCAN_TYPE_ORDER[self.scanTypeComboBox.currentIndex()]
|
||||
prefs.scan_tag_track = ischecked(self.tagTrackBox)
|
||||
@@ -110,15 +112,17 @@ class PreferencesDialog(PreferencesDialogBase):
|
||||
prefs.scan_tag_year = ischecked(self.tagYearBox)
|
||||
prefs.match_similar = ischecked(self.matchSimilarBox)
|
||||
prefs.word_weighting = ischecked(self.wordWeightingBox)
|
||||
|
||||
|
||||
def resetToDefaults(self):
|
||||
self.load(preferences.Preferences())
|
||||
|
||||
|
||||
#--- Events
|
||||
def scanTypeChanged(self, index):
|
||||
scan_type = SCAN_TYPE_ORDER[self.scanTypeComboBox.currentIndex()]
|
||||
word_based = scan_type in (ScanType.Filename, ScanType.Fields, ScanType.FieldsNoOrder,
|
||||
ScanType.Tag)
|
||||
word_based = scan_type in (
|
||||
ScanType.Filename, ScanType.Fields, ScanType.FieldsNoOrder,
|
||||
ScanType.Tag
|
||||
)
|
||||
tag_based = scan_type == ScanType.Tag
|
||||
self.filterHardnessSlider.setEnabled(word_based)
|
||||
self.matchSimilarBox.setEnabled(word_based)
|
||||
@@ -129,7 +133,7 @@ class PreferencesDialog(PreferencesDialogBase):
|
||||
self.tagTitleBox.setEnabled(tag_based)
|
||||
self.tagGenreBox.setEnabled(tag_based)
|
||||
self.tagYearBox.setEnabled(tag_based)
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from ..testapp import TestApp
|
||||
@@ -137,4 +141,5 @@ if __name__ == '__main__':
|
||||
dgapp = TestApp()
|
||||
dialog = PreferencesDialog(None, dgapp)
|
||||
dialog.show()
|
||||
sys.exit(app.exec_())
|
||||
sys.exit(app.exec_())
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Created On: 2011-11-27
|
||||
# Copyright 2014 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
|
||||
#
|
||||
# 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 qtlib.column import Column
|
||||
@@ -29,4 +29,5 @@ class ResultsModel(ResultsModelBase):
|
||||
Column('percentage', defaultWidth=60),
|
||||
Column('words', defaultWidth=120),
|
||||
Column('dupe_count', defaultWidth=80),
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# Created By: Virgil Dupras
|
||||
# Created On: 2009-05-10
|
||||
# Copyright 2014 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
|
||||
#
|
||||
# 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 ._block_qt import getblocks
|
||||
from ._block_qt import getblocks # NOQA
|
||||
|
||||
# Converted to C
|
||||
# def getblock(image):
|
||||
@@ -24,7 +24,7 @@ from ._block_qt import getblocks
|
||||
# return (red // pixel_count, green // pixel_count, blue // pixel_count)
|
||||
# else:
|
||||
# return (0, 0, 0)
|
||||
#
|
||||
#
|
||||
# def getblocks(image, block_count_per_side):
|
||||
# width = image.width()
|
||||
# height = image.height()
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
# Created By: Virgil Dupras
|
||||
# Created On: 2009-04-29
|
||||
# Copyright 2014 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
|
||||
#
|
||||
# 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
|
||||
|
||||
import sys
|
||||
@@ -25,9 +25,9 @@ SCAN_TYPE_ORDER = [
|
||||
class PreferencesDialog(PreferencesDialogBase):
|
||||
def __init__(self, parent, app):
|
||||
PreferencesDialogBase.__init__(self, parent, app)
|
||||
|
||||
|
||||
self.scanTypeComboBox.currentIndexChanged[int].connect(self.scanTypeChanged)
|
||||
|
||||
|
||||
def _setupPreferenceWidgets(self):
|
||||
scanTypeLabels = [
|
||||
tr("Contents"),
|
||||
@@ -49,25 +49,25 @@ class PreferencesDialog(PreferencesDialogBase):
|
||||
self._setupAddCheckbox('debugModeBox', tr("Debug mode (restart required)"))
|
||||
self.widgetsVLayout.addWidget(self.debugModeBox)
|
||||
self._setupBottomPart()
|
||||
|
||||
|
||||
def _load(self, prefs, setchecked):
|
||||
scan_type_index = SCAN_TYPE_ORDER.index(prefs.scan_type)
|
||||
self.scanTypeComboBox.setCurrentIndex(scan_type_index)
|
||||
setchecked(self.matchScaledBox, prefs.match_scaled)
|
||||
|
||||
|
||||
def _save(self, prefs, ischecked):
|
||||
prefs.scan_type = SCAN_TYPE_ORDER[self.scanTypeComboBox.currentIndex()]
|
||||
prefs.match_scaled = ischecked(self.matchScaledBox)
|
||||
|
||||
|
||||
def resetToDefaults(self):
|
||||
self.load(preferences.Preferences())
|
||||
|
||||
|
||||
#--- Events
|
||||
def scanTypeChanged(self, index):
|
||||
scan_type = SCAN_TYPE_ORDER[self.scanTypeComboBox.currentIndex()]
|
||||
fuzzy_scan = scan_type == ScanType.FuzzyBlock
|
||||
self.filterHardnessSlider.setEnabled(fuzzy_scan)
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from ..testapp import TestApp
|
||||
@@ -75,4 +75,5 @@ if __name__ == '__main__':
|
||||
dgapp = TestApp()
|
||||
dialog = PreferencesDialog(None, dgapp)
|
||||
dialog.show()
|
||||
sys.exit(app.exec_())
|
||||
sys.exit(app.exec_())
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Created On: 2011-11-27
|
||||
# Copyright 2014 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
|
||||
#
|
||||
# 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 qtlib.column import Column
|
||||
@@ -20,4 +20,5 @@ class ResultsModel(ResultsModelBase):
|
||||
Column('mtime', defaultWidth=120),
|
||||
Column('percentage', defaultWidth=60),
|
||||
Column('dupe_count', defaultWidth=80),
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
15
qt/se/app.py
15
qt/se/app.py
@@ -1,9 +1,9 @@
|
||||
# Created By: Virgil Dupras
|
||||
# Created On: 2009-05-24
|
||||
# Copyright 2014 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
|
||||
#
|
||||
# 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 core_se import __appname__
|
||||
@@ -18,6 +18,7 @@ from .preferences_dialog import PreferencesDialog
|
||||
|
||||
class Directories(DirectoriesBase):
|
||||
ROOT_PATH_TO_EXCLUDE = frozenset(['windows', 'program files'])
|
||||
|
||||
def _default_state_for_path(self, path):
|
||||
result = DirectoriesBase._default_state_for_path(self, path)
|
||||
if result is not None:
|
||||
@@ -30,16 +31,16 @@ class DupeGuru(DupeGuruBase):
|
||||
EDITION = 'se'
|
||||
LOGO_NAME = 'logo_se'
|
||||
NAME = __appname__
|
||||
|
||||
|
||||
DETAILS_DIALOG_CLASS = DetailsDialog
|
||||
RESULT_MODEL_CLASS = ResultsModel
|
||||
PREFERENCES_CLASS = Preferences
|
||||
PREFERENCES_DIALOG_CLASS = PreferencesDialog
|
||||
|
||||
|
||||
def _setup(self):
|
||||
self.directories = Directories()
|
||||
DupeGuruBase._setup(self)
|
||||
|
||||
|
||||
def _update_options(self):
|
||||
DupeGuruBase._update_options(self)
|
||||
self.model.scanner.min_match_percentage = self.prefs.filter_hardness
|
||||
@@ -48,4 +49,4 @@ class DupeGuru(DupeGuruBase):
|
||||
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.model.scanner.size_threshold = threshold * 1024 # threshold is in KB. the scanner wants bytes
|
||||
|
||||
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
# Created By: Virgil Dupras
|
||||
# Created On: 2009-05-24
|
||||
# Copyright 2014 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
|
||||
#
|
||||
# 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
|
||||
|
||||
import sys
|
||||
from PyQt5.QtCore import QSize
|
||||
from PyQt5.QtWidgets import (QVBoxLayout, QHBoxLayout, QLabel, QSizePolicy, QSpacerItem, QWidget,
|
||||
QLineEdit, QApplication)
|
||||
from PyQt5.QtWidgets import (
|
||||
QVBoxLayout, QHBoxLayout, QLabel, QSizePolicy, QSpacerItem, QWidget,
|
||||
QLineEdit, QApplication
|
||||
)
|
||||
|
||||
from hscommon.plat import ISWINDOWS, ISLINUX
|
||||
from hscommon.trans import trget
|
||||
@@ -31,9 +33,9 @@ SCAN_TYPE_ORDER = [
|
||||
class PreferencesDialog(PreferencesDialogBase):
|
||||
def __init__(self, parent, app, **kwargs):
|
||||
super().__init__(parent, app, **kwargs)
|
||||
|
||||
|
||||
self.scanTypeComboBox.currentIndexChanged[int].connect(self.scanTypeChanged)
|
||||
|
||||
|
||||
def _setupPreferenceWidgets(self):
|
||||
scanTypeLabels = [
|
||||
tr("Filename"),
|
||||
@@ -73,23 +75,26 @@ class PreferencesDialog(PreferencesDialogBase):
|
||||
spacerItem1 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
|
||||
self.horizontalLayout_2.addItem(spacerItem1)
|
||||
self.verticalLayout_4.addLayout(self.horizontalLayout_2)
|
||||
self._setupAddCheckbox('ignoreHardlinkMatches', tr("Ignore duplicates hardlinking to the same file"), self.widget)
|
||||
self._setupAddCheckbox(
|
||||
'ignoreHardlinkMatches',
|
||||
tr("Ignore duplicates hardlinking to the same file"), self.widget
|
||||
)
|
||||
self.verticalLayout_4.addWidget(self.ignoreHardlinkMatches)
|
||||
self._setupAddCheckbox('debugModeBox', tr("Debug mode (restart required)"), self.widget)
|
||||
self.verticalLayout_4.addWidget(self.debugModeBox)
|
||||
self.widgetsVLayout.addWidget(self.widget)
|
||||
self._setupBottomPart()
|
||||
|
||||
|
||||
def _setupUi(self):
|
||||
PreferencesDialogBase._setupUi(self)
|
||||
|
||||
|
||||
if ISLINUX:
|
||||
# Under linux, whether it's a Qt layout bug or something else, the size threshold text edit
|
||||
# doesn't have enough space, so we make the pref pane higher to compensate.
|
||||
self.resize(self.width(), 530)
|
||||
elif ISWINDOWS:
|
||||
self.resize(self.width(), 440)
|
||||
|
||||
|
||||
def _load(self, prefs, setchecked):
|
||||
scan_type_index = SCAN_TYPE_ORDER.index(prefs.scan_type)
|
||||
self.scanTypeComboBox.setCurrentIndex(scan_type_index)
|
||||
@@ -97,17 +102,17 @@ class PreferencesDialog(PreferencesDialogBase):
|
||||
setchecked(self.wordWeightingBox, prefs.word_weighting)
|
||||
setchecked(self.ignoreSmallFilesBox, prefs.ignore_small_files)
|
||||
self.sizeThresholdEdit.setText(str(prefs.small_file_threshold))
|
||||
|
||||
|
||||
def _save(self, prefs, ischecked):
|
||||
prefs.scan_type = SCAN_TYPE_ORDER[self.scanTypeComboBox.currentIndex()]
|
||||
prefs.match_similar = ischecked(self.matchSimilarBox)
|
||||
prefs.word_weighting = ischecked(self.wordWeightingBox)
|
||||
prefs.ignore_small_files = ischecked(self.ignoreSmallFilesBox)
|
||||
prefs.small_file_threshold = tryint(self.sizeThresholdEdit.text())
|
||||
|
||||
|
||||
def resetToDefaults(self):
|
||||
self.load(preferences.Preferences())
|
||||
|
||||
|
||||
#--- Events
|
||||
def scanTypeChanged(self, index):
|
||||
scan_type = SCAN_TYPE_ORDER[self.scanTypeComboBox.currentIndex()]
|
||||
@@ -115,7 +120,7 @@ class PreferencesDialog(PreferencesDialogBase):
|
||||
self.filterHardnessSlider.setEnabled(word_based)
|
||||
self.matchSimilarBox.setEnabled(word_based)
|
||||
self.wordWeightingBox.setEnabled(word_based)
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from ..testapp import TestApp
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Created On: 2011-11-27
|
||||
# Copyright 2014 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
|
||||
#
|
||||
# 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 qtlib.column import Column
|
||||
@@ -19,4 +19,5 @@ class ResultsModel(ResultsModelBase):
|
||||
Column('percentage', defaultWidth=60),
|
||||
Column('words', defaultWidth=120),
|
||||
Column('dupe_count', defaultWidth=80),
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user