2828import zipfile
2929
3030from qgis .PyQt .QtCore import Qt , QObject , QDir , QUrl , QFileInfo , QFile
31- from qgis .PyQt .QtWidgets import QMessageBox , QLabel , QFrame , QApplication , QFileDialog
31+ from qgis .PyQt .QtWidgets import QApplication , QDialog , QDialogButtonBox , QFrame , QMessageBox , QLabel , QVBoxLayout
3232from qgis .PyQt .QtNetwork import QNetworkRequest
3333
3434import qgis
3535from qgis .core import Qgis , QgsApplication , QgsNetworkAccessManager , QgsSettings
36- from qgis .gui import QgsMessageBar
36+ from qgis .gui import QgsMessageBar , QgsPasswordLineEdit
3737from qgis .utils import (iface , startPlugin , unloadPlugin , loadPlugin ,
3838 reloadPlugin , updateAvailablePlugins )
3939from .installer_data import (repositories , plugins , officialRepo ,
@@ -539,9 +539,6 @@ def installFromZipFile(self, filePath):
539539 settings .setValue (settingsGroup + '/lastZipDirectory' ,
540540 QFileInfo (filePath ).absoluteDir ().absolutePath ())
541541
542- error = False
543- infoString = None
544-
545542 with zipfile .ZipFile (filePath , 'r' ) as zf :
546543 pluginName = os .path .split (zf .namelist ()[0 ])[0 ]
547544
@@ -551,24 +548,54 @@ def installFromZipFile(self, filePath):
551548 if not QDir (pluginsDirectory ).exists ():
552549 QDir ().mkpath (pluginsDirectory )
553550
551+ pluginDirectory = QDir .cleanPath (os .path .join (pluginsDirectory , pluginName ))
552+
554553 # If the target directory already exists as a link,
555554 # remove the link without resolving
556- QFile (os . path . join ( pluginsDirectory , pluginFileName ) ).remove ()
555+ QFile (pluginDirectory ).remove ()
557556
558- try :
559- # Test extraction. If fails, then exception will be raised
560- # and no removing occurs
561- unzip (str (filePath ), str (pluginsDirectory ))
562- # Removing old plugin files if exist
563- removeDir (QDir .cleanPath (os .path .join (pluginsDirectory , pluginFileName )))
564- # Extract new files
565- unzip (str (filePath ), str (pluginsDirectory ))
566- except :
567- error = True
568- infoString = (self .tr ("Plugin installation failed" ),
569- self .tr ("Failed to unzip the plugin package\n {}.\n Probably it is broken" .format (filePath )))
557+ password = None
558+ infoString = None
559+ success = False
560+ keepTrying = True
561+
562+ while keepTrying :
563+ try :
564+ # Test extraction. If fails, then exception will be raised and no removing occurs
565+ unzip (filePath , pluginsDirectory , password )
566+ # Removing old plugin files if exist
567+ removeDir (pluginDirectory )
568+ # Extract new files
569+ unzip (filePath , pluginsDirectory , password )
570+ keepTrying = False
571+ success = True
572+ except Exception as e :
573+ success = False
574+ if 'password' in str (e ):
575+ infoString = self .tr ('Aborted by user' )
576+ if 'Bad password' in str (e ):
577+ msg = self .tr ('Wrong password. Please enter a correct password to the zip file.' )
578+ else :
579+ msg = self .tr ('The zip file is encrypted. Please enter password.' )
580+ # Display a password dialog with QgsPasswordLineEdit
581+ dlg = QDialog ()
582+ dlg .setWindowTitle (self .tr ('Enter password' ))
583+ buttonBox = QDialogButtonBox (QDialogButtonBox .Ok | QDialogButtonBox .Cancel , Qt .Horizontal )
584+ buttonBox .rejected .connect (dlg .reject )
585+ buttonBox .accepted .connect (dlg .accept )
586+ lePass = QgsPasswordLineEdit ()
587+ layout = QVBoxLayout ()
588+ layout .addWidget (QLabel (msg ))
589+ layout .addWidget (lePass )
590+ layout .addWidget (buttonBox )
591+ dlg .setLayout (layout )
592+ keepTrying = dlg .exec_ ()
593+ password = lePass .text ()
594+ else :
595+ infoString = self .tr ("Failed to unzip the plugin package\n {}.\n Probably it is broken" .format (filePath ))
596+ keepTrying = False
570597
571- if infoString is None :
598+ if success :
572599 updateAvailablePlugins ()
573600 loadPlugin (pluginName )
574601 plugins .getAllInstalled ()
@@ -585,11 +612,10 @@ def installFromZipFile(self, filePath):
585612 else :
586613 if startPlugin (pluginName ):
587614 settings .setValue ('/PythonPlugins/' + pluginName , True )
588- infoString = (self .tr ("Plugin installed successfully" ), "" )
589615
590- if infoString [ 0 ]:
591- level = error and Qgis . Critical or Qgis . Info
592- msg = "<b>%s</b>" % infoString [ 0 ]
593- if infoString [ 1 ]:
594- msg += "<b>:</b> %s" % infoString [ 1 ]
595- iface .pluginManagerInterface ().pushMessage (msg , level )
616+ msg = "<b>%s</b>" % self . tr ( "Plugin installed successfully" )
617+ else :
618+ msg = "<b>%s: </b> %s " % ( self . tr ( "Plugin installation failed" ), infoString )
619+
620+ level = Qgis . Info if success else Qgis . Critical
621+ iface .pluginManagerInterface ().pushMessage (msg , level )
0 commit comments