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.
OnClose)
157 self.Bind(wx.EVT_CLOSE, self.
OnClose)
159 self.SetSizer(mainSizer)
163 w, h = self.GetBestSize()
166 self.SetMinSize((w, 200))
168 self.SetMinSize((w, h))
170 if self.notebook.GetPageCount() == 0:
171 Debug.msg(2,
"DisplayAttributesDialog(): Nothing found!")
174 def __SelectAttributes(self, layer):
175 """!Select attributes"""
179 """!Update SQL statement"""
185 @return True on attributes found
186 @return False attributes not found
188 return bool(self.notebook.GetPageCount())
191 """!Create SQL statement string based on self.sqlStatement
193 Show error message when invalid values are entered.
195 If updateValues is True, update dataFrame according to values
200 for layer
in self.mapDBInfo.layers.keys():
201 table = self.mapDBInfo.GetTable(layer)
202 key = self.mapDBInfo.GetKeyColumn(layer)
203 columns = self.mapDBInfo.GetTableDesc(table)
204 for idx
in range(len(columns[key][
'values'])):
207 for name
in columns.keys():
209 cat = columns[name][
'values'][idx]
211 ctype = columns[name][
'ctype']
212 value = columns[name][
'values'][idx]
213 id = columns[name][
'ids'][idx]
215 newvalue = self.FindWindowById(id).
GetValue()
217 newvalue = self.FindWindowById(id).GetLabel()
222 newvalue = int(newvalue)
224 newvalue = float(newvalue)
226 GError(parent = self,
227 message = _(
"Column <%(col)s>: Value '%(value)s' needs to be entered as %(type)s.") % \
229 'value' : str(newvalue),
230 'type' : columns[name][
'type'].lower()},
231 showTraceback =
False)
232 sqlCommands.append(
None)
238 if newvalue != value:
239 updatedColumns.append(name)
241 updatedValues.append(
'NULL')
244 updatedValues.append(str(newvalue))
246 updatedValues.append(
"'" + str(newvalue) +
"'")
247 columns[name][
'values'][idx] = newvalue
249 if self.
action !=
"add" and len(updatedValues) == 0:
253 sqlString =
"INSERT INTO %s (%s," % (table, key)
255 sqlString =
"UPDATE %s SET " % table
257 for idx
in range(len(updatedColumns)):
258 name = updatedColumns[idx]
260 sqlString += name +
","
262 sqlString += name +
"=" + updatedValues[idx] +
","
264 sqlString = sqlString[:-1]
267 sqlString +=
") VALUES (%s," % cat
268 for value
in updatedValues:
269 sqlString += str(value) +
","
270 sqlString = sqlString[:-1]
273 sqlString +=
" WHERE cat=%s" % cat
274 sqlCommands.append(sqlString)
278 Debug.msg(3,
"DisplayAttributesDialog.GetSQLString(): %s" % sqlCommands)
284 for layer
in self.mapDBInfo.layers.keys():
285 table = self.mapDBInfo.layers[layer][
"table"]
286 key = self.mapDBInfo.layers[layer][
"key"]
287 columns = self.mapDBInfo.tables[table]
288 for idx
in range(len(columns[key][
'values'])):
289 for name
in columns.keys():
290 type = columns[name][
'type']
291 value = columns[name][
'values'][idx]
295 id = columns[name][
'ids'][idx]
299 if name != key
and id != wx.NOT_FOUND:
300 self.FindWindowById(id).
SetValue(str(value))
303 """!Closes dialog and removes query layer.
305 frame = self.parent.parent
306 frame.dialogs[
'attributes'] =
None
307 if hasattr(self,
"digit"):
308 self.parent.digit.GetDisplay().SetSelected([])
309 if frame.IsAutoRendered():
310 self.parent.UpdateMap(render =
False)
311 elif frame.IsAutoRendered():
312 frame.RemoveQueryLayer()
313 self.parent.UpdateMap(render =
True)
318 """!Submit records"""
320 enc = UserSettings.Get(group =
'atm', key =
'encoding', subkey =
'value')
321 if not enc
and 'GRASS_DB_ENCODING' in os.environ:
322 enc = os.environ[
'GRASS_DB_ENCODING']
329 sql = sql.encode(enc)
336 if close
and self.closeDialog.IsChecked():
340 self.
fid = int(event.GetString())
344 """!Get id of selected vector object or 'None' if nothing selected
346 @param id if true return ids otherwise cats
354 """!Get selected feature id"""
357 def UpdateDialog(self, map = None, query = None, cats = None, fid = -1,
361 @param map name of vector map
364 @param fid feature id
365 @param action add, update, display or None
367 @return True if updated
372 if action ==
'display':
376 self.closeDialog.Enable(enabled)
377 self.FindWindowById(wx.ID_OK).Enable(enabled)
387 self.mapDBInfo.Reset()
389 layers = self.mapDBInfo.layers.keys()
393 data = self.mapDBInfo.SelectByPoint(query[0],
396 if data
and 'Layer' in data:
398 for layer
in data[
'Layer']:
400 if data[
'Id'][idx]
is not None:
401 tfid = int(data[
'Id'][idx])
404 if not tfid
in self.
cats:
406 if not layer
in self.
cats[tfid]:
407 self.
cats[tfid][layer] = []
408 cat = int(data[
'Category'][idx])
409 self.
cats[tfid][layer].append(cat)
416 elif len(self.cats.keys()) > 0:
417 self.
fid = self.cats.keys()[0]
421 if len(self.cats.keys()) == 1:
422 self.fidMulti.Show(
False)
423 self.fidText.Show(
True)
425 self.fidText.SetLabel(
"%d" % self.
fid)
427 self.fidText.SetLabel(_(
"Unknown"))
429 self.fidMulti.Show(
True)
430 self.fidText.Show(
False)
432 for tfid
in self.cats.keys():
433 choices.append(str(tfid))
434 self.fidMulti.SetItems(choices)
435 self.fidMulti.SetStringSelection(str(self.
fid))
438 self.notebook.DeleteAllPages()
442 if self.
fid > 0
and layer
in self.
cats[self.
fid]:
443 for cat
in self.
cats[self.
fid][layer]:
444 nselected = self.mapDBInfo.SelectFromTable(layer,
446 (self.mapDBInfo.layers[layer][
'key'],
456 if layer
in self.
cats[self.
fid]:
457 table = self.mapDBInfo.layers[layer][
"table"]
458 key = self.mapDBInfo.layers[layer][
"key"]
459 columns = self.mapDBInfo.tables[table]
460 for name
in columns.keys():
462 for cat
in self.
cats[self.
fid][layer]:
463 self.mapDBInfo.tables[table][name][
'values'].append(cat)
465 self.mapDBInfo.tables[table][name][
'values'].append(
None)
469 table = self.mapDBInfo.layers[layer][
"table"]
470 key = self.mapDBInfo.layers[layer][
"key"]
471 columns = self.mapDBInfo.tables[table]
473 for idx
in range(len(columns[key][
'values'])):
474 for name
in columns.keys():
476 cat = int(columns[name][
'values'][idx])
480 panel = scrolled.ScrolledPanel(parent = self.
notebook, id = wx.ID_ANY,
482 panel.SetupScrolling(scroll_x =
False)
484 self.notebook.AddPage(page = panel, text =
" %s %d / %s %d" % (_(
"Layer"), layer,
488 border = wx.BoxSizer(wx.VERTICAL)
490 flexSizer = wx.FlexGridSizer (cols = 3, hgap = 3, vgap = 3)
491 flexSizer.AddGrowableCol(2)
493 names = [
''] * len(columns.keys())
494 for name
in columns.keys():
495 names[columns[name][
'index']] = name
501 vtype = columns[name][
'type'].lower()
502 ctype = columns[name][
'ctype']
504 if columns[name][
'values'][idx]
is not None:
505 if columns[name][
'ctype'] != types.StringType:
506 value = str(columns[name][
'values'][idx])
508 value = columns[name][
'values'][idx]
512 colName = wx.StaticText(parent = panel, id = wx.ID_ANY,
514 colType = wx.StaticText(parent = panel, id = wx.ID_ANY,
515 label =
"[%s]:" % vtype)
516 colValue = wx.TextCtrl(parent = panel, id = wx.ID_ANY, value = value)
517 colValue.SetName(name)
519 colValue.SetValidator(IntegerValidator())
521 colValue.SetValidator(FloatValidator())
524 if self.
action ==
'display':
525 colValue.SetWindowStyle(wx.TE_READONLY)
527 flexSizer.Add(colName, proportion = 0,
528 flag = wx.ALIGN_CENTER_VERTICAL)
529 flexSizer.Add(colType, proportion = 0,
530 flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT)
531 flexSizer.Add(colValue, proportion = 1,
532 flag = wx.EXPAND | wx.ALIGN_CENTER_VERTICAL)
534 columns[name][
'ids'].append(colValue.GetId())
536 border.Add(item = flexSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 5)
537 panel.SetSizer(border)
541 if self.notebook.GetPageCount() == 0:
542 self.noFoundMsg.Show(
True)
544 self.noFoundMsg.Show(
False)
551 """!Set attrbute value
553 @param column column name
556 table = self.mapDBInfo.GetTable(layer)
557 columns = self.mapDBInfo.GetTableDesc(table)
559 for key, col
in columns.iteritems():
561 col[
'values'] = [col[
'ctype'](value),]
565 def __init__(self, parent, title, data, keyEditable = (-1,
True),
566 id = wx.ID_ANY, style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER):
567 """!Dialog for inserting/updating table record
569 @param data a list: [(column, value)]
570 @param KeyEditable (id, editable?) indicates if textarea for key column
571 is editable(True) or not
574 wx.Dialog.__init__(self, parent, id, title, style = style)
576 self.CenterOnParent()
580 box = wx.StaticBox(parent = self, id = wx.ID_ANY)
582 self.
dataPanel = scrolled.ScrolledPanel(parent = self, id = wx.ID_ANY,
583 style = wx.TAB_TRAVERSAL)
584 self.dataPanel.SetupScrolling(scroll_x =
False)
588 self.
btnSubmit = wx.Button(self, wx.ID_OK, _(
"&Submit"))
589 self.btnSubmit.SetDefault()
598 for column, ctype, ctypeStr, value
in data:
599 if self.
keyId == cId:
600 self.
cat = int(value)
601 if not keyEditable[1]:
603 box.SetLabel(
" %s %d " % (_(
"Category"), self.
cat))
605 self.
boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
609 valueWin = wx.SpinCtrl(parent = self.
dataPanel, id = wx.ID_ANY,
610 value = value, min = -1e9, max = 1e9, size = (250, -1))
612 valueWin = wx.TextCtrl(parent = self.
dataPanel, id = wx.ID_ANY,
613 value = value, size = (250, -1))
615 valueWin.SetValidator(IntegerValidator())
617 valueWin.SetValidator(FloatValidator())
619 wx.CallAfter(valueWin.SetFocus)
622 label = wx.StaticText(parent = self.
dataPanel, id = wx.ID_ANY,
624 ctype = wx.StaticText(parent = self.
dataPanel, id = wx.ID_ANY,
625 label =
"[%s]:" % ctypeStr.lower())
626 self.widgets.append((label.GetId(), ctype.GetId(), valueWin.GetId()))
634 sizer = wx.BoxSizer(wx.VERTICAL)
637 dataSizer = wx.FlexGridSizer(cols = 3, hgap = 3, vgap = 3)
638 dataSizer.AddGrowableCol(2)
640 for labelId, ctypeId, valueId
in self.
widgets:
641 label = self.FindWindowById(labelId)
642 ctype = self.FindWindowById(ctypeId)
643 value = self.FindWindowById(valueId)
645 dataSizer.Add(label, proportion = 0,
646 flag = wx.ALIGN_CENTER_VERTICAL)
647 dataSizer.Add(ctype, proportion = 0,
648 flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT)
649 dataSizer.Add(value, proportion = 0,
650 flag = wx.EXPAND | wx.ALIGN_CENTER_VERTICAL)
652 self.dataPanel.SetAutoLayout(
True)
653 self.dataPanel.SetSizer(dataSizer)
657 self.boxSizer.Add(item = self.
dataPanel, proportion = 1,
658 flag = wx.EXPAND | wx.ALL, border = 5)
661 btnSizer = wx.StdDialogButtonSizer()
667 sizer.Add(item = self.
dataPanel, proportion = 1,
668 flag = wx.EXPAND | wx.ALL, border = 5)
670 sizer.Add(item = self.
boxSizer, proportion = 1,
671 flag = wx.EXPAND | wx.ALL, border = 5)
673 sizer.Add(item = btnSizer, proportion = 0,
674 flag = wx.EXPAND | wx.ALL, border = 5)
676 framewidth = self.GetBestSize()[0] + 25
677 self.SetMinSize((framewidth, 250))
679 self.SetAutoLayout(
True)
686 """!Return list of values (casted to string).
688 If columns is given (list), return only values of given columns.
691 for labelId, ctypeId, valueId
in self.
widgets:
692 column = self.FindWindowById(labelId).GetLabel().replace(
':',
'')
693 if columns
is None or column
in columns:
694 value = str(self.FindWindowById(valueId).
GetValue())
695 valueList.append(value)
699 valueList.insert(self.
keyId, str(self.
cat))
def GetValues
Return list of values (casted to string).
def SetColumnValue
Set attrbute value.
def OnClose
Closes dialog and removes query layer.
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.