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