1
+ # -*- coding: utf-8 -*-
2
+
3
+ """
4
+ ***************************************************************************
5
+ GetScriptsAndModels.py
6
+ ---------------------
7
+ Date : June 2014
8
+ Copyright : (C) 2014 by Victor Olaya
9
+ Email : volayaf at gmail dot com
10
+ ***************************************************************************
11
+ * *
12
+ * This program is free software; you can redistribute it and/or modify *
13
+ * it under the terms of the GNU General Public License as published by *
14
+ * the Free Software Foundation; either version 2 of the License, or *
15
+ * (at your option) any later version. *
16
+ * *
17
+ ***************************************************************************
18
+ """
19
+ import os
20
+ from PyQt4 import QtGui
21
+ from processing .ui .ui_DlgGetScriptsAndModels import Ui_DlgGetScriptsAndModels
22
+ from processing .script .ScriptUtils import ScriptUtils
23
+ from processing .modeler .ModelerUtils import ModelerUtils
24
+ import json
25
+ from processing .gui import Help2Html
26
+ from qgis .utils import iface
27
+ from processing .gui .Help2Html import getDescription , ALG_DESC , ALG_VERSION ,\
28
+ ALG_CREATOR
29
+
30
+ __author__ = 'Victor Olaya'
31
+ __date__ = 'June 2014'
32
+ __copyright__ = '(C) 201, Victor Olaya'
33
+
34
+ # This will get replaced with a git SHA1 when you do a git archive
35
+
36
+ __revision__ = '$Format:%H$'
37
+
38
+ import urllib2
39
+ from urllib2 import HTTPError
40
+ from PyQt4 .QtCore import *
41
+ from PyQt4 .QtGui import *
42
+ from processing .gui .ToolboxAction import ToolboxAction
43
+
44
+
45
+ class GetScriptsAction (ToolboxAction ):
46
+
47
+ def __init__ (self ):
48
+ self .name = "Get scripts from on-line scripts collection"
49
+ self .group = 'Tools'
50
+
51
+ def getIcon (self ):
52
+ return QIcon (':/processing/images/script.png' )
53
+
54
+ def execute (self ):
55
+ try :
56
+ dlg = GetScriptsAndModelsDialog (GetScriptsAndModelsDialog .SCRIPTS )
57
+ dlg .exec_ ()
58
+ if dlg .updateToolbox :
59
+ self .toolbox .updateProvider ('script' )
60
+
61
+ except HTTPError :
62
+ QMessageBox .critical (iface .mainWindow (), "Connection problem" , "Could not connect to scripts/models repository" )
63
+
64
+ class GetModelsAction (ToolboxAction ):
65
+
66
+ def __init__ (self ):
67
+ self .name = "Get models from on-line scripts collection"
68
+ self .group = 'Tools'
69
+
70
+ def getIcon (self ):
71
+ return QIcon (':/processing/images/model.png' )
72
+
73
+ def execute (self ):
74
+ try :
75
+ dlg = GetScriptsAndModelsDialog (GetScriptsAndModelsDialog .MODELS )
76
+ dlg .exec_ ()
77
+ if dlg .updateToolbox :
78
+ self .toolbox .updateProvider ('model' )
79
+ except HTTPError :
80
+ QMessageBox .critical (iface .mainWindow (), "Connection problem" , "Could not connect to scripts/models repository" )
81
+
82
+
83
+ def readUrl (url ):
84
+ try :
85
+ QApplication .setOverrideCursor (QCursor (Qt .WaitCursor ))
86
+ return urllib2 .urlopen (url ).read ()
87
+ finally :
88
+ QApplication .restoreOverrideCursor ()
89
+
90
+
91
+ class GetScriptsAndModelsDialog (QDialog , Ui_DlgGetScriptsAndModels ):
92
+
93
+ HELP_TEXT = ("<h3> Processing resources manager </h3>"
94
+ "<p>Check/uncheck algorithms in the tree to select the ones that you want to install or remove</p>"
95
+ "<p>Algorithms are divided in 3 groups:</p>"
96
+ "<ul><li><b>Installed:</b> Algorihms already in your system, with the latest version available</li>"
97
+ "<li><b>Upgradable:</b> Algorihms already in your system, but with a newer version available in the server</li>"
98
+ "<li><b>Not installed:</b> Algorithms not installed in your system</li></ul>" )
99
+ MODELS = 0
100
+ SCRIPTS = 1
101
+
102
+ def __init__ (self , resourceType ):
103
+ QDialog .__init__ (self , iface .mainWindow ())
104
+ self .resourceType = resourceType
105
+ if self .resourceType == self .MODELS :
106
+ self .folder = ModelerUtils .modelsFolder ()
107
+ self .urlBase = "https://raw.githubusercontent.com/qgis/QGIS-Processing/master/models/"
108
+ self .icon = QtGui .QIcon (os .path .dirname (__file__ ) + '/../images/model.png' )
109
+ else :
110
+ self .folder = ScriptUtils .scriptsFolder ()
111
+ self .urlBase = "https://raw.githubusercontent.com/qgis/QGIS-Processing/master/scripts/"
112
+ self .icon = QtGui .QIcon (os .path .dirname (__file__ ) + '/../images/script.png' )
113
+ self .lastSelectedItem = None
114
+ self .setupUi (self )
115
+ self .populateTree ()
116
+ self .updateToolbox = False
117
+ self .buttonBox .accepted .connect (self .okPressed )
118
+ self .buttonBox .rejected .connect (self .cancelPressed )
119
+ self .tree .currentItemChanged .connect (self .currentItemChanged )
120
+
121
+ def populateTree (self ):
122
+ self .uptodateItem = QTreeWidgetItem ()
123
+ self .uptodateItem .setText (0 , "Installed" )
124
+ self .toupdateItem = QTreeWidgetItem ()
125
+ self .toupdateItem .setText (0 , "Upgradable" )
126
+ self .notinstalledItem = QTreeWidgetItem ()
127
+ self .notinstalledItem .setText (0 , "Not installed" )
128
+ self .toupdateItem .setIcon (0 , self .icon )
129
+ self .uptodateItem .setIcon (0 , self .icon )
130
+ self .notinstalledItem .setIcon (0 , self .icon )
131
+ resources = readUrl (self .urlBase + "list.txt" ).splitlines ()
132
+ resources = [r .split ("," ) for r in resources ]
133
+ for filename , version , name in resources :
134
+ treeBranch = self .getTreeBranchForState (filename , float (version ))
135
+ item = TreeItem (filename , name , self .icon )
136
+ treeBranch .addChild (item )
137
+ if treeBranch != self .notinstalledItem :
138
+ item .setCheckState (0 , Qt .Checked )
139
+
140
+ self .tree .addTopLevelItem (self .toupdateItem )
141
+ self .tree .addTopLevelItem (self .notinstalledItem )
142
+ self .tree .addTopLevelItem (self .uptodateItem )
143
+
144
+ self .webView .setHtml (self .HELP_TEXT )
145
+
146
+ def currentItemChanged (self , item , prev ):
147
+ if isinstance (item , TreeItem ):
148
+ try :
149
+ url = self .urlBase + item .filename .replace (" " ,"%20" ) + ".help"
150
+ helpContent = readUrl (url )
151
+ descriptions = json .loads (helpContent )
152
+ html = "<h2>%s</h2>" % item .name
153
+ html += "<p><b>Description:</b> " + getDescription (ALG_DESC , descriptions )+ "</p>"
154
+ html += "<p><b>Created by:</b> " + getDescription (ALG_CREATOR , descriptions )+ "</p>"
155
+ html += "<p><b>Version:</b> " + getDescription (ALG_VERSION , descriptions )+ "</p>"
156
+ except HTTPError , e :
157
+ html = "<h2>No detailed description available for this script</h2>"
158
+ self .webView .setHtml (html )
159
+ else :
160
+ self .webView .setHtml (self .HELP_TEXT )
161
+
162
+ def getTreeBranchForState (self , filename , version ):
163
+ if not os .path .exists (os .path .join (self .folder , filename )):
164
+ return self .notinstalledItem
165
+ else :
166
+ helpFile = os .path .join (self .folder , filename + ".help" )
167
+ if not os .path .exists (helpFile ):
168
+ currentVersion = 1
169
+ else :
170
+ with open (helpFile ) as f :
171
+ helpContent = json .load (f )
172
+ try :
173
+ currentVersion = float (helpContent [Help2Html .ALG_VERSION ])
174
+ except :
175
+ currentVersion = 1
176
+ print filename , currentVersion , version
177
+ if version > currentVersion :
178
+ print version - currentVersion
179
+ return self .toupdateItem
180
+ else :
181
+ return self .uptodateItem
182
+
183
+
184
+ def cancelPressed (self ):
185
+ self .close ()
186
+
187
+ def okPressed (self ):
188
+ toDownload = []
189
+ for i in xrange (self .toupdateItem .childCount ()):
190
+ item = self .toupdateItem .child (i )
191
+ if item .checkState (0 ) == Qt .Checked :
192
+ toDownload .append (item .filename )
193
+ for i in xrange (self .notinstalledItem .childCount ()):
194
+ item = self .notinstalledItem .child (i )
195
+ if item .checkState (0 ) == Qt .Checked :
196
+ toDownload .append (item .filename )
197
+
198
+ if toDownload :
199
+ self .progressBar .setMaximum (len (toDownload ))
200
+ for i , filename in enumerate (toDownload ):
201
+ QCoreApplication .processEvents ()
202
+ url = self .urlBase + filename .replace (" " ,"%20" )
203
+ code = readUrl (url )
204
+ path = os .path .join (self .folder , filename )
205
+ with open (path , "w" ) as f :
206
+ f .write (code )
207
+ self .progressBar .setValue (i + 1 )
208
+
209
+ toDelete = []
210
+ for i in xrange (self .uptodateItem .childCount ()):
211
+ item = self .uptodateItem .child (i )
212
+ if item .checkState (0 ) == Qt .Unchecked :
213
+ toDelete .append (item .filename )
214
+ for filename in toDelete :
215
+ path = os .path .join (self .folder , filename )
216
+ os .remove (path )
217
+
218
+ self .updateToolbox = len (toDownload ) + len (toDelete )> 0
219
+ self .close ()
220
+
221
+
222
+ class TreeItem (QTreeWidgetItem ):
223
+
224
+ def __init__ (self , filename , name , icon ):
225
+ QTreeWidgetItem .__init__ (self )
226
+ self .name = name
227
+ self .filename = filename
228
+ self .setText (0 , name )
229
+ self .setIcon (0 , icon )
230
+ self .setCheckState (0 , Qt .Unchecked )
231
+
232
+
233
+
234
+
235
+
236
+
237
+
0 commit comments