Skip to content

Commit

Permalink
Edit service settings via tableView; avoid changing current edit serv…
Browse files Browse the repository at this point in the history
…ice without saving/discarding
  • Loading branch information
gacarrillor committed Apr 15, 2024
1 parent e6606e5 commit fd45bc1
Show file tree
Hide file tree
Showing 5 changed files with 205 additions and 30 deletions.
Empty file.
72 changes: 72 additions & 0 deletions pg_service_parser/core/item_models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
from qgis.PyQt.QtCore import QAbstractTableModel, Qt
from qgis.PyQt.QtGui import QFont


class ServiceConfigModel(QAbstractTableModel):
KEY_COL = 0
VALUE_COL = 1

def __init__(self, service_name, service_config):
super().__init__()
self.__service_name = service_name
self.__model_data = service_config
self.__dirty = False

def rowCount(self, parent):
return len(self.__model_data)

def columnCount(self, parent):
return 2

def data(self, index, role=Qt.DisplayRole):
if not index.isValid():
return None

key = list(self.__model_data.keys())[index.row()]
if role == Qt.DisplayRole:
if index.column() == self.KEY_COL:
return key
elif index.column() == self.VALUE_COL:
return self.__model_data[key]
elif role == Qt.EditRole and index.column() == self.VALUE_COL:
return self.__model_data[key]
elif role == Qt.FontRole and index.column() == self.KEY_COL:
font = QFont()
font.setBold(True)
return font

return None

def setData(self, index, value, role=Qt.EditRole) -> bool:
if not index.isValid():
return False

key = list(self.__model_data.keys())[index.row()]
if value != self.__model_data[key]:
self.__model_data[key] = value
self.__dirty = True
return True

return False

def flags(self, idx):
if not idx.isValid():
return ~Qt.ItemIsSelectable & ~Qt.ItemIsEnabled

_flags = Qt.ItemIsSelectable | Qt.ItemIsEnabled
if idx.column() == self.KEY_COL:
return _flags
elif idx.column() == self.VALUE_COL:
return _flags | Qt.ItemIsEditable

def is_dirty(self):
return self.__dirty

def service_config(self):
return self.__model_data.copy()

def service_name(self):
return self.__service_name

def set_not_dirty(self):
self.__dirty = False
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import os.path
from typing import List, Optional

import pgserviceparser
from typing import (List,
Optional)


def conf_path() -> str:
path = pgserviceparser.conf_path()
return path if os.path.exists(path) else None


def service_names(conf_file_path: Optional[str] = None) -> List[str]:
return pgserviceparser.service_names(conf_file_path)

Expand All @@ -18,9 +18,9 @@ def service_config(service_name: str, conf_file_path: Optional[str] = None) -> d


def write_service_settings(
service_name: str,
settings: dict,
conf_file_path: Optional[str] = None,
service_name: str,
settings: dict,
conf_file_path: Optional[str] = None,
) -> bool:
"""Returns true if it could write the settings to the file.
Expand All @@ -39,13 +39,15 @@ def write_service_settings(
return False


def create_service(service_name: str, settings: dict, conf_file_path: Optional[str] = None) -> bool:
def create_service(
service_name: str, settings: dict, conf_file_path: Optional[str] = None
) -> bool:
config = pgserviceparser.full_config(conf_file_path)
if service_name in config:
return False

config.add_section(service_name)
with open(conf_file_path or pgserviceparser.conf_path(), 'w') as f:
with open(conf_file_path or pgserviceparser.conf_path(), "w") as f:
config.write(f)

if service_name in config:
Expand All @@ -54,7 +56,9 @@ def create_service(service_name: str, settings: dict, conf_file_path: Optional[s
return False


def copy_service_settings(source_service_name: str, target_service_name: str, conf_file_path: Optional[str] = None) -> bool:
def copy_service_settings(
source_service_name: str, target_service_name: str, conf_file_path: Optional[str] = None
) -> bool:
settings = pgserviceparser.service_config(source_service_name, conf_file_path)

config = pgserviceparser.full_config(conf_file_path)
Expand All @@ -67,12 +71,17 @@ def copy_service_settings(source_service_name: str, target_service_name: str, co
return res


if __name__ == '__main__':
if __name__ == "__main__":
assert service_names() == []

# Add new service
_settings = {'host': 'localhost', 'port': '5432', 'user': 'postgres', 'password': 'secret',
'dbname': 'qgis_test_db'}
_settings = {
"host": "localhost",
"port": "5432",
"user": "postgres",
"password": "secret",
"dbname": "qgis_test_db",
}
assert create_service("qgis-test", _settings)
assert service_names() == ["qgis-test"]

Expand All @@ -82,8 +91,13 @@ def copy_service_settings(source_service_name: str, target_service_name: str, co
assert service_config("qgis-demo") == _settings

# Add new service
_settings = {'host': 'localhost', 'port': '5433', 'user': 'admin', 'password': 'secret',
'dbname': 'qgis_test_db2'}
_settings = {
"host": "localhost",
"port": "5433",
"user": "admin",
"password": "secret",
"dbname": "qgis_test_db2",
}
assert create_service("qgis-new-test", _settings)
assert service_names() == ["qgis-test", "qgis-demo", "qgis-new-test"]
assert service_config("qgis-new-test") == _settings
Expand Down
97 changes: 84 additions & 13 deletions pg_service_parser/gui/dlg_pg_service.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
from qgis.PyQt.QtCore import (Qt,
pyqtSlot)
from qgis.PyQt.QtWidgets import (QDialog,
QSizePolicy)
from qgis.gui import QgsMessageBar

from pg_service_parser.pg_service_parser_wrapper import (conf_path,
copy_service_settings,
service_names)
from qgis.PyQt.QtCore import Qt, pyqtSlot
from qgis.PyQt.QtWidgets import QDialog, QMessageBox, QSizePolicy

from pg_service_parser.core.item_models import ServiceConfigModel
from pg_service_parser.core.pg_service_parser_wrapper import (
conf_path,
copy_service_settings,
service_config,
service_names,
write_service_settings,
)
from pg_service_parser.utils import get_ui_class

DIALOG_UI = get_ui_class('pg_service_dialog.ui')
DIALOG_UI = get_ui_class("pg_service_dialog.ui")
COPY_TAB_INDEX = 0
EDIT_TAB_INDEX = 1

Expand All @@ -23,18 +26,24 @@ def __init__(self, parent):
conf_file_path = conf_path()
if not conf_file_path:
self.lblConfFile.setText("Config file not found!")
self.lblConfFile.setToolTip("Set your PGSERVICEFILE environment variable and reopen the dialog.")
self.lblConfFile.setToolTip(
"Set your PGSERVICEFILE environment variable and reopen the dialog."
)
self.txtConfFile.setVisible(False)
self.tabWidget.setEnabled(False)
return

self.__edit_model = None

self.txtConfFile.setText(conf_file_path)
self.lblWarning.setVisible(False)
self.tabWidget.setTabEnabled(EDIT_TAB_INDEX, False) # Not yet implemented

self.radOverwrite.toggled.connect(self.__update_target_controls)
self.btnCopyService.clicked.connect(self.__copy_service)
self.cboSourceService.currentIndexChanged.connect(self.__source_service_changed)
self.tabWidget.currentChanged.connect(self.__current_tab_changed)
self.cboEditService.currentIndexChanged.connect(self.__edit_service_changed)
self.btnUpdateService.clicked.connect(self.__update_service_clicked)

self.__initialize_copy_services()
self.__update_target_controls(True)
Expand Down Expand Up @@ -72,25 +81,87 @@ def __initialize_copy_services(self):
self.cboSourceService.addItems(service_names())
self.cboSourceService.setCurrentText(current_text)

def __initialize_edit_services(self):
self.__edit_model = None
current_text = self.cboEditService.currentText() # Remember latest currentText
self.cboEditService.blockSignals(True) # Avoid triggering custom slot while clearing
self.cboEditService.clear()
self.cboEditService.blockSignals(False)
self.cboEditService.addItems(service_names())
self.cboEditService.setCurrentText(current_text)

@pyqtSlot()
def __copy_service(self):
# Validations
if self.radCreate.isChecked():
if not self.txtNewService.text().strip():
self.bar.pushInfo("PG service", "Enter a service name and try again.")
return
elif self.txtNewService.text().strip() in service_names():
self.bar.pushWarning("PG service", "Service name already exists! Change it and try again.")
self.bar.pushWarning(
"PG service", "Service name already exists! Change it and try again."
)
return
elif self.radOverwrite.isChecked():
if not self.cboTargetService.currentText():
self.bar.pushInfo("PG service", "Select a valid target service and try again.")
return

target_service = self.cboTargetService.currentText() if self.radOverwrite.isChecked() else self.txtNewService.text().strip()
target_service = (
self.cboTargetService.currentText()
if self.radOverwrite.isChecked()
else self.txtNewService.text().strip()
)

if copy_service_settings(self.cboSourceService.currentText(), target_service):
self.bar.pushSuccess("PG service", f"PG service copied to '{target_service}'!")
if self.radCreate.isChecked():
self.__initialize_copy_services() # Reflect the newly added service
else:
self.bar.pushWarning("PG service", "There was a problem copying the service!")

@pyqtSlot(int)
def __current_tab_changed(self, index):
if index == COPY_TAB_INDEX:
# self.__initialize_copy_services()
pass # For now, services to be copied won't be altered in other tabs
elif index == EDIT_TAB_INDEX:
self.__initialize_edit_services()

@pyqtSlot(int)
def __edit_service_changed(self, index):
target_service = self.cboEditService.currentText()
if self.__edit_model and self.__edit_model.is_dirty():
if (
not QMessageBox.question(
self,
"Pending edits",
"There are pending edits for service '{}'. Are you sure you want to discard them?".format(
self.__edit_model.service_name()
),
QMessageBox.Yes | QMessageBox.No,
QMessageBox.No,
)
== QMessageBox.Yes
):

self.cboEditService.blockSignals(True)
self.cboEditService.setCurrentText(self.__edit_model.service_name())
self.cboEditService.blockSignals(False)
return

self.__edit_model = ServiceConfigModel(target_service, service_config(target_service))
self.tblServiceConfig.setModel(self.__edit_model)

@pyqtSlot()
def __update_service_clicked(self):
if self.__edit_model and self.__edit_model.is_dirty():
target_service = self.cboEditService.currentText()
res = write_service_settings(target_service, self.__edit_model.service_config())
if res:
self.bar.pushSuccess("PG service", f"PG service '{target_service}' updated!")
self.__edit_model.set_not_dirty()
else:
self.bar.pushWarning("PG service", "There was a problem updating the service!")
else:
self.bar.pushInfo("PG service", "Edit the service configuration and try again.")
26 changes: 22 additions & 4 deletions pg_service_parser/ui/pg_service_dialog.ui
Original file line number Diff line number Diff line change
Expand Up @@ -205,13 +205,31 @@
</layout>
</item>
<item>
<widget class="QListWidget" name="lstServiceSettings">
<widget class="QTableView" name="tblServiceConfig">
<property name="editTriggers">
<set>QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed</set>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="modelColumn">
<number>0</number>
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="gridStyle">
<enum>Qt::DotLine</enum>
</property>
<attribute name="horizontalHeaderVisible">
<bool>false</bool>
</attribute>
<attribute name="horizontalHeaderStretchLastSection">
<bool>true</bool>
</attribute>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
</widget>
</item>
<item>
Expand All @@ -230,7 +248,7 @@
</spacer>
</item>
<item>
<widget class="QPushButton" name="btnCopyService_2">
<widget class="QPushButton" name="btnUpdateService">
<property name="text">
<string>Update service</string>
</property>
Expand Down

0 comments on commit fd45bc1

Please sign in to comment.