4 @brief GRASS Attribute Table Manager
6 This program is based on FileHunter, published in 'The wxPython Linux
7 Tutorial' on wxPython WIKI pages.
9 It also uses some functions at
10 http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/426407
13 python dbm.py vector@mapset
18 - VirtualAttributeList
21 (C) 2007-2009, 2011 by the GRASS Development Team
23 This program is free software under the GNU General Public
24 License (>=v2). Read the file COPYING that comes with GRASS
27 @author Jachym Cepicky <jachym.cepicky gmail.com>
28 @author Martin Landa <landa.martin gmail.com>
40 gettext.install(
'grasswxpy', os.path.join(os.getenv(
"GISBASE"),
'locale'), unicode=
True)
44 import wx.lib.mixins.listctrl
as listmix
45 import wx.lib.flatnotebook
as FN
54 from debug
import Debug
55 from dbm_dialogs
import ModifyTableRecord
56 from preferences
import globalSettings
as UserSettings
60 The log output is redirected to the status bar of the containing frame.
66 """!Update status bar"""
67 self.parent.SetStatusText(text_string.strip())
71 listmix.ListCtrlAutoWidthMixin,
72 listmix.ColumnSorterMixin):
74 Support virtual list class
76 def __init__(self, parent, log, mapDBInfo, layer):
87 wx.ListCtrl.__init__(self, parent=parent, id=wx.ID_ANY,
88 style=wx.LC_REPORT | wx.LC_HRULES |
89 wx.LC_VRULES | wx.LC_VIRTUAL | wx.LC_SORT_ASCENDING)
102 self.attr1.SetBackgroundColour(wx.Colour(238,238,238))
104 self.attr2.SetBackgroundColour(
"white")
105 self.
il = wx.ImageList(16, 16)
106 self.
sm_up = self.il.Add(wx.ArtProvider_GetBitmap(wx.ART_GO_UP, wx.ART_TOOLBAR,
108 self.
sm_dn = self.il.Add(wx.ArtProvider_GetBitmap(wx.ART_GO_DOWN, wx.ART_TOOLBAR,
110 self.SetImageList(self.
il, wx.IMAGE_LIST_SMALL)
113 listmix.ListCtrlAutoWidthMixin.__init__(self)
114 listmix.ColumnSorterMixin.__init__(self, len(self.
columns))
118 self.SortListItems(col=keyColumn, ascending=
True)
120 self.SortListItems(col=0, ascending=
True)
126 self.Bind(wx.EVT_LIST_COL_RIGHT_CLICK, self.
OnColumnMenu)
129 """!Update list according new mapDBInfo description"""
133 def LoadData(self, layer, columns=None, where=None, sql=None):
134 """!Load data into list
136 @param layer layer number
137 @param columns list of columns for output (-> v.db.select)
138 @param where where statement (-> v.db.select)
139 @param sql full sql statement (-> db.select)
141 @return id of key column
142 @return -1 if key column is not displayed
144 self.log.write(_(
"Loading data..."))
146 tableName = self.mapDBInfo.layers[layer][
'table']
147 keyColumn = self.mapDBInfo.layers[layer][
'key']
149 self.
columns = self.mapDBInfo.tables[tableName]
152 "For creating the table switch to "
153 "'Manage layers' tab.") % tableName)
156 columns = self.mapDBInfo.GetColumns(tableName)
158 all = self.mapDBInfo.GetColumns(tableName)
161 wx.MessageBox(parent=self,
162 message=_(
"Column <%(column)s> not found in "
163 "in the table <%(table)s>.") % \
164 {
'column' : col,
'table' : tableName },
165 caption=_(
"Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
170 keyId = columns.index(keyColumn)
181 outFile = tempfile.NamedTemporaryFile(mode=
'w+b')
184 ret = gcmd.RunCommand(
'db.select',
189 output = outFile.name)
192 ret = gcmd.RunCommand(
'v.db.select',
195 map = self.mapDBInfo.map,
197 columns =
','.join(columns),
201 ret = gcmd.RunCommand(
'v.db.select',
204 map = self.mapDBInfo.map,
215 self.DeleteAllItems()
218 for i
in range(self.GetColumnCount()):
223 info.m_mask = wx.LIST_MASK_TEXT | wx.LIST_MASK_IMAGE | wx.LIST_MASK_FORMAT
226 for column
in columns:
228 self.InsertColumnInfo(i, info)
232 self.log.write(_(
"Can display only 256 columns."))
239 record = outFile.readline().replace(
'\n',
'')
248 self.log.write(_(
"Limit 100000 records."))
255 width = self.
columns[col][
'length'] * 6
260 self.SetColumnWidth(col=i, width=width)
265 self.log.write(_(
"Number of loaded records: %d") % \
271 """!Add row to the data list"""
273 keyColumn = self.mapDBInfo.layers[self.
layer][
'key']
277 if keyColumn ==
'OGC_FID':
282 for value
in record.split(
'|'):
283 if self.
columns[columns[j]][
'ctype'] != types.StringType:
293 self.
itemDataMap[i].append(dbm_base.unicodeValue(value))
294 except UnicodeDecodeError:
295 self.
itemDataMap[i].append(_(
"Unable to decode value. "
296 "Set encoding in GUI preferences ('Attributes')."))
298 if not cat
and keyId > -1
and keyId == j:
300 cat = self.
columns[columns[j]][
'ctype'] (value)
301 except ValueError, e:
304 message=_(
"Error loading attribute data. "
305 "Record number: %(rec)d. Unable to convert value '%(val)s' in "
306 "key column (%(key)s) to integer.\n\n"
307 "Details: %(detail)s") % \
308 {
'rec' : i + 1,
'val' : value,
309 'key' : keyColumn,
'detail' : e})
312 self.itemIndexMap.append(i)
317 """!Item selected. Add item to selected cats..."""
326 """!Item deselected. Remove item from selected cats..."""
335 """!Return list of selected items (category numbers)"""
337 item = self.GetFirstSelected()
339 cats.append(self.GetItemText(item))
340 item = self.GetNextSelected(item)
345 """!Return column text"""
346 item = self.GetItem(index, col)
347 return item.GetText()
360 """!Get item attributes"""
367 """!Column heading right mouse button -> pop-up menu"""
368 self.
_col = event.GetColumn()
370 popupMenu = wx.Menu()
372 if not hasattr (self,
"popupID1"):
386 popupMenu.Append(self.
popupID1, text=_(
"Sort ascending"))
387 popupMenu.Append(self.
popupID2, text=_(
"Sort descending"))
388 popupMenu.AppendSeparator()
390 popupMenu.AppendMenu(self.
popupID3, _(
"Calculate (only numeric columns)"),
392 if not self.log.parent.editable
or \
393 self.
columns[self.GetColumn(self.
_col).GetText()][
'ctype']
not in (types.IntType, types.FloatType):
394 popupMenu.Enable(self.
popupID3,
False)
396 subMenu.Append(self.
popupID4, text=_(
"Area size"))
397 subMenu.Append(self.
popupID5, text=_(
"Line length"))
398 subMenu.Append(self.
popupID6, text=_(
"Compactness of an area"))
399 subMenu.Append(self.
popupID7, text=_(
"Fractal dimension of boundary defining a polygon"))
400 subMenu.Append(self.
popupID8, text=_(
"Perimeter length of an area"))
401 subMenu.Append(self.
popupID9, text=_(
"Number of features for each category"))
402 subMenu.Append(self.
popupID10, text=_(
"Slope steepness of 3D line"))
403 subMenu.Append(self.
popupID11, text=_(
"Line sinuousity"))
404 subMenu.Append(self.
popupID12, text=_(
"Line azimuth"))
413 self.PopupMenu(popupMenu)
417 """!Column heading left mouse button -> sorting"""
418 self.
_col = event.GetColumn()
425 """!Sort values of selected column (ascending)"""
426 self.SortListItems(col = self.
_col, ascending =
True)
430 """!Sort values of selected column (descending)"""
431 self.SortListItems(col = self.
_col, ascending =
False)
435 """!Compute values of selected column"""
461 gcmd.RunCommand(
'v.to.db',
463 map = self.mapDBInfo.map,
466 columns = self.GetColumn(self.
_col).GetText())
471 """!Sort values of selected column (self._col)"""
475 info.m_mask = wx.LIST_MASK_TEXT | wx.LIST_MASK_IMAGE
477 for column
in range(self.GetColumnCount()):
478 info.m_text = self.GetColumn(column).GetText()
479 self.SetColumn(column, info)
483 items = list(self.itemDataMap.keys())
491 colName = self.GetColumn(self.
_col).GetText()
492 ascending = self._colSortFlag[self.
_col]
501 cmpVal = locale.strcoll(str(item1), str(item2))
503 cmpVal = cmp(item1, item2)
508 cmpVal = apply(cmp, self.GetSecondarySortValues(self.
_col, key1, key2))
516 """!Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py"""
520 """!Check if list if empty"""
528 GRASS Attribute manager main window
530 def __init__(self, parent, id=wx.ID_ANY,
531 size = wx.DefaultSize, style = wx.DEFAULT_FRAME_STYLE,
532 title=
None, vectorName=
None, item=
None, log=
None, selection = 0):
537 if self.
parent and self.parent.GetName() ==
"LayerManager" and \
539 maptree = self.parent.curr_page.maptree
540 name = maptree.GetPyData(self.
treeItem)[0][
'maplayer'].GetName()
545 if grass.find_file(name = self.
vectorName, element =
'vector')[
'mapset'] == grass.gisenv()[
'MAPSET']:
551 if sys.platform ==
'win32':
556 wx.Frame.__init__(self, parent, id, style=style)
560 self.SetTitle(
"%s - <%s>" % (_(
"GRASS GIS Attribute Table Manager"),
566 self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR,
'grass_sql.ico'), wx.BITMAP_TYPE_ICO))
568 self.
panel = wx.Panel(parent=self, id=wx.ID_ANY)
571 self.
map = self.parent.curr_page.maptree.Map
588 if len(self.mapDBInfo.layers.keys()) == 0:
589 wx.MessageBox(parent=self.
parent,
590 message=_(
"Database connection for vector map <%s> "
591 "is not defined in DB file. "
592 "You can define new connection in "
594 caption=_(
"Attribute Table Manager"),
595 style=wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
603 self.CreateStatusBar(number=1)
617 agwStyle = FN.FNB_BOTTOM |
618 FN.FNB_NO_NAV_BUTTONS |
619 FN.FNB_FANCY_TABS | FN.FNB_NO_X_BUTTON)
621 self.
notebook = FN.FlatNotebook(parent = self.
panel, id = wx.ID_ANY,
622 style = FN.FNB_BOTTOM |
623 FN.FNB_NO_NAV_BUTTONS |
624 FN.FNB_FANCY_TABS | FN.FNB_NO_X_BUTTON)
627 dbmStyle = {
'agwStyle' : globalvar.FNPageStyle }
629 dbmStyle = {
'style' : globalvar.FNPageStyle }
634 self.notebook.AddPage(self.
browsePage, text=_(
"Browse data"))
635 self.browsePage.SetTabAreaColour(globalvar.FNPageColor)
642 self.notebook.GetPage(self.notebook.GetPageCount()-1).Enable(
False)
643 self.manageTablePage.SetTabAreaColour(globalvar.FNPageColor)
649 self.manageLayerPage.SetTabAreaColour(globalvar.FNPageColor)
651 self.notebook.GetPage(self.notebook.GetPageCount()-1).Enable(
False)
656 wx.CallAfter(self.notebook.SetSelection, selection)
662 self.btnQuit.SetToolTipString(_(
"Close Attribute Table Manager"))
664 self.btnReload.SetToolTipString(_(
"Reload attribute data (selected layer only)"))
669 self.notebook.Bind(FN.EVT_FLATNOTEBOOK_PAGE_CHANGED, self.
OnPageChanged)
677 self.SetSize((680, 550))
678 self.SetMinSize(self.GetSize())
680 def __createBrowsePage(self, onlyLayer=-1):
681 """!Create browse tab page"""
682 for layer
in self.mapDBInfo.layers.keys():
683 if onlyLayer > 0
and layer != onlyLayer:
686 panel = wx.Panel(parent=self.
browsePage, id=wx.ID_ANY)
692 listBox = wx.StaticBox(parent=panel, id=wx.ID_ANY,
693 label=
" %s " % _(
"Attribute data - right-click to edit/manage records"))
694 listSizer = wx.StaticBoxSizer(listBox, wx.VERTICAL)
704 self.
layerPage[layer] = {
'browsePage': panel.GetId()}
706 self.browsePage.AddPage(page=panel, text=
" %d / %s %s" % \
707 (layer, _(
"Table"), self.mapDBInfo.layers[layer][
'table']))
709 pageSizer = wx.BoxSizer(wx.VERTICAL)
712 sqlBox = wx.StaticBox(parent=panel, id=wx.ID_ANY,
713 label=
" %s " % _(
"SQL Query"))
715 sqlSizer = wx.StaticBoxSizer(sqlBox, wx.VERTICAL)
719 if UserSettings.Get(group=
'atm', key=
'leftDbClick', subkey=
'selection') == 0:
727 listSizer.Add(item=win, proportion=1,
728 flag=wx.EXPAND | wx.ALL,
732 btnApply = wx.Button(parent=panel, id=wx.ID_APPLY)
733 btnApply.SetToolTipString(_(
"Apply SELECT statement and reload data records"))
735 btnSqlBuilder = wx.Button(parent=panel, id=wx.ID_ANY, label=_(
"SQL Builder"))
736 btnSqlBuilder.Bind(wx.EVT_BUTTON, self.
OnBuilder)
738 sqlSimple = wx.RadioButton(parent=panel, id=wx.ID_ANY,
740 sqlSimple.SetValue(
True)
741 sqlAdvanced = wx.RadioButton(parent=panel, id=wx.ID_ANY,
743 sqlSimple.Bind(wx.EVT_RADIOBUTTON, self.
OnChangeSql)
744 sqlAdvanced.Bind(wx.EVT_RADIOBUTTON, self.
OnChangeSql)
746 sqlWhereColumn = wx.Choice(parent=panel, id=wx.ID_ANY,
748 choices=self.mapDBInfo.GetColumns(self.mapDBInfo.layers[layer][
'table']))
749 sqlWhereValue = wx.TextCtrl(parent=panel, id=wx.ID_ANY, value=
"",
750 style=wx.TE_PROCESS_ENTER)
751 sqlWhereValue.SetToolTipString(_(
"Example: %s") %
"MULTILANE = 'no' AND OBJECTID < 10")
753 sqlStatement = wx.TextCtrl(parent=panel, id=wx.ID_ANY,
754 value=
"SELECT * FROM %s" % \
755 self.mapDBInfo.layers[layer][
'table'],
756 style=wx.TE_PROCESS_ENTER)
757 sqlStatement.SetToolTipString(_(
"Example: %s") %
"SELECT * FROM roadsmajor WHERE MULTILANE = 'no' AND OBJECTID < 10")
761 sqlLabel = wx.StaticText(parent=panel, id=wx.ID_ANY,
762 label=
"SELECT * FROM %s WHERE " % \
763 self.mapDBInfo.layers[layer][
'table'])
764 label_query = wx.StaticText(parent=panel, id=wx.ID_ANY,
767 sqlFlexSizer = wx.FlexGridSizer (cols=3, hgap=5, vgap=5)
768 sqlFlexSizer.AddGrowableCol(1)
770 sqlFlexSizer.Add(item=sqlSimple,
771 flag=wx.ALIGN_CENTER_VERTICAL)
772 sqlSimpleSizer = wx.BoxSizer(wx.HORIZONTAL)
773 sqlSimpleSizer.Add(item=sqlLabel,
774 flag=wx.ALIGN_CENTER_VERTICAL)
775 sqlSimpleSizer.Add(item=sqlWhereColumn,
776 flag=wx.EXPAND | wx.ALIGN_CENTER_VERTICAL)
777 sqlSimpleSizer.Add(item=sqlWhereValue, proportion=1,
778 flag=wx.EXPAND | wx.ALIGN_CENTER_VERTICAL)
779 sqlFlexSizer.Add(item=sqlSimpleSizer,
780 flag=wx.ALIGN_CENTER_VERTICAL | wx.EXPAND)
781 sqlFlexSizer.Add(item=btnApply,
783 sqlFlexSizer.Add(item=sqlAdvanced,
784 flag=wx.ALIGN_CENTER_VERTICAL)
785 sqlFlexSizer.Add(item=sqlStatement,
787 sqlFlexSizer.Add(item=btnSqlBuilder,
790 sqlSizer.Add(item=sqlFlexSizer,
791 flag=wx.ALL | wx.EXPAND,
794 pageSizer.Add(item=listSizer,
796 flag=wx.ALL | wx.EXPAND,
799 pageSizer.Add(item=sqlSizer,
801 flag=wx.BOTTOM | wx.LEFT | wx.RIGHT | wx.EXPAND,
804 panel.SetSizer(pageSizer)
806 self.
layerPage[layer][
'data'] = win.GetId()
807 self.
layerPage[layer][
'simple'] = sqlSimple.GetId()
808 self.
layerPage[layer][
'advanced'] = sqlAdvanced.GetId()
809 self.
layerPage[layer][
'whereColumn'] = sqlWhereColumn.GetId()
810 self.
layerPage[layer][
'where'] = sqlWhereValue.GetId()
811 self.
layerPage[layer][
'builder'] = btnSqlBuilder.GetId()
812 self.
layerPage[layer][
'statement'] = sqlStatement.GetId()
815 self.browsePage.SetSelection(0)
817 self.
layer = self.mapDBInfo.layers.keys()[0]
819 self.log.write(_(
"Number of loaded records: %d") % \
820 self.FindWindowById(self.
layerPage[self.
layer][
'data']).GetItemCount())
821 except (IndexError, KeyError):
824 def __createManageTablePage(self, onlyLayer=-1):
825 """!Create manage page (create/link and alter tables)"""
826 for layer
in self.mapDBInfo.layers.keys():
827 if onlyLayer > 0
and layer != onlyLayer:
834 self.
layerPage[layer][
'tablePage'] = panel.GetId()
835 self.manageTablePage.AddPage(page=panel,
836 text=
" %d / %s %s" % (layer,
838 self.mapDBInfo.layers[layer][
'table']))
840 pageSizer = wx.BoxSizer(wx.VERTICAL)
845 dbBox = wx.StaticBox(parent=panel, id=wx.ID_ANY,
846 label=
" %s " % _(
"Database connection"))
847 dbSizer = wx.StaticBoxSizer(dbBox, wx.VERTICAL)
848 dbSizer.Add(item=dbm_base.createDbInfoDesc(panel, self.
mapDBInfo, layer),
850 flag=wx.EXPAND | wx.ALL,
856 table = self.mapDBInfo.layers[layer][
'table']
857 tableBox = wx.StaticBox(parent=panel, id=wx.ID_ANY,
858 label=
" %s " % _(
"Table <%s> - right-click to delete column(s)") % table)
860 tableSizer = wx.StaticBoxSizer(tableBox, wx.VERTICAL)
865 self.
layerPage[layer][
'tableData'] = list.GetId()
868 addBox = wx.StaticBox(parent = panel, id = wx.ID_ANY,
869 label =
" %s " % _(
"Add column"))
870 addSizer = wx.StaticBoxSizer(addBox, wx.HORIZONTAL)
872 column = wx.TextCtrl(parent = panel, id = wx.ID_ANY, value =
'',
873 size=(150, -1), style = wx.TE_PROCESS_ENTER)
876 self.
layerPage[layer][
'addColName'] = column.GetId()
877 addSizer.Add(item= wx.StaticText(parent = panel, id = wx.ID_ANY, label=_(
"Column")),
878 flag = wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT,
880 addSizer.Add(item = column, proportion = 1,
881 flag = wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT,
884 ctype = wx.Choice (parent=panel, id=wx.ID_ANY,
885 choices = [
"integer",
889 ctype.SetSelection(0)
891 self.
layerPage[layer][
'addColType'] = ctype.GetId()
892 addSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY, label=_(
"Type")),
893 flag = wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT,
895 addSizer.Add(item = ctype,
896 flag=wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT,
899 length = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1),
903 self.
layerPage[layer][
'addColLength'] = length.GetId()
904 addSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _(
"Length")),
905 flag = wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT,
907 addSizer.Add(item = length,
908 flag = wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT,
911 btnAddCol = wx.Button(parent = panel, id = wx.ID_ADD)
913 btnAddCol.Enable(
False)
914 self.
layerPage[layer][
'addColButton'] = btnAddCol.GetId()
915 addSizer.Add(item = btnAddCol, flag = wx.ALL | wx.ALIGN_RIGHT | wx.EXPAND,
919 renameBox = wx.StaticBox(parent = panel, id = wx.ID_ANY,
920 label =
" %s " % _(
"Rename column"))
921 renameSizer = wx.StaticBoxSizer(renameBox, wx.HORIZONTAL)
923 column = wx.ComboBox(parent = panel, id = wx.ID_ANY, size = (150, -1),
924 style = wx.CB_SIMPLE | wx.CB_READONLY,
925 choices = self.mapDBInfo.GetColumns(table))
926 column.SetSelection(0)
927 self.
layerPage[layer][
'renameCol'] = column.GetId()
928 renameSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _(
"Column")),
929 flag = wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT,
931 renameSizer.Add(item = column, proportion = 1,
932 flag = wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT,
935 columnTo = wx.TextCtrl(parent = panel, id = wx.ID_ANY, value =
'',
936 size = (150, -1), style = wx.TE_PROCESS_ENTER)
939 self.
layerPage[layer][
'renameColTo'] = columnTo.GetId()
940 renameSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _(
"To")),
941 flag = wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT,
943 renameSizer.Add(item = columnTo, proportion = 1,
944 flag = wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT,
947 btnRenameCol = wx.Button(parent = panel, id = wx.ID_ANY, label = _(
"&Rename"))
949 btnRenameCol.Enable(
False)
950 self.
layerPage[layer][
'renameColButton'] = btnRenameCol.GetId()
951 renameSizer.Add(item = btnRenameCol, flag = wx.ALL | wx.ALIGN_RIGHT | wx.EXPAND,
954 tableSizer.Add(item = list,
955 flag = wx.ALL | wx.EXPAND,
959 pageSizer.Add(item=dbSizer,
960 flag = wx.ALL | wx.EXPAND,
964 pageSizer.Add(item = tableSizer,
965 flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND,
969 pageSizer.Add(item = addSizer,
970 flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND,
973 pageSizer.Add(item = renameSizer,
974 flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND,
978 panel.SetSizer(pageSizer)
980 self.manageTablePage.SetSelection(0)
982 self.
layer = self.mapDBInfo.layers.keys()[0]
986 def __createTableDesc(self, parent, table):
987 """!Create list with table description"""
989 table=self.mapDBInfo.tables[table],
990 columns=self.mapDBInfo.GetColumns(table))
998 def __createManageLayerPage(self):
999 """!Create manage page"""
1000 splitterWin = wx.SplitterWindow(parent=self.
manageLayerPage, id=wx.ID_ANY)
1001 splitterWin.SetMinimumPaneSize(100)
1003 self.manageLayerPage.AddPage(page=splitterWin,
1004 text=_(
"Layers of vector map"))
1009 panelList = wx.Panel(parent=splitterWin, id=wx.ID_ANY)
1011 panelListSizer = wx.BoxSizer(wx.VERTICAL)
1012 layerBox = wx.StaticBox(parent=panelList, id=wx.ID_ANY,
1013 label=
" %s " % _(
"List of layers"))
1014 layerSizer = wx.StaticBoxSizer(layerBox, wx.VERTICAL)
1017 self.layerList.Bind(wx.EVT_COMMAND_RIGHT_CLICK, self.
OnLayerRightUp)
1021 flag=wx.ALL | wx.EXPAND,
1025 panelListSizer.Add(item=layerSizer,
1026 flag=wx.ALL | wx.EXPAND,
1030 panelList.SetSizer(panelListSizer)
1035 panelManage = wx.Panel(parent=splitterWin, id=wx.ID_ANY)
1037 manageSizer = wx.BoxSizer(wx.VERTICAL)
1044 flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND,
1047 panelManage.SetSizer(manageSizer)
1048 splitterWin.SplitHorizontally(panelList, panelManage, 100)
1051 def __createLayerDesc(self, parent):
1052 """!Create list of linked layers"""
1054 layers=self.mapDBInfo.layers)
1066 mainSizer = wx.BoxSizer(wx.VERTICAL)
1069 btnSizer = wx.BoxSizer(wx.HORIZONTAL)
1070 btnSizer.Add(item=self.
btnReload, proportion=1,
1071 flag=wx.ALL | wx.ALIGN_RIGHT, border=5)
1072 btnSizer.Add(item=self.
btnQuit, proportion=1,
1073 flag=wx.ALL | wx.ALIGN_RIGHT, border=5)
1075 mainSizer.Add(item=self.
notebook, proportion=1, flag=wx.EXPAND)
1076 mainSizer.Add(item=btnSizer, flag=wx.ALIGN_RIGHT | wx.ALL, border=5)
1078 self.panel.SetAutoLayout(
True)
1079 self.panel.SetSizer(mainSizer)
1080 mainSizer.Fit(self.
panel)
1084 """!Table description area, context menu"""
1085 if not hasattr(self,
"popupDataID1"):
1113 menu.Append(self.
popupDataID1, _(
"Edit selected record"))
1114 selected = list.GetFirstSelected()
1115 if not self.
editable or selected == -1
or list.GetNextSelected(selected) != -1:
1118 menu.Append(self.
popupDataID3, _(
"Delete selected record(s)"))
1119 menu.Append(self.
popupDataID4, _(
"Delete all records"))
1124 menu.AppendSeparator()
1127 menu.AppendSeparator()
1128 menu.Append(self.
popupDataID7, _(
"Highlight selected features"))
1129 menu.Append(self.
popupDataID8, _(
"Highlight selected features and zoom"))
1130 if not self.
map or len(list.GetSelectedItems()) == 0:
1133 menu.Append(self.
popupDataID9, _(
"Extract selected features"))
1134 menu.Append(self.
popupDataID11, _(
"Delete selected features"))
1137 if list.GetFirstSelected() == -1:
1141 menu.AppendSeparator()
1144 self.PopupMenu(menu)
1148 self.log.write(_(
"Number of loaded records: %d") % \
1149 list.GetItemCount())
1152 """!Delete selected item(s) from the list (layer/category pair)"""
1154 item = list.GetFirstSelected()
1156 table = self.mapDBInfo.layers[self.
layer][
"table"]
1157 key = self.mapDBInfo.layers[self.
layer][
"key"]
1162 index = list.itemIndexMap[item]
1163 indeces.append(index)
1165 cat = list.itemCatsMap[index]
1167 self.listOfSQLStatements.append(
'DELETE FROM %s WHERE %s=%d' % \
1170 item = list.GetNextSelected(item)
1172 if UserSettings.Get(group=
'atm', key=
'askOnDeleteRec', subkey=
'enabled'):
1173 deleteDialog = wx.MessageBox(parent=self,
1174 message=_(
"Selected data records (%d) will be permanently deleted "
1175 "from table. Do you want to delete them?") % \
1177 caption=_(
"Delete records"),
1178 style=wx.YES_NO | wx.CENTRE)
1179 if deleteDialog != wx.YES:
1185 indexTemp = copy.copy(list.itemIndexMap)
1186 list.itemIndexMap = []
1187 dataTemp = copy.deepcopy(list.itemDataMap)
1188 list.itemDataMap = {}
1189 catsTemp = copy.deepcopy(list.itemCatsMap)
1190 list.itemCatsMap = {}
1193 for index
in indexTemp:
1194 if index
in indeces:
1196 list.itemIndexMap.append(i)
1197 list.itemDataMap[i] = dataTemp[index]
1198 list.itemCatsMap[i] = catsTemp[index]
1202 list.SetItemCount(len(list.itemIndexMap))
1205 item = list.GetFirstSelected()
1207 list.SetItemState(item, 0, wx.LIST_STATE_SELECTED | wx.LIST_STATE_FOCUSED)
1208 item = list.GetNextSelected(item)
1216 """!Delete all items from the list"""
1218 if UserSettings.Get(group=
'atm', key=
'askOnDeleteRec', subkey=
'enabled'):
1219 deleteDialog = wx.MessageBox(parent=self,
1220 message=_(
"All data records (%d) will be permanently deleted "
1221 "from table. Do you want to delete them?") % \
1222 (len(list.itemIndexMap)),
1223 caption=_(
"Delete records"),
1224 style=wx.YES_NO | wx.CENTRE)
1225 if deleteDialog != wx.YES:
1228 list.DeleteAllItems()
1229 list.itemDataMap = {}
1230 list.itemIndexMap = []
1231 list.SetItemCount(0)
1233 table = self.mapDBInfo.layers[self.
layer][
"table"]
1234 self.listOfSQLStatements.append(
'DELETE FROM %s' % table)
1240 def _drawSelected(self, zoom):
1241 """!Highlight selected features"""
1246 cats =
map(int, list.GetSelectedItems())
1248 digitToolbar = self.mapdisplay.toolbars[
'vdigit']
1249 if digitToolbar
and digitToolbar.GetLayer()
and \
1250 digitToolbar.GetLayer().GetName() == self.
vectorName:
1252 self.mapdisplay.digit.driver.SetSelected(cats, field=self.
layer)
1254 n, s, w, e = self.mapdisplay.digit.driver.GetRegionSelected()
1255 self.mapdisplay.Map.GetRegion(n=n, s=s, w=w, e=e,
1262 if self.
parent and self.parent.GetName() ==
"LayerManager" and \
1264 maptree = self.parent.curr_page.maptree
1265 opacity = maptree.GetPyData(self.
treeItem)[0][
'maplayer'].GetOpacity(float=
True)
1266 self.qlayer.SetOpacity(opacity)
1268 keyColumn = self.mapDBInfo.layers[self.
layer][
'key']
1270 for range
in utils.ListOfCatsToRange(cats).
split(
','):
1272 min, max = range.split(
'-')
1273 where +=
'%s >= %d and %s <= %d or ' % \
1274 (keyColumn, int(min),
1275 keyColumn, int(max))
1277 where +=
'%s = %d or ' % (keyColumn, int(range))
1278 where = where.rstrip(
'or ')
1280 select = gcmd.RunCommand(
'v.db.select',
1285 map = self.mapDBInfo.map,
1286 layer = int(self.layer),
1290 for line
in select.splitlines():
1291 key, value = line.split(
'=')
1292 region[key.strip()] = float(value.strip())
1294 self.mapdisplay.Map.GetRegion(n=region[
'n'], s=region[
's'],
1295 w=region[
'w'], e=region[
'e'],
1299 self.mapdisplay.Map.AdjustRegion()
1300 self.mapdisplay.Map.AlignExtentFromDisplay()
1301 self.mapdisplay.MapWindow.UpdateMap(render=
True, renderVector=
True)
1303 self.mapdisplay.MapWindow.UpdateMap(render=
False, renderVector=
True)
1306 """!Reload table description"""
1315 """!Add new record to the attribute table"""
1317 table = self.mapDBInfo.layers[self.
layer][
'table']
1318 keyColumn = self.mapDBInfo.layers[self.
layer][
'key']
1325 for i
in range(list.GetColumnCount()):
1326 columnName.append(list.GetColumn(i).GetText())
1329 if len(list.itemCatsMap.values()) > 0:
1330 maxCat =
max(list.itemCatsMap.values())
1335 if keyColumn
not in columnName:
1336 columnName.insert(0, keyColumn)
1337 data.append((keyColumn, str(maxCat + 1)))
1345 for col
in columnName:
1346 if col == keyColumn:
1347 if missingKey
is False:
1348 data.append((col, str(maxCat + 1)))
1351 data.append((col,
''))
1354 dlg = ModifyTableRecord(parent = self,
1355 title = _(
"Insert new record"),
1356 data = data, keyEditable = (keyId,
True))
1358 if dlg.ShowModal() == wx.ID_OK:
1360 cat = int(dlg.GetValues(columns=[keyColumn])[0])
1365 if cat
in list.itemCatsMap.values():
1366 raise ValueError(_(
"Record with category number %d "
1367 "already exists in the table.") % cat)
1369 values = dlg.GetValues()
1373 for i
in range(len(values)):
1374 if len(values[i]) == 0:
1375 if columnName[i] == keyColumn:
1376 raise ValueError(_(
"Category number (column %s)"
1377 " is missing.") % keyColumn)
1382 if list.columns[columnName[i]][
'ctype'] == int:
1384 value = float(values[i])
1387 values[i] = list.columns[columnName[i]][
'ctype'] (value)
1390 raise ValueError(_(
"Value '%(value)s' needs to be entered as %(type)s.") %
1391 {
'value' : str(values[i]),
1392 'type' : list.columns[columnName[i]][
'type']})
1393 columnsString +=
'%s,' % columnName[i]
1394 if list.columns[columnName[i]][
'ctype'] == str:
1395 valuesString +=
"'%s'," % values[i]
1397 valuesString +=
"%s," % values[i]
1399 except ValueError, err:
1400 wx.MessageBox(parent=self,
1401 message=
"%s%s%s" % (_(
"Unable to insert new record."),
1403 caption=_(
"Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
1407 if missingKey
is True:
1411 if len(list.itemIndexMap) > 0:
1412 index =
max(list.itemIndexMap) + 1
1416 list.itemIndexMap.append(index)
1417 list.itemDataMap[index] = values
1418 list.itemCatsMap[index] = cat
1419 list.SetItemCount(list.GetItemCount() + 1)
1421 self.listOfSQLStatements.append(
'INSERT INTO %s (%s) VALUES(%s)' % \
1423 columnsString.strip(
','),
1424 valuesString.strip(
',')))
1428 """!Edit selected record of the attribute table"""
1430 item = list.GetFirstSelected()
1434 table = self.mapDBInfo.layers[self.
layer][
'table']
1435 keyColumn = self.mapDBInfo.layers[self.
layer][
'key']
1436 cat = list.itemCatsMap[list.itemIndexMap[item]]
1443 for i
in range(list.GetColumnCount()):
1444 columnName.append(list.GetColumn(i).GetText())
1448 if keyColumn
not in columnName:
1449 columnName.insert(0, keyColumn)
1450 data.append((keyColumn, str(cat)))
1457 for i
in range(len(columnName)):
1458 if columnName[i] == keyColumn:
1459 if missingKey
is False:
1460 data.append((columnName[i], str(cat)))
1463 if missingKey
is True:
1464 value = list.GetItem(item, i-1).GetText()
1466 value = list.GetItem(item, i).GetText()
1467 data.append((columnName[i], value))
1469 dlg = ModifyTableRecord(parent = self,
1470 title = _(
"Update existing record"),
1471 data = data, keyEditable = (keyId,
False))
1473 if dlg.ShowModal() == wx.ID_OK:
1474 values = dlg.GetValues()
1477 for i
in range(len(values)):
1480 if list.GetItem(item, i).GetText() != values[i]:
1481 if len(values[i]) > 0:
1483 if missingKey
is True:
1487 if list.columns[columnName[i]][
'ctype'] !=
type(
''):
1488 if list.columns[columnName[i]][
'ctype'] == int:
1489 value = float(values[i])
1492 list.itemDataMap[item][idx] = \
1493 list.columns[columnName[i]][
'ctype'] (value)
1495 list.itemDataMap[item][idx] = values[i]
1497 raise ValueError(_(
"Value '%(value)s' needs to be entered as %(type)s.") % \
1498 {
'value' : str(values[i]),
1499 'type' : list.columns[columnName[i]][
'type']})
1501 if list.columns[columnName[i]][
'ctype'] == str:
1502 updateString +=
"%s='%s'," % (columnName[i], values[i])
1504 updateString +=
"%s=%s," % (columnName[i], values[i])
1506 updateString +=
"%s=NULL," % (columnName[i])
1508 except ValueError, err:
1509 wx.MessageBox(parent=self,
1510 message=
"%s%s%s" % (_(
"Unable to update existing record."),
1512 caption=_(
"Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
1515 if len(updateString) > 0:
1516 self.listOfSQLStatements.append(
'UPDATE %s SET %s WHERE %s=%d' % \
1517 (table, updateString.strip(
','),
1524 """!Reload list of records"""
1529 """!Select all items"""
1534 item = list.GetNextItem(item)
1537 list.SetItemState(item, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED)
1542 """!Deselect items"""
1547 item = list.GetNextItem(item, wx.LIST_STATE_SELECTED)
1550 list.SetItemState(item, 0, wx.LIST_STATE_SELECTED | wx.LIST_STATE_FOCUSED)
1556 """!Data type for new column changed. Enable or disable
1557 data length widget"""
1558 win = self.FindWindowById(self.
layerPage[self.
layer][
'addColLength'])
1559 if event.GetString() ==
"varchar":
1565 """!Editing column name to be added to the table"""
1566 btn = self.FindWindowById(self.
layerPage[self.
layer][
'renameColButton'])
1567 col = self.FindWindowById(self.
layerPage[self.
layer][
'renameCol'])
1568 colTo = self.FindWindowById(self.
layerPage[self.
layer][
'renameColTo'])
1569 if len(col.GetValue()) > 0
and len(colTo.GetValue()) > 0:
1577 """!Editing column name to be added to the table"""
1578 btn = self.FindWindowById(self.
layerPage[self.
layer][
'addColButton'])
1579 if len(event.GetString()) > 0:
1587 """!Rename column in the table"""
1588 list = self.FindWindowById(self.
layerPage[self.
layer][
'tableData'])
1589 name = self.FindWindowById(self.
layerPage[self.
layer][
'renameCol']).GetValue()
1590 nameTo = self.FindWindowById(self.
layerPage[self.
layer][
'renameColTo']).GetValue()
1592 table = self.mapDBInfo.layers[self.
layer][
"table"]
1594 if not name
or not nameTo:
1595 wx.MessageBox(self=self,
1596 message=_(
"Unable to rename column. "
1597 "No column name defined."),
1598 caption=_(
"Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
1601 item = list.FindItem(start=-1, str=name)
1603 if list.FindItem(start=-1, str=nameTo) > -1:
1604 wx.MessageBox(parent=self,
1605 message=_(
"Unable to rename column <%(column)s> to "
1606 "<%(columnTo)s>. Column already exists "
1607 "in the table <%(table)s>.") % \
1608 {
'column' : name,
'columnTo' : nameTo,
1610 caption=_(
"Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
1613 list.SetItemText(item, nameTo)
1615 self.listOfCommands.append((
'v.db.renamecol',
1617 'layer' : self.
layer,
1618 'column' :
'%s,%s' % (name, nameTo) }
1621 wx.MessageBox(parent=self,
1622 message=_(
"Unable to rename column. "
1623 "Column <%(column)s> doesn't exist in the table <%(table)s>.") %
1624 {
'column' : name,
'table' : table},
1625 caption=_(
"Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
1632 self.FindWindowById(self.
layerPage[self.
layer][
'renameCol']).SetItems(self.mapDBInfo.GetColumns(table))
1633 self.FindWindowById(self.
layerPage[self.
layer][
'renameCol']).SetSelection(0)
1634 self.FindWindowById(self.
layerPage[self.
layer][
'renameColTo']).SetValue(
'')
1639 """!Table description area, context menu"""
1640 if not hasattr(self,
"popupTableID"):
1651 if self.FindWindowById(self.
layerPage[self.
layer][
'tableData']).GetFirstSelected() == -1:
1654 menu.AppendSeparator()
1657 self.PopupMenu(menu)
1661 """!Delete selected item(s) from the list"""
1662 list = self.FindWindowById(self.
layerPage[self.
layer][
'tableData'])
1664 item = list.GetFirstSelected()
1666 if UserSettings.Get(group=
'atm', key=
'askOnDeleteRec', subkey=
'enabled'):
1667 deleteDialog = wx.MessageBox(parent=self,
1668 message=_(
"Selected column '%s' will PERMANENTLY removed "
1669 "from table. Do you want to drop the column?") % \
1670 (list.GetItemText(item)),
1671 caption=_(
"Drop column(s)"),
1672 style=wx.YES_NO | wx.CENTRE)
1673 if deleteDialog != wx.YES:
1677 self.listOfCommands.append((
'v.db.dropcol',
1679 'layer' : self.
layer,
1680 'column' : list.GetItemText(item) }
1682 list.DeleteItem(item)
1683 item = list.GetFirstSelected()
1689 table = self.mapDBInfo.layers[self.
layer][
'table']
1690 self.FindWindowById(self.
layerPage[self.
layer][
'renameCol']).SetItems(self.mapDBInfo.GetColumns(table))
1691 self.FindWindowById(self.
layerPage[self.
layer][
'renameCol']).SetSelection(0)
1696 """!Delete all items from the list"""
1697 table = self.mapDBInfo.layers[self.
layer][
'table']
1698 cols = self.mapDBInfo.GetColumns(table)
1699 keyColumn = self.mapDBInfo.layers[self.
layer][
'key']
1700 if keyColumn
in cols:
1701 cols.remove(keyColumn)
1703 if UserSettings.Get(group=
'atm', key=
'askOnDeleteRec', subkey=
'enabled'):
1704 deleteDialog = wx.MessageBox(parent=self,
1705 message=_(
"Selected columns\n%s\nwill PERMANENTLY removed "
1706 "from table. Do you want to drop the columns?") % \
1708 caption=_(
"Drop column(s)"),
1709 style=wx.YES_NO | wx.CENTRE)
1710 if deleteDialog != wx.YES:
1714 self.listOfCommands.append((
'v.db.dropcol',
1716 'layer' : self.
layer,
1719 self.FindWindowById(self.
layerPage[self.
layer][
'tableData']).DeleteAllItems()
1725 table = self.mapDBInfo.layers[self.
layer][
'table']
1726 self.FindWindowById(self.
layerPage[self.
layer][
'renameCol']).SetItems(self.mapDBInfo.GetColumns(table))
1727 self.FindWindowById(self.
layerPage[self.
layer][
'renameCol']).SetSelection(0)
1732 """!Reload table description"""
1733 self.FindWindowById(self.
layerPage[self.
layer][
'tableData']).Populate(update=
True)
1737 """!Add new column to the table"""
1738 table = self.mapDBInfo.layers[self.layer][
'table']
1739 name = self.FindWindowById(self.layerPage[self.layer][
'addColName']).GetValue()
1742 gcmd.GError(parent = self,
1743 message = _(
"Unable to add column to the table. "
1744 "No column name defined."))
1747 ctype = self.FindWindowById(self.layerPage[self.layer][
'addColType']). \
1748 GetStringSelection()
1751 if ctype ==
'double':
1752 ctype =
'double precision'
1753 if ctype ==
'varchar':
1754 length = int(self.FindWindowById(self.layerPage[self.layer][
'addColLength']). \
1760 tlist = self.FindWindowById(self.layerPage[self.layer][
'tableData'])
1762 if tlist.FindItem(start=-1, str=name) > -1:
1763 gcmd.GError(parent = self,
1764 message = _(
"Column <%(column)s> already exists in table <%(table)s>.") % \
1765 {
'column' : name,
'table' : self.mapDBInfo.layers[self.layer][
"table"]}
1768 index = tlist.InsertStringItem(sys.maxint, str(name))
1769 tlist.SetStringItem(index, 0, str(name))
1770 tlist.SetStringItem(index, 1, str(ctype))
1771 tlist.SetStringItem(index, 2, str(length))
1774 if ctype ==
'varchar':
1775 ctype +=
' (%d)' % length
1776 self.listOfCommands.append((
'v.db.addcol',
1777 {
'map' : self.vectorName,
1778 'layer' : self.layer,
1779 'columns' :
'%s %s' % (name, ctype) }
1782 self.ApplyCommands()
1785 self.FindWindowById(self.layerPage[self.layer][
'addColName']).SetValue(
'')
1786 self.FindWindowById(self.layerPage[self.layer][
'renameCol']).SetItems(self.mapDBInfo.GetColumns(table))
1787 self.FindWindowById(self.layerPage[self.layer][
'renameCol']).SetSelection(0)
1792 """!Layer tab changed"""
1793 pageNum = event.GetSelection()
1794 self.
layer = self.mapDBInfo.layers.keys()[pageNum]
1804 self.log.write(_(
"Number of loaded records: %d") % \
1811 winCol = self.FindWindowById(idCol)
1812 table = self.mapDBInfo.layers[self.
layer][
"table"]
1813 self.mapDBInfo.GetColumns(table)
1823 if event.GetSelection() == 0
and id:
1824 win = self.FindWindowById(id)
1826 self.log.write(_(
"Number of loaded records: %d") % win.GetItemCount())
1829 self.btnReload.Enable()
1832 self.btnReload.Enable(
False)
1837 """!Layer description area, context menu"""
1841 """!Switch simple/advanced sql statement"""
1842 if self.FindWindowById(self.layerPage[self.layer][
'simple']).GetValue():
1843 self.FindWindowById(self.layerPage[self.layer][
'where']).Enable(
True)
1844 self.FindWindowById(self.layerPage[self.layer][
'statement']).Enable(
False)
1845 self.FindWindowById(self.layerPage[self.layer][
'builder']).Enable(
False)
1847 self.FindWindowById(self.layerPage[self.layer][
'where']).Enable(
False)
1848 self.FindWindowById(self.layerPage[self.layer][
'statement']).Enable(
True)
1849 self.FindWindowById(self.layerPage[self.layer][
'builder']).Enable(
True)
1852 """!Apply changes"""
1854 wx.BeginBusyCursor()
1858 gcmd.RunCommand(prog = cmd[0],
1864 table = self.mapDBInfo.layers[self.
layer][
'table']
1867 list = self.FindWindowById(self.
layerPage[self.
layer][
'tableData'])
1868 list.Update(table=self.mapDBInfo.tables[table],
1869 columns=self.mapDBInfo.GetColumns(table))
1881 sqlFile = tempfile.NamedTemporaryFile(mode=
"wt")
1883 enc = UserSettings.Get(group=
'atm', key=
'encoding', subkey=
'value')
1884 if not enc
and 'GRASS_DB_ENCODING' in os.environ:
1885 enc = os.environ[
'GRASS_DB_ENCODING']
1887 sqlFile.file.write(sql.encode(enc) +
';')
1889 sqlFile.file.write(sql +
';')
1890 sqlFile.file.write(os.linesep)
1891 sqlFile.file.flush()
1893 driver = self.mapDBInfo.layers[self.
layer][
"driver"]
1894 database = self.mapDBInfo.layers[self.
layer][
"database"]
1896 Debug.msg(3,
'AttributeManger.ApplyCommands(): %s' %
1899 gcmd.RunCommand(
'db.execute',
1901 input = sqlFile.name,
1903 database = database)
1911 """!Apply simple/advanced sql statement"""
1913 listWin = self.FindWindowById(self.
layerPage[self.
layer][
'data'])
1916 wx.BeginBusyCursor()
1918 if self.FindWindowById(self.
layerPage[self.
layer][
'simple']).GetValue():
1920 whereCol = self.FindWindowById(self.
layerPage[self.
layer][
'whereColumn']).GetStringSelection()
1921 whereVal = self.FindWindowById(self.
layerPage[self.
layer][
'where']).GetValue().strip()
1923 if len(whereVal) > 0:
1924 keyColumn = listWin.LoadData(self.
layer, where=whereCol + whereVal)
1926 keyColumn = listWin.LoadData(self.
layer)
1929 message = _(
"Loading attribute data failed.\n\n%s") % e.value)
1930 self.FindWindowById(self.
layerPage[self.
layer][
'where']).SetValue(
'')
1933 win = self.FindWindowById(self.
layerPage[self.
layer][
'statement'])
1936 if cols
is None and where
is None:
1937 sql = win.GetValue()
1939 wx.MessageBox(parent=self,
1940 message=_(
"Loading attribute data failed.\n"
1941 "Invalid SQL select statement.\n\n%s") % win.GetValue(),
1942 caption=_(
"Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
1943 win.SetValue(
"SELECT * FROM %s" % self.mapDBInfo.layers[self.
layer][
'table'])
1947 if cols
or where
or sql:
1949 keyColumn = listWin.LoadData(self.
layer, columns=cols,
1950 where=where, sql=sql)
1953 message = _(
"Loading attribute data failed.\n\n%s") % e.value)
1954 win.SetValue(
"SELECT * FROM %s" % self.mapDBInfo.layers[self.
layer][
'table'])
1957 if sql
and 'order by' in sql.lower():
1961 listWin.SortListItems(col=keyColumn, ascending=
True)
1963 listWin.SortListItems(col=0, ascending=
True)
1968 self.log.write(_(
"Number of loaded records: %d") % \
1969 self.FindWindowById(self.
layerPage[self.
layer][
'data']).GetItemCount())
1972 """!Validate SQL select statement
1974 @return (columns, where)
1975 @return None on error
1977 if statement[0:7].lower() !=
'select ':
1982 for c
in statement[index:]:
1990 cols = cols.split(
',')
1992 tablelen = len(self.mapDBInfo.layers[self.
layer][
'table'])
1994 if statement[index+1:index+6].lower() !=
'from ' or \
1995 statement[index+6:index+6+tablelen] !=
'%s' % \
1996 (self.mapDBInfo.layers[self.
layer][
'table']):
1999 if len(statement[index+7+tablelen:]) > 0:
2000 index = statement.lower().find(
'where ')
2002 where = statement[index+6:]
2008 return (cols, where)
2011 """!Cancel button pressed"""
2013 if self.
parent and self.parent.GetName() ==
'LayerManager':
2015 self.parent.dialogs[
'atm'].remove(self)
2020 """!SQL Builder button pressed -> show the SQLBuilder dialog"""
2023 title = _(
"SQL Builder"),
2028 self.builder.Raise()
2031 if event ==
'apply':
2032 sqlstr = self.builder.GetSQLStatement()
2033 self.FindWindowById(self.
layerPage[self.
layer][
'statement']).SetValue(sqlstr)
2034 if self.builder.CloseOnApply():
2036 elif event ==
'close':
2043 """!Item activated, highlight selected item"""
2044 self.OnDataDrawSelected(event)
2049 """!Extract vector objects selected in attribute browse window
2054 cats = list.GetSelectedItems()
2056 wx.MessageBox(parent=self,
2057 message=_(
'Nothing to extract.'),
2058 caption=_(
'Message'), style=wx.CENTRE)
2062 dlg = gdialogs.CreateNewVector(parent = self, title = _(
'Extract selected features'),
2064 cmd = ((
'v.extract',
2066 'list' : utils.ListOfCatsToRange(cats) },
2068 disableTable =
True)
2072 name = dlg.GetName(full =
True)
2073 if name
and dlg.IsChecked(
'add'):
2075 self.parent.curr_page.maptree.AddLayer(ltype =
'vector',
2077 lcmd = [
'd.vect',
'map=%s' % name])
2082 Delete vector objects selected in attribute browse window
2083 (attribures and geometry)
2086 cats = list.GetSelectedItems()
2088 wx.MessageBox(parent=self,
2089 message=_(
'Nothing to delete.'),
2090 caption=_(
'Message'), style=wx.CENTRE)
2093 digitToolbar = self.mapdisplay.toolbars[
'vdigit']
2094 if digitToolbar
and digitToolbar.GetLayer()
and \
2095 digitToolbar.GetLayer().GetName() == self.
vectorName:
2096 self.mapdisplay.digit.driver.SetSelected(
map(int, cats), field=self.
layer)
2097 self.mapdisplay.digit.DeleteSelectedLines()
2099 gcmd.RunCommand(
'v.edit',
2104 cats = utils.ListOfCatsToRange(cats))
2106 self.mapdisplay.MapWindow.UpdateMap(render=
True, renderVector=
True)
2111 Return True if map has been redrawn, False if no map is given
2115 self.
layer : list.GetSelectedItems()
2118 if self.mapdisplay.Map.GetLayerIndex(self.
qlayer) < 0:
2122 self.qlayer.SetCmd(self.mapdisplay.AddTmpVectorMapLayer(self.
vectorName, cats, addLayer=
False))
2129 """!Updates dialog layout for given layer"""
2133 if layer
in self.mapDBInfo.layers.keys():
2139 self.browsePage.DeletePage(self.mapDBInfo.layers.keys().index(layer))
2140 self.manageTablePage.DeletePage(self.mapDBInfo.layers.keys().index(layer))
2142 self.notebook.SetSelection(2)
2150 if layer
in self.mapDBInfo.layers.keys():
2156 self.notebook.SetSelection(2)
2162 self.layerList.Update(self.mapDBInfo.layers)
2163 self.layerList.Populate(update=
True)
2165 listOfLayers =
map(str, self.mapDBInfo.layers.keys())
2167 self.manageLayerBook.deleteLayer.SetItems(listOfLayers)
2168 if len(listOfLayers) > 0:
2169 self.manageLayerBook.deleteLayer.SetStringSelection(listOfLayers[0])
2170 tableName = self.mapDBInfo.layers[int(listOfLayers[0])][
'table']
2171 maxLayer =
max(self.mapDBInfo.layers.keys())
2175 self.manageLayerBook.deleteTable.SetLabel( \
2176 _(
'Drop also linked attribute table (%s)') % \
2179 self.manageLayerBook.addLayerWidgets[
'layer'][1].SetValue(\
2182 self.manageLayerBook.modifyLayerWidgets[
'layer'][1].SetItems(listOfLayers)
2183 self.manageLayerBook.OnChangeLayer(event=
None)
2186 """!Get vector name"""
2189 def LoadData(self, layer, columns=None, where=None, sql=None):
2190 """!Load data into list
2192 @param layer layer number
2193 @param columns list of columns for output
2194 @param where where statement
2195 @param sql full sql statement
2197 @return id of key column
2198 @return -1 if key column is not displayed
2200 listWin = self.FindWindowById(self.
layerPage[layer][
'data'])
2201 return listWin.LoadData(layer, columns, where, sql)
2204 listmix.ListCtrlAutoWidthMixin):
2206 """!Table description list"""
2208 def __init__(self, parent, id, table, columns, pos=wx.DefaultPosition,
2209 size=wx.DefaultSize):
2214 wx.ListCtrl.__init__(self, parent, id, pos, size,
2215 style=wx.LC_REPORT | wx.LC_HRULES | wx.LC_VRULES |
2218 listmix.ListCtrlAutoWidthMixin.__init__(self)
2222 """!Update column description"""
2227 """!Populate the list"""
2231 headings = [_(
"Column name"), _(
"Data type"), _(
"Data length")]
2234 self.InsertColumn(col=i, heading=h)
2235 self.SetColumnWidth(col=i, width=150)
2238 self.DeleteAllItems()
2242 index = self.InsertStringItem(sys.maxint, str(column))
2243 self.SetStringItem(index, 0, str(column))
2244 self.SetStringItem(index, 1, str(self.
table[column][
'type']))
2245 self.SetStringItem(index, 2, str(self.
table[column][
'length']))
2246 self.SetItemData(index, i)
2247 itemData[i] = (str(column),
2248 str(self.
table[column][
'type']),
2249 int(self.
table[column][
'length']))
2252 self.SendSizeEvent()
2257 listmix.ListCtrlAutoWidthMixin):
2260 """!Layer description list"""
2262 def __init__(self, parent, id, layers,
2263 pos=wx.DefaultPosition,
2264 size=wx.DefaultSize):
2268 wx.ListCtrl.__init__(self, parent, id, pos, size,
2269 style=wx.LC_REPORT | wx.LC_HRULES | wx.LC_VRULES |
2272 listmix.ListCtrlAutoWidthMixin.__init__(self)
2276 """!Update description"""
2280 """!Populate the list"""
2284 headings = [_(
"Layer"), _(
"Driver"), _(
"Database"), _(
"Table"), _(
"Key")]
2287 self.InsertColumn(col=i, heading=h)
2290 self.DeleteAllItems()
2293 for layer
in self.layers.keys():
2294 index = self.InsertStringItem(sys.maxint, str(layer))
2295 self.SetStringItem(index, 0, str(layer))
2296 database = str(self.
layers[layer][
'database'])
2297 driver = str(self.
layers[layer][
'driver'])
2298 table = str(self.
layers[layer][
'table'])
2299 key = str(self.
layers[layer][
'key'])
2300 self.SetStringItem(index, 1, driver)
2301 self.SetStringItem(index, 2, database)
2302 self.SetStringItem(index, 3, table)
2303 self.SetStringItem(index, 4, key)
2304 self.SetItemData(index, i)
2305 itemData[i] = (str(layer),
2312 for i
in range(self.GetColumnCount()):
2313 self.SetColumnWidth(col=i, width=wx.LIST_AUTOSIZE)
2314 if self.GetColumnWidth(col=i) < 60:
2315 self.SetColumnWidth(col=i, width=60)
2317 self.SendSizeEvent()
2322 """!Manage layers (add, delete, modify)"""
2325 style=wx.BK_DEFAULT):
2326 wx.Notebook.__init__(self, parent, id, style=style)
2335 drivers = gcmd.RunCommand(
'db.drivers',
2341 for drv
in drivers.splitlines():
2342 self.listOfDrivers.append(drv.strip())
2348 connect = gcmd.RunCommand(
'db.connect',
2353 for line
in connect.splitlines():
2354 item, value = line.split(
':', 1)
2359 wx.MessageBox(parent=self.
parent,
2360 message=_(
"Unknown default DB connection. "
2361 "Please define DB connection using db.connect module."),
2362 caption=_(
"Warning"),
2363 style=wx.OK | wx.ICON_WARNING | wx.CENTRE)
2378 def __createAddPage(self):
2379 """!Add new layer"""
2381 self.AddPage(page=self.
addPanel, text=_(
"Add layer"))
2384 maxLayer =
max(self.mapDBInfo.layers.keys())
2390 layerBox = wx.StaticBox (parent=self.
addPanel, id=wx.ID_ANY,
2391 label=
" %s " % (_(
"Layer description")))
2392 layerSizer = wx.StaticBoxSizer(layerBox, wx.VERTICAL)
2398 (wx.StaticText(parent=self.
addPanel, id=wx.ID_ANY,
2399 label=
'%s:' % _(
"Layer")),
2400 wx.SpinCtrl(parent=self.
addPanel, id=wx.ID_ANY, size=(65, -1),
2404 (wx.StaticText(parent=self.
addPanel, id=wx.ID_ANY,
2405 label=
'%s:' % _(
"Driver")),
2406 wx.Choice(parent=self.
addPanel, id=wx.ID_ANY, size=(200, -1),
2409 (wx.StaticText(parent=self.
addPanel, id=wx.ID_ANY,
2410 label=
'%s:' % _(
"Database")),
2411 wx.TextCtrl(parent=self.
addPanel, id=wx.ID_ANY,
2413 style=wx.TE_PROCESS_ENTER)),
2415 (wx.StaticText(parent=self.
addPanel, id=wx.ID_ANY,
2416 label=
'%s:' % _(
"Table")),
2417 wx.Choice(parent=self.
addPanel, id=wx.ID_ANY, size=(200, -1),
2420 (wx.StaticText(parent=self.
addPanel, id=wx.ID_ANY,
2421 label=
'%s:' % _(
"Key column")),
2422 wx.Choice(parent=self.
addPanel, id=wx.ID_ANY, size=(200, -1),
2425 (wx.CheckBox(parent=self.
addPanel, id=wx.ID_ANY,
2426 label=_(
"Insert record for each category into table")),
2441 self.
addLayerWidgets[
'addCat'][0].SetToolTipString(_(
"You need to add categories "
2442 "by v.category module."))
2446 keyCol = UserSettings.Get(group=
'atm', key=
'keycolumn', subkey=
'value')
2448 label=
'%s:' % _(
"Table name")),
2449 wx.TextCtrl(parent=self.
addPanel, id=wx.ID_ANY,
2451 style=wx.TE_PROCESS_ENTER)),
2452 'key': (wx.StaticText(parent=self.
addPanel, id=wx.ID_ANY,
2453 label=
'%s:' % _(
"Key column")),
2454 wx.TextCtrl(parent=self.
addPanel, id=wx.ID_ANY,
2456 style=wx.TE_PROCESS_ENTER))}
2461 btnTable = wx.Button(self.
addPanel, wx.ID_ANY, _(
"&Create table"),
2465 btnLayer = wx.Button(self.
addPanel, wx.ID_ANY, _(
"&Add layer"),
2467 btnLayer.Bind(wx.EVT_BUTTON, self.
OnAddLayer)
2469 btnDefault = wx.Button(self.
addPanel, wx.ID_ANY, _(
"&Set default"),
2475 pageSizer = wx.BoxSizer(wx.HORIZONTAL)
2478 dataSizer = wx.GridBagSizer(hgap=5, vgap=5)
2479 dataSizer.AddGrowableCol(1)
2481 for key
in (
'layer',
'driver',
'database',
'table',
'key',
'addCat'):
2487 dataSizer.Add(item=label,
2488 flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0),
2495 if label.GetLabel() ==
"Layer:":
2496 style = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT
2498 style = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND
2500 dataSizer.Add(item=value,
2501 flag=style, pos=(row, 1))
2505 layerSizer.Add(item=dataSizer,
2507 flag=wx.ALL | wx.EXPAND,
2510 btnSizer = wx.BoxSizer(wx.HORIZONTAL)
2511 btnSizer.Add(item=btnDefault,
2513 flag=wx.ALL | wx.ALIGN_LEFT,
2516 btnSizer.Add(item=(5, 5),
2518 flag=wx.ALL | wx.EXPAND,
2521 btnSizer.Add(item=btnLayer,
2523 flag=wx.ALL | wx.ALIGN_RIGHT,
2526 layerSizer.Add(item=btnSizer,
2528 flag=wx.ALL | wx.EXPAND,
2532 tableBox = wx.StaticBox (parent=self.
addPanel, id=wx.ID_ANY,
2533 label=
" %s " % (_(
"Table description")))
2534 tableSizer = wx.StaticBoxSizer(tableBox, wx.VERTICAL)
2537 dataSizer = wx.FlexGridSizer(cols=2, hgap=5, vgap=5)
2538 dataSizer.AddGrowableCol(1)
2539 for key
in [
'table',
'key']:
2541 dataSizer.Add(item=label,
2542 flag=wx.ALIGN_CENTER_VERTICAL)
2543 dataSizer.Add(item=value,
2544 flag=wx.ALIGN_CENTER_VERTICAL | wx.EXPAND)
2546 tableSizer.Add(item=dataSizer,
2548 flag=wx.ALL | wx.EXPAND,
2551 tableSizer.Add(item=btnTable,
2553 flag=wx.ALL | wx.ALIGN_BOTTOM | wx.ALIGN_RIGHT,
2556 pageSizer.Add(item=layerSizer,
2558 flag=wx.ALL | wx.EXPAND,
2561 pageSizer.Add(item=tableSizer,
2563 flag=wx.TOP | wx.BOTTOM | wx.RIGHT | wx.EXPAND,
2566 layerSizer.SetVirtualSizeHints(self.
addPanel)
2567 self.addPanel.SetAutoLayout(
True)
2568 self.addPanel.SetSizer(pageSizer)
2571 def __createDeletePage(self):
2574 self.AddPage(page=self.
deletePanel, text=_(
"Remove layer"))
2576 label = wx.StaticText(parent=self.
deletePanel, id=wx.ID_ANY,
2577 label=
'%s:' % _(
"Layer to remove"))
2580 style=wx.CB_SIMPLE | wx.CB_READONLY,
2581 choices=
map(str, self.mapDBInfo.layers.keys()))
2582 self.deleteLayer.SetSelection(0)
2586 tableName = self.mapDBInfo.layers[int(self.deleteLayer.GetStringSelection())][
'table']
2591 label=_(
'Drop also linked attribute table (%s)') % \
2595 self.deleteLayer.Enable(
False)
2596 self.deleteTable.Enable(
False)
2598 btnDelete = wx.Button(self.
deletePanel, wx.ID_DELETE, _(
"&Remove layer"),
2605 pageSizer = wx.BoxSizer(wx.VERTICAL)
2607 dataSizer = wx.BoxSizer(wx.VERTICAL)
2609 flexSizer = wx.FlexGridSizer(cols=2, hgap=5, vgap=5)
2610 flexSizer.AddGrowableCol(2)
2612 flexSizer.Add(item=label,
2613 flag=wx.ALIGN_CENTER_VERTICAL)
2615 flag=wx.ALIGN_CENTER_VERTICAL)
2617 dataSizer.Add(item=flexSizer,
2619 flag=wx.ALL | wx.EXPAND,
2624 flag=wx.ALL | wx.EXPAND,
2627 pageSizer.Add(item=dataSizer,
2629 flag=wx.ALL | wx.EXPAND,
2632 pageSizer.Add(item=btnDelete,
2634 flag=wx.ALL | wx.ALIGN_RIGHT,
2637 self.deletePanel.SetSizer(pageSizer)
2639 def __createModifyPage(self):
2642 self.AddPage(page=self.
modifyPanel, text=_(
"Modify layer"))
2648 (wx.StaticText(parent=self.
modifyPanel, id=wx.ID_ANY,
2649 label=
'%s:' % _(
"Layer")),
2650 wx.ComboBox(parent=self.
modifyPanel, id=wx.ID_ANY,
2652 style=wx.CB_SIMPLE | wx.CB_READONLY,
2654 self.mapDBInfo.layers.keys()))),
2656 (wx.StaticText(parent=self.
modifyPanel, id=wx.ID_ANY,
2657 label=
'%s:' % _(
"Driver")),
2662 (wx.StaticText(parent=self.
modifyPanel, id=wx.ID_ANY,
2663 label=
'%s:' % _(
"Database")),
2664 wx.TextCtrl(parent=self.
modifyPanel, id=wx.ID_ANY,
2665 value=
'', size=(350, -1),
2666 style=wx.TE_PROCESS_ENTER)),
2668 (wx.StaticText(parent=self.
modifyPanel, id=wx.ID_ANY,
2669 label=
'%s:' % _(
"Table")),
2674 (wx.StaticText(parent=self.
modifyPanel, id=wx.ID_ANY,
2675 label=
'%s:' % _(
"Key column")),
2686 for label
in self.modifyLayerWidgets.keys():
2690 driver = self.mapDBInfo.layers[layer][
'driver']
2691 database = self.mapDBInfo.layers[layer][
'database']
2692 table = self.mapDBInfo.layers[layer][
'table']
2694 listOfColumns = self.
__getColumns(driver, database, table)
2703 table =
'public.' + table
2714 btnModify = wx.Button(self.
modifyPanel, wx.ID_DELETE, _(
"&Modify layer"),
2721 pageSizer = wx.BoxSizer(wx.VERTICAL)
2724 dataSizer = wx.FlexGridSizer(cols=2, hgap=5, vgap=5)
2725 dataSizer.AddGrowableCol(1)
2726 for key
in (
'layer',
'driver',
'database',
'table',
'key'):
2728 dataSizer.Add(item=label,
2729 flag=wx.ALIGN_CENTER_VERTICAL)
2730 if label.GetLabel() ==
"Layer:":
2731 dataSizer.Add(item=value,
2732 flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT)
2734 dataSizer.Add(item=value,
2735 flag=wx.ALIGN_CENTER_VERTICAL)
2737 pageSizer.Add(item=dataSizer,
2739 flag=wx.ALL | wx.EXPAND,
2742 pageSizer.Add(item=btnModify,
2744 flag=wx.ALL | wx.ALIGN_RIGHT,
2747 self.modifyPanel.SetSizer(pageSizer)
2749 def __getTables(self, driver, database):
2750 """!Get list of tables for given driver and database"""
2753 ret = gcmd.RunCommand(
'db.tables',
2758 database = database)
2761 wx.MessageBox(parent=self,
2762 message=_(
"Unable to get list of tables.\n"
2763 "Please use db.connect to set database parameters."),
2764 caption=_(
"Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
2768 for table
in ret.splitlines():
2769 tables.append(table)
2773 def __getColumns(self, driver, database, table):
2774 """!Get list of column of given table"""
2777 ret = gcmd.RunCommand(
'db.columns',
2782 database = database,
2788 for column
in ret.splitlines():
2789 columns.append(column)
2794 """!Driver selection changed, update list of tables"""
2795 driver = event.GetString()
2802 winTable.SetItems(tables)
2803 winTable.SetSelection(0)
2805 if len(tables) == 0:
2811 """!Database selection changed, update list of tables"""
2815 """!Table name changed, update list of columns"""
2818 table = event.GetString()
2828 """!Set default values"""
2838 table.SetItems(tables)
2839 table.SetSelection(0)
2840 if len(tables) == 0:
2852 """!Create new table (name and key column given)"""
2858 if not table
or not key:
2859 wx.MessageBox(parent=self,
2860 message=_(
"Unable to create new table. "
2861 "Table name or key column name is missing."),
2862 caption=_(
"Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
2866 wx.MessageBox(parent=self,
2867 message=_(
"Unable to create new table. "
2868 "Table <%s> already exists in the database.") % table,
2869 caption=_(
"Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
2873 sql =
'CREATE TABLE %s (%s INTEGER)' % (table, key)
2875 gcmd.RunCommand(
'db.execute',
2880 database = database)
2884 tableList.SetItems(self.
__getTables(driver, database))
2885 tableList.SetStringSelection(table)
2889 keyList.SetItems(self.
__getColumns(driver, database, table))
2890 keyList.SetStringSelection(key)
2895 """!Add new layer to vector map"""
2903 if layer
in self.mapDBInfo.layers.keys():
2904 wx.MessageBox(parent=self,
2905 message=_(
"Unable to add new layer to vector map <%(vector)s>. "
2906 "Layer %(layer)d already exists.") %
2907 {
'vector' : self.mapDBInfo.map,
'layer' : layer},
2908 caption=_(
"Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
2912 ret = gcmd.RunCommand(
'v.db.connect',
2915 map = self.mapDBInfo.map,
2917 database = database,
2924 gcmd.RunCommand(
'v.to.db',
2927 map = self.mapDBInfo.map,
2935 self.parentDialog.UpdateDialog(layer=layer)
2937 self.
mapDBInfo = self.parentDialog.mapDBInfo
2939 layerWin.SetValue(layer+1)
2941 if len(self.mapDBInfo.layers.keys()) == 1:
2943 self.deleteLayer.Enable()
2944 self.deleteTable.Enable()
2945 for label
in self.modifyLayerWidgets.keys():
2951 layer = int(self.deleteLayer.GetValue())
2955 gcmd.RunCommand(
'v.db.connect',
2958 map = self.mapDBInfo.map,
2962 if self.deleteTable.IsChecked():
2965 table = self.mapDBInfo.layers[layer][
'table']
2966 sql =
'DROP TABLE %s' % (table)
2968 gcmd.RunCommand(
'db.execute',
2973 database = database)
2977 tableList.SetItems(self.
__getTables(driver, database))
2978 tableList.SetStringSelection(table)
2981 self.parentDialog.UpdateDialog(layer=layer)
2983 self.
mapDBInfo = self.parentDialog.mapDBInfo
2985 if len(self.mapDBInfo.layers.keys()) == 0:
2987 self.deleteLayer.Enable(
False)
2988 self.deleteTable.Enable(
False)
2989 for label
in self.modifyLayerWidgets.keys():
2995 """!Layer number of layer to be deleted is changed"""
2997 layer = int(event.GetString())
3000 layer = self.mapDBInfo.layers.keys()[0]
3005 driver = self.mapDBInfo.layers[layer][
'driver']
3006 database = self.mapDBInfo.layers[layer][
'database']
3007 table = self.mapDBInfo.layers[layer][
'table']
3008 listOfColumns = self.
__getColumns(driver, database, table)
3015 self.deleteTable.SetLabel(_(
'Drop also linked attribute table (%s)') % \
3016 self.mapDBInfo.layers[layer][
'table'])
3021 """!Modify layer connection settings"""
3027 self.mapDBInfo.layers[layer][
'driver']
or \
3029 self.mapDBInfo.layers[layer][
'database']
or \
3031 self.mapDBInfo.layers[layer][
'table']
or \
3033 self.mapDBInfo.layers[layer][
'key']:
3038 gcmd.RunCommand(
'v.db.connect',
3042 map = self.mapDBInfo.map,
3046 gcmd.RunCommand(
'v.db.connect',
3048 map = self.mapDBInfo.map,
3056 self.parentDialog.UpdateDialog(layer=layer)
3058 self.
mapDBInfo = self.parentDialog.mapDBInfo
3067 print >> sys.stderr, __doc__
3076 wx.InitAllImageHandlers()
3078 app = wx.PySimpleApp()
3080 title=
"%s - <%s>" % (_(
"GRASS GIS Attribute Table Manager"),
3082 size=(900,600), vectorName=argv[1])
3087 if __name__ ==
'__main__':