diff --git a/arho_feature_template/core/plan_manager.py b/arho_feature_template/core/plan_manager.py index 43605ce..3947e19 100644 --- a/arho_feature_template/core/plan_manager.py +++ b/arho_feature_template/core/plan_manager.py @@ -279,16 +279,16 @@ def set_active_plan(self, plan_id: str | None): def load_land_use_plan(self): """Load an existing land use plan using a dialog selection.""" - connections = get_existing_database_connection_names() + connection_names = get_existing_database_connection_names() - if not connections: + if not connection_names: QMessageBox.critical(None, "Error", "No database connections found.") return if not handle_unsaved_changes(): return - dialog = LoadPlanDialog(None, connections) + dialog = LoadPlanDialog(None, connection_names) if dialog.exec_() == QDialog.Accepted: selected_plan_id = dialog.get_selected_plan_id() diff --git a/arho_feature_template/gui/dialogs/load_plan_dialog.py b/arho_feature_template/gui/dialogs/load_plan_dialog.py index a881d2a..de42c6e 100644 --- a/arho_feature_template/gui/dialogs/load_plan_dialog.py +++ b/arho_feature_template/gui/dialogs/load_plan_dialog.py @@ -1,12 +1,25 @@ +from __future__ import annotations + from importlib import resources +from typing import Sequence from qgis.core import QgsProviderRegistry from qgis.PyQt import uic from qgis.PyQt.QtCore import QRegularExpression, QSortFilterProxyModel, Qt from qgis.PyQt.QtGui import QStandardItem, QStandardItemModel -from qgis.PyQt.QtWidgets import QComboBox, QDialog, QDialogButtonBox, QLineEdit, QMessageBox, QPushButton, QTableView +from qgis.PyQt.QtWidgets import ( + QComboBox, + QDialog, + QDialogButtonBox, + QHeaderView, + QLineEdit, + QMessageBox, + QPushButton, + QTableView, +) from arho_feature_template.core.exceptions import UnexpectedNoneError +from arho_feature_template.utils.misc_utils import get_active_plan_id ui_path = resources.files(__package__) / "load_plan_dialog.ui" @@ -14,6 +27,11 @@ class PlanFilterProxyModel(QSortFilterProxyModel): + def __init__(self, model: QStandardItemModel): + super().__init__() + self.setSourceModel(model) + self.setFilterCaseSensitivity(Qt.CaseInsensitive) + def filterAcceptsRow(self, source_row, source_parent): # noqa: N802 model = self.sourceModel() if not model: @@ -33,57 +51,98 @@ def filterAcceptsRow(self, source_row, source_parent): # noqa: N802 class LoadPlanDialog(QDialog, LoadPlanDialogBase): # type: ignore - connectionComboBox: QComboBox # noqa: N815 - push_button_load: QPushButton - planTableView: QTableView # noqa: N815 - searchLineEdit: QLineEdit # noqa: N815 - buttonBox: QDialogButtonBox # noqa: N815 + connections_selection: QComboBox + load_btn: QPushButton + plan_table_view: QTableView + search_line_edit: QLineEdit + button_box: QDialogButtonBox - def __init__(self, parent, connections): + # ID_COLUMN = 4 + + def __init__(self, parent, connection_names: list[str]): super().__init__(parent) self.setupUi(self) self._selected_plan_id = None - self.buttonBox.rejected.connect(self.reject) - self.buttonBox.accepted.connect(self.accept) - self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(False) + self.button_box.rejected.connect(self.reject) + self.button_box.accepted.connect(self.accept) + self.button_box.button(QDialogButtonBox.Ok).setEnabled(False) - self.push_button_load.clicked.connect(self.load_plans) - self.searchLineEdit.textChanged.connect(self.filter_plans) + self.load_btn.clicked.connect(self.load_plans) + self.search_line_edit.textChanged.connect(self.filter_plans) - self.connectionComboBox.addItems(connections) + self.connections_selection.addItems(connection_names) - self.planTableView.setSelectionMode(QTableView.SingleSelection) - self.planTableView.setSelectionBehavior(QTableView.SelectRows) + self.plan_table_view: QTableView + self.plan_table_view.setSelectionMode(QTableView.SingleSelection) + self.plan_table_view.setSelectionBehavior(QTableView.SelectRows) self.model = QStandardItemModel() - self.model.setColumnCount(5) + self.model.setColumnCount(4) self.model.setHorizontalHeaderLabels( [ - "ID", - "Tuottajan kaavatunnus", "Nimi", - "Kaavan elinkaaren tila", "Kaavalaji", + "Kaavan elinkaaren tila", + "Tuottajan kaavatunnus", + # "ID", ] ) - self.filterProxyModel = PlanFilterProxyModel() - self.filterProxyModel.setSourceModel(self.model) - self.filterProxyModel.setFilterCaseSensitivity(Qt.CaseInsensitive) + self.filterProxyModel = PlanFilterProxyModel(self.model) - self.planTableView.setModel(self.filterProxyModel) - self.planTableView.selectionModel().selectionChanged.connect(self.on_selection_changed) + self.plan_table_view.setModel(self.filterProxyModel) + self.plan_table_view.selectionModel().selectionChanged.connect(self.on_selection_changed) + # self.plan_table_view.setSortingEnabled(True) - def load_plans(self): + header = self.plan_table_view.horizontalHeader() + for i in range(3): + header.setSectionResizeMode(i, QHeaderView.ResizeToContents) + header.setSectionResizeMode(3, QHeaderView.Stretch) + + # Show plans for the first connections by default + # NOTE: Could be changed to the previously used connection if/when plugin can remember it + if len(connection_names) > 0: + self.load_plans() + + def clear_table(self): self.model.removeRows(0, self.model.rowCount()) - selected_connection = self.connectionComboBox.currentText() + def load_plans(self): + self.clear_table() + + selected_connection = self.connections_selection.currentText() if not selected_connection: - self.planTableView.setModel(QStandardItemModel()) return + active_plan_id = get_active_plan_id() + row_to_select = None + plans = self.get_plans_from_db(selected_connection) + for i, plan in enumerate(plans): + id_, producers_plan_identifier, name, lifecycle_status, plan_type = plan + self.model.appendRow( + [ + QStandardItem(name or ""), + QStandardItem(plan_type or ""), + QStandardItem(lifecycle_status or ""), + QStandardItem(producers_plan_identifier or ""), + # QStandardItem(id_ or ""), + ] + ) + self.model.item(i, 0).setData(id_, Qt.UserRole) + if active_plan_id == id_: + row_to_select = i + + if row_to_select is not None: + self.plan_table_view.selectRow(row_to_select) + + def get_plans_from_db(self, selected_connection: str) -> Sequence[str]: + """ + Loads plans from the selected DB connection. + + Returns plan information in the format [ID, producers_plan_identifier, name, lifecycle_status, plan_type]. + """ provider_registry = QgsProviderRegistry.instance() if provider_registry is None: raise UnexpectedNoneError @@ -111,15 +170,13 @@ def load_plans(self): ON p.plan_type_id = pt.id; """) - for plan in plans: - self.model.appendRow([QStandardItem(column or "") for column in plan]) - except Exception as e: # noqa: BLE001 QMessageBox.critical(self, "Error", f"Failed to load plans: {e}") - self.model.removeRows(0, self.model.rowCount()) + self.clear_table() + return plans def filter_plans(self): - search_text = self.searchLineEdit.text() + search_text = self.search_line_edit.text() if search_text: search_regex = QRegularExpression(search_text) self.filterProxyModel.setFilterRegularExpression(search_regex) @@ -127,19 +184,22 @@ def filter_plans(self): self.filterProxyModel.setFilterRegularExpression("") def on_selection_changed(self): - # Enable the OK button only if a row is selected - selection = self.planTableView.selectionModel().selectedRows() - ok_button = self.buttonBox.button(QDialogButtonBox.Ok) + """ + Check active selection in `plan_table_view`. + + Enable the OK button only if a row is selected. + """ + selection = self.plan_table_view.selectionModel().selectedRows() if selection: selected_row = selection[0].row() - self._selected_plan_id = self.planTableView.model().index(selected_row, 0).data() - ok_button.setEnabled(True) + self._selected_plan_id = self.plan_table_view.model().index(selected_row, 0).data(Qt.UserRole) + self.button_box.button(QDialogButtonBox.Ok).setEnabled(True) else: self._selected_plan_id = None - ok_button.setEnabled(False) + self.button_box.button(QDialogButtonBox.Ok).setEnabled(False) def get_selected_connection(self): - return self.connectionComboBox.currentText() + return self.connections_selection.currentText() def get_selected_plan_id(self): return self._selected_plan_id diff --git a/arho_feature_template/gui/dialogs/load_plan_dialog.ui b/arho_feature_template/gui/dialogs/load_plan_dialog.ui index 0a0c82d..dd5c261 100644 --- a/arho_feature_template/gui/dialogs/load_plan_dialog.ui +++ b/arho_feature_template/gui/dialogs/load_plan_dialog.ui @@ -1,19 +1,25 @@ - LoadPlanDialog - + dialog + 0 0 - 800 - 600 + 642 + 414 - 800 - 600 + 440 + 360 + + + + + 650 + 440 @@ -21,26 +27,44 @@ - - - Valitse tietokantayhteys: - - - - - + - + - + 0 0 + + Tietokanta + - + + + + 0 + 0 + + + + + 200 + 0 + + + + + + + + + 0 + 0 + + Lataa kaavat @@ -49,92 +73,36 @@ - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 0 - 0 - - - - - - - - Etsi kaavoja: + + + true - - - - - - - 0 - 0 - - - - Etsi kaavoja... + + - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 0 - 0 - - - - - - - - Kaavat: - - - - - + 1 1 - - - - - - Qt::Vertical - - - QSizePolicy::Expanding - - + 0 0 - + + QAbstractItemView::NoEditTriggers + + - + QDialogButtonBox::Cancel|QDialogButtonBox::Ok @@ -142,6 +110,13 @@ + + + QgsFilterLineEdit + QLineEdit +
qgsfilterlineedit.h
+
+