GRASS Programmer's Manual  6.5.svn(2012)-r51648
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
lmgr/frame.py
Go to the documentation of this file.
00001 """!
00002 @package lmgr::frame
00003 
00004 @brief Layer Manager - main menu, layer management toolbar, notebook
00005 control for display management and access to command console.
00006 
00007 Classes:
00008  - frame::GMFrame
00009 
00010 (C) 2006-2011 by the GRASS Development Team
00011 
00012 This program is free software under the GNU General Public License
00013 (>=v2). Read the file COPYING that comes with GRASS for details.
00014 
00015 @author Michael Barton (Arizona State University)
00016 @author Jachym Cepicky (Mendel University of Agriculture)
00017 @author Martin Landa <landa.martin gmail.com>
00018 @author Vaclav Petras <wenzeslaus gmail.com> (menu customization)
00019 """
00020 
00021 import sys
00022 import os
00023 import tempfile
00024 import stat
00025 try:
00026     import xml.etree.ElementTree as etree
00027 except ImportError:
00028     import elementtree.ElementTree as etree # Python <= 2.4
00029 
00030 from core import globalvar
00031 import wx
00032 import wx.aui
00033 try:
00034     import wx.lib.agw.flatnotebook   as FN
00035 except ImportError:
00036     import wx.lib.flatnotebook   as FN
00037 
00038 sys.path.append(os.path.join(globalvar.ETCDIR, "python"))
00039 from grass.script          import core as grass
00040 
00041 from core.gcmd             import RunCommand, GError, GMessage
00042 from core.settings         import UserSettings
00043 from gui_core.preferences  import MapsetAccess, PreferencesDialog, EVT_SETTINGS_CHANGED
00044 from lmgr.layertree        import LayerTree, LMIcons
00045 from lmgr.menudata         import ManagerData
00046 from gui_core.widgets      import GNotebook
00047 from modules.mcalc_builder import MapCalcFrame
00048 from dbmgr.manager         import AttributeManager
00049 from core.workspace        import ProcessWorkspaceFile, ProcessGrcFile, WriteWorkspaceFile
00050 from gui_core.goutput      import GMConsole
00051 from gui_core.dialogs      import DxfImportDialog, GdalImportDialog, MapLayersDialog
00052 from gui_core.dialogs      import LocationDialog, MapsetDialog, CreateNewVector, GroupDialog
00053 from modules.ogc_services  import WMSDialog
00054 from modules.colorrules    import RasterColorTable, VectorColorTable
00055 from gui_core.menu         import Menu
00056 from gmodeler.model        import Model
00057 from gmodeler.frame        import ModelFrame
00058 from psmap.frame           import PsMapFrame
00059 from core.debug            import Debug
00060 from gui_core.ghelp        import MenuTreeWindow, AboutWindow
00061 from modules.extensions    import InstallExtensionWindow, UninstallExtensionWindow
00062 from lmgr.toolbars         import LMWorkspaceToolbar, LMDataToolbar, LMToolsToolbar
00063 from lmgr.toolbars         import LMMiscToolbar, LMVectorToolbar, LMNvizToolbar
00064 from lmgr.pyshell          import PyShellWindow
00065 from gui_core.forms        import GUI
00066 from gcp.manager           import GCPWizard
00067 from nviz.main             import haveNviz
00068 
00069 class GMFrame(wx.Frame):
00070     """!Layer Manager frame with notebook widget for controlling GRASS
00071     GIS. Includes command console page for typing GRASS (and other)
00072     commands, tree widget page for managing map layers.
00073     """
00074     def __init__(self, parent, id = wx.ID_ANY, title = _("GRASS GIS Layer Manager"),
00075                  workspace = None,
00076                  size = globalvar.GM_WINDOW_SIZE, style = wx.DEFAULT_FRAME_STYLE, **kwargs):
00077         self.parent    = parent
00078         self.baseTitle = title
00079         self.iconsize  = (16, 16)
00080         
00081         wx.Frame.__init__(self, parent = parent, id = id, size = size,
00082                           style = style, **kwargs)
00083                           
00084         self.SetTitle(self.baseTitle)
00085         self.SetName("LayerManager")
00086 
00087         self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
00088 
00089         self._auimgr = wx.aui.AuiManager(self)
00090 
00091         # initialize variables
00092         self.disp_idx      = 0            # index value for map displays and layer trees
00093         self.curr_page     = None         # currently selected page for layer tree notebook
00094         self.curr_pagenum  = None         # currently selected page number for layer tree notebook
00095         self.workspaceFile = workspace    # workspace file
00096         self.workspaceChanged = False     # track changes in workspace
00097         self.georectifying = None         # reference to GCP class or None
00098         self.gcpmanagement = None         # reference to GCP class or None
00099         
00100         # list of open dialogs
00101         self.dialogs        = dict()
00102         self.dialogs['preferences'] = None
00103         self.dialogs['atm'] = list()
00104         
00105         # creating widgets
00106         self._createMenuBar()
00107         self.statusbar = self.CreateStatusBar(number = 1)
00108         self.notebook  = self._createNoteBook()
00109         self.toolbars  = { 'workspace' : LMWorkspaceToolbar(parent = self),
00110                            'data'      : LMDataToolbar(parent = self),
00111                            'tools'     : LMToolsToolbar(parent = self),
00112                            'misc'      : LMMiscToolbar(parent = self),
00113                            'vector'    : LMVectorToolbar(parent = self),
00114                            'nviz'      : LMNvizToolbar(parent = self)}
00115         
00116         self._toolbarsData = { 'workspace' : ("toolbarWorkspace",     # name
00117                                               _("Workspace Toolbar"), # caption
00118                                               1),                     # row
00119                                'data'      : ("toolbarData",
00120                                               _("Data Toolbar"),
00121                                               1),
00122                                'misc'      : ("toolbarMisc",
00123                                               _("Misc Toolbar"),
00124                                               2),
00125                                'tools'     : ("toolbarTools",
00126                                               _("Tools Toolbar"),
00127                                               2),
00128                                'vector'    : ("toolbarVector",
00129                                               _("Vector Toolbar"),
00130                                               2),
00131                                'nviz'      : ("toolbarNviz",
00132                                               _("3D view Toolbar"),
00133                                               2),                                            
00134                                }
00135         if sys.platform == 'win32':
00136             self._toolbarsList = ('workspace', 'data',
00137                                   'vector', 'tools', 'misc', 'nviz')
00138         else:
00139             self._toolbarsList = ('data', 'workspace',
00140                                   'nviz', 'misc', 'tools', 'vector')
00141         for toolbar in self._toolbarsList:
00142             name, caption, row = self._toolbarsData[toolbar]
00143             self._auimgr.AddPane(self.toolbars[toolbar],
00144                                  wx.aui.AuiPaneInfo().
00145                                  Name(name).Caption(caption).
00146                                  ToolbarPane().Top().Row(row).
00147                                  LeftDockable(False).RightDockable(False).
00148                                  BottomDockable(False).TopDockable(True).
00149                                  CloseButton(False).Layer(2).
00150                                  BestSize((self.toolbars[toolbar].GetBestSize())))
00151         
00152         self._auimgr.GetPane('toolbarNviz').Hide()
00153         # bindings
00154         self.Bind(wx.EVT_CLOSE,    self.OnCloseWindow)
00155         self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
00156 
00157         # minimal frame size
00158         self.SetMinSize((500, 400))
00159 
00160         # AUI stuff
00161         self._auimgr.AddPane(self.notebook, wx.aui.AuiPaneInfo().
00162                              Left().CentrePane().BestSize((-1,-1)).Dockable(False).
00163                              CloseButton(False).DestroyOnClose(True).Row(1).Layer(0))
00164 
00165         self._auimgr.Update()
00166 
00167         wx.CallAfter(self.notebook.SetSelectionByName, 'layers')
00168         
00169         # use default window layout ?
00170         if UserSettings.Get(group = 'general', key = 'defWindowPos', subkey = 'enabled'):
00171             dim = UserSettings.Get(group = 'general', key = 'defWindowPos', subkey = 'dim')
00172             try:
00173                x, y = map(int, dim.split(',')[0:2])
00174                w, h = map(int, dim.split(',')[2:4])
00175                self.SetPosition((x, y))
00176                self.SetSize((w, h))
00177             except:
00178                 pass
00179         else:
00180             self.Centre()
00181         
00182         self.Layout()
00183         self.Show()
00184         
00185         # load workspace file if requested
00186         if self.workspaceFile:
00187             # load given workspace file
00188             if self.LoadWorkspaceFile(self.workspaceFile):
00189                 self.SetTitle(self.baseTitle + " - " +  os.path.basename(self.workspaceFile))
00190             else:
00191                 self.workspaceFile = None
00192         else:
00193             # start default initial display
00194             self.NewDisplay(show = False)
00195 
00196         # show map display widnow
00197         # -> OnSize() -> UpdateMap()
00198         if self.curr_page and not self.curr_page.maptree.mapdisplay.IsShown():
00199             self.curr_page.maptree.mapdisplay.Show()
00200         
00201         # redirect stderr to log area    
00202         self.goutput.Redirect()
00203         
00204         # fix goutput's pane size (required for Mac OSX)`
00205         self.goutput.SetSashPosition(int(self.GetSize()[1] * .8))
00206         
00207         self.workspaceChanged = False
00208         
00209         # start with layer manager on top
00210         if self.curr_page:
00211             self.curr_page.maptree.mapdisplay.Raise()
00212         wx.CallAfter(self.Raise)
00213         
00214     def _createMenuBar(self):
00215         """!Creates menu bar"""
00216         self.menubar = Menu(parent = self, data = ManagerData())
00217         self.SetMenuBar(self.menubar)
00218         self.menucmd = self.menubar.GetCmd()
00219         
00220     def _createTabMenu(self):
00221         """!Creates context menu for display tabs.
00222         
00223         Used to rename display.
00224         """
00225         menu = wx.Menu()
00226         item = wx.MenuItem(menu, id = wx.ID_ANY, text = _("Rename Map Display"))
00227         menu.AppendItem(item)
00228         self.Bind(wx.EVT_MENU, self.OnRenameDisplay, item)
00229         
00230         return menu
00231         
00232     def _setCopyingOfSelectedText(self):
00233         copy = UserSettings.Get(group = 'manager', key = 'copySelectedTextToClipboard', subkey = 'enabled')
00234         self.goutput.SetCopyingOfSelectedText(copy)
00235     
00236     def IsPaneShown(self, name):
00237         """!Check if pane (toolbar, ...) of given name is currently shown"""
00238         if self._auimgr.GetPane(name).IsOk():
00239             return self._auimgr.GetPane(name).IsShown()
00240         return False
00241     
00242     def _createNoteBook(self):
00243         """!Creates notebook widgets"""
00244         self.notebook = GNotebook(parent = self, style = globalvar.FNPageDStyle)
00245         # create displays notebook widget and add it to main notebook page
00246         cbStyle = globalvar.FNPageStyle
00247         if globalvar.hasAgw:
00248             self.gm_cb = FN.FlatNotebook(self, id = wx.ID_ANY, agwStyle = cbStyle)
00249         else:
00250             self.gm_cb = FN.FlatNotebook(self, id = wx.ID_ANY, style = cbStyle)
00251         self.gm_cb.SetTabAreaColour(globalvar.FNPageColor)
00252         menu = self._createTabMenu()
00253         self.gm_cb.SetRightClickMenu(menu)
00254         self.notebook.AddPage(page = self.gm_cb, text = _("Map layers"), name = 'layers')
00255         
00256         # create 'command output' text area
00257         self.goutput = GMConsole(self)
00258         self.notebook.AddPage(page = self.goutput, text = _("Command console"), name = 'output')
00259         self._setCopyingOfSelectedText()
00260         
00261         # create 'search module' notebook page
00262         if not UserSettings.Get(group = 'manager', key = 'hideTabs', subkey = 'search'):
00263             self.search = MenuTreeWindow(parent = self)
00264             self.notebook.AddPage(page = self.search, text = _("Search module"), name = 'search')
00265         else:
00266             self.search = None
00267         
00268         # create 'python shell' notebook page
00269         if not UserSettings.Get(group = 'manager', key = 'hideTabs', subkey = 'pyshell'):
00270             self.pyshell = PyShellWindow(parent = self)
00271             self.notebook.AddPage(page = self.pyshell, text = _("Python shell"), name = 'pyshell')
00272         else:
00273             self.pyshell = None
00274         
00275         # bindings
00276         self.gm_cb.Bind(FN.EVT_FLATNOTEBOOK_PAGE_CHANGED,    self.OnCBPageChanged)
00277         self.notebook.Bind(FN.EVT_FLATNOTEBOOK_PAGE_CHANGED, self.OnPageChanged)
00278         self.gm_cb.Bind(FN.EVT_FLATNOTEBOOK_PAGE_CLOSING,    self.OnCBPageClosed)
00279         
00280         return self.notebook
00281             
00282     def AddNvizTools(self):
00283         """!Add nviz notebook page"""
00284         Debug.msg(5, "GMFrame.AddNvizTools()")
00285         if not haveNviz:
00286             return
00287         
00288         from nviz.main import NvizToolWindow
00289         
00290         # show toolbar
00291         self._auimgr.GetPane('toolbarNviz').Show()
00292         # reorder other toolbars
00293         for pos, toolbar in enumerate(('toolbarVector', 'toolbarTools', 'toolbarMisc','toolbarNviz')):
00294             self._auimgr.GetPane(toolbar).Row(2).Position(pos)
00295         self._auimgr.Update()
00296         
00297         # create nviz tools tab
00298         self.nviz = NvizToolWindow(parent = self,
00299                                    display = self.curr_page.maptree.GetMapDisplay())
00300         idx = self.notebook.GetPageIndexByName('layers')
00301         self.notebook.InsertPage(indx = idx + 1, page = self.nviz, text = _("3D view"), name = 'nviz')
00302         self.notebook.SetSelectionByName('nviz')
00303         
00304         
00305     def RemoveNvizTools(self):
00306         """!Remove nviz notebook page"""
00307         # if more mapwindow3D were possible, check here if nb page should be removed
00308         self.notebook.SetSelectionByName('layers')
00309         self.notebook.RemovePage(self.notebook.GetPageIndexByName('nviz'))
00310         del self.nviz
00311         # hide toolbar
00312         self._auimgr.GetPane('toolbarNviz').Hide()
00313         for pos, toolbar in enumerate(('toolbarVector', 'toolbarTools', 'toolbarMisc')):
00314             self._auimgr.GetPane(toolbar).Row(2).Position(pos)
00315         self._auimgr.Update()
00316     
00317     def WorkspaceChanged(self):
00318         """!Update window title"""
00319         if not self.workspaceChanged:
00320             self.workspaceChanged = True
00321         
00322         if self.workspaceFile:
00323             self.SetTitle(self.baseTitle + " - " +  os.path.basename(self.workspaceFile) + '*')
00324         
00325     def OnLocationWizard(self, event):
00326         """!Launch location wizard"""
00327         from location_wizard.wizard import LocationWizard
00328         
00329         gWizard = LocationWizard(parent = self,
00330                                  grassdatabase = grass.gisenv()['GISDBASE'])
00331         location = gWizard.location
00332         
00333         if location !=  None:
00334             dlg = wx.MessageDialog(parent = self,
00335                                    message = _('Location <%s> created.\n\n'
00336                                                'Do you want to switch to the '
00337                                                'new location?') % location,
00338                                    caption=_("Switch to new location?"),
00339                                    style = wx.YES_NO | wx.NO_DEFAULT |
00340                                    wx.ICON_QUESTION | wx.CENTRE)
00341             
00342             ret = dlg.ShowModal()
00343             dlg.Destroy()
00344             if ret == wx.ID_YES:
00345                 if RunCommand('g.mapset', parent = self,
00346                               location = location,
00347                               mapset = 'PERMANENT') != 0:
00348                     return
00349                 
00350                 GMessage(parent = self,
00351                          message = _("Current location is <%(loc)s>.\n"
00352                                      "Current mapset is <%(mapset)s>.") % \
00353                              { 'loc' : location, 'mapset' : 'PERMANENT' })
00354         
00355     def OnSettingsChanged(self, event):
00356         """!Here can be functions which have to be called after EVT_SETTINGS_CHANGED. 
00357         Now only set copying of selected text to clipboard (in goutput).
00358         """
00359         ### self._createMenuBar() # bug when menu is re-created on the fly
00360         self._setCopyingOfSelectedText()
00361         
00362     def OnGCPManager(self, event):
00363         """!Launch georectifier module
00364         """
00365         GCPWizard(self)
00366 
00367     def OnGModeler(self, event):
00368         """!Launch Graphical Modeler"""
00369         win = ModelFrame(parent = self)
00370         win.CentreOnScreen()
00371         
00372         win.Show()
00373         
00374     def OnPsMap(self, event):
00375         """!Launch Cartographic Composer
00376         """
00377         win = PsMapFrame(parent = self)
00378         win.CentreOnScreen()
00379         
00380         win.Show()
00381         
00382     def OnDone(self, cmd, returncode):
00383         """Command execution finised"""
00384         if hasattr(self, "model"):
00385             self.model.DeleteIntermediateData(log = self.goutput)
00386             del self.model
00387         self.SetStatusText('')
00388         
00389     def OnRunModel(self, event):
00390         """!Run model"""
00391         filename = ''
00392         dlg = wx.FileDialog(parent = self, message =_("Choose model to run"),
00393                             defaultDir = os.getcwd(),
00394                             wildcard = _("GRASS Model File (*.gxm)|*.gxm"))
00395         if dlg.ShowModal() == wx.ID_OK:
00396             filename = dlg.GetPath()
00397         
00398         if not filename:
00399             dlg.Destroy()
00400             return
00401         
00402         self.model = Model()
00403         self.model.LoadModel(filename)
00404         self.model.Run(log = self.goutput, onDone = self.OnDone, parent = self)
00405         
00406         dlg.Destroy()
00407         
00408     def OnMapsets(self, event):
00409         """!Launch mapset access dialog
00410         """
00411         dlg = MapsetAccess(parent = self, id = wx.ID_ANY)
00412         dlg.CenterOnScreen()
00413         
00414         if dlg.ShowModal() == wx.ID_OK:
00415             ms = dlg.GetMapsets()
00416             RunCommand('g.mapsets',
00417                        parent = self,
00418                        mapset = '%s' % ','.join(ms))
00419             
00420     def OnCBPageChanged(self, event):
00421         """!Page in notebook (display) changed"""
00422         self.curr_page   = self.gm_cb.GetCurrentPage()
00423         self.curr_pagenum = self.gm_cb.GetSelection()
00424         try:
00425             self.curr_page.maptree.mapdisplay.SetFocus()
00426             self.curr_page.maptree.mapdisplay.Raise()
00427         except:
00428             pass
00429         
00430         event.Skip()
00431 
00432     def OnPageChanged(self, event):
00433         """!Page in notebook changed"""
00434         page = event.GetSelection()
00435         if page == self.notebook.GetPageIndexByName('output'):
00436             # remove '(...)'
00437             self.notebook.SetPageText(page, _("Command console"))
00438             wx.CallAfter(self.goutput.ResetFocus)
00439         self.SetStatusText('', 0)
00440         
00441         event.Skip()
00442 
00443     def OnCBPageClosed(self, event):
00444         """!Page of notebook closed
00445         Also close associated map display
00446         """
00447         if UserSettings.Get(group = 'manager', key = 'askOnQuit', subkey = 'enabled'):
00448             maptree = self.curr_page.maptree
00449             
00450             if self.workspaceFile:
00451                 message = _("Do you want to save changes in the workspace?")
00452             else:
00453                 message = _("Do you want to store current settings "
00454                             "to workspace file?")
00455             
00456             # ask user to save current settings
00457             if maptree.GetCount() > 0:
00458                 name = self.gm_cb.GetPageText(self.curr_pagenum)
00459                 dlg = wx.MessageDialog(self,
00460                                        message = message,
00461                                        caption = _("Close Map Display %s") % name,
00462                                        style = wx.YES_NO | wx.YES_DEFAULT |
00463                                        wx.CANCEL | wx.ICON_QUESTION | wx.CENTRE)
00464                 ret = dlg.ShowModal()
00465                 if ret == wx.ID_YES:
00466                     if not self.workspaceFile:
00467                         self.OnWorkspaceSaveAs()
00468                     else:
00469                         self.SaveToWorkspaceFile(self.workspaceFile)
00470                 elif ret == wx.ID_CANCEL:
00471                     event.Veto()
00472                     dlg.Destroy()
00473                     return
00474                 dlg.Destroy()
00475 
00476         self.gm_cb.GetPage(event.GetSelection()).maptree.Map.Clean()
00477         self.gm_cb.GetPage(event.GetSelection()).maptree.Close(True)
00478 
00479         self.curr_page = None
00480 
00481         event.Skip()
00482 
00483     def GetLayerTree(self):
00484         """!Get current layer tree"""
00485         return self.curr_page.maptree
00486     
00487     def GetLogWindow(self):
00488         """!Get widget for command output"""
00489         return self.goutput
00490     
00491     def GetMenuCmd(self, event):
00492         """!Get GRASS command from menu item
00493 
00494         Return command as a list"""
00495         layer = None
00496         
00497         if event:
00498             cmd = self.menucmd[event.GetId()]
00499         
00500         try:
00501             cmdlist = cmd.split(' ')
00502         except: # already list?
00503             cmdlist = cmd
00504         
00505         # check list of dummy commands for GUI modules that do not have GRASS
00506         # bin modules or scripts. 
00507         if cmd in ['vcolors', 'r.mapcalc', 'r3.mapcalc']:
00508             return cmdlist
00509 
00510         try:
00511             layer = self.curr_page.maptree.layer_selected
00512             name = self.curr_page.maptree.GetPyData(layer)[0]['maplayer'].name
00513             type = self.curr_page.maptree.GetPyData(layer)[0]['type']
00514         except:
00515             layer = None
00516 
00517         if layer and len(cmdlist) == 1: # only if no paramaters given
00518             if (type == 'raster' and cmdlist[0][0] == 'r' and cmdlist[0][1] != '3') or \
00519                     (type == 'vector' and cmdlist[0][0] == 'v'):
00520                 input = GUI().GetCommandInputMapParamKey(cmdlist[0])
00521                 if input:
00522                     cmdlist.append("%s=%s" % (input, name))
00523         
00524         return cmdlist
00525 
00526     def RunMenuCmd(self, event = None, cmd = []):
00527         """!Run command selected from menu"""
00528         if event:
00529             cmd = self.GetMenuCmd(event)
00530         self.goutput.RunCmd(cmd, switchPage = False)
00531 
00532     def OnMenuCmd(self, event = None, cmd = []):
00533         """!Parse command selected from menu"""
00534         if event:
00535             cmd = self.GetMenuCmd(event)
00536         GUI(parent = self).ParseCommand(cmd)
00537         
00538     def OnVDigit(self, event):
00539         """!Start vector digitizer
00540         """
00541         if not self.curr_page:
00542             self.MsgNoLayerSelected()
00543             return
00544         
00545         tree = self.GetLayerTree()
00546         layer = tree.layer_selected
00547         # no map layer selected
00548         if not layer:
00549             self.MsgNoLayerSelected()
00550             return
00551         
00552         # available only for vector map layers
00553         try:
00554             mapLayer = tree.GetPyData(layer)[0]['maplayer']
00555         except:
00556             mapLayer = None
00557         
00558         if not mapLayer or mapLayer.GetType() != 'vector':
00559             GMessage(parent = self,
00560                      message = _("Selected map layer is not vector."))
00561             return
00562         
00563         if mapLayer.GetMapset() != grass.gisenv()['MAPSET']:
00564             GMessage(parent = self,
00565                      message = _("Editing is allowed only for vector maps from the "
00566                                  "current mapset."))
00567             return
00568         
00569         if not tree.GetPyData(layer)[0]:
00570             return
00571         dcmd = tree.GetPyData(layer)[0]['cmd']
00572         if not dcmd:
00573             return
00574         
00575         tree.OnStartEditing(None)
00576         
00577     def OnRunScript(self, event):
00578         """!Run script"""
00579         # open dialog and choose script file
00580         dlg = wx.FileDialog(parent = self, message = _("Choose script file to run"),
00581                             defaultDir = os.getcwd(),
00582                             wildcard = _("Python script (*.py)|*.py|Bash script (*.sh)|*.sh"))
00583         
00584         filename = None
00585         if dlg.ShowModal() == wx.ID_OK:
00586             filename = dlg.GetPath()
00587         
00588         if not filename:
00589             return False
00590         
00591         if not os.path.exists(filename):
00592             GError(parent = self,
00593                    message = _("Script file '%s' doesn't exist. "
00594                                "Operation canceled.") % filename)
00595             return
00596 
00597         # check permission
00598         if not os.access(filename, os.X_OK):
00599             dlg = wx.MessageDialog(self,
00600                                    message = _("Script <%s> is not executable. "
00601                                                "Do you want to set the permissions "
00602                                                "that allows you to run this script "
00603                                                "(note that you must be the owner of the file)?" % \
00604                                                    os.path.basename(filename)),
00605                                    caption = _("Set permission?"),
00606                                    style = wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
00607             if dlg.ShowModal() != wx.ID_YES:
00608                 return
00609             dlg.Destroy()
00610             try:
00611                 mode = stat.S_IMODE(os.lstat(filename)[stat.ST_MODE])
00612                 os.chmod(filename, mode | stat.S_IXUSR)
00613             except OSError:
00614                 GError(_("Unable to set permission. Operation canceled."), parent = self)
00615                 return
00616         
00617         # check GRASS_ADDON_PATH
00618         addonPath = os.getenv('GRASS_ADDON_PATH', [])
00619         if addonPath:
00620             addonPath = addonPath.split(os.pathsep)
00621         dirName = os.path.dirname(filename)
00622         if dirName not in addonPath:
00623             addonPath.append(dirName)
00624             dlg = wx.MessageDialog(self,
00625                                    message = _("Directory '%s' is not defined in GRASS_ADDON_PATH. "
00626                                                "Do you want add this directory to GRASS_ADDON_PATH?") % \
00627                                        dirName,
00628                                    caption = _("Update Addons path?"),
00629                                    style = wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
00630             if dlg.ShowModal() == wx.ID_YES:
00631                 os.environ['GRASS_ADDON_PATH'] = os.pathsep.join(addonPath)
00632                 RunCommand('g.gisenv', set = 'ADDON_PATH=%s' % os.environ['GRASS_ADDON_PATH'])
00633         
00634         self.goutput.WriteCmdLog(_("Launching script '%s'...") % filename)
00635         self.goutput.RunCmd([filename], switchPage = True)
00636         
00637     def OnChangeLocation(self, event):
00638         """Change current location"""
00639         dlg = LocationDialog(parent = self)
00640         if dlg.ShowModal() == wx.ID_OK:
00641             location, mapset = dlg.GetValues()
00642             dlg.Destroy()
00643             
00644             if not location or not mapset:
00645                 GError(parent = self,
00646                        message = _("No location/mapset provided. Operation canceled."))
00647                 return # this should not happen
00648             
00649             if RunCommand('g.mapset', parent = self,
00650                           location = location,
00651                           mapset = mapset) != 0:
00652                 return # error reported
00653             
00654             # close workspace
00655             self.OnWorkspaceClose()
00656             self.OnWorkspaceNew()
00657             GMessage(parent = self,
00658                      message = _("Current location is <%(loc)s>.\n"
00659                                  "Current mapset is <%(mapset)s>.") % \
00660                          { 'loc' : location, 'mapset' : mapset })
00661         
00662     def OnCreateMapset(self, event):
00663         """!Create new mapset"""
00664         dlg = wx.TextEntryDialog(parent = self,
00665                                  message = _('Enter name for new mapset:'),
00666                                  caption = _('Create new mapset'))
00667         
00668         if dlg.ShowModal() ==  wx.ID_OK:
00669             mapset = dlg.GetValue()
00670             if not mapset:
00671                 GError(parent = self,
00672                        message = _("No mapset provided. Operation canceled."))
00673                 return
00674             
00675             ret = RunCommand('g.mapset',
00676                              parent = self,
00677                              flags = 'c',
00678                              mapset = mapset)
00679             if ret == 0:
00680                 GMessage(parent = self,
00681                          message = _("Current mapset is <%s>.") % mapset)
00682             
00683     def OnChangeMapset(self, event):
00684         """Change current mapset"""
00685         dlg = MapsetDialog(parent = self)
00686         
00687         if dlg.ShowModal() == wx.ID_OK:
00688             mapset = dlg.GetMapset()
00689             dlg.Destroy()
00690             
00691             if not mapset:
00692                 GError(parent = self,
00693                        message = _("No mapset provided. Operation canceled."))
00694                 return
00695             
00696             if RunCommand('g.mapset',
00697                           parent = self,
00698                           mapset = mapset) == 0:
00699                 GMessage(parent = self,
00700                          message = _("Current mapset is <%s>.") % mapset)
00701         
00702     def OnNewVector(self, event):
00703         """!Create new vector map layer"""
00704         dlg = CreateNewVector(self, log = self.goutput,
00705                               cmd = (('v.edit',
00706                                       { 'tool' : 'create' },
00707                                       'map')))
00708         
00709         if not dlg:
00710             return
00711         
00712         name = dlg.GetName(full = True)
00713         if name and dlg.IsChecked('add'):
00714             # add layer to map layer tree
00715             self.curr_page.maptree.AddLayer(ltype = 'vector',
00716                                             lname = name,
00717                                             lcmd = ['d.vect', 'map=%s' % name])
00718         dlg.Destroy()
00719         
00720     def OnAboutGRASS(self, event):
00721         """!Display 'About GRASS' dialog"""
00722         win = AboutWindow(self)
00723         win.CentreOnScreen()
00724         win.Show(True)  
00725 
00726     def _popupMenu(self, data):
00727         """!Create popup menu
00728         """
00729         point = wx.GetMousePosition()
00730         menu = wx.Menu()
00731         
00732         for key, handler in data:
00733             if key is None:
00734                 menu.AppendSeparator()
00735                 continue
00736             item = wx.MenuItem(menu, wx.ID_ANY, LMIcons[key].GetLabel())
00737             item.SetBitmap(LMIcons[key].GetBitmap(self.iconsize))
00738             menu.AppendItem(item)
00739             self.Bind(wx.EVT_MENU, handler, item)
00740         
00741         # create menu
00742         self.PopupMenu(menu)
00743         menu.Destroy()
00744 
00745     def OnImportMenu(self, event):
00746         """!Import maps menu (import, link)
00747         """
00748         self._popupMenu((('rastImport',    self.OnImportGdalLayers),
00749                          ('vectImport',    self.OnImportOgrLayers)))
00750         
00751     def OnWorkspaceNew(self, event = None):
00752         """!Create new workspace file
00753 
00754         Erase current workspace settings first
00755         """
00756         Debug.msg(4, "GMFrame.OnWorkspaceNew():")
00757         
00758         # start new map display if no display is available
00759         if not self.curr_page:
00760             self.NewDisplay()
00761         
00762         maptree = self.curr_page.maptree
00763         
00764         # ask user to save current settings
00765         if self.workspaceFile and self.workspaceChanged:
00766             self.OnWorkspaceSave()
00767         elif self.workspaceFile is None and maptree.GetCount() > 0:
00768              dlg = wx.MessageDialog(self, message = _("Current workspace is not empty. "
00769                                                     "Do you want to store current settings "
00770                                                     "to workspace file?"),
00771                                     caption = _("Create new workspace?"),
00772                                     style = wx.YES_NO | wx.YES_DEFAULT | \
00773                                         wx.CANCEL | wx.ICON_QUESTION)
00774              ret = dlg.ShowModal()
00775              if ret == wx.ID_YES:
00776                  self.OnWorkspaceSaveAs()
00777              elif ret == wx.ID_CANCEL:
00778                  dlg.Destroy()
00779                  return
00780              
00781              dlg.Destroy()
00782         
00783         # delete all items
00784         maptree.DeleteAllItems()
00785         
00786         # add new root element
00787         maptree.root = maptree.AddRoot("Map Layers")
00788         self.curr_page.maptree.SetPyData(maptree.root, (None,None))
00789         
00790         # no workspace file loaded
00791         self.workspaceFile = None
00792         self.workspaceChanged = False
00793         self.SetTitle(self.baseTitle)
00794         
00795     def OnWorkspaceOpen(self, event = None):
00796         """!Open file with workspace definition"""
00797         dlg = wx.FileDialog(parent = self, message = _("Choose workspace file"),
00798                             defaultDir = os.getcwd(), wildcard = _("GRASS Workspace File (*.gxw)|*.gxw"))
00799 
00800         filename = ''
00801         if dlg.ShowModal() == wx.ID_OK:
00802             filename = dlg.GetPath()
00803 
00804         if filename == '':
00805             return
00806 
00807         Debug.msg(4, "GMFrame.OnWorkspaceOpen(): filename=%s" % filename)
00808         
00809         # delete current layer tree content
00810         self.OnWorkspaceClose()
00811         
00812         self.LoadWorkspaceFile(filename)
00813 
00814         self.workspaceFile = filename
00815         self.SetTitle(self.baseTitle + " - " +  os.path.basename(self.workspaceFile))
00816 
00817     def LoadWorkspaceFile(self, filename):
00818         """!Load layer tree definition stored in GRASS Workspace XML file (gxw)
00819 
00820         @todo Validate against DTD
00821         
00822         @return True on success
00823         @return False on error
00824         """
00825         # dtd
00826         dtdFilename = os.path.join(globalvar.ETCWXDIR, "xml", "grass-gxw.dtd")
00827         
00828         # parse workspace file
00829         try:
00830             gxwXml = ProcessWorkspaceFile(etree.parse(filename))
00831         except Exception, e:
00832             GError(parent = self,
00833                    message = _("Reading workspace file <%s> failed.\n"
00834                                     "Invalid file, unable to parse XML document.") % filename)
00835             return
00836         
00837         busy = wx.BusyInfo(message = _("Please wait, loading workspace..."),
00838                            parent = self)
00839         wx.Yield()
00840 
00841         #
00842         # load layer manager window properties
00843         #
00844         if not UserSettings.Get(group = 'general', key = 'workspace',
00845                                 subkey = ['posManager', 'enabled']):
00846             if gxwXml.layerManager['pos']:
00847                 self.SetPosition(gxwXml.layerManager['pos'])
00848             if gxwXml.layerManager['size']:
00849                 self.SetSize(gxwXml.layerManager['size'])
00850         
00851         #
00852         # start map displays first (list of layers can be empty)
00853         #
00854         displayId = 0
00855         mapdisplay = list()
00856         for display in gxwXml.displays:
00857             mapdisp = self.NewDisplay(name = display['name'], show = False)
00858             mapdisplay.append(mapdisp)
00859             maptree = self.gm_cb.GetPage(displayId).maptree
00860             
00861             # set windows properties
00862             mapdisp.SetProperties(render = display['render'],
00863                                   mode = display['mode'],
00864                                   showCompExtent = display['showCompExtent'],
00865                                   alignExtent = display['alignExtent'],
00866                                   constrainRes = display['constrainRes'],
00867                                   projection = display['projection']['enabled'])
00868 
00869             if display['projection']['enabled']:
00870                 if display['projection']['epsg']:
00871                     UserSettings.Set(group = 'display', key = 'projection', subkey = 'epsg',
00872                                      value = display['projection']['epsg'])
00873                     if display['projection']['proj']:
00874                         UserSettings.Set(group = 'display', key = 'projection', subkey = 'proj4',
00875                                          value = display['projection']['proj'])
00876             
00877             # set position and size of map display
00878             if not UserSettings.Get(group = 'general', key = 'workspace', subkey = ['posDisplay', 'enabled']):
00879                 if display['pos']:
00880                     mapdisp.SetPosition(display['pos'])
00881                 if display['size']:
00882                     mapdisp.SetSize(display['size'])
00883                     
00884             # set extent if defined
00885             if display['extent']:
00886                 w, s, e, n = display['extent']
00887                 region = maptree.Map.region = maptree.Map.GetRegion(w = w, s = s, e = e, n = n)
00888                 mapdisp.GetWindow().ResetZoomHistory()
00889                 mapdisp.GetWindow().ZoomHistory(region['n'],
00890                                                 region['s'],
00891                                                 region['e'],
00892                                                 region['w'])
00893                 
00894             mapdisp.Show()
00895             
00896             displayId += 1
00897     
00898         maptree = None 
00899         selected = [] # list of selected layers
00900         # 
00901         # load list of map layers
00902         #
00903         for layer in gxwXml.layers:
00904             display = layer['display']
00905             maptree = self.gm_cb.GetPage(display).maptree
00906             
00907             newItem = maptree.AddLayer(ltype = layer['type'],
00908                                        lname = layer['name'],
00909                                        lchecked = layer['checked'],
00910                                        lopacity = layer['opacity'],
00911                                        lcmd = layer['cmd'],
00912                                        lgroup = layer['group'],
00913                                        lnviz = layer['nviz'],
00914                                        lvdigit = layer['vdigit'])
00915             
00916             if layer.has_key('selected'):
00917                 if layer['selected']:
00918                     selected.append((maptree, newItem))
00919                 else:
00920                     maptree.SelectItem(newItem, select = False)
00921             
00922         for maptree, layer in selected:
00923             if not maptree.IsSelected(layer):
00924                 maptree.SelectItem(layer, select = True)
00925                 maptree.layer_selected = layer
00926                 
00927         busy.Destroy()
00928             
00929         for idx, mdisp in enumerate(mapdisplay):
00930             mdisp.MapWindow2D.UpdateMap()
00931             #nviz
00932             if gxwXml.displays[idx]['viewMode'] == '3d':
00933                 mdisp.AddNviz()
00934                 self.nviz.UpdateState(view = gxwXml.nviz_state['view'],
00935                                               iview = gxwXml.nviz_state['iview'],
00936                                               light = gxwXml.nviz_state['light'])
00937                 mdisp.MapWindow3D.constants = gxwXml.nviz_state['constants']
00938                 for idx, constant in enumerate(mdisp.MapWindow3D.constants):
00939                     mdisp.MapWindow3D.AddConstant(constant, idx + 1)
00940                 for page in ('view', 'light', 'fringe', 'constant', 'cplane'):
00941                     self.nviz.UpdatePage(page)
00942                 self.nviz.UpdateSettings()
00943                 mapdisp.toolbars['map'].combo.SetSelection(1)
00944 
00945 
00946         return True
00947     
00948     def OnWorkspaceLoadGrcFile(self, event):
00949         """!Load map layers from GRC file (Tcl/Tk GUI) into map layer tree"""
00950         dlg = wx.FileDialog(parent = self, message = _("Choose GRC file to load"),
00951                             defaultDir = os.getcwd(), wildcard = _("Old GRASS Workspace File (*.grc)|*.grc"))
00952 
00953         filename = ''
00954         if dlg.ShowModal() == wx.ID_OK:
00955             filename = dlg.GetPath()
00956 
00957         if filename == '':
00958             return
00959 
00960         Debug.msg(4, "GMFrame.OnWorkspaceLoadGrcFile(): filename=%s" % filename)
00961 
00962         # start new map display if no display is available
00963         if not self.curr_page:
00964             self.NewDisplay()
00965 
00966         busy = wx.BusyInfo(message = _("Please wait, loading workspace..."),
00967                            parent = self)
00968         wx.Yield()
00969 
00970         maptree = None
00971         for layer in ProcessGrcFile(filename).read(self):
00972             maptree = self.gm_cb.GetPage(layer['display']).maptree
00973             newItem = maptree.AddLayer(ltype = layer['type'],
00974                                        lname = layer['name'],
00975                                        lchecked = layer['checked'],
00976                                        lopacity = layer['opacity'],
00977                                        lcmd = layer['cmd'],
00978                                        lgroup = layer['group'])
00979 
00980             busy.Destroy()
00981             
00982         if maptree:
00983             # reverse list of map layers
00984             maptree.Map.ReverseListOfLayers()
00985 
00986     def OnWorkspaceSaveAs(self, event = None):
00987         """!Save workspace definition to selected file"""
00988         dlg = wx.FileDialog(parent = self, message = _("Choose file to save current workspace"),
00989                             defaultDir = os.getcwd(), wildcard = _("GRASS Workspace File (*.gxw)|*.gxw"), style = wx.FD_SAVE)
00990 
00991         filename = ''
00992         if dlg.ShowModal() == wx.ID_OK:
00993             filename = dlg.GetPath()
00994 
00995         if filename == '':
00996             return False
00997 
00998         # check for extension
00999         if filename[-4:] != ".gxw":
01000             filename += ".gxw"
01001 
01002         if os.path.exists(filename):
01003             dlg = wx.MessageDialog(self, message = _("Workspace file <%s> already exists. "
01004                                                      "Do you want to overwrite this file?") % filename,
01005                                    caption = _("Save workspace"), style = wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
01006             if dlg.ShowModal() != wx.ID_YES:
01007                 dlg.Destroy()
01008                 return False
01009 
01010         Debug.msg(4, "GMFrame.OnWorkspaceSaveAs(): filename=%s" % filename)
01011 
01012         self.SaveToWorkspaceFile(filename)
01013         self.workspaceFile = filename
01014         self.SetTitle(self.baseTitle + " - " + os.path.basename(self.workspaceFile))
01015 
01016     def OnWorkspaceSave(self, event = None):
01017         """!Save file with workspace definition"""
01018         if self.workspaceFile:
01019             dlg = wx.MessageDialog(self, message = _("Workspace file <%s> already exists. "
01020                                                    "Do you want to overwrite this file?") % \
01021                                        self.workspaceFile,
01022                                    caption = _("Save workspace"), style = wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
01023             if dlg.ShowModal() == wx.ID_NO:
01024                 dlg.Destroy()
01025             else:
01026                 Debug.msg(4, "GMFrame.OnWorkspaceSave(): filename=%s" % self.workspaceFile)
01027                 self.SaveToWorkspaceFile(self.workspaceFile)
01028                 self.SetTitle(self.baseTitle + " - " + os.path.basename(self.workspaceFile))
01029                 self.workspaceChanged = False
01030         else:
01031             self.OnWorkspaceSaveAs()
01032 
01033     def SaveToWorkspaceFile(self, filename):
01034         """!Save layer tree layout to workspace file
01035         
01036         Return True on success, False on error
01037         """
01038         tmpfile = tempfile.TemporaryFile(mode = 'w+b')
01039         try:
01040             WriteWorkspaceFile(lmgr = self, file = tmpfile)
01041         except StandardError, e:
01042             GError(parent = self,
01043                    message = _("Writing current settings to workspace file "
01044                                "failed."))
01045             return False
01046         
01047         try:
01048             mfile = open(filename, "w")
01049             tmpfile.seek(0)
01050             for line in tmpfile.readlines():
01051                 mfile.write(line)
01052         except IOError:
01053             GError(parent = self,
01054                    message = _("Unable to open file <%s> for writing.") % filename)
01055             return False
01056         
01057         mfile.close()
01058         
01059         return True
01060     
01061     def OnWorkspaceClose(self, event = None):
01062         """!Close file with workspace definition
01063         
01064         If workspace has been modified ask user to save the changes.
01065         """
01066         Debug.msg(4, "GMFrame.OnWorkspaceClose(): file=%s" % self.workspaceFile)
01067         
01068         self.OnDisplayCloseAll()
01069         self.workspaceFile = None
01070         self.workspaceChanged = False
01071         self.SetTitle(self.baseTitle)
01072         self.disp_idx = 0
01073         self.curr_page = None
01074         
01075     def OnDisplayClose(self, event = None):
01076         """!Close current map display window
01077         """
01078         if self.curr_page and self.curr_page.maptree.mapdisplay:
01079             self.curr_page.maptree.mapdisplay.OnCloseWindow(event)
01080         
01081     def OnDisplayCloseAll(self, event = None):
01082         """!Close all open map display windows
01083         """
01084         displays = list()
01085         for page in range(0, self.gm_cb.GetPageCount()):
01086             displays.append(self.gm_cb.GetPage(page).maptree.mapdisplay)
01087         
01088         for display in displays:
01089             display.OnCloseWindow(event)
01090         
01091     def OnRenameDisplay(self, event):
01092         """!Change Map Display name"""
01093         name = self.gm_cb.GetPageText(self.curr_pagenum)
01094         dlg = wx.TextEntryDialog(self, message = _("Enter new name:"),
01095                                  caption = _("Rename Map Display"), defaultValue = name)
01096         if dlg.ShowModal() == wx.ID_OK:
01097             name = dlg.GetValue()
01098             self.gm_cb.SetPageText(page = self.curr_pagenum, text = name)
01099             mapdisplay = self.curr_page.maptree.mapdisplay
01100             mapdisplay.SetTitle(_("GRASS GIS Map Display: %(name)s  - Location: %(loc)s") % \
01101                                      { 'name' : name,
01102                                        'loc' : grass.gisenv()["LOCATION_NAME"] })
01103         dlg.Destroy()
01104         
01105     def RulesCmd(self, event):
01106         """!Launches dialog for commands that need rules input and
01107         processes rules
01108         """
01109         cmd = self.GetMenuCmd(event)
01110         
01111         if cmd[0] == 'r.colors':
01112             ctable = RasterColorTable(self)
01113         else:
01114             ctable = VectorColorTable(self, attributeType = 'color')
01115         ctable.CentreOnScreen()
01116         ctable.Show()
01117         
01118     def OnXTermNoXMon(self, event):
01119         """!
01120         Run commands that need xterm
01121         """
01122         self.OnXTerm(event, need_xmon = False)
01123         
01124     def OnXTerm(self, event, need_xmon = True):
01125         """!
01126         Run commands that need interactive xmon
01127 
01128         @param need_xmon True to start X monitor
01129         """
01130         # unset display mode
01131         del os.environ['GRASS_RENDER_IMMEDIATE']
01132         
01133         if need_xmon:
01134             # open next available xmon
01135             xmonlist = []
01136             
01137             # make list of xmons that are not running
01138             ret = RunCommand('d.mon',
01139                              flags = 'L',
01140                              read = True)
01141             
01142             for line in ret.split('\n'):               
01143                 line = line.strip()
01144                 if line.startswith('x') and 'not running' in line:
01145                     xmonlist.append(line[0:2])
01146             
01147             # find available xmon
01148             xmon = xmonlist[0]
01149             
01150             # bring up the xmon
01151             cmdlist = ['d.mon', xmon]
01152             p = Command(cmdlist, wait=False)
01153         
01154         # run the command        
01155         command = self.GetMenuCmd(event)
01156         command = ' '.join(command)
01157         
01158         gisbase = os.environ['GISBASE']
01159         
01160         if sys.platform == "win32":
01161             runbat = os.path.join(gisbase,'etc','grass-run.bat')
01162             cmdlist = ["start", runbat, runbat, command]
01163         else:
01164             if sys.platform == "darwin":
01165                 xtermwrapper = os.path.join(gisbase,'etc','grass-xterm-mac')
01166             else:
01167                 xtermwrapper = os.path.join(gisbase,'etc','grass-xterm-wrapper')
01168             
01169             grassrun = os.path.join(gisbase,'etc','grass-run.sh')
01170             cmdlist = [xtermwrapper, '-e', grassrun, command]
01171         
01172         p = Command(cmdlist, wait=False)
01173         
01174         # reset display mode
01175         os.environ['GRASS_RENDER_IMMEDIATE'] = 'TRUE'
01176         
01177     def OnEditImageryGroups(self, event, cmd = None):
01178         """!Show dialog for creating and editing groups.
01179         """
01180         dlg = GroupDialog(self)
01181         dlg.CentreOnScreen()
01182         dlg.Show()
01183         
01184     def OnInstallExtension(self, event):
01185         """!Install extension from GRASS Addons SVN repository"""
01186         win = InstallExtensionWindow(self, size = (650, 550))
01187         win.CentreOnScreen()
01188         win.Show()
01189 
01190     def OnUninstallExtension(self, event):
01191         """!Uninstall extension"""
01192         win = UninstallExtensionWindow(self, size = (650, 300))
01193         win.CentreOnScreen()
01194         win.Show()
01195 
01196     def OnPreferences(self, event):
01197         """!General GUI preferences/settings
01198         """
01199         if not self.dialogs['preferences']:
01200             dlg = PreferencesDialog(parent = self)
01201             self.dialogs['preferences'] = dlg
01202             self.dialogs['preferences'].CenterOnScreen()
01203             
01204             dlg.Bind(EVT_SETTINGS_CHANGED, self.OnSettingsChanged)
01205         
01206         self.dialogs['preferences'].ShowModal()
01207         
01208     def OnHelp(self, event):
01209         """!Show help
01210         """
01211         self.goutput.RunCmd(['g.manual','-i'])
01212         
01213     def OnHistogram(self, event):
01214         """!Init histogram display canvas and tools
01215         """
01216         from modules.histogram import HistogramFrame
01217         win = HistogramFrame(self)
01218         
01219         win.CentreOnScreen()
01220         win.Show()
01221         win.Refresh()
01222         win.Update()
01223         
01224     def OnProfile(self, event):
01225         """!Launch profile tool
01226         """
01227         win = profile.ProfileFrame(parent = self)
01228         
01229         win.CentreOnParent()
01230         win.Show()
01231         win.Refresh()
01232         win.Update()
01233         
01234     def OnMapCalculator(self, event, cmd = ''):
01235         """!Init map calculator for interactive creation of mapcalc statements
01236         """
01237         if event:
01238             try:
01239                 cmd = self.GetMenuCmd(event)
01240             except KeyError:
01241                 cmd = ['r.mapcalc']
01242         
01243         win = MapCalcFrame(parent = self,
01244                            cmd = cmd[0])
01245         win.CentreOnScreen()
01246         win.Show()
01247         
01248     def OnVectorCleaning(self, event, cmd = ''):
01249         """!Init interactive vector cleaning
01250         """
01251         from modules.vclean import VectorCleaningFrame
01252         win = VectorCleaningFrame(parent = self)
01253         win.CentreOnScreen()
01254         win.Show()
01255         
01256     def OnImportDxfFile(self, event, cmd = None):
01257         """!Convert multiple DXF layers to GRASS vector map layers"""
01258         dlg = DxfImportDialog(parent = self)
01259         dlg.CentreOnScreen()
01260         dlg.Show()
01261 
01262     def OnImportGdalLayers(self, event, cmd = None):
01263         """!Convert multiple GDAL layers to GRASS raster map layers"""
01264         dlg = GdalImportDialog(parent = self)
01265         dlg.CentreOnScreen()
01266         dlg.Show()
01267 
01268     def OnLinkGdalLayers(self, event, cmd = None):
01269         """!Link multiple GDAL layers to GRASS raster map layers"""
01270         dlg = GdalImportDialog(parent = self, link = True)
01271         dlg.CentreOnScreen()
01272         dlg.Show()
01273         
01274     def OnImportOgrLayers(self, event, cmd = None):
01275         """!Convert multiple OGR layers to GRASS vector map layers"""
01276         dlg = GdalImportDialog(parent = self, ogr = True)
01277         dlg.CentreOnScreen()
01278         dlg.Show()
01279         
01280     def OnLinkOgrLayers(self, event, cmd = None):
01281         """!Links multiple OGR layers to GRASS vector map layers"""
01282         dlg = GdalImportDialog(parent = self, ogr = True, link = True)
01283         dlg.CentreOnScreen()
01284         dlg.Show()
01285         
01286     def OnImportWMS(self, event):
01287         """!Import data from OGC WMS server"""
01288         dlg = WMSDialog(parent = self, service = 'wms')
01289         dlg.CenterOnScreen()
01290         
01291         if dlg.ShowModal() == wx.ID_OK: # -> import layers
01292             layers = dlg.GetLayers()
01293             
01294             if len(layers.keys()) > 0:
01295                 for layer in layers.keys():
01296                     cmd = ['r.in.wms',
01297                            'mapserver=%s' % dlg.GetSettings()['server'],
01298                            'layers=%s' % layer,
01299                            'output=%s' % layer,
01300                            'format=png',
01301                            '--overwrite']
01302                     styles = ','.join(layers[layer])
01303                     if styles:
01304                         cmd.append('styles=%s' % styles)
01305                     self.goutput.RunCmd(cmd, switchPage = True)
01306 
01307                     self.curr_page.maptree.AddLayer(ltype = 'raster',
01308                                                     lname = layer,
01309                                                     lcmd = ['d.rast', 'map=%s' % layer],
01310                                                     multiple = False)
01311             else:
01312                 self.goutput.WriteWarning(_("Nothing to import. No WMS layer selected."))
01313                 
01314                 
01315         dlg.Destroy()
01316         
01317     def OnShowAttributeTable(self, event, selection = None):
01318         """!Show attribute table of the given vector map layer
01319         """
01320         if not self.curr_page:
01321             self.MsgNoLayerSelected()
01322             return
01323         
01324         tree = self.GetLayerTree()
01325         layer = tree.layer_selected
01326         # no map layer selected
01327         if not layer:
01328             self.MsgNoLayerSelected()
01329             return
01330         
01331         # available only for vector map layers
01332         try:
01333             maptype = tree.GetPyData(layer)[0]['maplayer'].type
01334         except:
01335             maptype = None
01336         
01337         if not maptype or maptype != 'vector':
01338             GMessage(parent = self,
01339                           message = _("Selected map layer is not vector."))
01340             return
01341         
01342         if not tree.GetPyData(layer)[0]:
01343             return
01344         dcmd = tree.GetPyData(layer)[0]['cmd']
01345         if not dcmd:
01346             return
01347         
01348         busy = wx.BusyInfo(message = _("Please wait, loading attribute data..."),
01349                            parent = self)
01350         wx.Yield()
01351         
01352         dbmanager = AttributeManager(parent = self, id = wx.ID_ANY,
01353                                      size = wx.Size(500, 300),
01354                                      item = layer, log = self.goutput,
01355                                      selection = selection)
01356         
01357         busy.Destroy()
01358         
01359         # register ATM dialog
01360         self.dialogs['atm'].append(dbmanager)
01361         
01362         # show ATM window
01363         dbmanager.Show()
01364         
01365     def OnNewDisplayWMS(self, event = None):
01366         """!Create new layer tree and map display instance"""
01367         self.NewDisplayWMS()
01368 
01369     def OnNewDisplay(self, event = None):
01370         """!Create new layer tree and map display instance"""
01371         self.NewDisplay()
01372 
01373     def NewDisplay(self, name = None, show = True):
01374         """!Create new layer tree, which will
01375         create an associated map display frame
01376 
01377         @param name name of new map display
01378         @param show show map display window if True
01379 
01380         @return reference to mapdisplay intance
01381         """
01382         Debug.msg(1, "GMFrame.NewDisplay(): idx=%d" % self.disp_idx)
01383         
01384         # make a new page in the bookcontrol for the layer tree (on page 0 of the notebook)
01385         self.pg_panel = wx.Panel(self.gm_cb, id = wx.ID_ANY, style = wx.EXPAND)
01386         if name:
01387             dispName = name
01388         else:
01389             dispName = "Display " + str(self.disp_idx + 1)
01390         self.gm_cb.AddPage(self.pg_panel, text = dispName, select = True)
01391         self.curr_page = self.gm_cb.GetCurrentPage()
01392         
01393         # create layer tree (tree control for managing GIS layers)  and put on new notebook page
01394         self.curr_page.maptree = LayerTree(self.curr_page, id = wx.ID_ANY, pos = wx.DefaultPosition,
01395                                            size = wx.DefaultSize, style = wx.TR_HAS_BUTTONS |
01396                                            wx.TR_LINES_AT_ROOT| wx.TR_HIDE_ROOT |
01397                                            wx.TR_DEFAULT_STYLE| wx.NO_BORDER | wx.FULL_REPAINT_ON_RESIZE,
01398                                            idx = self.disp_idx, lmgr = self, notebook = self.gm_cb,
01399                                            auimgr = self._auimgr, showMapDisplay = show)
01400         
01401         # layout for controls
01402         cb_boxsizer = wx.BoxSizer(wx.VERTICAL)
01403         cb_boxsizer.Add(self.curr_page.maptree, proportion = 1, flag = wx.EXPAND, border = 1)
01404         self.curr_page.SetSizer(cb_boxsizer)
01405         cb_boxsizer.Fit(self.curr_page.maptree)
01406         self.curr_page.Layout()
01407         self.curr_page.maptree.Layout()
01408         
01409         # use default window layout
01410         if UserSettings.Get(group = 'general', key = 'defWindowPos', subkey = 'enabled'):
01411             dim = UserSettings.Get(group = 'general', key = 'defWindowPos', subkey = 'dim')
01412             idx = 4 + self.disp_idx * 4
01413             try:
01414                 x, y = map(int, dim.split(',')[idx:idx + 2])
01415                 w, h = map(int, dim.split(',')[idx + 2:idx + 4])
01416                 self.curr_page.maptree.mapdisplay.SetPosition((x, y))
01417                 self.curr_page.maptree.mapdisplay.SetSize((w, h))
01418             except:
01419                 pass
01420         
01421         self.disp_idx += 1
01422         
01423         return self.curr_page.maptree.mapdisplay
01424     
01425     def OnAddMaps(self, event = None):
01426         """!Add selected map layers into layer tree"""
01427         dialog = MapLayersDialog(parent = self, title = _("Add selected map layers into layer tree"))
01428         
01429         if dialog.ShowModal() != wx.ID_OK:
01430             dialog.Destroy()
01431             return
01432         
01433         # start new map display if no display is available
01434         if not self.curr_page:
01435             self.NewDisplay()
01436             
01437         maptree = self.curr_page.maptree
01438         
01439         for layerName in dialog.GetMapLayers():
01440             ltype = dialog.GetLayerType(cmd = True)
01441             if ltype == 'rast':
01442                 cmd = ['d.rast', 'map=%s' % layerName]
01443                 wxType = 'raster'
01444             elif ltype == 'rast3d':
01445                 cmd = ['d.rast3d', 'map=%s' % layerName]
01446                 wxType = '3d-raster'
01447             elif ltype == 'vect':
01448                 cmd = ['d.vect', 'map=%s' % layerName]
01449                 wxType = 'vector'
01450             else:
01451                 GError(parent = self,
01452                        message = _("Unsupported map layer type <%s>.") % ltype)
01453                 return
01454             
01455             newItem = maptree.AddLayer(ltype = wxType,
01456                                        lname = layerName,
01457                                        lchecked = False,
01458                                        lopacity = 1.0,
01459                                        lcmd = cmd,
01460                                        lgroup = None)
01461         dialog.Destroy()
01462         
01463     def OnAddRaster(self, event):
01464         """!Add raster map layer"""
01465         # start new map display if no display is available
01466         if not self.curr_page:
01467             self.NewDisplay(show = True)
01468         
01469         self.notebook.SetSelectionByName('layers')
01470         self.curr_page.maptree.AddLayer('raster')
01471         
01472     def OnAddRaster3D(self, event):
01473         """!Add 3D raster map layer"""
01474         # start new map display if no display is available
01475         if not self.curr_page:
01476             self.NewDisplay(show = True)
01477         
01478         self.AddRaster3D(event)
01479         
01480     def OnAddRasterMisc(self, event):
01481         """!Create misc raster popup-menu"""
01482         # start new map display if no display is available
01483         if not self.curr_page:
01484             self.NewDisplay(show = True)
01485         
01486         self._popupMenu((('addRast3d', self.OnAddRaster3D),
01487                          (None, None),
01488                          ('addRgb',    self.OnAddRasterRGB),
01489                          ('addHis',    self.OnAddRasterHIS),
01490                          (None, None),
01491                          ('addShaded', self.OnAddRasterShaded),
01492                          (None, None),
01493                          ('addRArrow', self.OnAddRasterArrow),
01494                          ('addRNum',   self.OnAddRasterNum)))
01495         
01496         # show map display
01497         self.curr_page.maptree.mapdisplay.Show()
01498         
01499     def OnAddVector(self, event):
01500         """!Add vector map to the current layer tree"""
01501         # start new map display if no display is available
01502         if not self.curr_page:
01503             self.NewDisplay(show = True)
01504         
01505         self.notebook.SetSelectionByName('layers')
01506         self.curr_page.maptree.AddLayer('vector')
01507 
01508     def OnAddVectorMisc(self, event):
01509         """!Create misc vector popup-menu"""
01510         # start new map display if no display is available
01511         if not self.curr_page:
01512             self.NewDisplay(show = True)
01513 
01514         self._popupMenu((('addThematic', self.OnAddVectorTheme),
01515                          ('addChart',    self.OnAddVectorChart)))
01516         
01517         # show map display
01518         self.curr_page.maptree.mapdisplay.Show()
01519 
01520     def OnAddVectorTheme(self, event):
01521         """!Add thematic vector map to the current layer tree"""
01522         self.notebook.SetSelectionByName('layers')
01523         self.curr_page.maptree.AddLayer('thememap')
01524 
01525     def OnAddVectorChart(self, event):
01526         """!Add chart vector map to the current layer tree"""
01527         self.notebook.SetSelectionByName('layers')
01528         self.curr_page.maptree.AddLayer('themechart')
01529 
01530     def OnAddOverlay(self, event):
01531         """!Create decoration overlay menu""" 
01532         # start new map display if no display is available
01533         if not self.curr_page:
01534             self.NewDisplay(show = True)
01535 
01536         self._popupMenu((('addGrid',     self.OnAddGrid),
01537                          ('addLabels',   self.OnAddLabels),
01538                          ('addGeodesic', self.OnAddGeodesic),
01539                          ('addRhumb',    self.OnAddRhumb),
01540                          (None, None),
01541                          ('addCmd',      self.OnAddCommand)))
01542         
01543         # show map display
01544         self.curr_page.maptree.mapdisplay.Show()
01545         
01546     def OnAddRaster3D(self, event):
01547         """!Add 3D raster map to the current layer tree"""
01548         self.notebook.SetSelectionByName('layers')
01549         self.curr_page.maptree.AddLayer('3d-raster')
01550 
01551     def OnAddRasterRGB(self, event):
01552         """!Add RGB raster map to the current layer tree"""
01553         self.notebook.SetSelectionByName('layers')
01554         self.curr_page.maptree.AddLayer('rgb')
01555 
01556     def OnAddRasterHIS(self, event):
01557         """!Add HIS raster map to the current layer tree"""
01558         self.notebook.SetSelectionByName('layers')
01559         self.curr_page.maptree.AddLayer('his')
01560 
01561     def OnAddRasterShaded(self, event):
01562         """!Add shaded relief raster map to the current layer tree"""
01563         self.notebook.SetSelectionByName('layers')
01564         self.curr_page.maptree.AddLayer('shaded')
01565 
01566     def OnAddRasterArrow(self, event):
01567         """!Add flow arrows raster map to the current layer tree"""
01568         self.notebook.SetSelectionByName('layers')
01569         self.curr_page.maptree.AddLayer('rastarrow')
01570 
01571     def OnAddRasterNum(self, event):
01572         """!Add cell number raster map to the current layer tree"""
01573         self.notebook.SetSelectionByName('layers')
01574         self.curr_page.maptree.AddLayer('rastnum')
01575 
01576     def OnAddCommand(self, event):
01577         """!Add command line map layer to the current layer tree"""
01578         # start new map display if no display is available
01579         if not self.curr_page:
01580             self.NewDisplay(show = True)
01581 
01582         self.notebook.SetSelectionByName('layers')
01583         self.curr_page.maptree.AddLayer('command')
01584 
01585         # show map display
01586         self.curr_page.maptree.mapdisplay.Show()
01587 
01588     def OnAddGroup(self, event):
01589         """!Add layer group"""
01590         # start new map display if no display is available
01591         if not self.curr_page:
01592             self.NewDisplay(show = True)
01593 
01594         self.notebook.SetSelectionByName('layers')
01595         self.curr_page.maptree.AddLayer('group')
01596 
01597         # show map display
01598         self.curr_page.maptree.mapdisplay.Show()
01599 
01600     def OnAddGrid(self, event):
01601         """!Add grid map layer to the current layer tree"""
01602         self.notebook.SetSelectionByName('layers')
01603         self.curr_page.maptree.AddLayer('grid')
01604 
01605     def OnAddGeodesic(self, event):
01606         """!Add geodesic line map layer to the current layer tree"""
01607         self.notebook.SetSelectionByName('layers')
01608         self.curr_page.maptree.AddLayer('geodesic')
01609 
01610     def OnAddRhumb(self, event):
01611         """!Add rhumb map layer to the current layer tree"""
01612         self.notebook.SetSelectionByName('layers')
01613         self.curr_page.maptree.AddLayer('rhumb')
01614 
01615     def OnAddLabels(self, event):
01616         """!Add vector labels map layer to the current layer tree"""
01617         # start new map display if no display is available
01618         if not self.curr_page:
01619             self.NewDisplay(show = True)
01620 
01621         self.notebook.SetSelectionByName('layers')
01622         self.curr_page.maptree.AddLayer('labels')
01623 
01624         # show map display
01625         self.curr_page.maptree.mapdisplay.Show()
01626 
01627     def OnDeleteLayer(self, event):
01628         """!Remove selected map layer from the current layer Tree
01629         """
01630         if not self.curr_page or not self.curr_page.maptree.layer_selected:
01631             self.MsgNoLayerSelected()
01632             return
01633 
01634         if UserSettings.Get(group = 'manager', key = 'askOnRemoveLayer', subkey = 'enabled'):
01635             layerName = ''
01636             for item in self.curr_page.maptree.GetSelections():
01637                 name = str(self.curr_page.maptree.GetItemText(item))
01638                 idx = name.find('(opacity')
01639                 if idx > -1:
01640                     layerName += '<' + name[:idx].strip(' ') + '>,\n'
01641                 else:
01642                     layerName += '<' + name + '>,\n'
01643             layerName = layerName.rstrip(',\n')
01644             
01645             if len(layerName) > 2: # <>
01646                 message = _("Do you want to remove map layer(s)\n%s\n"
01647                             "from layer tree?") % layerName
01648             else:
01649                 message = _("Do you want to remove selected map layer(s) "
01650                             "from layer tree?")
01651 
01652             dlg = wx.MessageDialog (parent = self, message = message,
01653                                     caption = _("Remove map layer"),
01654                                     style  =  wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
01655 
01656             if dlg.ShowModal() != wx.ID_YES:
01657                 dlg.Destroy()
01658                 return
01659             
01660             dlg.Destroy()
01661 
01662         for layer in self.curr_page.maptree.GetSelections():
01663             if self.curr_page.maptree.GetPyData(layer)[0]['type'] == 'group':
01664                 self.curr_page.maptree.DeleteChildren(layer)
01665             self.curr_page.maptree.Delete(layer)
01666         
01667     def OnKeyDown(self, event):
01668         """!Key pressed"""
01669         kc = event.GetKeyCode()
01670         
01671         if event.ControlDown():
01672             if kc == wx.WXK_TAB:
01673                 # switch layer list / command output
01674                 if self.notebook.GetSelection() == self.notebook.GetPageIndexByName('layers'):
01675                     self.notebook.SetSelectionByName('output')
01676                 else:
01677                     self.notebook.SetSelectionByName('layers')
01678         
01679         try:
01680             ckc = chr(kc)
01681         except ValueError:
01682             event.Skip()
01683             return
01684         
01685         if event.CtrlDown():
01686             if kc == 'R':
01687                 self.OnAddRaster(None)
01688             elif kc == 'V':
01689                 self.OnAddVector(None)
01690         
01691         event.Skip()
01692 
01693     def OnCloseWindow(self, event):
01694         """!Cleanup when wxGUI is quitted"""
01695         if not self.curr_page:
01696             self._auimgr.UnInit()
01697             self.Destroy()
01698             return
01699         
01700         maptree = self.curr_page.maptree
01701         if self.workspaceChanged and \
01702                 UserSettings.Get(group = 'manager', key = 'askOnQuit', subkey = 'enabled'):
01703             if self.workspaceFile:
01704                 message = _("Do you want to save changes in the workspace?")
01705             else:
01706                 message = _("Do you want to store current settings "
01707                             "to workspace file?")
01708             
01709             # ask user to save current settings
01710             if maptree.GetCount() > 0:
01711                 dlg = wx.MessageDialog(self,
01712                                        message = message,
01713                                        caption = _("Quit GRASS GUI"),
01714                                        style = wx.YES_NO | wx.YES_DEFAULT |
01715                                        wx.CANCEL | wx.ICON_QUESTION | wx.CENTRE)
01716                 ret = dlg.ShowModal()
01717                 if ret == wx.ID_YES:
01718                     if not self.workspaceFile:
01719                         self.OnWorkspaceSaveAs()
01720                     else:
01721                         self.SaveToWorkspaceFile(self.workspaceFile)
01722                 elif ret == wx.ID_CANCEL:
01723                     event.Veto()
01724                     dlg.Destroy()
01725                     return
01726                 dlg.Destroy()
01727         
01728         # don't ask any more...
01729         UserSettings.Set(group = 'manager', key = 'askOnQuit', subkey = 'enabled',
01730                          value = False)
01731         
01732         self.OnDisplayCloseAll()
01733         
01734         self.gm_cb.DeleteAllPages()
01735         
01736         self._auimgr.UnInit()
01737         self.Destroy()
01738         
01739     def MsgNoLayerSelected(self):
01740         """!Show dialog message 'No layer selected'"""
01741         wx.MessageBox(parent = self,
01742                       message = _("No map layer selected. Operation canceled."),
01743                       caption = _("Message"),
01744                       style = wx.OK | wx.ICON_INFORMATION | wx.CENTRE)