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  - manager::VirtualAttributeList 
   19  - manager::AttributeManager 
   20  - manager::TableListCtrl 
   21  - manager::LayerListCtrl 
   24 (C) 2007-2009, 2011 by the GRASS Development Team 
   26 This program is free software under the GNU General Public License 
   27 (>=v2). Read the file COPYING that comes with GRASS for details. 
   29 @author Jachym Cepicky <jachym.cepicky gmail.com> 
   30 @author Martin Landa <landa.martin gmail.com> 
   40 if __name__ == 
"__main__":
 
   41     sys.path.append(os.path.join(os.getenv(
'GISBASE'), 
'etc', 
'wxpython'))
 
   42 from core 
import globalvar
 
   44 import wx.lib.mixins.listctrl 
as listmix
 
   45 import wx.lib.flatnotebook    
as FN
 
   50 from core.gcmd        import RunCommand, GException, GError, GMessage, GWarning
 
   53 from dbmgr.vinfo      
import VectorDBInfo, unicodeValue, createDbInfoDesc
 
   61     The log output is redirected to the status bar of the containing frame. 
   67         """!Update status bar""" 
   68         self.parent.SetStatusText(text_string.strip())
 
   72                            listmix.ListCtrlAutoWidthMixin,
 
   73                            listmix.ColumnSorterMixin):
 
   75     Support virtual list class 
   77     def __init__(self, parent, log, mapDBInfo, layer):
 
   88         wx.ListCtrl.__init__(self, parent = parent, id = wx.ID_ANY,
 
   89                              style = wx.LC_REPORT | wx.LC_HRULES |
 
   90                              wx.LC_VRULES | wx.LC_VIRTUAL | wx.LC_SORT_ASCENDING)
 
  103         self.attr1.SetBackgroundColour(wx.Colour(238,238,238))
 
  105         self.attr2.SetBackgroundColour(
"white")
 
  106         self.
il = wx.ImageList(16, 16)
 
  107         self.
sm_up = self.il.Add(wx.ArtProvider_GetBitmap(wx.ART_GO_UP,   wx.ART_TOOLBAR,
 
  109         self.
sm_dn = self.il.Add(wx.ArtProvider_GetBitmap(wx.ART_GO_DOWN, wx.ART_TOOLBAR,
 
  111         self.SetImageList(self.
il, wx.IMAGE_LIST_SMALL)
 
  114         listmix.ListCtrlAutoWidthMixin.__init__(self)
 
  115         listmix.ColumnSorterMixin.__init__(self, len(self.
columns))
 
  119             self.SortListItems(col = keyColumn, ascending = 
True) 
 
  121             self.SortListItems(col = 0, ascending = 
True) 
 
  127         self.Bind(wx.EVT_LIST_COL_RIGHT_CLICK, self.
OnColumnMenu)     
 
  130         """!Update list according new mapDBInfo description""" 
  134     def LoadData(self, layer, columns = None, where = None, sql = None):
 
  135         """!Load data into list 
  137         @param layer layer number 
  138         @param columns list of columns for output (-> v.db.select) 
  139         @param where where statement (-> v.db.select) 
  140         @param sql full sql statement (-> db.select) 
  142         @return id of key column  
  143         @return -1 if key column is not displayed 
  145         self.log.write(_(
"Loading data..."))
 
  147         tableName    = self.mapDBInfo.layers[layer][
'table']
 
  148         keyColumn    = self.mapDBInfo.layers[layer][
'key']
 
  150             self.
columns = self.mapDBInfo.tables[tableName]
 
  152             raise GException(_(
"Attribute table <%s> not found. " 
  153                                "For creating the table switch to " 
  154                                "'Manage layers' tab.") % tableName)
 
  157             columns = self.mapDBInfo.GetColumns(tableName)
 
  159             all = self.mapDBInfo.GetColumns(tableName)
 
  162                     GError(parent = self,
 
  163                            message = _(
"Column <%(column)s> not found in " 
  164                                        "in the table <%(table)s>.") % \
 
  165                                { 
'column' : col, 
'table' : tableName })
 
  170             keyId = columns.index(keyColumn)
 
  181         outFile = tempfile.NamedTemporaryFile(mode = 
'w+b')
 
  188         cmdParams = dict(quiet = 
True,
 
  194             cmdParams.update(dict(sql = sql,
 
  195                                   output = outFile.name))
 
  199             cmdParams.update(dict(map = self.mapDBInfo.map,
 
  204                 cmdParams.update(dict(columns = 
','.join(columns)))
 
  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', 
'')
 
  244             record = record.split(fs) 
 
  245             if len(columns) != len(record):
 
  246                 GError(parent = self, 
 
  247                        message = _(
"Inconsistent number of columns "  
  248                                    "in the table <%(table)s>.") % \
 
  249                                 {
'table' : tableName })
 
  257                 self.log.write(_(
"Viewing limit: 100000 records."))
 
  264             width = self.
columns[col][
'length'] * 6 
 
  269             self.SetColumnWidth(col = i, width = width)
 
  274         self.log.write(_(
"Number of loaded records: %d") % \
 
  280         """!Add row to the data list""" 
  282         keyColumn = self.mapDBInfo.layers[self.
layer][
'key']
 
  286         if keyColumn == 
'OGC_FID':
 
  292             if self.
columns[columns[j]][
'ctype'] != types.StringType:
 
  303                 except UnicodeDecodeError:
 
  304                     self.
itemDataMap[i].append(_(
"Unable to decode value. " 
  305                                                  "Set encoding in GUI preferences ('Attributes')."))
 
  307             if not cat 
and keyId > -1 
and keyId == j:
 
  309                     cat = self.
columns[columns[j]][
'ctype'] (value)
 
  310                 except ValueError, e:
 
  312                     GError(parent = self,
 
  313                            message = _(
"Error loading attribute data. " 
  314                                        "Record number: %(rec)d. Unable to convert value '%(val)s' in " 
  315                                        "key column (%(key)s) to integer.\n\n" 
  316                                        "Details: %(detail)s") % \
 
  317                                { 
'rec' : i + 1, 
'val' : value,
 
  318                                  'key' : keyColumn, 
'detail' : e})
 
  321         self.itemIndexMap.append(i)
 
  326         """!Item selected. Add item to selected cats...""" 
  335         """!Item deselected. Remove item from selected cats...""" 
  344         """!Return list of selected items (category numbers)""" 
  346         item = self.GetFirstSelected()
 
  348             cats.append(self.GetItemText(item))
 
  349             item = self.GetNextSelected(item)
 
  354         """!Return column text""" 
  355         item = self.GetItem(index, col)
 
  356         return item.GetText()
 
  369         """!Get item attributes""" 
  376         """!Column heading right mouse button -> pop-up menu""" 
  377         self.
_col = event.GetColumn()
 
  379         popupMenu = wx.Menu()
 
  381         if not hasattr (self, 
"popupID1"):
 
  395         popupMenu.Append(self.
popupID1, text = _(
"Sort ascending"))
 
  396         popupMenu.Append(self.
popupID2, text = _(
"Sort descending"))
 
  397         popupMenu.AppendSeparator()
 
  399         popupMenu.AppendMenu(self.
popupID3, _(
"Calculate (only numeric columns)"),
 
  401         if not self.log.parent.editable 
or \
 
  402                 self.
columns[self.GetColumn(self.
_col).GetText()][
'ctype'] 
not in (types.IntType, types.FloatType):
 
  403             popupMenu.Enable(self.
popupID3, 
False)
 
  405         subMenu.Append(self.
popupID4,  text = _(
"Area size"))
 
  406         subMenu.Append(self.
popupID5,  text = _(
"Line length"))
 
  407         subMenu.Append(self.
popupID6,  text = _(
"Compactness of an area"))
 
  408         subMenu.Append(self.
popupID7,  text = _(
"Fractal dimension of boundary defining a polygon"))
 
  409         subMenu.Append(self.
popupID8,  text = _(
"Perimeter length of an area"))
 
  410         subMenu.Append(self.
popupID9,  text = _(
"Number of features for each category"))
 
  411         subMenu.Append(self.
popupID10, text = _(
"Slope steepness of 3D line"))
 
  412         subMenu.Append(self.
popupID11, text = _(
"Line sinuousity"))
 
  413         subMenu.Append(self.
popupID12, text = _(
"Line azimuth"))
 
  422         self.PopupMenu(popupMenu)
 
  426         """!Column heading left mouse button -> sorting""" 
  427         self.
_col = event.GetColumn()
 
  434         """!Sort values of selected column (ascending)""" 
  435         self.SortListItems(col = self.
_col, ascending = 
True)
 
  439         """!Sort values of selected column (descending)""" 
  440         self.SortListItems(col = self.
_col, ascending = 
False)
 
  444         """!Compute values of selected column""" 
  472                    map = self.mapDBInfo.map,
 
  475                    columns = self.GetColumn(self.
_col).GetText())
 
  480         """!Sort values of selected column (self._col)""" 
  484         info.m_mask = wx.LIST_MASK_TEXT | wx.LIST_MASK_IMAGE
 
  486         for column 
in range(self.GetColumnCount()):
 
  487             info.m_text = self.GetColumn(column).GetText()
 
  488             self.SetColumn(column, info)
 
  492         items = list(self.itemDataMap.keys())
 
  500         colName = self.GetColumn(self.
_col).GetText()
 
  501         ascending = self._colSortFlag[self.
_col]
 
  509         if type(item1) == types.StringType 
or type(item2) == types.StringTypes:
 
  510             cmpVal = locale.strcoll(str(item1), str(item2))
 
  512             cmpVal = cmp(item1, item2)
 
  517             cmpVal = apply(cmp, self.GetSecondarySortValues(self.
_col, key1, key2))
 
  525         """!Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py""" 
  529         """!Check if list if empty""" 
  536     def __init__(self, parent, id = wx.ID_ANY,
 
  537                  title = 
None, vectorName = 
None, item = 
None, log = 
None,
 
  538                  selection = 
None, **kwargs):
 
  539         """!GRASS Attribute Table Manager window 
  541         @param parent parent window 
  543         @param title window title or None for default title 
  544         @param vetorName name of vector map 
  545         @param item item from Layer Tree 
  546         @param log log window 
  547         @param selection name of page to be selected 
  548         @param kwagrs other wx.Frame's arguments 
  553         if self.
parent and self.parent.GetName() == 
"LayerManager" and \
 
  555             maptree = self.parent.GetLayerTree()
 
  556             name = maptree.GetPyData(self.
treeItem)[0][
'maplayer'].GetName()
 
  561         if grass.find_file(name = self.
vectorName, element = 
'vector')[
'mapset'] == grass.gisenv()[
'MAPSET']:
 
  568         wx.Frame.__init__(self, parent, id, *kwargs)
 
  572             self.SetTitle(
"%s - <%s>" % (_(
"GRASS GIS Attribute Table Manager"),
 
  578         self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 
'grass_sql.ico'), wx.BITMAP_TYPE_ICO))
 
  580         self.
panel = wx.Panel(parent = self, id = wx.ID_ANY)
 
  583             self.
map        = self.parent.GetLayerTree().GetMap()
 
  600         if len(self.mapDBInfo.layers.keys()) == 0:
 
  601             GMessage(parent = self.
parent,
 
  602                      message = _(
"Database connection for vector map <%s> " 
  603                                  "is not defined in DB file. " 
  604                                  "You can define new connection in " 
  613         self.CreateStatusBar(number = 1)
 
  622             dbmStyle = { 
'agwStyle' : globalvar.FNPageStyle }
 
  624             dbmStyle = { 
'style' : globalvar.FNPageStyle }
 
  628         self.notebook.AddPage(page = self.
browsePage, text = _(
"Browse data"),
 
  630         self.browsePage.SetTabAreaColour(globalvar.FNPageColor)
 
  634         self.notebook.AddPage(page = self.
manageTablePage, text = _(
"Manage tables"),
 
  637             self.notebook.GetPage(self.notebook.GetPageCount()-1).Enable(
False)
 
  638         self.manageTablePage.SetTabAreaColour(globalvar.FNPageColor)
 
  642         self.notebook.AddPage(page = self.
manageLayerPage, text = _(
"Manage layers"),
 
  644         self.manageLayerPage.SetTabAreaColour(globalvar.FNPageColor)
 
  646             self.notebook.GetPage(self.notebook.GetPageCount()-1).Enable(
False)
 
  653             wx.CallAfter(self.notebook.SetSelectionByName, selection)
 
  655             wx.CallAfter(self.notebook.SetSelection, 0) 
 
  659         self.btnQuit.SetToolTipString(_(
"Close Attribute Table Manager"))
 
  661         self.btnReload.SetToolTipString(_(
"Reload attribute data (selected layer only)"))
 
  666         self.notebook.Bind(FN.EVT_FLATNOTEBOOK_PAGE_CHANGED, self.
OnPageChanged)
 
  675         self.SetSize((700, 550)) 
 
  676         self.SetMinSize(self.GetSize())
 
  678     def _createBrowsePage(self, onlyLayer = -1):
 
  679         """!Create browse tab page""" 
  680         for layer 
in self.mapDBInfo.layers.keys():
 
  681             if onlyLayer > 0 
and layer != onlyLayer:
 
  684             panel = wx.Panel(parent = self.
browsePage, id = wx.ID_ANY)
 
  690             listBox = wx.StaticBox(parent = panel, id = wx.ID_ANY,
 
  691                                    label = 
" %s " % _(
"Attribute data - right-click to edit/manage records"))
 
  692             listSizer = wx.StaticBoxSizer(listBox, wx.VERTICAL)
 
  702             self.
layerPage[layer] = {
'browsePage': panel.GetId()}
 
  706                 label += _(
" (readonly)")
 
  707             self.browsePage.AddPage(page = panel, text = 
" %d / %s %s" % \
 
  708                                         (layer, label, self.mapDBInfo.layers[layer][
'table']))
 
  710             pageSizer = wx.BoxSizer(wx.VERTICAL)
 
  713             sqlBox = wx.StaticBox(parent = panel, id = wx.ID_ANY,
 
  714                                   label = 
" %s " % _(
"SQL Query"))
 
  716             sqlSizer = wx.StaticBoxSizer(sqlBox, wx.VERTICAL)
 
  720             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,
 
  742                                          label = _(
"Advanced"))
 
  743             sqlSimple.Bind(wx.EVT_RADIOBUTTON,   self.
OnChangeSql)
 
  744             sqlAdvanced.Bind(wx.EVT_RADIOBUTTON, self.
OnChangeSql)
 
  746             sqlWhereColumn = wx.ComboBox(parent = panel, id = wx.ID_ANY,
 
  748                                          style = wx.CB_SIMPLE | wx.CB_READONLY,
 
  749                                          choices = self.mapDBInfo.GetColumns(self.mapDBInfo.layers[layer][
'table']))
 
  750             sqlWhereColumn.SetSelection(0)
 
  751             sqlWhereCond = wx.Choice(parent = panel, id = wx.ID_ANY,
 
  753                                      choices = [
'=', 
'!=', 
'<', 
'<=', 
'>', 
'>='])
 
  754             sqlWhereValue = wx.TextCtrl(parent = panel, id = wx.ID_ANY, value = 
"",
 
  755                                         style = wx.TE_PROCESS_ENTER)
 
  756             sqlWhereValue.SetToolTipString(_(
"Example: %s") % 
"MULTILANE = 'no' AND OBJECTID < 10")
 
  758             sqlStatement = wx.TextCtrl(parent = panel, id = wx.ID_ANY,
 
  759                                        value = 
"SELECT * FROM %s" % \
 
  760                                            self.mapDBInfo.layers[layer][
'table'],
 
  761                                        style = wx.TE_PROCESS_ENTER)
 
  762             sqlStatement.SetToolTipString(_(
"Example: %s") % 
"SELECT * FROM roadsmajor WHERE MULTILANE = 'no' AND OBJECTID < 10")
 
  766             sqlLabel = wx.StaticText(parent = panel, id = wx.ID_ANY,
 
  767                                      label = 
"SELECT * FROM %s WHERE " % \
 
  768                                          self.mapDBInfo.layers[layer][
'table'])
 
  769             label_query = wx.StaticText(parent = panel, id = wx.ID_ANY,
 
  772             sqlFlexSizer = wx.FlexGridSizer (cols = 3, hgap = 5, vgap = 5)
 
  774             sqlFlexSizer.Add(item = sqlSimple,
 
  775                              flag = wx.ALIGN_CENTER_VERTICAL)
 
  776             sqlSimpleSizer = wx.BoxSizer(wx.HORIZONTAL)
 
  777             sqlSimpleSizer.Add(item = sqlLabel,
 
  778                                flag = wx.ALIGN_CENTER_VERTICAL)
 
  779             sqlSimpleSizer.Add(item = sqlWhereColumn,
 
  780                                flag = wx.EXPAND | wx.ALIGN_CENTER_VERTICAL)
 
  781             sqlSimpleSizer.Add(item = sqlWhereCond,
 
  782                                flag = wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT,
 
  784             sqlSimpleSizer.Add(item = sqlWhereValue, proportion = 1,
 
  785                                flag = wx.EXPAND | wx.ALIGN_CENTER_VERTICAL)
 
  786             sqlFlexSizer.Add(item = sqlSimpleSizer,
 
  787                              flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND)
 
  788             sqlFlexSizer.Add(item = btnApply,
 
  789                              flag = wx.ALIGN_RIGHT)
 
  790             sqlFlexSizer.Add(item = sqlAdvanced,
 
  791                              flag = wx.ALIGN_CENTER_VERTICAL)
 
  792             sqlFlexSizer.Add(item = sqlStatement,
 
  794             sqlFlexSizer.Add(item = btnSqlBuilder,
 
  795                              flag = wx.ALIGN_RIGHT)
 
  796             sqlFlexSizer.AddGrowableCol(1)
 
  798             sqlSizer.Add(item = sqlFlexSizer,
 
  799                          flag = wx.ALL | wx.EXPAND,
 
  802             pageSizer.Add(item = listSizer,
 
  804                           flag = wx.ALL | wx.EXPAND,
 
  807             pageSizer.Add(item = sqlSizer,
 
  809                           flag = wx.BOTTOM | wx.LEFT | wx.RIGHT | wx.EXPAND,
 
  812             panel.SetSizer(pageSizer)
 
  814             self.
layerPage[layer][
'data']      = win.GetId()
 
  815             self.
layerPage[layer][
'simple']    = sqlSimple.GetId()
 
  816             self.
layerPage[layer][
'advanced']  = sqlAdvanced.GetId()
 
  817             self.
layerPage[layer][
'whereColumn'] = sqlWhereColumn.GetId()
 
  818             self.
layerPage[layer][
'whereOperator'] = sqlWhereCond.GetId()
 
  819             self.
layerPage[layer][
'where']     = sqlWhereValue.GetId()
 
  820             self.
layerPage[layer][
'builder']   = btnSqlBuilder.GetId()
 
  821             self.
layerPage[layer][
'statement'] = sqlStatement.GetId()
 
  824         self.browsePage.SetSelection(0) 
 
  826             self.
layer = self.mapDBInfo.layers.keys()[0]
 
  828             self.log.write(_(
"Number of loaded records: %d") % \
 
  829                            self.FindWindowById(self.
layerPage[self.
layer][
'data']).GetItemCount())
 
  830         except (IndexError, KeyError):
 
  833     def _createManageTablePage(self, onlyLayer = -1):
 
  834         """!Create manage page (create/link and alter tables)""" 
  835         for layer 
in self.mapDBInfo.layers.keys():
 
  836             if onlyLayer > 0 
and layer != onlyLayer:
 
  843             self.
layerPage[layer][
'tablePage'] = panel.GetId()
 
  846                 label += _(
" (readonly)")
 
  847             self.manageTablePage.AddPage(page = panel,
 
  848                                          text = 
" %d / %s %s" % (layer, label,
 
  849                                                                self.mapDBInfo.layers[layer][
'table']))
 
  851             pageSizer = wx.BoxSizer(wx.VERTICAL)
 
  856             dbBox = wx.StaticBox(parent = panel, id = wx.ID_ANY,
 
  857                                           label = 
" %s " % _(
"Database connection"))
 
  858             dbSizer = wx.StaticBoxSizer(dbBox, wx.VERTICAL)
 
  861                         flag = wx.EXPAND | wx.ALL,
 
  867             table = self.mapDBInfo.layers[layer][
'table']
 
  868             tableBox = wx.StaticBox(parent = panel, id = wx.ID_ANY,
 
  869                                     label = 
" %s " % _(
"Table <%s> - right-click to delete column(s)") % table)
 
  871             tableSizer = wx.StaticBoxSizer(tableBox, wx.VERTICAL)
 
  876             self.
layerPage[layer][
'tableData'] = tlist.GetId()
 
  879             addBox = wx.StaticBox(parent = panel, id = wx.ID_ANY,
 
  880                                   label = 
" %s " % _(
"Add column"))
 
  881             addSizer = wx.StaticBoxSizer(addBox, wx.HORIZONTAL)
 
  883             column = wx.TextCtrl(parent = panel, id = wx.ID_ANY, value = 
'',
 
  884                                  size = (150, -1), style = wx.TE_PROCESS_ENTER)
 
  887             self.
layerPage[layer][
'addColName'] = column.GetId()
 
  888             addSizer.Add(item =  wx.StaticText(parent = panel, id = wx.ID_ANY, label = _(
"Column")),
 
  889                          flag = wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT,
 
  891             addSizer.Add(item = column, proportion = 1,
 
  892                          flag = wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT,
 
  895             ctype = wx.Choice (parent = panel, id = wx.ID_ANY,
 
  896                                choices = [
"integer",
 
  900             ctype.SetSelection(0)
 
  902             self.
layerPage[layer][
'addColType'] = ctype.GetId()
 
  903             addSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _(
"Type")), 
 
  904                          flag = wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT,
 
  906             addSizer.Add(item = ctype,
 
  907                          flag = wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT,
 
  910             length = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1),
 
  914             self.
layerPage[layer][
'addColLength'] = length.GetId()
 
  915             addSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _(
"Length")),
 
  916                          flag = wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT,
 
  918             addSizer.Add(item = length,
 
  919                          flag = wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT,
 
  922             btnAddCol = wx.Button(parent = panel, id = wx.ID_ADD)
 
  924             btnAddCol.Enable(
False)
 
  925             self.
layerPage[layer][
'addColButton'] = btnAddCol.GetId()
 
  926             addSizer.Add(item = btnAddCol, flag = wx.ALL | wx.ALIGN_RIGHT | wx.EXPAND,
 
  930             renameBox = wx.StaticBox(parent = panel, id = wx.ID_ANY,
 
  931                                      label = 
" %s " % _(
"Rename column"))
 
  932             renameSizer = wx.StaticBoxSizer(renameBox, wx.HORIZONTAL)
 
  934             column = wx.ComboBox(parent = panel, id = wx.ID_ANY, size = (150, -1),
 
  935                                  style = wx.CB_SIMPLE | wx.CB_READONLY,
 
  936                                  choices = self.mapDBInfo.GetColumns(table))
 
  937             column.SetSelection(0)
 
  938             self.
layerPage[layer][
'renameCol'] = column.GetId()
 
  939             renameSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _(
"Column")),
 
  940                             flag = wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT,
 
  942             renameSizer.Add(item = column, proportion = 1,
 
  943                             flag = wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT,
 
  946             columnTo = wx.TextCtrl(parent = panel, id = wx.ID_ANY, value = 
'',
 
  947                                    size = (150, -1), style = wx.TE_PROCESS_ENTER)
 
  950             self.
layerPage[layer][
'renameColTo'] = columnTo.GetId()
 
  951             renameSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _(
"To")),
 
  952                             flag = wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT,
 
  954             renameSizer.Add(item = columnTo, proportion = 1,
 
  955                             flag = wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT,
 
  958             btnRenameCol = wx.Button(parent = panel, id = wx.ID_ANY, label = _(
"&Rename"))
 
  960             btnRenameCol.Enable(
False)
 
  961             self.
layerPage[layer][
'renameColButton'] = btnRenameCol.GetId()
 
  962             renameSizer.Add(item = btnRenameCol, flag = wx.ALL | wx.ALIGN_RIGHT | wx.EXPAND,
 
  965             tableSizer.Add(item = tlist,
 
  966                            flag = wx.ALL | wx.EXPAND,
 
  970             pageSizer.Add(item=dbSizer,
 
  971                           flag = wx.ALL | wx.EXPAND,
 
  975             pageSizer.Add(item = tableSizer,
 
  976                           flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND,
 
  980             pageSizer.Add(item = addSizer,
 
  981                           flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND,
 
  984             pageSizer.Add(item = renameSizer,
 
  985                           flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND,
 
  989             panel.SetSizer(pageSizer)
 
  991         self.manageTablePage.SetSelection(0) 
 
  993             self.
layer = self.mapDBInfo.layers.keys()[0]
 
  997     def _createTableDesc(self, parent, table):
 
  998         """!Create list with table description""" 
 1000                              table = self.mapDBInfo.tables[table],
 
 1001                              columns = self.mapDBInfo.GetColumns(table))
 
 1009     def _createManageLayerPage(self):
 
 1010         """!Create manage page""" 
 1011         splitterWin = wx.SplitterWindow(parent = self.
manageLayerPage, id = wx.ID_ANY)
 
 1012         splitterWin.SetMinimumPaneSize(100)
 
 1014         label = _(
"Layers of vector map")
 
 1016             label += _(
" (readonly)")
 
 1017         self.manageLayerPage.AddPage(page = splitterWin,
 
 1023         panelList = wx.Panel(parent = splitterWin, id = wx.ID_ANY)
 
 1025         panelListSizer  = wx.BoxSizer(wx.VERTICAL)
 
 1026         layerBox = wx.StaticBox(parent = panelList, id = wx.ID_ANY,
 
 1027                                 label = 
" %s " % _(
"List of layers"))
 
 1028         layerSizer = wx.StaticBoxSizer(layerBox, wx.VERTICAL)
 
 1031         self.layerList.Bind(wx.EVT_COMMAND_RIGHT_CLICK, self.
OnLayerRightUp) 
 
 1035                        flag = wx.ALL | wx.EXPAND,
 
 1039         panelListSizer.Add(item = layerSizer,
 
 1040                            flag = wx.ALL | wx.EXPAND,
 
 1044         panelList.SetSizer(panelListSizer)
 
 1049         panelManage = wx.Panel(parent = splitterWin, id = wx.ID_ANY)
 
 1051         manageSizer = wx.BoxSizer(wx.VERTICAL)
 
 1054                                          parentDialog = self)
 
 1058                         flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND,
 
 1061         panelManage.SetSizer(manageSizer)
 
 1062         splitterWin.SplitHorizontally(panelList, panelManage, 100) 
 
 1065     def _createLayerDesc(self, parent):
 
 1066         """!Create list of linked layers""" 
 1068                              layers = self.mapDBInfo.layers)
 
 1080         mainSizer = wx.BoxSizer(wx.VERTICAL)
 
 1083         btnSizer = wx.BoxSizer(wx.HORIZONTAL)
 
 1084         btnSizer.Add(item = self.
btnReload, proportion = 1,
 
 1085                      flag = wx.ALL | wx.ALIGN_RIGHT, border = 5)
 
 1086         btnSizer.Add(item = self.
btnQuit, proportion = 1,
 
 1087                      flag = wx.ALL | wx.ALIGN_RIGHT, border = 5)
 
 1089         mainSizer.Add(item = self.
notebook, proportion = 1, flag = wx.EXPAND)
 
 1090         mainSizer.Add(item = btnSizer, flag = wx.ALIGN_RIGHT | wx.ALL, border = 5)
 
 1092         self.panel.SetAutoLayout(
True)
 
 1093         self.panel.SetSizer(mainSizer)
 
 1094         mainSizer.Fit(self.
panel)
 
 1098         """!Table description area, context menu""" 
 1099         if not hasattr(self, 
"popupDataID1"):
 
 1127         menu.Append(self.
popupDataID1, _(
"Edit selected record"))
 
 1128         selected = tlist.GetFirstSelected()
 
 1129         if not self.
editable or selected == -1 
or tlist.GetNextSelected(selected) != -1:
 
 1132         menu.Append(self.
popupDataID3, _(
"Delete selected record(s)"))
 
 1133         menu.Append(self.
popupDataID4, _(
"Delete all records"))
 
 1138         menu.AppendSeparator()
 
 1141         menu.AppendSeparator()
 
 1142         menu.Append(self.
popupDataID7, _(
"Highlight selected features"))
 
 1143         menu.Append(self.
popupDataID8, _(
"Highlight selected features and zoom"))
 
 1144         if not self.
map or len(tlist.GetSelectedItems()) == 0:
 
 1147         menu.Append(self.
popupDataID9, _(
"Extract selected features"))
 
 1148         menu.Append(self.
popupDataID11, _(
"Delete selected features"))
 
 1151         if tlist.GetFirstSelected() == -1:
 
 1155         menu.AppendSeparator()
 
 1158         self.PopupMenu(menu)
 
 1162         self.log.write(_(
"Number of loaded records: %d") % \
 
 1163                            tlist.GetItemCount())
 
 1166         """!Delete selected item(s) from the tlist (layer/category pair)""" 
 1168         item = dlist.GetFirstSelected()
 
 1170         table    = self.mapDBInfo.layers[self.
layer][
"table"]
 
 1171         key      = self.mapDBInfo.layers[self.
layer][
"key"]
 
 1176             index = dlist.itemIndexMap[item]
 
 1177             indeces.append(index)
 
 1179             cat = dlist.itemCatsMap[index]
 
 1181             self.listOfSQLStatements.append(
'DELETE FROM %s WHERE %s=%d' % \
 
 1184             item = dlist.GetNextSelected(item)
 
 1186         if UserSettings.Get(group = 
'atm', key = 
'askOnDeleteRec', subkey = 
'enabled'):
 
 1187             deleteDialog = wx.MessageBox(parent = self,
 
 1188                                          message = _(
"Selected data records (%d) will be permanently deleted " 
 1189                                                    "from table. Do you want to delete them?") % \
 
 1191                                          caption = _(
"Delete records"),
 
 1192                                          style = wx.YES_NO | wx.CENTRE)
 
 1193             if deleteDialog != wx.YES:
 
 1199         indexTemp = copy.copy(dlist.itemIndexMap)
 
 1200         dlist.itemIndexMap = []
 
 1201         dataTemp = copy.deepcopy(dlist.itemDataMap)
 
 1202         dlist.itemDataMap = {}
 
 1203         catsTemp = copy.deepcopy(dlist.itemCatsMap)
 
 1204         dlist.itemCatsMap = {}
 
 1207         for index 
in indexTemp:
 
 1208             if index 
in indeces:
 
 1210             dlist.itemIndexMap.append(i)
 
 1211             dlist.itemDataMap[i] = dataTemp[index]
 
 1212             dlist.itemCatsMap[i] = catsTemp[index]
 
 1216         dlist.SetItemCount(len(dlist.itemIndexMap))
 
 1219         item = dlist.GetFirstSelected()
 
 1221             dlist.SetItemState(item, 0, wx.LIST_STATE_SELECTED | wx.LIST_STATE_FOCUSED)
 
 1222             item = dlist.GetNextSelected(item)
 
 1230         """!Delete all items from the list""" 
 1232         if UserSettings.Get(group = 
'atm', key = 
'askOnDeleteRec', subkey = 
'enabled'):
 
 1233             deleteDialog = wx.MessageBox(parent = self,
 
 1234                                          message = _(
"All data records (%d) will be permanently deleted " 
 1235                                                    "from table. Do you want to delete them?") % \
 
 1236                                              (len(dlist.itemIndexMap)),
 
 1237                                          caption = _(
"Delete records"),
 
 1238                                          style = wx.YES_NO | wx.CENTRE)
 
 1239             if deleteDialog != wx.YES:
 
 1242         dlist.DeleteAllItems()
 
 1243         dlist.itemDataMap  = {}
 
 1244         dlist.itemIndexMap = []
 
 1245         dlist.SetItemCount(0)
 
 1247         table = self.mapDBInfo.layers[self.
layer][
"table"]
 
 1248         self.listOfSQLStatements.append(
'DELETE FROM %s' % table)
 
 1254     def _drawSelected(self, zoom):
 
 1255         """!Highlight selected features""" 
 1260         cats = 
map(int, tlist.GetSelectedItems())
 
 1262         digitToolbar = self.mapdisplay.GetToolbar(
'vdigit')
 
 1263         if digitToolbar 
and digitToolbar.GetLayer() 
and \
 
 1264                 digitToolbar.GetLayer().GetName() == self.
vectorName:
 
 1265             display = self.mapdisplay.GetMapWindow().GetDisplay()
 
 1266             display.SetSelected(cats, layer = self.
layer)
 
 1268                 n, s, w, e = display.GetRegionSelected()
 
 1269                 self.mapdisplay.Map.GetRegion(n = n, s = s, w = w, e = e,
 
 1276             if self.
parent and self.parent.GetName() == 
"LayerManager" and \
 
 1278                 maptree = self.parent.GetLayerTree()
 
 1279                 opacity = maptree.GetPyData(self.
treeItem)[0][
'maplayer'].GetOpacity(float = 
True)
 
 1280                 self.qlayer.SetOpacity(opacity)
 
 1282                 keyColumn = self.mapDBInfo.layers[self.
layer][
'key']
 
 1286                         min, max = range.split(
'-')
 
 1287                         where += 
'%s >= %d and %s <= %d or ' % \
 
 1288                             (keyColumn, int(min),
 
 1289                              keyColumn, int(max))
 
 1291                         where += 
'%s = %d or ' % (keyColumn, int(range))
 
 1292                 where = where.rstrip(
'or ')
 
 1299                                     map = self.mapDBInfo.map, 
 1300                                     layer = int(self.layer), 
 1304                 for line 
in select.splitlines():
 
 1305                     key, value = line.split(
'=')
 
 1306                     region[key.strip()] = float(value.strip())
 
 1309                 renderer = self.mapdisplay.GetMap()
 
 1310                 nsdist = 10 * ((renderer.GetCurrentRegion()[
'n'] - renderer.GetCurrentRegion()[
's']) /
 
 1312                 ewdist = 10 * ((renderer.GetCurrentRegion()[
'e'] - renderer.GetCurrentRegion()[
'w']) /
 
 1314                 north = region[
'n'] + nsdist
 
 1315                 south = region[
's'] - nsdist
 
 1316                 west = region[
'w'] - ewdist
 
 1317                 east = region[
'e'] + ewdist
 
 1318                 renderer.GetRegion(n = north, s = south, w = west, e = east, update = 
True)
 
 1319                 self.mapdisplay.GetMapWindow().ZoomHistory(n = north, s = south, w = west, e = east)
 
 1322             self.mapdisplay.Map.AdjustRegion()           
 
 1323             self.mapdisplay.Map.AlignExtentFromDisplay() 
 
 1324             self.mapdisplay.MapWindow.UpdateMap(render = 
True,  renderVector = 
True)
 
 1326             self.mapdisplay.MapWindow.UpdateMap(render = 
False, renderVector = 
True)
 
 1329         """!Reload table description""" 
 1338         """!Add new record to the attribute table""" 
 1340         table     = self.mapDBInfo.layers[self.
layer][
'table']
 
 1341         keyColumn = self.mapDBInfo.layers[self.
layer][
'key']
 
 1348         for i 
in range(tlist.GetColumnCount()): 
 
 1349             columnName.append(tlist.GetColumn(i).GetText())
 
 1352         if len(tlist.itemCatsMap.values()) > 0:
 
 1353             maxCat = 
max(tlist.itemCatsMap.values())
 
 1358         if keyColumn 
not in columnName:
 
 1359             columnName.insert(0, keyColumn) 
 
 1360             data.append((keyColumn, str(maxCat + 1)))
 
 1368         for col 
in columnName:
 
 1369             ctype = self.mapDBInfo.tables[table][col][
'ctype']
 
 1370             ctypeStr = self.mapDBInfo.tables[table][col][
'type']
 
 1371             if col == keyColumn: 
 
 1372                 if missingKey 
is False: 
 
 1373                     data.append((col, ctype, ctypeStr, str(maxCat + 1)))
 
 1376                 data.append((col, ctype, ctypeStr, 
''))
 
 1380         dlg = ModifyTableRecord(parent = self,
 
 1381                                 title = _(
"Insert new record"),
 
 1382                                 data = data, keyEditable = (keyId, 
True))
 
 1384         if dlg.ShowModal() == wx.ID_OK:
 
 1386                 cat = int(dlg.GetValues(columns = [keyColumn])[0])
 
 1391                 if cat 
in tlist.itemCatsMap.values():
 
 1392                     raise ValueError(_(
"Record with category number %d " 
 1393                                        "already exists in the table.") % cat)
 
 1395                 values = dlg.GetValues() 
 
 1399                 for i 
in range(len(values)):
 
 1400                     if len(values[i]) == 0: 
 
 1401                         if columnName[i] == keyColumn:
 
 1402                             raise ValueError(_(
"Category number (column %s)" 
 1403                                                " is missing.") % keyColumn)
 
 1408                         if tlist.columns[columnName[i]][
'ctype'] == int:
 
 1410                             value = float(values[i])
 
 1413                         values[i] = tlist.columns[columnName[i]][
'ctype'] (value)
 
 1416                         raise ValueError(_(
"Value '%(value)s' needs to be entered as %(type)s.") % 
 
 1417                                          {
'value' : str(values[i]),
 
 1418                                           'type' : tlist.columns[columnName[i]][
'type']})
 
 1419                     columnsString += 
'%s,' % columnName[i]
 
 1420                     if tlist.columns[columnName[i]][
'ctype'] == str:
 
 1421                         valuesString += 
"'%s'," % values[i]
 
 1423                         valuesString += 
"%s," % values[i]
 
 1425             except ValueError, err:
 
 1426                 GError(parent = self,
 
 1427                        message = _(
"Unable to insert new record.\n%s") % err,
 
 1428                        showTraceback = 
False)
 
 1433             if missingKey 
is True:
 
 1437             if len(tlist.itemIndexMap) > 0:
 
 1438                 index = 
max(tlist.itemIndexMap) + 1
 
 1442             tlist.itemIndexMap.append(index)
 
 1443             tlist.itemDataMap[index] = values
 
 1444             tlist.itemCatsMap[index] = cat
 
 1445             tlist.SetItemCount(tlist.GetItemCount() + 1)
 
 1447             self.listOfSQLStatements.append(
'INSERT INTO %s (%s) VALUES(%s)' % \
 
 1449                                                  columnsString.strip(
','),
 
 1450                                                  valuesString.strip(
',')))
 
 1454         """!Edit selected record of the attribute table""" 
 1456         item      = tlist.GetFirstSelected()
 
 1460         table     = self.mapDBInfo.layers[self.
layer][
'table']
 
 1461         keyColumn = self.mapDBInfo.layers[self.
layer][
'key']
 
 1462         cat       = tlist.itemCatsMap[tlist.itemIndexMap[item]]
 
 1469         for i 
in range(tlist.GetColumnCount()): 
 
 1470             columnName.append(tlist.GetColumn(i).GetText())
 
 1474         if keyColumn 
not in columnName:
 
 1475             columnName.insert(0, keyColumn) 
 
 1476             data.append((keyColumn, str(cat)))
 
 1483         for i 
in range(len(columnName)):
 
 1484             ctype = self.mapDBInfo.tables[table][columnName[i]][
'ctype']
 
 1485             ctypeStr = self.mapDBInfo.tables[table][columnName[i]][
'type']
 
 1486             if columnName[i] == keyColumn: 
 
 1487                 if missingKey 
is False: 
 
 1488                     data.append((columnName[i], ctype, ctypeStr, str(cat)))
 
 1491                 if missingKey 
is True:
 
 1492                     value = tlist.GetItem(item, i-1).GetText()
 
 1494                     value = tlist.GetItem(item, i).GetText()
 
 1495                 data.append((columnName[i], ctype, ctypeStr, value))
 
 1497         dlg = ModifyTableRecord(parent = self, 
 
 1498                                 title = _(
"Update existing record"),
 
 1499                                 data = data, keyEditable = (keyId, 
False))
 
 1501         if dlg.ShowModal() == wx.ID_OK:
 
 1502             values = dlg.GetValues() 
 
 1505                 for i 
in range(len(values)): 
 
 1508                     if tlist.GetItem(item, i).GetText() != values[i]:
 
 1509                         if len(values[i]) > 0:
 
 1511                                 if missingKey 
is True:
 
 1515                                 if tlist.columns[columnName[i]][
'ctype'] != types.StringType:
 
 1516                                     if tlist.columns[columnName[i]][
'ctype'] == int:
 
 1517                                         value = float(values[i])
 
 1520                                     tlist.itemDataMap[item][idx] = \
 
 1521                                         tlist.columns[columnName[i]][
'ctype'] (value)
 
 1523                                     tlist.itemDataMap[item][idx] = values[i]
 
 1525                                 raise ValueError(_(
"Value '%(value)s' needs to be entered as %(type)s.") % \
 
 1526                                                      {
'value' : str(values[i]),
 
 1527                                                       'type' : tlist.columns[columnName[i]][
'type']})
 
 1529                             if tlist.columns[columnName[i]][
'ctype'] == str:
 
 1530                                 updateString += 
"%s='%s'," % (columnName[i], values[i])
 
 1532                                 updateString += 
"%s=%s," % (columnName[i], values[i])
 
 1534                             updateString += 
"%s=NULL," % (columnName[i])
 
 1536             except ValueError, err:
 
 1537                 GError(parent = self,
 
 1538                        message = _(
"Unable to update existing record.\n%s") % err,
 
 1539                        showTraceback = 
False)
 
 1543             if len(updateString) > 0:
 
 1544                 self.listOfSQLStatements.append(
'UPDATE %s SET %s WHERE %s=%d' % \
 
 1545                                                     (table, updateString.strip(
','),
 
 1552         """!Reload tlist of records""" 
 1557         """!Select all items""" 
 1562             item = tlist.GetNextItem(item)
 
 1565             tlist.SetItemState(item, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED)
 
 1570         """!Deselect items""" 
 1575             item = tlist.GetNextItem(item, wx.LIST_STATE_SELECTED)
 
 1578             tlist.SetItemState(item, 0, wx.LIST_STATE_SELECTED | wx.LIST_STATE_FOCUSED)
 
 1584         """!Data type for new column changed. Enable or disable 
 1585         data length widget""" 
 1586         win = self.FindWindowById(self.
layerPage[self.
layer][
'addColLength'])
 
 1587         if event.GetString() == 
"varchar":
 
 1593         """!Editing column name to be added to the table""" 
 1594         btn  = self.FindWindowById(self.
layerPage[self.
layer][
'renameColButton'])
 
 1595         col  = self.FindWindowById(self.
layerPage[self.
layer][
'renameCol'])
 
 1596         colTo = self.FindWindowById(self.
layerPage[self.
layer][
'renameColTo'])
 
 1597         if len(col.GetValue()) > 0 
and len(colTo.GetValue()) > 0:
 
 1605         """!Editing column name to be added to the table""" 
 1606         btn = self.FindWindowById(self.
layerPage[self.
layer][
'addColButton'])
 
 1607         if len(event.GetString()) > 0:
 
 1615         """!Rename column in the table""" 
 1616         tlist   = self.FindWindowById(self.
layerPage[self.
layer][
'tableData'])
 
 1620         table = self.mapDBInfo.layers[self.
layer][
"table"]
 
 1622         if not name 
or not nameTo:
 
 1623             GError(parent = self,
 
 1624                    message = _(
"Unable to rename column. " 
 1625                                "No column name defined."))
 
 1628             item = tlist.FindItem(start = -1, str = name)
 
 1630                 if tlist.FindItem(start = -1, str = nameTo) > -1:
 
 1631                     GError(parent = self,
 
 1632                            message = _(
"Unable to rename column <%(column)s> to " 
 1633                                        "<%(columnTo)s>. Column already exists " 
 1634                                        "in the table <%(table)s>.") % \
 
 1635                                {
'column' : name, 
'columnTo' : nameTo,
 
 1639                     tlist.SetItemText(item, nameTo)
 
 1641                     self.listOfCommands.append((
'v.db.renamecol',
 
 1643                                                   'layer'  : self.
layer,
 
 1644                                                   'column' : 
'%s,%s' % (name, nameTo) }
 
 1647                 GError(parent = self,
 
 1648                        message = _(
"Unable to rename column. " 
 1649                                    "Column <%(column)s> doesn't exist in the table <%(table)s>.") % 
 
 1650                        {
'column' : name, 
'table' : table})
 
 1657         self.FindWindowById(self.
layerPage[self.
layer][
'renameCol']).SetItems(self.mapDBInfo.GetColumns(table))
 
 1658         self.FindWindowById(self.
layerPage[self.
layer][
'renameCol']).SetSelection(0)
 
 1664         """!Table description area, context menu""" 
 1665         if not hasattr(self, 
"popupTableID"):
 
 1676         if self.FindWindowById(self.
layerPage[self.
layer][
'tableData']).GetFirstSelected() == -1:
 
 1679         menu.AppendSeparator()
 
 1682         self.PopupMenu(menu)
 
 1686         """!Delete selected item(s) from the list""" 
 1687         tlist = self.FindWindowById(self.
layerPage[self.
layer][
'tableData'])
 
 1689         item = tlist.GetFirstSelected()
 
 1691         if UserSettings.Get(group = 
'atm', key = 
'askOnDeleteRec', subkey = 
'enabled'):
 
 1692             deleteDialog = wx.MessageBox(parent = self,
 
 1693                                          message = _(
"Selected column '%s' will PERMANENTLY removed " 
 1694                                                    "from table. Do you want to drop the column?") % \
 
 1695                                              (tlist.GetItemText(item)),
 
 1696                                          caption = _(
"Drop column(s)"),
 
 1697                                          style = wx.YES_NO | wx.CENTRE)
 
 1698             if deleteDialog != wx.YES:
 
 1702             self.listOfCommands.append((
'v.db.dropcol',
 
 1704                                           'layer' : self.
layer,
 
 1705                                           'column' : tlist.GetItemText(item) }
 
 1707             tlist.DeleteItem(item)
 
 1708             item = tlist.GetFirstSelected()
 
 1714         table = self.mapDBInfo.layers[self.
layer][
'table']
 
 1715         self.FindWindowById(self.
layerPage[self.
layer][
'renameCol']).SetItems(self.mapDBInfo.GetColumns(table))
 
 1716         self.FindWindowById(self.
layerPage[self.
layer][
'renameCol']).SetSelection(0)
 
 1721         """!Delete all items from the list""" 
 1722         table     = self.mapDBInfo.layers[self.
layer][
'table']
 
 1723         cols      = self.mapDBInfo.GetColumns(table)
 
 1724         keyColumn = self.mapDBInfo.layers[self.
layer][
'key']
 
 1725         if keyColumn 
in cols:
 
 1726             cols.remove(keyColumn)
 
 1728         if UserSettings.Get(group = 
'atm', key = 
'askOnDeleteRec', subkey = 
'enabled'):
 
 1729             deleteDialog = wx.MessageBox(parent = self,
 
 1730                                          message = _(
"Selected columns\n%s\nwill PERMANENTLY removed " 
 1731                                                    "from table. Do you want to drop the columns?") % \
 
 1733                                          caption = _(
"Drop column(s)"),
 
 1734                                          style = wx.YES_NO | wx.CENTRE)
 
 1735             if deleteDialog != wx.YES:
 
 1739             self.listOfCommands.append((
'v.db.dropcol',
 
 1741                                           'layer' : self.
layer,
 
 1744         self.FindWindowById(self.
layerPage[self.
layer][
'tableData']).DeleteAllItems()
 
 1750         table = self.mapDBInfo.layers[self.
layer][
'table']
 
 1751         self.FindWindowById(self.
layerPage[self.
layer][
'renameCol']).SetItems(self.mapDBInfo.GetColumns(table))
 
 1752         self.FindWindowById(self.
layerPage[self.
layer][
'renameCol']).SetSelection(0)
 
 1757         """!Reload table description""" 
 1758         self.FindWindowById(self.
layerPage[self.
layer][
'tableData']).Populate(update = 
True)
 
 1762         """!Add new column to the table""" 
 1763         table = self.mapDBInfo.layers[self.layer][
'table']
 
 1764         name = self.FindWindowById(self.layerPage[self.layer][
'addColName']).
GetValue()
 
 1767             GError(parent = self,
 
 1768                    message = _(
"Unable to add column to the table. " 
 1769                                "No column name defined."))
 
 1772         ctype = self.FindWindowById(self.layerPage[self.layer][
'addColType']). \
 
 1773             GetStringSelection()
 
 1776         if ctype == 
'double':
 
 1777             ctype = 
'double precision' 
 1778         if ctype == 
'varchar':
 
 1779             length = int(self.FindWindowById(self.layerPage[self.layer][
'addColLength']). \
 
 1785         tlist = self.FindWindowById(self.layerPage[self.layer][
'tableData'])
 
 1787         if tlist.FindItem(start = -1, str = name) > -1:
 
 1788             GError(parent = self,
 
 1789                    message = _(
"Column <%(column)s> already exists in table <%(table)s>.") % \
 
 1790                        {
'column' : name, 
'table' : self.mapDBInfo.layers[self.layer][
"table"]})
 
 1792         index = tlist.InsertStringItem(sys.maxint, str(name))
 
 1793         tlist.SetStringItem(index, 0, str(name))
 
 1794         tlist.SetStringItem(index, 1, str(ctype))
 
 1795         tlist.SetStringItem(index, 2, str(length))
 
 1798         if ctype == 
'varchar':
 
 1799             ctype += 
' (%d)' % length
 
 1800         self.listOfCommands.append((
'v.db.addcol',
 
 1801                                     { 
'map'     : self.vectorName,
 
 1802                                       'layer'   : self.layer,
 
 1803                                       'columns' : 
'%s %s' % (name, ctype) }
 
 1806         self.ApplyCommands()
 
 1809         self.FindWindowById(self.layerPage[self.layer][
'addColName']).
SetValue(
'')
 
 1810         self.FindWindowById(self.layerPage[self.layer][
'renameCol']).SetItems(self.mapDBInfo.GetColumns(table))
 
 1811         self.FindWindowById(self.layerPage[self.layer][
'renameCol']).SetSelection(0)
 
 1816         """!Layer tab changed""" 
 1817         pageNum = event.GetSelection()
 
 1818         self.
layer = self.mapDBInfo.layers.keys()[pageNum]
 
 1828             self.log.write(_(
"Number of loaded records: %d") % \
 
 1835             winCol = self.FindWindowById(idCol)
 
 1836             table = self.mapDBInfo.layers[self.
layer][
"table"]
 
 1837             self.mapDBInfo.GetColumns(table)
 
 1847         if event.GetSelection() == 0 
and id:
 
 1848             win = self.FindWindowById(id)
 
 1850                 self.log.write(_(
"Number of loaded records: %d") % win.GetItemCount())
 
 1853             self.btnReload.Enable()
 
 1856             self.btnReload.Enable(
False)
 
 1861         """!Layer description area, context menu""" 
 1865         """!Switch simple/advanced sql statement""" 
 1866         if self.FindWindowById(self.layerPage[self.layer][
'simple']).
GetValue():
 
 1867             self.FindWindowById(self.layerPage[self.layer][
'where']).Enable(
True)
 
 1868             self.FindWindowById(self.layerPage[self.layer][
'statement']).Enable(
False)
 
 1869             self.FindWindowById(self.layerPage[self.layer][
'builder']).Enable(
False)
 
 1871             self.FindWindowById(self.layerPage[self.layer][
'where']).Enable(
False)
 
 1872             self.FindWindowById(self.layerPage[self.layer][
'statement']).Enable(
True)
 
 1873             self.FindWindowById(self.layerPage[self.layer][
'builder']).Enable(
True)
 
 1876         """!Apply changes""" 
 1878         wx.BeginBusyCursor()
 
 1888             table = self.mapDBInfo.layers[self.
layer][
'table']
 
 1891             tlist = self.FindWindowById(self.
layerPage[self.
layer][
'tableData'])
 
 1892             tlist.Update(table = self.mapDBInfo.tables[table],
 
 1893                         columns = self.mapDBInfo.GetColumns(table))
 
 1905             fd, sqlFilePath = tempfile.mkstemp(text=
True)
 
 1906             sqlFile = open(sqlFilePath, 
'w')
 
 1908                 enc = UserSettings.Get(group = 
'atm', key = 
'encoding', subkey = 
'value')
 
 1909                 if not enc 
and 'GRASS_DB_ENCODING' in os.environ:
 
 1910                     enc = os.environ[
'GRASS_DB_ENCODING']
 
 1912                     sqlFile.write(sql.encode(enc) + 
';')
 
 1914                     sqlFile.write(sql + 
';')
 
 1915                 sqlFile.write(os.linesep)
 
 1918             driver   = self.mapDBInfo.layers[self.
layer][
"driver"]
 
 1919             database = self.mapDBInfo.layers[self.
layer][
"database"]
 
 1921             Debug.msg(3, 
'AttributeManger.ApplyCommands(): %s' %
 
 1926                        input = sqlFilePath,
 
 1928                        database = database)
 
 1931             os.remove(sqlFilePath)
 
 1938         """!Apply simple/advanced sql statement""" 
 1940         listWin = self.FindWindowById(self.
layerPage[self.
layer][
'data'])
 
 1946         wx.BeginBusyCursor()
 
 1949             whereCol = self.FindWindowById(self.
layerPage[self.
layer][
'whereColumn']).GetStringSelection()
 
 1950             whereOpe = self.FindWindowById(self.
layerPage[self.
layer][
'whereOperator']).GetStringSelection()
 
 1953                 if len(whereVal) > 0:
 
 1954                     keyColumn = listWin.LoadData(self.
layer, where = whereCol + whereOpe + whereVal)
 
 1956                     keyColumn = listWin.LoadData(self.
layer)
 
 1957             except GException, e:
 
 1958                 GError(parent = self,
 
 1959                        message = _(
"Loading attribute data failed.\n\n%s") % e.value)
 
 1963             win = self.FindWindowById(self.
layerPage[self.
layer][
'statement'])
 
 1966                 if cols 
is None and where 
is None:
 
 1967                     sql = win.GetValue()
 
 1969                 GError(parent = self,
 
 1970                        message = _(
"Loading attribute data failed.\n" 
 1971                                    "Invalid SQL select statement.\n\n%s") % win.GetValue())
 
 1972                 win.SetValue(
"SELECT * FROM %s" % self.mapDBInfo.layers[self.
layer][
'table'])
 
 1976             if cols 
or where 
or sql:
 
 1978                     keyColumn = listWin.LoadData(self.
layer, columns = cols,
 
 1979                                                  where = where, sql = sql)
 
 1980                 except GException, e:
 
 1981                     GError(parent = self,
 
 1982                            message = _(
"Loading attribute data failed.\n\n%s") % e.value)
 
 1983                     win.SetValue(
"SELECT * FROM %s" % self.mapDBInfo.layers[self.
layer][
'table'])
 
 1986         if sql 
and 'order by' in sql.lower():
 
 1990                 listWin.SortListItems(col = keyColumn, ascending = 
True)
 
 1992                 listWin.SortListItems(col = 0, ascending = 
True) 
 
 1997         self.log.write(_(
"Number of loaded records: %d") % \
 
 1998                            self.FindWindowById(self.
layerPage[self.
layer][
'data']).GetItemCount())
 
 2001         """!Validate SQL select statement 
 2003         @return (columns, where) 
 2004         @return None on error 
 2006         if statement[0:7].lower() != 
'select ':
 
 2011         for c 
in statement[index:]:
 
 2019             cols = cols.split(
',')
 
 2021         tablelen = len(self.mapDBInfo.layers[self.
layer][
'table'])
 
 2023         if statement[index+1:index+6].lower() != 
'from ' or \
 
 2024                 statement[index+6:index+6+tablelen] != 
'%s' % \
 
 2025                 (self.mapDBInfo.layers[self.
layer][
'table']):
 
 2028         if len(statement[index+7+tablelen:]) > 0:
 
 2029             index = statement.lower().find(
'where ')
 
 2031                 where = statement[index+6:]
 
 2037         return (cols, where)
 
 2040         """!Cancel button pressed""" 
 2041         if self.
parent and self.parent.GetName() == 
'LayerManager':
 
 2043             self.parent.dialogs[
'atm'].remove(self)
 
 2045         if not isinstance(event, wx.CloseEvent):
 
 2051         """!SQL Builder button pressed -> show the SQLBuilder dialog""" 
 2053             self.
builder = SQLFrame(parent = self, id = wx.ID_ANY,
 
 2054                                     title = _(
"SQL Builder"),
 
 2059             self.builder.Raise()
 
 2062         if event == 
'apply':
 
 2063             sqlstr = self.builder.GetSQLStatement()
 
 2066             self.listOfSQLStatements.append(sqlstr)
 
 2069             if self.builder.CloseOnApply():
 
 2071         elif event == 
'close':
 
 2078         """!Item activated, highlight selected item""" 
 2079         self.OnDataDrawSelected(event)
 
 2084         """!Extract vector objects selected in attribute browse window 
 2089         cats = tlist.GetSelectedItems()
 
 2091             GMessage(parent = self,
 
 2092                      message = _(
'Nothing to extract.'))
 
 2096             dlg = 
CreateNewVector(parent = self, title = _(
'Extract selected features'),
 
 2098                                   cmd = ((
'v.extract',
 
 2102                                   disableTable = 
True)
 
 2106             name = dlg.GetName(full = 
True)
 
 2107             if name 
and dlg.IsChecked(
'add'):
 
 2109                 self.parent.GetLayerTree().AddLayer(ltype = 
'vector',
 
 2111                                                     lcmd = [
'd.vect', 
'map=%s' % name])
 
 2115         """!Delete vector objects selected in attribute browse window 
 2116         (attribures and geometry) 
 2119         cats = tlist.GetSelectedItems()
 
 2121             GMessage(parent = self,
 
 2122                      message = _(
'Nothing to delete.'))
 
 2125         if 'vdigit' in self.mapdisplay.toolbars:
 
 2126             digitToolbar = self.mapdisplay.toolbars[
'vdigit']
 
 2127             if digitToolbar 
and digitToolbar.GetLayer() 
and \
 
 2128                     digitToolbar.GetLayer().GetName() == self.
vectorName:
 
 2129                 display = self.mapdisplay.GetMapWindow().GetDisplay()
 
 2130                 display.SetSelected(
map(int, cats), layer = self.
layer)
 
 2131                 self.mapdisplay.MapWindow.UpdateMap(render = 
True, renderVector = 
True)
 
 2135                 self.mapdisplay.GetMapWindow().digit.DeleteSelectedLines()
 
 2144             self.mapdisplay.MapWindow.UpdateMap(render = 
True, renderVector = 
True)
 
 2149         Return True if map has been redrawn, False if no map is given 
 2153             self.
layer : tlist.GetSelectedItems()
 
 2156         if self.mapdisplay.Map.GetLayerIndex(self.
qlayer) < 0:
 
 2160             self.qlayer.SetCmd(self.mapdisplay.AddTmpVectorMapLayer(self.
vectorName, cats, addLayer = 
False))
 
 2167         """!Updates dialog layout for given layer""" 
 2169         if layer 
in self.mapDBInfo.layers.keys():
 
 2175             self.browsePage.DeletePage(self.mapDBInfo.layers.keys().index(layer))
 
 2176             self.manageTablePage.DeletePage(self.mapDBInfo.layers.keys().index(layer))
 
 2178             self.notebook.SetSelectionByName(
'layers')
 
 2186         if layer 
in self.mapDBInfo.layers.keys():
 
 2192             self.notebook.SetSelectionByName(
'layers')
 
 2198         self.layerList.Update(self.mapDBInfo.layers)
 
 2199         self.layerList.Populate(update = 
True)
 
 2201         listOfLayers = 
map(str, self.mapDBInfo.layers.keys())
 
 2203         self.manageLayerBook.deleteLayer.SetItems(listOfLayers)
 
 2204         if len(listOfLayers) > 0:
 
 2205             self.manageLayerBook.deleteLayer.SetStringSelection(listOfLayers[0])
 
 2206             tableName = self.mapDBInfo.layers[int(listOfLayers[0])][
'table']
 
 2207             maxLayer = 
max(self.mapDBInfo.layers.keys())
 
 2211         self.manageLayerBook.deleteTable.SetLabel( \
 
 2212             _(
'Drop also linked attribute table (%s)') % \
 
 2215         self.manageLayerBook.addLayerWidgets[
'layer'][1].
SetValue(\
 
 2218         self.manageLayerBook.modifyLayerWidgets[
'layer'][1].SetItems(listOfLayers)
 
 2219         self.manageLayerBook.OnChangeLayer(event = 
None)
 
 2222         """!Get vector name""" 
 2225     def LoadData(self, layer, columns = None, where = None, sql = None):
 
 2226         """!Load data into list 
 2228         @param layer layer number 
 2229         @param columns list of columns for output 
 2230         @param where where statement 
 2231         @param sql full sql statement 
 2233         @return id of key column  
 2234         @return -1 if key column is not displayed 
 2236         listWin = self.FindWindowById(self.
layerPage[layer][
'data'])
 
 2237         return listWin.LoadData(layer, columns, where, sql)
 
 2240                     listmix.ListCtrlAutoWidthMixin):
 
 2242     """!Table description list""" 
 2244     def __init__(self, parent, id, table, columns, pos = wx.DefaultPosition,
 
 2245                  size = wx.DefaultSize):
 
 2250         wx.ListCtrl.__init__(self, parent, id, pos, size,
 
 2251                              style = wx.LC_REPORT | wx.LC_HRULES | wx.LC_VRULES |
 
 2254         listmix.ListCtrlAutoWidthMixin.__init__(self)
 
 2258         """!Update column description""" 
 2263         """!Populate the list""" 
 2267             headings = [_(
"Column name"), _(
"Data type"), _(
"Data length")]
 
 2270                 self.InsertColumn(col = i, heading = h)
 
 2272             self.SetColumnWidth(col = 0, width = 350)
 
 2273             self.SetColumnWidth(col = 1, width = 175)
 
 2275             self.DeleteAllItems()
 
 2279             index = self.InsertStringItem(sys.maxint, str(column))
 
 2280             self.SetStringItem(index, 0, str(column))
 
 2281             self.SetStringItem(index, 1, str(self.
table[column][
'type']))
 
 2282             self.SetStringItem(index, 2, str(self.
table[column][
'length']))
 
 2283             self.SetItemData(index, i)
 
 2284             itemData[i] = (str(column),
 
 2285                            str(self.
table[column][
'type']),
 
 2286                            int(self.
table[column][
'length']))
 
 2289         self.SendSizeEvent()
 
 2294                     listmix.ListCtrlAutoWidthMixin):
 
 2297     """!Layer description list""" 
 2299     def __init__(self, parent, id, layers,
 
 2300                  pos = wx.DefaultPosition,
 
 2301                  size = wx.DefaultSize):
 
 2305         wx.ListCtrl.__init__(self, parent, id, pos, size,
 
 2306                              style = wx.LC_REPORT | wx.LC_HRULES | wx.LC_VRULES |
 
 2309         listmix.ListCtrlAutoWidthMixin.__init__(self)
 
 2313         """!Update description""" 
 2317         """!Populate the list""" 
 2321             headings = [_(
"Layer"),  _(
"Driver"), _(
"Database"), _(
"Table"), _(
"Key")]
 
 2324                 self.InsertColumn(col = i, heading = h)
 
 2327             self.DeleteAllItems()
 
 2330         for layer 
in self.layers.keys():
 
 2331             index = self.InsertStringItem(sys.maxint, str(layer))
 
 2332             self.SetStringItem(index, 0, str(layer))
 
 2333             database = str(self.
layers[layer][
'database'])
 
 2334             driver   = str(self.
layers[layer][
'driver'])
 
 2335             table    = str(self.
layers[layer][
'table'])
 
 2336             key      = str(self.
layers[layer][
'key'])
 
 2337             self.SetStringItem(index, 1, driver)
 
 2338             self.SetStringItem(index, 2, database)
 
 2339             self.SetStringItem(index, 3, table)
 
 2340             self.SetStringItem(index, 4, key)
 
 2341             self.SetItemData(index, i)
 
 2342             itemData[i] = (str(layer),
 
 2349         for i 
in range(self.GetColumnCount()):
 
 2350             self.SetColumnWidth(col = i, width = wx.LIST_AUTOSIZE)
 
 2351             if self.GetColumnWidth(col = i) < 60:
 
 2352                 self.SetColumnWidth(col = i, width = 60)
 
 2354         self.SendSizeEvent()
 
 2359     """!Manage layers (add, delete, modify)""" 
 2362                  style = wx.BK_DEFAULT):
 
 2363         wx.Notebook.__init__(self, parent, id, style = style)
 
 2378         for drv 
in drivers.splitlines():
 
 2379             self.listOfDrivers.append(drv.strip())
 
 2390         for line 
in connect.splitlines():
 
 2391             item, value = line.split(
':', 1)
 
 2396             GWarning(parent = self.
parent,
 
 2397                      message = _(
"Unknown default DB connection. " 
 2398                                  "Please define DB connection using db.connect module."))
 
 2413     def _createAddPage(self):
 
 2414         """!Add new layer""" 
 2415         self.
addPanel = wx.Panel(parent = self, id = wx.ID_ANY)
 
 2416         self.AddPage(page = self.
addPanel, text = _(
"Add layer"))
 
 2419             maxLayer = 
max(self.mapDBInfo.layers.keys())
 
 2425         layerBox = wx.StaticBox (parent = self.
addPanel, id = wx.ID_ANY,
 
 2426                                  label = 
" %s " % (_(
"Layer description")))
 
 2427         layerSizer = wx.StaticBoxSizer(layerBox, wx.VERTICAL)
 
 2433                                     (wx.StaticText(parent = self.
addPanel, id = wx.ID_ANY,
 
 2434                                                    label = 
'%s:' % _(
"Layer")),
 
 2435                                      wx.SpinCtrl(parent = self.
addPanel, id = wx.ID_ANY, size = (65, -1),
 
 2436                                                  initial = maxLayer+1,
 
 2437                                                  min = 1, max = 1e6)),
 
 2439                                     (wx.StaticText(parent = self.
addPanel, id = wx.ID_ANY,
 
 2440                                                    label = 
'%s:' % _(
"Driver")),
 
 2441                                      wx.Choice(parent = self.
addPanel, id = wx.ID_ANY, size = (200, -1),
 
 2444                                     (wx.StaticText(parent = self.
addPanel, id = wx.ID_ANY,
 
 2445                                                    label = 
'%s:' % _(
"Database")),
 
 2446                                      wx.TextCtrl(parent = self.
addPanel, id = wx.ID_ANY,
 
 2448                                                  style = wx.TE_PROCESS_ENTER)),
 
 2450                                     (wx.StaticText(parent = self.
addPanel, id = wx.ID_ANY,
 
 2451                                                    label = 
'%s:' % _(
"Table")),
 
 2452                                      wx.Choice(parent = self.
addPanel, id = wx.ID_ANY, size = (200, -1),
 
 2455                                     (wx.StaticText(parent = self.
addPanel, id = wx.ID_ANY,
 
 2456                                                    label = 
'%s:' % _(
"Key column")),
 
 2457                                      wx.Choice(parent = self.
addPanel, id = wx.ID_ANY, size = (200, -1),
 
 2460                                     (wx.CheckBox(parent = self.
addPanel, id = wx.ID_ANY,
 
 2461                                                  label = _(
"Insert record for each category into table")),
 
 2476         self.
addLayerWidgets[
'addCat'][0].SetToolTipString(_(
"You need to add categories " 
 2477                                                              "by v.category module."))
 
 2480         tableBox = wx.StaticBox (parent = self.
addPanel, id = wx.ID_ANY,
 
 2481                                  label = 
" %s " % (_(
"Table description")))
 
 2482         tableSizer = wx.StaticBoxSizer(tableBox, wx.VERTICAL)
 
 2487         keyCol = UserSettings.Get(group = 
'atm', key = 
'keycolumn', subkey = 
'value')
 
 2489                                                      label = 
'%s:' % _(
"Table name")),
 
 2490                                        wx.TextCtrl(parent = self.
addPanel, id = wx.ID_ANY,
 
 2492                                                    style = wx.TE_PROCESS_ENTER)),
 
 2493                              'key': (wx.StaticText(parent = self.
addPanel, id = wx.ID_ANY,
 
 2494                                                    label = 
'%s:' % _(
"Key column")),
 
 2495                                      wx.TextCtrl(parent = self.
addPanel, id = wx.ID_ANY,
 
 2497                                                  style = wx.TE_PROCESS_ENTER))}
 
 2502         btnTable   = wx.Button(self.
addPanel, wx.ID_ANY, _(
"&Create table"),
 
 2506         btnLayer   = wx.Button(self.
addPanel, wx.ID_ANY, _(
"&Add layer"),
 
 2508         btnLayer.Bind(wx.EVT_BUTTON, self.
OnAddLayer)
 
 2510         btnDefault = wx.Button(self.
addPanel, wx.ID_ANY, _(
"&Set default"),
 
 2516         pageSizer = wx.BoxSizer(wx.HORIZONTAL)
 
 2519         dataSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
 
 2521         for key 
in (
'layer', 
'driver', 
'database', 
'table', 
'key', 
'addCat'):
 
 2527             dataSizer.Add(item = label,
 
 2528                           flag = wx.ALIGN_CENTER_VERTICAL, pos = (row, 0),
 
 2536                 style = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT
 
 2538                 style = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND
 
 2540             dataSizer.Add(item = value,
 
 2541                           flag = style, pos = (row, 1))
 
 2544         dataSizer.AddGrowableCol(1)
 
 2546         layerSizer.Add(item = dataSizer,
 
 2548                        flag = wx.ALL | wx.EXPAND,
 
 2551         btnSizer = wx.BoxSizer(wx.HORIZONTAL)
 
 2552         btnSizer.Add(item = btnDefault,
 
 2554                      flag = wx.ALL | wx.ALIGN_LEFT,
 
 2557         btnSizer.Add(item = (5, 5),
 
 2559                      flag = wx.ALL | wx.EXPAND,
 
 2562         btnSizer.Add(item = btnLayer,
 
 2564                      flag = wx.ALL | wx.ALIGN_RIGHT,
 
 2567         layerSizer.Add(item = btnSizer,
 
 2569                        flag = wx.ALL | wx.EXPAND,
 
 2573         dataSizer = wx.FlexGridSizer(cols = 2, hgap = 5, vgap = 5)
 
 2574         for key 
in [
'table', 
'key']:
 
 2576             dataSizer.Add(item = label,
 
 2577                           flag = wx.ALIGN_CENTER_VERTICAL)
 
 2578             dataSizer.Add(item = value,
 
 2579                           flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND)
 
 2580         dataSizer.AddGrowableCol(1)
 
 2582         tableSizer.Add(item = dataSizer,
 
 2584                        flag = wx.ALL | wx.EXPAND,
 
 2587         tableSizer.Add(item = btnTable,
 
 2589                        flag = wx.ALL | wx.ALIGN_BOTTOM | wx.ALIGN_RIGHT,
 
 2592         pageSizer.Add(item = layerSizer,
 
 2594                       flag = wx.ALL | wx.EXPAND,
 
 2597         pageSizer.Add(item = tableSizer,
 
 2599                       flag = wx.TOP | wx.BOTTOM | wx.RIGHT | wx.EXPAND,
 
 2602         layerSizer.SetVirtualSizeHints(self.
addPanel)
 
 2603         self.addPanel.SetAutoLayout(
True)
 
 2604         self.addPanel.SetSizer(pageSizer)
 
 2607     def _createDeletePage(self):
 
 2610         self.AddPage(page = self.
deletePanel, text = _(
"Remove layer"))
 
 2612         label = wx.StaticText(parent = self.
deletePanel, id = wx.ID_ANY,
 
 2613                               label = 
'%s:' % _(
"Layer to remove"))
 
 2616                                        style = wx.CB_SIMPLE | wx.CB_READONLY,
 
 2617                                        choices = map(str, self.mapDBInfo.layers.keys()))
 
 2618         self.deleteLayer.SetSelection(0)           
 
 2622             tableName = self.mapDBInfo.layers[int(self.deleteLayer.GetStringSelection())][
'table']
 
 2627                                        label = _(
'Drop also linked attribute table (%s)') % \
 
 2631             self.deleteLayer.Enable(
False)
 
 2632             self.deleteTable.Enable(
False)
 
 2634         btnDelete   = wx.Button(self.
deletePanel, wx.ID_DELETE, _(
"&Remove layer"),
 
 2641         pageSizer = wx.BoxSizer(wx.VERTICAL)
 
 2643         dataSizer = wx.BoxSizer(wx.VERTICAL)
 
 2645         flexSizer = wx.FlexGridSizer(cols = 2, hgap = 5, vgap = 5)
 
 2647         flexSizer.Add(item = label,
 
 2648                       flag = wx.ALIGN_CENTER_VERTICAL)
 
 2650                       flag = wx.ALIGN_CENTER_VERTICAL)
 
 2651         flexSizer.AddGrowableCol(1)
 
 2653         dataSizer.Add(item = flexSizer,
 
 2655                       flag = wx.ALL | wx.EXPAND,
 
 2660                       flag = wx.ALL | wx.EXPAND,
 
 2663         pageSizer.Add(item = dataSizer,
 
 2665                       flag = wx.ALL | wx.EXPAND,
 
 2668         pageSizer.Add(item = btnDelete,
 
 2670                       flag = wx.ALL | wx.ALIGN_RIGHT,
 
 2673         self.deletePanel.SetSizer(pageSizer)
 
 2675     def _createModifyPage(self):
 
 2678         self.AddPage(page = self.
modifyPanel, text = _(
"Modify layer"))
 
 2684                                        (wx.StaticText(parent = self.
modifyPanel, id = wx.ID_ANY,
 
 2685                                                       label = 
'%s:' % _(
"Layer")),
 
 2686                                         wx.ComboBox(parent = self.
modifyPanel, id = wx.ID_ANY,
 
 2688                                                     style = wx.CB_SIMPLE | wx.CB_READONLY,
 
 2690                                                                 self.mapDBInfo.layers.keys()))),
 
 2692                                        (wx.StaticText(parent = self.
modifyPanel, id = wx.ID_ANY,
 
 2693                                                       label = 
'%s:' % _(
"Driver")),
 
 2694                                         wx.Choice(parent = self.
modifyPanel, id = wx.ID_ANY,
 
 2698                                        (wx.StaticText(parent = self.
modifyPanel, id = wx.ID_ANY,
 
 2699                                                       label = 
'%s:' % _(
"Database")),
 
 2700                                         wx.TextCtrl(parent = self.
modifyPanel, id = wx.ID_ANY,
 
 2701                                                     value = 
'', size = (350, -1),
 
 2702                                                     style = wx.TE_PROCESS_ENTER)),
 
 2704                                        (wx.StaticText(parent = self.
modifyPanel, id = wx.ID_ANY,
 
 2705                                                       label = 
'%s:' % _(
"Table")),
 
 2706                                         wx.Choice(parent = self.
modifyPanel, id = wx.ID_ANY,
 
 2710                                        (wx.StaticText(parent = self.
modifyPanel, id = wx.ID_ANY,
 
 2711                                                       label = 
'%s:' % _(
"Key column")),
 
 2712                                         wx.Choice(parent = self.
modifyPanel, id = wx.ID_ANY,
 
 2722             for label 
in self.modifyLayerWidgets.keys():
 
 2726             driver   = self.mapDBInfo.layers[layer][
'driver']
 
 2727             database = self.mapDBInfo.layers[layer][
'database']
 
 2728             table    = self.mapDBInfo.layers[layer][
'table']
 
 2730             listOfColumns = self.
_getColumns(driver, database, table)
 
 2739                     table = 
'public.' + table 
 
 2750         btnModify = wx.Button(self.
modifyPanel, wx.ID_DELETE, _(
"&Modify layer"),
 
 2757         pageSizer = wx.BoxSizer(wx.VERTICAL)
 
 2760         dataSizer = wx.FlexGridSizer(cols = 2, hgap = 5, vgap = 5)
 
 2761         for key 
in (
'layer', 
'driver', 
'database', 
'table', 
'key'):
 
 2763             dataSizer.Add(item = label,
 
 2764                           flag = wx.ALIGN_CENTER_VERTICAL)
 
 2766                 dataSizer.Add(item = value,
 
 2767                               flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT)
 
 2769                 dataSizer.Add(item = value,
 
 2770                               flag = wx.ALIGN_CENTER_VERTICAL)
 
 2771         dataSizer.AddGrowableCol(1)
 
 2773         pageSizer.Add(item = dataSizer,
 
 2775                       flag = wx.ALL | wx.EXPAND,
 
 2778         pageSizer.Add(item = btnModify,
 
 2780                       flag = wx.ALL | wx.ALIGN_RIGHT,
 
 2783         self.modifyPanel.SetSizer(pageSizer)
 
 2785     def _getTables(self, driver, database):
 
 2786         """!Get list of tables for given driver and database""" 
 2794                          database = database)
 
 2797             GError(parent = self,
 
 2798                    message = _(
"Unable to get list of tables.\n" 
 2799                                "Please use db.connect to set database parameters."))
 
 2803         for table 
in ret.splitlines():
 
 2804             tables.append(table)
 
 2808     def _getColumns(self, driver, database, table):
 
 2809         """!Get list of column of given table""" 
 2817                          database = database,
 
 2823         for column 
in ret.splitlines():
 
 2824             columns.append(column)
 
 2829         """!Driver selection changed, update list of tables""" 
 2830         driver = event.GetString()
 
 2837         winTable.SetItems(tables)
 
 2838         winTable.SetSelection(0)
 
 2840         if len(tables) == 0:
 
 2846         """!Database selection changed, update list of tables""" 
 2850         """!Table name changed, update list of columns""" 
 2853         table    = event.GetString()
 
 2863         """!Set default values""" 
 2873         table.SetItems(tables)
 
 2874         table.SetSelection(0)
 
 2875         if len(tables) == 0:
 
 2887         """!Create new table (name and key column given)""" 
 2893         if not table 
or not key:
 
 2894             GError(parent = self,
 
 2895                    message = _(
"Unable to create new table. " 
 2896                                "Table name or key column name is missing."))
 
 2900             GError(parent = self,
 
 2901                    message = _(
"Unable to create new table. " 
 2902                                "Table <%s> already exists in the database.") % table)
 
 2906         sql = 
'CREATE TABLE %s (%s INTEGER)' % (table, key)
 
 2913                    database = database)
 
 2917         tableList.SetItems(self.
_getTables(driver, database))
 
 2918         tableList.SetStringSelection(table)
 
 2922         keyList.SetItems(self.
_getColumns(driver, database, table))
 
 2923         keyList.SetStringSelection(key)
 
 2928         """!Add new layer to vector map""" 
 2936         if layer 
in self.mapDBInfo.layers.keys():
 
 2937             GError(parent = self,
 
 2938                    message = _(
"Unable to add new layer to vector map <%(vector)s>. " 
 2939                                "Layer %(layer)d already exists.") % \
 
 2940                        {
'vector' : self.mapDBInfo.map, 
'layer' : layer})
 
 2947                          map = self.mapDBInfo.map,
 
 2949                          database = database,
 
 2959                        map = self.mapDBInfo.map,
 
 2967             self.parentDialog.UpdateDialog(layer = layer) 
 
 2969             self.
mapDBInfo = self.parentDialog.mapDBInfo
 
 2971             layerWin.SetValue(layer+1)
 
 2973         if len(self.mapDBInfo.layers.keys()) == 1:
 
 2975             self.deleteLayer.Enable()
 
 2976             self.deleteTable.Enable()
 
 2977             for label 
in self.modifyLayerWidgets.keys():
 
 2983             layer = int(self.deleteLayer.GetValue())
 
 2990                    map = self.mapDBInfo.map,
 
 2994         if self.deleteTable.IsChecked():
 
 2997             table    = self.mapDBInfo.layers[layer][
'table']
 
 2998             sql      = 
'DROP TABLE %s' % (table)
 
 3005                        database = database)
 
 3009             tableList.SetItems(self.
_getTables(driver, database))
 
 3010             tableList.SetStringSelection(table)
 
 3013         self.parentDialog.UpdateDialog(layer = layer) 
 
 3015         self.
mapDBInfo = self.parentDialog.mapDBInfo
 
 3017         if len(self.mapDBInfo.layers.keys()) == 0:
 
 3019             self.deleteLayer.Enable(
False)
 
 3020             self.deleteTable.Enable(
False)
 
 3021             for label 
in self.modifyLayerWidgets.keys():
 
 3027         """!Layer number of layer to be deleted is changed""" 
 3029             layer = int(event.GetString())
 
 3032                 layer = self.mapDBInfo.layers.keys()[0]
 
 3037             driver   = self.mapDBInfo.layers[layer][
'driver']
 
 3038             database = self.mapDBInfo.layers[layer][
'database']
 
 3039             table    = self.mapDBInfo.layers[layer][
'table']
 
 3040             listOfColumns = self.
_getColumns(driver, database, table)
 
 3047             self.deleteTable.SetLabel(_(
'Drop also linked attribute table (%s)') % \
 
 3048                                           self.mapDBInfo.layers[layer][
'table'])
 
 3053         """!Modify layer connection settings""" 
 3059                 self.mapDBInfo.layers[layer][
'driver'] 
or \
 
 3061                 self.mapDBInfo.layers[layer][
'database'] 
or \
 
 3063                 self.mapDBInfo.layers[layer][
'table'] 
or \
 
 3065                 self.mapDBInfo.layers[layer][
'key']:
 
 3074                        map = self.mapDBInfo.map,
 
 3080                        map = self.mapDBInfo.map,
 
 3088             self.parentDialog.UpdateDialog(layer = layer) 
 
 3090             self.
mapDBInfo = self.parentDialog.mapDBInfo
 
 3096     gettext.install(
'grasswxpy', os.path.join(os.getenv(
"GISBASE"), 
'locale'), unicode = 
True)
 
 3102         print >> sys.stderr, __doc__
 
 3106     wx.InitAllImageHandlers()
 
 3108     app = wx.PySimpleApp()
 
 3110                          title = 
"%s - <%s>" % (_(
"GRASS GIS Attribute Table Manager"),
 
 3112                          size = (900,600), vectorName = argv[1])
 
 3117 if __name__ == 
'__main__':
 
def OnColumnMenu
Column heading right mouse button -> pop-up menu. 
 
def IsEmpty
Check if list if empty. 
 
def OnExtractSelected
Extract vector objects selected in attribute browse window to new vector map. 
 
def UpdateDialog
Updates dialog layout for given layer. 
 
def LoadData
Load data into list. 
 
def OnItemDeselected
Item deselected. 
 
def OnDataItemDeleteAll
Delete all items from the list. 
 
def Update
Update description. 
 
def OnLayerPageChanged
Layer tab changed. 
 
def ListOfCatsToRange
Convert list of category number to range(s) 
 
def Update
Update column description. 
 
layerPage
{layer: list, widgets...} 
 
def OnLayerRightUp
Layer description area, context menu. 
 
def OnColumnSortAsc
Sort values of selected column (ascending) 
 
def OnCloseWindow
Cancel button pressed. 
 
def unicodeValue
Encode value. 
 
def OnDataDrawSelected
Reload table description. 
 
def OnDataItemAdd
Add new record to the attribute table. 
 
def OnDataItemEdit
Edit selected record of the attribute table. 
 
def __init__
GRASS Attribute Table Manager window. 
 
def createDbInfoDesc
Create database connection information content. 
 
def GetColumnText
Return column text. 
 
def OnColumnSort
Column heading left mouse button -> sorting. 
 
def OnTableChanged
Table name changed, update list of columns. 
 
def GetVectorName
Get vector name. 
 
def GetSortImages
Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py. 
 
def _getTables
Get list of tables for given driver and database. 
 
def Update
Update list according new mapDBInfo description. 
 
def OnGetItemText
Get item text. 
 
def _createBrowsePage
Create browse tab page. 
 
def OnTableChangeType
Data type for new column changed. 
 
def ColumnSort
Sort values of selected column (self._col) 
 
def OnDataDrawSelectedZoom
 
def OnDataItemDelete
Delete selected item(s) from the tlist (layer/category pair) 
 
Various dialogs used in wxGUI. 
 
def split
Platform spefic shlex.split. 
 
def OnTableItemChange
Rename column in the table. 
 
def OnDeleteLayer
Delete layer. 
 
def _createDeletePage
Delete layer. 
 
def OnDeleteSelected
Delete vector objects selected in attribute browse window (attribures and geometry) ...
 
def GetSelectedItems
Return list of selected items (category numbers) 
 
def OnColumnCompute
Compute values of selected column. 
 
def OnCreateTable
Create new table (name and key column given) 
 
def _createManageLayerPage
Create manage page. 
 
def Populate
Populate the list. 
 
def _createLayerDesc
Create list of linked layers. 
 
def _createManageTablePage
Create manage page (create/link and alter tables) 
 
def OnTableRenameColumnName
Editing column name to be added to the table. 
 
def ApplyCommands
Apply changes. 
 
def OnAddLayer
Add new layer to vector map. 
 
def write
Update status bar. 
 
Manage layers (add, delete, modify) 
 
def ValidateSelectStatement
Validate SQL select statement. 
 
def OnItemSelected
Item selected. 
 
def OnTableAddColumnName
Editing column name to be added to the table. 
 
def GetListCtrl
Returt list. 
 
def OnGetItemAttr
Get item attributes. 
 
def OnDriverChanged
Driver selection changed, update list of tables. 
 
def CreateNewVector
Create new vector map layer. 
 
def OnDataRightUp
Table description area, context menu. 
 
def AddDataRow
Add row to the data list. 
 
def Populate
Populate the list. 
 
def OnDataItemActivated
Item activated, highlight selected item. 
 
def OnDataSelectNone
Deselect items. 
 
def OnModifyLayer
Modify layer connection settings. 
 
def OnSetDefault
Set default values. 
 
def OnDataReload
Reload tlist of records. 
 
Misc utilities for wxGUI. 
 
def OnChangeLayer
Layer number of layer to be deleted is changed. 
 
def _createAddPage
Add new layer. 
 
def LoadData
Load data into list. 
 
def _createTableDesc
Create list with table description. 
 
def _getColumns
Get list of column of given table. 
 
def _createModifyPage
Modify layer. 
 
def AddQueryMapLayer
Redraw a map. 
 
def OnTableItemAdd
Add new column to the table. 
 
def OnTableReload
Reload table description. 
 
def OnBuilder
SQL Builder button pressed -> show the SQLBuilder dialog. 
 
def OnApplySqlStatement
Apply simple/advanced sql statement. 
 
def OnTableItemDeleteAll
Delete all items from the list. 
 
def OnDataSelectAll
Select all items. 
 
def OnDatabaseChanged
Database selection changed, update list of tables. 
 
def _drawSelected
Highlight selected features. 
 
def OnColumnSortDesc
Sort values of selected column (descending) 
 
def OnTableItemDelete
Delete selected item(s) from the list. 
 
def OnChangeSql
Switch simple/advanced sql statement. 
 
def RunCommand
Run GRASS command. 
 
def OnTableRightUp
Table description area, context menu.