mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -04:00
[Processing] Add proxy support for Get scripts and models (fixes #13412)
This commit is contained in:
parent
fe6456f86e
commit
f2e527f033
@ -20,7 +20,7 @@
|
||||
|
||||
__author__ = 'Victor Olaya'
|
||||
__date__ = 'June 2014'
|
||||
__copyright__ = '(C) 201, Victor Olaya'
|
||||
__copyright__ = '(C) 2014, Victor Olaya'
|
||||
|
||||
# This will get replaced with a git SHA1 when you do a git archive
|
||||
|
||||
@ -28,14 +28,16 @@ __revision__ = '$Format:%H$'
|
||||
|
||||
import os
|
||||
import json
|
||||
import urllib2
|
||||
from urllib2 import HTTPError
|
||||
from functools import partial
|
||||
|
||||
from PyQt4 import uic
|
||||
from PyQt4.QtCore import Qt, QCoreApplication
|
||||
from PyQt4.QtGui import QIcon, QMessageBox, QCursor, QApplication, QTreeWidgetItem
|
||||
from PyQt4.QtCore import Qt, QCoreApplication, QUrl
|
||||
from PyQt4.QtGui import QIcon, QCursor, QApplication, QTreeWidgetItem, QPushButton
|
||||
from PyQt4.QtNetwork import QNetworkReply, QNetworkRequest
|
||||
|
||||
from qgis.utils import iface
|
||||
from qgis.utils import iface, show_message_log
|
||||
from qgis.core import QgsNetworkAccessManager, QgsMessageLog
|
||||
from qgis.gui import QgsMessageBar
|
||||
|
||||
from processing.gui.ToolboxAction import ToolboxAction
|
||||
from processing.script.ScriptUtils import ScriptUtils
|
||||
@ -48,7 +50,6 @@ pluginPath = os.path.split(os.path.dirname(__file__))[0]
|
||||
WIDGET, BASE = uic.loadUiType(
|
||||
os.path.join(pluginPath, 'ui', 'DlgGetScriptsAndModels.ui'))
|
||||
|
||||
|
||||
class GetScriptsAction(ToolboxAction):
|
||||
|
||||
def __init__(self):
|
||||
@ -59,15 +60,10 @@ class GetScriptsAction(ToolboxAction):
|
||||
return QIcon(os.path.join(pluginPath, 'images', 'script.png'))
|
||||
|
||||
def execute(self):
|
||||
try:
|
||||
dlg = GetScriptsAndModelsDialog(GetScriptsAndModelsDialog.SCRIPTS)
|
||||
dlg.exec_()
|
||||
if dlg.updateToolbox:
|
||||
self.toolbox.updateProvider('script')
|
||||
except HTTPError:
|
||||
QMessageBox.critical(iface.mainWindow(),
|
||||
self.tr('Connection problem', 'GetScriptsAction'),
|
||||
self.tr('Could not connect to scripts/models repository', 'GetScriptsAction'))
|
||||
dlg = GetScriptsAndModelsDialog(GetScriptsAndModelsDialog.SCRIPTS)
|
||||
dlg.exec_()
|
||||
if dlg.updateToolbox:
|
||||
self.toolbox.updateProvider('script')
|
||||
|
||||
|
||||
class GetRScriptsAction(ToolboxAction):
|
||||
@ -80,15 +76,10 @@ class GetRScriptsAction(ToolboxAction):
|
||||
return QIcon(os.path.join(pluginPath, 'images', 'r.png'))
|
||||
|
||||
def execute(self):
|
||||
try:
|
||||
dlg = GetScriptsAndModelsDialog(GetScriptsAndModelsDialog.RSCRIPTS)
|
||||
dlg.exec_()
|
||||
if dlg.updateToolbox:
|
||||
self.toolbox.updateProvider('r')
|
||||
except HTTPError:
|
||||
QMessageBox.critical(iface.mainWindow(),
|
||||
self.tr('Connection problem', 'GetRScriptsAction'),
|
||||
self.tr('Could not connect to scripts/models repository', 'GetRScriptsAction'))
|
||||
dlg = GetScriptsAndModelsDialog(GetScriptsAndModelsDialog.RSCRIPTS)
|
||||
dlg.exec_()
|
||||
if dlg.updateToolbox:
|
||||
self.toolbox.updateProvider('r')
|
||||
|
||||
|
||||
class GetModelsAction(ToolboxAction):
|
||||
@ -101,23 +92,10 @@ class GetModelsAction(ToolboxAction):
|
||||
return QIcon(os.path.join(pluginPath, 'images', 'model.png'))
|
||||
|
||||
def execute(self):
|
||||
try:
|
||||
dlg = GetScriptsAndModelsDialog(GetScriptsAndModelsDialog.MODELS)
|
||||
dlg.exec_()
|
||||
if dlg.updateToolbox:
|
||||
self.toolbox.updateProvider('model')
|
||||
except (HTTPError, URLError):
|
||||
QMessageBox.critical(iface.mainWindow(),
|
||||
self.tr('Connection problem', 'GetModelsAction'),
|
||||
self.tr('Could not connect to scripts/models repository', 'GetModelsAction'))
|
||||
|
||||
|
||||
def readUrl(url):
|
||||
try:
|
||||
QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
|
||||
return urllib2.urlopen(url).read()
|
||||
finally:
|
||||
QApplication.restoreOverrideCursor()
|
||||
dlg = GetScriptsAndModelsDialog(GetScriptsAndModelsDialog.MODELS)
|
||||
dlg.exec_()
|
||||
if dlg.updateToolbox:
|
||||
self.toolbox.updateProvider('model')
|
||||
|
||||
|
||||
class GetScriptsAndModelsDialog(BASE, WIDGET):
|
||||
@ -137,9 +115,14 @@ class GetScriptsAndModelsDialog(BASE, WIDGET):
|
||||
SCRIPTS = 1
|
||||
RSCRIPTS = 2
|
||||
|
||||
tr_disambiguation = { 0: 'GetModelsAction',
|
||||
1: 'GetScriptsAction',
|
||||
2: 'GetRScriptsAction' }
|
||||
|
||||
def __init__(self, resourceType):
|
||||
super(GetScriptsAndModelsDialog, self).__init__(iface.mainWindow())
|
||||
self.setupUi(self)
|
||||
self.manager = QgsNetworkAccessManager.instance()
|
||||
|
||||
self.resourceType = resourceType
|
||||
if self.resourceType == self.MODELS:
|
||||
@ -160,8 +143,30 @@ class GetScriptsAndModelsDialog(BASE, WIDGET):
|
||||
self.populateTree()
|
||||
self.buttonBox.accepted.connect(self.okPressed)
|
||||
self.buttonBox.rejected.connect(self.cancelPressed)
|
||||
self.tree.currentItemChanged .connect(self.currentItemChanged)
|
||||
self.tree.currentItemChanged.connect(self.currentItemChanged)
|
||||
|
||||
def popupError(self, error=None, url=None):
|
||||
"""Popups an Error message bar for network errors."""
|
||||
disambiguation = self.tr_disambiguation[self.resourceType]
|
||||
widget = iface.messageBar().createMessage(self.tr('Connection problem', disambiguation),
|
||||
self.tr('Could not connect to scripts/models repository', disambiguation))
|
||||
if error and url:
|
||||
QgsMessageLog.logMessage(self.tr(u"Network error code: {} on URL: {}").format(error, url), u"Processing", QgsMessageLog.CRITICAL)
|
||||
button = QPushButton(QCoreApplication.translate("Python", "View message log"), pressed=show_message_log)
|
||||
widget.layout().addWidget(button)
|
||||
|
||||
iface.messageBar().pushWidget(widget, level=QgsMessageBar.CRITICAL, duration=5)
|
||||
|
||||
def grabHTTP(self, url, loadFunction, arguments=None):
|
||||
"""Grab distant content via QGIS internal classes and QtNetwork."""
|
||||
QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
|
||||
request = QUrl(url)
|
||||
reply = self.manager.get(QNetworkRequest(request))
|
||||
if arguments:
|
||||
reply.finished.connect(partial(loadFunction, reply, arguments))
|
||||
else:
|
||||
reply.finished.connect(partial(loadFunction, reply))
|
||||
|
||||
def populateTree(self):
|
||||
self.uptodateItem = QTreeWidgetItem()
|
||||
self.uptodateItem.setText(0, self.tr('Installed'))
|
||||
@ -172,35 +177,53 @@ class GetScriptsAndModelsDialog(BASE, WIDGET):
|
||||
self.toupdateItem.setIcon(0, self.icon)
|
||||
self.uptodateItem.setIcon(0, self.icon)
|
||||
self.notinstalledItem.setIcon(0, self.icon)
|
||||
resources = readUrl(self.urlBase + 'list.txt').splitlines()
|
||||
resources = [r.split(',') for r in resources]
|
||||
self.resources = {f: (v, n) for f, v, n in resources}
|
||||
for filename, version, name in sorted(resources, key=lambda kv: kv[2].lower()):
|
||||
treeBranch = self.getTreeBranchForState(filename, float(version))
|
||||
item = TreeItem(filename, name, self.icon)
|
||||
treeBranch.addChild(item)
|
||||
if treeBranch != self.notinstalledItem:
|
||||
item.setCheckState(0, Qt.Checked)
|
||||
self.grabHTTP(self.urlBase + 'list.txt', self.treeLoaded)
|
||||
|
||||
def treeLoaded(self, reply):
|
||||
"""
|
||||
update the tree of scripts/models whenever
|
||||
HTTP request is finished
|
||||
"""
|
||||
QApplication.restoreOverrideCursor()
|
||||
if reply.error() != QNetworkReply.NoError:
|
||||
self.popupError(reply.error(), reply.request().url().toString())
|
||||
else:
|
||||
resources = unicode(reply.readAll()).splitlines()
|
||||
resources = [r.split(',') for r in resources]
|
||||
self.resources = {f: (v, n) for f, v, n in resources}
|
||||
for filename, version, name in sorted(resources, key=lambda kv: kv[2].lower()):
|
||||
treeBranch = self.getTreeBranchForState(filename, float(version))
|
||||
item = TreeItem(filename, name, self.icon)
|
||||
treeBranch.addChild(item)
|
||||
if treeBranch != self.notinstalledItem:
|
||||
item.setCheckState(0, Qt.Checked)
|
||||
|
||||
reply.deleteLater()
|
||||
self.tree.addTopLevelItem(self.toupdateItem)
|
||||
self.tree.addTopLevelItem(self.notinstalledItem)
|
||||
self.tree.addTopLevelItem(self.uptodateItem)
|
||||
|
||||
self.webView.setHtml(self.HELP_TEXT)
|
||||
|
||||
def setHelp(self, reply, item):
|
||||
"""Change the webview HTML content"""
|
||||
QApplication.restoreOverrideCursor()
|
||||
if reply.error() != QNetworkReply.NoError:
|
||||
html = self.tr('<h2>No detailed description available for this script</h2>')
|
||||
else:
|
||||
content = unicode(reply.readAll())
|
||||
descriptions = json.loads(content)
|
||||
html = '<h2>%s</h2>' % item.name
|
||||
html += self.tr('<p><b>Description:</b> %s</p>') % getDescription(ALG_DESC, descriptions)
|
||||
html += self.tr('<p><b>Created by:</b> %s') % getDescription(ALG_CREATOR, descriptions)
|
||||
html += self.tr('<p><b>Version:</b> %s') % getDescription(ALG_VERSION, descriptions)
|
||||
reply.deleteLater()
|
||||
self.webView.setHtml(html)
|
||||
|
||||
def currentItemChanged(self, item, prev):
|
||||
if isinstance(item, TreeItem):
|
||||
try:
|
||||
url = self.urlBase + item.filename.replace(' ', '%20') + '.help'
|
||||
helpContent = readUrl(url)
|
||||
descriptions = json.loads(helpContent)
|
||||
html = '<h2>%s</h2>' % item.name
|
||||
html += self.tr('<p><b>Description:</b> %s</p>') % getDescription(ALG_DESC, descriptions)
|
||||
html += self.tr('<p><b>Created by:</b> %s') % getDescription(ALG_CREATOR, descriptions)
|
||||
html += self.tr('<p><b>Version:</b> %s') % getDescription(ALG_VERSION, descriptions)
|
||||
except HTTPError as e:
|
||||
html = self.tr('<h2>No detailed description available for this script</h2>')
|
||||
self.webView.setHtml(html)
|
||||
url = self.urlBase + item.filename.replace(' ', '%20') + '.help'
|
||||
self.grabHTTP(url, self.setHelp, item)
|
||||
else:
|
||||
self.webView.setHtml(self.HELP_TEXT)
|
||||
|
||||
@ -223,6 +246,26 @@ class GetScriptsAndModelsDialog(BASE, WIDGET):
|
||||
def cancelPressed(self):
|
||||
self.close()
|
||||
|
||||
def storeFile(self, reply, filename):
|
||||
"""store a script/model that has been downloaded"""
|
||||
QApplication.restoreOverrideCursor()
|
||||
if reply.error() != QNetworkReply.NoError:
|
||||
if os.path.splitext(filename)[1].lower() == '.help':
|
||||
content = '{"ALG_VERSION" : %s}' % self.resources[filename[:-5]][0]
|
||||
else:
|
||||
self.popupError(reply.error(), reply.request().url().toString())
|
||||
content = None
|
||||
else:
|
||||
content = reply.readAll()
|
||||
|
||||
reply.deleteLater()
|
||||
if content:
|
||||
path = os.path.join(self.folder, filename)
|
||||
with open(path, 'w') as f:
|
||||
f.write(content)
|
||||
|
||||
self.progressBar.setValue(self.progressBar.value() + 1)
|
||||
|
||||
def okPressed(self):
|
||||
toDownload = []
|
||||
for i in xrange(self.toupdateItem.childCount()):
|
||||
@ -235,39 +278,27 @@ class GetScriptsAndModelsDialog(BASE, WIDGET):
|
||||
toDownload.append(item.filename)
|
||||
|
||||
if toDownload:
|
||||
self.progressBar.setMaximum(len(toDownload))
|
||||
self.progressBar.setMaximum(len(toDownload) * 2)
|
||||
for i, filename in enumerate(toDownload):
|
||||
QCoreApplication.processEvents()
|
||||
url = self.urlBase + filename.replace(' ', '%20')
|
||||
try:
|
||||
code = readUrl(url)
|
||||
path = os.path.join(self.folder, filename)
|
||||
with open(path, 'w') as f:
|
||||
f.write(code)
|
||||
except HTTPError:
|
||||
QMessageBox.critical(iface.mainWindow(),
|
||||
self.tr('Connection problem'),
|
||||
self.tr('Could not download file: %s') % filename)
|
||||
return
|
||||
self.grabHTTP(url, self.storeFile, filename)
|
||||
|
||||
url += '.help'
|
||||
try:
|
||||
html = readUrl(url)
|
||||
except HTTPError:
|
||||
html = '{"ALG_VERSION" : %s}' % self.resources[filename][0]
|
||||
|
||||
path = os.path.join(self.folder, filename + '.help')
|
||||
with open(path, 'w') as f:
|
||||
f.write(html)
|
||||
self.progressBar.setValue(i + 1)
|
||||
self.grabHTTP(url, self.storeFile, filename + '.help')
|
||||
|
||||
toDelete = []
|
||||
for i in xrange(self.uptodateItem.childCount()):
|
||||
item = self.uptodateItem.child(i)
|
||||
if item.checkState(0) == Qt.Unchecked:
|
||||
toDelete.append(item.filename)
|
||||
|
||||
# Remove py and help files if they exist
|
||||
for filename in toDelete:
|
||||
path = os.path.join(self.folder, filename)
|
||||
os.remove(path)
|
||||
for pathname in (filename, filename + u".help"):
|
||||
path = os.path.join(self.folder, pathname)
|
||||
if os.path.exists(path):
|
||||
os.remove(path)
|
||||
|
||||
self.updateToolbox = len(toDownload) + len(toDelete) > 0
|
||||
self.close()
|
||||
|
Loading…
x
Reference in New Issue
Block a user