# -*- coding: utf-8 -*- """ *************************************************************************** GetScriptsAndModels.py --------------------- Date : June 2014 Copyright : (C) 2014 by Victor Olaya Email : volayaf at gmail dot com *************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * *************************************************************************** """ __author__ = 'Victor Olaya' __date__ = 'June 2014' __copyright__ = '(C) 201, Victor Olaya' # This will get replaced with a git SHA1 when you do a git archive __revision__ = '$Format:%H$' import os import json import urllib2 from urllib2 import HTTPError from PyQt4.QtCore import * from PyQt4.QtGui import * from processing.gui.ToolboxAction import ToolboxAction from PyQt4 import QtGui from processing.ui.ui_DlgGetScriptsAndModels import Ui_DlgGetScriptsAndModels from processing.script.ScriptUtils import ScriptUtils from processing.modeler.ModelerUtils import ModelerUtils from processing.gui import Help2Html from qgis.utils import iface from processing.gui.Help2Html import getDescription, ALG_DESC, ALG_VERSION, ALG_CREATOR class GetScriptsAction(ToolboxAction): def __init__(self): self.name = self.tr('Get scripts from on-line scripts collection', 'GetScriptsAction') self.group = self.tr('Tools', 'GetScriptsAction') def getIcon(self): return QIcon(':/processing/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')) class GetModelsAction(ToolboxAction): def __init__(self): self.name = self.tr('Get models from on-line scripts collection', 'GetModelsAction') self.group = self.tr('Tools', 'GetModelsAction') def getIcon(self): return QIcon(':/processing/images/model.png') def execute(self): try: dlg = GetScriptsAndModelsDialog(GetScriptsAndModelsDialog.MODELS) dlg.exec_() if dlg.updateToolbox: self.toolbox.updateProvider('model') except HTTPError: 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() class GetScriptsAndModelsDialog(QDialog, Ui_DlgGetScriptsAndModels): HELP_TEXT = QCoreApplication.translate('GetScriptsAndModelsDialog', '

Processing resources manager

' '

Check/uncheck algorithms in the tree to select the ones that you ' 'want to install or remove

' '

Algorithms are divided in 3 groups:

' '') MODELS = 0 SCRIPTS = 1 def __init__(self, resourceType): QDialog.__init__(self, iface.mainWindow()) self.resourceType = resourceType if self.resourceType == self.MODELS: self.folder = ModelerUtils.modelsFolder() self.urlBase = 'https://raw.githubusercontent.com/qgis/QGIS-Processing/master/models/' self.icon = QtGui.QIcon(os.path.dirname(__file__) + '/../images/model.png') else: self.folder = ScriptUtils.scriptsFolder() self.urlBase = 'https://raw.githubusercontent.com/qgis/QGIS-Processing/master/scripts/' self.icon = QtGui.QIcon(os.path.dirname(__file__) + '/../images/script.png') self.lastSelectedItem = None self.setupUi(self) self.populateTree() self.updateToolbox = False self.buttonBox.accepted.connect(self.okPressed) self.buttonBox.rejected.connect(self.cancelPressed) self.tree.currentItemChanged .connect(self.currentItemChanged) def populateTree(self): self.uptodateItem = QTreeWidgetItem() self.uptodateItem.setText(0, self.tr('Installed')) self.toupdateItem = QTreeWidgetItem() self.toupdateItem.setText(0, self.tr('Updatable')) self.notinstalledItem = QTreeWidgetItem() self.notinstalledItem.setText(0, self.tr('Not installed')) 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 resources: 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.tree.addTopLevelItem(self.toupdateItem) self.tree.addTopLevelItem(self.notinstalledItem) self.tree.addTopLevelItem(self.uptodateItem) self.webView.setHtml(self.HELP_TEXT) 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 = '

%s

' % item.name html += self.tr('

Description: %s

') % getDescription(ALG_DESC, descriptions) html += self.tr('

Created by: %s') % getDescription(ALG_CREATOR, descriptions) html += self.tr('

Version: %s') % getDescription(ALG_VERSION, descriptions) except HTTPError, e: html = self.tr('

No detailed description available for this script

') self.webView.setHtml(html) else: self.webView.setHtml(self.HELP_TEXT) def getTreeBranchForState(self, filename, version): if not os.path.exists(os.path.join(self.folder, filename)): return self.notinstalledItem else: helpFile = os.path.join(self.folder, filename + '.help') try: with open(helpFile) as f: helpContent = json.load(f) currentVersion = float(helpContent[Help2Html.ALG_VERSION]) except Exception: currentVersion = 0 if version > currentVersion: return self.toupdateItem else: return self.uptodateItem def cancelPressed(self): self.close() def okPressed(self): toDownload = [] for i in xrange(self.toupdateItem.childCount()): item = self.toupdateItem.child(i) if item.checkState(0) == Qt.Checked: toDownload.append(item.filename) for i in xrange(self.notinstalledItem.childCount()): item = self.notinstalledItem.child(i) if item.checkState(0) == Qt.Checked: toDownload.append(item.filename) if toDownload: self.progressBar.setMaximum(len(toDownload)) 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 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) toDelete = [] for i in xrange(self.uptodateItem.childCount()): item = self.uptodateItem.child(i) if item.checkState(0) == Qt.Unchecked: toDelete.append(item.filename) for filename in toDelete: path = os.path.join(self.folder, filename) os.remove(path) self.updateToolbox = len(toDownload) + len(toDelete)> 0 self.close() class TreeItem(QTreeWidgetItem): def __init__(self, filename, name, icon): QTreeWidgetItem.__init__(self) self.name = name self.filename = filename self.setText(0, name) self.setIcon(0, icon) self.setCheckState(0, Qt.Unchecked)