src/eric7/PluginManager/PluginRepositoryDialog.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9413
80c06d472826
equal deleted inserted replaced
9220:e9e7eca7efee 9221:bf71ee032bb4
11 import zipfile 11 import zipfile
12 import glob 12 import glob
13 import re 13 import re
14 14
15 from PyQt6.QtCore import ( 15 from PyQt6.QtCore import (
16 pyqtSignal, pyqtSlot, Qt, QFile, QIODevice, QUrl, QProcess, QPoint, 16 pyqtSignal,
17 QCoreApplication 17 pyqtSlot,
18 Qt,
19 QFile,
20 QIODevice,
21 QUrl,
22 QProcess,
23 QPoint,
24 QCoreApplication,
18 ) 25 )
19 from PyQt6.QtWidgets import ( 26 from PyQt6.QtWidgets import (
20 QWidget, QDialogButtonBox, QAbstractButton, QTreeWidgetItem, QDialog, 27 QWidget,
21 QVBoxLayout, QHBoxLayout, QMenu, QLabel, QToolButton 28 QDialogButtonBox,
29 QAbstractButton,
30 QTreeWidgetItem,
31 QDialog,
32 QVBoxLayout,
33 QHBoxLayout,
34 QMenu,
35 QLabel,
36 QToolButton,
22 ) 37 )
23 from PyQt6.QtNetwork import ( 38 from PyQt6.QtNetwork import (
24 QNetworkAccessManager, QNetworkRequest, QNetworkReply, QNetworkInformation 39 QNetworkAccessManager,
40 QNetworkRequest,
41 QNetworkReply,
42 QNetworkInformation,
25 ) 43 )
26 44
27 from .Ui_PluginRepositoryDialog import Ui_PluginRepositoryDialog 45 from .Ui_PluginRepositoryDialog import Ui_PluginRepositoryDialog
28 46
29 from EricWidgets import EricMessageBox 47 from EricWidgets import EricMessageBox
30 from EricWidgets.EricMainWindow import EricMainWindow 48 from EricWidgets.EricMainWindow import EricMainWindow
31 from EricWidgets.EricApplication import ericApp 49 from EricWidgets.EricApplication import ericApp
32 50
33 from EricNetwork.EricNetworkProxyFactory import proxyAuthenticationRequired 51 from EricNetwork.EricNetworkProxyFactory import proxyAuthenticationRequired
52
34 try: 53 try:
35 from EricNetwork.EricSslErrorHandler import ( 54 from EricNetwork.EricSslErrorHandler import EricSslErrorHandler, EricSslErrorState
36 EricSslErrorHandler, EricSslErrorState 55
37 )
38 SSL_AVAILABLE = True 56 SSL_AVAILABLE = True
39 except ImportError: 57 except ImportError:
40 SSL_AVAILABLE = False 58 SSL_AVAILABLE = False
41 59
42 import Globals 60 import Globals
49 67
50 68
51 class PluginRepositoryWidget(QWidget, Ui_PluginRepositoryDialog): 69 class PluginRepositoryWidget(QWidget, Ui_PluginRepositoryDialog):
52 """ 70 """
53 Class implementing a dialog showing the available plugins. 71 Class implementing a dialog showing the available plugins.
54 72
55 @signal closeAndInstall() emitted when the Close & Install button is 73 @signal closeAndInstall() emitted when the Close & Install button is
56 pressed 74 pressed
57 """ 75 """
76
58 closeAndInstall = pyqtSignal() 77 closeAndInstall = pyqtSignal()
59 78
60 DescrRole = Qt.ItemDataRole.UserRole 79 DescrRole = Qt.ItemDataRole.UserRole
61 UrlRole = Qt.ItemDataRole.UserRole + 1 80 UrlRole = Qt.ItemDataRole.UserRole + 1
62 FilenameRole = Qt.ItemDataRole.UserRole + 2 81 FilenameRole = Qt.ItemDataRole.UserRole + 2
63 AuthorRole = Qt.ItemDataRole.UserRole + 3 82 AuthorRole = Qt.ItemDataRole.UserRole + 3
64 83
65 PluginStatusUpToDate = 0 84 PluginStatusUpToDate = 0
66 PluginStatusNew = 1 85 PluginStatusNew = 1
67 PluginStatusLocalUpdate = 2 86 PluginStatusLocalUpdate = 2
68 PluginStatusRemoteUpdate = 3 87 PluginStatusRemoteUpdate = 3
69 PluginStatusError = 4 88 PluginStatusError = 4
70 89
71 def __init__(self, pluginManager, integrated=False, parent=None): 90 def __init__(self, pluginManager, integrated=False, parent=None):
72 """ 91 """
73 Constructor 92 Constructor
74 93
75 @param pluginManager reference to the plugin manager object 94 @param pluginManager reference to the plugin manager object
76 @type PluginManager 95 @type PluginManager
77 @param integrated flag indicating the integration into the sidebar 96 @param integrated flag indicating the integration into the sidebar
78 @type bool 97 @type bool
79 @param parent parent of this dialog 98 @param parent parent of this dialog
80 @type QWidget 99 @type QWidget
81 """ 100 """
82 super().__init__(parent) 101 super().__init__(parent)
83 self.setupUi(self) 102 self.setupUi(self)
84 103
85 if pluginManager is None: 104 if pluginManager is None:
86 # started as external plug-in repository dialog 105 # started as external plug-in repository dialog
87 from .PluginManager import PluginManager 106 from .PluginManager import PluginManager
107
88 self.__pluginManager = PluginManager() 108 self.__pluginManager = PluginManager()
89 self.__external = True 109 self.__external = True
90 else: 110 else:
91 self.__pluginManager = pluginManager 111 self.__pluginManager = pluginManager
92 self.__external = False 112 self.__external = False
93 self.__integratedWidget = integrated 113 self.__integratedWidget = integrated
94 114
95 if integrated: 115 if integrated:
96 self.layout().setContentsMargins(0, 3, 0, 0) 116 self.layout().setContentsMargins(0, 3, 0, 0)
97 117
98 if self.__integratedWidget: 118 if self.__integratedWidget:
99 self.__actionButtonsLayout = QHBoxLayout() 119 self.__actionButtonsLayout = QHBoxLayout()
100 self.__actionButtonsLayout.addStretch() 120 self.__actionButtonsLayout.addStretch()
101 121
102 self.__updateButton = QToolButton(self) 122 self.__updateButton = QToolButton(self)
103 self.__updateButton.setIcon(UI.PixmapCache.getIcon("reload")) 123 self.__updateButton.setIcon(UI.PixmapCache.getIcon("reload"))
104 self.__updateButton.setToolTip(self.tr("Update")) 124 self.__updateButton.setToolTip(self.tr("Update"))
105 self.__updateButton.clicked.connect(self.__updateList) 125 self.__updateButton.clicked.connect(self.__updateList)
106 self.__actionButtonsLayout.addWidget(self.__updateButton) 126 self.__actionButtonsLayout.addWidget(self.__updateButton)
107 127
108 self.__downloadButton = QToolButton(self) 128 self.__downloadButton = QToolButton(self)
109 self.__downloadButton.setIcon(UI.PixmapCache.getIcon("download")) 129 self.__downloadButton.setIcon(UI.PixmapCache.getIcon("download"))
110 self.__downloadButton.setToolTip(self.tr("Download")) 130 self.__downloadButton.setToolTip(self.tr("Download"))
111 self.__downloadButton.clicked.connect(self.__downloadButtonClicked) 131 self.__downloadButton.clicked.connect(self.__downloadButtonClicked)
112 self.__actionButtonsLayout.addWidget(self.__downloadButton) 132 self.__actionButtonsLayout.addWidget(self.__downloadButton)
113 133
114 self.__downloadInstallButton = QToolButton(self) 134 self.__downloadInstallButton = QToolButton(self)
115 self.__downloadInstallButton.setIcon( 135 self.__downloadInstallButton.setIcon(UI.PixmapCache.getIcon("downloadPlus"))
116 UI.PixmapCache.getIcon("downloadPlus")) 136 self.__downloadInstallButton.setToolTip(self.tr("Download & Install"))
117 self.__downloadInstallButton.setToolTip(
118 self.tr("Download & Install"))
119 self.__downloadInstallButton.clicked.connect( 137 self.__downloadInstallButton.clicked.connect(
120 self.__downloadInstallButtonClicked) 138 self.__downloadInstallButtonClicked
139 )
121 self.__actionButtonsLayout.addWidget(self.__downloadInstallButton) 140 self.__actionButtonsLayout.addWidget(self.__downloadInstallButton)
122 141
123 self.__downloadCancelButton = QToolButton(self) 142 self.__downloadCancelButton = QToolButton(self)
124 self.__downloadCancelButton.setIcon( 143 self.__downloadCancelButton.setIcon(UI.PixmapCache.getIcon("cancel"))
125 UI.PixmapCache.getIcon("cancel"))
126 self.__downloadCancelButton.setToolTip(self.tr("Cancel")) 144 self.__downloadCancelButton.setToolTip(self.tr("Cancel"))
127 self.__downloadCancelButton.clicked.connect(self.__downloadCancel) 145 self.__downloadCancelButton.clicked.connect(self.__downloadCancel)
128 self.__actionButtonsLayout.addWidget(self.__downloadCancelButton) 146 self.__actionButtonsLayout.addWidget(self.__downloadCancelButton)
129 147
130 self.__installButton = QToolButton(self) 148 self.__installButton = QToolButton(self)
131 self.__installButton.setIcon(UI.PixmapCache.getIcon("plus")) 149 self.__installButton.setIcon(UI.PixmapCache.getIcon("plus"))
132 self.__installButton.setToolTip(self.tr("Install")) 150 self.__installButton.setToolTip(self.tr("Install"))
133 self.__installButton.clicked.connect(self.__closeAndInstall) 151 self.__installButton.clicked.connect(self.__closeAndInstall)
134 self.__actionButtonsLayout.addWidget(self.__installButton) 152 self.__actionButtonsLayout.addWidget(self.__installButton)
135 153
136 self.__actionButtonsLayout.addStretch() 154 self.__actionButtonsLayout.addStretch()
137 155
138 self.layout().addLayout(self.__actionButtonsLayout) 156 self.layout().addLayout(self.__actionButtonsLayout)
139 self.buttonBox.hide() 157 self.buttonBox.hide()
140 else: 158 else:
141 self.__updateButton = self.buttonBox.addButton( 159 self.__updateButton = self.buttonBox.addButton(
142 self.tr("Update"), QDialogButtonBox.ButtonRole.ActionRole) 160 self.tr("Update"), QDialogButtonBox.ButtonRole.ActionRole
161 )
143 self.__downloadButton = self.buttonBox.addButton( 162 self.__downloadButton = self.buttonBox.addButton(
144 self.tr("Download"), QDialogButtonBox.ButtonRole.ActionRole) 163 self.tr("Download"), QDialogButtonBox.ButtonRole.ActionRole
164 )
145 self.__downloadInstallButton = self.buttonBox.addButton( 165 self.__downloadInstallButton = self.buttonBox.addButton(
146 self.tr("Download && Install"), 166 self.tr("Download && Install"), QDialogButtonBox.ButtonRole.ActionRole
147 QDialogButtonBox.ButtonRole.ActionRole) 167 )
148 self.__downloadCancelButton = self.buttonBox.addButton( 168 self.__downloadCancelButton = self.buttonBox.addButton(
149 self.tr("Cancel"), QDialogButtonBox.ButtonRole.ActionRole) 169 self.tr("Cancel"), QDialogButtonBox.ButtonRole.ActionRole
170 )
150 self.__installButton = self.buttonBox.addButton( 171 self.__installButton = self.buttonBox.addButton(
151 self.tr("Close && Install"), 172 self.tr("Close && Install"), QDialogButtonBox.ButtonRole.ActionRole
152 QDialogButtonBox.ButtonRole.ActionRole) 173 )
153 if not self.__integratedWidget: 174 if not self.__integratedWidget:
154 self.__closeButton = self.buttonBox.addButton( 175 self.__closeButton = self.buttonBox.addButton(
155 self.tr("Close"), QDialogButtonBox.ButtonRole.RejectRole) 176 self.tr("Close"), QDialogButtonBox.ButtonRole.RejectRole
177 )
156 self.__closeButton.setEnabled(True) 178 self.__closeButton.setEnabled(True)
157 179
158 self.__downloadButton.setEnabled(False) 180 self.__downloadButton.setEnabled(False)
159 self.__downloadInstallButton.setEnabled(False) 181 self.__downloadInstallButton.setEnabled(False)
160 self.__downloadCancelButton.setEnabled(False) 182 self.__downloadCancelButton.setEnabled(False)
161 self.__installButton.setEnabled(False) 183 self.__installButton.setEnabled(False)
162 184
163 self.repositoryUrlEdit.setText( 185 self.repositoryUrlEdit.setText(Preferences.getUI("PluginRepositoryUrl7"))
164 Preferences.getUI("PluginRepositoryUrl7")) 186
165
166 if self.__integratedWidget: 187 if self.__integratedWidget:
167 self.repositoryList.setHeaderHidden(True) 188 self.repositoryList.setHeaderHidden(True)
168 else: 189 else:
169 self.repositoryList.headerItem().setText( 190 self.repositoryList.headerItem().setText(
170 self.repositoryList.columnCount(), "") 191 self.repositoryList.columnCount(), ""
192 )
171 self.repositoryList.header().setSortIndicator( 193 self.repositoryList.header().setSortIndicator(
172 0, Qt.SortOrder.AscendingOrder) 194 0, Qt.SortOrder.AscendingOrder
173 195 )
196
174 self.__pluginContextMenu = QMenu(self) 197 self.__pluginContextMenu = QMenu(self)
175 self.__hideAct = self.__pluginContextMenu.addAction( 198 self.__hideAct = self.__pluginContextMenu.addAction(
176 self.tr("Hide"), self.__hidePlugin) 199 self.tr("Hide"), self.__hidePlugin
200 )
177 self.__hideSelectedAct = self.__pluginContextMenu.addAction( 201 self.__hideSelectedAct = self.__pluginContextMenu.addAction(
178 self.tr("Hide Selected"), self.__hideSelectedPlugins) 202 self.tr("Hide Selected"), self.__hideSelectedPlugins
203 )
179 self.__pluginContextMenu.addSeparator() 204 self.__pluginContextMenu.addSeparator()
180 self.__showAllAct = self.__pluginContextMenu.addAction( 205 self.__showAllAct = self.__pluginContextMenu.addAction(
181 self.tr("Show All"), self.__showAllPlugins) 206 self.tr("Show All"), self.__showAllPlugins
207 )
182 self.__pluginContextMenu.addSeparator() 208 self.__pluginContextMenu.addSeparator()
183 self.__pluginContextMenu.addAction( 209 self.__pluginContextMenu.addAction(
184 self.tr("Cleanup Downloads"), self.__cleanupDownloads) 210 self.tr("Cleanup Downloads"), self.__cleanupDownloads
185 211 )
186 self.pluginRepositoryFile = os.path.join(Utilities.getConfigDir(), 212
187 "PluginRepository") 213 self.pluginRepositoryFile = os.path.join(
188 214 Utilities.getConfigDir(), "PluginRepository"
189 self.__pluginManager.pluginRepositoryFileDownloaded.connect( 215 )
190 self.__populateList) 216
191 217 self.__pluginManager.pluginRepositoryFileDownloaded.connect(self.__populateList)
218
192 # attributes for the network objects 219 # attributes for the network objects
193 self.__networkManager = QNetworkAccessManager(self) 220 self.__networkManager = QNetworkAccessManager(self)
194 self.__networkManager.proxyAuthenticationRequired.connect( 221 self.__networkManager.proxyAuthenticationRequired.connect(
195 proxyAuthenticationRequired) 222 proxyAuthenticationRequired
223 )
196 if SSL_AVAILABLE: 224 if SSL_AVAILABLE:
197 self.__sslErrorHandler = EricSslErrorHandler(self) 225 self.__sslErrorHandler = EricSslErrorHandler(self)
198 self.__networkManager.sslErrors.connect(self.__sslErrors) 226 self.__networkManager.sslErrors.connect(self.__sslErrors)
199 self.__replies = [] 227 self.__replies = []
200 228
201 if ( 229 if Preferences.getUI("DynamicOnlineCheck") and QNetworkInformation.load(
202 Preferences.getUI("DynamicOnlineCheck") and 230 QNetworkInformation.Feature.Reachability
203 QNetworkInformation.load(QNetworkInformation.Feature.Reachability)
204 ): 231 ):
205 self.__reachabilityChanged( 232 self.__reachabilityChanged(QNetworkInformation.instance().reachability())
206 QNetworkInformation.instance().reachability())
207 QNetworkInformation.instance().reachabilityChanged.connect( 233 QNetworkInformation.instance().reachabilityChanged.connect(
208 self.__reachabilityChanged) 234 self.__reachabilityChanged
235 )
209 else: 236 else:
210 # assume to be 'always online' if no backend could be loaded or 237 # assume to be 'always online' if no backend could be loaded or
211 # dynamic online check is switched of 238 # dynamic online check is switched of
212 self.__reachabilityChanged(QNetworkInformation.Reachability.Online) 239 self.__reachabilityChanged(QNetworkInformation.Reachability.Online)
213 240
214 self.__pluginsToDownload = [] 241 self.__pluginsToDownload = []
215 self.__pluginsDownloaded = [] 242 self.__pluginsDownloaded = []
216 self.__isDownloadInstall = False 243 self.__isDownloadInstall = False
217 self.__allDownloadedOk = False 244 self.__allDownloadedOk = False
218 245
219 self.__hiddenPlugins = Preferences.getPluginManager("HiddenPlugins") 246 self.__hiddenPlugins = Preferences.getPluginManager("HiddenPlugins")
220 247
221 self.__populateList() 248 self.__populateList()
222 249
223 def __reachabilityChanged(self, reachability): 250 def __reachabilityChanged(self, reachability):
224 """ 251 """
225 Private slot handling reachability state changes. 252 Private slot handling reachability state changes.
226 253
227 @param reachability new reachability state 254 @param reachability new reachability state
228 @type QNetworkInformation.Reachability 255 @type QNetworkInformation.Reachability
229 """ 256 """
230 online = reachability == QNetworkInformation.Reachability.Online 257 online = reachability == QNetworkInformation.Reachability.Online
231 self.__online = online 258 self.__online = online
232 259
233 self.__updateButton.setEnabled(online) 260 self.__updateButton.setEnabled(online)
234 self.on_repositoryList_itemSelectionChanged() 261 self.on_repositoryList_itemSelectionChanged()
235 262
236 if not self.__integratedWidget: 263 if not self.__integratedWidget:
237 msg = ( 264 msg = (
238 self.tr("Internet Reachability Status: Reachable") 265 self.tr("Internet Reachability Status: Reachable")
239 if online else 266 if online
240 self.tr("Internet Reachability Status: Not Reachable") 267 else self.tr("Internet Reachability Status: Not Reachable")
241 ) 268 )
242 self.statusLabel.setText(msg) 269 self.statusLabel.setText(msg)
243 270
244 @pyqtSlot(QAbstractButton) 271 @pyqtSlot(QAbstractButton)
245 def on_buttonBox_clicked(self, button): 272 def on_buttonBox_clicked(self, button):
246 """ 273 """
247 Private slot to handle the click of a button of the button box. 274 Private slot to handle the click of a button of the button box.
248 275
249 @param button reference to the button pressed (QAbstractButton) 276 @param button reference to the button pressed (QAbstractButton)
250 """ 277 """
251 if button == self.__updateButton: 278 if button == self.__updateButton:
252 self.__updateList() 279 self.__updateList()
253 elif button == self.__downloadButton: 280 elif button == self.__downloadButton:
256 self.__downloadInstallButtonClicked() 283 self.__downloadInstallButtonClicked()
257 elif button == self.__downloadCancelButton: 284 elif button == self.__downloadCancelButton:
258 self.__downloadCancel() 285 self.__downloadCancel()
259 elif button == self.__installButton: 286 elif button == self.__installButton:
260 self.__closeAndInstall() 287 self.__closeAndInstall()
261 288
262 @pyqtSlot() 289 @pyqtSlot()
263 def __downloadButtonClicked(self): 290 def __downloadButtonClicked(self):
264 """ 291 """
265 Private slot to handle a click of the Download button. 292 Private slot to handle a click of the Download button.
266 """ 293 """
267 self.__isDownloadInstall = False 294 self.__isDownloadInstall = False
268 self.__downloadPlugins() 295 self.__downloadPlugins()
269 296
270 @pyqtSlot() 297 @pyqtSlot()
271 def __downloadInstallButtonClicked(self): 298 def __downloadInstallButtonClicked(self):
272 """ 299 """
273 Private slot to handle a click of the Download & Install button. 300 Private slot to handle a click of the Download & Install button.
274 """ 301 """
275 self.__isDownloadInstall = True 302 self.__isDownloadInstall = True
276 self.__allDownloadedOk = True 303 self.__allDownloadedOk = True
277 self.__downloadPlugins() 304 self.__downloadPlugins()
278 305
279 def __formatDescription(self, lines): 306 def __formatDescription(self, lines):
280 """ 307 """
281 Private method to format the description. 308 Private method to format the description.
282 309
283 @param lines lines of the description (list of strings) 310 @param lines lines of the description (list of strings)
284 @return formatted description (string) 311 @return formatted description (string)
285 """ 312 """
286 # remove empty line at start and end 313 # remove empty line at start and end
287 newlines = lines[:] 314 newlines = lines[:]
288 if len(newlines) and newlines[0] == '': 315 if len(newlines) and newlines[0] == "":
289 del newlines[0] 316 del newlines[0]
290 if len(newlines) and newlines[-1] == '': 317 if len(newlines) and newlines[-1] == "":
291 del newlines[-1] 318 del newlines[-1]
292 319
293 # replace empty lines by newline character 320 # replace empty lines by newline character
294 index = 0 321 index = 0
295 while index < len(newlines): 322 while index < len(newlines):
296 if newlines[index] == '': 323 if newlines[index] == "":
297 newlines[index] = '\n' 324 newlines[index] = "\n"
298 index += 1 325 index += 1
299 326
300 # join lines by a blank 327 # join lines by a blank
301 return ' '.join(newlines) 328 return " ".join(newlines)
302 329
303 def __changeScheme(self, url, newScheme=""): 330 def __changeScheme(self, url, newScheme=""):
304 """ 331 """
305 Private method to change the scheme of the given URL. 332 Private method to change the scheme of the given URL.
306 333
307 @param url URL to be modified 334 @param url URL to be modified
308 @type str 335 @type str
309 @param newScheme scheme to be set for the given URL 336 @param newScheme scheme to be set for the given URL
310 @return modified URL 337 @return modified URL
311 @rtype str 338 @rtype str
312 """ 339 """
313 if not newScheme: 340 if not newScheme:
314 newScheme = self.repositoryUrlEdit.text().split("//", 1)[0] 341 newScheme = self.repositoryUrlEdit.text().split("//", 1)[0]
315 342
316 return newScheme + "//" + url.split("//", 1)[1] 343 return newScheme + "//" + url.split("//", 1)[1]
317 344
318 @pyqtSlot(QPoint) 345 @pyqtSlot(QPoint)
319 def on_repositoryList_customContextMenuRequested(self, pos): 346 def on_repositoryList_customContextMenuRequested(self, pos):
320 """ 347 """
321 Private slot to show the context menu. 348 Private slot to show the context menu.
322 349
323 @param pos position to show the menu (QPoint) 350 @param pos position to show the menu (QPoint)
324 """ 351 """
325 self.__hideAct.setEnabled( 352 self.__hideAct.setEnabled(
326 self.repositoryList.currentItem() is not None and 353 self.repositoryList.currentItem() is not None
327 len(self.__selectedItems()) == 1) 354 and len(self.__selectedItems()) == 1
328 self.__hideSelectedAct.setEnabled( 355 )
329 len(self.__selectedItems()) > 1) 356 self.__hideSelectedAct.setEnabled(len(self.__selectedItems()) > 1)
330 self.__showAllAct.setEnabled(bool(self.__hasHiddenPlugins())) 357 self.__showAllAct.setEnabled(bool(self.__hasHiddenPlugins()))
331 self.__pluginContextMenu.popup(self.repositoryList.mapToGlobal(pos)) 358 self.__pluginContextMenu.popup(self.repositoryList.mapToGlobal(pos))
332 359
333 @pyqtSlot(QTreeWidgetItem, QTreeWidgetItem) 360 @pyqtSlot(QTreeWidgetItem, QTreeWidgetItem)
334 def on_repositoryList_currentItemChanged(self, current, previous): 361 def on_repositoryList_currentItemChanged(self, current, previous):
335 """ 362 """
336 Private slot to handle the change of the current item. 363 Private slot to handle the change of the current item.
337 364
338 @param current reference to the new current item (QTreeWidgetItem) 365 @param current reference to the new current item (QTreeWidgetItem)
339 @param previous reference to the old current item (QTreeWidgetItem) 366 @param previous reference to the old current item (QTreeWidgetItem)
340 """ 367 """
341 if self.__repositoryMissing or current is None: 368 if self.__repositoryMissing or current is None:
342 self.descriptionEdit.clear() 369 self.descriptionEdit.clear()
343 self.authorEdit.clear() 370 self.authorEdit.clear()
344 return 371 return
345 372
346 url = current.data(0, PluginRepositoryWidget.UrlRole) 373 url = current.data(0, PluginRepositoryWidget.UrlRole)
347 url = "" if url is None else self.__changeScheme(url) 374 url = "" if url is None else self.__changeScheme(url)
348 self.urlEdit.setText(url) 375 self.urlEdit.setText(url)
349 self.descriptionEdit.setPlainText( 376 self.descriptionEdit.setPlainText(
350 current.data(0, PluginRepositoryWidget.DescrRole) and 377 current.data(0, PluginRepositoryWidget.DescrRole)
351 self.__formatDescription( 378 and self.__formatDescription(
352 current.data(0, PluginRepositoryWidget.DescrRole)) or "") 379 current.data(0, PluginRepositoryWidget.DescrRole)
380 )
381 or ""
382 )
353 self.authorEdit.setText( 383 self.authorEdit.setText(
354 current.data(0, PluginRepositoryWidget.AuthorRole) or "") 384 current.data(0, PluginRepositoryWidget.AuthorRole) or ""
355 385 )
386
356 def __selectedItems(self): 387 def __selectedItems(self):
357 """ 388 """
358 Private method to get all selected items without the toplevel ones. 389 Private method to get all selected items without the toplevel ones.
359 390
360 @return list of selected items (list) 391 @return list of selected items (list)
361 """ 392 """
362 ql = self.repositoryList.selectedItems() 393 ql = self.repositoryList.selectedItems()
363 for index in range(self.repositoryList.topLevelItemCount()): 394 for index in range(self.repositoryList.topLevelItemCount()):
364 ti = self.repositoryList.topLevelItem(index) 395 ti = self.repositoryList.topLevelItem(index)
365 if ti in ql: 396 if ti in ql:
366 ql.remove(ti) 397 ql.remove(ti)
367 return ql 398 return ql
368 399
369 @pyqtSlot() 400 @pyqtSlot()
370 def on_repositoryList_itemSelectionChanged(self): 401 def on_repositoryList_itemSelectionChanged(self):
371 """ 402 """
372 Private slot to handle a change of the selection. 403 Private slot to handle a change of the selection.
373 """ 404 """
374 enable = bool(self.__selectedItems()) 405 enable = bool(self.__selectedItems())
375 self.__downloadButton.setEnabled(enable and self.__online) 406 self.__downloadButton.setEnabled(enable and self.__online)
376 self.__downloadInstallButton.setEnabled(enable and self.__online) 407 self.__downloadInstallButton.setEnabled(enable and self.__online)
377 self.__installButton.setEnabled(enable) 408 self.__installButton.setEnabled(enable)
378 409
379 def reloadList(self): 410 def reloadList(self):
380 """ 411 """
381 Public method to reload the list of plugins. 412 Public method to reload the list of plugins.
382 """ 413 """
383 self.__populateList() 414 self.__populateList()
384 415
385 @pyqtSlot() 416 @pyqtSlot()
386 def __updateList(self): 417 def __updateList(self):
387 """ 418 """
388 Private slot to download a new list and display the contents. 419 Private slot to download a new list and display the contents.
389 """ 420 """
390 url = self.repositoryUrlEdit.text() 421 url = self.repositoryUrlEdit.text()
391 self.__pluginManager.downLoadRepositoryFile(url=url) 422 self.__pluginManager.downLoadRepositoryFile(url=url)
392 423
393 def __downloadRepositoryFileDone(self, status, filename): 424 def __downloadRepositoryFileDone(self, status, filename):
394 """ 425 """
395 Private method called after the repository file was downloaded. 426 Private method called after the repository file was downloaded.
396 427
397 @param status flaging indicating a successful download (boolean) 428 @param status flaging indicating a successful download (boolean)
398 @param filename full path of the downloaded file (string) 429 @param filename full path of the downloaded file (string)
399 """ 430 """
400 self.__populateList() 431 self.__populateList()
401 432
402 def __downloadPluginDone(self, status, filename): 433 def __downloadPluginDone(self, status, filename):
403 """ 434 """
404 Private method called, when the download of a plugin is finished. 435 Private method called, when the download of a plugin is finished.
405 436
406 @param status flag indicating a successful download (boolean) 437 @param status flag indicating a successful download (boolean)
407 @param filename full path of the downloaded file (string) 438 @param filename full path of the downloaded file (string)
408 """ 439 """
409 if status: 440 if status:
410 self.__pluginsDownloaded.append(filename) 441 self.__pluginsDownloaded.append(filename)
411 if self.__isDownloadInstall: 442 if self.__isDownloadInstall:
412 self.__allDownloadedOk &= status 443 self.__allDownloadedOk &= status
413 444
414 if len(self.__pluginsToDownload): 445 if len(self.__pluginsToDownload):
415 self.__pluginsToDownload.pop(0) 446 self.__pluginsToDownload.pop(0)
416 447
417 if len(self.__pluginsToDownload): 448 if len(self.__pluginsToDownload):
418 self.__downloadPlugin() 449 self.__downloadPlugin()
419 else: 450 else:
420 self.__downloadPluginsDone() 451 self.__downloadPluginsDone()
421 452
422 def __downloadPlugin(self): 453 def __downloadPlugin(self):
423 """ 454 """
424 Private method to download the next plugin. 455 Private method to download the next plugin.
425 """ 456 """
426 self.__downloadFile(self.__pluginsToDownload[0][0], 457 self.__downloadFile(
427 self.__pluginsToDownload[0][1], 458 self.__pluginsToDownload[0][0],
428 self.__downloadPluginDone) 459 self.__pluginsToDownload[0][1],
429 460 self.__downloadPluginDone,
461 )
462
430 def __downloadPlugins(self): 463 def __downloadPlugins(self):
431 """ 464 """
432 Private slot to download the selected plugins. 465 Private slot to download the selected plugins.
433 """ 466 """
434 self.__pluginsDownloaded = [] 467 self.__pluginsDownloaded = []
435 self.__pluginsToDownload = [] 468 self.__pluginsToDownload = []
436 self.__downloadButton.setEnabled(False) 469 self.__downloadButton.setEnabled(False)
437 self.__downloadInstallButton.setEnabled(False) 470 self.__downloadInstallButton.setEnabled(False)
438 self.__installButton.setEnabled(False) 471 self.__installButton.setEnabled(False)
439 472
440 newScheme = self.repositoryUrlEdit.text().split("//", 1)[0] 473 newScheme = self.repositoryUrlEdit.text().split("//", 1)[0]
441 for itm in self.repositoryList.selectedItems(): 474 for itm in self.repositoryList.selectedItems():
442 if itm not in [self.__stableItem, self.__unstableItem, 475 if itm not in [
443 self.__unknownItem, self.__obsoleteItem]: 476 self.__stableItem,
477 self.__unstableItem,
478 self.__unknownItem,
479 self.__obsoleteItem,
480 ]:
444 url = self.__changeScheme( 481 url = self.__changeScheme(
445 itm.data(0, PluginRepositoryWidget.UrlRole), 482 itm.data(0, PluginRepositoryWidget.UrlRole), newScheme
446 newScheme) 483 )
447 filename = os.path.join( 484 filename = os.path.join(
448 Preferences.getPluginManager("DownloadPath"), 485 Preferences.getPluginManager("DownloadPath"),
449 itm.data(0, PluginRepositoryWidget.FilenameRole)) 486 itm.data(0, PluginRepositoryWidget.FilenameRole),
487 )
450 self.__pluginsToDownload.append((url, filename)) 488 self.__pluginsToDownload.append((url, filename))
451 if self.__pluginsToDownload: 489 if self.__pluginsToDownload:
452 self.__downloadPlugin() 490 self.__downloadPlugin()
453 491
454 def __downloadPluginsDone(self): 492 def __downloadPluginsDone(self):
455 """ 493 """
456 Private method called, when the download of the plugins is finished. 494 Private method called, when the download of the plugins is finished.
457 """ 495 """
458 self.__downloadButton.setEnabled(len(self.__selectedItems())) 496 self.__downloadButton.setEnabled(len(self.__selectedItems()))
459 self.__downloadInstallButton.setEnabled(len(self.__selectedItems())) 497 self.__downloadInstallButton.setEnabled(len(self.__selectedItems()))
460 self.__installButton.setEnabled(len(self.__selectedItems())) 498 self.__installButton.setEnabled(len(self.__selectedItems()))
461 ui = (ericApp().getObject("UserInterface") 499 ui = ericApp().getObject("UserInterface") if not self.__external else None
462 if not self.__external else None)
463 if ui is not None: 500 if ui is not None:
464 ui.showNotification( 501 ui.showNotification(
465 UI.PixmapCache.getPixmap("plugin48"), 502 UI.PixmapCache.getPixmap("plugin48"),
466 self.tr("Download Plugin Files"), 503 self.tr("Download Plugin Files"),
467 self.tr("""The requested plugins were downloaded.""")) 504 self.tr("""The requested plugins were downloaded."""),
468 505 )
506
469 if self.__isDownloadInstall: 507 if self.__isDownloadInstall:
470 self.closeAndInstall.emit() 508 self.closeAndInstall.emit()
471 else: 509 else:
472 if ui is None: 510 if ui is None:
473 EricMessageBox.information( 511 EricMessageBox.information(
474 self, 512 self,
475 self.tr("Download Plugin Files"), 513 self.tr("Download Plugin Files"),
476 self.tr("""The requested plugins were downloaded.""")) 514 self.tr("""The requested plugins were downloaded."""),
477 515 )
516
478 self.downloadProgress.setValue(0) 517 self.downloadProgress.setValue(0)
479 518
480 # repopulate the list to update the refresh icons 519 # repopulate the list to update the refresh icons
481 self.__populateList() 520 self.__populateList()
482 521
483 def __resortRepositoryList(self): 522 def __resortRepositoryList(self):
484 """ 523 """
485 Private method to resort the tree. 524 Private method to resort the tree.
486 """ 525 """
487 self.repositoryList.sortItems( 526 self.repositoryList.sortItems(
488 self.repositoryList.sortColumn(), 527 self.repositoryList.sortColumn(),
489 self.repositoryList.header().sortIndicatorOrder()) 528 self.repositoryList.header().sortIndicatorOrder(),
490 529 )
530
491 def __populateList(self): 531 def __populateList(self):
492 """ 532 """
493 Private method to populate the list of available plugins. 533 Private method to populate the list of available plugins.
494 """ 534 """
495 self.repositoryList.clear() 535 self.repositoryList.clear()
496 self.__stableItem = None 536 self.__stableItem = None
497 self.__unstableItem = None 537 self.__unstableItem = None
498 self.__unknownItem = None 538 self.__unknownItem = None
499 self.__obsoleteItem = None 539 self.__obsoleteItem = None
500 540
501 self.__newItems = 0 541 self.__newItems = 0
502 self.__updateLocalItems = 0 542 self.__updateLocalItems = 0
503 self.__updateRemoteItems = 0 543 self.__updateRemoteItems = 0
504 544
505 self.downloadProgress.setValue(0) 545 self.downloadProgress.setValue(0)
506 546
507 if os.path.exists(self.pluginRepositoryFile): 547 if os.path.exists(self.pluginRepositoryFile):
508 self.__repositoryMissing = False 548 self.__repositoryMissing = False
509 f = QFile(self.pluginRepositoryFile) 549 f = QFile(self.pluginRepositoryFile)
510 if f.open(QIODevice.OpenModeFlag.ReadOnly): 550 if f.open(QIODevice.OpenModeFlag.ReadOnly):
511 from EricXML.PluginRepositoryReader import ( 551 from EricXML.PluginRepositoryReader import PluginRepositoryReader
512 PluginRepositoryReader 552
513 )
514 reader = PluginRepositoryReader(f, self.addEntry) 553 reader = PluginRepositoryReader(f, self.addEntry)
515 reader.readXML() 554 reader.readXML()
516 self.repositoryList.resizeColumnToContents(0) 555 self.repositoryList.resizeColumnToContents(0)
517 self.repositoryList.resizeColumnToContents(1) 556 self.repositoryList.resizeColumnToContents(1)
518 self.repositoryList.resizeColumnToContents(2) 557 self.repositoryList.resizeColumnToContents(2)
524 self, 563 self,
525 self.tr("Plugins Repository URL Changed"), 564 self.tr("Plugins Repository URL Changed"),
526 self.tr( 565 self.tr(
527 """The URL of the Plugins Repository has""" 566 """The URL of the Plugins Repository has"""
528 """ changed. Select the "Update" button to get""" 567 """ changed. Select the "Update" button to get"""
529 """ the new repository file.""")) 568 """ the new repository file."""
569 ),
570 )
530 else: 571 else:
531 EricMessageBox.critical( 572 EricMessageBox.critical(
532 self, 573 self,
533 self.tr("Read plugins repository file"), 574 self.tr("Read plugins repository file"),
534 self.tr("<p>The plugins repository file <b>{0}</b> " 575 self.tr(
535 "could not be read. Select Update</p>") 576 "<p>The plugins repository file <b>{0}</b> "
536 .format(self.pluginRepositoryFile)) 577 "could not be read. Select Update</p>"
578 ).format(self.pluginRepositoryFile),
579 )
537 else: 580 else:
538 self.__repositoryMissing = True 581 self.__repositoryMissing = True
539 QTreeWidgetItem( 582 QTreeWidgetItem(
540 self.repositoryList, 583 self.repositoryList,
541 ["", self.tr( 584 ["", self.tr("No plugin repository file available.\nSelect Update.")],
542 "No plugin repository file available.\nSelect Update.") 585 )
543 ])
544 self.repositoryList.resizeColumnToContents(1) 586 self.repositoryList.resizeColumnToContents(1)
545 587
546 self.newLabel.setText(self.tr("New: <b>{0}</b>") 588 self.newLabel.setText(self.tr("New: <b>{0}</b>").format(self.__newItems))
547 .format(self.__newItems)) 589 self.updateLocalLabel.setText(
548 self.updateLocalLabel.setText(self.tr("Local Updates: <b>{0}</b>") 590 self.tr("Local Updates: <b>{0}</b>").format(self.__updateLocalItems)
549 .format(self.__updateLocalItems)) 591 )
550 self.updateRemoteLabel.setText(self.tr("Remote Updates: <b>{0}</b>") 592 self.updateRemoteLabel.setText(
551 .format(self.__updateRemoteItems)) 593 self.tr("Remote Updates: <b>{0}</b>").format(self.__updateRemoteItems)
552 594 )
595
553 def __downloadFile(self, url, filename, doneMethod=None): 596 def __downloadFile(self, url, filename, doneMethod=None):
554 """ 597 """
555 Private slot to download the given file. 598 Private slot to download the given file.
556 599
557 @param url URL for the download (string) 600 @param url URL for the download (string)
558 @param filename local name of the file (string) 601 @param filename local name of the file (string)
559 @param doneMethod method to be called when done 602 @param doneMethod method to be called when done
560 """ 603 """
561 if self.__online: 604 if self.__online:
563 self.__downloadButton.setEnabled(False) 606 self.__downloadButton.setEnabled(False)
564 self.__downloadInstallButton.setEnabled(False) 607 self.__downloadInstallButton.setEnabled(False)
565 if not self.__integratedWidget: 608 if not self.__integratedWidget:
566 self.__closeButton.setEnabled(False) 609 self.__closeButton.setEnabled(False)
567 self.__downloadCancelButton.setEnabled(True) 610 self.__downloadCancelButton.setEnabled(True)
568 611
569 self.statusLabel.setText(url) 612 self.statusLabel.setText(url)
570 613
571 request = QNetworkRequest(QUrl(url)) 614 request = QNetworkRequest(QUrl(url))
572 request.setAttribute( 615 request.setAttribute(
573 QNetworkRequest.Attribute.CacheLoadControlAttribute, 616 QNetworkRequest.Attribute.CacheLoadControlAttribute,
574 QNetworkRequest.CacheLoadControl.AlwaysNetwork) 617 QNetworkRequest.CacheLoadControl.AlwaysNetwork,
618 )
575 reply = self.__networkManager.get(request) 619 reply = self.__networkManager.get(request)
576 reply.finished.connect( 620 reply.finished.connect(
577 lambda: self.__downloadFileDone(reply, filename, doneMethod)) 621 lambda: self.__downloadFileDone(reply, filename, doneMethod)
622 )
578 reply.downloadProgress.connect(self.__downloadProgress) 623 reply.downloadProgress.connect(self.__downloadProgress)
579 self.__replies.append(reply) 624 self.__replies.append(reply)
580 else: 625 else:
581 EricMessageBox.warning( 626 EricMessageBox.warning(
582 self, 627 self,
583 self.tr("Error downloading file"), 628 self.tr("Error downloading file"),
584 self.tr( 629 self.tr(
585 """<p>Could not download the requested file""" 630 """<p>Could not download the requested file"""
586 """ from {0}.</p><p>Error: {1}</p>""" 631 """ from {0}.</p><p>Error: {1}</p>"""
587 ).format(url, self.tr("No connection to Internet."))) 632 ).format(url, self.tr("No connection to Internet.")),
588 633 )
634
589 def __downloadFileDone(self, reply, fileName, doneMethod): 635 def __downloadFileDone(self, reply, fileName, doneMethod):
590 """ 636 """
591 Private method called, after the file has been downloaded 637 Private method called, after the file has been downloaded
592 from the Internet. 638 from the Internet.
593 639
594 @param reply reference to the reply object of the download 640 @param reply reference to the reply object of the download
595 @type QNetworkReply 641 @type QNetworkReply
596 @param fileName local name of the file 642 @param fileName local name of the file
597 @type str 643 @type str
598 @param doneMethod method to be called when done 644 @param doneMethod method to be called when done
600 """ 646 """
601 self.__updateButton.setEnabled(True) 647 self.__updateButton.setEnabled(True)
602 if not self.__integratedWidget: 648 if not self.__integratedWidget:
603 self.__closeButton.setEnabled(True) 649 self.__closeButton.setEnabled(True)
604 self.__downloadCancelButton.setEnabled(False) 650 self.__downloadCancelButton.setEnabled(False)
605 651
606 ok = True 652 ok = True
607 if reply in self.__replies: 653 if reply in self.__replies:
608 self.__replies.remove(reply) 654 self.__replies.remove(reply)
609 if reply.error() != QNetworkReply.NetworkError.NoError: 655 if reply.error() != QNetworkReply.NetworkError.NoError:
610 ok = False 656 ok = False
611 if ( 657 if reply.error() != QNetworkReply.NetworkError.OperationCanceledError:
612 reply.error() !=
613 QNetworkReply.NetworkError.OperationCanceledError
614 ):
615 EricMessageBox.warning( 658 EricMessageBox.warning(
616 self, 659 self,
617 self.tr("Error downloading file"), 660 self.tr("Error downloading file"),
618 self.tr( 661 self.tr(
619 """<p>Could not download the requested file""" 662 """<p>Could not download the requested file"""
620 """ from {0}.</p><p>Error: {1}</p>""" 663 """ from {0}.</p><p>Error: {1}</p>"""
621 ).format(reply.url().toString(), reply.errorString()) 664 ).format(reply.url().toString(), reply.errorString()),
622 ) 665 )
623 self.downloadProgress.setValue(0) 666 self.downloadProgress.setValue(0)
624 if self.repositoryList.topLevelItemCount(): 667 if self.repositoryList.topLevelItemCount():
625 if self.repositoryList.currentItem() is None: 668 if self.repositoryList.currentItem() is None:
626 self.repositoryList.setCurrentItem( 669 self.repositoryList.setCurrentItem(
627 self.repositoryList.topLevelItem(0)) 670 self.repositoryList.topLevelItem(0)
671 )
628 else: 672 else:
629 self.__downloadButton.setEnabled( 673 self.__downloadButton.setEnabled(len(self.__selectedItems()))
630 len(self.__selectedItems())) 674 self.__downloadInstallButton.setEnabled(len(self.__selectedItems()))
631 self.__downloadInstallButton.setEnabled(
632 len(self.__selectedItems()))
633 reply.deleteLater() 675 reply.deleteLater()
634 return 676 return
635 677
636 downloadIODevice = QFile(fileName + ".tmp") 678 downloadIODevice = QFile(fileName + ".tmp")
637 downloadIODevice.open(QIODevice.OpenModeFlag.WriteOnly) 679 downloadIODevice.open(QIODevice.OpenModeFlag.WriteOnly)
638 # read data in chunks 680 # read data in chunks
639 chunkSize = 64 * 1024 * 1024 681 chunkSize = 64 * 1024 * 1024
640 while True: 682 while True:
645 downloadIODevice.close() 687 downloadIODevice.close()
646 if QFile.exists(fileName): 688 if QFile.exists(fileName):
647 QFile.remove(fileName) 689 QFile.remove(fileName)
648 downloadIODevice.rename(fileName) 690 downloadIODevice.rename(fileName)
649 reply.deleteLater() 691 reply.deleteLater()
650 692
651 if doneMethod is not None: 693 if doneMethod is not None:
652 doneMethod(ok, fileName) 694 doneMethod(ok, fileName)
653 695
654 def __downloadCancel(self, reply=None): 696 def __downloadCancel(self, reply=None):
655 """ 697 """
656 Private slot to cancel the current download. 698 Private slot to cancel the current download.
657 699
658 @param reply reference to the network reply 700 @param reply reference to the network reply
659 @type QNetworkReply 701 @type QNetworkReply
660 """ 702 """
661 if reply is None and bool(self.__replies): 703 if reply is None and bool(self.__replies):
662 reply = self.__replies[0] 704 reply = self.__replies[0]
663 self.__pluginsToDownload = [] 705 self.__pluginsToDownload = []
664 if reply is not None: 706 if reply is not None:
665 reply.abort() 707 reply.abort()
666 708
667 def __downloadProgress(self, done, total): 709 def __downloadProgress(self, done, total):
668 """ 710 """
669 Private slot to show the download progress. 711 Private slot to show the download progress.
670 712
671 @param done number of bytes downloaded so far (integer) 713 @param done number of bytes downloaded so far (integer)
672 @param total total bytes to be downloaded (integer) 714 @param total total bytes to be downloaded (integer)
673 """ 715 """
674 if total: 716 if total:
675 self.downloadProgress.setMaximum(total) 717 self.downloadProgress.setMaximum(total)
676 self.downloadProgress.setValue(done) 718 self.downloadProgress.setValue(done)
677 719
678 def addEntry(self, name, short, description, url, author, version, 720 def addEntry(
679 filename, status): 721 self, name, short, description, url, author, version, filename, status
722 ):
680 """ 723 """
681 Public method to add an entry to the list. 724 Public method to add an entry to the list.
682 725
683 @param name data for the name field (string) 726 @param name data for the name field (string)
684 @param short data for the short field (string) 727 @param short data for the short field (string)
685 @param description data for the description field (list of strings) 728 @param description data for the description field (list of strings)
686 @param url data for the url field (string) 729 @param url data for the url field (string)
687 @param author data for the author field (string) 730 @param author data for the author field (string)
690 @param status status of the plugin (string [stable, unstable, unknown]) 733 @param status status of the plugin (string [stable, unstable, unknown])
691 """ 734 """
692 pluginName = filename.rsplit("-", 1)[0] 735 pluginName = filename.rsplit("-", 1)[0]
693 if pluginName in self.__hiddenPlugins: 736 if pluginName in self.__hiddenPlugins:
694 return 737 return
695 738
696 if status == "stable": 739 if status == "stable":
697 if self.__stableItem is None: 740 if self.__stableItem is None:
698 self.__stableItem = QTreeWidgetItem( 741 self.__stableItem = QTreeWidgetItem(
699 self.repositoryList, [self.tr("Stable")]) 742 self.repositoryList, [self.tr("Stable")]
743 )
700 self.__stableItem.setExpanded(True) 744 self.__stableItem.setExpanded(True)
701 parent = self.__stableItem 745 parent = self.__stableItem
702 elif status == "unstable": 746 elif status == "unstable":
703 if self.__unstableItem is None: 747 if self.__unstableItem is None:
704 self.__unstableItem = QTreeWidgetItem( 748 self.__unstableItem = QTreeWidgetItem(
705 self.repositoryList, [self.tr("Unstable")]) 749 self.repositoryList, [self.tr("Unstable")]
750 )
706 self.__unstableItem.setExpanded(True) 751 self.__unstableItem.setExpanded(True)
707 parent = self.__unstableItem 752 parent = self.__unstableItem
708 elif status == "obsolete": 753 elif status == "obsolete":
709 if self.__obsoleteItem is None: 754 if self.__obsoleteItem is None:
710 self.__obsoleteItem = QTreeWidgetItem( 755 self.__obsoleteItem = QTreeWidgetItem(
711 self.repositoryList, [self.tr("Obsolete")]) 756 self.repositoryList, [self.tr("Obsolete")]
757 )
712 self.__obsoleteItem.setExpanded(True) 758 self.__obsoleteItem.setExpanded(True)
713 parent = self.__obsoleteItem 759 parent = self.__obsoleteItem
714 else: 760 else:
715 if self.__unknownItem is None: 761 if self.__unknownItem is None:
716 self.__unknownItem = QTreeWidgetItem( 762 self.__unknownItem = QTreeWidgetItem(
717 self.repositoryList, [self.tr("Unknown")]) 763 self.repositoryList, [self.tr("Unknown")]
764 )
718 self.__unknownItem.setExpanded(True) 765 self.__unknownItem.setExpanded(True)
719 parent = self.__unknownItem 766 parent = self.__unknownItem
720 767
721 if self.__integratedWidget: 768 if self.__integratedWidget:
722 entryFormat = "<b>{0}</b> - Version: <i>{1}</i><br/>{2}" 769 entryFormat = "<b>{0}</b> - Version: <i>{1}</i><br/>{2}"
723 itm = QTreeWidgetItem(parent) 770 itm = QTreeWidgetItem(parent)
724 itm.setFirstColumnSpanned(True) 771 itm.setFirstColumnSpanned(True)
725 label = QLabel(entryFormat.format(name, version, short)) 772 label = QLabel(entryFormat.format(name, version, short))
726 self.repositoryList.setItemWidget(itm, 0, label) 773 self.repositoryList.setItemWidget(itm, 0, label)
727 else: 774 else:
728 itm = QTreeWidgetItem(parent, [name, version, short]) 775 itm = QTreeWidgetItem(parent, [name, version, short])
729 776
730 itm.setData(0, PluginRepositoryWidget.UrlRole, url) 777 itm.setData(0, PluginRepositoryWidget.UrlRole, url)
731 itm.setData(0, PluginRepositoryWidget.FilenameRole, filename) 778 itm.setData(0, PluginRepositoryWidget.FilenameRole, filename)
732 itm.setData(0, PluginRepositoryWidget.AuthorRole, author) 779 itm.setData(0, PluginRepositoryWidget.AuthorRole, author)
733 itm.setData(0, PluginRepositoryWidget.DescrRole, description) 780 itm.setData(0, PluginRepositoryWidget.DescrRole, description)
734 781
735 iconColumn = 0 if self.__integratedWidget else 1 782 iconColumn = 0 if self.__integratedWidget else 1
736 updateStatus = self.__updateStatus(filename, version) 783 updateStatus = self.__updateStatus(filename, version)
737 if updateStatus == PluginRepositoryWidget.PluginStatusUpToDate: 784 if updateStatus == PluginRepositoryWidget.PluginStatusUpToDate:
738 itm.setIcon(iconColumn, UI.PixmapCache.getIcon("empty")) 785 itm.setIcon(iconColumn, UI.PixmapCache.getIcon("empty"))
739 itm.setToolTip(iconColumn, self.tr("up-to-date")) 786 itm.setToolTip(iconColumn, self.tr("up-to-date"))
750 itm.setToolTip(iconColumn, self.tr("updated download available")) 797 itm.setToolTip(iconColumn, self.tr("updated download available"))
751 self.__updateRemoteItems += 1 798 self.__updateRemoteItems += 1
752 elif updateStatus == PluginRepositoryWidget.PluginStatusError: 799 elif updateStatus == PluginRepositoryWidget.PluginStatusError:
753 itm.setIcon(iconColumn, UI.PixmapCache.getIcon("warning")) 800 itm.setIcon(iconColumn, UI.PixmapCache.getIcon("warning"))
754 itm.setToolTip(iconColumn, self.tr("error determining status")) 801 itm.setToolTip(iconColumn, self.tr("error determining status"))
755 802
756 def __updateStatus(self, filename, version): 803 def __updateStatus(self, filename, version):
757 """ 804 """
758 Private method to check the given archive update status. 805 Private method to check the given archive update status.
759 806
760 @param filename data for the filename field (string) 807 @param filename data for the filename field (string)
761 @param version data for the version field (string) 808 @param version data for the version field (string)
762 @return plug-in update status (integer, one of PluginStatusNew, 809 @return plug-in update status (integer, one of PluginStatusNew,
763 PluginStatusUpToDate, PluginStatusLocalUpdate, 810 PluginStatusUpToDate, PluginStatusLocalUpdate,
764 PluginStatusRemoteUpdate) 811 PluginStatusRemoteUpdate)
765 """ 812 """
766 archive = os.path.join(Preferences.getPluginManager("DownloadPath"), 813 archive = os.path.join(Preferences.getPluginManager("DownloadPath"), filename)
767 filename) 814
768
769 # check, if it is an update (i.e. we already have archives 815 # check, if it is an update (i.e. we already have archives
770 # with the same pattern) 816 # with the same pattern)
771 archivesPattern = archive.rsplit('-', 1)[0] + "-*.zip" 817 archivesPattern = archive.rsplit("-", 1)[0] + "-*.zip"
772 if len(glob.glob(archivesPattern)) == 0: 818 if len(glob.glob(archivesPattern)) == 0:
773 # Check against installed/loaded plug-ins 819 # Check against installed/loaded plug-ins
774 pluginName = filename.rsplit('-', 1)[0] 820 pluginName = filename.rsplit("-", 1)[0]
775 pluginDetails = self.__pluginManager.getPluginDetails(pluginName) 821 pluginDetails = self.__pluginManager.getPluginDetails(pluginName)
776 if ( 822 if pluginDetails is None or pluginDetails["moduleName"] != pluginName:
777 pluginDetails is None or
778 pluginDetails["moduleName"] != pluginName
779 ):
780 return PluginRepositoryWidget.PluginStatusNew 823 return PluginRepositoryWidget.PluginStatusNew
781 if pluginDetails["error"]: 824 if pluginDetails["error"]:
782 return PluginRepositoryWidget.PluginStatusError 825 return PluginRepositoryWidget.PluginStatusError
783 pluginVersionTuple = Globals.versionToTuple( 826 pluginVersionTuple = Globals.versionToTuple(pluginDetails["version"])[:3]
784 pluginDetails["version"])[:3]
785 versionTuple = Globals.versionToTuple(version)[:3] 827 versionTuple = Globals.versionToTuple(version)[:3]
786 if pluginVersionTuple < versionTuple: 828 if pluginVersionTuple < versionTuple:
787 return PluginRepositoryWidget.PluginStatusRemoteUpdate 829 return PluginRepositoryWidget.PluginStatusRemoteUpdate
788 else: 830 else:
789 return PluginRepositoryWidget.PluginStatusUpToDate 831 return PluginRepositoryWidget.PluginStatusUpToDate
790 832
791 # check, if the archive exists 833 # check, if the archive exists
792 if not os.path.exists(archive): 834 if not os.path.exists(archive):
793 return PluginRepositoryWidget.PluginStatusRemoteUpdate 835 return PluginRepositoryWidget.PluginStatusRemoteUpdate
794 836
795 # check, if the archive is a valid zip file 837 # check, if the archive is a valid zip file
796 if not zipfile.is_zipfile(archive): 838 if not zipfile.is_zipfile(archive):
797 return PluginRepositoryWidget.PluginStatusRemoteUpdate 839 return PluginRepositoryWidget.PluginStatusRemoteUpdate
798 840
799 zipFile = zipfile.ZipFile(archive, "r") 841 zipFile = zipfile.ZipFile(archive, "r")
800 try: 842 try:
801 aversion = zipFile.read("VERSION").decode("utf-8") 843 aversion = zipFile.read("VERSION").decode("utf-8")
802 except KeyError: 844 except KeyError:
803 aversion = "" 845 aversion = ""
804 zipFile.close() 846 zipFile.close()
805 847
806 if aversion == version: 848 if aversion == version:
807 # Check against installed/loaded plug-ins 849 # Check against installed/loaded plug-ins
808 pluginName = filename.rsplit('-', 1)[0] 850 pluginName = filename.rsplit("-", 1)[0]
809 pluginDetails = self.__pluginManager.getPluginDetails(pluginName) 851 pluginDetails = self.__pluginManager.getPluginDetails(pluginName)
810 if pluginDetails is None: 852 if pluginDetails is None:
811 return PluginRepositoryWidget.PluginStatusLocalUpdate 853 return PluginRepositoryWidget.PluginStatusLocalUpdate
812 if ( 854 if (
813 Globals.versionToTuple(pluginDetails["version"])[:3] < 855 Globals.versionToTuple(pluginDetails["version"])[:3]
814 Globals.versionToTuple(version)[:3] 856 < Globals.versionToTuple(version)[:3]
815 ): 857 ):
816 return PluginRepositoryWidget.PluginStatusLocalUpdate 858 return PluginRepositoryWidget.PluginStatusLocalUpdate
817 else: 859 else:
818 return PluginRepositoryWidget.PluginStatusUpToDate 860 return PluginRepositoryWidget.PluginStatusUpToDate
819 else: 861 else:
820 return PluginRepositoryWidget.PluginStatusRemoteUpdate 862 return PluginRepositoryWidget.PluginStatusRemoteUpdate
821 863
822 def __sslErrors(self, reply, errors): 864 def __sslErrors(self, reply, errors):
823 """ 865 """
824 Private slot to handle SSL errors. 866 Private slot to handle SSL errors.
825 867
826 @param reply reference to the reply object (QNetworkReply) 868 @param reply reference to the reply object (QNetworkReply)
827 @param errors list of SSL errors (list of QSslError) 869 @param errors list of SSL errors (list of QSslError)
828 """ 870 """
829 ignored = self.__sslErrorHandler.sslErrorsReply(reply, errors)[0] 871 ignored = self.__sslErrorHandler.sslErrorsReply(reply, errors)[0]
830 if ignored == EricSslErrorState.NOT_IGNORED: 872 if ignored == EricSslErrorState.NOT_IGNORED:
831 self.__downloadCancel(reply) 873 self.__downloadCancel(reply)
832 874
833 def getDownloadedPlugins(self): 875 def getDownloadedPlugins(self):
834 """ 876 """
835 Public method to get the list of recently downloaded plugin files. 877 Public method to get the list of recently downloaded plugin files.
836 878
837 @return list of plugin filenames (list of strings) 879 @return list of plugin filenames (list of strings)
838 """ 880 """
839 return self.__pluginsDownloaded 881 return self.__pluginsDownloaded
840 882
841 @pyqtSlot(bool) 883 @pyqtSlot(bool)
842 def on_repositoryUrlEditButton_toggled(self, checked): 884 def on_repositoryUrlEditButton_toggled(self, checked):
843 """ 885 """
844 Private slot to set the read only status of the repository URL line 886 Private slot to set the read only status of the repository URL line
845 edit. 887 edit.
846 888
847 @param checked state of the push button (boolean) 889 @param checked state of the push button (boolean)
848 """ 890 """
849 self.repositoryUrlEdit.setReadOnly(not checked) 891 self.repositoryUrlEdit.setReadOnly(not checked)
850 892
851 def __closeAndInstall(self): 893 def __closeAndInstall(self):
852 """ 894 """
853 Private method to close the dialog and invoke the install dialog. 895 Private method to close the dialog and invoke the install dialog.
854 """ 896 """
855 if not self.__pluginsDownloaded and self.__selectedItems(): 897 if not self.__pluginsDownloaded and self.__selectedItems():
856 for itm in self.__selectedItems(): 898 for itm in self.__selectedItems():
857 filename = os.path.join( 899 filename = os.path.join(
858 Preferences.getPluginManager("DownloadPath"), 900 Preferences.getPluginManager("DownloadPath"),
859 itm.data(0, PluginRepositoryWidget.FilenameRole)) 901 itm.data(0, PluginRepositoryWidget.FilenameRole),
902 )
860 self.__pluginsDownloaded.append(filename) 903 self.__pluginsDownloaded.append(filename)
861 self.closeAndInstall.emit() 904 self.closeAndInstall.emit()
862 905
863 def __hidePlugin(self): 906 def __hidePlugin(self):
864 """ 907 """
865 Private slot to hide the current plug-in. 908 Private slot to hide the current plug-in.
866 """ 909 """
867 itm = self.__selectedItems()[0] 910 itm = self.__selectedItems()[0]
868 pluginName = (itm.data(0, PluginRepositoryWidget.FilenameRole) 911 pluginName = itm.data(0, PluginRepositoryWidget.FilenameRole).rsplit("-", 1)[0]
869 .rsplit("-", 1)[0])
870 self.__updateHiddenPluginsList([pluginName]) 912 self.__updateHiddenPluginsList([pluginName])
871 913
872 def __hideSelectedPlugins(self): 914 def __hideSelectedPlugins(self):
873 """ 915 """
874 Private slot to hide all selected plug-ins. 916 Private slot to hide all selected plug-ins.
875 """ 917 """
876 hideList = [] 918 hideList = []
877 for itm in self.__selectedItems(): 919 for itm in self.__selectedItems():
878 pluginName = (itm.data(0, PluginRepositoryWidget.FilenameRole) 920 pluginName = itm.data(0, PluginRepositoryWidget.FilenameRole).rsplit(
879 .rsplit("-", 1)[0]) 921 "-", 1
922 )[0]
880 hideList.append(pluginName) 923 hideList.append(pluginName)
881 self.__updateHiddenPluginsList(hideList) 924 self.__updateHiddenPluginsList(hideList)
882 925
883 def __showAllPlugins(self): 926 def __showAllPlugins(self):
884 """ 927 """
885 Private slot to show all plug-ins. 928 Private slot to show all plug-ins.
886 """ 929 """
887 self.__hiddenPlugins = [] 930 self.__hiddenPlugins = []
888 self.__updateHiddenPluginsList([]) 931 self.__updateHiddenPluginsList([])
889 932
890 def __hasHiddenPlugins(self): 933 def __hasHiddenPlugins(self):
891 """ 934 """
892 Private method to check, if there are any hidden plug-ins. 935 Private method to check, if there are any hidden plug-ins.
893 936
894 @return flag indicating the presence of hidden plug-ins (boolean) 937 @return flag indicating the presence of hidden plug-ins (boolean)
895 """ 938 """
896 return bool(self.__hiddenPlugins) 939 return bool(self.__hiddenPlugins)
897 940
898 def __updateHiddenPluginsList(self, hideList): 941 def __updateHiddenPluginsList(self, hideList):
899 """ 942 """
900 Private method to store the list of hidden plug-ins to the settings. 943 Private method to store the list of hidden plug-ins to the settings.
901 944
902 @param hideList list of plug-ins to add to the list of hidden ones 945 @param hideList list of plug-ins to add to the list of hidden ones
903 (list of string) 946 (list of string)
904 """ 947 """
905 if hideList: 948 if hideList:
906 self.__hiddenPlugins.extend( 949 self.__hiddenPlugins.extend(
907 [p for p in hideList if p not in self.__hiddenPlugins]) 950 [p for p in hideList if p not in self.__hiddenPlugins]
951 )
908 Preferences.setPluginManager("HiddenPlugins", self.__hiddenPlugins) 952 Preferences.setPluginManager("HiddenPlugins", self.__hiddenPlugins)
909 self.__populateList() 953 self.__populateList()
910 954
911 def __cleanupDownloads(self): 955 def __cleanupDownloads(self):
912 """ 956 """
913 Private slot to cleanup the plug-in downloads area. 957 Private slot to cleanup the plug-in downloads area.
914 """ 958 """
915 PluginRepositoryDownloadCleanup() 959 PluginRepositoryDownloadCleanup()
917 961
918 class PluginRepositoryDialog(QDialog): 962 class PluginRepositoryDialog(QDialog):
919 """ 963 """
920 Class for the dialog variant. 964 Class for the dialog variant.
921 """ 965 """
966
922 def __init__(self, pluginManager, parent=None): 967 def __init__(self, pluginManager, parent=None):
923 """ 968 """
924 Constructor 969 Constructor
925 970
926 @param pluginManager reference to the plugin manager object 971 @param pluginManager reference to the plugin manager object
927 @type PluginManager 972 @type PluginManager
928 @param parent reference to the parent widget 973 @param parent reference to the parent widget
929 @type QWidget 974 @type QWidget
930 """ 975 """
931 super().__init__(parent) 976 super().__init__(parent)
932 self.setSizeGripEnabled(True) 977 self.setSizeGripEnabled(True)
933 978
934 self.__layout = QVBoxLayout(self) 979 self.__layout = QVBoxLayout(self)
935 self.__layout.setContentsMargins(0, 0, 0, 0) 980 self.__layout.setContentsMargins(0, 0, 0, 0)
936 self.setLayout(self.__layout) 981 self.setLayout(self.__layout)
937 982
938 self.cw = PluginRepositoryWidget(pluginManager, parent=self) 983 self.cw = PluginRepositoryWidget(pluginManager, parent=self)
939 size = self.cw.size() 984 size = self.cw.size()
940 self.__layout.addWidget(self.cw) 985 self.__layout.addWidget(self.cw)
941 self.resize(size) 986 self.resize(size)
942 self.setWindowTitle(self.cw.windowTitle()) 987 self.setWindowTitle(self.cw.windowTitle())
943 988
944 self.cw.buttonBox.accepted.connect(self.accept) 989 self.cw.buttonBox.accepted.connect(self.accept)
945 self.cw.buttonBox.rejected.connect(self.reject) 990 self.cw.buttonBox.rejected.connect(self.reject)
946 self.cw.closeAndInstall.connect(self.__closeAndInstall) 991 self.cw.closeAndInstall.connect(self.__closeAndInstall)
947 992
948 def __closeAndInstall(self): 993 def __closeAndInstall(self):
949 """ 994 """
950 Private slot to handle the closeAndInstall signal. 995 Private slot to handle the closeAndInstall signal.
951 """ 996 """
952 self.done(QDialog.DialogCode.Accepted + 1) 997 self.done(QDialog.DialogCode.Accepted + 1)
953 998
954 def getDownloadedPlugins(self): 999 def getDownloadedPlugins(self):
955 """ 1000 """
956 Public method to get the list of recently downloaded plugin files. 1001 Public method to get the list of recently downloaded plugin files.
957 1002
958 @return list of plugin filenames (list of strings) 1003 @return list of plugin filenames (list of strings)
959 """ 1004 """
960 return self.cw.getDownloadedPlugins() 1005 return self.cw.getDownloadedPlugins()
961 1006
962 1007
963 class PluginRepositoryWindow(EricMainWindow): 1008 class PluginRepositoryWindow(EricMainWindow):
964 """ 1009 """
965 Main window class for the standalone dialog. 1010 Main window class for the standalone dialog.
966 """ 1011 """
1012
967 def __init__(self, parent=None): 1013 def __init__(self, parent=None):
968 """ 1014 """
969 Constructor 1015 Constructor
970 1016
971 @param parent reference to the parent widget (QWidget) 1017 @param parent reference to the parent widget (QWidget)
972 """ 1018 """
973 super().__init__(parent) 1019 super().__init__(parent)
974 self.cw = PluginRepositoryWidget(None, parent=self) 1020 self.cw = PluginRepositoryWidget(None, parent=self)
975 size = self.cw.size() 1021 size = self.cw.size()
976 self.setCentralWidget(self.cw) 1022 self.setCentralWidget(self.cw)
977 self.resize(size) 1023 self.resize(size)
978 self.setWindowTitle(self.cw.windowTitle()) 1024 self.setWindowTitle(self.cw.windowTitle())
979 1025
980 self.setStyle(Preferences.getUI("Style"), 1026 self.setStyle(Preferences.getUI("Style"), Preferences.getUI("StyleSheet"))
981 Preferences.getUI("StyleSheet")) 1027
982
983 self.cw.buttonBox.accepted.connect(self.close) 1028 self.cw.buttonBox.accepted.connect(self.close)
984 self.cw.buttonBox.rejected.connect(self.close) 1029 self.cw.buttonBox.rejected.connect(self.close)
985 self.cw.closeAndInstall.connect(self.__startPluginInstall) 1030 self.cw.closeAndInstall.connect(self.__startPluginInstall)
986 1031
987 def __startPluginInstall(self): 1032 def __startPluginInstall(self):
988 """ 1033 """
989 Private slot to start the eric plugin installation dialog. 1034 Private slot to start the eric plugin installation dialog.
990 """ 1035 """
991 proc = QProcess() 1036 proc = QProcess()
992 applPath = os.path.join(getConfig("ericDir"), "eric7_plugininstall.py") 1037 applPath = os.path.join(getConfig("ericDir"), "eric7_plugininstall.py")
993 1038
994 args = [] 1039 args = []
995 args.append(applPath) 1040 args.append(applPath)
996 args += self.cw.getDownloadedPlugins() 1041 args += self.cw.getDownloadedPlugins()
997 1042
998 if ( 1043 if not os.path.isfile(applPath) or not proc.startDetached(
999 not os.path.isfile(applPath) or 1044 Globals.getPythonExecutable(), args
1000 not proc.startDetached(Globals.getPythonExecutable(), args)
1001 ): 1045 ):
1002 EricMessageBox.critical( 1046 EricMessageBox.critical(
1003 self, 1047 self,
1004 self.tr('Process Generation Error'), 1048 self.tr("Process Generation Error"),
1005 self.tr( 1049 self.tr(
1006 '<p>Could not start the process.<br>' 1050 "<p>Could not start the process.<br>"
1007 'Ensure that it is available as <b>{0}</b>.</p>' 1051 "Ensure that it is available as <b>{0}</b>.</p>"
1008 ).format(applPath), 1052 ).format(applPath),
1009 self.tr('OK')) 1053 self.tr("OK"),
1010 1054 )
1055
1011 self.close() 1056 self.close()
1012 1057
1013 1058
1014 def PluginRepositoryDownloadCleanup(quiet=False): 1059 def PluginRepositoryDownloadCleanup(quiet=False):
1015 """ 1060 """
1016 Module function to clean up the plug-in downloads area. 1061 Module function to clean up the plug-in downloads area.
1017 1062
1018 @param quiet flag indicating quiet operations 1063 @param quiet flag indicating quiet operations
1019 @type bool 1064 @type bool
1020 """ 1065 """
1021 pluginsRegister = [] # list of plug-ins contained in the repository 1066 pluginsRegister = [] # list of plug-ins contained in the repository
1022 1067
1023 def registerPlugin(name, short, description, url, author, version, 1068 def registerPlugin(
1024 filename, status): 1069 name, short, description, url, author, version, filename, status
1070 ):
1025 """ 1071 """
1026 Method to register a plug-in's data. 1072 Method to register a plug-in's data.
1027 1073
1028 @param name data for the name field (string) 1074 @param name data for the name field (string)
1029 @param short data for the short field (string) 1075 @param short data for the short field (string)
1030 @param description data for the description field (list of strings) 1076 @param description data for the description field (list of strings)
1031 @param url data for the url field (string) 1077 @param url data for the url field (string)
1032 @param author data for the author field (string) 1078 @param author data for the author field (string)
1035 @param status status of the plugin (string [stable, unstable, unknown]) 1081 @param status status of the plugin (string [stable, unstable, unknown])
1036 """ 1082 """
1037 pluginName = os.path.splitext(url.rsplit("/", 1)[1])[0] 1083 pluginName = os.path.splitext(url.rsplit("/", 1)[1])[0]
1038 if pluginName not in pluginsRegister: 1084 if pluginName not in pluginsRegister:
1039 pluginsRegister.append(pluginName) 1085 pluginsRegister.append(pluginName)
1040 1086
1041 downloadPath = Preferences.getPluginManager("DownloadPath") 1087 downloadPath = Preferences.getPluginManager("DownloadPath")
1042 downloads = {} # plug-in name as key, file name as value 1088 downloads = {} # plug-in name as key, file name as value
1043 1089
1044 # step 1: extract plug-ins and downloaded files 1090 # step 1: extract plug-ins and downloaded files
1045 for pluginFile in os.listdir(downloadPath): 1091 for pluginFile in os.listdir(downloadPath):
1046 if not os.path.isfile(os.path.join(downloadPath, pluginFile)): 1092 if not os.path.isfile(os.path.join(downloadPath, pluginFile)):
1047 continue 1093 continue
1048 1094
1049 try: 1095 try:
1050 pluginName, pluginVersion = ( 1096 pluginName, pluginVersion = pluginFile.replace(".zip", "").rsplit("-", 1)
1051 pluginFile.replace(".zip", "").rsplit("-", 1)
1052 )
1053 pluginVersionList = re.split("[._-]", pluginVersion) 1097 pluginVersionList = re.split("[._-]", pluginVersion)
1054 for index in range(len(pluginVersionList)): 1098 for index in range(len(pluginVersionList)):
1055 try: 1099 try:
1056 pluginVersionList[index] = int(pluginVersionList[index]) 1100 pluginVersionList[index] = int(pluginVersionList[index])
1057 except ValueError: 1101 except ValueError:
1061 # rsplit() returned just one entry, i.e. file name doesn't contain 1105 # rsplit() returned just one entry, i.e. file name doesn't contain
1062 # version info separated by '-' 1106 # version info separated by '-'
1063 # => assume version 0.0.0 1107 # => assume version 0.0.0
1064 pluginName = pluginFile.replace(".zip", "") 1108 pluginName = pluginFile.replace(".zip", "")
1065 pluginVersionList = [0, 0, 0] 1109 pluginVersionList = [0, 0, 0]
1066 1110
1067 if pluginName not in downloads: 1111 if pluginName not in downloads:
1068 downloads[pluginName] = [] 1112 downloads[pluginName] = []
1069 downloads[pluginName].append((pluginFile, tuple(pluginVersionList))) 1113 downloads[pluginName].append((pluginFile, tuple(pluginVersionList)))
1070 1114
1071 # step 2: delete old entries 1115 # step 2: delete old entries
1072 hiddenPlugins = Preferences.getPluginManager("HiddenPlugins") 1116 hiddenPlugins = Preferences.getPluginManager("HiddenPlugins")
1073 for pluginName in downloads: 1117 for pluginName in downloads:
1074 downloads[pluginName].sort(key=lambda x: x[1]) 1118 downloads[pluginName].sort(key=lambda x: x[1])
1075 1119
1076 removeFiles = ( 1120 removeFiles = (
1077 [f[0] for f in downloads[pluginName]] 1121 [f[0] for f in downloads[pluginName]]
1078 if (pluginName in hiddenPlugins and 1122 if (
1079 not Preferences.getPluginManager("KeepHidden")) else 1123 pluginName in hiddenPlugins
1080 [f[0] for f in downloads[pluginName][ 1124 and not Preferences.getPluginManager("KeepHidden")
1081 :-Preferences.getPluginManager("KeepGenerations")]] 1125 )
1126 else [
1127 f[0]
1128 for f in downloads[pluginName][
1129 : -Preferences.getPluginManager("KeepGenerations")
1130 ]
1131 ]
1082 ) 1132 )
1083 for removeFile in removeFiles: 1133 for removeFile in removeFiles:
1084 try: 1134 try:
1085 os.remove(os.path.join(downloadPath, removeFile)) 1135 os.remove(os.path.join(downloadPath, removeFile))
1086 except OSError as err: 1136 except OSError as err:
1087 if not quiet: 1137 if not quiet:
1088 EricMessageBox.critical( 1138 EricMessageBox.critical(
1089 None, 1139 None,
1090 QCoreApplication.translate( 1140 QCoreApplication.translate(
1091 "PluginRepositoryWidget", 1141 "PluginRepositoryWidget", "Cleanup of Plugin Downloads"
1092 "Cleanup of Plugin Downloads"), 1142 ),
1093 QCoreApplication.translate( 1143 QCoreApplication.translate(
1094 "PluginRepositoryWidget", 1144 "PluginRepositoryWidget",
1095 """<p>The plugin download <b>{0}</b> could""" 1145 """<p>The plugin download <b>{0}</b> could"""
1096 """ not be deleted.</p><p>Reason: {1}</p>""") 1146 """ not be deleted.</p><p>Reason: {1}</p>""",
1097 .format(removeFile, str(err))) 1147 ).format(removeFile, str(err)),
1098 1148 )
1149
1099 # step 3: delete entries of obsolete plug-ins 1150 # step 3: delete entries of obsolete plug-ins
1100 pluginRepositoryFile = os.path.join(Utilities.getConfigDir(), 1151 pluginRepositoryFile = os.path.join(Utilities.getConfigDir(), "PluginRepository")
1101 "PluginRepository")
1102 if os.path.exists(pluginRepositoryFile): 1152 if os.path.exists(pluginRepositoryFile):
1103 f = QFile(pluginRepositoryFile) 1153 f = QFile(pluginRepositoryFile)
1104 if f.open(QIODevice.OpenModeFlag.ReadOnly): 1154 if f.open(QIODevice.OpenModeFlag.ReadOnly):
1105 from EricXML.PluginRepositoryReader import PluginRepositoryReader 1155 from EricXML.PluginRepositoryReader import PluginRepositoryReader
1156
1106 reader = PluginRepositoryReader(f, registerPlugin) 1157 reader = PluginRepositoryReader(f, registerPlugin)
1107 reader.readXML() 1158 reader.readXML()
1108 1159
1109 for pluginName in downloads: 1160 for pluginName in downloads:
1110 if pluginName not in pluginsRegister: 1161 if pluginName not in pluginsRegister:
1111 removeFiles = [f[0] for f in downloads[pluginName]] 1162 removeFiles = [f[0] for f in downloads[pluginName]]
1112 for removeFile in removeFiles: 1163 for removeFile in removeFiles:
1113 try: 1164 try:
1116 if not quiet: 1167 if not quiet:
1117 EricMessageBox.critical( 1168 EricMessageBox.critical(
1118 None, 1169 None,
1119 QCoreApplication.translate( 1170 QCoreApplication.translate(
1120 "PluginRepositoryWidget", 1171 "PluginRepositoryWidget",
1121 "Cleanup of Plugin Downloads"), 1172 "Cleanup of Plugin Downloads",
1173 ),
1122 QCoreApplication.translate( 1174 QCoreApplication.translate(
1123 "PluginRepositoryWidget", 1175 "PluginRepositoryWidget",
1124 "<p>The plugin download <b>{0}</b>" 1176 "<p>The plugin download <b>{0}</b>"
1125 " could not be deleted.</p>" 1177 " could not be deleted.</p>"
1126 "<p>Reason: {1}</p>""") 1178 "<p>Reason: {1}</p>"
1127 .format(removeFile, str(err))) 1179 "",
1180 ).format(removeFile, str(err)),
1181 )

eric ide

mercurial