2 @package module.colorrules
4 @brief Dialog for interactive management of raster/vector color tables
8 - colorrules::RulesPanel
9 - colorrules::ColorTable
10 - colorrules::RasterColorTable
11 - colorrules::VectorColorTable
12 - colorrules::BufferedWindow
14 (C) 2008, 2010-2012 by the GRASS Development Team
16 This program is free software under the GNU General Public License
17 (>=v2). Read the file COPYING that comes with GRASS for details.
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)
30 import wx.lib.colourselect
as csel
31 import wx.lib.scrolledpanel
as scrolled
32 import wx.lib.filebrowsebutton
as filebrowse
36 from core
import globalvar
37 from core
import utils
38 from core.gcmd import GMessage, RunCommand, GError
41 from gui_core.forms
import GUI
46 def __init__(self, parent, mapType, attributeType, properties, panelWidth = 180):
47 """!Create rules panel
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"""
61 self.
mainSizer = wx.FlexGridSizer(cols = 3, vgap = 6, hgap = 4)
64 self.mainSizer.Add(item = wx.Size(3, 3))
66 self.
mainPanel = scrolled.ScrolledPanel(parent, id = wx.ID_ANY,
68 style = wx.TAB_TRAVERSAL | wx.SUNKEN_BORDER)
71 self.
checkAll = wx.CheckBox(parent, id = wx.ID_ANY, label = _(
"Check all"))
72 self.checkAll.SetValue(
True)
74 self.
clearAll = wx.Button(parent, id = wx.ID_ANY, label = _(
"Clear all"))
76 self.
numRules = wx.SpinCtrl(parent, id = wx.ID_ANY,
77 min = 1, max = 1e6, initial = 1)
79 self.
btnAdd = wx.Button(parent, id = wx.ID_ADD)
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)
86 self.mainPanel.SetAutoLayout(
True)
87 self.mainPanel.SetupScrolling()
90 """!Clear and widgets and delete information"""
91 self.ruleslines.clear()
92 self.mainSizer.Clear(deleteWindows=
True)
95 """!(Un)check all rules"""
96 check = event.GetInt()
97 for child
in self.mainPanel.GetChildren():
98 if child.GetName() ==
'enable':
104 """!Delete all widgets in panel"""
108 """!Add rules button pressed"""
109 nrules = self.numRules.GetValue()
114 @param start set widgets (not append)"""
116 snum = len(self.ruleslines.keys())
119 for num
in range(snum, snum + nrules):
121 enable = wx.CheckBox(parent = self.
mainPanel, id = num)
122 enable.SetValue(
True)
123 enable.SetName(
'enable')
126 txt_ctrl = wx.TextCtrl(parent = self.
mainPanel, id = 1000 + num,
128 style = wx.TE_NOHIDESEL)
130 txt_ctrl.SetToolTipString(_(
"Enter vector attribute values"))
132 txt_ctrl.SetName(
'source')
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')
140 self.
ruleslines[enable.GetId()] = {
'value' :
'',
147 columnCtrl = wx.SpinCtrl(self.
mainPanel, id = 2000 + num,
148 size = (50, -1), min = 1, max = 1e4,
150 columnCtrl.Bind(wx.EVT_SPINCTRL, self.
OnRuleSize)
152 columnCtrl.SetName(
'target')
154 self.
ruleslines[enable.GetId()] = {
'value' :
'',
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)
164 self.mainPanel.Layout()
165 self.mainPanel.SetupScrolling(scroll_x =
False)
168 """!Rule enabled/disabled"""
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:
176 vals.append(self.mainPanel.FindWindowById(id + 1000).
GetValue())
178 vals.append(self.mainPanel.FindWindowById(id + 1 + 1000).
GetValue())
179 except AttributeError:
183 value = self.mainPanel.FindWindowById(id + 1000).
GetValue()
184 color = self.mainPanel.FindWindowById(id + 2000).
GetValue()
188 color_str = str(color[0]) +
':' \
189 + str(color[1]) +
':' \
192 'color' : color_str }
200 self.mainPanel.FindWindowById(id + 1000).Disable()
201 self.mainPanel.FindWindowById(id + 2000).Disable()
205 """!Rule color changed"""
208 rgba_color = event.GetValue()
210 rgb_string = str(rgba_color[0]) +
':' \
211 + str(rgba_color[1]) +
':' \
214 self.
ruleslines[num-2000][
'color'] = rgb_string
217 """!Rule size changed"""
219 size = event.GetInt()
224 """!Rule value changed"""
226 val = event.GetString().strip()
231 table = self.parent.colorTable
232 except AttributeError:
234 if isinstance(self.parent.GetParent(), RasterColorTable):
235 table = self.parent.GetParent().colorTable
237 table = self.parent.GetParent().GetParent().colorTable
244 """!Set raster rule"""
248 """!Set vector rule"""
252 vals.append(self.mainPanel.FindWindowById(num + 1).
GetValue())
253 except AttributeError:
258 """!Enable/Disable all widgets"""
259 for child
in self.mainPanel.GetChildren():
262 self.LoadRulesline(sql)
263 self.btnAdd.Enable(enable)
264 self.numRules.Enable(enable)
265 self.checkAll.Enable(enable)
266 self.clearAll.Enable(enable)
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))
291 self.mainPanel.FindWindowById(item + 2000).
SetValue(value)
296 GMessage(parent = self.
parent, message = message)
302 """!Prepare value for SQL query"""
303 if vals[0].isdigit():
304 sqlrule =
'%s=%s' % (self.
properties[
'sourceColumn'], vals[0])
306 sqlrule +=
' AND %s<%s' % (self.
properties[
'sourceColumn'], vals[1])
308 sqlrule =
'%s=%s' % (self.
properties[
'sourceColumn'], vals[0])
313 def __init__(self, parent, title, layerTree = None, id = wx.ID_ANY,
314 style = wx.DEFAULT_FRAME_STYLE | wx.RESIZE_BORDER,
316 """!Dialog for interactively entering rules for map management
322 wx.Frame.__init__(self, parent, id, title, style = style, **kwargs)
324 self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR,
'grass.ico'), wx.BITMAP_TYPE_ICO))
326 self.
panel = wx.Panel(parent = self, id = wx.ID_ANY)
341 self.Bind(wx.EVT_BUTTON, self.OnHelp, self.
btnHelp)
342 self.selectionInput.Bind(wx.EVT_TEXT, self.OnSelectionInput)
345 self.Bind(wx.EVT_BUTTON, self.
OnOK, self.
btnOK)
350 self.Bind(wx.EVT_BUTTON, self.OnPreview, self.
btnPreview)
352 def _initLayer(self):
353 """!Set initial layer when opening dialog"""
357 sel = self.layerTree.layer_selected
358 if sel
and self.layerTree.GetPyData(sel)[0][
'type'] == self.
mapType:
361 layer = self.layerTree.FindItemByData(key =
'type', value = self.
mapType)
365 mapLayer = self.layerTree.GetPyData(layer)[0][
'maplayer']
366 name = mapLayer.GetName()
367 type = mapLayer.GetType()
368 self.selectionInput.SetValue(name)
371 def _createMapSelection(self, parent):
372 """!Create map selection part of dialog"""
375 maplabel = _(
'Select raster map:')
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)
383 size = globalvar.DIALOG_GSELECT_SIZE,
387 flag = wx.ALIGN_CENTER_VERTICAL | wx.ALL | wx.EXPAND, border = 5)
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)
397 self.
loadRules = filebrowse.FileBrowseButton(parent = parent, id = wx.ID_ANY, fileMask =
'*',
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,
405 self.
saveRules = filebrowse.FileBrowseButton(parent = parent, id = wx.ID_ANY, fileMask =
'*',
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,
414 colorTable = wx.Choice(parent = parent, id = wx.ID_ANY, size = (200, -1),
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)
422 gridSizer = wx.GridBagSizer(hgap = 2, vgap = 2)
423 gridSizer.AddGrowableCol(1)
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)
436 inputSizer.Add(gridSizer, proportion = 1, flag = wx.EXPAND | wx.ALL,
441 parent.SetSizer(inputSizer)
445 def _createPreview(self, parent):
446 """!Create preview"""
451 self.preview.EraseMap()
453 def _createButtons(self, parent):
454 """!Create buttons for leaving dialog"""
455 self.
btnHelp = wx.Button(parent, id = wx.ID_HELP)
457 self.
btnApply = wx.Button(parent, id = wx.ID_APPLY)
458 self.
btnOK = wx.Button(parent, id = wx.ID_OK)
460 label = _(
"Reload default table"))
462 self.btnOK.SetDefault()
463 self.btnOK.Enable(
False)
464 self.btnApply.Enable(
False)
465 self.btnDefault.Enable(
False)
468 btnSizer = wx.BoxSizer(wx.HORIZONTAL)
469 btnSizer.Add(wx.Size(-1, -1), proportion = 1)
471 flag = wx.LEFT | wx.RIGHT, border = 5)
473 flag = wx.LEFT | wx.RIGHT, border = 5)
475 flag = wx.LEFT | wx.RIGHT, border = 5)
477 flag = wx.LEFT | wx.RIGHT, border = 5)
478 btnSizer.Add(self.
btnOK,
479 flag = wx.LEFT | wx.RIGHT, border = 5)
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)
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)
498 attributeType = self.attributeType, properties = self.properties)
500 bodySizer.Add(item = self.rulesPanel.mainPanel, pos = (row, 0),
501 span = (1, 2), flag = wx.EXPAND)
503 self.rulesPanel.AddRules(2)
507 bodySizer.Add(item = self.
preview, pos = (row, 2),
508 flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER)
512 bodySizer.Add(item = self.rulesPanel.checkAll, flag = wx.ALIGN_CENTER_VERTICAL,
514 bodySizer.Add(item = self.rulesPanel.clearAll, pos = (row, 1))
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)."))
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))
534 """!Initialize preview display, set dimensions and region
546 """!Apply selected color table
548 @return True on success otherwise False
552 GMessage(parent = self, message = _(
"No valid color rules given."))
556 display = self.layerTree.GetMapDisplay()
557 if display
and display.IsAutoRendered():
558 display.GetWindow().UpdateMap(render =
True)
563 """!Apply selected color table and close the dialog"""
568 """!Do not apply any changes, remove associated
569 rendered images and close the dialog"""
574 """!Load pre-defined color table"""
575 ct = self.FindWindowByName(
"colorTableChoice").GetStringSelection()
577 ctOriginal =
RunCommand(
'r.colors.out', read =
True, map = self.
inmap, rules =
'-')
579 ret, err =
RunCommand(
'r.colors', map = self.
inmap, color = ct, getErrorMsg =
True)
581 GError(err, parent = self)
583 ctNew =
RunCommand(
'r.colors.out', read =
True, map = self.
inmap, rules =
'-')
585 RunCommand(
'r.colors', map = self.
inmap, rules =
'-', stdin = ctOriginal)
587 self.rulesPanel.Clear()
591 """!Save color table to file"""
592 path = event.GetString()
593 if not os.path.exists(path):
597 for rule
in self.rulesPanel.ruleslines.itervalues():
598 if 'value' not in rule:
600 rulestxt += rule[
'value'] +
' ' + rule[
'color'] +
'\n'
602 GMessage(message = _(
"Nothing to save."),
611 """!Load color table from file"""
612 path = event.GetString()
613 if not os.path.exists(path):
616 self.rulesPanel.Clear()
625 @param table color table in format coming from r.colors.out"""
627 rulesNumber = len(ctable.splitlines())
628 self.rulesPanel.AddRules(rulesNumber)
630 minim = maxim = count = 0
631 for line
in ctable.splitlines():
633 value, color = map(
lambda x: x.strip(), line.split(
' '))
635 GMessage(parent = self, message = _(
"Invalid color table format"))
636 self.rulesPanel.Clear()
639 self.rulesPanel.ruleslines[count][
'value'] = value
640 self.rulesPanel.ruleslines[count][
'color'] = color
641 self.rulesPanel.mainPanel.FindWindowById(count + 1000).
SetValue(value)
643 for c
in color.split(
':'):
645 self.rulesPanel.mainPanel.FindWindowById(count + 2000).SetColour(rgb)
648 if float(value) < minim:
650 if float(value) > maxim:
658 self.properties[
'min'], self.properties[
'max'] = minim, maxim
661 self.OnPreview(tmp =
True)
664 """!Load internal color table"""
668 """!Load current color table (using `r(v).colors.out`)
670 @param mapType map type (raster or vector)"""
671 self.rulesPanel.Clear()
673 if mapType ==
'raster':
674 cmd = [
'r.colors.out',
676 'map=%s' % self.
inmap,
679 cmd = [
'v.colors.out',
681 'map=%s' % self.
inmap,
684 if self.properties[
'sourceColumn']
and self.properties[
'sourceColumn'] !=
'cat':
685 cmd.append(
'column=%s' % self.properties[
'sourceColumn'])
698 """!Creates color table
700 @return True on success
701 @return False on failure
705 for rule
in self.rulesPanel.ruleslines.itervalues():
706 if 'value' not in rule:
709 if rule[
'value']
not in (
'nv',
'default')
and \
710 rule[
'value'][-1] !=
'%' and \
712 GError(_(
"Invalid rule value '%s'. Unable to apply color table.") % rule[
'value'],
716 rulestxt += rule[
'value'] +
' ' + rule[
'color'] +
'\n'
722 output = open(gtemp,
"w")
724 output.write(rulestxt)
728 cmd = [
'%s.colors' % self.
mapType[0],
729 'map=%s' % self.
inmap,
731 if self.
mapType ==
'vector' and self.properties[
'sourceColumn'] \
732 and self.properties[
'sourceColumn'] !=
'cat':
733 cmd.append(
'column=%s' % self.properties[
'sourceColumn'])
742 """!Update preview (based on computational region)"""
745 self.
layer = self.Map.AddLayer(type = ltype, name =
'preview', command = cmdlist,
746 l_active =
True, l_hidden =
False, l_opacity = 1.0,
749 self.layer.SetCmd(cmdlist)
753 self.preview.UpdatePreview()
756 """!Show GRASS manual page"""
763 """!Set map name and update dialog"""
764 self.selectionInput.SetValue(name)
766 def _IsNumber(self, s):
767 """!Check if 's' is a number"""
776 """!Dialog for interactively entering color rules for raster maps"""
789 ColorTable.__init__(self, parent,
790 title = _(
'Create new color table for raster map'), **kwargs)
795 self.SetMinSize((650, 700))
798 """!Do main layout"""
799 sizer = wx.BoxSizer(wx.VERTICAL)
804 sizer.Add(item = mapSelection, proportion = 0,
805 flag = wx.ALL | wx.EXPAND, border = 5)
810 sizer.Add(item = fileSelection, proportion = 0,
811 flag = wx.LEFT | wx.RIGHT | wx.EXPAND, border = 5)
816 sizer.Add(item = bodySizer, proportion = 1,
817 flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 5)
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)
826 sizer.Add(item = btnSizer, proportion = 0,
827 flag = wx.ALL | wx.ALIGN_RIGHT, border = 5)
829 self.panel.SetSizer(sizer)
831 sizer.Fit(self.
panel)
835 """!Raster map selected"""
839 self.loadRules.SetValue(
'')
840 self.saveRules.SetValue(
'')
843 if not grass.find_file(name = self.
inmap, element =
'cell')[
'file']:
853 info = grass.raster_info(map = self.
inmap)
865 self.preview.EraseMap()
866 self.cr_label.SetLabel(_(
'Enter raster category values or percents'))
869 if info[
'datatype'] ==
'CELL':
870 mapRange = _(
'range')
872 mapRange = _(
'fp range')
873 self.cr_label.SetLabel(_(
'Enter raster category values or percents (%(range)s = %(min)d-%(max)d)') %
874 {
'range' : mapRange,
883 """!Update preview (based on computational region)"""
885 self.preview.EraseMap()
889 'map=%s' % self.
inmap]
894 name, mapset = self.inmap.split(
'@')
897 mapset = grass.find_file(self.
inmap, element =
'cell')[
'mapset']
901 if mapset == grass.gisenv()[
'MAPSET']:
902 old_colrtable = grass.find_file(name = name, element =
'colr')[
'file']
904 old_colrtable = grass.find_file(name = name, element =
'colr2/' + mapset)[
'file']
908 shutil.copyfile(old_colrtable, colrtemp)
910 ColorTable.DoPreview(self, ltype, cmdlist)
915 shutil.copyfile(colrtemp, old_colrtable)
924 """!Show GRASS manual page"""
926 ColorTable.RunHelp(self, cmd = cmd)
929 def __init__(self, parent, attributeType, **kwargs):
930 """!Dialog for interactively entering color rules for vector maps"""
951 'tmpColumn' :
'tmp_0',
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)
972 self.cr_label.SetLabel(_(
"Enter vector attribute values or percents:"))
974 self.cr_label.SetLabel(_(
"Enter vector attribute values:"))
977 self.SetMinSize((650, 700))
979 self.CentreOnScreen()
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,
988 cb_vc_label = wx.StaticText(parent, id = wx.ID_ANY,
989 label = _(
'Attribute column:'))
992 labels = [_(
"Load color from column:"), _(
"Save color to column:")]
994 labels = [_(
"Load size from column:"), _(
"Save size to column:")]
996 labels = [_(
"Load width from column:"), _(
"Save width to column:")]
1000 label = _(
"Use color column instead of color table:"))
1003 fromColumnLabel = wx.StaticText(parent, id = wx.ID_ANY,
1005 toColumnLabel = wx.StaticText(parent, id = wx.ID_ANY,
1014 label = _(
'Add column'))
1015 self.addColumn.SetToolTipString(_(
"Add GRASSRGB column to current attribute table."))
1018 inputSizer = wx.StaticBoxSizer(inputBox, wx.VERTICAL)
1019 vSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
1021 vSizer.Add(cb_vl_label, pos = (row, 0),
1022 flag = wx.ALIGN_CENTER_VERTICAL)
1024 flag = wx.ALIGN_CENTER_VERTICAL)
1026 vSizer.Add(cb_vc_label, pos = (row, 0),
1027 flag = wx.ALIGN_CENTER_VERTICAL)
1029 flag = wx.ALIGN_CENTER_VERTICAL)
1031 flag = wx.ALIGN_CENTER_VERTICAL)
1034 vSizer.Add(self.
useColumn, pos = (row, 0), span = (1, 2),
1035 flag = wx.ALIGN_CENTER_VERTICAL)
1038 vSizer.Add(fromColumnLabel, pos = (row, 0),
1039 flag = wx.ALIGN_CENTER_VERTICAL)
1041 flag = wx.ALIGN_CENTER_VERTICAL)
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)
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)
1064 sizer.Add(item = mapSelection, proportion = 0,
1065 flag = wx.ALL | wx.EXPAND, border = 5)
1070 self.
cp = wx.CollapsiblePane(scrollPanel, label = _(
"Import or export color table"),
1072 style = wx.CP_DEFAULT_STYLE|wx.CP_NO_TLW_RESIZE)
1073 self.Bind(wx.EVT_COLLAPSIBLEPANE_CHANGED, self.
OnPaneChanged, self.
cp)
1076 sizer.Add(item = self.
cp, proportion = 0,
1077 flag = wx.ALL | wx.EXPAND, border = 5)
1082 sizer.Add(item = vectorAttrb, proportion = 0,
1083 flag = wx.ALL | wx.EXPAND, border = 5)
1087 bodySizer = self.
_createBody(parent = scrollPanel)
1088 sizer.Add(item = bodySizer, proportion = 1,
1089 flag = wx.ALL | wx.EXPAND, border = 5)
1091 scrollPanel.SetSizer(sizer)
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)
1107 self.panel.SetSizer(mainsizer)
1109 mainsizer.Fit(self.
panel)
1116 if self.cp.IsExpanded():
1117 self.cp.SetLabel(
'')
1119 self.cp.SetLabel(_(
"Import or export color table"))
1122 """!Check if current vector is in current mapset"""
1123 if grass.find_file(name = self.
inmap,
1124 element =
'vector')[
'mapset'] == grass.gisenv()[
'MAPSET']:
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:
1138 GUI(parent = self).ParseCommand([
'v.db.addtable',
'map=' + self.
inmap],
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)
1155 self.rulesPanel.Clear()
1159 self.fromColumn.Enable(
False)
1160 self.toColumn.Enable(
False)
1165 """!Enable/disable part of dialog connected with db"""
1166 for child
in self.colorColumnSizer.GetChildren():
1167 child.GetWindow().Enable(enable)
1170 """!Enable, disable the whole dialog"""
1171 self.rulesPanel.Clear()
1173 self.btnPreview.Enable(
False)
1174 self.btnOK.Enable(
False)
1175 self.btnApply.Enable(
False)
1176 self.preview.EraseMap()
1179 """!Vector map selected"""
1187 self.loadRules.SetValue(
'')
1188 self.saveRules.SetValue(
'')
1191 if not grass.find_file(name = self.
inmap, element =
'vector')[
'file']:
1197 """!Update dialog after map selection"""
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'] }
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)
1222 if not len(self.dbInfo.layers):
1229 for prop
in (
'sourceColumn',
'loadColumn',
'storeColumn'):
1235 self.layerSelect.InsertLayers(self.
inmap)
1237 self.
properties[
'layer'] = self.layerSelect.GetString(0)
1238 self.layerSelect.SetStringSelection(self.
properties[
'layer'])
1240 self.
properties[
'table'] = self.dbInfo.layers[layer][
'table']
1252 self.useColumn.SetValue(
False)
1257 self.btnPreview.Enable(enable)
1258 self.btnOK.Enable(enable)
1259 self.btnApply.Enable(enable)
1262 """!Add temporary column to not overwrite the original values,
1263 need to be deleted when closing dialog and unloading map
1265 @param type type of column (e.g. vachar(11))"""
1268 while self.
properties[
'tmpColumn']
in self.dbInfo.GetTableDesc(self.
properties[
'table']).keys():
1272 self.
properties[
'tmpColumn'] = name +
'_' + str(idx)
1275 modul =
'v.db.addcolumn'
1277 modul =
'v.db.addcol'
1282 column =
'%s %s' % (self.
properties[
'tmpColumn'], type))
1285 """!Delete temporary column"""
1288 modul =
'v.db.dropcolumn'
1290 modul =
'v.db.dropcol'
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)
1306 type = [
'character']
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'])
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)
1329 self.
properties[
'sourceColumn'] = event.GetString()
1334 """!Add GRASS(RGB,SIZE,WIDTH) column if it doesn't exist"""
1337 modul =
'v.db.addcolumn'
1339 modul =
'v.db.addcol'
1348 self.
properties[
'storeColumn'] = self.toColumn.GetStringSelection()
1352 GMessage(parent = self,
1353 message = _(
"%s column already exists.") % \
1357 """!Create attribute table"""
1373 ColorTable.LoadTable(self, mapType =
'vector')
1378 """!Load current column (GRASSRGB, size column)"""
1380 self.rulesPanel.Clear()
1382 self.preview.EraseMap()
1385 busy = wx.BusyInfo(message = _(
"Please wait, loading data from attribute table..."),
1391 columns +=
',' + self.
properties[
'loadColumn']
1395 outFile = tempfile.NamedTemporaryFile(mode =
'w+b')
1405 self.preview.EraseMap()
1419 record = outFile.readline().replace(
'\n',
'')
1422 self.rulesPanel.ruleslines[i] = {}
1428 col1, col2 = record.split(sep)
1430 if float(col1) < minim:
1432 if float(col1) > maxim:
1437 if col1
not in colvallist:
1438 self.rulesPanel.ruleslines[i][
'value'] = col1
1441 colvallist.append(col1)
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:
1461 self.rulesPanel.AddRules(i, start =
True)
1462 ret = self.rulesPanel.LoadRules()
1470 self.rulesPanel.Clear()
1475 """!Set labels with info about attribute column range"""
1478 ctype = self.dbInfo.GetTableDesc(self.
properties[
'table'])[self.
properties[
'sourceColumn']][
'ctype']
1485 range =
"%s: %.1f - %.1f)" % (_(
"range"),
1488 range =
"%s: %d - %d)" % (_(
"range"),
1492 self.cr_label.SetLabel(_(
"Enter vector attribute values or percents %s:") % range)
1494 self.cr_label.SetLabel(_(
"Enter vector attribute values %s:") % range)
1497 self.cr_label.SetLabel(_(
"Enter vector attribute values or percents:"))
1499 self.cr_label.SetLabel(_(
"Enter vector attribute values:"))
1502 """!Selection in combobox (for loading values) changed"""
1503 self.
properties[
'loadColumn'] = event.GetString()
1508 """!Selection in combobox (for storing values) changed"""
1509 self.
properties[
'storeColumn'] = event.GetString()
1512 """!Update preview (based on computational region)"""
1519 """!Update preview (based on computational region)"""
1521 self.preview.EraseMap()
1525 cmdlist = [
'd.vect',
1526 'map=%s' % self.
inmap]
1529 old_colrtable =
None
1530 path = grass.find_file(name = self.
inmap, element =
'vector')[
'file']
1532 if os.path.exists(os.path.join(path,
'colr')):
1533 old_colrtable = os.path.join(path,
'colr')
1535 shutil.copyfile(old_colrtable, colrtemp)
1537 ColorTable.DoPreview(self, ltype, cmdlist)
1542 shutil.copyfile(colrtemp, old_colrtable)
1551 """!Update preview (based on computational region)"""
1553 self.preview.EraseMap()
1556 cmdlist = [
'd.vect',
1557 'map=%s' % self.
inmap,
1558 'type=point,line,boundary,area']
1561 cmdlist.append(
'flags=a')
1562 cmdlist.append(
'rgb_column=%s' % self.
properties[
'tmpColumn'])
1564 cmdlist.append(
'size_column=%s' % self.
properties[
'tmpColumn'])
1566 cmdlist.append(
'width_column=%s' % self.
properties[
'tmpColumn'])
1570 ColorTable.DoPreview(self, ltype, cmdlist)
1573 """!Show GRASS manual page"""
1575 ColorTable.RunHelp(self, cmd = cmd)
1578 """!Find layers and apply the changes in d.vect command"""
1579 layers = self.layerTree.FindItemByData(key =
'name', value = self.
inmap)
1582 for layer
in layers:
1583 if self.layerTree.GetPyData(layer)[0][
'type'] !=
'vector':
1585 cmdlist = self.layerTree.GetPyData(layer)[0][
'maplayer'].GetCmd()
1589 cmdlist[1].
update({
'flags':
'a'})
1592 if 'flags' in cmdlist[1]:
1593 cmdlist[1][
'flags'] = cmdlist[1][
'flags'].replace(
'a',
'')
1594 cmdlist[1].pop(
'rgb_column',
None)
1599 self.layerTree.GetPyData(layer)[0][
'cmd'] = cmdlist
1602 """!Create color rules (color table or color column)"""
1604 ret = ColorTable.CreateColorTable(self)
1614 """!Creates color table
1616 @return True on success
1617 @return False on failure
1621 for rule
in self.rulesPanel.ruleslines.itervalues():
1622 if 'value' not in rule:
1630 GMessage(parent = self.
parent,
1631 message = _(
"Please select column to save values to."))
1633 rulestxt +=
"UPDATE %s SET %s='%s' WHERE %s ;\n" % (self.
properties[
'table'],
1641 output = open(gtemp,
"w")
1643 output.write(rulestxt)
1654 """!Do not apply any changes and close the dialog"""
1660 """!Apply selected color table
1662 @return True on success otherwise False
1668 GError(_(
"No color column defined. Operation canceled."),
1674 return ColorTable.OnApply(self, event)
1677 """!A Buffered window class"""
1679 style = wx.NO_FULL_REPAINT_ON_RESIZE,
1680 Map =
None, **kwargs):
1682 wx.Window.__init__(self, parent, id, style = style, **kwargs)
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)
1712 self.Map.region = self.Map.GetRegion()
1713 self.Map.SetRegion()
1715 def Draw(self, pdc, img = None, pdctype = 'image'):
1716 """!Draws preview or clears window"""
1719 Debug.msg (3,
"BufferedWindow.Draw(): pdctype=%s" % (pdctype))
1721 if pdctype ==
'clear':
1723 pdc.SetBackground(bg)
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)
1740 """!Draw pseudo DC to buffer"""
1741 self.
_Buffer = wx.EmptyBitmap(self.Map.width, self.Map.height)
1742 dc = wx.BufferedPaintDC(self, self.
_Buffer)
1749 bg = wx.Brush(self.GetBackgroundColour())
1750 dc.SetBackground(bg)
1755 rgn = self.GetUpdateRegion()
1759 self.pdc.DrawToDCClipped(dc, r)
1762 """!Init image size to match window size"""
1764 self.Map.width, self.Map.height = self.GetClientSize()
1769 self.
_Buffer = wx.EmptyBitmap(self.Map.width, self.Map.height)
1775 if self.
img and self.Map.width + self.Map.height > 0:
1776 self.
img = self.img.Scale(self.Map.width, self.Map.height)
1784 """!Only re-render a preview image from GRASS during
1785 idle time instead of multiple times during resizing.
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)
1803 """!Update canvas if window changes geometry"""
1804 Debug.msg (2,
"BufferedWindow.UpdatePreview(%s): render=%s" % (img, self.
render))
1811 self.Map.region = copy.deepcopy(self.parent.parent.GetLayerTree().GetMap().GetCurrentRegion())
1812 except AttributeError:
1813 self.Map.region = self.Map.GetRegion()
1824 self.pdc.RemoveAll()
1826 self.
Draw(self.
pdc, self.
img, pdctype =
'image')
1831 """!Erase preview"""
1832 self.
Draw(self.
pdc, pdctype =
'clear')
def CmdToTuple
Convert command list to tuple for gcmd.RunCommand()
def __init__
Dialog for interactively entering color rules for vector maps.
def AddTemporaryColumn
Add temporary column to not overwrite the original values, need to be deleted when closing dialog and...
def OnLoadRulesFile
Load color table from file.
def OnPreview
Update preview (based on computational region)
def OnRuleColor
Rule color changed.
def UseAttrColumn
Find layers and apply the changes in d.vect command.
def Draw
Draws preview or clears window.
def OnSelectionInput
Vector map selected.
def ReadColorTable
Read color table.
def UpdatePreview
Update canvas if window changes geometry.
def OnCheckColumn
Use color column instead of color table.
def OnPaint
Draw pseudo DC to buffer.
def OnIdle
Only re-render a preview image from GRASS during idle time instead of multiple times during resizing...
def CreateColorTable
Create color rules (color table or color column)
def OnApply
Apply selected color table.
def OnClearAll
Delete all widgets in panel.
def OnRuleEnable
Rule enabled/disabled.
def SetMap
Set map name and update dialog.
def OnSourceColumnSelection
def DeleteTemporaryColumn
Delete temporary column.
def OnCloseWindow
Window closed.
def UpdateDialog
Update dialog after map selection.
def OnTablePreview
Update preview (based on computational region)
def DoPreview
Update preview (based on computational region)
def _createVectorAttrb
Create part of dialog with layer/column selection.
def InitDisplay
Initialize preview display, set dimensions and region.
def CheckMapset
Check if current vector is in current mapset.
def LoadTable
Load current color table (using r(v).colors.out)
def OnCancel
Do not apply any changes, remove associated rendered images and close the dialog. ...
def OnHelp
Show GRASS manual page.
def OnSelectionInput
Raster map selected.
def CreateColorTable
Creates color table.
Custom control that selects elements.
Rendering map layers and overlays into map composition image.
def Clear
Clear and widgets and delete information.
def split
Platform spefic shlex.split.
def DisableClearAll
Enable, disable the whole dialog.
def SetRangeLabel
Set labels with info about attribute column range.
def __init__
Create rules panel.
def _createButtons
Create buttons for leaving dialog.
def _createPreview
Create preview.
def _createFileSelection
Create file (open/save rules) selection part of dialog.
def __init__
Dialog for interactively entering color rules for raster maps.
def _createMapSelection
Create map selection part of dialog.
def _createBody
Create dialog body consisting of rules and preview.
def EnableVectorAttributes
Enable/disable part of dialog connected with db.
def CreateAttrTable
Create attribute table.
def OnApply
Apply selected color table.
def UpdateColorColumn
Creates color table.
def SetRasterRule
Set raster rule.
def GetTempfile
Creates GRASS temporary file using defined prefix.
def OnLoadDefaultTable
Load internal color table.
def OnOK
Apply selected color table and close the dialog.
def OnSaveRulesFile
Save color table to file.
def OnRuleSize
Rule size changed.
def OnFromColSelection
Selection in combobox (for loading values) changed.
def OnHelp
Show GRASS manual page.
def OnCancel
Do not apply any changes and close the dialog.
def OnSize
Init image size to match window size.
def GetColorTables
Get list of color tables.
def GetImage
Converts files to wx.Image.
def __init__
Dialog for interactively entering rules for map management commands.
def OnAddRules
Add rules button pressed.
def LoadRulesFromColumn
Load current column (GRASSRGB, size column)
def OnToColSelection
Selection in combobox (for storing values) changed.
def OnAddColumn
Add GRASS(RGB,SIZE,WIDTH) column if it doesn't exist.
def OnSetTable
Load pre-defined color table.
def OnRuleValue
Rule value changed.
def _IsNumber
Check if 's' is a number.
def RunHelp
Show GRASS manual page.
def _initLayer
Set initial layer when opening dialog.
def SetVectorRule
Set vector rule.
def OnColumnPreview
Update preview (based on computational region)
def EraseMap
Erase preview.
def OnPreview
Update preview (based on computational region)
def OnCheckAll
(Un)check all rules
def RunCommand
Run GRASS command.
def SQLConvert
Prepare value for SQL query.
def Enable
Enable/Disable all widgets.