[GRASS-SVN] r55651 - in grass/trunk: gui/wxpython/gui_core scripts/v.db.join
svn_grass at osgeo.org
svn_grass at osgeo.org
Sun Apr 7 02:23:04 PDT 2013
Author: turek
Date: 2013-04-07 02:23:04 -0700 (Sun, 07 Apr 2013)
New Revision: 55651
Modified:
grass/trunk/gui/wxpython/gui_core/forms.py
grass/trunk/gui/wxpython/gui_core/gselect.py
grass/trunk/scripts/v.db.join/v.db.join.py
Log:
gselect: added new widget ListCtrlComboPopup for multiple selection, v.db.join: added scolumns parameter using the widget
Modified: grass/trunk/gui/wxpython/gui_core/forms.py
===================================================================
--- grass/trunk/gui/wxpython/gui_core/forms.py 2013-04-06 20:43:23 UTC (rev 55650)
+++ grass/trunk/gui/wxpython/gui_core/forms.py 2013-04-07 09:23:04 UTC (rev 55651)
@@ -276,15 +276,15 @@
if map in cparams:
if not cparams[map]['dbInfo']:
cparams[map]['dbInfo'] = gselect.VectorDBInfo(map)
- self.data[win.InsertColumns] = { 'vector' : map, 'layer' : layer,
- 'dbInfo' : cparams[map]['dbInfo'] }
+ self.data[win.GetParent().InsertColumns] = { 'vector' : map, 'layer' : layer,
+ 'dbInfo' : cparams[map]['dbInfo'] }
else: # table
if driver and db:
- self.data[win.InsertTableColumns] = { 'table' : pTable.get('value'),
- 'driver' : driver,
- 'database' : db }
+ self.data[win.GetParent().InsertTableColumns] = { 'table' : pTable.get('value'),
+ 'driver' : driver,
+ 'database' : db }
elif pTable:
- self.data[win.InsertTableColumns] = { 'table' : pTable.get('value') }
+ self.data[win.GetParent().InsertTableColumns] = { 'table' : pTable.get('value') }
elif name == 'SubGroupSelect':
self.data[win.Insert] = { 'group' : p.get('value', '')}
@@ -1179,7 +1179,7 @@
selection.SetValue(value)
formatSelector = True
- # A select.Select is a combobox with two children: a textctl and a popupwindow;
+ # A gselect.Select is a combobox with two children: a textctl and a popupwindow;
# we target the textctl here
textWin = selection.GetTextCtrl()
p['wxId'] = [ textWin.GetId(), ]
@@ -1317,9 +1317,16 @@
elif prompt == 'dbcolumn':
win = gselect.ColumnSelect(parent = which_panel,
value = value,
- param = p)
- win.Bind(wx.EVT_COMBOBOX, self.OnSetValue)
- win.Bind(wx.EVT_TEXT, self.OnSetValue)
+ param = p,
+ multiple = p.get('multiple', False))
+
+ # A gselect.ColumnSelect is a combobox with two children: a textctl and a popupwindow;
+ # we target the textctl here
+ textWin = win.GetTextCtrl()
+ p['wxId'] = [ textWin.GetId(), ]
+
+ textWin.Bind(wx.EVT_TEXT, self.OnSetValue)
+ win.Bind(wx.EVT_TEXT, self.OnUpdateSelection)
elif prompt == 'location':
win = gselect.LocationSelect(parent = which_panel,
Modified: grass/trunk/gui/wxpython/gui_core/gselect.py
===================================================================
--- grass/trunk/gui/wxpython/gui_core/gselect.py 2013-04-06 20:43:23 UTC (rev 55650)
+++ grass/trunk/gui/wxpython/gui_core/gselect.py 2013-04-07 09:23:04 UTC (rev 55651)
@@ -6,6 +6,7 @@
Classes:
- gselect::Select
- gselect::VectorSelect
+ - gselect::ListCtrlComboPopup
- gselect::TreeCrtlComboPopup
- gselect::VectorDBInfo
- gselect::LayerSelect
@@ -25,7 +26,7 @@
- gselect::CoordinatesSelect
- gselect::SignatureSelect
-(C) 2007-2012 by the GRASS Development Team
+(C) 2007-2013 by the GRASS Development Team
This program is free software under the GNU General Public License
(>=v2). Read the file COPYING that comes with GRASS for details.
@@ -33,7 +34,7 @@
@author Michael Barton
@author Martin Landa <landa.martin gmail.com>
@author Vaclav Petras <wenzeslaus gmail.com> (menu customization)
- at author Stepan Turek <stepan.turek seznam.cz> (CoordinatesSelect)
+ at author Stepan Turek <stepan.turek seznam.cz> (CoordinatesSelect, ListCtrlComboPopup)
"""
import os
@@ -153,25 +154,16 @@
return True
-class TreeCtrlComboPopup(wx.combo.ComboPopup):
- """!Create a tree ComboBox for selecting maps and other GIS elements
- in accessible mapsets within the current location
- """
+class ListCtrlComboPopup(wx.combo.ComboPopup):
+ """!Create a list ComboBox using TreeCtrl with hidden root.
+ """
# overridden ComboPopup methods
def Init(self):
self.value = [] # for multiple is False -> len(self.value) in [0,1]
self.curitem = None
self.multiple = False
- self.nmaps = 1
- self.type = None
- self.mapsets = None
self.updateOnPopup = True
- self.onPopup = None
- self.fullyQualified = True
- self.extraItems = dict()
-
- self.SetFilter(None)
-
+
def Create(self, parent):
self.seltree = wx.TreeCtrl(parent, style=wx.TR_HIDE_ROOT
|wx.TR_HAS_BUTTONS
@@ -181,24 +173,24 @@
|wx.TR_FULL_ROW_HIGHLIGHT)
self.seltree.Bind(wx.EVT_MOTION, self.OnMotion)
self.seltree.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
- self.seltree.Bind(wx.EVT_TREE_ITEM_EXPANDING, self.mapsetExpanded)
- self.seltree.Bind(wx.EVT_TREE_ITEM_COLLAPSED, self.mapsetCollapsed)
- self.seltree.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.mapsetActivated)
- self.seltree.Bind(wx.EVT_TREE_SEL_CHANGED, self.mapsetSelected)
+ self.seltree.Bind(wx.EVT_TREE_ITEM_EXPANDING, self.OnExpanded)
+ self.seltree.Bind(wx.EVT_TREE_ITEM_COLLAPSED, self.OnCollapsed)
+ self.seltree.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnActivated)
+ self.seltree.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnSelected)
self.seltree.Bind(wx.EVT_TREE_DELETE_ITEM, lambda x: None)
# the following dummy handler are needed to keep tree events from propagating up to
# the parent GIS Manager layer tree
- def mapsetExpanded(self, event):
+ def OnExpanded(self, event):
pass
- def mapsetCollapsed(self, event):
+ def OnCollapsed(self, event):
pass
- def mapsetActivated(self, event):
+ def OnActivated(self, event):
pass
- def mapsetSelected(self, event):
+ def OnSelected(self, event):
pass
# end of dummy events
@@ -206,8 +198,140 @@
return self.seltree
def GetStringValue(self):
- """!Get value as a string separated by commas"""
+ """!Get value as a string separated by commas
+ """
return ','.join(self.value)
+
+ def SetStringValue(self, value):
+ # this assumes that item strings are unique...
+ root = self.seltree.GetRootItem()
+ if not root:
+ return
+ winValue = self.GetCombo().GetValue().strip(',')
+ self.value = []
+ if winValue:
+ self.value = winValue.split(',')
+
+ def OnPopup(self, force = False):
+ """!Limited only for first selected
+ """
+ if not force and not self.updateOnPopup:
+ return
+
+ # selects map starting according to written text
+ inputText = self.GetCombo().GetValue().strip()
+ if inputText:
+ root = self.seltree.GetRootItem()
+ match = self.FindItem(root, inputText, startLetters = True)
+ self.seltree.EnsureVisible(match)
+ self.seltree.SelectItem(match)
+
+ def GetAdjustedSize(self, minWidth, prefHeight, maxHeight):
+ """!Reads UserSettings to get height (which was 200 in old implementation).
+ """
+ height = UserSettings.Get(group = 'appearance', key = 'gSelectPopupHeight', subkey = 'value')
+ return wx.Size(minWidth, min(height, maxHeight))
+
+ def FindItem(self, parentItem, text, startLetters = False):
+ """!Finds item with given name or starting with given text
+ """
+ startletters = startLetters
+ item, cookie = self.seltree.GetFirstChild(parentItem)
+ while wx.TreeItemId.IsOk(item):
+ if self.seltree.GetItemText(item) == text:
+ return item
+ if self.seltree.ItemHasChildren(item):
+ item = self.FindItem(item, text, startLetters = startletters)
+ if wx.TreeItemId.IsOk(item):
+ return item
+ elif startletters and self.seltree.GetItemText(item).startswith(text.split('@', 1)[0]):
+ return item
+ item, cookie = self.seltree.GetNextChild(parentItem, cookie)
+ return wx.TreeItemId()
+
+ def AddItem(self, value):
+ root = self.seltree.GetRootItem()
+ if not root:
+ root = self.seltree.AddRoot("<hidden root>")
+ self.seltree.AppendItem(root, text = value)
+
+ def OnKeyUp(self, event):
+ """!Enable to select items using keyboard
+ """
+ item = self.seltree.GetSelection()
+ if event.GetKeyCode() == wx.WXK_DOWN:
+ self.seltree.SelectItem(self.seltree.GetNextVisible(item))
+
+ elif event.GetKeyCode() == wx.WXK_UP:
+ itemPrev = self.seltree.GetPrevSibling(item)
+ self.seltree.SelectItem(itemPrev)
+
+ elif event.GetKeyCode() == wx.WXK_ESCAPE:
+ self.Dismiss()
+
+ elif event.GetKeyCode() == wx.WXK_RETURN:
+ self.seltree.SelectItem(item)
+ self.curitem = item
+ item_str = self.seltree.GetItemText(self.curitem)
+ if self.multiple:
+ if item_str not in self.value:
+ self.value.append(item_str)
+ else:
+ self.value = [item_str]
+ self.Dismiss()
+
+ def OnMotion(self, evt):
+ """!Have the selection follow the mouse, like in a real combobox
+ """
+ item, flags = self.seltree.HitTest(evt.GetPosition())
+ if item and flags & wx.TREE_HITTEST_ONITEMLABEL:
+ self.seltree.SelectItem(item)
+ self.curitem = item
+ evt.Skip()
+
+ def OnLeftDown(self, evt):
+ """!Do the combobox selection
+ """
+ if self.curitem is None:
+ return
+
+ item_str = self.seltree.GetItemText(self.curitem)
+ if self.multiple:
+ if item_str not in self.value:
+ self.value.append(item_str)
+ else:
+ self.value = [item_str]
+ self.Dismiss()
+
+ evt.Skip()
+
+ def SetData(self, **kargs):
+ """!Set object properties"""
+ if 'multiple' in kargs:
+ self.multiple = kargs['multiple']
+ if 'onPopup' in kargs:
+ self.onPopup = kargs['onPopup']
+
+ def DeleteAllItems(self):
+ """!Delete all items in popup"""
+ self.seltree.DeleteAllItems()
+
+class TreeCtrlComboPopup(ListCtrlComboPopup):
+ """!Create a tree ComboBox for selecting maps and other GIS elements
+ in accessible mapsets within the current location
+ """
+ # overridden ComboPopup methods
+ def Init(self):
+
+ ListCtrlComboPopup.Init(self)
+ self.nmaps = 1
+ self.type = None
+ self.mapsets = None
+ self.onPopup = None
+ self.fullyQualified = True
+ self.extraItems = dict()
+
+ self.SetFilter(None)
def SetFilter(self, filter):
"""!Set filter for GIS elements, see e.g. VectorSelect"""
@@ -225,14 +349,7 @@
self.GetElementList(selected, exclude)
- # selects map starting according to written text
- inputText = self.GetCombo().GetValue().strip()
- if inputText:
- root = self.seltree.GetRootItem()
- match = self.FindItem(root, inputText, startLetters = True)
- self.seltree.EnsureVisible(match)
- self.seltree.SelectItem(match)
-
+ ListCtrlComboPopup.OnPopup(self, force)
def GetElementList(self, elements = None, exclude = False):
"""!Get filtered list of GIS elements in accessible mapsets
@@ -253,23 +370,7 @@
self.seltree.SelectItem(item)
except:
pass
-
- def SetStringValue(self, value):
- # this assumes that item strings are unique...
- root = self.seltree.GetRootItem()
- if not root:
- return
- winValue = self.GetCombo().GetValue().strip(',')
- self.value = []
- if winValue:
- self.value = winValue.split(',')
-
- def GetAdjustedSize(self, minWidth, prefHeight, maxHeight):
- """!Reads UserSettings to get height (which was 200 in old implementation).
- """
- height = UserSettings.Get(group = 'appearance', key = 'gSelectPopupHeight', subkey = 'value')
- return wx.Size(minWidth, min(height, maxHeight))
-
+
def _getElementList(self, element, mapsets = None, elements = None, exclude = False):
"""!Get list of GIS elements in accessible mapsets and display as tree
with all relevant elements displayed beneath each mapset branch
@@ -444,22 +545,6 @@
self.AddItem(elem, mapset = mapset, node = False, parent = node)
else:
self.AddItem(elem, mapset = mapset, node = False, parent = node)
-
- def FindItem(self, parentItem, text, startLetters = False):
- """!Finds item with given name or starting with given text"""
- startletters = startLetters
- item, cookie = self.seltree.GetFirstChild(parentItem)
- while wx.TreeItemId.IsOk(item):
- if self.seltree.GetItemText(item) == text:
- return item
- if self.seltree.ItemHasChildren(item):
- item = self.FindItem(item, text, startLetters = startletters)
- if wx.TreeItemId.IsOk(item):
- return item
- elif startletters and self.seltree.GetItemText(item).startswith(text.split('@', 1)[0]):
- return item
- item, cookie = self.seltree.GetNextChild(parentItem, cookie)
- return wx.TreeItemId()
def AddItem(self, value, mapset = None, node = True, parent = None):
if not parent:
@@ -537,16 +622,7 @@
self.value = [fullName]
self.Dismiss()
-
- def OnMotion(self, evt):
- """!Have the selection follow the mouse, like in a real combobox
- """
- item, flags = self.seltree.HitTest(evt.GetPosition())
- if item and flags & wx.TREE_HITTEST_ONITEMLABEL:
- self.seltree.SelectItem(item)
- self.curitem = item
- evt.Skip()
-
+
def OnLeftDown(self, evt):
"""!Do the combobox selection
"""
@@ -579,20 +655,17 @@
def SetData(self, **kargs):
"""!Set object properties"""
+ ListCtrlComboPopup.SetData(self, **kargs)
if 'type' in kargs:
self.type = kargs['type']
if self.type in ('stds', 'strds', 'str3ds', 'stvds'):
tgis.init()
if 'mapsets' in kargs:
self.mapsets = kargs['mapsets']
- if 'multiple' in kargs:
- self.multiple = kargs['multiple']
if 'nmaps' in kargs:
self.nmaps = kargs['nmaps']
if 'updateOnPopup' in kargs:
self.updateOnPopup = kargs['updateOnPopup']
- if 'onPopup' in kargs:
- self.onPopup = kargs['onPopup']
if 'fullyQualified' in kargs:
self.fullyQualified = kargs['fullyQualified']
if 'extraItems' in kargs:
@@ -602,7 +675,7 @@
"""!Get element type
"""
return self.type
-
+
class VectorDBInfo:
"""!Class providing information about attribute tables
linked to a vector map"""
@@ -836,8 +909,8 @@
self.SetItems(items)
self.SetValue('')
-
-class ColumnSelect(wx.ComboBox):
+
+class ColumnSelect(wx.combo.ComboCtrl):
"""!Creates combo box for selecting columns in the attribute table
for a vector map.
@@ -847,21 +920,36 @@
@param size window size
@param vector vector map name
@param layer layer number
+ @param multiple - True if it is possible to add multiple columns
@param param parameters list (see menuform.py)
@param **kwags wx.ComboBox parameters
"""
def __init__(self, parent, id = wx.ID_ANY, value = '',
size = globalvar.DIALOG_COMBOBOX_SIZE,
- vector = None, layer = 1, param = None, **kwargs):
+ vector = None, layer = 1, multiple = False,
+ param = None, **kwargs):
self.defaultValue = value
self.param = param
- super(ColumnSelect, self).__init__(parent, id, value, size = size, **kwargs)
- self.SetName("ColumnSelect")
-
+ wx.combo.ComboCtrl.__init__(self, parent, id, size = size, **kwargs)
+ self.GetChildren()[0].SetName("ColumnSelect")
+ self.GetChildren()[0].type = type
+
+ self.tcp = ListCtrlComboPopup()
+ self.SetPopupControl(self.tcp)
+ self.tcp.SetData(multiple = multiple)
+
if vector:
self.InsertColumns(vector, layer)
-
+ self.GetChildren()[0].Bind(wx.EVT_KEY_UP, self.OnKeyUp)
+
+ def OnKeyUp(self, event):
+ """!Shows popupwindow if down arrow key is released"""
+ if event.GetKeyCode() == wx.WXK_DOWN and not self.IsPopupShown():
+ self.ShowPopup()
+ else:
+ event.Skip()
+
def InsertColumns(self, vector, layer, excludeKey = False, excludeCols = None, type = None, dbInfo = None):
"""!Insert columns for a vector attribute table into the columns combobox
@@ -896,8 +984,12 @@
pass
except (KeyError, ValueError):
columns = list()
-
- self.SetItems(columns)
+
+ # update list
+ self.tcp.DeleteAllItems()
+ for col in columns:
+ self.tcp.AddItem(col)
+
self.SetValue(self.defaultValue)
if self.param:
@@ -923,9 +1015,12 @@
if ret:
columns = ret.splitlines()
- self.SetItems(columns)
+ # update list
+ self.tcp.DeleteAllItems()
self.SetValue(self.defaultValue)
+ for col in columns:
+ self.tcp.AddItem(col)
if self.param:
value = self.param.get('value', '')
if value != '' and value in columns:
Modified: grass/trunk/scripts/v.db.join/v.db.join.py
===================================================================
--- grass/trunk/scripts/v.db.join/v.db.join.py 2013-04-06 20:43:23 UTC (rev 55650)
+++ grass/trunk/scripts/v.db.join/v.db.join.py 2013-04-07 09:23:04 UTC (rev 55651)
@@ -40,7 +40,7 @@
#% key: otable
#% description: Other table name
#% required: yes
-#% guidependency: ocolumn
+#% guidependency: ocolumn,scolumns
#%end
#%option G_OPT_DB_COLUMN
@@ -49,6 +49,13 @@
#% required: yes
#%end
+#%option G_OPT_DB_COLUMN
+#% key: scolumns
+#% multiple: yes
+#% required: no
+#% description: Subset of columns from the other table
+#%end
+
import sys
import os
import string
@@ -60,12 +67,16 @@
column = options['column']
otable = options['otable']
ocolumn = options['ocolumn']
-
+ if options['scolumns']:
+ scolumns = options['scolumns'].split(',')
+ else:
+ scolumns = None
+
f = grass.vector_layer_db(map, layer)
maptable = f['table']
database = f['database']
- driver = f['driver']
+ driver = f['driver']
if driver == 'dbf':
grass.fatal(_("JOIN is not supported for tables stored in DBF format"))
@@ -73,17 +84,41 @@
if not maptable:
grass.fatal(_("There is no table connected to this map. Unable to join any column."))
+ # check if column is in map table
if not grass.vector_columns(map, layer).has_key(column):
- grass.fatal(_("Column <%s> not found in table <%s> at layer <%s>") % (column, map, layer))
+ grass.fatal(_("Column <%s> not found in table <%s>") % (column, maptable))
+ # describe other table
all_cols_ot = grass.db_describe(otable, driver = driver, database = database)['cols']
+
+ # check if ocolumn is on other table
+ if ocolumn not in [ocol[0] for ocol in all_cols_ot]:
+ grass.fatal(_("Column <%s> not found in table <%s>") % (ocolumn, otable))
+
+ # determine columns subset from other table
+ if not scolumns:
+ # select all columns from other table
+ cols_to_add = all_cols_ot
+ else:
+ cols_to_add = []
+ # check if scolumns exists in the other table
+ for scol in scolumns:
+ found = False
+ for col_ot in all_cols_ot:
+ if scol == col_ot[0]:
+ found = True
+ cols_to_add.append(col_ot)
+ break
+ if not found:
+ grass.warning(_("Column <%s> not found in table <%s>.") % (scol, otable))
+
all_cols_tt = grass.vector_columns(map, int(layer)).keys()
select = "SELECT $colname FROM $otable WHERE $otable.$ocolumn=$table.$column"
template = string.Template("UPDATE $table SET $colname=(%s);" % select)
- for col in all_cols_ot:
- # Skip the vector column which is used for join
+ for col in cols_to_add:
+ # skip the vector column which is used for join
colname = col[0]
if colname == column:
continue
@@ -95,7 +130,7 @@
colspec = "%s %s" % (colname, coltype)
- # Add only the new column to the table
+ # add only the new column to the table
if colname not in all_cols_tt:
if grass.run_command('v.db.addcolumn', map = map, columns = colspec, layer = layer) != 0:
grass.fatal(_("Error creating column <%s>") % colname)
@@ -103,14 +138,15 @@
stmt = template.substitute(table = maptable, column = column,
otable = otable, ocolumn = ocolumn,
colname = colname)
-
+ grass.debug(stmt, 1)
grass.verbose(_("Updating column <%s> of vector map <%s>...") % (colname, map))
if grass.write_command('db.execute', stdin = stmt, input = '-', database = database, driver = driver) != 0:
grass.fatal(_("Error filling column <%s>") % colname)
- # write cmd history:
+ # write cmd history
grass.vector_history(map)
+ return 0
if __name__ == "__main__":
options, flags = grass.parser()
- main()
+ sys.exit(main())
More information about the grass-commit
mailing list