Untitled
unknown
plain_text
10 months ago
18 kB
12
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