[GRASS-SVN] r49738 - in grass/branches/releasebranch_6_4/gui:
scripts wxpython wxpython/gui_modules wxpython/xml
svn_grass at osgeo.org
svn_grass at osgeo.org
Wed Dec 14 06:57:31 EST 2011
Author: martinl
Date: 2011-12-14 03:57:31 -0800 (Wed, 14 Dec 2011)
New Revision: 49738
Modified:
grass/branches/releasebranch_6_4/gui/scripts/g.extension.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/gcmd.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/ghelp.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/goutput.py
grass/branches/releasebranch_6_4/gui/wxpython/wxgui.py
grass/branches/releasebranch_6_4/gui/wxpython/xml/menudata.xml
Log:
wxGUI: backport improved extension management from devbr6
new tool for uninstalling extensions
Modified: grass/branches/releasebranch_6_4/gui/scripts/g.extension.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/scripts/g.extension.py 2011-12-14 11:38:11 UTC (rev 49737)
+++ grass/branches/releasebranch_6_4/gui/scripts/g.extension.py 2011-12-14 11:57:31 UTC (rev 49738)
@@ -28,6 +28,7 @@
#% type: string
#% key_desc: name
#% description: Name of extension to install/remove
+#% guisection: Required
#%end
#%option
#% key: operation
@@ -42,7 +43,6 @@
#% type: string
#% key_desc: url
#% description: SVN Addons repository URL
-#% required: yes
#% answer: http://svn.osgeo.org/grass/grass-addons/grass6
#%end
#%option
@@ -56,34 +56,43 @@
#%flag
#% key: l
-#% description: List available modules in the GRASS Addons SVN repository
+#% description: List available extensions in the GRASS Addons SVN repository
#% guisection: Print
#%end
#%flag
#% key: c
-#% description: List available modules in the GRASS Addons SVN repository including module description
+#% description: List available extensions in the GRASS Addons SVN repository including module description
#% guisection: Print
#%end
#%flag
#% key: g
-#% description: List available modules in the GRASS Addons SVN repository (shell script style)
+#% description: List available extensions in the GRASS Addons SVN repository (shell script style)
#% guisection: Print
#%end
#%flag
+#% key: a
+#% description: List locally installed extension
+#% guisection: Print
+#%end
+#%flag
#% key: s
#% description: Install system-wide (may need system administrator rights)
+#% guisection: Install
#%end
#%flag
#% key: d
#% description: Download source code and exit
+#% guisection: Install
#%end
#%flag
#% key: i
#% description: Don't install new extension, just compile it
+#% guisection: Install
#%end
#%flag
#% key: f
#% description: Force removal when uninstalling extension (operation=remove)
+#% guisection: Remove
#%end
import os
@@ -135,8 +144,35 @@
return c
-# list modules (read XML file from grass.osgeo.org/addons)
-def list_available_modules():
+
+# list installed extensions
+def get_installed_extensions(force = False):
+ fXML = os.path.join(options['prefix'], 'modules.xml')
+ if not os.path.exists(fXML):
+ if force:
+ write_xml_modules(fXML)
+ else:
+ grass.warning(_("No metadata file available"))
+ return []
+
+ # read XML file
+ fo = open(fXML, 'r')
+ try:
+ tree = etree.fromstring(fo.read())
+ except:
+ os.remove(fXML)
+ write_xml_modules(fXML)
+ return []
+ fo.close()
+
+ ret = list()
+ for tnode in tree.findall('task'):
+ ret.append(tnode.get('name'))
+
+ return ret
+
+# list extensions (read XML file from grass.osgeo.org/addons)
+def list_available_extensions():
mlist = list()
# try to download XML metadata file first
@@ -163,14 +199,14 @@
else:
print name
except HTTPError:
- return list_available_modules_svn()
+ return list_available_extensions_svn()
return mlist
-# list modules (scan SVN repo)
-def list_available_modules_svn():
+# list extensions (scan SVN repo)
+def list_available_extensions_svn():
mlist = list()
- grass.message(_('Fetching list of modules from GRASS-Addons SVN (be patient)...'))
+ grass.message(_('Fetching list of extensions from GRASS-Addons SVN (be patient)...'))
pattern = re.compile(r'(<li><a href=".+">)(.+)(</a></li>)', re.IGNORECASE)
if flags['c']:
@@ -194,7 +230,7 @@
continue
for line in f.readlines():
- # list modules
+ # list extensions
sline = pattern.search(line)
if not sline:
continue
@@ -222,7 +258,7 @@
return
for line in f.readlines():
- # list modules
+ # list extensions
sline = pattern.search(line)
if not sline:
continue
@@ -241,6 +277,147 @@
grass.message(_("Path to the source code:"))
sys.stderr.write('%s\n' % os.path.join(tmpdir, options['extension']))
+# write out meta-file
+def write_xml_modules(name, tree = None):
+ fo = open(name, 'w')
+ version = grass.version()['version'].split('.')[0]
+ fo.write('<?xml version="1.0" encoding="UTF-8"?>\n')
+ fo.write('<!DOCTYPE task SYSTEM "grass-addons.dtd">\n')
+ fo.write('<addons version="%s">\n' % version)
+
+ if tree is not None:
+ for tnode in tree.findall('task'):
+ indent = 4
+ fo.write('%s<task name="%s">\n' % (' ' * indent, tnode.get('name')))
+ indent += 4
+ fo.write('%s<description>%s</description>\n' % \
+ (' ' * indent, tnode.find('description').text))
+ fo.write('%s<keywords>%s</keywords>\n' % \
+ (' ' * indent, tnode.find('keywords').text))
+ bnode = tnode.find('binary')
+ if bnode is not None:
+ fo.write('%s<binary>\n' % (' ' * indent))
+ indent += 4
+ for fnode in bnode.findall('file'):
+ fpath = fnode.text.split(os.path.sep)
+ if not flags['s']: # tidy citizen hacks
+ if fpath[0] in ('bin', 'scripts'):
+ del fpath[0]
+ if fpath[0] == 'man':
+ fpath.insert(0, 'docs')
+
+ fo.write('%s<file>%s</file>\n' % \
+ (' ' * indent, os.path.join(options['prefix'],
+ os.path.sep.join(fpath))))
+ indent -= 4
+ fo.write('%s</binary>\n' % (' ' * indent))
+ libgisRev = grass.version()['libgis_revision']
+ fo.write('%s<libgis revision="%s" />\n' % \
+ (' ' * indent, libgisRev))
+ indent -= 4
+ fo.write('%s</task>\n' % (' ' * indent))
+
+ fo.write('</addons>\n')
+ fo.close()
+
+# update local meta-file when installing new extension
+def install_extension_xml():
+ # read metadata from remote server
+ url = "http://grass.osgeo.org/addons/grass%s.xml" % grass.version()['version'].split('.')[0]
+ data = None
+ try:
+ f = urlopen(url)
+ tree = etree.fromstring(f.read())
+ for mnode in tree.findall('task'):
+ name = mnode.get('name')
+ if name != options['extension']:
+ continue
+
+ fList = list()
+ bnode = mnode.find('binary')
+ windows = sys.platform == 'win32'
+ if bnode is not None:
+ for fnode in bnode.findall('file'):
+ path = fnode.text.split('/')
+ if windows:
+ if path[0] == 'bin':
+ path[-1] += '.exe'
+ if path[0] == 'scripts':
+ path[-1] += '.py'
+ fList.append(os.path.sep.join(path))
+
+ desc = mnode.find('description').text
+ if not desc:
+ desc = ''
+ keyw = mnode.find('keywords').text
+ if not keyw:
+ keyw = ''
+
+ data = { 'name' : name,
+ 'desc' : desc,
+ 'keyw' : keyw,
+ 'files' : fList,
+ }
+ except HTTPError:
+ grass.error(_("Unable to read metadata file from the remote server"))
+
+ if not data:
+ grass.warning(_("No metadata available"))
+ return
+
+ fXML = os.path.join(options['prefix'], 'modules.xml')
+ # create an empty file if not exists
+ if not os.path.exists(fXML):
+ write_xml_modules(fXML)
+
+ # read XML file
+ fo = open(fXML, 'r')
+ tree = etree.fromstring(fo.read())
+ fo.close()
+
+ # update tree
+ tnode = None
+ for node in tree.findall('task'):
+ if node.get('name') == options['extension']:
+ tnode = node
+ break
+
+ if tnode is not None:
+ # update existing node
+ dnode = tnode.find('description')
+ if dnode is not None:
+ dnode.text = data['desc']
+ knode = tnode.find('keywords')
+ if knode is not None:
+ knode.text = data['keyw']
+ bnode = tnode.find('binary')
+ if bnode is not None:
+ tnode.remove(bnode)
+ bnode = etree.Element('binary')
+ for f in data['files']:
+ fnode = etree.Element('file')
+ fnode.text = f
+ bnode.append(fnode)
+ tnode.append(bnode)
+ else:
+ # create new node for task
+ tnode = etree.Element('task', attrib = { 'name' : data['name'] })
+ dnode = etree.Element('description')
+ dnode.text = data['desc']
+ tnode.append(dnode)
+ knode = etree.Element('keywords')
+ knode.text = data['keyw']
+ tnode.append(knode)
+ bnode = etree.Element('binary')
+ for f in data['files']:
+ fnode = etree.Element('file')
+ fnode.text = f
+ bnode.append(fnode)
+ tnode.append(bnode)
+ tree.append(tnode)
+
+ write_xml_modules(fXML, tree)
+
# install extension on MS Windows
def install_extension_win():
### TODO: do not use hardcoded url
@@ -271,23 +448,30 @@
fo.close()
except HTTPError:
grass.fatal(_("GRASS Addons <%s> not found") % options['extension'])
+
+ return 0
- grass.message(_("Installation of <%s> successfully finished.") % options['extension'])
-
# install extension
def install_extension():
gisbase = os.getenv('GISBASE')
if not gisbase:
grass.fatal(_('$GISBASE not defined'))
- if grass.find_program(options['extension'], ['--help']):
- grass.warning(_("Extension <%s> already installed. Will be updated...") % options['extension'])
+ if options['extension'] in get_installed_extensions(force = True):
+ grass.warning(_("Extension <%s> already installed. Re-installing...") % options['extension'])
if sys.platform == "win32":
- install_extension_win()
+ ret = install_extension_win()
else:
- install_extension_other()
+ ret = install_extension_other()
+ if ret != 0:
+ grass.warning(_('Installation failed, sorry. Please check above error messages.'))
+ else:
+ grass.message(_("Updating metadata file..."))
+ install_extension_xml()
+ grass.message(_("Installation of <%s> successfully finished") % options['extension'])
+
# cleanup build cruft
if not flags['s']:
tidy_citizen()
@@ -296,30 +480,6 @@
not os.environ['GRASS_ADDON_PATH']:
grass.warning(_('This add-on module will not function until you set the '
'GRASS_ADDON_PATH environment variable (see "g.manual variables")'))
-
- # manual page: fix href
- if os.getenv('GRASS_ADDON_PATH'):
- html_man = os.path.join(os.getenv('GRASS_ADDON_PATH'), 'docs', 'html', 'description.html')
- if os.path.exists(html_man):
- fd = open(html_man)
- html_str = '\n'.join(fd.readlines())
- fd.close()
- for rep in ('grassdocs.css', 'grass_logo.png'):
- patt = re.compile(rep, re.IGNORECASE)
- html_str = patt.sub(os.path.join(gisbase, 'docs', 'html', rep),
- html_str)
-
- patt = re.compile(r'(<a href=")(d|db|g|i|m|p|ps|r|r3|s|v|wxGUI)(\.)(.+)(.html">)', re.IGNORECASE)
- while True:
- m = patt.search(html_str)
- if not m:
- break
- html_str = patt.sub(m.group(1) + os.path.join(gisbase, 'docs', 'html',
- m.group(2) + m.group(3) + m.group(4)) + m.group(5),
- html_str, count = 1)
- fd = open(html_man, "w")
- fd.write(html_str)
- fd.close()
# install extension on other plaforms
def install_extension_other():
@@ -398,14 +558,9 @@
grass.message(_("Installing <%s>...") % options['extension'])
- ret = grass.call(installCmd,
- stdout = outdev)
-
- if ret != 0:
- grass.warning(_('Installation failed, sorry. Please check above error messages.'))
- else:
- grass.message(_("Installation of <%s> successfully finished.") % options['extension'])
-
+ return grass.call(installCmd,
+ stdout = outdev)
+
# remove dir if empty
def remove_empty_dir(path):
if os.path.exists(path) and not os.listdir(path):
@@ -444,41 +599,56 @@
# if empty, rmdir bin, etc, man, scripts
for d in ('bin', 'etc', os.path.join('man', 'man1'), 'man', 'scripts'):
remove_empty_dir(os.path.join(options['prefix'], d))
+
+# update local meta-file when removing existing extension
+def remove_extension_xml():
+ fXML = os.path.join(options['prefix'], 'modules.xml')
+ if not os.path.exists(fXML):
+ return
+ # read XML file
+ fo = open(fXML, 'r')
+ tree = etree.fromstring(fo.read())
+ fo.close()
+
+ tnode = None
+ for node in tree.findall('task'):
+ if node.get('name') == options['extension']:
+ tnode = node
+ break
+
+ if tnode is not None:
+ tree.remove(tnode)
+
+ write_xml_modules(fXML, tree)
+
# remove existing extension (reading XML file)
def remove_extension(force = False):
- # try to download XML metadata file first
- url = "http://grass.osgeo.org/addons/grass%s.xml" % grass.version()['version'].split('.')[0]
+ # try to read XML metadata file first
+ fXML = os.path.join(options['prefix'], 'modules.xml')
name = options['extension']
+ if name not in get_installed_extensions():
+ grass.warning(_("Extension <%s> not found") % name)
+
if force:
grass.verbose(_("List of removed files:"))
else:
grass.info(_("Files to be removed (use flag 'f' to force removal):"))
- try:
- f = urlopen(url)
+ if os.path.exists(fXML):
+ f = open(fXML, 'r')
tree = etree.fromstring(f.read())
flist = []
for task in tree.findall('task'):
if name == task.get('name', default = '') and \
task.find('binary') is not None:
for f in task.find('binary').findall('file'):
- fname = f.text
- if fname:
- fpath = fname.split('/')
- if sys.platform == 'win32':
- if fpath[0] == 'bin':
- fpath[-1] += '.exe'
- if fpath[0] == 'scripts':
- fpath[-1] += '.py'
-
- flist.append(fpath)
+ flist.append(f.text)
if flist:
removed = False
err = list()
- for f in flist:
- fpath = os.path.join(options['prefix'], os.path.sep.join(f))
+ for fpath in flist:
try:
if force:
grass.verbose(fpath)
@@ -496,13 +666,15 @@
grass.error(e)
else:
remove_extension_std(force)
- except HTTPError:
+ else:
remove_extension_std(force)
if force:
+ grass.message(_("Updating metadata file..."))
+ remove_extension_xml()
grass.message(_("Extension <%s> successfully uninstalled.") % options['extension'])
else:
- grass.warning(_("Extension <%s> not removed. "
+ grass.warning(_("Extension <%s> not removed.\n"
"Re-run '%s' with 'f' flag to force removal") % (options['extension'], 'g.extension'))
# remove exising extension (using standard files layout)
@@ -524,20 +696,17 @@
# check links in CSS
def check_style_files(fil):
- # check the links to grassdocs.css/grass_logo.png to a correct manual page of addons
- dist_file = os.path.join(os.getenv('GISBASE'), 'docs', 'html', fil)
+ dist_file = os.path.join(os.getenv('GISBASE'), 'docs', 'html', fil)
addons_file = os.path.join(options['prefix'], 'docs', 'html', fil)
- # check if file already exists in the grass addons docs html path
+
if os.path.isfile(addons_file):
return
- # otherwise copy the file from $GISBASE/docs/html, it doesn't use link
- # because os.symlink it work only in Linux
- else:
- try:
- shutil.copyfile(dist_file,addons_file)
- except OSError, e:
- grass.fatal(_("Unable to create '%s': %s") % (addons_file, e))
-
+
+ try:
+ shutil.copyfile(dist_file,addons_file)
+ except OSError, e:
+ grass.fatal(_("Unable to create '%s': %s") % (addons_file, e))
+
def create_dir(path):
if os.path.isdir(path):
return
@@ -564,14 +733,6 @@
if sys.platform != "win32":
check_progs()
- # list available modules
- if flags['l'] or flags['c'] or flags['g']:
- list_available_modules()
- return 0
- else:
- if not options['extension']:
- grass.fatal(_('You need to define an extension name or use -l'))
-
# define path
if flags['s']:
options['prefix'] = os.environ['GISBASE']
@@ -590,6 +751,20 @@
grass.warning(_("GRASS_ADDON_PATH has more items, using first defined - '%s'") % path_list[0])
options['prefix'] = path_list[0]
+ # list available modules
+ if flags['l'] or flags['c'] or flags['g']:
+ list_available_extensions()
+ return 0
+ elif flags['a']:
+ grass.message(_("List of installed extensions:"))
+ elist = get_installed_extensions()
+ if elist:
+ print os.linesep.join(elist)
+ return 0
+ else:
+ if not options['extension']:
+ grass.fatal(_('You need to define an extension name or use -l'))
+
if flags['d']:
if options['operation'] != 'add':
grass.warning(_("Flag 'd' is relevant only to 'operation=add'. Ignoring this flag."))
Modified: grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/gcmd.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/gcmd.py 2011-12-14 11:38:11 UTC (rev 49737)
+++ grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/gcmd.py 2011-12-14 11:57:31 UTC (rev 49738)
@@ -497,6 +497,7 @@
shell = sys.platform == "win32")
except OSError, e:
self.error = str(e)
+ print >> sys.stderr, e
return 1
if self.stdin: # read stdin if requested ...
Modified: grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/ghelp.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/ghelp.py 2011-12-14 11:38:11 UTC (rev 49737)
+++ grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/ghelp.py 2011-12-14 11:57:31 UTC (rev 49738)
@@ -11,6 +11,8 @@
- AboutWindow
- InstallExtensionWindow
- ExtensionTree
+ - UninstallExtensionWindow
+ - CheckListExtension
- HelpFrame
- HelpWindow
- HelpPanel
@@ -27,6 +29,7 @@
import sys
import wx
+import wx.lib.mixins.listctrl as listmix
try:
import wx.lib.agw.customtreectrl as CT
# import wx.lib.agw.hyperlink as hl
@@ -812,7 +815,7 @@
task = gtask.parse_interface('g.extension.py')
- ignoreFlags = ['l', 'c', 'g', 'f', 'quiet', 'verbose']
+ ignoreFlags = ['l', 'c', 'g', 'a', 'f', 'quiet', 'verbose']
if sys.platform == 'win32':
ignoreFlags.append('d')
ignoreFlags.append('i')
@@ -1120,6 +1123,131 @@
"""Check if items are loaded"""
return self._loaded
+class UninstallExtensionWindow(wx.Frame):
+ def __init__(self, parent, id = wx.ID_ANY,
+ title = _("Uninstall GRASS Addons extensions"), **kwargs):
+ self.parent = parent
+
+ wx.Frame.__init__(self, parent = parent, id = id, title = title, **kwargs)
+ self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
+
+ self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
+
+ self.extBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
+ label = " %s " % _("List of installed extensions"))
+
+ self.extList = CheckListExtension(parent = self.panel)
+
+ # buttons
+ self.btnUninstall = wx.Button(parent = self.panel, id = wx.ID_ANY,
+ label = _("&Uninstall"))
+ self.btnUninstall.SetToolTipString(_("Uninstall selected AddOns extensions"))
+ self.btnCmd = wx.Button(parent = self.panel, id = wx.ID_ANY,
+ label = _("Command dialog"))
+ self.btnCmd.SetToolTipString(_('Open %s dialog') % 'g.extension')
+ self.btnClose = wx.Button(parent = self.panel, id = wx.ID_CLOSE)
+
+ self.btnUninstall.Bind(wx.EVT_BUTTON, self.OnUninstall)
+ self.btnCmd.Bind(wx.EVT_BUTTON, self.OnCmdDialog)
+ self.btnClose.Bind(wx.EVT_BUTTON, self.OnCloseWindow)
+
+ self._layout()
+
+ def _layout(self):
+ """!Do layout"""
+ sizer = wx.BoxSizer(wx.VERTICAL)
+
+ extSizer = wx.StaticBoxSizer(self.extBox, wx.HORIZONTAL)
+ extSizer.Add(item = self.extList, proportion = 1,
+ flag = wx.ALL | wx.EXPAND, border = 1)
+
+ btnSizer = wx.BoxSizer(wx.HORIZONTAL)
+ btnSizer.Add(item = self.btnCmd, proportion = 0,
+ flag = wx.RIGHT, border = 5)
+ btnSizer.AddSpacer(10)
+ btnSizer.Add(item = self.btnClose, proportion = 0,
+ flag = wx.RIGHT, border = 5)
+ btnSizer.Add(item = self.btnUninstall, proportion = 0)
+
+ sizer.Add(item = extSizer, proportion = 1,
+ flag = wx.ALL | wx.EXPAND, border = 3)
+ sizer.Add(item = btnSizer, proportion = 0,
+ flag = wx.ALIGN_RIGHT | wx.ALL, border = 5)
+
+ self.panel.SetSizer(sizer)
+ sizer.Fit(self.panel)
+
+ self.Layout()
+
+ def OnCloseWindow(self, event):
+ """!Close window"""
+ self.Destroy()
+
+ def OnUninstall(self, event):
+ """!Uninstall selected extensions"""
+ log = self.parent.GetLogWindow()
+ eList = self.extList.GetExtensions()
+ if not eList:
+ gcmd.GError(_("No extension selected for removal. "
+ "Operation canceled."),
+ parent = self)
+ return
+
+ for ext in eList:
+ files = gcmd.RunCommand('g.extension.py', parent = self, read = True, quiet = True,
+ extension = ext, operation = 'remove').splitlines()
+ dlg = wx.MessageDialog(parent = self,
+ message = _("List of files to be removed:\n%(files)s\n\n"
+ "Do you want really to remove <%(ext)s> extension?") % \
+ { 'files' : os.linesep.join(files), 'ext' : ext },
+ caption = _("Remove extension"),
+ style = wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
+
+ if dlg.ShowModal() == wx.ID_YES:
+ gcmd.RunCommand('g.extension.py', flags = 'f', parent = self, quiet = True,
+ extension = ext, operation = 'remove')
+
+ self.extList.LoadData()
+
+ def OnCmdDialog(self, event):
+ """!Shows command dialog"""
+ menuform.GUI(parent = self).ParseCommand(cmd = ['g.extension.py'])
+
+class CheckListExtension(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin, listmix.CheckListCtrlMixin):
+ """!List of mapset/owner/group"""
+ def __init__(self, parent):
+ self.parent = parent
+
+ wx.ListCtrl.__init__(self, parent, id = wx.ID_ANY,
+ style = wx.LC_REPORT)
+ listmix.CheckListCtrlMixin.__init__(self)
+
+ # setup mixins
+ listmix.ListCtrlAutoWidthMixin.__init__(self)
+
+ self.InsertColumn(0, _('Extension'))
+ self.LoadData()
+
+ def LoadData(self):
+ """!Load data into list"""
+ self.DeleteAllItems()
+ for ext in gcmd.RunCommand('g.extension.py',
+ quiet = True, parent = self, read = True,
+ flags = 'a').splitlines():
+ self.InsertStringItem(sys.maxint, ext)
+
+ def GetExtensions(self):
+ """!Get extensions to be un-installed
+ """
+ extList = list()
+ for i in range(self.GetItemCount()):
+ if self.IsChecked(i):
+ name = self.GetItemText(i)
+ if name:
+ extList.append(name)
+
+ return extList
+
class HelpWindow(wx.html.HtmlWindow):
"""!This panel holds the text from GRASS docs.
Modified: grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/goutput.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/goutput.py 2011-12-14 11:38:11 UTC (rev 49737)
+++ grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/goutput.py 2011-12-14 11:57:31 UTC (rev 49738)
@@ -531,7 +531,10 @@
if len(command) == 1:
import menuform
- task = gtask.parse_interface(command[0])
+ try:
+ task = gtask.parse_interface(command[0])
+ except gcmd.ScriptError, e:
+ print >> sys.stderr, e
# if not task.has_required():
# task = None # run command
else:
Modified: grass/branches/releasebranch_6_4/gui/wxpython/wxgui.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/wxgui.py 2011-12-14 11:38:11 UTC (rev 49737)
+++ grass/branches/releasebranch_6_4/gui/wxpython/wxgui.py 2011-12-14 11:57:31 UTC (rev 49738)
@@ -82,7 +82,7 @@
from gui_modules import vclean
from gui_modules import nviz_tools
from gui_modules.debug import Debug
-from gui_modules.ghelp import MenuTreeWindow, AboutWindow, InstallExtensionWindow
+from gui_modules.ghelp import MenuTreeWindow, AboutWindow, InstallExtensionWindow, UninstallExtensionWindow
from gui_modules.toolbars import LMWorkspaceToolbar, LMDataToolbar, LMToolsToolbar, LMMiscToolbar, LMVectorToolbar
from gui_modules.gpyshell import PyShellWindow
from icons.icon import Icons
@@ -1054,6 +1054,12 @@
win.CentreOnScreen()
win.Show()
+ def OnUninstallExtension(self, event):
+ """!Uninstall extension"""
+ win = UninstallExtensionWindow(self, size = (650, 300))
+ win.CentreOnScreen()
+ win.Show()
+
def OnPreferences(self, event):
"""!General GUI preferences/settings
"""
Modified: grass/branches/releasebranch_6_4/gui/wxpython/xml/menudata.xml
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/xml/menudata.xml 2011-12-14 11:38:11 UTC (rev 49737)
+++ grass/branches/releasebranch_6_4/gui/wxpython/xml/menudata.xml 2011-12-14 11:57:31 UTC (rev 49738)
@@ -835,11 +835,18 @@
<separator />
<menuitem>
<label>Install extension from add-ons</label>
- <help>Install new extension from GRASS AddOns SVN repository.</help>
+ <help>Installs new extension from GRASS AddOns SVN repository.</help>
<keywords>general,extensions</keywords>
<handler>OnInstallExtension</handler>
<command>g.extension</command>
</menuitem>
+ <menuitem>
+ <label>Remove extension</label>
+ <help>Removes installed GRASS AddOns extension.</help>
+ <keywords>general,extensions</keywords>
+ <handler>OnUninstallExtension</handler>
+ <command>g.extension</command>
+ </menuitem>
<separator />
<menuitem>
<label>Preferences</label>
More information about the grass-commit
mailing list