2222#
2323# ---------------------------------------------------------------------
2424
25+ import logging
2526import os
27+ import shutil
2628
2729import psycopg
2830from qgis .PyQt .QtCore import Qt , QUrl
3436from ..libs .pum .config import PumConfig
3537from ..libs .pum .schema_migrations import SchemaMigrations
3638from ..libs .pum .upgrader import Upgrader
37- from ..utils .plugin_utils import PluginUtils
39+ from ..utils .plugin_utils import LoggingBridge , PluginUtils
3840from ..utils .qt_utils import OverrideCursor , QtUtils
3941from .database_create_dialog import DatabaseCreateDialog
4042from .database_duplicate_dialog import DatabaseDuplicateDialog
@@ -53,6 +55,11 @@ class MainDialog(QDialog, DIALOG_UI):
5355 def __init__ (self , modules_registry , parent = None ):
5456 QDialog .__init__ (self , parent )
5557 self .setupUi (self )
58+
59+ self .logger = logging .getLogger ()
60+ self .loggingBridge = LoggingBridge (self .__logged_line )
61+ self .logger .addHandler (self .loggingBridge )
62+
5663 self .buttonBox .rejected .connect (self .__closeDialog )
5764 self .buttonBox .helpRequested .connect (self .__helpRequested )
5865
@@ -61,8 +68,10 @@ def __init__(self, modules_registry, parent=None):
6168
6269 self .__database_connection = None
6370
64- self .__pum_config = None
71+ self .__package_dir = None
6572 self .__data_model_dir = None
73+ self .__pum_config = None
74+ self .__project_file = None
6675
6776 # Init GUI Modules
6877 self .__initGuiModules ()
@@ -73,12 +82,17 @@ def __init__(self, modules_registry, parent=None):
7382 # Init GUI Module Info
7483 self .__initGuiModuleInfo ()
7584
85+ # Init GUI Project
86+ self .__initGuiProject ()
87+
7688 self .__packagePrepareTask = PackagePrepareTask (self )
7789 self .__packagePrepareTask .finished .connect (self .__packagePrepareTaskFinished )
7890 self .__packagePrepareTask .signalPackagingProgress .connect (
7991 self .__packagePrepareTaskProgress
8092 )
8193
94+ self .logger .info ("Ready." )
95+
8296 def __initGuiModules (self ):
8397 self .module_module_comboBox .clear ()
8498 self .module_module_comboBox .addItem (self .tr ("Please select a module" ), None )
@@ -131,6 +145,17 @@ def __initGuiModuleInfo(self):
131145 self .moduleInfo_install_pushButton .clicked .connect (self .__installModuleClicked )
132146 self .moduleInfo_upgrade_pushButton .clicked .connect (self .__upgradeModuleClicked )
133147
148+ def __initGuiProject (self ):
149+ self .project_install_pushButton .clicked .connect (self .__projectInstallClicked )
150+ self .project_seeChangelog_pushButton .clicked .connect (self .__projectSeeChangelogClicked )
151+
152+ def __logged_line (self , line ):
153+ self .logs_plainTextEdit .appendPlainText (line )
154+
155+ # Automatically scroll to the bottom of the logs
156+ scroll_bar = self .logs_plainTextEdit .verticalScrollBar ()
157+ scroll_bar .setValue (scroll_bar .maximum ())
158+
134159 def __closeDialog (self ):
135160 if self .__packagePrepareTask .isRunning ():
136161 self .__packagePrepareTask .cancel ()
@@ -139,7 +164,9 @@ def __closeDialog(self):
139164 self .accept ()
140165
141166 def __helpRequested (self ):
142- QDesktopServices .openUrl (QUrl ("https://github.com/oqtopus/Oqtopus" ))
167+ help_page = "https://github.com/oqtopus/Oqtopus"
168+ self .logger .info (f"Opening help page { help_page } " )
169+ QDesktopServices .openUrl (QUrl (help_page ))
143170
144171 def __loadDatabaseInformations (self ):
145172 self .db_servicesConfigFilePath_label .setText (pgserviceparser .conf_path ().as_posix ())
@@ -211,8 +238,17 @@ def __moduleVersionChanged(self, index):
211238 if current_module_version is None :
212239 return
213240
214- self .__pum_config = None
241+ self .__package_dir = None
215242 self .__data_model_dir = None
243+ self .__pum_config = None
244+ self .__project_file = None
245+
246+ loading_text = self .tr (
247+ f"Loading package for module '{ self .module_module_comboBox .currentText ()} ' version '{ current_module_version .display_name ()} '..."
248+ )
249+ self .module_information_label .setText (loading_text )
250+ QtUtils .resetForegroundColor (self .module_information_label )
251+ self .logger .info (loading_text )
216252
217253 if self .__packagePrepareTask .isRunning ():
218254 self .__packagePrepareTask .cancel ()
@@ -263,8 +299,10 @@ def __moduleBrowseZipClicked(self):
263299
264300 def __loadModuleFromZip (self , filename ):
265301
266- self .__pum_config = None
302+ self .__package_dir = None
267303 self .__data_model_dir = None
304+ self .__pum_config = None
305+ self .__project_file = None
268306
269307 if self .__packagePrepareTask .isRunning ():
270308 self .__packagePrepareTask .cancel ()
@@ -273,16 +311,31 @@ def __loadModuleFromZip(self, filename):
273311 self .__packagePrepareTask .startFromZip (filename )
274312
275313 def __packagePrepareTaskFinished (self ):
314+ self .logger .info ("Load package task finished" )
276315
277316 if self .__packagePrepareTask .lastError is not None :
317+ error_text = f"Can't load module package:\n { self .__packagePrepareTask .lastError } "
318+ self .module_information_label .setText (error_text )
319+ QtUtils .setForegroundColor (self .module_information_label , self .COLOR_WARNING )
278320 QMessageBox .critical (
279321 self ,
280322 self .tr ("Error" ),
281- self .tr (f"Can't load module package: \n { self . __packagePrepareTask . lastError } " ),
323+ self .tr (error_text ),
282324 )
283325 return
284326
285- self .__data_model_dir = os .path .join (self .__packagePrepareTask .package_dir , "datamodel" )
327+ self .__package_dir = self .__packagePrepareTask .package_dir
328+ self .logger .info (f"Package loaded into '{ self .__package_dir } '" )
329+ self .module_information_label .setText (self .__package_dir )
330+ QtUtils .resetForegroundColor (self .module_information_label )
331+
332+ self .__packagePrepareGetPUMConfig ()
333+
334+ self .__packagePrepareGetProjectFilename ()
335+
336+ def __packagePrepareGetPUMConfig (self ):
337+
338+ self .__data_model_dir = os .path .join (self .__package_dir , "datamodel" )
286339 pumConfigFilename = os .path .join (self .__data_model_dir , ".pum.yaml" )
287340 if not os .path .exists (pumConfigFilename ):
288341 QMessageBox .critical (
@@ -324,8 +377,47 @@ def __packagePrepareTaskFinished(self):
324377 self .moduleInfo_stackedWidget_pageInstall
325378 )
326379
380+ def __packagePrepareGetProjectFilename (self ):
381+ # Search for QGIS project file in self.__package_dir
382+ project_file_dir = os .path .join (self .__package_dir , "project" )
383+
384+ # Check if the directory exists
385+ if not os .path .exists (project_file_dir ):
386+ self .project_info_label .setText (
387+ self .tr (f"Project directory '{ project_file_dir } ' does not exist." )
388+ )
389+ QtUtils .setForegroundColor (self .project_info_label , self .COLOR_WARNING )
390+ QtUtils .setFontItalic (self .db_database_label , True )
391+ return
392+
393+ self .__project_file = None
394+ for root , dirs , files in os .walk (project_file_dir ):
395+ for file in files :
396+ if file .endswith (".qgz" ) or file .endswith (".qgs" ):
397+ self .__project_file = os .path .join (root , file )
398+ break
399+
400+ if self .__project_file :
401+ break
402+
403+ if self .__project_file is None :
404+ self .project_info_label .setText (
405+ self .tr (f"No QGIS project file (.qgz or .qgs) found into { project_file_dir } ." ),
406+ )
407+ QtUtils .setForegroundColor (self .project_info_label , self .COLOR_WARNING )
408+ QtUtils .setFontItalic (self .db_database_label , True )
409+ return
410+
411+ self .project_info_label .setText (
412+ self .tr (self .__project_file ),
413+ )
414+ QtUtils .setForegroundColor (self .project_info_label , self .COLOR_GREEN )
415+ QtUtils .setFontItalic (self .db_database_label , False )
416+
327417 def __packagePrepareTaskProgress (self , progress ):
328- print (f"Progress: { progress } " )
418+ loading_text = self .tr ("Load package task running..." )
419+ self .logger .info (loading_text )
420+ self .module_information_label .setText (loading_text )
329421
330422 def __seeChangeLogClicked (self ):
331423 current_module_version = self .module_version_comboBox .currentData ()
@@ -354,7 +446,9 @@ def __seeChangeLogClicked(self):
354446 )
355447 return
356448
357- QDesktopServices .openUrl (QUrl (current_module_version .html_url ))
449+ changelog_url = current_module_version .html_url
450+ self .logger .info (f"Opening changelog URL: { changelog_url } " )
451+ QDesktopServices .openUrl (QUrl (changelog_url ))
358452
359453 def __serviceChanged (self , index = None ):
360454 if self .db_services_comboBox .currentText () == "" :
@@ -536,3 +630,92 @@ def __createAndGrantRolesClicked(self):
536630 return
537631
538632 raise NotImplementedError ("Create and grant roles is not implemented yet" )
633+
634+ def __projectInstallClicked (self ):
635+
636+ if self .__current_module is None :
637+ QMessageBox .warning (
638+ self ,
639+ self .tr ("Error" ),
640+ self .tr ("Please select a module and version first." ),
641+ )
642+ return
643+
644+ current_module_version = self .module_version_comboBox .currentData ()
645+ if current_module_version is None :
646+ QMessageBox .warning (
647+ self ,
648+ self .tr ("Error" ),
649+ self .tr ("Please select a module version first." ),
650+ )
651+ return
652+
653+ if self .__package_dir is None :
654+ QMessageBox .critical (
655+ self ,
656+ self .tr ("Error" ),
657+ self .tr ("No valid package directory available." ),
658+ )
659+ return
660+
661+ # Search for QGIS project file in self.__package_dir
662+ project_file_dir = os .path .join (self .__package_dir , "project" )
663+
664+ # Check if the directory exists
665+ if not os .path .exists (project_file_dir ):
666+ QMessageBox .critical (
667+ self ,
668+ self .tr ("Error" ),
669+ self .tr (f"Project directory '{ project_file_dir } ' does not exist." ),
670+ )
671+ return
672+
673+ self .__project_file = None
674+ for root , dirs , files in os .walk (project_file_dir ):
675+ print (f"Searching for QGIS project file in { root } : { files } " )
676+ for file in files :
677+ if file .endswith (".qgz" ) or file .endswith (".qgs" ):
678+ self .__project_file = os .path .join (root , file )
679+ break
680+
681+ if self .__project_file :
682+ break
683+
684+ if self .__project_file is None :
685+ QMessageBox .critical (
686+ self ,
687+ self .tr ("Error" ),
688+ self .tr (f"No QGIS project file (.qgz or .qgs) found into { project_file_dir } ." ),
689+ )
690+ return
691+
692+ install_destination = QFileDialog .getExistingDirectory (
693+ self ,
694+ self .tr ("Select installation directory" ),
695+ "" ,
696+ QFileDialog .ShowDirsOnly ,
697+ )
698+
699+ if not install_destination :
700+ return
701+
702+ # Copy the project file to the selected directory
703+ try :
704+ shutil .copy (self .__project_file , install_destination )
705+ QMessageBox .information (
706+ self ,
707+ self .tr ("Project installed" ),
708+ self .tr (
709+ f"Project file '{ self .__project_file } ' has been copied to '{ install_destination } '."
710+ ),
711+ )
712+ except Exception as e :
713+ QMessageBox .critical (
714+ self ,
715+ self .tr ("Error" ),
716+ self .tr (f"Failed to copy project file: { e } " ),
717+ )
718+ return
719+
720+ def __projectSeeChangelogClicked (self ):
721+ self .__seeChangeLogClicked ()
0 commit comments