|
GRASS Programmer's Manual
6.5.svn(2012)-r51648
|
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