Untitled
unknown
plain_text
7 days ago
18 kB
1
No Index
from qgis.PyQt.QtCore import Qt, QSettings, QObject, QItemSelectionModel, QCoreApplication from qgis.PyQt.QtWidgets import ( QLineEdit, QPushButton, QVBoxLayout, QWidget, QHBoxLayout, QDockWidget, QAbstractScrollArea, QAbstractItemView ) from qgis.core import ( QgsProject, QgsLayerTreeGroup, QgsLayerTreeLayer, QgsMessageLog, Qgis ) from qgis.gui import QgsLayerTreeView class LayerSearchPlugin(QObject): def tr(self, message): """Get the translation for a string using Qt translation API.""" return QCoreApplication.translate('LayerSearchPlugin', message) def __init__(self, iface): super().__init__() self.iface = iface QgsMessageLog.logMessage( "LayerSearch Plugin: Constructor called", 'LayerSearch', level=Qgis.Info ) self.settings = QSettings("QGIS", "LayerSearchPlugin") self._original_expanded = {} self.searchWidget = None self.searchBox = None self.clearButton = None self.modified_dock_widget = None self.original_dock_widget_content = None def initGui(self): QgsMessageLog.logMessage( "LayerSearch Plugin: Initializing GUI", 'LayerSearch', level=Qgis.Info ) self.searchWidget = QWidget() self.searchWidget.setObjectName("LayerSearchPluginWidget") layout = QHBoxLayout(self.searchWidget) layout.setContentsMargins(2, 2, 2, 2) layout.setSpacing(4) self.searchBox = QLineEdit() self.searchBox.setPlaceholderText(self.tr("Search layers...")) self.searchBox.textChanged.connect(self.on_search_text_changed) self.clearButton = QPushButton(self.tr("Clear")) self.clearButton.clicked.connect(self.clear_search) font_metrics = self.iface.mainWindow().fontMetrics() clear_text_width = font_metrics.horizontalAdvance(self.tr("Clear") + " ") self.clearButton.setMaximumWidth(clear_text_width * 2) layout.addWidget(self.searchBox) layout.addWidget(self.clearButton) layer_tree_view = self.iface.layerTreeView() if not layer_tree_view: QgsMessageLog.logMessage( "LayerSearch Plugin: Could not find QgsLayerTreeView (iface.layerTreeView() is None). Cannot add search bar.", 'LayerSearch', level=Qgis.Critical ) return target_dock = None max_parents_to_check = 10 layers_dock_by_name = self.iface.mainWindow().findChild(QDockWidget, "Layers") if layers_dock_by_name: is_parent_check_widget = layer_tree_view is_found_in_dock_by_name = False for _ in range(max_parents_to_check): if not is_parent_check_widget: break if is_parent_check_widget.parentWidget() == layers_dock_by_name: target_dock = layers_dock_by_name is_found_in_dock_by_name = True break is_parent_check_widget = is_parent_check_widget.parentWidget() if is_found_in_dock_by_name: QgsMessageLog.logMessage( f"LayerSearch Plugin: Target Layers Dock identified by objectName 'Layers': {target_dock.windowTitle()}", 'LayerSearch', level=Qgis.Info ) else: QgsMessageLog.logMessage( f"LayerSearch Plugin: Dock with objectName 'Layers' found, but it's not the parent of the active LayerTreeView. Fallback search needed.", 'LayerSearch', level=Qgis.Warning ) target_dock = None if not target_dock: QgsMessageLog.logMessage( "LayerSearch Plugin: LayersDock not found by objectName 'Layers' or it's not parent. Iterating all docks to find parent of LayerTreeView.", 'LayerSearch', level=Qgis.Info ) for dock_widget_candidate in self.iface.mainWindow().findChildren(QDockWidget): is_parent_check_widget = layer_tree_view is_found = False for _ in range(max_parents_to_check): if not is_parent_check_widget: break if is_parent_check_widget.parentWidget() == dock_widget_candidate: target_dock = dock_widget_candidate is_found = True break is_parent_check_widget = is_parent_check_widget.parentWidget() if is_found: QgsMessageLog.logMessage( f"LayerSearch Plugin: Found Layers Dock by iterating and checking parentage: {target_dock.windowTitle()} (ObjectName: {target_dock.objectName()})", 'LayerSearch', level=Qgis.Info ) break if target_dock: QgsMessageLog.logMessage( f"LayerSearch Plugin: Final Target Layers Dock: {target_dock.windowTitle()} (ObjectName: {target_dock.objectName()})", 'LayerSearch', level=Qgis.Info ) original_dock_content = target_dock.widget() if original_dock_content and original_dock_content.objectName() == "LayerSearchContainer": QgsMessageLog.logMessage( "LayerSearch Plugin: Layers panel already has LayerSearchContainer. Restoring original content before re-adding.", 'LayerSearch', level=Qgis.Warning ) old_container_layout = original_dock_content.layout() if old_container_layout and old_container_layout.count() == 2: original_dock_content_restored = old_container_layout.itemAt(1).widget() if original_dock_content_restored: old_search_widget = old_container_layout.itemAt(0).widget() if old_search_widget: old_search_widget.setParent(None) old_search_widget.deleteLater() target_dock.setWidget(original_dock_content_restored) original_dock_content = original_dock_content_restored QgsMessageLog.logMessage( "LayerSearch Plugin: Restored original widget from previous LayerSearchContainer.", 'LayerSearch', level=Qgis.Info ) else: QgsMessageLog.logMessage( "LayerSearch Plugin: Could not restore original widget from existing container. Aborting UI setup.", 'LayerSearch', level=Qgis.Critical ) return else: QgsMessageLog.logMessage( "LayerSearch Plugin: Existing LayerSearchContainer has unexpected layout. Aborting UI setup.", 'LayerSearch', level=Qgis.Critical ) return self.original_dock_widget_content = original_dock_content self.modified_dock_widget = target_dock container = QWidget() container.setObjectName("LayerSearchContainer") vlay = QVBoxLayout(container) vlay.setContentsMargins(0, 0, 0, 0) vlay.setSpacing(0) vlay.addWidget(self.searchWidget) vlay.addWidget(self.original_dock_widget_content) vlay.setStretchFactor(self.searchWidget, 0) vlay.setStretchFactor(self.original_dock_widget_content, 1) target_dock.setWidget(container) QgsMessageLog.logMessage( "LayerSearch Plugin: Search widget added to Layers Dock.", 'LayerSearch', level=Qgis.Info ) else: QgsMessageLog.logMessage( self.tr("LayerSearch Plugin: Could not find the Layers Panel (QDockWidget) to attach the search bar. The plugin will not be active."), self.tr('Layer Search Plugin Error'), level=Qgis.Critical ) self.iface.messageBar().pushMessage( self.tr("Error"), self.tr("Layer Search Plugin could not find the Layers Panel and will not be active."), level=Qgis.Critical, duration=10 ) def find_matching_layers(self, node, search_text): matches = [] if isinstance(node, QgsLayerTreeLayer): # Usar node.name() para obtener el nombre que se muestra en el árbol de capas layer_display_name = node.name() if layer_display_name and search_text.lower() in layer_display_name.lower(): matches.append(node) # Recursivamente buscar en todos los hijos for child in node.children(): matches.extend(self.find_matching_layers(child, search_text)) return matches def on_search_text_changed(self, text): root = QgsProject.instance().layerTreeRoot() main_layer_tree_view = self.iface.layerTreeView() if not main_layer_tree_view: QgsMessageLog.logMessage(self.tr("LayerSearch: Main QgsLayerTreeView (iface.layerTreeView()) not found."), 'LayerSearch', level=Qgis.Warning) return if not self.modified_dock_widget: return view_to_process = None is_descendant = False parent_widget = main_layer_tree_view max_checks = 10 count = 0 while parent_widget and count < max_checks: if parent_widget == self.modified_dock_widget: is_descendant = True break parent_widget = parent_widget.parentWidget() count += 1 if is_descendant: view_to_process = main_layer_tree_view else: QgsMessageLog.logMessage(self.tr("LayerSearch: Main LayerTreeView is not a descendant of the modified Layers Dock. Skipping search update."), 'LayerSearch', level=Qgis.Warning) return view = view_to_process view.selectionModel().clearSelection() if not text: if view in self._original_expanded: self.restore_expansion_state(view, root) del self._original_expanded[view] self.collapse_all_recursively(view, root) if view in self._original_expanded: self.restore_expansion_state(view, root) return if view not in self._original_expanded: self._original_expanded[view] = set() self.store_expanded_groups(root, view) matches = self.find_matching_layers(root, text) groups_to_expand = set() for node_match in matches: # Renombrada la variable para evitar confusión con el 'node' de los bucles de expansión parent = node_match.parent() while parent and isinstance(parent, QgsLayerTreeGroup): groups_to_expand.add(parent) parent = parent.parent() self.adjust_group_expansion(view, root, groups_to_expand, bool(text)) selection_model = view.selectionModel() for node_match in matches: # Renombrada la variable idx = view.node2index(node_match) if idx.isValid(): selection_model.select( idx, QItemSelectionModel.Select | QItemSelectionModel.Rows ) if matches: first_match_idx = view.node2index(matches[0]) if first_match_idx.isValid(): view.scrollTo(first_match_idx, QAbstractItemView.ScrollHint.PositionAtTop) def store_expanded_groups(self, node, view): if isinstance(node, QgsLayerTreeGroup): idx = view.node2index(node) if idx.isValid() and view.isExpanded(idx): self._original_expanded[view].add(node) for child in node.children(): self.store_expanded_groups(child, view) def adjust_group_expansion(self, view, node, groups_to_expand, is_searching): if not isinstance(node, QgsLayerTreeGroup): return root = QgsProject.instance().layerTreeRoot() idx = view.node2index(node) if not idx.isValid(): return if node is not root: if node in groups_to_expand: view.expand(idx) elif is_searching: original_set = self._original_expanded.get(view, set()) if node not in original_set: view.collapse(idx) for child in node.children(): self.adjust_group_expansion(view, child, groups_to_expand, is_searching) def restore_expansion_state(self, view, node): if not isinstance(node, QgsLayerTreeGroup): return root = QgsProject.instance().layerTreeRoot() idx = view.node2index(node) if not idx.isValid(): return if node is not root: original_set = self._original_expanded.get(view, set()) if node in original_set: view.expand(idx) else: view.collapse(idx) for child in node.children(): self.restore_expansion_state(view, child) def collapse_all_recursively(self, view, node): if isinstance(node, QgsLayerTreeGroup): idx = view.node2index(node) if idx.isValid() and node != QgsProject.instance().layerTreeRoot(): view.collapse(idx) for child in node.children(): self.collapse_all_recursively(view, child) def clear_search(self): QgsMessageLog.logMessage( "LayerSearch Plugin: clear_search called", 'LayerSearch', level=Qgis.Info ) if self.searchBox: self.searchBox.clear() else: root = QgsProject.instance().layerTreeRoot() main_layer_tree_view = self.iface.layerTreeView() if not main_layer_tree_view or not self.modified_dock_widget: return is_descendant = False parent_widget = main_layer_tree_view max_checks = 10 count = 0 while parent_widget and count < max_checks: if parent_widget == self.modified_dock_widget: is_descendant = True break parent_widget = parent_widget.parentWidget() count += 1 if is_descendant: view = main_layer_tree_view view.selectionModel().clearSelection() if view in self._original_expanded: # Comprobar si la vista existe como clave antes de acceder original_view_expansion = self._original_expanded.get(view) if original_view_expansion is not None: self.restore_expansion_state(view, root) # Solo eliminar si estamos seguros de que la clave existe y ha sido procesada if view in self._original_expanded: del self._original_expanded[view] def unload(self): QgsMessageLog.logMessage( "LayerSearch Plugin: Unloading", 'LayerSearch', level=Qgis.Info ) if self.modified_dock_widget and self.original_dock_widget_content: current_dock_content = self.modified_dock_widget.widget() if current_dock_content and current_dock_content.objectName() == "LayerSearchContainer": if self.searchWidget: self.searchWidget.setParent(None) self.modified_dock_widget.setWidget(self.original_dock_widget_content) QgsMessageLog.logMessage( "LayerSearch Plugin: Restored original Layers dock content.", 'LayerSearch', level=Qgis.Info ) else: QgsMessageLog.logMessage( "LayerSearch Plugin: Original dock content not found or already restored. Skipping restoration.", 'LayerSearch', level=Qgis.Warning ) elif self.modified_dock_widget: QgsMessageLog.logMessage( "LayerSearch Plugin: modified_dock_widget exists but original_dock_widget_content is missing. Cannot restore.", 'LayerSearch', level=Qgis.Warning ) if self.searchBox: try: self.searchBox.textChanged.disconnect(self.on_search_text_changed) except (TypeError, RuntimeError): pass if self.clearButton: try: self.clearButton.clicked.disconnect(self.clear_search) except (TypeError, RuntimeError): pass if self.searchWidget: self.searchWidget.deleteLater() QgsMessageLog.logMessage( "LayerSearch Plugin: searchWidget scheduled for deletion.", 'LayerSearch', level=Qgis.Info ) self._original_expanded = {} self.searchWidget = None self.searchBox = None self.clearButton = None self.modified_dock_widget = None self.original_dock_widget_content = None QgsMessageLog.logMessage( "LayerSearch Plugin: Unload finished.", 'LayerSearch', level=Qgis.Info )
Editor is loading...
Leave a Comment