diff --git a/.gitignore b/.gitignore
index c67859c..02b6b0c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,4 @@ pg_service_parser/libs/
!pg_service_parser/libs/__init__.py
.idea
__pycache__
+.DS_Store
diff --git a/pg_service_parser/core/copy_shortcuts.py b/pg_service_parser/core/copy_shortcuts.py
new file mode 100644
index 0000000..8aad107
--- /dev/null
+++ b/pg_service_parser/core/copy_shortcuts.py
@@ -0,0 +1,120 @@
+from qgis.PyQt.QtCore import QAbstractTableModel, QModelIndex, QObject, Qt
+
+from pg_service_parser.core.plugin_settings import PluginSettings
+
+
+class Shortcut:
+ def __init__(self, service_from: str, service_to: str, name: str = None):
+ if name:
+ self.name = name
+ else:
+ self.name = f"{service_from} -> {service_to}"
+ self.service_from = service_from
+ self.service_to = service_to
+
+ def save(self):
+ PluginSettings().shortcut_from.setValue(self.service_from, self.name)
+ PluginSettings().shortcut_to.setValue(self.service_to, self.name)
+
+ def rename(self, name: str):
+ PluginSettings().shortcuts_node.deleteItem(self.name)
+ self.name = name
+ self.save()
+
+ def delete(self):
+ PluginSettings().shortcuts_node.deleteItem(self.name)
+
+
+class ShortcutsModel(QAbstractTableModel):
+ def __init__(self, parent: QObject = None):
+ super().__init__(parent)
+ self.shortcuts = []
+
+ for shortcut in PluginSettings().shortcuts_node.items():
+ sh_from = PluginSettings().shortcut_from.value(shortcut)
+ sh_to = PluginSettings().shortcut_to.value(shortcut)
+ self.shortcuts.append(Shortcut(sh_from, sh_to, shortcut))
+
+ def add_shortcut(self, service_from: str, service_to: str):
+ existing_names = [sh.name for sh in self.shortcuts]
+ base_name = f"{service_from} -> {service_to}"
+ name = base_name
+ i = 2
+ while name in existing_names:
+ name = f"{base_name} ({i})"
+ i += 1
+
+ shortcut = Shortcut(service_from, service_to, name)
+ shortcut.save()
+ row = self.rowCount()
+ self.beginInsertRows(QModelIndex(), row, row)
+ self.shortcuts.append(shortcut)
+ self.endInsertRows()
+ self.dataChanged.emit(self.index(row, 0), self.index(row, 0))
+
+ def remove_shortcut(self, index: QModelIndex):
+ if not index.isValid():
+ return
+
+ self.beginRemoveRows(QModelIndex(), index.row(), index.row())
+ self.shortcuts[index.row()].delete()
+ del self.shortcuts[index.row()]
+ self.endRemoveRows()
+ self.dataChanged.emit(index, index)
+
+ def headerData(self, section, orientation, role=Qt.DisplayRole):
+ if orientation == Qt.Vertical:
+ return None
+
+ if role == Qt.DisplayRole:
+ if section == 0:
+ return self.tr("Name")
+ if section == 1:
+ return self.tr("From")
+ if section == 2:
+ return self.tr("To")
+
+ return super().headerData(section, orientation, role)
+
+ def rowCount(self, parent=QModelIndex()):
+ return len(self.shortcuts)
+
+ def columnCount(self, parent=QModelIndex()):
+ return 3
+
+ def flags(self, index):
+ if not index.isValid():
+ return None
+
+ if index.column() == 0:
+ return Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsEditable
+ else:
+ return Qt.ItemIsSelectable | Qt.ItemIsEnabled
+
+ def data(self, index, role=Qt.DisplayRole):
+ if not index.isValid:
+ return None
+
+ if role == Qt.DisplayRole:
+ if index.column() == 0:
+ return self.shortcuts[index.row()].name
+ if index.column() == 1:
+ return self.shortcuts[index.row()].service_from
+ if index.column() == 2:
+ return self.shortcuts[index.row()].service_to
+
+ return None
+
+ def setData(self, index, value, role=Qt.EditRole):
+ if not index.isValid():
+ return False
+
+ if role == Qt.EditRole and len(value) > 0:
+ for sh in self.shortcuts:
+ if sh.name == value:
+ return False
+ self.shortcuts[index.row()].rename(value)
+ self.dataChanged.emit(index, index)
+ return True
+
+ return False
diff --git a/pg_service_parser/core/plugin_settings.py b/pg_service_parser/core/plugin_settings.py
new file mode 100644
index 0000000..62c0c6c
--- /dev/null
+++ b/pg_service_parser/core/plugin_settings.py
@@ -0,0 +1,20 @@
+from qgis.core import QgsSettingsEntryString, QgsSettingsTree
+
+PLUGIN_NAME = "pg_service_parser"
+
+
+class PluginSettings:
+ instance = None
+
+ def __new__(cls):
+ if cls.instance is None:
+ cls.instance = super().__new__(cls)
+
+ settings_node = QgsSettingsTree.createPluginTreeNode(pluginName=PLUGIN_NAME)
+ shortcuts_node = settings_node.createNamedListNode("shortcuts")
+
+ cls.shortcut_from = QgsSettingsEntryString("shortcut_from", shortcuts_node)
+ cls.shortcut_to = QgsSettingsEntryString("shortcut_to", shortcuts_node)
+ cls.shortcuts_node = shortcuts_node
+
+ return cls.instance
diff --git a/pg_service_parser/gui/dlg_pg_service.py b/pg_service_parser/gui/dlg_pg_service.py
index b7b9e1a..255ca1f 100644
--- a/pg_service_parser/gui/dlg_pg_service.py
+++ b/pg_service_parser/gui/dlg_pg_service.py
@@ -7,6 +7,7 @@
from pg_service_parser.conf.service_settings import SERVICE_SETTINGS, SETTINGS_TEMPLATE
from pg_service_parser.core.connection_model import ServiceConnectionModel
+from pg_service_parser.core.copy_shortcuts import ShortcutsModel
from pg_service_parser.core.pg_service_parser_wrapper import (
add_new_service,
conf_path,
@@ -34,14 +35,15 @@
class PgServiceDialog(QDialog, DIALOG_UI):
-
- def __init__(self, parent):
+ def __init__(self, shortcuts_model: ShortcutsModel, parent):
QDialog.__init__(self, parent)
self.setupUi(self)
# Flag to handle initialization of new files
self.__new_empty_file = False
+ self.__shortcuts_model = shortcuts_model
+
self.__conf_file_path = conf_path()
self.__initialize_dialog()
@@ -68,6 +70,8 @@ def __initialize_dialog(self):
self.btnAddConnection.setIcon(QgsApplication.getThemeIcon("/symbologyAdd.svg"))
self.btnEditConnection.setIcon(QgsApplication.getThemeIcon("/symbologyEdit.svg"))
self.btnRemoveConnection.setIcon(QgsApplication.getThemeIcon("/symbologyRemove.svg"))
+ self.shortcutAddButton.setIcon(QgsApplication.getThemeIcon("/symbologyAdd.svg"))
+ self.shortcutRemoveButton.setIcon(QgsApplication.getThemeIcon("/symbologyRemove.svg"))
self.txtConfFile.setText(str(self.__conf_file_path))
self.lblWarning.setVisible(False)
self.lblConfFile.setText("Config file path found at ")
@@ -77,9 +81,12 @@ def __initialize_dialog(self):
self.btnCreateServiceFile.setVisible(False)
self.tblServiceConnections.horizontalHeader().setVisible(True)
self.btnRemoveSetting.setEnabled(False)
+ self.shortcutRemoveButton.setEnabled(False)
self.radOverwrite.toggled.connect(self.__update_target_controls)
self.btnCopyService.clicked.connect(self.__copy_service)
+ self.shortcutAddButton.clicked.connect(self.__create_copy_shortcut)
+ self.shortcutRemoveButton.clicked.connect(self.__remove_copy_shortcut)
self.cboSourceService.currentIndexChanged.connect(self.__source_service_changed)
self.tabWidget.currentChanged.connect(self.__current_tab_changed)
self.cboEditService.currentIndexChanged.connect(self.__edit_service_changed)
@@ -118,6 +125,7 @@ def __create_file_clicked(self):
def __update_target_controls(self, checked):
self.cboTargetService.setEnabled(self.radOverwrite.isChecked())
self.txtNewService.setEnabled(not self.radOverwrite.isChecked())
+ self.shortcutAddButton.setEnabled(self.radOverwrite.isChecked())
def __update_add_settings_button(self):
# Make sure to call this method whenever the settings are added/removed
@@ -148,6 +156,12 @@ def __initialize_copy_services(self):
self.cboSourceService.addItems(service_names(self.__conf_file_path))
self.cboSourceService.setCurrentText(current_text)
+ self.shortcutsTableView.setModel(self.__shortcuts_model)
+ self.shortcutsTableView.resizeColumnsToContents()
+ self.shortcutsTableView.selectionModel().selectionChanged.connect(
+ self.__shortcuts_selection_changed
+ )
+
def __initialize_edit_services(self):
self.__edit_model = None
current_text = self.cboEditService.currentText() # Remember latest currentText
@@ -199,6 +213,35 @@ def __copy_service(self):
if self.radCreate.isChecked():
self.__initialize_copy_services() # Reflect the newly added service
+ @pyqtSlot()
+ def __create_copy_shortcut(self):
+ target_service = self.cboTargetService.currentText()
+
+ if not self.cboTargetService.currentText():
+ self.bar.pushInfo("PG service", "Select a valid target service and try again.")
+ return
+ self.__shortcuts_model.add_shortcut(self.cboSourceService.currentText(), target_service)
+ if self.__shortcuts_model.rowCount() == 1:
+ self.shortcutsTableView.resizeColumnsToContents()
+
+ @pyqtSlot()
+ def __remove_copy_shortcut(self):
+ selectedIndexes = self.shortcutsTableView.selectedIndexes()
+ if len(selectedIndexes) == 0:
+ return
+
+ shortcut = self.__shortcuts_model.data(selectedIndexes[0])
+
+ res = QMessageBox.question(
+ self,
+ "Remove shortcut",
+ f"Are you sure you want to remove the shortcut '{shortcut}'?",
+ QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
+ QMessageBox.StandardButton.No,
+ )
+ if res == QMessageBox.StandardButton.Yes:
+ self.__shortcuts_model.remove_shortcut(selectedIndexes[0])
+
@pyqtSlot(int)
def __current_tab_changed(self, index):
if index == COPY_TAB_INDEX:
@@ -374,3 +417,7 @@ def __conn_table_selection_changed(self, selected, deselected):
def __update_connection_controls(self, enable):
self.btnEditConnection.setEnabled(enable)
self.btnRemoveConnection.setEnabled(enable)
+
+ @pyqtSlot(QItemSelection, QItemSelection)
+ def __shortcuts_selection_changed(self, selected, deselected):
+ self.shortcutRemoveButton.setEnabled(len(selected) > 0)
diff --git a/pg_service_parser/pg_service_parser_plugin.py b/pg_service_parser/pg_service_parser_plugin.py
index 36f5cde..26a1511 100644
--- a/pg_service_parser/pg_service_parser_plugin.py
+++ b/pg_service_parser/pg_service_parser_plugin.py
@@ -1,30 +1,113 @@
+import os
from pathlib import Path
+from qgis.core import NULL, QgsSettingsTree
+from qgis.PyQt.QtCore import QCoreApplication, QLocale, QSettings, QTranslator
from qgis.PyQt.QtGui import QIcon
-from qgis.PyQt.QtWidgets import QAction
+from qgis.PyQt.QtWidgets import QAction, QMenu, QToolButton
+from pg_service_parser.core.copy_shortcuts import ShortcutsModel
+from pg_service_parser.core.pg_service_parser_wrapper import (
+ conf_path,
+ copy_service_settings,
+ service_names,
+)
+from pg_service_parser.core.plugin_settings import PLUGIN_NAME
from pg_service_parser.gui.dlg_pg_service import PgServiceDialog
class PgServiceParserPlugin:
def __init__(self, iface):
self.iface = iface
+
+ # initialize translation
+ qgis_locale = QLocale(
+ str(QSettings().value("locale/userLocale")).replace(str(NULL), "en_CH")
+ )
+ locale_path = os.path.join(os.path.dirname(__file__), "i18n")
+ self.translator = QTranslator()
+ self.translator.load(qgis_locale, "qgis-pg-service-parser-plugin", "_", locale_path)
+ QCoreApplication.installTranslator(self.translator)
+
self.action = None
+ self.shortcuts_model = None
+
+ def tr(self, text: str) -> str:
+ return QCoreApplication.translate("Plugin", text)
def initGui(self):
- self.action = QAction(
+ icon = QIcon(str(Path(__file__).parent / "images" / "logo.png"))
+
+ self.shortcuts_model = ShortcutsModel(self.iface.mainWindow())
+ self.shortcuts_model.dataChanged.connect(self.build_menus)
+
+ self.button = QToolButton(self.iface.mainWindow())
+ self.button.setIcon(icon)
+
+ self.menu = self.iface.pluginMenu().addMenu(icon, "PG service parser")
+
+ self.default_action = QAction(
QIcon(str(Path(__file__).parent / "images" / "logo.png")),
"PG service parser",
self.iface.mainWindow(),
)
- self.action.triggered.connect(self.run)
- self.iface.addToolBarIcon(self.action)
- self.iface.addPluginToDatabaseMenu("PG service parser", self.action)
+ self.default_action.triggered.connect(self.run)
+ self.button.setDefaultAction(self.default_action)
+
+ self.action = self.iface.addToolBarWidget(self.button)
+
+ self.build_menus()
+
+ def build_menus(self):
+ self.menu.clear()
+
+ button_menu = QMenu()
+ button_menu.addAction(self.default_action)
+
+ self.menu.addAction(self.default_action)
+
+ if len(self.shortcuts_model.shortcuts):
+ _conf_path = conf_path()
+ _services = service_names(_conf_path)
+ self.button.setPopupMode(QToolButton.MenuButtonPopup)
+ button_menu.addSeparator()
+ for shortcut in self.shortcuts_model.shortcuts:
+ action = QAction(shortcut.name, self.iface.mainWindow())
+ action.setToolTip(
+ self.tr(f"Copy service '{shortcut.service_from}' to '{shortcut.service_to}'.")
+ )
+ action.setEnabled(
+ _conf_path.exists()
+ and shortcut.service_from in _services
+ and shortcut.service_to in _services
+ )
+ action.triggered.connect(
+ lambda _triggered, _shortcut=shortcut: self.copy_service(
+ _shortcut.service_from, _shortcut.service_to
+ )
+ )
+ button_menu.addAction(action)
+ self.menu.addAction(action)
+ else:
+ self.button.setPopupMode(QToolButton.DelayedPopup)
+
+ self.button.setMenu(button_menu)
def unload(self):
self.iface.removeToolBarIcon(self.action)
self.iface.removePluginDatabaseMenu("PG service parser", self.action)
+ self.iface.pluginMenu().removeAction(self.menu.menuAction())
+ QgsSettingsTree.unregisterPluginTreeNode(PLUGIN_NAME)
def run(self):
- dlg = PgServiceDialog(self.iface.mainWindow())
+ dlg = PgServiceDialog(self.shortcuts_model, self.iface.mainWindow())
dlg.exec()
+
+ def copy_service(self, service_from: str, service_to: str):
+ print(service_from, service_to)
+ _conf_path = conf_path()
+ if _conf_path.exists():
+ copy_service_settings(service_from, service_to, _conf_path)
+ self.iface.messageBar().pushMessage(
+ "PG service", f"PG service copied to '{service_to}'!"
+ )
diff --git a/pg_service_parser/ui/pg_service_dialog.ui b/pg_service_parser/ui/pg_service_dialog.ui
index c50ebb1..041cce2 100644
--- a/pg_service_parser/ui/pg_service_dialog.ui
+++ b/pg_service_parser/ui/pg_service_dialog.ui
@@ -6,8 +6,8 @@
0
0
- 499
- 316
+ 693
+ 574
@@ -231,22 +231,6 @@
Copy Service
- -
-
-
- Qt::Vertical
-
-
- QSizePolicy::Preferred
-
-
-
- 20
- 71
-
-
-
-
-
@@ -260,6 +244,59 @@
+ -
+
+
+ Copy service
+
+
+
+ -
+
+
+ Shortcuts
+
+
+
-
+
+
+ ...
+
+
+
+ -
+
+
+ ...
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
+
+ QAbstractItemView::SingleSelection
+
+
+ QAbstractItemView::SelectRows
+
+
+
+
+
+
-
@@ -317,12 +354,34 @@
- -
-
-
- Copy service
+
-
+
+
+ Qt::Vertical
-
+
+ QSizePolicy::Preferred
+
+
+
+ 20
+ 71
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+