Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Shortcuts to copy services #55

Merged
merged 4 commits into from
Nov 20, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ pg_service_parser/libs/
!pg_service_parser/libs/__init__.py
.idea
__pycache__
.DS_Store
121 changes: 121 additions & 0 deletions pg_service_parser/core/copy_shortcuts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
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
if index.column() == 0:
self.shortcuts[index.row()].rename(value)
self.dataChanged.emit(index, index)
return True

return False
20 changes: 20 additions & 0 deletions pg_service_parser/core/plugin_settings.py
Original file line number Diff line number Diff line change
@@ -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
51 changes: 49 additions & 2 deletions pg_service_parser/gui/dlg_pg_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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()

Expand All @@ -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"))
3nids marked this conversation as resolved.
Show resolved Hide resolved
self.txtConfFile.setText(str(self.__conf_file_path))
self.lblWarning.setVisible(False)
self.lblConfFile.setText("Config file path found at ")
Expand All @@ -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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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()
3nids marked this conversation as resolved.
Show resolved Hide resolved
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
Expand Down Expand Up @@ -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():
3nids marked this conversation as resolved.
Show resolved Hide resolved
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:
Expand Down Expand Up @@ -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)
97 changes: 91 additions & 6 deletions pg_service_parser/pg_service_parser_plugin.py
Original file line number Diff line number Diff line change
@@ -1,30 +1,115 @@
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")
3nids marked this conversation as resolved.
Show resolved Hide resolved
self.menu.setToolTipsVisible(True)

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.setToolTipsVisible(True)
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)
3nids marked this conversation as resolved.
Show resolved Hide resolved
_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}'!"
3nids marked this conversation as resolved.
Show resolved Hide resolved
)
Loading