|
1 | 1 | import os |
2 | 2 | import shutil |
3 | | -import tempfile |
4 | | -import zipfile |
5 | 3 |
|
6 | | -from qgis.PyQt.QtCore import QDir, QStandardPaths, QUrl |
| 4 | +from qgis.PyQt.QtCore import QUrl |
7 | 5 | from qgis.PyQt.QtGui import QDesktopServices |
8 | 6 | from qgis.PyQt.QtWidgets import QFileDialog, QMessageBox, QWidget |
9 | 7 |
|
@@ -84,141 +82,27 @@ def __installClicked(self): |
84 | 82 | QtUtils.setFontItalic(self.info_label, True) |
85 | 83 | return |
86 | 84 |
|
87 | | - # Determine QGIS user plugins directory (profile/python/plugins) |
88 | 85 | try: |
89 | | - from qgis.core import QgsApplication |
| 86 | + from pyplugin_installer import instance as plugin_installer_instance |
90 | 87 |
|
91 | | - qgis_settings_dir = QgsApplication.qgisSettingsDirPath() |
92 | | - except Exception: |
93 | | - qgis_settings_dir = None |
| 88 | + installer = plugin_installer_instance() |
| 89 | + installer.installFromZipFile(asset_plugin.package_zip) |
94 | 90 |
|
95 | | - if not qgis_settings_dir: |
96 | | - answer = QMessageBox.question( |
97 | | - self, |
98 | | - self.tr("Error"), |
99 | | - self.tr( |
100 | | - "Can't determine QGIS profile directory automatically. Please open the profile folder or cancel." |
101 | | - ), |
102 | | - QMessageBox.StandardButton.Open | QMessageBox.StandardButton.Cancel, |
103 | | - ) |
104 | | - if answer == QMessageBox.StandardButton.Cancel: |
105 | | - return |
106 | | - |
107 | | - # No qgis classes available: look into usual Qt settings folder |
108 | | - qgis_app_dir = QStandardPaths.locate( |
109 | | - QStandardPaths.StandardLocation.GenericDataLocation, |
110 | | - "QGIS/QGIS3/profiles", |
111 | | - QStandardPaths.LocateOption.LocateDirectory, |
112 | | - ) |
113 | | - |
114 | | - qgis_settings_dir = QFileDialog.getExistingDirectory( |
115 | | - self, |
116 | | - self.tr("Open QGIS Profile Folder"), |
117 | | - qgis_app_dir, |
118 | | - ) |
119 | | - if not qgis_settings_dir: |
120 | | - return |
121 | | - |
122 | | - plugins_dir = os.path.join(qgis_settings_dir, "python", "plugins") |
123 | | - |
124 | | - # Ensure plugins directory exists (create if necessary) |
125 | | - try: |
126 | | - os.makedirs(plugins_dir, exist_ok=True) |
127 | | - except Exception as e: |
128 | | - QMessageBox.critical( |
129 | | - self, |
130 | | - self.tr("Error"), |
131 | | - self.tr(f"Can't create plugins directory '{plugins_dir}': {e}"), |
132 | | - ) |
133 | 91 | return |
134 | 92 |
|
135 | | - # Extract zip to a temporary directory and move to plugins folder |
136 | | - try: |
137 | | - with tempfile.TemporaryDirectory() as tmpdir: |
138 | | - with zipfile.ZipFile(asset_plugin.package_zip, "r") as zf: |
139 | | - zf.extractall(tmpdir) |
140 | | - |
141 | | - # Inspect top-level entries |
142 | | - qdir = QDir(tmpdir) |
143 | | - entries_info = qdir.entryInfoList(QDir.Filter.NoDotAndDotDot | QDir.Filter.Dirs) |
144 | | - # Require exactly one top-level directory (well-formed plugin zip) |
145 | | - if len(entries_info) != 1: |
146 | | - QMessageBox.critical( |
147 | | - self, |
148 | | - self.tr("Invalid plugin package"), |
149 | | - self.tr( |
150 | | - "The plugin zip must contain exactly one top-level directory. " |
151 | | - "Please provide a properly packaged plugin." |
152 | | - ), |
153 | | - ) |
154 | | - return |
155 | | - |
156 | | - dest_name = entries_info[0].fileName() |
157 | | - src_path = os.path.join(tmpdir, dest_name) |
158 | | - dest_path = os.path.join(plugins_dir, dest_name) |
159 | | - |
160 | | - # If destination exists, ask user whether to overwrite |
161 | | - if os.path.exists(dest_path): |
162 | | - res = QMessageBox.question( |
163 | | - self, |
164 | | - self.tr("Overwrite plugin"), |
165 | | - self.tr( |
166 | | - f"The plugin '{dest_name}' already exists in the QGIS plugins folder. Overwrite?" |
167 | | - ), |
168 | | - QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, |
169 | | - ) |
170 | | - if res != QMessageBox.StandardButton.Yes: |
171 | | - return |
172 | | - # Remove existing plugin directory |
173 | | - try: |
174 | | - if os.path.islink(dest_path) or os.path.isfile(dest_path): |
175 | | - os.remove(dest_path) |
176 | | - else: |
177 | | - shutil.rmtree(dest_path) |
178 | | - except Exception as e: |
179 | | - QMessageBox.critical( |
180 | | - self, |
181 | | - self.tr("Error"), |
182 | | - self.tr(f"Failed to remove existing plugin '{dest_path}': {e}"), |
183 | | - ) |
184 | | - return |
185 | | - |
186 | | - # Move the extracted plugin into plugins directory |
187 | | - try: |
188 | | - shutil.move(src_path, dest_path) |
189 | | - except Exception: |
190 | | - # If move fails (cross-device), fallback to copytree |
191 | | - try: |
192 | | - shutil.copytree(src_path, dest_path) |
193 | | - except Exception as e2: |
194 | | - QMessageBox.critical( |
195 | | - self, |
196 | | - self.tr("Error"), |
197 | | - self.tr(f"Failed to install plugin to '{dest_path}': {e2}"), |
198 | | - ) |
199 | | - return |
200 | | - |
201 | | - QMessageBox.information( |
202 | | - self, |
203 | | - self.tr("Plugin installed"), |
204 | | - self.tr( |
205 | | - f"Plugin '{dest_name}' installed to QGIS profile plugins folder:\n{dest_path}\n\nYou may need to restart QGIS or enable the plugin from the Plugin Manager." |
206 | | - ), |
207 | | - ) |
208 | | - |
209 | | - except zipfile.BadZipFile: |
210 | | - QMessageBox.critical( |
| 93 | + except ImportError: |
| 94 | + QMessageBox.warning( |
211 | 95 | self, |
212 | 96 | self.tr("Error"), |
213 | | - self.tr("The plugin package is not a valid zip archive."), |
| 97 | + self.tr("Plugin installation is not possible when oQtopus is running standalone."), |
214 | 98 | ) |
215 | 99 | return |
| 100 | + |
216 | 101 | except Exception as e: |
217 | | - logger.exception("Unexpected error during plugin installation") |
218 | | - QMessageBox.critical( |
| 102 | + QMessageBox.warning( |
219 | 103 | self, |
220 | 104 | self.tr("Error"), |
221 | | - self.tr(f"Failed to install plugin: {e}"), |
| 105 | + self.tr("Plugin installation failed with an exception: {0}").format(str(e)), |
222 | 106 | ) |
223 | 107 | return |
224 | 108 |
|
|
0 commit comments