Browse Source

wxGUI major code reorganization (part 2)

git-svn-id: https://svn.osgeo.org/grass/grass/trunk@49348 15284696-431f-4ddb-bdfa-cd5b030d7da7
Martin Landa 13 years ago
parent
commit
835020d28a

+ 5 - 4
gui/wxpython/core/menudata.py

@@ -35,7 +35,7 @@ try:
 except ImportError:
 except ImportError:
     import elementtree.ElementTree as etree # Python <= 2.4
     import elementtree.ElementTree as etree # Python <= 2.4
 
 
-from wx import ID_ANY
+import wx
 
 
 if not os.getenv("GISBASE"):
 if not os.getenv("GISBASE"):
     sys.exit("GRASS is not running. Exiting...")
     sys.exit("GRASS is not running. Exiting...")
@@ -75,7 +75,7 @@ class MenuData:
             if wxId != None:
             if wxId != None:
                 wxId = eval('wx.' + wxId.text)
                 wxId = eval('wx.' + wxId.text)
             else:
             else:
-                wxId = ID_ANY
+                wxId = wx.ID_ANY
 	    return (label, help, handler, gcmd, keywords, shortcut, wxId)
 	    return (label, help, handler, gcmd, keywords, shortcut, wxId)
 	elif mi.tag == 'menu':
 	elif mi.tag == 'menu':
 	    return self._getMenu(mi)
 	    return self._getMenu(mi)
@@ -212,11 +212,12 @@ if __name__ == "__main__":
             menu = arg
             menu = arg
     
     
     sys.path.append(os.path.join(os.getenv("GISBASE"), "etc", "gui", "wxpython"))
     sys.path.append(os.path.join(os.getenv("GISBASE"), "etc", "gui", "wxpython"))
+    
     if menu == 'manager':
     if menu == 'manager':
-        from lmgr.menudata import ManagerData
+        from lmgr.menudata     import ManagerData
         data = ManagerData()
         data = ManagerData()
     else:
     else:
-        from gmodeler.frame import ModelerData
+        from gmodeler.menudata import ModelerData
         data = ModelerData()
         data = ModelerData()
     
     
     if action == 'strings':
     if action == 'strings':

+ 28 - 33
gui/wxpython/gis_set.py

@@ -22,7 +22,6 @@ This program is free software under the GNU General Public License
 
 
 import os
 import os
 import sys
 import sys
-import glob
 import shutil
 import shutil
 import copy
 import copy
 import platform
 import platform
@@ -32,17 +31,13 @@ import codecs
 import gettext
 import gettext
 gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode = True)
 gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode = True)
 
 
-from gui_modules import globalvar
+from core import globalvar
 import wx
 import wx
-import wx.html
-import wx.lib.rcsizer as rcs
-import wx.lib.filebrowsebutton as filebrowse
 import wx.lib.mixins.listctrl as listmix
 import wx.lib.mixins.listctrl as listmix
 import wx.lib.scrolledpanel as scrolled
 import wx.lib.scrolledpanel as scrolled
 
 
-from gui_modules import goutput
-from gui_modules.ghelp import HelpFrame
-from gui_modules.gcmd  import GMessage, GError
+from gui_core.ghelp import HelpFrame
+from core.gcmd      import GMessage, GError
 
 
 sys.stderr = codecs.getwriter('utf8')(sys.stderr)
 sys.stderr = codecs.getwriter('utf8')(sys.stderr)
 
 
@@ -369,7 +364,7 @@ class GRASSStartup(wx.Frame):
                 rc = open(gisrc, "r")
                 rc = open(gisrc, "r")
                 for line in rc.readlines():
                 for line in rc.readlines():
                     key, val = line.split(":", 1)
                     key, val = line.split(":", 1)
-                    grassrc[key.strip()] = utils.DecodeString(val.strip())
+                    grassrc[key.strip()] = DecodeString(val.strip())
             finally:
             finally:
                 rc.close()
                 rc.close()
         
         
@@ -385,9 +380,9 @@ class GRASSStartup(wx.Frame):
         
         
     def OnWizard(self, event):
     def OnWizard(self, event):
         """!Location wizard started"""
         """!Location wizard started"""
-        from gui_modules import location_wizard
-        gWizard = location_wizard.LocationWizard(parent = self,
-                                                 grassdatabase = self.tgisdbase.GetValue())
+        from location_wizard.wizard import LocationWizard
+        gWizard = LocationWizard(parent = self,
+                                 grassdatabase = self.tgisdbase.GetValue())
         if gWizard.location !=  None:
         if gWizard.location !=  None:
             self.OnSetDatabase(event)
             self.OnSetDatabase(event)
             self.UpdateMapsets(os.path.join(self.gisdbase, gWizard.location))
             self.UpdateMapsets(os.path.join(self.gisdbase, gWizard.location))
@@ -544,7 +539,7 @@ class GRASSStartup(wx.Frame):
     def UpdateLocations(self, dbase):
     def UpdateLocations(self, dbase):
         """!Update list of locations"""
         """!Update list of locations"""
         try:
         try:
-            self.listOfLocations = utils.GetListOfLocations(dbase)
+            self.listOfLocations = GetListOfLocations(dbase)
         except UnicodeEncodeError:
         except UnicodeEncodeError:
             wx.MessageBox(parent = self, caption = _("Error"),
             wx.MessageBox(parent = self, caption = _("Error"),
                           message = _("Unable to set GRASS database. "
                           message = _("Unable to set GRASS database. "
@@ -566,29 +561,29 @@ class GRASSStartup(wx.Frame):
         self.FormerMapsetSelection = wx.NOT_FOUND # for non-selectable item
         self.FormerMapsetSelection = wx.NOT_FOUND # for non-selectable item
         
         
         self.listOfMapsetsSelectable = list()
         self.listOfMapsetsSelectable = list()
-        self.listOfMapsets = utils.GetListOfMapsets(self.gisdbase, location)
+        self.listOfMapsets = GetListOfMapsets(self.gisdbase, location)
         
         
         self.lbmapsets.Clear()
         self.lbmapsets.Clear()
         
         
         # disable mapset with denied permission
         # disable mapset with denied permission
         locationName = os.path.basename(location)
         locationName = os.path.basename(location)
         
         
-        ret = gcmd.RunCommand('g.mapset',
-                              read = True,
-                              flags = 'l',
-                              location = locationName,
-                              gisdbase = self.gisdbase)
+        ret = RunCommand('g.mapset',
+                         read = True,
+                         flags = 'l',
+                         location = locationName,
+                         gisdbase = self.gisdbase)
             
             
         if ret:
         if ret:
             for line in ret.splitlines():
             for line in ret.splitlines():
                 self.listOfMapsetsSelectable += line.split(' ')
                 self.listOfMapsetsSelectable += line.split(' ')
         else:
         else:
-            gcmd.RunCommand("g.gisenv",
-                            set = "GISDBASE=%s" % self.gisdbase)
-            gcmd.RunCommand("g.gisenv",
-                            set = "LOCATION_NAME=%s" % locationName)
-            gcmd.RunCommand("g.gisenv",
-                            set = "MAPSET=PERMANENT")
+            RunCommand("g.gisenv",
+                       set = "GISDBASE=%s" % self.gisdbase)
+            RunCommand("g.gisenv",
+                       set = "LOCATION_NAME=%s" % locationName)
+            RunCommand("g.gisenv",
+                       set = "MAPSET=PERMANENT")
             # first run only
             # first run only
             self.listOfMapsetsSelectable = copy.copy(self.listOfMapsets)
             self.listOfMapsetsSelectable = copy.copy(self.listOfMapsets)
         
         
@@ -772,12 +767,12 @@ class GRASSStartup(wx.Frame):
             else:
             else:
                 return
                 return
         
         
-        gcmd.RunCommand("g.gisenv",
-                        set = "GISDBASE=%s" % dbase)
-        gcmd.RunCommand("g.gisenv",
-                        set = "LOCATION_NAME=%s" % location)
-        gcmd.RunCommand("g.gisenv",
-                        set = "MAPSET=%s" % mapset)
+        RunCommand("g.gisenv",
+                   set = "GISDBASE=%s" % dbase)
+        RunCommand("g.gisenv",
+                   set = "LOCATION_NAME=%s" % location)
+        RunCommand("g.gisenv",
+                   set = "MAPSET=%s" % mapset)
         
         
         self.Destroy()
         self.Destroy()
         sys.exit(0)
         sys.exit(0)
@@ -885,8 +880,8 @@ if __name__ ==  "__main__":
         import gettext
         import gettext
         gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode = True)
         gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode = True)
 
 
-        import gui_modules.gcmd as gcmd
-        import gui_modules.utils as utils
+        from core.gcmd  import RunCommand, DecodeString
+        from core.utils import GetListOfMapsets, GetListOfLocations
 
 
         GRASSStartUp = StartUp(0)
         GRASSStartUp = StartUp(0)
         GRASSStartUp.MainLoop()
         GRASSStartUp.MainLoop()

+ 0 - 10
gui/wxpython/gmodeler/frame.py

@@ -4,7 +4,6 @@
 @brief wxGUI Graphical Modeler for creating, editing, and managing models
 @brief wxGUI Graphical Modeler for creating, editing, and managing models
 
 
 Classes:
 Classes:
- - ModelerData
  - ModelToolbar
  - ModelToolbar
  - ModelFrame
  - ModelFrame
  - ModelCanvas
  - ModelCanvas
@@ -57,15 +56,6 @@ from gui_core.toolbars    import BaseToolbar
 
 
 from grass.script import core as grass
 from grass.script import core as grass
 
 
-class ModelerData(MenuData):
-    def __init__(self, filename = None):
-        if not filename:
-            gisbase = os.getenv('GISBASE')
-            global etcwxdir
-	    filename = os.path.join(globalvar.ETCWXDIR, 'xml', 'menudata_modeler.xml')
-        
-        MenuData.__init__(self, filename)
-
 class ModelToolbar(BaseToolbar):
 class ModelToolbar(BaseToolbar):
     """!Graphical modeler toolbaro (see gmodeler.py)
     """!Graphical modeler toolbaro (see gmodeler.py)
     """
     """

+ 28 - 0
gui/wxpython/gmodeler/menudata.py

@@ -0,0 +1,28 @@
+"""!
+@package gmodeler.menudata
+
+@brief wxGUI Graphical Modeler - menu data
+
+Classes:
+ - ModelerData
+
+(C) 2010-2011 by the GRASS Development Team
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+@author Martin Landa <landa.martin gmail.com>
+"""
+
+import os
+
+from core                 import globalvar
+from core.menudata        import MenuData
+
+class ModelerData(MenuData):
+    def __init__(self, filename = None):
+        if not filename:
+            gisbase = os.getenv('GISBASE')
+	    filename = os.path.join(globalvar.ETCWXDIR, 'xml', 'menudata_modeler.xml')
+        
+        MenuData.__init__(self, filename)
+

+ 1 - 1
gui/wxpython/gmodeler/model_file.py

@@ -19,7 +19,7 @@ import os
 import time
 import time
 import re
 import re
 
 
-from gui_core.forms import GUI
+from gui_core.task  import GUI
 from core.gcmd      import GWarning, EncodeString
 from core.gcmd      import GWarning, EncodeString
 
 
 class ProcessModelFile:
 class ProcessModelFile:

+ 1 - 32
gui/wxpython/gui_core/dialogs.py

@@ -48,7 +48,7 @@ from grass.script import task as gtask
 from core             import globalvar
 from core             import globalvar
 from core.gcmd        import GError, RunCommand, GMessage
 from core.gcmd        import GError, RunCommand, GMessage
 from gui_core.gselect import ElementSelect, LocationSelect, MapsetSelect, Select, OgrTypeSelect, GdalSelect
 from gui_core.gselect import ElementSelect, LocationSelect, MapsetSelect, Select, OgrTypeSelect, GdalSelect
-from core.forms       import GUI
+from gui_core.task    import GUI
 from core.utils       import GetListOfMapsets, GetLayerNameFromCmd, GetValidLayerName
 from core.utils       import GetListOfMapsets, GetLayerNameFromCmd, GetValidLayerName
 from core.settings    import UserSettings
 from core.settings    import UserSettings
 from core.debug       import Debug
 from core.debug       import Debug
@@ -2224,37 +2224,6 @@ def GetImageHandlers(image):
     
     
     return filetype, ltype
     return filetype, ltype
 
 
-class StaticWrapText(wx.StaticText):
-    """!A Static Text field that wraps its text to fit its width,
-    enlarging its height if necessary.
-    """
-    def __init__(self, parent, id = wx.ID_ANY, label = '', *args, **kwds):
-        self.parent        = parent
-        self.originalLabel = label
-        
-        wx.StaticText.__init__(self, parent, id, label = '', *args, **kwds)
-        
-        self.SetLabel(label)
-        self.Bind(wx.EVT_SIZE, self.OnResize)
-    
-    def SetLabel(self, label):
-        self.originalLabel = label
-        self.wrappedSize = None
-        self.OnResize(None)
-
-    def OnResize(self, event):
-        if not getattr(self, "resizing", False):
-            self.resizing = True
-            newSize = wx.Size(self.parent.GetSize().width - 50,
-                              self.GetSize().height)
-            if self.wrappedSize != newSize:
-                wx.StaticText.SetLabel(self, self.originalLabel)
-                self.Wrap(newSize.width)
-                self.wrappedSize = newSize
-                
-                self.SetSize(self.wrappedSize)
-            del self.resizing
-
 class ImageSizeDialog(wx.Dialog):
 class ImageSizeDialog(wx.Dialog):
     """!Set size for saved graphic file"""
     """!Set size for saved graphic file"""
     def __init__(self, parent, id = wx.ID_ANY, title = _("Set image size"),
     def __init__(self, parent, id = wx.ID_ANY, title = _("Set image size"),

+ 10 - 239
gui/wxpython/gui_core/forms.py

@@ -11,7 +11,6 @@ Classes:
  - GrassGUIApp
  - GrassGUIApp
  - GUI
  - GUI
  - FloatValidator
  - FloatValidator
- - GNotebook
 
 
 This program is just a coarse approach to automatically build a GUI
 This program is just a coarse approach to automatically build a GUI
 from a xml-based GRASS user interface description.
 from a xml-based GRASS user interface description.
@@ -46,13 +45,11 @@ COPYING coming with GRASS for details.
 """
 """
 
 
 import sys
 import sys
-import re
 import string
 import string
 import textwrap
 import textwrap
 import os
 import os
 import time
 import time
 import copy
 import copy
-import locale
 from threading import Thread
 from threading import Thread
 import Queue
 import Queue
 
 
@@ -65,17 +62,8 @@ except ImportError:
 import wx.lib.colourselect     as csel
 import wx.lib.colourselect     as csel
 import wx.lib.filebrowsebutton as filebrowse
 import wx.lib.filebrowsebutton as filebrowse
 import wx.lib.scrolledpanel    as scrolled
 import wx.lib.scrolledpanel    as scrolled
-from wx.lib.expando  import ExpandoTextCtrl, EVT_ETC_LAYOUT_NEEDED
 from wx.lib.newevent import NewEvent
 from wx.lib.newevent import NewEvent
 
 
-try:
-    import xml.etree.ElementTree as etree
-except ImportError:
-    import elementtree.ElementTree as etree # Python <= 2.4
-
-from gui_core.dialogs import StaticWrapText
-from gui_core.ghelp   import HelpPanel
-
 gisbase = os.getenv("GISBASE")
 gisbase = os.getenv("GISBASE")
 if gisbase is None:
 if gisbase is None:
     print >>sys.stderr, "We don't seem to be properly installed, or we are being run outside GRASS. Expect glitches."
     print >>sys.stderr, "We don't seem to be properly installed, or we are being run outside GRASS. Expect glitches."
@@ -89,15 +77,15 @@ sys.path.append(wxbase)
 from grass.script import core as grass
 from grass.script import core as grass
 from grass.script import task as gtask
 from grass.script import task as gtask
 
 
-from gui_core import gselect
-from core import cmd as gcmd
-from gui_core import goutput
-from core import utils
-from core.settings import UserSettings
-try:
-    import subprocess
-except:
-    from compat import subprocess
+from gui_core.widgets import StaticWrapText
+from gui_core.ghelp   import HelpPanel
+from gui_core         import gselect
+from core             import gcmd
+from core             import utils
+from gui_core.goutput import GMConsole
+from core.settings    import UserSettings
+from gui_core.widgets import FloatValidator
+from gui_core.task    import GUI
 
 
 wxUpdateDialog, EVT_DIALOG_UPDATE = NewEvent()
 wxUpdateDialog, EVT_DIALOG_UPDATE = NewEvent()
 
 
@@ -834,7 +822,7 @@ class cmdPanel(wx.Panel):
         # are we running from command line?
         # are we running from command line?
         ### add 'command output' tab regardless standalone dialog
         ### add 'command output' tab regardless standalone dialog
         if self.parent.GetName() ==  "MainFrame" and self.parent.get_dcmd is None:
         if self.parent.GetName() ==  "MainFrame" and self.parent.get_dcmd is None:
-            self.goutput = goutput.GMConsole(parent = self, margin = False)
+            self.goutput = GMConsole(parent = self, margin = False)
             self.outpage = self.notebook.AddPage(page = self.goutput, text = _("Command output"), name = 'output')
             self.outpage = self.notebook.AddPage(page = self.goutput, text = _("Command output"), name = 'output')
         else:
         else:
             self.goutput = None
             self.goutput = None
@@ -1943,223 +1931,6 @@ class GrassGUIApp(wx.App):
         
         
         return True
         return True
 
 
-class GUI:
-    def __init__(self, parent = None, show = True, modal = False,
-                 centreOnParent = False, checkError = False):
-        """!Parses GRASS commands when module is imported and used from
-        Layer Manager.
-        """
-        self.parent = parent
-        self.show   = show
-        self.modal  = modal
-        self.centreOnParent = centreOnParent
-        self.checkError     = checkError
-        
-        self.grass_task = None
-        self.cmd = list()
-        
-        global _blackList
-        if self.parent:
-            _blackList['enabled'] = True
-        else:
-            _blackList['enabled'] = False
-        
-    def GetCmd(self):
-        """!Get validated command"""
-        return self.cmd
-    
-    def ParseCommand(self, cmd, gmpath = None, completed = None):
-        """!Parse command
-        
-        Note: cmd is given as list
-        
-        If command is given with options, return validated cmd list:
-         - add key name for first parameter if not given
-         - change mapname to mapname@mapset
-        """
-        start = time.time()
-        dcmd_params = {}
-        if completed == None:
-            get_dcmd = None
-            layer = None
-            dcmd_params = None
-        else:
-            get_dcmd = completed[0]
-            layer = completed[1]
-            if completed[2]:
-                dcmd_params.update(completed[2])
-        
-        # parse the interface decription
-        try:
-            global _blackList
-            self.grass_task = gtask.parse_interface(cmd[0],
-                                                    blackList = _blackList)
-        except ValueError, e: #grass.ScriptError, e:
-            gcmd.GError(e.value)
-            return
-        
-        # if layer parameters previously set, re-insert them into dialog
-        if completed is not None:
-            if 'params' in dcmd_params:
-                self.grass_task.params = dcmd_params['params']
-            if 'flags' in dcmd_params:
-                self.grass_task.flags = dcmd_params['flags']
-        
-        err = list()
-        # update parameters if needed && validate command
-        if len(cmd) > 1:
-            i = 0
-            cmd_validated = [cmd[0]]
-            for option in cmd[1:]:
-                if option[0] ==  '-': # flag
-                    if option[1] ==  '-':
-                        self.grass_task.set_flag(option[2:], True)
-                    else:
-                        self.grass_task.set_flag(option[1], True)
-                    cmd_validated.append(option)
-                else: # parameter
-                    try:
-                        key, value = option.split('=', 1)
-                    except:
-                        if self.grass_task.firstParam:
-                            if i == 0: # add key name of first parameter if not given
-                                key = self.grass_task.firstParam
-                                value = option
-                            else:
-                                raise gcmd.GException, _("Unable to parse command '%s'") % ' '.join(cmd)
-                        else:
-                            continue
-                    
-                    element = self.grass_task.get_param(key, raiseError = False)
-                    if not element:
-                        err.append(_("%(cmd)s: parameter '%(key)s' not available") % \
-                                       { 'cmd' : cmd[0],
-                                         'key' : key })
-                        continue
-                    element = element['element']
-                    
-                    if element in ['cell', 'vector']:
-                        # mapname -> mapname@mapset
-                        try:
-                            name, mapset = value.split('@')
-                        except ValueError:
-                            mapset = grass.find_file(value, element)['mapset']
-                            curr_mapset = grass.gisenv()['MAPSET']
-                            if mapset and mapset !=  curr_mapset:
-                                value = value + '@' + mapset
-                    
-                    self.grass_task.set_param(key, value)
-                    cmd_validated.append(key + '=' + value)
-                    i += 1
-            
-            # update original command list
-            cmd = cmd_validated
-        
-        if self.show is not None:
-            self.mf = mainFrame(parent = self.parent, ID = wx.ID_ANY,
-                                task_description = self.grass_task,
-                                get_dcmd = get_dcmd, layer = layer)
-        else:
-            self.mf = None
-        
-        if get_dcmd is not None:
-            # update only propwin reference
-            get_dcmd(dcmd = None, layer = layer, params = None,
-                     propwin = self.mf)
-        
-        if self.show is not None:
-            self.mf.notebookpanel.OnUpdateSelection(None)
-            if self.show is True:
-                if self.parent and self.centreOnParent:
-                    self.mf.CentreOnParent()
-                else:
-                    self.mf.CenterOnScreen()
-                self.mf.Show(self.show)
-                self.mf.MakeModal(self.modal)
-            else:
-                self.mf.OnApply(None)
-        
-        self.cmd = cmd
-        
-        if self.checkError:
-            return self.grass_task, err
-        else:
-            return self.grass_task
-    
-    def GetCommandInputMapParamKey(self, cmd):
-        """!Get parameter key for input raster/vector map
-        
-        @param cmd module name
-        
-        @return parameter key
-        @return None on failure
-        """
-        # parse the interface decription
-        if not self.grass_task:
-            enc = locale.getdefaultlocale()[1]
-            if enc and enc.lower() == "cp932":
-                p = re.compile('encoding="' + enc + '"', re.IGNORECASE)
-                tree = etree.fromstring(p.sub('encoding="utf-8"',
-                                              gtask.get_interface_description(cmd).decode(enc).encode('utf-8')))
-            else:
-                tree = etree.fromstring(gtask.get_interface_description(cmd))
-            self.grass_task = gtask.processTask(tree).get_task()
-            
-            for p in self.grass_task.params:
-                if p.get('name', '') in ('input', 'map'):
-                    age = p.get('age', '')
-                    prompt = p.get('prompt', '')
-                    element = p.get('element', '') 
-                    if age ==  'old' and \
-                            element in ('cell', 'grid3', 'vector') and \
-                            prompt in ('raster', '3d-raster', 'vector'):
-                        return p.get('name', None)
-        return None
-
-class FloatValidator(wx.PyValidator):
-    """!Validator for floating-point input"""
-    def __init__(self):
-        wx.PyValidator.__init__(self)
-        
-        self.Bind(wx.EVT_TEXT, self.OnText) 
-        
-    def Clone(self):
-        """!Clone validator"""
-        return FloatValidator()
-
-    def Validate(self):
-        """Validate input"""
-        textCtrl = self.GetWindow()
-        text = textCtrl.GetValue()
-
-        if text:
-            try:
-                float(text)
-            except ValueError:
-                textCtrl.SetBackgroundColour("grey")
-                textCtrl.SetFocus()
-                textCtrl.Refresh()
-                return False
-        
-        sysColor = wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW)
-        textCtrl.SetBackgroundColour(sysColor)
-        
-        textCtrl.Refresh()
-        
-        return True
-
-    def OnText(self, event):
-        """!Do validation"""
-        self.Validate()
-        
-        event.Skip()
-        
-    def TransferToWindow(self):
-        return True # Prevent wxDialog from complaining.
-    
-    def TransferFromWindow(self):
-        return True # Prevent wxDialog from complaining.
-
 if __name__ ==  "__main__":
 if __name__ ==  "__main__":
     import gettext
     import gettext
     gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode = True)
     gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode = True)

+ 8 - 420
gui/wxpython/gui_core/ghelp.py

@@ -5,12 +5,9 @@
 
 
 Classes:
 Classes:
  - SearchModuleWindow
  - SearchModuleWindow
- - ItemTree
  - MenuTreeWindow
  - MenuTreeWindow
  - MenuTree
  - MenuTree
  - AboutWindow
  - AboutWindow
- - InstallExtensionWindow
- - ExtensionTree
  - HelpFrame
  - HelpFrame
  - HelpWindow
  - HelpWindow
  - HelpPanel
  - HelpPanel
@@ -26,6 +23,7 @@ import os
 import codecs
 import codecs
 
 
 import wx
 import wx
+from wx.html import HtmlWindow
 try:
 try:
     import wx.lib.agw.customtreectrl as CT
     import wx.lib.agw.customtreectrl as CT
     from wx.lib.agw.hyperlink import HyperLinkCtrl
     from wx.lib.agw.hyperlink import HyperLinkCtrl
@@ -33,18 +31,15 @@ except ImportError:
     import wx.lib.customtreectrl as CT
     import wx.lib.customtreectrl as CT
     from wx.lib.hyperlink import HyperLinkCtrl
     from wx.lib.hyperlink import HyperLinkCtrl
 import wx.lib.flatnotebook as FN
 import wx.lib.flatnotebook as FN
-import  wx.lib.scrolledpanel as scrolled
+import wx.lib.scrolledpanel as scrolled
 
 
 import grass.script as grass
 import grass.script as grass
-from grass.script import task as gtask
 
 
 from core             import globalvar
 from core             import globalvar
 from core             import utils
 from core             import utils
 from lmgr.menudata    import ManagerData
 from lmgr.menudata    import ManagerData
-from core.gcmd        import GError, RunCommand, DecodeString
-from gui_core.widgets import GNotebook
-from core.forms       import GUI
-from gui_core.dialogs import StaticWrapText
+from core.gcmd        import GError, DecodeString
+from gui_core.widgets import GNotebook, StaticWrapText, ItemTree
 
 
 class HelpFrame(wx.Frame):
 class HelpFrame(wx.Frame):
     """!GRASS Quickstart help window"""
     """!GRASS Quickstart help window"""
@@ -350,85 +345,6 @@ class MenuTreeWindow(wx.Panel):
         
         
         event.Skip()
         event.Skip()
         
         
-class ItemTree(CT.CustomTreeCtrl):
-    def __init__(self, parent, id = wx.ID_ANY,
-                 ctstyle = CT.TR_HIDE_ROOT | CT.TR_FULL_ROW_HIGHLIGHT | CT.TR_HAS_BUTTONS |
-                 CT.TR_LINES_AT_ROOT | CT.TR_SINGLE, **kwargs):
-        if globalvar.hasAgw:
-            super(ItemTree, self).__init__(parent, id, agwStyle = ctstyle, **kwargs)
-        else:
-            super(ItemTree, self).__init__(parent, id, style = ctstyle, **kwargs)
-        
-        self.root = self.AddRoot(_("Menu tree"))
-        self.itemsMarked = [] # list of marked items
-        self.itemSelected = None
-
-    def SearchItems(self, element, value):
-        """!Search item 
-
-        @param element element index (see self.searchBy)
-        @param value
-
-        @return list of found tree items
-        """
-        items = list()
-        if not value:
-            return items
-        
-        item = self.GetFirstChild(self.root)[0]
-        self._processItem(item, element, value, items)
-        
-        self.itemsMarked  = items
-        self.itemSelected = None
-        
-        return items
-    
-    def _processItem(self, item, element, value, listOfItems):
-        """!Search items (used by SearchItems)
-        
-        @param item reference item
-        @param listOfItems list of found items
-        """
-        while item and item.IsOk():
-            subItem = self.GetFirstChild(item)[0]
-            if subItem:
-                self._processItem(subItem, element, value, listOfItems)
-            data = self.GetPyData(item)
-            
-            if data and element in data and \
-                    value.lower() in data[element].lower():
-                listOfItems.append(item)
-            
-            item = self.GetNextSibling(item)
-            
-    def GetSelected(self):
-        """!Get selected item"""
-        return self.itemSelected
-
-    def OnShowItem(self, event):
-        """!Highlight first found item in menu tree"""
-        if len(self.itemsMarked) > 0:
-            if self.GetSelected():
-                self.ToggleItemSelection(self.GetSelected())
-                idx = self.itemsMarked.index(self.GetSelected()) + 1
-            else:
-                idx = 0
-            try:
-                self.ToggleItemSelection(self.itemsMarked[idx])
-                self.itemSelected = self.itemsMarked[idx]
-                self.EnsureVisible(self.itemsMarked[idx])
-            except IndexError:
-                self.ToggleItemSelection(self.itemsMarked[0]) # reselect first item
-                self.EnsureVisible(self.itemsMarked[0])
-                self.itemSelected = self.itemsMarked[0]
-        else:
-            for item in self.root.GetChildren():
-                self.Collapse(item)
-            itemSelected = self.GetSelection()
-            if itemSelected:
-                self.ToggleItemSelection(itemSelected)
-            self.itemSelected = None
-    
 class MenuTree(ItemTree):
 class MenuTree(ItemTree):
     """!Menu tree class"""
     """!Menu tree class"""
     def __init__(self, parent, data, **kwargs):
     def __init__(self, parent, data, **kwargs):
@@ -686,7 +602,7 @@ class AboutWindow(wx.Frame):
                 GError(parent = self,
                 GError(parent = self,
                        message = _("Error when reading file '%s'.") % contribfile + \
                        message = _("Error when reading file '%s'.") % contribfile + \
                            "\n\n" + _("Lines:") + " %s" % \
                            "\n\n" + _("Lines:") + " %s" % \
-                           os.linesep.join(map(utils.DecodeString, errLines)))
+                           os.linesep.join(map(DecodeString, errLines)))
         else:
         else:
             contribs = None
             contribs = None
         
         
@@ -746,7 +662,7 @@ class AboutWindow(wx.Frame):
                 GError(parent = self,
                 GError(parent = self,
                        message = _("Error when reading file '%s'.") % translatorsfile + \
                        message = _("Error when reading file '%s'.") % translatorsfile + \
                            "\n\n" + _("Lines:") + " %s" % \
                            "\n\n" + _("Lines:") + " %s" % \
-                           os.linesep.join(map(utils.DecodeString, errLines)))
+                           os.linesep.join(map(DecodeString, errLines)))
         else:
         else:
             translators = None
             translators = None
         
         
@@ -793,335 +709,7 @@ class AboutWindow(wx.Frame):
         """!Close window"""
         """!Close window"""
         self.Close()
         self.Close()
 
 
-class InstallExtensionWindow(wx.Frame):
-    def __init__(self, parent, id = wx.ID_ANY,
-                 title = _("Fetch & install extension from GRASS Addons"), **kwargs):
-        self.parent = parent
-        self.options = dict() # list of options
-        
-        wx.Frame.__init__(self, parent = parent, id = id, title = title, **kwargs)
-        
-        self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
-
-        self.repoBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
-                                    label = " %s " % _("Repository"))
-        self.treeBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
-                                    label = " %s " % _("List of extensions"))
-        
-        self.repo = wx.TextCtrl(parent = self.panel, id = wx.ID_ANY)
-        self.fullDesc = wx.CheckBox(parent = self.panel, id = wx.ID_ANY,
-                                    label = _("Fetch full info including description and keywords (takes time)"))
-        self.fullDesc.SetValue(True)
-        
-        self.search = SearchModuleWindow(parent = self.panel)
-        self.search.SetSelection(0) 
-        
-        self.tree   = ExtensionTree(parent = self.panel, log = parent.GetLogWindow())
-        
-        self.optionBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
-                                      label = " %s " % _("Options"))
-        task = gtask.parse_interface('g.extension')
-        for f in task.get_options()['flags']:
-            name = f.get('name', '')
-            desc = f.get('label', '')
-            if not desc:
-                desc = f.get('description', '')
-            if not name and not desc:
-                continue
-            if name in ('l', 'c', 'g', 'quiet', 'verbose'):
-                continue
-            self.options[name] = wx.CheckBox(parent = self.panel, id = wx.ID_ANY,
-                                             label = desc)
-        self.repo.SetValue(task.get_param(value = 'svnurl').get('default',
-                                                                'http://svn.osgeo.org/grass/grass-addons/grass7'))
-        
-        self.statusbar = self.CreateStatusBar(number = 1)
-        
-        self.btnFetch = wx.Button(parent = self.panel, id = wx.ID_ANY,
-                                  label = _("&Fetch"))
-        self.btnFetch.SetToolTipString(_("Fetch list of available modules from GRASS Addons SVN repository"))
-        self.btnClose = wx.Button(parent = self.panel, id = wx.ID_CLOSE)
-        self.btnInstall = wx.Button(parent = self.panel, id = wx.ID_ANY,
-                                    label = _("&Install"))
-        self.btnInstall.SetToolTipString(_("Install selected add-ons GRASS module"))
-        self.btnInstall.Enable(False)
-        self.btnCmd = wx.Button(parent = self.panel, id = wx.ID_ANY,
-                                label = _("Command dialog"))
-        self.btnCmd.SetToolTipString(_('Open %s dialog') % 'g.extension')
-
-        self.btnClose.Bind(wx.EVT_BUTTON, self.OnCloseWindow)
-        self.btnFetch.Bind(wx.EVT_BUTTON, self.OnFetch)
-        self.btnInstall.Bind(wx.EVT_BUTTON, self.OnInstall)
-        self.btnCmd.Bind(wx.EVT_BUTTON, self.OnCmdDialog)
-        self.tree.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnItemActivated)
-        self.tree.Bind(wx.EVT_TREE_SEL_CHANGED,    self.OnItemSelected)
-        self.search.Bind(wx.EVT_TEXT_ENTER,        self.OnShowItem)
-        self.search.Bind(wx.EVT_TEXT,              self.OnUpdateStatusBar)
-
-        self._layout()
-
-    def _layout(self):
-        """!Do layout"""
-        sizer = wx.BoxSizer(wx.VERTICAL)
-        repoSizer = wx.StaticBoxSizer(self.repoBox, wx.VERTICAL)
-        repo1Sizer = wx.BoxSizer(wx.HORIZONTAL)
-        repo1Sizer.Add(item = self.repo, proportion = 1,
-                      flag = wx.ALL | wx.ALIGN_CENTER_VERTICAL, border = 1)
-        repo1Sizer.Add(item = self.btnFetch, proportion = 0,
-                      flag = wx.ALL | wx.ALIGN_CENTER_VERTICAL, border = 1)
-        repoSizer.Add(item = repo1Sizer,
-                      flag = wx.EXPAND)
-        repoSizer.Add(item = self.fullDesc)
-        
-        findSizer = wx.BoxSizer(wx.HORIZONTAL)
-        findSizer.Add(item = self.search, proportion = 1)
-        
-        treeSizer = wx.StaticBoxSizer(self.treeBox, wx.HORIZONTAL)
-        treeSizer.Add(item = self.tree, proportion = 1,
-                      flag = wx.ALL | wx.EXPAND, border = 1)
-
-        # options
-        optionSizer = wx.StaticBoxSizer(self.optionBox, wx.VERTICAL)
-        for key in self.options.keys():
-            optionSizer.Add(item = self.options[key], proportion = 0)
-        
-        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.btnInstall, proportion = 0)
-        
-        sizer.Add(item = repoSizer, proportion = 0,
-                  flag = wx.ALL | wx.EXPAND, border = 3)
-        sizer.Add(item = findSizer, proportion = 0,
-                  flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 3)
-        sizer.Add(item = treeSizer, proportion = 1,
-                  flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 3)
-        sizer.Add(item = optionSizer, proportion = 0,
-                        flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | 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 _getCmd(self):
-        item = self.tree.GetSelected()
-        if not item or not item.IsOk():
-            return ['g.extension']
-        
-        name = self.tree.GetItemText(item)
-        if not name:
-            GError(_("Extension not defined"), parent = self)
-            return
-        
-        flags = list()
-        for key in self.options.keys():
-            if self.options[key].IsChecked():
-                flags.append('-%s' % key)
-        
-        return ['g.extension'] + flags + ['extension=' + name,
-                                          'svnurl=' + self.repo.GetValue().strip()]
-    
-    def OnUpdateStatusBar(self, event):
-        """!Update statusbar text"""
-        element = self.search.GetSelection()
-        if not self.tree.IsLoaded():
-            self.SetStatusText(_("Fetch list of available extensions by clicking on 'Fetch' button"), 0)
-            return
-        
-        self.tree.SearchItems(element = element,
-                              value = event.GetString())
-        
-        nItems = len(self.tree.itemsMarked)
-        if event.GetString():
-            self.SetStatusText(_("%d items match") % nItems, 0)
-        else:
-            self.SetStatusText("", 0)
-        
-        event.Skip()
-    
-    def OnCloseWindow(self, event):
-        """!Close window"""
-        self.Destroy()
-
-    def OnFetch(self, event):
-        """!Fetch list of available extensions"""
-        wx.BeginBusyCursor()
-        self.SetStatusText(_("Fetching list of modules from GRASS-Addons SVN (be patient)..."), 0)
-        self.tree.Load(url = self.repo.GetValue().strip(), full = self.fullDesc.IsChecked())
-        self.SetStatusText("", 0)
-        wx.EndBusyCursor()
-
-    def OnItemActivated(self, event):
-        item = event.GetItem()
-        data = self.tree.GetPyData(item)
-        if data and 'command' in data:
-            self.OnInstall(event = None)
-        
-    def OnInstall(self, event):
-        """!Install selected extension"""
-        log = self.parent.GetLogWindow()
-        log.RunCmd(self._getCmd(), onDone = self.OnDone)
-        
-    def OnDone(self, cmd, returncode):
-        item = self.tree.GetSelected()
-        if not item or not item.IsOk() or \
-                returncode != 0 or \
-                not os.getenv('GRASS_ADDON_PATH'):
-            return
-        
-        name = self.tree.GetItemText(item)
-        globalvar.grassCmd['all'].append(name)
-        
-    def OnItemSelected(self, event):
-        """!Item selected"""
-        item = event.GetItem()
-        self.tree.itemSelected = item
-        data = self.tree.GetPyData(item)
-        if not data:
-            self.SetStatusText('', 0)
-            self.btnInstall.Enable(False)
-        else:
-            self.SetStatusText(data.get('description', ''), 0)
-            self.btnInstall.Enable(True)
-
-    def OnShowItem(self, event):
-        """!Show selected item"""
-        self.tree.OnShowItem(event)
-        if self.tree.GetSelected():
-            self.btnInstall.Enable()
-        else:
-            self.btnInstall.Enable(False)
-
-    def OnCmdDialog(self, event):
-        """!Shows command dialog"""
-        GUI(parent = self).ParseCommand(cmd = self._getCmd())
-        
-class ExtensionTree(ItemTree):
-    """!List of available extensions"""
-    def __init__(self, parent, log, id = wx.ID_ANY,
-                 ctstyle = CT.TR_HIDE_ROOT | CT.TR_FULL_ROW_HIGHLIGHT | CT.TR_HAS_BUTTONS |
-                 CT.TR_LINES_AT_ROOT | CT.TR_SINGLE,
-                 **kwargs):
-        self.parent = parent # GMFrame
-        self.log    = log
-        
-        super(ExtensionTree, self).__init__(parent, id, ctstyle = ctstyle, **kwargs)
-        
-        self._initTree()
-        
-    def _initTree(self):
-        for prefix in ('display', 'database',
-                       'general', 'imagery',
-                       'misc', 'postscript', 'paint',
-                       'raster', 'raster3D', 'sites', 'vector', 'wxGUI', 'other'):
-            self.AppendItem(parentId = self.root,
-                            text = prefix)
-        self._loaded = False
-        
-    def _expandPrefix(self, c):
-        name = { 'd'  : 'display',
-                 'db' : 'database',
-                 'g'  : 'general',
-                 'i'  : 'imagery',
-                 'm'  : 'misc',
-                 'ps' : 'postscript',
-                 'p'  : 'paint',
-                 'r'  : 'raster',
-                 'r3' : 'raster3D',
-                 's'  : 'sites',
-                 'v'  : 'vector',
-                 'wx' : 'wxGUI',
-                 'u'  : 'other' }
-        
-        if c in name:
-            return name[c]
-        
-        return c
-    
-    def _findItem(self, text):
-        """!Find item"""
-        item = self.GetFirstChild(self.root)[0]
-        while item and item.IsOk():
-            if text == self.GetItemText(item):
-                return item
-            
-            item = self.GetNextSibling(item)
-        
-        return None
-    
-    def Load(self, url, full = False):
-        """!Load list of extensions"""
-        self.DeleteAllItems()
-        self.root = self.AddRoot(_("Menu tree"))
-        self._initTree()
-        
-        if full:
-            flags = 'g'
-        else:
-            flags = 'l'
-        ret = RunCommand('g.extension', read = True,
-                         svnurl = url,
-                         flags = flags, quiet = True)
-        if not ret:
-            return
-        
-        mdict = dict()
-        for line in ret.splitlines():
-            if full:
-                key, value = line.split('=', 1)
-                if key == 'name':
-                    try:
-                        prefix, name = value.split('.', 1)
-                    except ValueError:
-                        prefix = 'u'
-                        name = value
-                    if prefix not in mdict:
-                        mdict[prefix] = dict()
-                    mdict[prefix][name] = dict()
-                else:
-                    mdict[prefix][name][key] = value
-            else:
-                try:
-                    prefix, name = line.strip().split('.', 1)
-                except:
-                    prefix = 'unknown'
-                    name = line.strip()
-                
-                if self._expandPrefix(prefix) == prefix:
-                    prefix = 'unknown'
-                    
-                if prefix not in mdict:
-                    mdict[prefix] = dict()
-                    
-                mdict[prefix][name] = { 'command' : prefix + '.' + name }
-        
-        for prefix in mdict.keys():
-            prefixName = self._expandPrefix(prefix)
-            item = self._findItem(prefixName)
-            names = mdict[prefix].keys()
-            names.sort()
-            for name in names:
-                new = self.AppendItem(parentId = item,
-                                      text = prefix + '.' + name)
-                data = dict()
-                for key in mdict[prefix][name].keys():
-                    data[key] = mdict[prefix][name][key]
-                
-                self.SetPyData(new, data)
-        
-        self._loaded = True
-
-    def IsLoaded(self):
-        """Check if items are loaded"""
-        return self._loaded
-
-class HelpWindow(wx.html.HtmlWindow):
+class HelpWindow(HtmlWindow):
     """!This panel holds the text from GRASS docs.
     """!This panel holds the text from GRASS docs.
     
     
     GISBASE must be set in the environment to find the html docs dir.
     GISBASE must be set in the environment to find the html docs dir.
@@ -1143,7 +731,7 @@ class HelpWindow(wx.html.HtmlWindow):
         """
         """
         self.parent = parent
         self.parent = parent
         wx.InitAllImageHandlers()
         wx.InitAllImageHandlers()
-        wx.html.HtmlWindow.__init__(self, parent = parent, **kwargs)
+        HtmlWindow.__init__(self, parent = parent, **kwargs)
         
         
         gisbase = os.getenv("GISBASE")
         gisbase = os.getenv("GISBASE")
         self.loaded = False
         self.loaded = False

+ 1 - 1
gui/wxpython/gui_core/goutput.py

@@ -39,7 +39,7 @@ from   grass.script import task as gtask
 from core            import globalvar
 from core            import globalvar
 from core            import utils
 from core            import utils
 from core.gcmd       import CommandThread, GMessage, GError, GException, EncodeString
 from core.gcmd       import CommandThread, GMessage, GError, GException, EncodeString
-from gui_core.forms  import GUI
+from gui_core.task   import GUI
 from gui_core.prompt import GPromptSTC
 from gui_core.prompt import GPromptSTC
 from core.debug      import Debug
 from core.debug      import Debug
 from core.settings   import UserSettings, Settings
 from core.settings   import UserSettings, Settings

+ 210 - 0
gui/wxpython/gui_core/task.py

@@ -0,0 +1,210 @@
+"""
+@package gui_core.task
+
+@brief Construct simple wxPython GUI from a GRASS command interface
+description.
+
+Classes:
+ - GUI
+
+(C) 2000-2011 by the GRASS Development Team
+This program is free software under the GPL(>=v2) Read the file
+COPYING coming with GRASS for details.
+
+@author Jan-Oliver Wagner <jan@intevation.de>
+@author Bernhard Reiter <bernhard@intevation.de>
+@author Michael Barton, Arizona State University
+@author Daniel Calvelo <dca.gis@gmail.com>
+@author Martin Landa <landa.martin@gmail.com>
+@author Luca Delucchi <lucadeluge@gmail.com>
+"""
+
+import sys
+import re
+import os
+import time
+import locale
+try:
+    import xml.etree.ElementTree as etree
+except ImportError:
+    import elementtree.ElementTree as etree # Python <= 2.4
+
+from core import globalvar
+import wx
+
+from grass.script import core as grass
+from grass.script import task as gtask
+from core.gcmd    import GException, GError
+
+class GUI:
+    def __init__(self, parent = None, show = True, modal = False,
+                 centreOnParent = False, checkError = False):
+        """!Parses GRASS commands when module is imported and used from
+        Layer Manager.
+        """
+        self.parent = parent
+        self.show   = show
+        self.modal  = modal
+        self.centreOnParent = centreOnParent
+        self.checkError     = checkError
+        
+        self.grass_task = None
+        self.cmd = list()
+        
+        global _blackList
+        if self.parent:
+            _blackList['enabled'] = True
+        else:
+            _blackList['enabled'] = False
+        
+    def GetCmd(self):
+        """!Get validated command"""
+        return self.cmd
+    
+    def ParseCommand(self, cmd, gmpath = None, completed = None):
+        """!Parse command
+        
+        Note: cmd is given as list
+        
+        If command is given with options, return validated cmd list:
+         - add key name for first parameter if not given
+         - change mapname to mapname@mapset
+        """
+        start = time.time()
+        dcmd_params = {}
+        if completed == None:
+            get_dcmd = None
+            layer = None
+            dcmd_params = None
+        else:
+            get_dcmd = completed[0]
+            layer = completed[1]
+            if completed[2]:
+                dcmd_params.update(completed[2])
+        
+        # parse the interface decription
+        try:
+            global _blackList
+            self.grass_task = gtask.parse_interface(cmd[0],
+                                                    blackList = _blackList)
+        except ValueError, e: #grass.ScriptError, e:
+            GError(e.value)
+            return
+        
+        # if layer parameters previously set, re-insert them into dialog
+        if completed is not None:
+            if 'params' in dcmd_params:
+                self.grass_task.params = dcmd_params['params']
+            if 'flags' in dcmd_params:
+                self.grass_task.flags = dcmd_params['flags']
+        
+        err = list()
+        # update parameters if needed && validate command
+        if len(cmd) > 1:
+            i = 0
+            cmd_validated = [cmd[0]]
+            for option in cmd[1:]:
+                if option[0] ==  '-': # flag
+                    if option[1] ==  '-':
+                        self.grass_task.set_flag(option[2:], True)
+                    else:
+                        self.grass_task.set_flag(option[1], True)
+                    cmd_validated.append(option)
+                else: # parameter
+                    try:
+                        key, value = option.split('=', 1)
+                    except:
+                        if self.grass_task.firstParam:
+                            if i == 0: # add key name of first parameter if not given
+                                key = self.grass_task.firstParam
+                                value = option
+                            else:
+                                raise GException, _("Unable to parse command '%s'") % ' '.join(cmd)
+                        else:
+                            continue
+                    
+                    element = self.grass_task.get_param(key, raiseError = False)
+                    if not element:
+                        err.append(_("%(cmd)s: parameter '%(key)s' not available") % \
+                                       { 'cmd' : cmd[0],
+                                         'key' : key })
+                        continue
+                    element = element['element']
+                    
+                    if element in ['cell', 'vector']:
+                        # mapname -> mapname@mapset
+                        try:
+                            name, mapset = value.split('@')
+                        except ValueError:
+                            mapset = grass.find_file(value, element)['mapset']
+                            curr_mapset = grass.gisenv()['MAPSET']
+                            if mapset and mapset !=  curr_mapset:
+                                value = value + '@' + mapset
+                    
+                    self.grass_task.set_param(key, value)
+                    cmd_validated.append(key + '=' + value)
+                    i += 1
+            
+            # update original command list
+            cmd = cmd_validated
+        
+        if self.show is not None:
+            self.mf = mainFrame(parent = self.parent, ID = wx.ID_ANY,
+                                task_description = self.grass_task,
+                                get_dcmd = get_dcmd, layer = layer)
+        else:
+            self.mf = None
+        
+        if get_dcmd is not None:
+            # update only propwin reference
+            get_dcmd(dcmd = None, layer = layer, params = None,
+                     propwin = self.mf)
+        
+        if self.show is not None:
+            self.mf.notebookpanel.OnUpdateSelection(None)
+            if self.show is True:
+                if self.parent and self.centreOnParent:
+                    self.mf.CentreOnParent()
+                else:
+                    self.mf.CenterOnScreen()
+                self.mf.Show(self.show)
+                self.mf.MakeModal(self.modal)
+            else:
+                self.mf.OnApply(None)
+        
+        self.cmd = cmd
+        
+        if self.checkError:
+            return self.grass_task, err
+        else:
+            return self.grass_task
+    
+    def GetCommandInputMapParamKey(self, cmd):
+        """!Get parameter key for input raster/vector map
+        
+        @param cmd module name
+        
+        @return parameter key
+        @return None on failure
+        """
+        # parse the interface decription
+        if not self.grass_task:
+            enc = locale.getdefaultlocale()[1]
+            if enc and enc.lower() == "cp932":
+                p = re.compile('encoding="' + enc + '"', re.IGNORECASE)
+                tree = etree.fromstring(p.sub('encoding="utf-8"',
+                                              gtask.get_interface_description(cmd).decode(enc).encode('utf-8')))
+            else:
+                tree = etree.fromstring(gtask.get_interface_description(cmd))
+            self.grass_task = gtask.processTask(tree).get_task()
+            
+            for p in self.grass_task.params:
+                if p.get('name', '') in ('input', 'map'):
+                    age = p.get('age', '')
+                    prompt = p.get('prompt', '')
+                    element = p.get('element', '') 
+                    if age ==  'old' and \
+                            element in ('cell', 'grid3', 'vector') and \
+                            prompt in ('raster', '3d-raster', 'vector'):
+                        return p.get('name', None)
+        return None

+ 161 - 0
gui/wxpython/gui_core/widgets.py

@@ -9,6 +9,9 @@ Classes:
  - NumTextCtrl
  - NumTextCtrl
  - FloatSlider
  - FloatSlider
  - SymbolButton
  - SymbolButton
+ - StaticWrapText
+ - FloatValidator
+ - ItemTree
 
 
 (C) 2008-2011 by the GRASS Development Team
 (C) 2008-2011 by the GRASS Development Team
 This program is free software under the GNU General Public License
 This program is free software under the GNU General Public License
@@ -31,6 +34,10 @@ try:
     from wx.lib.buttons import ThemedGenBitmapTextButton as BitmapTextButton
     from wx.lib.buttons import ThemedGenBitmapTextButton as BitmapTextButton
 except ImportError: # not sure about TGBTButton version
 except ImportError: # not sure about TGBTButton version
     from wx.lib.buttons import GenBitmapTextButton as BitmapTextButton
     from wx.lib.buttons import GenBitmapTextButton as BitmapTextButton
+try:
+    import wx.lib.agw.customtreectrl as CT
+except ImportError:
+    import wx.lib.customtreectrl as CT
 
 
 from core import globalvar
 from core import globalvar
 
 
@@ -229,3 +236,157 @@ class SymbolButton(BitmapTextButton):
         dc.SetBrush(wx.Brush(wx.Color(50, 50, 50)))
         dc.SetBrush(wx.Brush(wx.Color(50, 50, 50)))
         dc.DrawRectangle(0, 0, 2 * size[0] / 5, size[1])
         dc.DrawRectangle(0, 0, 2 * size[0] / 5, size[1])
         dc.DrawRectangle(3 * size[0] / 5, 0, 2 * size[0] / 5, size[1])
         dc.DrawRectangle(3 * size[0] / 5, 0, 2 * size[0] / 5, size[1])
+
+class StaticWrapText(wx.StaticText):
+    """!A Static Text field that wraps its text to fit its width,
+    enlarging its height if necessary.
+    """
+    def __init__(self, parent, id = wx.ID_ANY, label = '', *args, **kwds):
+        self.parent        = parent
+        self.originalLabel = label
+        
+        wx.StaticText.__init__(self, parent, id, label = '', *args, **kwds)
+        
+        self.SetLabel(label)
+        self.Bind(wx.EVT_SIZE, self.OnResize)
+    
+    def SetLabel(self, label):
+        self.originalLabel = label
+        self.wrappedSize = None
+        self.OnResize(None)
+
+    def OnResize(self, event):
+        if not getattr(self, "resizing", False):
+            self.resizing = True
+            newSize = wx.Size(self.parent.GetSize().width - 50,
+                              self.GetSize().height)
+            if self.wrappedSize != newSize:
+                wx.StaticText.SetLabel(self, self.originalLabel)
+                self.Wrap(newSize.width)
+                self.wrappedSize = newSize
+                
+                self.SetSize(self.wrappedSize)
+            del self.resizing
+
+class FloatValidator(wx.PyValidator):
+    """!Validator for floating-point input"""
+    def __init__(self):
+        wx.PyValidator.__init__(self)
+        
+        self.Bind(wx.EVT_TEXT, self.OnText) 
+        
+    def Clone(self):
+        """!Clone validator"""
+        return FloatValidator()
+
+    def Validate(self):
+        """Validate input"""
+        textCtrl = self.GetWindow()
+        text = textCtrl.GetValue()
+
+        if text:
+            try:
+                float(text)
+            except ValueError:
+                textCtrl.SetBackgroundColour("grey")
+                textCtrl.SetFocus()
+                textCtrl.Refresh()
+                return False
+        
+        sysColor = wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW)
+        textCtrl.SetBackgroundColour(sysColor)
+        
+        textCtrl.Refresh()
+        
+        return True
+
+    def OnText(self, event):
+        """!Do validation"""
+        self.Validate()
+        
+        event.Skip()
+        
+    def TransferToWindow(self):
+        return True # Prevent wxDialog from complaining.
+    
+    def TransferFromWindow(self):
+        return True # Prevent wxDialog from complaining.
+
+class ItemTree(CT.CustomTreeCtrl):
+    def __init__(self, parent, id = wx.ID_ANY,
+                 ctstyle = CT.TR_HIDE_ROOT | CT.TR_FULL_ROW_HIGHLIGHT | CT.TR_HAS_BUTTONS |
+                 CT.TR_LINES_AT_ROOT | CT.TR_SINGLE, **kwargs):
+        if globalvar.hasAgw:
+            super(ItemTree, self).__init__(parent, id, agwStyle = ctstyle, **kwargs)
+        else:
+            super(ItemTree, self).__init__(parent, id, style = ctstyle, **kwargs)
+        
+        self.root = self.AddRoot(_("Menu tree"))
+        self.itemsMarked = [] # list of marked items
+        self.itemSelected = None
+
+    def SearchItems(self, element, value):
+        """!Search item 
+
+        @param element element index (see self.searchBy)
+        @param value
+
+        @return list of found tree items
+        """
+        items = list()
+        if not value:
+            return items
+        
+        item = self.GetFirstChild(self.root)[0]
+        self._processItem(item, element, value, items)
+        
+        self.itemsMarked  = items
+        self.itemSelected = None
+        
+        return items
+    
+    def _processItem(self, item, element, value, listOfItems):
+        """!Search items (used by SearchItems)
+        
+        @param item reference item
+        @param listOfItems list of found items
+        """
+        while item and item.IsOk():
+            subItem = self.GetFirstChild(item)[0]
+            if subItem:
+                self._processItem(subItem, element, value, listOfItems)
+            data = self.GetPyData(item)
+            
+            if data and element in data and \
+                    value.lower() in data[element].lower():
+                listOfItems.append(item)
+            
+            item = self.GetNextSibling(item)
+            
+    def GetSelected(self):
+        """!Get selected item"""
+        return self.itemSelected
+
+    def OnShowItem(self, event):
+        """!Highlight first found item in menu tree"""
+        if len(self.itemsMarked) > 0:
+            if self.GetSelected():
+                self.ToggleItemSelection(self.GetSelected())
+                idx = self.itemsMarked.index(self.GetSelected()) + 1
+            else:
+                idx = 0
+            try:
+                self.ToggleItemSelection(self.itemsMarked[idx])
+                self.itemSelected = self.itemsMarked[idx]
+                self.EnsureVisible(self.itemsMarked[idx])
+            except IndexError:
+                self.ToggleItemSelection(self.itemsMarked[0]) # reselect first item
+                self.EnsureVisible(self.itemsMarked[0])
+                self.itemSelected = self.itemsMarked[0]
+        else:
+            for item in self.root.GetChildren():
+                self.Collapse(item)
+            itemSelected = self.GetSelection()
+            if itemSelected:
+                self.ToggleItemSelection(itemSelected)
+            self.itemSelected = None

+ 1 - 1
gui/wxpython/lmgr/layertree.py

@@ -30,7 +30,7 @@ from grass.script import core as grass
 
 
 from core                import globalvar
 from core                import globalvar
 from gui_core.dialogs    import SqlQueryFrame, SetOpacityDialog
 from gui_core.dialogs    import SqlQueryFrame, SetOpacityDialog
-from core.forms          import GUI
+from gui_core.task       import GUI
 from mapdisp.frame       import MapFrame
 from mapdisp.frame       import MapFrame
 from core.render         import Map
 from core.render         import Map
 from modules.histogram   import HistogramFrame
 from modules.histogram   import HistogramFrame

+ 7 - 7
gui/wxpython/mapdisp/frame.py

@@ -50,9 +50,9 @@ from core.debug         import Debug
 from icon               import Icons
 from icon               import Icons
 from core.settings      import UserSettings
 from core.settings      import UserSettings
 from gui_core.mapdisp   import MapFrameBase
 from gui_core.mapdisp   import MapFrameBase
-from mapdisp.window     import BufferedWindow
-from modules.histogram  import HistFrame
-from wxplot.histogram   import HistFrame as HistFramePyPlot
+from mapdisp.mapwindow  import BufferedWindow
+from modules.histogram  import HistogramFrame
+from wxplot.histogram   import Histogram2Frame
 from wxplot.profile     import ProfileFrame
 from wxplot.profile     import ProfileFrame
 from wxplot.scatter     import ScatterFrame
 from wxplot.scatter     import ScatterFrame
 
 
@@ -1105,10 +1105,10 @@ class MapFrame(MapFrameBase):
                 continue
                 continue
             raster.append(self.tree.GetPyData(layer)[0]['maplayer'].GetName())
             raster.append(self.tree.GetPyData(layer)[0]['maplayer'].GetName())
 
 
-        self.histogramPyPlot = HistFramePyPlot(self, id = wx.ID_ANY, 
-                                                pos = wx.DefaultPosition, size = (700,300),
-                                                style = wx.DEFAULT_FRAME_STYLE, 
-                                                rasterList = raster)
+        self.histogramPyPlot = Histogram2Frame(self, id = wx.ID_ANY, 
+                                               pos = wx.DefaultPosition, size = (700,300),
+                                               style = wx.DEFAULT_FRAME_STYLE, 
+                                               rasterList = raster)
         self.histogramPyPlot.Show()
         self.histogramPyPlot.Show()
         # Open raster select dialog to make sure that a raster (and the desired raster)
         # Open raster select dialog to make sure that a raster (and the desired raster)
         # is selected to be histogrammed
         # is selected to be histogrammed

+ 1 - 1
gui/wxpython/modules/colorrules.py

@@ -38,7 +38,7 @@ from core             import utils
 from core.gcmd        import GMessage, RunCommand
 from core.gcmd        import GMessage, RunCommand
 from gui_core.gselect import Select, LayerSelect, ColumnSelect, VectorDBInfo
 from gui_core.gselect import Select, LayerSelect, ColumnSelect, VectorDBInfo
 from core.render      import Map
 from core.render      import Map
-from core.forms       import GUI
+from gui_core.task    import GUI
 from core.debug       import Debug as Debug
 from core.debug       import Debug as Debug
 from core.settings    import UserSettings
 from core.settings    import UserSettings
 from nviz.mapwindow   import wxUpdateProperties
 from nviz.mapwindow   import wxUpdateProperties

+ 360 - 0
gui/wxpython/modules/extensions.py

@@ -0,0 +1,360 @@
+"""!
+@package modules.extensions
+
+@brief GRASS Addons extensions management classes
+
+Classes:
+ - InstallExtensionWindow
+ - ExtensionTree
+
+(C) 2008-2011 by the GRASS Development Team
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+@author Martin Landa <landa.martin gmail.com>
+"""
+
+import os
+
+import wx
+try:
+    import wx.lib.agw.customtreectrl as CT
+except ImportError:
+    import wx.lib.customtreectrl as CT
+import wx.lib.flatnotebook as FN
+
+import grass.script as grass
+from grass.script import task as gtask
+
+from core             import globalvar
+from core.gcmd        import GError, RunCommand
+from gui_core.task    import GUI
+from gui_core.widgets import ItemTree
+
+class InstallExtensionWindow(wx.Frame):
+    def __init__(self, parent, id = wx.ID_ANY,
+                 title = _("Fetch & install extension from GRASS Addons"), **kwargs):
+        self.parent = parent
+        self.options = dict() # list of options
+        
+        wx.Frame.__init__(self, parent = parent, id = id, title = title, **kwargs)
+        
+        self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
+
+        self.repoBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
+                                    label = " %s " % _("Repository"))
+        self.treeBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
+                                    label = " %s " % _("List of extensions"))
+        
+        self.repo = wx.TextCtrl(parent = self.panel, id = wx.ID_ANY)
+        self.fullDesc = wx.CheckBox(parent = self.panel, id = wx.ID_ANY,
+                                    label = _("Fetch full info including description and keywords (takes time)"))
+        self.fullDesc.SetValue(True)
+        
+        self.search = SearchModuleWindow(parent = self.panel)
+        self.search.SetSelection(0) 
+        
+        self.tree   = ExtensionTree(parent = self.panel, log = parent.GetLogWindow())
+        
+        self.optionBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
+                                      label = " %s " % _("Options"))
+        task = gtask.parse_interface('g.extension')
+        for f in task.get_options()['flags']:
+            name = f.get('name', '')
+            desc = f.get('label', '')
+            if not desc:
+                desc = f.get('description', '')
+            if not name and not desc:
+                continue
+            if name in ('l', 'c', 'g', 'quiet', 'verbose'):
+                continue
+            self.options[name] = wx.CheckBox(parent = self.panel, id = wx.ID_ANY,
+                                             label = desc)
+        self.repo.SetValue(task.get_param(value = 'svnurl').get('default',
+                                                                'http://svn.osgeo.org/grass/grass-addons/grass7'))
+        
+        self.statusbar = self.CreateStatusBar(number = 1)
+        
+        self.btnFetch = wx.Button(parent = self.panel, id = wx.ID_ANY,
+                                  label = _("&Fetch"))
+        self.btnFetch.SetToolTipString(_("Fetch list of available modules from GRASS Addons SVN repository"))
+        self.btnClose = wx.Button(parent = self.panel, id = wx.ID_CLOSE)
+        self.btnInstall = wx.Button(parent = self.panel, id = wx.ID_ANY,
+                                    label = _("&Install"))
+        self.btnInstall.SetToolTipString(_("Install selected add-ons GRASS module"))
+        self.btnInstall.Enable(False)
+        self.btnCmd = wx.Button(parent = self.panel, id = wx.ID_ANY,
+                                label = _("Command dialog"))
+        self.btnCmd.SetToolTipString(_('Open %s dialog') % 'g.extension')
+
+        self.btnClose.Bind(wx.EVT_BUTTON, self.OnCloseWindow)
+        self.btnFetch.Bind(wx.EVT_BUTTON, self.OnFetch)
+        self.btnInstall.Bind(wx.EVT_BUTTON, self.OnInstall)
+        self.btnCmd.Bind(wx.EVT_BUTTON, self.OnCmdDialog)
+        self.tree.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnItemActivated)
+        self.tree.Bind(wx.EVT_TREE_SEL_CHANGED,    self.OnItemSelected)
+        self.search.Bind(wx.EVT_TEXT_ENTER,        self.OnShowItem)
+        self.search.Bind(wx.EVT_TEXT,              self.OnUpdateStatusBar)
+
+        self._layout()
+
+    def _layout(self):
+        """!Do layout"""
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        repoSizer = wx.StaticBoxSizer(self.repoBox, wx.VERTICAL)
+        repo1Sizer = wx.BoxSizer(wx.HORIZONTAL)
+        repo1Sizer.Add(item = self.repo, proportion = 1,
+                      flag = wx.ALL | wx.ALIGN_CENTER_VERTICAL, border = 1)
+        repo1Sizer.Add(item = self.btnFetch, proportion = 0,
+                      flag = wx.ALL | wx.ALIGN_CENTER_VERTICAL, border = 1)
+        repoSizer.Add(item = repo1Sizer,
+                      flag = wx.EXPAND)
+        repoSizer.Add(item = self.fullDesc)
+        
+        findSizer = wx.BoxSizer(wx.HORIZONTAL)
+        findSizer.Add(item = self.search, proportion = 1)
+        
+        treeSizer = wx.StaticBoxSizer(self.treeBox, wx.HORIZONTAL)
+        treeSizer.Add(item = self.tree, proportion = 1,
+                      flag = wx.ALL | wx.EXPAND, border = 1)
+
+        # options
+        optionSizer = wx.StaticBoxSizer(self.optionBox, wx.VERTICAL)
+        for key in self.options.keys():
+            optionSizer.Add(item = self.options[key], proportion = 0)
+        
+        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.btnInstall, proportion = 0)
+        
+        sizer.Add(item = repoSizer, proportion = 0,
+                  flag = wx.ALL | wx.EXPAND, border = 3)
+        sizer.Add(item = findSizer, proportion = 0,
+                  flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 3)
+        sizer.Add(item = treeSizer, proportion = 1,
+                  flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 3)
+        sizer.Add(item = optionSizer, proportion = 0,
+                        flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | 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 _getCmd(self):
+        item = self.tree.GetSelected()
+        if not item or not item.IsOk():
+            return ['g.extension']
+        
+        name = self.tree.GetItemText(item)
+        if not name:
+            GError(_("Extension not defined"), parent = self)
+            return
+        
+        flags = list()
+        for key in self.options.keys():
+            if self.options[key].IsChecked():
+                flags.append('-%s' % key)
+        
+        return ['g.extension'] + flags + ['extension=' + name,
+                                          'svnurl=' + self.repo.GetValue().strip()]
+    
+    def OnUpdateStatusBar(self, event):
+        """!Update statusbar text"""
+        element = self.search.GetSelection()
+        if not self.tree.IsLoaded():
+            self.SetStatusText(_("Fetch list of available extensions by clicking on 'Fetch' button"), 0)
+            return
+        
+        self.tree.SearchItems(element = element,
+                              value = event.GetString())
+        
+        nItems = len(self.tree.itemsMarked)
+        if event.GetString():
+            self.SetStatusText(_("%d items match") % nItems, 0)
+        else:
+            self.SetStatusText("", 0)
+        
+        event.Skip()
+    
+    def OnCloseWindow(self, event):
+        """!Close window"""
+        self.Destroy()
+
+    def OnFetch(self, event):
+        """!Fetch list of available extensions"""
+        wx.BeginBusyCursor()
+        self.SetStatusText(_("Fetching list of modules from GRASS-Addons SVN (be patient)..."), 0)
+        self.tree.Load(url = self.repo.GetValue().strip(), full = self.fullDesc.IsChecked())
+        self.SetStatusText("", 0)
+        wx.EndBusyCursor()
+
+    def OnItemActivated(self, event):
+        item = event.GetItem()
+        data = self.tree.GetPyData(item)
+        if data and 'command' in data:
+            self.OnInstall(event = None)
+        
+    def OnInstall(self, event):
+        """!Install selected extension"""
+        log = self.parent.GetLogWindow()
+        log.RunCmd(self._getCmd(), onDone = self.OnDone)
+        
+    def OnDone(self, cmd, returncode):
+        item = self.tree.GetSelected()
+        if not item or not item.IsOk() or \
+                returncode != 0 or \
+                not os.getenv('GRASS_ADDON_PATH'):
+            return
+        
+        name = self.tree.GetItemText(item)
+        globalvar.grassCmd['all'].append(name)
+        
+    def OnItemSelected(self, event):
+        """!Item selected"""
+        item = event.GetItem()
+        self.tree.itemSelected = item
+        data = self.tree.GetPyData(item)
+        if not data:
+            self.SetStatusText('', 0)
+            self.btnInstall.Enable(False)
+        else:
+            self.SetStatusText(data.get('description', ''), 0)
+            self.btnInstall.Enable(True)
+
+    def OnShowItem(self, event):
+        """!Show selected item"""
+        self.tree.OnShowItem(event)
+        if self.tree.GetSelected():
+            self.btnInstall.Enable()
+        else:
+            self.btnInstall.Enable(False)
+
+    def OnCmdDialog(self, event):
+        """!Shows command dialog"""
+        GUI(parent = self).ParseCommand(cmd = self._getCmd())
+        
+class ExtensionTree(ItemTree):
+    """!List of available extensions"""
+    def __init__(self, parent, log, id = wx.ID_ANY,
+                 ctstyle = CT.TR_HIDE_ROOT | CT.TR_FULL_ROW_HIGHLIGHT | CT.TR_HAS_BUTTONS |
+                 CT.TR_LINES_AT_ROOT | CT.TR_SINGLE,
+                 **kwargs):
+        self.parent = parent # GMFrame
+        self.log    = log
+        
+        super(ExtensionTree, self).__init__(parent, id, ctstyle = ctstyle, **kwargs)
+        
+        self._initTree()
+        
+    def _initTree(self):
+        for prefix in ('display', 'database',
+                       'general', 'imagery',
+                       'misc', 'postscript', 'paint',
+                       'raster', 'raster3D', 'sites', 'vector', 'wxGUI', 'other'):
+            self.AppendItem(parentId = self.root,
+                            text = prefix)
+        self._loaded = False
+        
+    def _expandPrefix(self, c):
+        name = { 'd'  : 'display',
+                 'db' : 'database',
+                 'g'  : 'general',
+                 'i'  : 'imagery',
+                 'm'  : 'misc',
+                 'ps' : 'postscript',
+                 'p'  : 'paint',
+                 'r'  : 'raster',
+                 'r3' : 'raster3D',
+                 's'  : 'sites',
+                 'v'  : 'vector',
+                 'wx' : 'wxGUI',
+                 'u'  : 'other' }
+        
+        if c in name:
+            return name[c]
+        
+        return c
+    
+    def _findItem(self, text):
+        """!Find item"""
+        item = self.GetFirstChild(self.root)[0]
+        while item and item.IsOk():
+            if text == self.GetItemText(item):
+                return item
+            
+            item = self.GetNextSibling(item)
+        
+        return None
+    
+    def Load(self, url, full = False):
+        """!Load list of extensions"""
+        self.DeleteAllItems()
+        self.root = self.AddRoot(_("Menu tree"))
+        self._initTree()
+        
+        if full:
+            flags = 'g'
+        else:
+            flags = 'l'
+        ret = RunCommand('g.extension', read = True,
+                         svnurl = url,
+                         flags = flags, quiet = True)
+        if not ret:
+            return
+        
+        mdict = dict()
+        for line in ret.splitlines():
+            if full:
+                key, value = line.split('=', 1)
+                if key == 'name':
+                    try:
+                        prefix, name = value.split('.', 1)
+                    except ValueError:
+                        prefix = 'u'
+                        name = value
+                    if prefix not in mdict:
+                        mdict[prefix] = dict()
+                    mdict[prefix][name] = dict()
+                else:
+                    mdict[prefix][name][key] = value
+            else:
+                try:
+                    prefix, name = line.strip().split('.', 1)
+                except:
+                    prefix = 'unknown'
+                    name = line.strip()
+                
+                if self._expandPrefix(prefix) == prefix:
+                    prefix = 'unknown'
+                    
+                if prefix not in mdict:
+                    mdict[prefix] = dict()
+                    
+                mdict[prefix][name] = { 'command' : prefix + '.' + name }
+        
+        for prefix in mdict.keys():
+            prefixName = self._expandPrefix(prefix)
+            item = self._findItem(prefixName)
+            names = mdict[prefix].keys()
+            names.sort()
+            for name in names:
+                new = self.AppendItem(parentId = item,
+                                      text = prefix + '.' + name)
+                data = dict()
+                for key in mdict[prefix][name].keys():
+                    data[key] = mdict[prefix][name][key]
+                
+                self.SetPyData(new, data)
+        
+        self._loaded = True
+
+    def IsLoaded(self):
+        """Check if items are loaded"""
+        return self._loaded

+ 2 - 2
gui/wxpython/modules/histogram.py

@@ -22,7 +22,7 @@ import wx
 
 
 from core                 import globalvar
 from core                 import globalvar
 from core.render          import Map
 from core.render          import Map
-from core.forms           import GUI
+from gui_core.task        import GUI
 from mapdisp.gprint       import PrintOptions
 from mapdisp.gprint       import PrintOptions
 from core.utils           import GetLayerNameFromCmd
 from core.utils           import GetLayerNameFromCmd
 from gui_core.dialogs     import GetImageHandlers, ImageSizeDialog
 from gui_core.dialogs     import GetImageHandlers, ImageSizeDialog
@@ -258,7 +258,7 @@ class BufferedWindow(wx.Window):
         """
         """
         self.Draw(self.pdc, pdctype = 'clear')
         self.Draw(self.pdc, pdctype = 'clear')
         
         
-class HistFrame(wx.Frame):
+class HistogramFrame(wx.Frame):
     """!Main frame for hisgram display window. Uses d.histogram
     """!Main frame for hisgram display window. Uses d.histogram
     rendered onto canvas
     rendered onto canvas
     """
     """

+ 1 - 1
gui/wxpython/modules/mcalc_builder.py

@@ -24,7 +24,7 @@ import grass.script as grass
 
 
 from core.gcmd        import GError, RunCommand
 from core.gcmd        import GError, RunCommand
 from gui_core.gselect import Select
 from gui_core.gselect import Select
-from core.forms       import GUI
+from gui_core.task    import GUI
 from core.settings    import UserSettings
 from core.settings    import UserSettings
 
 
 class MapCalcFrame(wx.Frame):
 class MapCalcFrame(wx.Frame):

+ 8 - 9
gui/wxpython/nviz/mapwindow.py

@@ -34,15 +34,14 @@ from   wx              import glcanvas
 
 
 import grass.script as grass
 import grass.script as grass
 
 
-from core.gcmd        import GMessage, GException, GError
-from core.debug       import Debug
-from mapdisp.window   import MapWindow
-from gui_core.goutput import wxCmdOutput
-from core.settings    import UserSettings
-from nviz.workspace   import NvizSettings
-from nviz.animation   import Animation
-
-import nviz.wxcore as wxnviz
+from core.gcmd          import GMessage, GException, GError
+from core.debug         import Debug
+from gui_core.mapwindow import MapWindow
+from gui_core.goutput   import wxCmdOutput
+from core.settings      import UserSettings
+from nviz.workspace     import NvizSettings
+from nviz.animation     import Animation
+from nviz               import wxnviz
 
 
 wxUpdateProperties, EVT_UPDATE_PROP  = NewEvent()
 wxUpdateProperties, EVT_UPDATE_PROP  = NewEvent()
 wxUpdateView,       EVT_UPDATE_VIEW  = NewEvent()
 wxUpdateView,       EVT_UPDATE_VIEW  = NewEvent()

+ 1 - 1
gui/wxpython/psmap/frame.py

@@ -41,7 +41,7 @@ from gui_core.goutput import CmdThread, EVT_CMD_DONE
 from psmap.toolbars   import PsMapToolbar
 from psmap.toolbars   import PsMapToolbar
 from icon             import Icons, MetaIcon, iconSet
 from icon             import Icons, MetaIcon, iconSet
 from core.gcmd        import RunCommand, GError, GMessage
 from core.gcmd        import RunCommand, GError, GMessage
-from core.forms       import GUI
+from gui_core.task    import GUI
 from psmap.dialogs    import *
 from psmap.dialogs    import *
 
 
 class PsMapFrame(wx.Frame):
 class PsMapFrame(wx.Frame):

+ 3 - 2
gui/wxpython/wxgui.py

@@ -53,7 +53,7 @@ from gui_core.preferences  import MapsetAccess, PreferencesDialog, EVT_SETTINGS_
 from lmgr.layertree        import LayerTree
 from lmgr.layertree        import LayerTree
 from lmgr.menudata         import ManagerData
 from lmgr.menudata         import ManagerData
 from gui_core.widgets      import GNotebook
 from gui_core.widgets      import GNotebook
-from modules.histogram     import HistFrame
+from modules.histogram     import HistogramFrame
 from modules.mcalc_builder import MapCalcFrame
 from modules.mcalc_builder import MapCalcFrame
 from dbm.manager           import AttributeManager
 from dbm.manager           import AttributeManager
 from core.workspace        import ProcessWorkspaceFile, ProcessGrcFile, WriteWorkspaceFile
 from core.workspace        import ProcessWorkspaceFile, ProcessGrcFile, WriteWorkspaceFile
@@ -69,7 +69,8 @@ from modules.vclean        import VectorCleaningFrame
 from nviz.tools            import NvizToolWindow
 from nviz.tools            import NvizToolWindow
 from psmap.frame           import PsMapFrame
 from psmap.frame           import PsMapFrame
 from core.debug            import Debug
 from core.debug            import Debug
-from gui_core.ghelp        import MenuTreeWindow, AboutWindow, InstallExtensionWindow
+from gui_core.ghelp        import MenuTreeWindow, AboutWindow
+from modules.extensions    import InstallExtensionWindow
 from lmgr.toolbars         import LMWorkspaceToolbar, LMDataToolbar, LMToolsToolbar
 from lmgr.toolbars         import LMWorkspaceToolbar, LMDataToolbar, LMToolsToolbar
 from lmgr.toolbars         import LMMiscToolbar, LMVectorToolbar, LMNvizToolbar
 from lmgr.toolbars         import LMMiscToolbar, LMVectorToolbar, LMNvizToolbar
 from lmgr.pyshell          import PyShellWindow
 from lmgr.pyshell          import PyShellWindow