GRASS Programmer's Manual  6.4.2(2012)
layertree.py
Go to the documentation of this file.
00001 """!
00002 @package layertree.py
00003 
00004 @brief Utility classes for map layer management.
00005 
00006 Classes:
00007  - AbstractLayer
00008  - Layer
00009  - LayerTree
00010 
00011 (C) 2007-2011 by the GRASS Development Team
00012 This program is free software under the GNU General Public
00013 License (>=v2). Read the file COPYING that comes with GRASS
00014 for details.
00015  
00016 @author Michael Barton (Arizona State University)
00017 @author Jachym Cepicky (Mendel University of Agriculture)
00018 @author Martin Landa <landa.martin gmail.com>
00019 """
00020 
00021 import os
00022 import sys
00023 import string
00024 
00025 import wx
00026 try:
00027     import wx.lib.agw.customtreectrl as CT
00028 except ImportError:
00029     import wx.lib.customtreectrl as CT
00030 import wx.combo
00031 import wx.lib.newevent
00032 import wx.lib.buttons  as  buttons
00033 try:
00034     import treemixin 
00035 except ImportError:
00036     from wx.lib.mixins import treemixin
00037 
00038 import globalvar
00039 
00040 from grass.script import core as grass
00041 
00042 import gdialogs
00043 import menuform
00044 import toolbars
00045 import mapdisp
00046 import render
00047 import histogram
00048 import utils
00049 import profile
00050 from debug import Debug as Debug
00051 from icon import Icons as Icons
00052 from preferences import globalSettings as UserSettings
00053 from vdigit import haveVDigit
00054 from gcmd import GWarning
00055 
00056 TREE_ITEM_HEIGHT = 25
00057 
00058 class LayerTree(treemixin.DragAndDrop, CT.CustomTreeCtrl):
00059     """!Creates layer tree structure
00060     """
00061     def __init__(self, parent,
00062                  id = wx.ID_ANY, style = wx.SUNKEN_BORDER,
00063                  ctstyle = CT.TR_HAS_BUTTONS | CT.TR_HAS_VARIABLE_ROW_HEIGHT |
00064                  CT.TR_HIDE_ROOT | CT.TR_ROW_LINES | CT.TR_FULL_ROW_HIGHLIGHT |
00065                  CT.TR_MULTIPLE, **kwargs):
00066         
00067         if 'style' in kwargs:
00068             ctstyle |= kwargs['style']
00069             del kwargs['style']
00070         self.disp_idx = kwargs['idx']
00071         del kwargs['idx']
00072         self.lmgr = kwargs['lmgr']
00073         del kwargs['lmgr']
00074         self.notebook = kwargs['notebook']   # GIS Manager notebook for layer tree
00075         del kwargs['notebook']
00076         self.auimgr = kwargs['auimgr']       # aui manager
00077         del kwargs['auimgr']
00078         showMapDisplay = kwargs['showMapDisplay']
00079         del kwargs['showMapDisplay']
00080         self.treepg = parent                 # notebook page holding layer tree
00081         self.Map = render.Map()              # instance of render.Map to be associated with display
00082         self.root = None                     # ID of layer tree root node
00083         self.groupnode = 0                   # index value for layers
00084         self.optpage = {}                    # dictionary of notebook option pages for each map layer
00085         self.layer_selected = None           # ID of currently selected layer
00086         self.saveitem = {}                   # dictionary to preserve layer attributes for drag and drop
00087         self.first = True                    # indicates if a layer is just added or not
00088         self.flag = ''                       # flag for drag and drop hittest
00089         self.rerender = False                # layer change requires a rerendering if auto render
00090         self.reorder = False                 # layer change requires a reordering
00091         
00092         try:
00093             ctstyle |= CT.TR_ALIGN_WINDOWS
00094         except AttributeError:
00095             pass
00096         
00097         if globalvar.hasAgw:
00098             super(LayerTree, self).__init__(parent, id, agwStyle = ctstyle, **kwargs)
00099         else:
00100             super(LayerTree, self).__init__(parent, id, style = ctstyle, **kwargs)
00101         self.SetName("LayerTree")
00102         
00103         ### SetAutoLayout() causes that no vertical scrollbar is displayed
00104         ### when some layers are not visible in layer tree
00105         # self.SetAutoLayout(True)
00106         self.SetGradientStyle(1)
00107         self.EnableSelectionGradient(True)
00108         self._setGradient()
00109         
00110         # init associated map display
00111         pos = wx.Point((self.disp_idx + 1) * 25, (self.disp_idx + 1) * 25)
00112         self.mapdisplay = mapdisp.MapFrame(self,
00113                                            id = wx.ID_ANY, pos = pos,
00114                                            size = globalvar.MAP_WINDOW_SIZE,
00115                                            style = wx.DEFAULT_FRAME_STYLE,
00116                                            tree = self, notebook = self.notebook,
00117                                            lmgr = self.lmgr, page = self.treepg,
00118                                            Map = self.Map, auimgr = self.auimgr)
00119         
00120         # title
00121         self.mapdisplay.SetTitle(_("GRASS GIS Map Display: %(id)d  - Location: %(loc)s") % \
00122                                      { 'id' : self.disp_idx + 1,
00123                                        'loc' : grass.gisenv()["LOCATION_NAME"] })
00124         
00125         # show new display
00126         if showMapDisplay is True:
00127             self.mapdisplay.Show()
00128             self.mapdisplay.Refresh()
00129             self.mapdisplay.Update()
00130         
00131         self.root = self.AddRoot(_("Map Layers"))
00132         self.SetPyData(self.root, (None, None))
00133         
00134         # create image list to use with layer tree
00135         il = wx.ImageList(16, 16, mask = False)
00136         
00137         trart = wx.ArtProvider.GetBitmap(wx.ART_FOLDER_OPEN, wx.ART_OTHER, (16, 16))
00138         self.folder_open = il.Add(trart)
00139         trart = wx.ArtProvider.GetBitmap(wx.ART_FOLDER, wx.ART_OTHER, (16, 16))
00140         self.folder = il.Add(trart)
00141         
00142         bmpsize = (16, 16)
00143         icons = Icons['layerManager']
00144         trgif = icons["addRast"].GetBitmap(bmpsize)
00145         self.rast_icon = il.Add(trgif)
00146         
00147         trgif = icons["addRast3d"].GetBitmap(bmpsize)
00148         self.rast3d_icon = il.Add(trgif)
00149         
00150         trgif = icons["addRgb"].GetBitmap(bmpsize)
00151         self.rgb_icon = il.Add(trgif)
00152         
00153         trgif = icons["addHis"].GetBitmap(bmpsize)
00154         self.his_icon = il.Add(trgif)
00155         
00156         trgif = icons["addShaded"].GetBitmap(bmpsize)
00157         self.shaded_icon = il.Add(trgif)
00158         
00159         trgif = icons["addRArrow"].GetBitmap(bmpsize)
00160         self.rarrow_icon = il.Add(trgif)
00161         
00162         trgif = icons["addRNum"].GetBitmap(bmpsize)
00163         self.rnum_icon = il.Add(trgif)
00164         
00165         trgif = icons["addVect"].GetBitmap(bmpsize)
00166         self.vect_icon = il.Add(trgif)
00167         
00168         trgif = icons["addThematic"].GetBitmap(bmpsize)
00169         self.theme_icon = il.Add(trgif)
00170         
00171         trgif = icons["addChart"].GetBitmap(bmpsize)
00172         self.chart_icon = il.Add(trgif)
00173         
00174         trgif = icons["addGrid"].GetBitmap(bmpsize)
00175         self.grid_icon = il.Add(trgif)
00176         
00177         trgif = icons["addGeodesic"].GetBitmap(bmpsize)
00178         self.geodesic_icon = il.Add(trgif)
00179         
00180         trgif = icons["addRhumb"].GetBitmap(bmpsize)
00181         self.rhumb_icon = il.Add(trgif)
00182         
00183         trgif = icons["addLabels"].GetBitmap(bmpsize)
00184         self.labels_icon = il.Add(trgif)
00185         
00186         trgif = icons["addCmd"].GetBitmap(bmpsize)
00187         self.cmd_icon = il.Add(trgif)
00188         
00189         self.AssignImageList(il)
00190         
00191         self.Bind(wx.EVT_TREE_ITEM_EXPANDING,   self.OnExpandNode)
00192         self.Bind(wx.EVT_TREE_ITEM_COLLAPSED,   self.OnCollapseNode)
00193         self.Bind(wx.EVT_TREE_ITEM_ACTIVATED,   self.OnActivateLayer)
00194         self.Bind(wx.EVT_TREE_SEL_CHANGED,      self.OnChangeSel)
00195         self.Bind(CT.EVT_TREE_ITEM_CHECKED,     self.OnLayerChecked)
00196         self.Bind(wx.EVT_TREE_DELETE_ITEM,      self.OnDeleteLayer)
00197         self.Bind(wx.EVT_TREE_ITEM_RIGHT_CLICK, self.OnLayerContextMenu)
00198         self.Bind(wx.EVT_TREE_END_DRAG,         self.OnEndDrag)
00199         self.Bind(wx.EVT_TREE_END_LABEL_EDIT,   self.OnRenamed)
00200         self.Bind(wx.EVT_KEY_UP,                self.OnKeyUp)
00201         self.Bind(wx.EVT_IDLE,                  self.OnIdle)
00202 
00203     def _setGradient(self, iType = None):
00204         """!Set gradient for items
00205 
00206         @param iType bgmap, vdigit or None
00207         """
00208         if iType == 'bgmap':
00209             self.SetFirstGradientColour(wx.Colour(0, 100, 0))
00210             self.SetSecondGradientColour(wx.Colour(0, 150, 0))
00211         elif iType == 'vdigit':
00212             self.SetFirstGradientColour(wx.Colour(100, 0, 0))
00213             self.SetSecondGradientColour(wx.Colour(150, 0, 0))
00214         else:
00215             self.SetFirstGradientColour(wx.Colour(100, 100, 100))
00216             self.SetSecondGradientColour(wx.Colour(150, 150, 150))
00217         
00218     def GetMap(self):
00219         """!Get map instace"""
00220         return self.Map
00221     
00222     def GetMapDisplay(self):
00223         """!Get associated MapFrame"""
00224         return self.mapdisplay
00225     
00226     def OnIdle(self, event):
00227         """!Only re-order and re-render a composite map image from GRASS during
00228         idle time instead of multiple times during layer changing.
00229         """
00230         if self.rerender:
00231             if self.mapdisplay.toolbars['vdigit']:
00232                 vector = True
00233             else:
00234                 vector = False
00235             if self.mapdisplay.statusbarWin['render'].GetValue():
00236                 self.mapdisplay.MapWindow.UpdateMap(render = True, renderVector = vector)
00237             
00238             self.rerender = False
00239         
00240         event.Skip()
00241         
00242     def OnKeyUp(self, event):
00243         """!Key pressed"""
00244         key = event.GetKeyCode()
00245         
00246         if key == wx.WXK_DELETE and self.lmgr and \
00247                 not self.GetEditControl():
00248             self.lmgr.OnDeleteLayer(None)
00249         
00250         event.Skip()
00251         
00252     def OnLayerContextMenu (self, event):
00253         """!Contextual menu for item/layer"""
00254         if not self.layer_selected:
00255             event.Skip()
00256             return
00257 
00258         ltype = self.GetPyData(self.layer_selected)[0]['type']
00259         mapLayer = self.GetPyData(self.layer_selected)[0]['maplayer']
00260         
00261         Debug.msg (4, "LayerTree.OnContextMenu: layertype=%s" % \
00262                        ltype)
00263 
00264         if not hasattr (self, "popupID"):
00265             self.popupID = dict()
00266             for key in ('remove', 'rename', 'opacity', 'nviz', 'zoom',
00267                         'region', 'export', 'attr', 'edit0', 'edit1',
00268                         'bgmap', 'topo', 'meta', 'null', 'zoom1', 'region1',
00269                         'color', 'hist', 'univar', 'prof', 'properties'):
00270                 self.popupID[key] = wx.NewId()
00271         
00272         self.popupMenu = wx.Menu()
00273         
00274         numSelected = len(self.GetSelections())
00275         
00276         self.popupMenu.Append(self.popupID['remove'], text = _("Remove"))
00277         self.Bind(wx.EVT_MENU, self.lmgr.OnDeleteLayer, id = self.popupID['remove'])
00278         
00279         if ltype != "command":
00280             self.popupMenu.Append(self.popupID['rename'], text = _("Rename"))
00281             self.Bind(wx.EVT_MENU, self.OnRenameLayer, id = self.popupID['rename'])
00282             if numSelected > 1:
00283                 self.popupMenu.Enable(self.popupID['rename'], False)
00284         
00285         # map layer items
00286         if ltype not in ("group", "command"):
00287             self.popupMenu.AppendSeparator()
00288             self.popupMenu.Append(self.popupID['opacity'], text = _("Change opacity level"))
00289             self.Bind(wx.EVT_MENU, self.OnPopupOpacityLevel, id = self.popupID['opacity'])
00290             self.popupMenu.Append(self.popupID['properties'], text = _("Properties"))
00291             self.Bind(wx.EVT_MENU, self.OnPopupProperties, id = self.popupID['properties'])
00292             
00293             if numSelected > 1:
00294                 self.popupMenu.Enable(self.popupID['opacity'], False)
00295                 self.popupMenu.Enable(self.popupID['properties'], False)
00296             
00297             if ltype in ('raster', 'vector', '3d-raster') and self.mapdisplay.toolbars['nviz']:
00298                 self.popupMenu.Append(self.popupID['nviz'], _("3D view properties"))
00299                 self.Bind (wx.EVT_MENU, self.OnNvizProperties, id = self.popupID['nviz'])
00300             
00301             if ltype in ('raster', 'vector', 'rgb'):
00302                 self.popupMenu.Append(self.popupID['zoom'], text = _("Zoom to selected map(s)"))
00303                 self.Bind(wx.EVT_MENU, self.mapdisplay.OnZoomToMap, id = self.popupID['zoom'])
00304                 self.popupMenu.Append(self.popupID['region'], text = _("Set computational region from selected map(s)"))
00305                 self.Bind(wx.EVT_MENU, self.OnSetCompRegFromMap, id = self.popupID['region'])
00306         
00307         # specific items
00308         try:
00309             mltype = self.GetPyData(self.layer_selected)[0]['type']
00310         except:
00311             mltype = None
00312         
00313         # vector layers (specific items)
00314         if mltype and mltype == "vector":
00315             self.popupMenu.AppendSeparator()
00316             self.popupMenu.Append(self.popupID['export'], text = _("Export"))
00317             self.Bind(wx.EVT_MENU, lambda x: self.lmgr.OnMenuCmd(cmd = ['v.out.ogr',
00318                                                                         'input=%s' % mapLayer.GetName()]),
00319                       id = self.popupID['export'])
00320             
00321             self.popupMenu.AppendSeparator()
00322             self.popupMenu.Append(self.popupID['attr'], text = _("Show attribute data"))
00323             self.Bind(wx.EVT_MENU, self.lmgr.OnShowAttributeTable, id = self.popupID['attr'])
00324 
00325             self.popupMenu.Append(self.popupID['edit0'], text = _("Start editing"))
00326             self.popupMenu.Append(self.popupID['edit1'], text = _("Stop editing"))
00327             self.popupMenu.Enable(self.popupID['edit1'], False)
00328             self.Bind (wx.EVT_MENU, self.OnStartEditing, id = self.popupID['edit0'])
00329             self.Bind (wx.EVT_MENU, self.OnStopEditing,  id = self.popupID['edit1'])
00330             
00331             layer = self.GetPyData(self.layer_selected)[0]['maplayer']
00332             # enable editing only for vector map layers available in the current mapset
00333             digitToolbar = self.mapdisplay.toolbars['vdigit']
00334             if digitToolbar:
00335                 # background vector map
00336                 self.popupMenu.Append(self.popupID['bgmap'],
00337                                       text = _("Use as background vector map for digitizer"),
00338                                       kind = wx.ITEM_CHECK)
00339                 self.Bind(wx.EVT_MENU, self.OnSetBgMap, id = self.popupID['bgmap'])
00340                 if UserSettings.Get(group = 'vdigit', key = 'bgmap', subkey = 'value',
00341                                     internal = True) == layer.GetName():
00342                     self.popupMenu.Check(self.popupID['bgmap'], True)
00343             
00344             self.popupMenu.Append(self.popupID['topo'], text = _("Rebuild topology"))
00345             self.Bind(wx.EVT_MENU, self.OnTopology, id = self.popupID['topo'])
00346             
00347             if layer.GetMapset() != grass.gisenv()['MAPSET']:
00348                 # only vector map in current mapset can be edited
00349                 self.popupMenu.Enable (self.popupID['edit0'], False)
00350                 self.popupMenu.Enable (self.popupID['edit1'], False)
00351                 self.popupMenu.Enable (self.popupID['topo'], False)
00352             elif digitToolbar and digitToolbar.GetLayer():
00353                 # vector map already edited
00354                 vdigitLayer = digitToolbar.GetLayer()
00355                 if vdigitLayer is layer:
00356                     self.popupMenu.Enable(self.popupID['edit0'],  False)
00357                     self.popupMenu.Enable(self.popupID['edit1'],  True)
00358                     self.popupMenu.Enable(self.popupID['remove'], False)
00359                     self.popupMenu.Enable(self.popupID['bgmap'],  False)
00360                     self.popupMenu.Enable(self.popupID['topo'],   False)
00361                 else:
00362                     self.popupMenu.Enable(self.popupID['edit0'], False)
00363                     self.popupMenu.Enable(self.popupID['edit1'], False)
00364                     self.popupMenu.Enable(self.popupID['bgmap'], True)
00365             
00366             self.popupMenu.Append(self.popupID['meta'], _("Metadata"))
00367             self.Bind (wx.EVT_MENU, self.OnMetadata, id = self.popupID['meta'])
00368             if numSelected > 1:
00369                 self.popupMenu.Enable(self.popupID['attr'],   False)
00370                 self.popupMenu.Enable(self.popupID['edit0'],  False)
00371                 self.popupMenu.Enable(self.popupID['edit1'],  False)
00372                 self.popupMenu.Enable(self.popupID['meta'],   False)
00373                 self.popupMenu.Enable(self.popupID['bgmap'],  False)
00374                 self.popupMenu.Enable(self.popupID['topo'],   False)
00375                 self.popupMenu.Enable(self.popupID['export'], False)
00376         
00377         # raster layers (specific items)
00378         elif mltype and mltype == "raster":
00379             self.popupMenu.Append(self.popupID['zoom1'], text = _("Zoom to selected map(s) (ignore NULLs)"))
00380             self.Bind(wx.EVT_MENU, self.mapdisplay.OnZoomToRaster, id = self.popupID['zoom1'])
00381             self.popupMenu.Append(self.popupID['region1'], text = _("Set computational region from selected map(s) (ignore NULLs)"))
00382             self.Bind(wx.EVT_MENU, self.OnSetCompRegFromRaster, id = self.popupID['region1'])
00383             
00384             self.popupMenu.AppendSeparator()
00385             self.popupMenu.Append(self.popupID['export'], text = _("Export"))
00386             self.Bind(wx.EVT_MENU, lambda x: self.lmgr.OnMenuCmd(cmd = ['r.out.gdal',
00387                                                                         'input=%s' % mapLayer.GetName()]),
00388                       id = self.popupID['export'])
00389             
00390             self.popupMenu.AppendSeparator()
00391             self.popupMenu.Append(self.popupID['color'], _("Set color table"))
00392             self.Bind (wx.EVT_MENU, self.OnColorTable, id = self.popupID['color'])
00393             self.popupMenu.Append(self.popupID['hist'], _("Histogram"))
00394             self.Bind (wx.EVT_MENU, self.OnHistogram, id = self.popupID['hist'])
00395             self.popupMenu.Append(self.popupID['univar'], _("Univariate raster statistics"))
00396             self.Bind (wx.EVT_MENU, self.OnUnivariateStats, id = self.popupID['univar'])
00397             self.popupMenu.Append(self.popupID['prof'], _("Profile"))
00398             self.Bind (wx.EVT_MENU, self.OnProfile, id = self.popupID['prof'])
00399             self.popupMenu.Append(self.popupID['meta'], _("Metadata"))
00400             self.Bind (wx.EVT_MENU, self.OnMetadata, id = self.popupID['meta'])
00401             
00402             if numSelected > 1:
00403                 self.popupMenu.Enable(self.popupID['zoom1'],   False)
00404                 self.popupMenu.Enable(self.popupID['region1'], False)
00405                 self.popupMenu.Enable(self.popupID['color'],   False)
00406                 self.popupMenu.Enable(self.popupID['hist'],    False)
00407                 self.popupMenu.Enable(self.popupID['univar'],  False)
00408                 self.popupMenu.Enable(self.popupID['prof'],    False)
00409                 self.popupMenu.Enable(self.popupID['meta'],    False)
00410                 self.popupMenu.Enable(self.popupID['nviz'],    False)
00411                 self.popupMenu.Enable(self.popupID['export'],  False)
00412 
00413         self.PopupMenu(self.popupMenu)
00414         self.popupMenu.Destroy()
00415         
00416     def OnTopology(self, event):
00417         """!Rebuild topology of selected vector map"""
00418         mapLayer = self.GetPyData(self.layer_selected)[0]['maplayer']
00419         cmd = ['v.build',
00420                'map=%s' % mapLayer.GetName()]
00421         self.lmgr.goutput.RunCmd(cmd, switchPage = True)
00422         
00423     def OnMetadata(self, event):
00424         """!Print metadata of raster/vector map layer
00425         TODO: Dialog to modify metadata
00426         """
00427         mapLayer = self.GetPyData(self.layer_selected)[0]['maplayer']
00428         mltype = self.GetPyData(self.layer_selected)[0]['type']
00429 
00430         if mltype == 'raster':
00431             cmd = ['r.info']
00432         elif mltype == 'vector':
00433             cmd = ['v.info']
00434         cmd.append('map=%s' % mapLayer.GetName())
00435 
00436         # print output to command log area
00437         self.lmgr.goutput.RunCmd(cmd, switchPage = True)
00438 
00439     def OnSetCompRegFromRaster(self, event):
00440         """!Set computational region from selected raster map (ignore NULLs)"""
00441         mapLayer = self.GetPyData(self.layer_selected)[0]['maplayer']
00442         
00443         cmd = ['g.region',
00444                '-p',
00445                'zoom=%s' % mapLayer.GetName()]
00446         
00447         # print output to command log area
00448         self.lmgr.goutput.RunCmd(cmd)
00449          
00450     def OnSetCompRegFromMap(self, event):
00451         """!Set computational region from selected raster/vector map
00452         """
00453         rast = []
00454         vect = []
00455         rast3d = []
00456         for layer in self.GetSelections():
00457             mapLayer = self.GetPyData(layer)[0]['maplayer']
00458             mltype = self.GetPyData(layer)[0]['type']
00459                 
00460             if mltype == 'raster':
00461                 rast.append(mapLayer.GetName())
00462             elif mltype == 'vector':
00463                 vect.append(mapLayer.GetName())
00464             elif mltype == '3d-raster':
00465                 rast3d.append(mapLayer.GetName())
00466             elif mltype == 'rgb':
00467                 for rname in mapLayer.GetName().splitlines():
00468                     rast.append(rname)
00469         
00470         cmd = ['g.region']
00471         if rast:
00472             cmd.append('rast=%s' % ','.join(rast))
00473         if vect:
00474             cmd.append('vect=%s' % ','.join(vect))
00475         if rast3d:
00476             cmd.append('rast3d=%s' % ','.join(rast3d))
00477         
00478         # print output to command log area
00479         if len(cmd) > 1:
00480             cmd.append('-p')
00481             self.lmgr.goutput.RunCmd(cmd)
00482         
00483     def OnProfile(self, event):
00484         """!Plot profile of given raster map layer"""
00485         mapLayer = self.GetPyData(self.layer_selected)[0]['maplayer']
00486         if not mapLayer.GetName():
00487             wx.MessageBox(parent = self,
00488                           message = _("Unable to create profile of "
00489                                     "raster map."),
00490                           caption = _("Error"), style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
00491             return False
00492 
00493         if not hasattr (self, "profileFrame"):
00494             self.profileFrame = None
00495 
00496         if hasattr (self.mapdisplay, "profile") and self.mapdisplay.profile:
00497             self.profileFrame = self.mapdisplay.profile
00498 
00499         if not self.profileFrame:
00500             self.profileFrame = profile.ProfileFrame(self.mapdisplay,
00501                                                      id = wx.ID_ANY, pos = wx.DefaultPosition, size = (700,300),
00502                                                      style = wx.DEFAULT_FRAME_STYLE, rasterList = [mapLayer.GetName()])
00503             # show new display
00504             self.profileFrame.Show()
00505         
00506     def OnColorTable(self, event):
00507         """!Set color table for raster map"""
00508         name = self.GetPyData(self.layer_selected)[0]['maplayer'].GetName()
00509         menuform.GUI(parent = self).ParseCommand(['r.colors',
00510                                                   'map=%s' % name])
00511         
00512     def OnHistogram(self, event):
00513         """
00514         Plot histogram for given raster map layer
00515         """
00516         mapLayer = self.GetPyData(self.layer_selected)[0]['maplayer']
00517         if not mapLayer.GetName():
00518             wx.MessageBox(parent = self,
00519                           message = _("Unable to display histogram of "
00520                                     "raster map."),
00521                           caption = _("Error"), style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
00522             return False
00523 
00524         if not hasattr (self, "histogramFrame"):
00525             self.histogramFrame = None
00526 
00527         if hasattr (self.mapdisplay, "histogram") and self.mapdisplay.histogram:
00528             self.histogramFrame = self.mapdisplay.histogram
00529 
00530         if not self.histogramFrame:
00531             self.histogramFrame = histogram.HistFrame(self,
00532                                                       id = wx.ID_ANY,
00533                                                       pos = wx.DefaultPosition, size = globalvar.HIST_WINDOW_SIZE,
00534                                                       style = wx.DEFAULT_FRAME_STYLE)
00535             # show new display
00536             self.histogramFrame.Show()
00537 
00538         self.histogramFrame.SetHistLayer(mapLayer.GetName())
00539         self.histogramFrame.HistWindow.UpdateHist()
00540         self.histogramFrame.Refresh()
00541         self.histogramFrame.Update()
00542 
00543         return True
00544 
00545     def OnUnivariateStats(self, event):
00546         """!Univariate raster statistics"""
00547         name = self.GetPyData(self.layer_selected)[0]['maplayer'].GetName()
00548         menuform.GUI(parent = self).ParseCommand(['r.univar',
00549                                                   'map=%s' % name])
00550 
00551     def OnStartEditing(self, event):
00552         """!Start editing vector map layer requested by the user
00553         """
00554         try:
00555             maplayer = self.GetPyData(self.layer_selected)[0]['maplayer']
00556         except:
00557             event.Skip()
00558             return
00559         
00560         if not self.mapdisplay.toolbars['vdigit']: # enable tool
00561             self.mapdisplay.AddToolbar('vdigit')
00562         
00563         if not self.mapdisplay.toolbars['vdigit']:
00564             return
00565         
00566         self.mapdisplay.toolbars['vdigit'].StartEditing(maplayer)
00567         
00568         self._setGradient('vdigit')
00569         self.RefreshLine(self.layer_selected)
00570         
00571     def OnStopEditing(self, event):
00572         """!Stop editing the current vector map layer
00573         """
00574         maplayer = self.GetPyData(self.layer_selected)[0]['maplayer']
00575         
00576         self.mapdisplay.toolbars['vdigit'].OnExit()
00577         if self.lmgr:
00578             self.lmgr.toolbars['tools'].Enable('vdigit', enable = True)
00579         
00580         self._setGradient()
00581         self.RefreshLine(self.layer_selected)
00582         
00583     def OnSetBgMap(self, event):
00584         """!Set background vector map for editing sesstion"""
00585         digit = self.mapdisplay.GetWindow().digit
00586         if event.IsChecked():
00587             mapName = self.GetPyData(self.layer_selected)[0]['maplayer'].GetName()
00588             UserSettings.Set(group = 'vdigit', key = 'bgmap', subkey = 'value',
00589                              value = str(mapName), internal = True)
00590             digit.OpenBackgroundMap(mapName)
00591             self._setGradient('bgmap')
00592         else:
00593             UserSettings.Set(group = 'vdigit', key = 'bgmap', subkey = 'value',
00594                              value = '', internal = True)
00595             digit.CloseBackgroundMap()
00596             self._setGradient()
00597         
00598         self.RefreshLine(self.layer_selected)
00599 
00600     def OnPopupProperties (self, event):
00601         """!Popup properties dialog"""
00602         self.PropertiesDialog(self.layer_selected)
00603 
00604     def OnPopupOpacityLevel(self, event):
00605         """!Popup opacity level indicator"""
00606         if not self.GetPyData(self.layer_selected)[0]['ctrl']:
00607             return
00608         
00609         maplayer = self.GetPyData(self.layer_selected)[0]['maplayer']
00610         current_opacity = maplayer.GetOpacity()
00611         
00612         dlg = gdialogs.SetOpacityDialog(self, opacity = current_opacity,
00613                                         title = _("Set opacity <%s>") % maplayer.GetName())
00614         dlg.CentreOnParent()
00615 
00616         if dlg.ShowModal() == wx.ID_OK:
00617             new_opacity = dlg.GetOpacity() # string
00618             self.Map.ChangeOpacity(maplayer, new_opacity)
00619             maplayer.SetOpacity(new_opacity)
00620             self.SetItemText(self.layer_selected,
00621                              self._getLayerName(self.layer_selected))
00622             
00623             # vector layer currently edited
00624             if self.mapdisplay.toolbars['vdigit'] and \
00625                     self.mapdisplay.toolbars['vdigit'].GetLayer() == maplayer:   
00626                 alpha = int(new_opacity * 255)
00627                 self.mapdisplay.GetWindow().digit.GetDisplay().UpdateSettings(alpha = alpha)
00628                 
00629             # redraw map if auto-rendering is enabled
00630             self.rerender = True
00631             self.reorder = True
00632 
00633     def OnNvizProperties(self, event):
00634         """!Nviz-related properties (raster/vector/volume)
00635 
00636         @todo vector/volume
00637         """
00638         self.lmgr.notebook.SetSelectionByName('nviz')
00639         ltype = self.GetPyData(self.layer_selected)[0]['type']
00640         if ltype == 'raster':
00641             self.lmgr.nviz.SetPage('surface')
00642         elif ltype == 'vector':
00643             self.lmgr.nviz.SetPage('vector')
00644         elif ltype == '3d-raster':
00645             self.lmgr.nviz.SetPage('volume')
00646         
00647     def OnRenameLayer (self, event):
00648         """!Rename layer"""
00649         self.EditLabel(self.layer_selected)
00650         self.GetEditControl().SetSelection(-1, -1)
00651         
00652     def OnRenamed(self, event):
00653         """!Layer renamed"""
00654         item = self.layer_selected
00655         self.GetPyData(item)[0]['label'] = event.GetLabel()
00656         self.SetItemText(item, self._getLayerName(item)) # not working, why?
00657         
00658         event.Skip()
00659 
00660     def AddLayer(self, ltype, lname = None, lchecked = None,
00661                  lopacity = 1.0, lcmd = None, lgroup = None, lvdigit = None, lnviz = None, multiple = True):
00662         """!Add new item to the layer tree, create corresponding MapLayer instance.
00663         Launch property dialog if needed (raster, vector, etc.)
00664 
00665         @param ltype layer type (raster, vector, 3d-raster, ...)
00666         @param lname layer name
00667         @param lchecked if True layer is checked
00668         @param lopacity layer opacity level
00669         @param lcmd command (given as a list)
00670         @param lgroup index of group item (-1 for root) or None
00671         @param lvdigit vector digitizer settings (eg. geometry attributes)
00672         @param lnviz layer Nviz properties
00673         @param multiple True to allow multiple map layers in layer tree
00674         """
00675         if lname and not multiple:
00676             # check for duplicates
00677             item = self.GetFirstVisibleItem()
00678             while item and item.IsOk():
00679                 if self.GetPyData(item)[0]['type'] == 'vector':
00680                     name = self.GetPyData(item)[0]['maplayer'].GetName()
00681                     if name == lname:
00682                         return
00683                 item = self.GetNextVisible(item)
00684         
00685         self.first = True
00686         params = {} # no initial options parameters
00687         
00688         # deselect active item
00689         if self.layer_selected:
00690             self.SelectItem(self.layer_selected, select = False)
00691         
00692         Debug.msg (3, "LayerTree().AddLayer(): ltype=%s" % (ltype))
00693         
00694         if ltype == 'command':
00695             # generic command item
00696             ctrl = wx.TextCtrl(self, id = wx.ID_ANY, value = '',
00697                                pos = wx.DefaultPosition, size = (self.GetSize()[0]-100,25),
00698                                # style = wx.TE_MULTILINE|wx.TE_WORDWRAP)
00699                                style = wx.TE_PROCESS_ENTER | wx.TE_DONTWRAP)
00700             ctrl.Bind(wx.EVT_TEXT_ENTER, self.OnCmdChanged)
00701             # ctrl.Bind(wx.EVT_TEXT,       self.OnCmdChanged)
00702         elif ltype == 'group':
00703             # group item
00704             ctrl = None
00705             grouptext = _('Layer group:') + str(self.groupnode)
00706             self.groupnode += 1
00707         else:
00708             btnbmp = Icons['layerManager']["layerOptions"].GetBitmap((16,16))
00709             ctrl = buttons.GenBitmapButton(self, id = wx.ID_ANY, bitmap = btnbmp, size = (24,24))
00710             ctrl.SetToolTipString(_("Click to edit layer settings"))
00711             self.Bind(wx.EVT_BUTTON, self.OnLayerContextMenu, ctrl)
00712         # add layer to the layer tree
00713         if self.layer_selected and self.layer_selected != self.GetRootItem():
00714             if self.GetPyData(self.layer_selected)[0]['type'] == 'group' \
00715                 and self.IsExpanded(self.layer_selected):
00716                 # add to group (first child of self.layer_selected) if group expanded
00717                 layer = self.PrependItem(parent = self.layer_selected,
00718                                          text = '', ct_type = 1, wnd = ctrl)
00719             else:
00720                 # prepend to individual layer or non-expanded group
00721                 if lgroup == -1:
00722                     # -> last child of root (loading from workspace)
00723                     layer = self.AppendItem(parentId = self.root,
00724                                             text = '', ct_type = 1, wnd = ctrl)
00725                 elif lgroup > -1:
00726                     # -> last child of group (loading from workspace)
00727                     parent = self.FindItemByIndex(index = lgroup)
00728                     if not parent:
00729                         parent = self.root
00730                     layer = self.AppendItem(parentId = parent,
00731                                             text = '', ct_type = 1, wnd = ctrl)
00732                 elif lgroup is None:
00733                     # -> previous sibling of selected layer
00734                     parent = self.GetItemParent(self.layer_selected)
00735                     layer = self.InsertItem(parentId = parent,
00736                                             input = self.GetPrevSibling(self.layer_selected),
00737                                             text = '', ct_type = 1, wnd = ctrl)
00738         else: # add first layer to the layer tree (first child of root)
00739             layer = self.PrependItem(parent = self.root, text = '', ct_type = 1, wnd = ctrl)
00740         
00741         # layer is initially unchecked as inactive (beside 'command')
00742         # use predefined value if given
00743         if lchecked is not None:
00744             checked = lchecked
00745         else:
00746             checked = True
00747         
00748         self.CheckItem(layer, checked = checked)
00749         
00750         # add text and icons for each layer ltype
00751         label =  _('(double click to set properties)') + ' ' * 15
00752         if ltype == 'raster':
00753             self.SetItemImage(layer, self.rast_icon)
00754             self.SetItemText(layer, '%s %s' % (_('raster'), label))
00755         elif ltype == '3d-raster':
00756             self.SetItemImage(layer, self.rast3d_icon)
00757             self.SetItemText(layer, '%s %s' % (_('3d raster'), label))
00758         elif ltype == 'rgb':
00759             self.SetItemImage(layer, self.rgb_icon)
00760             self.SetItemText(layer, '%s %s' % (_('RGB'), label))
00761         elif ltype == 'his':
00762             self.SetItemImage(layer, self.his_icon)
00763             self.SetItemText(layer, '%s %s' % (_('HIS'), label))
00764         elif ltype == 'shaded':
00765             self.SetItemImage(layer, self.shaded_icon)
00766             self.SetItemText(layer, '%s %s' % (_('Shaded relief'), label))
00767         elif ltype == 'rastnum':
00768             self.SetItemImage(layer, self.rnum_icon)
00769             self.SetItemText(layer, '%s %s' % (_('raster cell numbers'), label))
00770         elif ltype == 'rastarrow':
00771             self.SetItemImage(layer, self.rarrow_icon)
00772             self.SetItemText(layer, '%s %s' % (_('raster flow arrows'), label))
00773         elif ltype == 'vector':
00774             self.SetItemImage(layer, self.vect_icon)
00775             self.SetItemText(layer, '%s %s' % (_('vector'), label))
00776         elif ltype == 'thememap':
00777             self.SetItemImage(layer, self.theme_icon)
00778             self.SetItemText(layer, '%s %s' % (_('thematic map'), label))
00779         elif ltype == 'themechart':
00780             self.SetItemImage(layer, self.chart_icon)
00781             self.SetItemText(layer, '%s %s' % (_('thematic charts'), label))
00782         elif ltype == 'grid':
00783             self.SetItemImage(layer, self.grid_icon)
00784             self.SetItemText(layer, '%s %s' % (_('grid'), label))
00785         elif ltype == 'geodesic':
00786             self.SetItemImage(layer, self.geodesic_icon)
00787             self.SetItemText(layer, '%s %s' % (_('geodesic line'), label))
00788         elif ltype == 'rhumb':
00789             self.SetItemImage(layer, self.rhumb_icon)
00790             self.SetItemText(layer, '%s %s' % (_('rhumbline'), label))
00791         elif ltype == 'labels':
00792             self.SetItemImage(layer, self.labels_icon)
00793             self.SetItemText(layer, '%s %s' % (_('vector labels'), label))
00794         elif ltype == 'command':
00795             self.SetItemImage(layer, self.cmd_icon)
00796         elif ltype == 'group':
00797             self.SetItemImage(layer, self.folder)
00798             self.SetItemText(layer, grouptext)
00799         
00800         self.first = False
00801         
00802         if ltype != 'group':
00803             if lcmd and len(lcmd) > 1:
00804                 cmd = lcmd
00805                 render = False
00806                 name, found = utils.GetLayerNameFromCmd(lcmd)
00807             else:
00808                 cmd = []
00809                 if ltype == 'command' and lname:
00810                     for c in lname.split(';'):
00811                         cmd.append(c.split(' '))
00812                 
00813                 render = False
00814                 name = None
00815             
00816             if ctrl:
00817                 ctrlId = ctrl.GetId()
00818             else:
00819                 ctrlId = None
00820                 
00821             # add a data object to hold the layer's command (does not apply to generic command layers)
00822             self.SetPyData(layer, ({'cmd'      : cmd,
00823                                     'type'     : ltype,
00824                                     'ctrl'     : ctrlId,
00825                                     'label'    : None,
00826                                     'maplayer' : None,
00827                                     'vdigit'   : lvdigit,
00828                                     'nviz'     : lnviz,
00829                                     'propwin'  : None}, 
00830                                    None))
00831             
00832             # find previous map layer instance 
00833             prevItem = self.GetFirstChild(self.root)[0]
00834             prevMapLayer = None 
00835             pos = -1
00836             while prevItem and prevItem.IsOk() and prevItem != layer: 
00837                 if self.GetPyData(prevItem)[0]['maplayer']: 
00838                     prevMapLayer = self.GetPyData(prevItem)[0]['maplayer'] 
00839                 
00840                 prevItem = self.GetNextSibling(prevItem) 
00841                 
00842                 if prevMapLayer: 
00843                     pos = self.Map.GetLayerIndex(prevMapLayer)
00844                 else: 
00845                     pos = -1
00846             
00847             maplayer = self.Map.AddLayer(pos = pos,
00848                                          type = ltype, command = self.GetPyData(layer)[0]['cmd'], name = name,
00849                                          l_active = checked, l_hidden = False,
00850                                          l_opacity = lopacity, l_render = render)
00851             self.GetPyData(layer)[0]['maplayer'] = maplayer
00852             
00853             # run properties dialog if no properties given
00854             if len(cmd) == 0:
00855                 self.PropertiesDialog(layer, show = True)
00856         
00857         else: # group
00858             self.SetPyData(layer, ({'cmd'      : None,
00859                                     'type'     : ltype,
00860                                     'ctrl'     : None,
00861                                     'label'    : None,
00862                                     'maplayer' : None,
00863                                     'propwin'  : None}, 
00864                                    None))
00865         
00866         # select new item
00867         self.SelectItem(layer, select = True)
00868         self.layer_selected = layer
00869         
00870         # use predefined layer name if given
00871         if lname:
00872             if ltype == 'group':
00873                 self.SetItemText(layer, lname)
00874             elif ltype == 'command':
00875                 ctrl.SetValue(lname)
00876             else:
00877                 self.SetItemText(layer, self._getLayerName(layer, lname))
00878         
00879         # updated progress bar range (mapwindow statusbar)
00880         if checked is True:
00881             self.mapdisplay.statusbarWin['progress'].SetRange(len(self.Map.GetListOfLayers(l_active = True)))
00882             
00883         return layer
00884 
00885     def PropertiesDialog (self, layer, show = True):
00886         """!Launch the properties dialog"""
00887         if 'propwin' in self.GetPyData(layer)[0] and \
00888                 self.GetPyData(layer)[0]['propwin'] is not None:
00889             # recycle GUI dialogs
00890             win = self.GetPyData(layer)[0]['propwin']
00891             # update properties (columns, layers)
00892             win.notebookpanel.OnUpdateSelection(None)
00893             if win.IsShown():
00894                 win.SetFocus()
00895             else:
00896                 win.Show()
00897             
00898             return
00899         
00900         completed = ''
00901         params = self.GetPyData(layer)[1]
00902         ltype  = self.GetPyData(layer)[0]['type']
00903                 
00904         Debug.msg (3, "LayerTree.PropertiesDialog(): ltype=%s" % \
00905                    ltype)
00906 
00907         if self.GetPyData(layer)[0]['cmd']:
00908             module = menuform.GUI(parent = self, show = show, centreOnParent = False)
00909             module.ParseCommand(self.GetPyData(layer)[0]['cmd'],
00910                                 completed = (self.GetOptData,layer,params))
00911             
00912             self.GetPyData(layer)[0]['cmd'] = module.GetCmd()
00913         elif ltype == 'raster':
00914             cmd = ['d.rast']
00915             
00916             if UserSettings.Get(group='cmd', key='rasterOverlay', subkey='enabled'):
00917                 cmd.append('-o')
00918             
00919             menuform.GUI(parent = self, centreOnParent = False).ParseCommand(cmd,
00920                                                                              completed = (self.GetOptData,layer,params))
00921                          
00922         elif ltype == '3d-raster':
00923             cmd = ['d.rast3d']
00924             menuform.GUI(parent = self, centreOnParent = False).ParseCommand(cmd,
00925                                                                              completed = (self.GetOptData,layer,params))
00926                                         
00927         elif ltype == 'rgb':
00928             menuform.GUI(parent = self, centreOnParent = False).ParseCommand(['d.rgb'],
00929                                                                              completed = (self.GetOptData,layer,params))
00930             
00931         elif ltype == 'his':
00932             menuform.GUI(parent = self, centreOnParent = False).ParseCommand(['d.his'],
00933                                                                              completed = (self.GetOptData,layer,params))
00934             
00935         elif ltype == 'shaded':
00936             menuform.GUI(parent = self, centreOnParent = False).ParseCommand(['d.shadedmap'],
00937                                                                              completed = (self.GetOptData,layer,params))
00938             
00939         elif ltype == 'rastarrow':
00940             menuform.GUI(parent = self, centreOnParent = False).ParseCommand(['d.rast.arrow'],
00941                                                                              completed = (self.GetOptData,layer,params))
00942             
00943         elif ltype == 'rastnum':
00944             menuform.GUI(parent = self, centreOnParent = False).ParseCommand(['d.rast.num'],
00945                                                                              completed = (self.GetOptData,layer,params))
00946             
00947         elif ltype == 'vector':
00948             types = list()
00949             for ftype in ['point', 'line', 'boundary', 'centroid', 'area', 'face']:
00950                 if UserSettings.Get(group = 'cmd', key = 'showType', subkey = [ftype, 'enabled']):
00951                     types.append(ftype)
00952             
00953             menuform.GUI(parent = self, centreOnParent = False).ParseCommand(['d.vect', 'type=%s' % ','.join(types)],
00954                                                                              completed = (self.GetOptData,layer,params))
00955             
00956         elif ltype == 'thememap':
00957             # -s flag requested, otherwise only first thematic category is displayed
00958             # should be fixed by C-based d.thematic.* modules
00959             menuform.GUI(parent = self, centreOnParent = False).ParseCommand(['d.vect.thematic', '-s'], 
00960                                                                              completed = (self.GetOptData,layer,params))
00961             
00962         elif ltype == 'themechart':
00963             menuform.GUI(parent = self, centreOnParent = False).ParseCommand(['d.vect.chart'],
00964                                                                              completed = (self.GetOptData,layer,params))
00965             
00966         elif ltype == 'grid':
00967             menuform.GUI(parent = self, centreOnParent = False).ParseCommand(['d.grid'],
00968                                                                              completed = (self.GetOptData,layer,params))
00969             
00970         elif ltype == 'geodesic':
00971             menuform.GUI(parent = self, centreOnParent = False).ParseCommand(['d.geodesic'],
00972                                                                              completed = (self.GetOptData,layer,params))
00973             
00974         elif ltype == 'rhumb':
00975             menuform.GUI(parent = self, centreOnParent = False).ParseCommand(['d.rhumbline'],
00976                                                                              completed = (self.GetOptData,layer,params))
00977             
00978         elif ltype == 'labels':
00979             menuform.GUI(parent = self, centreOnParent = False).ParseCommand(['d.labels'],
00980                                                                              completed = (self.GetOptData,layer,params))
00981             
00982         elif ltype == 'cmdlayer':
00983             pass
00984         elif ltype == 'group':
00985             pass
00986         
00987     def OnActivateLayer(self, event):
00988         """!Double click on the layer item.
00989         Launch property dialog, or expand/collapse group of items, etc.
00990         """
00991         self.lmgr.WorkspaceChanged()
00992         layer = event.GetItem()
00993         self.layer_selected = layer
00994         
00995         self.PropertiesDialog (layer)
00996         
00997         if self.GetPyData(layer)[0]['type'] == 'group':
00998             if self.IsExpanded(layer):
00999                 self.Collapse(layer)
01000             else:
01001                 self.Expand(layer)
01002         
01003     def OnDeleteLayer(self, event):
01004         """!Remove selected layer item from the layer tree"""
01005         self.lmgr.WorkspaceChanged()
01006         item = event.GetItem()
01007         
01008         try:
01009             item.properties.Close(True)
01010         except:
01011             pass
01012 
01013         if item != self.root:
01014             Debug.msg (3, "LayerTree.OnDeleteLayer(): name=%s" % \
01015                            (self.GetItemText(item)))
01016         else:
01017             self.root = None
01018 
01019         # unselect item
01020         self.Unselect()
01021         self.layer_selected = None
01022 
01023         try:
01024             if self.GetPyData(item)[0]['type'] != 'group':
01025                 self.Map.DeleteLayer( self.GetPyData(item)[0]['maplayer'])
01026         except:
01027             pass
01028 
01029         # redraw map if auto-rendering is enabled
01030         self.rerender = True
01031         self.reorder = True
01032         
01033         if self.mapdisplay.toolbars['vdigit']:
01034             self.mapdisplay.toolbars['vdigit'].UpdateListOfLayers (updateTool = True)
01035 
01036         # update progress bar range (mapwindow statusbar)
01037         self.mapdisplay.statusbarWin['progress'].SetRange(len(self.Map.GetListOfLayers(l_active = True)))
01038 
01039         event.Skip()
01040 
01041     def OnLayerChecked(self, event):
01042         """!Enable/disable data layer"""
01043         self.lmgr.WorkspaceChanged()
01044         
01045         item    = event.GetItem()
01046         checked = item.IsChecked()
01047 
01048         digitToolbar = self.mapdisplay.toolbars['vdigit']
01049         if self.first == False:
01050             # change active parameter for item in layers list in render.Map
01051             if self.GetPyData(item)[0]['type'] == 'group':
01052                 child, cookie = self.GetFirstChild(item)
01053                 while child:
01054                     self.CheckItem(child, checked)
01055                     mapLayer = self.GetPyData(child)[0]['maplayer']
01056                     if not digitToolbar or \
01057                            (digitToolbar and digitToolbar.GetLayer() != mapLayer):
01058                         # ignore when map layer is edited
01059                         self.Map.ChangeLayerActive(mapLayer, checked)
01060                     child = self.GetNextSibling(child)
01061             else:
01062                 mapLayer = self.GetPyData(item)[0]['maplayer']
01063                 if not digitToolbar or \
01064                        (digitToolbar and digitToolbar.GetLayer() != mapLayer):
01065                     # ignore when map layer is edited
01066                     self.Map.ChangeLayerActive(mapLayer, checked)
01067 
01068         #
01069         # update progress bar range (mapwindow statusbar)
01070         #
01071         self.mapdisplay.statusbarWin['progress'].SetRange(len(self.Map.GetListOfLayers(l_active = True)))
01072 
01073         #
01074         # nviz
01075         #
01076         if self.mapdisplay.toolbars['nviz'] and \
01077                 self.GetPyData(item) is not None:
01078             # nviz - load/unload data layer
01079             mapLayer = self.GetPyData(item)[0]['maplayer']
01080 
01081             self.mapdisplay.SetStatusText(_("Please wait, updating data..."), 0)
01082 
01083             if checked: # enable
01084                 if mapLayer.type == 'raster':
01085                     self.mapdisplay.MapWindow.LoadRaster(item)
01086                 elif mapLayer.type == '3d-raster':
01087                     self.mapdisplay.MapWindow.LoadRaster3d(item)
01088                 elif mapLayer.type == 'vector':
01089                     npoints, nlines, nfeatures, mapIs3D = self.lmgr.nviz.VectorInfo(mapLayer)
01090                     if npoints > 0:
01091                         self.mapdisplay.MapWindow.LoadVector(item, points = True)
01092                     if nlines > 0:
01093                         self.mapdisplay.MapWindow.LoadVector(item, points = False)
01094 
01095             else: # disable
01096                 if mapLayer.type == 'raster':
01097                     self.mapdisplay.MapWindow.UnloadRaster(item)
01098                 elif mapLayer.type == '3d-raster':
01099                     self.mapdisplay.MapWindow.UnloadRaster3d(item)
01100                 elif mapLayer.type == 'vector':
01101                     self.mapdisplay.MapWindow.UnloadVector(item)
01102             
01103             self.mapdisplay.SetStatusText("", 0)
01104 
01105         # redraw map if auto-rendering is enabled
01106         self.rerender = True
01107         self.reorder = True
01108         
01109     def OnCmdChanged(self, event):
01110         """!Change command string"""
01111         ctrl = event.GetEventObject().GetId()
01112         cmd = event.GetString()
01113         
01114         layer = self.GetFirstVisibleItem()
01115 
01116         while layer and layer.IsOk():
01117             if self.GetPyData(layer)[0]['ctrl'] == ctrl:
01118                 break
01119             
01120             layer = self.GetNextVisible(layer)
01121 
01122         # change parameters for item in layers list in render.Map
01123         self.ChangeLayer(layer)
01124         
01125         event.Skip()
01126 
01127     def OnChangeSel(self, event):
01128         """!Selection changed"""
01129         oldlayer = event.GetOldItem()
01130         layer = event.GetItem()
01131         if layer == oldlayer:
01132             event.Veto()
01133             return
01134         
01135         digitToolbar = self.mapdisplay.toolbars['vdigit']
01136         if digitToolbar:
01137             mapLayer = self.GetPyData(layer)[0]['maplayer']
01138             bgmap = UserSettings.Get(group = 'vdigit', key = 'bgmap', subkey = 'value',
01139                                      internal = True)
01140             
01141             if digitToolbar.GetLayer() == mapLayer:
01142                 self._setGradient('vdigit')
01143             elif bgmap == mapLayer.GetName():
01144                 self._setGradient('bgmap')
01145             else:
01146                 self._setGradient()
01147         else:
01148             self._setGradient()
01149         
01150         self.layer_selected = layer
01151         
01152         try:
01153             if self.IsSelected(oldlayer):
01154                 self.SetItemWindowEnabled(oldlayer, True)
01155             else:
01156                 self.SetItemWindowEnabled(oldlayer, False)
01157 
01158             if self.IsSelected(layer):
01159                 self.SetItemWindowEnabled(layer, True)
01160             else:
01161                 self.SetItemWindowEnabled(layer, False)
01162         except:
01163             pass
01164         
01165         try:
01166             self.RefreshLine(oldlayer)
01167             self.RefreshLine(layer)
01168         except:
01169             pass
01170         
01171         # update statusbar -> show command string
01172         if self.GetPyData(layer) and self.GetPyData(layer)[0]['maplayer']:
01173             cmd = self.GetPyData(layer)[0]['maplayer'].GetCmd(string = True)
01174             if len(cmd) > 0:
01175                 self.lmgr.SetStatusText(cmd)
01176         
01177         # set region if auto-zooming is enabled
01178         if self.GetPyData(layer) and self.GetPyData(layer)[0]['cmd'] and \
01179                UserSettings.Get(group = 'display', key = 'autoZooming', subkey = 'enabled'):
01180             mapLayer = self.GetPyData(layer)[0]['maplayer']
01181             if mapLayer.GetType() in ('raster', 'vector'):
01182                 render = self.mapdisplay.statusbarWin['render'].IsChecked()
01183                 self.mapdisplay.MapWindow.ZoomToMap(layers = [mapLayer,],
01184                                                     render = render)
01185         
01186         # update nviz tools
01187         if self.mapdisplay.toolbars['nviz'] and \
01188                 self.GetPyData(self.layer_selected) is not None:
01189             if self.layer_selected.IsChecked():
01190                 # update Nviz tool window
01191                 type = self.GetPyData(self.layer_selected)[0]['maplayer'].type
01192                 
01193                 if type == 'raster':
01194                     self.lmgr.nviz.UpdatePage('surface')
01195                     self.lmgr.nviz.SetPage('surface')
01196                 elif type == 'vector':
01197                     self.lmgr.nviz.UpdatePage('vector')
01198                     self.lmgr.nviz.SetPage('vector')
01199                 elif type == '3d-raster':
01200                     self.lmgr.nviz.UpdatePage('volume')
01201                     self.lmgr.nviz.SetPage('volume')
01202         
01203     def OnCollapseNode(self, event):
01204         """!Collapse node
01205         """
01206         if self.GetPyData(self.layer_selected)[0]['type'] == 'group':
01207             self.SetItemImage(self.layer_selected, self.folder)
01208 
01209     def OnExpandNode(self, event):
01210         """!Expand node
01211         """
01212         self.layer_selected = event.GetItem()
01213         if self.GetPyData(self.layer_selected)[0]['type'] == 'group':
01214             self.SetItemImage(self.layer_selected, self.folder_open)
01215     
01216     def OnEndDrag(self, event):
01217         self.StopDragging()
01218         dropTarget = event.GetItem()
01219         self.flag = self.HitTest(event.GetPoint())[1]
01220         if self.IsValidDropTarget(dropTarget):
01221             self.UnselectAll()
01222             if dropTarget != None:
01223                 self.SelectItem(dropTarget)
01224             self.OnDrop(dropTarget, self._dragItem)
01225         elif dropTarget == None:
01226             self.OnDrop(dropTarget, self._dragItem)
01227 
01228     def OnDrop(self, dropTarget, dragItem):
01229         # save everthing associated with item to drag
01230         try:
01231             old = dragItem  # make sure this member exists
01232         except:
01233             return
01234 
01235         Debug.msg (4, "LayerTree.OnDrop(): layer=%s" % \
01236                    (self.GetItemText(dragItem)))
01237         
01238         # recreate data layer, insert copy of layer in new position, and delete original at old position
01239         newItem  = self.RecreateItem (dragItem, dropTarget)
01240 
01241         # if recreated layer is a group, also recreate its children
01242         if  self.GetPyData(newItem)[0]['type'] == 'group':
01243             (child, cookie) = self.GetFirstChild(dragItem)
01244             if child:
01245                 while child:
01246                     self.RecreateItem(child, dropTarget, parent = newItem)
01247                     self.Delete(child)
01248                     child = self.GetNextChild(old, cookie)[0]
01249         
01250         # delete layer at original position
01251         try:
01252             self.Delete(old) # entry in render.Map layers list automatically deleted by OnDeleteLayer handler
01253         except AttributeError:
01254             pass
01255 
01256         # redraw map if auto-rendering is enabled
01257         self.rerender = True
01258         self.reorder = True
01259         
01260         # select new item
01261         self.SelectItem(newItem)
01262         
01263     def RecreateItem (self, dragItem, dropTarget, parent = None):
01264         """!Recreate item (needed for OnEndDrag())
01265         """
01266         Debug.msg (4, "LayerTree.RecreateItem(): layer=%s" % \
01267                    self.GetItemText(dragItem))
01268 
01269         # fetch data (dragItem)
01270         checked = self.IsItemChecked(dragItem)
01271         image   = self.GetItemImage(dragItem, 0)
01272         text    = self.GetItemText(dragItem)
01273         if self.GetPyData(dragItem)[0]['ctrl']:
01274             # recreate data layer
01275             btnbmp = Icons['layerManager']["layerOptions"].GetBitmap((16,16))
01276             newctrl = buttons.GenBitmapButton(self, id = wx.ID_ANY, bitmap = btnbmp, size = (24, 24))
01277             newctrl.SetToolTipString(_("Click to edit layer settings"))
01278             self.Bind(wx.EVT_BUTTON, self.OnLayerContextMenu, newctrl)
01279             data    = self.GetPyData(dragItem)
01280         
01281         elif self.GetPyData(dragItem)[0]['type'] == 'command':
01282             # recreate command layer
01283             oldctrl = None
01284             newctrl = wx.TextCtrl(self, id = wx.ID_ANY, value = '',
01285                                   pos = wx.DefaultPosition, size = (250,25),
01286                                   style = wx.TE_MULTILINE|wx.TE_WORDWRAP)
01287             try:
01288                 newctrl.SetValue(self.GetPyData(dragItem)[0]['maplayer'].GetCmd(string = True))
01289             except:
01290                 pass
01291             newctrl.Bind(wx.EVT_TEXT_ENTER, self.OnCmdChanged)
01292             newctrl.Bind(wx.EVT_TEXT,       self.OnCmdChanged)
01293             data    = self.GetPyData(dragItem)
01294 
01295         elif self.GetPyData(dragItem)[0]['type'] == 'group':
01296             # recreate group
01297             newctrl = None
01298             data    = None
01299             
01300         # decide where to put recreated item
01301         if dropTarget != None and dropTarget != self.GetRootItem():
01302             if parent:
01303                 # new item is a group
01304                 afteritem = parent
01305             else:
01306                 # new item is a single layer
01307                 afteritem = dropTarget
01308 
01309             # dragItem dropped on group
01310             if  self.GetPyData(afteritem)[0]['type'] == 'group':
01311                 newItem = self.PrependItem(afteritem, text = text, \
01312                                       ct_type = 1, wnd = newctrl, image = image, \
01313                                       data = data)
01314                 self.Expand(afteritem)
01315             else:
01316                 #dragItem dropped on single layer
01317                 newparent = self.GetItemParent(afteritem)
01318                 newItem = self.InsertItem(newparent, self.GetPrevSibling(afteritem), \
01319                                        text = text, ct_type = 1, wnd = newctrl, \
01320                                        image = image, data = data)
01321         else:
01322             # if dragItem not dropped on a layer or group, append or prepend it to the layer tree
01323             if self.flag & wx.TREE_HITTEST_ABOVE:
01324                 newItem = self.PrependItem(self.root, text = text, \
01325                                       ct_type = 1, wnd = newctrl, image = image, \
01326                                       data = data)
01327             elif (self.flag &  wx.TREE_HITTEST_BELOW) or (self.flag & wx.TREE_HITTEST_NOWHERE) \
01328                      or (self.flag & wx.TREE_HITTEST_TOLEFT) or (self.flag & wx.TREE_HITTEST_TORIGHT):
01329                 newItem = self.AppendItem(self.root, text = text, \
01330                                       ct_type = 1, wnd = newctrl, image = image, \
01331                                       data = data)
01332 
01333         #update new layer 
01334         self.SetPyData(newItem, self.GetPyData(dragItem))
01335         if newctrl:
01336             self.GetPyData(newItem)[0]['ctrl'] = newctrl.GetId()
01337         else:
01338             self.GetPyData(newItem)[0]['ctrl'] = None
01339             
01340         self.CheckItem(newItem, checked = checked) # causes a new render
01341         
01342         return newItem
01343 
01344     def _getLayerName(self, item, lname = ''):
01345         """!Get layer name string
01346 
01347         @param lname optional layer name
01348         """
01349         mapLayer = self.GetPyData(item)[0]['maplayer']
01350         if not lname:
01351             lname  = self.GetPyData(item)[0]['label']
01352         opacity  = int(mapLayer.GetOpacity(float = True) * 100)
01353         if not lname:
01354             dcmd    = self.GetPyData(item)[0]['cmd']
01355             lname, found = utils.GetLayerNameFromCmd(dcmd, layerType = mapLayer.GetType(),
01356                                                      fullyQualified = True)
01357             if not found:
01358                 return None
01359         
01360         if opacity < 100:
01361             return lname + ' (%s %d' % (_('opacity:'), opacity) + '%)'
01362         
01363         return lname
01364                 
01365     def GetOptData(self, dcmd, layer, params, propwin):
01366         """!Process layer data (when changes in propertiesdialog are applied)"""
01367         # set layer text to map name
01368         if dcmd:
01369             self.GetPyData(layer)[0]['cmd'] = dcmd
01370             mapText  = self._getLayerName(layer)
01371             mapName, found = utils.GetLayerNameFromCmd(dcmd)
01372             mapLayer = self.GetPyData(layer)[0]['maplayer']
01373             self.SetItemText(layer, mapName)
01374             
01375             if not mapText or not found:
01376                 propwin.Hide()
01377                 GWarning(parent = self,
01378                          message = _("Map <%s> not found.") % mapName)
01379                 return
01380             
01381         # update layer data
01382         if params:
01383             self.SetPyData(layer, (self.GetPyData(layer)[0], params))
01384         self.GetPyData(layer)[0]['propwin'] = propwin
01385         
01386         # change parameters for item in layers list in render.Map
01387         self.ChangeLayer(layer)
01388 
01389         # set region if auto-zooming is enabled
01390         if dcmd and UserSettings.Get(group = 'display', key = 'autoZooming', subkey = 'enabled'):
01391             mapLayer = self.GetPyData(layer)[0]['maplayer']
01392             if mapLayer.GetType() in ('raster', 'vector'):
01393                 render = UserSettings.Get(group = 'display', key = 'autoRendering', subkey = 'enabled')
01394                 self.mapdisplay.MapWindow.ZoomToMap(layers = [mapLayer,],
01395                                                     render = render)
01396 
01397         # update nviz session        
01398         if self.mapdisplay.toolbars['nviz'] and dcmd:
01399             mapLayer = self.GetPyData(layer)[0]['maplayer']
01400             mapWin = self.mapdisplay.MapWindow
01401             if len(mapLayer.GetCmd()) > 0:
01402                 id = -1
01403                 if mapLayer.type == 'raster':
01404                     if mapWin.IsLoaded(layer):
01405                         mapWin.UnloadRaster(layer)
01406                     
01407                     mapWin.LoadRaster(layer)
01408                     
01409                 elif mapLayer.type == '3d-raster':
01410                     if mapWin.IsLoaded(layer):
01411                         mapWin.UnloadRaster3d(layer)
01412                     
01413                     mapWin.LoadRaster3d(layer)
01414                     
01415                 elif mapLayer.type == 'vector':
01416                     if mapWin.IsLoaded(layer):
01417                         mapWin.UnloadVector(layer)
01418                     
01419                     mapWin.LoadVector(layer)
01420 
01421                 # reset view when first layer loaded
01422                 nlayers = len(mapWin.Map.GetListOfLayers(l_type = ('raster', 'vector'),
01423                                                          l_active = True))
01424                 if nlayers < 2:
01425                     mapWin.ResetView()
01426         
01427     def ReorderLayers(self):
01428         """!Add commands from data associated with any valid layers
01429         (checked or not) to layer list in order to match layers in
01430         layer tree."""
01431 
01432         # make a list of visible layers
01433         treelayers = []
01434         
01435         vislayer = self.GetFirstVisibleItem()
01436         
01437         if not vislayer or self.GetPyData(vislayer) is None:
01438             return
01439         
01440         itemList = ""
01441         
01442         for item in range(self.GetCount()):
01443             itemList += self.GetItemText(vislayer) + ','
01444             if self.GetPyData(vislayer)[0]['type'] != 'group':
01445                 treelayers.append(self.GetPyData(vislayer)[0]['maplayer'])
01446 
01447             if not self.GetNextVisible(vislayer):
01448                 break
01449             else:
01450                 vislayer = self.GetNextVisible(vislayer)
01451         
01452         Debug.msg (4, "LayerTree.ReorderLayers(): items=%s" % \
01453                    (itemList))
01454         
01455         # reorder map layers
01456         treelayers.reverse()
01457         self.Map.ReorderLayers(treelayers)
01458         self.reorder = False
01459         
01460     def ChangeLayer(self, item):
01461         """!Change layer"""
01462         type = self.GetPyData(item)[0]['type']
01463         layerName = None
01464         
01465         if type == 'command':
01466             win = self.FindWindowById(self.GetPyData(item)[0]['ctrl'])
01467             if win.GetValue() != None:
01468                 cmd = win.GetValue().split(';')
01469                 cmdlist = []
01470                 for c in cmd:
01471                     cmdlist.append(c.split(' '))
01472                 opac = 1.0
01473                 chk = self.IsItemChecked(item)
01474                 hidden = not self.IsVisible(item)
01475         elif type != 'group':
01476             if self.GetPyData(item)[0] is not None:
01477                 cmdlist = self.GetPyData(item)[0]['cmd']
01478                 opac = self.GetPyData(item)[0]['maplayer'].GetOpacity(float = True)
01479                 chk = self.IsItemChecked(item)
01480                 hidden = not self.IsVisible(item)
01481                 # determine layer name
01482                 layerName, found = utils.GetLayerNameFromCmd(cmdlist, fullyQualified = True)
01483                 if not found:
01484                     layerName = self.GetItemText(item)
01485         
01486         maplayer = self.Map.ChangeLayer(layer = self.GetPyData(item)[0]['maplayer'], type = type,
01487                                         command = cmdlist, name = layerName,
01488                                         l_active = chk, l_hidden = hidden, l_opacity = opac, l_render = False)
01489         
01490         self.GetPyData(item)[0]['maplayer'] = maplayer
01491         
01492         # if digitization tool enabled -> update list of available vector map layers
01493         if self.mapdisplay.toolbars['vdigit']:
01494             self.mapdisplay.toolbars['vdigit'].UpdateListOfLayers(updateTool = True)
01495         
01496         # redraw map if auto-rendering is enabled
01497         self.rerender = True
01498         self.reorder = True
01499         
01500     def OnCloseWindow(self, event):
01501         pass
01502         # self.Map.Clean()
01503 
01504     def FindItemByData(self, key, value):
01505         """!Find item based on key and value (see PyData[0])
01506         
01507         @return item instance
01508         @return None not found
01509         """
01510         item = self.GetFirstChild(self.root)[0]
01511         return self.__FindSubItemByData(item, key, value)
01512 
01513     def FindItemByIndex(self, index):
01514         """!Find item by index (starting at 0)
01515 
01516         @return item instance
01517         @return None not found
01518         """
01519         item = self.GetFirstChild(self.root)[0]
01520         i = 0
01521         while item and item.IsOk():
01522             if i == index:
01523                 return item
01524             
01525             item = self.GetNextVisible(item)
01526             i += 1
01527         
01528         return None
01529     
01530     def EnableItemType(self, type, enable = True):
01531         """!Enable/disable items in layer tree"""
01532         item = self.GetFirstChild(self.root)[0]
01533         while item and item.IsOk():
01534             mapLayer = self.GetPyData(item)[0]['maplayer']
01535             if mapLayer and type == mapLayer.type:
01536                 self.EnableItem(item, enable)
01537             
01538             item = self.GetNextSibling(item)
01539         
01540     def __FindSubItemByData(self, item, key, value):
01541         """!Support method for FindItemByValue"""
01542         while item and item.IsOk():
01543             try:
01544                 itemValue = self.GetPyData(item)[0][key]
01545             except KeyError:
01546                 return None
01547             
01548             if value == itemValue:
01549                 return item
01550             if self.GetPyData(item)[0]['type'] == 'group':
01551                 subItem = self.GetFirstChild(item)[0]
01552                 found = self.__FindSubItemByData(subItem, key, value)
01553                 if found:
01554                     return found
01555             item = self.GetNextSibling(item)
01556 
01557         return None
01558 
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines