~ubuntu-branches/ubuntu/wily/grass/wily

« back to all changes in this revision

Viewing changes to gui/wxpython/gui_modules/colorrules.py

Tags: 7.0.0~rc1+ds1-1~exp1
* New upstream release candidate.
* Repack upstream tarball, remove precompiled Python objects.
* Add upstream metadata.
* Update gbp.conf and Vcs-Git URL to use the experimental branch.
* Update watch file for GRASS 7.0.
* Drop build dependencies for Tcl/Tk, add build dependencies:
  python-numpy, libnetcdf-dev, netcdf-bin, libblas-dev, liblapack-dev
* Update Vcs-Browser URL to use cgit instead of gitweb.
* Update paths to use grass70.
* Add configure options: --with-netcdf, --with-blas, --with-lapack,
  remove --with-tcltk-includes.
* Update patches for GRASS 7.
* Update copyright file, changes:
  - Update copyright years
  - Group files by license
  - Remove unused license sections
* Add patches for various typos.
* Fix desktop file with patch instead of d/rules.
* Use minimal dh rules.
* Bump Standards-Version to 3.9.6, no changes.
* Use dpkg-maintscript-helper to replace directories with symlinks.
  (closes: #776349)
* Update my email to use @debian.org address.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
"""
2
 
@package colorrules.py
3
 
 
4
 
@brief Dialog for interactive management of raster color tables and vector
5
 
rgb_column
6
 
 
7
 
Classes:
8
 
 - ColorTable
9
 
 - BuferedWindow
10
 
 
11
 
(C) 2008 by the GRASS Development Team
12
 
This program is free software under the GNU General Public License
13
 
(>=v2). Read the file COPYING that comes with GRASS for details.
14
 
 
15
 
@author Michael Barton (Arizona State University)
16
 
@author Martin Landa <landa.martin gmail.com> (various updates)
17
 
"""
18
 
 
19
 
import os
20
 
import sys
21
 
import shutil
22
 
 
23
 
import wx
24
 
import wx.lib.colourselect as csel
25
 
import wx.lib.scrolledpanel as scrolled
26
 
 
27
 
from grass.script import core as grass
28
 
 
29
 
import dbm
30
 
import gcmd
31
 
import globalvar
32
 
import gselect
33
 
import render
34
 
import utils
35
 
from debug import Debug as Debug
36
 
from preferences import globalSettings as UserSettings
37
 
 
38
 
class ColorTable(wx.Frame):
39
 
    def __init__(self, parent, id=wx.ID_ANY, title='',
40
 
                 pos=wx.DefaultPosition, size=(-1, -1),
41
 
                 style=wx.DEFAULT_FRAME_STYLE | wx.RESIZE_BORDER,
42
 
                 **kwargs):
43
 
        wx.Frame.__init__(self, parent, id, title, pos, size, style)
44
 
        """
45
 
        Dialog for interactively entering rules for map management
46
 
        commands
47
 
 
48
 
        @param cmd command (given as list)
49
 
        """
50
 
        self.parent = parent # GMFrame
51
 
  
52
 
        self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
53
 
        
54
 
        # grass command
55
 
        self.cmd = kwargs['cmd']
56
 
        
57
 
        # input map to change
58
 
        self.inmap = ''
59
 
        
60
 
        # raster properties
61
 
        self.rast = {
62
 
            # min cat in raster map
63
 
            'min' : None,
64
 
            # max cat in raster map
65
 
            'max' : None,
66
 
            }
67
 
        
68
 
        # vector properties
69
 
        self.vect = {
70
 
            # list of database layers for vector (minimum of 1)
71
 
            'layers' : ['1'],
72
 
            # list of database columns for vector
73
 
            'columns' : [],
74
 
            # vector layer for attribute table to use for setting color
75
 
            'layer' : 1, 
76
 
            # vector attribute table used for setting color         
77
 
            'table' : '',
78
 
            # vector attribute column for assigning colors
79
 
            'column' : '', 
80
 
            # vector attribute column to use for storing colors
81
 
            'rgb' : '',
82
 
            }
83
 
 
84
 
        # rules for creating colortable
85
 
        self.ruleslines = {}
86
 
 
87
 
        # instance of render.Map to be associated with display
88
 
        self.Map   = render.Map()  
89
 
 
90
 
        # reference to layer with preview
91
 
        self.layer = None          
92
 
        
93
 
        if self.cmd == 'r.colors':
94
 
            self.SetTitle(_('Create new color table for raster map'))
95
 
            self.elem = 'cell'
96
 
            crlabel = _('Enter raster cat values or percents')
97
 
        elif self.cmd == 'vcolors':
98
 
            self.SetTitle(_('Create new color table for vector map'))
99
 
            self.elem = 'vector'
100
 
            crlabel = _('Enter vector attribute values or ranges (n or n1 to n2)')
101
 
 
102
 
        #
103
 
        # Set the size & cursor
104
 
        #
105
 
        self.SetClientSize(size)
106
 
 
107
 
        ### self.panel = wx.Panel(parent=self, id=wx.ID_ANY)
108
 
 
109
 
        # top controls
110
 
        if self.cmd == 'r.colors':
111
 
            maplabel = _('Select raster map:')
112
 
        elif self.cmd == 'vcolors':
113
 
            maplabel = _('Select vector map:')
114
 
        inputBox = wx.StaticBox(parent=self, id=wx.ID_ANY,
115
 
                                label=" %s " % maplabel)
116
 
        self.inputSizer = wx.StaticBoxSizer(inputBox, wx.VERTICAL)
117
 
        self.selectionInput = gselect.Select(parent=self, id=wx.ID_ANY,
118
 
                                             size=globalvar.DIALOG_GSELECT_SIZE,
119
 
                                             type=self.elem)
120
 
        
121
 
        self.ovrwrtcheck = wx.CheckBox(parent=self, id=wx.ID_ANY,
122
 
                                       label=_('replace existing color table'))
123
 
        self.ovrwrtcheck.SetValue(UserSettings.Get(group='cmd', key='overwrite', subkey='enabled'))
124
 
        self.helpbtn = wx.Button(parent=self, id=wx.ID_HELP)
125
 
 
126
 
        if self.elem == 'vector':
127
 
            self.cb_vl_label = wx.StaticText(parent=self, id=wx.ID_ANY,
128
 
                                             label=_('Layer:'))
129
 
            self.cb_vc_label = wx.StaticText(parent=self, id=wx.ID_ANY,
130
 
                                             label=_('Attribute column:'))
131
 
            self.cb_vrgb_label = wx.StaticText(parent=self, id=wx.ID_ANY,
132
 
                                               label=_('RGB color column:'))
133
 
            self.cb_vlayer = gselect.LayerSelect(self)
134
 
            self.cb_vcol = gselect.ColumnSelect(self)
135
 
            self.cb_vrgb = gselect.ColumnSelect(self)
136
 
        
137
 
        # color table and preview window
138
 
        self.cr_label = wx.StaticText(parent=self, id=wx.ID_ANY,
139
 
                                      label=crlabel)
140
 
        self.cr_panel = self.__colorrulesPanel()
141
 
        # add two rules as default
142
 
        self.AddRules(2)
143
 
        
144
 
        self.numRules = wx.SpinCtrl(parent=self, id=wx.ID_ANY,
145
 
                                    min=1, max=1e6)
146
 
        
147
 
        # initialize preview display
148
 
        self.InitDisplay()
149
 
        self.preview = BufferedWindow(self, id=wx.ID_ANY, size=(400, 300),
150
 
                                      Map=self.Map)
151
 
        self.preview.EraseMap()
152
 
        
153
 
        self.btnCancel = wx.Button(parent=self, id=wx.ID_CANCEL)
154
 
        self.btnApply = wx.Button(parent=self, id=wx.ID_APPLY) 
155
 
        self.btnOK = wx.Button(parent=self, id=wx.ID_OK)
156
 
        self.btnOK.SetDefault()
157
 
        self.btnOK.Enable(False)
158
 
        self.btnApply.Enable(False)
159
 
 
160
 
        self.btnPreview = wx.Button(parent=self, id=wx.ID_ANY,
161
 
                                    label=_("Preview"))
162
 
        self.btnPreview.Enable(False)
163
 
        self.btnAdd = wx.Button(parent=self, id=wx.ID_ADD)
164
 
        
165
 
        # bindings
166
 
        self.Bind(wx.EVT_BUTTON, self.OnHelp, self.helpbtn)
167
 
        self.selectionInput.Bind(wx.EVT_TEXT, self.OnSelectionInput)
168
 
        self.Bind(wx.EVT_BUTTON, self.OnCancel, self.btnCancel)
169
 
        self.Bind(wx.EVT_BUTTON, self.OnApply, self.btnApply)
170
 
        self.Bind(wx.EVT_BUTTON, self.OnOK, self.btnOK)
171
 
        self.Bind(wx.EVT_BUTTON, self.OnPreview, self.btnPreview)
172
 
        self.Bind(wx.EVT_BUTTON, self.OnAddRules, self.btnAdd)
173
 
        self.Bind(wx.EVT_CLOSE,  self.OnCloseWindow)
174
 
 
175
 
        # additional bindings for vector color management
176
 
        if self.cmd == 'vcolors':
177
 
            self.Bind(wx.EVT_COMBOBOX, self.OnLayerSelection, self.cb_vlayer)
178
 
            self.Bind(wx.EVT_COMBOBOX, self.OnColumnSelection, self.cb_vcol)
179
 
            self.Bind(wx.EVT_COMBOBOX, self.OnRGBColSelection, self.cb_vrgb)
180
 
 
181
 
        # set map layer from layer tree
182
 
        try:
183
 
            layer = self.parent.curr_page.maptree.layer_selected
184
 
        except:
185
 
            layer = None
186
 
        if layer:
187
 
            mapLayer = self.parent.curr_page.maptree.GetPyData(layer)[0]['maplayer']
188
 
            name = mapLayer.GetName()
189
 
            type = mapLayer.GetType()
190
 
            if (type == 'raster' and self.elem == 'cell') or \
191
 
                    (type == 'vector' and self.elem == 'vector'):
192
 
                self.selectionInput.SetValue(name)
193
 
                self.inmap = name
194
 
                self.OnSelectionInput(None)
195
 
        
196
 
        # layout
197
 
        self.__doLayout()
198
 
 
199
 
        self.CentreOnScreen()
200
 
        self.Show()
201
 
        
202
 
    def __doLayout(self):
203
 
        sizer = wx.BoxSizer(wx.VERTICAL)
204
 
        
205
 
        #
206
 
        # input
207
 
        #
208
 
        self.inputSizer.Add(item=self.selectionInput,
209
 
                       flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL | wx.EXPAND, border=5)
210
 
        replaceSizer = wx.BoxSizer(wx.HORIZONTAL)
211
 
        replaceSizer.Add(item=self.ovrwrtcheck, proportion=1,
212
 
                         flag=wx.ALL | wx.EXPAND, border=1)
213
 
        replaceSizer.Add(item=self.helpbtn, proportion=0,
214
 
                         flag=wx.ALIGN_RIGHT | wx.ALL, border=1)
215
 
 
216
 
        self.inputSizer.Add(item=replaceSizer, proportion=1,
217
 
                       flag=wx.ALL | wx.EXPAND, border=1)
218
 
 
219
 
        #
220
 
        # body & preview
221
 
        #
222
 
        bodySizer =  wx.GridBagSizer(hgap=5, vgap=5)
223
 
 
224
 
        row = 0
225
 
        bodySizer.Add(item=self.cr_label, pos=(row, 0), span=(1, 3),
226
 
                      flag=wx.ALL, border=5)
227
 
 
228
 
        if self.cmd == 'vcolors':
229
 
            vSizer = wx.GridBagSizer(hgap=5, vgap=5)
230
 
            vSizer.Add(self.cb_vl_label, pos=(0, 0),
231
 
                       flag=wx.ALIGN_CENTER_VERTICAL)
232
 
            vSizer.Add(self.cb_vlayer,  pos=(0, 1),
233
 
                       flag=wx.ALIGN_CENTER_VERTICAL)
234
 
            vSizer.Add(self.cb_vc_label, pos=(0, 2),
235
 
                       flag=wx.ALIGN_CENTER_VERTICAL)
236
 
            vSizer.Add(self.cb_vcol, pos=(0, 3),
237
 
                       flag=wx.ALIGN_CENTER_VERTICAL)
238
 
            vSizer.Add(self.cb_vrgb_label, pos=(1, 2),
239
 
                      flag=wx.ALIGN_CENTER_VERTICAL)
240
 
            vSizer.Add(self.cb_vrgb, pos=(1, 3),
241
 
                       flag=wx.ALIGN_CENTER_VERTICAL)
242
 
            row += 1
243
 
            bodySizer.Add(item=vSizer, pos=(row, 0), span=(1, 3))
244
 
        
245
 
        row += 1
246
 
        bodySizer.Add(item=self.cr_panel, pos=(row, 0), span=(1, 2))
247
 
        
248
 
        bodySizer.Add(item=self.preview, pos=(row, 2),
249
 
                      flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=10)
250
 
        bodySizer.AddGrowableCol(2)
251
 
        
252
 
        row += 1
253
 
        bodySizer.Add(item=self.numRules, pos=(row, 0),
254
 
                      flag=wx.ALIGN_CENTER_VERTICAL)
255
 
        
256
 
        bodySizer.Add(item=self.btnAdd, pos=(row, 1))
257
 
        bodySizer.Add(item=self.btnPreview, pos=(row, 2),
258
 
                      flag=wx.ALIGN_RIGHT)
259
 
        
260
 
        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
261
 
        btnSizer.Add(self.btnCancel,
262
 
                     flag=wx.LEFT | wx.RIGHT, border=5)
263
 
        btnSizer.Add(self.btnApply,
264
 
                     flag=wx.LEFT | wx.RIGHT, border=5)
265
 
        btnSizer.Add(self.btnOK,
266
 
                     flag=wx.LEFT | wx.RIGHT, border=5)
267
 
        
268
 
        sizer.Add(item=self.inputSizer, proportion=0,
269
 
                  flag=wx.ALL | wx.EXPAND, border=5)
270
 
        
271
 
        sizer.Add(item=bodySizer, proportion=1,
272
 
                  flag=wx.ALL | wx.EXPAND, border=5)
273
 
 
274
 
        sizer.Add(item=wx.StaticLine(parent=self, id=wx.ID_ANY,
275
 
                                     style=wx.LI_HORIZONTAL),
276
 
                  proportion=0,
277
 
                  flag=wx.EXPAND | wx.ALL, border=5) 
278
 
        
279
 
        sizer.Add(item=btnSizer, proportion=0,
280
 
                  flag=wx.ALL | wx.ALIGN_RIGHT, border=5)
281
 
        
282
 
        self.SetSizer(sizer)
283
 
        sizer.Fit(self)
284
 
        self.Layout()
285
 
        
286
 
    def __colorrulesPanel(self):
287
 
        cr_panel = scrolled.ScrolledPanel(parent=self, id=wx.ID_ANY,
288
 
                                          size=(180, 300),
289
 
                                          style=wx.TAB_TRAVERSAL | wx.SUNKEN_BORDER)
290
 
        
291
 
        self.cr_sizer = wx.GridBagSizer(vgap=2, hgap=4)
292
 
        
293
 
        cr_panel.SetSizer(self.cr_sizer)
294
 
        cr_panel.SetAutoLayout(True)
295
 
        
296
 
        return cr_panel        
297
 
 
298
 
    def OnAddRules(self, event):
299
 
        """Add rules button pressed"""
300
 
        nrules = self.numRules.GetValue()
301
 
        self.AddRules(nrules)
302
 
        
303
 
    def AddRules(self, nrules):
304
 
        """Add rules"""
305
 
        snum = len(self.ruleslines.keys())
306
 
        for num in range(snum, snum+nrules):
307
 
            # enable
308
 
            enable = wx.CheckBox(parent=self.cr_panel, id=num)
309
 
            enable.SetValue(True)
310
 
            self.Bind(wx.EVT_CHECKBOX, self.OnRuleEnable, enable)
311
 
            # value
312
 
            txt_ctrl = wx.TextCtrl(parent=self.cr_panel, id=1000+num, value='',
313
 
                                   size=(100,-1),
314
 
                                   style=wx.TE_NOHIDESEL)
315
 
            self.Bind(wx.EVT_TEXT, self.OnRuleValue, txt_ctrl)
316
 
            # color
317
 
            color_ctrl = csel.ColourSelect(self.cr_panel, id=2000+num)
318
 
            self.Bind(csel.EVT_COLOURSELECT, self.OnRuleColor, color_ctrl)
319
 
            self.ruleslines[enable.GetId()] = { 'value' : '',
320
 
                                                'color': "0:0:0" }
321
 
            
322
 
            self.cr_sizer.Add(item=enable, pos=(num, 0),
323
 
                              flag=wx.ALIGN_CENTER_VERTICAL)
324
 
            self.cr_sizer.Add(item=txt_ctrl, pos=(num, 1),
325
 
                              flag=wx.ALIGN_CENTER | wx.RIGHT, border=5)
326
 
            self.cr_sizer.Add(item=color_ctrl, pos=(num, 2),
327
 
                              flag=wx.ALIGN_CENTER | wx.RIGHT, border=5)
328
 
        
329
 
        self.cr_panel.Layout()
330
 
        self.cr_panel.SetupScrolling()
331
 
        
332
 
    def InitDisplay(self):
333
 
        """
334
 
        Initialize preview display, set dimensions and region
335
 
        """
336
 
        #self.width, self.height = self.GetClientSize()
337
 
        self.width = self.Map.width = 400
338
 
        self.height = self.Map.height = 300
339
 
        self.Map.geom = self.width, self.height
340
 
 
341
 
    def OnErase(self, event):
342
 
        """
343
 
        Erase the histogram display
344
 
        """
345
 
        self.PreviewWindow.Draw(self.HistWindow.pdc, pdctype='clear')
346
 
 
347
 
    def OnCloseWindow(self, event):
348
 
        """
349
 
        Window closed
350
 
        Also remove associated rendered images
351
 
        """
352
 
        #try:
353
 
        #    self.propwin.Close(True)
354
 
        #except:
355
 
        #    pass
356
 
        self.Map.Clean()
357
 
        self.Destroy()
358
 
        
359
 
    def OnSelectionInput(self, event):
360
 
        if event:
361
 
            self.inmap = event.GetString()
362
 
        
363
 
        if self.inmap == '':
364
 
            self.btnPreview.Enable(False)
365
 
            self.btnOK.Enable(False)
366
 
            self.btnApply.Enable(False)
367
 
            return
368
 
        
369
 
        if self.elem == 'cell':
370
 
            cmdlist = ['r.info',
371
 
                       '-r',
372
 
                       'map=%s' % self.inmap]
373
 
 
374
 
            try:
375
 
                p = gcmd.Command(cmdlist)
376
 
 
377
 
                for line in p.ReadStdOutput():
378
 
                    if 'min' in line:
379
 
                        self.rast['min'] = float(line.split('=')[1])
380
 
                    elif 'max' in line:
381
 
                        self.rast['max'] = float(line.split('=')[1])
382
 
            except gcmd.CmdError:
383
 
                self.inmap = ''
384
 
                self.rast['min'] = self.rast['max'] = None
385
 
                self.btnPreview.Enable(False)
386
 
                self.btnOK.Enable(False)
387
 
                self.btnApply.Enable(False)
388
 
                self.preview.EraseMap()
389
 
                self.cr_label.SetLabel(_('Enter raster cat values or percents'))
390
 
                return
391
 
            
392
 
            self.cr_label.SetLabel(_('Enter raster cat values or percents (range = %(min)d-%(max)d)') %
393
 
                                     { 'min' : self.rast['min'],
394
 
                                       'max' : self.rast['max'] })
395
 
        elif self.elem == 'vector':
396
 
            # initialize layer selection combobox
397
 
            self.cb_vlayer.InsertLayers(self.inmap)
398
 
            # initialize attribute table for layer=1
399
 
            layer = int(self.vect['layer'])
400
 
            self.vect['table'] = gselect.VectorDBInfo(self.inmap).layers[layer]['table']
401
 
            # initialize column selection comboboxes 
402
 
            self.cb_vcol.InsertColumns(vector=self.inmap, layer=layer)
403
 
            self.cb_vrgb.InsertColumns(vector=self.inmap, layer=layer)
404
 
            self.Update()
405
 
    
406
 
        self.btnPreview.Enable(True)
407
 
        self.btnOK.Enable(True)
408
 
        self.btnApply.Enable(True)
409
 
        
410
 
    def OnLayerSelection(self, event):
411
 
        # reset choices in column selection comboboxes if layer changes
412
 
        self.vlayer = int(event.GetString())
413
 
        self.vtable = gselect.VectorDBInfo(self.inmap).layers[str(self.vlayer)]
414
 
        self.cb_vcol.InsertColumns(vector=self.inmap, layer=self.vlayer)
415
 
        self.cb_vrgb.InsertColumns(vector=self.inmap, layer=self.vlayer)
416
 
        self.Update()
417
 
        
418
 
    def OnColumnSelection(self, event):
419
 
        self.vect['column'] = event.GetString()
420
 
    
421
 
    def OnRGBColSelection(self, event):
422
 
        self.vect['rgb'] = event.GetString()
423
 
        
424
 
    def OnRuleEnable(self, event):
425
 
        """Rule enabled/disabled"""
426
 
        id = event.GetId()
427
 
        
428
 
        if event.IsChecked():
429
 
            value = self.FindWindowById(id+1000).GetValue()
430
 
            color = self.FindWindowById(id+2000).GetValue()
431
 
            color_str = str(color[0]) + ':' \
432
 
                + str(color[1]) + ':' + \
433
 
                str(color[2])
434
 
            
435
 
            self.ruleslines[id] = {
436
 
                'value' : value,
437
 
                'color' : color_str }
438
 
        else:
439
 
            del self.ruleslines[id]
440
 
        
441
 
    def OnRuleValue(self, event):
442
 
        """Rule value changed"""
443
 
        num = event.GetId()
444
 
        vals = event.GetString().strip()
445
 
 
446
 
        if vals == '':
447
 
            return
448
 
 
449
 
        tc = self.FindWindowById(num)
450
 
        
451
 
        if self.elem == 'cell':
452
 
 
453
 
            try:
454
 
                if vals != '-' and \
455
 
                        vals[-1] != '%':
456
 
                    float(vals)
457
 
            except (IndexError, ValueError):
458
 
                tc.SetValue('')
459
 
                self.ruleslines[num-1000]['value'] = ''
460
 
                return
461
 
            
462
 
            self.ruleslines[num-1000]['value'] = vals
463
 
            
464
 
        elif self.elem == 'vector':
465
 
            if self.vect['column'] == '' or self.vect['rgb'] == '':
466
 
                tc.SetValue('')
467
 
                wx.MessageBox(parent=self,
468
 
                              message=_("Please select attribute column "
469
 
                                        "and RGB color column first"),
470
 
                              style=wx.CENTRE)
471
 
            else:
472
 
                try:
473
 
                    self.ruleslines[num-1000]['value'] = self.SQLConvert(vals)
474
 
                except ValueError:
475
 
                    tc.SetValue('')
476
 
                    self.ruleslines[num-1000]['value'] = ''
477
 
                    return
478
 
        
479
 
    def OnRuleColor(self, event):
480
 
        """Rule color changed"""
481
 
        num = event.GetId()
482
 
        
483
 
        rgba_color = event.GetValue()
484
 
        
485
 
        rgb_string = str(rgba_color[0]) + ':' \
486
 
            + str(rgba_color[1]) + ':' + \
487
 
            str(rgba_color[2])
488
 
        
489
 
        self.ruleslines[num-2000]['color'] = rgb_string
490
 
        
491
 
    def SQLConvert(self, vals):
492
 
        valslist = []
493
 
        valslist = vals.split('to')
494
 
        if len(valslist) == 1:
495
 
            sqlrule = '%s=%s' % (self.vect['column'], valslist[0])
496
 
        elif len(valslist) > 1:
497
 
            sqlrule = '%s>=%s AND %s<=%s' % (self.vect['column'], valslist[0],
498
 
                                             self.vect['column'], valslist[1])
499
 
        else:
500
 
            return None
501
 
        
502
 
        return sqlrule
503
 
        
504
 
    def OnApply(self, event):
505
 
        self.CreateColorTable()
506
 
    
507
 
    def OnOK(self, event):
508
 
        self.OnApply(event)
509
 
        self.Destroy()
510
 
    
511
 
    def OnCancel(self, event):
512
 
        self.Destroy()
513
 
        
514
 
    def OnPreview(self, event):
515
 
        """Update preview"""
516
 
        # raster
517
 
        if self.elem == 'cell':
518
 
            cmdlist = ['d.rast',
519
 
                       'map=%s' % self.inmap]
520
 
            ltype = 'raster'
521
 
            
522
 
            # find existing color table and copy to temp file
523
 
            try:
524
 
                name, mapset = self.inmap.split('@')
525
 
                old_colrtable = grass.find_file(name=name, element='colr2/' + mapset)['file']
526
 
            except (TypeError, ValueError):
527
 
                old_colrtable = None
528
 
            
529
 
            if old_colrtable:
530
 
                colrtemp = utils.GetTempfile()
531
 
                shutil.copyfile(old_colrtable, colrtemp)
532
 
        # vector
533
 
        elif self.elem == 'vector':
534
 
            cmdlist = ['d.vect',
535
 
                        '-a',
536
 
                       'map=%s' % self.inmap,
537
 
                       'rgb_column=%s' % self.vect["rgb"],
538
 
                       'type=point,line,boundary,area']
539
 
            ltype = 'vector'
540
 
        else:
541
 
            return
542
 
        
543
 
        if not self.layer:
544
 
            self.layer = self.Map.AddLayer(type=ltype, name='preview', command=cmdlist,
545
 
                                           l_active=True, l_hidden=False, l_opacity=1.0,
546
 
                                           l_render=False) 
547
 
        else:
548
 
            self.layer.SetCmd(cmdlist)
549
 
        
550
 
        # apply new color table and display preview
551
 
        self.CreateColorTable(force=True)
552
 
        self.preview.UpdatePreview()
553
 
        
554
 
        # restore previous color table
555
 
        if self.elem == 'cell':
556
 
            if old_colrtable:
557
 
                shutil.copyfile(colrtemp, old_colrtable)
558
 
                os.remove(colrtemp)
559
 
            else:
560
 
                gcmd.Command(['r.colors',
561
 
                              '-r',
562
 
                              'map=%s' % self.inmap])
563
 
        
564
 
    def OnHelp(self, event):
565
 
        """Show GRASS manual page"""
566
 
        gcmd.Command(['g.manual',
567
 
                      '--quiet', 
568
 
                      '%s' % self.cmd])
569
 
    
570
 
    def CreateColorTable(self, force=False):
571
 
        """Creates color table"""
572
 
        rulestxt = ''
573
 
        
574
 
        for rule in self.ruleslines.itervalues():
575
 
            if not rule['value']: # skip empty rules
576
 
                continue
577
 
            
578
 
            if self.elem == 'cell':
579
 
                rulestxt += rule['value'] + ' ' + rule['color'] + '\n'
580
 
            elif self.elem == 'vector':
581
 
                rulestxt += "UPDATE %s SET %s='%s' WHERE %s ;\n" % (self.vect['table'],
582
 
                                                                    self.vect['rgb'],
583
 
                                                                    rule['color'],
584
 
                                                                    rule['value'])
585
 
        if rulestxt == '':
586
 
            return
587
 
        
588
 
        gtemp = utils.GetTempfile()
589
 
        output = open(gtemp, "w")
590
 
        try:
591
 
            output.write(rulestxt)
592
 
        finally:
593
 
            output.close()
594
 
        
595
 
        if self.elem == 'cell': 
596
 
            cmdlist = ['r.colors',
597
 
                       'map=%s' % self.inmap,
598
 
                       'rules=%s' % gtemp]
599
 
            
600
 
            if not force and \
601
 
                    not self.ovrwrtcheck.IsChecked():
602
 
                cmdlist.append('-w')
603
 
        
604
 
        elif self.elem == 'vector':
605
 
            cmdlist = ['db.execute',
606
 
                       'input=%s' % gtemp]
607
 
        
608
 
        p = gcmd.Command(cmdlist)
609
 
        
610
 
class BufferedWindow(wx.Window):
611
 
    """A Buffered window class"""
612
 
    def __init__(self, parent, id,
613
 
                 pos = wx.DefaultPosition,
614
 
                 size = wx.DefaultSize,
615
 
                 style=wx.NO_FULL_REPAINT_ON_RESIZE,
616
 
                 Map=None):
617
 
 
618
 
        wx.Window.__init__(self, parent, id, pos, size, style)
619
 
 
620
 
        self.parent = parent
621
 
        self.Map = Map
622
 
        
623
 
        # re-render the map from GRASS or just redraw image
624
 
        self.render = True
625
 
        # indicates whether or not a resize event has taken place
626
 
        self.resize = False 
627
 
 
628
 
        #
629
 
        # event bindings
630
 
        #
631
 
        self.Bind(wx.EVT_PAINT,        self.OnPaint)
632
 
        self.Bind(wx.EVT_IDLE,         self.OnIdle)
633
 
        self.Bind(wx.EVT_ERASE_BACKGROUND, lambda x: None)
634
 
 
635
 
        #
636
 
        # render output objects
637
 
        #
638
 
        # image file to be rendered
639
 
        self.mapfile = None 
640
 
        # wx.Image object (self.mapfile)
641
 
        self.img = None
642
 
 
643
 
        self.pdc = wx.PseudoDC()
644
 
        # will store an off screen empty bitmap for saving to file
645
 
        self._Buffer = None 
646
 
 
647
 
        # make sure that extents are updated at init
648
 
        self.Map.region = self.Map.GetRegion()
649
 
        self.Map.SetRegion()
650
 
 
651
 
    def Draw(self, pdc, img=None, pdctype='image'):
652
 
        """Draws preview or clears window"""
653
 
        pdc.BeginDrawing()
654
 
 
655
 
        Debug.msg (3, "BufferedWindow.Draw(): pdctype=%s" % (pdctype))
656
 
 
657
 
        if pdctype == 'clear': # erase the display
658
 
            bg = wx.WHITE_BRUSH
659
 
            pdc.SetBackground(bg)
660
 
            pdc.Clear()
661
 
            self.Refresh()
662
 
            pdc.EndDrawing()
663
 
            return
664
 
 
665
 
        if pdctype == 'image' and img:
666
 
            bg = wx.TRANSPARENT_BRUSH
667
 
            pdc.SetBackground(bg)
668
 
            bitmap = wx.BitmapFromImage(img)
669
 
            w, h = bitmap.GetSize()
670
 
            pdc.DrawBitmap(bitmap, 0, 0, True) # draw the composite map
671
 
            
672
 
        pdc.EndDrawing()
673
 
        self.Refresh()
674
 
 
675
 
    def OnPaint(self, event):
676
 
        """Draw pseudo DC to buffer"""
677
 
        self._Buffer = wx.EmptyBitmap(self.Map.width, self.Map.height)
678
 
        dc = wx.BufferedPaintDC(self, self._Buffer)
679
 
        
680
 
        # use PrepareDC to set position correctly
681
 
        self.PrepareDC(dc)
682
 
        
683
 
        # we need to clear the dc BEFORE calling PrepareDC
684
 
        bg = wx.Brush(self.GetBackgroundColour())
685
 
        dc.SetBackground(bg)
686
 
        dc.Clear()
687
 
        
688
 
        # create a clipping rect from our position and size
689
 
        # and the Update Region
690
 
        rgn = self.GetUpdateRegion()
691
 
        r = rgn.GetBox()
692
 
        
693
 
        # draw to the dc using the calculated clipping rect
694
 
        self.pdc.DrawToDCClipped(dc, r)
695
 
        
696
 
    def OnSize(self, event):
697
 
        """Init image size to match window size"""
698
 
        # set size of the input image
699
 
        self.Map.width, self.Map.height = self.GetClientSize()
700
 
 
701
 
        # Make new off screen bitmap: this bitmap will always have the
702
 
        # current drawing in it, so it can be used to save the image to
703
 
        # a file, or whatever.
704
 
        self._Buffer = wx.EmptyBitmap(self.Map.width, self.Map.height)
705
 
 
706
 
        # get the image to be rendered
707
 
        self.img = self.GetImage()
708
 
 
709
 
        # update map display
710
 
        if self.img and self.Map.width + self.Map.height > 0: # scale image during resize
711
 
            self.img = self.img.Scale(self.Map.width, self.Map.height)
712
 
            self.render = False
713
 
            self.UpdatePreview()
714
 
 
715
 
        # re-render image on idle
716
 
        self.resize = True
717
 
 
718
 
    def OnIdle(self, event):
719
 
        """Only re-render a preview image from GRASS during
720
 
        idle time instead of multiple times during resizing.
721
 
        """
722
 
        if self.resize:
723
 
            self.render = True
724
 
            self.UpdatePreview()
725
 
        event.Skip()
726
 
 
727
 
    def GetImage(self):
728
 
        """Converts files to wx.Image"""
729
 
        if self.Map.mapfile and os.path.isfile(self.Map.mapfile) and \
730
 
                os.path.getsize(self.Map.mapfile):
731
 
            img = wx.Image(self.Map.mapfile, wx.BITMAP_TYPE_ANY)
732
 
        else:
733
 
            img = None
734
 
        
735
 
        return img
736
 
    
737
 
    def UpdatePreview(self, img=None):
738
 
        """Update canvas if window changes geometry"""
739
 
        Debug.msg (2, "BufferedWindow.UpdatePreview(%s): render=%s" % (img, self.render))
740
 
        oldfont = ""
741
 
        oldencoding = ""
742
 
 
743
 
        if self.render:
744
 
            # make sure that extents are updated
745
 
            self.Map.region = self.Map.GetRegion()
746
 
            self.Map.SetRegion()
747
 
            
748
 
            # render new map images
749
 
            self.mapfile = self.Map.Render(force=self.render)
750
 
            self.img = self.GetImage()
751
 
            self.resize = False
752
 
 
753
 
        if not self.img:
754
 
            return
755
 
        
756
 
        # paint images to PseudoDC
757
 
        self.pdc.Clear()
758
 
        self.pdc.RemoveAll()
759
 
        # draw map image background
760
 
        self.Draw(self.pdc, self.img, pdctype='image')
761
 
 
762
 
        self.resize = False
763
 
        
764
 
    def EraseMap(self):
765
 
        """Erase preview"""
766
 
        self.Draw(self.pdc, pdctype='clear')
767