|
GRASS Programmer's Manual
6.5.svn(2012)-r51648
|
00001 """! 00002 @package lmgr::frame 00003 00004 @brief Layer Manager - main menu, layer management toolbar, notebook 00005 control for display management and access to command console. 00006 00007 Classes: 00008 - frame::GMFrame 00009 00010 (C) 2006-2011 by the GRASS Development Team 00011 00012 This program is free software under the GNU General Public License 00013 (>=v2). Read the file COPYING that comes with GRASS for details. 00014 00015 @author Michael Barton (Arizona State University) 00016 @author Jachym Cepicky (Mendel University of Agriculture) 00017 @author Martin Landa <landa.martin gmail.com> 00018 @author Vaclav Petras <wenzeslaus gmail.com> (menu customization) 00019 """ 00020 00021 import sys 00022 import os 00023 import tempfile 00024 import stat 00025 try: 00026 import xml.etree.ElementTree as etree 00027 except ImportError: 00028 import elementtree.ElementTree as etree # Python <= 2.4 00029 00030 from core import globalvar 00031 import wx 00032 import wx.aui 00033 try: 00034 import wx.lib.agw.flatnotebook as FN 00035 except ImportError: 00036 import wx.lib.flatnotebook as FN 00037 00038 sys.path.append(os.path.join(globalvar.ETCDIR, "python")) 00039 from grass.script import core as grass 00040 00041 from core.gcmd import RunCommand, GError, GMessage 00042 from core.settings import UserSettings 00043 from gui_core.preferences import MapsetAccess, PreferencesDialog, EVT_SETTINGS_CHANGED 00044 from lmgr.layertree import LayerTree, LMIcons 00045 from lmgr.menudata import ManagerData 00046 from gui_core.widgets import GNotebook 00047 from modules.mcalc_builder import MapCalcFrame 00048 from dbmgr.manager import AttributeManager 00049 from core.workspace import ProcessWorkspaceFile, ProcessGrcFile, WriteWorkspaceFile 00050 from gui_core.goutput import GMConsole 00051 from gui_core.dialogs import DxfImportDialog, GdalImportDialog, MapLayersDialog 00052 from gui_core.dialogs import LocationDialog, MapsetDialog, CreateNewVector, GroupDialog 00053 from modules.ogc_services import WMSDialog 00054 from modules.colorrules import RasterColorTable, VectorColorTable 00055 from gui_core.menu import Menu 00056 from gmodeler.model import Model 00057 from gmodeler.frame import ModelFrame 00058 from psmap.frame import PsMapFrame 00059 from core.debug import Debug 00060 from gui_core.ghelp import MenuTreeWindow, AboutWindow 00061 from modules.extensions import InstallExtensionWindow, UninstallExtensionWindow 00062 from lmgr.toolbars import LMWorkspaceToolbar, LMDataToolbar, LMToolsToolbar 00063 from lmgr.toolbars import LMMiscToolbar, LMVectorToolbar, LMNvizToolbar 00064 from lmgr.pyshell import PyShellWindow 00065 from gui_core.forms import GUI 00066 from gcp.manager import GCPWizard 00067 from nviz.main import haveNviz 00068 00069 class GMFrame(wx.Frame): 00070 """!Layer Manager frame with notebook widget for controlling GRASS 00071 GIS. Includes command console page for typing GRASS (and other) 00072 commands, tree widget page for managing map layers. 00073 """ 00074 def __init__(self, parent, id = wx.ID_ANY, title = _("GRASS GIS Layer Manager"), 00075 workspace = None, 00076 size = globalvar.GM_WINDOW_SIZE, style = wx.DEFAULT_FRAME_STYLE, **kwargs): 00077 self.parent = parent 00078 self.baseTitle = title 00079 self.iconsize = (16, 16) 00080 00081 wx.Frame.__init__(self, parent = parent, id = id, size = size, 00082 style = style, **kwargs) 00083 00084 self.SetTitle(self.baseTitle) 00085 self.SetName("LayerManager") 00086 00087 self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO)) 00088 00089 self._auimgr = wx.aui.AuiManager(self) 00090 00091 # initialize variables 00092 self.disp_idx = 0 # index value for map displays and layer trees 00093 self.curr_page = None # currently selected page for layer tree notebook 00094 self.curr_pagenum = None # currently selected page number for layer tree notebook 00095 self.workspaceFile = workspace # workspace file 00096 self.workspaceChanged = False # track changes in workspace 00097 self.georectifying = None # reference to GCP class or None 00098 self.gcpmanagement = None # reference to GCP class or None 00099 00100 # list of open dialogs 00101 self.dialogs = dict() 00102 self.dialogs['preferences'] = None 00103 self.dialogs['atm'] = list() 00104 00105 # creating widgets 00106 self._createMenuBar() 00107 self.statusbar = self.CreateStatusBar(number = 1) 00108 self.notebook = self._createNoteBook() 00109 self.toolbars = { 'workspace' : LMWorkspaceToolbar(parent = self), 00110 'data' : LMDataToolbar(parent = self), 00111 'tools' : LMToolsToolbar(parent = self), 00112 'misc' : LMMiscToolbar(parent = self), 00113 'vector' : LMVectorToolbar(parent = self), 00114 'nviz' : LMNvizToolbar(parent = self)} 00115 00116 self._toolbarsData = { 'workspace' : ("toolbarWorkspace", # name 00117 _("Workspace Toolbar"), # caption 00118 1), # row 00119 'data' : ("toolbarData", 00120 _("Data Toolbar"), 00121 1), 00122 'misc' : ("toolbarMisc", 00123 _("Misc Toolbar"), 00124 2), 00125 'tools' : ("toolbarTools", 00126 _("Tools Toolbar"), 00127 2), 00128 'vector' : ("toolbarVector", 00129 _("Vector Toolbar"), 00130 2), 00131 'nviz' : ("toolbarNviz", 00132 _("3D view Toolbar"), 00133 2), 00134 } 00135 if sys.platform == 'win32': 00136 self._toolbarsList = ('workspace', 'data', 00137 'vector', 'tools', 'misc', 'nviz') 00138 else: 00139 self._toolbarsList = ('data', 'workspace', 00140 'nviz', 'misc', 'tools', 'vector') 00141 for toolbar in self._toolbarsList: 00142 name, caption, row = self._toolbarsData[toolbar] 00143 self._auimgr.AddPane(self.toolbars[toolbar], 00144 wx.aui.AuiPaneInfo(). 00145 Name(name).Caption(caption). 00146 ToolbarPane().Top().Row(row). 00147 LeftDockable(False).RightDockable(False). 00148 BottomDockable(False).TopDockable(True). 00149 CloseButton(False).Layer(2). 00150 BestSize((self.toolbars[toolbar].GetBestSize()))) 00151 00152 self._auimgr.GetPane('toolbarNviz').Hide() 00153 # bindings 00154 self.Bind(wx.EVT_CLOSE, self.OnCloseWindow) 00155 self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown) 00156 00157 # minimal frame size 00158 self.SetMinSize((500, 400)) 00159 00160 # AUI stuff 00161 self._auimgr.AddPane(self.notebook, wx.aui.AuiPaneInfo(). 00162 Left().CentrePane().BestSize((-1,-1)).Dockable(False). 00163 CloseButton(False).DestroyOnClose(True).Row(1).Layer(0)) 00164 00165 self._auimgr.Update() 00166 00167 wx.CallAfter(self.notebook.SetSelectionByName, 'layers') 00168 00169 # use default window layout ? 00170 if UserSettings.Get(group = 'general', key = 'defWindowPos', subkey = 'enabled'): 00171 dim = UserSettings.Get(group = 'general', key = 'defWindowPos', subkey = 'dim') 00172 try: 00173 x, y = map(int, dim.split(',')[0:2]) 00174 w, h = map(int, dim.split(',')[2:4]) 00175 self.SetPosition((x, y)) 00176 self.SetSize((w, h)) 00177 except: 00178 pass 00179 else: 00180 self.Centre() 00181 00182 self.Layout() 00183 self.Show() 00184 00185 # load workspace file if requested 00186 if self.workspaceFile: 00187 # load given workspace file 00188 if self.LoadWorkspaceFile(self.workspaceFile): 00189 self.SetTitle(self.baseTitle + " - " + os.path.basename(self.workspaceFile)) 00190 else: 00191 self.workspaceFile = None 00192 else: 00193 # start default initial display 00194 self.NewDisplay(show = False) 00195 00196 # show map display widnow 00197 # -> OnSize() -> UpdateMap() 00198 if self.curr_page and not self.curr_page.maptree.mapdisplay.IsShown(): 00199 self.curr_page.maptree.mapdisplay.Show() 00200 00201 # redirect stderr to log area 00202 self.goutput.Redirect() 00203 00204 # fix goutput's pane size (required for Mac OSX)` 00205 self.goutput.SetSashPosition(int(self.GetSize()[1] * .8)) 00206 00207 self.workspaceChanged = False 00208 00209 # start with layer manager on top 00210 if self.curr_page: 00211 self.curr_page.maptree.mapdisplay.Raise() 00212 wx.CallAfter(self.Raise) 00213 00214 def _createMenuBar(self): 00215 """!Creates menu bar""" 00216 self.menubar = Menu(parent = self, data = ManagerData()) 00217 self.SetMenuBar(self.menubar) 00218 self.menucmd = self.menubar.GetCmd() 00219 00220 def _createTabMenu(self): 00221 """!Creates context menu for display tabs. 00222 00223 Used to rename display. 00224 """ 00225 menu = wx.Menu() 00226 item = wx.MenuItem(menu, id = wx.ID_ANY, text = _("Rename Map Display")) 00227 menu.AppendItem(item) 00228 self.Bind(wx.EVT_MENU, self.OnRenameDisplay, item) 00229 00230 return menu 00231 00232 def _setCopyingOfSelectedText(self): 00233 copy = UserSettings.Get(group = 'manager', key = 'copySelectedTextToClipboard', subkey = 'enabled') 00234 self.goutput.SetCopyingOfSelectedText(copy) 00235 00236 def IsPaneShown(self, name): 00237 """!Check if pane (toolbar, ...) of given name is currently shown""" 00238 if self._auimgr.GetPane(name).IsOk(): 00239 return self._auimgr.GetPane(name).IsShown() 00240 return False 00241 00242 def _createNoteBook(self): 00243 """!Creates notebook widgets""" 00244 self.notebook = GNotebook(parent = self, style = globalvar.FNPageDStyle) 00245 # create displays notebook widget and add it to main notebook page 00246 cbStyle = globalvar.FNPageStyle 00247 if globalvar.hasAgw: 00248 self.gm_cb = FN.FlatNotebook(self, id = wx.ID_ANY, agwStyle = cbStyle) 00249 else: 00250 self.gm_cb = FN.FlatNotebook(self, id = wx.ID_ANY, style = cbStyle) 00251 self.gm_cb.SetTabAreaColour(globalvar.FNPageColor) 00252 menu = self._createTabMenu() 00253 self.gm_cb.SetRightClickMenu(menu) 00254 self.notebook.AddPage(page = self.gm_cb, text = _("Map layers"), name = 'layers') 00255 00256 # create 'command output' text area 00257 self.goutput = GMConsole(self) 00258 self.notebook.AddPage(page = self.goutput, text = _("Command console"), name = 'output') 00259 self._setCopyingOfSelectedText() 00260 00261 # create 'search module' notebook page 00262 if not UserSettings.Get(group = 'manager', key = 'hideTabs', subkey = 'search'): 00263 self.search = MenuTreeWindow(parent = self) 00264 self.notebook.AddPage(page = self.search, text = _("Search module"), name = 'search') 00265 else: 00266 self.search = None 00267 00268 # create 'python shell' notebook page 00269 if not UserSettings.Get(group = 'manager', key = 'hideTabs', subkey = 'pyshell'): 00270 self.pyshell = PyShellWindow(parent = self) 00271 self.notebook.AddPage(page = self.pyshell, text = _("Python shell"), name = 'pyshell') 00272 else: 00273 self.pyshell = None 00274 00275 # bindings 00276 self.gm_cb.Bind(FN.EVT_FLATNOTEBOOK_PAGE_CHANGED, self.OnCBPageChanged) 00277 self.notebook.Bind(FN.EVT_FLATNOTEBOOK_PAGE_CHANGED, self.OnPageChanged) 00278 self.gm_cb.Bind(FN.EVT_FLATNOTEBOOK_PAGE_CLOSING, self.OnCBPageClosed) 00279 00280 return self.notebook 00281 00282 def AddNvizTools(self): 00283 """!Add nviz notebook page""" 00284 Debug.msg(5, "GMFrame.AddNvizTools()") 00285 if not haveNviz: 00286 return 00287 00288 from nviz.main import NvizToolWindow 00289 00290 # show toolbar 00291 self._auimgr.GetPane('toolbarNviz').Show() 00292 # reorder other toolbars 00293 for pos, toolbar in enumerate(('toolbarVector', 'toolbarTools', 'toolbarMisc','toolbarNviz')): 00294 self._auimgr.GetPane(toolbar).Row(2).Position(pos) 00295 self._auimgr.Update() 00296 00297 # create nviz tools tab 00298 self.nviz = NvizToolWindow(parent = self, 00299 display = self.curr_page.maptree.GetMapDisplay()) 00300 idx = self.notebook.GetPageIndexByName('layers') 00301 self.notebook.InsertPage(indx = idx + 1, page = self.nviz, text = _("3D view"), name = 'nviz') 00302 self.notebook.SetSelectionByName('nviz') 00303 00304 00305 def RemoveNvizTools(self): 00306 """!Remove nviz notebook page""" 00307 # if more mapwindow3D were possible, check here if nb page should be removed 00308 self.notebook.SetSelectionByName('layers') 00309 self.notebook.RemovePage(self.notebook.GetPageIndexByName('nviz')) 00310 del self.nviz 00311 # hide toolbar 00312 self._auimgr.GetPane('toolbarNviz').Hide() 00313 for pos, toolbar in enumerate(('toolbarVector', 'toolbarTools', 'toolbarMisc')): 00314 self._auimgr.GetPane(toolbar).Row(2).Position(pos) 00315 self._auimgr.Update() 00316 00317 def WorkspaceChanged(self): 00318 """!Update window title""" 00319 if not self.workspaceChanged: 00320 self.workspaceChanged = True 00321 00322 if self.workspaceFile: 00323 self.SetTitle(self.baseTitle + " - " + os.path.basename(self.workspaceFile) + '*') 00324 00325 def OnLocationWizard(self, event): 00326 """!Launch location wizard""" 00327 from location_wizard.wizard import LocationWizard 00328 00329 gWizard = LocationWizard(parent = self, 00330 grassdatabase = grass.gisenv()['GISDBASE']) 00331 location = gWizard.location 00332 00333 if location != None: 00334 dlg = wx.MessageDialog(parent = self, 00335 message = _('Location <%s> created.\n\n' 00336 'Do you want to switch to the ' 00337 'new location?') % location, 00338 caption=_("Switch to new location?"), 00339 style = wx.YES_NO | wx.NO_DEFAULT | 00340 wx.ICON_QUESTION | wx.CENTRE) 00341 00342 ret = dlg.ShowModal() 00343 dlg.Destroy() 00344 if ret == wx.ID_YES: 00345 if RunCommand('g.mapset', parent = self, 00346 location = location, 00347 mapset = 'PERMANENT') != 0: 00348 return 00349 00350 GMessage(parent = self, 00351 message = _("Current location is <%(loc)s>.\n" 00352 "Current mapset is <%(mapset)s>.") % \ 00353 { 'loc' : location, 'mapset' : 'PERMANENT' }) 00354 00355 def OnSettingsChanged(self, event): 00356 """!Here can be functions which have to be called after EVT_SETTINGS_CHANGED. 00357 Now only set copying of selected text to clipboard (in goutput). 00358 """ 00359 ### self._createMenuBar() # bug when menu is re-created on the fly 00360 self._setCopyingOfSelectedText() 00361 00362 def OnGCPManager(self, event): 00363 """!Launch georectifier module 00364 """ 00365 GCPWizard(self) 00366 00367 def OnGModeler(self, event): 00368 """!Launch Graphical Modeler""" 00369 win = ModelFrame(parent = self) 00370 win.CentreOnScreen() 00371 00372 win.Show() 00373 00374 def OnPsMap(self, event): 00375 """!Launch Cartographic Composer 00376 """ 00377 win = PsMapFrame(parent = self) 00378 win.CentreOnScreen() 00379 00380 win.Show() 00381 00382 def OnDone(self, cmd, returncode): 00383 """Command execution finised""" 00384 if hasattr(self, "model"): 00385 self.model.DeleteIntermediateData(log = self.goutput) 00386 del self.model 00387 self.SetStatusText('') 00388 00389 def OnRunModel(self, event): 00390 """!Run model""" 00391 filename = '' 00392 dlg = wx.FileDialog(parent = self, message =_("Choose model to run"), 00393 defaultDir = os.getcwd(), 00394 wildcard = _("GRASS Model File (*.gxm)|*.gxm")) 00395 if dlg.ShowModal() == wx.ID_OK: 00396 filename = dlg.GetPath() 00397 00398 if not filename: 00399 dlg.Destroy() 00400 return 00401 00402 self.model = Model() 00403 self.model.LoadModel(filename) 00404 self.model.Run(log = self.goutput, onDone = self.OnDone, parent = self) 00405 00406 dlg.Destroy() 00407 00408 def OnMapsets(self, event): 00409 """!Launch mapset access dialog 00410 """ 00411 dlg = MapsetAccess(parent = self, id = wx.ID_ANY) 00412 dlg.CenterOnScreen() 00413 00414 if dlg.ShowModal() == wx.ID_OK: 00415 ms = dlg.GetMapsets() 00416 RunCommand('g.mapsets', 00417 parent = self, 00418 mapset = '%s' % ','.join(ms)) 00419 00420 def OnCBPageChanged(self, event): 00421 """!Page in notebook (display) changed""" 00422 self.curr_page = self.gm_cb.GetCurrentPage() 00423 self.curr_pagenum = self.gm_cb.GetSelection() 00424 try: 00425 self.curr_page.maptree.mapdisplay.SetFocus() 00426 self.curr_page.maptree.mapdisplay.Raise() 00427 except: 00428 pass 00429 00430 event.Skip() 00431 00432 def OnPageChanged(self, event): 00433 """!Page in notebook changed""" 00434 page = event.GetSelection() 00435 if page == self.notebook.GetPageIndexByName('output'): 00436 # remove '(...)' 00437 self.notebook.SetPageText(page, _("Command console")) 00438 wx.CallAfter(self.goutput.ResetFocus) 00439 self.SetStatusText('', 0) 00440 00441 event.Skip() 00442 00443 def OnCBPageClosed(self, event): 00444 """!Page of notebook closed 00445 Also close associated map display 00446 """ 00447 if UserSettings.Get(group = 'manager', key = 'askOnQuit', subkey = 'enabled'): 00448 maptree = self.curr_page.maptree 00449 00450 if self.workspaceFile: 00451 message = _("Do you want to save changes in the workspace?") 00452 else: 00453 message = _("Do you want to store current settings " 00454 "to workspace file?") 00455 00456 # ask user to save current settings 00457 if maptree.GetCount() > 0: 00458 name = self.gm_cb.GetPageText(self.curr_pagenum) 00459 dlg = wx.MessageDialog(self, 00460 message = message, 00461 caption = _("Close Map Display %s") % name, 00462 style = wx.YES_NO | wx.YES_DEFAULT | 00463 wx.CANCEL | wx.ICON_QUESTION | wx.CENTRE) 00464 ret = dlg.ShowModal() 00465 if ret == wx.ID_YES: 00466 if not self.workspaceFile: 00467 self.OnWorkspaceSaveAs() 00468 else: 00469 self.SaveToWorkspaceFile(self.workspaceFile) 00470 elif ret == wx.ID_CANCEL: 00471 event.Veto() 00472 dlg.Destroy() 00473 return 00474 dlg.Destroy() 00475 00476 self.gm_cb.GetPage(event.GetSelection()).maptree.Map.Clean() 00477 self.gm_cb.GetPage(event.GetSelection()).maptree.Close(True) 00478 00479 self.curr_page = None 00480 00481 event.Skip() 00482 00483 def GetLayerTree(self): 00484 """!Get current layer tree""" 00485 return self.curr_page.maptree 00486 00487 def GetLogWindow(self): 00488 """!Get widget for command output""" 00489 return self.goutput 00490 00491 def GetMenuCmd(self, event): 00492 """!Get GRASS command from menu item 00493 00494 Return command as a list""" 00495 layer = None 00496 00497 if event: 00498 cmd = self.menucmd[event.GetId()] 00499 00500 try: 00501 cmdlist = cmd.split(' ') 00502 except: # already list? 00503 cmdlist = cmd 00504 00505 # check list of dummy commands for GUI modules that do not have GRASS 00506 # bin modules or scripts. 00507 if cmd in ['vcolors', 'r.mapcalc', 'r3.mapcalc']: 00508 return cmdlist 00509 00510 try: 00511 layer = self.curr_page.maptree.layer_selected 00512 name = self.curr_page.maptree.GetPyData(layer)[0]['maplayer'].name 00513 type = self.curr_page.maptree.GetPyData(layer)[0]['type'] 00514 except: 00515 layer = None 00516 00517 if layer and len(cmdlist) == 1: # only if no paramaters given 00518 if (type == 'raster' and cmdlist[0][0] == 'r' and cmdlist[0][1] != '3') or \ 00519 (type == 'vector' and cmdlist[0][0] == 'v'): 00520 input = GUI().GetCommandInputMapParamKey(cmdlist[0]) 00521 if input: 00522 cmdlist.append("%s=%s" % (input, name)) 00523 00524 return cmdlist 00525 00526 def RunMenuCmd(self, event = None, cmd = []): 00527 """!Run command selected from menu""" 00528 if event: 00529 cmd = self.GetMenuCmd(event) 00530 self.goutput.RunCmd(cmd, switchPage = False) 00531 00532 def OnMenuCmd(self, event = None, cmd = []): 00533 """!Parse command selected from menu""" 00534 if event: 00535 cmd = self.GetMenuCmd(event) 00536 GUI(parent = self).ParseCommand(cmd) 00537 00538 def OnVDigit(self, event): 00539 """!Start vector digitizer 00540 """ 00541 if not self.curr_page: 00542 self.MsgNoLayerSelected() 00543 return 00544 00545 tree = self.GetLayerTree() 00546 layer = tree.layer_selected 00547 # no map layer selected 00548 if not layer: 00549 self.MsgNoLayerSelected() 00550 return 00551 00552 # available only for vector map layers 00553 try: 00554 mapLayer = tree.GetPyData(layer)[0]['maplayer'] 00555 except: 00556 mapLayer = None 00557 00558 if not mapLayer or mapLayer.GetType() != 'vector': 00559 GMessage(parent = self, 00560 message = _("Selected map layer is not vector.")) 00561 return 00562 00563 if mapLayer.GetMapset() != grass.gisenv()['MAPSET']: 00564 GMessage(parent = self, 00565 message = _("Editing is allowed only for vector maps from the " 00566 "current mapset.")) 00567 return 00568 00569 if not tree.GetPyData(layer)[0]: 00570 return 00571 dcmd = tree.GetPyData(layer)[0]['cmd'] 00572 if not dcmd: 00573 return 00574 00575 tree.OnStartEditing(None) 00576 00577 def OnRunScript(self, event): 00578 """!Run script""" 00579 # open dialog and choose script file 00580 dlg = wx.FileDialog(parent = self, message = _("Choose script file to run"), 00581 defaultDir = os.getcwd(), 00582 wildcard = _("Python script (*.py)|*.py|Bash script (*.sh)|*.sh")) 00583 00584 filename = None 00585 if dlg.ShowModal() == wx.ID_OK: 00586 filename = dlg.GetPath() 00587 00588 if not filename: 00589 return False 00590 00591 if not os.path.exists(filename): 00592 GError(parent = self, 00593 message = _("Script file '%s' doesn't exist. " 00594 "Operation canceled.") % filename) 00595 return 00596 00597 # check permission 00598 if not os.access(filename, os.X_OK): 00599 dlg = wx.MessageDialog(self, 00600 message = _("Script <%s> is not executable. " 00601 "Do you want to set the permissions " 00602 "that allows you to run this script " 00603 "(note that you must be the owner of the file)?" % \ 00604 os.path.basename(filename)), 00605 caption = _("Set permission?"), 00606 style = wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION) 00607 if dlg.ShowModal() != wx.ID_YES: 00608 return 00609 dlg.Destroy() 00610 try: 00611 mode = stat.S_IMODE(os.lstat(filename)[stat.ST_MODE]) 00612 os.chmod(filename, mode | stat.S_IXUSR) 00613 except OSError: 00614 GError(_("Unable to set permission. Operation canceled."), parent = self) 00615 return 00616 00617 # check GRASS_ADDON_PATH 00618 addonPath = os.getenv('GRASS_ADDON_PATH', []) 00619 if addonPath: 00620 addonPath = addonPath.split(os.pathsep) 00621 dirName = os.path.dirname(filename) 00622 if dirName not in addonPath: 00623 addonPath.append(dirName) 00624 dlg = wx.MessageDialog(self, 00625 message = _("Directory '%s' is not defined in GRASS_ADDON_PATH. " 00626 "Do you want add this directory to GRASS_ADDON_PATH?") % \ 00627 dirName, 00628 caption = _("Update Addons path?"), 00629 style = wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION) 00630 if dlg.ShowModal() == wx.ID_YES: 00631 os.environ['GRASS_ADDON_PATH'] = os.pathsep.join(addonPath) 00632 RunCommand('g.gisenv', set = 'ADDON_PATH=%s' % os.environ['GRASS_ADDON_PATH']) 00633 00634 self.goutput.WriteCmdLog(_("Launching script '%s'...") % filename) 00635 self.goutput.RunCmd([filename], switchPage = True) 00636 00637 def OnChangeLocation(self, event): 00638 """Change current location""" 00639 dlg = LocationDialog(parent = self) 00640 if dlg.ShowModal() == wx.ID_OK: 00641 location, mapset = dlg.GetValues() 00642 dlg.Destroy() 00643 00644 if not location or not mapset: 00645 GError(parent = self, 00646 message = _("No location/mapset provided. Operation canceled.")) 00647 return # this should not happen 00648 00649 if RunCommand('g.mapset', parent = self, 00650 location = location, 00651 mapset = mapset) != 0: 00652 return # error reported 00653 00654 # close workspace 00655 self.OnWorkspaceClose() 00656 self.OnWorkspaceNew() 00657 GMessage(parent = self, 00658 message = _("Current location is <%(loc)s>.\n" 00659 "Current mapset is <%(mapset)s>.") % \ 00660 { 'loc' : location, 'mapset' : mapset }) 00661 00662 def OnCreateMapset(self, event): 00663 """!Create new mapset""" 00664 dlg = wx.TextEntryDialog(parent = self, 00665 message = _('Enter name for new mapset:'), 00666 caption = _('Create new mapset')) 00667 00668 if dlg.ShowModal() == wx.ID_OK: 00669 mapset = dlg.GetValue() 00670 if not mapset: 00671 GError(parent = self, 00672 message = _("No mapset provided. Operation canceled.")) 00673 return 00674 00675 ret = RunCommand('g.mapset', 00676 parent = self, 00677 flags = 'c', 00678 mapset = mapset) 00679 if ret == 0: 00680 GMessage(parent = self, 00681 message = _("Current mapset is <%s>.") % mapset) 00682 00683 def OnChangeMapset(self, event): 00684 """Change current mapset""" 00685 dlg = MapsetDialog(parent = self) 00686 00687 if dlg.ShowModal() == wx.ID_OK: 00688 mapset = dlg.GetMapset() 00689 dlg.Destroy() 00690 00691 if not mapset: 00692 GError(parent = self, 00693 message = _("No mapset provided. Operation canceled.")) 00694 return 00695 00696 if RunCommand('g.mapset', 00697 parent = self, 00698 mapset = mapset) == 0: 00699 GMessage(parent = self, 00700 message = _("Current mapset is <%s>.") % mapset) 00701 00702 def OnNewVector(self, event): 00703 """!Create new vector map layer""" 00704 dlg = CreateNewVector(self, log = self.goutput, 00705 cmd = (('v.edit', 00706 { 'tool' : 'create' }, 00707 'map'))) 00708 00709 if not dlg: 00710 return 00711 00712 name = dlg.GetName(full = True) 00713 if name and dlg.IsChecked('add'): 00714 # add layer to map layer tree 00715 self.curr_page.maptree.AddLayer(ltype = 'vector', 00716 lname = name, 00717 lcmd = ['d.vect', 'map=%s' % name]) 00718 dlg.Destroy() 00719 00720 def OnAboutGRASS(self, event): 00721 """!Display 'About GRASS' dialog""" 00722 win = AboutWindow(self) 00723 win.CentreOnScreen() 00724 win.Show(True) 00725 00726 def _popupMenu(self, data): 00727 """!Create popup menu 00728 """ 00729 point = wx.GetMousePosition() 00730 menu = wx.Menu() 00731 00732 for key, handler in data: 00733 if key is None: 00734 menu.AppendSeparator() 00735 continue 00736 item = wx.MenuItem(menu, wx.ID_ANY, LMIcons[key].GetLabel()) 00737 item.SetBitmap(LMIcons[key].GetBitmap(self.iconsize)) 00738 menu.AppendItem(item) 00739 self.Bind(wx.EVT_MENU, handler, item) 00740 00741 # create menu 00742 self.PopupMenu(menu) 00743 menu.Destroy() 00744 00745 def OnImportMenu(self, event): 00746 """!Import maps menu (import, link) 00747 """ 00748 self._popupMenu((('rastImport', self.OnImportGdalLayers), 00749 ('vectImport', self.OnImportOgrLayers))) 00750 00751 def OnWorkspaceNew(self, event = None): 00752 """!Create new workspace file 00753 00754 Erase current workspace settings first 00755 """ 00756 Debug.msg(4, "GMFrame.OnWorkspaceNew():") 00757 00758 # start new map display if no display is available 00759 if not self.curr_page: 00760 self.NewDisplay() 00761 00762 maptree = self.curr_page.maptree 00763 00764 # ask user to save current settings 00765 if self.workspaceFile and self.workspaceChanged: 00766 self.OnWorkspaceSave() 00767 elif self.workspaceFile is None and maptree.GetCount() > 0: 00768 dlg = wx.MessageDialog(self, message = _("Current workspace is not empty. " 00769 "Do you want to store current settings " 00770 "to workspace file?"), 00771 caption = _("Create new workspace?"), 00772 style = wx.YES_NO | wx.YES_DEFAULT | \ 00773 wx.CANCEL | wx.ICON_QUESTION) 00774 ret = dlg.ShowModal() 00775 if ret == wx.ID_YES: 00776 self.OnWorkspaceSaveAs() 00777 elif ret == wx.ID_CANCEL: 00778 dlg.Destroy() 00779 return 00780 00781 dlg.Destroy() 00782 00783 # delete all items 00784 maptree.DeleteAllItems() 00785 00786 # add new root element 00787 maptree.root = maptree.AddRoot("Map Layers") 00788 self.curr_page.maptree.SetPyData(maptree.root, (None,None)) 00789 00790 # no workspace file loaded 00791 self.workspaceFile = None 00792 self.workspaceChanged = False 00793 self.SetTitle(self.baseTitle) 00794 00795 def OnWorkspaceOpen(self, event = None): 00796 """!Open file with workspace definition""" 00797 dlg = wx.FileDialog(parent = self, message = _("Choose workspace file"), 00798 defaultDir = os.getcwd(), wildcard = _("GRASS Workspace File (*.gxw)|*.gxw")) 00799 00800 filename = '' 00801 if dlg.ShowModal() == wx.ID_OK: 00802 filename = dlg.GetPath() 00803 00804 if filename == '': 00805 return 00806 00807 Debug.msg(4, "GMFrame.OnWorkspaceOpen(): filename=%s" % filename) 00808 00809 # delete current layer tree content 00810 self.OnWorkspaceClose() 00811 00812 self.LoadWorkspaceFile(filename) 00813 00814 self.workspaceFile = filename 00815 self.SetTitle(self.baseTitle + " - " + os.path.basename(self.workspaceFile)) 00816 00817 def LoadWorkspaceFile(self, filename): 00818 """!Load layer tree definition stored in GRASS Workspace XML file (gxw) 00819 00820 @todo Validate against DTD 00821 00822 @return True on success 00823 @return False on error 00824 """ 00825 # dtd 00826 dtdFilename = os.path.join(globalvar.ETCWXDIR, "xml", "grass-gxw.dtd") 00827 00828 # parse workspace file 00829 try: 00830 gxwXml = ProcessWorkspaceFile(etree.parse(filename)) 00831 except Exception, e: 00832 GError(parent = self, 00833 message = _("Reading workspace file <%s> failed.\n" 00834 "Invalid file, unable to parse XML document.") % filename) 00835 return 00836 00837 busy = wx.BusyInfo(message = _("Please wait, loading workspace..."), 00838 parent = self) 00839 wx.Yield() 00840 00841 # 00842 # load layer manager window properties 00843 # 00844 if not UserSettings.Get(group = 'general', key = 'workspace', 00845 subkey = ['posManager', 'enabled']): 00846 if gxwXml.layerManager['pos']: 00847 self.SetPosition(gxwXml.layerManager['pos']) 00848 if gxwXml.layerManager['size']: 00849 self.SetSize(gxwXml.layerManager['size']) 00850 00851 # 00852 # start map displays first (list of layers can be empty) 00853 # 00854 displayId = 0 00855 mapdisplay = list() 00856 for display in gxwXml.displays: 00857 mapdisp = self.NewDisplay(name = display['name'], show = False) 00858 mapdisplay.append(mapdisp) 00859 maptree = self.gm_cb.GetPage(displayId).maptree 00860 00861 # set windows properties 00862 mapdisp.SetProperties(render = display['render'], 00863 mode = display['mode'], 00864 showCompExtent = display['showCompExtent'], 00865 alignExtent = display['alignExtent'], 00866 constrainRes = display['constrainRes'], 00867 projection = display['projection']['enabled']) 00868 00869 if display['projection']['enabled']: 00870 if display['projection']['epsg']: 00871 UserSettings.Set(group = 'display', key = 'projection', subkey = 'epsg', 00872 value = display['projection']['epsg']) 00873 if display['projection']['proj']: 00874 UserSettings.Set(group = 'display', key = 'projection', subkey = 'proj4', 00875 value = display['projection']['proj']) 00876 00877 # set position and size of map display 00878 if not UserSettings.Get(group = 'general', key = 'workspace', subkey = ['posDisplay', 'enabled']): 00879 if display['pos']: 00880 mapdisp.SetPosition(display['pos']) 00881 if display['size']: 00882 mapdisp.SetSize(display['size']) 00883 00884 # set extent if defined 00885 if display['extent']: 00886 w, s, e, n = display['extent'] 00887 region = maptree.Map.region = maptree.Map.GetRegion(w = w, s = s, e = e, n = n) 00888 mapdisp.GetWindow().ResetZoomHistory() 00889 mapdisp.GetWindow().ZoomHistory(region['n'], 00890 region['s'], 00891 region['e'], 00892 region['w']) 00893 00894 mapdisp.Show() 00895 00896 displayId += 1 00897 00898 maptree = None 00899 selected = [] # list of selected layers 00900 # 00901 # load list of map layers 00902 # 00903 for layer in gxwXml.layers: 00904 display = layer['display'] 00905 maptree = self.gm_cb.GetPage(display).maptree 00906 00907 newItem = maptree.AddLayer(ltype = layer['type'], 00908 lname = layer['name'], 00909 lchecked = layer['checked'], 00910 lopacity = layer['opacity'], 00911 lcmd = layer['cmd'], 00912 lgroup = layer['group'], 00913 lnviz = layer['nviz'], 00914 lvdigit = layer['vdigit']) 00915 00916 if layer.has_key('selected'): 00917 if layer['selected']: 00918 selected.append((maptree, newItem)) 00919 else: 00920 maptree.SelectItem(newItem, select = False) 00921 00922 for maptree, layer in selected: 00923 if not maptree.IsSelected(layer): 00924 maptree.SelectItem(layer, select = True) 00925 maptree.layer_selected = layer 00926 00927 busy.Destroy() 00928 00929 for idx, mdisp in enumerate(mapdisplay): 00930 mdisp.MapWindow2D.UpdateMap() 00931 #nviz 00932 if gxwXml.displays[idx]['viewMode'] == '3d': 00933 mdisp.AddNviz() 00934 self.nviz.UpdateState(view = gxwXml.nviz_state['view'], 00935 iview = gxwXml.nviz_state['iview'], 00936 light = gxwXml.nviz_state['light']) 00937 mdisp.MapWindow3D.constants = gxwXml.nviz_state['constants'] 00938 for idx, constant in enumerate(mdisp.MapWindow3D.constants): 00939 mdisp.MapWindow3D.AddConstant(constant, idx + 1) 00940 for page in ('view', 'light', 'fringe', 'constant', 'cplane'): 00941 self.nviz.UpdatePage(page) 00942 self.nviz.UpdateSettings() 00943 mapdisp.toolbars['map'].combo.SetSelection(1) 00944 00945 00946 return True 00947 00948 def OnWorkspaceLoadGrcFile(self, event): 00949 """!Load map layers from GRC file (Tcl/Tk GUI) into map layer tree""" 00950 dlg = wx.FileDialog(parent = self, message = _("Choose GRC file to load"), 00951 defaultDir = os.getcwd(), wildcard = _("Old GRASS Workspace File (*.grc)|*.grc")) 00952 00953 filename = '' 00954 if dlg.ShowModal() == wx.ID_OK: 00955 filename = dlg.GetPath() 00956 00957 if filename == '': 00958 return 00959 00960 Debug.msg(4, "GMFrame.OnWorkspaceLoadGrcFile(): filename=%s" % filename) 00961 00962 # start new map display if no display is available 00963 if not self.curr_page: 00964 self.NewDisplay() 00965 00966 busy = wx.BusyInfo(message = _("Please wait, loading workspace..."), 00967 parent = self) 00968 wx.Yield() 00969 00970 maptree = None 00971 for layer in ProcessGrcFile(filename).read(self): 00972 maptree = self.gm_cb.GetPage(layer['display']).maptree 00973 newItem = maptree.AddLayer(ltype = layer['type'], 00974 lname = layer['name'], 00975 lchecked = layer['checked'], 00976 lopacity = layer['opacity'], 00977 lcmd = layer['cmd'], 00978 lgroup = layer['group']) 00979 00980 busy.Destroy() 00981 00982 if maptree: 00983 # reverse list of map layers 00984 maptree.Map.ReverseListOfLayers() 00985 00986 def OnWorkspaceSaveAs(self, event = None): 00987 """!Save workspace definition to selected file""" 00988 dlg = wx.FileDialog(parent = self, message = _("Choose file to save current workspace"), 00989 defaultDir = os.getcwd(), wildcard = _("GRASS Workspace File (*.gxw)|*.gxw"), style = wx.FD_SAVE) 00990 00991 filename = '' 00992 if dlg.ShowModal() == wx.ID_OK: 00993 filename = dlg.GetPath() 00994 00995 if filename == '': 00996 return False 00997 00998 # check for extension 00999 if filename[-4:] != ".gxw": 01000 filename += ".gxw" 01001 01002 if os.path.exists(filename): 01003 dlg = wx.MessageDialog(self, message = _("Workspace file <%s> already exists. " 01004 "Do you want to overwrite this file?") % filename, 01005 caption = _("Save workspace"), style = wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION) 01006 if dlg.ShowModal() != wx.ID_YES: 01007 dlg.Destroy() 01008 return False 01009 01010 Debug.msg(4, "GMFrame.OnWorkspaceSaveAs(): filename=%s" % filename) 01011 01012 self.SaveToWorkspaceFile(filename) 01013 self.workspaceFile = filename 01014 self.SetTitle(self.baseTitle + " - " + os.path.basename(self.workspaceFile)) 01015 01016 def OnWorkspaceSave(self, event = None): 01017 """!Save file with workspace definition""" 01018 if self.workspaceFile: 01019 dlg = wx.MessageDialog(self, message = _("Workspace file <%s> already exists. " 01020 "Do you want to overwrite this file?") % \ 01021 self.workspaceFile, 01022 caption = _("Save workspace"), style = wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION) 01023 if dlg.ShowModal() == wx.ID_NO: 01024 dlg.Destroy() 01025 else: 01026 Debug.msg(4, "GMFrame.OnWorkspaceSave(): filename=%s" % self.workspaceFile) 01027 self.SaveToWorkspaceFile(self.workspaceFile) 01028 self.SetTitle(self.baseTitle + " - " + os.path.basename(self.workspaceFile)) 01029 self.workspaceChanged = False 01030 else: 01031 self.OnWorkspaceSaveAs() 01032 01033 def SaveToWorkspaceFile(self, filename): 01034 """!Save layer tree layout to workspace file 01035 01036 Return True on success, False on error 01037 """ 01038 tmpfile = tempfile.TemporaryFile(mode = 'w+b') 01039 try: 01040 WriteWorkspaceFile(lmgr = self, file = tmpfile) 01041 except StandardError, e: 01042 GError(parent = self, 01043 message = _("Writing current settings to workspace file " 01044 "failed.")) 01045 return False 01046 01047 try: 01048 mfile = open(filename, "w") 01049 tmpfile.seek(0) 01050 for line in tmpfile.readlines(): 01051 mfile.write(line) 01052 except IOError: 01053 GError(parent = self, 01054 message = _("Unable to open file <%s> for writing.") % filename) 01055 return False 01056 01057 mfile.close() 01058 01059 return True 01060 01061 def OnWorkspaceClose(self, event = None): 01062 """!Close file with workspace definition 01063 01064 If workspace has been modified ask user to save the changes. 01065 """ 01066 Debug.msg(4, "GMFrame.OnWorkspaceClose(): file=%s" % self.workspaceFile) 01067 01068 self.OnDisplayCloseAll() 01069 self.workspaceFile = None 01070 self.workspaceChanged = False 01071 self.SetTitle(self.baseTitle) 01072 self.disp_idx = 0 01073 self.curr_page = None 01074 01075 def OnDisplayClose(self, event = None): 01076 """!Close current map display window 01077 """ 01078 if self.curr_page and self.curr_page.maptree.mapdisplay: 01079 self.curr_page.maptree.mapdisplay.OnCloseWindow(event) 01080 01081 def OnDisplayCloseAll(self, event = None): 01082 """!Close all open map display windows 01083 """ 01084 displays = list() 01085 for page in range(0, self.gm_cb.GetPageCount()): 01086 displays.append(self.gm_cb.GetPage(page).maptree.mapdisplay) 01087 01088 for display in displays: 01089 display.OnCloseWindow(event) 01090 01091 def OnRenameDisplay(self, event): 01092 """!Change Map Display name""" 01093 name = self.gm_cb.GetPageText(self.curr_pagenum) 01094 dlg = wx.TextEntryDialog(self, message = _("Enter new name:"), 01095 caption = _("Rename Map Display"), defaultValue = name) 01096 if dlg.ShowModal() == wx.ID_OK: 01097 name = dlg.GetValue() 01098 self.gm_cb.SetPageText(page = self.curr_pagenum, text = name) 01099 mapdisplay = self.curr_page.maptree.mapdisplay 01100 mapdisplay.SetTitle(_("GRASS GIS Map Display: %(name)s - Location: %(loc)s") % \ 01101 { 'name' : name, 01102 'loc' : grass.gisenv()["LOCATION_NAME"] }) 01103 dlg.Destroy() 01104 01105 def RulesCmd(self, event): 01106 """!Launches dialog for commands that need rules input and 01107 processes rules 01108 """ 01109 cmd = self.GetMenuCmd(event) 01110 01111 if cmd[0] == 'r.colors': 01112 ctable = RasterColorTable(self) 01113 else: 01114 ctable = VectorColorTable(self, attributeType = 'color') 01115 ctable.CentreOnScreen() 01116 ctable.Show() 01117 01118 def OnXTermNoXMon(self, event): 01119 """! 01120 Run commands that need xterm 01121 """ 01122 self.OnXTerm(event, need_xmon = False) 01123 01124 def OnXTerm(self, event, need_xmon = True): 01125 """! 01126 Run commands that need interactive xmon 01127 01128 @param need_xmon True to start X monitor 01129 """ 01130 # unset display mode 01131 del os.environ['GRASS_RENDER_IMMEDIATE'] 01132 01133 if need_xmon: 01134 # open next available xmon 01135 xmonlist = [] 01136 01137 # make list of xmons that are not running 01138 ret = RunCommand('d.mon', 01139 flags = 'L', 01140 read = True) 01141 01142 for line in ret.split('\n'): 01143 line = line.strip() 01144 if line.startswith('x') and 'not running' in line: 01145 xmonlist.append(line[0:2]) 01146 01147 # find available xmon 01148 xmon = xmonlist[0] 01149 01150 # bring up the xmon 01151 cmdlist = ['d.mon', xmon] 01152 p = Command(cmdlist, wait=False) 01153 01154 # run the command 01155 command = self.GetMenuCmd(event) 01156 command = ' '.join(command) 01157 01158 gisbase = os.environ['GISBASE'] 01159 01160 if sys.platform == "win32": 01161 runbat = os.path.join(gisbase,'etc','grass-run.bat') 01162 cmdlist = ["start", runbat, runbat, command] 01163 else: 01164 if sys.platform == "darwin": 01165 xtermwrapper = os.path.join(gisbase,'etc','grass-xterm-mac') 01166 else: 01167 xtermwrapper = os.path.join(gisbase,'etc','grass-xterm-wrapper') 01168 01169 grassrun = os.path.join(gisbase,'etc','grass-run.sh') 01170 cmdlist = [xtermwrapper, '-e', grassrun, command] 01171 01172 p = Command(cmdlist, wait=False) 01173 01174 # reset display mode 01175 os.environ['GRASS_RENDER_IMMEDIATE'] = 'TRUE' 01176 01177 def OnEditImageryGroups(self, event, cmd = None): 01178 """!Show dialog for creating and editing groups. 01179 """ 01180 dlg = GroupDialog(self) 01181 dlg.CentreOnScreen() 01182 dlg.Show() 01183 01184 def OnInstallExtension(self, event): 01185 """!Install extension from GRASS Addons SVN repository""" 01186 win = InstallExtensionWindow(self, size = (650, 550)) 01187 win.CentreOnScreen() 01188 win.Show() 01189 01190 def OnUninstallExtension(self, event): 01191 """!Uninstall extension""" 01192 win = UninstallExtensionWindow(self, size = (650, 300)) 01193 win.CentreOnScreen() 01194 win.Show() 01195 01196 def OnPreferences(self, event): 01197 """!General GUI preferences/settings 01198 """ 01199 if not self.dialogs['preferences']: 01200 dlg = PreferencesDialog(parent = self) 01201 self.dialogs['preferences'] = dlg 01202 self.dialogs['preferences'].CenterOnScreen() 01203 01204 dlg.Bind(EVT_SETTINGS_CHANGED, self.OnSettingsChanged) 01205 01206 self.dialogs['preferences'].ShowModal() 01207 01208 def OnHelp(self, event): 01209 """!Show help 01210 """ 01211 self.goutput.RunCmd(['g.manual','-i']) 01212 01213 def OnHistogram(self, event): 01214 """!Init histogram display canvas and tools 01215 """ 01216 from modules.histogram import HistogramFrame 01217 win = HistogramFrame(self) 01218 01219 win.CentreOnScreen() 01220 win.Show() 01221 win.Refresh() 01222 win.Update() 01223 01224 def OnProfile(self, event): 01225 """!Launch profile tool 01226 """ 01227 win = profile.ProfileFrame(parent = self) 01228 01229 win.CentreOnParent() 01230 win.Show() 01231 win.Refresh() 01232 win.Update() 01233 01234 def OnMapCalculator(self, event, cmd = ''): 01235 """!Init map calculator for interactive creation of mapcalc statements 01236 """ 01237 if event: 01238 try: 01239 cmd = self.GetMenuCmd(event) 01240 except KeyError: 01241 cmd = ['r.mapcalc'] 01242 01243 win = MapCalcFrame(parent = self, 01244 cmd = cmd[0]) 01245 win.CentreOnScreen() 01246 win.Show() 01247 01248 def OnVectorCleaning(self, event, cmd = ''): 01249 """!Init interactive vector cleaning 01250 """ 01251 from modules.vclean import VectorCleaningFrame 01252 win = VectorCleaningFrame(parent = self) 01253 win.CentreOnScreen() 01254 win.Show() 01255 01256 def OnImportDxfFile(self, event, cmd = None): 01257 """!Convert multiple DXF layers to GRASS vector map layers""" 01258 dlg = DxfImportDialog(parent = self) 01259 dlg.CentreOnScreen() 01260 dlg.Show() 01261 01262 def OnImportGdalLayers(self, event, cmd = None): 01263 """!Convert multiple GDAL layers to GRASS raster map layers""" 01264 dlg = GdalImportDialog(parent = self) 01265 dlg.CentreOnScreen() 01266 dlg.Show() 01267 01268 def OnLinkGdalLayers(self, event, cmd = None): 01269 """!Link multiple GDAL layers to GRASS raster map layers""" 01270 dlg = GdalImportDialog(parent = self, link = True) 01271 dlg.CentreOnScreen() 01272 dlg.Show() 01273 01274 def OnImportOgrLayers(self, event, cmd = None): 01275 """!Convert multiple OGR layers to GRASS vector map layers""" 01276 dlg = GdalImportDialog(parent = self, ogr = True) 01277 dlg.CentreOnScreen() 01278 dlg.Show() 01279 01280 def OnLinkOgrLayers(self, event, cmd = None): 01281 """!Links multiple OGR layers to GRASS vector map layers""" 01282 dlg = GdalImportDialog(parent = self, ogr = True, link = True) 01283 dlg.CentreOnScreen() 01284 dlg.Show() 01285 01286 def OnImportWMS(self, event): 01287 """!Import data from OGC WMS server""" 01288 dlg = WMSDialog(parent = self, service = 'wms') 01289 dlg.CenterOnScreen() 01290 01291 if dlg.ShowModal() == wx.ID_OK: # -> import layers 01292 layers = dlg.GetLayers() 01293 01294 if len(layers.keys()) > 0: 01295 for layer in layers.keys(): 01296 cmd = ['r.in.wms', 01297 'mapserver=%s' % dlg.GetSettings()['server'], 01298 'layers=%s' % layer, 01299 'output=%s' % layer, 01300 'format=png', 01301 '--overwrite'] 01302 styles = ','.join(layers[layer]) 01303 if styles: 01304 cmd.append('styles=%s' % styles) 01305 self.goutput.RunCmd(cmd, switchPage = True) 01306 01307 self.curr_page.maptree.AddLayer(ltype = 'raster', 01308 lname = layer, 01309 lcmd = ['d.rast', 'map=%s' % layer], 01310 multiple = False) 01311 else: 01312 self.goutput.WriteWarning(_("Nothing to import. No WMS layer selected.")) 01313 01314 01315 dlg.Destroy() 01316 01317 def OnShowAttributeTable(self, event, selection = None): 01318 """!Show attribute table of the given vector map layer 01319 """ 01320 if not self.curr_page: 01321 self.MsgNoLayerSelected() 01322 return 01323 01324 tree = self.GetLayerTree() 01325 layer = tree.layer_selected 01326 # no map layer selected 01327 if not layer: 01328 self.MsgNoLayerSelected() 01329 return 01330 01331 # available only for vector map layers 01332 try: 01333 maptype = tree.GetPyData(layer)[0]['maplayer'].type 01334 except: 01335 maptype = None 01336 01337 if not maptype or maptype != 'vector': 01338 GMessage(parent = self, 01339 message = _("Selected map layer is not vector.")) 01340 return 01341 01342 if not tree.GetPyData(layer)[0]: 01343 return 01344 dcmd = tree.GetPyData(layer)[0]['cmd'] 01345 if not dcmd: 01346 return 01347 01348 busy = wx.BusyInfo(message = _("Please wait, loading attribute data..."), 01349 parent = self) 01350 wx.Yield() 01351 01352 dbmanager = AttributeManager(parent = self, id = wx.ID_ANY, 01353 size = wx.Size(500, 300), 01354 item = layer, log = self.goutput, 01355 selection = selection) 01356 01357 busy.Destroy() 01358 01359 # register ATM dialog 01360 self.dialogs['atm'].append(dbmanager) 01361 01362 # show ATM window 01363 dbmanager.Show() 01364 01365 def OnNewDisplayWMS(self, event = None): 01366 """!Create new layer tree and map display instance""" 01367 self.NewDisplayWMS() 01368 01369 def OnNewDisplay(self, event = None): 01370 """!Create new layer tree and map display instance""" 01371 self.NewDisplay() 01372 01373 def NewDisplay(self, name = None, show = True): 01374 """!Create new layer tree, which will 01375 create an associated map display frame 01376 01377 @param name name of new map display 01378 @param show show map display window if True 01379 01380 @return reference to mapdisplay intance 01381 """ 01382 Debug.msg(1, "GMFrame.NewDisplay(): idx=%d" % self.disp_idx) 01383 01384 # make a new page in the bookcontrol for the layer tree (on page 0 of the notebook) 01385 self.pg_panel = wx.Panel(self.gm_cb, id = wx.ID_ANY, style = wx.EXPAND) 01386 if name: 01387 dispName = name 01388 else: 01389 dispName = "Display " + str(self.disp_idx + 1) 01390 self.gm_cb.AddPage(self.pg_panel, text = dispName, select = True) 01391 self.curr_page = self.gm_cb.GetCurrentPage() 01392 01393 # create layer tree (tree control for managing GIS layers) and put on new notebook page 01394 self.curr_page.maptree = LayerTree(self.curr_page, id = wx.ID_ANY, pos = wx.DefaultPosition, 01395 size = wx.DefaultSize, style = wx.TR_HAS_BUTTONS | 01396 wx.TR_LINES_AT_ROOT| wx.TR_HIDE_ROOT | 01397 wx.TR_DEFAULT_STYLE| wx.NO_BORDER | wx.FULL_REPAINT_ON_RESIZE, 01398 idx = self.disp_idx, lmgr = self, notebook = self.gm_cb, 01399 auimgr = self._auimgr, showMapDisplay = show) 01400 01401 # layout for controls 01402 cb_boxsizer = wx.BoxSizer(wx.VERTICAL) 01403 cb_boxsizer.Add(self.curr_page.maptree, proportion = 1, flag = wx.EXPAND, border = 1) 01404 self.curr_page.SetSizer(cb_boxsizer) 01405 cb_boxsizer.Fit(self.curr_page.maptree) 01406 self.curr_page.Layout() 01407 self.curr_page.maptree.Layout() 01408 01409 # use default window layout 01410 if UserSettings.Get(group = 'general', key = 'defWindowPos', subkey = 'enabled'): 01411 dim = UserSettings.Get(group = 'general', key = 'defWindowPos', subkey = 'dim') 01412 idx = 4 + self.disp_idx * 4 01413 try: 01414 x, y = map(int, dim.split(',')[idx:idx + 2]) 01415 w, h = map(int, dim.split(',')[idx + 2:idx + 4]) 01416 self.curr_page.maptree.mapdisplay.SetPosition((x, y)) 01417 self.curr_page.maptree.mapdisplay.SetSize((w, h)) 01418 except: 01419 pass 01420 01421 self.disp_idx += 1 01422 01423 return self.curr_page.maptree.mapdisplay 01424 01425 def OnAddMaps(self, event = None): 01426 """!Add selected map layers into layer tree""" 01427 dialog = MapLayersDialog(parent = self, title = _("Add selected map layers into layer tree")) 01428 01429 if dialog.ShowModal() != wx.ID_OK: 01430 dialog.Destroy() 01431 return 01432 01433 # start new map display if no display is available 01434 if not self.curr_page: 01435 self.NewDisplay() 01436 01437 maptree = self.curr_page.maptree 01438 01439 for layerName in dialog.GetMapLayers(): 01440 ltype = dialog.GetLayerType(cmd = True) 01441 if ltype == 'rast': 01442 cmd = ['d.rast', 'map=%s' % layerName] 01443 wxType = 'raster' 01444 elif ltype == 'rast3d': 01445 cmd = ['d.rast3d', 'map=%s' % layerName] 01446 wxType = '3d-raster' 01447 elif ltype == 'vect': 01448 cmd = ['d.vect', 'map=%s' % layerName] 01449 wxType = 'vector' 01450 else: 01451 GError(parent = self, 01452 message = _("Unsupported map layer type <%s>.") % ltype) 01453 return 01454 01455 newItem = maptree.AddLayer(ltype = wxType, 01456 lname = layerName, 01457 lchecked = False, 01458 lopacity = 1.0, 01459 lcmd = cmd, 01460 lgroup = None) 01461 dialog.Destroy() 01462 01463 def OnAddRaster(self, event): 01464 """!Add raster map layer""" 01465 # start new map display if no display is available 01466 if not self.curr_page: 01467 self.NewDisplay(show = True) 01468 01469 self.notebook.SetSelectionByName('layers') 01470 self.curr_page.maptree.AddLayer('raster') 01471 01472 def OnAddRaster3D(self, event): 01473 """!Add 3D raster map layer""" 01474 # start new map display if no display is available 01475 if not self.curr_page: 01476 self.NewDisplay(show = True) 01477 01478 self.AddRaster3D(event) 01479 01480 def OnAddRasterMisc(self, event): 01481 """!Create misc raster popup-menu""" 01482 # start new map display if no display is available 01483 if not self.curr_page: 01484 self.NewDisplay(show = True) 01485 01486 self._popupMenu((('addRast3d', self.OnAddRaster3D), 01487 (None, None), 01488 ('addRgb', self.OnAddRasterRGB), 01489 ('addHis', self.OnAddRasterHIS), 01490 (None, None), 01491 ('addShaded', self.OnAddRasterShaded), 01492 (None, None), 01493 ('addRArrow', self.OnAddRasterArrow), 01494 ('addRNum', self.OnAddRasterNum))) 01495 01496 # show map display 01497 self.curr_page.maptree.mapdisplay.Show() 01498 01499 def OnAddVector(self, event): 01500 """!Add vector map to the current layer tree""" 01501 # start new map display if no display is available 01502 if not self.curr_page: 01503 self.NewDisplay(show = True) 01504 01505 self.notebook.SetSelectionByName('layers') 01506 self.curr_page.maptree.AddLayer('vector') 01507 01508 def OnAddVectorMisc(self, event): 01509 """!Create misc vector popup-menu""" 01510 # start new map display if no display is available 01511 if not self.curr_page: 01512 self.NewDisplay(show = True) 01513 01514 self._popupMenu((('addThematic', self.OnAddVectorTheme), 01515 ('addChart', self.OnAddVectorChart))) 01516 01517 # show map display 01518 self.curr_page.maptree.mapdisplay.Show() 01519 01520 def OnAddVectorTheme(self, event): 01521 """!Add thematic vector map to the current layer tree""" 01522 self.notebook.SetSelectionByName('layers') 01523 self.curr_page.maptree.AddLayer('thememap') 01524 01525 def OnAddVectorChart(self, event): 01526 """!Add chart vector map to the current layer tree""" 01527 self.notebook.SetSelectionByName('layers') 01528 self.curr_page.maptree.AddLayer('themechart') 01529 01530 def OnAddOverlay(self, event): 01531 """!Create decoration overlay menu""" 01532 # start new map display if no display is available 01533 if not self.curr_page: 01534 self.NewDisplay(show = True) 01535 01536 self._popupMenu((('addGrid', self.OnAddGrid), 01537 ('addLabels', self.OnAddLabels), 01538 ('addGeodesic', self.OnAddGeodesic), 01539 ('addRhumb', self.OnAddRhumb), 01540 (None, None), 01541 ('addCmd', self.OnAddCommand))) 01542 01543 # show map display 01544 self.curr_page.maptree.mapdisplay.Show() 01545 01546 def OnAddRaster3D(self, event): 01547 """!Add 3D raster map to the current layer tree""" 01548 self.notebook.SetSelectionByName('layers') 01549 self.curr_page.maptree.AddLayer('3d-raster') 01550 01551 def OnAddRasterRGB(self, event): 01552 """!Add RGB raster map to the current layer tree""" 01553 self.notebook.SetSelectionByName('layers') 01554 self.curr_page.maptree.AddLayer('rgb') 01555 01556 def OnAddRasterHIS(self, event): 01557 """!Add HIS raster map to the current layer tree""" 01558 self.notebook.SetSelectionByName('layers') 01559 self.curr_page.maptree.AddLayer('his') 01560 01561 def OnAddRasterShaded(self, event): 01562 """!Add shaded relief raster map to the current layer tree""" 01563 self.notebook.SetSelectionByName('layers') 01564 self.curr_page.maptree.AddLayer('shaded') 01565 01566 def OnAddRasterArrow(self, event): 01567 """!Add flow arrows raster map to the current layer tree""" 01568 self.notebook.SetSelectionByName('layers') 01569 self.curr_page.maptree.AddLayer('rastarrow') 01570 01571 def OnAddRasterNum(self, event): 01572 """!Add cell number raster map to the current layer tree""" 01573 self.notebook.SetSelectionByName('layers') 01574 self.curr_page.maptree.AddLayer('rastnum') 01575 01576 def OnAddCommand(self, event): 01577 """!Add command line map layer to the current layer tree""" 01578 # start new map display if no display is available 01579 if not self.curr_page: 01580 self.NewDisplay(show = True) 01581 01582 self.notebook.SetSelectionByName('layers') 01583 self.curr_page.maptree.AddLayer('command') 01584 01585 # show map display 01586 self.curr_page.maptree.mapdisplay.Show() 01587 01588 def OnAddGroup(self, event): 01589 """!Add layer group""" 01590 # start new map display if no display is available 01591 if not self.curr_page: 01592 self.NewDisplay(show = True) 01593 01594 self.notebook.SetSelectionByName('layers') 01595 self.curr_page.maptree.AddLayer('group') 01596 01597 # show map display 01598 self.curr_page.maptree.mapdisplay.Show() 01599 01600 def OnAddGrid(self, event): 01601 """!Add grid map layer to the current layer tree""" 01602 self.notebook.SetSelectionByName('layers') 01603 self.curr_page.maptree.AddLayer('grid') 01604 01605 def OnAddGeodesic(self, event): 01606 """!Add geodesic line map layer to the current layer tree""" 01607 self.notebook.SetSelectionByName('layers') 01608 self.curr_page.maptree.AddLayer('geodesic') 01609 01610 def OnAddRhumb(self, event): 01611 """!Add rhumb map layer to the current layer tree""" 01612 self.notebook.SetSelectionByName('layers') 01613 self.curr_page.maptree.AddLayer('rhumb') 01614 01615 def OnAddLabels(self, event): 01616 """!Add vector labels map layer to the current layer tree""" 01617 # start new map display if no display is available 01618 if not self.curr_page: 01619 self.NewDisplay(show = True) 01620 01621 self.notebook.SetSelectionByName('layers') 01622 self.curr_page.maptree.AddLayer('labels') 01623 01624 # show map display 01625 self.curr_page.maptree.mapdisplay.Show() 01626 01627 def OnDeleteLayer(self, event): 01628 """!Remove selected map layer from the current layer Tree 01629 """ 01630 if not self.curr_page or not self.curr_page.maptree.layer_selected: 01631 self.MsgNoLayerSelected() 01632 return 01633 01634 if UserSettings.Get(group = 'manager', key = 'askOnRemoveLayer', subkey = 'enabled'): 01635 layerName = '' 01636 for item in self.curr_page.maptree.GetSelections(): 01637 name = str(self.curr_page.maptree.GetItemText(item)) 01638 idx = name.find('(opacity') 01639 if idx > -1: 01640 layerName += '<' + name[:idx].strip(' ') + '>,\n' 01641 else: 01642 layerName += '<' + name + '>,\n' 01643 layerName = layerName.rstrip(',\n') 01644 01645 if len(layerName) > 2: # <> 01646 message = _("Do you want to remove map layer(s)\n%s\n" 01647 "from layer tree?") % layerName 01648 else: 01649 message = _("Do you want to remove selected map layer(s) " 01650 "from layer tree?") 01651 01652 dlg = wx.MessageDialog (parent = self, message = message, 01653 caption = _("Remove map layer"), 01654 style = wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION) 01655 01656 if dlg.ShowModal() != wx.ID_YES: 01657 dlg.Destroy() 01658 return 01659 01660 dlg.Destroy() 01661 01662 for layer in self.curr_page.maptree.GetSelections(): 01663 if self.curr_page.maptree.GetPyData(layer)[0]['type'] == 'group': 01664 self.curr_page.maptree.DeleteChildren(layer) 01665 self.curr_page.maptree.Delete(layer) 01666 01667 def OnKeyDown(self, event): 01668 """!Key pressed""" 01669 kc = event.GetKeyCode() 01670 01671 if event.ControlDown(): 01672 if kc == wx.WXK_TAB: 01673 # switch layer list / command output 01674 if self.notebook.GetSelection() == self.notebook.GetPageIndexByName('layers'): 01675 self.notebook.SetSelectionByName('output') 01676 else: 01677 self.notebook.SetSelectionByName('layers') 01678 01679 try: 01680 ckc = chr(kc) 01681 except ValueError: 01682 event.Skip() 01683 return 01684 01685 if event.CtrlDown(): 01686 if kc == 'R': 01687 self.OnAddRaster(None) 01688 elif kc == 'V': 01689 self.OnAddVector(None) 01690 01691 event.Skip() 01692 01693 def OnCloseWindow(self, event): 01694 """!Cleanup when wxGUI is quitted""" 01695 if not self.curr_page: 01696 self._auimgr.UnInit() 01697 self.Destroy() 01698 return 01699 01700 maptree = self.curr_page.maptree 01701 if self.workspaceChanged and \ 01702 UserSettings.Get(group = 'manager', key = 'askOnQuit', subkey = 'enabled'): 01703 if self.workspaceFile: 01704 message = _("Do you want to save changes in the workspace?") 01705 else: 01706 message = _("Do you want to store current settings " 01707 "to workspace file?") 01708 01709 # ask user to save current settings 01710 if maptree.GetCount() > 0: 01711 dlg = wx.MessageDialog(self, 01712 message = message, 01713 caption = _("Quit GRASS GUI"), 01714 style = wx.YES_NO | wx.YES_DEFAULT | 01715 wx.CANCEL | wx.ICON_QUESTION | wx.CENTRE) 01716 ret = dlg.ShowModal() 01717 if ret == wx.ID_YES: 01718 if not self.workspaceFile: 01719 self.OnWorkspaceSaveAs() 01720 else: 01721 self.SaveToWorkspaceFile(self.workspaceFile) 01722 elif ret == wx.ID_CANCEL: 01723 event.Veto() 01724 dlg.Destroy() 01725 return 01726 dlg.Destroy() 01727 01728 # don't ask any more... 01729 UserSettings.Set(group = 'manager', key = 'askOnQuit', subkey = 'enabled', 01730 value = False) 01731 01732 self.OnDisplayCloseAll() 01733 01734 self.gm_cb.DeleteAllPages() 01735 01736 self._auimgr.UnInit() 01737 self.Destroy() 01738 01739 def MsgNoLayerSelected(self): 01740 """!Show dialog message 'No layer selected'""" 01741 wx.MessageBox(parent = self, 01742 message = _("No map layer selected. Operation canceled."), 01743 caption = _("Message"), 01744 style = wx.OK | wx.ICON_INFORMATION | wx.CENTRE)