4 @brief DBM-related dialogs
7 - dialogs::DisplayAttributesDialog
8 - dialogs::ModifyTableRecord
10 (C) 2007-2011 by the GRASS Development Team
12 This program is free software under the GNU General Public License
13 (>=v2). Read the file COPYING that comes with GRASS for details.
15 @author Martin Landa <landa.martin gmail.com>
21 from core
import globalvar
23 import wx.lib.scrolledpanel
as scrolled
28 from dbmgr.vinfo
import VectorDBInfo
33 query =
None, cats =
None, line =
None,
34 style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER,
35 pos = wx.DefaultPosition,
36 action =
"add", ignoreError =
False):
37 """!Standard dialog used to add/update/display attributes linked
40 Attribute data can be selected based on layer and category number
45 @param query query coordinates and distance (used for v.edit)
46 @param cats {layer: cats}
47 @param line feature id (requested for cats)
50 @param action (add, update, display)
51 @param ignoreError True to ignore errors
65 layers = self.mapDBInfo.layers.keys()
70 dlg = wx.MessageDialog(parent = self.
parent,
71 message = _(
"No attribute table found.\n\n"
72 "Do you want to create a new attribute table "
73 "and defined a link to vector map <%s>?") % self.
map,
74 caption = _(
"Create table?"),
75 style = wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
76 if dlg.ShowModal() == wx.ID_YES:
77 lmgr = self.parent.lmgr
78 lmgr.OnShowAttributeTable(event =
None, selection =
'layers')
84 wx.Dialog.__init__(self, parent = self.
parent, id = wx.ID_ANY,
85 title =
"", style = style, pos = pos)
88 mainSizer = wx.BoxSizer(wx.VERTICAL)
91 self.
notebook = wx.Notebook(parent = self, id = wx.ID_ANY, style = wx.BK_DEFAULT)
94 label = _(
"Close dialog on submit"))
95 self.closeDialog.SetValue(
True)
96 if self.
action ==
'display':
97 self.closeDialog.Enable(
False)
100 self.
fidMulti = wx.Choice(parent = self, id = wx.ID_ANY,
102 self.fidMulti.Bind(wx.EVT_CHOICE, self.
OnFeature)
103 self.
fidText = wx.StaticText(parent = self, id = wx.ID_ANY)
105 self.
noFoundMsg = wx.StaticText(parent = self, id = wx.ID_ANY,
106 label = _(
"No attributes found"))
111 if self.
action ==
"update":
112 self.SetTitle(_(
"Update attributes"))
113 elif self.
action ==
"add":
114 self.SetTitle(_(
"Define attributes"))
116 self.SetTitle(_(
"Display attributes"))
119 btnCancel = wx.Button(self, wx.ID_CANCEL)
120 btnReset = wx.Button(self, wx.ID_UNDO, _(
"&Reload"))
121 btnSubmit = wx.Button(self, wx.ID_OK, _(
"&Submit"))
122 if self.
action ==
'display':
123 btnSubmit.Enable(
False)
125 btnSizer = wx.StdDialogButtonSizer()
126 btnSizer.AddButton(btnCancel)
127 btnSizer.AddButton(btnReset)
128 btnSizer.SetNegativeButton(btnReset)
129 btnSubmit.SetDefault()
130 btnSizer.AddButton(btnSubmit)
133 mainSizer.Add(item = self.
noFoundMsg, proportion = 0,
134 flag = wx.EXPAND | wx.ALL, border = 5)
135 mainSizer.Add(item = self.
notebook, proportion = 1,
136 flag = wx.EXPAND | wx.ALL, border = 5)
137 fidSizer = wx.BoxSizer(wx.HORIZONTAL)
138 fidSizer.Add(item = wx.StaticText(parent = self, id = wx.ID_ANY,
139 label = _(
"Feature id:")),
140 proportion = 0, border = 5,
141 flag = wx.ALIGN_CENTER_VERTICAL)
142 fidSizer.Add(item = self.
fidMulti, proportion = 0,
143 flag = wx.EXPAND | wx.ALL, border = 5)
144 fidSizer.Add(item = self.
fidText, proportion = 0,
145 flag = wx.EXPAND | wx.ALL, border = 5)
146 mainSizer.Add(item = fidSizer, proportion = 0,
147 flag = wx.EXPAND | wx.LEFT | wx.RIGHT, border = 5)
148 mainSizer.Add(item = self.
closeDialog, proportion = 0, flag = wx.EXPAND | wx.LEFT | wx.RIGHT,
150 mainSizer.Add(item = btnSizer, proportion = 0,
151 flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
154 btnReset.Bind(wx.EVT_BUTTON, self.
OnReset)
155 btnSubmit.Bind(wx.EVT_BUTTON, self.
OnSubmit)
156 btnCancel.Bind(wx.EVT_BUTTON, self.
OnCancel)
158 self.SetSizer(mainSizer)
162 w, h = self.GetBestSize()
165 self.SetMinSize((w, 200))
167 self.SetMinSize((w, h))
169 if self.notebook.GetPageCount() == 0:
170 Debug.msg(2,
"DisplayAttributesDialog(): Nothing found!")
173 def __SelectAttributes(self, layer):
174 """!Select attributes"""
178 """!Update SQL statement"""
184 @return True on attributes found
185 @return False attributes not found
187 return bool(self.notebook.GetPageCount())
190 """!Create SQL statement string based on self.sqlStatement
192 Show error message when invalid values are entered.
194 If updateValues is True, update dataFrame according to values
199 for layer
in self.mapDBInfo.layers.keys():
200 table = self.mapDBInfo.GetTable(layer)
201 key = self.mapDBInfo.GetKeyColumn(layer)
202 columns = self.mapDBInfo.GetTableDesc(table)
203 for idx
in range(len(columns[key][
'values'])):
206 for name
in columns.keys():
208 cat = columns[name][
'values'][idx]
210 ctype = columns[name][
'ctype']
211 value = columns[name][
'values'][idx]
212 id = columns[name][
'ids'][idx]
214 newvalue = self.FindWindowById(id).
GetValue()
216 newvalue = self.FindWindowById(id).GetLabel()
221 newvalue =
int(newvalue)
223 newvalue = float(newvalue)
225 GError(parent = self,
226 message = _(
"Column <%(col)s>: Value '%(value)s' needs to be entered as %(type)s.") % \
228 'value' : str(newvalue),
229 'type' : columns[name][
'type'].lower()},
230 showTraceback =
False)
231 sqlCommands.append(
None)
237 if newvalue != value:
238 updatedColumns.append(name)
240 updatedValues.append(
'NULL')
243 updatedValues.append(str(newvalue))
245 updatedValues.append(
"'" + str(newvalue) +
"'")
246 columns[name][
'values'][idx] = newvalue
248 if self.
action !=
"add" and len(updatedValues) == 0:
252 sqlString =
"INSERT INTO %s (%s," % (table, key)
254 sqlString =
"UPDATE %s SET " % table
256 for idx
in range(len(updatedColumns)):
257 name = updatedColumns[idx]
259 sqlString += name +
","
261 sqlString += name +
"=" + updatedValues[idx] +
","
263 sqlString = sqlString[:-1]
266 sqlString +=
") VALUES (%s," % cat
267 for value
in updatedValues:
268 sqlString += str(value) +
","
269 sqlString = sqlString[:-1]
272 sqlString +=
" WHERE cat=%s" % cat
273 sqlCommands.append(sqlString)
277 Debug.msg(3,
"DisplayAttributesDialog.GetSQLString(): %s" % sqlCommands)
283 for layer
in self.mapDBInfo.layers.keys():
284 table = self.mapDBInfo.layers[layer][
"table"]
285 key = self.mapDBInfo.layers[layer][
"key"]
286 columns = self.mapDBInfo.tables[table]
287 for idx
in range(len(columns[key][
'values'])):
288 for name
in columns.keys():
289 type = columns[name][
'type']
290 value = columns[name][
'values'][idx]
294 id = columns[name][
'ids'][idx]
298 if name != key
and id != wx.NOT_FOUND:
299 self.FindWindowById(id).
SetValue(str(value))
302 """!Cancel button pressed
304 frame = self.parent.parent
305 frame.dialogs[
'attributes'] =
None
306 if hasattr(self,
"digit"):
307 self.parent.digit.GetDisplay().SetSelected([])
308 if frame.IsAutoRendered():
309 self.parent.UpdateMap(render =
False)
310 elif frame.IsAutoRendered():
311 frame.RemoveQueryLayer()
312 self.parent.UpdateMap(render =
True)
317 """!Submit records"""
319 enc = UserSettings.Get(group =
'atm', key =
'encoding', subkey =
'value')
320 if not enc
and 'GRASS_DB_ENCODING' in os.environ:
321 enc = os.environ[
'GRASS_DB_ENCODING']
328 sql = sql.encode(enc)
335 if close
and self.closeDialog.IsChecked():
339 self.
fid =
int(event.GetString())
343 """!Get id of selected vector object or 'None' if nothing selected
345 @param id if true return ids otherwise cats
353 """!Get selected feature id"""
356 def UpdateDialog(self, map = None, query = None, cats = None, fid = -1,
360 @param map name of vector map
363 @param fid feature id
364 @param action add, update, display or None
366 @return True if updated
371 if action ==
'display':
375 self.closeDialog.Enable(enabled)
376 self.FindWindowById(wx.ID_OK).Enable(enabled)
386 self.mapDBInfo.Reset()
388 layers = self.mapDBInfo.layers.keys()
392 data = self.mapDBInfo.SelectByPoint(query[0],
395 if data
and 'Layer' in data:
397 for layer
in data[
'Layer']:
399 if data[
'Id'][idx]
is not None:
400 tfid =
int(data[
'Id'][idx])
403 if not tfid
in self.
cats:
405 if not layer
in self.
cats[tfid]:
406 self.
cats[tfid][layer] = []
407 cat =
int(data[
'Category'][idx])
408 self.
cats[tfid][layer].append(cat)
415 elif len(self.cats.keys()) > 0:
416 self.
fid = self.cats.keys()[0]
420 if len(self.cats.keys()) == 1:
421 self.fidMulti.Show(
False)
422 self.fidText.Show(
True)
424 self.fidText.SetLabel(
"%d" % self.
fid)
426 self.fidText.SetLabel(_(
"Unknown"))
428 self.fidMulti.Show(
True)
429 self.fidText.Show(
False)
431 for tfid
in self.cats.keys():
432 choices.append(str(tfid))
433 self.fidMulti.SetItems(choices)
434 self.fidMulti.SetStringSelection(str(self.
fid))
437 self.notebook.DeleteAllPages()
441 if self.
fid > 0
and layer
in self.
cats[self.
fid]:
442 for cat
in self.
cats[self.
fid][layer]:
443 nselected = self.mapDBInfo.SelectFromTable(layer,
445 (self.mapDBInfo.layers[layer][
'key'],
455 if layer
in self.
cats[self.
fid]:
456 table = self.mapDBInfo.layers[layer][
"table"]
457 key = self.mapDBInfo.layers[layer][
"key"]
458 columns = self.mapDBInfo.tables[table]
459 for name
in columns.keys():
461 for cat
in self.
cats[self.
fid][layer]:
462 self.mapDBInfo.tables[table][name][
'values'].append(cat)
464 self.mapDBInfo.tables[table][name][
'values'].append(
None)
468 table = self.mapDBInfo.layers[layer][
"table"]
469 key = self.mapDBInfo.layers[layer][
"key"]
470 columns = self.mapDBInfo.tables[table]
472 for idx
in range(len(columns[key][
'values'])):
473 for name
in columns.keys():
475 cat =
int(columns[name][
'values'][idx])
479 panel = scrolled.ScrolledPanel(parent = self.
notebook, id = wx.ID_ANY,
481 panel.SetupScrolling(scroll_x =
False)
483 self.notebook.AddPage(page = panel, text =
" %s %d / %s %d" % (_(
"Layer"), layer,
487 border = wx.BoxSizer(wx.VERTICAL)
489 flexSizer = wx.FlexGridSizer (cols = 3, hgap = 3, vgap = 3)
490 flexSizer.AddGrowableCol(2)
492 names = [
''] * len(columns.keys())
493 for name
in columns.keys():
494 names[columns[name][
'index']] = name
500 vtype = columns[name][
'type'].lower()
501 ctype = columns[name][
'ctype']
503 if columns[name][
'values'][idx]
is not None:
504 if columns[name][
'ctype'] != types.StringType:
505 value = str(columns[name][
'values'][idx])
507 value = columns[name][
'values'][idx]
511 colName = wx.StaticText(parent = panel, id = wx.ID_ANY,
513 colType = wx.StaticText(parent = panel, id = wx.ID_ANY,
514 label =
"[%s]:" % vtype)
515 colValue = wx.TextCtrl(parent = panel, id = wx.ID_ANY, value = value)
516 colValue.SetName(name)
518 colValue.SetValidator(IntegerValidator())
520 colValue.SetValidator(FloatValidator())
523 if self.
action ==
'display':
524 colValue.SetWindowStyle(wx.TE_READONLY)
526 flexSizer.Add(colName, proportion = 0,
527 flag = wx.ALIGN_CENTER_VERTICAL)
528 flexSizer.Add(colType, proportion = 0,
529 flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT)
530 flexSizer.Add(colValue, proportion = 1,
531 flag = wx.EXPAND | wx.ALIGN_CENTER_VERTICAL)
533 columns[name][
'ids'].append(colValue.GetId())
535 border.Add(item = flexSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 5)
536 panel.SetSizer(border)
540 if self.notebook.GetPageCount() == 0:
541 self.noFoundMsg.Show(
True)
543 self.noFoundMsg.Show(
False)
550 """!Set attrbute value
552 @param column column name
555 table = self.mapDBInfo.GetTable(layer)
556 columns = self.mapDBInfo.GetTableDesc(table)
558 for key, col
in columns.iteritems():
560 col[
'values'] = [col[
'ctype'](value),]
564 def __init__(self, parent, title, data, keyEditable = (-1,
True),
565 id = wx.ID_ANY, style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER):
566 """!Dialog for inserting/updating table record
568 @param data a list: [(column, value)]
569 @param KeyEditable (id, editable?) indicates if textarea for key column
570 is editable(True) or not
573 wx.Dialog.__init__(self, parent, id, title, style = style)
575 self.CenterOnParent()
579 box = wx.StaticBox(parent = self, id = wx.ID_ANY)
581 self.
dataPanel = scrolled.ScrolledPanel(parent = self, id = wx.ID_ANY,
582 style = wx.TAB_TRAVERSAL)
583 self.dataPanel.SetupScrolling(scroll_x =
False)
587 self.
btnSubmit = wx.Button(self, wx.ID_OK, _(
"&Submit"))
588 self.btnSubmit.SetDefault()
597 for column, ctype, ctypeStr, value
in data:
598 if self.
keyId == cId:
600 if not keyEditable[1]:
602 box.SetLabel(
" %s %d " % (_(
"Category"), self.
cat))
604 self.
boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
608 valueWin = wx.SpinCtrl(parent = self.
dataPanel, id = wx.ID_ANY,
609 value = value, min = -1e9, max = 1e9, size = (250, -1))
611 valueWin = wx.TextCtrl(parent = self.
dataPanel, id = wx.ID_ANY,
612 value = value, size = (250, -1))
614 valueWin.SetValidator(IntegerValidator())
616 valueWin.SetValidator(FloatValidator())
618 wx.CallAfter(valueWin.SetFocus)
621 label = wx.StaticText(parent = self.
dataPanel, id = wx.ID_ANY,
623 ctype = wx.StaticText(parent = self.
dataPanel, id = wx.ID_ANY,
624 label =
"[%s]:" % ctypeStr.lower())
625 self.widgets.append((label.GetId(), ctype.GetId(), valueWin.GetId()))
633 sizer = wx.BoxSizer(wx.VERTICAL)
636 dataSizer = wx.FlexGridSizer(cols = 3, hgap = 3, vgap = 3)
637 dataSizer.AddGrowableCol(2)
639 for labelId, ctypeId, valueId
in self.
widgets:
640 label = self.FindWindowById(labelId)
641 ctype = self.FindWindowById(ctypeId)
642 value = self.FindWindowById(valueId)
644 dataSizer.Add(label, proportion = 0,
645 flag = wx.ALIGN_CENTER_VERTICAL)
646 dataSizer.Add(ctype, proportion = 0,
647 flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT)
648 dataSizer.Add(value, proportion = 0,
649 flag = wx.EXPAND | wx.ALIGN_CENTER_VERTICAL)
651 self.dataPanel.SetAutoLayout(
True)
652 self.dataPanel.SetSizer(dataSizer)
656 self.boxSizer.Add(item = self.
dataPanel, proportion = 1,
657 flag = wx.EXPAND | wx.ALL, border = 5)
660 btnSizer = wx.StdDialogButtonSizer()
666 sizer.Add(item = self.
dataPanel, proportion = 1,
667 flag = wx.EXPAND | wx.ALL, border = 5)
669 sizer.Add(item = self.
boxSizer, proportion = 1,
670 flag = wx.EXPAND | wx.ALL, border = 5)
672 sizer.Add(item = btnSizer, proportion = 0,
673 flag = wx.EXPAND | wx.ALL, border = 5)
675 framewidth = self.GetBestSize()[0] + 25
676 self.SetMinSize((framewidth, 250))
678 self.SetAutoLayout(
True)
685 """!Return list of values (casted to string).
687 If columns is given (list), return only values of given columns.
690 for labelId, ctypeId, valueId
in self.
widgets:
691 column = self.FindWindowById(labelId).GetLabel().replace(
':',
'')
692 if columns
is None or column
in columns:
693 value = str(self.FindWindowById(valueId).
GetValue())
694 valueList.append(value)
698 valueList.insert(self.
keyId, str(self.
cat))
def GetValues
Return list of values (casted to string).
def SetColumnValue
Set attrbute value.
def OnCancel
Cancel button pressed.
def UpdateDialog
Update dialog.
def GetFid
Get selected feature id.
def GetSQLString
Create SQL statement string based on self.sqlStatement.
def OnSQLStatement
Update SQL statement.
def OnSubmit
Submit records.
def IsFound
Check for status.
def GetCats
Get id of selected vector object or 'None' if nothing selected.
def __init__
Standard dialog used to add/update/display attributes linked to the vector map.
def __init__
Dialog for inserting/updating table record.
def RunCommand
Run GRASS command.