~ubuntu-branches/ubuntu/vivid/grass/vivid-proposed

« back to all changes in this revision

Viewing changes to gui/wxpython/lmgr/layertree.py

  • Committer: Package Import Robot
  • Author(s): Bas Couwenberg
  • Date: 2015-02-20 23:12:08 UTC
  • mfrom: (8.2.6 experimental)
  • Revision ID: package-import@ubuntu.com-20150220231208-1u6qvqm84v430b10
Tags: 7.0.0-1~exp1
* New upstream release.
* Update python-ctypes-ternary.patch to use if/else instead of and/or.
* Drop check4dev patch, rely on upstream check.
* Add build dependency on libpq-dev to grass-dev for libpq-fe.h.
* Drop patches applied upstream, refresh remaining patches.
* Update symlinks for images switched from jpg to png.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
"""!
 
1
"""
2
2
@package lmgr.layertree
3
3
 
4
4
@brief Utility classes for map layer management.
6
6
Classes:
7
7
 - layertree::LayerTree
8
8
 
9
 
(C) 2007-2013 by the GRASS Development Team
 
9
(C) 2007-2014 by the GRASS Development Team
10
10
 
11
11
This program is free software under the GNU General Public License
12
12
(>=v2). Read the file COPYING that comes with GRASS for details.
31
31
from grass.script import core as grass
32
32
from grass.script import vector as gvector
33
33
 
34
 
from core                import globalvar
35
 
from gui_core.dialogs    import SetOpacityDialog, EVT_APPLY_OPACITY
36
 
from gui_core.forms      import GUI
37
 
from mapdisp.frame       import MapFrame
38
 
from core.render         import Map
39
 
from modules.histogram   import HistogramFrame
40
 
from core.utils          import GetLayerNameFromCmd
41
 
from wxplot.profile      import ProfileFrame
42
 
from core.debug          import Debug
43
 
from core.settings       import UserSettings
44
 
from core.gcmd           import GWarning
45
 
from gui_core.toolbars   import BaseIcons
46
 
from icons.icon          import MetaIcon
 
34
from core                 import globalvar
 
35
from gui_core.dialogs     import SqlQueryFrame, SetOpacityDialog, TextEntryDialog
 
36
from gui_core.forms       import GUI
 
37
from mapdisp.frame        import MapFrame
 
38
from core.render          import Map
 
39
from wxplot.histogram     import HistogramPlotFrame
 
40
from core.utils           import GetLayerNameFromCmd, ltype2command, _
 
41
from wxplot.profile       import ProfileFrame
 
42
from core.debug           import Debug
 
43
from core.settings        import UserSettings, GetDisplayVectSettings
 
44
from vdigit.main          import haveVDigit
 
45
from core.gcmd            import GWarning, GError, RunCommand
 
46
from icons.icon           import MetaIcon
 
47
from web_services.dialogs import SaveWMSLayerDialog
 
48
from gui_core.widgets import GenericValidator
 
49
from lmgr.giface import LayerManagerGrassInterfaceForMapDisplay
 
50
from core.giface import Notification
47
51
 
48
52
TREE_ITEM_HEIGHT = 25
49
53
 
52
56
                            label = _('Import raster data')),
53
57
    'rastLink'   : MetaIcon(img = 'layer-import',
54
58
                            label = _('Link external raster data')),
 
59
    'rastUnpack' : MetaIcon(img = 'layer-import',
 
60
                            label = _('Unpack raster map')),
55
61
    'rastOut'    : MetaIcon(img = 'layer-export',
56
62
                            label = _('Set raster output format')),
57
63
    'vectImport' : MetaIcon(img = 'layer-import',
58
64
                            label = _('Import vector data')),
59
65
    'vectLink'   : MetaIcon(img = 'layer-import',
60
66
                                    label = _('Link external vector data')),
 
67
    'vectUnpack' : MetaIcon(img = 'layer-import',
 
68
                            label = _('Unpack vector map')),
61
69
    'vectOut'    : MetaIcon(img = 'layer-export',
62
70
                            label = _('Set vector output format')),
63
 
    'addCmd'     : MetaIcon(img = 'layer-command-add',
 
71
    'wmsImport'  : MetaIcon(img = 'layer-wms-add',
 
72
                            label = _('Import data from WMS server')),
 
73
    'layerCmd'     : MetaIcon(img = 'layer-command-add',
64
74
                            label = _('Add command layer')),
65
75
    'quit'       : MetaIcon(img = 'quit',
66
76
                            label = _('Quit')),
67
 
    'addRgb'     : MetaIcon(img = 'layer-rgb-add',
 
77
    'layerRaster'    : MetaIcon(img = 'raster',
 
78
                            label = _('Add raster map layer')),
 
79
    'layerRgb'     : MetaIcon(img = 'rgb',
68
80
                            label = _('Add RGB map layer')),
69
 
    'addHis'     : MetaIcon(img = 'layer-his-add',
 
81
    'layerHis'     : MetaIcon(img = 'his',
70
82
                                    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',
 
83
    'layerShaded'  : MetaIcon(img = 'shaded-relief',
 
84
                              label = _('Add shaded relief map layer')),
 
85
    'layerRastarrow'  : MetaIcon(img = 'aspect-arrow',
74
86
                            label = _('Add raster flow arrows')),
75
 
    'addRNum'    : MetaIcon(img = 'layer-cell-cats-add',
 
87
    'layerRastnum'    : MetaIcon(img = 'cell-cats',
76
88
                            label = _('Add raster cell numbers')),
77
 
    'addThematic': MetaIcon(img = 'layer-vector-thematic-add',
 
89
    'layerVector'    : MetaIcon(img = 'vector',
 
90
                            label = _('Add vector map layer')),
 
91
    'layerThememap': MetaIcon(img = 'vector-thematic',
78
92
                            label = _('Add thematic area (choropleth) map layer')),
79
 
    'addChart'   : MetaIcon(img = 'layer-vector-chart-add',
 
93
    'layerThemechart'   : MetaIcon(img = 'vector-chart',
80
94
                            label = _('Add thematic chart layer')),
81
 
    'addGrid'    : MetaIcon(img = 'layer-grid-add',
 
95
    'layerGrid'    : MetaIcon(img = 'layer-grid-add',
82
96
                            label = _('Add grid layer')),
83
 
    'addGeodesic': MetaIcon(img = 'shortest-distance',
 
97
    'layerGeodesic': MetaIcon(img = 'shortest-distance',
84
98
                            label = _('Add geodesic line layer')),
85
 
    'addRhumb'   : MetaIcon(img = 'shortest-distance',
 
99
    'layerRhumb'   : MetaIcon(img = 'shortest-distance',
86
100
                            label = _('Add rhumbline layer')),
87
 
    'addLabels'  : MetaIcon(img = 'layer-label-add',
 
101
    'layerLabels'  : MetaIcon(img = 'label',
88
102
                            label = _('Add labels')),
89
 
    'addRast3d'  : MetaIcon(img = 'layer-raster3d-add',
 
103
    'layer3d-raster'  : MetaIcon(img = 'raster3d',
90
104
                            label = _('Add 3D raster map layer'),
91
105
                            desc  =  _('Note that 3D raster data are rendered only in 3D view mode')),
 
106
    'layerWms'      :  MetaIcon(img = 'wms',
 
107
                            label = _('Add WMS layer.')),
92
108
    'layerOptions'  : MetaIcon(img = 'options',
93
109
                               label = _('Set options')),
 
110
    'layerEdited'     : MetaIcon(img = 'layer-edit',
 
111
                               label = _("Editing mode")),
 
112
    'layerBgmap'     : MetaIcon(img = 'layer-bottom',
 
113
                               label = _("Background vector map"))
94
114
    }
95
115
 
96
116
class LayerTree(treemixin.DragAndDrop, CT.CustomTreeCtrl):
97
 
    """!Creates layer tree structure
 
117
    """Creates layer tree structure
98
118
    """
99
 
    def __init__(self, parent,
 
119
    def __init__(self, parent, giface,
100
120
                 id = wx.ID_ANY, style = wx.SUNKEN_BORDER,
101
121
                 ctstyle = CT.TR_HAS_BUTTONS | CT.TR_HAS_VARIABLE_ROW_HEIGHT |
102
122
                 CT.TR_HIDE_ROOT | CT.TR_ROW_LINES | CT.TR_FULL_ROW_HIGHLIGHT |
105
125
        if 'style' in kwargs:
106
126
            ctstyle |= kwargs['style']
107
127
            del kwargs['style']
108
 
        self.disp_idx = kwargs['idx']
 
128
        self.displayIndex = kwargs['idx']
109
129
        del kwargs['idx']
110
130
        self.lmgr = kwargs['lmgr']
111
131
        del kwargs['lmgr']
112
132
        self.notebook = kwargs['notebook']   # GIS Manager notebook for layer tree
113
133
        del kwargs['notebook']
114
 
        self.auimgr = kwargs['auimgr']       # aui manager
115
 
        del kwargs['auimgr']
116
134
        showMapDisplay = kwargs['showMapDisplay']
117
135
        del kwargs['showMapDisplay']
 
136
 
 
137
        self._giface = giface
118
138
        self.treepg = parent                 # notebook page holding layer tree
119
139
        self.Map = Map()                     # instance of render.Map to be associated with display
120
140
        self.root = None                     # ID of layer tree root node
121
141
        self.groupnode = 0                   # index value for layers
122
142
        self.optpage = {}                    # dictionary of notebook option pages for each map layer
123
 
        self.layer_selected = None           # ID of currently selected layer
124
143
        self.saveitem = {}                   # dictionary to preserve layer attributes for drag and drop
125
144
        self.first = True                    # indicates if a layer is just added or not
126
145
        self.flag = ''                       # flag for drag and drop hittest
127
 
        self.rerender = False                # layer change requires a rerendering if auto render
128
 
        self.reorder = False                 # layer change requires a reordering
 
146
        # layer change requires a rerendering
 
147
        # (used to request rendering only when layer changes are finished)
 
148
        self.rerender = False
129
149
        self.hitCheckbox = False             # if cursor points at layer checkbox (to cancel selection changes)
130
150
        self.forceCheck = False              # force check layer if CheckItem is called
131
151
        
139
159
        else:
140
160
            super(LayerTree, self).__init__(parent, id, style = ctstyle, **kwargs)
141
161
        self.SetName("LayerTree")
 
162
        self.SetBackgroundColour("white")
142
163
        
143
164
        ### SetAutoLayout() causes that no vertical scrollbar is displayed
144
165
        ### when some layers are not visible in layer tree
148
169
        self._setGradient()
149
170
        
150
171
        # init associated map display
151
 
        pos = wx.Point((self.disp_idx + 1) * 25, (self.disp_idx + 1) * 25)
152
 
        self.mapdisplay = MapFrame(self,
 
172
        pos = wx.Point((self.displayIndex + 1) * 25, (self.displayIndex + 1) * 25)
 
173
        self._gifaceForDisplay = LayerManagerGrassInterfaceForMapDisplay(self._giface,
 
174
                                                                         self)
 
175
        self.mapdisplay = MapFrame(self, giface=self._gifaceForDisplay,
153
176
                                   id = wx.ID_ANY, pos = pos,
154
177
                                   size = globalvar.MAP_WINDOW_SIZE,
155
178
                                   style = wx.DEFAULT_FRAME_STYLE,
156
 
                                   tree = self, notebook = self.notebook,
 
179
                                   tree=self, notebook=self.notebook,
157
180
                                   lmgr = self.lmgr, page = self.treepg,
158
 
                                   Map = self.Map, auimgr = self.auimgr)
 
181
                                   Map = self.Map)
159
182
        
160
 
        # title
161
 
        self.mapdisplay.SetTitle(_("GRASS GIS %(version)s Map Display: %(id)d  - Location: %(loc)s") % \
162
 
                                     { 'version' : grass.version()['version'],
163
 
                                       'id' : self.disp_idx + 1,
164
 
                                       'loc' : grass.gisenv()["LOCATION_NAME"] })
 
183
        self.mapdisplay.SetTitleNumber(self.displayIndex + 1)
165
184
        
166
185
        # show new display
167
186
        if showMapDisplay is True:
173
192
        self.SetPyData(self.root, (None, None))
174
193
        
175
194
        # create image list to use with layer tree
 
195
        self.bmpsize = (16, 16)
176
196
        il = wx.ImageList(16, 16, mask = False)
177
 
        
178
 
        trart = wx.ArtProvider.GetBitmap(wx.ART_FOLDER_OPEN, wx.ART_OTHER, (16, 16))
 
197
        trart = wx.ArtProvider.GetBitmap(wx.ART_FILE_OPEN, wx.ART_OTHER, (16, 16))
179
198
        self.folder_open = il.Add(trart)
180
199
        trart = wx.ArtProvider.GetBitmap(wx.ART_FOLDER, wx.ART_OTHER, (16, 16))
181
200
        self.folder = il.Add(trart)
182
 
        
183
 
        bmpsize = (16, 16)
184
 
        trgif = BaseIcons["addRast"].GetBitmap(bmpsize)
185
 
        self.rast_icon = il.Add(trgif)
186
 
        
187
 
        trgif = LMIcons["addRast3d"].GetBitmap(bmpsize)
188
 
        self.rast3d_icon = il.Add(trgif)
189
 
        
190
 
        trgif = LMIcons["addRgb"].GetBitmap(bmpsize)
191
 
        self.rgb_icon = il.Add(trgif)
192
 
        
193
 
        trgif = LMIcons["addHis"].GetBitmap(bmpsize)
194
 
        self.his_icon = il.Add(trgif)
195
 
        
196
 
        trgif = LMIcons["addShaded"].GetBitmap(bmpsize)
197
 
        self.shaded_icon = il.Add(trgif)
198
 
        
199
 
        trgif = LMIcons["addRArrow"].GetBitmap(bmpsize)
200
 
        self.rarrow_icon = il.Add(trgif)
201
 
        
202
 
        trgif = LMIcons["addRNum"].GetBitmap(bmpsize)
203
 
        self.rnum_icon = il.Add(trgif)
204
 
        
205
 
        trgif = BaseIcons["addVect"].GetBitmap(bmpsize)
206
 
        self.vect_icon = il.Add(trgif)
207
 
        
208
 
        trgif = LMIcons["addThematic"].GetBitmap(bmpsize)
209
 
        self.theme_icon = il.Add(trgif)
210
 
        
211
 
        trgif = LMIcons["addChart"].GetBitmap(bmpsize)
212
 
        self.chart_icon = il.Add(trgif)
213
 
        
214
 
        trgif = LMIcons["addGrid"].GetBitmap(bmpsize)
215
 
        self.grid_icon = il.Add(trgif)
216
 
        
217
 
        trgif = LMIcons["addGeodesic"].GetBitmap(bmpsize)
218
 
        self.geodesic_icon = il.Add(trgif)
219
 
        
220
 
        trgif = LMIcons["addRhumb"].GetBitmap(bmpsize)
221
 
        self.rhumb_icon = il.Add(trgif)
222
 
        
223
 
        trgif = LMIcons["addLabels"].GetBitmap(bmpsize)
224
 
        self.labels_icon = il.Add(trgif)
225
 
        
226
 
        trgif = LMIcons["addCmd"].GetBitmap(bmpsize)
227
 
        self.cmd_icon = il.Add(trgif)
228
 
        
 
201
        self._setIcons(il)
229
202
        self.AssignImageList(il)
230
 
        
231
 
        self.Bind(wx.EVT_TREE_ITEM_EXPANDING,   self.OnExpandNode)
232
 
        self.Bind(wx.EVT_TREE_ITEM_COLLAPSED,   self.OnCollapseNode)
 
203
 
233
204
        self.Bind(wx.EVT_TREE_ITEM_ACTIVATED,   self.OnActivateLayer)
234
205
        self.Bind(wx.EVT_TREE_SEL_CHANGED,      self.OnChangeSel)
235
206
        self.Bind(wx.EVT_TREE_SEL_CHANGING,     self.OnChangingSel)
240
211
        self.Bind(wx.EVT_TREE_END_DRAG,         self.OnEndDrag)
241
212
        self.Bind(wx.EVT_TREE_END_LABEL_EDIT,   self.OnRenamed)
242
213
        self.Bind(wx.EVT_KEY_UP,                self.OnKeyUp)
 
214
        self.Bind(wx.EVT_KEY_DOWN,                self.OnKeyDown)
243
215
        self.Bind(wx.EVT_IDLE,                  self.OnIdle)
244
216
        self.Bind(wx.EVT_MOTION,                self.OnMotion)
245
217
 
 
218
    def _setIcons(self, il):
 
219
        self._icon = {}
 
220
        for iconName in ("layerRaster", "layer3d-raster", "layerRgb",
 
221
                         "layerHis", "layerShaded", "layerRastarrow",
 
222
                         "layerRastnum", "layerVector", "layerThememap",
 
223
                         "layerThemechart", "layerGrid", "layerGeodesic",
 
224
                         "layerRhumb", "layerLabels", "layerCmd",
 
225
                         "layerWms", "layerEdited", "layerBgmap"):
 
226
            iconKey = iconName[len("layer"):].lower()
 
227
            icon = LMIcons[iconName].GetBitmap(self.bmpsize)
 
228
            self._icon[iconKey] = il.Add(icon)
 
229
            
 
230
    def _getSelectedLayer(self):
 
231
        """Get selected layer.
 
232
 
 
233
        :return: None if no layer selected
 
234
        :return: first layer (GenericTreeItem instance) of all selected
 
235
        """
 
236
        return self.GetSelectedLayer(multi = False, checkedOnly = False)
 
237
 
 
238
    # for compatibility
 
239
    layer_selected = property(fget = _getSelectedLayer)
 
240
 
 
241
    def GetSelectedLayers(self, checkedOnly = False):
 
242
        """Get selected layers as a list.
 
243
 
 
244
        .. todo::
 
245
            somewhere we have checkedOnly default True and elsewhere False
 
246
        """
 
247
        return self.GetSelectedLayer(multi = True, checkedOnly = checkedOnly)
 
248
 
 
249
    def GetSelectedLayer(self, multi = False, checkedOnly = False):
 
250
        """Get selected layer from layer tree.
 
251
        
 
252
        :param bool multi: return multiple selection as a list
 
253
        :param bool checkedOnly: return only the checked layers
 
254
 
 
255
        :return: None or [] for multi == True if no layer selected 
 
256
        :return: first layer (GenericTreeItem instance) of all selected or a list
 
257
        """
 
258
        ret = []
 
259
        layers = self.GetSelections()
 
260
 
 
261
        for layer in layers:
 
262
            if not checkedOnly or (checkedOnly and layer.IsChecked()):
 
263
                ret.append(layer)
 
264
        if multi:
 
265
            return ret
 
266
 
 
267
        if ret:
 
268
            return ret[0]
 
269
 
 
270
        return None
 
271
 
 
272
    def GetNextItem(self, item):
 
273
        """!Returns next item from tree (flattened expanded tree)"""
 
274
        # this is a not empty group
 
275
        if self.GetChildrenCount(item):
 
276
                return self.GetFirstChild(item)[0]
 
277
        # this is a layer outside group
 
278
        if self.GetItemParent(item) == self.root:
 
279
            return self.GetNextSibling(item)
 
280
 
 
281
        # this is a layer inside group
 
282
        sibling = self.GetNextSibling(item)
 
283
        if sibling:
 
284
            # this is a layer inside group
 
285
            return sibling
 
286
        # skip one up the hierarchy
 
287
        return self.GetNextSibling(self.GetItemParent(item))
 
288
 
 
289
    def SetItemIcon(self, item, iconName=None):
 
290
        if not iconName:
 
291
            iconName = self.GetLayerInfo(item, key = 'maplayer').GetType()
 
292
        self.SetItemImage(item, self._icon[iconName])
 
293
        
246
294
    def _setGradient(self, iType = None):
247
 
        """!Set gradient for items
 
295
        """Set gradient for items
248
296
 
249
 
        @param iType bgmap, vdigit or None
 
297
        :param iType: bgmap, vdigit or None
250
298
        """
251
299
        if iType == 'bgmap':
252
300
            self.SetFirstGradientColour(wx.Colour(0, 100, 0))
275
323
        return array
276
324
 
277
325
    def GetMap(self):
278
 
        """!Get map instace"""
 
326
        """Get map instace"""
279
327
        return self.Map
280
328
    
281
329
    def GetMapDisplay(self):
282
 
        """!Get associated MapFrame"""
 
330
        """Get associated MapFrame"""
283
331
        return self.mapdisplay
284
 
    
 
332
 
 
333
    def GetLayerInfo(self, layer, key = None):
 
334
        """Get layer info.
 
335
 
 
336
        :param layer: GenericTreeItem instance
 
337
        :param key: cmd, type, ctrl, label, maplayer, propwin, vdigit, nviz
 
338
         (vdigit, nviz for map layers only)
 
339
        """
 
340
        if not self.GetPyData(layer):
 
341
            return None
 
342
        if key:
 
343
            return self.GetPyData(layer)[0][key]
 
344
        return self.GetPyData(layer)[0]
 
345
 
 
346
    def SetLayerInfo(self, layer, key, value):
 
347
        """Set layer info.
 
348
 
 
349
        :param layer: GenericTreeItem instance
 
350
        :param key: cmd, type, ctrl, label, maplayer, propwin, vdigit, nviz
 
351
         (vdigit, nviz for map layers only)
 
352
        :param value: value
 
353
        """
 
354
        info = self.GetPyData(layer)[0]
 
355
        info[key] = value
 
356
 
 
357
    def GetLayerParams(self, layer):
 
358
        """Get layer command params"""
 
359
        return self.GetPyData(layer)[1]
 
360
 
285
361
    def OnIdle(self, event):
286
 
        """!Only re-order and re-render a composite map image from GRASS during
 
362
        """Only re-order and re-render a composite map image from GRASS during
287
363
        idle time instead of multiple times during layer changing.
288
364
        """
 
365
        # no need to check for digitizer since it is handled internaly
 
366
        # no need to distinguish 2D and 3D since the interface is the same
 
367
        # remove this comment when it is onl enough
289
368
        if self.rerender:
290
 
            if self.mapdisplay.GetToolbar('vdigit'):
291
 
                vector = True
292
 
            else:
293
 
                vector = False
 
369
            # restart rerender value here before wx.Yield
 
370
            # can cause another idle event
 
371
            self.rerender = False
294
372
            if self.mapdisplay.IsAutoRendered():
295
 
                self.mapdisplay.MapWindow2D.UpdateMap(render = True, renderVector = vector)
296
 
                if self.lmgr.IsPaneShown('toolbarNviz'): # nviz
297
 
                    self.mapdisplay.MapWindow3D.UpdateMap(render = True)
298
 
            
299
 
            self.rerender = False
 
373
                self.mapdisplay.GetMapWindow().UpdateMap(render=True)
300
374
        
301
375
        event.Skip()
302
376
        
303
377
    def OnKeyUp(self, event):
304
 
        """!Key pressed"""
 
378
        """Key pressed"""
305
379
        key = event.GetKeyCode()
306
380
        
307
381
        if key == wx.WXK_DELETE and self.lmgr and \
309
383
            self.lmgr.OnDeleteLayer(None)
310
384
        
311
385
        event.Skip()
312
 
        
 
386
 
 
387
    def OnKeyDown(self, event):
 
388
        """Skip event, otherwise causing error when layertree is empty"""
 
389
        event.Skip()
 
390
 
313
391
    def OnLayerContextMenu (self, event):
314
 
        """!Contextual menu for item/layer"""
 
392
        """Contextual menu for item/layer"""
315
393
        if not self.layer_selected:
316
394
            event.Skip()
317
395
            return
318
396
 
319
 
        ltype = self.GetPyData(self.layer_selected)[0]['type']
320
 
        mapLayer = self.GetPyData(self.layer_selected)[0]['maplayer']
 
397
        ltype = self.GetLayerInfo(self.layer_selected, key = 'type')
 
398
        mapLayer = self.GetLayerInfo(self.layer_selected, key = 'maplayer')
321
399
        
322
400
        Debug.msg (4, "LayerTree.OnContextMenu: layertype=%s" % \
323
401
                       ltype)
325
403
        if not hasattr (self, "popupID"):
326
404
            self.popupID = dict()
327
405
            for key in ('remove', 'rename', 'opacity', 'nviz', 'zoom',
328
 
                        'region', 'export', 'attr', 'edit0', 'edit1',
 
406
                        'region', 'export', 'attr', 'edit', 'save_ws',
329
407
                        'bgmap', 'topo', 'meta', 'null', 'zoom1', 'region1',
330
 
                        'color', 'hist', 'univar', 'prof', 'properties'):
 
408
                        'color', 'hist', 'univar', 'prof', 'properties', 'sql', 'copy',
 
409
                        'report', 'export-pg', 'pack'):
331
410
                self.popupID[key] = wx.NewId()
332
411
        
 
412
        # get current mapset
 
413
        currentMapset = grass.gisenv()['MAPSET']
 
414
 
333
415
        self.popupMenu = wx.Menu()
334
 
        
 
416
 
335
417
        numSelected = len(self.GetSelections())
336
418
        
337
 
        self.popupMenu.Append(self.popupID['remove'], text = _("Remove"))
 
419
        item = wx.MenuItem(self.popupMenu, id = self.popupID['remove'], text = _("Remove"))
 
420
        item.SetBitmap(MetaIcon(img = 'layer-remove').GetBitmap(self.bmpsize))
 
421
        self.popupMenu.AppendItem(item)
338
422
        self.Bind(wx.EVT_MENU, self.lmgr.OnDeleteLayer, id = self.popupID['remove'])
339
423
        
340
 
        if ltype != "command":
 
424
        if ltype != "command" and numSelected == 1:
341
425
            self.popupMenu.Append(self.popupID['rename'], text = _("Rename"))
342
426
            self.Bind(wx.EVT_MENU, self.OnRenameLayer, id = self.popupID['rename'])
343
 
            if numSelected > 1:
344
 
                self.popupMenu.Enable(self.popupID['rename'], False)
 
427
 
 
428
        # when multiple maps are selected of different types
 
429
        # we cannot zoom or change region
 
430
        # because g.region can handle only the same type
 
431
        same = True
 
432
        selected = self.GetSelectedLayers()
 
433
        for layer in selected:
 
434
            if self.GetLayerInfo(layer, key='type') != ltype:
 
435
                same = False
 
436
                break
345
437
        
346
438
        # map layer items
347
439
        if ltype not in ("group", "command"):
348
 
            self.popupMenu.AppendSeparator()
349
 
            self.popupMenu.Append(self.popupID['opacity'], text = _("Change opacity level"))
350
 
            self.Bind(wx.EVT_MENU, self.OnPopupOpacityLevel, id = self.popupID['opacity'])
351
 
            self.popupMenu.Append(self.popupID['properties'], text = _("Properties"))
352
 
            self.Bind(wx.EVT_MENU, self.OnPopupProperties, id = self.popupID['properties'])
353
 
            
354
 
            if numSelected > 1:
355
 
                self.popupMenu.Enable(self.popupID['opacity'], False)
356
 
                self.popupMenu.Enable(self.popupID['properties'], False)
357
 
            
358
 
            if ltype in ('raster', 'vector', '3d-raster') and self.lmgr.IsPaneShown('toolbarNviz'):
359
 
                self.popupMenu.Append(self.popupID['nviz'], _("3D view properties"))
360
 
                self.Bind (wx.EVT_MENU, self.OnNvizProperties, id = self.popupID['nviz'])
361
 
            
362
 
            if ltype in ('raster', 'vector', 'rgb'):
363
 
                self.popupMenu.Append(self.popupID['zoom'], text = _("Zoom to selected map(s)"))
 
440
            if numSelected == 1:
 
441
                self.popupMenu.AppendSeparator()
 
442
                if ltype != '3d-raster':
 
443
                    item = wx.MenuItem(self.popupMenu, id = self.popupID['opacity'], text=_("Change opacity level"))
 
444
                    item.SetBitmap(MetaIcon(img = 'layer-opacity').GetBitmap(self.bmpsize))
 
445
                    self.popupMenu.AppendItem(item)
 
446
                    self.Bind(wx.EVT_MENU, self.OnPopupOpacityLevel, id=self.popupID['opacity'])
 
447
                item = wx.MenuItem(self.popupMenu, id = self.popupID['properties'], text = _("Properties"))
 
448
                item.SetBitmap(MetaIcon(img = 'options').GetBitmap(self.bmpsize))
 
449
                self.popupMenu.AppendItem(item)
 
450
                self.Bind(wx.EVT_MENU, self.OnPopupProperties, id = self.popupID['properties'])
 
451
            
 
452
                if ltype in ('raster', 'vector', '3d-raster') and self.mapdisplay.IsPaneShown('3d'):
 
453
                    self.popupMenu.Append(self.popupID['nviz'], _("3D view properties"))
 
454
                    self.Bind (wx.EVT_MENU, self.OnNvizProperties, id = self.popupID['nviz'])
 
455
 
 
456
            if same and ltype in ('raster', 'vector', 'rgb', '3d-raster'):
 
457
                self.popupMenu.AppendSeparator()
 
458
                item = wx.MenuItem(self.popupMenu, id = self.popupID['zoom'], text = _("Zoom to selected map(s)"))
 
459
                item.SetBitmap(MetaIcon(img = 'zoom-layer').GetBitmap(self.bmpsize))
 
460
                self.popupMenu.AppendItem(item)
364
461
                self.Bind(wx.EVT_MENU, self.mapdisplay.OnZoomToMap, id = self.popupID['zoom'])
365
 
                self.popupMenu.Append(self.popupID['region'], text = _("Set computational region from selected map(s)"))
 
462
                
 
463
                item = wx.MenuItem(self.popupMenu, id = self.popupID['region'], text = _("Set computational region from selected map(s)"))
 
464
                item.SetBitmap(MetaIcon(img = 'region').GetBitmap(self.bmpsize))
 
465
                self.popupMenu.AppendItem(item)
366
466
                self.Bind(wx.EVT_MENU, self.OnSetCompRegFromMap, id = self.popupID['region'])
367
467
        
368
468
        # specific items
369
469
        try:
370
 
            mltype = self.GetPyData(self.layer_selected)[0]['type']
 
470
            mltype = self.GetLayerInfo(self.layer_selected, key = 'type')
371
471
        except:
372
472
            mltype = None
373
473
        
374
474
        # vector layers (specific items)
375
 
        if mltype and mltype == "vector":
 
475
        if mltype and mltype == "vector" and numSelected == 1:
376
476
            self.popupMenu.AppendSeparator()
377
 
            self.popupMenu.Append(self.popupID['export'], text = _("Export"))
 
477
            item = wx.MenuItem(self.popupMenu, id = self.popupID['export'], text = _("Export common formats"))
 
478
            item.SetBitmap(MetaIcon(img = 'layer-export').GetBitmap(self.bmpsize))
 
479
            self.popupMenu.AppendItem(item)
378
480
            self.Bind(wx.EVT_MENU, lambda x: self.lmgr.OnMenuCmd(cmd = ['v.out.ogr',
379
481
                                                                        'input=%s' % mapLayer.GetName()]),
380
482
                      id = self.popupID['export'])
 
483
            if 'v.out.ogr' not in globalvar.grassCmd:
 
484
                self.popupMenu.Enable(self.popupID['export'], False)
 
485
 
 
486
            self.popupMenu.Append(self.popupID['export-pg'], text = _("Export PostGIS"))
 
487
            self.Bind(wx.EVT_MENU, lambda x: self.lmgr.OnMenuCmd(cmd = ['v.out.postgis',
 
488
                                                                        'input=%s' % mapLayer.GetName()]),
 
489
                      id = self.popupID['export-pg'])
 
490
            if 'v.out.postgis' not in globalvar.grassCmd:
 
491
                self.popupMenu.Enable(self.popupID['export-pg'], False)
 
492
 
 
493
            item = wx.MenuItem(self.popupMenu, id = self.popupID['pack'], text = _("Create pack"))
 
494
            self.popupMenu.AppendItem(item)
 
495
            self.Bind(wx.EVT_MENU, lambda x: self.lmgr.OnMenuCmd(cmd = ['v.pack',
 
496
                                                                        'input=%s' % mapLayer.GetName()]),
 
497
                      id = self.popupID['pack'])
 
498
            
 
499
            lmapset = self.GetLayerInfo(self.layer_selected, key = 'maplayer').GetMapset()
 
500
            if lmapset != currentMapset:
 
501
                self.popupMenu.Append(self.popupID['copy'], text = _("Make a copy in the current mapset"))
 
502
                self.Bind(wx.EVT_MENU, self.OnCopyMap, id = self.popupID['copy'])
381
503
            
382
504
            self.popupMenu.AppendSeparator()
383
505
 
384
506
            self.popupMenu.Append(self.popupID['color'], _("Set color table"))
385
507
            self.Bind (wx.EVT_MENU, self.OnVectorColorTable, id = self.popupID['color'])
386
508
 
387
 
            self.popupMenu.Append(self.popupID['attr'], text = _("Show attribute data"))
 
509
            item = wx.MenuItem(self.popupMenu, id = self.popupID['attr'], text = _("Show attribute data"))
 
510
            item.SetBitmap(MetaIcon(img = 'table').GetBitmap(self.bmpsize))
 
511
            self.popupMenu.AppendItem(item)
388
512
            self.Bind(wx.EVT_MENU, self.lmgr.OnShowAttributeTable, id = self.popupID['attr'])
389
513
 
390
 
            self.popupMenu.Append(self.popupID['edit0'], text = _("Start editing"))
391
 
            self.popupMenu.Append(self.popupID['edit1'], text = _("Stop editing"))
392
 
            self.popupMenu.Enable(self.popupID['edit1'], False)
393
 
            self.Bind (wx.EVT_MENU, self.OnStartEditing, id = self.popupID['edit0'])
394
 
            self.Bind (wx.EVT_MENU, self.OnStopEditing,  id = self.popupID['edit1'])
395
 
            
396
 
            layer = self.GetPyData(self.layer_selected)[0]['maplayer']
397
 
            # enable editing only for vector map layers available in the current mapset
398
514
            digitToolbar = self.mapdisplay.GetToolbar('vdigit')
399
515
            if digitToolbar:
 
516
                vdigitLayer = digitToolbar.GetLayer()
 
517
            else:
 
518
                vdigitLayer = None
 
519
            layer = self.GetLayerInfo(self.layer_selected, key = 'maplayer')
 
520
            if vdigitLayer is not layer:
 
521
                item = wx.MenuItem(self.popupMenu, id = self.popupID['edit'], text = _("Start editing"))
 
522
                self.Bind (wx.EVT_MENU, self.OnStartEditing, id = self.popupID['edit'])
 
523
            else:
 
524
                item = wx.MenuItem(self.popupMenu, id = self.popupID['edit'], text = _("Stop editing"))
 
525
                self.Bind (wx.EVT_MENU, self.OnStopEditing,  id = self.popupID['edit'])
 
526
            item.SetBitmap(MetaIcon(img = 'edit').GetBitmap(self.bmpsize))
 
527
            self.popupMenu.AppendItem(item)
 
528
            
 
529
            ### removed from layer tree
 
530
            #  if digitToolbar:
400
531
                # background vector map
401
 
                self.popupMenu.Append(self.popupID['bgmap'],
402
 
                                      text = _("Use as background vector map for digitizer"),
403
 
                                      kind = wx.ITEM_CHECK)
404
 
                self.Bind(wx.EVT_MENU, self.OnSetBgMap, id = self.popupID['bgmap'])
405
 
                if UserSettings.Get(group = 'vdigit', key = 'bgmap', subkey = 'value',
406
 
                                    internal = True) == layer.GetName():
407
 
                    self.popupMenu.Check(self.popupID['bgmap'], True)
 
532
                # self.popupMenu.Append(self.popupID['bgmap'],
 
533
                #                       text = _("Use as background vector map for digitizer"),
 
534
                #                       kind = wx.ITEM_CHECK)
 
535
                # self.Bind(wx.EVT_MENU, self.OnSetBgMap, id = self.popupID['bgmap'])
 
536
                # if UserSettings.Get(group = 'vdigit', key = 'bgmap', subkey = 'value',
 
537
                #                     internal = True) == layer.GetName():
 
538
                #     self.popupMenu.Check(self.popupID['bgmap'], True)
408
539
            
409
540
            self.popupMenu.Append(self.popupID['topo'], text = _("Rebuild topology"))
410
541
            self.Bind(wx.EVT_MENU, self.OnTopology, id = self.popupID['topo'])
 
542
 
 
543
            # determine format
 
544
            # if layer and layer.GetType() == 'vector':
 
545
            #     if 'info' not in self.GetLayerInfo(self.layer_selected):
 
546
            #         info = grass.parse_command('v.info',
 
547
            #                                    flags = 'e',
 
548
            #                                    map = layer.GetName())
 
549
            #         self.SetLayerInfo(self.layer_selected, key = 'info', value = info)
 
550
            #     info = self.GetLayerInfo(self.layer_selected, key = 'info')
 
551
            #     if info and info['format'] != 'native' and \
 
552
            #             info['format'].split(',')[1] == 'PostgreSQL':
 
553
            #         self.popupMenu.Append(self.popupID['sql'], text = _("SQL Spatial Query"))
 
554
            #         self.Bind(wx.EVT_MENU, self.OnSqlQuery, id = self.popupID['sql'])
411
555
            
412
 
            if layer.GetMapset() != grass.gisenv()['MAPSET']:
 
556
            if layer.GetMapset() != currentMapset:
413
557
                # only vector map in current mapset can be edited
414
 
                self.popupMenu.Enable (self.popupID['edit0'], False)
415
 
                self.popupMenu.Enable (self.popupID['edit1'], False)
 
558
                self.popupMenu.Enable (self.popupID['edit'], False)
416
559
                self.popupMenu.Enable (self.popupID['topo'], False)
417
560
            elif digitToolbar and digitToolbar.GetLayer():
418
561
                # vector map already edited
419
562
                vdigitLayer = digitToolbar.GetLayer()
420
563
                if vdigitLayer is layer:
421
 
                    self.popupMenu.Enable(self.popupID['edit0'],  False)
422
 
                    self.popupMenu.Enable(self.popupID['edit1'],  True)
423
564
                    self.popupMenu.Enable(self.popupID['remove'], False)
424
565
                    self.popupMenu.Enable(self.popupID['bgmap'],  False)
425
566
                    self.popupMenu.Enable(self.popupID['topo'],   False)
426
567
                else:
427
 
                    self.popupMenu.Enable(self.popupID['edit0'], False)
428
 
                    self.popupMenu.Enable(self.popupID['edit1'], False)
429
568
                    self.popupMenu.Enable(self.popupID['bgmap'], True)
430
569
            
431
 
            self.popupMenu.Append(self.popupID['meta'], _("Metadata"))
 
570
            item = wx.MenuItem(self.popupMenu, id = self.popupID['meta'], text = _("Metadata"))
 
571
            item.SetBitmap(MetaIcon(img = 'layer-info').GetBitmap(self.bmpsize))
 
572
            self.popupMenu.AppendItem(item)
432
573
            self.Bind (wx.EVT_MENU, self.OnMetadata, id = self.popupID['meta'])
433
 
            if numSelected > 1:
434
 
                self.popupMenu.Enable(self.popupID['attr'],   False)
435
 
                self.popupMenu.Enable(self.popupID['edit0'],  False)
436
 
                self.popupMenu.Enable(self.popupID['edit1'],  False)
437
 
                self.popupMenu.Enable(self.popupID['meta'],   False)
438
 
                self.popupMenu.Enable(self.popupID['bgmap'],  False)
439
 
                self.popupMenu.Enable(self.popupID['topo'],   False)
440
 
                self.popupMenu.Enable(self.popupID['export'], False)
441
574
        
442
575
        # raster layers (specific items)
443
576
        elif mltype and mltype == "raster":
444
 
            self.popupMenu.Append(self.popupID['zoom1'], text = _("Zoom to selected map(s) (ignore NULLs)"))
445
 
            self.Bind(wx.EVT_MENU, self.mapdisplay.OnZoomToRaster, id = self.popupID['zoom1'])
446
 
            self.popupMenu.Append(self.popupID['region1'], text = _("Set computational region from selected map(s) (ignore NULLs)"))
447
 
            self.Bind(wx.EVT_MENU, self.OnSetCompRegFromRaster, id = self.popupID['region1'])
448
 
            
449
 
            self.popupMenu.AppendSeparator()
450
 
            self.popupMenu.Append(self.popupID['export'], text = _("Export"))
451
 
            self.Bind(wx.EVT_MENU, lambda x: self.lmgr.OnMenuCmd(cmd = ['r.out.gdal',
452
 
                                                                        'input=%s' % mapLayer.GetName()]),
453
 
                      id = self.popupID['export'])
454
 
            
455
 
            self.popupMenu.AppendSeparator()
 
577
            if same:
 
578
                self.popupMenu.Append(self.popupID['zoom1'], text=_("Zoom to selected map(s) (ignore NULLs)"))
 
579
                self.Bind(wx.EVT_MENU, self.mapdisplay.OnZoomToRaster, id=self.popupID['zoom1'])
 
580
                self.popupMenu.Append(self.popupID['region1'], text=_("Set computational region from selected map(s) (ignore NULLs)"))
 
581
                self.Bind(wx.EVT_MENU, self.OnSetCompRegFromRaster, id=self.popupID['region1'])
 
582
            
 
583
            self.popupMenu.AppendSeparator()
 
584
            
 
585
            if numSelected == 1:
 
586
                item = wx.MenuItem(self.popupMenu, id = self.popupID['export'], text = _("Export"))
 
587
                item.SetBitmap(MetaIcon(img = 'layer-export').GetBitmap(self.bmpsize))
 
588
                self.popupMenu.AppendItem(item)
 
589
                self.Bind(wx.EVT_MENU, lambda x: self.lmgr.OnMenuCmd(cmd = ['r.out.gdal',
 
590
                                                                            'input=%s' % mapLayer.GetName()]),
 
591
                          id = self.popupID['export'])
 
592
 
 
593
                item = wx.MenuItem(self.popupMenu, id = self.popupID['pack'], text = _("Create pack"))
 
594
                self.popupMenu.AppendItem(item)
 
595
                self.Bind(wx.EVT_MENU, lambda x: self.lmgr.OnMenuCmd(cmd = ['r.pack',
 
596
                                                                            'input=%s' % mapLayer.GetName()]),
 
597
                          id = self.popupID['pack'])
 
598
                
 
599
                lmapset = self.GetLayerInfo(self.layer_selected, key = 'maplayer').GetMapset()
 
600
                if lmapset != currentMapset:
 
601
                    self.popupMenu.Append(self.popupID['copy'], text = _("Make a copy in the current mapset"))
 
602
                    self.Bind(wx.EVT_MENU, self.OnCopyMap, id = self.popupID['copy'])
 
603
                
 
604
                self.popupMenu.AppendSeparator()
 
605
                
456
606
            self.popupMenu.Append(self.popupID['color'], _("Set color table"))
457
607
            self.Bind (wx.EVT_MENU, self.OnRasterColorTable, id = self.popupID['color'])
458
 
            self.popupMenu.Append(self.popupID['hist'], _("Histogram"))
 
608
 
 
609
            item = wx.MenuItem(self.popupMenu, id = self.popupID['hist'], text = _("Histogram"))
 
610
            item.SetBitmap(MetaIcon(img = 'layer-raster-histogram').GetBitmap(self.bmpsize))
 
611
            self.popupMenu.AppendItem(item)
459
612
            self.Bind (wx.EVT_MENU, self.OnHistogram, id = self.popupID['hist'])
460
 
            self.popupMenu.Append(self.popupID['univar'], _("Univariate raster statistics"))
 
613
 
 
614
            item = wx.MenuItem(self.popupMenu, id = self.popupID['univar'], text = _("Univariate raster statistics"))
 
615
            item.SetBitmap(MetaIcon(img = 'raster-stats').GetBitmap(self.bmpsize))
 
616
            self.popupMenu.AppendItem(item)
461
617
            self.Bind (wx.EVT_MENU, self.OnUnivariateStats, id = self.popupID['univar'])
462
 
            self.popupMenu.Append(self.popupID['prof'], _("Profile"))
463
 
            self.Bind (wx.EVT_MENU, self.OnProfile, id = self.popupID['prof'])
464
 
            self.popupMenu.Append(self.popupID['meta'], _("Metadata"))
465
 
            self.Bind (wx.EVT_MENU, self.OnMetadata, id = self.popupID['meta'])
466
 
            
467
 
            if numSelected > 1:
468
 
                self.popupMenu.Enable(self.popupID['zoom1'],   False)
469
 
                self.popupMenu.Enable(self.popupID['region1'], False)
470
 
                self.popupMenu.Enable(self.popupID['color'],   False)
471
 
                self.popupMenu.Enable(self.popupID['hist'],    False)
472
 
                self.popupMenu.Enable(self.popupID['univar'],  False)
473
 
                self.popupMenu.Enable(self.popupID['prof'],    False)
474
 
                self.popupMenu.Enable(self.popupID['meta'],    False)
475
 
                self.popupMenu.Enable(self.popupID['export'],  False)
476
 
                if self.lmgr.IsPaneShown('toolbarNviz'):
477
 
                    self.popupMenu.Enable(self.popupID['nviz'], False)
 
618
 
 
619
            item = wx.MenuItem(self.popupMenu, id = self.popupID['report'], text = _("Report raster statistics"))
 
620
            item.SetBitmap(MetaIcon(img = 'stats').GetBitmap(self.bmpsize))
 
621
            self.popupMenu.AppendItem(item)
 
622
            self.Bind(wx.EVT_MENU, self.OnReportStats, id = self.popupID['report'])
 
623
            
 
624
            if numSelected == 1:
 
625
                item = wx.MenuItem(self.popupMenu, id = self.popupID['prof'], text = _("Profile"))
 
626
                item.SetBitmap(MetaIcon(img = 'layer-raster-profile').GetBitmap(self.bmpsize))
 
627
                self.popupMenu.AppendItem(item)
 
628
                self.Bind (wx.EVT_MENU, self.OnProfile, id = self.popupID['prof'])
 
629
 
 
630
                item = wx.MenuItem(self.popupMenu, id = self.popupID['meta'], text = _("Metadata"))
 
631
                item.SetBitmap(MetaIcon(img = 'layer-info').GetBitmap(self.bmpsize))
 
632
                self.popupMenu.AppendItem(item)
 
633
                self.Bind (wx.EVT_MENU, self.OnMetadata, id = self.popupID['meta'])
 
634
            
 
635
        elif mltype and mltype == '3d-raster':
 
636
            if numSelected == 1:
 
637
                self.popupMenu.AppendSeparator()
 
638
                self.popupMenu.Append(self.popupID['color'], _("Set color table"))
 
639
                self.Bind(wx.EVT_MENU, self.OnRasterColorTable, id=self.popupID['color'])
 
640
                
 
641
                item = wx.MenuItem(self.popupMenu, id = self.popupID['univar'], text = _("Univariate raster statistics"))
 
642
                item.SetBitmap(MetaIcon(img = 'stats').GetBitmap(self.bmpsize))
 
643
                self.popupMenu.AppendItem(item)
 
644
                self.Bind (wx.EVT_MENU, self.OnUnivariateStats, id = self.popupID['univar'])
 
645
                 
 
646
                item = wx.MenuItem(self.popupMenu, id = self.popupID['meta'], text = _("Metadata"))
 
647
                item.SetBitmap(MetaIcon(img = 'layer-info').GetBitmap(self.bmpsize))
 
648
                self.popupMenu.AppendItem(item)
 
649
                self.Bind (wx.EVT_MENU, self.OnMetadata, id = self.popupID['meta'])
 
650
        
 
651
        # web service layers (specific item)
 
652
        elif mltype and mltype == "wms":
 
653
            self.popupMenu.Append(self.popupID['save_ws'], text = _("Save web service layer"))
 
654
            self.Bind(wx.EVT_MENU, self.OnSaveWs, id = self.popupID['save_ws'])
478
655
 
479
656
        self.PopupMenu(self.popupMenu)
480
657
        self.popupMenu.Destroy()
481
 
        
 
658
 
 
659
    def OnSaveWs(self, event):
 
660
        """Show dialog for saving web service layer into GRASS vector/raster layer"""
 
661
        mapLayer = self.GetLayerInfo(self.layer_selected, key = 'maplayer')
 
662
        dlg = SaveWMSLayerDialog(parent=self, layer=mapLayer,
 
663
                                 giface=self._gifaceForDisplay)
 
664
        dlg.CentreOnScreen()
 
665
        dlg.Show()
 
666
 
482
667
    def OnTopology(self, event):
483
 
        """!Rebuild topology of selected vector map"""
484
 
        mapLayer = self.GetPyData(self.layer_selected)[0]['maplayer']
 
668
        """Rebuild topology of selected vector map"""
 
669
        mapLayer = self.GetLayerInfo(self.layer_selected, key = 'maplayer')
485
670
        cmd = ['v.build',
486
671
               'map=%s' % mapLayer.GetName()]
487
 
        self.lmgr.goutput.RunCmd(cmd, switchPage = True)
 
672
        self._giface.RunCmd(cmd)
 
673
 
 
674
    def OnSqlQuery(self, event):
 
675
        """Show SQL query window for PostGIS layers
 
676
        """
 
677
        dlg = SqlQueryFrame(parent = self)
 
678
        dlg.CentreOnScreen()
 
679
        dlg.Show()
488
680
        
489
681
    def OnMetadata(self, event):
490
 
        """!Print metadata of raster/vector map layer
491
 
        TODO: Dialog to modify metadata
 
682
        """Print metadata of raster/vector map layer
 
683
        
 
684
        .. todo::
 
685
            Dialog to modify metadata
492
686
        """
493
 
        mapLayer = self.GetPyData(self.layer_selected)[0]['maplayer']
494
 
        mltype = self.GetPyData(self.layer_selected)[0]['type']
 
687
        mapLayer = self.GetLayerInfo(self.layer_selected, key = 'maplayer')
 
688
        mltype = self.GetLayerInfo(self.layer_selected,key = 'type')
495
689
 
496
690
        if mltype == 'raster':
497
691
            cmd = ['r.info']
498
692
        elif mltype == 'vector':
499
693
            cmd = ['v.info']
 
694
        elif mltype == '3d-raster':
 
695
            cmd = ['r3.info']
500
696
        cmd.append('map=%s' % mapLayer.GetName())
501
697
 
502
698
        # print output to command log area
503
 
        self.lmgr.goutput.RunCmd(cmd, switchPage = True)
 
699
        self._giface.RunCmd(cmd)
504
700
 
505
701
    def OnSetCompRegFromRaster(self, event):
506
 
        """!Set computational region from selected raster map (ignore NULLs)"""
507
 
        mapLayer = self.GetPyData(self.layer_selected)[0]['maplayer']
 
702
        """Set computational region from selected raster map (ignore NULLs)"""
 
703
        mapLayer = self.GetLayerInfo(self.layer_selected, key = 'maplayer')
508
704
        
509
705
        cmd = ['g.region',
510
 
               '-p',
511
706
               'zoom=%s' % mapLayer.GetName()]
512
707
        
513
708
        # print output to command log area
514
 
        self.lmgr.goutput.RunCmd(cmd)
515
 
         
 
709
        self._giface.RunCmd(cmd, notification=Notification.NO_NOTIFICATION)
 
710
        
 
711
        # re-render map display
 
712
        self._giface.GetMapWindow().UpdateMap(render=True)
 
713
 
516
714
    def OnSetCompRegFromMap(self, event):
517
 
        """!Set computational region from selected raster/vector map
 
715
        """Set computational region from selected raster/vector map
518
716
        """
519
717
        rast = []
520
718
        vect = []
521
719
        rast3d = []
522
720
        for layer in self.GetSelections():
523
 
            mapLayer = self.GetPyData(layer)[0]['maplayer']
524
 
            mltype = self.GetPyData(layer)[0]['type']
 
721
            mapLayer = self.GetLayerInfo(layer, key = 'maplayer')
 
722
            mltype = self.GetLayerInfo(layer, key = 'type')
525
723
                
526
724
            if mltype == 'raster':
527
725
                rast.append(mapLayer.GetName())
535
733
        
536
734
        cmd = ['g.region']
537
735
        if rast:
538
 
            cmd.append('rast=%s' % ','.join(rast))
 
736
            cmd.append('raster=%s' % ','.join(rast))
539
737
        if vect:
540
 
            cmd.append('vect=%s' % ','.join(vect))
 
738
            cmd.append('vector=%s' % ','.join(vect))
541
739
        if rast3d:
542
 
            cmd.append('rast3d=%s' % ','.join(rast3d))
 
740
            cmd.append('raster_3d=%s' % ','.join(rast3d))
543
741
        
544
742
        # print output to command log area
545
743
        if len(cmd) > 1:
546
 
            cmd.append('-p')
547
 
            self.lmgr.goutput.RunCmd(cmd, compReg = False)
 
744
            if mltype == '3d-raster':
 
745
                cmd.append('-3')
 
746
            self._giface.RunCmd(cmd, compReg = False,
 
747
                                notification=Notification.NO_NOTIFICATION)
548
748
        
 
749
        # re-render map display
 
750
        self._giface.GetMapWindow().UpdateMap(render=True)
 
751
            
549
752
    def OnProfile(self, event):
550
 
        """!Plot profile of given raster map layer"""
551
 
        mapLayer = self.GetPyData(self.layer_selected)[0]['maplayer']
 
753
        """Plot profile of given raster map layer"""
 
754
        mapLayer = self.GetLayerInfo(self.layer_selected, key = 'maplayer')
552
755
        if not mapLayer.GetName():
553
756
            wx.MessageBox(parent = self,
554
757
                          message = _("Unable to create profile of "
555
758
                                    "raster map."),
556
759
                          caption = _("Error"), style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
557
 
            return False
558
 
 
559
 
        if not hasattr (self, "profileFrame"):
560
 
            self.profileFrame = None
561
 
 
562
 
        if hasattr (self.mapdisplay, "profile") and self.mapdisplay.profile:
563
 
            self.profileFrame = self.mapdisplay.profile
564
 
 
565
 
        if not self.profileFrame:
566
 
            self.profileFrame = ProfileFrame(self.mapdisplay,
567
 
                                             id = wx.ID_ANY, pos = wx.DefaultPosition, size = (700,300),
568
 
                                             style = wx.DEFAULT_FRAME_STYLE, rasterList = [mapLayer.GetName()])
569
 
            # show new display
570
 
            self.profileFrame.Show()
571
 
        
 
760
            return
 
761
        self.mapdisplay.Profile(rasters=[mapLayer.GetName()])
 
762
 
572
763
    def OnRasterColorTable(self, event):
573
 
        """!Set color table for raster map"""
574
 
        name = self.GetPyData(self.layer_selected)[0]['maplayer'].GetName()
575
 
        GUI(parent = self).ParseCommand(['r.colors',
576
 
                                         'map=%s' % name])
577
 
 
 
764
        """Set color table for 2D/3D raster map"""
 
765
        raster2d = []
 
766
        raster3d = []
 
767
        for layer in self.GetSelectedLayers():
 
768
            if self.GetLayerInfo(layer, key='type') == '3d-raster':
 
769
                raster3d.append(self.GetLayerInfo(layer, key = 'maplayer').GetName())
 
770
            else:
 
771
                raster2d.append(self.GetLayerInfo(layer, key = 'maplayer').GetName())
 
772
        
 
773
        if raster2d:
 
774
            GUI(parent = self, giface = self._giface).ParseCommand(['r.colors',
 
775
                                                                    'map=%s' % ','.join(raster2d)])
 
776
        if raster3d:
 
777
            GUI(parent = self, giface = self._giface).ParseCommand(['r3.colors',
 
778
                                                                    'map=%s' % ','.join(raster3d)])
 
779
            
578
780
    def OnVectorColorTable(self, event):
579
 
        """!Set color table for vector map"""
580
 
        name = self.GetPyData(self.layer_selected)[0]['maplayer'].GetName()
 
781
        """Set color table for vector map"""
 
782
        name = self.GetLayerInfo(self.layer_selected, key = 'maplayer').GetName()
581
783
        GUI(parent = self, centreOnParent = False).ParseCommand(['v.colors',
582
784
                                                                 'map=%s' % name])
583
785
        
 
786
    def _mapNameValidationFailed(self, ctrl):
 
787
        message = _("Name <%(name)s> is not a valid name for GRASS map. "
 
788
                    "Please use only ASCII characters excluding %(chars)s "
 
789
                    "and space.") % {'name': ctrl.GetValue(), 'chars': '/"\'@,=*~'}
 
790
        GError(parent=self, message=message, caption=_("Invalid name"))
 
791
 
 
792
    def OnCopyMap(self, event):
 
793
        """Copy selected map into current mapset"""
 
794
        layer = self.GetSelectedLayer()
 
795
        ltype = self.GetLayerInfo(layer, key='type')
 
796
        lnameSrc = self.GetLayerInfo(layer, key = 'maplayer').GetName()
 
797
        
 
798
        if ltype == 'raster':
 
799
            key = 'raster'
 
800
            module = 'rast'
 
801
            label = _('Raster map')
 
802
        elif ltype == 'vector':
 
803
            key = 'vector'
 
804
            module = 'vect'
 
805
            label = _('Vector map')
 
806
        elif ltype == '3d-raster':
 
807
            key = 'raster_3d'
 
808
            module = 'rast3d'
 
809
            label = _('3D raster map')
 
810
        else:
 
811
            GError(_("Unsupported map type <%s>") % ltype, parent = self)
 
812
            return
 
813
        
 
814
        # TODO: replace by New[Raster|Vector]Dialog
 
815
        dlg = TextEntryDialog(parent = self,
 
816
                              message = _('Enter name for the new %s in the current mapset:') % label.lower(),
 
817
                              caption = _('Make a copy of %s <%s>') % (label.lower(), lnameSrc),
 
818
                              defaultValue = lnameSrc.split('@')[0],
 
819
                              validator = GenericValidator(grass.legal_name, self._mapNameValidationFailed),
 
820
                              size = (700, -1))
 
821
        if dlg.ShowModal() == wx.ID_OK:
 
822
            lnameDst = dlg.GetValue()
 
823
            dlg.Destroy()
 
824
        else:
 
825
            dlg.Destroy()
 
826
            return
 
827
        
 
828
        currentMapset = grass.gisenv()['MAPSET']
 
829
        # check if map already exists
 
830
        if lnameDst in grass.list_grouped(key)[currentMapset]:
 
831
            dlgOw = wx.MessageDialog(parent = self, message = _("%s <%s> already exists "
 
832
                                                                "in the current mapset. "
 
833
                                                                "Do you want to overwrite it?") % (label, lnameDst),
 
834
                                     caption = _("Overwrite?"),
 
835
                                     style = wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
 
836
            if dlgOw.ShowModal() != wx.ID_YES:
 
837
                return
 
838
        
 
839
        kwargs = {key : '%s,%s' % (lnameSrc, lnameDst)}
 
840
        if 0 != RunCommand('g.copy', overwrite = True, **kwargs):
 
841
            GError(_("Unable to make copy of <%s>") % lnameSrc,
 
842
                   parent=self)
 
843
            return
 
844
        
 
845
        if '@' in lnameDst:
 
846
            mapsetDst = lnameDst.split('@')[1]
 
847
            if mapsetDst != currentMapset:
 
848
                GError(_("Unable to make copy of <%s>. Mapset <%s> is not current mapset.") % \
 
849
                           (lnameSrc, mapsetDst))
 
850
                return
 
851
            
 
852
        lnameDst += '@' + currentMapset
 
853
        # add copied map to the layer tree
 
854
        self.AddLayer(ltype, lname = lnameDst, lcmd = ['d.%s' % module, 'map=%s' % lnameDst])
 
855
 
584
856
    def OnHistogram(self, event):
585
 
        """!Plot histogram for given raster map layer
 
857
        """Plot histogram for given raster map layer
586
858
        """
587
 
        mapLayer = self.GetPyData(self.layer_selected)[0]['maplayer']
588
 
        if not mapLayer.GetName():
 
859
        rasterList = []
 
860
        for layer in self.GetSelectedLayers():
 
861
            rasterList.append(self.GetLayerInfo(layer, key = 'maplayer').GetName())
 
862
 
 
863
        if not rasterList:
589
864
            GError(parent = self,
590
865
                   message = _("Unable to display histogram of "
591
866
                               "raster map. No map name defined."))
592
867
            return
593
868
        
594
 
        win = HistogramFrame(parent = self)
595
 
        
 
869
        win = HistogramPlotFrame(parent = self, rasterList = rasterList)
596
870
        win.CentreOnScreen()
597
871
        win.Show()
598
 
        win.SetHistLayer(mapLayer.GetName())
599
 
        win.HistWindow.UpdateHist()
600
 
        win.Refresh()
601
 
        win.Update()
602
 
        
 
872
                
603
873
    def OnUnivariateStats(self, event):
604
 
        """!Univariate raster statistics"""
605
 
        name = self.GetPyData(self.layer_selected)[0]['maplayer'].GetName()
606
 
        self.lmgr.goutput.RunCmd(['r.univar', 'map=%s' % name], switchPage = True)
 
874
        """Univariate 2D/3D raster statistics"""
 
875
        raster2d = []
 
876
        raster3d = []
 
877
        for layer in self.GetSelectedLayers():
 
878
            if self.GetLayerInfo(layer, key='type') == '3d-raster':
 
879
                raster3d.append(self.GetLayerInfo(layer, key = 'maplayer').GetName())
 
880
            else:
 
881
                raster2d.append(self.GetLayerInfo(layer, key = 'maplayer').GetName())
 
882
        
 
883
        if raster2d:
 
884
            self._giface.RunCmd(['r.univar', 'map=%s' % ','.join(raster2d)])
 
885
        
 
886
        if raster3d:
 
887
            self._giface.RunCmd(['r3.univar', 'map=%s' % ','.join(raster3d)])
607
888
 
 
889
    def OnReportStats(self, event):
 
890
        """Print 2D statistics"""
 
891
        rasters = []
 
892
        # TODO: Implement self.GetSelectedLayers(ltype='raster')
 
893
        for layer in self.GetSelectedLayers():
 
894
            if self.GetLayerInfo(layer, key='type') == 'raster':
 
895
                rasters.append(self.GetLayerInfo(layer, key = 'maplayer').GetName())
 
896
        
 
897
        if rasters:
 
898
            self._giface.RunCmd(['r.report', 'map=%s' % ','.join(rasters), 'units=h,c,p'])
 
899
        
608
900
    def OnStartEditing(self, event):
609
 
        """!Start editing vector map layer requested by the user
 
901
        """Start editing vector map layer requested by the user
610
902
        """
611
 
        try:
612
 
            maplayer = self.GetPyData(self.layer_selected)[0]['maplayer']
613
 
        except:
614
 
            event.Skip()
 
903
        mapLayer = self.GetLayerInfo(self.layer_selected, key = 'maplayer')
 
904
        if not haveVDigit:
 
905
            from vdigit import errorMsg
 
906
            
 
907
            self.mapdisplay.toolbars['map'].combo.SetValue (_("2D view"))
 
908
            
 
909
            GError(_("Unable to start wxGUI vector digitizer.\n"
 
910
                     "Details: %s") % errorMsg, parent = self)
615
911
            return
616
912
        
617
913
        if not self.mapdisplay.GetToolbar('vdigit'): # enable tool
618
914
            self.mapdisplay.AddToolbar('vdigit')
619
 
        
620
 
        if not self.mapdisplay.toolbars['vdigit']:
621
 
            return
622
 
        
623
 
        self.mapdisplay.toolbars['vdigit'].StartEditing(maplayer)
624
 
        
 
915
 
 
916
        else: # tool already enabled
 
917
            pass
 
918
        
 
919
        # mark layer as 'edited'
 
920
        self.mapdisplay.toolbars['vdigit'].StartEditing(mapLayer)
 
921
        
 
922
    def StartEditing(self, layerItem):
625
923
        self._setGradient('vdigit')
626
 
        self.RefreshLine(self.layer_selected)
 
924
        if layerItem:
 
925
            self.SetItemIcon(layerItem, 'edited')
 
926
            self.RefreshLine(layerItem)
627
927
        
628
928
    def OnStopEditing(self, event):
629
 
        """!Stop editing the current vector map layer
 
929
        """Stop editing the current vector map layer
630
930
        """
631
 
        maplayer = self.GetPyData(self.layer_selected)[0]['maplayer']
632
 
        
633
931
        self.mapdisplay.toolbars['vdigit'].OnExit()
634
 
        if self.lmgr:
635
 
            self.lmgr.toolbars['tools'].Enable('vdigit', enable = True)
636
 
        
 
932
 
 
933
    def StopEditing(self, layerItem):
637
934
        self._setGradient()
638
 
        self.RefreshLine(self.layer_selected)
 
935
        self.SetItemIcon(layerItem)
 
936
        self.RefreshLine(layerItem)
 
937
 
 
938
    def SetBgMapForEditing(self, mapName, unset=False):
 
939
        try:
 
940
            layerItem = self.FindItemByData('name', mapName)[0]
 
941
        except IndexError:
 
942
             return
639
943
        
640
 
    def OnSetBgMap(self, event):
641
 
        """!Set background vector map for editing sesstion"""
642
 
        digit = self.mapdisplay.GetWindow().digit
643
 
        if event.IsChecked():
644
 
            mapName = self.GetPyData(self.layer_selected)[0]['maplayer'].GetName()
645
 
            UserSettings.Set(group = 'vdigit', key = 'bgmap', subkey = 'value',
646
 
                             value = str(mapName), internal = True)
647
 
            digit.OpenBackgroundMap(mapName)
 
944
        if not unset:
648
945
            self._setGradient('bgmap')
 
946
            self.SetItemIcon(layerItem, 'bgmap')
649
947
        else:
650
 
            UserSettings.Set(group = 'vdigit', key = 'bgmap', subkey = 'value',
651
 
                             value = '', internal = True)
652
 
            digit.CloseBackgroundMap()
653
948
            self._setGradient()
 
949
            self.SetItemIcon(layerItem)
654
950
        
655
 
        self.RefreshLine(self.layer_selected)
 
951
        self.RefreshLine(layerItem)
656
952
 
657
953
    def OnPopupProperties (self, event):
658
 
        """!Popup properties dialog"""
 
954
        """Popup properties dialog"""
659
955
        self.PropertiesDialog(self.layer_selected)
660
956
 
661
957
    def OnPopupOpacityLevel(self, event):
662
 
        """!Popup opacity level indicator"""
663
 
        if not self.GetPyData(self.layer_selected)[0]['ctrl']:
 
958
        """Popup opacity level indicator"""
 
959
        if not self.GetLayerInfo(self.layer_selected, key = 'ctrl'):
664
960
            return
665
961
        
666
 
        maplayer = self.GetPyData(self.layer_selected)[0]['maplayer']
 
962
        maplayer = self.GetLayerInfo(self.layer_selected, key = 'maplayer')
667
963
        current_opacity = maplayer.GetOpacity()
668
964
        
669
965
        dlg = SetOpacityDialog(self, opacity = current_opacity,
670
966
                               title = _("Set opacity of <%s>") % maplayer.GetName())
 
967
        dlg.applyOpacity.connect(lambda value:
 
968
                                 self.ChangeLayerOpacity(layer=self.layer_selected, value=value))
671
969
        dlg.CentreOnParent()
672
 
        dlg.Bind(EVT_APPLY_OPACITY, self.OnApplyLayerOpacity)
673
970
 
674
971
        if dlg.ShowModal() == wx.ID_OK:
675
972
            self.ChangeLayerOpacity(layer = self.layer_selected, value = dlg.GetOpacity())
676
973
        dlg.Destroy()
677
974
 
678
 
    def OnApplyLayerOpacity(self, event):
679
 
        """!Handles EVT_APPLY_OPACITY event."""
680
 
        self.ChangeLayerOpacity(layer = self.layer_selected, value = event.value)
681
 
 
682
975
    def ChangeLayerOpacity(self, layer, value):
683
 
        """!Change opacity value of layer
684
 
        @param layer layer for which to change (item in layertree)
685
 
        @param value opacity value (float between 0 and 1)
 
976
        """Change opacity value of layer
 
977
 
 
978
        :param layer: layer for which to change (item in layertree)
 
979
        :param value: opacity value (float between 0 and 1)
686
980
        """
687
 
        maplayer = self.GetPyData(layer)[0]['maplayer']
 
981
        maplayer = self.GetLayerInfo(layer, key = 'maplayer')
688
982
        self.Map.ChangeOpacity(maplayer, value)
689
983
        maplayer.SetOpacity(value)
690
984
        self.SetItemText(layer,
703
997
        self.GetMapDisplay().GetWindow().UpdateMap(render = False, renderVector = renderVector)
704
998
 
705
999
    def OnNvizProperties(self, event):
706
 
        """!Nviz-related properties (raster/vector/volume)
 
1000
        """Nviz-related properties (raster/vector/volume)
707
1001
 
708
 
        @todo vector/volume
 
1002
        .. todo::
 
1003
            vector/volume
709
1004
        """
710
1005
        self.lmgr.notebook.SetSelectionByName('nviz')
711
 
        ltype = self.GetPyData(self.layer_selected)[0]['type']
 
1006
        ltype = self.GetLayerInfo(self.layer_selected, key = 'type')
712
1007
        if ltype == 'raster':
713
1008
            self.lmgr.nviz.SetPage('surface')
714
1009
        elif ltype == 'vector':
717
1012
            self.lmgr.nviz.SetPage('volume')
718
1013
        
719
1014
    def OnRenameLayer (self, event):
720
 
        """!Rename layer"""
 
1015
        """Rename layer"""
721
1016
        self.EditLabel(self.layer_selected)
722
1017
        self.GetEditControl().SetSelection(-1, -1)
723
1018
        
724
1019
    def OnRenamed(self, event):
725
 
        """!Layer renamed"""
 
1020
        """Layer renamed"""
 
1021
        if not event.GetLabel():
 
1022
            event.Skip()
 
1023
            return
 
1024
        
726
1025
        item = self.layer_selected
727
 
        self.GetPyData(item)[0]['label'] = event.GetLabel()
728
 
        self.SetItemText(item, self._getLayerName(item)) # not working, why?
 
1026
        self.SetLayerInfo(item, key = 'label', value = event.GetLabel())
 
1027
        self.SetItemText(item, self._getLayerName(item))
729
1028
        
730
1029
        event.Skip()
731
1030
 
732
1031
    def AddLayer(self, ltype, lname = None, lchecked = None,
733
1032
                 lopacity = 1.0, lcmd = None, lgroup = None, lvdigit = None, lnviz = None, multiple = True):
734
 
        """!Add new item to the layer tree, create corresponding MapLayer instance.
 
1033
        """Add new item to the layer tree, create corresponding MapLayer instance.
735
1034
        Launch property dialog if needed (raster, vector, etc.)
736
1035
 
737
 
        @param ltype layer type (raster, vector, 3d-raster, ...)
738
 
        @param lname layer name
739
 
        @param lchecked if True layer is checked
740
 
        @param lopacity layer opacity level
741
 
        @param lcmd command (given as a list)
742
 
        @param lgroup index of group item (-1 for root) or None
743
 
        @param lvdigit vector digitizer settings (eg. geometry attributes)
744
 
        @param lnviz layer Nviz properties
745
 
        @param multiple True to allow multiple map layers in layer tree
 
1036
        :param ltype: layer type (raster, vector, 3d-raster, ...)
 
1037
        :param lname: layer name
 
1038
        :param lchecked: if True layer is checked
 
1039
        :param lopacity: layer opacity level
 
1040
        :param lcmd: command (given as a list)
 
1041
        :param lgroup: index of group item (-1 for root) or None
 
1042
        :param lvdigit: vector digitizer settings (eg. geometry attributes)
 
1043
        :param lnviz: layer Nviz properties
 
1044
        :param bool multiple: True to allow multiple map layers in layer tree
746
1045
        """
747
1046
        if lname and not multiple:
748
1047
            # check for duplicates
749
 
            item = self.GetFirstVisibleItem()
 
1048
            item = self.GetFirstChild(self.root)[0]
750
1049
            while item and item.IsOk():
751
 
                if self.GetPyData(item)[0]['type'] == 'vector':
752
 
                    name = self.GetPyData(item)[0]['maplayer'].GetName()
 
1050
                if self.GetLayerInfo(item, key = 'type') == 'vector':
 
1051
                    name = self.GetLayerInfo(item, key = 'maplayer').GetName()
753
1052
                    if name == lname:
754
1053
                        return
755
 
                item = self.GetNextVisible(item)
756
 
        
757
 
        self.first = True
758
 
        params = {} # no initial options parameters
759
 
        
 
1054
                item = self.GetNextItem(item)
 
1055
        
 
1056
        selectedLayer = self.GetSelectedLayer()
760
1057
        # deselect active item
761
 
        if self.layer_selected:
762
 
            self.SelectItem(self.layer_selected, select = False)
 
1058
        if selectedLayer:
 
1059
            self.SelectItem(selectedLayer, select=False)
763
1060
        
764
1061
        Debug.msg (3, "LayerTree().AddLayer(): ltype=%s" % (ltype))
765
1062
        
779
1076
            ctrl.SetToolTipString(_("Click to edit layer settings"))
780
1077
            self.Bind(wx.EVT_BUTTON, self.OnLayerContextMenu, ctrl)
781
1078
        # add layer to the layer tree
782
 
        if self.layer_selected and self.layer_selected != self.GetRootItem():
783
 
            if self.GetPyData(self.layer_selected)[0]['type'] == 'group' \
784
 
                and self.IsExpanded(self.layer_selected):
 
1079
        if selectedLayer and selectedLayer != self.GetRootItem():
 
1080
            if self.GetLayerInfo(selectedLayer, key = 'type') == 'group' \
 
1081
                and self.IsExpanded(selectedLayer):
785
1082
                # add to group (first child of self.layer_selected) if group expanded
786
 
                layer = self.PrependItem(parent = self.layer_selected,
 
1083
                layer = self.PrependItem(parent = selectedLayer,
787
1084
                                         text = '', ct_type = 1, wnd = ctrl)
788
1085
            else:
789
1086
                # prepend to individual layer or non-expanded group
800
1097
                                            text = '', ct_type = 1, wnd = ctrl)
801
1098
                elif lgroup is None:
802
1099
                    # -> previous sibling of selected layer
803
 
                    parent = self.GetItemParent(self.layer_selected)
 
1100
                    parent = self.GetItemParent(selectedLayer)
804
1101
                    layer = self.InsertItem(parentId = parent,
805
 
                                            input = self.GetPrevSibling(self.layer_selected),
 
1102
                                            input = self.GetPrevSibling(selectedLayer),
806
1103
                                            text = '', ct_type = 1, wnd = ctrl)
807
1104
        else: # add first layer to the layer tree (first child of root)
808
1105
            layer = self.PrependItem(parent = self.root, text = '', ct_type = 1, wnd = ctrl)
815
1112
            checked = True
816
1113
        
817
1114
        self.forceCheck = True
818
 
        self.CheckItem(layer, checked = checked)
819
1115
        
820
1116
        # add text and icons for each layer ltype
821
 
        label =  _('(double click to set properties)') + ' ' * 15
822
 
        if ltype == 'raster':
823
 
            self.SetItemImage(layer, self.rast_icon)
824
 
            self.SetItemText(layer, '%s %s' % (_('raster'), label))
825
 
        elif ltype == '3d-raster':
826
 
            self.SetItemImage(layer, self.rast3d_icon)
827
 
            self.SetItemText(layer, '%s %s' % (_('3D raster'), label))
828
 
        elif ltype == 'rgb':
829
 
            self.SetItemImage(layer, self.rgb_icon)
830
 
            self.SetItemText(layer, '%s %s' % (_('RGB'), label))
831
 
        elif ltype == 'his':
832
 
            self.SetItemImage(layer, self.his_icon)
833
 
            self.SetItemText(layer, '%s %s' % (_('HIS'), label))
834
 
        elif ltype == 'shaded':
835
 
            self.SetItemImage(layer, self.shaded_icon)
836
 
            self.SetItemText(layer, '%s %s' % (_('shaded relief'), label))
837
 
        elif ltype == 'rastnum':
838
 
            self.SetItemImage(layer, self.rnum_icon)
839
 
            self.SetItemText(layer, '%s %s' % (_('raster cell numbers'), label))
840
 
        elif ltype == 'rastarrow':
841
 
            self.SetItemImage(layer, self.rarrow_icon)
842
 
            self.SetItemText(layer, '%s %s' % (_('raster flow arrows'), label))
843
 
        elif ltype == 'vector':
844
 
            self.SetItemImage(layer, self.vect_icon)
845
 
            self.SetItemText(layer, '%s %s' % (_('vector'), label))
846
 
        elif ltype == 'thememap':
847
 
            self.SetItemImage(layer, self.theme_icon)
848
 
            self.SetItemText(layer, '%s %s' % (_('thematic map'), label))
849
 
        elif ltype == 'themechart':
850
 
            self.SetItemImage(layer, self.chart_icon)
851
 
            self.SetItemText(layer, '%s %s' % (_('thematic charts'), label))
852
 
        elif ltype == 'grid':
853
 
            self.SetItemImage(layer, self.grid_icon)
854
 
            self.SetItemText(layer, '%s %s' % (_('grid'), label))
855
 
        elif ltype == 'geodesic':
856
 
            self.SetItemImage(layer, self.geodesic_icon)
857
 
            self.SetItemText(layer, '%s %s' % (_('geodesic line'), label))
858
 
        elif ltype == 'rhumb':
859
 
            self.SetItemImage(layer, self.rhumb_icon)
860
 
            self.SetItemText(layer, '%s %s' % (_('rhumbline'), label))
861
 
        elif ltype == 'labels':
862
 
            self.SetItemImage(layer, self.labels_icon)
863
 
            self.SetItemText(layer, '%s %s' % (_('vector labels'), label))
864
 
        elif ltype == 'command':
865
 
            self.SetItemImage(layer, self.cmd_icon)
 
1117
        if ltype == 'command':
 
1118
            self.SetItemImage(layer, self._icon['cmd'])
866
1119
        elif ltype == 'group':
867
 
            self.SetItemImage(layer, self.folder)
 
1120
            self.SetItemImage(layer, self.folder, CT.TreeItemIcon_Normal)
 
1121
            self.SetItemImage(layer, self.folder_open, CT.TreeItemIcon_Expanded)
868
1122
            self.SetItemText(layer, grouptext)
869
 
        
870
 
        self.first = False
871
 
        
 
1123
        else:
 
1124
            if ltype in self._icon:
 
1125
                self.SetItemImage(layer, self._icon[ltype])
 
1126
                # do not use title() - will not work with ltype == '3d-raster'
 
1127
                self.SetItemText(layer, '%s %s' % (LMIcons["layer"+ltype[0].upper()+ltype[1:]].GetLabel(),
 
1128
                                                   _('(double click to set properties)') + ' ' * 15))
 
1129
            else:
 
1130
                self.SetItemImage(layer, self._icon['cmd'])
 
1131
                self.SetItemText(layer, ltype)
 
1132
 
872
1133
        if ltype != 'group':
873
1134
            if lcmd and len(lcmd) > 1:
874
1135
                cmd = lcmd
898
1159
                                    'nviz'     : lnviz,
899
1160
                                    'propwin'  : None}, 
900
1161
                                   None))
 
1162
            # must be after SetPyData because it calls OnLayerChecked
 
1163
            # which calls GetVisibleLayers which requires already set PyData
 
1164
            self.CheckItem(layer, checked=checked)
901
1165
            
902
1166
            # find previous map layer instance 
903
1167
            prevItem = self.GetFirstChild(self.root)[0]
904
1168
            prevMapLayer = None 
905
1169
            pos = -1
906
1170
            while prevItem and prevItem.IsOk() and prevItem != layer: 
907
 
                if self.GetPyData(prevItem)[0]['maplayer']: 
908
 
                    prevMapLayer = self.GetPyData(prevItem)[0]['maplayer'] 
 
1171
                if self.GetLayerInfo(prevItem, key = 'maplayer'): 
 
1172
                    prevMapLayer = self.GetLayerInfo(prevItem, key = 'maplayer')
909
1173
                
910
 
                prevItem = self.GetNextSibling(prevItem) 
 
1174
                prevItem = self.GetNextItem(prevItem) 
911
1175
                
912
1176
                if prevMapLayer: 
913
1177
                    pos = self.Map.GetLayerIndex(prevMapLayer)
915
1179
                    pos = -1
916
1180
            
917
1181
            maplayer = self.Map.AddLayer(pos = pos,
918
 
                                         type = ltype, command = self.GetPyData(layer)[0]['cmd'], name = name,
919
 
                                         l_active = checked, l_hidden = False,
920
 
                                         l_opacity = lopacity, l_render = render)
921
 
            self.GetPyData(layer)[0]['maplayer'] = maplayer
 
1182
                                         ltype = ltype, command = self.GetLayerInfo(prevItem, key = 'cmd'), name = name,
 
1183
                                         active = checked, hidden = False,
 
1184
                                         opacity = lopacity, render = render)
 
1185
            self.SetLayerInfo(layer, key = 'maplayer', value = maplayer)
922
1186
            
923
1187
            # run properties dialog if no properties given
924
1188
            if len(cmd) == 0:
925
1189
                self.PropertiesDialog(layer, show = True)
 
1190
            else:
 
1191
                self.first = False
926
1192
        
927
1193
        else: # group
928
1194
            self.SetPyData(layer, ({'cmd'      : None,
935
1201
        
936
1202
        # select new item
937
1203
        self.SelectItem(layer, select = True)
938
 
        self.layer_selected = layer
939
 
        
 
1204
 
940
1205
        # use predefined layer name if given
941
1206
        if lname:
942
1207
            if ltype == 'group':
945
1210
                ctrl.SetValue(lname)
946
1211
            else:
947
1212
                self.SetItemText(layer, self._getLayerName(layer, lname))
 
1213
        else:
 
1214
            if ltype == 'group':
 
1215
                self.OnRenameLayer(None)
 
1216
 
948
1217
        
949
 
        # updated progress bar range (mapwindow statusbar)
950
 
        if checked is True:
951
 
            self.mapdisplay.GetProgressBar().SetRange(len(self.Map.GetListOfLayers(l_active = True)))
952
 
            
953
1218
        return layer
954
1219
 
955
1220
    def PropertiesDialog(self, layer, show = True):
956
 
        """!Launch the properties dialog"""
957
 
        if 'propwin' in self.GetPyData(layer)[0] and \
958
 
                self.GetPyData(layer)[0]['propwin'] is not None:
 
1221
        """Launch the properties dialog"""
 
1222
        ltype  = self.GetLayerInfo(layer, key = 'type')
 
1223
        if 'propwin' in self.GetLayerInfo(layer) and \
 
1224
                self.GetLayerInfo(layer, key = 'propwin') is not None:
959
1225
            # recycle GUI dialogs
960
 
            win = self.GetPyData(layer)[0]['propwin']
 
1226
            win = self.GetLayerInfo(layer, key = 'propwin')
961
1227
            if win.IsShown():
962
1228
                win.SetFocus()
963
1229
            else:
965
1231
            
966
1232
            return
967
1233
        
968
 
        completed = ''
969
 
        params = self.GetPyData(layer)[1]
970
 
        ltype  = self.GetPyData(layer)[0]['type']
 
1234
        params = self.GetLayerParams(layer)
971
1235
                
972
1236
        Debug.msg (3, "LayerTree.PropertiesDialog(): ltype=%s" % \
973
1237
                   ltype)
974
 
        
 
1238
 
975
1239
        cmd = None
976
 
        if self.GetPyData(layer)[0]['cmd']:
 
1240
        if self.GetLayerInfo(layer, key = 'cmd'):
 
1241
 
977
1242
            module = GUI(parent = self, show = show, centreOnParent = False)
978
 
            module.ParseCommand(self.GetPyData(layer)[0]['cmd'],
 
1243
            module.ParseCommand(self.GetLayerInfo(layer, key = 'cmd'),
979
1244
                                completed = (self.GetOptData,layer,params))
980
1245
            
981
 
            self.GetPyData(layer)[0]['cmd'] = module.GetCmd()
982
 
        elif ltype == 'raster':
983
 
            cmd = ['d.rast']
984
 
            if UserSettings.Get(group='cmd', key='rasterOverlay', subkey='enabled'):
985
 
                cmd.append('-o')
986
 
                         
987
 
        elif ltype == '3d-raster':
988
 
            cmd = ['d.rast3d.py']
989
 
                                        
990
 
        elif ltype == 'rgb':
991
 
            cmd = ['d.rgb']
992
 
            if UserSettings.Get(group='cmd', key='rasterOverlay', subkey='enabled'):
993
 
                cmd.append('-o')
994
 
            
995
 
        elif ltype == 'his':
996
 
            cmd = ['d.his']
997
 
            
998
 
        elif ltype == 'shaded':
999
 
            cmd = ['d.shadedmap']
1000
 
            
1001
 
        elif ltype == 'rastarrow':
1002
 
            cmd = ['d.rast.arrow']
1003
 
            
1004
 
        elif ltype == 'rastnum':
1005
 
            cmd = ['d.rast.num']
1006
 
            
1007
 
        elif ltype == 'vector':
1008
 
            types = list()
1009
 
            for ftype in ['point', 'line', 'boundary', 'centroid', 'area', 'face']:
1010
 
                if UserSettings.Get(group = 'cmd', key = 'showType', subkey = [ftype, 'enabled']):
1011
 
                    types.append(ftype)
1012
 
            
1013
 
            cmd = ['d.vect', 'type=%s' % ','.join(types)]
1014
 
            
1015
 
        elif ltype == 'thememap':
1016
 
            # -s flag requested, otherwise only first thematic category is displayed
1017
 
            # should be fixed by C-based d.thematic.* modules
1018
 
            cmd = ['d.vect.thematic', '-s']
1019
 
            
1020
 
        elif ltype == 'themechart':
1021
 
            cmd = ['d.vect.chart']
1022
 
            
1023
 
        elif ltype == 'grid':
1024
 
            cmd = ['d.grid']
1025
 
            
1026
 
        elif ltype == 'geodesic':
1027
 
            cmd = ['d.geodesic']
1028
 
            
1029
 
        elif ltype == 'rhumb':
1030
 
            cmd = ['d.rhumbline']
1031
 
            
1032
 
        elif ltype == 'labels':
1033
 
            cmd = ['d.labels']
1034
 
        
 
1246
            self.SetLayerInfo(layer, key = 'cmd', value = module.GetCmd())
 
1247
        elif self.GetLayerInfo(layer, key = 'type') != 'command':
 
1248
            cmd = [ltype2command[ltype]]
 
1249
            if ltype == 'raster':
 
1250
                if UserSettings.Get(group = 'rasterLayer', key = 'opaque', subkey = 'enabled'):
 
1251
                    cmd.append('-n')
 
1252
            elif ltype == 'rgb':
 
1253
                if UserSettings.Get(group = 'rasterLayer', key = 'opaque', subkey = 'enabled'):
 
1254
                    cmd.append('-n')
 
1255
            elif ltype == 'vector':
 
1256
                cmd += GetDisplayVectSettings()
 
1257
            
1035
1258
        if cmd:
1036
1259
            GUI(parent = self, centreOnParent = False).ParseCommand(cmd,
1037
1260
                                                                    completed = (self.GetOptData,layer,params))
1038
1261
        
1039
1262
    def OnActivateLayer(self, event):
1040
 
        """!Double click on the layer item.
 
1263
        """Double click on the layer item.
1041
1264
        Launch property dialog, or expand/collapse group of items, etc.
1042
1265
        """
1043
1266
        self.lmgr.WorkspaceChanged()
1044
1267
        layer = event.GetItem()
1045
 
        self.layer_selected = layer
1046
 
        
1047
 
        self.PropertiesDialog (layer)
1048
 
        
1049
 
        if self.GetPyData(layer)[0]['type'] == 'group':
 
1268
 
 
1269
        if self.GetLayerInfo(layer, key='type') == 'group':
1050
1270
            if self.IsExpanded(layer):
1051
1271
                self.Collapse(layer)
1052
1272
            else:
1053
1273
                self.Expand(layer)
 
1274
            return
 
1275
 
 
1276
        self.PropertiesDialog(layer)
 
1277
        
1054
1278
        
1055
1279
    def OnDeleteLayer(self, event):
1056
 
        """!Remove selected layer item from the layer tree"""
 
1280
        """Remove selected layer item from the layer tree"""
1057
1281
        self.lmgr.WorkspaceChanged()
1058
1282
        item = event.GetItem()
1059
1283
        
1070
1294
 
1071
1295
        # unselect item
1072
1296
        self.Unselect()
1073
 
        self.layer_selected = None
1074
1297
 
1075
1298
        try:
1076
 
            if self.GetPyData(item)[0]['type'] != 'group':
1077
 
                self.Map.DeleteLayer( self.GetPyData(item)[0]['maplayer'])
 
1299
            if self.GetLayerInfo(item, key = 'type') != 'group':
 
1300
                self.Map.DeleteLayer(self.GetLayerInfo(item, key = 'maplayer'))
1078
1301
        except:
1079
1302
            pass
1080
1303
 
1081
1304
        # redraw map if auto-rendering is enabled
1082
1305
        self.rerender = True
1083
 
        self.reorder = True
 
1306
        nlayers = self.GetVisibleLayers()
 
1307
        if not nlayers:
 
1308
            self.first = True # layer tree is empty
 
1309
        self.Map.SetLayers(nlayers)
1084
1310
        
1085
1311
        if self.mapdisplay.GetToolbar('vdigit'):
1086
1312
            self.mapdisplay.toolbars['vdigit'].UpdateListOfLayers (updateTool = True)
1087
1313
 
1088
 
        # update progress bar range (mapwindow statusbar)
1089
 
        self.mapdisplay.GetProgressBar().SetRange(len(self.Map.GetListOfLayers(l_active = True)))
 
1314
        # here was some dead code related to layer and nviz
 
1315
        # however, in condition was rerender = False
 
1316
        # but rerender is alway True
 
1317
        # (here no change and also in UpdateListOfLayers and GetListOfLayers)
 
1318
        # You can safely remove this comment after some testing.
1090
1319
 
1091
 
        #
1092
 
        # nviz
1093
 
        #
1094
 
        if self.lmgr.IsPaneShown('toolbarNviz') and \
1095
 
                self.GetPyData(item) is not None:
1096
 
            # nviz - load/unload data layer
1097
 
            mapLayer = self.GetPyData(item)[0]['maplayer']
1098
 
            self.mapdisplay.SetStatusText(_("Please wait, updating data..."), 0)
1099
 
            if mapLayer.type == 'raster':
1100
 
                self.mapdisplay.MapWindow.UnloadRaster(item)
1101
 
            elif mapLayer.type == '3d-raster':
1102
 
                self.mapdisplay.MapWindow.UnloadRaster3d(item)
1103
 
            elif mapLayer.type == 'vector':
1104
 
                self.mapdisplay.MapWindow.UnloadVector(item)
1105
 
            self.mapdisplay.SetStatusText("", 0)
1106
 
            
1107
1320
        event.Skip()
1108
1321
 
1109
1322
    def OnLayerChecking(self, event):
1110
 
        """!Layer checkbox is being checked.
 
1323
        """Layer checkbox is being checked.
1111
1324
 
1112
1325
        Continue only if mouse is above checkbox or layer was checked programatically.
1113
1326
        """
1118
1331
            event.Veto()
1119
1332
 
1120
1333
    def OnLayerChecked(self, event):
1121
 
        """!Enable/disable data layer"""
 
1334
        """Enable/disable data layer"""
1122
1335
        self.lmgr.WorkspaceChanged()
1123
1336
        
1124
1337
        item    = event.GetItem()
1127
1340
        digitToolbar = self.mapdisplay.GetToolbar('vdigit')
1128
1341
        if not self.first:
1129
1342
            # change active parameter for item in layers list in render.Map
1130
 
            if self.GetPyData(item)[0]['type'] == 'group':
 
1343
            if self.GetLayerInfo(item, key = 'type') == 'group':
1131
1344
                child, cookie = self.GetFirstChild(item)
1132
1345
                while child:
1133
1346
                    self.forceCheck = True
1134
1347
                    self.CheckItem(child, checked)
1135
 
                    mapLayer = self.GetPyData(child)[0]['maplayer']
 
1348
                    mapLayer = self.GetLayerInfo(child, key = 'maplayer')
1136
1349
                    if not digitToolbar or \
1137
1350
                           (digitToolbar and digitToolbar.GetLayer() != mapLayer):
1138
1351
                        # ignore when map layer is edited
1139
1352
                        self.Map.ChangeLayerActive(mapLayer, checked)
1140
1353
                    child = self.GetNextSibling(child)
1141
1354
            else:
1142
 
                mapLayer = self.GetPyData(item)[0]['maplayer']
1143
 
                if not digitToolbar or \
1144
 
                       (digitToolbar and digitToolbar.GetLayer() != mapLayer):
 
1355
                mapLayer = self.GetLayerInfo(item, key = 'maplayer')
 
1356
                if mapLayer and (not digitToolbar or \
 
1357
                       (digitToolbar and digitToolbar.GetLayer() != mapLayer)):
1145
1358
                    # ignore when map layer is edited
1146
1359
                    self.Map.ChangeLayerActive(mapLayer, checked)
1147
1360
        
1148
 
        # update progress bar range (mapwindow statusbar)
1149
 
        self.mapdisplay.GetProgressBar().SetRange(len(self.Map.GetListOfLayers(l_active = True)))
1150
 
        
1151
1361
        # nviz
1152
 
        if self.lmgr.IsPaneShown('toolbarNviz') and \
 
1362
        if self.mapdisplay.IsPaneShown('3d') and \
1153
1363
                self.GetPyData(item) is not None:
1154
1364
            # nviz - load/unload data layer
1155
 
            mapLayer = self.GetPyData(item)[0]['maplayer']
 
1365
            mapLayer = self.GetLayerInfo(item, key = 'maplayer')
 
1366
            if mapLayer is None:
 
1367
                return
1156
1368
 
1157
1369
            self.mapdisplay.SetStatusText(_("Please wait, updating data..."), 0)
1158
1370
 
1180
1392
        
1181
1393
        # redraw map if auto-rendering is enabled
1182
1394
        self.rerender = True
1183
 
        self.reorder = True
 
1395
        self.Map.SetLayers(self.GetVisibleLayers())
1184
1396
        
1185
1397
    def OnCmdChanged(self, event):
1186
 
        """!Change command string"""
 
1398
        """Change command string"""
1187
1399
        ctrl = event.GetEventObject().GetId()
1188
 
        cmd = event.GetString()
1189
1400
        
1190
1401
        # find layer tree item by ctrl
1191
 
        layer = self.GetFirstVisibleItem()
 
1402
        layer = self.GetFirstChild(self.root)[0]
1192
1403
        while layer and layer.IsOk():
1193
 
            if self.GetPyData(layer)[0]['ctrl'] == ctrl:
 
1404
            if self.GetLayerInfo(layer, key = 'ctrl') == ctrl:
1194
1405
                break
1195
 
            layer = self.GetNextVisible(layer)
 
1406
            layer = self.GetNextItem(layer)
1196
1407
        
1197
1408
        # change parameters for item in layers list in render.Map
1198
1409
        self.ChangeLayer(layer)
1200
1411
        event.Skip()
1201
1412
 
1202
1413
    def OnMotion(self, event):
1203
 
        """!Mouse is moving.
 
1414
        """Mouse is moving.
1204
1415
 
1205
1416
        Detects if mouse points at checkbox.
1206
1417
        """
1215
1426
        event.Skip()
1216
1427
        
1217
1428
    def OnChangingSel(self, event):
1218
 
        """!Selection is changing.
 
1429
        """Selection is changing.
1219
1430
 
1220
1431
        If the user is clicking on checkbox, selection change is vetoed.
1221
1432
        """
1223
1434
            event.Veto()
1224
1435
 
1225
1436
    def OnChangeSel(self, event):
1226
 
        """!Selection changed"""
 
1437
        """Selection changed
 
1438
 
 
1439
        Preconditions:
 
1440
            event.GetItem() is a valid layer;
 
1441
            self.layer_selected is a valid layer
 
1442
        """
 
1443
        # when no layer selected, nothing to do here
 
1444
        if self.layer_selected is None:
 
1445
            event.Skip()
 
1446
            return
 
1447
 
1227
1448
        layer = event.GetItem()
1228
1449
        digitToolbar = self.mapdisplay.GetToolbar('vdigit')
1229
1450
        if digitToolbar:
1230
 
            mapLayer = self.GetPyData(layer)[0]['maplayer']
 
1451
            mapLayer = self.GetLayerInfo(layer, key = 'maplayer')
1231
1452
            bgmap = UserSettings.Get(group = 'vdigit', key = 'bgmap', subkey = 'value',
1232
 
                                     internal = True)
 
1453
                                     settings_type='internal')
1233
1454
            
1234
1455
            if digitToolbar.GetLayer() == mapLayer:
1235
1456
                self._setGradient('vdigit')
1239
1460
                self._setGradient()
1240
1461
        else:
1241
1462
            self._setGradient()
1242
 
        
1243
 
        self.layer_selected = layer
1244
 
        
1245
 
        try:
1246
 
            if self.IsSelected(oldlayer):
1247
 
                self.SetItemWindowEnabled(oldlayer, True)
1248
 
            else:
1249
 
                self.SetItemWindowEnabled(oldlayer, False)
1250
1463
 
1251
 
            if self.IsSelected(layer):
1252
 
                self.SetItemWindowEnabled(layer, True)
1253
 
            else:
1254
 
                self.SetItemWindowEnabled(layer, False)
1255
 
        except:
1256
 
            pass
1257
 
        
1258
 
        try:
1259
 
            self.RefreshLine(oldlayer)
1260
 
            self.RefreshLine(layer)
1261
 
        except:
1262
 
            pass
 
1464
        self.RefreshLine(layer)
1263
1465
        
1264
1466
        # update statusbar -> show command string
1265
 
        if self.GetPyData(layer) and self.GetPyData(layer)[0]['maplayer']:
1266
 
            cmd = self.GetPyData(layer)[0]['maplayer'].GetCmd(string = True)
 
1467
        if self.GetLayerInfo(layer, key = 'maplayer'):
 
1468
            cmd = self.GetLayerInfo(layer, key = 'maplayer').GetCmd(string = True)
1267
1469
            if len(cmd) > 0:
1268
1470
                self.lmgr.SetStatusText(cmd)
1269
1471
        
1270
1472
        # set region if auto-zooming is enabled
1271
 
        if self.GetPyData(layer) and self.GetPyData(layer)[0]['cmd'] and \
 
1473
        if self.GetLayerInfo(layer, key = 'cmd') and \
1272
1474
               UserSettings.Get(group = 'display', key = 'autoZooming', subkey = 'enabled'):
1273
 
            mapLayer = self.GetPyData(layer)[0]['maplayer']
 
1475
            mapLayer = self.GetLayerInfo(layer, key = 'maplayer')
1274
1476
            if mapLayer.GetType() in ('raster', 'vector'):
1275
1477
                render = self.mapdisplay.IsAutoRendered()
1276
1478
                self.mapdisplay.MapWindow.ZoomToMap(layers = [mapLayer,],
1277
1479
                                                    render = render)
1278
1480
        
1279
1481
        # update nviz tools
1280
 
        if self.lmgr.IsPaneShown('toolbarNviz') and \
1281
 
                self.GetPyData(self.layer_selected) is not None:
 
1482
        if self.mapdisplay.IsPaneShown('3d'):
1282
1483
            if self.layer_selected.IsChecked():
1283
1484
                # update Nviz tool window
1284
 
                type = self.GetPyData(self.layer_selected)[0]['maplayer'].type
 
1485
                type = self.GetLayerInfo(self.layer_selected, key = 'maplayer').type
1285
1486
                
1286
1487
                if type == 'raster':
1287
1488
                    self.lmgr.nviz.UpdatePage('surface')
1292
1493
                elif type == '3d-raster':
1293
1494
                    self.lmgr.nviz.UpdatePage('volume')
1294
1495
                    self.lmgr.nviz.SetPage('volume')
1295
 
        
1296
 
    def OnCollapseNode(self, event):
1297
 
        """!Collapse node
1298
 
        """
1299
 
        if self.GetPyData(self.layer_selected)[0]['type'] == 'group':
1300
 
            self.SetItemImage(self.layer_selected, self.folder)
1301
1496
 
1302
 
    def OnExpandNode(self, event):
1303
 
        """!Expand node
1304
 
        """
1305
 
        self.layer_selected = event.GetItem()
1306
 
        if self.GetPyData(self.layer_selected)[0]['type'] == 'group':
1307
 
            self.SetItemImage(self.layer_selected, self.folder_open)
1308
 
    
1309
1497
    def OnEndDrag(self, event):
1310
1498
        self.StopDragging()
1311
1499
        dropTarget = event.GetItem()
1312
1500
        self.flag = self.HitTest(event.GetPoint())[1]
 
1501
        if self.mapdisplay.IsPaneShown('3d'):
 
1502
            self.mapdisplay.MapWindow.UnloadDataLayers(True)
1313
1503
        if self.IsValidDropTarget(dropTarget):
1314
1504
            self.UnselectAll()
1315
1505
            if dropTarget != None:
1317
1507
            self.OnDrop(dropTarget, self._dragItem)
1318
1508
        elif dropTarget == None:
1319
1509
            self.OnDrop(dropTarget, self._dragItem)
1320
 
 
 
1510
            
1321
1511
    def OnDrop(self, dropTarget, dragItem):
1322
1512
        # save everthing associated with item to drag
1323
1513
        try:
1332
1522
        newItem  = self.RecreateItem (dragItem, dropTarget)
1333
1523
 
1334
1524
        # if recreated layer is a group, also recreate its children
1335
 
        if  self.GetPyData(newItem)[0]['type'] == 'group':
 
1525
        if  self.GetLayerInfo(newItem, key = 'type') == 'group':
1336
1526
            (child, cookie) = self.GetFirstChild(dragItem)
1337
1527
            if child:
1338
1528
                while child:
1339
1529
                    self.RecreateItem(child, dropTarget, parent = newItem)
1340
 
                    self.Delete(child)
1341
 
                    child = self.GetNextChild(old, cookie)[0]
 
1530
                    child, cookie = self.GetNextChild(old, cookie)
1342
1531
        
1343
1532
        # delete layer at original position
1344
1533
        try:
1348
1537
 
1349
1538
        # redraw map if auto-rendering is enabled
1350
1539
        self.rerender = True
1351
 
        self.reorder = True
 
1540
        self.Map.SetLayers(self.GetVisibleLayers())
1352
1541
        
1353
1542
        # select new item
1354
1543
        self.SelectItem(newItem)
1355
1544
        
1356
1545
    def RecreateItem (self, dragItem, dropTarget, parent = None):
1357
 
        """!Recreate item (needed for OnEndDrag())
 
1546
        """Recreate item (needed for OnEndDrag())
1358
1547
        """
1359
1548
        Debug.msg (4, "LayerTree.RecreateItem(): layer=%s" % \
1360
1549
                   self.GetItemText(dragItem))
1363
1552
        checked = self.IsItemChecked(dragItem)
1364
1553
        image   = self.GetItemImage(dragItem, 0)
1365
1554
        text    = self.GetItemText(dragItem)
1366
 
 
1367
 
        if self.GetPyData(dragItem)[0]['type'] == 'command':
 
1555
        if self.GetLayerInfo(dragItem, key = 'type') == 'command':
1368
1556
            # recreate command layer
1369
1557
            newctrl = self._createCommandCtrl()
1370
1558
            try:
1371
 
                newctrl.SetValue(self.GetPyData(dragItem)[0]['maplayer'].GetCmd(string = True))
 
1559
                newctrl.SetValue(self.GetLayerInfo(dragItem, key = 'maplayer').GetCmd(string = True))
1372
1560
            except:
1373
1561
                pass
1374
1562
            newctrl.Bind(wx.EVT_TEXT_ENTER, self.OnCmdChanged)
1375
1563
            data = self.GetPyData(dragItem)
1376
1564
 
1377
 
        elif self.GetPyData(dragItem)[0]['ctrl']:
 
1565
        elif self.GetLayerInfo(dragItem, key = 'ctrl'):
1378
1566
            # recreate data layer
1379
1567
            btnbmp = LMIcons["layerOptions"].GetBitmap((16,16))
1380
1568
            newctrl = buttons.GenBitmapButton(self, id = wx.ID_ANY, bitmap = btnbmp, size = (24, 24))
1381
1569
            newctrl.SetToolTipString(_("Click to edit layer settings"))
1382
1570
            self.Bind(wx.EVT_BUTTON, self.OnLayerContextMenu, newctrl)
1383
 
            data    = self.GetPyData(dragItem)
 
1571
            data = self.GetPyData(dragItem)
 
1572
        
1384
1573
 
1385
 
        elif self.GetPyData(dragItem)[0]['type'] == 'group':
 
1574
        elif self.GetLayerInfo(dragItem, key = 'type') == 'group':
1386
1575
            # recreate group
1387
1576
            newctrl = None
1388
1577
            data    = None
1397
1586
                afteritem = dropTarget
1398
1587
 
1399
1588
            # dragItem dropped on group
1400
 
            if  self.GetPyData(afteritem)[0]['type'] == 'group':
 
1589
            if  self.GetLayerInfo(afteritem, key = 'type') == 'group':
1401
1590
                newItem = self.PrependItem(afteritem, text = text, \
1402
1591
                                      ct_type = 1, wnd = newctrl, image = image, \
1403
1592
                                      data = data)
1423
1612
        #update new layer 
1424
1613
        self.SetPyData(newItem, self.GetPyData(dragItem))
1425
1614
        if newctrl:
1426
 
            self.GetPyData(newItem)[0]['ctrl'] = newctrl.GetId()
 
1615
            self.SetLayerInfo(newItem, key = 'ctrl', value = newctrl.GetId())
1427
1616
        else:
1428
 
            self.GetPyData(newItem)[0]['ctrl'] = None
 
1617
            self.SetLayerInfo(newItem, key = 'ctrl', value = None)
1429
1618
            
1430
1619
        self.forceCheck = True
1431
1620
        self.CheckItem(newItem, checked = checked) # causes a new render
1433
1622
        return newItem
1434
1623
 
1435
1624
    def _getLayerName(self, item, lname = ''):
1436
 
        """!Get layer name string
 
1625
        """Get layer name string
1437
1626
 
1438
 
        @param lname optional layer name
 
1627
        :param lname: optional layer name
1439
1628
        """
1440
 
        mapLayer = self.GetPyData(item)[0]['maplayer']
1441
 
        if not lname:
1442
 
            lname  = self.GetPyData(item)[0]['label']
1443
 
        opacity  = int(mapLayer.GetOpacity(float = True) * 100)
1444
 
        if not lname:
1445
 
            dcmd    = self.GetPyData(item)[0]['cmd']
 
1629
        mapLayer = self.GetLayerInfo(item, key = 'maplayer')
 
1630
        if not mapLayer:
 
1631
            return lname
 
1632
        
 
1633
        if not lname:
 
1634
            lname  = self.GetLayerInfo(item, key = 'label')
 
1635
        opacity  = int(mapLayer.GetOpacity() * 100)
 
1636
        if not lname:
 
1637
            dcmd    = self.GetLayerInfo(item, key = 'cmd')
1446
1638
            lname, found = GetLayerNameFromCmd(dcmd, layerType = mapLayer.GetType(),
1447
1639
                                               fullyQualified = True)
1448
1640
            if not found:
1454
1646
        return lname
1455
1647
                
1456
1648
    def GetOptData(self, dcmd, layer, params, propwin):
1457
 
        """!Process layer data (when changes in propertiesdialog are applied)"""
 
1649
        """Process layer data (when changes in properties dialog are applied)
 
1650
        """
1458
1651
        # set layer text to map name
1459
1652
        if dcmd:
1460
 
            self.GetPyData(layer)[0]['cmd'] = dcmd
 
1653
            self.SetLayerInfo(layer, key = 'cmd', value = dcmd)
1461
1654
            mapText  = self._getLayerName(layer)
1462
1655
            mapName, found = GetLayerNameFromCmd(dcmd)
1463
 
            mapLayer = self.GetPyData(layer)[0]['maplayer']
 
1656
            mapLayer = self.GetLayerInfo(layer, key = 'maplayer')
1464
1657
            self.SetItemText(layer, mapName)
1465
1658
            
1466
1659
            if not mapText or not found:
1468
1661
                GWarning(parent = self,
1469
1662
                         message = _("Map <%s> not found.") % mapName)
1470
1663
                return
1471
 
            
 
1664
        
1472
1665
        # update layer data
1473
1666
        if params:
1474
 
            self.SetPyData(layer, (self.GetPyData(layer)[0], params))
1475
 
        self.GetPyData(layer)[0]['propwin'] = propwin
 
1667
            self.SetPyData(layer, (self.GetLayerInfo(layer), params))
 
1668
        self.SetLayerInfo(layer, key = 'propwin', value = propwin)
1476
1669
        
1477
1670
        # change parameters for item in layers list in render.Map
1478
1671
        self.ChangeLayer(layer)
1479
 
 
1480
 
        # set region if auto-zooming is enabled
1481
 
        if dcmd and UserSettings.Get(group = 'display', key = 'autoZooming', subkey = 'enabled'):
1482
 
            mapLayer = self.GetPyData(layer)[0]['maplayer']
1483
 
            if mapLayer.GetType() in ('raster', 'vector'):
1484
 
                render = UserSettings.Get(group = 'display', key = 'autoRendering', subkey = 'enabled')
1485
 
                self.mapdisplay.MapWindow.ZoomToMap(layers = [mapLayer,],
1486
 
                                                    render = render)
1487
 
 
 
1672
        
 
1673
        # set region if auto-zooming is enabled or layer tree contains
 
1674
        # only one map layer
 
1675
        if dcmd:
 
1676
            if not self.mapdisplay.IsPaneShown('3d') and (self.first or
 
1677
                    UserSettings.Get(group = 'display', key = 'autoZooming', subkey = 'enabled')):
 
1678
                mapLayer = self.GetLayerInfo(layer, key = 'maplayer')
 
1679
                if mapLayer.GetType() in ('raster', 'vector'):
 
1680
                    self.mapdisplay.MapWindow.ZoomToMap(layers = [mapLayer,],
 
1681
                                                        render = False)
 
1682
            
 
1683
            self.first = False # first layer has been already added to
 
1684
                               # the layer tree
 
1685
        
1488
1686
        # update nviz session        
1489
 
        if self.lmgr.IsPaneShown('toolbarNviz') and dcmd:
1490
 
            mapLayer = self.GetPyData(layer)[0]['maplayer']
 
1687
        if self.mapdisplay.IsPaneShown('3d') and dcmd:
 
1688
            mapLayer = self.GetLayerInfo(layer, key = 'maplayer')
1491
1689
            mapWin = self.mapdisplay.MapWindow
1492
1690
            if len(mapLayer.GetCmd()) > 0:
1493
 
                id = -1
1494
1691
                if mapLayer.type == 'raster':
1495
1692
                    if mapWin.IsLoaded(layer):
1496
1693
                        mapWin.UnloadRaster(layer)
1510
1707
                    mapWin.LoadVector(layer)
1511
1708
 
1512
1709
                # reset view when first layer loaded
1513
 
                nlayers = len(mapWin.Map.GetListOfLayers(l_type = ('raster', '3d-raster', 'vector'),
1514
 
                                                         l_active = True))
 
1710
                nlayers = len(mapWin.Map.GetListOfLayers(ltype = ('raster', '3d-raster', 'vector'),
 
1711
                                                         active = True))
1515
1712
                if nlayers < 2:
1516
1713
                    mapWin.ResetView()
1517
 
        
1518
 
    def ReorderLayers(self):
1519
 
        """!Add commands from data associated with any valid layers
1520
 
        (checked or not) to layer list in order to match layers in
1521
 
        layer tree."""
1522
1714
 
 
1715
    def GetVisibleLayers(self, skipDigitized=False):
1523
1716
        # make a list of visible layers
1524
 
        treelayers = []
1525
 
        
1526
 
        vislayer = self.GetFirstVisibleItem()
1527
 
        
 
1717
        layers = []
 
1718
 
 
1719
        vislayer = self.GetFirstChild(self.root)[0]
 
1720
 
1528
1721
        if not vislayer or self.GetPyData(vislayer) is None:
1529
 
            return
1530
 
        
 
1722
            return layers
 
1723
 
 
1724
        vdigitLayer = None
 
1725
        if skipDigitized:
 
1726
            digitToolbar = self.mapdisplay.GetToolbar('vdigit')
 
1727
            if digitToolbar:
 
1728
                vdigitLayer = digitToolbar.GetLayer()
 
1729
 
1531
1730
        itemList = ""
1532
 
        
1533
 
        for item in range(self.GetCount()):
 
1731
        while vislayer:
1534
1732
            itemList += self.GetItemText(vislayer) + ','
1535
 
            if self.GetPyData(vislayer)[0]['type'] != 'group':
1536
 
                treelayers.append(self.GetPyData(vislayer)[0]['maplayer'])
1537
 
 
1538
 
            if not self.GetNextVisible(vislayer):
1539
 
                break
1540
 
            else:
1541
 
                vislayer = self.GetNextVisible(vislayer)
1542
 
        
1543
 
        Debug.msg (4, "LayerTree.ReorderLayers(): items=%s" % \
1544
 
                   (itemList))
1545
 
        
1546
 
        # reorder map layers
1547
 
        treelayers.reverse()
1548
 
        self.Map.ReorderLayers(treelayers)
1549
 
        self.reorder = False
1550
 
        
 
1733
            lType = self.GetLayerInfo(vislayer, key='type')
 
1734
            mapLayer = self.GetLayerInfo(vislayer, key='maplayer')
 
1735
            if lType and lType != 'group' and mapLayer is not vdigitLayer:
 
1736
                layers.append(mapLayer)
 
1737
 
 
1738
            vislayer = self.GetNextItem(vislayer)
 
1739
 
 
1740
        Debug.msg(5, "LayerTree.GetVisibleLayers(): items=%s" %
 
1741
                  (reversed(itemList)))
 
1742
 
 
1743
        layers.reverse()
 
1744
        return layers
 
1745
 
1551
1746
    def ChangeLayer(self, item):
1552
 
        """!Change layer"""
1553
 
        type = self.GetPyData(item)[0]['type']
 
1747
        """Change layer"""
 
1748
        type = self.GetLayerInfo(item, key = 'type')
1554
1749
        layerName = None
1555
1750
        
1556
1751
        if type == 'command':
1557
 
            win = self.FindWindowById(self.GetPyData(item)[0]['ctrl'])
 
1752
            win = self.FindWindowById(self.GetLayerInfo(item, key = 'ctrl'))
1558
1753
            if win.GetValue() != None:
1559
1754
                cmd = win.GetValue().split(';')
1560
1755
                cmdlist = []
1564
1759
                chk = self.IsItemChecked(item)
1565
1760
                hidden = not self.IsVisible(item)
1566
1761
        elif type != 'group':
1567
 
            if self.GetPyData(item)[0] is not None:
1568
 
                cmdlist = self.GetPyData(item)[0]['cmd']
1569
 
                opac = self.GetPyData(item)[0]['maplayer'].GetOpacity(float = True)
 
1762
            if self.GetPyData(item) is not None:
 
1763
                cmdlist = self.GetLayerInfo(item, key = 'cmd')
 
1764
                opac = self.GetLayerInfo(item, key = 'maplayer').GetOpacity()
1570
1765
                chk = self.IsItemChecked(item)
1571
1766
                hidden = not self.IsVisible(item)
1572
1767
                # determine layer name
1574
1769
                if not found:
1575
1770
                    layerName = self.GetItemText(item)
1576
1771
        
1577
 
        maplayer = self.Map.ChangeLayer(layer = self.GetPyData(item)[0]['maplayer'], type = type,
 
1772
        maplayer = self.Map.ChangeLayer(layer = self.GetLayerInfo(item, key = 'maplayer'), type = type,
1578
1773
                                        command = cmdlist, name = layerName,
1579
 
                                        l_active = chk, l_hidden = hidden, l_opacity = opac, l_render = False)
 
1774
                                        active = chk, hidden = hidden, opacity = opac, render = False)
1580
1775
        
1581
 
        self.GetPyData(item)[0]['maplayer'] = maplayer
 
1776
        self.SetLayerInfo(item, key = 'maplayer', value = maplayer)
1582
1777
        
1583
1778
        # if digitization tool enabled -> update list of available vector map layers
1584
1779
        if self.mapdisplay.GetToolbar('vdigit'):
1585
1780
            self.mapdisplay.GetToolbar('vdigit').UpdateListOfLayers(updateTool = True)
1586
 
        
 
1781
 
 
1782
        self.Map.SetLayers(self.GetVisibleLayers())
1587
1783
        # redraw map if auto-rendering is enabled
1588
 
        self.rerender = self.reorder = True
1589
 
        
 
1784
        self.rerender = True
 
1785
 
1590
1786
    def OnCloseWindow(self, event):
1591
1787
        pass
1592
1788
        # self.Map.Clean()
1593
1789
 
1594
1790
    def FindItemByData(self, key, value):
1595
 
        """!Find item based on key and value (see PyData[0])
1596
 
        
1597
 
        @return item instance
1598
 
        @return None not found
 
1791
        """Find item based on key and value (see PyData[0]).
 
1792
        
 
1793
        If key is 'name', finds item(s) of given maplayer name.
 
1794
        
 
1795
        :return: item instance
 
1796
        :return: None not found
1599
1797
        """
1600
1798
        item = self.GetFirstChild(self.root)[0]
1601
 
        return self.__FindSubItemByData(item, key, value)
 
1799
        if key == 'name':
 
1800
            return self.__FindSubItemByName(item, value)
 
1801
        else:
 
1802
            return self.__FindSubItemByData(item, key, value)
1602
1803
 
1603
1804
    def FindItemByIndex(self, index):
1604
 
        """!Find item by index (starting at 0)
 
1805
        """Find item by index (starting at 0)
1605
1806
 
1606
 
        @return item instance
1607
 
        @return None not found
 
1807
        :return: item instance
 
1808
        :return: None not found
1608
1809
        """
1609
1810
        item = self.GetFirstChild(self.root)[0]
1610
1811
        i = 0
1612
1813
            if i == index:
1613
1814
                return item
1614
1815
            
1615
 
            item = self.GetNextVisible(item)
 
1816
            item = self.GetNextItem(item)
1616
1817
            i += 1
1617
1818
        
1618
1819
        return None
1619
1820
    
1620
1821
    def EnableItemType(self, type, enable = True):
1621
 
        """!Enable/disable items in layer tree"""
 
1822
        """Enable/disable items in layer tree"""
1622
1823
        item = self.GetFirstChild(self.root)[0]
1623
1824
        while item and item.IsOk():
1624
 
            mapLayer = self.GetPyData(item)[0]['maplayer']
 
1825
            mapLayer = self.GetLayerInfo(item, key = 'maplayer')
1625
1826
            if mapLayer and type == mapLayer.type:
1626
1827
                self.EnableItem(item, enable)
1627
1828
            
1628
1829
            item = self.GetNextSibling(item)
1629
1830
        
1630
1831
    def __FindSubItemByData(self, item, key, value):
1631
 
        """!Support method for FindItemByValue"""
 
1832
        """Support method for FindItemByData"""
1632
1833
        while item and item.IsOk():
1633
 
            try:
1634
 
                itemValue = self.GetPyData(item)[0][key]
1635
 
            except KeyError:
1636
 
                return None
 
1834
            itemValue = self.GetLayerInfo(item, key = key)
1637
1835
            
1638
1836
            if value == itemValue:
1639
1837
                return item
1640
 
            if self.GetPyData(item)[0]['type'] == 'group':
 
1838
            if self.GetLayerInfo(item, key = 'type') == 'group':
1641
1839
                subItem = self.GetFirstChild(item)[0]
1642
1840
                found = self.__FindSubItemByData(subItem, key, value)
1643
1841
                if found:
1646
1844
 
1647
1845
        return None
1648
1846
 
 
1847
    def __FindSubItemByName(self, item, value):
 
1848
        """Support method for FindItemByData for searching by name"""
 
1849
        items = []
 
1850
        while item and item.IsOk():
 
1851
            try:
 
1852
                itemLayer = self.GetLayerInfo(item, key = 'maplayer')
 
1853
            except KeyError:
 
1854
                return None
 
1855
            
 
1856
            if itemLayer and value == itemLayer.GetName():
 
1857
                items.append(item)
 
1858
            if self.GetLayerInfo(item, key = 'type') == 'group':
 
1859
                subItem = self.GetFirstChild(item)[0]
 
1860
                found = self.__FindSubItemByName(subItem, value)
 
1861
                if found:
 
1862
                    items.extend(found)
 
1863
            item = self.GetNextSibling(item)
 
1864
        
 
1865
        if items:
 
1866
            return items
 
1867
        return None
 
1868
 
1649
1869
    def _createCommandCtrl(self):
1650
 
        """!Creates text control for command layer"""
 
1870
        """Creates text control for command layer"""
1651
1871
        height = 25
1652
1872
        if sys.platform in ('win32', 'darwin'):
1653
1873
            height = 40
1654
1874
        ctrl = wx.TextCtrl(self, id = wx.ID_ANY, value = '',
1655
 
                           size = (self.GetSize()[0]-100, height),
1656
 
                           style = wx.TE_PROCESS_ENTER | wx.TE_DONTWRAP)
 
1875
                               pos = wx.DefaultPosition, size = (self.GetSize()[0]-100, height),
 
1876
                               style = wx.TE_PROCESS_ENTER | wx.TE_DONTWRAP)
1657
1877
        return ctrl