# -*- 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 Qt, QCoreApplication from PyQt4.QtGui import QIcon, QMessageBox, QCursor, QApplication, QDialog, QTreeWidgetItem from qgis.utils import iface from processing.gui.ToolboxAction import ToolboxAction from processing.script.ScriptUtils import ScriptUtils from processing.modeler.ModelerUtils import ModelerUtils from processing.gui import Help2Html from processing.gui.Help2Html import getDescription, ALG_DESC, ALG_VERSION, ALG_CREATOR from processing.ui.ui_DlgGetScriptsAndModels import Ui_DlgGetScriptsAndModels pluginPath = os.path.split(os.path.dirname(__file__))[0] 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(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')) 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(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: 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 = QIcon(os.path.join(pluginPath, 'images', 'model.png')) else: self.folder = ScriptUtils.scriptsFolder() self.urlBase = 'https://raw.githubusercontent.com/qgis/QGIS-Processing/master/scripts/' self.icon = QIcon(os.path.join(pluginPath, '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)