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