GRASS Programmer's Manual
6.4.2(2012)
|
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