2 @package lmgr.layertree
4 @brief Utility classes for map layer management.
9 (C) 2007-2011 by the GRASS Development Team
11 This program is free software under the GNU General Public License
12 (>=v2). Read the file COPYING that comes with GRASS for details.
14 @author Michael Barton (Arizona State University)
15 @author Jachym Cepicky (Mendel University of Agriculture)
16 @author Martin Landa <landa.martin gmail.com>
22 import wx.lib.agw.customtreectrl
as CT
24 import wx.lib.customtreectrl
as CT
25 import wx.lib.buttons
as buttons
29 from wx.lib.mixins
import treemixin
34 from core
import globalvar
36 from gui_core.forms
import GUI
46 from icons.icon
import MetaIcon
51 'rastImport' : MetaIcon(img =
'layer-import',
52 label = _(
'Import raster data')),
53 'rastLink' : MetaIcon(img =
'layer-import',
54 label = _(
'Link external raster data')),
55 'rastOut' : MetaIcon(img =
'layer-export',
56 label = _(
'Set raster output format')),
57 'vectImport' : MetaIcon(img =
'layer-import',
58 label = _(
'Import vector data')),
59 'vectLink' : MetaIcon(img =
'layer-import',
60 label = _(
'Link external vector data')),
61 'vectOut' : MetaIcon(img =
'layer-export',
62 label = _(
'Set vector output format')),
63 'addCmd' : MetaIcon(img =
'layer-command-add',
64 label = _(
'Add command layer')),
65 'quit' : MetaIcon(img =
'quit',
67 'addRgb' : MetaIcon(img =
'layer-rgb-add',
68 label = _(
'Add RGB map layer')),
69 'addHis' : MetaIcon(img =
'layer-his-add',
70 label = _(
'Add HIS map layer')),
71 'addShaded' : MetaIcon(img =
'layer-shaded-relief-add',
72 label = _(
'Add shaded relief map layer')),
73 'addRArrow' : MetaIcon(img =
'layer-aspect-arrow-add',
74 label = _(
'Add raster flow arrows')),
75 'addRNum' : MetaIcon(img =
'layer-cell-cats-add',
76 label = _(
'Add raster cell numbers')),
77 'addThematic': MetaIcon(img =
'layer-vector-thematic-add',
78 label = _(
'Add thematic area (choropleth) map layer')),
79 'addChart' : MetaIcon(img =
'layer-vector-chart-add',
80 label = _(
'Add thematic chart layer')),
81 'addGrid' : MetaIcon(img =
'layer-grid-add',
82 label = _(
'Add grid layer')),
83 'addGeodesic': MetaIcon(img =
'shortest-distance',
84 label = _(
'Add geodesic line layer')),
85 'addRhumb' : MetaIcon(img =
'shortest-distance',
86 label = _(
'Add rhumbline layer')),
87 'addLabels' : MetaIcon(img =
'layer-label-add',
88 label = _(
'Add labels')),
89 'addRast3d' : MetaIcon(img =
'layer-raster3d-add',
90 label = _(
'Add 3D raster map layer'),
91 desc = _(
'Note that 3D raster data are rendered only in 3D view mode')),
92 'layerOptions' : MetaIcon(img =
'options',
93 label = _(
'Set options')),
96 class LayerTree(treemixin.DragAndDrop, CT.CustomTreeCtrl):
97 """!Creates layer tree structure
100 id = wx.ID_ANY, style = wx.SUNKEN_BORDER,
101 ctstyle = CT.TR_HAS_BUTTONS | CT.TR_HAS_VARIABLE_ROW_HEIGHT |
102 CT.TR_HIDE_ROOT | CT.TR_ROW_LINES | CT.TR_FULL_ROW_HIGHLIGHT |
103 CT.TR_MULTIPLE, **kwargs):
105 if 'style' in kwargs:
106 ctstyle |= kwargs[
'style']
113 del kwargs[
'notebook']
116 showMapDisplay = kwargs[
'showMapDisplay']
117 del kwargs[
'showMapDisplay']
133 ctstyle |= CT.TR_ALIGN_WINDOWS
134 except AttributeError:
138 super(LayerTree, self).
__init__(parent, id, agwStyle = ctstyle, **kwargs)
140 super(LayerTree, self).
__init__(parent, id, style = ctstyle, **kwargs)
141 self.SetName(
"LayerTree")
146 self.SetGradientStyle(1)
147 self.EnableSelectionGradient(
True)
153 id = wx.ID_ANY, pos = pos,
154 size = globalvar.MAP_WINDOW_SIZE,
155 style = wx.DEFAULT_FRAME_STYLE,
156 tree = self, notebook = self.
notebook,
161 self.mapdisplay.SetTitle(_(
"GRASS GIS Map Display: %(id)d - Location: %(loc)s") % \
163 'loc' : grass.gisenv()[
"LOCATION_NAME"] })
166 if showMapDisplay
is True:
167 self.mapdisplay.Show()
168 self.mapdisplay.Refresh()
169 self.mapdisplay.Update()
171 self.
root = self.AddRoot(_(
"Map Layers"))
172 self.SetPyData(self.
root, (
None,
None))
175 il = wx.ImageList(16, 16, mask =
False)
177 trart = wx.ArtProvider.GetBitmap(wx.ART_FOLDER_OPEN, wx.ART_OTHER, (16, 16))
179 trart = wx.ArtProvider.GetBitmap(wx.ART_FOLDER, wx.ART_OTHER, (16, 16))
183 trgif = BaseIcons[
"addRast"].GetBitmap(bmpsize)
186 trgif = LMIcons[
"addRast3d"].GetBitmap(bmpsize)
189 trgif = LMIcons[
"addRgb"].GetBitmap(bmpsize)
192 trgif = LMIcons[
"addHis"].GetBitmap(bmpsize)
195 trgif = LMIcons[
"addShaded"].GetBitmap(bmpsize)
198 trgif = LMIcons[
"addRArrow"].GetBitmap(bmpsize)
201 trgif = LMIcons[
"addRNum"].GetBitmap(bmpsize)
204 trgif = BaseIcons[
"addVect"].GetBitmap(bmpsize)
207 trgif = LMIcons[
"addThematic"].GetBitmap(bmpsize)
210 trgif = LMIcons[
"addChart"].GetBitmap(bmpsize)
213 trgif = LMIcons[
"addGrid"].GetBitmap(bmpsize)
216 trgif = LMIcons[
"addGeodesic"].GetBitmap(bmpsize)
219 trgif = LMIcons[
"addRhumb"].GetBitmap(bmpsize)
222 trgif = LMIcons[
"addLabels"].GetBitmap(bmpsize)
225 trgif = LMIcons[
"addCmd"].GetBitmap(bmpsize)
228 self.AssignImageList(il)
230 self.Bind(wx.EVT_TREE_ITEM_EXPANDING, self.
OnExpandNode)
233 self.Bind(wx.EVT_TREE_SEL_CHANGED, self.
OnChangeSel)
239 self.Bind(wx.EVT_TREE_END_DRAG, self.
OnEndDrag)
240 self.Bind(wx.EVT_TREE_END_LABEL_EDIT, self.
OnRenamed)
241 self.Bind(wx.EVT_KEY_UP, self.
OnKeyUp)
242 self.Bind(wx.EVT_IDLE, self.
OnIdle)
243 self.Bind(wx.EVT_MOTION, self.
OnMotion)
245 def _setGradient(self, iType = None):
246 """!Set gradient for items
248 @param iType bgmap, vdigit or None
251 self.SetFirstGradientColour(wx.Colour(0, 100, 0))
252 self.SetSecondGradientColour(wx.Colour(0, 150, 0))
253 elif iType ==
'vdigit':
254 self.SetFirstGradientColour(wx.Colour(100, 0, 0))
255 self.SetSecondGradientColour(wx.Colour(150, 0, 0))
257 self.SetFirstGradientColour(wx.Colour(100, 100, 100))
258 self.SetSecondGradientColour(wx.Colour(150, 150, 150))
261 """Returns a list of selected items.
263 This method is copied from customtreecontrol and overriden because
264 with some version wx (?) multiple selection doesn't work.
265 Probably it is caused by another GetSelections method in treemixin.DragAndDrop?
268 idRoot = self.GetRootItem()
270 array = self.FillArray(idRoot, array)
277 """!Get map instace"""
281 """!Get associated MapFrame"""
285 """!Only re-order and re-render a composite map image from GRASS during
286 idle time instead of multiple times during layer changing.
289 if self.mapdisplay.GetToolbar(
'vdigit'):
293 if self.mapdisplay.IsAutoRendered():
294 self.mapdisplay.MapWindow2D.UpdateMap(render =
True, renderVector = vector)
295 if self.lmgr.IsPaneShown(
'toolbarNviz'):
296 self.mapdisplay.MapWindow3D.UpdateMap(render =
True)
304 key = event.GetKeyCode()
306 if key == wx.WXK_DELETE
and self.
lmgr and \
307 not self.GetEditControl():
308 self.lmgr.OnDeleteLayer(
None)
313 """!Contextual menu for item/layer"""
321 Debug.msg (4,
"LayerTree.OnContextMenu: layertype=%s" % \
324 if not hasattr (self,
"popupID"):
326 for key
in (
'remove',
'rename',
'opacity',
'nviz',
'zoom',
327 'region',
'export',
'attr',
'edit0',
'edit1',
328 'bgmap',
'topo',
'meta',
'null',
'zoom1',
'region1',
329 'color',
'hist',
'univar',
'prof',
'properties'):
336 self.popupMenu.Append(self.
popupID[
'remove'], text = _(
"Remove"))
337 self.Bind(wx.EVT_MENU, self.lmgr.OnDeleteLayer, id = self.
popupID[
'remove'])
339 if ltype !=
"command":
340 self.popupMenu.Append(self.
popupID[
'rename'], text = _(
"Rename"))
343 self.popupMenu.Enable(self.
popupID[
'rename'],
False)
346 if ltype
not in (
"group",
"command"):
347 self.popupMenu.AppendSeparator()
348 self.popupMenu.Append(self.
popupID[
'opacity'], text = _(
"Change opacity level"))
350 self.popupMenu.Append(self.
popupID[
'properties'], text = _(
"Properties"))
354 self.popupMenu.Enable(self.
popupID[
'opacity'],
False)
355 self.popupMenu.Enable(self.
popupID[
'properties'],
False)
357 if ltype
in (
'raster',
'vector',
'3d-raster')
and self.lmgr.IsPaneShown(
'toolbarNviz'):
358 self.popupMenu.Append(self.
popupID[
'nviz'], _(
"3D view properties"))
361 if ltype
in (
'raster',
'vector',
'rgb'):
362 self.popupMenu.Append(self.
popupID[
'zoom'], text = _(
"Zoom to selected map(s)"))
363 self.Bind(wx.EVT_MENU, self.mapdisplay.OnZoomToMap, id = self.
popupID[
'zoom'])
364 self.popupMenu.Append(self.
popupID[
'region'], text = _(
"Set computational region from selected map(s)"))
374 if mltype
and mltype ==
"vector":
375 self.popupMenu.AppendSeparator()
376 self.popupMenu.Append(self.
popupID[
'export'], text = _(
"Export"))
377 self.Bind(wx.EVT_MENU,
lambda x: self.lmgr.OnMenuCmd(cmd = [
'v.out.ogr',
378 'input=%s' % mapLayer.GetName()]),
381 self.popupMenu.AppendSeparator()
383 self.popupMenu.Append(self.
popupID[
'color'], _(
"Set color table"))
386 self.popupMenu.Append(self.
popupID[
'attr'], text = _(
"Show attribute data"))
387 self.Bind(wx.EVT_MENU, self.lmgr.OnShowAttributeTable, id = self.
popupID[
'attr'])
389 self.popupMenu.Append(self.
popupID[
'edit0'], text = _(
"Start editing"))
390 self.popupMenu.Append(self.
popupID[
'edit1'], text = _(
"Stop editing"))
391 self.popupMenu.Enable(self.
popupID[
'edit1'],
False)
397 digitToolbar = self.mapdisplay.GetToolbar(
'vdigit')
400 self.popupMenu.Append(self.
popupID[
'bgmap'],
401 text = _(
"Use as background vector map for digitizer"),
402 kind = wx.ITEM_CHECK)
404 if UserSettings.Get(group =
'vdigit', key =
'bgmap', subkey =
'value',
405 internal =
True) == layer.GetName():
406 self.popupMenu.Check(self.
popupID[
'bgmap'],
True)
408 self.popupMenu.Append(self.
popupID[
'topo'], text = _(
"Rebuild topology"))
411 if layer.GetMapset() != grass.gisenv()[
'MAPSET']:
413 self.popupMenu.Enable (self.
popupID[
'edit0'],
False)
414 self.popupMenu.Enable (self.
popupID[
'edit1'],
False)
415 self.popupMenu.Enable (self.
popupID[
'topo'],
False)
416 elif digitToolbar
and digitToolbar.GetLayer():
418 vdigitLayer = digitToolbar.GetLayer()
419 if vdigitLayer
is layer:
420 self.popupMenu.Enable(self.
popupID[
'edit0'],
False)
421 self.popupMenu.Enable(self.
popupID[
'edit1'],
True)
422 self.popupMenu.Enable(self.
popupID[
'remove'],
False)
423 self.popupMenu.Enable(self.
popupID[
'bgmap'],
False)
424 self.popupMenu.Enable(self.
popupID[
'topo'],
False)
426 self.popupMenu.Enable(self.
popupID[
'edit0'],
False)
427 self.popupMenu.Enable(self.
popupID[
'edit1'],
False)
428 self.popupMenu.Enable(self.
popupID[
'bgmap'],
True)
430 self.popupMenu.Append(self.
popupID[
'meta'], _(
"Metadata"))
433 self.popupMenu.Enable(self.
popupID[
'attr'],
False)
434 self.popupMenu.Enable(self.
popupID[
'edit0'],
False)
435 self.popupMenu.Enable(self.
popupID[
'edit1'],
False)
436 self.popupMenu.Enable(self.
popupID[
'meta'],
False)
437 self.popupMenu.Enable(self.
popupID[
'bgmap'],
False)
438 self.popupMenu.Enable(self.
popupID[
'topo'],
False)
439 self.popupMenu.Enable(self.
popupID[
'export'],
False)
442 elif mltype
and mltype ==
"raster":
443 self.popupMenu.Append(self.
popupID[
'zoom1'], text = _(
"Zoom to selected map(s) (ignore NULLs)"))
444 self.Bind(wx.EVT_MENU, self.mapdisplay.OnZoomToRaster, id = self.
popupID[
'zoom1'])
445 self.popupMenu.Append(self.
popupID[
'region1'], text = _(
"Set computational region from selected map(s) (ignore NULLs)"))
448 self.popupMenu.AppendSeparator()
449 self.popupMenu.Append(self.
popupID[
'export'], text = _(
"Export"))
450 self.Bind(wx.EVT_MENU,
lambda x: self.lmgr.OnMenuCmd(cmd = [
'r.out.gdal',
451 'input=%s' % mapLayer.GetName()]),
454 self.popupMenu.AppendSeparator()
455 self.popupMenu.Append(self.
popupID[
'color'], _(
"Set color table"))
457 self.popupMenu.Append(self.
popupID[
'hist'], _(
"Histogram"))
459 self.popupMenu.Append(self.
popupID[
'univar'], _(
"Univariate raster statistics"))
461 self.popupMenu.Append(self.
popupID[
'prof'], _(
"Profile"))
463 self.popupMenu.Append(self.
popupID[
'meta'], _(
"Metadata"))
467 self.popupMenu.Enable(self.
popupID[
'zoom1'],
False)
468 self.popupMenu.Enable(self.
popupID[
'region1'],
False)
469 self.popupMenu.Enable(self.
popupID[
'color'],
False)
470 self.popupMenu.Enable(self.
popupID[
'hist'],
False)
471 self.popupMenu.Enable(self.
popupID[
'univar'],
False)
472 self.popupMenu.Enable(self.
popupID[
'prof'],
False)
473 self.popupMenu.Enable(self.
popupID[
'meta'],
False)
474 self.popupMenu.Enable(self.
popupID[
'export'],
False)
475 if self.lmgr.IsPaneShown(
'toolbarNviz'):
476 self.popupMenu.Enable(self.
popupID[
'nviz'],
False)
479 self.popupMenu.Destroy()
482 """!Rebuild topology of selected vector map"""
485 'map=%s' % mapLayer.GetName()]
486 self.lmgr.goutput.RunCmd(cmd, switchPage =
True)
489 """!Print metadata of raster/vector map layer
490 TODO: Dialog to modify metadata
495 if mltype ==
'raster':
497 elif mltype ==
'vector':
499 cmd.append(
'map=%s' % mapLayer.GetName())
502 self.lmgr.goutput.RunCmd(cmd, switchPage =
True)
505 """!Set computational region from selected raster map (ignore NULLs)"""
510 'zoom=%s' % mapLayer.GetName()]
513 self.lmgr.goutput.RunCmd(cmd)
516 """!Set computational region from selected raster/vector map
522 mapLayer = self.GetPyData(layer)[0][
'maplayer']
523 mltype = self.GetPyData(layer)[0][
'type']
525 if mltype ==
'raster':
526 rast.append(mapLayer.GetName())
527 elif mltype ==
'vector':
528 vect.append(mapLayer.GetName())
529 elif mltype ==
'3d-raster':
530 rast3d.append(mapLayer.GetName())
531 elif mltype ==
'rgb':
532 for rname
in mapLayer.GetName().splitlines():
537 cmd.append(
'rast=%s' %
','.join(rast))
539 cmd.append(
'vect=%s' %
','.join(vect))
541 cmd.append(
'rast3d=%s' %
','.join(rast3d))
546 self.lmgr.goutput.RunCmd(cmd, compReg =
False)
549 """!Plot profile of given raster map layer"""
551 if not mapLayer.GetName():
552 wx.MessageBox(parent = self,
553 message = _(
"Unable to create profile of "
555 caption = _(
"Error"), style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
558 if not hasattr (self,
"profileFrame"):
561 if hasattr (self.
mapdisplay,
"profile")
and self.mapdisplay.profile:
566 id = wx.ID_ANY, pos = wx.DefaultPosition, size = (700,300),
567 style = wx.DEFAULT_FRAME_STYLE, rasterList = [mapLayer.GetName()])
569 self.profileFrame.Show()
572 """!Set color table for raster map"""
573 name = self.GetPyData(self.
layer_selected)[0][
'maplayer'].GetName()
574 GUI(parent = self).ParseCommand([
'r.colors',
578 """!Set color table for vector map"""
579 name = self.GetPyData(self.
layer_selected)[0][
'maplayer'].GetName()
580 GUI(parent = self, centreOnParent =
False).ParseCommand([
'v.colors',
584 """!Plot histogram for given raster map layer
587 if not mapLayer.GetName():
588 GError(parent = self,
589 message = _(
"Unable to display histogram of "
590 "raster map. No map name defined."))
593 win = HistogramFrame(parent = self)
597 win.SetHistLayer(mapLayer.GetName())
598 win.HistWindow.UpdateHist()
603 """!Univariate raster statistics"""
604 name = self.GetPyData(self.
layer_selected)[0][
'maplayer'].GetName()
605 self.lmgr.goutput.RunCmd([
'r.univar',
'map=%s' % name], switchPage =
True)
608 """!Start editing vector map layer requested by the user
616 if not self.mapdisplay.GetToolbar(
'vdigit'):
617 self.mapdisplay.AddToolbar(
'vdigit')
619 if not self.mapdisplay.toolbars[
'vdigit']:
622 self.mapdisplay.toolbars[
'vdigit'].StartEditing(maplayer)
628 """!Stop editing the current vector map layer
632 self.mapdisplay.toolbars[
'vdigit'].OnExit()
634 self.lmgr.toolbars[
'tools'].Enable(
'vdigit', enable =
True)
640 """!Set background vector map for editing sesstion"""
641 digit = self.mapdisplay.GetWindow().digit
642 if event.IsChecked():
643 mapName = self.GetPyData(self.
layer_selected)[0][
'maplayer'].GetName()
644 UserSettings.Set(group =
'vdigit', key =
'bgmap', subkey =
'value',
645 value = str(mapName), internal =
True)
646 digit.OpenBackgroundMap(mapName)
649 UserSettings.Set(group =
'vdigit', key =
'bgmap', subkey =
'value',
650 value =
'', internal =
True)
651 digit.CloseBackgroundMap()
657 """!Popup properties dialog"""
661 """!Popup opacity level indicator"""
666 current_opacity = maplayer.GetOpacity()
668 dlg = SetOpacityDialog(self, opacity = current_opacity,
669 title = _(
"Set opacity of <%s>") % maplayer.GetName())
673 if dlg.ShowModal() == wx.ID_OK:
678 """!Handles EVT_APPLY_OPACITY event."""
682 """!Change opacity value of layer
683 @param layer layer for which to change (item in layertree)
684 @param value opacity value (float between 0 and 1)
686 maplayer = self.GetPyData(layer)[0][
'maplayer']
687 self.Map.ChangeOpacity(maplayer, value)
688 maplayer.SetOpacity(value)
689 self.SetItemText(layer,
694 self.
GetMapDisplay().GetToolbar(
'vdigit').GetLayer() == maplayer:
695 alpha = int(value * 255)
702 self.
GetMapDisplay().GetWindow().UpdateMap(render =
False, renderVector = renderVector)
705 """!Nviz-related properties (raster/vector/volume)
709 self.lmgr.notebook.SetSelectionByName(
'nviz')
711 if ltype ==
'raster':
712 self.lmgr.nviz.SetPage(
'surface')
713 elif ltype ==
'vector':
714 self.lmgr.nviz.SetPage(
'vector')
715 elif ltype ==
'3d-raster':
716 self.lmgr.nviz.SetPage(
'volume')
721 self.GetEditControl().SetSelection(-1, -1)
726 self.GetPyData(item)[0][
'label'] = event.GetLabel()
731 def AddLayer(self, ltype, lname = None, lchecked = None,
732 lopacity = 1.0, lcmd =
None, lgroup =
None, lvdigit =
None, lnviz =
None, multiple =
True):
733 """!Add new item to the layer tree, create corresponding MapLayer instance.
734 Launch property dialog if needed (raster, vector, etc.)
736 @param ltype layer type (raster, vector, 3d-raster, ...)
737 @param lname layer name
738 @param lchecked if True layer is checked
739 @param lopacity layer opacity level
740 @param lcmd command (given as a list)
741 @param lgroup index of group item (-1 for root) or None
742 @param lvdigit vector digitizer settings (eg. geometry attributes)
743 @param lnviz layer Nviz properties
744 @param multiple True to allow multiple map layers in layer tree
746 if lname
and not multiple:
748 item = self.GetFirstVisibleItem()
749 while item
and item.IsOk():
750 if self.GetPyData(item)[0][
'type'] ==
'vector':
751 name = self.GetPyData(item)[0][
'maplayer'].GetName()
754 item = self.GetNextVisible(item)
763 Debug.msg (3,
"LayerTree().AddLayer(): ltype=%s" % (ltype))
765 if ltype ==
'command':
770 elif ltype ==
'group':
773 grouptext = _(
'Layer group:') + str(self.
groupnode)
776 btnbmp = LMIcons[
"layerOptions"].GetBitmap((16,16))
777 ctrl = buttons.GenBitmapButton(self, id = wx.ID_ANY, bitmap = btnbmp, size = (24,24))
778 ctrl.SetToolTipString(_(
"Click to edit layer settings"))
786 text =
'', ct_type = 1, wnd = ctrl)
791 layer = self.AppendItem(parentId = self.
root,
792 text =
'', ct_type = 1, wnd = ctrl)
798 layer = self.AppendItem(parentId = parent,
799 text =
'', ct_type = 1, wnd = ctrl)
803 layer = self.InsertItem(parentId = parent,
805 text =
'', ct_type = 1, wnd = ctrl)
807 layer = self.PrependItem(parent = self.
root, text =
'', ct_type = 1, wnd = ctrl)
811 if lchecked
is not None:
817 self.CheckItem(layer, checked = checked)
820 label = _(
'(double click to set properties)') +
' ' * 15
821 if ltype ==
'raster':
823 self.SetItemText(layer,
'%s %s' % (_(
'raster'), label))
824 elif ltype ==
'3d-raster':
826 self.SetItemText(layer,
'%s %s' % (_(
'3D raster'), label))
828 self.SetItemImage(layer, self.
rgb_icon)
829 self.SetItemText(layer,
'%s %s' % (_(
'RGB'), label))
831 self.SetItemImage(layer, self.
his_icon)
832 self.SetItemText(layer,
'%s %s' % (_(
'HIS'), label))
833 elif ltype ==
'shaded':
835 self.SetItemText(layer,
'%s %s' % (_(
'shaded relief'), label))
836 elif ltype ==
'rastnum':
838 self.SetItemText(layer,
'%s %s' % (_(
'raster cell numbers'), label))
839 elif ltype ==
'rastarrow':
841 self.SetItemText(layer,
'%s %s' % (_(
'raster flow arrows'), label))
842 elif ltype ==
'vector':
844 self.SetItemText(layer,
'%s %s' % (_(
'vector'), label))
845 elif ltype ==
'thememap':
847 self.SetItemText(layer,
'%s %s' % (_(
'thematic map'), label))
848 elif ltype ==
'themechart':
850 self.SetItemText(layer,
'%s %s' % (_(
'thematic charts'), label))
851 elif ltype ==
'grid':
853 self.SetItemText(layer,
'%s %s' % (_(
'grid'), label))
854 elif ltype ==
'geodesic':
856 self.SetItemText(layer,
'%s %s' % (_(
'geodesic line'), label))
857 elif ltype ==
'rhumb':
859 self.SetItemText(layer,
'%s %s' % (_(
'rhumbline'), label))
860 elif ltype ==
'labels':
862 self.SetItemText(layer,
'%s %s' % (_(
'vector labels'), label))
863 elif ltype ==
'command':
864 self.SetItemImage(layer, self.
cmd_icon)
865 elif ltype ==
'group':
866 self.SetItemImage(layer, self.
folder)
867 self.SetItemText(layer, grouptext)
872 if lcmd
and len(lcmd) > 1:
878 if ltype ==
'command' and lname:
879 for c
in lname.split(
';'):
880 cmd.append(c.split(
' '))
886 ctrlId = ctrl.GetId()
891 self.SetPyData(layer, ({
'cmd' : cmd,
902 prevItem = self.GetFirstChild(self.
root)[0]
905 while prevItem
and prevItem.IsOk()
and prevItem != layer:
906 if self.GetPyData(prevItem)[0][
'maplayer']:
907 prevMapLayer = self.GetPyData(prevItem)[0][
'maplayer']
909 prevItem = self.GetNextSibling(prevItem)
912 pos = self.Map.GetLayerIndex(prevMapLayer)
916 maplayer = self.Map.AddLayer(pos = pos,
917 type = ltype, command = self.GetPyData(layer)[0][
'cmd'], name = name,
918 l_active = checked, l_hidden =
False,
919 l_opacity = lopacity, l_render = render)
920 self.GetPyData(layer)[0][
'maplayer'] = maplayer
927 self.SetPyData(layer, ({
'cmd' :
None,
936 self.SelectItem(layer, select =
True)
942 self.SetItemText(layer, lname)
943 elif ltype ==
'command':
950 self.mapdisplay.GetProgressBar().
SetRange(len(self.Map.GetListOfLayers(l_active =
True)))
955 """!Launch the properties dialog"""
956 if 'propwin' in self.GetPyData(layer)[0]
and \
957 self.GetPyData(layer)[0][
'propwin']
is not None:
959 win = self.GetPyData(layer)[0][
'propwin']
968 params = self.GetPyData(layer)[1]
969 ltype = self.GetPyData(layer)[0][
'type']
971 Debug.msg (3,
"LayerTree.PropertiesDialog(): ltype=%s" % \
975 if self.GetPyData(layer)[0][
'cmd']:
976 module = GUI(parent = self, show = show, centreOnParent =
False)
977 module.ParseCommand(self.GetPyData(layer)[0][
'cmd'],
980 self.GetPyData(layer)[0][
'cmd'] = module.GetCmd()
981 elif ltype ==
'raster':
983 if UserSettings.Get(group=
'cmd', key=
'rasterOverlay', subkey=
'enabled'):
986 elif ltype ==
'3d-raster':
987 cmd = [
'd.rast3d.py']
991 if UserSettings.Get(group=
'cmd', key=
'rasterOverlay', subkey=
'enabled'):
997 elif ltype ==
'shaded':
998 cmd = [
'd.shadedmap']
1000 elif ltype ==
'rastarrow':
1001 cmd = [
'd.rast.arrow']
1003 elif ltype ==
'rastnum':
1004 cmd = [
'd.rast.num']
1006 elif ltype ==
'vector':
1008 for ftype
in [
'point',
'line',
'boundary',
'centroid',
'area',
'face']:
1009 if UserSettings.Get(group =
'cmd', key =
'showType', subkey = [ftype,
'enabled']):
1012 cmd = [
'd.vect',
'type=%s' %
','.join(types)]
1014 elif ltype ==
'thememap':
1017 cmd = [
'd.vect.thematic',
'-s']
1019 elif ltype ==
'themechart':
1020 cmd = [
'd.vect.chart']
1022 elif ltype ==
'grid':
1025 elif ltype ==
'geodesic':
1026 cmd = [
'd.geodesic']
1028 elif ltype ==
'rhumb':
1029 cmd = [
'd.rhumbline']
1031 elif ltype ==
'labels':
1035 GUI(parent = self, centreOnParent =
False).ParseCommand(cmd,
1039 """!Double click on the layer item.
1040 Launch property dialog, or expand/collapse group of items, etc.
1042 self.lmgr.WorkspaceChanged()
1043 layer = event.GetItem()
1048 if self.GetPyData(layer)[0][
'type'] ==
'group':
1049 if self.IsExpanded(layer):
1050 self.Collapse(layer)
1055 """!Remove selected layer item from the layer tree"""
1056 self.lmgr.WorkspaceChanged()
1057 item = event.GetItem()
1060 item.properties.Close(
True)
1064 if item != self.
root:
1065 Debug.msg (3,
"LayerTree.OnDeleteLayer(): name=%s" % \
1066 (self.GetItemText(item)))
1075 if self.GetPyData(item)[0][
'type'] !=
'group':
1076 self.Map.DeleteLayer( self.GetPyData(item)[0][
'maplayer'])
1084 if self.mapdisplay.GetToolbar(
'vdigit'):
1085 self.mapdisplay.toolbars[
'vdigit'].UpdateListOfLayers (updateTool =
True)
1088 self.mapdisplay.GetProgressBar().
SetRange(len(self.Map.GetListOfLayers(l_active =
True)))
1093 if self.lmgr.IsPaneShown(
'toolbarNviz')
and \
1094 self.GetPyData(item)
is not None:
1096 mapLayer = self.GetPyData(item)[0][
'maplayer']
1097 self.mapdisplay.SetStatusText(_(
"Please wait, updating data..."), 0)
1098 if mapLayer.type ==
'raster':
1099 self.mapdisplay.MapWindow.UnloadRaster(item)
1100 elif mapLayer.type ==
'3d-raster':
1101 self.mapdisplay.MapWindow.UnloadRaster3d(item)
1102 elif mapLayer.type ==
'vector':
1103 self.mapdisplay.MapWindow.UnloadVector(item)
1104 self.mapdisplay.SetStatusText(
"", 0)
1109 """!Layer checkbox is being checked.
1111 Continue only if mouse is above checkbox or layer was checked programatically.
1120 """!Enable/disable data layer"""
1121 self.lmgr.WorkspaceChanged()
1123 item = event.GetItem()
1124 checked = item.IsChecked()
1126 digitToolbar = self.mapdisplay.GetToolbar(
'vdigit')
1129 if self.GetPyData(item)[0][
'type'] ==
'group':
1130 child, cookie = self.GetFirstChild(item)
1133 self.CheckItem(child, checked)
1134 mapLayer = self.GetPyData(child)[0][
'maplayer']
1135 if not digitToolbar
or \
1136 (digitToolbar
and digitToolbar.GetLayer() != mapLayer):
1138 self.Map.ChangeLayerActive(mapLayer, checked)
1139 child = self.GetNextSibling(child)
1141 mapLayer = self.GetPyData(item)[0][
'maplayer']
1142 if not digitToolbar
or \
1143 (digitToolbar
and digitToolbar.GetLayer() != mapLayer):
1145 self.Map.ChangeLayerActive(mapLayer, checked)
1148 self.mapdisplay.GetProgressBar().
SetRange(len(self.Map.GetListOfLayers(l_active =
True)))
1151 if self.lmgr.IsPaneShown(
'toolbarNviz')
and \
1152 self.GetPyData(item)
is not None:
1154 mapLayer = self.GetPyData(item)[0][
'maplayer']
1156 self.mapdisplay.SetStatusText(_(
"Please wait, updating data..."), 0)
1159 if mapLayer.type ==
'raster':
1160 self.mapdisplay.MapWindow.LoadRaster(item)
1161 elif mapLayer.type ==
'3d-raster':
1162 self.mapdisplay.MapWindow.LoadRaster3d(item)
1163 elif mapLayer.type ==
'vector':
1164 vInfo = gvector.vector_info_topo(mapLayer.GetName())
1165 if (vInfo[
'points'] + vInfo[
'centroids']) > 0:
1166 self.mapdisplay.MapWindow.LoadVector(item, points =
True)
1167 if (vInfo[
'lines'] + vInfo[
'boundaries']) > 0:
1168 self.mapdisplay.MapWindow.LoadVector(item, points =
False)
1171 if mapLayer.type ==
'raster':
1172 self.mapdisplay.MapWindow.UnloadRaster(item)
1173 elif mapLayer.type ==
'3d-raster':
1174 self.mapdisplay.MapWindow.UnloadRaster3d(item)
1175 elif mapLayer.type ==
'vector':
1176 self.mapdisplay.MapWindow.UnloadVector(item)
1178 self.mapdisplay.SetStatusText(
"", 0)
1185 """!Change command string"""
1186 ctrl = event.GetEventObject().GetId()
1187 cmd = event.GetString()
1190 layer = self.GetFirstVisibleItem()
1191 while layer
and layer.IsOk():
1192 if self.GetPyData(layer)[0][
'ctrl'] == ctrl:
1194 layer = self.GetNextVisible(layer)
1202 """!Mouse is moving.
1204 Detects if mouse points at checkbox.
1206 thisItem, flags = self.HitTest(event.GetPosition())
1210 if (flags & CT.TREE_HITTEST_ONITEMCHECKICON)
and not (flags & CT.TREE_HITTEST_ONITEMLABEL):
1217 """!Selection is changing.
1219 If the user is clicking on checkbox, selection change is vetoed.
1225 """!Selection changed"""
1226 layer = event.GetItem()
1227 digitToolbar = self.mapdisplay.GetToolbar(
'vdigit')
1229 mapLayer = self.GetPyData(layer)[0][
'maplayer']
1230 bgmap = UserSettings.Get(group =
'vdigit', key =
'bgmap', subkey =
'value',
1233 if digitToolbar.GetLayer() == mapLayer:
1235 elif bgmap == mapLayer.GetName():
1245 if self.IsSelected(oldlayer):
1246 self.SetItemWindowEnabled(oldlayer,
True)
1248 self.SetItemWindowEnabled(oldlayer,
False)
1250 if self.IsSelected(layer):
1251 self.SetItemWindowEnabled(layer,
True)
1253 self.SetItemWindowEnabled(layer,
False)
1258 self.RefreshLine(oldlayer)
1259 self.RefreshLine(layer)
1264 if self.GetPyData(layer)
and self.GetPyData(layer)[0][
'maplayer']:
1265 cmd = self.GetPyData(layer)[0][
'maplayer'].GetCmd(string =
True)
1267 self.lmgr.SetStatusText(cmd)
1270 if self.GetPyData(layer)
and self.GetPyData(layer)[0][
'cmd']
and \
1271 UserSettings.Get(group =
'display', key =
'autoZooming', subkey =
'enabled'):
1272 mapLayer = self.GetPyData(layer)[0][
'maplayer']
1273 if mapLayer.GetType()
in (
'raster',
'vector'):
1274 render = self.mapdisplay.IsAutoRendered()
1275 self.mapdisplay.MapWindow.ZoomToMap(layers = [mapLayer,],
1279 if self.lmgr.IsPaneShown(
'toolbarNviz')
and \
1281 if self.layer_selected.IsChecked():
1285 if type ==
'raster':
1286 self.lmgr.nviz.UpdatePage(
'surface')
1287 self.lmgr.nviz.SetPage(
'surface')
1288 elif type ==
'vector':
1289 self.lmgr.nviz.UpdatePage(
'vector')
1290 self.lmgr.nviz.SetPage(
'vector')
1291 elif type ==
'3d-raster':
1292 self.lmgr.nviz.UpdatePage(
'volume')
1293 self.lmgr.nviz.SetPage(
'volume')
1310 dropTarget = event.GetItem()
1311 self.
flag = self.HitTest(event.GetPoint())[1]
1312 if self.IsValidDropTarget(dropTarget):
1314 if dropTarget !=
None:
1315 self.SelectItem(dropTarget)
1316 self.
OnDrop(dropTarget, self._dragItem)
1317 elif dropTarget ==
None:
1318 self.
OnDrop(dropTarget, self._dragItem)
1327 Debug.msg (4,
"LayerTree.OnDrop(): layer=%s" % \
1328 (self.GetItemText(dragItem)))
1334 if self.GetPyData(newItem)[0][
'type'] ==
'group':
1335 (child, cookie) = self.GetFirstChild(dragItem)
1340 child = self.GetNextChild(old, cookie)[0]
1345 except AttributeError:
1353 self.SelectItem(newItem)
1356 """!Recreate item (needed for OnEndDrag())
1358 Debug.msg (4,
"LayerTree.RecreateItem(): layer=%s" % \
1359 self.GetItemText(dragItem))
1362 checked = self.IsItemChecked(dragItem)
1363 image = self.GetItemImage(dragItem, 0)
1364 text = self.GetItemText(dragItem)
1366 if self.GetPyData(dragItem)[0][
'type'] ==
'command':
1370 newctrl.SetValue(self.GetPyData(dragItem)[0][
'maplayer'].GetCmd(string =
True))
1374 data = self.GetPyData(dragItem)
1376 elif self.GetPyData(dragItem)[0][
'ctrl']:
1378 btnbmp = LMIcons[
"layerOptions"].GetBitmap((16,16))
1379 newctrl = buttons.GenBitmapButton(self, id = wx.ID_ANY, bitmap = btnbmp, size = (24, 24))
1380 newctrl.SetToolTipString(_(
"Click to edit layer settings"))
1382 data = self.GetPyData(dragItem)
1384 elif self.GetPyData(dragItem)[0][
'type'] ==
'group':
1390 if dropTarget !=
None and dropTarget != self.GetRootItem():
1396 afteritem = dropTarget
1399 if self.GetPyData(afteritem)[0][
'type'] ==
'group':
1400 newItem = self.PrependItem(afteritem, text = text, \
1401 ct_type = 1, wnd = newctrl, image = image, \
1403 self.Expand(afteritem)
1406 newparent = self.GetItemParent(afteritem)
1407 newItem = self.InsertItem(newparent, self.GetPrevSibling(afteritem), \
1408 text = text, ct_type = 1, wnd = newctrl, \
1409 image = image, data = data)
1412 if self.
flag & wx.TREE_HITTEST_ABOVE:
1413 newItem = self.PrependItem(self.
root, text = text, \
1414 ct_type = 1, wnd = newctrl, image = image, \
1416 elif (self.
flag & wx.TREE_HITTEST_BELOW)
or (self.
flag & wx.TREE_HITTEST_NOWHERE) \
1417 or (self.
flag & wx.TREE_HITTEST_TOLEFT)
or (self.
flag & wx.TREE_HITTEST_TORIGHT):
1418 newItem = self.AppendItem(self.
root, text = text, \
1419 ct_type = 1, wnd = newctrl, image = image, \
1423 self.SetPyData(newItem, self.GetPyData(dragItem))
1425 self.GetPyData(newItem)[0][
'ctrl'] = newctrl.GetId()
1427 self.GetPyData(newItem)[0][
'ctrl'] =
None
1430 self.CheckItem(newItem, checked = checked)
1434 def _getLayerName(self, item, lname = ''):
1435 """!Get layer name string
1437 @param lname optional layer name
1439 mapLayer = self.GetPyData(item)[0][
'maplayer']
1441 lname = self.GetPyData(item)[0][
'label']
1442 opacity = int(mapLayer.GetOpacity(float =
True) * 100)
1444 dcmd = self.GetPyData(item)[0][
'cmd']
1446 fullyQualified =
True)
1451 return lname +
' (%s %d' % (_(
'opacity:'), opacity) +
'%)'
1456 """!Process layer data (when changes in propertiesdialog are applied)"""
1459 self.GetPyData(layer)[0][
'cmd'] = dcmd
1462 mapLayer = self.GetPyData(layer)[0][
'maplayer']
1463 self.SetItemText(layer, mapName)
1465 if not mapText
or not found:
1467 GWarning(parent = self,
1468 message = _(
"Map <%s> not found.") % mapName)
1473 self.SetPyData(layer, (self.GetPyData(layer)[0], params))
1474 self.GetPyData(layer)[0][
'propwin'] = propwin
1480 if dcmd
and UserSettings.Get(group =
'display', key =
'autoZooming', subkey =
'enabled'):
1481 mapLayer = self.GetPyData(layer)[0][
'maplayer']
1482 if mapLayer.GetType()
in (
'raster',
'vector'):
1483 render = UserSettings.Get(group =
'display', key =
'autoRendering', subkey =
'enabled')
1484 self.mapdisplay.MapWindow.ZoomToMap(layers = [mapLayer,],
1488 if self.lmgr.IsPaneShown(
'toolbarNviz')
and dcmd:
1489 mapLayer = self.GetPyData(layer)[0][
'maplayer']
1490 mapWin = self.mapdisplay.MapWindow
1491 if len(mapLayer.GetCmd()) > 0:
1493 if mapLayer.type ==
'raster':
1494 if mapWin.IsLoaded(layer):
1495 mapWin.UnloadRaster(layer)
1497 mapWin.LoadRaster(layer)
1499 elif mapLayer.type ==
'3d-raster':
1500 if mapWin.IsLoaded(layer):
1501 mapWin.UnloadRaster3d(layer)
1503 mapWin.LoadRaster3d(layer)
1505 elif mapLayer.type ==
'vector':
1506 if mapWin.IsLoaded(layer):
1507 mapWin.UnloadVector(layer)
1509 mapWin.LoadVector(layer)
1512 nlayers = len(mapWin.Map.GetListOfLayers(l_type = (
'raster',
'3d-raster',
'vector'),
1518 """!Add commands from data associated with any valid layers
1519 (checked or not) to layer list in order to match layers in
1525 vislayer = self.GetFirstVisibleItem()
1527 if not vislayer
or self.GetPyData(vislayer)
is None:
1532 for item
in range(self.GetCount()):
1533 itemList += self.GetItemText(vislayer) +
','
1534 if self.GetPyData(vislayer)[0][
'type'] !=
'group':
1535 treelayers.append(self.GetPyData(vislayer)[0][
'maplayer'])
1537 if not self.GetNextVisible(vislayer):
1540 vislayer = self.GetNextVisible(vislayer)
1542 Debug.msg (4,
"LayerTree.ReorderLayers(): items=%s" % \
1546 treelayers.reverse()
1547 self.Map.ReorderLayers(treelayers)
1552 type = self.GetPyData(item)[0][
'type']
1555 if type ==
'command':
1556 win = self.FindWindowById(self.GetPyData(item)[0][
'ctrl'])
1557 if win.GetValue() !=
None:
1558 cmd = win.GetValue().
split(
';')
1561 cmdlist.append(c.split(
' '))
1563 chk = self.IsItemChecked(item)
1564 hidden =
not self.IsVisible(item)
1565 elif type !=
'group':
1566 if self.GetPyData(item)[0]
is not None:
1567 cmdlist = self.GetPyData(item)[0][
'cmd']
1568 opac = self.GetPyData(item)[0][
'maplayer'].GetOpacity(float =
True)
1569 chk = self.IsItemChecked(item)
1570 hidden =
not self.IsVisible(item)
1574 layerName = self.GetItemText(item)
1576 maplayer = self.Map.ChangeLayer(layer = self.GetPyData(item)[0][
'maplayer'], type = type,
1577 command = cmdlist, name = layerName,
1578 l_active = chk, l_hidden = hidden, l_opacity = opac, l_render =
False)
1580 self.GetPyData(item)[0][
'maplayer'] = maplayer
1583 if self.mapdisplay.GetToolbar(
'vdigit'):
1584 self.mapdisplay.GetToolbar(
'vdigit').UpdateListOfLayers(updateTool =
True)
1594 """!Find item based on key and value (see PyData[0])
1596 @return item instance
1597 @return None not found
1599 item = self.GetFirstChild(self.root)[0]
1600 return self.__FindSubItemByData(item, key, value)
1603 """!Find item by index (starting at 0)
1605 @return item instance
1606 @return None not found
1608 item = self.GetFirstChild(self.
root)[0]
1610 while item
and item.IsOk():
1614 item = self.GetNextVisible(item)
1620 """!Enable/disable items in layer tree"""
1621 item = self.GetFirstChild(self.
root)[0]
1622 while item
and item.IsOk():
1623 mapLayer = self.GetPyData(item)[0][
'maplayer']
1624 if mapLayer
and type == mapLayer.type:
1625 self.EnableItem(item, enable)
1627 item = self.GetNextSibling(item)
1629 def __FindSubItemByData(self, item, key, value):
1630 """!Support method for FindItemByValue"""
1631 while item
and item.IsOk():
1633 itemValue = self.GetPyData(item)[0][key]
1637 if value == itemValue:
1639 if self.GetPyData(item)[0][
'type'] ==
'group':
1640 subItem = self.GetFirstChild(item)[0]
1644 item = self.GetNextSibling(item)
1648 def _createCommandCtrl(self):
1649 """!Creates text control for command layer"""
1651 if sys.platform
in (
'win32',
'darwin'):
1653 ctrl = wx.TextCtrl(self, id = wx.ID_ANY, value =
'',
1654 size = (self.GetSize()[0]-100, height),
1655 style = wx.TE_PROCESS_ENTER | wx.TE_DONTWRAP)