oqtopus 0.1.14__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- oqtopus/__init__.py +4 -0
- oqtopus/core/module.py +115 -0
- oqtopus/core/module_asset.py +16 -0
- oqtopus/core/module_package.py +118 -0
- oqtopus/core/modules_config.py +11 -0
- oqtopus/core/package_prepare_task.py +148 -0
- oqtopus/gui/__init__.py +0 -0
- oqtopus/gui/about_dialog.py +61 -0
- oqtopus/gui/database_connection_widget.py +154 -0
- oqtopus/gui/database_create_dialog.py +210 -0
- oqtopus/gui/database_duplicate_dialog.py +100 -0
- oqtopus/gui/logs_widget.py +177 -0
- oqtopus/gui/main_dialog.py +168 -0
- oqtopus/gui/module_selection_widget.py +350 -0
- oqtopus/gui/module_widget.py +199 -0
- oqtopus/gui/parameters_groupbox.py +75 -0
- oqtopus/gui/project_widget.py +170 -0
- oqtopus/gui/settings_dialog.py +37 -0
- oqtopus/oqtopus.py +67 -0
- oqtopus/oqtopus_plugin.py +184 -0
- oqtopus/ui/__init__.py +0 -0
- oqtopus/utils/__init__.py +0 -0
- oqtopus/utils/plugin_utils.py +172 -0
- oqtopus/utils/qt_utils.py +94 -0
- oqtopus/utils/tmmtlogging.py +50 -0
- oqtopus/utils/translation.py +84 -0
- oqtopus-0.1.14.dist-info/METADATA +363 -0
- oqtopus-0.1.14.dist-info/RECORD +33 -0
- oqtopus-0.1.14.dist-info/WHEEL +5 -0
- oqtopus-0.1.14.dist-info/licenses/LICENSE +339 -0
- oqtopus-0.1.14.dist-info/top_level.txt +2 -0
- tests/__init__.py +12 -0
- tests/test_plugin_load.py +22 -0
@@ -0,0 +1,350 @@
|
|
1
|
+
from qgis.PyQt.QtCore import Qt, QUrl, pyqtSignal
|
2
|
+
from qgis.PyQt.QtGui import QDesktopServices
|
3
|
+
from qgis.PyQt.QtWidgets import QApplication, QFileDialog, QMessageBox, QWidget
|
4
|
+
|
5
|
+
from ..core.module import Module
|
6
|
+
from ..core.module_package import ModulePackage
|
7
|
+
from ..core.package_prepare_task import PackagePrepareTask, PackagePrepareTaskCanceled
|
8
|
+
from ..utils.plugin_utils import PluginUtils, logger
|
9
|
+
from ..utils.qt_utils import CriticalMessageBox, OverrideCursor, QtUtils
|
10
|
+
|
11
|
+
DIALOG_UI = PluginUtils.get_ui_class("module_selection_widget.ui")
|
12
|
+
|
13
|
+
|
14
|
+
class ModuleSelectionWidget(QWidget, DIALOG_UI):
|
15
|
+
|
16
|
+
module_package_SPECIAL_LOAD_DEVELOPMENT = "Load development versions"
|
17
|
+
|
18
|
+
signal_loadingStarted = pyqtSignal()
|
19
|
+
signal_loadingFinished = pyqtSignal()
|
20
|
+
|
21
|
+
def __init__(self, modules_config, parent=None):
|
22
|
+
QWidget.__init__(self, parent)
|
23
|
+
self.setupUi(self)
|
24
|
+
|
25
|
+
self.__current_module = None
|
26
|
+
self.__current_module_package = None
|
27
|
+
self.__modules_config = modules_config
|
28
|
+
|
29
|
+
self.module_progressBar.setVisible(False)
|
30
|
+
|
31
|
+
self.module_module_comboBox.clear()
|
32
|
+
self.module_module_comboBox.addItem(self.tr("Please select a module"), None)
|
33
|
+
for config_module in self.__modules_config.modules:
|
34
|
+
module = Module(
|
35
|
+
name=config_module.name,
|
36
|
+
organisation=config_module.organisation,
|
37
|
+
repository=config_module.repository,
|
38
|
+
parent=self,
|
39
|
+
)
|
40
|
+
self.module_module_comboBox.addItem(module.name, module)
|
41
|
+
module.signal_versionsLoaded.connect(self.__loadVersionsFinished)
|
42
|
+
module.signal_developmentVersionsLoaded.connect(self.__loadDevelopmentVersionsFinished)
|
43
|
+
|
44
|
+
self.module_latestVersion_label.setText("")
|
45
|
+
QtUtils.setForegroundColor(self.module_latestVersion_label, PluginUtils.COLOR_GREEN)
|
46
|
+
|
47
|
+
self.module_package_comboBox.clear()
|
48
|
+
self.module_package_comboBox.addItem(self.tr("Please select a version"), None)
|
49
|
+
|
50
|
+
self.module_zipPackage_groupBox.setVisible(False)
|
51
|
+
|
52
|
+
self.module_module_comboBox.currentIndexChanged.connect(self.__moduleChanged)
|
53
|
+
self.module_package_comboBox.currentIndexChanged.connect(self.__moduleVersionChanged)
|
54
|
+
self.module_seeChangeLog_pushButton.clicked.connect(self.__seeChangeLogClicked)
|
55
|
+
self.module_browseZip_toolButton.clicked.connect(self.__moduleBrowseZipClicked)
|
56
|
+
|
57
|
+
self.__packagePrepareTask = PackagePrepareTask(self)
|
58
|
+
self.__packagePrepareTask.finished.connect(self.__packagePrepareTaskFinished)
|
59
|
+
self.__packagePrepareTask.signalPackagingProgress.connect(
|
60
|
+
self.__packagePrepareTaskProgress
|
61
|
+
)
|
62
|
+
|
63
|
+
def close(self):
|
64
|
+
if self.__packagePrepareTask.isRunning():
|
65
|
+
self.__packagePrepareTask.cancel()
|
66
|
+
self.__packagePrepareTask.wait()
|
67
|
+
|
68
|
+
def getSelectedModulePackage(self):
|
69
|
+
return self.__current_module_package
|
70
|
+
|
71
|
+
def lastError(self):
|
72
|
+
"""
|
73
|
+
Returns the last error occurred during the loading process.
|
74
|
+
If no error occurred, returns None.
|
75
|
+
"""
|
76
|
+
return self.__packagePrepareTask.lastError
|
77
|
+
|
78
|
+
def __moduleChanged(self, index):
|
79
|
+
if self.module_module_comboBox.currentData() == self.__current_module:
|
80
|
+
return
|
81
|
+
|
82
|
+
self.__current_module = self.module_module_comboBox.currentData()
|
83
|
+
|
84
|
+
self.module_latestVersion_label.setText("")
|
85
|
+
self.module_package_comboBox.clear()
|
86
|
+
self.module_package_comboBox.addItem(self.tr("Please select a version"), None)
|
87
|
+
|
88
|
+
if self.__current_module is None:
|
89
|
+
return
|
90
|
+
|
91
|
+
if self.__current_module.versions == list():
|
92
|
+
QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor)
|
93
|
+
self.__current_module.start_load_versions()
|
94
|
+
|
95
|
+
def __moduleVersionChanged(self, index):
|
96
|
+
|
97
|
+
if (
|
98
|
+
self.module_package_comboBox.currentData()
|
99
|
+
== self.module_package_SPECIAL_LOAD_DEVELOPMENT
|
100
|
+
):
|
101
|
+
self.__loadDevelopmentVersions()
|
102
|
+
return
|
103
|
+
|
104
|
+
if self.__packagePrepareTask.isRunning():
|
105
|
+
logger.info("Package prepare task is running, canceling it.")
|
106
|
+
self.__packagePrepareTask.cancel()
|
107
|
+
self.__packagePrepareTask.wait()
|
108
|
+
|
109
|
+
self.__current_module_package = self.module_package_comboBox.currentData()
|
110
|
+
if self.__current_module_package is None:
|
111
|
+
return
|
112
|
+
|
113
|
+
if self.__current_module_package.type == self.__current_module_package.Type.FROM_ZIP:
|
114
|
+
self.module_zippackage_groupBox.setVisible(True)
|
115
|
+
return
|
116
|
+
else:
|
117
|
+
self.module_zipPackage_groupBox.setVisible(False)
|
118
|
+
|
119
|
+
loading_text = self.tr(
|
120
|
+
f"Loading packages for module '{self.module_module_comboBox.currentText()}' version '{self.__current_module_package.display_name()}'..."
|
121
|
+
)
|
122
|
+
self.module_information_label.setText(loading_text)
|
123
|
+
QtUtils.resetForegroundColor(self.module_information_label)
|
124
|
+
logger.info(loading_text)
|
125
|
+
|
126
|
+
self.module_informationProject_label.setText("-")
|
127
|
+
self.module_informationPlugin_label.setText("-")
|
128
|
+
|
129
|
+
self.__packagePrepareTask.startFromModulePackage(self.__current_module_package)
|
130
|
+
|
131
|
+
self.signal_loadingStarted.emit()
|
132
|
+
self.module_progressBar.setVisible(True)
|
133
|
+
|
134
|
+
def __loadDevelopmentVersions(self):
|
135
|
+
if self.__current_module is None:
|
136
|
+
return
|
137
|
+
|
138
|
+
if self.__current_module.development_versions == list():
|
139
|
+
QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor)
|
140
|
+
self.__current_module.start_load_development_versions()
|
141
|
+
|
142
|
+
def __moduleBrowseZipClicked(self):
|
143
|
+
filename, format = QFileDialog.getOpenFileName(
|
144
|
+
self, self.tr("Open from zip"), None, self.tr("Zip package (*.zip)")
|
145
|
+
)
|
146
|
+
|
147
|
+
if filename == "":
|
148
|
+
return
|
149
|
+
|
150
|
+
self.module_fromZip_lineEdit.setText(filename)
|
151
|
+
|
152
|
+
try:
|
153
|
+
with OverrideCursor(Qt.CursorShape.WaitCursor):
|
154
|
+
self.__loadModuleFromZip(filename)
|
155
|
+
except Exception as exception:
|
156
|
+
CriticalMessageBox(
|
157
|
+
self.tr("Error"), self.tr("Can't load module from zip file:"), exception, self
|
158
|
+
).exec()
|
159
|
+
return
|
160
|
+
|
161
|
+
def __loadModuleFromZip(self, filename):
|
162
|
+
|
163
|
+
if self.__packagePrepareTask.isRunning():
|
164
|
+
self.__packagePrepareTask.cancel()
|
165
|
+
self.__packagePrepareTask.wait()
|
166
|
+
|
167
|
+
self.__packagePrepareTask.startFromZip(filename)
|
168
|
+
|
169
|
+
self.signal_loadingStarted.emit()
|
170
|
+
self.module_progressBar.setVisible(True)
|
171
|
+
|
172
|
+
def __packagePrepareTaskFinished(self):
|
173
|
+
logger.info("Load package task finished")
|
174
|
+
|
175
|
+
self.signal_loadingFinished.emit()
|
176
|
+
self.module_progressBar.setVisible(False)
|
177
|
+
|
178
|
+
if isinstance(self.__packagePrepareTask.lastError, PackagePrepareTaskCanceled):
|
179
|
+
logger.info("Load package task was canceled by user.")
|
180
|
+
self.module_information_label.setText(self.tr("Package loading canceled."))
|
181
|
+
QtUtils.setForegroundColor(self.module_information_label, PluginUtils.COLOR_WARNING)
|
182
|
+
return
|
183
|
+
|
184
|
+
if self.__packagePrepareTask.lastError is not None:
|
185
|
+
error_text = self.tr("Can't load module package:")
|
186
|
+
CriticalMessageBox(
|
187
|
+
self.tr("Error"), error_text, self.__packagePrepareTask.lastError, self
|
188
|
+
).exec()
|
189
|
+
self.module_information_label.setText(error_text)
|
190
|
+
QtUtils.setForegroundColor(self.module_information_label, PluginUtils.COLOR_WARNING)
|
191
|
+
return
|
192
|
+
|
193
|
+
package_dir = self.module_package_comboBox.currentData().package_dir
|
194
|
+
logger.info(f"Package loaded into '{package_dir}'")
|
195
|
+
self.module_information_label.setText(package_dir)
|
196
|
+
QtUtils.resetForegroundColor(self.module_information_label)
|
197
|
+
|
198
|
+
asset_project = self.module_package_comboBox.currentData().asset_project
|
199
|
+
if asset_project:
|
200
|
+
self.module_informationProject_label.setText(asset_project.package_dir)
|
201
|
+
else:
|
202
|
+
self.module_informationProject_label.setText("No asset available")
|
203
|
+
|
204
|
+
asset_plugin = self.module_package_comboBox.currentData().asset_plugin
|
205
|
+
if asset_plugin:
|
206
|
+
self.module_informationPlugin_label.setText(asset_plugin.package_dir)
|
207
|
+
else:
|
208
|
+
self.module_informationPlugin_label.setText("No asset available")
|
209
|
+
|
210
|
+
def __packagePrepareTaskProgress(self, progress):
|
211
|
+
loading_text = self.tr("Load package task running...")
|
212
|
+
logger.info(loading_text)
|
213
|
+
self.module_information_label.setText(loading_text)
|
214
|
+
|
215
|
+
def __seeChangeLogClicked(self):
|
216
|
+
if self.__current_module_package.type == ModulePackage.Type.FROM_ZIP:
|
217
|
+
QMessageBox.warning(
|
218
|
+
self,
|
219
|
+
self.tr("Can't open changelog"),
|
220
|
+
self.tr("Changelog is not available for Zip packages."),
|
221
|
+
)
|
222
|
+
return
|
223
|
+
|
224
|
+
if self.__current_module_package is None:
|
225
|
+
QMessageBox.warning(
|
226
|
+
self,
|
227
|
+
self.tr("Can't open changelog"),
|
228
|
+
self.tr("Please select a module and version first."),
|
229
|
+
)
|
230
|
+
return
|
231
|
+
|
232
|
+
if self.__current_module_package.html_url is None:
|
233
|
+
QMessageBox.warning(
|
234
|
+
self,
|
235
|
+
self.tr("Can't open changelog"),
|
236
|
+
self.tr(
|
237
|
+
f"Changelog not available for version '{self.__current_module_package.display_name()}'."
|
238
|
+
),
|
239
|
+
)
|
240
|
+
return
|
241
|
+
|
242
|
+
changelog_url = self.__current_module_package.html_url
|
243
|
+
logger.info(f"Opening changelog URL: {changelog_url}")
|
244
|
+
QDesktopServices.openUrl(QUrl(changelog_url))
|
245
|
+
|
246
|
+
def __loadVersionsFinished(self, error):
|
247
|
+
logger.info("Loading versions finished")
|
248
|
+
|
249
|
+
QApplication.restoreOverrideCursor()
|
250
|
+
self.signal_loadingFinished.emit()
|
251
|
+
self.module_progressBar.setVisible(False)
|
252
|
+
|
253
|
+
if error:
|
254
|
+
if "rate limit exceeded for url" in error.lower():
|
255
|
+
QMessageBox.critical(
|
256
|
+
self,
|
257
|
+
self.tr("GitHub API Rate Limit Exceeded"),
|
258
|
+
self.tr(
|
259
|
+
"Oqtopus needs to download release data from GitHub to work properly.<br><br>"
|
260
|
+
"GitHub limits the number of requests that can be made without authentication. "
|
261
|
+
"You have reached the maximum number of requests allowed for unauthenticated users.<br><br>"
|
262
|
+
"To continue using this feature, please create a free GitHub personal access token and enter it in the Settings dialog.<br><br>"
|
263
|
+
"This will increase your request limit.<br><br>"
|
264
|
+
"<b>How to get a token:</b><br>"
|
265
|
+
"1. Go to <a href='https://github.com/settings/tokens'>GitHub Personal Access Tokens</a>.<br>"
|
266
|
+
"2. Click <b>Generate new token</b> and select the <code>repo</code> scope.<br>"
|
267
|
+
"3. Copy the generated token and paste it in the Settings dialog of this application."
|
268
|
+
),
|
269
|
+
)
|
270
|
+
return
|
271
|
+
|
272
|
+
error_text = self.tr(f"Can't load module versions: {error}")
|
273
|
+
QMessageBox.critical(self, self.tr("Error"), error_text)
|
274
|
+
self.module_information_label.setText(error_text)
|
275
|
+
QtUtils.setForegroundColor(self.module_information_label, PluginUtils.COLOR_WARNING)
|
276
|
+
return
|
277
|
+
|
278
|
+
for module_package in self.__current_module.versions:
|
279
|
+
self.module_package_comboBox.addItem(module_package.display_name(), module_package)
|
280
|
+
|
281
|
+
if self.__current_module.latest_version is not None:
|
282
|
+
self.module_latestVersion_label.setText(
|
283
|
+
f"Latest: {self.__current_module.latest_version.name}"
|
284
|
+
)
|
285
|
+
|
286
|
+
self.module_package_comboBox.insertSeparator(self.module_package_comboBox.count())
|
287
|
+
self.module_package_comboBox.addItem(
|
288
|
+
self.tr("Load from ZIP file"),
|
289
|
+
ModulePackage(
|
290
|
+
module=self.__current_module,
|
291
|
+
organisation=self.__current_module.organisation,
|
292
|
+
repository=self.__current_module.repository,
|
293
|
+
json_payload=None,
|
294
|
+
type=ModulePackage.Type.FROM_ZIP,
|
295
|
+
),
|
296
|
+
)
|
297
|
+
|
298
|
+
self.module_package_comboBox.insertSeparator(self.module_package_comboBox.count())
|
299
|
+
self.module_package_comboBox.addItem(
|
300
|
+
self.tr("Load development branches"), self.module_package_SPECIAL_LOAD_DEVELOPMENT
|
301
|
+
)
|
302
|
+
|
303
|
+
self.module_progressBar.setVisible(False)
|
304
|
+
logger.info(f"Versions loaded for module '{self.__current_module.name}'.")
|
305
|
+
|
306
|
+
def __loadDevelopmentVersionsFinished(self, error):
|
307
|
+
logger.info("Loading development versions finished")
|
308
|
+
|
309
|
+
QApplication.restoreOverrideCursor()
|
310
|
+
self.signal_loadingFinished.emit()
|
311
|
+
self.module_progressBar.setVisible(False)
|
312
|
+
|
313
|
+
if error:
|
314
|
+
if "rate limit exceeded for url" in error.lower():
|
315
|
+
QMessageBox.critical(
|
316
|
+
self,
|
317
|
+
self.tr("GitHub API Rate Limit Exceeded"),
|
318
|
+
self.tr(
|
319
|
+
"Oqtopus needs to download release data from GitHub to work properly.<br><br>"
|
320
|
+
"GitHub limits the number of requests that can be made without authentication. "
|
321
|
+
"You have reached the maximum number of requests allowed for unauthenticated users.<br><br>"
|
322
|
+
"To continue using this feature, please create a free GitHub personal access token and enter it in the Settings dialog.<br><br>"
|
323
|
+
"This will increase your request limit.<br><br>"
|
324
|
+
"<b>How to get a token:</b><br>"
|
325
|
+
"1. Go to <a href='https://github.com/settings/tokens'>GitHub Personal Access Tokens</a>.<br>"
|
326
|
+
"2. Click <b>Generate new token</b> and select the <code>repo</code> scope.<br>"
|
327
|
+
"3. Copy the generated token and paste it in the Settings dialog of this application."
|
328
|
+
),
|
329
|
+
)
|
330
|
+
return
|
331
|
+
|
332
|
+
error_text = self.tr(f"Can't load module versions: {error}")
|
333
|
+
QMessageBox.critical(self, self.tr("Error"), error_text)
|
334
|
+
self.module_information_label.setText(error_text)
|
335
|
+
QtUtils.setForegroundColor(self.module_information_label, PluginUtils.COLOR_WARNING)
|
336
|
+
return
|
337
|
+
|
338
|
+
if self.__current_module.development_versions == list():
|
339
|
+
QMessageBox.warning(
|
340
|
+
self,
|
341
|
+
self.tr("No development versions found"),
|
342
|
+
self.tr("No development versions found for this module."),
|
343
|
+
)
|
344
|
+
return
|
345
|
+
|
346
|
+
self.module_package_comboBox.removeItem(self.module_package_comboBox.count() - 1)
|
347
|
+
self.module_package_comboBox.setCurrentIndex(0)
|
348
|
+
|
349
|
+
for module_package in self.__current_module.development_versions:
|
350
|
+
self.module_package_comboBox.addItem(module_package.display_name(), module_package)
|
@@ -0,0 +1,199 @@
|
|
1
|
+
import os
|
2
|
+
|
3
|
+
import psycopg
|
4
|
+
from pum.pum_config import PumConfig
|
5
|
+
from pum.schema_migrations import SchemaMigrations
|
6
|
+
from pum.upgrader import Upgrader
|
7
|
+
from qgis.PyQt.QtCore import Qt
|
8
|
+
from qgis.PyQt.QtWidgets import QMessageBox, QWidget
|
9
|
+
|
10
|
+
from ..core.module import Module
|
11
|
+
from ..utils.plugin_utils import PluginUtils, logger
|
12
|
+
from ..utils.qt_utils import CriticalMessageBox, OverrideCursor, QtUtils
|
13
|
+
|
14
|
+
DIALOG_UI = PluginUtils.get_ui_class("module_widget.ui")
|
15
|
+
|
16
|
+
|
17
|
+
class ModuleWidget(QWidget, DIALOG_UI):
|
18
|
+
|
19
|
+
def __init__(self, parent=None):
|
20
|
+
QWidget.__init__(self, parent)
|
21
|
+
self.setupUi(self)
|
22
|
+
|
23
|
+
self.moduleInfo_stackedWidget.setCurrentWidget(self.moduleInfo_stackedWidget_pageInstall)
|
24
|
+
|
25
|
+
self.db_demoData_checkBox.clicked.connect(
|
26
|
+
lambda checked: self.db_demoData_comboBox.setEnabled(checked)
|
27
|
+
)
|
28
|
+
|
29
|
+
self.moduleInfo_install_pushButton.clicked.connect(self.__installModuleClicked)
|
30
|
+
self.moduleInfo_upgrade_pushButton.clicked.connect(self.__upgradeModuleClicked)
|
31
|
+
|
32
|
+
self.__current_module_package = None
|
33
|
+
self.__database_connection = None
|
34
|
+
|
35
|
+
def setModulePackage(self, module_package: Module):
|
36
|
+
self.__current_module_package = module_package
|
37
|
+
self.__packagePrepareGetPUMConfig()
|
38
|
+
self.__updateModuleInfo()
|
39
|
+
|
40
|
+
def setDatabaseConnection(self, connection: psycopg.Connection):
|
41
|
+
self.__database_connection = connection
|
42
|
+
self.__updateModuleInfo()
|
43
|
+
|
44
|
+
def __packagePrepareGetPUMConfig(self):
|
45
|
+
package_dir = self.__current_module_package.package_dir
|
46
|
+
|
47
|
+
if package_dir is None:
|
48
|
+
CriticalMessageBox(
|
49
|
+
self.tr("Error"),
|
50
|
+
self.tr(
|
51
|
+
f"The selected file '{self.__current_module_package.zip_file}' does not contain a valid package directory."
|
52
|
+
),
|
53
|
+
None,
|
54
|
+
self,
|
55
|
+
).exec()
|
56
|
+
return
|
57
|
+
|
58
|
+
self.__data_model_dir = os.path.join(package_dir, "datamodel")
|
59
|
+
pumConfigFilename = os.path.join(self.__data_model_dir, ".pum.yaml")
|
60
|
+
if not os.path.exists(pumConfigFilename):
|
61
|
+
CriticalMessageBox(
|
62
|
+
self.tr("Error"),
|
63
|
+
self.tr(
|
64
|
+
f"The selected file '{self.__current_module_package.zip_file}' does not contain a valid .pum.yaml file."
|
65
|
+
),
|
66
|
+
None,
|
67
|
+
self,
|
68
|
+
).exec()
|
69
|
+
return
|
70
|
+
|
71
|
+
try:
|
72
|
+
self.__pum_config = PumConfig.from_yaml(pumConfigFilename, install_dependencies=True)
|
73
|
+
except Exception as exception:
|
74
|
+
CriticalMessageBox(
|
75
|
+
self.tr("Error"),
|
76
|
+
self.tr(f"Can't load PUM config from '{pumConfigFilename}':"),
|
77
|
+
exception,
|
78
|
+
self,
|
79
|
+
).exec()
|
80
|
+
return
|
81
|
+
|
82
|
+
logger.info(f"PUM config loaded from '{pumConfigFilename}'")
|
83
|
+
|
84
|
+
self.parameters_groupbox.setParameters(self.__pum_config.parameters())
|
85
|
+
|
86
|
+
self.db_demoData_comboBox.clear()
|
87
|
+
for demo_data_name, demo_data_file in self.__pum_config.demo_data().items():
|
88
|
+
self.db_demoData_comboBox.addItem(demo_data_name, demo_data_file)
|
89
|
+
|
90
|
+
def __installModuleClicked(self):
|
91
|
+
|
92
|
+
if self.__current_module_package is None:
|
93
|
+
CriticalMessageBox(
|
94
|
+
self.tr("Error"), self.tr("Please select a module package first."), None, self
|
95
|
+
).exec()
|
96
|
+
return
|
97
|
+
|
98
|
+
if self.__database_connection is None:
|
99
|
+
CriticalMessageBox(
|
100
|
+
self.tr("Error"), self.tr("Please select a database service first."), None, self
|
101
|
+
).exec()
|
102
|
+
return
|
103
|
+
|
104
|
+
if self.__pum_config is None:
|
105
|
+
CriticalMessageBox(
|
106
|
+
self.tr("Error"), self.tr("No valid module available."), None, self
|
107
|
+
).exec()
|
108
|
+
return
|
109
|
+
|
110
|
+
parameters = self.parameters_groupbox.parameters_values()
|
111
|
+
|
112
|
+
try:
|
113
|
+
upgrader = Upgrader(
|
114
|
+
config=self.__pum_config,
|
115
|
+
)
|
116
|
+
with OverrideCursor(Qt.CursorShape.WaitCursor):
|
117
|
+
upgrader.install(
|
118
|
+
parameters=parameters,
|
119
|
+
connection=self.__database_connection,
|
120
|
+
roles=self.db_parameters_CreateAndGrantRoles_checkBox.isChecked(),
|
121
|
+
grant=self.db_parameters_CreateAndGrantRoles_checkBox.isChecked(),
|
122
|
+
)
|
123
|
+
|
124
|
+
if self.db_demoData_checkBox.isChecked():
|
125
|
+
demo_data_name = self.db_demoData_comboBox.currentText()
|
126
|
+
upgrader.install_demo_data(
|
127
|
+
connection=self.__database_connection,
|
128
|
+
name=demo_data_name,
|
129
|
+
parameters=parameters,
|
130
|
+
)
|
131
|
+
except Exception as exception:
|
132
|
+
CriticalMessageBox(
|
133
|
+
self.tr("Error"), self.tr("Can't install the module:"), exception, self
|
134
|
+
).exec()
|
135
|
+
return
|
136
|
+
|
137
|
+
QMessageBox.information(
|
138
|
+
self,
|
139
|
+
self.tr("Module installed"),
|
140
|
+
self.tr(
|
141
|
+
f"Module '{self.__current_module_package.module.name}' version '{self.__current_module_package.name}' has been successfully installed."
|
142
|
+
),
|
143
|
+
)
|
144
|
+
logger.info(
|
145
|
+
f"Module '{self.__current_module_package.module.name}' version '{self.__current_module_package.name}' has been successfully installed."
|
146
|
+
)
|
147
|
+
|
148
|
+
self.__updateModuleInfo()
|
149
|
+
|
150
|
+
def __upgradeModuleClicked(self):
|
151
|
+
QMessageBox.critical(
|
152
|
+
self,
|
153
|
+
self.tr("Not implemented"),
|
154
|
+
self.tr("Upgrade module is not implemented yet."),
|
155
|
+
)
|
156
|
+
return
|
157
|
+
|
158
|
+
def __updateModuleInfo(self):
|
159
|
+
if self.__current_module_package is None:
|
160
|
+
self.moduleInfo_label.setText(self.tr("No module package selected"))
|
161
|
+
QtUtils.setForegroundColor(self.moduleInfo_label, PluginUtils.COLOR_WARNING)
|
162
|
+
return
|
163
|
+
|
164
|
+
if self.__database_connection is None:
|
165
|
+
self.moduleInfo_label.setText(self.tr("No database connection available"))
|
166
|
+
QtUtils.setForegroundColor(self.moduleInfo_label, PluginUtils.COLOR_WARNING)
|
167
|
+
return
|
168
|
+
|
169
|
+
if self.__pum_config is None:
|
170
|
+
self.moduleInfo_label.setText(self.tr("No PUM config available"))
|
171
|
+
QtUtils.setForegroundColor(self.moduleInfo_label, PluginUtils.COLOR_WARNING)
|
172
|
+
return
|
173
|
+
|
174
|
+
migrationVersion = self.__pum_config.last_version()
|
175
|
+
sm = SchemaMigrations(self.__pum_config)
|
176
|
+
|
177
|
+
if sm.exists(self.__database_connection):
|
178
|
+
# Case upgrade
|
179
|
+
baseline_version = sm.baseline(self.__database_connection)
|
180
|
+
self.moduleInfo_label.setText(self.tr(f"Version {baseline_version} found"))
|
181
|
+
QtUtils.resetForegroundColor(self.moduleInfo_label)
|
182
|
+
self.moduleInfo_upgrade_pushButton.setText(self.tr(f"Upgrade to {migrationVersion}"))
|
183
|
+
|
184
|
+
self.moduleInfo_stackedWidget.setCurrentWidget(
|
185
|
+
self.moduleInfo_stackedWidget_pageUpgrade
|
186
|
+
)
|
187
|
+
|
188
|
+
logger.info(
|
189
|
+
f"Migration table details: {sm.migration_details(self.__database_connection)}"
|
190
|
+
)
|
191
|
+
|
192
|
+
else:
|
193
|
+
# Case install
|
194
|
+
self.moduleInfo_label.setText(self.tr("No module found"))
|
195
|
+
QtUtils.resetForegroundColor(self.moduleInfo_label)
|
196
|
+
self.moduleInfo_install_pushButton.setText(self.tr(f"Install {migrationVersion}"))
|
197
|
+
self.moduleInfo_stackedWidget.setCurrentWidget(
|
198
|
+
self.moduleInfo_stackedWidget_pageInstall
|
199
|
+
)
|
@@ -0,0 +1,75 @@
|
|
1
|
+
import logging
|
2
|
+
|
3
|
+
from pum import ParameterDefinition, ParameterType
|
4
|
+
from qgis.PyQt.QtWidgets import (
|
5
|
+
QCheckBox,
|
6
|
+
QGroupBox,
|
7
|
+
QHBoxLayout,
|
8
|
+
QLabel,
|
9
|
+
QLineEdit,
|
10
|
+
QWidget,
|
11
|
+
)
|
12
|
+
|
13
|
+
logger = logging.getLogger(__name__)
|
14
|
+
|
15
|
+
|
16
|
+
class ParameterWidget(QWidget):
|
17
|
+
def __init__(self, parameter_definition: ParameterDefinition, parent):
|
18
|
+
QWidget.__init__(self, parent)
|
19
|
+
self.layout = QHBoxLayout(self)
|
20
|
+
self.layout.setContentsMargins(0, 0, 0, 0)
|
21
|
+
self.setLayout(self.layout)
|
22
|
+
self.value = None
|
23
|
+
self.__valueChanged = False
|
24
|
+
|
25
|
+
if parameter_definition.type != ParameterType.BOOLEAN:
|
26
|
+
self.layout.addWidget(QLabel(parameter_definition.name, self))
|
27
|
+
|
28
|
+
if parameter_definition.type == ParameterType.BOOLEAN:
|
29
|
+
self.widget = QCheckBox(parameter_definition.name, self)
|
30
|
+
self.widget.setChecked(parameter_definition.default)
|
31
|
+
self.widget.checked.connect(self.__valueChanged)
|
32
|
+
self.layout.addWidget(self.widget)
|
33
|
+
self.value = lambda: self.widget.isChecked()
|
34
|
+
elif parameter_definition.type in (
|
35
|
+
ParameterType.DECIMAL,
|
36
|
+
ParameterType.INTEGER,
|
37
|
+
ParameterType.TEXT,
|
38
|
+
):
|
39
|
+
self.widget = QLineEdit(self)
|
40
|
+
if parameter_definition.default is not None:
|
41
|
+
self.widget.setPlaceholderText(str(parameter_definition.default))
|
42
|
+
self.layout.addWidget(self.widget)
|
43
|
+
if parameter_definition.type == ParameterType.INTEGER:
|
44
|
+
self.value = lambda: int(self.widget.text() or self.widget.placeholderText())
|
45
|
+
elif parameter_definition.type == ParameterType.DECIMAL:
|
46
|
+
self.value = lambda: float(self.widget.text() or self.widget.placeholderText())
|
47
|
+
else:
|
48
|
+
self.value = lambda: self.widget.text() or self.widget.placeholderText()
|
49
|
+
|
50
|
+
|
51
|
+
class ParametersGroupBox(QGroupBox):
|
52
|
+
def __init__(self, parent):
|
53
|
+
QGroupBox.__init__(self, parent)
|
54
|
+
self.parameter_widgets = {}
|
55
|
+
|
56
|
+
def setParameters(self, parameters: list[ParameterDefinition]):
|
57
|
+
logger.info(f"Setting parameters in ParametersGroupBox ({len(parameters)})")
|
58
|
+
self.clean()
|
59
|
+
self.parameters = parameters
|
60
|
+
# Remove all widgets from the parameters_group_box layout
|
61
|
+
for parameter in parameters:
|
62
|
+
pw = ParameterWidget(parameter, self)
|
63
|
+
self.layout().addWidget(pw)
|
64
|
+
self.parameter_widgets[parameter.name] = pw
|
65
|
+
|
66
|
+
def parameters_values(self):
|
67
|
+
values = {}
|
68
|
+
for parameter in self.parameters:
|
69
|
+
values[parameter.name] = self.parameter_widgets[parameter.name].value()
|
70
|
+
return values
|
71
|
+
|
72
|
+
def clean(self):
|
73
|
+
for widget in self.parameter_widgets.values():
|
74
|
+
widget.deleteLater()
|
75
|
+
self.parameter_widgets = {}
|