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 ADDED
@@ -0,0 +1,4 @@
1
+ def classFactory(iface):
2
+ from .oqtopus_plugin import OqtopusPlugin
3
+
4
+ return OqtopusPlugin(iface)
oqtopus/core/module.py ADDED
@@ -0,0 +1,115 @@
1
+ import json
2
+
3
+ from qgis.PyQt.QtCore import QByteArray, QObject, QUrl, pyqtSignal
4
+ from qgis.PyQt.QtNetwork import QNetworkAccessManager, QNetworkReply, QNetworkRequest
5
+
6
+ from ..utils.plugin_utils import PluginUtils
7
+ from .module_package import ModulePackage
8
+
9
+
10
+ class Module(QObject):
11
+ signal_versionsLoaded = pyqtSignal(str)
12
+ signal_developmentVersionsLoaded = pyqtSignal(str)
13
+
14
+ def __init__(self, name: str, organisation: str, repository: str, parent=None):
15
+ super().__init__(parent)
16
+ self.name = name
17
+ self.organisation = organisation
18
+ self.repository = repository
19
+ self.versions = []
20
+ self.development_versions = []
21
+ self.latest_version = None
22
+ self.network_manager = QNetworkAccessManager(self)
23
+
24
+ def __repr__(self):
25
+ return f"Module(name={self.name}, organisation={self.organisation}, repository={self.repository})"
26
+
27
+ def start_load_versions(self):
28
+ url = QUrl(f"https://api.github.com/repos/{self.organisation}/{self.repository}/releases")
29
+ request = QNetworkRequest(url)
30
+ headers = PluginUtils.get_github_headers()
31
+ for key, value in headers.items():
32
+ request.setRawHeader(QByteArray(key.encode()), QByteArray(value.encode()))
33
+ reply = self.network_manager.get(request)
34
+ reply.finished.connect(lambda: self._on_versions_reply(reply))
35
+
36
+ def _on_versions_reply(self, reply):
37
+ if reply.error() != QNetworkReply.NetworkError.NoError:
38
+ self.signal_versionsLoaded.emit(reply.errorString())
39
+ reply.deleteLater()
40
+ return
41
+ try:
42
+ data = reply.readAll().data()
43
+ json_versions = json.loads(data.decode())
44
+ self.versions = []
45
+ self.latest_version = None
46
+ for json_version in json_versions:
47
+ module_package = ModulePackage(
48
+ module=self,
49
+ organisation=self.organisation,
50
+ repository=self.repository,
51
+ json_payload=json_version,
52
+ type=ModulePackage.Type.RELEASE,
53
+ )
54
+ self.versions.append(module_package)
55
+
56
+ # Latest version -> most recent commit date for non prerelease
57
+ if module_package.prerelease is True:
58
+ continue
59
+
60
+ if self.latest_version is None:
61
+ self.latest_version = module_package
62
+ continue
63
+
64
+ if module_package.created_at > self.latest_version.created_at:
65
+ self.latest_version = module_package
66
+ self.signal_versionsLoaded.emit("")
67
+ except Exception as e:
68
+ self.signal_versionsLoaded.emit(str(e))
69
+ reply.deleteLater()
70
+
71
+ def start_load_development_versions(self):
72
+ self.development_versions = []
73
+
74
+ # Create version for the main branch
75
+ mainVersion = ModulePackage(
76
+ module=self,
77
+ organisation=self.organisation,
78
+ repository=self.repository,
79
+ json_payload="",
80
+ type=ModulePackage.Type.BRANCH,
81
+ name="main",
82
+ branch="main",
83
+ )
84
+ self.development_versions.append(mainVersion)
85
+
86
+ url = QUrl(f"https://api.github.com/repos/{self.organisation}/{self.repository}/pulls")
87
+ request = QNetworkRequest(url)
88
+ headers = PluginUtils.get_github_headers()
89
+ for key, value in headers.items():
90
+ request.setRawHeader(QByteArray(key.encode()), QByteArray(value.encode()))
91
+ reply = self.network_manager.get(request)
92
+ reply.finished.connect(lambda: self._on_development_versions_reply(reply))
93
+
94
+ def _on_development_versions_reply(self, reply):
95
+ if reply.error() != QNetworkReply.NetworkError.NoError:
96
+ self.signal_developmentVersionsLoaded.emit(reply.errorString())
97
+ reply.deleteLater()
98
+ return
99
+
100
+ try:
101
+ data = reply.readAll().data()
102
+ json_versions = json.loads(data.decode())
103
+ for json_version in json_versions:
104
+ module_package = ModulePackage(
105
+ module=self,
106
+ organisation=self.organisation,
107
+ repository=self.repository,
108
+ json_payload=json_version,
109
+ type=ModulePackage.Type.PULL_REQUEST,
110
+ )
111
+ self.development_versions.append(module_package)
112
+ self.signal_developmentVersionsLoaded.emit("")
113
+ except Exception as e:
114
+ self.signal_developmentVersionsLoaded.emit(str(e))
115
+ reply.deleteLater()
@@ -0,0 +1,16 @@
1
+ from enum import Enum
2
+
3
+
4
+ class ModuleAsset:
5
+ class Type(Enum):
6
+ PLUGIN = "oqtopus.plugin"
7
+ PROJECT = "oqtopus.project"
8
+
9
+ def __init__(
10
+ self, name: str, label: str, download_url: str, size: int, type: "ModuleAsset.Type" = None
11
+ ):
12
+ self.name = name
13
+ self.label = label
14
+ self.download_url = download_url
15
+ self.size = size
16
+ self.type = type
@@ -0,0 +1,118 @@
1
+ import requests
2
+ from qgis.PyQt.QtCore import QDateTime, Qt
3
+
4
+ from ..utils.plugin_utils import PluginUtils
5
+ from .module_asset import ModuleAsset
6
+
7
+
8
+ class ModulePackage:
9
+
10
+ # enum for package type
11
+ class Type:
12
+ RELEASE = "release"
13
+ BRANCH = "branch"
14
+ PULL_REQUEST = "pull_request"
15
+ FROM_ZIP = "from_zip"
16
+
17
+ def __init__(
18
+ self,
19
+ module,
20
+ organisation,
21
+ repository,
22
+ json_payload: dict,
23
+ type=Type.RELEASE,
24
+ name=None,
25
+ branch=None,
26
+ ):
27
+ self.module = module
28
+ self.type = type
29
+ self.name = name
30
+ self.branch = branch
31
+ self.created_at = None
32
+ self.prerelease = False
33
+ self.html_url = None
34
+
35
+ self.asset_project = None
36
+ self.asset_plugin = None
37
+
38
+ if self.type == ModulePackage.Type.RELEASE:
39
+ self.__parse_release(json_payload)
40
+ elif self.type == ModulePackage.Type.BRANCH:
41
+ pass
42
+ elif self.type == ModulePackage.Type.PULL_REQUEST:
43
+ self.__parse_pull_request(json_payload)
44
+ elif self.type == ModulePackage.Type.FROM_ZIP:
45
+ return
46
+ else:
47
+ raise ValueError(f"Unknown type '{type}'")
48
+
49
+ type = "heads"
50
+ if self.type == ModulePackage.Type.RELEASE:
51
+ type = "tags"
52
+
53
+ self.download_url = (
54
+ f"https://github.com/{organisation}/{repository}/archive/refs/{type}/{self.branch}.zip"
55
+ )
56
+
57
+ self.zip_file = None
58
+ self.package_dir = None
59
+
60
+ def display_name(self):
61
+ if self.prerelease:
62
+ return f"{self.name} (prerelease)"
63
+
64
+ return self.name
65
+
66
+ def __parse_release(self, json_payload: dict):
67
+ if self.name is None:
68
+ self.name = json_payload["name"]
69
+
70
+ if self.name is None or self.name == "":
71
+ self.name = json_payload["tag_name"]
72
+
73
+ self.branch = self.name
74
+ self.created_at = QDateTime.fromString(json_payload["created_at"], Qt.DateFormat.ISODate)
75
+ self.prerelease = json_payload["prerelease"]
76
+ self.html_url = json_payload["html_url"]
77
+
78
+ self.__parse_release_assets(json_payload["assets_url"])
79
+
80
+ def __parse_release_assets(self, assets_url: str):
81
+
82
+ # Load assets
83
+ r = requests.get(assets_url, headers=PluginUtils.get_github_headers())
84
+
85
+ # Raise an exception in case of http errors
86
+ r.raise_for_status()
87
+
88
+ json_assets = r.json()
89
+ for json_asset in json_assets:
90
+ asset = ModuleAsset(
91
+ name=json_asset["name"],
92
+ label=json_asset["label"],
93
+ download_url=json_asset["browser_download_url"],
94
+ size=json_asset["size"],
95
+ type=None,
96
+ )
97
+
98
+ if asset.label == ModuleAsset.Type.PROJECT.value:
99
+ asset.type = ModuleAsset.Type.PROJECT
100
+ self.asset_project = asset
101
+ continue
102
+
103
+ if asset.label == ModuleAsset.Type.PLUGIN.value:
104
+ asset.type = ModuleAsset.Type.PLUGIN
105
+ self.asset_plugin = asset
106
+ continue
107
+
108
+ if self.asset_project and self.asset_plugin:
109
+ # We already have all assets we need
110
+ break
111
+
112
+ def __parse_pull_request(self, json_payload: dict):
113
+ if self.name is None:
114
+ self.name = f"#{json_payload['number']} {json_payload['title']}"
115
+ self.branch = json_payload["head"]["ref"]
116
+ self.created_at = QDateTime.fromString(json_payload["created_at"], Qt.DateFormat.ISODate)
117
+ self.prerelease = False
118
+ self.html_url = json_payload["html_url"]
@@ -0,0 +1,11 @@
1
+ from pydantic import BaseModel
2
+
3
+
4
+ class ModuleConfig(BaseModel):
5
+ name: str
6
+ organisation: str
7
+ repository: str
8
+
9
+
10
+ class ModulesConfig(BaseModel):
11
+ modules: list[ModuleConfig]
@@ -0,0 +1,148 @@
1
+ import os
2
+ import shutil
3
+ import zipfile
4
+
5
+ import requests
6
+ from qgis.PyQt.QtCore import QThread, pyqtSignal
7
+
8
+ from ..utils.plugin_utils import PluginUtils, logger
9
+
10
+
11
+ class PackagePrepareTaskCanceled(Exception):
12
+ pass
13
+
14
+
15
+ class PackagePrepareTask(QThread):
16
+ """
17
+ This class is responsible for preparing the package for the Oqtopus module management tool.
18
+ It inherits from QThread to run the preparation process in a separate thread.
19
+ """
20
+
21
+ signalPackagingProgress = pyqtSignal(float)
22
+
23
+ def __init__(self, parent=None):
24
+ super().__init__(parent)
25
+
26
+ self.module_package = None
27
+
28
+ self.__canceled = False
29
+ self.lastError = None
30
+
31
+ def startFromZip(self, zip_file: str):
32
+
33
+ self.module_package = None
34
+
35
+ self.__canceled = False
36
+ self.start()
37
+
38
+ def startFromModulePackage(self, module_package):
39
+ self.module_package = module_package
40
+
41
+ self.__canceled = False
42
+ self.start()
43
+
44
+ def cancel(self):
45
+ self.__canceled = True
46
+
47
+ def run(self):
48
+ """
49
+ The main method that runs when the thread starts.
50
+ """
51
+
52
+ try:
53
+ if self.module_package is None:
54
+ raise Exception(self.tr("No module version provided."))
55
+
56
+ self.__download_module_assets(self.module_package)
57
+ self.lastError = None
58
+
59
+ except Exception as e:
60
+ # Handle any exceptions that occur during processing
61
+ logger.critical(f"Package prepare task error: {e}")
62
+ self.lastError = e
63
+
64
+ def __download_module_assets(self, module_package):
65
+
66
+ # Download the source
67
+ zip_file = self.__download_module_asset(module_package.download_url, "source.zip")
68
+ module_package.zip_file = zip_file
69
+ package_dir = self.__extract_zip_file(zip_file)
70
+ module_package.package_dir = package_dir
71
+
72
+ # Download the release assets
73
+ self.__checkForCanceled()
74
+ if module_package.asset_project is not None:
75
+ zip_file = self.__download_module_asset(
76
+ module_package.asset_project.download_url,
77
+ module_package.asset_project.type.value + ".zip",
78
+ )
79
+ package_dir = self.__extract_zip_file(zip_file)
80
+ module_package.asset_project.package_dir = package_dir
81
+
82
+ self.__checkForCanceled()
83
+ if module_package.asset_plugin is not None:
84
+ zip_file = self.__download_module_asset(
85
+ module_package.asset_plugin.download_url,
86
+ module_package.asset_plugin.type.value + ".zip",
87
+ )
88
+ package_dir = self.__extract_zip_file(zip_file)
89
+ module_package.asset_plugin.package_dir = package_dir
90
+
91
+ def __download_module_asset(self, url: str, filename: str):
92
+
93
+ temp_dir = PluginUtils.plugin_temp_path()
94
+ destination_directory = os.path.join(temp_dir, "Downloads")
95
+ os.makedirs(destination_directory, exist_ok=True)
96
+
97
+ zip_file = os.path.join(destination_directory, filename)
98
+
99
+ # Streaming, so we can iterate over the response.
100
+ response = requests.get(url, allow_redirects=True, stream=True)
101
+
102
+ # Raise an exception in case of http errors
103
+ response.raise_for_status()
104
+
105
+ self.__checkForCanceled()
106
+
107
+ logger.info(f"Downloading from '{url}' to '{zip_file}'")
108
+ data_size = 0
109
+ with open(zip_file, "wb") as file:
110
+ next_emit_threshold = 10 * 1024 * 1024 # 10MB threshold
111
+ for data in response.iter_content(chunk_size=None):
112
+ file.write(data)
113
+
114
+ self.__checkForCanceled()
115
+
116
+ data_size += len(data)
117
+ if data_size >= next_emit_threshold: # Emit signal when threshold is exceeded
118
+ self.signalPackagingProgress.emit(data_size)
119
+ next_emit_threshold += 10 * 1024 * 1024 # Update to the next threshold
120
+
121
+ return zip_file
122
+
123
+ def __extract_zip_file(self, zip_file):
124
+ temp_dir = PluginUtils.plugin_temp_path()
125
+
126
+ # Unzip the file to plugin temp dir
127
+ try:
128
+ with zipfile.ZipFile(zip_file, "r") as zip_ref:
129
+ # Find the top-level directory
130
+ zip_dirname = zip_ref.namelist()[0].split("/")[0]
131
+ package_dir = os.path.join(temp_dir, zip_dirname)
132
+
133
+ if os.path.exists(package_dir):
134
+ shutil.rmtree(package_dir)
135
+
136
+ zip_ref.extractall(temp_dir)
137
+
138
+ except zipfile.BadZipFile:
139
+ raise Exception(self.tr(f"The selected file '{zip_file}' is not a valid zip archive."))
140
+
141
+ return package_dir
142
+
143
+ def __checkForCanceled(self):
144
+ """
145
+ Check if the task has been canceled.
146
+ """
147
+ if self.__canceled:
148
+ raise PackagePrepareTaskCanceled(self.tr("The task has been canceled."))
File without changes
@@ -0,0 +1,61 @@
1
+ # -----------------------------------------------------------
2
+ #
3
+ # Profile
4
+ # Copyright (C) 2012 Patrice Verchere
5
+ # -----------------------------------------------------------
6
+ #
7
+ # licensed under the terms of GNU GPL 2
8
+ #
9
+ # This program is free software; you can redistribute it and/or modify
10
+ # it under the terms of the GNU General Public License as published by
11
+ # the Free Software Foundation; either version 2 of the License, or
12
+ # (at your option) any later version.
13
+ #
14
+ # This program is distributed in the hope that it will be useful,
15
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
+ # GNU General Public License for more details.
18
+ #
19
+ # You should have received a copy of the GNU General Public License along
20
+ # with this program; if not, print to the Free Software Foundation, Inc.,
21
+ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22
+ #
23
+ # ---------------------------------------------------------------------
24
+
25
+
26
+ from qgis.PyQt.QtCore import QSettings, Qt
27
+ from qgis.PyQt.QtGui import QPixmap
28
+ from qgis.PyQt.QtWidgets import QDialog
29
+
30
+ from ..utils.plugin_utils import PluginUtils
31
+
32
+ DIALOG_UI = PluginUtils.get_ui_class("about_dialog.ui")
33
+
34
+
35
+ class AboutDialog(QDialog, DIALOG_UI):
36
+ def __init__(self, parent=None):
37
+ QDialog.__init__(self, parent)
38
+ self.setupUi(self)
39
+
40
+ metadata_file_path = PluginUtils.get_metadata_file_path()
41
+
42
+ ini_text = QSettings(metadata_file_path, QSettings.Format.IniFormat)
43
+ version = ini_text.value("version")
44
+ name = ini_text.value("name")
45
+ description = "".join(ini_text.value("description"))
46
+ about = " ".join(ini_text.value("about"))
47
+ qgisMinimumVersion = ini_text.value("qgisMinimumVersion")
48
+
49
+ self.setWindowTitle(f"{name} - {version}")
50
+ self.titleLabel.setText(self.windowTitle())
51
+ self.descriptionLabel.setText(description)
52
+ self.aboutLabel.setText(about)
53
+ self.qgisMinimumVersionLabel.setText(qgisMinimumVersion)
54
+
55
+ scaled_logo = QPixmap(PluginUtils.get_plugin_icon_path("oqtopus-logo.png")).scaled(
56
+ 254,
57
+ 254,
58
+ aspectRatioMode=Qt.AspectRatioMode.KeepAspectRatio,
59
+ transformMode=Qt.TransformationMode.SmoothTransformation,
60
+ )
61
+ self.iconLabel.setPixmap(scaled_logo)
@@ -0,0 +1,154 @@
1
+ import psycopg
2
+ from pgserviceparser import conf_path as pgserviceparser_conf_path
3
+ from pgserviceparser import service_config as pgserviceparser_service_config
4
+ from pgserviceparser import service_names as pgserviceparser_service_names
5
+ from qgis.PyQt.QtCore import pyqtSignal
6
+ from qgis.PyQt.QtGui import QAction
7
+ from qgis.PyQt.QtWidgets import QDialog, QMenu, QWidget
8
+
9
+ from ..utils.plugin_utils import PluginUtils, logger
10
+ from ..utils.qt_utils import CriticalMessageBox, QtUtils
11
+ from .database_create_dialog import DatabaseCreateDialog
12
+ from .database_duplicate_dialog import DatabaseDuplicateDialog
13
+
14
+ DIALOG_UI = PluginUtils.get_ui_class("database_connection_widget.ui")
15
+
16
+
17
+ class DatabaseConnectionWidget(QWidget, DIALOG_UI):
18
+
19
+ signal_connectionChanged = pyqtSignal()
20
+
21
+ def __init__(self, parent=None):
22
+ QWidget.__init__(self, parent)
23
+ self.setupUi(self)
24
+
25
+ self.db_database_label.setText(self.tr("No database"))
26
+ QtUtils.setForegroundColor(self.db_database_label, PluginUtils.COLOR_WARNING)
27
+ QtUtils.setFontItalic(self.db_database_label, True)
28
+
29
+ self.__loadDatabaseInformations()
30
+ self.db_services_comboBox.currentIndexChanged.connect(self.__serviceChanged)
31
+
32
+ db_operations_menu = QMenu(self.db_operations_toolButton)
33
+
34
+ actionCreateDb = QAction(self.tr("Create database"), db_operations_menu)
35
+ self.__actionDuplicateDb = QAction(self.tr("Duplicate database"), db_operations_menu)
36
+ actionReloadPgServices = QAction(self.tr("Reload PG Service config"), db_operations_menu)
37
+
38
+ actionCreateDb.triggered.connect(self.__createDatabaseClicked)
39
+ self.__actionDuplicateDb.triggered.connect(self.__duplicateDatabaseClicked)
40
+ actionReloadPgServices.triggered.connect(self.__loadDatabaseInformations)
41
+
42
+ db_operations_menu.addAction(actionCreateDb)
43
+ db_operations_menu.addAction(self.__actionDuplicateDb)
44
+ db_operations_menu.addAction(actionReloadPgServices)
45
+
46
+ self.db_operations_toolButton.setMenu(db_operations_menu)
47
+
48
+ self.__database_connection = None
49
+
50
+ try:
51
+ self.__serviceChanged()
52
+ except Exception:
53
+ # Silence errors during widget initialization
54
+ pass
55
+
56
+ def getConnection(self):
57
+ """
58
+ Returns the current database connection.
59
+ If no connection is established, returns None.
60
+ """
61
+ return self.__database_connection
62
+
63
+ def __loadDatabaseInformations(self):
64
+ pg_service_conf_path = pgserviceparser_conf_path()
65
+ self.db_servicesConfigFilePath_label.setText(
66
+ f"<a href='file://{pg_service_conf_path.resolve()}'>{pg_service_conf_path.as_posix()}</a>"
67
+ )
68
+
69
+ self.db_services_comboBox.clear()
70
+
71
+ try:
72
+ for service_name in pgserviceparser_service_names():
73
+ self.db_services_comboBox.addItem(service_name)
74
+ except Exception as exception:
75
+ CriticalMessageBox(
76
+ self.tr("Error"), self.tr("Can't load database services:"), exception, self
77
+ ).exec()
78
+ return
79
+
80
+ def __serviceChanged(self, index=None):
81
+ if self.db_services_comboBox.currentText() == "":
82
+ self.db_database_label.setText(self.tr("No database"))
83
+ QtUtils.setForegroundColor(self.db_database_label, PluginUtils.COLOR_WARNING)
84
+ QtUtils.setFontItalic(self.db_database_label, True)
85
+
86
+ self.__actionDuplicateDb.setDisabled(True)
87
+
88
+ self.__set_connection(None)
89
+ return
90
+
91
+ service_name = self.db_services_comboBox.currentText()
92
+ service_config = pgserviceparser_service_config(service_name)
93
+
94
+ service_database = service_config.get("dbname", None)
95
+
96
+ if service_database is None:
97
+ self.db_database_label.setText(self.tr("No database provided by the service"))
98
+ QtUtils.setForegroundColor(self.db_database_label, PluginUtils.COLOR_WARNING)
99
+ QtUtils.setFontItalic(self.db_database_label, True)
100
+
101
+ self.__actionDuplicateDb.setDisabled(True)
102
+ return
103
+
104
+ self.db_database_label.setText(service_database)
105
+ QtUtils.resetForegroundColor(self.db_database_label)
106
+ QtUtils.setFontItalic(self.db_database_label, False)
107
+
108
+ self.__actionDuplicateDb.setEnabled(True)
109
+
110
+ # Try connection
111
+ try:
112
+ database_connection = psycopg.connect(service=service_name)
113
+ self.__set_connection(database_connection)
114
+
115
+ except Exception as exception:
116
+ self.__set_connection(None)
117
+
118
+ self.db_moduleInfo_label.setText("Can't connect to service.")
119
+ QtUtils.setForegroundColor(self.db_moduleInfo_label, PluginUtils.COLOR_WARNING)
120
+ errorText = self.tr(f"Can't connect to service '{service_name}':\n{exception}.")
121
+ logger.error(errorText)
122
+ return
123
+
124
+ self.db_moduleInfo_label.setText("Connected.")
125
+ logger.info(f"Connected to service '{service_name}'.")
126
+ QtUtils.resetForegroundColor(self.db_moduleInfo_label)
127
+
128
+ def __createDatabaseClicked(self):
129
+ databaseCreateDialog = DatabaseCreateDialog(
130
+ selected_service=self.db_services_comboBox.currentText(), parent=self
131
+ )
132
+
133
+ if databaseCreateDialog.exec() == QDialog.DialogCode.Rejected:
134
+ return
135
+
136
+ self.__loadDatabaseInformations()
137
+
138
+ # Select the created service
139
+ created_service_name = databaseCreateDialog.created_service_name()
140
+ self.db_services_comboBox.setCurrentText(created_service_name)
141
+
142
+ def __duplicateDatabaseClicked(self):
143
+ databaseDuplicateDialog = DatabaseDuplicateDialog(
144
+ selected_service=self.db_services_comboBox.currentText(), parent=self
145
+ )
146
+ if databaseDuplicateDialog.exec() == QDialog.DialogCode.Rejected:
147
+ return
148
+
149
+ def __set_connection(self, connection):
150
+ """
151
+ Set the current database connection and emit the signal_connectionChanged signal.
152
+ """
153
+ self.__database_connection = connection
154
+ self.signal_connectionChanged.emit()