GRASS Programmer's Manual  6.5.svn(2014)-r66266
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
core/workspace.py
Go to the documentation of this file.
1 """!
2 @package core.workspace
3 
4 @brief Open/save workspace definition file
5 
6 Classes:
7  - workspace::ProcessWorkspaceFile
8  - workspace::WriteWorkspaceFile
9  - workspace::ProcessGrcFile
10 
11 (C) 2007-2011 by the GRASS Development Team
12 
13 This program is free software under the GNU General Public License
14 (>=v2). Read the file COPYING that comes with GRASS for details.
15 
16 @author Martin Landa <landa.martin gmail.com>
17 """
18 
19 import os
20 
21 import wx
22 
23 from core.utils import normalize_whitespace
24 from core.settings import UserSettings
25 from core.gcmd import EncodeString, GetDefaultEncoding
26 from nviz.main import NvizSettings
27 
29  def __init__(self, tree):
30  """!A ElementTree handler for the GXW XML file, as defined in
31  grass-gxw.dtd.
32  """
33  self.tree = tree
34  self.root = self.tree.getroot()
35 
36  #
37  # layer manager properties
38  #
39  self.layerManager = {}
40  self.layerManager['pos'] = None # window position
41  self.layerManager['size'] = None # window size
42 
43  #
44  # list of mapdisplays
45  #
46  self.displays = []
47  #
48  # list of map layers
49  #
50  self.layers = []
51  #
52  # nviz state
53  #
54  self.nviz_state = {}
55 
56  self.displayIndex = -1 # first display has index '0'
57 
58  self.__processFile()
59 
60  if NvizSettings:
62  else:
63  self.nvizDefault = None
64 
65  def __filterValue(self, value):
66  """!Filter value
67 
68  @param value
69  """
70  value = value.replace('&lt;', '<')
71  value = value.replace('&gt;', '>')
72 
73  return value
74 
75  def __getNodeText(self, node, tag, default = ''):
76  """!Get node text"""
77  p = node.find(tag)
78  if p is not None:
79  return normalize_whitespace(p.text)
80 
81  return default
82 
83  def __processFile(self):
84  """!Process workspace file"""
85  #
86  # layer manager
87  #
88  node_lm = self.root.find('layer_manager')
89  if node_lm is not None:
90  posAttr = node_lm.get('dim', '')
91  if posAttr:
92  posVal = map(int, posAttr.split(','))
93  try:
94  self.layerManager['pos'] = (posVal[0], posVal[1])
95  self.layerManager['size'] = (posVal[2], posVal[3])
96  except:
97  pass
98 
99  #
100  # displays
101  #
102  for display in self.root.findall('display'):
103  self.displayIndex += 1
104 
105  # window position and size
106  posAttr = display.get('dim', '')
107  if posAttr:
108  posVal = map(int, posAttr.split(','))
109  try:
110  pos = (posVal[0], posVal[1])
111  size = (posVal[2], posVal[3])
112  except:
113  pos = None
114  size = None
115  else:
116  pos = None
117  size = None
118 
119  extentAttr = display.get('extent', '')
120  if extentAttr:
121  # w, s, e, n
122  extent = map(float, extentAttr.split(','))
123  else:
124  extent = None
125 
126  # projection
127  node_projection = display.find('projection')
128  if node_projection is not None:
129  projection = { 'enabled' : True,
130  'epsg' : node_projection.get('epsg', ''),
131  'proj' : self.__getNodeText(node_projection, 'value') }
132  else:
133  projection = { 'enabled' : False }
134 
135  self.displays.append( {
136  "name" : display.get('name'),
137  "render" : bool(int(display.get('render', "0"))),
138  "mode" : int(display.get('mode', 0)),
139  "showCompExtent" : bool(int(display.get('showCompExtent', "0"))),
140  "pos" : pos,
141  "size" : size,
142  "extent" : extent,
143  "alignExtent" : bool(int(display.get('alignExtent', "0"))),
144  "constrainRes" : bool(int(display.get('constrainRes', "0"))),
145  "projection" : projection,
146  "viewMode" : display.get('viewMode', '2d')} )
147 
148  # process all layers/groups in the display
149  self.__processLayers(display)
150  # process nviz_state
151  self.__processNvizState(display)
152 
153  def __processLayers(self, node, inGroup = -1):
154  """!Process layers/groups of selected display
155 
156  @param node display tree node
157  @param inGroup in group -> index of group item otherwise -1
158  """
159  for item in node.getchildren():
160  if item.tag == 'group':
161  # -> group
162  self.layers.append( {
163  "type" : 'group',
164  "name" : item.get('name', ''),
165  "checked" : bool(int(item.get('checked', "0"))),
166  "opacity" : None,
167  "cmd" : None,
168  "group" : inGroup,
169  "display" : self.displayIndex,
170  "vdigit" : None,
171  "nviz" : None})
172 
173  self.__processLayers(item, inGroup = len(self.layers) - 1) # process items in group
174 
175  elif item.tag == 'layer':
176  cmd, selected, vdigit, nviz = self.__processLayer(item)
177  lname = item.get('name', None)
178  if lname and '\\n' in lname:
179  lname = lname.replace('\\n', os.linesep)
180 
181  self.layers.append( {
182  "type" : item.get('type', None),
183  "name" : lname,
184  "checked" : bool(int(item.get('checked', "0"))),
185  "opacity" : float(item.get('opacity', '1.0')),
186  "cmd" : cmd,
187  "group" : inGroup,
188  "display" : self.displayIndex,
189  "selected" : selected,
190  "vdigit" : vdigit,
191  "nviz" : nviz } )
192 
193  def __processLayer(self, layer):
194  """!Process layer item
195 
196  @param layer tree node
197  """
198  cmd = list()
199 
200  #
201  # layer attributes (task) - 2D settings
202  #
203  node_task = layer.find('task')
204  cmd.append(node_task.get('name', "unknown"))
205 
206  # flags
207  for p in node_task.findall('flag'):
208  flag = p.get('name', '')
209  if len(flag) > 1:
210  cmd.append('--' + flag)
211  else:
212  cmd.append('-' + flag)
213 
214  # parameters
215  for p in node_task.findall('parameter'):
216  cmd.append('%s=%s' % (p.get('name', ''),
217  self.__filterValue(self.__getNodeText(p, 'value'))))
218 
219  if layer.find('selected') is not None:
220  selected = True
221  else:
222  selected = False
223 
224  #
225  # Vector digitizer settings
226  #
227  node_vdigit = layer.find('vdigit')
228  if node_vdigit is not None:
229  vdigit = self.__processLayerVdigit(node_vdigit)
230  else:
231  vdigit = None
232 
233  #
234  # Nviz (3D settings)
235  #
236  node_nviz = layer.find('nviz')
237  if node_nviz is not None:
238  nviz = self.__processLayerNviz(node_nviz)
239  else:
240  nviz = None
241 
242  return (cmd, selected, vdigit, nviz)
243 
244  def __processLayerVdigit(self, node_vdigit):
245  """!Process vector digitizer layer settings
246 
247  @param node_vdigit vdigit node
248  """
249  # init nviz layer properties
250  vdigit = dict()
251  for node in node_vdigit.findall('geometryAttribute'):
252  if 'geomAttr' not in vdigit:
253  vdigit['geomAttr'] = dict()
254  type = node.get('type')
255  vdigit['geomAttr'][type] = dict()
256  vdigit['geomAttr'][type]['column'] = node.get('column') # required
257  # default map units
258  vdigit['geomAttr'][type]['units'] = node.get('units', 'mu')
259 
260  return vdigit
261 
262  def __processLayerNviz(self, node_nviz):
263  """!Process 3D layer settings
264 
265  @param node_nviz nviz node
266  """
267  # init nviz layer properties
268  nviz = {}
269  if node_nviz.find('surface') is not None: # -> raster
270  nviz['surface'] = {}
271  for sec in ('attribute', 'draw', 'position'):
272  nviz['surface'][sec] = {}
273  elif node_nviz.find('vlines') is not None or \
274  node_nviz.find('vpoints') is not None: # -> vector
275  nviz['vector'] = {}
276  for sec in ('lines', 'points'):
277  nviz['vector'][sec] = {}
278 
279  if 'surface' in nviz:
280  node_surface = node_nviz.find('surface')
281  # attributes
282  for attrb in node_surface.findall('attribute'):
283  tagName = str(attrb.tag)
284  attrbName = attrb.get('name', '')
285  dc = nviz['surface'][tagName][attrbName] = {}
286  if attrb.get('map', '0') == '0':
287  dc['map'] = False
288  else:
289  dc['map'] = True
290  value = self.__getNodeText(attrb, 'value')
291  try:
292  dc['value'] = int(value)
293  except ValueError:
294  try:
295  dc['value'] = float(value)
296  except ValueError:
297  dc['value'] = str(value)
298 
299  # draw
300  node_draw = node_surface.find('draw')
301  if node_draw is not None:
302  tagName = str(node_draw.tag)
303  nviz['surface'][tagName]['all'] = False
304  nviz['surface'][tagName]['mode'] = {}
305  nviz['surface'][tagName]['mode']['value'] = -1 # to be calculated
306  nviz['surface'][tagName]['mode']['desc'] = {}
307  nviz['surface'][tagName]['mode']['desc']['shading'] = \
308  str(node_draw.get('shading', ''))
309  nviz['surface'][tagName]['mode']['desc']['style'] = \
310  str(node_draw.get('style', ''))
311  nviz['surface'][tagName]['mode']['desc']['mode'] = \
312  str(node_draw.get('mode', ''))
313 
314  # resolution
315  for node_res in node_draw.findall('resolution'):
316  resType = str(node_res.get('type', ''))
317  if 'resolution' not in nviz['surface']['draw']:
318  nviz['surface']['draw']['resolution'] = {}
319  value = int(self.__getNodeText(node_res, 'value'))
320  nviz['surface']['draw']['resolution'][resType] = value
321 
322  # wire-color
323  node_wire_color = node_draw.find('wire_color')
324  if node_wire_color is not None:
325  nviz['surface']['draw']['wire-color'] = {}
326  value = str(self.__getNodeText(node_wire_color, 'value'))
327  nviz['surface']['draw']['wire-color']['value'] = value
328 
329  # position
330  node_pos = node_surface.find('position')
331  if node_pos is not None:
332  dc = nviz['surface']['position'] = {}
333  for coor in ['x', 'y', 'z']:
334  node = node_pos.find(coor)
335  if node is None:
336  continue
337  value = int(self.__getNodeText(node_pos, coor))
338  dc[coor] = value
339 
340  elif 'vector' in nviz:
341  # vpoints
342  node_vpoints = node_nviz.find('vpoints')
343  if node_vpoints is not None:
344  marker = str(node_vpoints.get('marker', ''))
345  markerId = list(UserSettings.Get(group='nviz', key='vector',
346  subkey=['points', 'marker'], internal=True)).index(marker)
347  nviz['vector']['points']['marker'] = { 'value' : markerId }
348 
349  node_mode = node_vpoints.find('mode')
350  if node_mode is not None:
351  nviz['vector']['points']['mode'] = {}
352  nviz['vector']['points']['mode']['type'] = str(node_mode.get('type', 'surface'))
353  nviz['vector']['points']['mode']['surface'] = {}
354  nviz['vector']['points']['mode']['surface']['value'] = []
355  nviz['vector']['points']['mode']['surface']['show'] = []
356 
357  # map
358  for node_map in node_mode.findall('map'):
359  nviz['vector']['points']['mode']['surface']['value'].append(
360  self.__processLayerNvizNode(node_map, 'name', str))
361  nviz['vector']['points']['mode']['surface']['show'].append(bool(
362  self.__processLayerNvizNode(node_map, 'checked', int)))
363 
364  # color
365  self.__processLayerNvizNode(node_vpoints, 'color', str,
366  nviz['vector']['points'])
367 
368  # width
369  self.__processLayerNvizNode(node_vpoints, 'width', int,
370  nviz['vector']['points'])
371 
372  # height
373  self.__processLayerNvizNode(node_vpoints, 'height', float,
374  nviz['vector']['points'])
375 
376  # height
377  self.__processLayerNvizNode(node_vpoints, 'size', float,
378  nviz['vector']['points'])
379 
380  # vlines
381  node_vlines = node_nviz.find('vlines')
382  if node_vlines is not None:
383  node_mode = node_vlines.find('mode')
384  if node_mode is not None:
385  nviz['vector']['lines']['mode'] = {}
386  nviz['vector']['lines']['mode']['type'] = str(node_mode.get('type', ''))
387  nviz['vector']['lines']['mode']['surface'] = {}
388  nviz['vector']['lines']['mode']['surface']['value'] = []
389  nviz['vector']['lines']['mode']['surface']['show'] = []
390 
391  # map
392  for node_map in node_mode.findall('map'):
393  nviz['vector']['lines']['mode']['surface']['value'].append(
394  self.__processLayerNvizNode(node_map, 'name', str))
395  nviz['vector']['lines']['mode']['surface']['show'].append(bool(
396  self.__processLayerNvizNode(node_map, 'checked', int)))
397 
398  # color
399  self.__processLayerNvizNode(node_vlines, 'color', str,
400  nviz['vector']['lines'])
401 
402  # width
403  self.__processLayerNvizNode(node_vlines, 'width', int,
404  nviz['vector']['lines'])
405 
406  # height
407  self.__processLayerNvizNode(node_vlines, 'height', int,
408  nviz['vector']['lines'])
409 
410  return nviz
411 
412  def __processLayerNvizNode(self, node, tag, cast, dc = None):
413  """!Process given tag nviz/vector"""
414  node_tag = node.find(tag)
415  if node_tag is not None:
416  if node_tag.find('value') is not None:
417  value = cast(self.__getNodeText(node_tag, 'value'))
418  else:
419  try:
420  value = cast(node_tag.text)
421  except ValueError:
422  if cast == str:
423  value = ''
424  else:
425  value = None
426  if dc:
427  dc[tag] = dict()
428  dc[tag]['value'] = value
429  else:
430  return value
431 
432  def __processNvizState(self, node):
433  """!Process tag nviz_state"""
434  node_state = node.find('nviz_state')
435  if node_state is None:
436  return
437  self.nviz_state['display'] = self.displayIndex
438  #
439  # view
440  #
441  node_view = node_state.find('view')
442  view = {}
443  iview = {}
444 
445  node_position = node_view.find('v_position')
446  view['position'] = {}
447  view['position']['x'] = self.__processLayerNvizNode(node_position, 'x', float)
448  view['position']['y'] = self.__processLayerNvizNode(node_position, 'y', float)
449  node_persp = node_view.find('persp')
450  view['persp'] = {}
451  iview['persp'] = {}
452  view['persp']['value'] = self.__processLayerNvizNode(node_persp, 'value', int)
453  view['persp']['step'] = self.__processLayerNvizNode(node_persp, 'step', int)
454  iview['persp']['min'] = self.__processLayerNvizNode(node_persp, 'min', int)
455  iview['persp']['max'] = self.__processLayerNvizNode(node_persp, 'max', int)
456  node_height = node_view.find('v_height')
457  iview['height'] = {}
458  iview['height']['value'] = self.__processLayerNvizNode(node_height, 'value', int)
459  iview['height']['min'] = self.__processLayerNvizNode(node_height, 'min', int)
460  iview['height']['max'] = self.__processLayerNvizNode(node_height, 'max', int)
461  node_twist = node_view.find('twist')
462  view['twist'] = {}
463  iview['twist'] = {}
464  view['twist']['value'] = self.__processLayerNvizNode(node_twist, 'value', int)
465  iview['twist']['min'] = self.__processLayerNvizNode(node_twist, 'min', int)
466  iview['twist']['max'] = self.__processLayerNvizNode(node_twist, 'max', int)
467  node_zexag = node_view.find('z-exag')
468  view['z-exag'] = {}
469  iview['z-exag'] = {}
470  view['z-exag']['value'] = self.__processLayerNvizNode(node_zexag, 'value', float)
471  view['z-exag']['min'] = self.__processLayerNvizNode(node_zexag, 'min', int)
472  view['z-exag']['max'] = self.__processLayerNvizNode(node_zexag, 'max', int)
473  iview['z-exag']['llRatio'] = self.__processLayerNvizNode(node_zexag, 'llRatio', float)
474  node_focus = node_view.find('focus')
475  iview['focus'] = {}
476  iview['focus']['x'] = self.__processLayerNvizNode(node_focus, 'x', int)
477  iview['focus']['y'] = self.__processLayerNvizNode(node_focus, 'y', int)
478  iview['focus']['z'] = self.__processLayerNvizNode(node_focus, 'z', int)
479  node_dir = node_view.find('dir')
480  if node_dir:
481  iview['dir'] = {}
482  iview['dir']['x'] = self.__processLayerNvizNode(node_dir, 'x', int)
483  iview['dir']['y'] = self.__processLayerNvizNode(node_dir, 'y', int)
484  iview['dir']['z'] = self.__processLayerNvizNode(node_dir, 'z', int)
485  iview['dir']['use'] = True
486  else:
487  iview['dir'] = {}
488  iview['dir']['x'] = -1
489  iview['dir']['y'] = -1
490  iview['dir']['z'] = -1
491  iview['dir']['use'] = False
492 
493  view['background'] = {}
494  color = self.__processLayerNvizNode(node_view, 'background_color', str)
495  view['background']['color'] = tuple(map(int, color.split(':')))
496 
497  self.nviz_state['view'] = view
498  self.nviz_state['iview'] = iview
499  #
500  # light
501  #
502  node_light = node_state.find('light')
503  light = {}
504 
505  node_position = node_light.find('l_position')
506  light['position'] = {}
507  light['position']['x'] = self.__processLayerNvizNode(node_position, 'x', float)
508  light['position']['y'] = self.__processLayerNvizNode(node_position, 'y', float)
509  light['position']['z'] = self.__processLayerNvizNode(node_position, 'z', int)
510 
511  light['bright'] = self.__processLayerNvizNode(node_light, 'bright', int)
512  light['ambient'] = self.__processLayerNvizNode(node_light, 'ambient', int)
513  color = self.__processLayerNvizNode(node_light, 'color', str)
514  light['color'] = tuple(map(int, color.split(':')))
515 
516  self.nviz_state['light'] = light
517 
518  node_constants = node_state.find('constant_planes')
519  constants = []
520  if node_constants:
521  for i, node_plane in enumerate(node_constants.findall('plane')):
522  plane = {}
523  plane['color'] = self.__processLayerNvizNode(node_plane, 'color', str)
524  plane['resolution'] = self.__processLayerNvizNode(node_plane, 'fine_resolution', int)
525  plane['value'] = self.__processLayerNvizNode(node_plane, 'height', int)
526  plane['object'] = {}
527  constants.append({'constant': plane})
528  self.nviz_state['constants'] = constants
529 
530 class WriteWorkspaceFile(object):
531  """!Generic class for writing workspace file"""
532  def __init__(self, lmgr, file):
533  self.file = file
534  self.lmgr = lmgr
535  self.indent = 0
536 
537  # write header
538 
539  self.file.write('<?xml version="1.0" encoding="%s"?>\n' % GetDefaultEncoding(forceUTF8 = True))
540  self.file.write('<!DOCTYPE gxw SYSTEM "grass-gxw.dtd">\n')
541  self.file.write('%s<gxw>\n' % (' ' * self.indent))
542 
543  self.indent =+ 4
544 
545  # layer manager
546  windowPos = self.lmgr.GetPosition()
547  windowSize = self.lmgr.GetSize()
548  file.write('%s<layer_manager dim="%d,%d,%d,%d">\n' % (' ' * self.indent,
549  windowPos[0],
550  windowPos[1],
551  windowSize[0],
552  windowSize[1]
553  ))
554 
555  file.write('%s</layer_manager>\n' % (' ' * self.indent))
556 
557  # list of displays
558  for page in range(0, self.lmgr.GetLayerNotebook().GetPageCount()):
559  dispName = self.lmgr.GetLayerNotebook().GetPageText(page)
560  mapTree = self.lmgr.GetLayerNotebook().GetPage(page).maptree
561  region = mapTree.GetMap().GetCurrentRegion()
562  mapdisp = mapTree.GetMapDisplay()
563 
564  displayPos = mapTree.mapdisplay.GetPosition()
565  displaySize = mapTree.mapdisplay.GetSize()
566  if mapTree.mapdisplay.toolbars['map'].combo.GetSelection() == 1:
567  viewmode = '3d'
568  else:
569  viewmode = '2d'
570 
571  file.write('%s<display '
572  'name="%s" render="%d" '
573  'mode="%d" showCompExtent="%d" '
574  'alignExtent="%d" '
575  'constrainRes="%d" '
576  'dim="%d,%d,%d,%d" '
577  'extent="%f,%f,%f,%f" '
578  'viewMode="%s" >\n' % (' ' * self.indent,
579  dispName.encode('utf8'),
580  int(mapTree.mapdisplay.GetProperty('render')),
581  mapTree.mapdisplay.statusbarManager.GetMode(),
582  int(mapTree.mapdisplay.GetProperty('region')),
583  int(mapTree.mapdisplay.GetProperty('alignExtent')),
584  int(mapTree.mapdisplay.GetProperty('resolution')),
585  displayPos[0],
586  displayPos[1],
587  displaySize[0],
588  displaySize[1],
589  region['w'],
590  region['s'],
591  region['e'],
592  region['n'],
593  viewmode
594  ))
595  # projection statusbar info
596  if mapTree.mapdisplay.GetProperty('projection') and \
597  UserSettings.Get(group='display', key='projection', subkey='proj4'):
598  self.indent += 4
599  file.write('%s<projection' % (' ' * self.indent))
600  epsg = UserSettings.Get(group='display', key='projection', subkey='epsg')
601  if epsg:
602  file.write(' epsg="%s"' % epsg)
603  file.write('>\n')
604  proj = UserSettings.Get(group='display', key='projection', subkey='proj4')
605  self.indent += 4
606  file.write('%s<value>%s</value>\n' % (' ' * self.indent, proj))
607  self.indent -= 4
608  file.write('%s</projection>\n' % (' ' * self.indent))
609  self.indent -= 4
610 
611  # list of layers
612  item = mapTree.GetFirstChild(mapTree.root)[0]
613  self.__writeLayer(mapTree, item)
614 
615  if mapTree.mapdisplay.MapWindow3D is not None:
616  nvizDisp = mapTree.mapdisplay.MapWindow3D
617  self.__writeNvizState(view = nvizDisp.view, iview = nvizDisp.iview,
618  light = nvizDisp.light, constants = nvizDisp.constants)
619 
620  file.write('%s</display>\n' % (' ' * self.indent))
621 
622  self.indent =- 4
623  file.write('%s</gxw>\n' % (' ' * self.indent))
624 
625  def __filterValue(self, value):
626  """!Make value XML-valid"""
627  value = value.replace('<', '&lt;')
628  value = value.replace('>', '&gt;')
629 
630  return value
631 
632  def __writeLayer(self, mapTree, item):
633  """!Write bunch of layers to GRASS Workspace XML file"""
634  self.indent += 4
635  itemSelected = mapTree.GetSelections()
636  while item and item.IsOk():
637  type = mapTree.GetPyData(item)[0]['type']
638  if type != 'group':
639  maplayer = mapTree.GetPyData(item)[0]['maplayer']
640  else:
641  maplayer = None
642 
643  checked = int(item.IsChecked())
644  if type == 'command':
645  cmd = mapTree.GetPyData(item)[0]['maplayer'].GetCmd(string=True)
646  self.file.write('%s<layer type="%s" name="%s" checked="%d">\n' % \
647  (' ' * self.indent, type, EncodeString(cmd), checked));
648  self.file.write('%s</layer>\n' % (' ' * self.indent));
649  elif type == 'group':
650  name = mapTree.GetItemText(item)
651  self.file.write('%s<group name="%s" checked="%d">\n' % \
652  (' ' * self.indent, EncodeString(name), checked));
653  self.indent += 4
654  subItem = mapTree.GetFirstChild(item)[0]
655  self.__writeLayer(mapTree, subItem)
656  self.indent -= 4
657  self.file.write('%s</group>\n' % (' ' * self.indent));
658  else:
659  cmd = mapTree.GetPyData(item)[0]['maplayer'].GetCmd(string = False)
660  name = mapTree.GetItemText(item).replace(os.linesep, '\\n')
661  opacity = maplayer.GetOpacity(float = True)
662  # remove 'opacity' part
663  if opacity < 1:
664  name = name.split('(', -1)[0].strip()
665  self.file.write('%s<layer type="%s" name="%s" checked="%d" opacity="%f">\n' % \
666  (' ' * self.indent, type, EncodeString(name), checked, opacity));
667 
668  self.indent += 4
669  # selected ?
670  if item in itemSelected:
671  self.file.write('%s<selected />\n' % (' ' * self.indent))
672  # layer properties
673  self.file.write('%s<task name="%s">\n' % (' ' * self.indent, cmd[0]))
674  self.indent += 4
675  for key, val in cmd[1].iteritems():
676  if key == 'flags':
677  for f in val:
678  self.file.write('%s<flag name="%s" />\n' %
679  (' ' * self.indent, f))
680  elif val in (True, False):
681  self.file.write('%s<flag name="%s" />\n' %
682  (' ' * self.indent, key))
683  else: # parameter
684  self.file.write('%s<parameter name="%s">\n' %
685  (' ' * self.indent, key))
686  self.indent += 4
687  self.file.write('%s<value>%s</value>\n' %
688  (' ' * self.indent, self.__filterValue(val)))
689  self.indent -= 4
690  self.file.write('%s</parameter>\n' % (' ' * self.indent));
691  self.indent -= 4
692  self.file.write('%s</task>\n' % (' ' * self.indent));
693  # vector digitizer
694  vdigit = mapTree.GetPyData(item)[0]['vdigit']
695  if vdigit:
696  self.file.write('%s<vdigit>\n' % (' ' * self.indent))
697  if 'geomAttr' in vdigit:
698  self.indent += 4
699  for type, val in vdigit['geomAttr'].iteritems():
700  units = ''
701  if val['units'] != 'mu':
702  units = ' units="%s"' % val['units']
703  self.file.write('%s<geometryAttribute type="%s" column="%s"%s />\n' % \
704  (' ' * self.indent, type, val['column'], units))
705  self.indent -= 4
706  self.file.write('%s</vdigit>\n' % (' ' * self.indent))
707  # nviz
708  nviz = mapTree.GetPyData(item)[0]['nviz']
709  if nviz:
710  self.file.write('%s<nviz>\n' % (' ' * self.indent))
711  if maplayer.type == 'raster':
712  self.__writeNvizSurface(nviz['surface'])
713  elif maplayer.type == 'vector':
714  self.__writeNvizVector(nviz['vector'])
715  self.file.write('%s</nviz>\n' % (' ' * self.indent))
716  self.indent -= 4
717  self.file.write('%s</layer>\n' % (' ' * self.indent))
718  item = mapTree.GetNextSibling(item)
719  self.indent -= 4
720 
721  def __writeNvizSurface(self, data):
722  """!Save Nviz raster layer properties to workspace
723 
724  @param data Nviz layer properties
725  """
726  if 'object' not in data: # skip disabled
727  return
728  self.indent += 4
729  self.file.write('%s<surface>\n' % (' ' * self.indent))
730  self.indent += 4
731  for attrb in data.iterkeys():
732  if len(data[attrb]) < 1: # skip empty attributes
733  continue
734  if attrb == 'object':
735  continue
736 
737  for name in data[attrb].iterkeys():
738  # surface attribute
739  if attrb == 'attribute':
740  if data[attrb][name]['map'] is None:
741  continue
742  self.file.write('%s<%s name="%s" map="%d">\n' % \
743  (' ' * self.indent, attrb, name, data[attrb][name]['map']))
744  self.indent += 4
745  self.file.write('%s<value>%s</value>\n' % (' ' * self.indent, data[attrb][name]['value']))
746  self.indent -= 4
747  # end tag
748  self.file.write('%s</%s>\n' % (' ' * self.indent, attrb))
749 
750  # draw mode
751  if attrb == 'draw':
752  self.file.write('%s<%s' %(' ' * self.indent, attrb))
753  if 'mode' in data[attrb]:
754  for tag, value in data[attrb]['mode']['desc'].iteritems():
755  self.file.write(' %s="%s"' % (tag, value))
756  self.file.write('>\n') # <draw ...>
757 
758  if 'resolution' in data[attrb]:
759  self.indent += 4
760  for type in ('coarse', 'fine'):
761  self.file.write('%s<resolution type="%s">\n' % (' ' * self.indent, type))
762  self.indent += 4
763  self.file.write('%s<value>%d</value>\n' % (' ' * self.indent,
764  data[attrb]['resolution'][type]))
765  self.indent -= 4
766  self.file.write('%s</resolution>\n' % (' ' * self.indent))
767 
768  if 'wire-color' in data[attrb]:
769  self.file.write('%s<wire_color>\n' % (' ' * self.indent))
770  self.indent += 4
771  self.file.write('%s<value>%s</value>\n' % (' ' * self.indent,
772  data[attrb]['wire-color']['value']))
773  self.indent -= 4
774  self.file.write('%s</wire_color>\n' % (' ' * self.indent))
775  self.indent -= 4
776 
777  # position
778  elif attrb == 'position':
779  self.file.write('%s<%s>\n' %(' ' * self.indent, attrb))
780  i = 0
781  for tag in ('x', 'y', 'z'):
782  self.indent += 4
783  self.file.write('%s<%s>%d</%s>\n' % (' ' * self.indent, tag,
784  data[attrb][tag], tag))
785  i += 1
786  self.indent -= 4
787 
788  if attrb != 'attribute':
789  # end tag
790  self.file.write('%s</%s>\n' % (' ' * self.indent, attrb))
791 
792  self.indent -= 4
793  self.file.write('%s</surface>\n' % (' ' * self.indent))
794  self.indent -= 4
795 
796  def __writeNvizVector(self, data):
797  """!Save Nviz vector layer properties (lines/points) to workspace
798 
799  @param data Nviz layer properties
800  """
801  self.indent += 4
802  for attrb in data.iterkeys():
803  if len(data[attrb]) < 1: # skip empty attributes
804  continue
805 
806  if 'object' not in data[attrb]: # skip disabled
807  continue
808  if attrb == 'lines':
809  self.file.write('%s<v%s>\n' % (' ' * self.indent, attrb))
810  elif attrb == 'points':
811  markerId = data[attrb]['marker']['value']
812  marker = UserSettings.Get(group = 'nviz', key = 'vector',
813  subkey = ['points', 'marker'], internal = True)[markerId]
814  self.file.write('%s<v%s marker="%s">\n' % (' ' * self.indent,
815  attrb,
816  marker))
817  self.indent += 4
818  for name in data[attrb].iterkeys():
819  if name in ('object', 'marker'):
820  continue
821  if name == 'mode':
822  self.file.write('%s<%s type="%s">\n' % (' ' * self.indent, name,
823  data[attrb][name]['type']))
824  if data[attrb][name]['type'] == 'surface':
825  self.indent += 4
826  for idx, surface in enumerate(data[attrb][name]['surface']['value']):
827  checked = data[attrb][name]['surface']['show'][idx]
828  self.file.write('%s<map>\n' % (' ' * self.indent))
829  self.indent += 4
830  self.file.write('%s<name>%s</name>\n' % (' ' * self.indent, surface))
831  self.file.write('%s<checked>%s</checked>\n' % (' ' * self.indent, int(checked)))
832  self.indent -= 4
833  self.file.write('%s</map>\n' % (' ' * self.indent))
834  self.indent -= 4
835  self.file.write('%s</%s>\n' % ((' ' * self.indent, name)))
836  else:
837  self.file.write('%s<%s>\n' % (' ' * self.indent, name))
838  self.indent += 4
839  self.file.write('%s<value>%s</value>\n' % (' ' * self.indent, data[attrb][name]['value']))
840  self.indent -= 4
841  self.file.write('%s</%s>\n' % (' ' * self.indent, name))
842  self.indent -= 4
843  self.file.write('%s</v%s>\n' % (' ' * self.indent, attrb))
844 
845  self.indent -= 4
846 
847  def __writeNvizState(self, view, iview, light, constants):
848  """"!Save Nviz properties (view, light) to workspace
849 
850  @param view Nviz view properties
851  @param iview Nviz internal view properties
852  @param light Nviz light properties
853  """
854  self.indent += 4
855  self.file.write('%s<nviz_state>\n' % (' ' * self.indent))
856  #
857  # view
858  #
859  self.indent += 4
860  self.file.write('%s<view>\n' % (' ' * self.indent))
861  self.indent += 4
862  # position
863  self.file.write('%s<v_position>\n' % (' ' * self.indent))
864  self.indent += 4
865  self.file.write('%s<x>%.2f</x>\n' % (' ' * self.indent, view['position']['x']))
866  self.file.write('%s<y>%.2f</y>\n' % (' ' * self.indent, view['position']['y']))
867  self.indent -= 4
868  self.file.write('%s</v_position>\n' % (' ' * self.indent))
869  # perspective
870  self.file.write('%s<persp>\n' % (' ' * self.indent))
871  self.indent += 4
872  self.file.write('%s<value>%d</value>\n' % (' ' * self.indent, view['persp']['value']))
873  self.file.write('%s<step>%d</step>\n' % (' ' * self.indent, view['persp']['step']))
874  self.file.write('%s<min>%d</min>\n' % (' ' * self.indent, iview['persp']['min']))
875  self.file.write('%s<max>%d</max>\n' % (' ' * self.indent, iview['persp']['max']))
876  self.indent -= 4
877  self.file.write('%s</persp>\n' % (' ' * self.indent))
878  # height
879  self.file.write('%s<v_height>\n' % (' ' * self.indent))
880  self.indent += 4
881  self.file.write('%s<value>%d</value>\n' % (' ' * self.indent, iview['height']['value']))
882  self.file.write('%s<min>%d</min>\n' % (' ' * self.indent, iview['height']['min']))
883  self.file.write('%s<max>%d</max>\n' % (' ' * self.indent, iview['height']['max']))
884  self.indent -= 4
885  self.file.write('%s</v_height>\n' % (' ' * self.indent))
886  # twist
887  self.file.write('%s<twist>\n' % (' ' * self.indent))
888  self.indent += 4
889  self.file.write('%s<value>%d</value>\n' % (' ' * self.indent, view['twist']['value']))
890  self.file.write('%s<min>%d</min>\n' % (' ' * self.indent, iview['twist']['min']))
891  self.file.write('%s<max>%d</max>\n' % (' ' * self.indent, iview['twist']['max']))
892  self.indent -= 4
893  self.file.write('%s</twist>\n' % (' ' * self.indent))
894  # z-exag
895  self.file.write('%s<z-exag>\n' % (' ' * self.indent))
896  self.indent += 4
897  self.file.write('%s<value>%.2f</value>\n' % (' ' * self.indent, view['z-exag']['value']))
898  self.file.write('%s<min>%d</min>\n' % (' ' * self.indent, view['z-exag']['min']))
899  self.file.write('%s<max>%d</max>\n' % (' ' * self.indent, view['z-exag']['max']))
900  self.file.write('%s<llRatio>%.2f</llRatio>\n' % (' ' * self.indent, iview['z-exag']['llRatio']))
901  self.indent -= 4
902  self.file.write('%s</z-exag>\n' % (' ' * self.indent))
903  # focus (look here)
904  self.file.write('%s<focus>\n' % (' ' * self.indent))
905  self.indent += 4
906  self.file.write('%s<x>%d</x>\n' % (' ' * self.indent, iview['focus']['x']))
907  self.file.write('%s<y>%d</y>\n' % (' ' * self.indent, iview['focus']['y']))
908  self.file.write('%s<z>%d</z>\n' % (' ' * self.indent, iview['focus']['z']))
909  self.indent -= 4
910  self.file.write('%s</focus>\n' % (' ' * self.indent))
911  # background
912  self.__writeTagWithValue('background_color', view['background']['color'][:3], format = 'd:%d:%d')
913 
914  self.indent -= 4
915  self.file.write('%s</view>\n' % (' ' * self.indent))
916  #
917  # light
918  #
919  self.file.write('%s<light>\n' % (' ' * self.indent))
920  self.indent += 4
921  # position
922  self.file.write('%s<l_position>\n' % (' ' * self.indent))
923  self.indent += 4
924  self.file.write('%s<x>%.2f</x>\n' % (' ' * self.indent, light['position']['x']))
925  self.file.write('%s<y>%.2f</y>\n' % (' ' * self.indent, light['position']['y']))
926  self.file.write('%s<z>%d</z>\n' % (' ' * self.indent, light['position']['z']))
927  self.indent -= 4
928  self.file.write('%s</l_position>\n' % (' ' * self.indent))
929  # bright
930  self.__writeTagWithValue('bright', light['bright'])
931  # ambient
932  self.__writeTagWithValue('ambient', light['ambient'])
933  # color
934  self.__writeTagWithValue('color', light['color'][:3], format = 'd:%d:%d')
935 
936  self.indent -= 4
937  self.file.write('%s</light>\n' % (' ' * self.indent))
938  #
939  # constant planes
940  #
941  if constants:
942  self.file.write('%s<constant_planes>\n' % (' ' * self.indent))
943  self.indent += 4
944  for idx, plane in enumerate(constants):
945  self.file.write('%s<plane>\n' % (' ' * self.indent))
946  self.indent += 4
947  self.__writeTagWithValue('height', constants[idx]['constant']['value'])
948  self.__writeTagWithValue('fine_resolution', constants[idx]['constant']['resolution'])
949  self.__writeTagWithValue('color', constants[idx]['constant']['color'], format = 's')
950  self.indent -= 4
951  self.file.write('%s</plane>\n' % (' ' * self.indent))
952  self.indent -= 4
953  self.file.write('%s</constant_planes>\n' % (' ' * self.indent))
954  self.indent -= 4
955 
956  self.file.write('%s</nviz_state>\n' % (' ' * self.indent))
957  self.indent -= 4
958 
959  def __writeTagWithValue(self, tag, data, format = 'd'):
960  """!Helper function for writing pair tag
961 
962  @param tag written tag
963  @param data written data
964  @param format conversion type
965  """
966  self.file.write('%s<%s>\n' % (' ' * self.indent, tag))
967  self.indent += 4
968  self.file.write('%s' % (' ' * self.indent))
969  self.file.write(('<value>%' + format + '</value>\n') % data)
970  self.indent -= 4
971  self.file.write('%s</%s>\n' % (' ' * self.indent, tag))
972 
973 class ProcessGrcFile(object):
974  def __init__(self, filename):
975  """!Process GRC file"""
976  self.filename = filename
977 
978  # elements
979  self.inGroup = False
980  self.inRaster = False
981  self.inVector = False
982 
983  # list of layers
984  self.layers = []
985 
986  # error message
987  self.error = ''
988  self.num_error = 0
989 
990  def read(self, parent):
991  """!Read GRC file
992 
993  @param parent parent window
994 
995  @return list of map layers
996  """
997  try:
998  file = open(self.filename, "r")
999  except IOError:
1000  wx.MessageBox(parent=parent,
1001  message=_("Unable to open file <%s> for reading.") % self.filename,
1002  caption=_("Error"), style=wx.OK | wx.ICON_ERROR)
1003  return []
1004 
1005  line_id = 1
1006  for line in file.readlines():
1007  self.process_line(line.rstrip('\n'), line_id)
1008  line_id +=1
1009 
1010  file.close()
1011 
1012  if self.num_error > 0:
1013  wx.MessageBox(parent=parent,
1014  message=_("Some lines were skipped when reading settings "
1015  "from file <%(file)s>.\nSee 'Command output' window for details.\n\n"
1016  "Number of skipped lines: %(line)d") % \
1017  { 'file' : self.filename, 'line' : self.num_error },
1018  caption=_("Warning"), style=wx.OK | wx.ICON_EXCLAMATION)
1019  parent.goutput.WriteLog('Map layers loaded from GRC file <%s>' % self.filename)
1020  parent.goutput.WriteLog('Skipped lines:\n%s' % self.error)
1021 
1022  return self.layers
1023 
1024  def process_line(self, line, line_id):
1025  """!Process line definition"""
1026  element = self._get_element(line)
1027  if element == 'Group':
1028  self.groupName = self._get_value(line)
1029  self.layers.append({
1030  "type" : 'group',
1031  "name" : self.groupName,
1032  "checked" : None,
1033  "opacity" : None,
1034  "cmd" : None,
1035  "group" : self.inGroup,
1036  "display" : 0 })
1037  self.inGroup = True
1038 
1039  elif element == '_check':
1040  if int(self._get_value(line)) == 1:
1041  self.layers[-1]['checked'] = True
1042  else:
1043  self.layers[-1]['checked'] = False
1044 
1045  elif element == 'End':
1046  if self.inRaster:
1047  self.inRaster = False
1048  elif self.inVector:
1049  self.inVector = False
1050  elif self.inGroup:
1051  self.inGroup = False
1052  elif self.inGridline:
1053  self.inGridline = False
1054 
1055  elif element == 'opacity':
1056  self.layers[-1]['opacity'] = float(self._get_value(line))
1057 
1058  # raster
1059  elif element == 'Raster':
1060  self.inRaster = True
1061  self.layers.append({
1062  "type" : 'raster',
1063  "name" : self._get_value(line),
1064  "checked" : None,
1065  "opacity" : None,
1066  "cmd" : ['d.rast'],
1067  "group" : self.inGroup,
1068  "display" : 0})
1069 
1070  elif element == 'map' and self.inRaster:
1071  self.layers[-1]['cmd'].append('map=%s' % self._get_value(line))
1072 
1073  elif element == 'overlay' and self.inRaster:
1074  if int(self._get_value(line)) == 1:
1075  self.layers[-1]['cmd'].append('-o')
1076 
1077  elif element == 'rastquery' and self.inRaster:
1078  value = self._get_value(line)
1079  if value != '':
1080  self.layers[-1]['cmd'].append('catlist=%s' % value)
1081 
1082  elif element == 'bkcolor' and self.inRaster:
1083  value = self._get_value(line)
1084  if value != '':
1085  self.layers[-1]['cmd'].append('bg=%s' % value)
1086 
1087  # vector
1088  elif element == 'Vector':
1089  self.inVector = True
1090  self.layers.append({
1091  "type" : 'vector',
1092  "name" : self._get_value(line),
1093  "checked" : None,
1094  "opacity" : None,
1095  "cmd" : ['d.vect'],
1096  "group" : self.inGroup,
1097  "display" : 0})
1098 
1099  elif element == 'vect' and self.inVector:
1100  self.layers[-1]['cmd'].append('map=%s' % self._get_value(line))
1101 
1102  elif element in ('display_shape',
1103  'display_cat',
1104  'display_topo',
1105  'display_dir',
1106  'display_attr',
1107  'type_point',
1108  'type_line',
1109  'type_boundary',
1110  'type_centroid',
1111  'type_area',
1112  'type_face') and self.inVector:
1113 
1114  if int(self._get_value(line)) == 1:
1115  name = element.split('_')[0]
1116  type = element.split('_')[1]
1117  paramId = self._get_cmd_param_index(self.layers[-1]['cmd'], name)
1118  if paramId == -1:
1119  self.layers[-1]['cmd'].append('%s=%s' % (name, type))
1120  else:
1121  self.layers[-1]['cmd'][paramId] += ',%s' % type
1122 
1123  elif element in ('color',
1124  'fcolor',
1125  'lcolor') and self.inVector:
1126  value = self._get_value(line)
1127  if value != '':
1128  self.layers[-1]['cmd'].append('%s=%s' % (element,
1129  self._color_name_to_rgb(value)))
1130 
1131  elif element == 'rdmcolor' and self.inVector:
1132  if int(self._get_value(line)) == 1:
1133  self.layers[-1]['cmd'].append('-c')
1134 
1135  elif element == 'sqlcolor' and self.inVector:
1136  if int(self._get_value(line)) == 1:
1137  self.layers[-1]['cmd'].append('-a')
1138 
1139  elif element in ('icon',
1140  'size',
1141  'layer',
1142  'xref',
1143  'yref',
1144  'lsize',
1145  'where',
1146  'minreg',
1147  'maxreg') and self.inVector:
1148  value = self._get_value(line)
1149  if value != '':
1150  self.layers[-1]['cmd'].append('%s=%s' % (element,
1151  value))
1152 
1153  elif element == 'lwidth':
1154  value = self._get_value(line)
1155  if value != '':
1156  self.layers[-1]['cmd'].append('width=%s' % value)
1157 
1158  elif element == 'lfield':
1159  value = self._get_value(line)
1160  if value != '':
1161  self.layers[-1]['cmd'].append('llayer=%s' % value)
1162 
1163  elif element == 'attribute':
1164  value = self._get_value(line)
1165  if value != '':
1166  self.layers[-1]['cmd'].append('attrcol=%s' % value)
1167 
1168  elif element == 'cat':
1169  value = self._get_value(line)
1170  if value != '':
1171  self.layers[-1]['cmd'].append('cats=%s' % value)
1172 
1173  # gridline
1174  elif element == 'gridline':
1175  self.inGridline = True
1176  self.layers.append({
1177  "type" : 'grid',
1178  "name" : self._get_value(line),
1179  "checked" : None,
1180  "opacity" : None,
1181  "cmd" : ['d.grid'],
1182  "group" : self.inGroup,
1183  "display" : 0})
1184 
1185  elif element == 'gridcolor':
1186  value = self._get_value(line)
1187  if value != '':
1188  self.layers[-1]['cmd'].append('color=%s' % self._color_name_to_rgb(value))
1189 
1190  elif element == 'gridborder':
1191  value = self._get_value(line)
1192  if value != '':
1193  self.layers[-1]['cmd'].append('bordercolor=%s' % self._color_name_to_rgb(value))
1194 
1195  elif element == 'textcolor':
1196  value = self._get_value(line)
1197  if value != '':
1198  self.layers[-1]['cmd'].append('textcolor=%s' % self._color_name_to_rgb(value))
1199 
1200  elif element in ('gridsize',
1201  'gridorigin'):
1202  value = self._get_value(line)
1203  if value != '':
1204  self.layers[-1]['cmd'].append('%s=%s' % (element[4:], value))
1205 
1206  elif element in 'fontsize':
1207  value = self._get_value(line)
1208  if value != '':
1209  self.layers[-1]['cmd'].append('%s=%s' % (element, value))
1210 
1211  elif element == 'griddraw':
1212  value = self._get_value(line)
1213  if value == '0':
1214  self.layers[-1]['cmd'].append('-n')
1215 
1216  elif element == 'gridgeo':
1217  value = self._get_value(line)
1218  if value == '1':
1219  self.layers[-1]['cmd'].append('-g')
1220 
1221  elif element == 'borderdraw':
1222  value = self._get_value(line)
1223  if value == '0':
1224  self.layers[-1]['cmd'].append('-b')
1225 
1226  elif element == 'textdraw':
1227  value = self._get_value(line)
1228  if value == '0':
1229  self.layers[-1]['cmd'].append('-t')
1230 
1231  else:
1232  self.error += _(' row %d:') % line_id + line + os.linesep
1233  self.num_error += 1
1234 
1235  def _get_value(self, line):
1236  """!Get value of element"""
1237  try:
1238  return line.strip(' ').split(' ')[1].strip(' ')
1239  except:
1240  return ''
1241 
1242  def _get_element(self, line):
1243  """!Get element tag"""
1244  return line.strip(' ').split(' ')[0].strip(' ')
1245 
1246  def _get_cmd_param_index(self, cmd, name):
1247  """!Get index of parameter in cmd list
1248 
1249  @param cmd cmd list
1250  @param name parameter name
1251 
1252  @return index
1253  @return -1 if not found
1254  """
1255  i = 0
1256  for param in cmd:
1257  if '=' not in param:
1258  i += 1
1259  continue
1260  if param.split('=')[0] == name:
1261  return i
1262 
1263  i += 1
1264 
1265  return -1
1266 
1267  def _color_name_to_rgb(self, value):
1268  """!Convert color name (#) to rgb values"""
1269  col = wx.NamedColour(value)
1270  return str(col.Red()) + ':' + \
1271  str(col.Green()) + ':' + \
1272  str(col.Blue())
def normalize_whitespace
Remove redundant whitespace from a string.
Definition: core/utils.py:33
def EncodeString
Return encoded string using system locales.
Definition: gcmd.py:85
wxGUI command interface
def __processLayerNvizNode
Process given tag nviz/vector.
def __processFile
Process workspace file.
def read
Read GRC file.
def __writeTagWithValue
Helper function for writing pair tag.
def __init__
Process GRC file.
def __filterValue
Filter value.
def __processLayer
Process layer item.
Nviz (3D view) module.
def __processLayerNviz
Process 3D layer settings.
def split
Platform spefic shlex.split.
Definition: core/utils.py:37
def __writeNvizSurface
Save Nviz raster layer properties to workspace.
def __init__
A ElementTree handler for the GXW XML file, as defined in grass-gxw.dtd.
def _get_element
Get element tag.
def __processNvizState
Process tag nviz_state.
def GetDefaultEncoding
Get default system encoding.
Definition: gcmd.py:701
def __writeLayer
Write bunch of layers to GRASS Workspace XML file.
Misc utilities for wxGUI.
def process_line
Process line definition.
def _get_cmd_param_index
Get index of parameter in cmd list.
def _get_value
Get value of element.
def __filterValue
Make value XML-valid.
def __processLayers
Process layers/groups of selected display.
Default GUI settings.
tuple range
Definition: tools.py:1406
def __writeNvizVector
Save Nviz vector layer properties (lines/points) to workspace.
Generic class for writing workspace file.
def __getNodeText
Get node text.
def __processLayerVdigit
Process vector digitizer layer settings.
def _color_name_to_rgb
Convert color name (#) to rgb values.