GRASS Programmer's Manual  6.5.svn(2014)-r66266
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
colorrules.py
Go to the documentation of this file.
1 """
2 @package module.colorrules
3 
4 @brief Dialog for interactive management of raster/vector color tables
5 and color rules.
6 
7 Classes:
8  - colorrules::RulesPanel
9  - colorrules::ColorTable
10  - colorrules::RasterColorTable
11  - colorrules::VectorColorTable
12  - colorrules::BufferedWindow
13 
14 (C) 2008, 2010-2012 by the GRASS Development Team
15 
16 This program is free software under the GNU General Public License
17 (>=v2). Read the file COPYING that comes with GRASS for details.
18 
19 @author Michael Barton (Arizona State University)
20 @author Martin Landa <landa.martin gmail.com> (various updates, pre-defined color table)
21 @author Anna Kratochvilova <kratochanna gmail.com> (split to base and derived classes)
22 """
23 
24 import os
25 import shutil
26 import copy
27 import tempfile
28 
29 import wx
30 import wx.lib.colourselect as csel
31 import wx.lib.scrolledpanel as scrolled
32 import wx.lib.filebrowsebutton as filebrowse
33 
34 import grass.script as grass
35 
36 from core import globalvar
37 from core import utils
38 from core.gcmd import GMessage, RunCommand, GError
39 from gui_core.gselect import Select, LayerSelect, ColumnSelect, VectorDBInfo
40 from core.render import Map
41 from gui_core.forms import GUI
42 from core.debug import Debug as Debug
43 from core.settings import UserSettings
44 
45 class RulesPanel:
46  def __init__(self, parent, mapType, attributeType, properties, panelWidth = 180):
47  """!Create rules panel
48 
49  @param mapType raster/vector
50  @param attributeType color/size for choosing widget type
51  @param properties properties of classes derived from ColorTable
52  @param panelWidth width of scroll panel"""
53 
54  self.ruleslines = {}
55  self.mapType = mapType
56  self.attributeType = attributeType
57  self.properties = properties
58  self.parent = parent
59  self.panelWidth = panelWidth
60 
61  self.mainSizer = wx.FlexGridSizer(cols = 3, vgap = 6, hgap = 4)
62  # put small border at the top of panel
63  for i in range(3):
64  self.mainSizer.Add(item = wx.Size(3, 3))
65 
66  self.mainPanel = scrolled.ScrolledPanel(parent, id = wx.ID_ANY,
67  size = (self.panelWidth, 300),
68  style = wx.TAB_TRAVERSAL | wx.SUNKEN_BORDER)
69 
70  # (un)check all
71  self.checkAll = wx.CheckBox(parent, id = wx.ID_ANY, label = _("Check all"))
72  self.checkAll.SetValue(True)
73  # clear button
74  self.clearAll = wx.Button(parent, id = wx.ID_ANY, label = _("Clear all"))
75  # determines how many rules should be added
76  self.numRules = wx.SpinCtrl(parent, id = wx.ID_ANY,
77  min = 1, max = 1e6, initial = 1)
78  # add rules
79  self.btnAdd = wx.Button(parent, id = wx.ID_ADD)
80 
81  self.btnAdd.Bind(wx.EVT_BUTTON, self.OnAddRules)
82  self.checkAll.Bind(wx.EVT_CHECKBOX, self.OnCheckAll)
83  self.clearAll.Bind(wx.EVT_BUTTON, self.OnClearAll)
84 
85  self.mainPanel.SetSizer(self.mainSizer)
86  self.mainPanel.SetAutoLayout(True)
87  self.mainPanel.SetupScrolling()
88 
89  def Clear(self):
90  """!Clear and widgets and delete information"""
91  self.ruleslines.clear()
92  self.mainSizer.Clear(deleteWindows=True)
93 
94  def OnCheckAll(self, event):
95  """!(Un)check all rules"""
96  check = event.GetInt()
97  for child in self.mainPanel.GetChildren():
98  if child.GetName() == 'enable':
99  child.SetValue(check)
100  else:
101  child.Enable(check)
102 
103  def OnClearAll(self, event):
104  """!Delete all widgets in panel"""
105  self.Clear()
106 
107  def OnAddRules(self, event):
108  """!Add rules button pressed"""
109  nrules = self.numRules.GetValue()
110  self.AddRules(nrules)
111 
112  def AddRules(self, nrules, start = False):
113  """!Add rules
114  @param start set widgets (not append)"""
115 
116  snum = len(self.ruleslines.keys())
117  if start:
118  snum = 0
119  for num in range(snum, snum + nrules):
120  # enable
121  enable = wx.CheckBox(parent = self.mainPanel, id = num)
122  enable.SetValue(True)
123  enable.SetName('enable')
124  enable.Bind(wx.EVT_CHECKBOX, self.OnRuleEnable)
125  # value
126  txt_ctrl = wx.TextCtrl(parent = self.mainPanel, id = 1000 + num,
127  size = (80, -1),
128  style = wx.TE_NOHIDESEL)
129  if self.mapType == 'vector':
130  txt_ctrl.SetToolTipString(_("Enter vector attribute values"))
131  txt_ctrl.Bind(wx.EVT_TEXT, self.OnRuleValue)
132  txt_ctrl.SetName('source')
133  if self.attributeType == 'color':
134  # color
135  columnCtrl = csel.ColourSelect(self.mainPanel, id = 2000 + num,
136  size = globalvar.DIALOG_COLOR_SIZE)
137  columnCtrl.Bind(csel.EVT_COLOURSELECT, self.OnRuleColor)
138  columnCtrl.SetName('target')
139  if not start:
140  self.ruleslines[enable.GetId()] = { 'value' : '',
141  'color': "0:0:0" }
142  else:
143  # size or width
144  init = 2
145  if self.attributeType == 'size':
146  init = 100
147  columnCtrl = wx.SpinCtrl(self.mainPanel, id = 2000 + num,
148  size = (50, -1), min = 1, max = 1e4,
149  initial = init)
150  columnCtrl.Bind(wx.EVT_SPINCTRL, self.OnRuleSize)
151  columnCtrl.Bind(wx.EVT_TEXT, self.OnRuleSize)
152  columnCtrl.SetName('target')
153  if not start:
154  self.ruleslines[enable.GetId()] = { 'value' : '',
155  self.attributeType: init }
156 
157  self.mainSizer.Add(item = enable, proportion = 0,
158  flag = wx.ALIGN_CENTER_VERTICAL)
159  self.mainSizer.Add(item = txt_ctrl, proportion = 0,
160  flag = wx.ALIGN_CENTER | wx.RIGHT, border = 5)
161  self.mainSizer.Add(item = columnCtrl, proportion = 0,
162  flag = wx.ALIGN_CENTER | wx.RIGHT, border = 10)
163 
164  self.mainPanel.Layout()
165  self.mainPanel.SetupScrolling(scroll_x = False)
166 
167  def OnRuleEnable(self, event):
168  """!Rule enabled/disabled"""
169  id = event.GetId()
170 
171  if event.IsChecked():
172  self.mainPanel.FindWindowById(id + 1000).Enable()
173  self.mainPanel.FindWindowById(id + 2000).Enable()
174  if self.mapType == 'vector' and not self.parent.GetParent().colorTable:
175  vals = []
176  vals.append(self.mainPanel.FindWindowById(id + 1000).GetValue())
177  try:
178  vals.append(self.mainPanel.FindWindowById(id + 1 + 1000).GetValue())
179  except AttributeError:
180  vals.append(None)
181  value = self.SQLConvert(vals)
182  else:
183  value = self.mainPanel.FindWindowById(id + 1000).GetValue()
184  color = self.mainPanel.FindWindowById(id + 2000).GetValue()
185 
186  if self.attributeType == 'color':
187  # color
188  color_str = str(color[0]) + ':' \
189  + str(color[1]) + ':' \
190  + str(color[2])
191  self.ruleslines[id] = {'value' : value,
192  'color' : color_str }
193 
194  else:
195  # size or width
196  self.ruleslines[id] = {'value' : value,
197  self.attributeType : float(color) }
198 
199  else:
200  self.mainPanel.FindWindowById(id + 1000).Disable()
201  self.mainPanel.FindWindowById(id + 2000).Disable()
202  del self.ruleslines[id]
203 
204  def OnRuleColor(self, event):
205  """!Rule color changed"""
206  num = event.GetId()
207 
208  rgba_color = event.GetValue()
209 
210  rgb_string = str(rgba_color[0]) + ':' \
211  + str(rgba_color[1]) + ':' \
212  + str(rgba_color[2])
213 
214  self.ruleslines[num-2000]['color'] = rgb_string
215 
216  def OnRuleSize(self, event):
217  """!Rule size changed"""
218  num = event.GetId()
219  size = event.GetInt()
220 
221  self.ruleslines[num - 2000][self.attributeType] = size
222 
223  def OnRuleValue(self, event):
224  """!Rule value changed"""
225  num = event.GetId()
226  val = event.GetString().strip()
227 
228  if val == '':
229  return
230  try:
231  table = self.parent.colorTable
232  except AttributeError:
233  # due to panel/scrollpanel in vector dialog
234  if isinstance(self.parent.GetParent(), RasterColorTable):
235  table = self.parent.GetParent().colorTable
236  else:
237  table = self.parent.GetParent().GetParent().colorTable
238  if table:
239  self.SetRasterRule(num, val)
240  else:
241  self.SetVectorRule(num, val)
242 
243  def SetRasterRule(self, num, val):
244  """!Set raster rule"""
245  self.ruleslines[num - 1000]['value'] = val
246 
247  def SetVectorRule(self, num, val):
248  """!Set vector rule"""
249  vals = []
250  vals.append(val)
251  try:
252  vals.append(self.mainPanel.FindWindowById(num + 1).GetValue())
253  except AttributeError:
254  vals.append(None)
255  self.ruleslines[num - 1000]['value'] = self.SQLConvert(vals)
256 
257  def Enable(self, enable = True):
258  """!Enable/Disable all widgets"""
259  for child in self.mainPanel.GetChildren():
260  child.Enable(enable)
261  sql = True
262  self.LoadRulesline(sql)# todo
263  self.btnAdd.Enable(enable)
264  self.numRules.Enable(enable)
265  self.checkAll.Enable(enable)
266  self.clearAll.Enable(enable)
267 
268 
269  def LoadRules(self):
270  message = ""
271  for item in range(len(self.ruleslines)):
272  try:
273  self.mainPanel.FindWindowById(item + 1000).SetValue(self.ruleslines[item]['value'])
274  r, g, b = (0, 0, 0) # default
275  if not self.ruleslines[item][self.attributeType]:
276  if self.attributeType == 'color':
277  self.ruleslines[item][self.attributeType] = '%d:%d:%d' % (r, g, b)
278  elif self.attributeType == 'size':
279  self.ruleslines[item][self.attributeType] = 100
280  elif self.attributeType == 'width':
281  self.ruleslines[item][self.attributeType] = 2
282 
283  if self.attributeType == 'color':
284  try:
285  r, g, b = map(int, self.ruleslines[item][self.attributeType].split(':'))
286  except ValueError, e:
287  message = _("Bad color format. Use color format '0:0:0'")
288  self.mainPanel.FindWindowById(item + 2000).SetValue((r, g, b))
289  else:
290  value = float(self.ruleslines[item][self.attributeType])
291  self.mainPanel.FindWindowById(item + 2000).SetValue(value)
292  except:
293  continue
294 
295  if message:
296  GMessage(parent = self.parent, message = message)
297  return False
298 
299  return True
300 
301  def SQLConvert(self, vals):
302  """!Prepare value for SQL query"""
303  if vals[0].isdigit():
304  sqlrule = '%s=%s' % (self.properties['sourceColumn'], vals[0])
305  if vals[1]:
306  sqlrule += ' AND %s<%s' % (self.properties['sourceColumn'], vals[1])
307  else:
308  sqlrule = '%s=%s' % (self.properties['sourceColumn'], vals[0])
309 
310  return sqlrule
311 
312 class ColorTable(wx.Frame):
313  def __init__(self, parent, title, layerTree = None, id = wx.ID_ANY,
314  style = wx.DEFAULT_FRAME_STYLE | wx.RESIZE_BORDER,
315  **kwargs):
316  """!Dialog for interactively entering rules for map management
317  commands
318  """
319  self.parent = parent # GMFrame ?
320  self.layerTree = layerTree # LayerTree or None
321 
322  wx.Frame.__init__(self, parent, id, title, style = style, **kwargs)
323 
324  self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
325 
326  self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
327 
328  # instance of render.Map to be associated with display
329  self.Map = Map()
330 
331  # input map to change
332  self.inmap = ''
333 
334  # reference to layer with preview
335  self.layer = None
336 
337  # layout
338  self._doLayout()
339 
340  # bindings
341  self.Bind(wx.EVT_BUTTON, self.OnHelp, self.btnHelp)
342  self.selectionInput.Bind(wx.EVT_TEXT, self.OnSelectionInput)
343  self.Bind(wx.EVT_BUTTON, self.OnCancel, self.btnCancel)
344  self.Bind(wx.EVT_BUTTON, self.OnApply, self.btnApply)
345  self.Bind(wx.EVT_BUTTON, self.OnOK, self.btnOK)
346  self.Bind(wx.EVT_BUTTON, self.OnLoadDefaultTable, self.btnDefault)
347 
348  self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
349 
350  self.Bind(wx.EVT_BUTTON, self.OnPreview, self.btnPreview)
351 
352  def _initLayer(self):
353  """!Set initial layer when opening dialog"""
354  # set map layer from layer tree, first selected,
355  # if not the right type, than select another
356  try:
357  sel = self.layerTree.layer_selected
358  if sel and self.layerTree.GetPyData(sel)[0]['type'] == self.mapType:
359  layer = sel
360  else:
361  layer = self.layerTree.FindItemByData(key = 'type', value = self.mapType)
362  except:
363  layer = None
364  if layer:
365  mapLayer = self.layerTree.GetPyData(layer)[0]['maplayer']
366  name = mapLayer.GetName()
367  type = mapLayer.GetType()
368  self.selectionInput.SetValue(name)
369  self.inmap = name
370 
371  def _createMapSelection(self, parent):
372  """!Create map selection part of dialog"""
373  # top controls
374  if self.mapType == 'raster':
375  maplabel = _('Select raster map:')
376  else:
377  maplabel = _('Select vector map:')
378  inputBox = wx.StaticBox(parent, id = wx.ID_ANY,
379  label = " %s " % maplabel)
380  inputSizer = wx.StaticBoxSizer(inputBox, wx.VERTICAL)
381 
382  self.selectionInput = Select(parent = parent, id = wx.ID_ANY,
383  size = globalvar.DIALOG_GSELECT_SIZE,
384  type = self.mapType)
385  # layout
386  inputSizer.Add(item = self.selectionInput,
387  flag = wx.ALIGN_CENTER_VERTICAL | wx.ALL | wx.EXPAND, border = 5)
388 
389  return inputSizer
390 
391  def _createFileSelection(self, parent):
392  """!Create file (open/save rules) selection part of dialog"""
393  inputBox = wx.StaticBox(parent, id = wx.ID_ANY,
394  label = " %s " % _("Import or export color table:"))
395  inputSizer = wx.StaticBoxSizer(inputBox, wx.HORIZONTAL)
396 
397  self.loadRules = filebrowse.FileBrowseButton(parent = parent, id = wx.ID_ANY, fileMask = '*',
398  labelText = '',
399  dialogTitle = _('Choose file to load color table'),
400  buttonText = _('Load'),
401  toolTip = _("Type filename or click to choose "
402  "file and load color table"),
403  startDirectory = os.getcwd(), fileMode = wx.OPEN,
404  changeCallback = self.OnLoadRulesFile)
405  self.saveRules = filebrowse.FileBrowseButton(parent = parent, id = wx.ID_ANY, fileMask = '*',
406  labelText = '',
407  dialogTitle = _('Choose file to save color table'),
408  toolTip = _("Type filename or click to choose "
409  "file and save color table"),
410  buttonText = _('Save'),
411  startDirectory = os.getcwd(), fileMode = wx.SAVE,
412  changeCallback = self.OnSaveRulesFile)
413 
414  colorTable = wx.Choice(parent = parent, id = wx.ID_ANY, size = (200, -1),
415  choices = utils.GetColorTables(),
416  name = "colorTableChoice")
417  self.btnSet = wx.Button(parent = parent, id = wx.ID_ANY, label = _("&Set"), name = 'btnSet')
418  self.btnSet.Bind(wx.EVT_BUTTON, self.OnSetTable)
419  self.btnSet.Enable(False)
420 
421  # layout
422  gridSizer = wx.GridBagSizer(hgap = 2, vgap = 2)
423  gridSizer.AddGrowableCol(1)
424 
425  gridSizer.Add(item = wx.StaticText(parent, label = _("Load color table:")),
426  pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL)
427  gridSizer.Add(item = colorTable, pos = (0, 1))
428  gridSizer.Add(item = self.btnSet, pos = (0, 2), flag = wx.ALIGN_RIGHT)
429  gridSizer.Add(item = wx.StaticText(parent, label = _('Load color table from file:')),
430  pos = (1, 0), flag = wx.ALIGN_CENTER_VERTICAL)
431  gridSizer.Add(item = self.loadRules, pos = (1, 1), span = (1, 2), flag = wx.EXPAND)
432  gridSizer.Add(item = wx.StaticText(parent, label = _('Save color table to file:')),
433  pos = (2, 0), flag = wx.ALIGN_CENTER_VERTICAL)
434  gridSizer.Add(item = self.saveRules, pos = (2, 1), span = (1, 2), flag = wx.EXPAND)
435 
436  inputSizer.Add(gridSizer, proportion = 1, flag = wx.EXPAND | wx.ALL,
437  border = 5)
438 
439  if self.mapType == 'vector':
440  # parent is collapsible pane
441  parent.SetSizer(inputSizer)
442 
443  return inputSizer
444 
445  def _createPreview(self, parent):
446  """!Create preview"""
447  # initialize preview display
448  self.InitDisplay()
449  self.preview = BufferedWindow(parent, id = wx.ID_ANY, size = (400, 300),
450  Map = self.Map)
451  self.preview.EraseMap()
452 
453  def _createButtons(self, parent):
454  """!Create buttons for leaving dialog"""
455  self.btnHelp = wx.Button(parent, id = wx.ID_HELP)
456  self.btnCancel = wx.Button(parent, id = wx.ID_CANCEL)
457  self.btnApply = wx.Button(parent, id = wx.ID_APPLY)
458  self.btnOK = wx.Button(parent, id = wx.ID_OK)
459  self.btnDefault = wx.Button(parent, id = wx.ID_ANY,
460  label = _("Reload default table"))
461 
462  self.btnOK.SetDefault()
463  self.btnOK.Enable(False)
464  self.btnApply.Enable(False)
465  self.btnDefault.Enable(False)
466 
467  # layout
468  btnSizer = wx.BoxSizer(wx.HORIZONTAL)
469  btnSizer.Add(wx.Size(-1, -1), proportion = 1)
470  btnSizer.Add(self.btnDefault,
471  flag = wx.LEFT | wx.RIGHT, border = 5)
472  btnSizer.Add(self.btnHelp,
473  flag = wx.LEFT | wx.RIGHT, border = 5)
474  btnSizer.Add(self.btnCancel,
475  flag = wx.LEFT | wx.RIGHT, border = 5)
476  btnSizer.Add(self.btnApply,
477  flag = wx.LEFT | wx.RIGHT, border = 5)
478  btnSizer.Add(self.btnOK,
479  flag = wx.LEFT | wx.RIGHT, border = 5)
480 
481  return btnSizer
482 
483  def _createBody(self, parent):
484  """!Create dialog body consisting of rules and preview"""
485  bodySizer = wx.GridBagSizer(hgap = 5, vgap = 5)
486  bodySizer.AddGrowableRow(1)
487  bodySizer.AddGrowableCol(2)
488 
489  row = 0
490  # label with range
491  self.cr_label = wx.StaticText(parent, id = wx.ID_ANY)
492  bodySizer.Add(item = self.cr_label, pos = (row, 0), span = (1, 3),
493  flag = wx.ALL, border = 5)
494 
495  row += 1
496  # color table
497  self.rulesPanel = RulesPanel(parent = parent, mapType = self.mapType,
498  attributeType = self.attributeType, properties = self.properties)
499 
500  bodySizer.Add(item = self.rulesPanel.mainPanel, pos = (row, 0),
501  span = (1, 2), flag = wx.EXPAND)
502  # add two rules as default
503  self.rulesPanel.AddRules(2)
504 
505  # preview window
506  self._createPreview(parent = parent)
507  bodySizer.Add(item = self.preview, pos = (row, 2),
508  flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER)
509 
510  row += 1
511  # add ckeck all and clear all
512  bodySizer.Add(item = self.rulesPanel.checkAll, flag = wx.ALIGN_CENTER_VERTICAL,
513  pos = (row, 0))
514  bodySizer.Add(item = self.rulesPanel.clearAll, pos = (row, 1))
515 
516  # preview button
517  self.btnPreview = wx.Button(parent, id = wx.ID_ANY,
518  label = _("Preview"))
519  bodySizer.Add(item = self.btnPreview, pos = (row, 2),
520  flag = wx.ALIGN_RIGHT)
521  self.btnPreview.Enable(False)
522  self.btnPreview.SetToolTipString(_("Show preview of map "
523  "(current Map Display extent is used)."))
524 
525  row +=1
526  # add rules button and spin to sizer
527  bodySizer.Add(item = self.rulesPanel.numRules, pos = (row, 0),
528  flag = wx.ALIGN_CENTER_VERTICAL)
529  bodySizer.Add(item = self.rulesPanel.btnAdd, pos = (row, 1))
530 
531  return bodySizer
532 
533  def InitDisplay(self):
534  """!Initialize preview display, set dimensions and region
535  """
536  self.width = self.Map.width = 400
537  self.height = self.Map.height = 300
538  self.Map.geom = self.width, self.height
539 
540  def OnCloseWindow(self, event):
541  """!Window closed
542  """
543  self.OnCancel(event)
544 
545  def OnApply(self, event):
546  """!Apply selected color table
547 
548  @return True on success otherwise False
549  """
550  ret = self.CreateColorTable()
551  if not ret:
552  GMessage(parent = self, message = _("No valid color rules given."))
553  else:
554  # re-render preview and current map window
555  self.OnPreview(None)
556  display = self.layerTree.GetMapDisplay()
557  if display and display.IsAutoRendered():
558  display.GetWindow().UpdateMap(render = True)
559 
560  return ret
561 
562  def OnOK(self, event):
563  """!Apply selected color table and close the dialog"""
564  if self.OnApply(event):
565  self.OnCancel(event)
566 
567  def OnCancel(self, event):
568  """!Do not apply any changes, remove associated
569  rendered images and close the dialog"""
570  self.Map.Clean()
571  self.Destroy()
572 
573  def OnSetTable(self, event):
574  """!Load pre-defined color table"""
575  ct = self.FindWindowByName("colorTableChoice").GetStringSelection()
576  # save original color table
577  ctOriginal = RunCommand('r.colors.out', read = True, map = self.inmap, rules = '-')
578  # set new color table
579  ret, err = RunCommand('r.colors', map = self.inmap, color = ct, getErrorMsg = True)
580  if ret != 0:
581  GError(err, parent = self)
582  return
583  ctNew = RunCommand('r.colors.out', read = True, map = self.inmap, rules = '-')
584  # restore original table
585  RunCommand('r.colors', map = self.inmap, rules = '-', stdin = ctOriginal)
586  # load color table
587  self.rulesPanel.Clear()
588  self.ReadColorTable(ctable = ctNew)
589 
590  def OnSaveRulesFile(self, event):
591  """!Save color table to file"""
592  path = event.GetString()
593  if not os.path.exists(path):
594  return
595 
596  rulestxt = ''
597  for rule in self.rulesPanel.ruleslines.itervalues():
598  if 'value' not in rule:
599  continue
600  rulestxt += rule['value'] + ' ' + rule['color'] + '\n'
601  if not rulestxt:
602  GMessage(message = _("Nothing to save."),
603  parent = self)
604  return
605 
606  fd = open(path, 'w')
607  fd.write(rulestxt)
608  fd.close()
609 
610  def OnLoadRulesFile(self, event):
611  """!Load color table from file"""
612  path = event.GetString()
613  if not os.path.exists(path):
614  return
615 
616  self.rulesPanel.Clear()
617 
618  fd = open(path, 'r')
619  self.ReadColorTable(ctable = fd.read())
620  fd.close()
621 
622  def ReadColorTable(self, ctable):
623  """!Read color table
624 
625  @param table color table in format coming from r.colors.out"""
626 
627  rulesNumber = len(ctable.splitlines())
628  self.rulesPanel.AddRules(rulesNumber)
629 
630  minim = maxim = count = 0
631  for line in ctable.splitlines():
632  try:
633  value, color = map(lambda x: x.strip(), line.split(' '))
634  except ValueError:
635  GMessage(parent = self, message = _("Invalid color table format"))
636  self.rulesPanel.Clear()
637  return
638 
639  self.rulesPanel.ruleslines[count]['value'] = value
640  self.rulesPanel.ruleslines[count]['color'] = color
641  self.rulesPanel.mainPanel.FindWindowById(count + 1000).SetValue(value)
642  rgb = list()
643  for c in color.split(':'):
644  rgb.append(int(c))
645  self.rulesPanel.mainPanel.FindWindowById(count + 2000).SetColour(rgb)
646  # range
647  try:
648  if float(value) < minim:
649  minim = float(value)
650  if float(value) > maxim:
651  maxim = float(value)
652  except ValueError: # nv, default
653  pass
654  count += 1
655 
656  if self.mapType == 'vector':
657  # raster min, max is known from r.info
658  self.properties['min'], self.properties['max'] = minim, maxim
659  self.SetRangeLabel()
660 
661  self.OnPreview(tmp = True)
662 
663  def OnLoadDefaultTable(self, event):
664  """!Load internal color table"""
665  self.LoadTable()
666 
667  def LoadTable(self, mapType = 'raster'):
668  """!Load current color table (using `r(v).colors.out`)
669 
670  @param mapType map type (raster or vector)"""
671  self.rulesPanel.Clear()
672 
673  if mapType == 'raster':
674  cmd = ['r.colors.out',
675  'read=True',
676  'map=%s' % self.inmap,
677  'rules=-']
678  else:
679  cmd = ['v.colors.out',
680  'read=True',
681  'map=%s' % self.inmap,
682  'rules=-']
683 
684  if self.properties['sourceColumn'] and self.properties['sourceColumn'] != 'cat':
685  cmd.append('column=%s' % self.properties['sourceColumn'])
686 
687  cmd = utils.CmdToTuple(cmd)
688 
689  if self.inmap:
690  ctable = RunCommand(cmd[0], **cmd[1])
691  else:
692  self.OnPreview()
693  return
694 
695  self.ReadColorTable(ctable = ctable)
696 
697  def CreateColorTable(self, tmp = False):
698  """!Creates color table
699 
700  @return True on success
701  @return False on failure
702  """
703  rulestxt = ''
704 
705  for rule in self.rulesPanel.ruleslines.itervalues():
706  if 'value' not in rule: # skip empty rules
707  continue
708 
709  if rule['value'] not in ('nv', 'default') and \
710  rule['value'][-1] != '%' and \
711  not self._IsNumber(rule['value']):
712  GError(_("Invalid rule value '%s'. Unable to apply color table.") % rule['value'],
713  parent = self)
714  return False
715 
716  rulestxt += rule['value'] + ' ' + rule['color'] + '\n'
717 
718  if not rulestxt:
719  return False
720 
721  gtemp = utils.GetTempfile()
722  output = open(gtemp, "w")
723  try:
724  output.write(rulestxt)
725  finally:
726  output.close()
727 
728  cmd = ['%s.colors' % self.mapType[0], #r.colors/v.colors
729  'map=%s' % self.inmap,
730  'rules=%s' % gtemp]
731  if self.mapType == 'vector' and self.properties['sourceColumn'] \
732  and self.properties['sourceColumn'] != 'cat':
733  cmd.append('column=%s' % self.properties['sourceColumn'])
734  cmd = utils.CmdToTuple(cmd)
735  ret = RunCommand(cmd[0], **cmd[1])
736  if ret != 0:
737  return False
738 
739  return True
740 
741  def DoPreview(self, ltype, cmdlist):
742  """!Update preview (based on computational region)"""
743 
744  if not self.layer:
745  self.layer = self.Map.AddLayer(type = ltype, name = 'preview', command = cmdlist,
746  l_active = True, l_hidden = False, l_opacity = 1.0,
747  l_render = False)
748  else:
749  self.layer.SetCmd(cmdlist)
750 
751  # apply new color table and display preview
752  self.CreateColorTable(tmp = True)
753  self.preview.UpdatePreview()
754 
755  def RunHelp(self, cmd):
756  """!Show GRASS manual page"""
757  RunCommand('g.manual',
758  quiet = True,
759  parent = self,
760  entry = cmd)
761 
762  def SetMap(self, name):
763  """!Set map name and update dialog"""
764  self.selectionInput.SetValue(name)
765 
766  def _IsNumber(self, s):
767  """!Check if 's' is a number"""
768  try:
769  float(s)
770  return True
771  except ValueError:
772  return False
773 
775  def __init__(self, parent, **kwargs):
776  """!Dialog for interactively entering color rules for raster maps"""
777 
778  self.mapType = 'raster'
779  self.attributeType = 'color'
780  self.colorTable = True
781  # raster properties
782  self.properties = {
783  # min cat in raster map
784  'min' : None,
785  # max cat in raster map
786  'max' : None,
787  }
788 
789  ColorTable.__init__(self, parent,
790  title = _('Create new color table for raster map'), **kwargs)
791 
792  self._initLayer()
793 
794  # self.SetMinSize(self.GetSize())
795  self.SetMinSize((650, 700))
796 
797  def _doLayout(self):
798  """!Do main layout"""
799  sizer = wx.BoxSizer(wx.VERTICAL)
800  #
801  # map selection
802  #
803  mapSelection = self._createMapSelection(parent = self.panel)
804  sizer.Add(item = mapSelection, proportion = 0,
805  flag = wx.ALL | wx.EXPAND, border = 5)
806  #
807  # manage extern tables
808  #
809  fileSelection = self._createFileSelection(parent = self.panel)
810  sizer.Add(item = fileSelection, proportion = 0,
811  flag = wx.LEFT | wx.RIGHT | wx.EXPAND, border = 5)
812  #
813  # body & preview
814  #
815  bodySizer = self._createBody(parent = self.panel)
816  sizer.Add(item = bodySizer, proportion = 1,
817  flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 5)
818  #
819  # buttons
820  #
821  btnSizer = self._createButtons(parent = self.panel)
822  sizer.Add(item = wx.StaticLine(parent = self.panel, id = wx.ID_ANY,
823  style = wx.LI_HORIZONTAL), proportion = 0,
824  flag = wx.EXPAND | wx.ALL, border = 5)
825 
826  sizer.Add(item = btnSizer, proportion = 0,
827  flag = wx.ALL | wx.ALIGN_RIGHT, border = 5)
828 
829  self.panel.SetSizer(sizer)
830  sizer.Layout()
831  sizer.Fit(self.panel)
832  self.Layout()
833 
834  def OnSelectionInput(self, event):
835  """!Raster map selected"""
836  if event:
837  self.inmap = event.GetString()
838 
839  self.loadRules.SetValue('')
840  self.saveRules.SetValue('')
841 
842  if self.inmap:
843  if not grass.find_file(name = self.inmap, element = 'cell')['file']:
844  self.inmap = None
845 
846  if not self.inmap:
847  for btn in (self.btnPreview, self.btnOK,
848  self.btnApply, self.btnDefault, self.btnSet):
849  btn.Enable(False)
850  self.LoadTable()
851  return
852 
853  info = grass.raster_info(map = self.inmap)
854 
855  if info:
856  self.properties['min'] = info['min']
857  self.properties['max'] = info['max']
858  self.LoadTable()
859  else:
860  self.inmap = ''
861  self.properties['min'] = self.properties['max'] = None
862  for btn in (self.btnPreview, self.btnOK,
863  self.btnApply, self.btnDefault, self.btnSet):
864  btn.Enable(False)
865  self.preview.EraseMap()
866  self.cr_label.SetLabel(_('Enter raster category values or percents'))
867  return
868 
869  if info['datatype'] == 'CELL':
870  mapRange = _('range')
871  else:
872  mapRange = _('fp range')
873  self.cr_label.SetLabel(_('Enter raster category values or percents (%(range)s = %(min)d-%(max)d)') %
874  { 'range' : mapRange,
875  'min' : self.properties['min'],
876  'max' : self.properties['max'] })
877 
878  for btn in (self.btnPreview, self.btnOK,
879  self.btnApply, self.btnDefault, self.btnSet):
880  btn.Enable()
881 
882  def OnPreview(self, tmp = True):
883  """!Update preview (based on computational region)"""
884  if not self.inmap:
885  self.preview.EraseMap()
886  return
887 
888  cmdlist = ['d.rast',
889  'map=%s' % self.inmap]
890  ltype = 'raster'
891 
892  # find existing color table and copy to temp file
893  try:
894  name, mapset = self.inmap.split('@')
895  except ValueError:
896  name = self.inmap
897  mapset = grass.find_file(self.inmap, element = 'cell')['mapset']
898  if not mapset:
899  return
900  old_colrtable = None
901  if mapset == grass.gisenv()['MAPSET']:
902  old_colrtable = grass.find_file(name = name, element = 'colr')['file']
903  else:
904  old_colrtable = grass.find_file(name = name, element = 'colr2/' + mapset)['file']
905 
906  if old_colrtable:
907  colrtemp = utils.GetTempfile()
908  shutil.copyfile(old_colrtable, colrtemp)
909 
910  ColorTable.DoPreview(self, ltype, cmdlist)
911 
912  # restore previous color table
913  if tmp:
914  if old_colrtable:
915  shutil.copyfile(colrtemp, old_colrtable)
916  os.remove(colrtemp)
917  else:
918  RunCommand('r.colors',
919  parent = self,
920  flags = 'r',
921  map = self.inmap)
922 
923  def OnHelp(self, event):
924  """!Show GRASS manual page"""
925  cmd = 'r.colors'
926  ColorTable.RunHelp(self, cmd = cmd)
927 
929  def __init__(self, parent, attributeType, **kwargs):
930  """!Dialog for interactively entering color rules for vector maps"""
931  # dialog attributes
932  self.mapType = 'vector'
933  self.attributeType = attributeType # color, size, width
934  # in version 7 v.colors used, otherwise color column only
935  self.version7 = int(grass.version()['version'].split('.')[0]) >= 7
936  self.colorTable = False
937  self.updateColumn = True
938  # vector properties
939  self.properties = {
940  # vector layer for attribute table to use for setting color
941  'layer' : 1,
942  # vector attribute table used for setting color
943  'table' : '',
944  # vector attribute column for assigning colors
945  'sourceColumn' : '',
946  # vector attribute column to use for loading colors
947  'loadColumn' : '',
948  # vector attribute column to use for storing colors
949  'storeColumn' : '',
950  # vector attribute column for temporary storing colors
951  'tmpColumn' : 'tmp_0',
952  # min value of attribute column/vector color table
953  'min': None,
954  # max value of attribute column/vector color table
955  'max': None
956  }
957  self.columnsProp = {'color': {'name': 'GRASSRGB', 'type1': 'varchar(11)', 'type2': ['character']},
958  'size' : {'name': 'GRASSSIZE', 'type1': 'integer', 'type2': ['integer']},
959  'width': {'name': 'GRASSWIDTH', 'type1': 'integer', 'type2': ['integer']}}
960  ColorTable.__init__(self, parent = parent,
961  title = _('Create new color rules for vector map'), **kwargs)
962 
963  # additional bindings for vector color management
964  self.Bind(wx.EVT_COMBOBOX, self.OnLayerSelection, self.layerSelect)
965  self.Bind(wx.EVT_COMBOBOX, self.OnSourceColumnSelection, self.sourceColumn)
966  self.Bind(wx.EVT_COMBOBOX, self.OnFromColSelection, self.fromColumn)
967  self.Bind(wx.EVT_COMBOBOX, self.OnToColSelection, self.toColumn)
968  self.Bind(wx.EVT_BUTTON, self.OnAddColumn, self.addColumn)
969 
970  self._initLayer()
971  if self.colorTable:
972  self.cr_label.SetLabel(_("Enter vector attribute values or percents:"))
973  else:
974  self.cr_label.SetLabel(_("Enter vector attribute values:"))
975 
976  #self.SetMinSize(self.GetSize())
977  self.SetMinSize((650, 700))
978 
979  self.CentreOnScreen()
980  self.Show()
981 
982  def _createVectorAttrb(self, parent):
983  """!Create part of dialog with layer/column selection"""
984  inputBox = wx.StaticBox(parent = parent, id = wx.ID_ANY,
985  label = " %s " % _("Select vector columns"))
986  cb_vl_label = wx.StaticText(parent, id = wx.ID_ANY,
987  label = _('Layer:'))
988  cb_vc_label = wx.StaticText(parent, id = wx.ID_ANY,
989  label = _('Attribute column:'))
990 
991  if self.attributeType == 'color':
992  labels = [_("Load color from column:"), _("Save color to column:")]
993  elif self.attributeType == 'size':
994  labels = [_("Load size from column:"), _("Save size to column:")]
995  elif self.attributeType == 'width':
996  labels = [_("Load width from column:"), _("Save width to column:")]
997 
998  if self.version7 and self.attributeType == 'color':
999  self.useColumn = wx.CheckBox(parent, id = wx.ID_ANY,
1000  label = _("Use color column instead of color table:"))
1001  self.useColumn.Bind(wx.EVT_CHECKBOX, self.OnCheckColumn)
1002 
1003  fromColumnLabel = wx.StaticText(parent, id = wx.ID_ANY,
1004  label = labels[0])
1005  toColumnLabel = wx.StaticText(parent, id = wx.ID_ANY,
1006  label = labels[1])
1007 
1008  self.rgb_range_label = wx.StaticText(parent, id = wx.ID_ANY)
1009  self.layerSelect = LayerSelect(parent)
1010  self.sourceColumn = ColumnSelect(parent)
1011  self.fromColumn = ColumnSelect(parent)
1012  self.toColumn = ColumnSelect(parent)
1013  self.addColumn = wx.Button(parent, id = wx.ID_ANY,
1014  label = _('Add column'))
1015  self.addColumn.SetToolTipString(_("Add GRASSRGB column to current attribute table."))
1016 
1017  # layout
1018  inputSizer = wx.StaticBoxSizer(inputBox, wx.VERTICAL)
1019  vSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
1020  row = 0
1021  vSizer.Add(cb_vl_label, pos = (row, 0),
1022  flag = wx.ALIGN_CENTER_VERTICAL)
1023  vSizer.Add(self.layerSelect, pos = (row, 1),
1024  flag = wx.ALIGN_CENTER_VERTICAL)
1025  row += 1
1026  vSizer.Add(cb_vc_label, pos = (row, 0),
1027  flag = wx.ALIGN_CENTER_VERTICAL)
1028  vSizer.Add(self.sourceColumn, pos = (row, 1),
1029  flag = wx.ALIGN_CENTER_VERTICAL)
1030  vSizer.Add(self.rgb_range_label, pos = (row, 2),
1031  flag = wx.ALIGN_CENTER_VERTICAL)
1032  row += 1
1033  if self.version7 and self.attributeType == 'color':
1034  vSizer.Add(self.useColumn, pos = (row, 0), span = (1, 2),
1035  flag = wx.ALIGN_CENTER_VERTICAL)
1036  row += 1
1037 
1038  vSizer.Add(fromColumnLabel, pos = (row, 0),
1039  flag = wx.ALIGN_CENTER_VERTICAL)
1040  vSizer.Add(self.fromColumn, pos = (row, 1),
1041  flag = wx.ALIGN_CENTER_VERTICAL)
1042  row += 1
1043  vSizer.Add(toColumnLabel, pos = (row, 0),
1044  flag = wx.ALIGN_CENTER_VERTICAL)
1045  vSizer.Add(self.toColumn, pos = (row, 1),
1046  flag = wx.ALIGN_CENTER_VERTICAL)
1047  vSizer.Add(self.addColumn, pos = (row, 2),
1048  flag = wx.ALIGN_CENTER_VERTICAL)
1049  inputSizer.Add(item = vSizer,
1050  flag = wx.ALIGN_CENTER_VERTICAL | wx.ALL | wx.EXPAND, border = 5)
1051  self.colorColumnSizer = vSizer
1052  return inputSizer
1053 
1054  def _doLayout(self):
1055  """!Do main layout"""
1056  scrollPanel = scrolled.ScrolledPanel(parent = self.panel, id = wx.ID_ANY,
1057  style = wx.TAB_TRAVERSAL)
1058  scrollPanel.SetupScrolling()
1059  sizer = wx.BoxSizer(wx.VERTICAL)
1060  #
1061  # map selection
1062  #
1063  mapSelection = self._createMapSelection(parent = scrollPanel)
1064  sizer.Add(item = mapSelection, proportion = 0,
1065  flag = wx.ALL | wx.EXPAND, border = 5)
1066  #
1067  # manage extern tables
1068  #
1069  if self.version7 and self.attributeType == 'color':
1070  self.cp = wx.CollapsiblePane(scrollPanel, label = _("Import or export color table"),
1071  winid = wx.ID_ANY,
1072  style = wx.CP_DEFAULT_STYLE|wx.CP_NO_TLW_RESIZE)
1073  self.Bind(wx.EVT_COLLAPSIBLEPANE_CHANGED, self.OnPaneChanged, self.cp)
1074 
1075  self._createFileSelection(parent = self.cp.GetPane())
1076  sizer.Add(item = self.cp, proportion = 0,
1077  flag = wx.ALL | wx.EXPAND, border = 5)
1078  #
1079  # set vector attributes
1080  #
1081  vectorAttrb = self._createVectorAttrb(parent = scrollPanel)
1082  sizer.Add(item = vectorAttrb, proportion = 0,
1083  flag = wx.ALL | wx.EXPAND, border = 5)
1084  #
1085  # body & preview
1086  #
1087  bodySizer = self._createBody(parent = scrollPanel)
1088  sizer.Add(item = bodySizer, proportion = 1,
1089  flag = wx.ALL | wx.EXPAND, border = 5)
1090 
1091  scrollPanel.SetSizer(sizer)
1092  scrollPanel.Fit()
1093 
1094  #
1095  # buttons
1096  #
1097  btnSizer = self._createButtons(self.panel)
1098 
1099  mainsizer = wx.BoxSizer(wx.VERTICAL)
1100  mainsizer.Add(scrollPanel, proportion = 1, flag = wx.EXPAND | wx.ALL, border = 5)
1101  mainsizer.Add(item = wx.StaticLine(parent = self.panel, id = wx.ID_ANY,
1102  style = wx.LI_HORIZONTAL), proportion = 0,
1103  flag = wx.EXPAND | wx.ALL, border = 5)
1104  mainsizer.Add(item = btnSizer, proportion = 0,
1105  flag = wx.ALL | wx.ALIGN_RIGHT | wx.EXPAND, border = 5)
1106 
1107  self.panel.SetSizer(mainsizer)
1108  mainsizer.Layout()
1109  mainsizer.Fit(self.panel)
1110  self.Layout()
1111 
1112  def OnPaneChanged(self, event = None):
1113  # redo the layout
1114  self.Layout()
1115  # and also change the labels
1116  if self.cp.IsExpanded():
1117  self.cp.SetLabel('')
1118  else:
1119  self.cp.SetLabel(_("Import or export color table"))
1120 
1121  def CheckMapset(self):
1122  """!Check if current vector is in current mapset"""
1123  if grass.find_file(name = self.inmap,
1124  element = 'vector')['mapset'] == grass.gisenv()['MAPSET']:
1125  return True
1126  else:
1127  return False
1128 
1129  def NoConnection(self, vectorName):
1130  dlg = wx.MessageDialog(parent = self,
1131  message = _("Database connection for vector map <%s> "
1132  "is not defined in DB file. Do you want to create and "
1133  "connect new attribute table?") % vectorName,
1134  caption = _("No database connection defined"),
1135  style = wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION | wx.CENTRE)
1136  if dlg.ShowModal() == wx.ID_YES:
1137  dlg.Destroy()
1138  GUI(parent = self).ParseCommand(['v.db.addtable', 'map=' + self.inmap],
1139  completed = (self.CreateAttrTable, self.inmap, ''))
1140  else:
1141  dlg.Destroy()
1142 
1143  def OnCheckColumn(self, event):
1144  """!Use color column instead of color table"""
1145  if self.useColumn.GetValue():
1146  self.properties['loadColumn'] = self.fromColumn.GetStringSelection()
1147  self.properties['storeColumn'] = self.toColumn.GetStringSelection()
1148  self.fromColumn.Enable(True)
1149  self.toColumn.Enable(True)
1150  self.colorTable = False
1151 
1152  if self.properties['loadColumn']:
1153  self.LoadTable()
1154  else:
1155  self.rulesPanel.Clear()
1156  else:
1157  self.properties['loadColumn'] = ''
1158  self.properties['storeColumn'] = ''
1159  self.fromColumn.Enable(False)
1160  self.toColumn.Enable(False)
1161  self.colorTable = True
1162  self.LoadTable()
1163 
1164  def EnableVectorAttributes(self, enable):
1165  """!Enable/disable part of dialog connected with db"""
1166  for child in self.colorColumnSizer.GetChildren():
1167  child.GetWindow().Enable(enable)
1168 
1169  def DisableClearAll(self):
1170  """!Enable, disable the whole dialog"""
1171  self.rulesPanel.Clear()
1172  self.EnableVectorAttributes(False)
1173  self.btnPreview.Enable(False)
1174  self.btnOK.Enable(False)
1175  self.btnApply.Enable(False)
1176  self.preview.EraseMap()
1177 
1178  def OnSelectionInput(self, event):
1179  """!Vector map selected"""
1180  if event:
1181  if self.inmap:
1182  # switch to another map -> delete temporary column
1183  self.DeleteTemporaryColumn()
1184  self.inmap = event.GetString()
1185 
1186  if self.version7 and self.attributeType == 'color':
1187  self.loadRules.SetValue('')
1188  self.saveRules.SetValue('')
1189 
1190  if self.inmap:
1191  if not grass.find_file(name = self.inmap, element = 'vector')['file']:
1192  self.inmap = None
1193 
1194  self.UpdateDialog()
1195 
1196  def UpdateDialog(self):
1197  """!Update dialog after map selection"""
1198 
1199  if not self.inmap:
1200  self.DisableClearAll()
1201  return
1202 
1203  if self.inmap and not self.CheckMapset():
1204  # currently v.colors need the map to be in current mapset
1205  if self.version7 and self.attributeType == 'color':
1206  message = _("Selected map <%(map)s> is not in current mapset <%(mapset)s>. "
1207  "Color rules cannot be edited.") % \
1208  { 'map' : self.inmap,
1209  'mapset' : grass.gisenv()['MAPSET'] }
1210  else:
1211  message = _("Selected map <%(map)s> is not in current mapset <%(mapset)s>. "
1212  "Attribute table cannot be edited.") % \
1213  { 'map' : self.inmap,
1214  'mapset' : grass.gisenv()['MAPSET'] }
1215  wx.CallAfter(GMessage, parent = self, message = message)
1216  self.DisableClearAll()
1217  return
1218 
1219  # check for db connection
1220  self.dbInfo = VectorDBInfo(self.inmap)
1221  enable = True
1222  if not len(self.dbInfo.layers): # no connection
1223  if not (self.version7 and self.attributeType == 'color'): # otherwise it doesn't matter
1224  wx.CallAfter(self.NoConnection, self.inmap)
1225  enable = False
1226  for combo in (self.layerSelect, self.sourceColumn, self.fromColumn, self.toColumn):
1227  combo.SetValue("")
1228  combo.Clear()
1229  for prop in ('sourceColumn', 'loadColumn', 'storeColumn'):
1230  self.properties[prop] = ''
1231  self.EnableVectorAttributes(False)
1232  else: # db connection exist
1233  # initialize layer selection combobox
1234  self.EnableVectorAttributes(True)
1235  self.layerSelect.InsertLayers(self.inmap)
1236  # initialize attribute table for layer=1
1237  self.properties['layer'] = self.layerSelect.GetString(0)
1238  self.layerSelect.SetStringSelection(self.properties['layer'])
1239  layer = int(self.properties['layer'])
1240  self.properties['table'] = self.dbInfo.layers[layer]['table']
1241 
1242  if self.attributeType == 'color':
1243  self.AddTemporaryColumn(type = 'varchar(11)')
1244  else:
1245  self.AddTemporaryColumn(type = 'integer')
1246 
1247  # initialize column selection comboboxes
1248 
1249  self.OnLayerSelection(event = None)
1250 
1251  if self.version7 and self.attributeType == 'color':
1252  self.useColumn.SetValue(False)
1253  self.OnCheckColumn(event = None)
1254 
1255  self.LoadTable()
1256 
1257  self.btnPreview.Enable(enable)
1258  self.btnOK.Enable(enable)
1259  self.btnApply.Enable(enable)
1260 
1261  def AddTemporaryColumn(self, type):
1262  """!Add temporary column to not overwrite the original values,
1263  need to be deleted when closing dialog and unloading map
1264 
1265  @param type type of column (e.g. vachar(11))"""
1266  # because more than one dialog with the same map can be opened we must test column name and
1267  # create another one
1268  while self.properties['tmpColumn'] in self.dbInfo.GetTableDesc(self.properties['table']).keys():
1269  name, idx = self.properties['tmpColumn'].split('_')
1270  idx = int(idx)
1271  idx += 1
1272  self.properties['tmpColumn'] = name + '_' + str(idx)
1273 
1274  if self.version7:
1275  modul = 'v.db.addcolumn'
1276  else:
1277  modul = 'v.db.addcol'
1278  ret = RunCommand(modul,
1279  parent = self,
1280  map = self.inmap,
1281  layer = self.properties['layer'],
1282  column = '%s %s' % (self.properties['tmpColumn'], type))
1283 
1285  """!Delete temporary column"""
1286  if self.inmap:
1287  if self.version7:
1288  modul = 'v.db.dropcolumn'
1289  else:
1290  modul = 'v.db.dropcol'
1291  ret = RunCommand(modul,
1292  map = self.inmap,
1293  layer = self.properties['layer'],
1294  column = self.properties['tmpColumn'])
1295 
1296  def OnLayerSelection(self, event):
1297  # reset choices in column selection comboboxes if layer changes
1298  vlayer = int(self.layerSelect.GetStringSelection())
1299  self.sourceColumn.InsertColumns(vector = self.inmap, layer = vlayer,
1300  type = ['integer', 'double precision'], dbInfo = self.dbInfo,
1301  excludeCols = ['tmpColumn'])
1302  self.sourceColumn.SetStringSelection('cat')
1303  self.properties['sourceColumn'] = self.sourceColumn.GetString(0)
1304 
1305  if self.attributeType == 'color':
1306  type = ['character']
1307  else:
1308  type = ['integer']
1309  self.fromColumn.InsertColumns(vector = self.inmap, layer = vlayer, type = type,
1310  dbInfo = self.dbInfo, excludeCols = ['tmpColumn'])
1311  self.toColumn.InsertColumns(vector = self.inmap, layer = vlayer, type = type,
1312  dbInfo = self.dbInfo, excludeCols = ['tmpColumn'])
1313 
1314  found = self.fromColumn.FindString(self.columnsProp[self.attributeType]['name'])
1315  if found != wx.NOT_FOUND:
1316  self.fromColumn.SetSelection(found)
1317  self.toColumn.SetSelection(found)
1318  self.properties['loadColumn'] = self.fromColumn.GetString(found)
1319  self.properties['storeColumn'] = self.toColumn.GetString(found)
1320  else:
1321  self.properties['loadColumn'] = ''
1322  self.properties['storeColumn'] = ''
1323 
1324  if event:
1325  self.LoadTable()
1326  self.Update()
1327 
1328  def OnSourceColumnSelection(self, event):
1329  self.properties['sourceColumn'] = event.GetString()
1330 
1331  self.LoadTable()
1332 
1333  def OnAddColumn(self, event):
1334  """!Add GRASS(RGB,SIZE,WIDTH) column if it doesn't exist"""
1335  if self.columnsProp[self.attributeType]['name'] not in self.fromColumn.GetItems():
1336  if self.version7:
1337  modul = 'v.db.addcolumn'
1338  else:
1339  modul = 'v.db.addcol'
1340  ret = RunCommand(modul,
1341  map = self.inmap,
1342  layer = self.properties['layer'],
1343  columns = '%s %s' % (self.columnsProp[self.attributeType]['name'],
1344  self.columnsProp[self.attributeType]['type1']))
1345  self.toColumn.InsertColumns(self.inmap, self.properties['layer'],
1346  type = self.columnsProp[self.attributeType]['type2'])
1347  self.toColumn.SetStringSelection(self.columnsProp[self.attributeType]['name'])
1348  self.properties['storeColumn'] = self.toColumn.GetStringSelection()
1349 
1350  self.LoadTable()
1351  else:
1352  GMessage(parent = self,
1353  message = _("%s column already exists.") % \
1354  self.columnsProp[self.attributeType]['name'])
1355 
1356  def CreateAttrTable(self, dcmd, layer, params, propwin):
1357  """!Create attribute table"""
1358  if dcmd:
1359  cmd = utils.CmdToTuple(dcmd)
1360  ret = RunCommand(cmd[0], **cmd[1])
1361  if ret == 0:
1362  self.OnSelectionInput(None)
1363  return True
1364 
1365  for combo in (self.layerSelect, self.sourceColumn, self.fromColumn, self.toColumn):
1366  combo.SetValue("")
1367  combo.Disable()
1368  return False
1369 
1370  def LoadTable(self):
1371  """!Load table"""
1372  if self.colorTable:
1373  ColorTable.LoadTable(self, mapType = 'vector')
1374  else:
1375  self.LoadRulesFromColumn()
1376 
1378  """!Load current column (GRASSRGB, size column)"""
1379 
1380  self.rulesPanel.Clear()
1381  if not self.properties['sourceColumn']:
1382  self.preview.EraseMap()
1383  return
1384 
1385  busy = wx.BusyInfo(message = _("Please wait, loading data from attribute table..."),
1386  parent = self)
1387  wx.Yield()
1388 
1389  columns = self.properties['sourceColumn']
1390  if self.properties['loadColumn']:
1391  columns += ',' + self.properties['loadColumn']
1392 
1393  sep = ';'
1394  if self.inmap:
1395  outFile = tempfile.NamedTemporaryFile(mode = 'w+b')
1396  ret = RunCommand('v.db.select',
1397  quiet = True,
1398  flags = 'c',
1399  map = self.inmap,
1400  layer = self.properties['layer'],
1401  columns = columns,
1402  fs = sep,
1403  stdout = outFile)
1404  else:
1405  self.preview.EraseMap()
1406  busy.Destroy()
1407  return
1408 
1409  outFile.seek(0)
1410  i = 0
1411  minim = maxim = 0.0
1412  limit = 1000
1413 
1414  colvallist = []
1415  readvals = False
1416 
1417  while True:
1418  # os.linesep doesn't work here (MSYS)
1419  record = outFile.readline().replace('\n', '')
1420  if not record:
1421  break
1422  self.rulesPanel.ruleslines[i] = {}
1423 
1424  if not self.properties['loadColumn']:
1425  col1 = record
1426  col2 = None
1427  else:
1428  col1, col2 = record.split(sep)
1429 
1430  if float(col1) < minim:
1431  minim = float(col1)
1432  if float(col1) > maxim:
1433  maxim = float(col1)
1434 
1435 
1436  # color rules list should only have unique values of col1, not all records
1437  if col1 not in colvallist:
1438  self.rulesPanel.ruleslines[i]['value'] = col1
1439  self.rulesPanel.ruleslines[i][self.attributeType] = col2
1440 
1441  colvallist.append(col1)
1442  i += 1
1443 
1444  if i > limit and readvals == False:
1445  dlg = wx.MessageDialog (parent = self, message = _(
1446  "Number of loaded records reached %d, "
1447  "displaying all the records will be time-consuming "
1448  "and may lead to computer freezing, "
1449  "do you still want to continue?") % i,
1450  caption = _("Too many records"),
1451  style = wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
1452  if dlg.ShowModal() == wx.ID_YES:
1453  readvals = True
1454  dlg.Destroy()
1455  else:
1456  busy.Destroy()
1457  dlg.Destroy()
1458  self.updateColumn = False
1459  return
1460 
1461  self.rulesPanel.AddRules(i, start = True)
1462  ret = self.rulesPanel.LoadRules()
1463 
1464  self.properties['min'], self.properties['max'] = minim, maxim
1465  self.SetRangeLabel()
1466 
1467  if ret:
1468  self.OnPreview()
1469  else:
1470  self.rulesPanel.Clear()
1471 
1472  busy.Destroy()
1473 
1474  def SetRangeLabel(self):
1475  """!Set labels with info about attribute column range"""
1476 
1477  if self.properties['sourceColumn']:
1478  ctype = self.dbInfo.GetTableDesc(self.properties['table'])[self.properties['sourceColumn']]['ctype']
1479  else:
1480  ctype = int
1481 
1482  range = ''
1483  if self.properties['min'] or self.properties['max']:
1484  if ctype == float:
1485  range = "%s: %.1f - %.1f)" % (_("range"),
1486  self.properties['min'], self.properties['max'])
1487  elif ctype == int:
1488  range = "%s: %d - %d)" % (_("range"),
1489  self.properties['min'], self.properties['max'])
1490  if range:
1491  if self.colorTable:
1492  self.cr_label.SetLabel(_("Enter vector attribute values or percents %s:") % range)
1493  else:
1494  self.cr_label.SetLabel(_("Enter vector attribute values %s:") % range)
1495  else:
1496  if self.colorTable:
1497  self.cr_label.SetLabel(_("Enter vector attribute values or percents:"))
1498  else:
1499  self.cr_label.SetLabel(_("Enter vector attribute values:"))
1500 
1501  def OnFromColSelection(self, event):
1502  """!Selection in combobox (for loading values) changed"""
1503  self.properties['loadColumn'] = event.GetString()
1504 
1505  self.LoadTable()
1506 
1507  def OnToColSelection(self, event):
1508  """!Selection in combobox (for storing values) changed"""
1509  self.properties['storeColumn'] = event.GetString()
1510 
1511  def OnPreview(self, event = None, tmp = True):
1512  """!Update preview (based on computational region)"""
1513  if self.colorTable:
1514  self.OnTablePreview(tmp)
1515  else:
1516  self.OnColumnPreview()
1517 
1518  def OnTablePreview(self, tmp):
1519  """!Update preview (based on computational region)"""
1520  if not self.inmap:
1521  self.preview.EraseMap()
1522  return
1523 
1524  ltype = 'vector'
1525  cmdlist = ['d.vect',
1526  'map=%s' % self.inmap]
1527 
1528  # find existing color table and copy to temp file
1529  old_colrtable = None
1530  path = grass.find_file(name = self.inmap, element = 'vector')['file']
1531 
1532  if os.path.exists(os.path.join(path, 'colr')):
1533  old_colrtable = os.path.join(path, 'colr')
1534  colrtemp = utils.GetTempfile()
1535  shutil.copyfile(old_colrtable, colrtemp)
1536 
1537  ColorTable.DoPreview(self, ltype, cmdlist)
1538 
1539  # restore previous color table
1540  if tmp:
1541  if old_colrtable:
1542  shutil.copyfile(colrtemp, old_colrtable)
1543  os.remove(colrtemp)
1544  else:
1545  RunCommand('v.colors',
1546  parent = self,
1547  flags = 'r',
1548  map = self.inmap)
1549 
1550  def OnColumnPreview(self):
1551  """!Update preview (based on computational region)"""
1552  if not self.inmap or not self.properties['tmpColumn']:
1553  self.preview.EraseMap()
1554  return
1555 
1556  cmdlist = ['d.vect',
1557  'map=%s' % self.inmap,
1558  'type=point,line,boundary,area']
1559 
1560  if self.attributeType == 'color':
1561  cmdlist.append('flags=a')
1562  cmdlist.append('rgb_column=%s' % self.properties['tmpColumn'])
1563  elif self.attributeType == 'size':
1564  cmdlist.append('size_column=%s' % self.properties['tmpColumn'])
1565  elif self.attributeType == 'width':
1566  cmdlist.append('width_column=%s' % self.properties['tmpColumn'])
1567 
1568  ltype = 'vector'
1569 
1570  ColorTable.DoPreview(self, ltype, cmdlist)
1571 
1572  def OnHelp(self, event):
1573  """!Show GRASS manual page"""
1574  cmd = 'v.colors'
1575  ColorTable.RunHelp(self, cmd = cmd)
1576 
1577  def UseAttrColumn(self, useAttrColumn):
1578  """!Find layers and apply the changes in d.vect command"""
1579  layers = self.layerTree.FindItemByData(key = 'name', value = self.inmap)
1580  if not layers:
1581  return
1582  for layer in layers:
1583  if self.layerTree.GetPyData(layer)[0]['type'] != 'vector':
1584  continue
1585  cmdlist = self.layerTree.GetPyData(layer)[0]['maplayer'].GetCmd()
1586 
1587  if self.attributeType == 'color':
1588  if useAttrColumn:
1589  cmdlist[1].update({'flags': 'a'})
1590  cmdlist[1].update({'rgb_column': self.properties['storeColumn']})
1591  else:
1592  if 'flags' in cmdlist[1]:
1593  cmdlist[1]['flags'] = cmdlist[1]['flags'].replace('a', '')
1594  cmdlist[1].pop('rgb_column', None)
1595  elif self.attributeType == 'size':
1596  cmdlist[1].update({'size_column': self.properties['storeColumn']})
1597  elif self.attributeType == 'width':
1598  cmdlist[1].update({'width_column' :self.properties['storeColumn']})
1599  self.layerTree.GetPyData(layer)[0]['cmd'] = cmdlist
1600 
1601  def CreateColorTable(self, tmp = False):
1602  """!Create color rules (color table or color column)"""
1603  if self.colorTable:
1604  ret = ColorTable.CreateColorTable(self)
1605  else:
1606  if self.updateColumn:
1607  ret = self.UpdateColorColumn(tmp)
1608  else:
1609  ret = True
1610 
1611  return ret
1612 
1613  def UpdateColorColumn(self, tmp):
1614  """!Creates color table
1615 
1616  @return True on success
1617  @return False on failure
1618  """
1619  rulestxt = ''
1620 
1621  for rule in self.rulesPanel.ruleslines.itervalues():
1622  if 'value' not in rule: # skip empty rules
1623  break
1624 
1625  if tmp:
1626  rgb_col = self.properties['tmpColumn']
1627  else:
1628  rgb_col = self.properties['storeColumn']
1629  if not self.properties['storeColumn']:
1630  GMessage(parent = self.parent,
1631  message = _("Please select column to save values to."))
1632 
1633  rulestxt += "UPDATE %s SET %s='%s' WHERE %s ;\n" % (self.properties['table'],
1634  rgb_col,
1635  rule[self.attributeType],
1636  rule['value'])
1637  if not rulestxt:
1638  return False
1639 
1640  gtemp = utils.GetTempfile()
1641  output = open(gtemp, "w")
1642  try:
1643  output.write(rulestxt)
1644  finally:
1645  output.close()
1646 
1647  RunCommand('db.execute',
1648  parent = self,
1649  input = gtemp)
1650 
1651  return True
1652 
1653  def OnCancel(self, event):
1654  """!Do not apply any changes and close the dialog"""
1655  self.DeleteTemporaryColumn()
1656  self.Map.Clean()
1657  self.Destroy()
1658 
1659  def OnApply(self, event):
1660  """!Apply selected color table
1661 
1662  @return True on success otherwise False
1663  """
1664  if self.colorTable:
1665  self.UseAttrColumn(False)
1666  else:
1667  if not self.properties['storeColumn']:
1668  GError(_("No color column defined. Operation canceled."),
1669  parent = self)
1670  return
1671 
1672  self.UseAttrColumn(True)
1673 
1674  return ColorTable.OnApply(self, event)
1675 
1676 class BufferedWindow(wx.Window):
1677  """!A Buffered window class"""
1678  def __init__(self, parent, id,
1679  style = wx.NO_FULL_REPAINT_ON_RESIZE,
1680  Map = None, **kwargs):
1681 
1682  wx.Window.__init__(self, parent, id, style = style, **kwargs)
1683 
1684  self.parent = parent
1685  self.Map = Map
1686 
1687  # re-render the map from GRASS or just redraw image
1688  self.render = True
1689  # indicates whether or not a resize event has taken place
1690  self.resize = False
1691 
1692  #
1693  # event bindings
1694  #
1695  self.Bind(wx.EVT_PAINT, self.OnPaint)
1696  self.Bind(wx.EVT_IDLE, self.OnIdle)
1697  self.Bind(wx.EVT_ERASE_BACKGROUND, lambda x: None)
1698 
1699  #
1700  # render output objects
1701  #
1702  # image file to be rendered
1703  self.mapfile = None
1704  # wx.Image object (self.mapfile)
1705  self.img = None
1706 
1707  self.pdc = wx.PseudoDC()
1708  # will store an off screen empty bitmap for saving to file
1709  self._Buffer = None
1710 
1711  # make sure that extents are updated at init
1712  self.Map.region = self.Map.GetRegion()
1713  self.Map.SetRegion()
1714 
1715  def Draw(self, pdc, img = None, pdctype = 'image'):
1716  """!Draws preview or clears window"""
1717  pdc.BeginDrawing()
1718 
1719  Debug.msg (3, "BufferedWindow.Draw(): pdctype=%s" % (pdctype))
1720 
1721  if pdctype == 'clear': # erase the display
1722  bg = wx.WHITE_BRUSH
1723  pdc.SetBackground(bg)
1724  pdc.Clear()
1725  self.Refresh()
1726  pdc.EndDrawing()
1727  return
1728 
1729  if pdctype == 'image' and img:
1730  bg = wx.TRANSPARENT_BRUSH
1731  pdc.SetBackground(bg)
1732  bitmap = wx.BitmapFromImage(img)
1733  w, h = bitmap.GetSize()
1734  pdc.DrawBitmap(bitmap, 0, 0, True) # draw the composite map
1735 
1736  pdc.EndDrawing()
1737  self.Refresh()
1738 
1739  def OnPaint(self, event):
1740  """!Draw pseudo DC to buffer"""
1741  self._Buffer = wx.EmptyBitmap(self.Map.width, self.Map.height)
1742  dc = wx.BufferedPaintDC(self, self._Buffer)
1743 
1744  # use PrepareDC to set position correctly
1745  # probably does nothing, removed from wxPython 2.9
1746  # self.PrepareDC(dc)
1747 
1748  # we need to clear the dc BEFORE calling PrepareDC
1749  bg = wx.Brush(self.GetBackgroundColour())
1750  dc.SetBackground(bg)
1751  dc.Clear()
1752 
1753  # create a clipping rect from our position and size
1754  # and the Update Region
1755  rgn = self.GetUpdateRegion()
1756  r = rgn.GetBox()
1757 
1758  # draw to the dc using the calculated clipping rect
1759  self.pdc.DrawToDCClipped(dc, r)
1760 
1761  def OnSize(self, event):
1762  """!Init image size to match window size"""
1763  # set size of the input image
1764  self.Map.width, self.Map.height = self.GetClientSize()
1765 
1766  # Make new off screen bitmap: this bitmap will always have the
1767  # current drawing in it, so it can be used to save the image to
1768  # a file, or whatever.
1769  self._Buffer = wx.EmptyBitmap(self.Map.width, self.Map.height)
1770 
1771  # get the image to be rendered
1772  self.img = self.GetImage()
1773 
1774  # update map display
1775  if self.img and self.Map.width + self.Map.height > 0: # scale image during resize
1776  self.img = self.img.Scale(self.Map.width, self.Map.height)
1777  self.render = False
1778  self.UpdatePreview()
1779 
1780  # re-render image on idle
1781  self.resize = True
1782 
1783  def OnIdle(self, event):
1784  """!Only re-render a preview image from GRASS during
1785  idle time instead of multiple times during resizing.
1786  """
1787  if self.resize:
1788  self.render = True
1789  self.UpdatePreview()
1790  event.Skip()
1791 
1792  def GetImage(self):
1793  """!Converts files to wx.Image"""
1794  if self.Map.mapfile and os.path.isfile(self.Map.mapfile) and \
1795  os.path.getsize(self.Map.mapfile):
1796  img = wx.Image(self.Map.mapfile, wx.BITMAP_TYPE_ANY)
1797  else:
1798  img = None
1799 
1800  return img
1801 
1802  def UpdatePreview(self, img = None):
1803  """!Update canvas if window changes geometry"""
1804  Debug.msg (2, "BufferedWindow.UpdatePreview(%s): render=%s" % (img, self.render))
1805  oldfont = ""
1806  oldencoding = ""
1807 
1808  if self.render:
1809  # extent is taken from current map display
1810  try:
1811  self.Map.region = copy.deepcopy(self.parent.parent.GetLayerTree().GetMap().GetCurrentRegion())
1812  except AttributeError:
1813  self.Map.region = self.Map.GetRegion()
1814  # render new map images
1815  self.mapfile = self.Map.Render(force = self.render)
1816  self.img = self.GetImage()
1817  self.resize = False
1818 
1819  if not self.img:
1820  return
1821 
1822  # paint images to PseudoDC
1823  self.pdc.Clear()
1824  self.pdc.RemoveAll()
1825  # draw map image background
1826  self.Draw(self.pdc, self.img, pdctype = 'image')
1827 
1828  self.resize = False
1829 
1830  def EraseMap(self):
1831  """!Erase preview"""
1832  self.Draw(self.pdc, pdctype = 'clear')
def CmdToTuple
Convert command list to tuple for gcmd.RunCommand()
Definition: core/utils.py:527
def __init__
Dialog for interactively entering color rules for vector maps.
Definition: colorrules.py:929
def AddTemporaryColumn
Add temporary column to not overwrite the original values, need to be deleted when closing dialog and...
Definition: colorrules.py:1261
def GetValue
Definition: widgets.py:118
def OnLoadRulesFile
Load color table from file.
Definition: colorrules.py:610
wxGUI command interface
def OnPreview
Update preview (based on computational region)
Definition: colorrules.py:1511
def OnRuleColor
Rule color changed.
Definition: colorrules.py:204
def UseAttrColumn
Find layers and apply the changes in d.vect command.
Definition: colorrules.py:1577
def Draw
Draws preview or clears window.
Definition: colorrules.py:1715
def OnSelectionInput
Vector map selected.
Definition: colorrules.py:1178
def ReadColorTable
Read color table.
Definition: colorrules.py:622
def UpdatePreview
Update canvas if window changes geometry.
Definition: colorrules.py:1802
def OnCheckColumn
Use color column instead of color table.
Definition: colorrules.py:1143
def OnPaint
Draw pseudo DC to buffer.
Definition: colorrules.py:1739
wxGUI debugging
def OnIdle
Only re-render a preview image from GRASS during idle time instead of multiple times during resizing...
Definition: colorrules.py:1783
def CreateColorTable
Create color rules (color table or color column)
Definition: colorrules.py:1601
def OnApply
Apply selected color table.
Definition: colorrules.py:545
def OnClearAll
Delete all widgets in panel.
Definition: colorrules.py:103
def OnRuleEnable
Rule enabled/disabled.
Definition: colorrules.py:167
def SetMap
Set map name and update dialog.
Definition: colorrules.py:762
def DeleteTemporaryColumn
Delete temporary column.
Definition: colorrules.py:1284
def OnCloseWindow
Window closed.
Definition: colorrules.py:540
def UpdateDialog
Update dialog after map selection.
Definition: colorrules.py:1196
def AddRules
Add rules.
Definition: colorrules.py:112
def OnTablePreview
Update preview (based on computational region)
Definition: colorrules.py:1518
def DoPreview
Update preview (based on computational region)
Definition: colorrules.py:741
def _createVectorAttrb
Create part of dialog with layer/column selection.
Definition: colorrules.py:982
def InitDisplay
Initialize preview display, set dimensions and region.
Definition: colorrules.py:533
def CheckMapset
Check if current vector is in current mapset.
Definition: colorrules.py:1121
def LoadTable
Load current color table (using r(v).colors.out)
Definition: colorrules.py:667
def SetValue
Definition: widgets.py:115
def OnCancel
Do not apply any changes, remove associated rendered images and close the dialog. ...
Definition: colorrules.py:567
def OnHelp
Show GRASS manual page.
Definition: colorrules.py:1572
def OnSelectionInput
Raster map selected.
Definition: colorrules.py:834
def CreateColorTable
Creates color table.
Definition: colorrules.py:697
Custom control that selects elements.
Rendering map layers and overlays into map composition image.
def Clear
Clear and widgets and delete information.
Definition: colorrules.py:89
def split
Platform spefic shlex.split.
Definition: core/utils.py:37
def DisableClearAll
Enable, disable the whole dialog.
Definition: colorrules.py:1169
def SetRangeLabel
Set labels with info about attribute column range.
Definition: colorrules.py:1474
def __init__
Create rules panel.
Definition: colorrules.py:46
def _createButtons
Create buttons for leaving dialog.
Definition: colorrules.py:453
def _createPreview
Create preview.
Definition: colorrules.py:445
def _createFileSelection
Create file (open/save rules) selection part of dialog.
Definition: colorrules.py:391
def __init__
Dialog for interactively entering color rules for raster maps.
Definition: colorrules.py:775
A Buffered window class.
Definition: colorrules.py:1676
def _createMapSelection
Create map selection part of dialog.
Definition: colorrules.py:371
def _createBody
Create dialog body consisting of rules and preview.
Definition: colorrules.py:483
def EnableVectorAttributes
Enable/disable part of dialog connected with db.
Definition: colorrules.py:1164
def CreateAttrTable
Create attribute table.
Definition: colorrules.py:1356
def OnApply
Apply selected color table.
Definition: colorrules.py:1659
def UpdateColorColumn
Creates color table.
Definition: colorrules.py:1613
def SetRasterRule
Set raster rule.
Definition: colorrules.py:243
def GetTempfile
Creates GRASS temporary file using defined prefix.
Definition: core/utils.py:44
def OnLoadDefaultTable
Load internal color table.
Definition: colorrules.py:663
def OnOK
Apply selected color table and close the dialog.
Definition: colorrules.py:562
def OnSaveRulesFile
Save color table to file.
Definition: colorrules.py:590
def OnRuleSize
Rule size changed.
Definition: colorrules.py:216
def OnFromColSelection
Selection in combobox (for loading values) changed.
Definition: colorrules.py:1501
def OnHelp
Show GRASS manual page.
Definition: colorrules.py:923
def OnCancel
Do not apply any changes and close the dialog.
Definition: colorrules.py:1653
def OnSize
Init image size to match window size.
Definition: colorrules.py:1761
def GetColorTables
Get list of color tables.
Definition: core/utils.py:694
def GetImage
Converts files to wx.Image.
Definition: colorrules.py:1792
def __init__
Dialog for interactively entering rules for map management commands.
Definition: colorrules.py:315
def OnAddRules
Add rules button pressed.
Definition: colorrules.py:107
def LoadRulesFromColumn
Load current column (GRASSRGB, size column)
Definition: colorrules.py:1377
def OnToColSelection
Selection in combobox (for storing values) changed.
Definition: colorrules.py:1507
def OnAddColumn
Add GRASS(RGB,SIZE,WIDTH) column if it doesn&#39;t exist.
Definition: colorrules.py:1333
def OnSetTable
Load pre-defined color table.
Definition: colorrules.py:573
def OnRuleValue
Rule value changed.
Definition: colorrules.py:223
def _IsNumber
Check if &#39;s&#39; is a number.
Definition: colorrules.py:766
def RunHelp
Show GRASS manual page.
Definition: colorrules.py:755
Default GUI settings.
def _initLayer
Set initial layer when opening dialog.
Definition: colorrules.py:352
def SetVectorRule
Set vector rule.
Definition: colorrules.py:247
tuple range
Definition: tools.py:1406
def OnColumnPreview
Update preview (based on computational region)
Definition: colorrules.py:1550
def EraseMap
Erase preview.
Definition: colorrules.py:1830
def OnPreview
Update preview (based on computational region)
Definition: colorrules.py:882
def LoadTable
Load table.
Definition: colorrules.py:1370
def OnCheckAll
(Un)check all rules
Definition: colorrules.py:94
def RunCommand
Run GRASS command.
Definition: gcmd.py:625
def SQLConvert
Prepare value for SQL query.
Definition: colorrules.py:301
def Enable
Enable/Disable all widgets.
Definition: colorrules.py:257