This commit is contained in:
Ignacio Serantes
2026-03-25 22:02:13 +01:00
parent 56ef674d4a
commit dfddfd17b3
10 changed files with 430 additions and 53 deletions

View File

@@ -14,7 +14,7 @@ Classes:
MainWindow: The main application window containing the thumbnail grid and docks.
"""
__appname__ = "BagheeraView"
__version__ = "0.9.12"
__version__ = "0.9.13"
__author__ = "Ignacio Serantes"
__email__ = "kde@aynoa.net"
__license__ = "LGPL"
@@ -55,7 +55,7 @@ from pathlib import Path
from constants import (
APP_CONFIG, CONFIG_PATH, CURRENT_LANGUAGE, DEFAULT_GLOBAL_SHORTCUTS,
DEFAULT_VIEWER_SHORTCUTS, GLOBAL_ACTIONS, HISTORY_PATH, ICON_THEME,
ICON_THEME_FALLBACK, IMAGE_MIME_TYPES, LAYOUTS_DIR, PROG_AUTHOR,
ICON_THEME_FALLBACK, IMAGE_MIME_TYPES, LAYOUTS_DIR, FAVORITES_PATH, PROG_AUTHOR,
PROG_NAME, PROG_VERSION, RATING_XATTR_NAME, SCANNER_GENERATE_SIZES,
SCANNER_SETTINGS_DEFAULTS, SUPPORTED_LANGUAGES, TAGS_MENU_MAX_ITEMS_DEFAULT,
THUMBNAILS_BG_COLOR_DEFAULT, THUMBNAILS_DEFAULT_SIZE, VIEWER_ACTIONS,
@@ -74,7 +74,8 @@ from imageviewer import ImageViewer
from propertiesdialog import PropertiesDialog
from widgets import (
CircularProgressBar,
TagEditWidget, LayoutsWidget, HistoryWidget, RatingWidget, CommentWidget
TagEditWidget, LayoutsWidget, HistoryWidget, RatingWidget, CommentWidget,
FavoritesWidget
)
from metadatamanager import XattrManager
@@ -255,16 +256,13 @@ class ShortcutHelpDialog(QDialog):
new_mods = new_key_combo.keyboardModifiers()
new_key_tuple = (int(new_key), new_mods)
# Check for conflicts in the same scope
if new_key_tuple in source_dict and new_key_tuple != original_key_combo:
# Handle different value structures
val = source_dict[new_key_tuple]
# Global: (action, ignore, desc, category), Viewer: (action, desc)
if len(val) == 4:
conflict_desc = val[2]
else:
conflict_desc = val[1]
# Check for conflicts globally
conflict_desc = self.main_win.shortcut_controller.check_conflict(
new_key, new_mods)
is_same = (new_key_tuple == original_key_combo)
if conflict_desc and not is_same:
QMessageBox.warning(self, UITexts.SHORTCUT_CONFLICT_TITLE,
UITexts.SHORTCUT_CONFLICT_TEXT.format(
new_sequence.toString(QKeySequence.NativeText),
@@ -300,6 +298,7 @@ class AppShortcutController(QObject):
self.main_win = main_win
self._actions = self._get_actions()
self._shortcuts = {}
self._favorite_shortcuts = {}
self.action_to_shortcut = {}
self._register_shortcuts()
@@ -317,6 +316,44 @@ class AppShortcutController(QObject):
key_tuple = (k, Qt.KeyboardModifiers(m))
self._shortcuts[key_tuple] = (act, ignore, desc, cat)
self.action_to_shortcut[act] = key_tuple
self.refresh_favorite_shortcuts()
def refresh_favorite_shortcuts(self):
"""Loads dynamic shortcuts assigned to favorite queries."""
self._favorite_shortcuts.clear()
if not os.path.exists(FAVORITES_PATH):
return
try:
with open(FAVORITES_PATH, 'r', encoding='utf-8') as f:
favorites = json.load(f)
for fav in favorites:
sc_str = fav.get('shortcut', '')
if sc_str:
seq = QKeySequence(sc_str)
if not seq.isEmpty():
self._favorite_shortcuts[
(seq[0].key(), seq[0].keyboardModifiers())
] = fav.get('query')
except (json.JSONDecodeError, OSError):
pass
def check_conflict(self, key, mods):
"""Checks if a shortcut is already assigned and returns its description."""
key_tuple = (int(key), mods)
# Global
if key_tuple in self._shortcuts:
return self._shortcuts[key_tuple][2]
# Viewer
if key_tuple in self.main_win.viewer_shortcuts:
return self.main_win.viewer_shortcuts[key_tuple][1]
# Favorites
if key_tuple in self._favorite_shortcuts:
return f"{UITexts.FAVORITES_TAB}: {self._favorite_shortcuts[key_tuple]}"
return None
def _get_actions(self):
"""Returns a dictionary mapping action strings to callable functions."""
@@ -375,6 +412,12 @@ class AppShortcutController(QObject):
if is_typing:
return False
# 1. Check Favorite Shortcuts FIRST (Priority Override)
if (key, mods) in self._favorite_shortcuts:
query = self._favorite_shortcuts[(key, mods)]
self.main_win.process_term(query)
return True
# Check if we have a handler for this combination
if (key, mods) in self._shortcuts:
action_name, ignore_if_typing, _, _ = self._shortcuts[(key, mods)]
@@ -1172,16 +1215,26 @@ class MainWindow(QMainWindow):
self.tags_tabs.addTab(self.filter_widget, UITexts.TAG_FILTER_TAB)
# Tab 4: Layouts
# Tab 4: Favorites
self.favorites_tab = FavoritesWidget(self)
self.tags_tabs.addTab(self.favorites_tab, UITexts.FAVORITES_TAB)
# Tab 5: Layouts
self.is_xcb = QApplication.platformName() == "xcb"
if self.is_xcb:
self.layouts_tab = LayoutsWidget(self)
self.tags_tabs.addTab(self.layouts_tab, UITexts.LAYOUTS_TAB)
# Tab 5: History
# Tab 6: History
self.history_tab = HistoryWidget(self)
self.tags_tabs.addTab(self.history_tab, UITexts.HISTORY_TAB)
# Initialize the shortcut controller
self.shortcut_controller = AppShortcutController(self)
self.favorites_tab.favorites_changed.connect(
self.shortcut_controller.refresh_favorite_shortcuts)
self.main_dock.setWidget(self.tags_tabs)
self.addDockWidget(Qt.RightDockWidgetArea, self.main_dock)
@@ -1233,6 +1286,11 @@ class MainWindow(QMainWindow):
self.load_config()
self.load_full_history()
# Initialize the shortcut controller (after config is loaded)
self.shortcut_controller = AppShortcutController(self)
self.favorites_tab.favorites_changed.connect(
self.shortcut_controller.refresh_favorite_shortcuts)
self._apply_global_stylesheet()
# Set the initial thumbnail generation tier based on the loaded config size
self._current_thumb_tier = self._get_tier_for_size(self.current_thumb_size)
@@ -1558,15 +1616,23 @@ class MainWindow(QMainWindow):
# Actions to show different tabs in the dock
show_tags_action = menu.addAction(QIcon.fromTheme("document-properties"),
UITexts.MENU_SHOW_TAGS)
show_tags_action.triggered.connect(lambda: self.open_sidebar_tab(0))
show_tags_action.triggered.connect(
lambda: self.open_sidebar_tab(self.tags_tabs.indexOf(self.tag_edit_widget)))
show_info_action = menu.addAction(QIcon.fromTheme("dialog-information"),
UITexts.MENU_SHOW_INFO)
show_info_action.triggered.connect(lambda: self.open_sidebar_tab(1))
show_info_action.triggered.connect(
lambda: self.open_sidebar_tab(self.tags_tabs.indexOf(self.info_widget)))
show_favorites_action = menu.addAction(QIcon.fromTheme("bookmarks"),
UITexts.MENU_SHOW_FAVORITES)
f_idx = self.tags_tabs.indexOf(self.favorites_tab)
show_favorites_action.triggered.connect(lambda: self.open_sidebar_tab(f_idx))
show_filter_action = menu.addAction(QIcon.fromTheme("view-filter"),
UITexts.MENU_SHOW_FILTER)
show_filter_action.triggered.connect(lambda: self.open_sidebar_tab(2))
show_filter_action.triggered.connect(
lambda: self.open_sidebar_tab(self.tags_tabs.indexOf(self.filter_widget)))
if self.is_xcb:
show_layouts_action = menu.addAction(QIcon.fromTheme("view-grid"),
@@ -2911,6 +2977,8 @@ class MainWindow(QMainWindow):
self.update_tag_list()
elif widget == self.info_widget:
self.update_info_widget()
elif widget == self.favorites_tab:
self.favorites_tab.refresh_list()
def update_tag_edit_widget(self):
"""Updates the tag editor widget with data from the currently selected files."""
@@ -3852,7 +3920,7 @@ class MainWindow(QMainWindow):
self.proxy_model.data(index_at_pos, ITEM_TYPE_ROLE) == 'header':
group_name = self.proxy_model.data(index_at_pos, GROUP_NAME_ROLE)
if group_name:
action_toggle = menu.addAction("Collapse/Expand Group")
action_toggle = menu.addAction(UITexts.COLLAPSE_EXPAND_GROUP)
action_toggle.triggered.connect(
lambda: self.toggle_group_collapse(group_name))
menu.exec(self.thumbnail_view.mapToGlobal(pos))
@@ -4006,7 +4074,7 @@ class MainWindow(QMainWindow):
self.on_high_res_generation_finished)
self.thumbnail_generator.progress.connect(
lambda p, t: self.status_lbl.setText(
f"Regenerating thumbnail: {p}/{t}")
UITexts.THUMBNAILS_REGENERATE_PROGRESS.format(p, t))
)
self.thumbnail_generator.start()
@@ -4397,9 +4465,7 @@ def main():
path = path[6:]
win = MainWindow(cache, args, thread_pool_manager)
shortcut_controller = AppShortcutController(win)
win.shortcut_controller = shortcut_controller
app.installEventFilter(shortcut_controller)
app.installEventFilter(win.shortcut_controller)
sys.exit(app.exec())