mirror of
https://github.com/arsenetar/dupeguru.git
synced 2025-05-07 01:19:48 +00:00
More updates mainly in preferences
This commit is contained in:
parent
ec35c2df8f
commit
2f23f34b91
106
qt/app.py
106
qt/app.py
@ -6,15 +6,18 @@
|
|||||||
|
|
||||||
import sys
|
import sys
|
||||||
import os.path as op
|
import os.path as op
|
||||||
|
from typing import Type
|
||||||
|
|
||||||
from PyQt5.QtCore import QTimer, QObject, QUrl, pyqtSignal, Qt
|
from PyQt6.QtCore import QTimer, QObject, QUrl, pyqtSignal, Qt
|
||||||
from PyQt5.QtGui import QColor, QDesktopServices, QPalette
|
from PyQt6.QtGui import QColor, QDesktopServices, QPalette
|
||||||
from PyQt5.QtWidgets import QApplication, QFileDialog, QDialog, QMessageBox, QStyleFactory, QToolTip
|
from PyQt6.QtWidgets import QApplication, QFileDialog, QDialog, QMessageBox, QStyleFactory, QToolTip
|
||||||
|
|
||||||
from hscommon.trans import trget
|
from hscommon.trans import trget
|
||||||
from hscommon import desktop, plat
|
from hscommon import desktop, plat
|
||||||
|
|
||||||
from qt.about_box import AboutBox
|
from qt.about_box import AboutBox
|
||||||
|
from qt.details_dialog import DetailsDialog
|
||||||
|
from qt.preferences_dialog import PreferencesDialogBase
|
||||||
from qt.recent import Recent
|
from qt.recent import Recent
|
||||||
from qt.util import create_actions
|
from qt.util import create_actions
|
||||||
from qt.progress_window import ProgressWindow
|
from qt.progress_window import ProgressWindow
|
||||||
@ -42,10 +45,10 @@ tr = trget("ui")
|
|||||||
|
|
||||||
|
|
||||||
class DupeGuru(QObject):
|
class DupeGuru(QObject):
|
||||||
LOGO_NAME = "logo_se"
|
LOGO_NAME = "dgse_logo"
|
||||||
NAME = "dupeGuru"
|
NAME = "dupeGuru"
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs) -> None:
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
self.prefs = Preferences()
|
self.prefs = Preferences()
|
||||||
self.prefs.load()
|
self.prefs.load()
|
||||||
@ -56,7 +59,7 @@ class DupeGuru(QObject):
|
|||||||
self._setup()
|
self._setup()
|
||||||
|
|
||||||
# --- Private
|
# --- Private
|
||||||
def _setup(self):
|
def _setup(self) -> None:
|
||||||
core.pe.photo.PLAT_SPECIFIC_PHOTO_CLASS = PlatSpecificPhoto
|
core.pe.photo.PLAT_SPECIFIC_PHOTO_CLASS = PlatSpecificPhoto
|
||||||
self._setupActions()
|
self._setupActions()
|
||||||
self.details_dialog = None
|
self.details_dialog = None
|
||||||
@ -108,7 +111,7 @@ class DupeGuru(QObject):
|
|||||||
# that the application haven't launched.
|
# that the application haven't launched.
|
||||||
QTimer.singleShot(0, self.finishedLaunching)
|
QTimer.singleShot(0, self.finishedLaunching)
|
||||||
|
|
||||||
def _setupActions(self):
|
def _setupActions(self) -> None:
|
||||||
# Setup actions that are common to both the directory dialog and the results window.
|
# Setup actions that are common to both the directory dialog and the results window.
|
||||||
# (name, shortcut, icon, desc, func)
|
# (name, shortcut, icon, desc, func)
|
||||||
ACTIONS = [
|
ACTIONS = [
|
||||||
@ -154,7 +157,7 @@ class DupeGuru(QObject):
|
|||||||
]
|
]
|
||||||
create_actions(ACTIONS, self)
|
create_actions(ACTIONS, self)
|
||||||
|
|
||||||
def _update_options(self):
|
def _update_options(self) -> None:
|
||||||
self.model.options["mix_file_kind"] = self.prefs.mix_file_kind
|
self.model.options["mix_file_kind"] = self.prefs.mix_file_kind
|
||||||
self.model.options["escape_filter_regexp"] = not self.prefs.use_regexp
|
self.model.options["escape_filter_regexp"] = not self.prefs.use_regexp
|
||||||
self.model.options["clean_empty_dirs"] = self.prefs.remove_empty_folders
|
self.model.options["clean_empty_dirs"] = self.prefs.remove_empty_folders
|
||||||
@ -200,7 +203,7 @@ class DupeGuru(QObject):
|
|||||||
self._set_style("dark" if self.prefs.use_dark_style else "light")
|
self._set_style("dark" if self.prefs.use_dark_style else "light")
|
||||||
|
|
||||||
# --- Private
|
# --- Private
|
||||||
def _get_details_dialog_class(self):
|
def _get_details_dialog_class(self) -> Type[DetailsDialog]:
|
||||||
if self.model.app_mode == AppMode.PICTURE:
|
if self.model.app_mode == AppMode.PICTURE:
|
||||||
return DetailsDialogPicture
|
return DetailsDialogPicture
|
||||||
elif self.model.app_mode == AppMode.MUSIC:
|
elif self.model.app_mode == AppMode.MUSIC:
|
||||||
@ -208,7 +211,7 @@ class DupeGuru(QObject):
|
|||||||
else:
|
else:
|
||||||
return DetailsDialogStandard
|
return DetailsDialogStandard
|
||||||
|
|
||||||
def _get_preferences_dialog_class(self):
|
def _get_preferences_dialog_class(self) -> Type[PreferencesDialogBase]:
|
||||||
if self.model.app_mode == AppMode.PICTURE:
|
if self.model.app_mode == AppMode.PICTURE:
|
||||||
return PreferencesDialogPicture
|
return PreferencesDialogPicture
|
||||||
elif self.model.app_mode == AppMode.MUSIC:
|
elif self.model.app_mode == AppMode.MUSIC:
|
||||||
@ -216,7 +219,7 @@ class DupeGuru(QObject):
|
|||||||
else:
|
else:
|
||||||
return PreferencesDialogStandard
|
return PreferencesDialogStandard
|
||||||
|
|
||||||
def _set_style(self, style="light"):
|
def _set_style(self, style: str = "light") -> None:
|
||||||
# Only support this feature on windows for now
|
# Only support this feature on windows for now
|
||||||
if not plat.ISWINDOWS:
|
if not plat.ISWINDOWS:
|
||||||
return
|
return
|
||||||
@ -224,18 +227,18 @@ class DupeGuru(QObject):
|
|||||||
QApplication.setStyle(QStyleFactory.create("Fusion"))
|
QApplication.setStyle(QStyleFactory.create("Fusion"))
|
||||||
palette = QApplication.style().standardPalette()
|
palette = QApplication.style().standardPalette()
|
||||||
palette.setColor(QPalette.ColorRole.Window, QColor(53, 53, 53))
|
palette.setColor(QPalette.ColorRole.Window, QColor(53, 53, 53))
|
||||||
palette.setColor(QPalette.ColorRole.WindowText, Qt.white)
|
palette.setColor(QPalette.ColorRole.WindowText, Qt.GlobalColor.white)
|
||||||
palette.setColor(QPalette.ColorRole.Base, QColor(25, 25, 25))
|
palette.setColor(QPalette.ColorRole.Base, QColor(25, 25, 25))
|
||||||
palette.setColor(QPalette.ColorRole.AlternateBase, QColor(53, 53, 53))
|
palette.setColor(QPalette.ColorRole.AlternateBase, QColor(53, 53, 53))
|
||||||
palette.setColor(QPalette.ColorRole.ToolTipBase, QColor(53, 53, 53))
|
palette.setColor(QPalette.ColorRole.ToolTipBase, QColor(53, 53, 53))
|
||||||
palette.setColor(QPalette.ColorRole.ToolTipText, Qt.white)
|
palette.setColor(QPalette.ColorRole.ToolTipText, Qt.GlobalColor.white)
|
||||||
palette.setColor(QPalette.ColorRole.Text, Qt.white)
|
palette.setColor(QPalette.ColorRole.Text, Qt.GlobalColor.white)
|
||||||
palette.setColor(QPalette.ColorRole.Button, QColor(53, 53, 53))
|
palette.setColor(QPalette.ColorRole.Button, QColor(53, 53, 53))
|
||||||
palette.setColor(QPalette.ColorRole.ButtonText, Qt.white)
|
palette.setColor(QPalette.ColorRole.ButtonText, Qt.GlobalColor.white)
|
||||||
palette.setColor(QPalette.ColorRole.BrightText, Qt.red)
|
palette.setColor(QPalette.ColorRole.BrightText, Qt.GlobalColor.red)
|
||||||
palette.setColor(QPalette.ColorRole.Link, QColor(42, 130, 218))
|
palette.setColor(QPalette.ColorRole.Link, QColor(42, 130, 218))
|
||||||
palette.setColor(QPalette.ColorRole.Highlight, QColor(42, 130, 218))
|
palette.setColor(QPalette.ColorRole.Highlight, QColor(42, 130, 218))
|
||||||
palette.setColor(QPalette.ColorRole.HighlightedText, Qt.black)
|
palette.setColor(QPalette.ColorRole.HighlightedText, Qt.GlobalColor.black)
|
||||||
palette.setColor(QPalette.ColorGroup.Disabled, QPalette.ColorRole.Text, QColor(164, 166, 168))
|
palette.setColor(QPalette.ColorGroup.Disabled, QPalette.ColorRole.Text, QColor(164, 166, 168))
|
||||||
palette.setColor(QPalette.ColorGroup.Disabled, QPalette.ColorRole.WindowText, QColor(164, 166, 168))
|
palette.setColor(QPalette.ColorGroup.Disabled, QPalette.ColorRole.WindowText, QColor(164, 166, 168))
|
||||||
palette.setColor(QPalette.ColorGroup.Disabled, QPalette.ColorRole.ButtonText, QColor(164, 166, 168))
|
palette.setColor(QPalette.ColorGroup.Disabled, QPalette.ColorRole.ButtonText, QColor(164, 166, 168))
|
||||||
@ -250,29 +253,31 @@ class DupeGuru(QObject):
|
|||||||
QApplication.setPalette(palette)
|
QApplication.setPalette(palette)
|
||||||
|
|
||||||
# --- Public
|
# --- Public
|
||||||
def add_selected_to_ignore_list(self):
|
def add_selected_to_ignore_list(self) -> None:
|
||||||
self.model.add_selected_to_ignore_list()
|
self.model.add_selected_to_ignore_list()
|
||||||
|
|
||||||
def remove_selected(self):
|
def remove_selected(self) -> None:
|
||||||
self.model.remove_selected(self)
|
self.model.remove_selected()
|
||||||
|
|
||||||
def confirm(self, title, msg, default_button=QMessageBox.Yes):
|
def confirm(
|
||||||
|
self, title: str, msg: str, default_button: QMessageBox.StandardButton = QMessageBox.StandardButton.Yes
|
||||||
|
) -> bool:
|
||||||
active = QApplication.activeWindow()
|
active = QApplication.activeWindow()
|
||||||
buttons = QMessageBox.Yes | QMessageBox.No
|
buttons = QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
|
||||||
answer = QMessageBox.question(active, title, msg, buttons, default_button)
|
answer = QMessageBox.question(active, title, msg, buttons, default_button)
|
||||||
return answer == QMessageBox.Yes
|
return answer == QMessageBox.StandardButton.Yes
|
||||||
|
|
||||||
def invokeCustomCommand(self):
|
def invokeCustomCommand(self) -> None:
|
||||||
self.model.invoke_custom_command()
|
self.model.invoke_custom_command()
|
||||||
|
|
||||||
def show_details(self):
|
def show_details(self) -> None:
|
||||||
if self.details_dialog is not None:
|
if self.details_dialog is not None:
|
||||||
if not self.details_dialog.isVisible():
|
if not self.details_dialog.isVisible():
|
||||||
self.details_dialog.show()
|
self.details_dialog.show()
|
||||||
else:
|
else:
|
||||||
self.details_dialog.hide()
|
self.details_dialog.hide()
|
||||||
|
|
||||||
def showResultsWindow(self):
|
def showResultsWindow(self) -> None:
|
||||||
if self.resultWindow is not None:
|
if self.resultWindow is not None:
|
||||||
if self.use_tabs:
|
if self.use_tabs:
|
||||||
if self.main_window.indexOfWidget(self.resultWindow) < 0:
|
if self.main_window.indexOfWidget(self.resultWindow) < 0:
|
||||||
@ -282,14 +287,14 @@ class DupeGuru(QObject):
|
|||||||
else:
|
else:
|
||||||
self.resultWindow.show()
|
self.resultWindow.show()
|
||||||
|
|
||||||
def showDirectoriesWindow(self):
|
def showDirectoriesWindow(self) -> None:
|
||||||
if self.directories_dialog is not None:
|
if self.directories_dialog is not None:
|
||||||
if self.use_tabs:
|
if self.use_tabs:
|
||||||
self.main_window.showTab(self.directories_dialog)
|
self.main_window.showTab(self.directories_dialog)
|
||||||
else:
|
else:
|
||||||
self.directories_dialog.show()
|
self.directories_dialog.show()
|
||||||
|
|
||||||
def shutdown(self):
|
def shutdown(self) -> None:
|
||||||
self.willSavePrefs.emit()
|
self.willSavePrefs.emit()
|
||||||
self.prefs.save()
|
self.prefs.save()
|
||||||
self.model.save()
|
self.model.save()
|
||||||
@ -304,7 +309,7 @@ class DupeGuru(QObject):
|
|||||||
SIGTERM = pyqtSignal()
|
SIGTERM = pyqtSignal()
|
||||||
|
|
||||||
# --- Events
|
# --- Events
|
||||||
def finishedLaunching(self):
|
def finishedLaunching(self) -> None:
|
||||||
if sys.getfilesystemencoding() == "ascii":
|
if sys.getfilesystemencoding() == "ascii":
|
||||||
# No need to localize this, it's a debugging message.
|
# No need to localize this, it's a debugging message.
|
||||||
msg = (
|
msg = (
|
||||||
@ -324,28 +329,28 @@ class DupeGuru(QObject):
|
|||||||
self.model.load_from(results)
|
self.model.load_from(results)
|
||||||
self.recentResults.insertItem(results)
|
self.recentResults.insertItem(results)
|
||||||
|
|
||||||
def clearCacheTriggered(self):
|
def clearCacheTriggered(self) -> None:
|
||||||
title = tr("Clear Cache")
|
title = tr("Clear Cache")
|
||||||
msg = tr("Do you really want to clear the cache? This will remove all cached file hashes and picture analysis.")
|
msg = tr("Do you really want to clear the cache? This will remove all cached file hashes and picture analysis.")
|
||||||
if self.confirm(title, msg, QMessageBox.No):
|
if self.confirm(title, msg, QMessageBox.StandardButton.No):
|
||||||
self.model.clear_picture_cache()
|
self.model.clear_picture_cache()
|
||||||
self.model.clear_hash_cache()
|
self.model.clear_hash_cache()
|
||||||
active = QApplication.activeWindow()
|
active = QApplication.activeWindow()
|
||||||
QMessageBox.information(active, title, tr("Cache cleared."))
|
QMessageBox.information(active, title, tr("Cache cleared."))
|
||||||
|
|
||||||
def ignoreListTriggered(self):
|
def ignoreListTriggered(self) -> None:
|
||||||
if self.use_tabs:
|
if self.use_tabs:
|
||||||
self.showTriggeredTabbedDialog(self.ignoreListDialog, tr("Ignore List"))
|
self.showTriggeredTabbedDialog(self.ignoreListDialog, tr("Ignore List"))
|
||||||
else: # floating windows
|
else: # floating windows
|
||||||
self.model.ignore_list_dialog.show()
|
self.model.ignore_list_dialog.show()
|
||||||
|
|
||||||
def excludeListTriggered(self):
|
def excludeListTriggered(self) -> None:
|
||||||
if self.use_tabs:
|
if self.use_tabs:
|
||||||
self.showTriggeredTabbedDialog(self.excludeListDialog, tr("Exclusion Filters"))
|
self.showTriggeredTabbedDialog(self.excludeListDialog, tr("Exclusion Filters"))
|
||||||
else: # floating windows
|
else: # floating windows
|
||||||
self.model.exclude_list_dialog.show()
|
self.model.exclude_list_dialog.show()
|
||||||
|
|
||||||
def showTriggeredTabbedDialog(self, dialog, desc_string):
|
def showTriggeredTabbedDialog(self, dialog, desc_string: str) -> None:
|
||||||
"""Add tab for dialog, name the tab with desc_string, then show it."""
|
"""Add tab for dialog, name the tab with desc_string, then show it."""
|
||||||
index = self.main_window.indexOfWidget(dialog)
|
index = self.main_window.indexOfWidget(dialog)
|
||||||
# Create the tab if it doesn't exist already
|
# Create the tab if it doesn't exist already
|
||||||
@ -354,23 +359,22 @@ class DupeGuru(QObject):
|
|||||||
# Show the tab for that widget
|
# Show the tab for that widget
|
||||||
self.main_window.setCurrentIndex(index)
|
self.main_window.setCurrentIndex(index)
|
||||||
|
|
||||||
def openDebugLogTriggered(self):
|
def openDebugLogTriggered(self) -> None:
|
||||||
debug_log_path = op.join(self.model.appdata, "debug.log")
|
debug_log_path = op.join(self.model.appdata, "debug.log")
|
||||||
desktop.open_path(debug_log_path)
|
desktop.open_path(debug_log_path)
|
||||||
|
|
||||||
def preferencesTriggered(self):
|
def preferencesTriggered(self) -> None:
|
||||||
preferences_dialog = self._get_preferences_dialog_class()(
|
preferences_dialog = self._get_preferences_dialog_class()(
|
||||||
self.main_window if self.main_window else self.directories_dialog, self
|
self.main_window if self.main_window else self.directories_dialog, self
|
||||||
)
|
)
|
||||||
preferences_dialog.load()
|
preferences_dialog.load()
|
||||||
result = preferences_dialog.exec()
|
result = preferences_dialog.exec()
|
||||||
if result == QDialog.Accepted:
|
if result == QDialog.DialogCode.Accepted:
|
||||||
preferences_dialog.save()
|
preferences_dialog.save()
|
||||||
self.prefs.save()
|
self.prefs.save()
|
||||||
self._update_options()
|
self._update_options()
|
||||||
preferences_dialog.setParent(None)
|
|
||||||
|
|
||||||
def quitTriggered(self):
|
def quitTriggered(self) -> None:
|
||||||
if self.details_dialog is not None:
|
if self.details_dialog is not None:
|
||||||
self.details_dialog.close()
|
self.details_dialog.close()
|
||||||
|
|
||||||
@ -379,10 +383,10 @@ class DupeGuru(QObject):
|
|||||||
else:
|
else:
|
||||||
self.directories_dialog.close()
|
self.directories_dialog.close()
|
||||||
|
|
||||||
def showAboutBoxTriggered(self):
|
def showAboutBoxTriggered(self) -> None:
|
||||||
self.about_box.show()
|
self.about_box.show()
|
||||||
|
|
||||||
def showHelpTriggered(self):
|
def showHelpTriggered(self) -> None:
|
||||||
base_path = platform.HELP_PATH
|
base_path = platform.HELP_PATH
|
||||||
help_path = op.abspath(op.join(base_path, "index.html"))
|
help_path = op.abspath(op.join(base_path, "index.html"))
|
||||||
if op.exists(help_path):
|
if op.exists(help_path):
|
||||||
@ -391,7 +395,7 @@ class DupeGuru(QObject):
|
|||||||
url = QUrl("https://dupeguru.voltaicideas.net/help/en/")
|
url = QUrl("https://dupeguru.voltaicideas.net/help/en/")
|
||||||
QDesktopServices.openUrl(url)
|
QDesktopServices.openUrl(url)
|
||||||
|
|
||||||
def handleSIGTERM(self):
|
def handleSIGTERM(self) -> None:
|
||||||
self.shutdown()
|
self.shutdown()
|
||||||
|
|
||||||
# --- model --> view
|
# --- model --> view
|
||||||
@ -401,20 +405,20 @@ class DupeGuru(QObject):
|
|||||||
def set_default(self, key, value):
|
def set_default(self, key, value):
|
||||||
self.prefs.set_value(key, value)
|
self.prefs.set_value(key, value)
|
||||||
|
|
||||||
def show_message(self, msg):
|
def show_message(self, msg: str) -> None:
|
||||||
window = QApplication.activeWindow()
|
window = QApplication.activeWindow()
|
||||||
QMessageBox.information(window, "", msg)
|
QMessageBox.information(window, "", msg)
|
||||||
|
|
||||||
def ask_yes_no(self, prompt):
|
def ask_yes_no(self, prompt: str) -> bool:
|
||||||
return self.confirm("", prompt)
|
return self.confirm("", prompt)
|
||||||
|
|
||||||
def create_results_window(self):
|
def create_results_window(self) -> None:
|
||||||
"""Creates resultWindow and details_dialog depending on the selected ``app_mode``."""
|
"""Creates resultWindow and details_dialog depending on the selected ``app_mode``."""
|
||||||
if self.details_dialog is not None:
|
if self.details_dialog is not None:
|
||||||
# The object is not deleted entirely, avoid saving its geometry in the future
|
# The object is not deleted entirely, avoid saving its geometry in the future
|
||||||
# self.willSavePrefs.disconnect(self.details_dialog.appWillSavePrefs)
|
# self.willSavePrefs.disconnect(self.details_dialog.appWillSavePrefs)
|
||||||
# or simply delete it on close which is probably cleaner:
|
# or simply delete it on close which is probably cleaner:
|
||||||
self.details_dialog.setAttribute(Qt.WA_DeleteOnClose)
|
self.details_dialog.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose)
|
||||||
self.details_dialog.close()
|
self.details_dialog.close()
|
||||||
# if we don't do the following, Qt will crash when we recreate the Results dialog
|
# if we don't do the following, Qt will crash when we recreate the Results dialog
|
||||||
self.details_dialog.setParent(None)
|
self.details_dialog.setParent(None)
|
||||||
@ -429,17 +433,17 @@ class DupeGuru(QObject):
|
|||||||
self.directories_dialog._updateActionsState()
|
self.directories_dialog._updateActionsState()
|
||||||
self.details_dialog = self._get_details_dialog_class()(self.resultWindow, self)
|
self.details_dialog = self._get_details_dialog_class()(self.resultWindow, self)
|
||||||
|
|
||||||
def show_results_window(self):
|
def show_results_window(self) -> None:
|
||||||
self.showResultsWindow()
|
self.showResultsWindow()
|
||||||
|
|
||||||
def show_problem_dialog(self):
|
def show_problem_dialog(self) -> None:
|
||||||
self.problemDialog.show()
|
self.problemDialog.show()
|
||||||
|
|
||||||
def select_dest_folder(self, prompt):
|
def select_dest_folder(self, prompt: str) -> str:
|
||||||
flags = QFileDialog.ShowDirsOnly
|
flags = QFileDialog.Option.ShowDirsOnly
|
||||||
return QFileDialog.getExistingDirectory(self.resultWindow, prompt, "", flags)
|
return QFileDialog.getExistingDirectory(self.resultWindow, prompt, "", flags)
|
||||||
|
|
||||||
def select_dest_file(self, prompt, extension):
|
def select_dest_file(self, prompt: str, extension: str) -> str:
|
||||||
files = tr("{} file (*.{})").format(extension.upper(), extension)
|
files = tr("{} file (*.{})").format(extension.upper(), extension)
|
||||||
destination, chosen_filter = QFileDialog.getSaveFileName(self.resultWindow, prompt, "", files)
|
destination, chosen_filter = QFileDialog.getSaveFileName(self.resultWindow, prompt, "", files)
|
||||||
if not destination.endswith(f".{extension}"):
|
if not destination.endswith(f".{extension}"):
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
# which should be included with this package. The terms are also available at
|
# which should be included with this package. The terms are also available at
|
||||||
# http://www.gnu.org/licenses/gpl-3.0.html
|
# http://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
|
||||||
from PyQt5.QtCore import QSize
|
from PyQt6.QtCore import QSize
|
||||||
from PyQt5.QtWidgets import QAbstractItemView
|
from PyQt6.QtWidgets import QAbstractItemView
|
||||||
|
|
||||||
from hscommon.trans import trget
|
from hscommon.trans import trget
|
||||||
from qt.details_dialog import DetailsDialog as DetailsDialogBase
|
from qt.details_dialog import DetailsDialog as DetailsDialogBase
|
||||||
@ -15,12 +15,12 @@ tr = trget("ui")
|
|||||||
|
|
||||||
|
|
||||||
class DetailsDialog(DetailsDialogBase):
|
class DetailsDialog(DetailsDialogBase):
|
||||||
def _setupUi(self):
|
def _setupUi(self) -> None:
|
||||||
self.setWindowTitle(tr("Details"))
|
self.setWindowTitle(tr("Details"))
|
||||||
self.resize(502, 295)
|
self.resize(502, 295)
|
||||||
self.setMinimumSize(QSize(250, 250))
|
self.setMinimumSize(QSize(250, 250))
|
||||||
self.tableView = DetailsTable(self)
|
self.tableView = DetailsTable(self)
|
||||||
self.tableView.setAlternatingRowColors(True)
|
self.tableView.setAlternatingRowColors(True)
|
||||||
self.tableView.setSelectionBehavior(QAbstractItemView.SelectRows)
|
self.tableView.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
|
||||||
self.tableView.setShowGrid(False)
|
self.tableView.setShowGrid(False)
|
||||||
self.setWidget(self.tableView)
|
self.setWidget(self.tableView)
|
||||||
|
@ -4,27 +4,22 @@
|
|||||||
# which should be included with this package. The terms are also available at
|
# which should be included with this package. The terms are also available at
|
||||||
# http://www.gnu.org/licenses/gpl-3.0.html
|
# http://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
|
||||||
from PyQt5.QtCore import QSize
|
from typing import Callable
|
||||||
from PyQt5.QtWidgets import (
|
from PyQt6.QtCore import QSize
|
||||||
QVBoxLayout,
|
from PyQt6.QtWidgets import QVBoxLayout, QHBoxLayout, QLabel, QSizePolicy, QSpacerItem, QWidget, QCheckBox
|
||||||
QHBoxLayout,
|
|
||||||
QLabel,
|
|
||||||
QSizePolicy,
|
|
||||||
QSpacerItem,
|
|
||||||
QWidget,
|
|
||||||
)
|
|
||||||
|
|
||||||
from hscommon.trans import trget
|
from hscommon.trans import trget
|
||||||
from core.app import AppMode
|
from core.app import AppMode
|
||||||
from core.scanner import ScanType
|
from core.scanner import ScanType
|
||||||
|
from qt.preferences import Preferences
|
||||||
|
|
||||||
from qt.preferences_dialog import PreferencesDialogBase
|
from qt.preferences_dialog import PreferencesDialogBase, Sections
|
||||||
|
|
||||||
tr = trget("ui")
|
tr = trget("ui")
|
||||||
|
|
||||||
|
|
||||||
class PreferencesDialog(PreferencesDialogBase):
|
class PreferencesDialog(PreferencesDialogBase):
|
||||||
def _setupPreferenceWidgets(self):
|
def _setupPreferenceWidgets(self) -> None:
|
||||||
self._setupFilterHardnessBox()
|
self._setupFilterHardnessBox()
|
||||||
self.widgetsVLayout.addLayout(self.filterHardnessHLayout)
|
self.widgetsVLayout.addLayout(self.filterHardnessHLayout)
|
||||||
self.widget = QWidget(self)
|
self.widget = QWidget(self)
|
||||||
@ -37,7 +32,7 @@ class PreferencesDialog(PreferencesDialogBase):
|
|||||||
self.verticalLayout_4.addWidget(self.label_6)
|
self.verticalLayout_4.addWidget(self.label_6)
|
||||||
self.horizontalLayout_2 = QHBoxLayout()
|
self.horizontalLayout_2 = QHBoxLayout()
|
||||||
self.horizontalLayout_2.setSpacing(0)
|
self.horizontalLayout_2.setSpacing(0)
|
||||||
spacer_item = QSpacerItem(15, 20, QSizePolicy.Fixed, QSizePolicy.Minimum)
|
spacer_item = QSpacerItem(15, 20, QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Minimum)
|
||||||
self.horizontalLayout_2.addItem(spacer_item)
|
self.horizontalLayout_2.addItem(spacer_item)
|
||||||
self._setupAddCheckbox("tagTrackBox", tr("Track"), self.widget)
|
self._setupAddCheckbox("tagTrackBox", tr("Track"), self.widget)
|
||||||
self.horizontalLayout_2.addWidget(self.tagTrackBox)
|
self.horizontalLayout_2.addWidget(self.tagTrackBox)
|
||||||
@ -70,7 +65,7 @@ class PreferencesDialog(PreferencesDialogBase):
|
|||||||
self.widgetsVLayout.addWidget(self.ignoreHardlinkMatches)
|
self.widgetsVLayout.addWidget(self.ignoreHardlinkMatches)
|
||||||
self._setupBottomPart()
|
self._setupBottomPart()
|
||||||
|
|
||||||
def _load(self, prefs, setchecked, section):
|
def _load(self, prefs: Preferences, setchecked: Callable[[QCheckBox, bool], None], section: Sections) -> None:
|
||||||
setchecked(self.tagTrackBox, prefs.scan_tag_track)
|
setchecked(self.tagTrackBox, prefs.scan_tag_track)
|
||||||
setchecked(self.tagArtistBox, prefs.scan_tag_artist)
|
setchecked(self.tagArtistBox, prefs.scan_tag_artist)
|
||||||
setchecked(self.tagAlbumBox, prefs.scan_tag_album)
|
setchecked(self.tagAlbumBox, prefs.scan_tag_album)
|
||||||
@ -99,7 +94,7 @@ class PreferencesDialog(PreferencesDialogBase):
|
|||||||
self.tagGenreBox.setEnabled(tag_based)
|
self.tagGenreBox.setEnabled(tag_based)
|
||||||
self.tagYearBox.setEnabled(tag_based)
|
self.tagYearBox.setEnabled(tag_based)
|
||||||
|
|
||||||
def _save(self, prefs, ischecked):
|
def _save(self, prefs: Preferences, ischecked: Callable[[QCheckBox], bool]) -> None:
|
||||||
prefs.scan_tag_track = ischecked(self.tagTrackBox)
|
prefs.scan_tag_track = ischecked(self.tagTrackBox)
|
||||||
prefs.scan_tag_artist = ischecked(self.tagArtistBox)
|
prefs.scan_tag_artist = ischecked(self.tagArtistBox)
|
||||||
prefs.scan_tag_album = ischecked(self.tagAlbumBox)
|
prefs.scan_tag_album = ischecked(self.tagAlbumBox)
|
||||||
|
@ -4,21 +4,23 @@
|
|||||||
# which should be included with this package. The terms are also available at
|
# which should be included with this package. The terms are also available at
|
||||||
# http://www.gnu.org/licenses/gpl-3.0.html
|
# http://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
|
||||||
from PyQt5.QtWidgets import QFormLayout
|
from typing import Callable
|
||||||
from PyQt5.QtCore import Qt
|
from PyQt6.QtWidgets import QFormLayout, QCheckBox
|
||||||
|
from PyQt6.QtCore import Qt
|
||||||
from hscommon.trans import trget
|
from hscommon.trans import trget
|
||||||
from hscommon.plat import ISLINUX
|
from hscommon.plat import ISLINUX
|
||||||
|
from qt.preferences import Preferences
|
||||||
from qt.radio_box import RadioBox
|
from qt.radio_box import RadioBox
|
||||||
from core.scanner import ScanType
|
from core.scanner import ScanType
|
||||||
from core.app import AppMode
|
from core.app import AppMode
|
||||||
|
|
||||||
from qt.preferences_dialog import PreferencesDialogBase
|
from qt.preferences_dialog import PreferencesDialogBase, Sections
|
||||||
|
|
||||||
tr = trget("ui")
|
tr = trget("ui")
|
||||||
|
|
||||||
|
|
||||||
class PreferencesDialog(PreferencesDialogBase):
|
class PreferencesDialog(PreferencesDialogBase):
|
||||||
def _setupPreferenceWidgets(self):
|
def _setupPreferenceWidgets(self) -> None:
|
||||||
self._setupFilterHardnessBox()
|
self._setupFilterHardnessBox()
|
||||||
self.widgetsVLayout.addLayout(self.filterHardnessHLayout)
|
self.widgetsVLayout.addLayout(self.filterHardnessHLayout)
|
||||||
self._setupAddCheckbox("matchScaledBox", tr("Match pictures of different dimensions"))
|
self._setupAddCheckbox("matchScaledBox", tr("Match pictures of different dimensions"))
|
||||||
@ -37,12 +39,12 @@ class PreferencesDialog(PreferencesDialogBase):
|
|||||||
|
|
||||||
self.cacheTypeRadio = RadioBox(self, items=["Sqlite", "Shelve"], spread=False)
|
self.cacheTypeRadio = RadioBox(self, items=["Sqlite", "Shelve"], spread=False)
|
||||||
cache_form = QFormLayout()
|
cache_form = QFormLayout()
|
||||||
cache_form.setLabelAlignment(Qt.AlignLeft)
|
cache_form.setLabelAlignment(Qt.AlignmentFlag.AlignLeft)
|
||||||
cache_form.addRow(tr("Picture cache mode:"), self.cacheTypeRadio)
|
cache_form.addRow(tr("Picture cache mode:"), self.cacheTypeRadio)
|
||||||
self.widgetsVLayout.addLayout(cache_form)
|
self.widgetsVLayout.addLayout(cache_form)
|
||||||
self._setupBottomPart()
|
self._setupBottomPart()
|
||||||
|
|
||||||
def _setupDisplayPage(self):
|
def _setupDisplayPage(self) -> None:
|
||||||
super()._setupDisplayPage()
|
super()._setupDisplayPage()
|
||||||
self._setupAddCheckbox("details_dialog_override_theme_icons", tr("Override theme icons in viewer toolbar"))
|
self._setupAddCheckbox("details_dialog_override_theme_icons", tr("Override theme icons in viewer toolbar"))
|
||||||
self.details_dialog_override_theme_icons.setToolTip(
|
self.details_dialog_override_theme_icons.setToolTip(
|
||||||
@ -62,7 +64,7 @@ show scrollbars to span the view around"
|
|||||||
)
|
)
|
||||||
self.details_groupbox_layout.insertWidget(index + 2, self.details_dialog_viewers_show_scrollbars)
|
self.details_groupbox_layout.insertWidget(index + 2, self.details_dialog_viewers_show_scrollbars)
|
||||||
|
|
||||||
def _load(self, prefs, setchecked, section):
|
def _load(self, prefs: Preferences, setchecked: Callable[[QCheckBox, bool], None], section: Sections) -> None:
|
||||||
setchecked(self.matchScaledBox, prefs.match_scaled)
|
setchecked(self.matchScaledBox, prefs.match_scaled)
|
||||||
self.cacheTypeRadio.selected_index = 1 if prefs.picture_cache_type == "shelve" else 0
|
self.cacheTypeRadio.selected_index = 1 if prefs.picture_cache_type == "shelve" else 0
|
||||||
|
|
||||||
@ -73,7 +75,7 @@ show scrollbars to span the view around"
|
|||||||
setchecked(self.details_dialog_override_theme_icons, prefs.details_dialog_override_theme_icons)
|
setchecked(self.details_dialog_override_theme_icons, prefs.details_dialog_override_theme_icons)
|
||||||
setchecked(self.details_dialog_viewers_show_scrollbars, prefs.details_dialog_viewers_show_scrollbars)
|
setchecked(self.details_dialog_viewers_show_scrollbars, prefs.details_dialog_viewers_show_scrollbars)
|
||||||
|
|
||||||
def _save(self, prefs, ischecked):
|
def _save(self, prefs: Preferences, ischecked: Callable[[QCheckBox], bool]) -> None:
|
||||||
prefs.match_scaled = ischecked(self.matchScaledBox)
|
prefs.match_scaled = ischecked(self.matchScaledBox)
|
||||||
prefs.picture_cache_type = "shelve" if self.cacheTypeRadio.selected_index == 1 else "sqlite"
|
prefs.picture_cache_type = "shelve" if self.cacheTypeRadio.selected_index == 1 else "sqlite"
|
||||||
prefs.details_dialog_override_theme_icons = ischecked(self.details_dialog_override_theme_icons)
|
prefs.details_dialog_override_theme_icons = ischecked(self.details_dialog_override_theme_icons)
|
||||||
|
@ -4,9 +4,10 @@
|
|||||||
# which should be included with this package. The terms are also available at
|
# which should be included with this package. The terms are also available at
|
||||||
# http://www.gnu.org/licenses/gpl-3.0.html
|
# http://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
|
||||||
from PyQt5.QtWidgets import QApplication, QDockWidget
|
from typing import Any, Tuple
|
||||||
from PyQt5.QtCore import Qt, QRect, QObject, pyqtSignal
|
from PyQt6.QtWidgets import QApplication, QDockWidget
|
||||||
from PyQt5.QtGui import QColor
|
from PyQt6.QtCore import Qt, QRect, QObject, pyqtSignal
|
||||||
|
from PyQt6.QtGui import QColor
|
||||||
|
|
||||||
from hscommon import trans
|
from hscommon import trans
|
||||||
from hscommon.plat import ISLINUX
|
from hscommon.plat import ISLINUX
|
||||||
@ -126,7 +127,7 @@ class PreferencesBase(QObject):
|
|||||||
def set_value(self, name, value):
|
def set_value(self, name, value):
|
||||||
self._settings.setValue(name, _normalize_for_serialization(value))
|
self._settings.setValue(name, _normalize_for_serialization(value))
|
||||||
|
|
||||||
def saveGeometry(self, name, widget):
|
def saveGeometry(self, name, widget) -> None:
|
||||||
# We save geometry under a 7-sized int array: first item is a flag
|
# We save geometry under a 7-sized int array: first item is a flag
|
||||||
# for whether the widget is maximized, second item is a flag for whether
|
# for whether the widget is maximized, second item is a flag for whether
|
||||||
# the widget is docked, third item is a Qt::DockWidgetArea enum value,
|
# the widget is docked, third item is a Qt::DockWidgetArea enum value,
|
||||||
@ -138,12 +139,12 @@ class PreferencesBase(QObject):
|
|||||||
rect_as_list = [r.x(), r.y(), r.width(), r.height()]
|
rect_as_list = [r.x(), r.y(), r.width(), r.height()]
|
||||||
self.set_value(name, [m, d, area] + rect_as_list)
|
self.set_value(name, [m, d, area] + rect_as_list)
|
||||||
|
|
||||||
def restoreGeometry(self, name, widget):
|
def restoreGeometry(self, name, widget) -> Tuple[bool, Any]:
|
||||||
geometry = self.get_value(name)
|
geometry = self.get_value(name)
|
||||||
if geometry and len(geometry) == 7:
|
if geometry and len(geometry) == 7:
|
||||||
m, d, area, x, y, w, h = geometry
|
m, d, area, x, y, w, h = geometry
|
||||||
if m:
|
if m:
|
||||||
widget.setWindowState(Qt.WindowMaximized)
|
widget.setWindowState(Qt.WindowState.WindowMaximized)
|
||||||
else:
|
else:
|
||||||
r = QRect(x, y, w, h)
|
r = QRect(x, y, w, h)
|
||||||
widget.setGeometry(r)
|
widget.setGeometry(r)
|
||||||
@ -154,7 +155,7 @@ class PreferencesBase(QObject):
|
|||||||
|
|
||||||
|
|
||||||
class Preferences(PreferencesBase):
|
class Preferences(PreferencesBase):
|
||||||
def _load_values(self, settings):
|
def _load_values(self, settings) -> None:
|
||||||
get = self.get_value
|
get = self.get_value
|
||||||
self.filter_hardness = get("FilterHardness", self.filter_hardness)
|
self.filter_hardness = get("FilterHardness", self.filter_hardness)
|
||||||
self.mix_file_kind = get("MixFileKind", self.mix_file_kind)
|
self.mix_file_kind = get("MixFileKind", self.mix_file_kind)
|
||||||
@ -225,7 +226,7 @@ class Preferences(PreferencesBase):
|
|||||||
self.match_scaled = get("MatchScaled", self.match_scaled)
|
self.match_scaled = get("MatchScaled", self.match_scaled)
|
||||||
self.picture_cache_type = get("PictureCacheType", self.picture_cache_type)
|
self.picture_cache_type = get("PictureCacheType", self.picture_cache_type)
|
||||||
|
|
||||||
def reset(self):
|
def reset(self) -> None:
|
||||||
self.filter_hardness = 95
|
self.filter_hardness = 95
|
||||||
self.mix_file_kind = True
|
self.mix_file_kind = True
|
||||||
self.use_regexp = False
|
self.use_regexp = False
|
||||||
@ -247,8 +248,8 @@ class Preferences(PreferencesBase):
|
|||||||
# By default use internal icons on platforms other than Linux for now
|
# By default use internal icons on platforms other than Linux for now
|
||||||
self.details_dialog_override_theme_icons = False if not ISLINUX else True
|
self.details_dialog_override_theme_icons = False if not ISLINUX else True
|
||||||
self.details_dialog_viewers_show_scrollbars = True
|
self.details_dialog_viewers_show_scrollbars = True
|
||||||
self.result_table_ref_foreground_color = QColor(Qt.blue)
|
self.result_table_ref_foreground_color = QColor(Qt.GlobalColor.blue)
|
||||||
self.result_table_ref_background_color = QColor(Qt.lightGray)
|
self.result_table_ref_background_color = QColor(Qt.GlobalColor.lightGray)
|
||||||
self.result_table_delta_foreground_color = QColor(255, 142, 40) # orange
|
self.result_table_delta_foreground_color = QColor(255, 142, 40) # orange
|
||||||
self.resultWindowIsMaximized = False
|
self.resultWindowIsMaximized = False
|
||||||
self.resultWindowRect = None
|
self.resultWindowRect = None
|
||||||
@ -276,7 +277,7 @@ class Preferences(PreferencesBase):
|
|||||||
self.match_scaled = False
|
self.match_scaled = False
|
||||||
self.picture_cache_type = "sqlite"
|
self.picture_cache_type = "sqlite"
|
||||||
|
|
||||||
def _save_values(self, settings):
|
def _save_values(self, settings) -> None:
|
||||||
set_ = self.set_value
|
set_ = self.set_value
|
||||||
set_("FilterHardness", self.filter_hardness)
|
set_("FilterHardness", self.filter_hardness)
|
||||||
set_("MixFileKind", self.mix_file_kind)
|
set_("MixFileKind", self.mix_file_kind)
|
||||||
|
@ -4,8 +4,9 @@
|
|||||||
# which should be included with this package. The terms are also available at
|
# which should be included with this package. The terms are also available at
|
||||||
# http://www.gnu.org/licenses/gpl-3.0.html
|
# http://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
|
||||||
from PyQt5.QtCore import Qt, QSize, pyqtSlot
|
from typing import Union
|
||||||
from PyQt5.QtWidgets import (
|
from PyQt6.QtCore import Qt, QSize, pyqtSlot
|
||||||
|
from PyQt6.QtWidgets import (
|
||||||
QDialog,
|
QDialog,
|
||||||
QDialogButtonBox,
|
QDialogButtonBox,
|
||||||
QVBoxLayout,
|
QVBoxLayout,
|
||||||
@ -28,7 +29,7 @@ from PyQt5.QtWidgets import (
|
|||||||
QGroupBox,
|
QGroupBox,
|
||||||
QFormLayout,
|
QFormLayout,
|
||||||
)
|
)
|
||||||
from PyQt5.QtGui import QPixmap, QIcon
|
from PyQt6.QtGui import QPixmap, QIcon, QShowEvent
|
||||||
from hscommon import desktop, plat
|
from hscommon import desktop, plat
|
||||||
|
|
||||||
from hscommon.trans import trget
|
from hscommon.trans import trget
|
||||||
@ -39,6 +40,11 @@ from enum import Flag, auto
|
|||||||
|
|
||||||
from qt.preferences import Preferences
|
from qt.preferences import Preferences
|
||||||
|
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from qt.app import DupeGuru
|
||||||
|
|
||||||
tr = trget("ui")
|
tr = trget("ui")
|
||||||
|
|
||||||
|
|
||||||
@ -52,8 +58,8 @@ class Sections(Flag):
|
|||||||
|
|
||||||
|
|
||||||
class PreferencesDialogBase(QDialog):
|
class PreferencesDialogBase(QDialog):
|
||||||
def __init__(self, parent, app, **kwargs):
|
def __init__(self, parent: QWidget, app: "DupeGuru", **kwargs):
|
||||||
flags = Qt.CustomizeWindowHint | Qt.WindowTitleHint | Qt.WindowSystemMenuHint
|
flags = Qt.WindowType.CustomizeWindowHint | Qt.WindowType.WindowTitleHint | Qt.WindowType.WindowSystemMenuHint
|
||||||
super().__init__(parent, flags, **kwargs)
|
super().__init__(parent, flags, **kwargs)
|
||||||
self.app = app
|
self.app = app
|
||||||
self.supportedLanguages = dict(sorted(get_langnames().items(), key=lambda item: item[1]))
|
self.supportedLanguages = dict(sorted(get_langnames().items(), key=lambda item: item[1]))
|
||||||
@ -65,7 +71,7 @@ class PreferencesDialogBase(QDialog):
|
|||||||
self.buttonBox.accepted.connect(self.accept)
|
self.buttonBox.accepted.connect(self.accept)
|
||||||
self.buttonBox.rejected.connect(self.reject)
|
self.buttonBox.rejected.connect(self.reject)
|
||||||
|
|
||||||
def _setupFilterHardnessBox(self):
|
def _setupFilterHardnessBox(self) -> None:
|
||||||
self.filterHardnessHLayout = QHBoxLayout()
|
self.filterHardnessHLayout = QHBoxLayout()
|
||||||
self.filterHardnessLabel = QLabel(self)
|
self.filterHardnessLabel = QLabel(self)
|
||||||
self.filterHardnessLabel.setText(tr("Filter Hardness:"))
|
self.filterHardnessLabel.setText(tr("Filter Hardness:"))
|
||||||
@ -76,7 +82,7 @@ class PreferencesDialogBase(QDialog):
|
|||||||
self.filterHardnessHLayoutSub1 = QHBoxLayout()
|
self.filterHardnessHLayoutSub1 = QHBoxLayout()
|
||||||
self.filterHardnessHLayoutSub1.setSpacing(12)
|
self.filterHardnessHLayoutSub1.setSpacing(12)
|
||||||
self.filterHardnessSlider = QSlider(self)
|
self.filterHardnessSlider = QSlider(self)
|
||||||
size_policy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
|
size_policy = QSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
|
||||||
size_policy.setHorizontalStretch(0)
|
size_policy.setHorizontalStretch(0)
|
||||||
size_policy.setVerticalStretch(0)
|
size_policy.setVerticalStretch(0)
|
||||||
size_policy.setHeightForWidth(self.filterHardnessSlider.sizePolicy().hasHeightForWidth())
|
size_policy.setHeightForWidth(self.filterHardnessSlider.sizePolicy().hasHeightForWidth())
|
||||||
@ -84,7 +90,7 @@ class PreferencesDialogBase(QDialog):
|
|||||||
self.filterHardnessSlider.setMinimum(1)
|
self.filterHardnessSlider.setMinimum(1)
|
||||||
self.filterHardnessSlider.setMaximum(100)
|
self.filterHardnessSlider.setMaximum(100)
|
||||||
self.filterHardnessSlider.setTracking(True)
|
self.filterHardnessSlider.setTracking(True)
|
||||||
self.filterHardnessSlider.setOrientation(Qt.Horizontal)
|
self.filterHardnessSlider.setOrientation(Qt.Orientation.Horizontal)
|
||||||
self.filterHardnessHLayoutSub1.addWidget(self.filterHardnessSlider)
|
self.filterHardnessHLayoutSub1.addWidget(self.filterHardnessSlider)
|
||||||
self.filterHardnessLabel = QLabel(self)
|
self.filterHardnessLabel = QLabel(self)
|
||||||
self.filterHardnessLabel.setText("100")
|
self.filterHardnessLabel.setText("100")
|
||||||
@ -96,7 +102,7 @@ class PreferencesDialogBase(QDialog):
|
|||||||
self.moreResultsLabel = QLabel(self)
|
self.moreResultsLabel = QLabel(self)
|
||||||
self.moreResultsLabel.setText(tr("More Results"))
|
self.moreResultsLabel.setText(tr("More Results"))
|
||||||
self.filterHardnessHLayoutSub2.addWidget(self.moreResultsLabel)
|
self.filterHardnessHLayoutSub2.addWidget(self.moreResultsLabel)
|
||||||
spacer_item = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
|
spacer_item = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
|
||||||
self.filterHardnessHLayoutSub2.addItem(spacer_item)
|
self.filterHardnessHLayoutSub2.addItem(spacer_item)
|
||||||
self.fewerResultsLabel = QLabel(self)
|
self.fewerResultsLabel = QLabel(self)
|
||||||
self.fewerResultsLabel.setText(tr("Fewer Results"))
|
self.fewerResultsLabel.setText(tr("Fewer Results"))
|
||||||
@ -104,7 +110,7 @@ class PreferencesDialogBase(QDialog):
|
|||||||
self.filterHardnessVLayout.addLayout(self.filterHardnessHLayoutSub2)
|
self.filterHardnessVLayout.addLayout(self.filterHardnessHLayoutSub2)
|
||||||
self.filterHardnessHLayout.addLayout(self.filterHardnessVLayout)
|
self.filterHardnessHLayout.addLayout(self.filterHardnessVLayout)
|
||||||
|
|
||||||
def _setupBottomPart(self):
|
def _setupBottomPart(self) -> None:
|
||||||
# The bottom part of the pref panel is always the same in all editions.
|
# The bottom part of the pref panel is always the same in all editions.
|
||||||
self.copyMoveLabel = QLabel(self)
|
self.copyMoveLabel = QLabel(self)
|
||||||
self.copyMoveLabel.setText(tr("Copy and Move:"))
|
self.copyMoveLabel.setText(tr("Copy and Move:"))
|
||||||
@ -120,7 +126,7 @@ class PreferencesDialogBase(QDialog):
|
|||||||
self.customCommandEdit = QLineEdit(self)
|
self.customCommandEdit = QLineEdit(self)
|
||||||
self.widgetsVLayout.addWidget(self.customCommandEdit)
|
self.widgetsVLayout.addWidget(self.customCommandEdit)
|
||||||
|
|
||||||
def _setupDisplayPage(self):
|
def _setupDisplayPage(self) -> None:
|
||||||
self.ui_groupbox = QGroupBox("&" + tr("General Interface"))
|
self.ui_groupbox = QGroupBox("&" + tr("General Interface"))
|
||||||
layout = QVBoxLayout()
|
layout = QVBoxLayout()
|
||||||
self.languageLabel = QLabel(tr("Language:"), self)
|
self.languageLabel = QLabel(tr("Language:"), self)
|
||||||
@ -171,7 +177,7 @@ On MacOS, the tab bar will fill up the window's width instead."
|
|||||||
formlayout.addRow(tr("Reference background color:"), self.result_table_ref_background_color)
|
formlayout.addRow(tr("Reference background color:"), self.result_table_ref_background_color)
|
||||||
self.result_table_delta_foreground_color = ColorPickerButton(self)
|
self.result_table_delta_foreground_color = ColorPickerButton(self)
|
||||||
formlayout.addRow(tr("Delta foreground color:"), self.result_table_delta_foreground_color)
|
formlayout.addRow(tr("Delta foreground color:"), self.result_table_delta_foreground_color)
|
||||||
formlayout.setLabelAlignment(Qt.AlignLeft)
|
formlayout.setLabelAlignment(Qt.AlignmentFlag.AlignLeft)
|
||||||
|
|
||||||
# Keep same vertical spacing as parent layout for consistency
|
# Keep same vertical spacing as parent layout for consistency
|
||||||
formlayout.setVerticalSpacing(self.displayVLayout.spacing())
|
formlayout.setVerticalSpacing(self.displayVLayout.spacing())
|
||||||
@ -213,7 +219,7 @@ use the modifier key to drag the floating window around"
|
|||||||
details_groupbox.setLayout(self.details_groupbox_layout)
|
details_groupbox.setLayout(self.details_groupbox_layout)
|
||||||
self.displayVLayout.addWidget(details_groupbox)
|
self.displayVLayout.addWidget(details_groupbox)
|
||||||
|
|
||||||
def _setupDebugPage(self):
|
def _setupDebugPage(self) -> None:
|
||||||
self._setupAddCheckbox("debugModeBox", tr("Debug mode (restart required)"))
|
self._setupAddCheckbox("debugModeBox", tr("Debug mode (restart required)"))
|
||||||
self._setupAddCheckbox("profile_scan_box", tr("Profile scan operation"))
|
self._setupAddCheckbox("profile_scan_box", tr("Profile scan operation"))
|
||||||
self.profile_scan_box.setToolTip(tr("Profile the scan operation and save logs for optimization."))
|
self.profile_scan_box.setToolTip(tr("Profile the scan operation and save logs for optimization."))
|
||||||
@ -225,7 +231,7 @@ use the modifier key to drag the floating window around"
|
|||||||
)
|
)
|
||||||
self.debugVLayout.addWidget(self.debug_location_label)
|
self.debugVLayout.addWidget(self.debug_location_label)
|
||||||
|
|
||||||
def _setupAddCheckbox(self, name, label, parent=None):
|
def _setupAddCheckbox(self, name: str, label: str, parent: Union[QWidget, None] = None) -> None:
|
||||||
if parent is None:
|
if parent is None:
|
||||||
parent = self
|
parent = self
|
||||||
cb = QCheckBox(parent)
|
cb = QCheckBox(parent)
|
||||||
@ -236,7 +242,7 @@ use the modifier key to drag the floating window around"
|
|||||||
# Edition-specific
|
# Edition-specific
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def _setupUi(self):
|
def _setupUi(self) -> None:
|
||||||
self.setWindowTitle(tr("Options"))
|
self.setWindowTitle(tr("Options"))
|
||||||
self.setSizeGripEnabled(False)
|
self.setSizeGripEnabled(False)
|
||||||
self.setModal(True)
|
self.setModal(True)
|
||||||
@ -258,11 +264,13 @@ use the modifier key to drag the floating window around"
|
|||||||
# self.mainVLayout.addLayout(self.widgetsVLayout)
|
# self.mainVLayout.addLayout(self.widgetsVLayout)
|
||||||
self.buttonBox = QDialogButtonBox(self)
|
self.buttonBox = QDialogButtonBox(self)
|
||||||
self.buttonBox.setStandardButtons(
|
self.buttonBox.setStandardButtons(
|
||||||
QDialogButtonBox.Cancel | QDialogButtonBox.Ok | QDialogButtonBox.RestoreDefaults
|
QDialogButtonBox.StandardButton.Cancel
|
||||||
|
| QDialogButtonBox.StandardButton.Ok
|
||||||
|
| QDialogButtonBox.StandardButton.RestoreDefaults
|
||||||
)
|
)
|
||||||
self.mainVLayout.addWidget(self.tabwidget)
|
self.mainVLayout.addWidget(self.tabwidget)
|
||||||
self.mainVLayout.addWidget(self.buttonBox)
|
self.mainVLayout.addWidget(self.buttonBox)
|
||||||
self.layout().setSizeConstraint(QLayout.SetFixedSize)
|
self.layout().setSizeConstraint(QLayout.SizeConstraint.SetFixedSize)
|
||||||
self.tabwidget.addTab(self.page_general, tr("General"))
|
self.tabwidget.addTab(self.page_general, tr("General"))
|
||||||
self.tabwidget.addTab(self.page_display, tr("Display"))
|
self.tabwidget.addTab(self.page_display, tr("Display"))
|
||||||
self.tabwidget.addTab(self.page_debug, tr("Debug"))
|
self.tabwidget.addTab(self.page_debug, tr("Debug"))
|
||||||
@ -270,20 +278,20 @@ use the modifier key to drag the floating window around"
|
|||||||
self.widgetsVLayout.addStretch(0)
|
self.widgetsVLayout.addStretch(0)
|
||||||
self.debugVLayout.addStretch(0)
|
self.debugVLayout.addStretch(0)
|
||||||
|
|
||||||
def _load(self, prefs, setchecked, section):
|
def _load(self, prefs, setchecked, section) -> None:
|
||||||
# Edition-specific
|
# Edition-specific
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def _save(self, prefs, ischecked):
|
def _save(self, prefs, ischecked) -> None:
|
||||||
# Edition-specific
|
# Edition-specific
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def load(self, prefs=None, section=Sections.ALL):
|
def load(self, prefs: Preferences = None, section: Sections = Sections.ALL) -> None:
|
||||||
if prefs is None:
|
if prefs is None:
|
||||||
prefs = self.app.prefs
|
prefs = self.app.prefs
|
||||||
|
|
||||||
def setchecked(cb, b):
|
def setchecked(cb: QCheckBox, b: bool) -> None:
|
||||||
cb.setCheckState(Qt.Checked if b else Qt.Unchecked)
|
cb.setCheckState(Qt.CheckState.Checked if b else Qt.CheckState.Unchecked)
|
||||||
|
|
||||||
if section & Sections.GENERAL:
|
if section & Sections.GENERAL:
|
||||||
self.filterHardnessSlider.setValue(prefs.filter_hardness)
|
self.filterHardnessSlider.setValue(prefs.filter_hardness)
|
||||||
@ -323,12 +331,12 @@ use the modifier key to drag the floating window around"
|
|||||||
setchecked(self.profile_scan_box, prefs.profile_scan)
|
setchecked(self.profile_scan_box, prefs.profile_scan)
|
||||||
self._load(prefs, setchecked, section)
|
self._load(prefs, setchecked, section)
|
||||||
|
|
||||||
def save(self):
|
def save(self) -> None:
|
||||||
prefs = self.app.prefs
|
prefs = self.app.prefs
|
||||||
prefs.filter_hardness = self.filterHardnessSlider.value()
|
prefs.filter_hardness = self.filterHardnessSlider.value()
|
||||||
|
|
||||||
def ischecked(cb):
|
def ischecked(cb: QCheckBox) -> bool:
|
||||||
return cb.checkState() == Qt.Checked
|
return cb.checkState() == Qt.CheckState.Checked
|
||||||
|
|
||||||
prefs.mix_file_kind = ischecked(self.mixFileKindBox)
|
prefs.mix_file_kind = ischecked(self.mixFileKindBox)
|
||||||
prefs.use_regexp = ischecked(self.useRegexpBox)
|
prefs.use_regexp = ischecked(self.useRegexpBox)
|
||||||
@ -363,13 +371,13 @@ use the modifier key to drag the floating window around"
|
|||||||
self.app.prefs.language = lang_code
|
self.app.prefs.language = lang_code
|
||||||
self._save(prefs, ischecked)
|
self._save(prefs, ischecked)
|
||||||
|
|
||||||
def resetToDefaults(self, section_to_update):
|
def resetToDefaults(self, section_to_update: Sections) -> None:
|
||||||
self.load(Preferences(), section_to_update)
|
self.load(Preferences(), section_to_update)
|
||||||
|
|
||||||
# --- Events
|
# --- Events
|
||||||
def buttonClicked(self, button):
|
def buttonClicked(self, button: QPushButton) -> None:
|
||||||
role = self.buttonBox.buttonRole(button)
|
role = self.buttonBox.buttonRole(button)
|
||||||
if role == QDialogButtonBox.ResetRole:
|
if role == QDialogButtonBox.ButtonRole.ResetRole:
|
||||||
current_tab = self.tabwidget.currentWidget()
|
current_tab = self.tabwidget.currentWidget()
|
||||||
section_to_update = Sections.ALL
|
section_to_update = Sections.ALL
|
||||||
if current_tab is self.page_general:
|
if current_tab is self.page_general:
|
||||||
@ -380,30 +388,31 @@ use the modifier key to drag the floating window around"
|
|||||||
section_to_update = Sections.DEBUG
|
section_to_update = Sections.DEBUG
|
||||||
self.resetToDefaults(section_to_update)
|
self.resetToDefaults(section_to_update)
|
||||||
|
|
||||||
def showEvent(self, event):
|
def showEvent(self, event: QShowEvent) -> None:
|
||||||
# have to do this here as the frameGeometry is not correct until shown
|
# have to do this here as the frameGeometry is not correct until shown
|
||||||
move_to_screen_center(self)
|
move_to_screen_center(self)
|
||||||
super().showEvent(event)
|
super().showEvent(event)
|
||||||
|
|
||||||
|
|
||||||
class ColorPickerButton(QPushButton):
|
class ColorPickerButton(QPushButton):
|
||||||
def __init__(self, parent):
|
def __init__(self, parent: QWidget) -> None:
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self.parent = parent
|
|
||||||
self.color = None
|
self.color = None
|
||||||
self.clicked.connect(self.onClicked)
|
self.clicked.connect(self.onClicked)
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def onClicked(self):
|
def onClicked(self) -> None:
|
||||||
color = QColorDialog.getColor(self.color if self.color is not None else Qt.white, self.parent)
|
color = QColorDialog.getColor(
|
||||||
|
self.color if self.color is not None else Qt.GlobalColor.white, self.parentWidget()
|
||||||
|
)
|
||||||
self.setColor(color)
|
self.setColor(color)
|
||||||
|
|
||||||
def setColor(self, color):
|
def setColor(self, color) -> None:
|
||||||
size = QSize(16, 16)
|
size = QSize(16, 16)
|
||||||
px = QPixmap(size)
|
px = QPixmap(size)
|
||||||
if color is None:
|
if color is None:
|
||||||
size.width = 0
|
size.setWidth(0)
|
||||||
size.height = 0
|
size.setHeight(0)
|
||||||
elif not color.isValid():
|
elif not color.isValid():
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
|
@ -4,29 +4,23 @@
|
|||||||
# which should be included with this package. The terms are also available at
|
# which should be included with this package. The terms are also available at
|
||||||
# http://www.gnu.org/licenses/gpl-3.0.html
|
# http://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
|
||||||
from PyQt5.QtCore import QSize
|
from typing import Callable
|
||||||
from PyQt5.QtWidgets import (
|
from PyQt6.QtCore import QSize
|
||||||
QSpinBox,
|
from PyQt6.QtWidgets import QSpinBox, QVBoxLayout, QHBoxLayout, QLabel, QSizePolicy, QSpacerItem, QWidget, QCheckBox
|
||||||
QVBoxLayout,
|
|
||||||
QHBoxLayout,
|
|
||||||
QLabel,
|
|
||||||
QSizePolicy,
|
|
||||||
QSpacerItem,
|
|
||||||
QWidget,
|
|
||||||
)
|
|
||||||
|
|
||||||
from hscommon.trans import trget
|
from hscommon.trans import trget
|
||||||
|
|
||||||
from core.app import AppMode
|
from core.app import AppMode
|
||||||
from core.scanner import ScanType
|
from core.scanner import ScanType
|
||||||
|
from qt.preferences import Preferences
|
||||||
|
|
||||||
from qt.preferences_dialog import PreferencesDialogBase
|
from qt.preferences_dialog import PreferencesDialogBase, Sections
|
||||||
|
|
||||||
tr = trget("ui")
|
tr = trget("ui")
|
||||||
|
|
||||||
|
|
||||||
class PreferencesDialog(PreferencesDialogBase):
|
class PreferencesDialog(PreferencesDialogBase):
|
||||||
def _setupPreferenceWidgets(self):
|
def _setupPreferenceWidgets(self) -> None:
|
||||||
self._setupFilterHardnessBox()
|
self._setupFilterHardnessBox()
|
||||||
self.widgetsVLayout.addLayout(self.filterHardnessHLayout)
|
self.widgetsVLayout.addLayout(self.filterHardnessHLayout)
|
||||||
self.widget = QWidget(self)
|
self.widget = QWidget(self)
|
||||||
@ -50,7 +44,7 @@ class PreferencesDialog(PreferencesDialogBase):
|
|||||||
self._setupAddCheckbox("ignoreSmallFilesBox", tr("Ignore files smaller than"), self.widget)
|
self._setupAddCheckbox("ignoreSmallFilesBox", tr("Ignore files smaller than"), self.widget)
|
||||||
self.horizontalLayout_2.addWidget(self.ignoreSmallFilesBox)
|
self.horizontalLayout_2.addWidget(self.ignoreSmallFilesBox)
|
||||||
self.sizeThresholdSpinBox = QSpinBox(self.widget)
|
self.sizeThresholdSpinBox = QSpinBox(self.widget)
|
||||||
size_policy = QSizePolicy(QSizePolicy.Maximum, QSizePolicy.Fixed)
|
size_policy = QSizePolicy(QSizePolicy.Policy.Maximum, QSizePolicy.Policy.Fixed)
|
||||||
size_policy.setHorizontalStretch(0)
|
size_policy.setHorizontalStretch(0)
|
||||||
size_policy.setVerticalStretch(0)
|
size_policy.setVerticalStretch(0)
|
||||||
size_policy.setHeightForWidth(self.sizeThresholdSpinBox.sizePolicy().hasHeightForWidth())
|
size_policy.setHeightForWidth(self.sizeThresholdSpinBox.sizePolicy().hasHeightForWidth())
|
||||||
@ -61,14 +55,14 @@ class PreferencesDialog(PreferencesDialogBase):
|
|||||||
self.label_6 = QLabel(self.widget)
|
self.label_6 = QLabel(self.widget)
|
||||||
self.label_6.setText(tr("KB"))
|
self.label_6.setText(tr("KB"))
|
||||||
self.horizontalLayout_2.addWidget(self.label_6)
|
self.horizontalLayout_2.addWidget(self.label_6)
|
||||||
spacer_item1 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
|
spacer_item1 = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
|
||||||
self.horizontalLayout_2.addItem(spacer_item1)
|
self.horizontalLayout_2.addItem(spacer_item1)
|
||||||
self.verticalLayout_4.addLayout(self.horizontalLayout_2)
|
self.verticalLayout_4.addLayout(self.horizontalLayout_2)
|
||||||
self.horizontalLayout_2a = QHBoxLayout()
|
self.horizontalLayout_2a = QHBoxLayout()
|
||||||
self._setupAddCheckbox("ignoreLargeFilesBox", tr("Ignore files larger than"), self.widget)
|
self._setupAddCheckbox("ignoreLargeFilesBox", tr("Ignore files larger than"), self.widget)
|
||||||
self.horizontalLayout_2a.addWidget(self.ignoreLargeFilesBox)
|
self.horizontalLayout_2a.addWidget(self.ignoreLargeFilesBox)
|
||||||
self.sizeSaturationSpinBox = QSpinBox(self.widget)
|
self.sizeSaturationSpinBox = QSpinBox(self.widget)
|
||||||
size_policy = QSizePolicy(QSizePolicy.Maximum, QSizePolicy.Fixed)
|
size_policy = QSizePolicy(QSizePolicy.Policy.Maximum, QSizePolicy.Policy.Fixed)
|
||||||
self.sizeSaturationSpinBox.setSizePolicy(size_policy)
|
self.sizeSaturationSpinBox.setSizePolicy(size_policy)
|
||||||
self.sizeSaturationSpinBox.setMaximumSize(QSize(300, 16777215))
|
self.sizeSaturationSpinBox.setMaximumSize(QSize(300, 16777215))
|
||||||
self.sizeSaturationSpinBox.setRange(0, 1000000)
|
self.sizeSaturationSpinBox.setRange(0, 1000000)
|
||||||
@ -76,7 +70,7 @@ class PreferencesDialog(PreferencesDialogBase):
|
|||||||
self.label_6a = QLabel(self.widget)
|
self.label_6a = QLabel(self.widget)
|
||||||
self.label_6a.setText(tr("MB"))
|
self.label_6a.setText(tr("MB"))
|
||||||
self.horizontalLayout_2a.addWidget(self.label_6a)
|
self.horizontalLayout_2a.addWidget(self.label_6a)
|
||||||
spacer_item3 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
|
spacer_item3 = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
|
||||||
self.horizontalLayout_2a.addItem(spacer_item3)
|
self.horizontalLayout_2a.addItem(spacer_item3)
|
||||||
self.verticalLayout_4.addLayout(self.horizontalLayout_2a)
|
self.verticalLayout_4.addLayout(self.horizontalLayout_2a)
|
||||||
self.horizontalLayout_2b = QHBoxLayout()
|
self.horizontalLayout_2b = QHBoxLayout()
|
||||||
@ -94,7 +88,7 @@ class PreferencesDialog(PreferencesDialogBase):
|
|||||||
self.label_6b = QLabel(self.widget)
|
self.label_6b = QLabel(self.widget)
|
||||||
self.label_6b.setText(tr("MB"))
|
self.label_6b.setText(tr("MB"))
|
||||||
self.horizontalLayout_2b.addWidget(self.label_6b)
|
self.horizontalLayout_2b.addWidget(self.label_6b)
|
||||||
spacer_item2 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
|
spacer_item2 = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
|
||||||
self.horizontalLayout_2b.addItem(spacer_item2)
|
self.horizontalLayout_2b.addItem(spacer_item2)
|
||||||
self.verticalLayout_4.addLayout(self.horizontalLayout_2b)
|
self.verticalLayout_4.addLayout(self.horizontalLayout_2b)
|
||||||
self._setupAddCheckbox(
|
self._setupAddCheckbox(
|
||||||
@ -106,7 +100,7 @@ class PreferencesDialog(PreferencesDialogBase):
|
|||||||
self.widgetsVLayout.addWidget(self.widget)
|
self.widgetsVLayout.addWidget(self.widget)
|
||||||
self._setupBottomPart()
|
self._setupBottomPart()
|
||||||
|
|
||||||
def _load(self, prefs, setchecked, section):
|
def _load(self, prefs: Preferences, setchecked: Callable[[QCheckBox, bool], None], section: Sections) -> None:
|
||||||
setchecked(self.matchSimilarBox, prefs.match_similar)
|
setchecked(self.matchSimilarBox, prefs.match_similar)
|
||||||
setchecked(self.wordWeightingBox, prefs.word_weighting)
|
setchecked(self.wordWeightingBox, prefs.word_weighting)
|
||||||
setchecked(self.ignoreSmallFilesBox, prefs.ignore_small_files)
|
setchecked(self.ignoreSmallFilesBox, prefs.ignore_small_files)
|
||||||
@ -123,7 +117,7 @@ class PreferencesDialog(PreferencesDialogBase):
|
|||||||
self.matchSimilarBox.setEnabled(word_based)
|
self.matchSimilarBox.setEnabled(word_based)
|
||||||
self.wordWeightingBox.setEnabled(word_based)
|
self.wordWeightingBox.setEnabled(word_based)
|
||||||
|
|
||||||
def _save(self, prefs, ischecked):
|
def _save(self, prefs: Preferences, ischecked: Callable[[QCheckBox], bool]) -> None:
|
||||||
prefs.match_similar = ischecked(self.matchSimilarBox)
|
prefs.match_similar = ischecked(self.matchSimilarBox)
|
||||||
prefs.word_weighting = ischecked(self.wordWeightingBox)
|
prefs.word_weighting = ischecked(self.wordWeightingBox)
|
||||||
prefs.ignore_small_files = ischecked(self.ignoreSmallFilesBox)
|
prefs.ignore_small_files = ischecked(self.ignoreSmallFilesBox)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user