GRASS Programmer's Manual  6.4.2(2012)
gselect.py
Go to the documentation of this file.
00001 """!
00002 @package gselect
00003 
00004 @brief Custom control that selects elements
00005 
00006 Classes:
00007  - Select
00008  - VectorSelect
00009  - TreeCrtlComboPopup
00010  - VectorDBInfo
00011  - LayerSelect
00012  - DriverSelect
00013  - DatabaseSelect
00014  - ColumnSelect
00015  - DbaseSelect
00016  - LocationSelect
00017  - MapsetSelect
00018  - SubGroupSelect
00019  - FormatSelect
00020  - GdalSelect
00021  - ProjSelect
00022  - ElementSelect
00023 
00024 (C) 2007-2011 by the GRASS Development Team This program is free
00025 software under the GNU General Public License (>=v2). Read the file
00026 COPYING that comes with GRASS for details.
00027 
00028 @author Michael Barton
00029 @author Martin Landa <landa.martin gmail.com>
00030 @author Vaclav Petras <wenzeslaus gmail.com> (menu customization)
00031 """
00032 
00033 import os
00034 import sys
00035 import glob
00036 
00037 import wx
00038 import wx.combo
00039 import wx.lib.filebrowsebutton as filebrowse
00040 from wx.lib.newevent import NewEvent
00041 
00042 import globalvar
00043 
00044 sys.path.append(os.path.join(globalvar.ETCDIR, "python"))
00045 import grass.script as grass
00046 from   grass.script import task as gtask
00047 
00048 import gcmd
00049 import utils
00050 from preferences import globalSettings as UserSettings
00051 from debug       import Debug
00052 
00053 wxGdalSelect, EVT_GDALSELECT = NewEvent()
00054 
00055 class Select(wx.combo.ComboCtrl):
00056     def __init__(self, parent, id = wx.ID_ANY, size = globalvar.DIALOG_GSELECT_SIZE,
00057                  type = None, multiple = False, mapsets = None,
00058                  updateOnPopup = True, onPopup = None):
00059         """!Custom control to create a ComboBox with a tree control to
00060         display and select GIS elements within acessible mapsets.
00061         Elements can be selected with mouse. Can allow multiple
00062         selections, when argument multiple=True. Multiple selections
00063         are separated by commas.
00064 
00065         @param type type of GIS elements ('raster, 'vector', ...)
00066         @param multiple multiple input allowed?
00067         @param mapsets force list of mapsets (otherwise search path)
00068         @param updateOnPopup True for updating list of elements on popup
00069         @param onPopup function to be called on Popup
00070         """
00071         wx.combo.ComboCtrl.__init__(self, parent=parent, id=id, size=size)
00072         self.GetChildren()[0].SetName("Select")
00073         self.GetChildren()[0].type = type
00074         
00075         self.tcp = TreeCtrlComboPopup()
00076         self.SetPopupControl(self.tcp)
00077         self.SetPopupExtents(0, 100)
00078         if type:
00079             self.tcp.SetData(type = type, mapsets = mapsets,
00080                              multiple = multiple,
00081                              updateOnPopup = updateOnPopup, onPopup = onPopup)
00082         self.GetChildren()[0].Bind(wx.EVT_KEY_UP, self.OnKeyUp)
00083      
00084     def OnKeyUp(self, event):
00085         """!Shows popupwindow if down arrow key is released"""
00086         if event.GetKeyCode() == wx.WXK_DOWN:
00087             self.ShowPopup() 
00088         else:
00089             event.Skip()
00090         
00091     def SetElementList(self, type, mapsets = None):
00092         """!Set element list
00093 
00094         @param type GIS element type
00095         @param mapsets list of acceptable mapsets (None for all in search path)
00096         """
00097         self.tcp.SetData(type = type, mapsets = mapsets)
00098         
00099     def GetElementList(self):
00100         """!Load elements"""
00101         self.tcp.GetElementList()
00102     
00103     def SetType(self, etype, multiple = False, mapsets = None,
00104                 updateOnPopup = True, onPopup = None):
00105         """!Param set element type for widget
00106 
00107         @param etype element type, see gselect.ElementSelect
00108         """
00109         self.tcp.SetData(type = etype, mapsets = mapsets,
00110                          multiple = multiple,
00111                          updateOnPopup = updateOnPopup, onPopup = onPopup)
00112         
00113 class VectorSelect(Select):
00114     def __init__(self, parent, ftype, **kwargs):
00115         """!Custom to create a ComboBox with a tree control to display and
00116         select vector maps. Control allows to filter vector maps. If you
00117         don't need this feature use Select class instead
00118         
00119         @ftype filter vector maps based on feature type
00120         """
00121         Select.__init__(self, parent = parent, id = wx.ID_ANY,
00122                         type = 'vector', **kwargs)
00123         
00124         self.ftype = ftype
00125         
00126         # remove vector maps which do not contain given feature type
00127         self.tcp.SetFilter(self._isElement)
00128         
00129     def _isElement(self, vectorName):
00130         """!Check if element should be filtered out"""
00131         try:
00132             if int(grass.vector_info_topo(vectorName)[self.ftype]) < 1:
00133                 return False
00134         except KeyError:
00135             return False
00136         
00137         return True
00138 
00139 class TreeCtrlComboPopup(wx.combo.ComboPopup):
00140     """!Create a tree ComboBox for selecting maps and other GIS elements
00141     in accessible mapsets within the current location
00142     """
00143     # overridden ComboPopup methods
00144     def Init(self):
00145         self.value = [] # for multiple is False -> len(self.value) in [0,1]
00146         self.curitem = None
00147         self.multiple = False
00148         self.type = None
00149         self.mapsets = None
00150         self.updateOnPopup = True
00151         self.onPopup = None
00152         
00153         self.SetFilter(None)
00154         
00155     def Create(self, parent):
00156         self.seltree = wx.TreeCtrl(parent, style=wx.TR_HIDE_ROOT
00157                                    |wx.TR_HAS_BUTTONS
00158                                    |wx.TR_SINGLE
00159                                    |wx.TR_LINES_AT_ROOT
00160                                    |wx.SIMPLE_BORDER
00161                                    |wx.TR_FULL_ROW_HIGHLIGHT)
00162         self.seltree.Bind(wx.EVT_KEY_UP, self.OnKeyUp)
00163         self.seltree.Bind(wx.EVT_MOTION, self.OnMotion)
00164         self.seltree.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
00165         self.seltree.Bind(wx.EVT_TREE_ITEM_EXPANDING, self.mapsetExpanded)
00166         self.seltree.Bind(wx.EVT_TREE_ITEM_COLLAPSED, self.mapsetCollapsed)
00167         self.seltree.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.mapsetActivated)
00168         self.seltree.Bind(wx.EVT_TREE_SEL_CHANGED, self.mapsetSelected)
00169         self.seltree.Bind(wx.EVT_TREE_DELETE_ITEM, lambda x: None)
00170         
00171     # the following dummy handler are needed to keep tree events from propagating up to
00172     # the parent GIS Manager layer tree
00173     def mapsetExpanded(self, event):
00174         pass
00175 
00176     def mapsetCollapsed(self, event):
00177         pass
00178 
00179     def mapsetActivated(self, event):
00180         pass
00181 
00182     def mapsetSelected(self, event):
00183         pass
00184     # end of dummy events
00185 
00186     def GetControl(self):
00187         return self.seltree
00188 
00189     def GetStringValue(self):
00190         """!Get value as a string separated by commas"""
00191         return ','.join(self.value)
00192     
00193     def SetFilter(self, filter):
00194         """!Set filter for GIS elements, see e.g. VectorSelect"""
00195         self.filterElements = filter
00196     
00197     def OnPopup(self, force = False):
00198         """!Limited only for first selected"""
00199         if not force and not self.updateOnPopup:
00200             return
00201         if self.onPopup:
00202             selected, exclude = self.onPopup(self.type)
00203         else:
00204             selected = None
00205             exclude  = False
00206  
00207         self.GetElementList(selected, exclude)
00208         
00209         # selects map starting according to written text
00210         inputText = self.GetCombo().GetValue().strip()
00211         if inputText:
00212             root = self.seltree.GetRootItem()
00213             match = self.FindItem(root, inputText, startLetters = True)
00214             self.seltree.EnsureVisible(match)
00215             self.seltree.SelectItem(match)
00216             
00217       
00218     def GetElementList(self, elements = None, exclude = False):
00219         """!Get filtered list of GIS elements in accessible mapsets
00220         and display as tree with all relevant elements displayed
00221         beneath each mapset branch
00222         """
00223         # update list
00224         self.seltree.DeleteAllItems()
00225         self._getElementList(self.type, self.mapsets, elements, exclude)
00226         
00227         if len(self.value) > 0:
00228             root = self.seltree.GetRootItem()
00229             if not root:
00230                 return
00231             item = self.FindItem(root, self.value[0])
00232             try:
00233                 self.seltree.EnsureVisible(item)
00234                 self.seltree.SelectItem(item)
00235             except:
00236                 pass
00237             
00238     def SetStringValue(self, value):
00239         # this assumes that item strings are unique...
00240         root = self.seltree.GetRootItem()
00241         if not root:
00242             return
00243         found = self.FindItem(root, value)
00244         winValue = self.GetCombo().GetValue().strip(',')
00245         self.value = []
00246         if winValue:
00247             self.value = winValue.split(',')
00248         
00249         if found:
00250             self.value.append(found)
00251             self.seltree.SelectItem(found)
00252         
00253     def GetAdjustedSize(self, minWidth, prefHeight, maxHeight):
00254         """!Reads UserSettings to get height (which was 200 in old implementation).
00255         """
00256         height = UserSettings.Get(group = 'appearance', key = 'gSelectPopupHeight', subkey = 'value')
00257         return wx.Size(minWidth, min(height, maxHeight))
00258 
00259     def _getElementList(self, element, mapsets = None, elements = None, exclude = False):
00260         """!Get list of GIS elements in accessible mapsets and display as tree
00261         with all relevant elements displayed beneath each mapset branch
00262 
00263         @param element GIS element
00264         @param mapsets list of acceptable mapsets (None for all mapsets in search path)
00265         @param elements list of forced GIS elements
00266         @param exclude True to exclude, False for forcing the list (elements)
00267         """
00268         # get current mapset
00269         curr_mapset = grass.gisenv()['MAPSET']
00270         
00271         # map element types to g.mlist types
00272         elementdict = {'cell':'rast',
00273                        'raster':'rast',
00274                        'rast':'rast',
00275                        'raster files':'rast',
00276                        'grid3':'rast3d',
00277                        'rast3d':'rast3d',
00278                        'raster3d':'rast3d',
00279                        'raster3D files':'rast3d',
00280                        'vector':'vect',
00281                        'vect':'vect',
00282                        'binary vector files':'vect',
00283                        'dig':'oldvect',
00284                        'oldvect':'oldvect',
00285                        'old vector':'oldvect',
00286                        'dig_ascii':'asciivect',
00287                        'asciivect':'asciivect',
00288                        'asciivector':'asciivect',
00289                        'ascii vector files':'asciivect',
00290                        'icons':'icon',
00291                        'icon':'icon',
00292                        'paint icon files':'icon',
00293                        'paint/labels':'labels',
00294                        'labels':'labels',
00295                        'label':'labels',
00296                        'paint label files':'labels',
00297                        'site_lists':'sites',
00298                        'sites':'sites',
00299                        'site list':'sites',
00300                        'site list files':'sites',
00301                        'windows':'region',
00302                        'region':'region',
00303                        'region definition':'region',
00304                        'region definition files':'region',
00305                        'windows3d':'region3d',
00306                        'region3d':'region3d',
00307                        'region3D definition':'region3d',
00308                        'region3D definition files':'region3d',
00309                        'group':'group',
00310                        'imagery group':'group',
00311                        'imagery group files':'group',
00312                        '3d.view':'3dview',
00313                        '3dview':'3dview',
00314                        '3D viewing parameters':'3dview',
00315                        '3D view parameters':'3dview'}
00316         
00317         if element not in elementdict:
00318             self.AddItem(_('Not selectable element'))
00319             return
00320         
00321         if globalvar.have_mlist:
00322             filesdict = grass.mlist_grouped(elementdict[element],
00323                                             check_search_path = False)
00324         else:
00325             filesdict = grass.list_grouped(elementdict[element],
00326                                            check_search_path = False)
00327         
00328         # list of mapsets in current location
00329         if mapsets is None:
00330             mapsets = grass.mapsets(search_path = True)
00331         
00332         # current mapset first
00333         if curr_mapset in mapsets and mapsets[0] != curr_mapset:
00334             mapsets.remove(curr_mapset)
00335             mapsets.insert(0, curr_mapset)
00336         
00337         first_mapset = None
00338         for mapset in mapsets:
00339             mapset_node = self.AddItem(_('Mapset') + ': ' + mapset)
00340             if not first_mapset:
00341                 first_mapset = mapset_node
00342             
00343             self.seltree.SetItemTextColour(mapset_node, wx.Colour(50, 50, 200))
00344             if mapset not in filesdict:
00345                 continue
00346             try:
00347                 elem_list = filesdict[mapset]
00348                 elem_list.sort()
00349                 for elem in elem_list:
00350                     if elem != '':
00351                         fullqElem = elem + '@' + mapset
00352                         if elements is not None:
00353                             if (exclude and fullqElem in elements) or \
00354                                     (not exclude and fullqElem not in elements):
00355                                 continue
00356                         
00357                         if self.filterElements:
00358                             if self.filterElements(fullqElem):
00359                                 self.AddItem(elem, parent = mapset_node)
00360                         else:
00361                             self.AddItem(elem, parent = mapset_node)
00362             except StandardError, e:
00363                 sys.stderr.write(_("GSelect: invalid item: %s") % e)
00364                 continue
00365             
00366             if self.seltree.ItemHasChildren(mapset_node):
00367                 sel = UserSettings.Get(group='appearance', key='elementListExpand',
00368                                        subkey='selection')
00369                 collapse = True
00370 
00371                 if sel == 0: # collapse all except PERMANENT and current
00372                     if mapset in ('PERMANENT', curr_mapset):
00373                         collapse = False
00374                 elif sel == 1: # collapse all except PERMANENT
00375                     if mapset == 'PERMANENT':
00376                         collapse = False
00377                 elif sel == 2: # collapse all except current
00378                     if mapset == curr_mapset:
00379                         collapse = False
00380                 elif sel == 3: # collapse all
00381                     pass
00382                 elif sel == 4: # expand all
00383                     collapse = False
00384                 
00385                 if collapse:
00386                     self.seltree.Collapse(mapset_node)
00387                 else:
00388                     self.seltree.Expand(mapset_node)
00389         
00390         if first_mapset:
00391             # select first mapset (MSW hack)
00392             self.seltree.SelectItem(first_mapset)
00393     
00394     # helpers
00395     def FindItem(self, parentItem, text, startLetters = False):
00396         """!Finds item with given name or starting with given text"""
00397         startletters = startLetters
00398         item, cookie = self.seltree.GetFirstChild(parentItem)
00399         while wx.TreeItemId.IsOk(item):
00400             if self.seltree.GetItemText(item) == text:
00401                 return item
00402             if self.seltree.ItemHasChildren(item):
00403                 item = self.FindItem(item, text, startLetters = startletters)
00404                 if wx.TreeItemId.IsOk(item):
00405                     return item
00406             elif startletters and self.seltree.GetItemText(item).startswith(text.split('@', 1)[0]):
00407                 return item
00408             item, cookie = self.seltree.GetNextChild(parentItem, cookie)
00409         return wx.TreeItemId()
00410     
00411     def AddItem(self, value, parent=None):
00412         if not parent:
00413             root = self.seltree.GetRootItem()
00414             if not root:
00415                 root = self.seltree.AddRoot("<hidden root>")
00416             parent = root
00417 
00418         item = self.seltree.AppendItem(parent, text=value)
00419         return item
00420     
00421     # able to recieve only wx.EVT_KEY_UP
00422     def OnKeyUp(self, event):
00423         """!Enables to select items using keyboard"""
00424         
00425         item = self.seltree.GetSelection()
00426         if event.GetKeyCode() == wx.WXK_DOWN:
00427             self.seltree.SelectItem(self.seltree.GetNextVisible(item))
00428             
00429         # problem with GetPrevVisible   
00430         elif event.GetKeyCode() == wx.WXK_UP: 
00431             if self.seltree.ItemHasChildren(item) and self.seltree.IsExpanded(self.seltree.GetPrevSibling(item)):
00432                 itemPrev = self.seltree.GetLastChild(self.seltree.GetPrevSibling(item))
00433             else:
00434                 itemPrev = self.seltree.GetPrevSibling(item)
00435                 if not wx.TreeItemId.IsOk(itemPrev):
00436                     itemPrev = self.seltree.GetItemParent(item)
00437                     if item == self.seltree.GetFirstChild(self.seltree.GetRootItem())[0]:
00438                         itemPrev = item
00439             self.seltree.SelectItem(itemPrev)
00440         
00441         # selects first item starting with the written text in next mapset
00442         elif event.GetKeyCode() == wx.WXK_TAB:
00443             selected = self.seltree.GetSelection()
00444             if self.seltree.ItemHasChildren(selected):
00445                 parent = selected
00446             else:
00447                 parent = self.seltree.GetItemParent(selected)
00448             nextSibling = self.seltree.GetNextSibling(parent)
00449             if wx.TreeItemId.IsOk(nextSibling):
00450                 match = self.FindItem(nextSibling, self.GetCombo().GetValue().strip(), True) 
00451             else: 
00452                 match = self.FindItem(self.seltree.GetFirstChild(self.seltree.GetItemParent(parent))[0],
00453                                         self.GetCombo().GetValue().strip(), True) 
00454             self.seltree.SelectItem(match)
00455             
00456         elif event.GetKeyCode() == wx.WXK_RIGHT:
00457             if self.seltree.ItemHasChildren(item):
00458                 self.seltree.Expand(item)
00459         
00460         elif event.GetKeyCode() == wx.WXK_LEFT:
00461             if self.seltree.ItemHasChildren(item):
00462                 self.seltree.Collapse(item)
00463                 
00464         elif event.GetKeyCode() == wx.WXK_ESCAPE:
00465             self.Dismiss()
00466             
00467         elif event.GetKeyCode() == wx.WXK_RETURN:
00468             if self.seltree.GetRootItem() == self.seltree.GetItemParent(item):
00469                 self.value = [] 
00470             else:
00471                 mapsetItem = self.seltree.GetItemParent(item)
00472                 fullName = self.seltree.GetItemText(item) + '@' + \
00473                     self.seltree.GetItemText(mapsetItem).split(':', -1)[1].strip()
00474                 
00475                 if self.multiple is True:
00476                     # text item should be unique
00477                     self.value.append(fullName)
00478                 else:
00479                     self.value = [fullName]
00480             
00481             self.Dismiss()
00482         
00483     def OnMotion(self, evt):
00484         """!Have the selection follow the mouse, like in a real combobox
00485         """
00486         item, flags = self.seltree.HitTest(evt.GetPosition())
00487         if item and flags & wx.TREE_HITTEST_ONITEMLABEL:
00488             self.seltree.SelectItem(item)
00489             self.curitem = item
00490         evt.Skip()
00491 
00492     def OnLeftDown(self, evt):
00493         """!Do the combobox selection
00494         """
00495         item, flags = self.seltree.HitTest(evt.GetPosition())
00496         if item and flags & wx.TREE_HITTEST_ONITEMLABEL:
00497             self.curitem = item
00498             
00499             if self.seltree.GetRootItem() == self.seltree.GetItemParent(item):
00500                 self.value = [] # cannot select mapset item
00501             else:
00502                 mapsetItem = self.seltree.GetItemParent(item)
00503                 fullName = self.seltree.GetItemText(item) + '@' + \
00504                     self.seltree.GetItemText(mapsetItem).split(':', -1)[1].strip()
00505                 
00506                 if self.multiple is True:
00507                     # text item should be unique
00508                     self.value.append(fullName)
00509                 else:
00510                     self.value = [fullName]
00511             
00512             self.Dismiss()
00513         
00514         evt.Skip()
00515 
00516     def SetData(self, **kargs):
00517         """!Set object properties"""
00518         if 'type' in kargs:
00519             self.type = kargs['type']
00520         if 'mapsets' in kargs:
00521             self.mapsets = kargs['mapsets']
00522         if 'multiple' in kargs:
00523             self.multiple = kargs['multiple']
00524         if 'updateOnPopup' in kargs:
00525             self.updateOnPopup = kargs['updateOnPopup']
00526         if 'onPopup' in kargs:
00527             self.onPopup = kargs['onPopup']
00528 
00529     def GetType(self):
00530         """!Get element type
00531         """
00532         return self.type
00533     
00534 class VectorDBInfo:
00535     """!Class providing information about attribute tables
00536     linked to a vector map"""
00537     def __init__(self, map):
00538         self.map = map
00539 
00540         # dictionary of layer number and associated (driver, database, table)
00541         self.layers = {}
00542          # dictionary of table and associated columns (type, length, values, ids)
00543         self.tables = {}
00544         
00545         if not self._CheckDBConnection(): # -> self.layers
00546             return
00547 
00548         self._DescribeTables() # -> self.tables
00549 
00550     def _CheckDBConnection(self):
00551         """!Check DB connection"""
00552         nuldev = file(os.devnull, 'w+')
00553         self.layers = grass.vector_db(map=self.map, stderr=nuldev)
00554         nuldev.close()
00555         
00556         if (len(self.layers.keys()) == 0):
00557             return False
00558 
00559         return True
00560 
00561     def _DescribeTables(self):
00562         """!Describe linked tables"""
00563         for layer in self.layers.keys():
00564             # determine column names and types
00565             table = self.layers[layer]["table"]
00566             columns = {} # {name: {type, length, [values], [ids]}}
00567             i = 0
00568             Debug.msg(1, "gselect.VectorDBInfo._DescribeTables(): table=%s driver=%s database=%s" % \
00569                           (self.layers[layer]["table"], self.layers[layer]["driver"],
00570                            self.layers[layer]["database"]))
00571             for item in grass.db_describe(table = self.layers[layer]["table"],
00572                                           driver = self.layers[layer]["driver"],
00573                                           database = self.layers[layer]["database"])['cols']:
00574                 name, type, length = item
00575                 # FIXME: support more datatypes
00576                 if type.lower() == "integer":
00577                     ctype = int
00578                 elif type.lower() == "double precision":
00579                     ctype = float
00580                 else:
00581                     ctype = str
00582 
00583                 columns[name.strip()] = { 'index'  : i,
00584                                           'type'   : type.lower(),
00585                                           'ctype'  : ctype,
00586                                           'length' : int(length),
00587                                           'values' : [],
00588                                           'ids'    : []}
00589                 i += 1
00590             
00591             # check for key column
00592             # v.db.connect -g/p returns always key column name lowercase
00593             if self.layers[layer]["key"] not in columns.keys():
00594                 for col in columns.keys():
00595                     if col.lower() == self.layers[layer]["key"]:
00596                         self.layers[layer]["key"] = col.upper()
00597                         break
00598             
00599             self.tables[table] = columns
00600             
00601         return True
00602     
00603     def Reset(self):
00604         """!Reset"""
00605         for layer in self.layers:
00606             table = self.layers[layer]["table"] # get table desc
00607             columns = self.tables[table]
00608             for name in self.tables[table].keys():
00609                 self.tables[table][name]['values'] = []
00610                 self.tables[table][name]['ids']    = []
00611     
00612     def GetName(self):
00613         """!Get vector name"""
00614         return self.map
00615     
00616     def GetKeyColumn(self, layer):
00617         """!Get key column of given layer
00618         
00619         @param layer vector layer number
00620         """
00621         return str(self.layers[layer]['key'])
00622     
00623     def GetTable(self, layer):
00624         """!Get table name of given layer
00625         
00626         @param layer vector layer number
00627         """
00628         return self.layers[layer]['table']
00629     
00630     def GetDbSettings(self, layer):
00631         """!Get database settins
00632 
00633         @param layer layer number
00634         
00635         @return (driver, database)
00636         """
00637         return self.layers[layer]['driver'], self.layers[layer]['database']
00638     
00639     def GetTableDesc(self, table):
00640         """!Get table columns
00641 
00642         @param table table name
00643         """
00644         return self.tables[table]
00645 
00646 class LayerSelect(wx.ComboBox):
00647     """!Creates combo box for selecting data layers defined for vector.
00648     """
00649     def __init__(self, parent,
00650                  id = wx.ID_ANY, pos = wx.DefaultPosition,
00651                  size = globalvar.DIALOG_LAYER_SIZE,
00652                  vector = None, choices = [], initial = [], default = None):
00653         
00654         super(LayerSelect, self).__init__(parent, id, pos=pos, size=size,
00655                                           choices=choices)
00656         
00657         self.parent  = parent
00658         self.initial = initial
00659         
00660         self.SetName("LayerSelect")
00661 
00662         # default value
00663         self.default = default
00664 
00665         self.InsertLayers(vector = vector)
00666         
00667     def InsertLayers(self, vector):
00668         """!Insert layers for a vector into the layer combobox
00669 
00670         @param vector name of vector map
00671         """
00672         if vector:
00673             layers = utils.GetVectorNumberOfLayers(vector)
00674         else:
00675             layers = list()
00676         
00677         for layer in self.initial:
00678             if layer in layers:
00679                 continue
00680             layers.append(layer)
00681         
00682         if self.default:
00683             if len(layers) == 0:
00684                 layers.insert(0, str(self.default))
00685             elif self.default not in layers:
00686                 layers.append(self.default)
00687         
00688         if len(layers) >= 1:
00689             self.SetItems(layers)
00690 
00691     def Reset(self):
00692         """!Reset value"""
00693         items = self.GetItems()
00694         if items:
00695             if '-1' in items:
00696                 self.SetStringSelection('-1')
00697             else:
00698                 self.SetSelection(0)
00699         else:
00700             self.SetValue('')
00701         
00702 class DriverSelect(wx.ComboBox):
00703     """!Creates combo box for selecting database driver.
00704     """
00705     def __init__(self, parent, choices, value,
00706                  id=wx.ID_ANY, pos=wx.DefaultPosition,
00707                  size=globalvar.DIALOG_LAYER_SIZE, **kargs):
00708 
00709         super(DriverSelect, self).__init__(parent, id, value, pos, size,
00710                                            choices, style=wx.CB_READONLY)
00711         
00712         self.SetName("DriverSelect")
00713         
00714         self.SetStringSelection(value)
00715 
00716 class DatabaseSelect(wx.TextCtrl):
00717     """!Creates combo box for selecting database driver.
00718     """
00719     def __init__(self, parent, value='',
00720                  id=wx.ID_ANY, pos=wx.DefaultPosition,
00721                  size=globalvar.DIALOG_TEXTCTRL_SIZE, **kargs):
00722         
00723         super(DatabaseSelect, self).__init__(parent, id, value, pos, size)
00724                                
00725         self.SetName("DatabaseSelect")
00726 
00727 class TableSelect(wx.ComboBox):
00728     """!Creates combo box for selecting attribute tables from the database
00729     """
00730     def __init__(self, parent,
00731                  id=wx.ID_ANY, value='', pos=wx.DefaultPosition,
00732                  size=globalvar.DIALOG_COMBOBOX_SIZE,
00733                  choices=[]):
00734 
00735         super(TableSelect, self).__init__(parent, id, value, pos, size, choices,
00736                                           style=wx.CB_READONLY)
00737 
00738         self.SetName("TableSelect")
00739 
00740         if not choices:
00741             self.InsertTables()
00742                 
00743     def InsertTables(self, driver=None, database=None):
00744         """!Insert attribute tables into combobox"""
00745         items = []
00746 
00747         if not driver or not database:
00748             connect = grass.db_connection()
00749             
00750             driver = connect['driver']
00751             database = connect['database']
00752         
00753         ret = gcmd.RunCommand('db.tables',
00754                               flags = 'p',
00755                               read = True,
00756                               driver = driver,
00757                               database = database)
00758         
00759         if ret:
00760             for table in ret.splitlines():
00761                 items.append(table)
00762             
00763         self.SetItems(items)
00764         self.SetValue('')
00765         
00766 class ColumnSelect(wx.ComboBox):
00767     """!Creates combo box for selecting columns in the attribute table
00768     for a vector map.
00769 
00770     @param parent window parent
00771     @param id window id
00772     @param value default value
00773     @param size window size
00774     @param vector vector map name
00775     @param layer layer number
00776     @param param parameters list (see menuform.py)
00777     @param **kwags wx.ComboBox parameters
00778     """
00779     def __init__(self, parent, id = wx.ID_ANY, value = '', 
00780                  size=globalvar.DIALOG_COMBOBOX_SIZE,
00781                  vector = None, layer = 1, param = None, **kwargs):
00782         self.defaultValue = value
00783         self.param = param
00784         
00785         super(ColumnSelect, self).__init__(parent, id, value, size = size, **kwargs)
00786         self.SetName("ColumnSelect")
00787         
00788         if vector:
00789             self.InsertColumns(vector, layer)
00790     
00791     def InsertColumns(self, vector, layer, excludeKey = False, type = None, dbInfo = None):
00792         """!Insert columns for a vector attribute table into the columns combobox
00793 
00794         @param vector vector name
00795         @param layer vector layer number
00796         @param excludeKey exclude key column from the list?
00797         @param type only columns of given type (given as list)
00798         """
00799         if not dbInfo:
00800             dbInfo = VectorDBInfo(vector)
00801         
00802         try:
00803             table = dbInfo.GetTable(int(layer))
00804             columnchoices = dbInfo.GetTableDesc(table)
00805             keyColumn = dbInfo.GetKeyColumn(int(layer))
00806             columns = len(columnchoices.keys()) * ['']
00807             for key, val in columnchoices.iteritems():
00808                 columns[val['index']] = key
00809             if excludeKey: # exclude key column
00810                 columns.remove(keyColumn)
00811             if type: # only selected column types
00812                 for key, value in columnchoices.iteritems():
00813                     if value['type'] not in type:
00814                         columns.remove(key)
00815         except (KeyError, ValueError):
00816             columns = list()
00817         
00818         self.SetItems(columns)
00819         self.SetValue(self.defaultValue)
00820         
00821         if self.param:
00822             self.param['value'] = ''
00823         
00824     def InsertTableColumns(self, table, driver=None, database=None):
00825         """!Insert table columns
00826 
00827         @param table table name
00828         @param driver driver name
00829         @param database database name
00830         """
00831         columns = list()
00832         
00833         ret = gcmd.RunCommand('db.columns',
00834                               read = True,
00835                               driver = driver,
00836                               database = database,
00837                               table = table)
00838         
00839         if ret:
00840             columns = ret.splitlines()
00841         
00842         self.SetItems(columns)
00843         self.SetValue(self.defaultValue)
00844         
00845         if self.param:
00846             self.param['value'] = ''
00847 
00848 class DbaseSelect(wx.lib.filebrowsebutton.DirBrowseButton):
00849     """!Widget for selecting GRASS Database"""
00850     def __init__(self, parent, **kwargs):
00851         super(DbaseSelect, self).__init__(parent, id = wx.ID_ANY,
00852                                           size = globalvar.DIALOG_GSELECT_SIZE, labelText = '',
00853                                           dialogTitle = _('Choose GIS Data Directory'),
00854                                           buttonText = _('Browse'),
00855                                           startDirectory = grass.gisenv()['GISDBASE'],
00856                                           **kwargs)
00857         
00858 class LocationSelect(wx.ComboBox):
00859     """!Widget for selecting GRASS location"""
00860     def __init__(self, parent, id = wx.ID_ANY, size = globalvar.DIALOG_COMBOBOX_SIZE, 
00861                  gisdbase = None, **kwargs):
00862         super(LocationSelect, self).__init__(parent, id, size = size, 
00863                                              style = wx.CB_READONLY, **kwargs)
00864         self.SetName("LocationSelect")
00865         
00866         if not gisdbase:
00867             self.gisdbase = grass.gisenv()['GISDBASE']
00868         else:
00869             self.gisdbase = gisdbase
00870         
00871         self.SetItems(utils.GetListOfLocations(self.gisdbase))
00872 
00873     def UpdateItems(self, dbase):
00874         """!Update list of locations
00875 
00876         @param dbase path to GIS database
00877         """
00878         self.gisdbase = dbase
00879         if dbase:
00880             self.SetItems(utils.GetListOfLocations(self.gisdbase))
00881         else:
00882             self.SetItems([])
00883         
00884 class MapsetSelect(wx.ComboBox):
00885     """!Widget for selecting GRASS mapset"""
00886     def __init__(self, parent, id = wx.ID_ANY, size = globalvar.DIALOG_COMBOBOX_SIZE, 
00887                  gisdbase = None, location = None, setItems = True, **kwargs):
00888         super(MapsetSelect, self).__init__(parent, id, size = size, 
00889                                            style = wx.CB_READONLY, **kwargs)
00890         
00891         self.SetName("MapsetSelect")
00892         if not gisdbase:
00893             self.gisdbase = grass.gisenv()['GISDBASE']
00894         else:
00895             self.gisdbase = gisdbase
00896         
00897         if not location:
00898             self.location = grass.gisenv()['LOCATION_NAME']
00899         else:
00900             self.location = location
00901         
00902         if setItems:
00903             self.SetItems(utils.GetListOfMapsets(self.gisdbase, self.location, selectable = False)) # selectable
00904 
00905     def UpdateItems(self, location, dbase = None):
00906         """!Update list of mapsets for given location
00907 
00908         @param dbase path to GIS database (None to use currently selected)
00909         @param location name of location
00910         """
00911         if dbase:
00912             self.gisdbase = dbase
00913         self.location = location
00914         if location:
00915             self.SetItems(utils.GetListOfMapsets(self.gisdbase, self.location, selectable = False))
00916         else:
00917             self.SetItems([])
00918         
00919 class SubGroupSelect(wx.ComboBox):
00920     """!Widget for selecting subgroups"""
00921     def __init__(self, parent, id = wx.ID_ANY, size = globalvar.DIALOG_GSELECT_SIZE, 
00922                  **kwargs):
00923         super(SubGroupSelect, self).__init__(parent, id, size = size, 
00924                                              style = wx.CB_READONLY, **kwargs)
00925         self.SetName("SubGroupSelect")
00926 
00927     def Insert(self, group):
00928         """!Insert subgroups for defined group"""
00929         if not group:
00930             return
00931         gisenv = grass.gisenv()
00932         try:
00933             name, mapset = group.split('@', 1)
00934         except ValueError:
00935             name = group
00936             mapset = gisenv['MAPSET']
00937         
00938         path = os.path.join(gisenv['GISDBASE'], gisenv['LOCATION_NAME'], mapset,
00939                             'group', name, 'subgroup')
00940         try:
00941             self.SetItems(os.listdir(path))
00942         except OSError:
00943             self.SetItems([])
00944         self.SetValue('')
00945 
00946 class FormatSelect(wx.Choice):
00947     def __init__(self, parent, ogr = False,
00948                  sourceType = None, id = wx.ID_ANY, size = globalvar.DIALOG_COMBOBOX_SIZE, 
00949                  **kwargs):
00950         """!Widget for selecting external (GDAL/OGR) format
00951 
00952         @param parent parent window
00953         @param sourceType source type ('file', 'directory', 'database', 'protocol') or None
00954         @param ogr True for OGR otherwise GDAL
00955         """
00956         super(FormatSelect, self).__init__(parent, id, size = size, 
00957                                            **kwargs)
00958         self.SetName("FormatSelect")
00959         
00960         if ogr:
00961             ftype = 'ogr'
00962         else:
00963             ftype = 'gdal'
00964         
00965         formats = list()
00966         for f in utils.GetFormats()[ftype].values():
00967             formats += f
00968         self.SetItems(formats)
00969         
00970     def GetExtension(self, name):
00971         """!Get file extension by format name"""
00972         formatToExt = {
00973             # raster
00974             'GeoTIFF' : 'tif',
00975             'Erdas Imagine Images (.img)' : 'img',
00976             'Ground-based SAR Applications Testbed File Format (.gff)' : 'gff',
00977             'Arc/Info Binary Grid' : 'adf',
00978             'Portable Network Graphics' : 'png',
00979             'JPEG JFIF' : 'jpg',
00980             'Japanese DEM (.mem)' : 'mem',
00981             'Graphics Interchange Format (.gif)' : 'gif',
00982             'X11 PixMap Format' : 'xpm',
00983             'MS Windows Device Independent Bitmap' : 'bmp',
00984             'SPOT DIMAP' : 'dim',
00985             'RadarSat 2 XML Product' : 'xml',
00986             'EarthWatch .TIL' : 'til',
00987             'ERMapper .ers Labelled' : 'ers',
00988             'ERMapper Compressed Wavelets' : 'ecw',
00989             'GRIdded Binary (.grb)' : 'grb',
00990             'EUMETSAT Archive native (.nat)' : 'nat',
00991             'Idrisi Raster A.1' : 'rst',
00992             'Golden Software ASCII Grid (.grd)' : 'grd',
00993             'Golden Software Binary Grid (.grd)' : 'grd',
00994             'Golden Software 7 Binary Grid (.grd)' : 'grd',
00995             'R Object Data Store' : 'r',
00996             'USGS DOQ (Old Style)' : 'doq',
00997             'USGS DOQ (New Style)' : 'doq',
00998             'ENVI .hdr Labelled' : 'hdr',
00999             'ESRI .hdr Labelled' : 'hdr',
01000             'Generic Binary (.hdr Labelled)' : 'hdr',
01001             'PCI .aux Labelled' : 'aux',
01002             'EOSAT FAST Format' : 'fst',
01003             'VTP .bt (Binary Terrain) 1.3 Format' : 'bt',
01004             'FARSITE v.4 Landscape File (.lcp)' : 'lcp',
01005             'Swedish Grid RIK (.rik)' : 'rik',
01006             'USGS Optional ASCII DEM (and CDED)' : 'dem',
01007             'Northwood Numeric Grid Format .grd/.tab' : '',
01008             'Northwood Classified Grid Format .grc/.tab' : '',
01009             'ARC Digitized Raster Graphics' : 'arc',
01010             'Magellan topo (.blx)' : 'blx',
01011             'SAGA GIS Binary Grid (.sdat)' : 'sdat',
01012             # vector
01013             'ESRI Shapefile' : 'shp',
01014             'UK .NTF'        : 'ntf',
01015             'SDTS'           : 'ddf',
01016             'DGN'            : 'dgn',
01017             'VRT'            : 'vrt',
01018             'REC'            : 'rec',
01019             'BNA'            : 'bna',
01020             'CSV'            : 'csv',
01021             'GML'            : 'gml',
01022             'GPX'            : 'gpx',
01023             'KML'            : 'kml',
01024             'GMT'            : 'gmt',
01025             'PGeo'           : 'mdb',
01026             'XPlane'         : 'dat',
01027             'AVCBin'         : 'adf',
01028             'AVCE00'         : 'e00',
01029             'DXF'            : 'dxf',
01030             'Geoconcept'     : 'gxt',
01031             'GeoRSS'         : 'xml',
01032             'GPSTrackMaker'  : 'gtm',
01033             'VFK'            : 'vfk'
01034             }
01035         
01036         try:
01037             return formatToExt[name]
01038         except KeyError:
01039             return ''
01040         
01041 class GdalSelect(wx.Panel):
01042     def __init__(self, parent, panel, ogr = False,
01043                  default = 'file',
01044                  exclude = [],
01045                  envHandler = None):
01046         """!Widget for selecting GDAL/OGR datasource, format
01047         
01048         @param parent parent window
01049         @param ogr    use OGR selector instead of GDAL
01050         """
01051         self.parent = parent
01052         self.ogr    = ogr
01053         wx.Panel.__init__(self, parent = panel, id = wx.ID_ANY)
01054 
01055         self.settingsBox = wx.StaticBox(parent = self, id=wx.ID_ANY,
01056                                         label=" %s " % _("Settings"))
01057         
01058         self.inputBox = wx.StaticBox(parent = self, id=wx.ID_ANY,
01059                                      label=" %s " % _("Source"))
01060         
01061         # source type
01062         sources = list()
01063         self.sourceMap = { 'file' : -1,
01064                            'dir'  : -1,
01065                            'db'   : -1,
01066                            'pro'  : -1 }
01067         idx = 0
01068         if 'file' not in exclude:
01069             sources.append(_("File"))
01070             self.sourceMap['file'] = idx
01071             idx += 1
01072         if 'directory' not in exclude:
01073             sources.append(_("Directory"))
01074             self.sourceMap['dir'] = idx
01075             idx += 1
01076         if 'database' not in exclude:
01077             sources.append(_("Database"))
01078             self.sourceMap['db'] = idx
01079             idx += 1
01080         if 'protocol' not in exclude:
01081             sources.append(_("Protocol"))
01082             self.sourceMap['pro'] = idx
01083         
01084         if self.ogr:
01085             self.settingsFile = os.path.join(utils.GetSettingsPath(), 'wxOGR')
01086         else:
01087             self.settingsFile = os.path.join(utils.GetSettingsPath(), 'wxGDAL')
01088         
01089         self._settings = self._loadSettings()
01090         self.settingsChoice = wx.Choice(parent = self, id = wx.ID_ANY)
01091         self.settingsChoice.Bind(wx.EVT_CHOICE, self.OnSettingsLoad)
01092         self.settingsChoice.SetItems(self._settings.keys())
01093         self.btnSettings = wx.Button(parent = self, id = wx.ID_SAVE)
01094         self.btnSettings.Bind(wx.EVT_BUTTON, self.OnSettingsSave)
01095         
01096         self.source = wx.RadioBox(parent = self, id = wx.ID_ANY,
01097                                   label = _('Source type'),
01098                                   style = wx.RA_SPECIFY_COLS,
01099                                   choices = sources)
01100         self.source.SetSelection(0)
01101         self.source.Bind(wx.EVT_RADIOBOX, self.OnSetType)
01102         
01103         # dsn widgets
01104         if not ogr:
01105             filemask = 'GeoTIFF (%s)|%s|%s (*.*)|*.*' % \
01106                 (self._getExtPattern('tif'), self._getExtPattern('tif'), _('All files'))
01107         else:
01108             filemask = 'ESRI Shapefile (%s)|%s|%s (*.*)|*.*' % \
01109                 (self._getExtPattern('shp'), self._getExtPattern('shp'), _('All files'))
01110         
01111         dsnFile = filebrowse.FileBrowseButton(parent=self, id=wx.ID_ANY, 
01112                                               size=globalvar.DIALOG_GSELECT_SIZE, labelText = '',
01113                                               dialogTitle=_('Choose file to import'),
01114                                               buttonText=_('Browse'),
01115                                               startDirectory=os.getcwd(),
01116                                               changeCallback=self.OnSetDsn,
01117                                               fileMask=filemask)
01118         dsnFile.Hide()
01119         
01120         dsnDir = filebrowse.DirBrowseButton(parent=self, id=wx.ID_ANY, 
01121                                             size=globalvar.DIALOG_GSELECT_SIZE, labelText='',
01122                                             dialogTitle=_('Choose input directory'),
01123                                             buttonText=_('Browse'),
01124                                             startDirectory=os.getcwd(),
01125                                             changeCallback=self.OnSetDsn)
01126         dsnDir.SetName('GdalSelect')
01127         dsnDir.Hide()
01128         
01129         dsnDbFile = filebrowse.FileBrowseButton(parent=self, id=wx.ID_ANY, 
01130                                                 size=globalvar.DIALOG_GSELECT_SIZE, labelText='',
01131                                                 dialogTitle=_('Choose file'),
01132                                                 buttonText=_('Browse'),
01133                                                 startDirectory=os.getcwd(),
01134                                                 changeCallback=self.OnSetDsn)
01135         dsnDbFile.Hide()
01136         dsnDbFile.SetName('GdalSelect')
01137 
01138         dsnDbText = wx.TextCtrl(parent = self, id = wx.ID_ANY)
01139         dsnDbText.Hide()
01140         dsnDbText.Bind(wx.EVT_TEXT, self.OnSetDsn)
01141         dsnDbText.SetName('GdalSelect')
01142 
01143         dsnDbChoice = wx.Choice(parent = self, id = wx.ID_ANY)
01144         dsnDbChoice.Hide()
01145         dsnDbChoice.Bind(wx.EVT_CHOICE, self.OnSetDsn)
01146         dsnDbChoice.SetName('GdalSelect')
01147 
01148         dsnPro = wx.TextCtrl(parent = self, id = wx.ID_ANY)
01149         dsnPro.Hide()
01150         dsnPro.Bind(wx.EVT_TEXT, self.OnSetDsn)
01151         dsnPro.SetName('GdalSelect')
01152 
01153         # format
01154         self.format = FormatSelect(parent = self,
01155                                    ogr = ogr)
01156         self.format.Bind(wx.EVT_CHOICE, self.OnSetFormat)
01157         self.extension = wx.TextCtrl(parent = self, id = wx.ID_ANY)
01158         self.extension.Bind(wx.EVT_TEXT, self.OnSetExtension)
01159         self.extension.Hide()
01160         
01161         if ogr:
01162             fType = 'ogr'
01163         else:
01164             fType = 'gdal'
01165         self.input = { 'file' : [_("File:"),
01166                                  dsnFile,
01167                                  utils.GetFormats()[fType]['file']],
01168                        'dir'  : [_("Directory:"),
01169                                  dsnDir,
01170                                  utils.GetFormats()[fType]['file']],
01171                        'db'   : [_("Database:"),
01172                                  dsnDbFile,
01173                                  utils.GetFormats()[fType]['database']],
01174                        'pro'  : [_("Protocol:"),
01175                                  dsnPro,
01176                                  utils.GetFormats()[fType]['protocol']],
01177                        'db-win' : { 'file'   : dsnDbFile,
01178                                     'text'   : dsnDbText,
01179                                     'choice' : dsnDbChoice },
01180                        }
01181         
01182         self.dsnType = default
01183         self.input[self.dsnType][1].Show()
01184         self.format.SetItems(self.input[self.dsnType][2])
01185         
01186         self.dsnText = wx.StaticText(parent = self, id = wx.ID_ANY,
01187                                      label = self.input[self.dsnType][0],
01188                                      size = (75, -1))
01189         self.extensionText = wx.StaticText(parent = self, id = wx.ID_ANY,
01190                                            label = _("Extension:"))
01191         self.extensionText.Hide()
01192         
01193         self._layout()
01194         
01195         if not ogr:
01196             self.OnSetFormat(event = None, format = 'GeoTIFF')
01197         else:
01198             self.OnSetFormat(event = None, format = 'ESRI Shapefile')
01199         
01200     def _layout(self):
01201         """!Layout"""
01202         mainSizer = wx.BoxSizer(wx.VERTICAL)
01203         
01204         settingsSizer = wx.StaticBoxSizer(self.settingsBox, wx.HORIZONTAL)
01205         settingsSizer.Add(item = wx.StaticText(parent = self,
01206                                                id = wx.ID_ANY,
01207                                                label = _("Load settings:")),
01208                           flag = wx.ALIGN_CENTER_VERTICAL | wx.RIGHT,
01209                           border  = 5)
01210         settingsSizer.Add(item = self.settingsChoice,
01211                           proportion = 1,
01212                           flag = wx.EXPAND)
01213         settingsSizer.Add(item = self.btnSettings,
01214                           flag = wx.LEFT,
01215                           border = 5)
01216         
01217         inputSizer = wx.StaticBoxSizer(self.inputBox, wx.HORIZONTAL)
01218         
01219         self.dsnSizer = wx.GridBagSizer(vgap = 3, hgap = 3)
01220         self.dsnSizer.AddGrowableRow(1)
01221         self.dsnSizer.AddGrowableCol(3)
01222         
01223         self.dsnSizer.Add(item=self.dsnText,
01224                           flag=wx.ALIGN_CENTER_VERTICAL,
01225                           pos = (0, 0))
01226         self.dsnSizer.Add(item=self.input[self.dsnType][1],
01227                           flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND,
01228                           pos = (0, 1), span = (1, 3))
01229         
01230         self.dsnSizer.Add(item = wx.StaticText(parent = self, id = wx.ID_ANY,
01231                                                label = _("Format:")),
01232                           flag = wx.ALIGN_CENTER_VERTICAL,
01233                           pos = (1, 0))
01234         self.dsnSizer.Add(item=self.format,
01235                           flag = wx.ALIGN_CENTER_VERTICAL,
01236                           pos = (1, 1))
01237         self.dsnSizer.Add(item = self.extensionText,
01238                           flag=wx.ALIGN_CENTER_VERTICAL,
01239                           pos = (1, 2))
01240         self.dsnSizer.Add(item=self.extension,
01241                           flag = wx.ALIGN_CENTER_VERTICAL,
01242                           pos = (1, 3))
01243         
01244         inputSizer.Add(item=self.dsnSizer, proportion=1,
01245                        flag=wx.EXPAND | wx.ALL)
01246 
01247         mainSizer.Add(item=settingsSizer, proportion=0,
01248                       flag=wx.ALL | wx.EXPAND, border=5)
01249         mainSizer.Add(item=self.source, proportion=0,
01250                       flag=wx.LEFT | wx.RIGHT | wx.EXPAND, border=5)
01251         mainSizer.Add(item=inputSizer, proportion=0,
01252                       flag=wx.ALL | wx.EXPAND, border=5)
01253         
01254         self.SetSizer(mainSizer)
01255         mainSizer.Fit(self)
01256 
01257     def _getExtPatternGlob(self, ext):
01258         """!Get pattern for case-insensitive globing"""
01259         pattern = '*.'
01260         for c in ext:
01261             pattern += '[%s%s]' % (c.lower(), c.upper())
01262         return pattern
01263     
01264     def _getExtPattern(self, ext):
01265         """!Get pattern for case-insensitive file mask"""
01266         return '*.%s;*.%s' % (ext.lower(), ext.upper())
01267 
01268     def OnSettingsLoad(self, event):
01269         """!Load named settings"""
01270         name = event.GetString()
01271         if name not in self._settings:
01272             gcmd.GError(parent = self,
01273                         message = _("Settings named '%s' not found") % name)
01274             return
01275         data = self._settings[name]
01276         self.OnSetType(event = None, sel = self.sourceMap[data[0]])
01277         self.OnSetFormat(event = None, format = data[2])
01278         self.OnSetDsn(event = None, path = data[1])
01279         
01280     def OnSettingsSave(self, event):
01281         """!Save settings"""
01282         dlg = wx.TextEntryDialog(parent = self,
01283                                  message = _("Name:"),
01284                                  caption = _("Save settings"))
01285         if dlg.ShowModal() != wx.ID_OK:
01286             return
01287         
01288         if not dlg.GetValue():
01289             gcmd.GMessage(parent = self,
01290                           message = _("Name not given, settings is not saved."))
01291             return
01292         
01293         name = dlg.GetValue()
01294         try:
01295             fd = open(self.settingsFile, 'a')
01296             fd.write(name + ';' + self.dsnType + ';' +
01297                      self._getDsn() + ';' +
01298                      self.format.GetStringSelection())
01299             fd.write('\n')
01300         except IOError:
01301             gcmd.GError(parent = self,
01302                         message = _("Unable to save settings"))
01303             return
01304         fd.close()
01305         
01306         self._settings = self._loadSettings()
01307         self.settingsChoice.Append(name)
01308         self.settingsChoice.SetStringSelection(name)
01309         
01310         dlg.Destroy()
01311                 
01312     def _loadSettings(self):
01313         """!Load settings from the file
01314 
01315         The file is defined by self.SettingsFile.
01316         
01317         @return parsed dict
01318         @return empty dict on error
01319         """
01320         data = dict()
01321         if not os.path.exists(self.settingsFile):
01322             return data
01323         
01324         try:
01325             fd = open(self.settingsFile, 'r')
01326             for line in fd.readlines():
01327                 try:
01328                     name, ftype, dsn, format = line.rstrip('\n').split(';')
01329                     data[name] = (ftype, dsn, format)
01330                 except ValueError:
01331                     pass
01332         except IOError:
01333             return data
01334         
01335         fd.close()
01336         
01337         return data
01338 
01339     def OnSetType(self, event, sel = None):
01340         """!Datasource type changed"""
01341         if event:
01342             sel = event.GetSelection()
01343         else:
01344             self.source.SetSelection(sel)
01345         
01346         win = self.input[self.dsnType][1]
01347         self.dsnSizer.Remove(win)
01348         win.Hide()
01349         if sel == self.sourceMap['file']:   # file
01350             self.dsnType = 'file'
01351             format = self.input[self.dsnType][2][0]
01352             try:
01353                 ext = self.format.GetExtension(format)
01354                 if not ext:
01355                     raise KeyError
01356                 format += ' (%s)|%s|%s (*.*)|*.*' % \
01357                     (self._getExtPattern(ext), self._getExtPattern(ext), _('All files'))
01358             except KeyError:
01359                 format += '%s (*.*)|*.*' % _('All files')
01360             
01361             win = filebrowse.FileBrowseButton(parent=self, id=wx.ID_ANY, 
01362                                               size=globalvar.DIALOG_GSELECT_SIZE, labelText='',
01363                                               dialogTitle=_('Choose file to import'),
01364                                               buttonText=_('Browse'),
01365                                               startDirectory=os.getcwd(),
01366                                               changeCallback=self.OnSetDsn,
01367                                               fileMask = format)
01368             self.input[self.dsnType][1] = win
01369         
01370         elif sel == self.sourceMap['dir']: # directory
01371             self.dsnType = 'dir'
01372         elif sel == self.sourceMap['db']: # database
01373             self.dsnType = 'db'
01374         elif sel == self.sourceMap['pro']: # protocol
01375             self.dsnType = 'pro'
01376         
01377         self.dsnText.SetLabel(self.input[self.dsnType][0])
01378         if self.parent.GetName() == 'MultiImportDialog':
01379             self.parent.list.DeleteAllItems()
01380         self.format.SetItems(self.input[self.dsnType][2])        
01381         
01382         if sel in (self.sourceMap['file'],
01383                    self.sourceMap['dir']):
01384             win = self.input[self.dsnType][1]
01385             self.dsnSizer.Add(item=self.input[self.dsnType][1],
01386                               flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND,
01387                               pos = (0, 1))
01388             win.SetValue('')
01389             win.Show()
01390             
01391             if not self.ogr:
01392                 self.OnSetFormat(event = None, format = 'GeoTIFF')
01393             else:
01394                 self.OnSetFormat(event = None, format = 'ESRI Shapefile')
01395         else:
01396             if sel == self.sourceMap['pro']:
01397                 win = self.input[self.dsnType][1]
01398                 self.dsnSizer.Add(item=self.input[self.dsnType][1],
01399                                   flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND,
01400                                   pos = (0, 1))
01401                 win.SetValue('')
01402                 win.Show()
01403         
01404         if sel == self.sourceMap['dir']:
01405             if not self.extension.IsShown():
01406                 self.extensionText.Show()
01407                 self.extension.Show()
01408         else:
01409             if self.extension.IsShown():
01410                 self.extensionText.Hide()
01411                 self.extension.Hide()
01412             
01413         self.dsnSizer.Layout()
01414         
01415     def _getDsn(self):
01416         """!Get datasource name"""
01417         if self.format.GetStringSelection() == 'PostgreSQL':
01418             return 'PG:dbname=%s' % self.input[self.dsnType][1].GetStringSelection()
01419         
01420         return self.input[self.dsnType][1].GetValue()
01421     
01422     def OnSetDsn(self, event, path = None):
01423         """!Input DXF file/OGR dsn defined, update list of layer widget"""
01424         if event:
01425             path = event.GetString()
01426         else:
01427             if self.format.GetStringSelection() == 'PostgreSQL':
01428                 for item in path.split(':', 1)[1].split(','):
01429                     key, value = item.split('=', 1)
01430                     if key == 'dbname':
01431                         self.input[self.dsnType][1].SetStringSelection(value)
01432                         break
01433             else:
01434                 self.input[self.dsnType][1].SetValue(path)
01435         
01436         if not path:
01437             return 
01438         
01439         self._reloadLayers()
01440         
01441         if event:
01442             event.Skip()
01443         
01444     def _reloadLayers(self):
01445         """!Reload list of layers"""
01446         dsn = self._getDsn()
01447         if not dsn:
01448             return
01449         
01450         data = list()        
01451         
01452         layerId = 1
01453         dsn = self._getDsn()
01454         
01455         if self.dsnType == 'file':
01456             baseName = os.path.basename(dsn)
01457             grassName = utils.GetValidLayerName(baseName.split('.', -1)[0])
01458             data.append((layerId, baseName, grassName))
01459         elif self.dsnType == 'dir':
01460             ext = self.extension.GetValue()
01461             for file in glob.glob(os.path.join(dsn, "%s") % self._getExtPatternGlob(ext)):
01462                 baseName = os.path.basename(file)
01463                 grassName = utils.GetValidLayerName(baseName.split('.', -1)[0])
01464                 data.append((layerId, baseName, grassName))
01465                 layerId += 1
01466         elif self.dsnType == 'db':
01467             ret = gcmd.RunCommand('v.in.ogr',
01468                                   quiet = True,
01469                                   read = True,
01470                                   flags = 'l',
01471                                   dsn = dsn)
01472             if not ret:
01473                 self.parent.list.LoadData()
01474                 if hasattr(self, "btn_run"):
01475                     self.btn_run.Enable(False)
01476                 return
01477             layerId = 1
01478             for line in ret.split(','):
01479                 layerName = line.strip()
01480                 grassName = utils.GetValidLayerName(layerName)
01481                 data.append((layerId, layerName.strip(), grassName.strip()))
01482                 layerId += 1
01483         
01484         evt = wxGdalSelect(dsn = dsn + '@OGR')
01485         evt.SetId(self.input[self.dsnType][1].GetId())
01486         wx.PostEvent(self.parent, evt)
01487         
01488         if self.parent.GetName() == 'MultiImportDialog':
01489             self.parent.list.LoadData(data)
01490             if len(data) > 0:
01491                 self.parent.btn_run.Enable(True)
01492             else:
01493                 self.parent.btn_run.Enable(False)
01494         
01495     def OnSetExtension(self, event):
01496         """!Extension changed"""
01497         # reload layers
01498         self._reloadLayers()
01499         
01500     def OnSetFormat(self, event, format = None):
01501         """!Format changed"""
01502         if self.dsnType not in ['file', 'dir', 'db']:
01503             return
01504         
01505         win = self.input[self.dsnType][1]
01506         self.dsnSizer.Remove(win)
01507         
01508         if self.dsnType == 'file':
01509             win.Destroy()
01510         else: # database
01511             win.Hide()
01512         
01513         if event:
01514             format = event.GetString()
01515         else:
01516             self.format.SetStringSelection(format)
01517         
01518         if self.dsnType == 'file':
01519             try:
01520                 ext = self.format.GetExtension(format)
01521                 if not ext:
01522                     raise KeyError
01523                 format += ' (%s)|%s|%s (*.*)|*.*' % \
01524                     (self._getExtPattern(ext), self._getExtPattern(ext), _('All files'))
01525             except KeyError:
01526                 format += '%s (*.*)|*.*' % _('All files')
01527             
01528             win = filebrowse.FileBrowseButton(parent=self, id=wx.ID_ANY, 
01529                                               size=globalvar.DIALOG_GSELECT_SIZE, labelText='',
01530                                               dialogTitle=_('Choose file'),
01531                                               buttonText=_('Browse'),
01532                                               startDirectory=os.getcwd(),
01533                                               changeCallback=self.OnSetDsn,
01534                                               fileMask = format)
01535             
01536         elif self.dsnType == 'dir':
01537             pass
01538         
01539         else: # database
01540             if format == 'SQLite' or format == 'Rasterlite':
01541                 win = self.input['db-win']['file']
01542             elif format == 'PostgreSQL' or format == 'PostGIS WKT Raster driver':
01543                 if grass.find_program('psql', ['--help']):
01544                     win = self.input['db-win']['choice']
01545                     if not win.GetItems():
01546                         p = grass.Popen(['psql', '-ltA'], stdout = grass.PIPE)
01547                         ret = p.communicate()[0]
01548                         if ret:
01549                             db = list()
01550                             for line in ret.splitlines():
01551                                 sline = line.split('|')
01552                                 if len(sline) < 2:
01553                                     continue
01554                                 dbname = sline[0]
01555                                 if dbname:
01556                                     db.append(dbname)
01557                             win.SetItems(db)
01558                 else:
01559                     win = self.input['db-win']['text']
01560             else:
01561                 win = self.input['db-win']['text']
01562             
01563         self.input[self.dsnType][1] = win
01564         if not win.IsShown():
01565             win.Show()
01566         self.dsnSizer.Add(item = self.input[self.dsnType][1],
01567                           flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND,
01568                           pos = (0, 1), span = (1, 3))
01569         self.dsnSizer.Layout()
01570         
01571         # update extension
01572         self.extension.SetValue(self.GetFormatExt())
01573 
01574         # reload layers
01575         self._reloadLayers()
01576         
01577     def GetType(self):
01578         """!Get source type"""
01579         return self.dsnType
01580 
01581     def GetDsn(self):
01582         """!Get DSN"""
01583         if self.format.GetStringSelection() == 'PostgreSQL':
01584             return 'PG:dbname=%s' % self.input[self.dsnType][1].GetStringSelection()
01585         
01586         return self.input[self.dsnType][1].GetValue()
01587 
01588     def GetDsnWin(self):
01589         """!Get list of DSN windows"""
01590         win = list()
01591         for stype in ('file', 'dir', 'pro'):
01592             win.append(self.input[stype][1])
01593         for stype in ('file', 'text', 'choice'):
01594             win.append(self.input['db-win'][stype])
01595         
01596         return win
01597     
01598     def GetFormatExt(self):
01599         """!Get format extension"""
01600         return self.format.GetExtension(self.format.GetStringSelection())
01601     
01602 class ProjSelect(wx.ComboBox):
01603     """!Widget for selecting input raster/vector map used by
01604     r.proj/v.proj modules."""
01605     def __init__(self, parent, isRaster, id = wx.ID_ANY, size = globalvar.DIALOG_COMBOBOX_SIZE,
01606                  **kwargs):
01607         super(ProjSelect, self).__init__(parent, id, size = size, 
01608                                          style = wx.CB_READONLY, **kwargs)
01609         self.SetName("ProjSelect")
01610         self.isRaster = isRaster
01611         
01612     def UpdateItems(self, dbase, location, mapset):
01613         """!Update list of maps
01614         
01615         """
01616         if not dbase:
01617             dbase = grass.gisenv()['GISDBASE']
01618         if not mapset:
01619             mapset = grass.gisenv()['MAPSET']
01620         if self.isRaster:
01621             ret = gcmd.RunCommand('r.proj',
01622                                   quiet = True,
01623                                   read = True,
01624                                   flags = 'l',
01625                                   dbase = dbase,
01626                                   location = location,
01627                                   mapset = mapset)
01628         else:
01629             ret = gcmd.RunCommand('v.proj',
01630                                   quiet = True,
01631                                   read = True,
01632                                   flags = 'l',
01633                                   dbase = dbase,
01634                                   location = location,
01635                                   mapset = mapset)
01636         listMaps = list()
01637         if ret:
01638             for line in ret.splitlines():
01639                 listMaps.append(line.strip())
01640         utils.ListSortLower(listMaps)
01641         
01642         self.SetItems(listMaps)
01643         self.SetValue('')
01644 
01645 class ElementSelect(wx.Choice):
01646     def __init__(self, parent, id = wx.ID_ANY, size = globalvar.DIALOG_COMBOBOX_SIZE, 
01647                  **kwargs):
01648         """!Widget for selecting GIS element
01649         
01650         @param parent parent window
01651         """
01652         super(ElementSelect, self).__init__(parent, id, size = size, 
01653                                             **kwargs)
01654         self.SetName("ElementSelect")
01655         
01656         task = gtask.parse_interface('g.list')
01657         p = task.get_param(value = 'type')
01658         self.values = p.get('values', [])
01659                 
01660         self.SetItems(self.values)
01661 
01662     def GetValue(self, name):
01663         """!Translate value
01664 
01665         @param name element name
01666         """
01667         return name
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines