PluginManager/PluginRepositoryDialog.py

branch
Py2 comp.
changeset 3484
645c12de6b0c
parent 3178
f25fc1364c88
parent 3345
071afe8be2a1
child 3656
441956d8fce5
equal deleted inserted replaced
3456:96232974dcdb 3484:645c12de6b0c
11 from __future__ import unicode_literals 11 from __future__ import unicode_literals
12 12
13 import sys 13 import sys
14 import os 14 import os
15 import zipfile 15 import zipfile
16 import glob
16 17
17 from PyQt4.QtCore import pyqtSignal, pyqtSlot, Qt, QFile, QIODevice, QUrl, \ 18 from PyQt4.QtCore import pyqtSignal, pyqtSlot, Qt, QFile, QIODevice, QUrl, \
18 QProcess 19 QProcess, QPoint
19 from PyQt4.QtGui import QWidget, QDialogButtonBox, QAbstractButton, \ 20 from PyQt4.QtGui import QWidget, QDialogButtonBox, QAbstractButton, \
20 QTreeWidgetItem, QDialog, QVBoxLayout 21 QTreeWidgetItem, QDialog, QVBoxLayout, QMenu
21 from PyQt4.QtNetwork import QNetworkAccessManager, QNetworkRequest, \ 22 from PyQt4.QtNetwork import QNetworkAccessManager, QNetworkRequest, \
22 QNetworkReply 23 QNetworkReply
23 24
24 from .Ui_PluginRepositoryDialog import Ui_PluginRepositoryDialog 25 from .Ui_PluginRepositoryDialog import Ui_PluginRepositoryDialog
25 26
39 40
40 import UI.PixmapCache 41 import UI.PixmapCache
41 42
42 from eric5config import getConfig 43 from eric5config import getConfig
43 44
44 descrRole = Qt.UserRole
45 urlRole = Qt.UserRole + 1
46 filenameRole = Qt.UserRole + 2
47 authorRole = Qt.UserRole + 3
48
49 45
50 class PluginRepositoryWidget(QWidget, Ui_PluginRepositoryDialog): 46 class PluginRepositoryWidget(QWidget, Ui_PluginRepositoryDialog):
51 """ 47 """
52 Class implementing a dialog showing the available plugins. 48 Class implementing a dialog showing the available plugins.
53 49
54 @signal closeAndInstall() emitted when the Close & Install button is 50 @signal closeAndInstall() emitted when the Close & Install button is
55 pressed 51 pressed
56 """ 52 """
57 closeAndInstall = pyqtSignal() 53 closeAndInstall = pyqtSignal()
58 54
55 DescrRole = Qt.UserRole
56 UrlRole = Qt.UserRole + 1
57 FilenameRole = Qt.UserRole + 2
58 AuthorRole = Qt.UserRole + 3
59
60 PluginStatusUpToDate = 0
61 PluginStatusNew = 1
62 PluginStatusLocalUpdate = 2
63 PluginStatusRemoteUpdate = 3
64
59 def __init__(self, parent=None, external=False): 65 def __init__(self, parent=None, external=False):
60 """ 66 """
61 Constructor 67 Constructor
62 68
63 @param parent parent of this dialog (QWidget) 69 @param parent parent of this dialog (QWidget)
66 """ 72 """
67 super(PluginRepositoryWidget, self).__init__(parent) 73 super(PluginRepositoryWidget, self).__init__(parent)
68 self.setupUi(self) 74 self.setupUi(self)
69 75
70 self.__updateButton = self.buttonBox.addButton( 76 self.__updateButton = self.buttonBox.addButton(
71 self.trUtf8("Update"), QDialogButtonBox.ActionRole) 77 self.tr("Update"), QDialogButtonBox.ActionRole)
72 self.__downloadButton = self.buttonBox.addButton( 78 self.__downloadButton = self.buttonBox.addButton(
73 self.trUtf8("Download"), QDialogButtonBox.ActionRole) 79 self.tr("Download"), QDialogButtonBox.ActionRole)
74 self.__downloadButton.setEnabled(False) 80 self.__downloadButton.setEnabled(False)
75 self.__downloadInstallButton = self.buttonBox.addButton( 81 self.__downloadInstallButton = self.buttonBox.addButton(
76 self.trUtf8("Download && Install"), 82 self.tr("Download && Install"),
77 QDialogButtonBox.ActionRole) 83 QDialogButtonBox.ActionRole)
78 self.__downloadInstallButton.setEnabled(False) 84 self.__downloadInstallButton.setEnabled(False)
79 self.__downloadCancelButton = self.buttonBox.addButton( 85 self.__downloadCancelButton = self.buttonBox.addButton(
80 self.trUtf8("Cancel"), QDialogButtonBox.ActionRole) 86 self.tr("Cancel"), QDialogButtonBox.ActionRole)
81 self.__installButton = \ 87 self.__installButton = \
82 self.buttonBox.addButton(self.trUtf8("Close && Install"), 88 self.buttonBox.addButton(self.tr("Close && Install"),
83 QDialogButtonBox.ActionRole) 89 QDialogButtonBox.ActionRole)
84 self.__downloadCancelButton.setEnabled(False) 90 self.__downloadCancelButton.setEnabled(False)
85 self.__installButton.setEnabled(False) 91 self.__installButton.setEnabled(False)
86 92
87 self.repositoryUrlEdit.setText( 93 self.repositoryUrlEdit.setText(
88 Preferences.getUI("PluginRepositoryUrl5")) 94 Preferences.getUI("PluginRepositoryUrl5"))
89 95
90 self.repositoryList.headerItem().setText( 96 self.repositoryList.headerItem().setText(
91 self.repositoryList.columnCount(), "") 97 self.repositoryList.columnCount(), "")
92 self.repositoryList.header().setSortIndicator(0, Qt.AscendingOrder) 98 self.repositoryList.header().setSortIndicator(0, Qt.AscendingOrder)
99
100 self.__pluginContextMenu = QMenu(self)
101 self.__hideAct = self.__pluginContextMenu.addAction(
102 self.tr("Hide"), self.__hidePlugin)
103 self.__hideSelectedAct = self.__pluginContextMenu.addAction(
104 self.tr("Hide Selected"), self.__hideSelectedPlugins)
105 self.__pluginContextMenu.addSeparator()
106 self.__showAllAct = self.__pluginContextMenu.addAction(
107 self.tr("Show All"), self.__showAllPlugins)
108 self.__pluginContextMenu.addSeparator()
109 self.__pluginContextMenu.addAction(
110 self.tr("Cleanup Downloads"), self.__cleanupDownloads)
93 111
94 self.pluginRepositoryFile = \ 112 self.pluginRepositoryFile = \
95 os.path.join(Utilities.getConfigDir(), "PluginRepository") 113 os.path.join(Utilities.getConfigDir(), "PluginRepository")
96 114
97 self.__external = external 115 self.__external = external
109 self.__inDownload = False 127 self.__inDownload = False
110 self.__pluginsToDownload = [] 128 self.__pluginsToDownload = []
111 self.__pluginsDownloaded = [] 129 self.__pluginsDownloaded = []
112 self.__isDownloadInstall = False 130 self.__isDownloadInstall = False
113 self.__allDownloadedOk = False 131 self.__allDownloadedOk = False
132
133 self.__hiddenPlugins = Preferences.getPluginManager("HiddenPlugins")
114 134
115 self.__populateList() 135 self.__populateList()
116 136
117 @pyqtSlot(QAbstractButton) 137 @pyqtSlot(QAbstractButton)
118 def on_buttonBox_clicked(self, button): 138 def on_buttonBox_clicked(self, button):
131 self.__allDownloadedOk = True 151 self.__allDownloadedOk = True
132 self.__downloadPlugins() 152 self.__downloadPlugins()
133 elif button == self.__downloadCancelButton: 153 elif button == self.__downloadCancelButton:
134 self.__downloadCancel() 154 self.__downloadCancel()
135 elif button == self.__installButton: 155 elif button == self.__installButton:
136 self.closeAndInstall.emit() 156 self.__closeAndInstall()
137 157
138 def __formatDescription(self, lines): 158 def __formatDescription(self, lines):
139 """ 159 """
140 Private method to format the description. 160 Private method to format the description.
141 161
157 index += 1 177 index += 1
158 178
159 # join lines by a blank 179 # join lines by a blank
160 return ' '.join(newlines) 180 return ' '.join(newlines)
161 181
182 @pyqtSlot(QPoint)
183 def on_repositoryList_customContextMenuRequested(self, pos):
184 """
185 Private slot to show the context menu.
186
187 @param pos position to show the menu (QPoint)
188 """
189 self.__hideAct.setEnabled(
190 self.repositoryList.currentItem() is not None and
191 len(self.__selectedItems()) == 1)
192 self.__hideSelectedAct.setEnabled(
193 len(self.__selectedItems()) > 1)
194 self.__showAllAct.setEnabled(bool(self.__hasHiddenPlugins()))
195 self.__pluginContextMenu.popup(self.repositoryList.mapToGlobal(pos))
196
162 @pyqtSlot(QTreeWidgetItem, QTreeWidgetItem) 197 @pyqtSlot(QTreeWidgetItem, QTreeWidgetItem)
163 def on_repositoryList_currentItemChanged(self, current, previous): 198 def on_repositoryList_currentItemChanged(self, current, previous):
164 """ 199 """
165 Private slot to handle the change of the current item. 200 Private slot to handle the change of the current item.
166 201
168 @param previous reference to the old current item (QTreeWidgetItem) 203 @param previous reference to the old current item (QTreeWidgetItem)
169 """ 204 """
170 if self.__repositoryMissing or current is None: 205 if self.__repositoryMissing or current is None:
171 return 206 return
172 207
173 self.urlEdit.setText(current.data(0, urlRole) or "") 208 self.urlEdit.setText(
209 current.data(0, PluginRepositoryWidget.UrlRole) or "")
174 self.descriptionEdit.setPlainText( 210 self.descriptionEdit.setPlainText(
175 current.data(0, descrRole) and 211 current.data(0, PluginRepositoryWidget.DescrRole) and
176 self.__formatDescription(current.data(0, descrRole)) or "") 212 self.__formatDescription(
177 self.authorEdit.setText(current.data(0, authorRole) or "") 213 current.data(0, PluginRepositoryWidget.DescrRole)) or "")
214 self.authorEdit.setText(
215 current.data(0, PluginRepositoryWidget.AuthorRole) or "")
178 216
179 def __selectedItems(self): 217 def __selectedItems(self):
180 """ 218 """
181 Private method to get all selected items without the toplevel ones. 219 Private method to get all selected items without the toplevel ones.
182 220
194 """ 232 """
195 Private slot to handle a change of the selection. 233 Private slot to handle a change of the selection.
196 """ 234 """
197 self.__downloadButton.setEnabled(len(self.__selectedItems())) 235 self.__downloadButton.setEnabled(len(self.__selectedItems()))
198 self.__downloadInstallButton.setEnabled(len(self.__selectedItems())) 236 self.__downloadInstallButton.setEnabled(len(self.__selectedItems()))
237 self.__installButton.setEnabled(len(self.__selectedItems()))
199 238
200 def __updateList(self): 239 def __updateList(self):
201 """ 240 """
202 Private slot to download a new list and display the contents. 241 Private slot to download a new list and display the contents.
203 """ 242 """
251 self.__downloadInstallButton.setEnabled(False) 290 self.__downloadInstallButton.setEnabled(False)
252 self.__installButton.setEnabled(False) 291 self.__installButton.setEnabled(False)
253 for itm in self.repositoryList.selectedItems(): 292 for itm in self.repositoryList.selectedItems():
254 if itm not in [self.__stableItem, self.__unstableItem, 293 if itm not in [self.__stableItem, self.__unstableItem,
255 self.__unknownItem]: 294 self.__unknownItem]:
256 url = itm.data(0, urlRole) 295 url = itm.data(0, PluginRepositoryWidget.UrlRole)
257 filename = os.path.join( 296 filename = os.path.join(
258 Preferences.getPluginManager("DownloadPath"), 297 Preferences.getPluginManager("DownloadPath"),
259 itm.data(0, filenameRole)) 298 itm.data(0, PluginRepositoryWidget.FilenameRole))
260 self.__pluginsToDownload.append((url, filename)) 299 self.__pluginsToDownload.append((url, filename))
261 self.__downloadPlugin() 300 self.__downloadPlugin()
262 301
263 def __downloadPluginsDone(self): 302 def __downloadPluginsDone(self):
264 """ 303 """
273 else: 312 else:
274 ui = None 313 ui = None
275 if ui and ui.notificationsEnabled(): 314 if ui and ui.notificationsEnabled():
276 ui.showNotification( 315 ui.showNotification(
277 UI.PixmapCache.getPixmap("plugin48.png"), 316 UI.PixmapCache.getPixmap("plugin48.png"),
278 self.trUtf8("Download Plugin Files"), 317 self.tr("Download Plugin Files"),
279 self.trUtf8("""The requested plugins were downloaded.""")) 318 self.tr("""The requested plugins were downloaded."""))
280 319
281 if self.__isDownloadInstall: 320 if self.__isDownloadInstall:
282 self.closeAndInstall.emit() 321 self.closeAndInstall.emit()
283 else: 322 else:
284 if ui is None or not ui.notificationsEnabled(): 323 if ui is None or not ui.notificationsEnabled():
285 E5MessageBox.information( 324 E5MessageBox.information(
286 self, 325 self,
287 self.trUtf8("Download Plugin Files"), 326 self.tr("Download Plugin Files"),
288 self.trUtf8("""The requested plugins were downloaded.""")) 327 self.tr("""The requested plugins were downloaded."""))
289 self.downloadProgress.setValue(0) 328 self.downloadProgress.setValue(0)
290 329
291 # repopulate the list to update the refresh icons 330 # repopulate the list to update the refresh icons
292 self.__populateList() 331 self.__populateList()
293 332
325 url = Preferences.getUI("PluginRepositoryUrl5") 364 url = Preferences.getUI("PluginRepositoryUrl5")
326 if url != self.repositoryUrlEdit.text(): 365 if url != self.repositoryUrlEdit.text():
327 self.repositoryUrlEdit.setText(url) 366 self.repositoryUrlEdit.setText(url)
328 E5MessageBox.warning( 367 E5MessageBox.warning(
329 self, 368 self,
330 self.trUtf8("Plugins Repository URL Changed"), 369 self.tr("Plugins Repository URL Changed"),
331 self.trUtf8( 370 self.tr(
332 """The URL of the Plugins Repository has""" 371 """The URL of the Plugins Repository has"""
333 """ changed. Select the "Update" button to get""" 372 """ changed. Select the "Update" button to get"""
334 """ the new repository file.""")) 373 """ the new repository file."""))
335 else: 374 else:
336 E5MessageBox.critical( 375 E5MessageBox.critical(
337 self, 376 self,
338 self.trUtf8("Read plugins repository file"), 377 self.tr("Read plugins repository file"),
339 self.trUtf8("<p>The plugins repository file <b>{0}</b> " 378 self.tr("<p>The plugins repository file <b>{0}</b> "
340 "could not be read. Select Update</p>") 379 "could not be read. Select Update</p>")
341 .format(self.pluginRepositoryFile)) 380 .format(self.pluginRepositoryFile))
342 else: 381 else:
343 self.__repositoryMissing = True 382 self.__repositoryMissing = True
344 QTreeWidgetItem( 383 QTreeWidgetItem(
345 self.repositoryList, 384 self.repositoryList,
346 ["", self.trUtf8( 385 ["", self.tr(
347 "No plugin repository file available.\nSelect Update.") 386 "No plugin repository file available.\nSelect Update.")
348 ]) 387 ])
349 self.repositoryList.resizeColumnToContents(1) 388 self.repositoryList.resizeColumnToContents(1)
350 389
351 def __downloadFile(self, url, filename, doneMethod=None): 390 def __downloadFile(self, url, filename, doneMethod=None):
371 410
372 request = QNetworkRequest(QUrl(url)) 411 request = QNetworkRequest(QUrl(url))
373 request.setAttribute(QNetworkRequest.CacheLoadControlAttribute, 412 request.setAttribute(QNetworkRequest.CacheLoadControlAttribute,
374 QNetworkRequest.AlwaysNetwork) 413 QNetworkRequest.AlwaysNetwork)
375 reply = self.__networkManager.get(request) 414 reply = self.__networkManager.get(request)
376 reply.finished[()].connect(self.__downloadFileDone) 415 reply.finished.connect(self.__downloadFileDone)
377 reply.downloadProgress.connect(self.__downloadProgress) 416 reply.downloadProgress.connect(self.__downloadProgress)
378 self.__replies.append(reply) 417 self.__replies.append(reply)
379 418
380 def __downloadFileDone(self): 419 def __downloadFileDone(self):
381 """ 420 """
393 if reply.error() != QNetworkReply.NoError: 432 if reply.error() != QNetworkReply.NoError:
394 ok = False 433 ok = False
395 if not self.__downloadCancelled: 434 if not self.__downloadCancelled:
396 E5MessageBox.warning( 435 E5MessageBox.warning(
397 self, 436 self,
398 self.trUtf8("Error downloading file"), 437 self.tr("Error downloading file"),
399 self.trUtf8( 438 self.tr(
400 """<p>Could not download the requested file""" 439 """<p>Could not download the requested file"""
401 """ from {0}.</p><p>Error: {1}</p>""" 440 """ from {0}.</p><p>Error: {1}</p>"""
402 ).format(self.__downloadURL, reply.errorString()) 441 ).format(self.__downloadURL, reply.errorString())
403 ) 442 )
404 self.downloadProgress.setValue(0) 443 self.downloadProgress.setValue(0)
461 @param author data for the author field (string) 500 @param author data for the author field (string)
462 @param version data for the version field (string) 501 @param version data for the version field (string)
463 @param filename data for the filename field (string) 502 @param filename data for the filename field (string)
464 @param status status of the plugin (string [stable, unstable, unknown]) 503 @param status status of the plugin (string [stable, unstable, unknown])
465 """ 504 """
505 pluginName = filename.rsplit("-", 1)[0]
506 if pluginName in self.__hiddenPlugins:
507 return
508
466 if status == "stable": 509 if status == "stable":
467 if self.__stableItem is None: 510 if self.__stableItem is None:
468 self.__stableItem = \ 511 self.__stableItem = \
469 QTreeWidgetItem(self.repositoryList, 512 QTreeWidgetItem(self.repositoryList,
470 [self.trUtf8("Stable")]) 513 [self.tr("Stable")])
471 self.__stableItem.setExpanded(True) 514 self.__stableItem.setExpanded(True)
472 parent = self.__stableItem 515 parent = self.__stableItem
473 elif status == "unstable": 516 elif status == "unstable":
474 if self.__unstableItem is None: 517 if self.__unstableItem is None:
475 self.__unstableItem = \ 518 self.__unstableItem = \
476 QTreeWidgetItem(self.repositoryList, 519 QTreeWidgetItem(self.repositoryList,
477 [self.trUtf8("Unstable")]) 520 [self.tr("Unstable")])
478 self.__unstableItem.setExpanded(True) 521 self.__unstableItem.setExpanded(True)
479 parent = self.__unstableItem 522 parent = self.__unstableItem
480 else: 523 else:
481 if self.__unknownItem is None: 524 if self.__unknownItem is None:
482 self.__unknownItem = \ 525 self.__unknownItem = \
483 QTreeWidgetItem(self.repositoryList, 526 QTreeWidgetItem(self.repositoryList,
484 [self.trUtf8("Unknown")]) 527 [self.tr("Unknown")])
485 self.__unknownItem.setExpanded(True) 528 self.__unknownItem.setExpanded(True)
486 parent = self.__unknownItem 529 parent = self.__unknownItem
487 itm = QTreeWidgetItem(parent, [name, version, short]) 530 itm = QTreeWidgetItem(parent, [name, version, short])
488 531
489 itm.setData(0, urlRole, url) 532 itm.setData(0, PluginRepositoryWidget.UrlRole, url)
490 itm.setData(0, filenameRole, filename) 533 itm.setData(0, PluginRepositoryWidget.FilenameRole, filename)
491 itm.setData(0, authorRole, author) 534 itm.setData(0, PluginRepositoryWidget.AuthorRole, author)
492 itm.setData(0, descrRole, description) 535 itm.setData(0, PluginRepositoryWidget.DescrRole, description)
493 536
494 if self.__isUpToDate(filename, version): 537 updateStatus = self.__updateStatus(filename, version)
538 if updateStatus == PluginRepositoryWidget.PluginStatusUpToDate:
495 itm.setIcon(1, UI.PixmapCache.getIcon("empty.png")) 539 itm.setIcon(1, UI.PixmapCache.getIcon("empty.png"))
496 else: 540 itm.setToolTip(1, self.tr("up-to-date"))
541 elif updateStatus == PluginRepositoryWidget.PluginStatusNew:
497 itm.setIcon(1, UI.PixmapCache.getIcon("download.png")) 542 itm.setIcon(1, UI.PixmapCache.getIcon("download.png"))
498 543 itm.setToolTip(1, self.tr("new download available"))
499 def __isUpToDate(self, filename, version): 544 elif updateStatus == PluginRepositoryWidget.PluginStatusLocalUpdate:
500 """ 545 itm.setIcon(1, UI.PixmapCache.getIcon("updateLocal.png"))
501 Private method to check, if the given archive is up-to-date. 546 itm.setToolTip(1, self.tr("update installable"))
547 elif updateStatus == PluginRepositoryWidget.PluginStatusRemoteUpdate:
548 itm.setIcon(1, UI.PixmapCache.getIcon("updateRemote.png"))
549 itm.setToolTip(1, self.tr("updated download available"))
550
551 def __updateStatus(self, filename, version):
552 """
553 Private method to check, if the given archive update status.
502 554
503 @param filename data for the filename field (string) 555 @param filename data for the filename field (string)
504 @param version data for the version field (string) 556 @param version data for the version field (string)
505 @return flag indicating up-to-date (boolean) 557 @return plug-in update status (integer, one of PluginStatusNew,
558 PluginStatusUpToDate, PluginStatusLocalUpdate,
559 PluginStatusRemoteUpdate)
506 """ 560 """
507 archive = os.path.join(Preferences.getPluginManager("DownloadPath"), 561 archive = os.path.join(Preferences.getPluginManager("DownloadPath"),
508 filename) 562 filename)
509 563
564 # check, if it is an update (i.e. we already have archives
565 # with the same pattern)
566 archivesPattern = archive.rsplit('-', 1)[0] + "-*.zip"
567 if len(glob.glob(archivesPattern)) == 0:
568 return PluginRepositoryWidget.PluginStatusNew
569
510 # check, if the archive exists 570 # check, if the archive exists
511 if not os.path.exists(archive): 571 if not os.path.exists(archive):
512 return False 572 return PluginRepositoryWidget.PluginStatusRemoteUpdate
513 573
514 # check, if the archive is a valid zip file 574 # check, if the archive is a valid zip file
515 if not zipfile.is_zipfile(archive): 575 if not zipfile.is_zipfile(archive):
516 return False 576 return PluginRepositoryWidget.PluginStatusRemoteUpdate
517 577
518 zip = zipfile.ZipFile(archive, "r") 578 zip = zipfile.ZipFile(archive, "r")
519 try: 579 try:
520 aversion = zip.read("VERSION").decode("utf-8") 580 aversion = zip.read("VERSION").decode("utf-8")
521 except KeyError: 581 except KeyError:
522 aversion = "" 582 aversion = ""
523 zip.close() 583 zip.close()
524 584
525 return aversion == version 585 if aversion == version:
586 if not self.__external:
587 # Check against installed/loaded plug-ins
588 pluginManager = e5App().getObject("PluginManager")
589 pluginName = filename.rsplit('-', 1)[0]
590 pluginDetails = pluginManager.getPluginDetails(pluginName)
591 if pluginDetails is None or pluginDetails["version"] < version:
592 return PluginRepositoryWidget.PluginStatusLocalUpdate
593
594 return PluginRepositoryWidget.PluginStatusUpToDate
595 else:
596 return PluginRepositoryWidget.PluginStatusRemoteUpdate
526 597
527 def __sslErrors(self, reply, errors): 598 def __sslErrors(self, reply, errors):
528 """ 599 """
529 Private slot to handle SSL errors. 600 Private slot to handle SSL errors.
530 601
550 edit. 621 edit.
551 622
552 @param checked state of the push button (boolean) 623 @param checked state of the push button (boolean)
553 """ 624 """
554 self.repositoryUrlEdit.setReadOnly(not checked) 625 self.repositoryUrlEdit.setReadOnly(not checked)
626
627 def __closeAndInstall(self):
628 """
629 Private method to close the dialog and invoke the install dialog.
630 """
631 if not self.__pluginsDownloaded and self.__selectedItems():
632 for itm in self.__selectedItems():
633 filename = os.path.join(
634 Preferences.getPluginManager("DownloadPath"),
635 itm.data(0, PluginRepositoryWidget.FilenameRole))
636 self.__pluginsDownloaded.append(filename)
637 self.closeAndInstall.emit()
638
639 def __hidePlugin(self):
640 """
641 Private slot to hide the current plug-in.
642 """
643 itm = self.__selectedItems()[0]
644 pluginName = (itm.data(0, PluginRepositoryWidget.FilenameRole)
645 .rsplit("-", 1)[0])
646 self.__updateHiddenPluginsList([pluginName])
647
648 def __hideSelectedPlugins(self):
649 """
650 Private slot to hide all selected plug-ins.
651 """
652 hideList = []
653 for itm in self.__selectedItems():
654 pluginName = (itm.data(0, PluginRepositoryWidget.FilenameRole)
655 .rsplit("-", 1)[0])
656 hideList.append(pluginName)
657 self.__updateHiddenPluginsList(hideList)
658
659 def __showAllPlugins(self):
660 """
661 Private slot to show all plug-ins.
662 """
663 self.__hiddenPlugins = []
664 self.__updateHiddenPluginsList([])
665
666 def __hasHiddenPlugins(self):
667 """
668 Private method to check, if there are any hidden plug-ins.
669
670 @return flag indicating the presence of hidden plug-ins (boolean)
671 """
672 return bool(self.__hiddenPlugins)
673
674 def __updateHiddenPluginsList(self, hideList):
675 """
676 Private method to store the list of hidden plug-ins to the settings.
677
678 @param hideList list of plug-ins to add to the list of hidden ones
679 (list of string)
680 """
681 if hideList:
682 self.__hiddenPlugins.extend(
683 [p for p in hideList if p not in self.__hiddenPlugins])
684 Preferences.setPluginManager("HiddenPlugins", self.__hiddenPlugins)
685 self.__populateList()
686
687 def __cleanupDownloads(self):
688 """
689 Private slot to cleanup the plug-in downloads area.
690 """
691 downloadPath = Preferences.getPluginManager("DownloadPath")
692 downloads = {} # plug-in name as key, file name as value
693
694 # step 1: extract plug-ins and downloaded files
695 for pluginFile in os.listdir(downloadPath):
696 if not os.path.isfile(os.path.join(downloadPath, pluginFile)):
697 continue
698
699 pluginName = pluginFile.rsplit("-", 1)[0]
700 if pluginName not in downloads:
701 downloads[pluginName] = []
702 downloads[pluginName].append(pluginFile)
703
704 # step 2: delete old entries
705 for pluginName in downloads:
706 downloads[pluginName].sort()
707
708 if pluginName in self.__hiddenPlugins and \
709 not Preferences.getPluginManager("KeepHidden"):
710 removeFiles = downloads[pluginName]
711 else:
712 removeFiles = downloads[pluginName][
713 :-Preferences.getPluginManager("KeepGenerations")]
714 for removeFile in removeFiles:
715 try:
716 os.remove(os.path.join(downloadPath, removeFile))
717 except (IOError, OSError) as err:
718 E5MessageBox.critical(
719 self,
720 self.tr("Cleanup of Plugin Downloads"),
721 self.tr("""<p>The plugin download <b>{0}</b> could"""
722 """ not be deleted.</p><p>Reason: {1}</p>""")
723 .format(removeFile, str(err)))
555 724
556 725
557 class PluginRepositoryDialog(QDialog): 726 class PluginRepositoryDialog(QDialog):
558 """ 727 """
559 Class for the dialog variant. 728 Class for the dialog variant.
573 742
574 self.cw = PluginRepositoryWidget(self) 743 self.cw = PluginRepositoryWidget(self)
575 size = self.cw.size() 744 size = self.cw.size()
576 self.__layout.addWidget(self.cw) 745 self.__layout.addWidget(self.cw)
577 self.resize(size) 746 self.resize(size)
578 747 self.setWindowTitle(self.cw.windowTitle())
579 self.cw.buttonBox.accepted[()].connect(self.accept) 748
580 self.cw.buttonBox.rejected[()].connect(self.reject) 749 self.cw.buttonBox.accepted.connect(self.accept)
750 self.cw.buttonBox.rejected.connect(self.reject)
581 self.cw.closeAndInstall.connect(self.__closeAndInstall) 751 self.cw.closeAndInstall.connect(self.__closeAndInstall)
582 752
583 def __closeAndInstall(self): 753 def __closeAndInstall(self):
584 """ 754 """
585 Private slot to handle the closeAndInstall signal. 755 Private slot to handle the closeAndInstall signal.
608 super(PluginRepositoryWindow, self).__init__(parent) 778 super(PluginRepositoryWindow, self).__init__(parent)
609 self.cw = PluginRepositoryWidget(self, external=True) 779 self.cw = PluginRepositoryWidget(self, external=True)
610 size = self.cw.size() 780 size = self.cw.size()
611 self.setCentralWidget(self.cw) 781 self.setCentralWidget(self.cw)
612 self.resize(size) 782 self.resize(size)
783 self.setWindowTitle(self.cw.windowTitle())
613 784
614 self.setStyle(Preferences.getUI("Style"), 785 self.setStyle(Preferences.getUI("Style"),
615 Preferences.getUI("StyleSheet")) 786 Preferences.getUI("StyleSheet"))
616 787
617 self.cw.buttonBox.accepted[()].connect(self.close) 788 self.cw.buttonBox.accepted.connect(self.close)
618 self.cw.buttonBox.rejected[()].connect(self.close) 789 self.cw.buttonBox.rejected.connect(self.close)
619 self.cw.closeAndInstall.connect(self.__startPluginInstall) 790 self.cw.closeAndInstall.connect(self.__startPluginInstall)
620 791
621 def __startPluginInstall(self): 792 def __startPluginInstall(self):
622 """ 793 """
623 Private slot to start the eric5 plugin installation dialog. 794 Private slot to start the eric5 plugin installation dialog.
631 802
632 if not os.path.isfile(applPath) or \ 803 if not os.path.isfile(applPath) or \
633 not proc.startDetached(sys.executable, args): 804 not proc.startDetached(sys.executable, args):
634 E5MessageBox.critical( 805 E5MessageBox.critical(
635 self, 806 self,
636 self.trUtf8('Process Generation Error'), 807 self.tr('Process Generation Error'),
637 self.trUtf8( 808 self.tr(
638 '<p>Could not start the process.<br>' 809 '<p>Could not start the process.<br>'
639 'Ensure that it is available as <b>{0}</b>.</p>' 810 'Ensure that it is available as <b>{0}</b>.</p>'
640 ).format(applPath), 811 ).format(applPath),
641 self.trUtf8('OK')) 812 self.tr('OK'))
642 813
643 self.close() 814 self.close()

eric ide

mercurial