New Definitions editor
This commit is contained in:
@@ -1,12 +1,12 @@
|
||||
import logging
|
||||
from PySide6.QtWidgets import (
|
||||
QDialog, QVBoxLayout, QTabWidget, QWidget, QListWidget, QPushButton,
|
||||
QDialog, QVBoxLayout, QTabWidget, QWidget, QListWidget, QListWidgetItem, QPushButton,
|
||||
QHBoxLayout, QLabel, QGroupBox, QDialogButtonBox, QFormLayout,
|
||||
QTextEdit, QColorDialog, QInputDialog, QMessageBox, QFrame, QComboBox,
|
||||
QLineEdit, QCheckBox
|
||||
QLineEdit, QCheckBox, QAbstractItemView
|
||||
)
|
||||
from PySide6.QtGui import QColor, QPalette
|
||||
from PySide6.QtCore import Qt
|
||||
from PySide6.QtGui import QColor, QPalette, QMouseEvent # Added QMouseEvent
|
||||
from PySide6.QtCore import Qt, QEvent
|
||||
|
||||
# Assuming load_asset_definitions, load_file_type_definitions, load_supplier_settings
|
||||
# are in configuration.py at the root level.
|
||||
@@ -38,6 +38,17 @@ except ImportError as e:
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class DebugListWidget(QListWidget):
|
||||
def mousePressEvent(self, event: QMouseEvent): # QMouseEvent needs to be imported from PySide6.QtGui
|
||||
logger.info(f"DebugListWidget.mousePressEvent: pos={event.pos()}")
|
||||
item = self.itemAt(event.pos())
|
||||
if item:
|
||||
logger.info(f"DebugListWidget.mousePressEvent: Item under cursor: {item.text()}")
|
||||
else:
|
||||
logger.info("DebugListWidget.mousePressEvent: No item under cursor.")
|
||||
super().mousePressEvent(event)
|
||||
logger.info("DebugListWidget.mousePressEvent: super call finished.")
|
||||
|
||||
class DefinitionsEditorDialog(QDialog):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
@@ -48,6 +59,7 @@ class DefinitionsEditorDialog(QDialog):
|
||||
self.file_type_data = {}
|
||||
self.supplier_data = {}
|
||||
self.unsaved_changes = False # For unsaved changes tracking
|
||||
self.asset_types_tab_page_for_filtering = None # For event filtering
|
||||
|
||||
self._load_all_definitions()
|
||||
|
||||
@@ -64,6 +76,8 @@ class DefinitionsEditorDialog(QDialog):
|
||||
main_layout.addWidget(self.button_box)
|
||||
|
||||
self.setLayout(main_layout)
|
||||
# self.tab_widget.installEventFilter(self) # Temporarily disable event filter on tab_widget for this test
|
||||
# logger.info(f"Event filter on self.tab_widget ({self.tab_widget}) TEMPORARILY DISABLED for DebugListWidget test.")
|
||||
|
||||
def _load_all_definitions(self):
|
||||
logger.info("Loading all definitions...")
|
||||
@@ -95,8 +109,45 @@ class DefinitionsEditorDialog(QDialog):
|
||||
self.tab_widget.addTab(self._create_file_types_tab(), "File Type Definitions")
|
||||
self.tab_widget.addTab(self._create_suppliers_tab(), "Supplier Settings")
|
||||
|
||||
# Add a diagnostic button
|
||||
self.diag_button = QPushButton("Test Select Item 2 (Asset)")
|
||||
self.diag_button.clicked.connect(self._run_diag_selection)
|
||||
# Assuming main_layout is accessible here or passed if _create_ui is part of __init__
|
||||
# If main_layout is self.layout() established in __init__
|
||||
if self.layout(): # Check if layout exists
|
||||
self.layout().addWidget(self.diag_button)
|
||||
else:
|
||||
logger.error("Main layout not found for diagnostic button in _create_ui. Button not added.")
|
||||
|
||||
|
||||
def _run_diag_selection(self):
|
||||
logger.info("Diagnostic button clicked. Attempting to select second item in asset_type_list_widget.")
|
||||
if hasattr(self, 'asset_type_list_widget') and self.asset_type_list_widget.count() > 1:
|
||||
logger.info(f"Asset type list widget isEnabled: {self.asset_type_list_widget.isEnabled()}") # Check if enabled
|
||||
logger.info(f"Asset type list widget signalsBlocked: {self.asset_type_list_widget.signalsBlocked()}")
|
||||
|
||||
self.asset_type_list_widget.setFocus() # Explicitly set focus
|
||||
logger.info(f"Attempted to set focus to asset_type_list_widget. Has focus: {self.asset_type_list_widget.hasFocus()}")
|
||||
|
||||
item_to_select = self.asset_type_list_widget.item(1) # Select the second item (index 1)
|
||||
if item_to_select:
|
||||
logger.info(f"Programmatically selecting: {item_to_select.text()}")
|
||||
self.asset_type_list_widget.setCurrentItem(item_to_select)
|
||||
# Check if it's actually selected
|
||||
if self.asset_type_list_widget.currentItem() == item_to_select:
|
||||
logger.info(f"Programmatic selection successful. Current item is now: {self.asset_type_list_widget.currentItem().text()}")
|
||||
else:
|
||||
logger.warning("Programmatic selection FAILED. Current item did not change as expected.")
|
||||
else:
|
||||
logger.warning("Second item not found in asset_type_list_widget.")
|
||||
elif hasattr(self, 'asset_type_list_widget'):
|
||||
logger.warning("asset_type_list_widget has less than 2 items for diagnostic selection.")
|
||||
else:
|
||||
logger.warning("asset_type_list_widget not found for diagnostic selection.")
|
||||
|
||||
def _create_tab_pane(self, title_singular, data_dict, list_widget_name):
|
||||
tab_page = QWidget()
|
||||
tab_page.setFocusPolicy(Qt.FocusPolicy.ClickFocus)
|
||||
tab_layout = QHBoxLayout(tab_page)
|
||||
|
||||
# Left Pane
|
||||
@@ -105,12 +156,32 @@ class DefinitionsEditorDialog(QDialog):
|
||||
lbl_list_title = QLabel(f"{title_singular}s:")
|
||||
left_pane_layout.addWidget(lbl_list_title)
|
||||
|
||||
list_widget = QListWidget()
|
||||
if list_widget_name == "asset_type_list_widget":
|
||||
logger.info(f"Creating DebugListWidget for {list_widget_name}")
|
||||
list_widget = DebugListWidget(self) # Pass parent
|
||||
else:
|
||||
list_widget = QListWidget(self) # Pass parent
|
||||
|
||||
from PySide6.QtWidgets import QAbstractItemView
|
||||
list_widget.setSelectionMode(QAbstractItemView.SingleSelection)
|
||||
list_widget.setEnabled(True)
|
||||
logger.info(f"For {list_widget_name}, SelectionMode set to SingleSelection, Enabled set to True.")
|
||||
setattr(self, list_widget_name, list_widget) # e.g., self.asset_type_list_widget = list_widget
|
||||
logger.info(f"Creating tab pane for {title_singular}, list_widget_name: {list_widget_name}")
|
||||
logger.info(f"List widget instance for {list_widget_name}: {list_widget}")
|
||||
|
||||
# Ensure no other event filters are active on the list_widget for this specific test
|
||||
if list_widget_name == "asset_type_list_widget":
|
||||
# If an event filter was installed on list_widget by a previous debug step via self.installEventFilter(list_widget),
|
||||
# it would need to be removed here, or the logic installing it should be conditional.
|
||||
# For now, we assume no other filter is on list_widget itself.
|
||||
logger.info(f"Ensuring no stray event filter on DebugListWidget instance for {list_widget_name}.")
|
||||
|
||||
if isinstance(data_dict, dict):
|
||||
for key, value_dict in data_dict.items(): # Iterate over items for UserRole data
|
||||
item = QListWidgetItem(key)
|
||||
item.setData(Qt.UserRole, value_dict) # Store the whole dict
|
||||
item.setFlags(item.flags() | Qt.ItemIsSelectable | Qt.ItemIsEnabled) # Explicitly set flags
|
||||
list_widget.addItem(item)
|
||||
else:
|
||||
logger.warning(f"Data for {title_singular} is not a dictionary, cannot populate list.")
|
||||
@@ -125,15 +196,37 @@ class DefinitionsEditorDialog(QDialog):
|
||||
if list_widget_name == "asset_type_list_widget":
|
||||
btn_add.clicked.connect(self._add_asset_type)
|
||||
btn_remove.clicked.connect(self._remove_asset_type)
|
||||
# The event filter on asset_type_list_widget should be disabled for this test.
|
||||
# Assuming the Debug mode task that set it up can be told to disable/remove it,
|
||||
# or we ensure it's not re-added here if it was part of this method.
|
||||
# For now, we just connect currentItemChanged directly.
|
||||
list_widget.currentItemChanged.connect(
|
||||
lambda current, previous, name=list_widget_name:
|
||||
logger.info(f"LAMBDA: currentItemChanged for {name}. Current: {current.text() if current else 'None'}")
|
||||
)
|
||||
list_widget.currentItemChanged.connect(self._display_asset_type_details)
|
||||
logger.info(f"Connected currentItemChanged for {list_widget_name} to _display_asset_type_details AND diagnostic lambda.")
|
||||
elif list_widget_name == "file_type_list_widget":
|
||||
# For other list widgets, keep the previous event filter setup if it was specific,
|
||||
# or remove if it was generic and now we only want DebugListWidget for assets.
|
||||
# For this step, we are only changing asset_type_list_widget.
|
||||
btn_add.clicked.connect(self._add_file_type)
|
||||
btn_remove.clicked.connect(self._remove_file_type)
|
||||
list_widget.currentItemChanged.connect(
|
||||
lambda current, previous, name=list_widget_name:
|
||||
logger.info(f"LAMBDA: currentItemChanged for {name}. Current: {current.text() if current else 'None'}")
|
||||
)
|
||||
list_widget.currentItemChanged.connect(self._display_file_type_details)
|
||||
logger.info(f"Connected currentItemChanged for {list_widget_name} to _display_file_type_details AND diagnostic lambda.")
|
||||
elif list_widget_name == "supplier_list_widget": # Connections for Supplier tab
|
||||
btn_add.clicked.connect(self._add_supplier)
|
||||
btn_remove.clicked.connect(self._remove_supplier)
|
||||
list_widget.currentItemChanged.connect(
|
||||
lambda current, previous, name=list_widget_name:
|
||||
logger.info(f"LAMBDA: currentItemChanged for {name}. Current: {current.text() if current else 'None'}")
|
||||
)
|
||||
list_widget.currentItemChanged.connect(self._display_supplier_details)
|
||||
logger.info(f"Connected currentItemChanged for {list_widget_name} to _display_supplier_details AND diagnostic lambda.")
|
||||
|
||||
buttons_layout.addWidget(btn_add)
|
||||
buttons_layout.addWidget(btn_remove)
|
||||
@@ -145,12 +238,17 @@ class DefinitionsEditorDialog(QDialog):
|
||||
right_pane_widget = QWidget() # Create a generic widget to be returned
|
||||
tab_layout.addWidget(right_pane_widget, 2) # 2 parts for right pane
|
||||
|
||||
tab_page.setEnabled(True) # Explicitly enable the tab page widget
|
||||
logger.info(f"Tab page for {title_singular} explicitly enabled.")
|
||||
tab_page.setLayout(tab_layout)
|
||||
return tab_page, right_pane_widget # Return the pane for customization
|
||||
|
||||
def _create_asset_types_tab(self):
|
||||
tab_page, right_pane_container = self._create_tab_pane("Asset Type", self.asset_type_data, "asset_type_list_widget")
|
||||
|
||||
self.asset_types_tab_page_for_filtering = tab_page # Store reference for event filter
|
||||
# Ensure event filter on tab_page is also disabled if it was installed
|
||||
# logger.info(f"Event filter on asset_types_tab_page ({tab_page}) should be disabled for DebugListWidget test.")
|
||||
|
||||
# Customize the right pane for Asset Types
|
||||
right_pane_groupbox = QGroupBox("Details for Selected Asset Type")
|
||||
details_layout = QFormLayout(right_pane_groupbox)
|
||||
@@ -229,41 +327,61 @@ class DefinitionsEditorDialog(QDialog):
|
||||
self.asset_type_list_widget.addItem(item)
|
||||
|
||||
def _display_asset_type_details(self, current_item, previous_item=None):
|
||||
# Disconnect signals temporarily to prevent feedback loops during population
|
||||
if hasattr(self, 'asset_description_edit'):
|
||||
try:
|
||||
self.asset_description_edit.textChanged.disconnect(self._on_asset_detail_changed)
|
||||
except TypeError: # Signal not connected
|
||||
pass
|
||||
|
||||
logger.info(f"_display_asset_type_details called. Current: {current_item.text() if current_item else 'None'}, Previous: {previous_item.text() if previous_item else 'None'}")
|
||||
if current_item:
|
||||
asset_data = current_item.data(Qt.UserRole)
|
||||
if not isinstance(asset_data, dict): # Should not happen if _populate is correct
|
||||
logger.error(f"Invalid data for item {current_item.text()}. Expected dict, got {type(asset_data)}")
|
||||
asset_data = {"description": "Error: Invalid data", "color": "#ff0000", "examples": []}
|
||||
|
||||
self.asset_description_edit.setText(asset_data.get('description', ''))
|
||||
|
||||
color_hex = asset_data.get('color', '#ffffff')
|
||||
self._update_color_swatch(color_hex)
|
||||
|
||||
self.asset_examples_list_widget.clear()
|
||||
for example in asset_data.get('examples', []):
|
||||
self.asset_examples_list_widget.addItem(example)
|
||||
logger.info(f"Current item text: {current_item.text()}")
|
||||
logger.info(f"Current item data (UserRole): {current_item.data(Qt.UserRole)}")
|
||||
else:
|
||||
# Clear details if no item is selected
|
||||
self.asset_description_edit.clear()
|
||||
self._update_color_swatch("#ffffff")
|
||||
self.asset_examples_list_widget.clear()
|
||||
logger.info("Current item is None for asset_type_details.")
|
||||
|
||||
# Reconnect signals
|
||||
if hasattr(self, 'asset_description_edit'):
|
||||
self.asset_description_edit.textChanged.connect(self._on_asset_detail_changed)
|
||||
try:
|
||||
# Disconnect signals temporarily to prevent feedback loops during population
|
||||
if hasattr(self, 'asset_description_edit'):
|
||||
try:
|
||||
self.asset_description_edit.textChanged.disconnect(self._on_asset_detail_changed)
|
||||
logger.debug("Disconnected asset_description_edit.textChanged")
|
||||
except TypeError: # Signal not connected
|
||||
logger.debug("asset_description_edit.textChanged was not connected or already disconnected.")
|
||||
pass
|
||||
|
||||
if current_item:
|
||||
asset_data = current_item.data(Qt.UserRole)
|
||||
if not isinstance(asset_data, dict): # Should not happen if _populate is correct
|
||||
logger.error(f"Invalid data for item {current_item.text()}. Expected dict, got {type(asset_data)}")
|
||||
asset_data = {"description": "Error: Invalid data", "color": "#ff0000", "examples": []}
|
||||
|
||||
self.asset_description_edit.setText(asset_data.get('description', ''))
|
||||
|
||||
color_hex = asset_data.get('color', '#ffffff')
|
||||
self._update_color_swatch(color_hex)
|
||||
|
||||
self.asset_examples_list_widget.clear()
|
||||
for example in asset_data.get('examples', []):
|
||||
self.asset_examples_list_widget.addItem(example)
|
||||
logger.debug(f"Populated details for {current_item.text()}")
|
||||
else:
|
||||
# Clear details if no item is selected
|
||||
self.asset_description_edit.clear()
|
||||
self._update_color_swatch("#ffffff")
|
||||
self.asset_examples_list_widget.clear()
|
||||
logger.debug("Cleared asset type details as no item is selected.")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error in _display_asset_type_details: {e}", exc_info=True)
|
||||
finally:
|
||||
# Reconnect signals
|
||||
if hasattr(self, 'asset_description_edit'):
|
||||
try:
|
||||
self.asset_description_edit.textChanged.connect(self._on_asset_detail_changed)
|
||||
logger.debug("Reconnected asset_description_edit.textChanged")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to reconnect asset_description_edit.textChanged: {e}", exc_info=True)
|
||||
logger.info("_display_asset_type_details finished.")
|
||||
|
||||
def _update_color_swatch(self, color_hex):
|
||||
if hasattr(self, 'asset_color_swatch_label'):
|
||||
palette = self.asset_color_swatch_label.palette()
|
||||
palette.setColor(QPalette.Background, QColor(color_hex))
|
||||
palette.setColor(QPalette.Window, QColor(color_hex))
|
||||
self.asset_color_swatch_label.setPalette(palette)
|
||||
|
||||
def _choose_asset_color(self):
|
||||
@@ -420,9 +538,9 @@ class DefinitionsEditorDialog(QDialog):
|
||||
|
||||
|
||||
def _update_file_type_color_swatch(self, color_hex, swatch_label):
|
||||
if hasattr(self, swatch_label_name): # Check if the specific swatch label exists
|
||||
if hasattr(self, swatch_label): # Check if the specific swatch label exists
|
||||
palette = swatch_label.palette()
|
||||
palette.setColor(QPalette.Background, QColor(color_hex))
|
||||
palette.setColor(QPalette.Window, QColor(color_hex))
|
||||
swatch_label.setPalette(palette)
|
||||
|
||||
def _create_file_types_tab(self):
|
||||
@@ -526,69 +644,88 @@ class DefinitionsEditorDialog(QDialog):
|
||||
self.file_type_list_widget.addItem(item)
|
||||
|
||||
def _display_file_type_details(self, current_item, previous_item=None):
|
||||
# Disconnect signals temporarily
|
||||
try: self.ft_description_edit.textChanged.disconnect(self._on_file_type_detail_changed)
|
||||
except TypeError: pass
|
||||
try: self.ft_standard_type_edit.textChanged.disconnect(self._on_file_type_detail_changed)
|
||||
except TypeError: pass
|
||||
try: self.ft_bit_depth_combo.currentIndexChanged.disconnect(self._on_file_type_detail_changed)
|
||||
except TypeError: pass
|
||||
try: self.ft_is_grayscale_check.stateChanged.disconnect(self._on_file_type_detail_changed)
|
||||
except TypeError: pass
|
||||
try: self.ft_keybind_edit.textChanged.disconnect(self._on_file_type_detail_changed)
|
||||
except TypeError: pass
|
||||
# Color and examples are handled by their own buttons/actions, not direct textChanged etc.
|
||||
|
||||
logger.info(f"_display_file_type_details called. Current: {current_item.text() if current_item else 'None'}, Previous: {previous_item.text() if previous_item else 'None'}")
|
||||
if current_item:
|
||||
ft_data = current_item.data(Qt.UserRole)
|
||||
if not isinstance(ft_data, dict):
|
||||
logger.error(f"Invalid data for file type item {current_item.text()}. Expected dict, got {type(ft_data)}")
|
||||
# Use placeholder data to avoid crashing UI
|
||||
ft_data = {
|
||||
"description": "Error: Invalid data", "color": "#ff0000", "examples": [],
|
||||
"standard_type": "error", "bit_depth_rule": "respect",
|
||||
"is_grayscale": False, "keybind": "X"
|
||||
}
|
||||
|
||||
self.ft_description_edit.setText(ft_data.get('description', ''))
|
||||
self._update_color_swatch_generic(self.ft_color_swatch_label, ft_data.get('color', '#ffffff'))
|
||||
|
||||
self.ft_examples_list_widget.clear()
|
||||
for example in ft_data.get('examples', []):
|
||||
self.ft_examples_list_widget.addItem(example)
|
||||
|
||||
self.ft_standard_type_edit.setText(ft_data.get('standard_type', ''))
|
||||
|
||||
bdr_index = self.ft_bit_depth_combo.findText(ft_data.get('bit_depth_rule', 'respect'))
|
||||
if bdr_index != -1:
|
||||
self.ft_bit_depth_combo.setCurrentIndex(bdr_index)
|
||||
else:
|
||||
self.ft_bit_depth_combo.setCurrentIndex(0) # Default to 'respect'
|
||||
|
||||
self.ft_is_grayscale_check.setChecked(ft_data.get('is_grayscale', False))
|
||||
self.ft_keybind_edit.setText(ft_data.get('keybind', ''))
|
||||
logger.info(f"Current item text: {current_item.text()}")
|
||||
logger.info(f"Current item data (UserRole): {current_item.data(Qt.UserRole)}")
|
||||
else:
|
||||
# Clear details if no item is selected
|
||||
self.ft_description_edit.clear()
|
||||
self._update_color_swatch_generic(self.ft_color_swatch_label, "#ffffff")
|
||||
self.ft_examples_list_widget.clear()
|
||||
self.ft_standard_type_edit.clear()
|
||||
self.ft_bit_depth_combo.setCurrentIndex(0)
|
||||
self.ft_is_grayscale_check.setChecked(False)
|
||||
self.ft_keybind_edit.clear()
|
||||
logger.info("Current item is None for file_type_details.")
|
||||
|
||||
# Reconnect signals
|
||||
self.ft_description_edit.textChanged.connect(self._on_file_type_detail_changed)
|
||||
self.ft_standard_type_edit.textChanged.connect(self._on_file_type_detail_changed)
|
||||
self.ft_bit_depth_combo.currentIndexChanged.connect(self._on_file_type_detail_changed)
|
||||
self.ft_is_grayscale_check.stateChanged.connect(self._on_file_type_detail_changed)
|
||||
self.ft_keybind_edit.textChanged.connect(self._on_file_type_detail_changed)
|
||||
try:
|
||||
# Disconnect signals temporarily
|
||||
logger.debug("Disconnecting file type detail signals...")
|
||||
try: self.ft_description_edit.textChanged.disconnect(self._on_file_type_detail_changed)
|
||||
except TypeError: pass
|
||||
try: self.ft_standard_type_edit.textChanged.disconnect(self._on_file_type_detail_changed)
|
||||
except TypeError: pass
|
||||
try: self.ft_bit_depth_combo.currentIndexChanged.disconnect(self._on_file_type_detail_changed)
|
||||
except TypeError: pass
|
||||
try: self.ft_is_grayscale_check.stateChanged.disconnect(self._on_file_type_detail_changed)
|
||||
except TypeError: pass
|
||||
try: self.ft_keybind_edit.textChanged.disconnect(self._on_file_type_detail_changed)
|
||||
except TypeError: pass
|
||||
logger.debug("Finished disconnecting file type detail signals.")
|
||||
|
||||
if current_item:
|
||||
ft_data = current_item.data(Qt.UserRole)
|
||||
if not isinstance(ft_data, dict):
|
||||
logger.error(f"Invalid data for file type item {current_item.text()}. Expected dict, got {type(ft_data)}")
|
||||
ft_data = {
|
||||
"description": "Error: Invalid data", "color": "#ff0000", "examples": [],
|
||||
"standard_type": "error", "bit_depth_rule": "respect",
|
||||
"is_grayscale": False, "keybind": "X"
|
||||
}
|
||||
|
||||
self.ft_description_edit.setText(ft_data.get('description', ''))
|
||||
self._update_color_swatch_generic(self.ft_color_swatch_label, ft_data.get('color', '#ffffff'))
|
||||
|
||||
self.ft_examples_list_widget.clear()
|
||||
for example in ft_data.get('examples', []):
|
||||
self.ft_examples_list_widget.addItem(example)
|
||||
|
||||
self.ft_standard_type_edit.setText(ft_data.get('standard_type', ''))
|
||||
|
||||
bdr_index = self.ft_bit_depth_combo.findText(ft_data.get('bit_depth_rule', 'respect'))
|
||||
if bdr_index != -1:
|
||||
self.ft_bit_depth_combo.setCurrentIndex(bdr_index)
|
||||
else:
|
||||
self.ft_bit_depth_combo.setCurrentIndex(0) # Default to 'respect'
|
||||
|
||||
self.ft_is_grayscale_check.setChecked(ft_data.get('is_grayscale', False))
|
||||
self.ft_keybind_edit.setText(ft_data.get('keybind', ''))
|
||||
logger.debug(f"Populated details for file type {current_item.text()}")
|
||||
else:
|
||||
# Clear details if no item is selected
|
||||
self.ft_description_edit.clear()
|
||||
self._update_color_swatch_generic(self.ft_color_swatch_label, "#ffffff")
|
||||
self.ft_examples_list_widget.clear()
|
||||
self.ft_standard_type_edit.clear()
|
||||
self.ft_bit_depth_combo.setCurrentIndex(0)
|
||||
self.ft_is_grayscale_check.setChecked(False)
|
||||
self.ft_keybind_edit.clear()
|
||||
logger.debug("Cleared file type details as no item is selected.")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error in _display_file_type_details: {e}", exc_info=True)
|
||||
finally:
|
||||
# Reconnect signals
|
||||
logger.debug("Reconnecting file type detail signals...")
|
||||
try:
|
||||
self.ft_description_edit.textChanged.connect(self._on_file_type_detail_changed)
|
||||
self.ft_standard_type_edit.textChanged.connect(self._on_file_type_detail_changed)
|
||||
self.ft_bit_depth_combo.currentIndexChanged.connect(self._on_file_type_detail_changed)
|
||||
self.ft_is_grayscale_check.stateChanged.connect(self._on_file_type_detail_changed)
|
||||
self.ft_keybind_edit.textChanged.connect(self._on_file_type_detail_changed)
|
||||
logger.debug("Finished reconnecting file type detail signals.")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to reconnect file type detail signals: {e}", exc_info=True)
|
||||
logger.info("_display_file_type_details finished.")
|
||||
|
||||
def _update_color_swatch_generic(self, swatch_label, color_hex):
|
||||
"""Generic color swatch update for any QLabel."""
|
||||
if swatch_label: # Check if the swatch label exists and is passed correctly
|
||||
palette = swatch_label.palette()
|
||||
palette.setColor(QPalette.Background, QColor(color_hex))
|
||||
palette.setColor(QPalette.Window, QColor(color_hex))
|
||||
swatch_label.setPalette(palette)
|
||||
swatch_label.update() # Ensure the label repaints
|
||||
|
||||
@@ -814,41 +951,59 @@ class DefinitionsEditorDialog(QDialog):
|
||||
self.supplier_list_widget.addItem(item)
|
||||
|
||||
def _display_supplier_details(self, current_item, previous_item=None):
|
||||
# Disconnect signals temporarily
|
||||
if hasattr(self, 'supplier_normal_map_type_combo'):
|
||||
try: self.supplier_normal_map_type_combo.currentIndexChanged.disconnect(self._on_supplier_detail_changed)
|
||||
except TypeError: pass
|
||||
|
||||
logger.info(f"_display_supplier_details called. Current: {current_item.text() if current_item else 'None'}, Previous: {previous_item.text() if previous_item else 'None'}")
|
||||
if current_item:
|
||||
supplier_name = current_item.text()
|
||||
# Prefer getting data directly from self.supplier_data to ensure it's the master copy
|
||||
# The UserRole data on the item should be a reflection or copy.
|
||||
supplier_data = self.supplier_data.get(supplier_name)
|
||||
|
||||
if not isinstance(supplier_data, dict):
|
||||
logger.error(f"Invalid data for supplier item {supplier_name}. Expected dict, got {type(supplier_data)}")
|
||||
# Fallback if data is somehow corrupted or missing from self.supplier_data
|
||||
# This might happen if an item is in the list but not in self.supplier_data
|
||||
item_data_role = current_item.data(Qt.UserRole)
|
||||
if isinstance(item_data_role, dict):
|
||||
supplier_data = item_data_role
|
||||
else:
|
||||
supplier_data = {"normal_map_type": "OpenGL"} # Absolute fallback
|
||||
|
||||
normal_map_type = supplier_data.get('normal_map_type', 'OpenGL')
|
||||
nmt_index = self.supplier_normal_map_type_combo.findText(normal_map_type)
|
||||
if nmt_index != -1:
|
||||
self.supplier_normal_map_type_combo.setCurrentIndex(nmt_index)
|
||||
else:
|
||||
self.supplier_normal_map_type_combo.setCurrentIndex(0) # Default to OpenGL
|
||||
logger.info(f"Current item text: {current_item.text()}")
|
||||
logger.info(f"Current item data (UserRole): {current_item.data(Qt.UserRole)}")
|
||||
else:
|
||||
# Clear details if no item is selected
|
||||
if hasattr(self, 'supplier_normal_map_type_combo'):
|
||||
self.supplier_normal_map_type_combo.setCurrentIndex(0) # Default to OpenGL
|
||||
logger.info("Current item is None for supplier_details.")
|
||||
|
||||
# Reconnect signals
|
||||
if hasattr(self, 'supplier_normal_map_type_combo'):
|
||||
self.supplier_normal_map_type_combo.currentIndexChanged.connect(self._on_supplier_detail_changed)
|
||||
try:
|
||||
# Disconnect signals temporarily
|
||||
if hasattr(self, 'supplier_normal_map_type_combo'):
|
||||
try:
|
||||
self.supplier_normal_map_type_combo.currentIndexChanged.disconnect(self._on_supplier_detail_changed)
|
||||
logger.debug("Disconnected supplier_normal_map_type_combo.currentIndexChanged")
|
||||
except TypeError:
|
||||
logger.debug("supplier_normal_map_type_combo.currentIndexChanged was not connected or already disconnected.")
|
||||
pass
|
||||
|
||||
if current_item:
|
||||
supplier_name = current_item.text()
|
||||
supplier_data = self.supplier_data.get(supplier_name)
|
||||
|
||||
if not isinstance(supplier_data, dict):
|
||||
logger.error(f"Invalid data for supplier item {supplier_name}. Expected dict, got {type(supplier_data)}")
|
||||
item_data_role = current_item.data(Qt.UserRole)
|
||||
if isinstance(item_data_role, dict):
|
||||
supplier_data = item_data_role
|
||||
else:
|
||||
supplier_data = {"normal_map_type": "OpenGL"}
|
||||
|
||||
normal_map_type = supplier_data.get('normal_map_type', 'OpenGL')
|
||||
nmt_index = self.supplier_normal_map_type_combo.findText(normal_map_type)
|
||||
if nmt_index != -1:
|
||||
self.supplier_normal_map_type_combo.setCurrentIndex(nmt_index)
|
||||
else:
|
||||
self.supplier_normal_map_type_combo.setCurrentIndex(0)
|
||||
logger.debug(f"Populated details for supplier {current_item.text()}")
|
||||
else:
|
||||
# Clear details if no item is selected
|
||||
if hasattr(self, 'supplier_normal_map_type_combo'):
|
||||
self.supplier_normal_map_type_combo.setCurrentIndex(0)
|
||||
logger.debug("Cleared supplier details as no item is selected.")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error in _display_supplier_details: {e}", exc_info=True)
|
||||
finally:
|
||||
# Reconnect signals
|
||||
if hasattr(self, 'supplier_normal_map_type_combo'):
|
||||
try:
|
||||
self.supplier_normal_map_type_combo.currentIndexChanged.connect(self._on_supplier_detail_changed)
|
||||
logger.debug("Reconnected supplier_normal_map_type_combo.currentIndexChanged")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to reconnect supplier_normal_map_type_combo.currentIndexChanged: {e}", exc_info=True)
|
||||
logger.info("_display_supplier_details finished.")
|
||||
|
||||
def _on_supplier_detail_changed(self):
|
||||
current_item = self.supplier_list_widget.currentItem()
|
||||
@@ -1036,6 +1191,71 @@ class DefinitionsEditorDialog(QDialog):
|
||||
else:
|
||||
event.accept()
|
||||
|
||||
def eventFilter(self, watched, event: QEvent): # Renamed from mouse_event_filter
|
||||
event_type = event.type()
|
||||
|
||||
if watched == self.tab_widget:
|
||||
# Construct a more identifiable name for the tab widget in logs
|
||||
tab_widget_name_for_log = self.tab_widget.objectName() if self.tab_widget.objectName() else watched.__class__.__name__
|
||||
prefix = f"EventFilter (QTabWidget '{tab_widget_name_for_log}'):"
|
||||
|
||||
if event_type == QEvent.MouseButtonPress or event_type == QEvent.MouseButtonRelease:
|
||||
event_name = "Press" if event_type == QEvent.MouseButtonPress else "Release"
|
||||
|
||||
# Ensure event has position method (it's a QMouseEvent)
|
||||
if hasattr(event, 'position') and hasattr(event, 'globalPosition') and hasattr(event, 'button'):
|
||||
log_line = (f"{prefix} MouseButton{event_name} "
|
||||
f"global_pos={event.globalPosition().toPoint()}, "
|
||||
f"widget_pos={event.position().toPoint()}, "
|
||||
f"button={event.button()}, accepted={event.isAccepted()}")
|
||||
logger.info(log_line)
|
||||
|
||||
current_page = self.tab_widget.currentWidget()
|
||||
if current_page:
|
||||
# event.position() is relative to self.tab_widget (the watched object)
|
||||
tab_widget_event_pos_float = event.position() # QPointF
|
||||
tab_widget_event_pos = tab_widget_event_pos_float.toPoint() # QPoint
|
||||
|
||||
# Map event position from tab_widget coordinates to global, then to page coordinates
|
||||
global_pos = self.tab_widget.mapToGlobal(tab_widget_event_pos)
|
||||
page_event_pos = current_page.mapFromGlobal(global_pos)
|
||||
|
||||
is_over_page = current_page.rect().contains(page_event_pos)
|
||||
page_name_for_log = current_page.objectName() if current_page.objectName() else current_page.__class__.__name__
|
||||
|
||||
logger.info(f"{prefix} Event mapped to page '{page_name_for_log}' coords: {page_event_pos}. "
|
||||
f"Page rect: {current_page.rect()}. Is over page: {is_over_page}")
|
||||
|
||||
if is_over_page:
|
||||
logger.info(f"{prefix} Event IS OVER CURRENT PAGE. "
|
||||
f"Current event.isAccepted(): {event.isAccepted()}. "
|
||||
f"Returning False from filter to allow propagation to QTabWidget's default handling.")
|
||||
# Returning False means this filter does not stop the event.
|
||||
# The event will be sent to self.tab_widget.event() for its default handling,
|
||||
# which should then propagate to children if appropriate.
|
||||
return False
|
||||
else:
|
||||
logger.info(f"{prefix} Event is NOT over current page (likely on tab bar). Allowing default QTabWidget handling.")
|
||||
else:
|
||||
logger.info(f"{prefix} No current page for tab_widget during mouse event.")
|
||||
else:
|
||||
logger.warning(f"{prefix} MouseButton{event_name} received, but event object lacks expected QMouseEvent attributes.")
|
||||
|
||||
# Example: Log other event types if needed for debugging, but keep it concise
|
||||
# elif event_type == QEvent.Enter:
|
||||
# logger.debug(f"{prefix} Enter event")
|
||||
# elif event_type == QEvent.Leave:
|
||||
# logger.debug(f"{prefix} Leave event")
|
||||
# elif event_type == QEvent.FocusIn:
|
||||
# logger.debug(f"{prefix} FocusIn event")
|
||||
# elif event_type == QEvent.FocusOut:
|
||||
# logger.debug(f"{prefix} FocusOut event")
|
||||
|
||||
# For other watched objects (if any were installed on), or for events on self.tab_widget
|
||||
# that were not explicitly handled (e.g., not mouse press/release over page),
|
||||
# call the base class implementation.
|
||||
return super().eventFilter(watched, event)
|
||||
|
||||
if __name__ == '__main__':
|
||||
# This is for testing the dialog independently
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
|
||||
Reference in New Issue
Block a user