GRASS Programmer's Manual  6.4.2(2012)
mapdisp.py
Go to the documentation of this file.
00001 """!
00002 @package mapdisp.py
00003 
00004 @brief GIS map display canvas, with toolbar for various display
00005 management functions, and additional toolbars (vector digitizer, 3d
00006 view).
00007 
00008 Can be used either from Layer Manager or as p.mon backend.
00009 
00010 Classes:
00011 - MapFrame
00012 - MapApp
00013 
00014 Usage:
00015 python mapdisp.py monitor-identifier /path/to/command/file
00016 
00017 (C) 2006-2011 by the GRASS Development Team
00018 This program is free software under the GNU General Public
00019 License (>=v2). Read the file COPYING that comes with GRASS
00020 for details.
00021 
00022 @author Michael Barton
00023 @author Jachym Cepicky
00024 @author Martin Landa <landa.martin gmail.com>
00025 """
00026 
00027 import os
00028 import sys
00029 import glob
00030 import math
00031 import tempfile
00032 import copy
00033 
00034 import globalvar
00035 import wx
00036 import wx.aui
00037 
00038 try:
00039     import subprocess
00040 except:
00041     CompatPath = os.path.join(globalvar.ETCWXDIR)
00042     sys.path.append(CompatPath)
00043     from compat import subprocess
00044 
00045 gmpath = os.path.join(globalvar.ETCWXDIR, "icons")
00046 sys.path.append(gmpath)
00047 
00048 grassPath = os.path.join(globalvar.ETCDIR, "python")
00049 sys.path.append(grassPath)
00050 
00051 import render
00052 import toolbars
00053 import menuform
00054 import gselect
00055 import disp_print
00056 import gcmd
00057 import dbm
00058 import dbm_dialogs
00059 import histogram
00060 import profile
00061 import globalvar
00062 import utils
00063 import gdialogs
00064 from grass.script import core as grass
00065 from debug import Debug
00066 from icon  import Icons
00067 from preferences import globalSettings as UserSettings
00068 
00069 from mapdisp_command import Command
00070 from mapdisp_window import BufferedWindow
00071 
00072 # for standalone app
00073 cmdfilename = None
00074 
00075 haveCtypes = False
00076 
00077 class MapFrame(wx.Frame):
00078     """!Main frame for map display window. Drawing takes place in
00079     child double buffered drawing window.
00080     """
00081     def __init__(self, parent = None, id = wx.ID_ANY, title = _("GRASS GIS - Map display"),
00082                  style = wx.DEFAULT_FRAME_STYLE, toolbars = ["map"],
00083                  tree = None, notebook = None, lmgr = None, page = None,
00084                  Map = None, auimgr = None, **kwargs):
00085         """!Main map display window with toolbars, statusbar and
00086         DrawWindow
00087 
00088         @param toolbars array of activated toolbars, e.g. ['map', 'digit']
00089         @param tree reference to layer tree
00090         @param notebook control book ID in Layer Manager
00091         @param lmgr Layer Manager
00092         @param page notebook page with layer tree
00093         @param Map instance of render.Map
00094         @param auimgs AUI manager
00095         @param kwargs wx.Frame attribures
00096         """
00097         self._layerManager = lmgr   # Layer Manager object
00098         self.Map        = Map       # instance of render.Map
00099         self.tree       = tree      # Layer Manager layer tree object
00100         self.page       = page      # Notebook page holding the layer tree
00101         self.layerbook  = notebook  # Layer Manager layer tree notebook
00102         self.parent     = parent
00103         
00104         if 'name' not in kwargs:
00105             kwargs['name'] = 'MapWindow'
00106         wx.Frame.__init__(self, parent, id, title, style = style, **kwargs)
00107         
00108         # available cursors
00109         self.cursors = {
00110             # default: cross
00111             # "default" : wx.StockCursor(wx.CURSOR_DEFAULT),
00112             "default" : wx.StockCursor(wx.CURSOR_ARROW),
00113             "cross"   : wx.StockCursor(wx.CURSOR_CROSS),
00114             "hand"    : wx.StockCursor(wx.CURSOR_HAND),
00115             "pencil"  : wx.StockCursor(wx.CURSOR_PENCIL),
00116             "sizenwse": wx.StockCursor(wx.CURSOR_SIZENWSE)
00117             }
00118         
00119         #
00120         # set the size & system icon
00121         #
00122         self.SetClientSize(self.GetSize())
00123         self.iconsize = (16, 16)
00124 
00125         self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass_map.ico'), wx.BITMAP_TYPE_ICO))
00126 
00127         #
00128         # Fancy gui
00129         #
00130         self._mgr = wx.aui.AuiManager(self)
00131 
00132         #
00133         # Add toolbars
00134         #
00135         self.toolbars = { 'map' : None,
00136                           'vdigit' : None,
00137                           'georect' : None, 
00138                           'gcpdisp' : None, 
00139                           'nviz' : None }
00140         for toolb in toolbars:
00141             self.AddToolbar(toolb)
00142 
00143         #
00144         # Add statusbar
00145         #
00146         self.statusbar = self.CreateStatusBar(number = 4, style = 0)
00147         self.statusbar.SetStatusWidths([-5, -2, -1, -1])
00148         self.statusbarWin = dict()
00149         self.statusbarWin['toggle'] = wx.Choice(self.statusbar, wx.ID_ANY,
00150                                                 choices = globalvar.MAP_DISPLAY_STATUSBAR_MODE)
00151         self.statusbarWin['toggle'].SetSelection(UserSettings.Get(group = 'display',
00152                                                                   key = 'statusbarMode',
00153                                                                   subkey = 'selection'))
00154         self.statusbar.Bind(wx.EVT_CHOICE, self.OnToggleStatus, self.statusbarWin['toggle'])
00155         # auto-rendering checkbox
00156         self.statusbarWin['render'] = wx.CheckBox(parent = self.statusbar, id = wx.ID_ANY,
00157                                                   label = _("Render"))
00158         self.statusbar.Bind(wx.EVT_CHECKBOX, self.OnToggleRender, self.statusbarWin['render'])
00159         self.statusbarWin['render'].SetValue(UserSettings.Get(group = 'display',
00160                                                               key = 'autoRendering',
00161                                                               subkey = 'enabled'))
00162         self.statusbarWin['render'].SetToolTip(wx.ToolTip (_("Enable/disable auto-rendering")))
00163         # show region
00164         self.statusbarWin['region'] = wx.CheckBox(parent = self.statusbar, id = wx.ID_ANY,
00165                                                   label = _("Show computational extent"))
00166         self.statusbar.Bind(wx.EVT_CHECKBOX, self.OnToggleShowRegion, self.statusbarWin['region'])
00167         
00168         self.statusbarWin['region'].SetValue(False)
00169         self.statusbarWin['region'].Hide()
00170         self.statusbarWin['region'].SetToolTip(wx.ToolTip (_("Show/hide computational "
00171                                                              "region extent (set with g.region). "
00172                                                              "Display region drawn as a blue box inside the "
00173                                                              "computational region, "
00174                                                              "computational region inside a display region "
00175                                                              "as a red box).")))
00176         # set resolution
00177         self.statusbarWin['resolution'] = wx.CheckBox(parent = self.statusbar, id = wx.ID_ANY,
00178                                                       label = _("Constrain display resolution to computational settings"))
00179         self.statusbar.Bind(wx.EVT_CHECKBOX, self.OnToggleResolution, self.statusbarWin['resolution'])
00180         self.statusbarWin['resolution'].SetValue(UserSettings.Get(group = 'display', key = 'compResolution', subkey = 'enabled'))
00181         self.statusbarWin['resolution'].Hide()
00182         self.statusbarWin['resolution'].SetToolTip(wx.ToolTip (_("Constrain display resolution "
00183                                                                  "to computational region settings. "
00184                                                                  "Default value for new map displays can "
00185                                                                  "be set up in 'User GUI settings' dialog.")))
00186         # map scale
00187         self.statusbarWin['mapscale'] = wx.ComboBox(parent = self.statusbar, id = wx.ID_ANY,
00188                                                     style = wx.TE_PROCESS_ENTER,
00189                                                     size = (150, -1))
00190         self.statusbarWin['mapscale'].SetItems(['1:1000',
00191                                                 '1:5000',
00192                                                 '1:10000',
00193                                                 '1:25000',
00194                                                 '1:50000',
00195                                                 '1:100000',
00196                                                 '1:1000000'])
00197         self.statusbarWin['mapscale'].Hide()
00198         self.statusbar.Bind(wx.EVT_TEXT_ENTER, self.OnChangeMapScale, self.statusbarWin['mapscale'])
00199         self.statusbar.Bind(wx.EVT_COMBOBOX, self.OnChangeMapScale, self.statusbarWin['mapscale'])
00200 
00201         # go to
00202         self.statusbarWin['goto'] = wx.TextCtrl(parent = self.statusbar, id = wx.ID_ANY,
00203                                                 value = "", style = wx.TE_PROCESS_ENTER,
00204                                                 size = (300, -1))
00205         self.statusbarWin['goto'].Hide()
00206         self.statusbar.Bind(wx.EVT_TEXT_ENTER, self.OnGoTo, self.statusbarWin['goto'])
00207 
00208         # projection
00209         self.statusbarWin['projection'] = wx.CheckBox(parent = self.statusbar, id = wx.ID_ANY,
00210                                                       label = _("Use defined projection"))
00211         self.statusbarWin['projection'].SetValue(False)
00212         size = self.statusbarWin['projection'].GetSize()
00213         self.statusbarWin['projection'].SetMinSize((size[0] + 150, size[1]))
00214         self.statusbarWin['projection'].SetToolTip(wx.ToolTip (_("Reproject coordinates displayed "
00215                                                                  "in the statusbar. Projection can be "
00216                                                                  "defined in GUI preferences dialog "
00217                                                                  "(tab 'Display')")))
00218         self.statusbarWin['projection'].Hide()
00219         
00220         # mask
00221         self.statusbarWin['mask'] = wx.StaticText(parent = self.statusbar, id = wx.ID_ANY,
00222                                                   label = '')
00223         self.statusbarWin['mask'].SetForegroundColour(wx.Colour(255, 0, 0))
00224         
00225         # on-render gauge
00226         self.statusbarWin['progress'] = wx.Gauge(parent = self.statusbar, id = wx.ID_ANY,
00227                                       range = 0, style = wx.GA_HORIZONTAL)
00228         self.statusbarWin['progress'].Hide()
00229         
00230         self.StatusbarReposition() # reposition statusbar
00231 
00232         #
00233         # Init map display (buffered DC & set default cursor)
00234         #
00235         self.MapWindow2D = BufferedWindow(self, id = wx.ID_ANY,
00236                                           Map = self.Map, tree = self.tree, lmgr = self._layerManager)
00237         # default is 2D display mode
00238         self.MapWindow = self.MapWindow2D
00239         self.MapWindow.SetCursor(self.cursors["default"])
00240         # used by vector digitizer
00241         self.MapWindowVDigit = None
00242         # used by Nviz (3D display mode)
00243         self.MapWindow3D = None 
00244 
00245         #
00246         # initialize region values
00247         #
00248         self._initDisplay() 
00249 
00250         #
00251         # Bind various events
00252         #
00253         self.Bind(wx.EVT_ACTIVATE, self.OnFocus)
00254         self.Bind(wx.EVT_CLOSE,    self.OnCloseWindow)
00255         self.Bind(render.EVT_UPDATE_PRGBAR, self.OnUpdateProgress)
00256         
00257         #
00258         # Update fancy gui style
00259         #
00260         self._mgr.AddPane(self.MapWindow, wx.aui.AuiPaneInfo().CentrePane().
00261                           Dockable(False).BestSize((-1,-1)).
00262                           CloseButton(False).DestroyOnClose(True).
00263                           Layer(0))
00264         self._mgr.Update()
00265 
00266         #
00267         # Init print module and classes
00268         #
00269         self.printopt = disp_print.PrintOptions(self, self.MapWindow)
00270         
00271         #
00272         # Init zoom history
00273         #
00274         self.MapWindow.ZoomHistory(self.Map.region['n'],
00275                                    self.Map.region['s'],
00276                                    self.Map.region['e'],
00277                                    self.Map.region['w'])
00278 
00279         #
00280         # Re-use dialogs
00281         #
00282         self.dialogs = {}
00283         self.dialogs['attributes'] = None
00284         self.dialogs['category'] = None
00285         self.dialogs['barscale'] = None
00286         self.dialogs['legend'] = None
00287 
00288         self.decorationDialog = None # decoration/overlays
00289 
00290     def _addToolbarVDigit(self):
00291         """!Add vector digitizer toolbar
00292         """
00293         from vdigit import haveVDigit
00294         
00295         if not haveVDigit:
00296             from vdigit import errorMsg
00297             msg = _("Unable to start wxGUI vector digitizer.\nDo you want to start "
00298                     "TCL/TK digitizer (v.digit) instead?\n\n"
00299                     "Details: %s" % errorMsg)
00300             
00301             self.toolbars['map'].combo.SetValue(_("2D view"))
00302             dlg = wx.MessageDialog(parent = self,
00303                                    message = msg,
00304                                    caption=_("Vector digitizer failed"),
00305                                    style = wx.YES_NO | wx.CENTRE)
00306             if dlg.ShowModal() == wx.ID_YES:
00307                 mapName = self.tree.GetPyData(self.tree.layer_selected)[0]['maplayer'].GetName()
00308                 self._layerManager.goutput.RunCmd(['v.digit', 'map=%s' % mapName],
00309                                                   switchPage = False)
00310             dlg.Destroy()
00311             
00312             self.toolbars['map'].combo.SetValue(_("2D view"))
00313             return
00314         
00315         if self._layerManager:
00316             log = self._layerManager.goutput
00317         else:
00318             log = None
00319         
00320         if not self.MapWindowVDigit:
00321             from mapdisp_vdigit import VDigitWindow
00322             self.MapWindowVDigit = VDigitWindow(self, id = wx.ID_ANY,
00323                                                 Map = self.Map, tree = self.tree,
00324                                                 lmgr = self._layerManager)
00325             self.MapWindowVDigit.Show()
00326         
00327         self.MapWindow = self.MapWindowVDigit
00328         
00329         self._mgr.DetachPane(self.MapWindow2D)
00330         self.MapWindow2D.Hide()
00331         
00332         self.toolbars['vdigit'] = toolbars.VDigitToolbar(parent = self, mapcontent = self.Map,
00333                                                          layerTree = self.tree,
00334                                                          log = log)
00335         self.MapWindowVDigit.SetToolbar(self.toolbars['vdigit'])
00336         
00337         self._mgr.AddPane(self.MapWindowVDigit, wx.aui.AuiPaneInfo().CentrePane().
00338                           Dockable(False).BestSize((-1,-1)).
00339                           CloseButton(False).DestroyOnClose(True).
00340                           Layer(0))
00341         self._mgr.AddPane(self.toolbars['vdigit'],
00342                           wx.aui.AuiPaneInfo().
00343                           Name("vdigittoolbar").Caption(_("Vector Digitizer Toolbar")).
00344                           ToolbarPane().Top().Row(1).
00345                           LeftDockable(False).RightDockable(False).
00346                           BottomDockable(False).TopDockable(True).
00347                           CloseButton(False).Layer(2).
00348                           BestSize((self.toolbars['vdigit'].GetBestSize())))
00349         # change mouse to draw digitized line
00350         self.MapWindow.mouse['box'] = "point"
00351         self.MapWindow.zoomtype     = 0
00352         self.MapWindow.pen          = wx.Pen(colour = 'red',   width = 2, style = wx.SOLID)
00353         self.MapWindow.polypen      = wx.Pen(colour = 'green', width = 2, style = wx.SOLID)
00354 
00355     def _addToolbarNviz(self):
00356         """!Add 3D view mode toolbar
00357         """
00358         import nviz
00359         
00360         # check for GLCanvas and OpenGL
00361         if not nviz.haveNviz:
00362             self.toolbars['map'].combo.SetValue (_("2D view"))
00363             gcmd.GError(parent = self,
00364                         message = _("Unable to switch to 3D display mode.\nThe Nviz python extension "
00365                                     "was not found or loaded properly.\n"
00366                                     "Switching back to 2D display mode.\n\nDetails: %s" % nviz.errorMsg))
00367             return
00368         
00369         # add Nviz toolbar and disable 2D display mode tools
00370         self.toolbars['nviz'] = toolbars.NvizToolbar(self, self.Map)
00371         self.toolbars['map'].Enable2D(False)
00372         
00373         # update status bar
00374         self.statusbarWin['toggle'].Enable(False)
00375         
00376         # erase map window
00377         self.MapWindow.EraseMap()
00378         
00379         self._layerManager.goutput.WriteCmdLog(_("Starting 3D view mode..."))
00380         self.statusbar.SetStatusText(_("Please wait, loading data..."), 0)
00381         
00382         # create GL window & NVIZ toolbar
00383         if not self.MapWindow3D:
00384             self.MapWindow3D = nviz.GLWindow(self, id = wx.ID_ANY,
00385                                              Map = self.Map, tree = self.tree, lmgr = self._layerManager)
00386             self.MapWindow = self.MapWindow3D
00387             self.MapWindow.SetCursor(self.cursors["default"])
00388             
00389                 # add Nviz notebookpage
00390             self._layerManager.AddNviz()
00391             
00392             self.MapWindow3D.OnPaint(None) # -> LoadData
00393             self.MapWindow3D.Show()
00394             self.MapWindow3D.UpdateView(None)
00395         else:
00396             self.MapWindow = self.MapWindow3D
00397             # add Nviz notebookpage
00398             self._layerManager.AddNviz()
00399             self._layerManager.nviz.UpdatePage('view')
00400             self._layerManager.nviz.UpdatePage('light')
00401         
00402         # switch from MapWindow to MapWindowGL
00403         # add nviz toolbar
00404         self._mgr.DetachPane(self.MapWindow2D)
00405         self.MapWindow2D.Hide()
00406         self._mgr.AddPane(self.MapWindow3D, wx.aui.AuiPaneInfo().CentrePane().
00407                           Dockable(False).BestSize((-1,-1)).
00408                           CloseButton(False).DestroyOnClose(True).
00409                           Layer(0))
00410         self._mgr.AddPane(self.toolbars['nviz'],
00411                           wx.aui.AuiPaneInfo().
00412                           Name("nviztoolbar").Caption(_("3D View Toolbar")).
00413                           ToolbarPane().Top().Row(1).
00414                           LeftDockable(False).RightDockable(False).
00415                           BottomDockable(False).TopDockable(True).
00416                           CloseButton(False).Layer(2).
00417                           BestSize((self.toolbars['nviz'].GetBestSize())))
00418         
00419         self.SetStatusText("", 0)
00420         
00421     def AddToolbar(self, name):
00422         """!Add defined toolbar to the window
00423         
00424         Currently known toolbars are:
00425          - 'map'     - basic map toolbar
00426          - 'vdigit'  - vector digitizer
00427          - 'gcpdisp' - GCP Manager Display
00428          - 'georect' - georectifier
00429          - 'nviz'    - 3D view mode
00430         """
00431         # default toolbar
00432         if name == "map":
00433             self.toolbars['map'] = toolbars.MapToolbar(self, self.Map)
00434             
00435             self._mgr.AddPane(self.toolbars['map'],
00436                               wx.aui.AuiPaneInfo().
00437                               Name("maptoolbar").Caption(_("Map Toolbar")).
00438                               ToolbarPane().Top().
00439                               LeftDockable(False).RightDockable(False).
00440                               BottomDockable(False).TopDockable(True).
00441                               CloseButton(False).Layer(2).
00442                               BestSize((self.toolbars['map'].GetBestSize())))
00443             
00444         # vector digitizer
00445         elif name == "vdigit":
00446             self._addToolbarVDigit()
00447         # georectifier
00448         elif name == "georect":
00449             self.toolbars['georect'] = toolbars.GRToolbar(self, self.Map)
00450             
00451             self._mgr.AddPane(self.toolbars['georect'],
00452                               wx.aui.AuiPaneInfo().
00453                               Name("georecttoolbar").Caption(_("Georectification Toolbar")).
00454                               ToolbarPane().Top().
00455                               LeftDockable(False).RightDockable(False).
00456                               BottomDockable(False).TopDockable(True).
00457                               CloseButton(False).Layer(2).
00458                               BestSize((self.toolbars['georect'].GetBestSize())))
00459         # nviz
00460         elif name == "nviz":
00461             self._addToolbarNviz()
00462         
00463         self._mgr.Update()
00464         
00465     def RemoveToolbar (self, name):
00466         """!Removes defined toolbar from the window
00467 
00468         @todo Only hide, activate by calling AddToolbar()
00469         """
00470         # cannot hide main toolbar
00471         if name == "map":
00472             return
00473         
00474         self._mgr.DetachPane(self.toolbars[name])
00475         self.toolbars[name].Destroy()
00476         self.toolbars[name] = None
00477         
00478         if name == 'vdigit':
00479             self._mgr.DetachPane(self.MapWindowVDigit)
00480             self.MapWindowVDigit.Hide()
00481             self.MapWindow2D.Show()
00482             self._mgr.AddPane(self.MapWindow2D, wx.aui.AuiPaneInfo().CentrePane().
00483                               Dockable(False).BestSize((-1,-1)).
00484                               CloseButton(False).DestroyOnClose(True).
00485                               Layer(0))
00486             self.MapWindow = self.MapWindow2D
00487         
00488         elif name == 'nviz':
00489             # unload data
00490             # self.MapWindow3D.Reset()
00491             # switch from MapWindowGL to MapWindow
00492             self._mgr.DetachPane(self.MapWindow3D)
00493             self.MapWindow3D.Hide()
00494             self.MapWindow2D.Show()
00495             self._mgr.AddPane(self.MapWindow2D, wx.aui.AuiPaneInfo().CentrePane().
00496                               Dockable(False).BestSize((-1,-1)).
00497                               CloseButton(False).DestroyOnClose(True).
00498                               Layer(0))
00499             self.MapWindow = self.MapWindow2D
00500             # remove nviz notebook page
00501             self._layerManager.RemoveNviz()
00502             
00503             self.MapWindow.UpdateMap()
00504         
00505         self.toolbars['map'].combo.SetValue(_("2D view"))
00506         self.toolbars['map'].Enable2D(True)
00507         self.statusbarWin['toggle'].Enable(True)
00508         
00509         self._mgr.Update()
00510 
00511     def _initDisplay(self):
00512         """!Initialize map display, set dimensions and map region
00513         """
00514         if not grass.find_program('g.region', ['--help']):
00515             sys.exit(_("GRASS module '%s' not found. Unable to start map "
00516                        "display window.") % 'g.region')
00517         
00518         self.width, self.height = self.GetClientSize()
00519         
00520         Debug.msg(2, "MapFrame._initDisplay():")
00521         self.Map.ChangeMapSize(self.GetClientSize())
00522         self.Map.region = self.Map.GetRegion() # g.region -upgc
00523         # self.Map.SetRegion() # adjust region to match display window
00524 
00525     def OnUpdateProgress(self, event):
00526         """!Update progress bar info
00527         """
00528         self.statusbarWin['progress'].SetValue(event.value)
00529         
00530         event.Skip()
00531         
00532     def OnFocus(self, event):
00533         """
00534         Change choicebook page to match display.
00535         Or set display for georectifying
00536         """
00537         if self._layerManager and \
00538                 self._layerManager.georectifying:
00539             # in georectifying session; display used to get geographic
00540             # coordinates for GCPs
00541             self.OnPointer(event)
00542         else:
00543             # change bookcontrol page to page associated with display
00544             if self.page:
00545                 pgnum = self.layerbook.GetPageIndex(self.page)
00546                 if pgnum > -1:
00547                     self.layerbook.SetSelection(pgnum)
00548         
00549         event.Skip()
00550         
00551     def OnDraw(self, event):
00552         """!Re-display current map composition
00553         """
00554         self.MapWindow.UpdateMap(render = False)
00555         
00556     def OnRender(self, event):
00557         """!Re-render map composition (each map layer)
00558         """
00559         # delete tmp map layers (queries)
00560         qlayer = self.Map.GetListOfLayers(l_name = globalvar.QUERYLAYER)
00561         for layer in qlayer:
00562             self.Map.DeleteLayer(layer)
00563         
00564         # delete tmp lines
00565         if self.MapWindow.mouse["use"] in ("measure",
00566                                            "profile"):
00567             self.MapWindow.polycoords = []
00568             self.MapWindow.ClearLines()
00569         
00570         # deselect features in vdigit
00571         if self.toolbars['vdigit']:
00572             if self.MapWindow.digit:
00573                 self.MapWindow.digit.GetDisplay().SetSelected([])
00574             self.MapWindow.UpdateMap(render = True, renderVector = True)
00575         else:
00576             self.MapWindow.UpdateMap(render = True)
00577         
00578         # update statusbar
00579         self.StatusbarUpdate()
00580 
00581     def OnPointer(self, event):
00582         """!Pointer button clicked
00583         """
00584         if self.toolbars['map']:
00585             if event:
00586                 self.toolbars['map'].OnTool(event)
00587             self.toolbars['map'].action['desc'] = ''
00588         
00589         self.MapWindow.mouse['use'] = "pointer"
00590         self.MapWindow.mouse['box'] = "point"
00591 
00592         # change the cursor
00593         if self.toolbars['vdigit']:
00594             # digitization tool activated
00595             self.MapWindow.SetCursor(self.cursors["cross"])
00596 
00597             # reset mouse['box'] if needed
00598             if self.toolbars['vdigit'].GetAction() in ['addLine']:
00599                 if self.toolbars['vdigit'].GetAction('type') in ['point', 'centroid']:
00600                     self.MapWindow.mouse['box'] = 'point'
00601                 else: # line, boundary
00602                     self.MapWindow.mouse['box'] = 'line'
00603             elif self.toolbars['vdigit'].GetAction() in ['addVertex', 'removeVertex', 'splitLine',
00604                                                          'editLine', 'displayCats', 'queryMap',
00605                                                          'copyCats']:
00606                 self.MapWindow.mouse['box'] = 'point'
00607             else: # moveLine, deleteLine
00608                 self.MapWindow.mouse['box'] = 'box'
00609         
00610         elif self._layerManager and self._layerManager.georectifying:
00611             self.MapWindow.SetCursor(self.cursors["cross"])
00612         
00613         else:
00614             self.MapWindow.SetCursor(self.cursors["default"])
00615 
00616     def OnZoomIn(self, event):
00617         """
00618         Zoom in the map.
00619         Set mouse cursor, zoombox attributes, and zoom direction
00620         """
00621         if self.toolbars['map']:
00622             self.toolbars['map'].OnTool(event)
00623             self.toolbars['map'].action['desc'] = ''
00624         
00625         self.MapWindow.mouse['use'] = "zoom"
00626         self.MapWindow.mouse['box'] = "box"
00627         self.MapWindow.zoomtype = 1
00628         self.MapWindow.pen = wx.Pen(colour = 'Red', width = 2, style = wx.SHORT_DASH)
00629         
00630         # change the cursor
00631         self.MapWindow.SetCursor(self.cursors["cross"])
00632 
00633     def OnZoomOut(self, event):
00634         """
00635         Zoom out the map.
00636         Set mouse cursor, zoombox attributes, and zoom direction
00637         """
00638         if self.toolbars['map']:
00639             self.toolbars['map'].OnTool(event)
00640             self.toolbars['map'].action['desc'] = ''
00641         
00642         self.MapWindow.mouse['use'] = "zoom"
00643         self.MapWindow.mouse['box'] = "box"
00644         self.MapWindow.zoomtype = -1
00645         self.MapWindow.pen = wx.Pen(colour = 'Red', width = 2, style = wx.SHORT_DASH)
00646         
00647         # change the cursor
00648         self.MapWindow.SetCursor(self.cursors["cross"])
00649 
00650     def OnZoomBack(self, event):
00651         """
00652         Zoom last (previously stored position)
00653         """
00654         self.MapWindow.ZoomBack()
00655 
00656     def OnPan(self, event):
00657         """
00658         Panning, set mouse to drag
00659         """
00660         if self.toolbars['map']:
00661             self.toolbars['map'].OnTool(event)
00662             self.toolbars['map'].action['desc'] = ''
00663         
00664         self.MapWindow.mouse['use'] = "pan"
00665         self.MapWindow.mouse['box'] = "pan"
00666         self.MapWindow.zoomtype = 0
00667         
00668         # change the cursor
00669         self.MapWindow.SetCursor(self.cursors["hand"])
00670 
00671     def OnErase(self, event):
00672         """
00673         Erase the canvas
00674         """
00675         self.MapWindow.EraseMap()
00676 
00677     def OnZoomRegion(self, event):
00678         """
00679         Zoom to region
00680         """
00681         self.Map.getRegion()
00682         self.Map.getResolution()
00683         self.UpdateMap()
00684         # event.Skip()
00685 
00686     def OnAlignRegion(self, event):
00687         """
00688         Align region
00689         """
00690         if not self.Map.alignRegion:
00691             self.Map.alignRegion = True
00692         else:
00693             self.Map.alignRegion = False
00694         # event.Skip()
00695 
00696     def OnToggleRender(self, event):
00697         """!Enable/disable auto-rendering
00698         """
00699         if self.statusbarWin['render'].GetValue():
00700             self.OnRender(None)
00701 
00702     def IsAutoRendered(self):
00703         """!Check if auto-rendering is enabled"""
00704         return self.statusbarWin['render'].IsChecked()
00705     
00706     def OnToggleShowRegion(self, event):
00707         """!Show/Hide extent in map canvas
00708         """
00709         if self.statusbarWin['region'].GetValue():
00710             # show extent
00711             self.MapWindow.regionCoords = []
00712         else:
00713             del self.MapWindow.regionCoords
00714 
00715         # redraw map if auto-rendering is enabled
00716         if self.statusbarWin['render'].GetValue():
00717             self.OnRender(None)
00718 
00719     def OnToggleResolution(self, event):
00720         """
00721         Use resolution of computation region settings
00722         for redering image instead of display resolution
00723         """
00724         # redraw map if auto-rendering is enabled
00725         if self.statusbarWin['render'].GetValue():
00726             self.OnRender(None)
00727         
00728     def OnToggleStatus(self, event):
00729         """
00730         Toggle status text
00731         """
00732         self.StatusbarUpdate()
00733 
00734     def OnChangeMapScale(self, event):
00735         """
00736         Map scale changed by user
00737         """
00738         scale = event.GetString()
00739 
00740         try:
00741             if scale[:2] != '1:':
00742                 raise ValueError
00743             value = int(scale[2:])
00744         except ValueError:
00745             self.statusbarWin['mapscale'].SetValue('1:%ld' % int(self.mapScaleValue))
00746             return
00747 
00748         dEW = value * (self.Map.region['cols'] / self.ppm[0])
00749         dNS = value * (self.Map.region['rows'] / self.ppm[1])
00750         self.Map.region['n'] = self.Map.region['center_northing'] + dNS / 2.
00751         self.Map.region['s'] = self.Map.region['center_northing'] - dNS / 2.
00752         self.Map.region['w'] = self.Map.region['center_easting']  - dEW / 2.
00753         self.Map.region['e'] = self.Map.region['center_easting']  + dEW / 2.
00754         
00755         # add to zoom history
00756         self.MapWindow.ZoomHistory(self.Map.region['n'], self.Map.region['s'],
00757                                    self.Map.region['e'], self.Map.region['w'])
00758         
00759         # redraw a map
00760         self.MapWindow.UpdateMap()
00761         self.statusbarWin['mapscale'].SetFocus()
00762         
00763     def OnGoTo(self, event):
00764         """
00765         Go to position
00766         """
00767         try:
00768             if self.statusbarWin['projection'].IsChecked():
00769                 if not UserSettings.Get(group = 'projection', key = 'statusbar', subkey = 'proj4'):
00770                     self.statusbar.SetStatusText(_("Projection not defined (check the settings)"), 0)
00771                 else:
00772                     # reproject values
00773                     projIn = UserSettings.Get(group = 'projection',
00774                                               key = 'statusbar',
00775                                               subkey = 'proj4')
00776                     projOut = gcmd.RunCommand('g.proj',
00777                                               flags = 'jf',
00778                                               read = True)
00779                     proj = projIn.split(' ')[0].split('=')[1]
00780                     if proj in ('ll', 'latlong', 'longlat'):
00781                         e, n = self.statusbarWin['goto'].GetValue().split(';')
00782                         e, n = utils.DMS2Deg(e, n)
00783                         proj, coord1 = utils.ReprojectCoordinates(coord = (e, n),
00784                                                                   projIn = projIn,
00785                                                                   projOut = projOut, flags = 'd')
00786                         e, n = coord1
00787                     else:
00788                         e, n = map(float, self.statusbarWin['goto'].GetValue().split(';'))
00789                         proj, coord1 = utils.ReprojectCoordinates(coord = (e, n),
00790                                                                   projIn = projIn,
00791                                                                   projOut = projOut, flags = 'd')
00792                         e, n = coord1
00793             else:
00794                 if self.Map.projinfo['proj'] == 'll':
00795                     e, n = self.statusbarWin['goto'].GetValue().split(';')
00796                 else:
00797                     e, n = map(float, self.statusbarWin['goto'].GetValue().split(';'))
00798                     
00799             region = self.Map.GetCurrentRegion()
00800             if self.statusbarWin['projection'].IsChecked():
00801                 if not UserSettings.Get(group = 'projection', key = 'statusbar', subkey = 'proj4'):
00802                     self.statusbar.SetStatusText(_("Projection not defined (check the settings)"), 0)
00803                 else:
00804                     region['center_easting'], region['center_northing'] = e, n
00805             else:
00806                 if self.Map.projinfo['proj'] == 'll':
00807                     region['center_easting'], region['center_northing'] = utils.DMS2Deg(e, n)
00808                 else:
00809                     region['center_easting'], region['center_northing'] = e, n
00810         except ValueError:
00811             region = self.Map.GetCurrentRegion()
00812             precision = int(UserSettings.Get(group = 'projection', key = 'format',
00813                                              subkey = 'precision'))
00814             format = UserSettings.Get(group = 'projection', key = 'format',
00815                                       subkey = 'll')
00816             if self.Map.projinfo['proj'] == 'll' and format == 'DMS':
00817                     self.statusbarWin['goto'].SetValue("%s" % utils.Deg2DMS(region['center_easting'], 
00818                                                                             region['center_northing'],
00819                                                                             precision = precision))
00820             else:
00821                 self.statusbarWin['goto'].SetValue("%.*f; %.*f" % \
00822                                                        (precision, region['center_easting'],
00823                                                         precision, region['center_northing']))
00824             return
00825         
00826         
00827         dn = (region['nsres'] * region['rows']) / 2.
00828         region['n'] = region['center_northing'] + dn
00829         region['s'] = region['center_northing'] - dn
00830         de = (region['ewres'] * region['cols']) / 2.
00831         region['e'] = region['center_easting'] + de
00832         region['w'] = region['center_easting'] - de
00833         
00834         self.Map.AdjustRegion()
00835 
00836         # add to zoom history
00837         self.MapWindow.ZoomHistory(region['n'], region['s'],
00838                                    region['e'], region['w'])
00839         
00840         # redraw a map
00841         self.MapWindow.UpdateMap()
00842         self.statusbarWin['goto'].SetFocus()
00843         
00844     def StatusbarUpdate(self):
00845         """!Update statusbar content"""
00846 
00847         self.statusbarWin['region'].Hide()
00848         self.statusbarWin['resolution'].Hide()
00849         self.statusbarWin['mapscale'].Hide()
00850         self.statusbarWin['goto'].Hide()
00851         self.statusbarWin['projection'].Hide()
00852         self.mapScaleValue = self.ppm = None
00853 
00854         if self.statusbarWin['toggle'].GetSelection() == 0: # Coordinates
00855             self.statusbar.SetStatusText("", 0)
00856             # enable long help
00857             self.StatusbarEnableLongHelp()
00858 
00859         elif self.statusbarWin['toggle'].GetSelection() in (1, 2): # Extent
00860             sel = self.statusbarWin['toggle'].GetSelection()
00861             if sel == 1:
00862                 region = self.Map.region
00863             else:
00864                 region = self.Map.GetRegion() # computation region
00865 
00866             precision = int(UserSettings.Get(group = 'projection', key = 'format',
00867                                              subkey = 'precision'))
00868             format = UserSettings.Get(group = 'projection', key = 'format',
00869                                       subkey = 'll')
00870             
00871             if self.statusbarWin['projection'].IsChecked():
00872                 if not UserSettings.Get(group = 'projection', key = 'statusbar', subkey = 'proj4'):
00873                     self.statusbar.SetStatusText(_("Projection not defined (check the settings)"), 0)
00874                 else:
00875                     projOut = UserSettings.Get(group = 'projection',
00876                                                key = 'statusbar',
00877                                                subkey = 'proj4')
00878                     proj, coord1 = utils.ReprojectCoordinates(coord = (region["w"], region["s"]),
00879                                                               projOut = projOut, flags = 'd')
00880                     proj, coord2 = utils.ReprojectCoordinates(coord = (region["e"], region["n"]),
00881                                                           projOut = projOut, flags = 'd')
00882                     if sel == 2:
00883                         proj, coord3 = utils.ReprojectCoordinates(coord = (0.0, 0.0),
00884                                                                   projOut = projOut, flags = 'd')
00885                         proj, coord4 = utils.ReprojectCoordinates(coord = (region["ewres"], region["nsres"]),
00886                                                                   projOut = projOut, flags = 'd')
00887                     if coord1 and coord2:
00888                         if proj in ('ll', 'latlong', 'longlat') and format == 'DMS':
00889                             w, s = utils.Deg2DMS(coord1[0], coord1[1], string = False,
00890                                                  precision = precision)
00891                             e, n = utils.Deg2DMS(coord2[0], coord2[1], string = False,
00892                                                  precision = precision)
00893                             if sel == 1:
00894                                 self.statusbar.SetStatusText("%s - %s, %s - %s" %
00895                                                              (w, e, s, n), 0)
00896                             else:
00897                                 ewres, nsres = utils.Deg2DMS(abs(coord3[0]) - abs(coord4[0]),
00898                                                              abs(coord3[1]) - abs(coord4[1]),
00899                                                              string = False, hemisphere = False,
00900                                                              precision = precision)
00901                                 self.statusbar.SetStatusText("%s - %s, %s - %s (%s, %s)" %
00902                                                              (w, e, s, n, ewres, nsres), 0)
00903                         else:
00904                             w, s = coord1
00905                             e, n = coord2
00906                             if sel == 1:
00907                                 self.statusbar.SetStatusText("%.*f - %.*f, %.*f - %.*f" %
00908                                                          (precision, w, precision, e,
00909                                                           precision, s, precision, n), 0)
00910                             else:
00911                                 ewres, nsres = coord3
00912                                 self.statusbar.SetStatusText("%.*f - %.*f, %.*f - %.*f (%.*f, %.*f)" %
00913                                                              (precision, w, precision, e,
00914                                                               precision, s, precision, n,
00915                                                               precision, ewres, precision, nsres), 0)
00916                     else:
00917                         self.statusbar.SetStatusText(_("Error in projection (check the settings)"), 0)
00918             else:
00919                 if self.Map.projinfo['proj'] == 'll' and format == 'DMS':
00920                     w, s = utils.Deg2DMS(region["w"], region["s"],
00921                                          string = False, precision = precision)
00922                     e, n = utils.Deg2DMS(region["e"], region["n"],
00923                                          string = False, precision = precision)
00924                     if sel == 1:
00925                         self.statusbar.SetStatusText("%s - %s, %s - %s" %
00926                                                      (w, e, s, n), 0)
00927                     else:
00928                         ewres, nsres = utils.Deg2DMS(region['ewres'], region['nsres'],
00929                                                      string = False, precision = precision)
00930                         self.statusbar.SetStatusText("%s - %s, %s - %s (%s, %s)" %
00931                                                      (w, e, s, n, ewres, nsres), 0)
00932                 else:
00933                     w, s = region["w"], region["s"]
00934                     e, n = region["e"], region["n"]
00935                     if sel == 1:
00936                         self.statusbar.SetStatusText("%.*f - %.*f, %.*f - %.*f" %
00937                                                      (precision, w, precision, e,
00938                                                       precision, s, precision, n), 0)
00939                     else:
00940                         ewres, nsres = region['ewres'], region['nsres']
00941                         self.statusbar.SetStatusText("%.*f - %.*f, %.*f - %.*f (%.*f, %.*f)" %
00942                                                      (precision, w, precision, e,
00943                                                       precision, s, precision, n,
00944                                                       precision, ewres, precision, nsres), 0)
00945             # enable long help
00946             self.StatusbarEnableLongHelp()
00947 
00948         elif self.statusbarWin['toggle'].GetSelection() == 3: # Show comp. extent
00949             self.statusbar.SetStatusText("", 0)
00950             self.statusbarWin['region'].Show()
00951             # disable long help
00952             self.StatusbarEnableLongHelp(False)
00953 
00954         elif self.statusbarWin['toggle'].GetSelection() == 4: # Display mode
00955             self.statusbar.SetStatusText("", 0)
00956             self.statusbarWin['resolution'].Show()
00957             # disable long help
00958             self.StatusbarEnableLongHelp(False)
00959 
00960         elif self.statusbarWin['toggle'].GetSelection() == 5: # Display geometry
00961             self.statusbar.SetStatusText("rows=%d; cols=%d; nsres=%.2f; ewres=%.2f" %
00962                                          (self.Map.region["rows"], self.Map.region["cols"],
00963                                           self.Map.region["nsres"], self.Map.region["ewres"]), 0)
00964             # enable long help
00965             self.StatusbarEnableLongHelp()
00966 
00967         elif self.statusbarWin['toggle'].GetSelection() == 6: # Map scale
00968             # TODO: need to be fixed...
00969             ### screen X region problem
00970             ### user should specify ppm
00971             dc = wx.ScreenDC()
00972             dpSizePx = wx.DisplaySize()   # display size in pixels
00973             dpSizeMM = wx.DisplaySizeMM() # display size in mm (system)
00974             dpSizeIn = (dpSizeMM[0] / 25.4, dpSizeMM[1] / 25.4) # inches
00975             sysPpi  = dc.GetPPI()
00976             comPpi = (dpSizePx[0] / dpSizeIn[0],
00977                       dpSizePx[1] / dpSizeIn[1])
00978 
00979             ppi = comPpi                  # pixel per inch
00980             self.ppm = ((ppi[0] / 2.54) * 100, # pixel per meter
00981                         (ppi[1] / 2.54) * 100)
00982 
00983             Debug.msg(4, "MapFrame.StatusbarUpdate(mapscale): size: px=%d,%d mm=%f,%f "
00984                       "in=%f,%f ppi: sys=%d,%d com=%d,%d; ppm=%f,%f" % \
00985                           (dpSizePx[0], dpSizePx[1], dpSizeMM[0], dpSizeMM[1],
00986                            dpSizeIn[0], dpSizeIn[1],
00987                            sysPpi[0], sysPpi[1], comPpi[0], comPpi[1],
00988                            self.ppm[0], self.ppm[1]))
00989 
00990             region = self.Map.region
00991 
00992             heightCm = region['rows'] / self.ppm[1] * 100
00993             widthCm  = region['cols'] / self.ppm[0] * 100
00994 
00995             Debug.msg(4, "MapFrame.StatusbarUpdate(mapscale): width_cm=%f, height_cm=%f" %
00996                       (widthCm, heightCm))
00997 
00998             xscale = (region['e'] - region['w']) / (region['cols'] / self.ppm[0])
00999             yscale = (region['n'] - region['s']) / (region['rows'] / self.ppm[1])
01000             scale = (xscale + yscale) / 2.
01001             
01002             Debug.msg(3, "MapFrame.StatusbarUpdate(mapscale): xscale=%f, yscale=%f -> scale=%f" % \
01003                           (xscale, yscale, scale))
01004 
01005             self.statusbar.SetStatusText("")
01006             try:
01007                 self.statusbarWin['mapscale'].SetValue("1:%ld" % (scale + 0.5))
01008             except TypeError:
01009                 pass
01010             self.mapScaleValue = scale
01011             self.statusbarWin['mapscale'].Show()
01012 
01013             # disable long help
01014             self.StatusbarEnableLongHelp(False)
01015 
01016         elif self.statusbarWin['toggle'].GetSelection() == 7: # go to
01017             self.statusbar.SetStatusText("")
01018             region = self.Map.GetCurrentRegion()
01019             precision = int(UserSettings.Get(group = 'projection', key = 'format',
01020                                              subkey = 'precision'))
01021             format = UserSettings.Get(group = 'projection', key = 'format',
01022                                       subkey = 'll')
01023             
01024             if self.statusbarWin['projection'].IsChecked():
01025                 if not UserSettings.Get(group='projection', key='statusbar', subkey='proj4'):
01026                     self.statusbar.SetStatusText(_("Projection not defined (check the settings)"), 0)
01027                 else:
01028                     proj, coord  = utils.ReprojectCoordinates(coord = (region['center_easting'],
01029                                                                        region['center_northing']),
01030                                                               projOut = UserSettings.Get(group = 'projection',
01031                                                                                          key = 'statusbar',
01032                                                                                          subkey = 'proj4'),
01033                                                               flags = 'd')
01034                     if coord:
01035                         if proj in ('ll', 'latlong', 'longlat') and format == 'DMS':
01036                             self.statusbarWin['goto'].SetValue("%s" % utils.Deg2DMS(coord[0],
01037                                                                                     coord[1],
01038                                                                                     precision = precision))
01039                         else:
01040                             self.statusbarWin['goto'].SetValue("%.*f; %.*f" % (precision, coord[0],
01041                                                                                precision, coord[1]))
01042                     else:
01043                         self.statusbar.SetStatusText(_("Error in projection (check the settings)"), 0)
01044             else:
01045                 if self.Map.projinfo['proj'] == 'll' and format == 'DMS':
01046                     self.statusbarWin['goto'].SetValue("%s" % utils.Deg2DMS(region['center_easting'], 
01047                                                                             region['center_northing'],
01048                                                                             precision = precision))
01049                 else:
01050                     self.statusbarWin['goto'].SetValue("%.*f; %.*f" % (precision, region['center_easting'],
01051                                                                        precision, region['center_northing']))
01052             self.statusbarWin['goto'].Show()
01053 
01054             # disable long help
01055             self.StatusbarEnableLongHelp(False)
01056         
01057         elif self.statusbarWin['toggle'].GetSelection() == 8: # projection
01058             self.statusbar.SetStatusText("")
01059             epsg = UserSettings.Get(group = 'projection', key = 'statusbar', subkey = 'epsg')
01060             if epsg:
01061                 label = '%s (EPSG: %s)' % (_("Use defined projection"), epsg)
01062                 self.statusbarWin['projection'].SetLabel(label)
01063             else:
01064                 self.statusbarWin['projection'].SetLabel(_("Use defined projection"))
01065             self.statusbarWin['projection'].Show()
01066             
01067             # disable long help
01068             self.StatusbarEnableLongHelp(False)
01069             
01070         else:
01071             self.statusbar.SetStatusText("", 1)
01072 
01073     def StatusbarEnableLongHelp(self, enable = True):
01074         """!Enable/disable toolbars long help"""
01075         for toolbar in self.toolbars.itervalues():
01076             if toolbar:
01077                 toolbar.EnableLongHelp(enable)
01078                 
01079     def StatusbarReposition(self):
01080         """!Reposition checkbox in statusbar"""
01081         # reposition checkbox
01082         widgets = [(0, self.statusbarWin['region']),
01083                    (0, self.statusbarWin['resolution']),
01084                    (0, self.statusbarWin['mapscale']),
01085                    (0, self.statusbarWin['progress']),
01086                    (0, self.statusbarWin['projection']),
01087                    (1, self.statusbarWin['toggle']),
01088                    (2, self.statusbarWin['mask']),
01089                    (3, self.statusbarWin['render'])]
01090         for idx, win in widgets:
01091             rect = self.statusbar.GetFieldRect(idx)
01092             if idx == 0: # show region / mapscale / process bar
01093                 # -> size
01094                 wWin, hWin = win.GetBestSize()
01095                 if win == self.statusbarWin['progress']:
01096                     wWin = rect.width - 6
01097                 # -> position
01098                 # if win == self.statusbarWin['region']:
01099                 # x, y = rect.x + rect.width - wWin, rect.y - 1
01100                 # align left
01101                 # else:
01102                 x, y = rect.x + 3, rect.y - 1
01103                 w, h = wWin, rect.height + 2
01104             else: # choice || auto-rendering
01105                 x, y = rect.x, rect.y - 1
01106                 w, h = rect.width, rect.height + 2
01107                 if idx == 2: # mask
01108                     x += 5
01109                     y += 4
01110                 elif idx == 3: # render
01111                     x += 5
01112             win.SetPosition((x, y))
01113             win.SetSize((w, h))
01114 
01115     def SaveToFile(self, event):
01116         """!Save map to image
01117         """
01118         if self.toolbars['nviz']:
01119             filetype = "PPM file (*.ppm)|*.ppm|TIF file (*.tif)|*.tif"
01120             ltype = [{ 'ext' : 'ppm', 'type' : -1 },
01121                      { 'ext' : 'tif', 'type' : wx.BITMAP_TYPE_TIF }]
01122         else:
01123             img = self.MapWindow.img
01124             if not img:
01125                 gcmd.GMessage(parent = self,
01126                               message = _("Nothing to render (empty map). Operation canceled."))
01127                 return
01128             filetype, ltype = gdialogs.GetImageHandlers(img)
01129         
01130         # get size
01131         dlg = gdialogs.ImageSizeDialog(self)
01132         dlg.CentreOnParent()
01133         if dlg.ShowModal() != wx.ID_OK:
01134             dlg.Destroy()
01135             return
01136         width, height = dlg.GetValues()
01137         dlg.Destroy()
01138         
01139         # get filename
01140         dlg = wx.FileDialog(parent = self,
01141                             message = _("Choose a file name to save the image "
01142                                         "(no need to add extension)"),
01143                             wildcard = filetype,
01144                             style = wx.SAVE | wx.FD_OVERWRITE_PROMPT)
01145         
01146         if dlg.ShowModal() == wx.ID_OK:
01147             path = dlg.GetPath()
01148             if not path:
01149                 dlg.Destroy()
01150                 return
01151             
01152             base, ext = os.path.splitext(path)
01153             fileType = ltype[dlg.GetFilterIndex()]['type']
01154             extType  = ltype[dlg.GetFilterIndex()]['ext']
01155             if ext != extType:
01156                 path = base + '.' + extType
01157             
01158             self.MapWindow.SaveToFile(path, fileType,
01159                                       width, height)
01160             
01161         dlg.Destroy()
01162 
01163     def PrintMenu(self, event):
01164         """
01165         Print options and output menu for map display
01166         """
01167         point = wx.GetMousePosition()
01168         printmenu = wx.Menu()
01169         # Add items to the menu
01170         setup = wx.MenuItem(printmenu, wx.ID_ANY, _('Page setup'))
01171         printmenu.AppendItem(setup)
01172         self.Bind(wx.EVT_MENU, self.printopt.OnPageSetup, setup)
01173 
01174         preview = wx.MenuItem(printmenu, wx.ID_ANY, _('Print preview'))
01175         printmenu.AppendItem(preview)
01176         self.Bind(wx.EVT_MENU, self.printopt.OnPrintPreview, preview)
01177 
01178         doprint = wx.MenuItem(printmenu, wx.ID_ANY, _('Print display'))
01179         printmenu.AppendItem(doprint)
01180         self.Bind(wx.EVT_MENU, self.printopt.OnDoPrint, doprint)
01181 
01182         # Popup the menu.  If an item is selected then its handler
01183         # will be called before PopupMenu returns.
01184         self.PopupMenu(printmenu)
01185         printmenu.Destroy()
01186 
01187     def OnCloseWindow(self, event):
01188         """!Window closed.
01189         Also close associated layer tree page
01190         """
01191         pgnum = None
01192         self.Map.Clean()
01193         
01194         # close edited map and 3D tools properly
01195         if self.toolbars['vdigit']:
01196             maplayer = self.toolbars['vdigit'].GetLayer()
01197             if maplayer:
01198                 self.toolbars['vdigit'].OnExit()
01199         
01200         if self.toolbars['nviz']:
01201             self.toolbars['nviz'].OnExit()
01202         
01203         if not self._layerManager:
01204             self.Destroy()
01205         elif self.page:
01206             pgnum = self.layerbook.GetPageIndex(self.page)
01207             if pgnum > -1:
01208                 self.layerbook.DeletePage(pgnum)
01209         
01210     def GetRender(self):
01211         """!Returns current instance of render.Map()
01212         """
01213         return self.Map
01214 
01215     def GetWindow(self):
01216         """!Get map window"""
01217         return self.MapWindow
01218     
01219     def OnNvizQuerySurface(self, event):
01220         """!Query current surface in 3D view mode"""
01221         if self.toolbars['map'].GetAction() == 'nvizQuerySurface':
01222             self.toolbars['map'].SelectDefault(event)
01223             return
01224         
01225         self.toolbars['map'].action['desc'] = 'nvizQuerySurface'
01226         
01227         self.MapWindow.mouse['use'] = "nvizQuerySurface"
01228         self._OnQuery()
01229 
01230     def OnNvizQueryVector(self, event):
01231         """!Query current vector in 3D view mode"""
01232         if self.toolbars['map'].GetAction() == 'nvizQueryVector':
01233             self.toolbars['map'].SelectDefault(event)
01234             return
01235         
01236         self.toolbars['map'].action['desc'] = 'nvizQueryVector'
01237         
01238         self.MapWindow.mouse['use'] = "nvizQueryVector"
01239         self._OnQuery()
01240         
01241     def QueryMap(self, x, y):
01242         """!Query raster or vector map layers by r/v.what
01243         
01244         @param x,y coordinates
01245         """
01246         # set query snap distance for v.what at map unit equivalent of 10 pixels
01247         qdist = 10.0 * ((self.Map.region['e'] - self.Map.region['w']) / self.Map.width)
01248         east, north = self.MapWindow.Pixel2Cell((x, y))
01249         
01250         if not self.IsStandalone():
01251             num = 0
01252             for layer in self.tree.GetSelections():
01253                 ltype = self.tree.GetPyData(layer)[0]['maplayer'].GetType()
01254                 if ltype in ('raster', 'rgb', 'his',
01255                              'vector', 'thememap', 'themechart'):
01256                     num += 1
01257             
01258             if num < 1:
01259                 gcmd.GMessage(parent = self,
01260                               message = _('No raster or vector map layer selected for querying.'))
01261                 return
01262         
01263         rast = list()
01264         vect = list()
01265         rcmd = ['r.what', '--v']
01266         vcmd = ['v.what', '--v']
01267         
01268         if self.IsStandalone():
01269             pass
01270         else:
01271             for layer in self.tree.GetSelections():
01272                 ltype = self.tree.GetPyData(layer)[0]['maplayer'].GetType()
01273                 dcmd = self.tree.GetPyData(layer)[0]['cmd']
01274                 name, found = utils.GetLayerNameFromCmd(dcmd)
01275                 
01276                 if not found:
01277                     continue
01278                 if ltype == 'raster':
01279                     rast.append(name)
01280                 elif ltype in ('rgb', 'his'):
01281                     for iname in name.split('\n'):
01282                         rast.append(iname)
01283                 elif ltype in ('vector', 'thememap', 'themechart'):
01284                     vect.append(name)
01285         
01286         # use display region settings instead of computation region settings
01287         self.tmpreg = os.getenv("GRASS_REGION")
01288         os.environ["GRASS_REGION"] = self.Map.SetRegion(windres = False)
01289         
01290         # build query commands for any selected rasters and vectors
01291         if rast:
01292             rcmd.append('-f')
01293             rcmd.append('-n')
01294             rcmd.append('input=%s' % ','.join(rast))
01295             rcmd.append('east_north=%f,%f' % (float(east), float(north)))
01296         
01297         if vect:
01298             # check for vector maps open to be edited
01299             digitToolbar = self.toolbars['vdigit']
01300             if digitToolbar:
01301                 lmap = digitToolbar.GetLayer().GetName()
01302                 for name in vect:
01303                     if lmap == name:
01304                         self._layerManager.goutput.WriteWarning(_("Vector map <%s> "
01305                                                                   "opened for editing - skipped.") % map)
01306                         vect.remove(name)
01307             
01308             if len(vect) < 1:
01309                 self._layerManager.goutput.WriteCmdLog(_("Nothing to query."))
01310                 return
01311             
01312             vcmd.append('-a')
01313             vcmd.append('map=%s' % ','.join(vect))
01314             vcmd.append('east_north=%f,%f' % (float(east), float(north)))
01315             vcmd.append('distance=%f' % float(qdist))
01316         
01317         Debug.msg(1, "QueryMap(): raster=%s vector=%s" % (','.join(rast),
01318                                                           ','.join(vect)))
01319         # parse query command(s)
01320         if not self.IsStandalone():
01321             if rast:
01322                 self._layerManager.goutput.RunCmd(rcmd,
01323                                                   compReg = False,
01324                                                   onDone  =  self._QueryMapDone)
01325             if vect:
01326                 self._layerManager.goutput.RunCmd(vcmd,
01327                                                   onDone = self._QueryMapDone)
01328         else:
01329             if rast:
01330                 gcmd.RunCommand(rcmd)
01331             if vect:
01332                 gcmd.RunCommand(vcmd)
01333         
01334     def _QueryMapDone(self, cmd, returncode):
01335         """!Restore settings after querying (restore GRASS_REGION)
01336         
01337         @param returncode command return code
01338         """
01339         if hasattr(self, "tmpreg"):
01340             if self.tmpreg:
01341                 os.environ["GRASS_REGION"] = self.tmpreg
01342             elif 'GRASS_REGION' in os.environ:
01343                 del os.environ["GRASS_REGION"]
01344         elif 'GRASS_REGION' in os.environ:
01345             del os.environ["GRASS_REGION"]
01346         
01347         if hasattr(self, "tmpreg"):
01348             del self.tmpreg
01349         
01350     def QueryVector(self, x, y):
01351         """!Query vector map layer features
01352 
01353         Attribute data of selected vector object are displayed in GUI dialog.
01354         Data can be modified (On Submit)
01355         """
01356         if not self.tree.layer_selected or \
01357                 self.tree.GetPyData(self.tree.layer_selected)[0]['type'] != 'vector':
01358             gcmd.GMessage(parent = self,
01359                           message = _("No map layer selected for querying."))
01360             return
01361         
01362         posWindow = self.ClientToScreen((x + self.MapWindow.dialogOffset,
01363                                          y + self.MapWindow.dialogOffset))
01364         
01365         qdist = 10.0 * ((self.Map.region['e'] - self.Map.region['w']) /
01366                         self.Map.width)
01367         
01368         east, north = self.MapWindow.Pixel2Cell((x, y))
01369         
01370         mapName = self.tree.GetPyData(self.tree.layer_selected)[0]['maplayer'].name
01371         
01372         if self.tree.GetPyData(self.tree.layer_selected)[0]['maplayer'].GetMapset() != \
01373                 grass.gisenv()['MAPSET']:
01374             mode = 'display'
01375         else:
01376             mode = 'update'
01377         
01378         if self.dialogs['attributes'] is None:
01379             dlg = dbm_dialogs.DisplayAttributesDialog(parent = self.MapWindow,
01380                                                       map = mapName,
01381                                                       query = ((east, north), qdist),
01382                                                       pos = posWindow,
01383                                                       action = mode)
01384             self.dialogs['attributes'] = dlg
01385         
01386         else:
01387             # selection changed?
01388             if not self.dialogs['attributes'].mapDBInfo or \
01389                     self.dialogs['attributes'].mapDBInfo.map != mapName:
01390                 self.dialogs['attributes'].UpdateDialog(map = mapName, query = ((east, north), qdist),
01391                                                         action = mode)
01392             else:
01393                 self.dialogs['attributes'].UpdateDialog(query = ((east, north), qdist),
01394                                                         action = mode)
01395         if not self.dialogs['attributes'].IsFound():
01396             self._layerManager.goutput.WriteLog(_('Nothing found.'))
01397         
01398         cats = self.dialogs['attributes'].GetCats()
01399         
01400         try:
01401             qlayer = self.Map.GetListOfLayers(l_name = globalvar.QUERYLAYER)[0]
01402         except IndexError:
01403             qlayer = None
01404         
01405         if self.dialogs['attributes'].mapDBInfo and cats:
01406             # highlight feature & re-draw map
01407             if qlayer:
01408                 qlayer.SetCmd(self.AddTmpVectorMapLayer(mapName, cats,
01409                                                         useId = False,
01410                                                         addLayer = False))
01411             else:
01412                 qlayer = self.AddTmpVectorMapLayer(mapName, cats, useId = False)
01413             
01414             # set opacity based on queried layer
01415             opacity = self.tree.GetPyData(self.tree.layer_selected)[0]['maplayer'].GetOpacity(float = True)
01416             qlayer.SetOpacity(opacity)
01417             
01418             self.MapWindow.UpdateMap(render = False, renderVector = False)
01419             if not self.dialogs['attributes'].IsShown():
01420                 self.dialogs['attributes'].Show()
01421         else:
01422             if qlayer:
01423                 self.Map.DeleteLayer(qlayer)
01424                 self.MapWindow.UpdateMap(render = False, renderVector = False)
01425             if self.dialogs['attributes'].IsShown():
01426                 self.dialogs['attributes'].Hide()
01427         
01428     def OnQuery(self, event):
01429         """!Query tools menu"""
01430         if self.toolbars['map']:
01431             self.toolbars['map'].OnTool(event)
01432             action = self.toolbars['map'].GetAction()
01433         
01434         if self.toolbars['nviz']:
01435             toolsmenu = wx.Menu()
01436             raster = wx.MenuItem(parentMenu = toolsmenu, id = wx.ID_ANY,
01437                                  text = _("Query surface (raster map)"),
01438                                  kind = wx.ITEM_CHECK)
01439             toolsmenu.AppendItem(raster)
01440             self.Bind(wx.EVT_MENU, self.OnNvizQuerySurface, raster)
01441             if action == "nvizQuerySurface":
01442                 raster.Check(True)
01443             vector = wx.MenuItem(parentMenu = toolsmenu, id = wx.ID_ANY,
01444                                  text = _("Query vector map"),
01445                                  kind = wx.ITEM_CHECK)
01446             toolsmenu.AppendItem(vector)
01447             self.Bind(wx.EVT_MENU, self.OnNvizQueryVector, vector)
01448             if action == "nvizQueryVector":
01449                 vector.Check(True)
01450 
01451             self.PopupMenu(toolsmenu)
01452             toolsmenu.Destroy()
01453         else:
01454             self.toolbars['map'].action['desc'] = 'queryMap'
01455             self.MapWindow.mouse['use'] = "query"
01456             
01457             if not self.IsStandalone():
01458                 # switch to output console to show query results
01459                 self._layerManager.notebook.SetSelectionByName('output')
01460             
01461             self.MapWindow.mouse['box'] = "point"
01462             self.MapWindow.zoomtype = 0
01463             
01464             # change the cursor
01465             self.MapWindow.SetCursor(self.cursors["cross"])
01466         
01467     def AddTmpVectorMapLayer(self, name, cats, useId = False, addLayer = True):
01468         """!Add temporal vector map layer to map composition
01469 
01470         @param name name of map layer
01471         @param useId use feature id instead of category 
01472         """
01473         # color settings from ATM
01474         color = UserSettings.Get(group = 'atm', key = 'highlight', subkey = 'color')
01475         colorStr = str(color[0]) + ":" + \
01476             str(color[1]) + ":" + \
01477             str(color[2])
01478 
01479         # icon used in vector display and its size
01480         icon = ''
01481         size = 0
01482         vparam = self.tree.GetPyData(self.tree.layer_selected)[0]['cmd']
01483         for p in vparam:
01484             if '=' in p:
01485                 parg,pval = p.split('=')
01486                 if parg == 'icon': icon = pval
01487                 elif parg == 'size': size = int(pval)
01488 
01489         pattern = ["d.vect",
01490                    "map=%s" % name,
01491                    "color=%s" % colorStr,
01492                    "fcolor=%s" % colorStr,
01493                    "width=%d"  % UserSettings.Get(group = 'atm', key = 'highlight', subkey = 'width')]
01494         if icon != '':
01495             pattern.append('icon=%s' % icon)
01496         if size > 0:
01497             pattern.append('size=%i' % size)
01498         
01499         if useId:
01500             cmd = pattern
01501             cmd.append('-i')
01502             cmd.append('cats=%s' % str(cats))
01503         else:
01504             cmd = []
01505             for layer in cats.keys():
01506                 cmd.append(copy.copy(pattern))
01507                 lcats = cats[layer]
01508                 cmd[-1].append("layer=%d" % layer)
01509                 cmd[-1].append("cats=%s" % utils.ListOfCatsToRange(lcats))
01510         
01511         if addLayer:
01512             if useId:
01513                 return self.Map.AddLayer(type = 'vector', name = globalvar.QUERYLAYER, command = cmd,
01514                                          l_active = True, l_hidden = True, l_opacity = 1.0)
01515             else:
01516                 return self.Map.AddLayer(type = 'command', name = globalvar.QUERYLAYER, command = cmd,
01517                                          l_active = True, l_hidden = True, l_opacity = 1.0)
01518         else:
01519             return cmd
01520 
01521     def OnAnalyze(self, event):
01522         """!Analysis tools menu
01523         """
01524         point = wx.GetMousePosition()
01525         toolsmenu = wx.Menu()
01526         icons = Icons['displayWindow']
01527         
01528         # Add items to the menu
01529         measure = wx.MenuItem(toolsmenu, wx.ID_ANY, icons["measure"].GetLabel())
01530         measure.SetBitmap(icons["measure"].GetBitmap(self.iconsize))
01531         toolsmenu.AppendItem(measure)
01532         self.Bind(wx.EVT_MENU, self.OnMeasure, measure)
01533         
01534         profile = wx.MenuItem(toolsmenu, wx.ID_ANY, icons["profile"].GetLabel())
01535         profile.SetBitmap(icons["profile"].GetBitmap(self.iconsize))
01536         toolsmenu.AppendItem(profile)
01537         self.Bind(wx.EVT_MENU, self.Profile, profile)
01538 
01539         histogram = wx.MenuItem(toolsmenu, wx.ID_ANY, icons["histogram"].GetLabel())
01540         histogram.SetBitmap(icons["histogram"].GetBitmap(self.iconsize))
01541         toolsmenu.AppendItem(histogram)
01542         self.Bind(wx.EVT_MENU, self.Histogram, histogram)
01543 
01544         # Popup the menu.  If an item is selected then its handler
01545         # will be called before PopupMenu returns.
01546         self.PopupMenu(toolsmenu)
01547         toolsmenu.Destroy()
01548 
01549     def OnMeasure(self, event):
01550         """!Init measurement routine that calculates map distance
01551         along transect drawn on map display
01552         """
01553         self.totaldist = 0.0 # total measured distance
01554         
01555         # switch Layer Manager to output console to show measure results
01556         self._layerManager.notebook.SetSelectionByName('output')
01557         
01558         # change mouse to draw line for measurement
01559         self.MapWindow.mouse['use'] = "measure"
01560         self.MapWindow.mouse['box'] = "line"
01561         self.MapWindow.zoomtype = 0
01562         self.MapWindow.pen     = wx.Pen(colour = 'red', width = 2, style = wx.SHORT_DASH)
01563         self.MapWindow.polypen = wx.Pen(colour = 'green', width = 2, style = wx.SHORT_DASH)
01564         
01565         # change the cursor
01566         self.MapWindow.SetCursor(self.cursors["pencil"])
01567         
01568         # initiating output
01569         style = self._layerManager.goutput.cmd_output.StyleWarning
01570         self._layerManager.goutput.WriteLog(_('Click and drag with left mouse button '
01571                                               'to measure.%s'
01572                                               'Double click with left button to clear.') % \
01573                                                 (os.linesep), style)
01574         if self.Map.projinfo['proj'] != 'xy':
01575             units = self.Map.projinfo['units']
01576             self._layerManager.goutput.WriteCmdLog(_('Measuring distance') + ' ('
01577                                                    + units + '):')
01578         else:
01579             self._layerManager.goutput.WriteCmdLog(_('Measuring distance:'))
01580         
01581         if self.Map.projinfo['proj'] == 'll':
01582             try:
01583                 import grass.lib.gis as gislib
01584                 global haveCtypes
01585                 haveCtypes = True
01586 
01587                 gislib.G_begin_distance_calculations()
01588             except ImportError, e:
01589                 self._layerManager.goutput.WriteWarning(_('Geodesic distance is not yet '
01590                                                           'supported by this tool.\n'
01591                                                           'Reason: %s' % e))
01592         
01593     def MeasureDist(self, beginpt, endpt):
01594         """!Calculate map distance from screen distance
01595         and print to output window
01596         """
01597         self._layerManager.notebook.SetSelectionByName('output')
01598         
01599         dist, (north, east) = self.MapWindow.Distance(beginpt, endpt)
01600         
01601         dist = round(dist, 3)
01602         d, dunits = self.FormatDist(dist)
01603         
01604         self.totaldist += dist
01605         td, tdunits = self.FormatDist(self.totaldist)
01606         
01607         strdist = str(d)
01608         strtotdist = str(td)
01609         
01610         if self.Map.projinfo['proj'] == 'xy' or 'degree' not in self.Map.projinfo['unit']:
01611             angle = int(math.degrees(math.atan2(north,east)) + 0.5)
01612             angle = 180 - angle
01613             if angle < 0:
01614                 angle = 360 + angle
01615             
01616             mstring = '%s = %s %s\n%s = %s %s\n%s = %d %s\n%s' \
01617                 % (_('segment'), strdist, dunits,
01618                    _('total distance'), strtotdist, tdunits,
01619                    _('bearing'), angle, _('deg'),
01620                    '-' * 60)
01621         else:
01622             mstring = '%s = %s %s\n%s = %s %s\n%s' \
01623                 % (_('segment'), strdist, dunits,
01624                    _('total distance'), strtotdist, tdunits,
01625                    '-' * 60)
01626         
01627         self._layerManager.goutput.WriteLog(mstring)
01628         
01629         return dist
01630 
01631     def Profile(self, event):
01632         """!Init profile canvas and tools
01633         """
01634         raster = []
01635         if self.tree.layer_selected and \
01636                 self.tree.GetPyData(self.tree.layer_selected)[0]['type'] == 'raster':
01637             raster.append(self.tree.GetPyData(self.tree.layer_selected)[0]['maplayer'].name)
01638 
01639         self.profile = profile.ProfileFrame(self,
01640                                             id = wx.ID_ANY, pos = wx.DefaultPosition, size = (700,300),
01641                                             style = wx.DEFAULT_FRAME_STYLE, rasterList = raster)
01642         self.profile.Show()
01643         # Open raster select dialog to make sure that a raster (and the desired raster)
01644         # is selected to be profiled
01645         self.profile.OnSelectRaster(None)
01646 
01647     def FormatDist(self, dist):
01648         """!Format length numbers and units in a nice way,
01649         as a function of length. From code by Hamish Bowman
01650         Grass Development Team 2006"""
01651         
01652         mapunits = self.Map.projinfo['units']
01653         if mapunits == 'metres':
01654             mapunits = 'meters'
01655         outunits = mapunits
01656         dist = float(dist)
01657         divisor = 1.0
01658         
01659         # figure out which units to use
01660         if mapunits == 'meters':
01661             if dist > 2500.0:
01662                 outunits = 'km'
01663                 divisor = 1000.0
01664             else: outunits = 'm'
01665         elif mapunits == 'feet':
01666             # nano-bug: we match any "feet", but US Survey feet is really
01667             #  5279.9894 per statute mile, or 10.6' per 1000 miles. As >1000
01668             #  miles the tick markers are rounded to the nearest 10th of a
01669             #  mile (528'), the difference in foot flavours is ignored.
01670             if dist > 5280.0:
01671                 outunits = 'miles'
01672                 divisor = 5280.0
01673             else:
01674                 outunits = 'ft'
01675         elif 'degree' in mapunits and \
01676                 not haveCtypes:
01677             if dist < 1:
01678                 outunits = 'min'
01679                 divisor = (1/60.0)
01680             else:
01681                 outunits = 'deg'
01682         else:
01683             outunits = 'meters'
01684         
01685         # format numbers in a nice way
01686         if (dist/divisor) >= 2500.0:
01687             outdist = round(dist/divisor)
01688         elif (dist/divisor) >= 1000.0:
01689             outdist = round(dist/divisor,1)
01690         elif (dist/divisor) > 0.0:
01691             outdist = round(dist/divisor,int(math.ceil(3-math.log10(dist/divisor))))
01692         else:
01693             outdist = float(dist/divisor)
01694         
01695         return (outdist, outunits)
01696     
01697     def Histogram(self, event):
01698         """!Init histogram display canvas and tools
01699         """
01700         self.histogram = histogram.HistFrame(self,
01701                                              id = wx.ID_ANY, size = globalvar.HIST_WINDOW_SIZE,
01702                                              style = wx.DEFAULT_FRAME_STYLE)
01703 
01704         #show new display
01705         self.histogram.Show()
01706         self.histogram.Refresh()
01707         self.histogram.Update()
01708 
01709 
01710     def OnDecoration(self, event):
01711         """!Decorations overlay menu
01712         """
01713         point = wx.GetMousePosition()
01714         decmenu = wx.Menu()
01715         icons = Icons['displayWindow']
01716         
01717         # Add items to the menu
01718         AddScale = wx.MenuItem(decmenu, wx.ID_ANY, icons["addBarscale"].GetLabel())
01719         AddScale.SetBitmap(icons["addBarscale"].GetBitmap(self.iconsize))
01720         decmenu.AppendItem(AddScale)
01721         self.Bind(wx.EVT_MENU, self.OnAddBarscale, AddScale)
01722         
01723         AddLegend = wx.MenuItem(decmenu, wx.ID_ANY, icons["addLegend"].GetLabel())
01724         AddLegend.SetBitmap(icons["addLegend"].GetBitmap(self.iconsize))
01725         decmenu.AppendItem(AddLegend)
01726         self.Bind(wx.EVT_MENU, self.OnAddLegend, AddLegend)
01727         
01728         AddText = wx.MenuItem(decmenu, wx.ID_ANY, icons["addText"].GetLabel())
01729         AddText.SetBitmap(icons["addText"].GetBitmap(self.iconsize))
01730         decmenu.AppendItem(AddText)
01731         self.Bind(wx.EVT_MENU, self.OnAddText, AddText)
01732         
01733         # Popup the menu.  If an item is selected then its handler
01734         # will be called before PopupMenu returns.
01735         self.PopupMenu(decmenu)
01736         decmenu.Destroy()
01737         
01738     def OnAddBarscale(self, event):
01739         """!Handler for scale/arrow map decoration menu selection.
01740         """
01741         if self.dialogs['barscale']:
01742             return
01743         
01744         id = 0 # unique index for overlay layer
01745 
01746         # If location is latlon, only display north arrow (scale won't work)
01747         #        proj = self.Map.projinfo['proj']
01748         #        if proj == 'll':
01749         #            barcmd = 'd.barscale -n'
01750         #        else:
01751         #            barcmd = 'd.barscale'
01752 
01753         # decoration overlay control dialog
01754         self.dialogs['barscale'] = \
01755             gdialogs.DecorationDialog(parent = self, title = _('Scale and North arrow'),
01756                                       size = (350, 200),
01757                                       style = wx.DEFAULT_DIALOG_STYLE | wx.CENTRE,
01758                                       cmd = ['d.barscale', 'at=0,5'],
01759                                       ovlId = id,
01760                                       name = 'barscale',
01761                                       checktxt = _("Show/hide scale and North arrow"),
01762                                       ctrltxt = _("scale object"))
01763 
01764         self.dialogs['barscale'].CentreOnParent()
01765         ### dialog cannot be show as modal - in the result d.barscale is not selectable
01766         ### self.dialogs['barscale'].ShowModal()
01767         self.dialogs['barscale'].Show()
01768         self.MapWindow.mouse['use'] = 'pointer'        
01769 
01770     def OnAddLegend(self, event):
01771         """!Handler for legend map decoration menu selection.
01772         """
01773         if self.dialogs['legend']:
01774             return
01775         
01776         id = 1 # index for overlay layer in render
01777 
01778         cmd = ['d.legend', 'at=5,50,2,5']
01779         if self.tree.layer_selected and \
01780                 self.tree.GetPyData(self.tree.layer_selected)[0]['type'] == 'raster':
01781             cmd.append('map=%s' % self.tree.GetPyData(self.tree.layer_selected)[0]['maplayer'].name)
01782 
01783         # Decoration overlay control dialog
01784         self.dialogs['legend'] = \
01785             gdialogs.DecorationDialog(parent = self, title = ('Legend'),
01786                                       size = (350, 200),
01787                                       style = wx.DEFAULT_DIALOG_STYLE | wx.CENTRE,
01788                                       cmd = cmd,
01789                                       ovlId = id,
01790                                       name = 'legend',
01791                                       checktxt = _("Show/hide legend"),
01792                                       ctrltxt = _("legend object")) 
01793 
01794         self.dialogs['legend'].CentreOnParent() 
01795         ### dialog cannot be show as modal - in the result d.legend is not selectable
01796         ### self.dialogs['legend'].ShowModal()
01797         self.dialogs['legend'].Show()
01798         self.MapWindow.mouse['use'] = 'pointer'
01799 
01800     def OnAddText(self, event):
01801         """!Handler for text decoration menu selection.
01802         """
01803         if self.MapWindow.dragid > -1:
01804             id = self.MapWindow.dragid
01805         else:
01806             # index for overlay layer in render
01807             if len(self.MapWindow.textdict.keys()) > 0:
01808                 id = self.MapWindow.textdict.keys()[-1] + 1
01809             else:
01810                 id = 101
01811 
01812         self.dialogs['text'] = gdialogs.TextLayerDialog(parent = self, ovlId = id, 
01813                                                         title = _('Add text layer'),
01814                                                         size = (400, 200))
01815         self.dialogs['text'].CenterOnParent()
01816 
01817         # If OK button pressed in decoration control dialog
01818         if self.dialogs['text'].ShowModal() == wx.ID_OK:
01819             text = self.dialogs['text'].GetValues()['text']
01820             active = self.dialogs['text'].GetValues()['active']
01821             coords, w, h = self.MapWindow.TextBounds(self.dialogs['text'].GetValues())
01822         
01823             # delete object if it has no text or is not active
01824             if text == '' or active == False:
01825                 try:
01826                     self.MapWindow.pdc.ClearId(id)
01827                     self.MapWindow.pdc.RemoveId(id)
01828                     del self.MapWindow.textdict[id]
01829                 except:
01830                     pass
01831                 return
01832 
01833             self.MapWindow.pdc.ClearId(id)
01834             self.MapWindow.pdc.SetId(id)
01835             self.MapWindow.textdict[id] = self.dialogs['text'].GetValues()
01836             
01837             self.MapWindow.Draw(self.MapWindow.pdcDec, img = self.MapWindow.textdict[id],
01838                                 drawid = id, pdctype = 'text', coords = coords)
01839             
01840             self.MapWindow.UpdateMap(render = False, renderVector = False)
01841             
01842         self.MapWindow.mouse['use'] = 'pointer'
01843 
01844     def GetOptData(self, dcmd, type, params, propwin):
01845         """!Callback method for decoration overlay command generated by
01846         dialog created in menuform.py
01847         """
01848         # Reset comand and rendering options in render.Map. Always render decoration.
01849         # Showing/hiding handled by PseudoDC
01850         self.Map.ChangeOverlay(ovltype = type, type = 'overlay', name = '', command = dcmd,
01851                                l_active = True, l_render = False)
01852         self.params[type] = params
01853         self.propwin[type] = propwin
01854 
01855     def OnZoomToMap(self, event):
01856         """!Set display extents to match selected raster (including
01857         NULLs) or vector map.
01858         """
01859         self.MapWindow.ZoomToMap()
01860 
01861     def OnZoomToRaster(self, event):
01862         """!Set display extents to match selected raster map (ignore NULLs)
01863         """
01864         self.MapWindow.ZoomToMap(ignoreNulls = True)
01865 
01866     def OnZoomToWind(self, event):
01867         """!Set display geometry to match computational region
01868         settings (set with g.region)
01869         """
01870         self.MapWindow.ZoomToWind()
01871         
01872     def OnZoomToDefault(self, event):
01873         """!Set display geometry to match default region settings
01874         """
01875         self.MapWindow.ZoomToDefault()
01876         
01877     def OnZoomToSaved(self, event):
01878         """!Set display geometry to match extents in
01879         saved region file
01880         """
01881         self.MapWindow.ZoomToSaved()
01882         
01883     def OnDisplayToWind(self, event):
01884         """!Set computational region (WIND file) to match display
01885         extents
01886         """
01887         self.MapWindow.DisplayToWind()
01888  
01889     def SaveDisplayRegion(self, event):
01890         """!Save display extents to named region file.
01891         """
01892         self.MapWindow.SaveDisplayRegion()
01893         
01894     def OnZoomMenu(self, event):
01895         """!Popup Zoom menu
01896         """
01897         point = wx.GetMousePosition()
01898         zoommenu = wx.Menu()
01899         # Add items to the menu
01900 
01901         zoomwind = wx.MenuItem(zoommenu, wx.ID_ANY, _('Zoom to computational region (set with g.region)'))
01902         zoommenu.AppendItem(zoomwind)
01903         self.Bind(wx.EVT_MENU, self.OnZoomToWind, zoomwind)
01904 
01905         zoomdefault = wx.MenuItem(zoommenu, wx.ID_ANY, _('Zoom to default region'))
01906         zoommenu.AppendItem(zoomdefault)
01907         self.Bind(wx.EVT_MENU, self.OnZoomToDefault, zoomdefault)
01908 
01909         zoomsaved = wx.MenuItem(zoommenu, wx.ID_ANY, _('Zoom to saved region'))
01910         zoommenu.AppendItem(zoomsaved)
01911         self.Bind(wx.EVT_MENU, self.OnZoomToSaved, zoomsaved)
01912 
01913         savewind = wx.MenuItem(zoommenu, wx.ID_ANY, _('Set computational region from display extent'))
01914         zoommenu.AppendItem(savewind)
01915         self.Bind(wx.EVT_MENU, self.OnDisplayToWind, savewind)
01916 
01917         savezoom = wx.MenuItem(zoommenu, wx.ID_ANY, _('Save display geometry to named region'))
01918         zoommenu.AppendItem(savezoom)
01919         self.Bind(wx.EVT_MENU, self.SaveDisplayRegion, savezoom)
01920 
01921         # Popup the menu. If an item is selected then its handler
01922         # will be called before PopupMenu returns.
01923         self.PopupMenu(zoommenu)
01924         zoommenu.Destroy()
01925         
01926     def SetProperties(self, render = False, mode = 0, showCompExtent = False,
01927                       constrainRes = False, projection = False):
01928         """!Set properies of map display window"""
01929         self.statusbarWin['render'].SetValue(render)
01930         self.statusbarWin['toggle'].SetSelection(mode)
01931         self.StatusbarUpdate()
01932         self.statusbarWin['region'].SetValue(showCompExtent)
01933         self.statusbarWin['resolution'].SetValue(constrainRes)
01934         self.statusbarWin['projection'].SetValue(projection)
01935         if showCompExtent:
01936             self.MapWindow.regionCoords = []
01937         
01938     def IsStandalone(self):
01939         """!Check if Map display is standalone"""
01940         if self._layerManager:
01941             return False
01942         
01943         return True
01944     
01945     def GetLayerManager(self):
01946         """!Get reference to Layer Manager
01947 
01948         @return window reference
01949         @return None (if standalone)
01950         """
01951         return self._layerManager
01952     
01953 # end of class MapFrame
01954 
01955 class MapApp(wx.App):
01956     def OnInit(self):
01957         wx.InitAllImageHandlers()
01958         if __name__ == "__main__":
01959             Map = render.Map() # instance of Map class to render GRASS display output to PPM file
01960         else:
01961             Map = None
01962 
01963         self.mapFrm = MapFrame(parent = None, id = wx.ID_ANY, Map = Map,
01964                                size = globalvar.MAP_WINDOW_SIZE)
01965         #self.SetTopWindow(Map)
01966         self.mapFrm.Show()
01967 
01968         if __name__ == "__main__":
01969             # redraw map, if new command appears
01970             self.redraw = False
01971             status = Command(self, Map, cmdfilename)
01972             status.start()
01973             self.timer = wx.PyTimer(self.watcher)
01974             # check each 0.1s
01975             self.timer.Start(100)
01976 
01977         return 1
01978 
01979     def OnExit(self):
01980         if __name__ == "__main__":
01981             # stop the timer
01982             self.timer.Stop()
01983             # terminate thread (a bit ugly)
01984             os.system("""!echo "quit" >> %s""" % (cmdfilename))
01985 
01986     def watcher(self):
01987         """!Redraw, if new layer appears"""
01988         if self.redraw:
01989             self.mapFrm.OnDraw(None)
01990         self.redraw = False
01991         return
01992 # end of class MapApp
01993 
01994 if __name__ == "__main__":
01995 
01996     ###### SET command variable
01997     if len(sys.argv) != 3:
01998         print __doc__
01999         sys.exit()
02000 
02001     title = sys.argv[1]
02002     cmdfilename = sys.argv[2]
02003 
02004     import gettext
02005     gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode = True)
02006 
02007     print >> sys.stderr, "\nStarting monitor <%s>...\n" % (title)
02008 
02009     gm_map = MapApp(0)
02010     # set title
02011     gm_map.mapFrm.SetTitle(_("GRASS GIS Map Display: " +
02012                              title + 
02013                              " - Location: " + grass.gisenv()["LOCATION_NAME"]))
02014     
02015     gm_map.MainLoop()
02016 
02017     if grass.gisenv().has_key("MONITOR"):
02018         os.system("d.mon sel=%s" % grass.gisenv()["MONITOR"])
02019 
02020     os.remove(cmdfilename)
02021     os.system("""!g.gisenv set="GRASS_PYCMDFILE" """)
02022 
02023     print >> sys.stderr, "\nStoping monitor <%s>...\n" % (title)
02024 
02025     sys.exit(0)
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines