2 @package modules.extensions
4 @brief GRASS Addons extensions management classes
7 - extensions::InstallExtensionWindow
8 - extensions::ExtensionTree
9 - extensions::UninstallExtensionWindow
10 - extensions::CheckListExtension
12 (C) 2008-2011 by the GRASS Development Team
14 This program is free software under the GNU General Public License
15 (>=v2). Read the file COPYING that comes with GRASS for details.
17 @author Martin Landa <landa.martin gmail.com>
24 import wx.lib.mixins.listctrl
as listmix
26 import wx.lib.agw.customtreectrl
as CT
28 import wx.lib.customtreectrl
as CT
29 import wx.lib.flatnotebook
as FN
34 from core
import globalvar
37 from gui_core.forms
import GUI
42 def __init__(self, parent, id = wx.ID_ANY,
43 title = _(
"Fetch & install extension from GRASS Addons"), **kwargs):
47 wx.Frame.__init__(self, parent = parent, id = id, title = title, **kwargs)
48 self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR,
'grass.ico'), wx.BITMAP_TYPE_ICO))
50 self.
panel = wx.Panel(parent = self, id = wx.ID_ANY)
53 label =
" %s " % _(
"Repository"))
55 label =
" %s " % _(
"List of extensions"))
57 self.
repo = wx.TextCtrl(parent = self.
panel, id = wx.ID_ANY)
59 label = _(
"Fetch full info including description and keywords"))
60 self.fullDesc.SetValue(
True)
63 self.search.SetSelection(0)
68 label =
" %s " % _(
"Options"))
70 task = gtask.parse_interface(
'g.extension.py')
72 ignoreFlags = [
'l',
'c',
'g',
'a',
'f',
'quiet',
'verbose']
73 if sys.platform ==
'win32':
74 ignoreFlags.append(
'd')
75 ignoreFlags.append(
'i')
77 for f
in task.get_options()[
'flags']:
78 name = f.get(
'name',
'')
79 desc = f.get(
'label',
'')
81 desc = f.get(
'description',
'')
82 if not name
and not desc:
84 if name
in ignoreFlags:
86 self.
options[name] = wx.CheckBox(parent = self.
panel, id = wx.ID_ANY,
88 self.repo.SetValue(task.get_param(value =
'svnurl').get(
'default',
89 'http://svn.osgeo.org/grass/grass-addons'))
95 self.btnFetch.SetToolTipString(_(
"Fetch list of available modules from GRASS Addons SVN repository"))
98 label = _(
"&Install"))
99 self.btnInstall.SetToolTipString(_(
"Install selected add-ons GRASS module"))
100 self.btnInstall.Enable(
False)
102 label = _(
"Command dialog"))
103 self.btnCmd.SetToolTipString(_(
'Open %s dialog') %
'g.extension.py')
106 self.btnFetch.Bind(wx.EVT_BUTTON, self.
OnFetch)
107 self.btnInstall.Bind(wx.EVT_BUTTON, self.
OnInstall)
111 self.search.Bind(wx.EVT_TEXT_ENTER, self.
OnShowItem)
118 sizer = wx.BoxSizer(wx.VERTICAL)
119 repoSizer = wx.StaticBoxSizer(self.
repoBox, wx.VERTICAL)
120 repo1Sizer = wx.BoxSizer(wx.HORIZONTAL)
121 repo1Sizer.Add(item = self.
repo, proportion = 1,
122 flag = wx.ALL | wx.ALIGN_CENTER_VERTICAL, border = 1)
123 repo1Sizer.Add(item = self.
btnFetch, proportion = 0,
124 flag = wx.ALL | wx.ALIGN_CENTER_VERTICAL, border = 1)
125 repoSizer.Add(item = repo1Sizer,
129 findSizer = wx.BoxSizer(wx.HORIZONTAL)
130 findSizer.Add(item = self.
search, proportion = 1)
132 treeSizer = wx.StaticBoxSizer(self.
treeBox, wx.HORIZONTAL)
133 treeSizer.Add(item = self.
tree, proportion = 1,
134 flag = wx.ALL | wx.EXPAND, border = 1)
137 optionSizer = wx.StaticBoxSizer(self.
optionBox, wx.VERTICAL)
138 for key
in self.options.keys():
139 optionSizer.Add(item = self.
options[key], proportion = 0)
141 btnSizer = wx.BoxSizer(wx.HORIZONTAL)
142 btnSizer.Add(item = self.
btnCmd, proportion = 0,
143 flag = wx.RIGHT, border = 5)
144 btnSizer.AddSpacer(10)
145 btnSizer.Add(item = self.
btnClose, proportion = 0,
146 flag = wx.RIGHT, border = 5)
147 btnSizer.Add(item = self.
btnInstall, proportion = 0)
149 sizer.Add(item = repoSizer, proportion = 0,
150 flag = wx.ALL | wx.EXPAND, border = 3)
151 sizer.Add(item = findSizer, proportion = 0,
152 flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 3)
153 sizer.Add(item = treeSizer, proportion = 1,
154 flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 3)
155 sizer.Add(item = optionSizer, proportion = 0,
156 flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 3)
157 sizer.Add(item = btnSizer, proportion = 0,
158 flag = wx.ALIGN_RIGHT | wx.ALL, border = 5)
160 self.panel.SetSizer(sizer)
161 sizer.Fit(self.
panel)
166 item = self.tree.GetSelected()
167 if not item
or not item.IsOk():
168 return [
'g.extension.py']
170 name = self.tree.GetItemText(item)
172 GError(_(
"Extension not defined"), parent = self)
175 for key
in self.options.keys():
176 if self.
options[key].IsChecked():
177 flags.append(
'-%s' % key)
179 return [
'g.extension.py'] + flags + [
'extension=' + name,
180 'svnurl=' + self.repo.GetValue().strip()]
183 """!Update statusbar text"""
184 element = self.search.GetSelection()
185 if not self.tree.IsLoaded():
186 self.SetStatusText(_(
"Fetch list of available extensions by clicking on 'Fetch' button"), 0)
189 self.tree.SearchItems(element = element,
190 value = event.GetString())
192 nItems = len(self.tree.itemsMarked)
193 if event.GetString():
194 self.SetStatusText(_(
"%d items match") % nItems, 0)
196 self.SetStatusText(
"", 0)
205 """!Fetch list of available extensions"""
207 self.SetStatusText(_(
"Fetching list of modules from GRASS-Addons SVN (be patient)..."), 0)
208 self.tree.Load(url = self.repo.GetValue().strip(), full = self.fullDesc.IsChecked())
209 self.SetStatusText(
"", 0)
213 item = event.GetItem()
214 data = self.tree.GetPyData(item)
215 if data
and 'command' in data:
219 """!Install selected extension"""
220 log = self.parent.GetLogWindow()
225 if not os.getenv(
'GRASS_ADDON_PATH'):
229 log = self.parent.GetLogWindow()
230 log.GetPrompt().SetFilter(
None)
234 item = event.GetItem()
235 self.tree.itemSelected = item
236 data = self.tree.GetPyData(item)
238 self.SetStatusText(
'', 0)
239 self.btnInstall.Enable(
False)
241 self.SetStatusText(data.get(
'description',
''), 0)
242 self.btnInstall.Enable(
True)
245 """!Show selected item"""
246 self.tree.OnShowItem(event)
247 if self.tree.GetSelected():
248 self.btnInstall.Enable()
250 self.btnInstall.Enable(
False)
253 """!Shows command dialog"""
254 GUI(parent = self).ParseCommand(cmd = self.
_getCmd())
257 """!List of available extensions"""
258 def __init__(self, parent, log, id = wx.ID_ANY,
259 ctstyle = CT.TR_HIDE_ROOT | CT.TR_FULL_ROW_HIGHLIGHT | CT.TR_HAS_BUTTONS |
260 CT.TR_LINES_AT_ROOT | CT.TR_SINGLE,
265 super(ExtensionTree, self).
__init__(parent, id, ctstyle = ctstyle, **kwargs)
270 for prefix
in (
'display',
'database',
271 'general',
'imagery',
272 'misc',
'postscript',
'paint',
273 'raster',
'raster3d',
'sites',
'vector',
'wxGUI',
'other'):
274 self.AppendItem(parentId = self.
root,
278 def _expandPrefix(self, c):
279 name = {
'd' :
'display',
298 def _findItem(self, text):
300 item = self.GetFirstChild(self.
root)[0]
301 while item
and item.IsOk():
302 if text == self.GetItemText(item):
305 item = self.GetNextSibling(item)
309 def Load(self, url, full = False):
310 """!Load list of extensions"""
311 self.DeleteAllItems()
312 self.
root = self.AddRoot(_(
"Menu tree"))
319 ret =
RunCommand(
'g.extension.py', read =
True, parent = self,
321 flags = flags, quiet =
True)
326 for line
in ret.splitlines():
329 key, value = line.split(
'=', 1)
336 prefix, name = value.split(
'.', 1)
340 if prefix
not in mdict:
341 mdict[prefix] = dict()
342 mdict[prefix][name] = dict()
344 mdict[prefix][name][key] = value
347 prefix, name = line.strip().
split(
'.', 1)
355 if prefix
not in mdict:
356 mdict[prefix] = dict()
358 mdict[prefix][name] = {
'command' : prefix +
'.' + name }
360 for prefix
in mdict.keys():
363 names = mdict[prefix].keys()
367 text = prefix +
'.' + name
370 new = self.AppendItem(parentId = item,
373 for key
in mdict[prefix][name].keys():
374 data[key] = mdict[prefix][name][key]
376 self.SetPyData(new, data)
381 """Check if items are loaded"""
385 def __init__(self, parent, id = wx.ID_ANY,
386 title = _(
"Uninstall GRASS Addons extensions"), **kwargs):
389 wx.Frame.__init__(self, parent = parent, id = id, title = title, **kwargs)
390 self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR,
'grass.ico'), wx.BITMAP_TYPE_ICO))
392 self.
panel = wx.Panel(parent = self, id = wx.ID_ANY)
395 label =
" %s " % _(
"List of installed extensions"))
401 label = _(
"&Uninstall"))
402 self.btnUninstall.SetToolTipString(_(
"Uninstall selected AddOns extensions"))
404 label = _(
"Command dialog"))
405 self.btnCmd.SetToolTipString(_(
'Open %s dialog') %
'g.extension')
408 self.btnUninstall.Bind(wx.EVT_BUTTON, self.
OnUninstall)
416 sizer = wx.BoxSizer(wx.VERTICAL)
418 extSizer = wx.StaticBoxSizer(self.
extBox, wx.HORIZONTAL)
419 extSizer.Add(item = self.
extList, proportion = 1,
420 flag = wx.ALL | wx.EXPAND, border = 1)
422 btnSizer = wx.BoxSizer(wx.HORIZONTAL)
423 btnSizer.Add(item = self.
btnCmd, proportion = 0,
424 flag = wx.RIGHT, border = 5)
425 btnSizer.AddSpacer(10)
426 btnSizer.Add(item = self.
btnClose, proportion = 0,
427 flag = wx.RIGHT, border = 5)
430 sizer.Add(item = extSizer, proportion = 1,
431 flag = wx.ALL | wx.EXPAND, border = 3)
432 sizer.Add(item = btnSizer, proportion = 0,
433 flag = wx.ALIGN_RIGHT | wx.ALL, border = 5)
435 self.panel.SetSizer(sizer)
436 sizer.Fit(self.
panel)
445 """!Uninstall selected extensions"""
446 log = self.parent.GetLogWindow()
447 eList = self.extList.GetExtensions()
449 GError(_(
"No extension selected for removal. "
450 "Operation canceled."),
455 files =
RunCommand(
'g.extension.py', parent = self, read =
True, quiet =
True,
456 extension = ext, operation =
'remove').splitlines()
457 dlg = wx.MessageDialog(parent = self,
458 message = _(
"List of files to be removed:\n%(files)s\n\n"
459 "Do you want really to remove <%(ext)s> extension?") % \
460 {
'files' : os.linesep.join(files),
'ext' : ext },
461 caption = _(
"Remove extension"),
462 style = wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
464 if dlg.ShowModal() == wx.ID_YES:
465 RunCommand(
'g.extension.py', flags =
'f', parent = self, quiet =
True,
466 extension = ext, operation =
'remove')
468 self.extList.LoadData()
472 log = self.parent.GetLogWindow()
473 log.GetPrompt().SetFilter(
None)
476 """!Shows command dialog"""
477 GUI(parent = self).ParseCommand(cmd = [
'g.extension.py'])
480 """!List of mapset/owner/group"""
484 wx.ListCtrl.__init__(self, parent, id = wx.ID_ANY,
485 style = wx.LC_REPORT)
486 listmix.CheckListCtrlMixin.__init__(self)
489 listmix.ListCtrlAutoWidthMixin.__init__(self)
491 self.InsertColumn(0, _(
'Extension'))
495 """!Load data into list"""
496 self.DeleteAllItems()
498 quiet =
True, parent = self, read =
True,
499 flags =
'a').splitlines():
501 self.InsertStringItem(sys.maxint, ext)
504 """!Get extensions to be un-installed
507 for i
in range(self.GetItemCount()):
508 if self.IsChecked(i):
509 name = self.GetItemText(i)