Compare commits
2 Commits
7dfaee6831
...
80a2c06b5a
| Author | SHA1 | Date | |
|---|---|---|---|
|
80a2c06b5a
|
|||
|
f0a4ace735
|
@@ -9,6 +9,10 @@ logger = get_logger(__name__)
|
|||||||
_portproton_location = None
|
_portproton_location = None
|
||||||
_portproton_start_sh = None
|
_portproton_start_sh = None
|
||||||
|
|
||||||
|
# Configuration cache for performance optimization
|
||||||
|
_config_cache = {}
|
||||||
|
_config_last_modified = {}
|
||||||
|
|
||||||
# Paths to configuration files
|
# Paths to configuration files
|
||||||
CONFIG_FILE = os.path.join(
|
CONFIG_FILE = os.path.join(
|
||||||
os.getenv("XDG_CONFIG_HOME", os.path.join(os.path.expanduser("~"), ".config")),
|
os.getenv("XDG_CONFIG_HOME", os.path.join(os.path.expanduser("~"), ".config")),
|
||||||
@@ -28,13 +32,35 @@ THEMES_DIRS = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
def read_config_safely(config_file: str) -> configparser.ConfigParser | None:
|
def read_config_safely(config_file: str) -> configparser.ConfigParser | None:
|
||||||
"""Safely reads a configuration file and returns a ConfigParser object or None if reading fails."""
|
"""Safely reads a configuration file and returns a ConfigParser object or None if reading fails.
|
||||||
cp = configparser.ConfigParser()
|
Uses caching to avoid repeated file reads for better performance.
|
||||||
|
"""
|
||||||
|
# Check if file exists
|
||||||
if not os.path.exists(config_file):
|
if not os.path.exists(config_file):
|
||||||
logger.debug(f"Configuration file {config_file} not found")
|
logger.debug(f"Configuration file {config_file} not found")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
# Get file modification time
|
||||||
|
try:
|
||||||
|
current_mtime = os.path.getmtime(config_file)
|
||||||
|
except OSError:
|
||||||
|
logger.warning(f"Failed to get modification time for {config_file}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Check if we have a cached version that's still valid
|
||||||
|
if config_file in _config_cache and config_file in _config_last_modified:
|
||||||
|
if _config_last_modified[config_file] == current_mtime:
|
||||||
|
logger.debug(f"Using cached config for {config_file}")
|
||||||
|
return _config_cache[config_file]
|
||||||
|
|
||||||
|
# Read and parse the config file
|
||||||
|
cp = configparser.ConfigParser()
|
||||||
try:
|
try:
|
||||||
cp.read(config_file, encoding="utf-8")
|
cp.read(config_file, encoding="utf-8")
|
||||||
|
# Update cache
|
||||||
|
_config_cache[config_file] = cp
|
||||||
|
_config_last_modified[config_file] = current_mtime
|
||||||
|
logger.debug(f"Config file {config_file} loaded and cached")
|
||||||
return cp
|
return cp
|
||||||
except (configparser.DuplicateSectionError, configparser.DuplicateOptionError) as e:
|
except (configparser.DuplicateSectionError, configparser.DuplicateOptionError) as e:
|
||||||
logger.warning(f"Invalid configuration file format: {e}")
|
logger.warning(f"Invalid configuration file format: {e}")
|
||||||
@@ -43,6 +69,14 @@ def read_config_safely(config_file: str) -> configparser.ConfigParser | None:
|
|||||||
logger.warning(f"Failed to read configuration file: {e}")
|
logger.warning(f"Failed to read configuration file: {e}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def invalidate_config_cache(config_file: str = CONFIG_FILE):
|
||||||
|
"""Invalidates the cached configuration for the specified file."""
|
||||||
|
if config_file in _config_cache:
|
||||||
|
del _config_cache[config_file]
|
||||||
|
if config_file in _config_last_modified:
|
||||||
|
del _config_last_modified[config_file]
|
||||||
|
logger.debug(f"Config cache invalidated for {config_file}")
|
||||||
|
|
||||||
def read_config():
|
def read_config():
|
||||||
"""Reads the configuration file and returns a dictionary of parameters.
|
"""Reads the configuration file and returns a dictionary of parameters.
|
||||||
Example line in config (no sections):
|
Example line in config (no sections):
|
||||||
@@ -77,6 +111,8 @@ def save_theme_to_config(theme_name):
|
|||||||
cp["Appearance"]["theme"] = theme_name
|
cp["Appearance"]["theme"] = theme_name
|
||||||
with open(CONFIG_FILE, "w", encoding="utf-8") as configfile:
|
with open(CONFIG_FILE, "w", encoding="utf-8") as configfile:
|
||||||
cp.write(configfile)
|
cp.write(configfile)
|
||||||
|
# Invalidate cache after saving
|
||||||
|
invalidate_config_cache()
|
||||||
|
|
||||||
def read_time_config():
|
def read_time_config():
|
||||||
"""Reads time settings from the [Time] section of the configuration file.
|
"""Reads time settings from the [Time] section of the configuration file.
|
||||||
@@ -96,6 +132,8 @@ def save_time_config(detail_level):
|
|||||||
cp["Time"]["detail_level"] = detail_level
|
cp["Time"]["detail_level"] = detail_level
|
||||||
with open(CONFIG_FILE, "w", encoding="utf-8") as configfile:
|
with open(CONFIG_FILE, "w", encoding="utf-8") as configfile:
|
||||||
cp.write(configfile)
|
cp.write(configfile)
|
||||||
|
# Invalidate cache after saving
|
||||||
|
invalidate_config_cache()
|
||||||
|
|
||||||
def read_file_content(file_path):
|
def read_file_content(file_path):
|
||||||
"""Reads the content of a file and returns it as a string."""
|
"""Reads the content of a file and returns it as a string."""
|
||||||
@@ -205,6 +243,8 @@ def save_card_size(card_width):
|
|||||||
cp["Cards"]["card_width"] = str(card_width)
|
cp["Cards"]["card_width"] = str(card_width)
|
||||||
with open(CONFIG_FILE, "w", encoding="utf-8") as configfile:
|
with open(CONFIG_FILE, "w", encoding="utf-8") as configfile:
|
||||||
cp.write(configfile)
|
cp.write(configfile)
|
||||||
|
# Invalidate cache after saving
|
||||||
|
invalidate_config_cache()
|
||||||
|
|
||||||
def read_auto_card_size():
|
def read_auto_card_size():
|
||||||
"""Reads the card size (width) for Auto Install from the [Cards] section.
|
"""Reads the card size (width) for Auto Install from the [Cards] section.
|
||||||
@@ -224,6 +264,8 @@ def save_auto_card_size(card_width):
|
|||||||
cp["Cards"]["auto_card_width"] = str(card_width)
|
cp["Cards"]["auto_card_width"] = str(card_width)
|
||||||
with open(CONFIG_FILE, "w", encoding="utf-8") as configfile:
|
with open(CONFIG_FILE, "w", encoding="utf-8") as configfile:
|
||||||
cp.write(configfile)
|
cp.write(configfile)
|
||||||
|
# Invalidate cache after saving
|
||||||
|
invalidate_config_cache()
|
||||||
|
|
||||||
|
|
||||||
def read_sort_method():
|
def read_sort_method():
|
||||||
@@ -244,6 +286,8 @@ def save_sort_method(sort_method):
|
|||||||
cp["Games"]["sort_method"] = sort_method
|
cp["Games"]["sort_method"] = sort_method
|
||||||
with open(CONFIG_FILE, "w", encoding="utf-8") as configfile:
|
with open(CONFIG_FILE, "w", encoding="utf-8") as configfile:
|
||||||
cp.write(configfile)
|
cp.write(configfile)
|
||||||
|
# Invalidate cache after saving
|
||||||
|
invalidate_config_cache()
|
||||||
|
|
||||||
def read_display_filter():
|
def read_display_filter():
|
||||||
"""Reads the display_filter parameter from the [Games] section.
|
"""Reads the display_filter parameter from the [Games] section.
|
||||||
@@ -263,6 +307,8 @@ def save_display_filter(filter_value):
|
|||||||
cp["Games"]["display_filter"] = filter_value
|
cp["Games"]["display_filter"] = filter_value
|
||||||
with open(CONFIG_FILE, "w", encoding="utf-8") as configfile:
|
with open(CONFIG_FILE, "w", encoding="utf-8") as configfile:
|
||||||
cp.write(configfile)
|
cp.write(configfile)
|
||||||
|
# Invalidate cache after saving
|
||||||
|
invalidate_config_cache()
|
||||||
|
|
||||||
def read_favorites():
|
def read_favorites():
|
||||||
"""Reads the list of favorite games from the [Favorites] section.
|
"""Reads the list of favorite games from the [Favorites] section.
|
||||||
@@ -288,6 +334,8 @@ def save_favorites(favorites):
|
|||||||
cp["Favorites"]["games"] = f'"{fav_str}"'
|
cp["Favorites"]["games"] = f'"{fav_str}"'
|
||||||
with open(CONFIG_FILE, "w", encoding="utf-8") as configfile:
|
with open(CONFIG_FILE, "w", encoding="utf-8") as configfile:
|
||||||
cp.write(configfile)
|
cp.write(configfile)
|
||||||
|
# Invalidate cache after saving
|
||||||
|
invalidate_config_cache()
|
||||||
|
|
||||||
def read_rumble_config():
|
def read_rumble_config():
|
||||||
"""Reads the gamepad rumble setting from the [Gamepad] section.
|
"""Reads the gamepad rumble setting from the [Gamepad] section.
|
||||||
@@ -307,6 +355,8 @@ def save_rumble_config(rumble_enabled):
|
|||||||
cp["Gamepad"]["rumble_enabled"] = str(rumble_enabled)
|
cp["Gamepad"]["rumble_enabled"] = str(rumble_enabled)
|
||||||
with open(CONFIG_FILE, "w", encoding="utf-8") as configfile:
|
with open(CONFIG_FILE, "w", encoding="utf-8") as configfile:
|
||||||
cp.write(configfile)
|
cp.write(configfile)
|
||||||
|
# Invalidate cache after saving
|
||||||
|
invalidate_config_cache()
|
||||||
|
|
||||||
def read_gamepad_type():
|
def read_gamepad_type():
|
||||||
"""Reads the gamepad type from the [Gamepad] section.
|
"""Reads the gamepad type from the [Gamepad] section.
|
||||||
@@ -326,6 +376,8 @@ def save_gamepad_type(gpad_type):
|
|||||||
cp["Gamepad"]["type"] = gpad_type
|
cp["Gamepad"]["type"] = gpad_type
|
||||||
with open(CONFIG_FILE, "w", encoding="utf-8") as configfile:
|
with open(CONFIG_FILE, "w", encoding="utf-8") as configfile:
|
||||||
cp.write(configfile)
|
cp.write(configfile)
|
||||||
|
# Invalidate cache after saving
|
||||||
|
invalidate_config_cache()
|
||||||
|
|
||||||
def ensure_default_proxy_config():
|
def ensure_default_proxy_config():
|
||||||
"""Ensures the [Proxy] section exists in the configuration file.
|
"""Ensures the [Proxy] section exists in the configuration file.
|
||||||
@@ -370,6 +422,8 @@ def save_proxy_config(proxy_url="", proxy_user="", proxy_password=""):
|
|||||||
cp["Proxy"]["proxy_password"] = proxy_password
|
cp["Proxy"]["proxy_password"] = proxy_password
|
||||||
with open(CONFIG_FILE, "w", encoding="utf-8") as configfile:
|
with open(CONFIG_FILE, "w", encoding="utf-8") as configfile:
|
||||||
cp.write(configfile)
|
cp.write(configfile)
|
||||||
|
# Invalidate cache after saving
|
||||||
|
invalidate_config_cache()
|
||||||
|
|
||||||
def read_fullscreen_config():
|
def read_fullscreen_config():
|
||||||
"""Reads the fullscreen mode setting from the [Display] section.
|
"""Reads the fullscreen mode setting from the [Display] section.
|
||||||
@@ -389,6 +443,8 @@ def save_fullscreen_config(fullscreen):
|
|||||||
cp["Display"]["fullscreen"] = str(fullscreen)
|
cp["Display"]["fullscreen"] = str(fullscreen)
|
||||||
with open(CONFIG_FILE, "w", encoding="utf-8") as configfile:
|
with open(CONFIG_FILE, "w", encoding="utf-8") as configfile:
|
||||||
cp.write(configfile)
|
cp.write(configfile)
|
||||||
|
# Invalidate cache after saving
|
||||||
|
invalidate_config_cache()
|
||||||
|
|
||||||
def read_window_geometry() -> tuple[int, int]:
|
def read_window_geometry() -> tuple[int, int]:
|
||||||
"""Reads the window width and height from the [MainWindow] section.
|
"""Reads the window width and height from the [MainWindow] section.
|
||||||
@@ -410,6 +466,8 @@ def save_window_geometry(width: int, height: int):
|
|||||||
cp["MainWindow"]["height"] = str(height)
|
cp["MainWindow"]["height"] = str(height)
|
||||||
with open(CONFIG_FILE, "w", encoding="utf-8") as configfile:
|
with open(CONFIG_FILE, "w", encoding="utf-8") as configfile:
|
||||||
cp.write(configfile)
|
cp.write(configfile)
|
||||||
|
# Invalidate cache after saving
|
||||||
|
invalidate_config_cache()
|
||||||
|
|
||||||
def reset_config():
|
def reset_config():
|
||||||
"""Resets the configuration file by deleting it.
|
"""Resets the configuration file by deleting it.
|
||||||
@@ -419,6 +477,8 @@ def reset_config():
|
|||||||
try:
|
try:
|
||||||
os.remove(CONFIG_FILE)
|
os.remove(CONFIG_FILE)
|
||||||
logger.info("Configuration file %s deleted", CONFIG_FILE)
|
logger.info("Configuration file %s deleted", CONFIG_FILE)
|
||||||
|
# Invalidate cache after deletion
|
||||||
|
invalidate_config_cache()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(f"Failed to delete configuration file: {e}")
|
logger.warning(f"Failed to delete configuration file: {e}")
|
||||||
|
|
||||||
@@ -433,6 +493,9 @@ def clear_cache():
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(f"Failed to delete cache: {e}")
|
logger.warning(f"Failed to delete cache: {e}")
|
||||||
|
|
||||||
|
# Also clear our internal config cache
|
||||||
|
invalidate_config_cache()
|
||||||
|
|
||||||
def read_auto_fullscreen_gamepad():
|
def read_auto_fullscreen_gamepad():
|
||||||
"""Reads the auto-fullscreen setting for gamepad from the [Display] section.
|
"""Reads the auto-fullscreen setting for gamepad from the [Display] section.
|
||||||
Returns False if the parameter is missing.
|
Returns False if the parameter is missing.
|
||||||
@@ -451,6 +514,8 @@ def save_auto_fullscreen_gamepad(auto_fullscreen):
|
|||||||
cp["Display"]["auto_fullscreen_gamepad"] = str(auto_fullscreen)
|
cp["Display"]["auto_fullscreen_gamepad"] = str(auto_fullscreen)
|
||||||
with open(CONFIG_FILE, "w", encoding="utf-8") as configfile:
|
with open(CONFIG_FILE, "w", encoding="utf-8") as configfile:
|
||||||
cp.write(configfile)
|
cp.write(configfile)
|
||||||
|
# Invalidate cache after saving
|
||||||
|
invalidate_config_cache()
|
||||||
|
|
||||||
def read_favorite_folders():
|
def read_favorite_folders():
|
||||||
"""Reads the list of favorite folders from the [FavoritesFolders] section.
|
"""Reads the list of favorite folders from the [FavoritesFolders] section.
|
||||||
@@ -476,6 +541,8 @@ def save_favorite_folders(folders):
|
|||||||
cp["FavoritesFolders"]["folders"] = f'"{fav_str}"'
|
cp["FavoritesFolders"]["folders"] = f'"{fav_str}"'
|
||||||
with open(CONFIG_FILE, "w", encoding="utf-8") as configfile:
|
with open(CONFIG_FILE, "w", encoding="utf-8") as configfile:
|
||||||
cp.write(configfile)
|
cp.write(configfile)
|
||||||
|
# Invalidate cache after saving
|
||||||
|
invalidate_config_cache()
|
||||||
|
|
||||||
def read_minimize_to_tray():
|
def read_minimize_to_tray():
|
||||||
"""Reads the minimize-to-tray setting from the [Display] section.
|
"""Reads the minimize-to-tray setting from the [Display] section.
|
||||||
@@ -495,3 +562,5 @@ def save_minimize_to_tray(minimize_to_tray):
|
|||||||
cp["Display"]["minimize_to_tray"] = str(minimize_to_tray)
|
cp["Display"]["minimize_to_tray"] = str(minimize_to_tray)
|
||||||
with open(CONFIG_FILE, "w", encoding="utf-8") as configfile:
|
with open(CONFIG_FILE, "w", encoding="utf-8") as configfile:
|
||||||
cp.write(configfile)
|
cp.write(configfile)
|
||||||
|
# Invalidate cache after saving
|
||||||
|
invalidate_config_cache()
|
||||||
|
|||||||
@@ -565,6 +565,16 @@ class MainWindow(QMainWindow):
|
|||||||
self.game_library_manager.set_games(games)
|
self.game_library_manager.set_games(games)
|
||||||
self.progress_bar.setVisible(False)
|
self.progress_bar.setVisible(False)
|
||||||
|
|
||||||
|
# Clear the refresh in progress flag
|
||||||
|
if hasattr(self, '_refresh_in_progress'):
|
||||||
|
self._refresh_in_progress = False
|
||||||
|
|
||||||
|
# Re-enable the refresh button if it exists
|
||||||
|
if hasattr(self, 'refreshButton'):
|
||||||
|
self.refreshButton.setEnabled(True)
|
||||||
|
self.refreshButton.setText(_("Refresh Grid"))
|
||||||
|
self.update_status_message.emit(_("Game library refreshed"), 3000)
|
||||||
|
|
||||||
def open_portproton_forum_topic(self, topic_name: str):
|
def open_portproton_forum_topic(self, topic_name: str):
|
||||||
"""Open the PortProton forum topic or search page for this game."""
|
"""Open the PortProton forum topic or search page for this game."""
|
||||||
result = self.portproton_api.get_forum_topic_slug(topic_name)
|
result = self.portproton_api.get_forum_topic_slug(topic_name)
|
||||||
@@ -881,7 +891,16 @@ class MainWindow(QMainWindow):
|
|||||||
self.addGameButton.setStyleSheet(self.theme.ADDGAME_BACK_BUTTON_STYLE)
|
self.addGameButton.setStyleSheet(self.theme.ADDGAME_BACK_BUTTON_STYLE)
|
||||||
self.addGameButton.setFocusPolicy(Qt.FocusPolicy.NoFocus)
|
self.addGameButton.setFocusPolicy(Qt.FocusPolicy.NoFocus)
|
||||||
self.addGameButton.clicked.connect(self.openAddGameDialog)
|
self.addGameButton.clicked.connect(self.openAddGameDialog)
|
||||||
layout.addWidget(self.addGameButton, alignment=Qt.AlignmentFlag.AlignRight)
|
layout.addWidget(self.addGameButton)
|
||||||
|
|
||||||
|
# Refresh button
|
||||||
|
self.refreshButton = AutoSizeButton(_("Refresh Grid"), icon=self.theme_manager.get_icon("update"))
|
||||||
|
self.refreshButton.setStyleSheet(self.theme.ADDGAME_BACK_BUTTON_STYLE)
|
||||||
|
self.refreshButton.setFocusPolicy(Qt.FocusPolicy.NoFocus)
|
||||||
|
self.refreshButton.clicked.connect(self.refreshGames)
|
||||||
|
layout.addWidget(self.refreshButton)
|
||||||
|
|
||||||
|
layout.addStretch() # Add stretch to push search to the right
|
||||||
|
|
||||||
self.searchEdit = CustomLineEdit(self, theme=self.theme)
|
self.searchEdit = CustomLineEdit(self, theme=self.theme)
|
||||||
icon: QIcon = cast(QIcon, self.theme_manager.get_icon("search"))
|
icon: QIcon = cast(QIcon, self.theme_manager.get_icon("search"))
|
||||||
@@ -901,6 +920,32 @@ class MainWindow(QMainWindow):
|
|||||||
layout.addWidget(self.searchEdit)
|
layout.addWidget(self.searchEdit)
|
||||||
return self.container, self.searchEdit
|
return self.container, self.searchEdit
|
||||||
|
|
||||||
|
def refreshGames(self):
|
||||||
|
"""Refresh the game grid by reloading all games without restarting the application."""
|
||||||
|
# Prevent multiple refreshes at once
|
||||||
|
if hasattr(self, '_refresh_in_progress') and self._refresh_in_progress:
|
||||||
|
# If refresh is already in progress, just update the status
|
||||||
|
self.update_status_message.emit(_("A refresh is already in progress..."), 3000)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Mark that a refresh is in progress
|
||||||
|
self._refresh_in_progress = True
|
||||||
|
|
||||||
|
# Clear the search field to ensure all games are shown after refresh
|
||||||
|
self.searchEdit.clear()
|
||||||
|
|
||||||
|
# Disable the refresh button during refresh to prevent multiple clicks
|
||||||
|
self.refreshButton.setEnabled(False)
|
||||||
|
self.refreshButton.setText(_("Refreshing..."))
|
||||||
|
|
||||||
|
# Show progress bar
|
||||||
|
self.progress_bar.setVisible(True)
|
||||||
|
self.progress_bar.setRange(0, 0) # Indeterminate
|
||||||
|
self.update_status_message.emit(_("Refreshing game library..."), 0)
|
||||||
|
|
||||||
|
# Reload games using the existing loadGames functionality
|
||||||
|
QTimer.singleShot(0, self.loadGames)
|
||||||
|
|
||||||
def on_search_text_changed(self, text: str):
|
def on_search_text_changed(self, text: str):
|
||||||
"""Search text change handler with debounce."""
|
"""Search text change handler with debounce."""
|
||||||
self.searchDebounceTimer.stop()
|
self.searchDebounceTimer.stop()
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ from portprotonqt.logger import get_logger
|
|||||||
from PySide6.QtGui import QIcon, QFontDatabase, QPixmap
|
from PySide6.QtGui import QIcon, QFontDatabase, QPixmap
|
||||||
from portprotonqt.config_utils import save_theme_to_config, load_theme_metainfo
|
from portprotonqt.config_utils import save_theme_to_config, load_theme_metainfo
|
||||||
|
|
||||||
|
# Icon caching for performance optimization
|
||||||
|
_icon_cache = {}
|
||||||
|
|
||||||
logger = get_logger(__name__)
|
logger = get_logger(__name__)
|
||||||
|
|
||||||
# Папка, где располагаются все дополнительные темы
|
# Папка, где располагаются все дополнительные темы
|
||||||
@@ -232,6 +235,14 @@ class ThemeManager:
|
|||||||
а если файл не найден, то из стандартной темы.
|
а если файл не найден, то из стандартной темы.
|
||||||
Если as_path=True, возвращает путь к иконке вместо QIcon.
|
Если as_path=True, возвращает путь к иконке вместо QIcon.
|
||||||
"""
|
"""
|
||||||
|
# Create cache key
|
||||||
|
cache_key = f"{icon_name}_{theme_name or self.current_theme_name}_{as_path}"
|
||||||
|
|
||||||
|
# Check if we already have this icon cached
|
||||||
|
if cache_key in _icon_cache:
|
||||||
|
logger.debug(f"Using cached icon for {icon_name}")
|
||||||
|
return _icon_cache[cache_key]
|
||||||
|
|
||||||
icon_path = None
|
icon_path = None
|
||||||
theme_name = theme_name or self.current_theme_name
|
theme_name = theme_name or self.current_theme_name
|
||||||
supported_extensions = ['.svg', '.png', '.jpg', '.jpeg']
|
supported_extensions = ['.svg', '.png', '.jpg', '.jpeg']
|
||||||
@@ -279,12 +290,20 @@ class ThemeManager:
|
|||||||
# Если иконка всё равно не найдена
|
# Если иконка всё равно не найдена
|
||||||
if not icon_path or not os.path.exists(icon_path):
|
if not icon_path or not os.path.exists(icon_path):
|
||||||
logger.error(f"Warning: icon '{icon_name}' not found")
|
logger.error(f"Warning: icon '{icon_name}' not found")
|
||||||
return QIcon() if not as_path else None
|
result = QIcon() if not as_path else None
|
||||||
|
# Cache the result even if it's None
|
||||||
|
_icon_cache[cache_key] = result
|
||||||
|
return result
|
||||||
|
|
||||||
if as_path:
|
if as_path:
|
||||||
|
# Cache the path
|
||||||
|
_icon_cache[cache_key] = icon_path
|
||||||
return icon_path
|
return icon_path
|
||||||
|
|
||||||
return QIcon(icon_path)
|
# Create QIcon and cache it
|
||||||
|
icon = QIcon(icon_path)
|
||||||
|
_icon_cache[cache_key] = icon
|
||||||
|
return icon
|
||||||
|
|
||||||
def get_theme_image(self, image_name, theme_name=None):
|
def get_theme_image(self, image_name, theme_name=None):
|
||||||
"""
|
"""
|
||||||
|
|||||||
Reference in New Issue
Block a user