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-2011 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)
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, id = wx.ID_ANY,
314 style = wx.DEFAULT_FRAME_STYLE | wx.RESIZE_BORDER,
316 """!Dialog for interactively entering rules for map management
320 wx.Frame.__init__(self, parent, id, title, style = style, **kwargs)
322 self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR,
'grass.ico'), wx.BITMAP_TYPE_ICO))
324 self.
panel = wx.Panel(parent = self, id = wx.ID_ANY)
337 self.Bind(wx.EVT_BUTTON, self.OnHelp, self.
btnHelp)
338 self.selectionInput.Bind(wx.EVT_TEXT, self.OnSelectionInput)
341 self.Bind(wx.EVT_BUTTON, self.
OnOK, self.
btnOK)
344 self.Bind(wx.EVT_BUTTON, self.OnPreview, self.
btnPreview)
346 def _initLayer(self):
347 """!Set initial layer when opening dialog"""
351 sel = self.parent.curr_page.maptree.layer_selected
352 if sel
and self.parent.curr_page.maptree.GetPyData(sel)[0][
'type'] == self.
mapType:
355 layer = self.parent.curr_page.maptree.FindItemByData(key =
'type', value = self.
mapType)
359 mapLayer = self.parent.curr_page.maptree.GetPyData(layer)[0][
'maplayer']
360 name = mapLayer.GetName()
361 type = mapLayer.GetType()
362 self.selectionInput.SetValue(name)
365 def _createMapSelection(self, parent):
366 """!Create map selection part of dialog"""
369 maplabel = _(
'Select raster map:')
371 maplabel = _(
'Select vector map:')
372 inputBox = wx.StaticBox(parent, id = wx.ID_ANY,
373 label =
" %s " % maplabel)
374 inputSizer = wx.StaticBoxSizer(inputBox, wx.VERTICAL)
377 size = globalvar.DIALOG_GSELECT_SIZE,
381 flag = wx.ALIGN_CENTER_VERTICAL | wx.ALL | wx.EXPAND, border = 5)
385 def _createFileSelection(self, parent):
386 """!Create file (open/save rules) selection part of dialog"""
387 inputBox = wx.StaticBox(parent, id = wx.ID_ANY,
388 label =
" %s " % _(
"Import or export color table:"))
389 inputSizer = wx.StaticBoxSizer(inputBox, wx.VERTICAL)
391 self.
loadRules = filebrowse.FileBrowseButton(parent = parent, id = wx.ID_ANY, fileMask =
'*',
392 size = globalvar.DIALOG_GSELECT_SIZE,
393 labelText = _(
'Load color table from file:'),
394 dialogTitle = _(
'Choose file to load color table'),
395 buttonText = _(
'Load'),
396 toolTip = _(
"Type filename or click to choose "
397 "file and load color table"),
398 startDirectory = os.getcwd(), fileMode = wx.FD_OPEN,
400 self.
saveRules = filebrowse.FileBrowseButton(parent = parent, id = wx.ID_ANY, fileMask =
'*',
401 size = globalvar.DIALOG_GSELECT_SIZE,
402 labelText = _(
'Save color table to file:'),
403 dialogTitle = _(
'Choose file to save color table'),
404 toolTip = _(
"Type filename or click to choose "
405 "file and save color table"),
406 buttonText = _(
'Save'),
407 startDirectory = os.getcwd(), fileMode = wx.FD_SAVE,
410 default = wx.Button(parent = parent, id = wx.ID_ANY, label = _(
"Reload default table"))
412 sizer = wx.BoxSizer(wx.HORIZONTAL)
413 sizer.Add(item = self.
loadRules, proportion = 1,
414 flag = wx.RIGHT | wx.EXPAND, border = 10)
415 sizer.Add(item = default, flag = wx.ALIGN_CENTER_VERTICAL)
416 inputSizer.Add(item = sizer,
417 flag = wx.TOP | wx.LEFT | wx.RIGHT | wx.EXPAND, border = 5)
418 sizer = wx.BoxSizer(wx.HORIZONTAL)
419 sizer.Add(item = self.
saveRules, proportion = 1,
420 flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND)
421 inputSizer.Add(item = sizer, proportion = 1,
422 flag = wx.ALL | wx.EXPAND, border = 5)
428 parent.SetSizer(inputSizer)
432 def _createPreview(self, parent):
433 """!Create preview"""
438 self.preview.EraseMap()
440 def _createButtons(self, parent):
441 """!Create buttons for leaving dialog"""
442 self.
btnHelp = wx.Button(parent, id = wx.ID_HELP)
444 self.
btnApply = wx.Button(parent, id = wx.ID_APPLY)
445 self.
btnOK = wx.Button(parent, id = wx.ID_OK)
447 self.btnOK.SetDefault()
448 self.btnOK.Enable(
False)
449 self.btnApply.Enable(
False)
452 btnSizer = wx.BoxSizer(wx.HORIZONTAL)
453 btnSizer.Add(wx.Size(-1, -1), proportion = 1)
455 flag = wx.LEFT | wx.RIGHT, border = 5)
457 flag = wx.LEFT | wx.RIGHT, border = 5)
459 flag = wx.LEFT | wx.RIGHT, border = 5)
460 btnSizer.Add(self.
btnOK,
461 flag = wx.LEFT | wx.RIGHT, border = 5)
465 def _createBody(self, parent):
466 """!Create dialog body consisting of rules and preview"""
467 bodySizer = wx.GridBagSizer(hgap = 5, vgap = 5)
468 bodySizer.AddGrowableRow(1)
469 bodySizer.AddGrowableCol(2)
473 self.
cr_label = wx.StaticText(parent, id = wx.ID_ANY)
474 bodySizer.Add(item = self.
cr_label, pos = (row, 0), span = (1, 3),
475 flag = wx.ALL, border = 5)
480 attributeType = self.attributeType, properties = self.properties)
482 bodySizer.Add(item = self.rulesPanel.mainPanel, pos = (row, 0),
483 span = (1, 2), flag = wx.EXPAND)
485 self.rulesPanel.AddRules(2)
489 bodySizer.Add(item = self.
preview, pos = (row, 2),
490 flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER)
494 bodySizer.Add(item = self.rulesPanel.checkAll, flag = wx.ALIGN_CENTER_VERTICAL,
496 bodySizer.Add(item = self.rulesPanel.clearAll, pos = (row, 1))
500 label = _(
"Preview"))
501 bodySizer.Add(item = self.
btnPreview, pos = (row, 2),
502 flag = wx.ALIGN_RIGHT)
503 self.btnPreview.Enable(
False)
504 self.btnPreview.SetToolTipString(_(
"Show preview of map "
505 "(current Map Display extent is used)."))
509 bodySizer.Add(item = self.rulesPanel.numRules, pos = (row, 0),
510 flag = wx.ALIGN_CENTER_VERTICAL)
511 bodySizer.Add(item = self.rulesPanel.btnAdd, pos = (row, 1))
516 """!Initialize preview display, set dimensions and region
528 """!Apply selected color table
530 @return True on success otherwise False
534 GMessage(parent = self, message = _(
"No valid color rules given."))
538 display = self.parent.GetLayerTree().GetMapDisplay()
539 if display
and display.IsAutoRendered():
540 display.GetWindow().UpdateMap(render =
True)
545 """!Apply selected color table and close the dialog"""
550 """!Do not apply any changes, remove associated
551 rendered images and close the dialog"""
556 """!Save color table to file"""
557 path = event.GetString()
558 if not os.path.exists(path):
562 for rule
in self.rulesPanel.ruleslines.itervalues():
563 if 'value' not in rule:
565 rulestxt += rule[
'value'] +
' ' + rule[
'color'] +
'\n'
567 GMessage(message = _(
"Nothing to save."),
576 """!Load color table from file"""
577 path = event.GetString()
578 if not os.path.exists(path):
581 self.rulesPanel.Clear()
583 file = open(path,
'r')
590 @param table color table in format coming from r.colors.out"""
592 rulesNumber = len(ctable.splitlines())
593 self.rulesPanel.AddRules(rulesNumber)
595 minim = maxim = count = 0
596 for line
in ctable.splitlines():
598 value, color = map(
lambda x: x.strip(), line.split(
' '))
600 GMessage(parent = self, message = _(
"Invalid color table format"))
601 self.rulesPanel.Clear()
604 self.rulesPanel.ruleslines[count][
'value'] = value
605 self.rulesPanel.ruleslines[count][
'color'] = color
606 self.rulesPanel.mainPanel.FindWindowById(count + 1000).
SetValue(value)
608 for c
in color.split(
':'):
610 self.rulesPanel.mainPanel.FindWindowById(count + 2000).SetColour(rgb)
613 if float(value) < minim:
615 if float(value) > maxim:
623 self.properties[
'min'], self.properties[
'max'] = minim, maxim
626 self.OnPreview(tmp =
True)
629 """!Load internal color table"""
633 """!Load current color table (using `r(v).colors.out`)
635 @param mapType map type (raster or vector)"""
636 self.rulesPanel.Clear()
638 if mapType ==
'raster':
639 cmd = [
'r.colors.out',
641 'map=%s' % self.
inmap,
644 cmd = [
'v.colors.out',
646 'map=%s' % self.
inmap,
649 if self.properties[
'sourceColumn']
and self.properties[
'sourceColumn'] !=
'cat':
650 cmd.append(
'column=%s' % self.properties[
'sourceColumn'])
663 """!Creates color table
665 @return True on success
666 @return False on failure
670 for rule
in self.rulesPanel.ruleslines.itervalues():
671 if 'value' not in rule:
674 if rule[
'value']
not in (
'nv',
'default')
and \
675 rule[
'value'][-1] !=
'%' and \
677 GError(_(
"Invalid rule value '%s'. Unable to apply color table.") % rule[
'value'],
681 rulestxt += rule[
'value'] +
' ' + rule[
'color'] +
'\n'
687 output = open(gtemp,
"w")
689 output.write(rulestxt)
693 cmd = [
'%s.colors' % self.
mapType[0],
694 'map=%s' % self.
inmap,
696 if self.
mapType ==
'vector' and self.properties[
'sourceColumn'] \
697 and self.properties[
'sourceColumn'] !=
'cat':
698 cmd.append(
'column=%s' % self.properties[
'sourceColumn'])
707 """!Update preview (based on computational region)"""
710 self.
layer = self.Map.AddLayer(type = ltype, name =
'preview', command = cmdlist,
711 l_active =
True, l_hidden =
False, l_opacity = 1.0,
714 self.layer.SetCmd(cmdlist)
718 self.preview.UpdatePreview()
721 """!Show GRASS manual page"""
727 def _IsNumber(self, s):
728 """!Check if 's' is a number"""
738 """!Dialog for interactively entering color rules for raster maps"""
751 ColorTable.__init__(self, parent,
752 title = _(
'Create new color table for raster map'), **kwargs)
757 self.SetMinSize((650, 700))
759 self.CentreOnScreen()
763 """!Do main layout"""
764 sizer = wx.BoxSizer(wx.VERTICAL)
769 sizer.Add(item = mapSelection, proportion = 0,
770 flag = wx.ALL | wx.EXPAND, border = 5)
775 sizer.Add(item = fileSelection, proportion = 0,
776 flag = wx.ALL | wx.EXPAND, border = 5)
781 sizer.Add(item = bodySizer, proportion = 1,
782 flag = wx.ALL | wx.EXPAND, border = 5)
787 sizer.Add(item = wx.StaticLine(parent = self.
panel, id = wx.ID_ANY,
788 style = wx.LI_HORIZONTAL), proportion = 0,
789 flag = wx.EXPAND | wx.ALL, border = 5)
791 sizer.Add(item = btnSizer, proportion = 0,
792 flag = wx.ALL | wx.ALIGN_RIGHT, border = 5)
794 self.panel.SetSizer(sizer)
796 sizer.Fit(self.
panel)
800 """!Raster map selected"""
804 self.loadRules.SetValue(
'')
805 self.saveRules.SetValue(
'')
807 if not grass.find_file(name = self.
inmap, element =
'cell')[
'file']:
811 self.btnPreview.Enable(
False)
812 self.btnOK.Enable(
False)
813 self.btnApply.Enable(
False)
817 info = grass.raster_info(map = self.
inmap)
826 self.btnPreview.Enable(
False)
827 self.btnOK.Enable(
False)
828 self.btnApply.Enable(
False)
829 self.preview.EraseMap()
830 self.cr_label.SetLabel(_(
'Enter raster category values or percents'))
833 if info[
'datatype'] ==
'CELL':
834 mapRange = _(
'range')
836 mapRange = _(
'fp range')
837 self.cr_label.SetLabel(_(
'Enter raster category values or percents (%(range)s = %(min)d-%(max)d)') %
838 {
'range' : mapRange,
842 self.btnPreview.Enable()
844 self.btnApply.Enable()
848 """!Update preview (based on computational region)"""
850 self.preview.EraseMap()
854 'map=%s' % self.
inmap]
859 name, mapset = self.inmap.split(
'@')
862 mapset = grass.find_file(self.
inmap, element =
'cell')[
'mapset']
866 if mapset == grass.gisenv()[
'MAPSET']:
867 old_colrtable = grass.find_file(name = name, element =
'colr')[
'file']
869 old_colrtable = grass.find_file(name = name, element =
'colr2/' + mapset)[
'file']
873 shutil.copyfile(old_colrtable, colrtemp)
875 ColorTable.DoPreview(self, ltype, cmdlist)
880 shutil.copyfile(colrtemp, old_colrtable)
889 """!Show GRASS manual page"""
891 ColorTable.RunHelp(self, cmd = cmd)
894 def __init__(self, parent, attributeType, **kwargs):
895 """!Dialog for interactively entering color rules for vector maps"""
916 'tmpColumn' :
'tmp_0',
922 self.
columnsProp = {
'color': {
'name':
'GRASSRGB',
'type1':
'varchar(11)',
'type2': [
'character']},
923 'size' : {
'name':
'GRASSSIZE',
'type1':
'integer',
'type2': [
'integer']},
924 'width': {
'name':
'GRASSWIDTH',
'type1':
'integer',
'type2': [
'integer']}}
925 ColorTable.__init__(self, parent = parent,
926 title = _(
'Create new color rules for vector map'), **kwargs)
937 self.cr_label.SetLabel(_(
"Enter vector attribute values or percents:"))
939 self.cr_label.SetLabel(_(
"Enter vector attribute values:"))
942 self.SetMinSize((650, 700))
944 self.CentreOnScreen()
947 def _createVectorAttrb(self, parent):
948 """!Create part of dialog with layer/column selection"""
949 inputBox = wx.StaticBox(parent = parent, id = wx.ID_ANY,
950 label =
" %s " % _(
"Select vector columns"))
951 cb_vl_label = wx.StaticText(parent, id = wx.ID_ANY,
953 cb_vc_label = wx.StaticText(parent, id = wx.ID_ANY,
954 label = _(
'Attribute column:'))
957 labels = [_(
"Load color from column:"), _(
"Save color to column:")]
959 labels = [_(
"Load size from column:"), _(
"Save size to column:")]
961 labels = [_(
"Load width from column:"), _(
"Save width to column:")]
965 label = _(
"Use color column instead of color table:"))
968 fromColumnLabel = wx.StaticText(parent, id = wx.ID_ANY,
970 toColumnLabel = wx.StaticText(parent, id = wx.ID_ANY,
979 label = _(
'Add column'))
980 self.addColumn.SetToolTipString(_(
"Add GRASSRGB column to current attribute table."))
983 inputSizer = wx.StaticBoxSizer(inputBox, wx.VERTICAL)
984 vSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
986 vSizer.Add(cb_vl_label, pos = (row, 0),
987 flag = wx.ALIGN_CENTER_VERTICAL)
989 flag = wx.ALIGN_CENTER_VERTICAL)
991 vSizer.Add(cb_vc_label, pos = (row, 0),
992 flag = wx.ALIGN_CENTER_VERTICAL)
994 flag = wx.ALIGN_CENTER_VERTICAL)
996 flag = wx.ALIGN_CENTER_VERTICAL)
999 vSizer.Add(self.
useColumn, pos = (row, 0), span = (1, 2),
1000 flag = wx.ALIGN_CENTER_VERTICAL)
1003 vSizer.Add(fromColumnLabel, pos = (row, 0),
1004 flag = wx.ALIGN_CENTER_VERTICAL)
1006 flag = wx.ALIGN_CENTER_VERTICAL)
1008 vSizer.Add(toColumnLabel, pos = (row, 0),
1009 flag = wx.ALIGN_CENTER_VERTICAL)
1010 vSizer.Add(self.
toColumn, pos = (row, 1),
1011 flag = wx.ALIGN_CENTER_VERTICAL)
1012 vSizer.Add(self.
addColumn, pos = (row, 2),
1013 flag = wx.ALIGN_CENTER_VERTICAL)
1014 inputSizer.Add(item = vSizer,
1015 flag = wx.ALIGN_CENTER_VERTICAL | wx.ALL | wx.EXPAND, border = 5)
1019 def _doLayout(self):
1020 """!Do main layout"""
1021 scrollPanel = scrolled.ScrolledPanel(parent = self.
panel, id = wx.ID_ANY,
1022 style = wx.TAB_TRAVERSAL)
1023 scrollPanel.SetupScrolling()
1024 sizer = wx.BoxSizer(wx.VERTICAL)
1029 sizer.Add(item = mapSelection, proportion = 0,
1030 flag = wx.ALL | wx.EXPAND, border = 5)
1035 self.
cp = wx.CollapsiblePane(scrollPanel, label = _(
"Import or export color table"),
1037 style = wx.CP_DEFAULT_STYLE|wx.CP_NO_TLW_RESIZE)
1038 self.Bind(wx.EVT_COLLAPSIBLEPANE_CHANGED, self.
OnPaneChanged, self.
cp)
1041 sizer.Add(item = self.
cp, proportion = 0,
1042 flag = wx.ALL | wx.EXPAND, border = 5)
1047 sizer.Add(item = vectorAttrb, proportion = 0,
1048 flag = wx.ALL | wx.EXPAND, border = 5)
1052 bodySizer = self.
_createBody(parent = scrollPanel)
1053 sizer.Add(item = bodySizer, proportion = 1,
1054 flag = wx.ALL | wx.EXPAND, border = 5)
1056 scrollPanel.SetSizer(sizer)
1064 mainsizer = wx.BoxSizer(wx.VERTICAL)
1065 mainsizer.Add(scrollPanel, proportion = 1, flag = wx.EXPAND | wx.ALL, border = 5)
1066 mainsizer.Add(item = wx.StaticLine(parent = self.
panel, id = wx.ID_ANY,
1067 style = wx.LI_HORIZONTAL), proportion = 0,
1068 flag = wx.EXPAND | wx.ALL, border = 5)
1069 mainsizer.Add(item = btnSizer, proportion = 0,
1070 flag = wx.ALL | wx.ALIGN_RIGHT | wx.EXPAND, border = 5)
1072 self.panel.SetSizer(mainsizer)
1074 mainsizer.Fit(self.
panel)
1081 if self.cp.IsExpanded():
1082 self.cp.SetLabel(
'')
1084 self.cp.SetLabel(_(
"Import or export color table"))
1087 """!Check if current vector is in current mapset"""
1088 if grass.find_file(name = self.
inmap,
1089 element =
'vector')[
'mapset'] == grass.gisenv()[
'MAPSET']:
1095 dlg = wx.MessageDialog(parent = self,
1096 message = _(
"Database connection for vector map <%s> "
1097 "is not defined in DB file. Do you want to create and "
1098 "connect new attribute table?") % vectorName,
1099 caption = _(
"No database connection defined"),
1100 style = wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION | wx.CENTRE)
1101 if dlg.ShowModal() == wx.ID_YES:
1103 GUI(parent = self).ParseCommand([
'v.db.addtable',
'map=' + self.
inmap],
1109 """!Use color column instead of color table"""
1110 if self.useColumn.GetValue():
1111 self.
properties[
'loadColumn'] = self.fromColumn.GetStringSelection()
1112 self.
properties[
'storeColumn'] = self.toColumn.GetStringSelection()
1113 self.fromColumn.Enable(
True)
1114 self.toColumn.Enable(
True)
1120 self.rulesPanel.Clear()
1124 self.fromColumn.Enable(
False)
1125 self.toColumn.Enable(
False)
1130 """!Enable/disable part of dialog connected with db"""
1131 for child
in self.colorColumnSizer.GetChildren():
1132 child.GetWindow().Enable(enable)
1135 """!Enable, disable the whole dialog"""
1136 self.rulesPanel.Clear()
1138 self.btnPreview.Enable(
False)
1139 self.btnOK.Enable(
False)
1140 self.btnApply.Enable(
False)
1141 self.preview.EraseMap()
1144 """!Vector map selected"""
1152 self.loadRules.SetValue(
'')
1153 self.saveRules.SetValue(
'')
1156 if not grass.find_file(name = self.
inmap, element =
'vector')[
'file']:
1162 """!Update dialog after map selection"""
1171 message = _(
"Selected map <%(map)s> is not in current mapset <%(mapset)s>. "
1172 "Color rules cannot be edited.") % \
1173 {
'map' : self.
inmap,
1174 'mapset' : grass.gisenv()[
'MAPSET'] }
1176 message = _(
"Selected map <%(map)s> is not in current mapset <%(mapset)s>. "
1177 "Attribute table cannot be edited.") % \
1178 {
'map' : self.
inmap,
1179 'mapset' : grass.gisenv()[
'MAPSET'] }
1180 wx.CallAfter(GMessage, parent = self, message = message)
1187 if not len(self.dbInfo.layers):
1194 for prop
in (
'sourceColumn',
'loadColumn',
'storeColumn'):
1200 self.layerSelect.InsertLayers(self.
inmap)
1202 self.
properties[
'layer'] = self.layerSelect.GetString(0)
1203 self.layerSelect.SetStringSelection(self.
properties[
'layer'])
1205 self.
properties[
'table'] = self.dbInfo.layers[layer][
'table']
1217 self.useColumn.SetValue(
False)
1222 self.btnPreview.Enable(enable)
1223 self.btnOK.Enable(enable)
1224 self.btnApply.Enable(enable)
1227 """!Add temporary column to not overwrite the original values,
1228 need to be deleted when closing dialog and unloading map
1230 @param type type of column (e.g. vachar(11))"""
1233 while self.
properties[
'tmpColumn']
in self.dbInfo.GetTableDesc(self.
properties[
'table']).keys():
1237 self.
properties[
'tmpColumn'] = name +
'_' + str(idx)
1240 modul =
'v.db.addcolumn'
1242 modul =
'v.db.addcol'
1247 column =
'%s %s' % (self.
properties[
'tmpColumn'], type))
1250 """!Delete temporary column"""
1253 modul =
'v.db.dropcolumn'
1255 modul =
'v.db.dropcol'
1263 vlayer = int(self.layerSelect.GetStringSelection())
1264 self.sourceColumn.InsertColumns(vector = self.
inmap, layer = vlayer,
1265 type = [
'integer',
'double precision'], dbInfo = self.
dbInfo,
1266 excludeCols = [
'tmpColumn'])
1267 self.sourceColumn.SetStringSelection(
'cat')
1268 self.
properties[
'sourceColumn'] = self.sourceColumn.GetString(0)
1271 type = [
'character']
1274 self.fromColumn.InsertColumns(vector = self.
inmap, layer = vlayer, type = type,
1275 dbInfo = self.
dbInfo, excludeCols = [
'tmpColumn'])
1276 self.toColumn.InsertColumns(vector = self.
inmap, layer = vlayer, type = type,
1277 dbInfo = self.
dbInfo, excludeCols = [
'tmpColumn'])
1280 if found != wx.NOT_FOUND:
1281 self.fromColumn.SetSelection(found)
1282 self.toColumn.SetSelection(found)
1283 self.
properties[
'loadColumn'] = self.fromColumn.GetString(found)
1284 self.
properties[
'storeColumn'] = self.toColumn.GetString(found)
1294 self.
properties[
'sourceColumn'] = event.GetString()
1299 """!Add GRASS(RGB,SIZE,WIDTH) column if it doesn't exist"""
1302 modul =
'v.db.addcolumn'
1304 modul =
'v.db.addcol'
1313 self.
properties[
'storeColumn'] = self.toColumn.GetStringSelection()
1317 GMessage(parent = self,
1318 message = _(
"%s column already exists.") % \
1322 """!Create attribute table"""
1338 ColorTable.LoadTable(self, mapType =
'vector')
1343 """!Load current column (GRASSRGB, size column)"""
1345 self.rulesPanel.Clear()
1347 self.preview.EraseMap()
1350 busy = wx.BusyInfo(message = _(
"Please wait, loading data from attribute table..."),
1356 columns +=
',' + self.
properties[
'loadColumn']
1360 outFile = tempfile.NamedTemporaryFile(mode =
'w+b')
1370 self.preview.EraseMap()
1384 record = outFile.readline().replace(
'\n',
'')
1387 self.rulesPanel.ruleslines[i] = {}
1393 col1, col2 = record.split(sep)
1395 if float(col1) < minim:
1397 if float(col1) > maxim:
1402 if col1
not in colvallist:
1403 self.rulesPanel.ruleslines[i][
'value'] = col1
1406 colvallist.append(col1)
1409 if i > limit
and readvals ==
False:
1410 dlg = wx.MessageDialog (parent = self, message = _(
1411 "Number of loaded records reached %d, "
1412 "displaying all the records will be time-consuming "
1413 "and may lead to computer freezing, "
1414 "do you still want to continue?") % i,
1415 caption = _(
"Too many records"),
1416 style = wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
1417 if dlg.ShowModal() == wx.ID_YES:
1426 self.rulesPanel.AddRules(i, start =
True)
1427 ret = self.rulesPanel.LoadRules()
1435 self.rulesPanel.Clear()
1440 """!Set labels with info about attribute column range"""
1443 ctype = self.dbInfo.GetTableDesc(self.
properties[
'table'])[self.
properties[
'sourceColumn']][
'ctype']
1450 range =
"%s: %.1f - %.1f)" % (_(
"range"),
1453 range =
"%s: %d - %d)" % (_(
"range"),
1457 self.cr_label.SetLabel(_(
"Enter vector attribute values or percents %s:") % range)
1459 self.cr_label.SetLabel(_(
"Enter vector attribute values %s:") % range)
1462 self.cr_label.SetLabel(_(
"Enter vector attribute values or percents:"))
1464 self.cr_label.SetLabel(_(
"Enter vector attribute values:"))
1467 """!Selection in combobox (for loading values) changed"""
1468 self.
properties[
'loadColumn'] = event.GetString()
1473 """!Selection in combobox (for storing values) changed"""
1474 self.
properties[
'storeColumn'] = event.GetString()
1477 """!Update preview (based on computational region)"""
1484 """!Update preview (based on computational region)"""
1486 self.preview.EraseMap()
1490 cmdlist = [
'd.vect',
1491 'map=%s' % self.
inmap]
1494 old_colrtable =
None
1495 path = grass.find_file(name = self.
inmap, element =
'vector')[
'file']
1497 if os.path.exists(os.path.join(path,
'colr')):
1498 old_colrtable = os.path.join(path,
'colr')
1500 shutil.copyfile(old_colrtable, colrtemp)
1502 ColorTable.DoPreview(self, ltype, cmdlist)
1507 shutil.copyfile(colrtemp, old_colrtable)
1516 """!Update preview (based on computational region)"""
1518 self.preview.EraseMap()
1521 cmdlist = [
'd.vect',
1522 'map=%s' % self.
inmap,
1523 'type=point,line,boundary,area']
1526 cmdlist.append(
'flags=a')
1527 cmdlist.append(
'rgb_column=%s' % self.
properties[
'tmpColumn'])
1529 cmdlist.append(
'size_column=%s' % self.
properties[
'tmpColumn'])
1531 cmdlist.append(
'width_column=%s' % self.
properties[
'tmpColumn'])
1535 ColorTable.DoPreview(self, ltype, cmdlist)
1538 """!Show GRASS manual page"""
1540 ColorTable.RunHelp(self, cmd = cmd)
1543 """!Find layers and apply the changes in d.vect command"""
1544 layers = self.parent.curr_page.maptree.FindItemByData(key =
'name', value = self.
inmap)
1547 for layer
in layers:
1548 if self.parent.curr_page.maptree.GetPyData(layer)[0][
'type'] !=
'vector':
1550 cmdlist = self.parent.curr_page.maptree.GetPyData(layer)[0][
'maplayer'].GetCmd()
1554 cmdlist[1].
update({
'flags':
'a'})
1557 if 'flags' in cmdlist[1]:
1558 cmdlist[1][
'flags'] = cmdlist[1][
'flags'].replace(
'a',
'')
1559 cmdlist[1].pop(
'rgb_column',
None)
1564 self.parent.curr_page.maptree.GetPyData(layer)[0][
'cmd'] = cmdlist
1567 """!Create color rules (color table or color column)"""
1569 ret = ColorTable.CreateColorTable(self)
1579 """!Creates color table
1581 @return True on success
1582 @return False on failure
1586 for rule
in self.rulesPanel.ruleslines.itervalues():
1587 if 'value' not in rule:
1595 GMessage(parent = self.
parent,
1596 message = _(
"Please select column to save values to."))
1598 rulestxt +=
"UPDATE %s SET %s='%s' WHERE %s ;\n" % (self.
properties[
'table'],
1606 output = open(gtemp,
"w")
1608 output.write(rulestxt)
1619 """!Do not apply any changes and close the dialog"""
1625 """!Apply selected color table
1627 @return True on success otherwise False
1633 GError(_(
"No color column defined. Operation canceled."),
1639 return ColorTable.OnApply(self, event)
1642 """!A Buffered window class"""
1644 style = wx.NO_FULL_REPAINT_ON_RESIZE,
1645 Map =
None, **kwargs):
1647 wx.Window.__init__(self, parent, id, style = style, **kwargs)
1660 self.Bind(wx.EVT_PAINT, self.
OnPaint)
1661 self.Bind(wx.EVT_IDLE, self.
OnIdle)
1662 self.Bind(wx.EVT_ERASE_BACKGROUND,
lambda x:
None)
1677 self.Map.region = self.Map.GetRegion()
1678 self.Map.SetRegion()
1680 def Draw(self, pdc, img = None, pdctype = 'image'):
1681 """!Draws preview or clears window"""
1684 Debug.msg (3,
"BufferedWindow.Draw(): pdctype=%s" % (pdctype))
1686 if pdctype ==
'clear':
1688 pdc.SetBackground(bg)
1694 if pdctype ==
'image' and img:
1695 bg = wx.TRANSPARENT_BRUSH
1696 pdc.SetBackground(bg)
1697 bitmap = wx.BitmapFromImage(img)
1698 w, h = bitmap.GetSize()
1699 pdc.DrawBitmap(bitmap, 0, 0,
True)
1705 """!Draw pseudo DC to buffer"""
1706 self.
_Buffer = wx.EmptyBitmap(self.Map.width, self.Map.height)
1707 dc = wx.BufferedPaintDC(self, self.
_Buffer)
1714 bg = wx.Brush(self.GetBackgroundColour())
1715 dc.SetBackground(bg)
1720 rgn = self.GetUpdateRegion()
1724 self.pdc.DrawToDCClipped(dc, r)
1727 """!Init image size to match window size"""
1729 self.Map.width, self.Map.height = self.GetClientSize()
1734 self.
_Buffer = wx.EmptyBitmap(self.Map.width, self.Map.height)
1740 if self.
img and self.Map.width + self.Map.height > 0:
1741 self.
img = self.img.Scale(self.Map.width, self.Map.height)
1749 """!Only re-render a preview image from GRASS during
1750 idle time instead of multiple times during resizing.
1758 """!Converts files to wx.Image"""
1759 if self.Map.mapfile
and os.path.isfile(self.Map.mapfile)
and \
1760 os.path.getsize(self.Map.mapfile):
1761 img = wx.Image(self.Map.mapfile, wx.BITMAP_TYPE_ANY)
1768 """!Update canvas if window changes geometry"""
1769 Debug.msg (2,
"BufferedWindow.UpdatePreview(%s): render=%s" % (img, self.
render))
1776 self.Map.region = copy.deepcopy(self.parent.parent.curr_page.maptree.Map.region)
1777 except AttributeError:
1778 self.Map.region = self.Map.GetRegion()
1789 self.pdc.RemoveAll()
1791 self.
Draw(self.
pdc, self.
img, pdctype =
'image')
1796 """!Erase preview"""
1797 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 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 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 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.