2 @package gui_core.gselect
4 @brief Custom control that selects elements
8 - gselect::VectorSelect
9 - gselect::TreeCrtlComboPopup
10 - gselect::VectorDBInfo
11 - gselect::LayerSelect
12 - gselect::DriverSelect
13 - gselect::DatabaseSelect
14 - gselect::TableSelect
15 - gselect::ColumnSelect
16 - gselect::DbaseSelect
17 - gselect::LocationSelect
18 - gselect::MapsetSelect
19 - gselect::SubGroupSelect
20 - gselect::FormatSelect
23 - gselect::ElementSelect
25 (C) 2007-2011 by the GRASS Development Team
27 This program is free software under the GNU General Public License
28 (>=v2). Read the file COPYING that comes with GRASS for details.
30 @author Michael Barton
31 @author Martin Landa <landa.martin gmail.com>
32 @author Vaclav Petras <wenzeslaus gmail.com> (menu customization)
41 import wx.lib.filebrowsebutton
as filebrowse
42 from wx.lib.newevent
import NewEvent
44 from core
import globalvar
49 from core.gcmd import RunCommand, GError, GMessage
50 from core.utils import GetListOfLocations, GetListOfMapsets, GetFormats
51 from core.utils import GetSettingsPath, GetValidLayerName, ListSortLower, GetAllVectorLayers
55 wxGdalSelect, EVT_GDALSELECT = NewEvent()
58 def __init__(self, parent, id = wx.ID_ANY, size = globalvar.DIALOG_GSELECT_SIZE,
59 type =
None, multiple =
False, nmaps = 1,
60 mapsets =
None, updateOnPopup =
True, onPopup =
None,
61 fullyQualified =
True):
62 """!Custom control to create a ComboBox with a tree control to
63 display and select GIS elements within acessible mapsets.
64 Elements can be selected with mouse. Can allow multiple
65 selections, when argument <em>multiple</em> is True. Multiple
66 selections are separated by commas.
68 @param type type of GIS elements ('raster, 'vector', ...)
69 @param multiple True for multiple input
70 @param nmaps number of maps to be entered
71 @param mapsets force list of mapsets (otherwise search path)
72 @param updateOnPopup True for updating list of elements on popup
73 @param onPopup function to be called on Popup
74 @param fullyQualified True to provide fully qualified names (map@mapset)
76 wx.combo.ComboCtrl.__init__(self, parent=parent, id=id, size=size)
77 self.GetChildren()[0].SetName(
"Select")
78 self.GetChildren()[0].type = type
81 self.SetPopupControl(self.
tcp)
82 self.SetPopupExtents(0, 100)
84 self.tcp.SetData(type = type, mapsets = mapsets,
85 multiple = multiple, nmaps = nmaps,
86 updateOnPopup = updateOnPopup, onPopup = onPopup,
87 fullyQualified = fullyQualified)
88 self.GetChildren()[0].Bind(wx.EVT_KEY_UP, self.
OnKeyUp)
91 """!Shows popupwindow if down arrow key is released"""
92 if event.GetKeyCode() == wx.WXK_DOWN
and not self.IsPopupShown():
100 @param type GIS element type
101 @param mapsets list of acceptable mapsets (None for all in search path)
103 self.tcp.SetData(type = type, mapsets = mapsets)
107 self.tcp.GetElementList()
109 def SetType(self, etype, multiple = False, nmaps = 1,
110 mapsets =
None, updateOnPopup =
True, onPopup =
None):
111 """!Param set element type for widget
113 @param etype element type, see gselect.ElementSelect
115 self.tcp.SetData(type = etype, mapsets = mapsets,
116 multiple = multiple, nmaps = nmaps,
117 updateOnPopup = updateOnPopup, onPopup = onPopup)
121 """!Custom to create a ComboBox with a tree control to display and
122 select vector maps. You can filter the vector maps. If you
123 don't need this feature use Select class instead
125 @ftype filter vector maps based on feature type
127 Select.__init__(self, parent = parent, id = wx.ID_ANY,
128 type =
'vector', **kwargs)
135 def _isElement(self, vectorName):
136 """!Check if element should be filtered out"""
138 if int(grass.vector_info_topo(vectorName)[self.
ftype]) < 1:
146 """!Create a tree ComboBox for selecting maps and other GIS elements
147 in accessible mapsets within the current location
164 self.
seltree = wx.TreeCtrl(parent, style=wx.TR_HIDE_ROOT
169 |wx.TR_FULL_ROW_HIGHLIGHT)
170 self.seltree.Bind(wx.EVT_KEY_UP, self.
OnKeyUp)
171 self.seltree.Bind(wx.EVT_MOTION, self.
OnMotion)
172 self.seltree.Bind(wx.EVT_LEFT_DOWN, self.
OnLeftDown)
175 self.seltree.Bind(wx.EVT_TREE_ITEM_EXPANDING,
lambda x:
None)
176 self.seltree.Bind(wx.EVT_TREE_ITEM_COLLAPSED,
lambda x:
None)
177 self.seltree.Bind(wx.EVT_TREE_ITEM_ACTIVATED,
lambda x:
None)
178 self.seltree.Bind(wx.EVT_TREE_SEL_CHANGED,
lambda x:
None)
179 self.seltree.Bind(wx.EVT_TREE_DELETE_ITEM,
lambda x:
None)
180 self.seltree.Bind(wx.EVT_TREE_BEGIN_DRAG,
lambda x:
None)
181 self.seltree.Bind(wx.EVT_TREE_ITEM_RIGHT_CLICK,
lambda x:
None)
187 """!Get value as a string separated by commas"""
188 return ','.join(self.
value)
191 """!Set filter for GIS elements, see e.g. VectorSelect"""
195 """!Limited only for first selected"""
207 inputText = self.GetCombo().
GetValue().strip()
209 root = self.seltree.GetRootItem()
210 match = self.
FindItem(root, inputText, startLetters =
True)
211 self.seltree.EnsureVisible(match)
212 self.seltree.SelectItem(match)
216 """!Get filtered list of GIS elements in accessible mapsets
217 and display as tree with all relevant elements displayed
218 beneath each mapset branch
221 self.seltree.DeleteAllItems()
224 if len(self.
value) > 0:
225 root = self.seltree.GetRootItem()
230 self.seltree.EnsureVisible(item)
231 self.seltree.SelectItem(item)
237 root = self.seltree.GetRootItem()
241 winValue = self.GetCombo().
GetValue().strip(
',')
244 self.
value = winValue.split(
',')
247 self.value.append(found)
248 self.seltree.SelectItem(found)
251 """!Reads UserSettings to get height (which was 200 in old implementation).
253 height = UserSettings.Get(group =
'appearance', key =
'gSelectPopupHeight', subkey =
'value')
254 return wx.Size(minWidth,
min(height, maxHeight))
256 def _getElementList(self, element, mapsets = None, elements = None, exclude = False):
257 """!Get list of GIS elements in accessible mapsets and display as tree
258 with all relevant elements displayed beneath each mapset branch
260 @param element GIS element
261 @param mapsets list of acceptable mapsets (None for all mapsets in search path)
262 @param elements list of forced GIS elements
263 @param exclude True to exclude, False for forcing the list (elements)
266 curr_mapset = grass.gisenv()[
'MAPSET']
269 elementdict = {
'cell':
'rast',
272 'raster files':
'rast',
275 '3d-raster':
'rast3d',
277 'raster3D files':
'rast3d',
280 'binary vector files':
'vect',
283 'old vector':
'oldvect',
284 'dig_ascii':
'asciivect',
285 'asciivect':
'asciivect',
286 'asciivector':
'asciivect',
287 'ascii vector files':
'asciivect',
290 'paint icon files':
'icon',
291 'paint/labels':
'labels',
294 'paint label files':
'labels',
295 'site_lists':
'sites',
298 'site list files':
'sites',
301 'region definition':
'region',
302 'region definition files':
'region',
303 'windows3d':
'region3d',
304 'region3d':
'region3d',
305 'region3D definition':
'region3d',
306 'region3D definition files':
'region3d',
308 'imagery group':
'group',
309 'imagery group files':
'group',
312 '3D viewing parameters':
'3dview',
313 '3D view parameters':
'3dview'}
315 if element
not in elementdict:
316 self.
AddItem(_(
'Not selectable element'))
319 if globalvar.have_mlist:
320 filesdict = grass.mlist_grouped(elementdict[element],
321 check_search_path =
False)
323 filesdict = grass.list_grouped(elementdict[element],
324 check_search_path =
False)
328 mapsets = grass.mapsets(search_path =
True)
331 if curr_mapset
in mapsets
and mapsets[0] != curr_mapset:
332 mapsets.remove(curr_mapset)
333 mapsets.insert(0, curr_mapset)
336 for mapset
in mapsets:
337 mapset_node = self.
AddItem(_(
'Mapset') +
': ' + mapset)
339 first_mapset = mapset_node
341 self.seltree.SetItemTextColour(mapset_node, wx.Colour(50, 50, 200))
342 if mapset
not in filesdict:
345 elem_list = filesdict[mapset]
347 for elem
in elem_list:
349 fullqElem = elem +
'@' + mapset
350 if elements
is not None:
351 if (exclude
and fullqElem
in elements)
or \
352 (
not exclude
and fullqElem
not in elements):
357 self.
AddItem(elem, parent = mapset_node)
359 self.
AddItem(elem, parent = mapset_node)
360 except StandardError, e:
361 sys.stderr.write(_(
"GSelect: invalid item: %s") % e)
364 if self.seltree.ItemHasChildren(mapset_node):
365 sel = UserSettings.Get(group=
'appearance', key=
'elementListExpand',
370 if mapset
in (
'PERMANENT', curr_mapset):
373 if mapset ==
'PERMANENT':
376 if mapset == curr_mapset:
384 self.seltree.Collapse(mapset_node)
386 self.seltree.Expand(mapset_node)
390 self.seltree.SelectItem(first_mapset)
393 def FindItem(self, parentItem, text, startLetters = False):
394 """!Finds item with given name or starting with given text"""
395 startletters = startLetters
396 item, cookie = self.seltree.GetFirstChild(parentItem)
397 while wx.TreeItemId.IsOk(item):
398 if self.seltree.GetItemText(item) == text:
400 if self.seltree.ItemHasChildren(item):
401 item = self.
FindItem(item, text, startLetters = startletters)
402 if wx.TreeItemId.IsOk(item):
404 elif startletters
and self.seltree.GetItemText(item).startswith(text.split(
'@', 1)[0]):
406 item, cookie = self.seltree.GetNextChild(parentItem, cookie)
407 return wx.TreeItemId()
411 root = self.seltree.GetRootItem()
413 root = self.seltree.AddRoot(
"<hidden root>")
416 item = self.seltree.AppendItem(parent, text=value)
421 """!Enables to select items using keyboard"""
423 item = self.seltree.GetSelection()
424 if event.GetKeyCode() == wx.WXK_DOWN:
425 self.seltree.SelectItem(self.seltree.GetNextVisible(item))
428 elif event.GetKeyCode() == wx.WXK_UP:
429 if self.seltree.ItemHasChildren(item)
and self.seltree.IsExpanded(self.seltree.GetPrevSibling(item)):
430 itemPrev = self.seltree.GetLastChild(self.seltree.GetPrevSibling(item))
432 itemPrev = self.seltree.GetPrevSibling(item)
433 if not wx.TreeItemId.IsOk(itemPrev):
434 itemPrev = self.seltree.GetItemParent(item)
435 if item == self.seltree.GetFirstChild(self.seltree.GetRootItem())[0]:
437 self.seltree.SelectItem(itemPrev)
440 elif event.GetKeyCode() == wx.WXK_TAB:
441 selected = self.seltree.GetSelection()
442 if self.seltree.ItemHasChildren(selected):
445 parent = self.seltree.GetItemParent(selected)
446 nextSibling = self.seltree.GetNextSibling(parent)
447 if wx.TreeItemId.IsOk(nextSibling):
448 match = self.
FindItem(nextSibling, self.GetCombo().
GetValue().strip(),
True)
450 match = self.
FindItem(self.seltree.GetFirstChild(self.seltree.GetItemParent(parent))[0],
451 self.GetCombo().
GetValue().strip(),
True)
452 self.seltree.SelectItem(match)
454 elif event.GetKeyCode() == wx.WXK_RIGHT:
455 if self.seltree.ItemHasChildren(item):
456 self.seltree.Expand(item)
458 elif event.GetKeyCode() == wx.WXK_LEFT:
459 if self.seltree.ItemHasChildren(item):
460 self.seltree.Collapse(item)
462 elif event.GetKeyCode() == wx.WXK_ESCAPE:
465 elif event.GetKeyCode() == wx.WXK_RETURN:
466 if self.seltree.GetRootItem() == self.seltree.GetItemParent(item):
469 mapsetItem = self.seltree.GetItemParent(item)
470 fullName = self.seltree.GetItemText(item)
472 fullName +=
'@' + self.seltree.GetItemText(mapsetItem).
split(
':', -1)[1].strip()
475 self.value.append(fullName)
479 self.
value = [fullName]
481 self.value.append(fullName)
483 self.
value = [fullName]
488 """!Have the selection follow the mouse, like in a real combobox
490 item, flags = self.seltree.HitTest(evt.GetPosition())
491 if item
and flags & wx.TREE_HITTEST_ONITEMLABEL:
492 self.seltree.SelectItem(item)
497 """!Do the combobox selection
499 item, flags = self.seltree.HitTest(evt.GetPosition())
500 if item
and flags & wx.TREE_HITTEST_ONITEMLABEL:
503 if self.seltree.GetRootItem() == self.seltree.GetItemParent(item):
507 mapsetItem = self.seltree.GetItemParent(item)
508 fullName = self.seltree.GetItemText(item)
510 fullName +=
'@' + self.seltree.GetItemText(mapsetItem).
split(
':', -1)[1].strip()
513 self.value.append(fullName)
517 self.
value = [fullName]
519 self.value.append(fullName)
521 self.
value = [fullName]
528 """!Set object properties"""
530 self.
type = kargs[
'type']
531 if 'mapsets' in kargs:
532 self.
mapsets = kargs[
'mapsets']
533 if 'multiple' in kargs:
536 self.
nmaps = kargs[
'nmaps']
537 if 'updateOnPopup' in kargs:
539 if 'onPopup' in kargs:
540 self.
onPopup = kargs[
'onPopup']
541 if 'fullyQualified' in kargs:
550 """!Class providing information about attribute tables
551 linked to a vector map"""
565 def _CheckDBConnection(self):
566 """!Check DB connection"""
567 nuldev = file(os.devnull,
'w+')
568 self.
layers = grass.vector_db(map=self.
map, stderr=nuldev)
571 if (len(self.layers.keys()) == 0):
576 def _DescribeTables(self):
577 """!Describe linked tables"""
578 for layer
in self.layers.keys():
580 table = self.
layers[layer][
"table"]
583 Debug.msg(1,
"gselect.VectorDBInfo._DescribeTables(): table=%s driver=%s database=%s" % \
584 (self.
layers[layer][
"table"], self.
layers[layer][
"driver"],
585 self.
layers[layer][
"database"]))
586 for item
in grass.db_describe(table = self.
layers[layer][
"table"],
587 driver = self.
layers[layer][
"driver"],
588 database = self.
layers[layer][
"database"])[
'cols']:
589 name, type, length = item
591 if type.lower() ==
"integer":
593 elif type.lower() ==
"double precision":
598 columns[name.strip()] = {
'index' : i,
599 'type' : type.lower(),
601 'length' : int(length),
608 if self.
layers[layer][
"key"]
not in columns.keys():
609 for col
in columns.keys():
610 if col.lower() == self.
layers[layer][
"key"]:
611 self.
layers[layer][
"key"] = col.upper()
614 self.
tables[table] = columns
621 table = self.
layers[layer][
"table"]
622 columns = self.
tables[table]
623 for name
in self.
tables[table].keys():
624 self.
tables[table][name][
'values'] = []
625 self.
tables[table][name][
'ids'] = []
628 """!Get vector name"""
632 """!Get key column of given layer
634 @param layer vector layer number
636 return str(self.
layers[layer][
'key'])
639 """!Get table name of given layer
641 @param layer vector layer number
643 return self.
layers[layer][
'table']
646 """!Get database settins
648 @param layer layer number
650 @return (driver, database)
652 return self.
layers[layer][
'driver'], self.
layers[layer][
'database']
655 """!Get table columns
657 @param table table name
662 """!Creates combo box for selecting data layers defined for vector.
665 id = wx.ID_ANY, pos = wx.DefaultPosition,
666 size = globalvar.DIALOG_LAYER_SIZE,
667 vector =
None, choices = [], initial = [], default =
None):
669 super(LayerSelect, self).
__init__(parent, id, pos=pos, size=size,
675 self.SetName(
"LayerSelect")
683 """!Insert layers for a vector into the layer combobox
685 @param vector name of vector map
699 layers.insert(0, str(self.
default))
700 elif self.
default not in layers:
704 self.SetItems(layers)
708 items = self.GetItems()
711 self.SetStringSelection(
'-1')
718 """!Creates combo box for selecting database driver.
720 def __init__(self, parent, choices, value,
721 id=wx.ID_ANY, pos=wx.DefaultPosition,
722 size=globalvar.DIALOG_LAYER_SIZE, **kargs):
724 super(DriverSelect, self).
__init__(parent, id, value, pos, size,
725 choices, style=wx.CB_READONLY)
727 self.SetName(
"DriverSelect")
729 self.SetStringSelection(value)
732 """!Creates combo box for selecting database driver.
734 def __init__(self, parent, value='',
735 id=wx.ID_ANY, pos=wx.DefaultPosition,
736 size=globalvar.DIALOG_TEXTCTRL_SIZE, **kargs):
738 super(DatabaseSelect, self).
__init__(parent, id, value, pos, size)
740 self.SetName(
"DatabaseSelect")
743 """!Creates combo box for selecting attribute tables from the database
746 id=wx.ID_ANY, value=
'', pos=wx.DefaultPosition,
747 size=globalvar.DIALOG_COMBOBOX_SIZE,
750 super(TableSelect, self).
__init__(parent, id, value, pos, size, choices,
751 style=wx.CB_READONLY)
753 self.SetName(
"TableSelect")
759 """!Insert attribute tables into combobox"""
762 if not driver
or not database:
763 connect = grass.db_connection()
765 driver = connect[
'driver']
766 database = connect[
'database']
775 for table
in ret.splitlines():
782 """!Creates combo box for selecting columns in the attribute table
785 @param parent window parent
787 @param value default value
788 @param size window size
789 @param vector vector map name
790 @param layer layer number
791 @param param parameters list (see menuform.py)
792 @param **kwags wx.ComboBox parameters
794 def __init__(self, parent, id = wx.ID_ANY, value = '',
795 size=globalvar.DIALOG_COMBOBOX_SIZE,
796 vector =
None, layer = 1, param =
None, **kwargs):
800 super(ColumnSelect, self).
__init__(parent, id, value, size = size, **kwargs)
801 self.SetName(
"ColumnSelect")
806 def InsertColumns(self, vector, layer, excludeKey = False, excludeCols = None, type = None, dbInfo = None):
807 """!Insert columns for a vector attribute table into the columns combobox
809 @param vector vector name
810 @param layer vector layer number
811 @param excludeKey exclude key column from the list?
812 @param excludeCols list of columns to be removed from the list
813 @param type only columns of given type (given as list)
819 table = dbInfo.GetTable(int(layer))
820 columnchoices = dbInfo.GetTableDesc(table)
821 keyColumn = dbInfo.GetKeyColumn(int(layer))
822 columns = len(columnchoices.keys()) * [
'']
823 for key, val
in columnchoices.iteritems():
824 columns[val[
'index']] = key
826 columns.remove(keyColumn)
828 for key
in columnchoices.iterkeys():
829 if key
in excludeCols:
832 for key, value
in columnchoices.iteritems():
833 if value[
'type']
not in type:
838 except (KeyError, ValueError):
841 self.SetItems(columns)
845 value = self.param.get(
'value',
'')
846 if value !=
'' and value
in columns:
850 """!Insert table columns
852 @param table table name
853 @param driver driver name
854 @param database database name
865 columns = ret.splitlines()
867 self.SetItems(columns)
871 value = self.param.get(
'value',
'')
872 if value !=
'' and value
in columns:
876 """!Widget for selecting GRASS Database"""
878 super(DbaseSelect, self).
__init__(parent, id = wx.ID_ANY,
879 size = globalvar.DIALOG_GSELECT_SIZE, labelText =
'',
880 dialogTitle = _(
'Choose GIS Data Directory'),
881 buttonText = _(
'Browse'),
882 startDirectory = grass.gisenv()[
'GISDBASE'],
886 """!Widget for selecting GRASS location"""
887 def __init__(self, parent, id = wx.ID_ANY, size = globalvar.DIALOG_COMBOBOX_SIZE,
888 gisdbase =
None, **kwargs):
889 super(LocationSelect, self).
__init__(parent, id, size = size,
890 style = wx.CB_READONLY, **kwargs)
891 self.SetName(
"LocationSelect")
901 """!Update list of locations
903 @param dbase path to GIS database
912 """!Widget for selecting GRASS mapset"""
913 def __init__(self, parent, id = wx.ID_ANY, size = globalvar.DIALOG_COMBOBOX_SIZE,
914 gisdbase =
None, location =
None, setItems =
True,
915 searchPath =
False, skipCurrent =
False, **kwargs):
916 super(MapsetSelect, self).
__init__(parent, id, size = size,
917 style = wx.CB_READONLY, **kwargs)
921 self.SetName(
"MapsetSelect")
936 """!Update list of mapsets for given location
938 @param dbase path to GIS database (None to use currently selected)
939 @param location name of location
949 def _getMapsets(self):
952 read =
True, flags =
'p',
953 fs =
'newline').splitlines()
958 gisenv = grass.gisenv()
960 gisenv[
'LOCATION_NAME'] == self.
location and \
961 gisenv[
'MAPSET']
in mlist:
962 mlist.remove(gisenv[
'MAPSET'])
967 """!Widget for selecting subgroups"""
968 def __init__(self, parent, id = wx.ID_ANY, size = globalvar.DIALOG_GSELECT_SIZE,
970 super(SubGroupSelect, self).
__init__(parent, id, size = size,
972 self.SetName(
"SubGroupSelect")
975 """!Insert subgroups for defined group"""
978 gisenv = grass.gisenv()
980 name, mapset = group.split(
'@', 1)
983 mapset = gisenv[
'MAPSET']
985 path = os.path.join(gisenv[
'GISDBASE'], gisenv[
'LOCATION_NAME'], mapset,
986 'group', name,
'subgroup')
988 self.SetItems(os.listdir(path))
994 def __init__(self, parent, ogr = False,
995 sourceType =
None, id = wx.ID_ANY, size = globalvar.DIALOG_COMBOBOX_SIZE,
997 """!Widget for selecting external (GDAL/OGR) format
999 @param parent parent window
1000 @param sourceType source type ('file', 'directory', 'database', 'protocol') or None
1001 @param ogr True for OGR otherwise GDAL
1003 super(FormatSelect, self).
__init__(parent, id, size = size,
1005 self.SetName(
"FormatSelect")
1015 self.SetItems(formats)
1018 """!Get file extension by format name"""
1022 'Erdas Imagine Images (.img)' :
'img',
1023 'Ground-based SAR Applications Testbed File Format (.gff)' :
'gff',
1024 'Arc/Info Binary Grid' :
'adf',
1025 'Portable Network Graphics' :
'png',
1026 'JPEG JFIF' :
'jpg',
1027 'Japanese DEM (.mem)' :
'mem',
1028 'Graphics Interchange Format (.gif)' :
'gif',
1029 'X11 PixMap Format' :
'xpm',
1030 'MS Windows Device Independent Bitmap' :
'bmp',
1031 'SPOT DIMAP' :
'dim',
1032 'RadarSat 2 XML Product' :
'xml',
1033 'EarthWatch .TIL' :
'til',
1034 'ERMapper .ers Labelled' :
'ers',
1035 'ERMapper Compressed Wavelets' :
'ecw',
1036 'GRIdded Binary (.grb)' :
'grb',
1037 'EUMETSAT Archive native (.nat)' :
'nat',
1038 'Idrisi Raster A.1' :
'rst',
1039 'Golden Software ASCII Grid (.grd)' :
'grd',
1040 'Golden Software Binary Grid (.grd)' :
'grd',
1041 'Golden Software 7 Binary Grid (.grd)' :
'grd',
1042 'R Object Data Store' :
'r',
1043 'USGS DOQ (Old Style)' :
'doq',
1044 'USGS DOQ (New Style)' :
'doq',
1045 'ENVI .hdr Labelled' :
'hdr',
1046 'ESRI .hdr Labelled' :
'hdr',
1047 'Generic Binary (.hdr Labelled)' :
'hdr',
1048 'PCI .aux Labelled' :
'aux',
1049 'EOSAT FAST Format' :
'fst',
1050 'VTP .bt (Binary Terrain) 1.3 Format' :
'bt',
1051 'FARSITE v.4 Landscape File (.lcp)' :
'lcp',
1052 'Swedish Grid RIK (.rik)' :
'rik',
1053 'USGS Optional ASCII DEM (and CDED)' :
'dem',
1054 'Northwood Numeric Grid Format .grd/.tab' :
'',
1055 'Northwood Classified Grid Format .grc/.tab' :
'',
1056 'ARC Digitized Raster Graphics' :
'arc',
1057 'Magellan topo (.blx)' :
'blx',
1058 'SAGA GIS Binary Grid (.sdat)' :
'sdat',
1060 'ESRI Shapefile' :
'shp',
1077 'Geoconcept' :
'gxt',
1079 'GPSTrackMaker' :
'gtm',
1084 return formatToExt[name]
1089 def __init__(self, parent, panel, ogr = False, link = False, dest = False,
1090 default =
'file', exclude = [], envHandler =
None):
1091 """!Widget for selecting GDAL/OGR datasource, format
1093 @param parent parent window
1094 @param ogr use OGR selector instead of GDAL
1095 @param dest True for output (destination)
1096 @param default deafult type (ignored when dest == True)
1097 @param exclude list of types to be excluded
1102 wx.Panel.__init__(self, parent = panel, id = wx.ID_ANY)
1105 label =
" %s " % _(
"Settings"))
1107 self.
inputBox = wx.StaticBox(parent = self, id = wx.ID_ANY)
1109 self.inputBox.SetLabel(
" %s " % _(
"Output settings"))
1111 self.inputBox.SetLabel(
" %s " % _(
"Source settings"))
1122 sources.append(_(
"Native"))
1125 if 'file' not in exclude:
1126 sources.append(_(
"File"))
1129 if 'directory' not in exclude:
1130 sources.append(_(
"Directory"))
1133 if 'database' not in exclude:
1134 sources.append(_(
"Database"))
1137 if 'protocol' not in exclude:
1138 sources.append(_(
"Protocol"))
1152 self.btnSettingsSave.SetToolTipString(_(
"Save current settings"))
1155 self.btnSettingsSave.SetToolTipString(_(
"Delete currently selected settings"))
1157 self.
source = wx.RadioBox(parent = self, id = wx.ID_ANY,
1158 style = wx.RA_SPECIFY_COLS,
1161 self.source.SetLabel(
" %s " % _(
'Output type'))
1163 self.source.SetLabel(
" %s " % _(
'Source type'))
1165 self.source.SetSelection(0)
1166 self.source.Bind(wx.EVT_RADIOBOX, self.
OnSetType)
1170 filemask =
'GeoTIFF (%s)|%s|%s (*.*)|*.*' % \
1173 filemask =
'ESRI Shapefile (%s)|%s|%s (*.*)|*.*' % \
1176 dsnFile = filebrowse.FileBrowseButton(parent=self, id=wx.ID_ANY,
1177 size=globalvar.DIALOG_GSELECT_SIZE, labelText =
'',
1178 dialogTitle=_(
'Choose file to import'),
1179 buttonText=_(
'Browse'),
1180 startDirectory=os.getcwd(),
1185 dsnDir = filebrowse.DirBrowseButton(parent=self, id=wx.ID_ANY,
1186 size=globalvar.DIALOG_GSELECT_SIZE, labelText=
'',
1187 dialogTitle=_(
'Choose input directory'),
1188 buttonText=_(
'Browse'),
1189 startDirectory=os.getcwd(),
1191 dsnDir.SetName(
'GdalSelect')
1194 dsnDbFile = filebrowse.FileBrowseButton(parent=self, id=wx.ID_ANY,
1195 size=globalvar.DIALOG_GSELECT_SIZE, labelText=
'',
1196 dialogTitle=_(
'Choose file'),
1197 buttonText=_(
'Browse'),
1198 startDirectory=os.getcwd(),
1201 dsnDbFile.SetName(
'GdalSelect')
1203 dsnDbText = wx.TextCtrl(parent = self, id = wx.ID_ANY)
1205 dsnDbText.Bind(wx.EVT_TEXT, self.
OnSetDsn)
1206 dsnDbText.SetName(
'GdalSelect')
1208 dsnDbChoice = wx.Choice(parent = self, id = wx.ID_ANY)
1210 dsnDbChoice.Bind(wx.EVT_CHOICE, self.
OnSetDsn)
1211 dsnDbChoice.SetName(
'GdalSelect')
1213 dsnPro = wx.TextCtrl(parent = self, id = wx.ID_ANY)
1215 dsnPro.Bind(wx.EVT_TEXT, self.
OnSetDsn)
1216 dsnPro.SetName(
'GdalSelect')
1224 self.extension.Hide()
1233 'dir' : [_(
"Name:"),
1239 'pro' : [_(
"Protocol:"),
1242 'db-win' : {
'file' : dsnDbFile,
1244 'choice' : dsnDbChoice },
1245 'native' : [_(
"Name:"), dsnDir,
''],
1251 read =
True, parse = grass.parse_key_val,
1253 if current[
'format'] ==
'native':
1255 elif current[
'format']
in GetFormats()[
'ogr'][
'database']:
1262 self.
dsnText = wx.StaticText(parent = self, id = wx.ID_ANY,
1266 label = _(
"Extension:"))
1267 self.extensionText.Hide()
1271 self.creationOpt.Hide()
1277 if current[
'format'] !=
'native':
1278 self.
OnSetFormat(event =
None, format = current[
'format'])
1279 self.
OnSetDsn(event =
None, path = current[
'dsn'])
1280 self.creationOpt.SetValue(current[
'options'])
1283 self.
OnSetFormat(event =
None, format =
'GeoTIFF')
1285 self.
OnSetFormat(event =
None, format =
'ESRI Shapefile')
1289 mainSizer = wx.BoxSizer(wx.VERTICAL)
1291 settingsSizer = wx.StaticBoxSizer(self.
settingsBox, wx.HORIZONTAL)
1292 settingsSizer.Add(item = wx.StaticText(parent = self,
1294 label = _(
"Load settings:")),
1295 flag = wx.ALIGN_CENTER_VERTICAL | wx.RIGHT,
1301 flag = wx.LEFT | wx.RIGHT,
1307 inputSizer = wx.StaticBoxSizer(self.
inputBox, wx.HORIZONTAL)
1312 self.dsnSizer.Add(item = wx.StaticText(parent = self, id = wx.ID_ANY,
1313 label = _(
"Format:")),
1314 flag = wx.ALIGN_CENTER_VERTICAL,
1316 self.dsnSizer.Add(item=self.
format,
1317 flag = wx.ALIGN_CENTER_VERTICAL,
1320 flag=wx.ALIGN_CENTER_VERTICAL,
1323 flag = wx.ALIGN_CENTER_VERTICAL,
1326 self.dsnSizer.Add(item = self.
dsnText,
1327 flag = wx.ALIGN_CENTER_VERTICAL,
1330 flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND,
1331 pos = (row, 1), span = (1, 3))
1333 if self.creationOpt.IsShown():
1334 self.dsnSizer.Add(item = wx.StaticText(parent = self, id = wx.ID_ANY,
1335 label = _(
"Creation options:")),
1336 flag = wx.ALIGN_CENTER_VERTICAL,
1339 flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND,
1340 pos = (row, 1), span = (1, 3))
1342 self.dsnSizer.AddGrowableCol(3)
1344 inputSizer.Add(item=self.
dsnSizer, proportion = 1,
1345 flag=wx.EXPAND | wx.BOTTOM, border = 10)
1347 mainSizer.Add(item=settingsSizer, proportion=0,
1348 flag=wx.ALL | wx.EXPAND, border=5)
1349 mainSizer.Add(item=self.
source, proportion=0,
1350 flag=wx.LEFT | wx.RIGHT | wx.EXPAND, border=5)
1351 mainSizer.Add(item=inputSizer, proportion=0,
1352 flag=wx.ALL | wx.EXPAND, border=5)
1354 self.SetSizer(mainSizer)
1357 def _getExtPatternGlob(self, ext):
1358 """!Get pattern for case-insensitive globing"""
1361 pattern +=
'[%s%s]' % (c.lower(), c.upper())
1364 def _getExtPattern(self, ext):
1365 """!Get pattern for case-insensitive file mask"""
1366 return '*.%s;*.%s' % (ext.lower(), ext.upper())
1369 """!Load named settings"""
1370 name = event.GetString()
1372 GError(parent = self,
1373 message = _(
"Settings <%s> not found") % name)
1378 self.
OnSetDsn(event =
None, path = data[1])
1379 self.creationOpt.SetValue(data[3])
1382 """!Save settings"""
1383 dlg = wx.TextEntryDialog(parent = self,
1384 message = _(
"Name:"),
1385 caption = _(
"Save settings"))
1386 if dlg.ShowModal() != wx.ID_OK:
1390 if not dlg.GetValue():
1391 GMessage(parent = self,
1392 message = _(
"Name not given, settings is not saved."))
1396 GMessage(parent = self,
1397 message = _(
"No data source defined, settings is not saved."))
1400 name = dlg.GetValue()
1404 dlgOwt = wx.MessageDialog(self, message = _(
"Settings <%s> already exists. "
1405 "Do you want to overwrite the settings?") % name,
1406 caption = _(
"Save settings"), style = wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
1407 if dlgOwt.ShowModal() != wx.ID_YES:
1412 self.format.GetStringSelection(),
1413 self.creationOpt.GetValue())
1417 self.settingsChoice.SetStringSelection(name)
1422 """!Save settings"""
1423 name = self.settingsChoice.GetStringSelection()
1425 GMessage(parent = self,
1426 message = _(
"No settings is defined. Operation canceled."))
1429 self._settings.pop(name)
1433 def _saveSettings(self):
1434 """!Save settings into the file
1436 @return 0 on success
1437 @return -1 on failure
1441 for key, value
in self._settings.iteritems():
1442 fd.write(
'%s;%s;%s;%s\n' % (key, value[0], value[1], value[2]))
1444 GError(parent = self,
1445 message = _(
"Unable to save settings"))
1452 def _loadSettings(self):
1453 """!Load settings from the file
1455 The file is defined by self.SettingsFile.
1458 @return empty dict on error
1466 for line
in fd.readlines():
1468 lineData = line.rstrip(
'\n').
split(
';')
1469 if len(lineData) > 4:
1471 data[lineData[0]] = (lineData[1], lineData[2], lineData[3], lineData[4])
1473 data[lineData[0]] = (lineData[1], lineData[2], lineData[3],
'')
1481 self.settingsChoice.SetItems(sorted(data.keys()))
1486 """!Datasource type changed.
1488 @todo improve showing/hiding widgets
1491 sel = event.GetSelection()
1493 self.source.SetSelection(sel)
1496 self.dsnSizer.Detach(win)
1506 ext = self.format.GetExtension(format)
1509 format +=
' (%s)|%s|%s (*.*)|*.*' % \
1512 format +=
'%s (*.*)|*.*' % _(
'All files')
1514 win = filebrowse.FileBrowseButton(parent=self, id=wx.ID_ANY,
1515 size=globalvar.DIALOG_GSELECT_SIZE, labelText=
'',
1516 dialogTitle=_(
'Choose file to import'),
1517 buttonText=_(
'Browse'),
1518 startDirectory=os.getcwd(),
1537 flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND,
1538 pos = (1, 1), span = (1, 3))
1544 self.format.Enable(
False)
1545 self.creationOpt.Enable(
False)
1546 self.parent.btnOk.Enable(
True)
1548 if not win.IsEnabled():
1550 if not self.format.IsEnabled():
1551 self.format.Enable(
True)
1552 self.creationOpt.Enable(
True)
1555 if self.parent.GetName() ==
'MultiImportDialog':
1556 self.parent.list.DeleteAllItems()
1560 self.
OnSetFormat(event =
None, format =
'GeoTIFF')
1562 self.
OnSetFormat(event =
None, format =
'ESRI Shapefile')
1565 if not self.extension.IsShown():
1566 self.extensionText.Show()
1567 self.extension.Show()
1569 if self.extension.IsShown():
1570 self.extensionText.Hide()
1571 self.extension.Hide()
1573 self.dsnSizer.Layout()
1576 """!Get datasource name
1578 if self.format.GetStringSelection() ==
'PostgreSQL':
1579 dsn =
'PG:dbname=%s' % self.
input[self.
dsnType][1].GetStringSelection()
1586 """!Input DXF file/OGR dsn defined, update list of layer
1589 path = event.GetString()
1591 if self.format.GetStringSelection() ==
'PostgreSQL':
1592 for item
in path.split(
':', 1)[1].
split(
','):
1593 key, value = item.split(
'=', 1)
1595 if not self.
input[self.
dsnType][1].SetStringSelection(value):
1596 GMessage(_(
"Database <%s> not accessible.") % value,
1604 self.parent.btnOk.Enable(
False)
1608 self.parent.btnOk.Enable(
True)
1615 def _reloadLayers(self):
1616 """!Reload list of layers"""
1631 self.parent.list.LoadData()
1632 if hasattr(self,
"btn_run"):
1633 self.btn_run.Enable(
False)
1637 for line
in ret.split(
','):
1638 layerName = line.strip()
1640 data.append((layerId, layerName, grassName))
1644 baseName = os.path.basename(dsn)
1646 data.append((layerId, baseName, grassName))
1648 ext = self.extension.GetValue()
1650 baseName = os.path.basename(filename)
1652 data.append((layerId, baseName, grassName))
1657 evt = wxGdalSelect(dsn = dsn)
1659 wx.PostEvent(self.
parent, evt)
1661 if self.parent.GetName() ==
'MultiImportDialog':
1662 self.parent.list.LoadData(data)
1664 self.parent.btn_run.Enable(
True)
1666 self.parent.btn_run.Enable(
False)
1669 """!Extension changed"""
1675 """!Format changed"""
1676 if self.
dsnType not in [
'file',
'dir',
'db']:
1680 self.dsnSizer.Detach(win)
1688 format = event.GetString()
1690 self.format.SetStringSelection(format)
1694 ext = self.format.GetExtension(format)
1697 format +=
' (%s)|%s|%s (*.*)|*.*' % \
1700 format +=
'%s (*.*)|*.*' % _(
'All files')
1702 win = filebrowse.FileBrowseButton(parent=self, id=wx.ID_ANY,
1703 size=globalvar.DIALOG_GSELECT_SIZE, labelText=
'',
1704 dialogTitle=_(
'Choose file'),
1705 buttonText=_(
'Browse'),
1706 startDirectory=os.getcwd(),
1714 if format ==
'SQLite' or format ==
'Rasterlite':
1715 win = self.
input[
'db-win'][
'file']
1716 elif format ==
'PostgreSQL' or format ==
'PostGIS WKT Raster driver':
1717 if grass.find_program(
'psql', [
'--help']):
1718 win = self.
input[
'db-win'][
'choice']
1719 if not win.GetItems():
1720 p = grass.Popen([
'psql',
'-ltA'], stdout = grass.PIPE)
1721 ret = p.communicate()[0]
1724 for line
in ret.splitlines():
1725 sline = line.split(
'|')
1732 if self.
dest and win.GetStringSelection():
1733 self.parent.btnOk.Enable(
True)
1735 win = self.
input[
'db-win'][
'text']
1737 win = self.
input[
'db-win'][
'text']
1740 if not win.IsShown():
1743 flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND,
1744 pos = (1, 1), span = (1, 3))
1745 self.dsnSizer.Layout()
1755 """!Get source type"""
1759 """!Get list of DSN windows"""
1761 for stype
in (
'file',
'dir',
'pro'):
1762 win.append(self.
input[stype][1])
1763 for stype
in (
'file',
'text',
'choice'):
1764 win.append(self.
input[
'db-win'][stype])
1769 """!Get format as string"""
1770 return self.format.GetStringSelection().replace(
' ',
'_')
1773 """!Get format extension"""
1774 return self.format.GetExtension(self.format.GetStringSelection())
1777 """!Get creation options"""
1778 if not self.creationOpt.IsShown():
1781 return self.creationOpt.GetValue()
1784 """!Widget for selecting input raster/vector map used by
1785 r.proj/v.proj modules."""
1786 def __init__(self, parent, isRaster, id = wx.ID_ANY, size = globalvar.DIALOG_COMBOBOX_SIZE,
1788 super(ProjSelect, self).
__init__(parent, id, size = size,
1789 style = wx.CB_READONLY, **kwargs)
1790 self.SetName(
"ProjSelect")
1794 """!Update list of maps
1798 dbase = grass.gisenv()[
'GISDBASE']
1800 mapset = grass.gisenv()[
'MAPSET']
1807 location = location,
1815 location = location,
1819 for line
in ret.splitlines():
1820 listMaps.append(line.strip())
1823 self.SetItems(listMaps)
1827 def __init__(self, parent, id = wx.ID_ANY, size = globalvar.DIALOG_COMBOBOX_SIZE,
1829 """!Widget for selecting GIS element
1831 @param parent parent window
1833 super(ElementSelect, self).
__init__(parent, id, size = size,
1835 self.SetName(
"ElementSelect")
1837 task = gtask.parse_interface(
'g.list')
1838 p = task.get_param(value =
'type')
1841 self.SetItems(self.
values)
1846 @param name element name
def InsertTableColumns
Insert table columns.
def GetListOfLocations
Get list of GRASS locations in given dbase.
def SetElementList
Set element list.
def __init__
Custom to create a ComboBox with a tree control to display and select vector maps.
def GetFormat
Get format as string.
def GetDbSettings
Get database settins.
def GetSettingsPath
Get full path to the settings directory.
def __init__
Custom control to create a ComboBox with a tree control to display and select GIS elements within ace...
def UpdateItems
Update list of locations.
def GetDsnWin
Get list of DSN windows.
Creates combo box for selecting data layers defined for vector.
def _saveSettings
Save settings into the file.
def _reloadLayers
Reload list of layers.
def GetDsn
Get datasource name.
def GetElementList
Load elements.
def GetListOfMapsets
Get list of mapsets in given GRASS location.
def _CheckDBConnection
Check DB connection.
def GetTableDesc
Get table columns.
def OnSetDsn
Input DXF file/OGR dsn defined, update list of layer widget.
def __init__
Widget for selecting GDAL/OGR datasource, format.
def OnSettingsDelete
Save settings.
def SetType
Param set element type for widget.
def _DescribeTables
Describe linked tables.
def _loadSettings
Load settings from the file.
def Insert
Insert subgroups for defined group.
def split
Platform spefic shlex.split.
def GetFormats
Get GDAL/OGR formats.
def OnSetFormat
Format changed.
Widget for selecting input raster/vector map used by r.proj/v.proj modules.
def UpdateItems
Update list of mapsets for given location.
Creates combo box for selecting attribute tables from the database.
Widget for selecting GRASS Database.
Creates combo box for selecting database driver.
def OnSetExtension
Extension changed.
def InsertTables
Insert attribute tables into combobox.
def GetKeyColumn
Get key column of given layer.
def _isElement
Check if element should be filtered out.
def GetTable
Get table name of given layer.
def GetValue
Translate value.
def _getExtPatternGlob
Get pattern for case-insensitive globing.
Widget for selecting GRASS location.
def ListSortLower
Sort list items (not case-sensitive)
def GetValidLayerName
Make layer name SQL compliant, based on G_str_to_sql()
def OnSettingsLoad
Load named settings.
def OnSetType
Datasource type changed.
def InsertLayers
Insert layers for a vector into the layer combobox.
def OnSettingsSave
Save settings.
Widget for selecting GRASS mapset.
Widget for selecting subgroups.
def _getExtPattern
Get pattern for case-insensitive file mask.
Creates combo box for selecting columns in the attribute table for a vector map.
Misc utilities for wxGUI.
Creates combo box for selecting database driver.
def GetAllVectorLayers
Returns list of all vector layers as strings.
def GetOptions
Get creation options.
def InsertColumns
Insert columns for a vector attribute table into the columns combobox.
def __init__
Widget for selecting GIS element.
Class providing information about attribute tables linked to a vector map.
def GetName
Get vector name.
def UpdateItems
Update list of maps.
def GetFormatExt
Get format extension.
def OnKeyUp
Shows popupwindow if down arrow key is released.
def GetType
Get source type.
def RunCommand
Run GRASS command.