GRASS Programmer's Manual  6.5.svn(2012)-r51648
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
statusbar.py
Go to the documentation of this file.
00001 """!
00002 @package mapdisp.statusbar
00003 
00004 @brief Classes for statusbar management
00005 
00006 Classes:
00007  - statusbar::SbException
00008  - statusbar::SbManager
00009  - statusbar::SbItem
00010  - statusbar::SbRender
00011  - statusbar::SbShowRegion
00012  - statusbar::SbAlignExtent
00013  - statusbar::SbResolution
00014  - statusbar::SbMapScale
00015  - statusbar::SbGoTo
00016  - statusbar::SbProjection
00017  - statusbar::SbMask
00018  - statusbar::SbTextItem
00019  - statusbar::SbDisplayGeometry
00020  - statusbar::SbCoordinates
00021  - statusbar::SbRegionExtent
00022  - statusbar::SbCompRegionExtent
00023  - statusbar::SbProgress
00024 
00025 (C) 2006-2011 by the GRASS Development Team
00026 
00027 This program is free software under the GNU General Public License
00028 (>=v2). Read the file COPYING that comes with GRASS for details.
00029 
00030 @author Vaclav Petras <wenzeslaus gmail.com>
00031 @author Anna Kratochvilova <kratochanna gmail.com>
00032 """
00033 
00034 import wx
00035 
00036 from core          import utils
00037 from core.gcmd     import GMessage, RunCommand
00038 from core.settings import UserSettings
00039 
00040 from grass.script  import core as grass
00041 
00042 class SbException:
00043     """! Exception class used in SbManager and SbItems"""
00044     def __init__(self, message):
00045         self.message = message
00046     def __str__(self):
00047         return self.message
00048 
00049 
00050 class SbManager:
00051     """!Statusbar manager for wx.Statusbar and SbItems.
00052     
00053     Statusbar manager manages items added by AddStatusbarItem method.
00054     Provides progress bar (SbProgress) and choice (wx.Choice).
00055     Items with position 0 are shown according to choice selection.
00056     Only one item of the same class is supposed to be in statusbar.
00057     Manager user have to create statusbar on his own, add items to manager
00058     and call Update method to show particular widgets.
00059     User settings (group = 'display', key = 'statusbarMode', subkey = 'selection')
00060     are taken into account.
00061     
00062     @todo generalize access to UserSettings (specify group, etc.) 
00063     @todo add GetMode method using name instead of index
00064     """
00065     def __init__(self, mapframe, statusbar):
00066         """!Connects manager to statusbar
00067         
00068         Creates choice and progress bar.
00069         """
00070         self.mapFrame = mapframe
00071         self.statusbar = statusbar
00072         
00073         self.choice = wx.Choice(self.statusbar, wx.ID_ANY)
00074         
00075         self.choice.Bind(wx.EVT_CHOICE, self.OnToggleStatus)
00076         
00077         self.statusbarItems = dict()
00078         
00079         self._postInitialized = False
00080         
00081         self.progressbar = SbProgress(self.mapFrame, self.statusbar)
00082         
00083         self._hiddenItems = {}
00084     
00085     def SetProperty(self, name, value):
00086         """!Sets property represented by one of contained SbItems
00087             
00088         @param name name of SbItem (from name attribute)
00089         @param value value to be set
00090         """
00091         self.statusbarItems[name].SetValue(value)
00092         
00093     def GetProperty(self, name):
00094         """!Returns property represented by one of contained SbItems
00095         
00096         @param name name of SbItem (from name attribute)
00097         """
00098         return self.statusbarItems[name].GetValue()
00099         
00100     def HasProperty(self, name):
00101         """!Checks whether property is represented by one of contained SbItems
00102         
00103         @param name name of SbItem (from name attribute)
00104         
00105         @returns True if particular SbItem is contained, False otherwise
00106         """
00107         if name in self.statusbarItems:
00108             return True
00109         return False
00110     
00111     def AddStatusbarItem(self, item):
00112         """!Adds item to statusbar
00113         
00114         If item position is 0, item is managed by choice.
00115         
00116         @see AddStatusbarItemsByClass
00117         """
00118         self.statusbarItems[item.name] = item
00119         if item.GetPosition() == 0:
00120             self.choice.Append(item.label, clientData = item) #attrError?
00121             
00122     def AddStatusbarItemsByClass(self, itemClasses, **kwargs):
00123         """!Adds items to statusbar
00124 
00125         @param itemClasses list of classes of items to be add
00126         @param kwargs SbItem constructor parameters
00127         
00128         @see AddStatusbarItem
00129         """
00130         for Item in itemClasses:
00131             item = Item(**kwargs)
00132             self.AddStatusbarItem(item)
00133                       
00134     def HideStatusbarChoiceItemsByClass(self, itemClasses):
00135         """!Hides items showed in choice
00136         
00137         Hides items with position 0 (items showed in choice) by removing
00138         them from choice.
00139         
00140         @param itemClasses list of classes of items to be hided
00141         
00142         @see ShowStatusbarChoiceItemsByClass
00143         @todo consider adding similar function which would take item names
00144         """
00145         index = []
00146         for itemClass in itemClasses:
00147             for i in range(0, self.choice.GetCount() - 1):
00148                 item = self.choice.GetClientData(i)
00149                 if item.__class__ == itemClass:
00150                     index.append(i)
00151                     self._hiddenItems[i] = item
00152         # must be sorted in reverse order to be removed correctly
00153         for i in sorted(index, reverse = True):
00154             self.choice.Delete(i)
00155         
00156     def ShowStatusbarChoiceItemsByClass(self, itemClasses):
00157         """!Shows items showed in choice
00158         
00159         Shows items with position 0 (items showed in choice) by adding
00160         them to choice.
00161         Items are restored in their old positions.
00162         
00163         @param itemClasses list of classes of items to be showed
00164         
00165         @see HideStatusbarChoiceItemsByClass
00166         """
00167         # must be sorted to be inserted correctly
00168         for pos in sorted(self._hiddenItems.keys()):
00169             item = self._hiddenItems[pos]
00170             if item.__class__ in itemClasses:
00171                 self.choice.Insert(item.label, pos, item)
00172         
00173     def ShowItem(self, itemName):
00174         """!Invokes showing of particular item
00175         
00176         @see Update
00177         """
00178         self.statusbarItems[itemName].Show()
00179         
00180     def _postInit(self):
00181         """!Post-initialization method
00182         
00183         It sets internal user settings,
00184         set choice's selection (from user settings) and does reposition.
00185         It needs choice filled by items.
00186         it is called automatically.
00187         """
00188         UserSettings.Set(group = 'display',
00189                          key = 'statusbarMode',
00190                          subkey = 'choices',
00191                          value = self.choice.GetItems(),
00192                          internal = True)
00193         
00194         self.choice.SetSelection(UserSettings.Get(group = 'display',
00195                                                   key = 'statusbarMode',
00196                                                   subkey = 'selection')) 
00197         self.Reposition()
00198         
00199         self._postInitialized = True
00200         
00201     def Update(self):
00202         """!Updates statusbar
00203 
00204         It always updates mask.
00205         """
00206         if not self._postInitialized:
00207             self._postInit()
00208         
00209         for item in self.statusbarItems.values():
00210             if item.GetPosition() == 0:
00211                 item.Hide()
00212             else:
00213                 item.Update() # mask, render
00214         
00215         if self.choice.GetCount() > 0:
00216             item = self.choice.GetClientData(self.choice.GetSelection())
00217             item.Update()
00218         
00219     def Reposition(self):
00220         """!Reposition items in statusbar
00221         
00222         Set positions to all items managed by statusbar manager.
00223         It should not be necessary to call it manually.
00224         """
00225         
00226         widgets = []
00227         for item in self.statusbarItems.values():
00228             widgets.append((item.GetPosition(), item.GetWidget()))
00229             
00230         widgets.append((1, self.choice))
00231         widgets.append((0, self.progressbar.GetWidget()))
00232                 
00233         for idx, win in widgets:
00234             if not win:
00235                 continue
00236             rect = self.statusbar.GetFieldRect(idx)
00237             if idx == 0: # show region / mapscale / process bar
00238                 # -> size
00239                 wWin, hWin = win.GetBestSize()
00240                 if win == self.progressbar.GetWidget():
00241                     wWin = rect.width - 6
00242                 # -> position
00243                 # if win == self.statusbarWin['region']:
00244                 # x, y = rect.x + rect.width - wWin, rect.y - 1
00245                 # align left
00246                 # else:
00247                 x, y = rect.x + 3, rect.y - 1
00248                 w, h = wWin, rect.height + 2
00249             else: # choice || auto-rendering
00250                 x, y = rect.x, rect.y - 1
00251                 w, h = rect.width, rect.height + 2
00252                 if idx == 2: # mask
00253                     x += 5
00254                     y += 4
00255                 elif idx == 3: # render
00256                     x += 5
00257             win.SetPosition((x, y))
00258             win.SetSize((w, h))
00259         
00260     def GetProgressBar(self):
00261         """!Returns progress bar"""
00262         return self.progressbar
00263     
00264     def OnToggleStatus(self, event):
00265         """!Toggle status text
00266         """
00267         self.Update()
00268         
00269     def SetMode(self, modeIndex):
00270         """!Sets current mode
00271         
00272         Mode is usually driven by user through choice.
00273         """
00274         self.choice.SetSelection(modeIndex)
00275     
00276     def GetMode(self):
00277         """!Returns current mode"""
00278         return self.choice.GetSelection()
00279 
00280 class SbItem:
00281     """!Base class for statusbar items.
00282     
00283     Each item represents functionality (or action) controlled by statusbar
00284     and related to MapFrame.
00285     One item is usually connected with one widget but it is not necessary.
00286     Item can represent property (depends on manager).
00287     Items are not widgets but can provide interface to them.
00288     Items usually has requirements to MapFrame instance
00289     (specified as MapFrame.methodname or MapWindow.methodname).
00290     
00291     @todo consider externalizing position (see SbProgress use in SbManager)
00292     """
00293     def __init__(self, mapframe, statusbar, position = 0):
00294         """!
00295         
00296         @param mapframe instance of class with MapFrame interface
00297         @param statusbar statusbar instance (wx.Statusbar)
00298         @param position item position in statusbar
00299         
00300         @todo rewrite Update also in derived classes to take in account item position
00301         """
00302         self.mapFrame = mapframe
00303         self.statusbar = statusbar
00304         self.position = position
00305     
00306     def Show(self):
00307         """!Invokes showing of underlying widget.
00308         
00309         In derived classes it can do what is appropriate for it,
00310         e.g. showing text on statusbar (only).
00311         """
00312         self.widget.Show()
00313         
00314     def Hide(self):
00315         self.widget.Hide()
00316         
00317     def SetValue(self, value):
00318         self.widget.SetValue(value)
00319     
00320     def GetValue(self):
00321         return self.widget.GetValue()
00322         
00323     def GetPosition(self):
00324         return self.position
00325     
00326     def GetWidget(self):
00327         """!Returns underlaying winget.
00328         
00329         @return widget or None if doesn't exist
00330         """
00331         return self.widget
00332     
00333     def _update(self, longHelp):
00334         """!Default implementation for Update method.
00335         
00336         @param longHelp True to enable long help (help from toolbars)
00337         """
00338         self.statusbar.SetStatusText("", 0)
00339         self.Show()
00340         self.mapFrame.StatusbarEnableLongHelp(longHelp)
00341         
00342     def Update(self):
00343         """!Called when statusbar action is activated (e.g. through wx.Choice).
00344         """
00345         self._update(longHelp = False)
00346 
00347 class SbRender(SbItem):
00348     """!Checkbox to enable and disable auto-rendering.
00349     
00350     Requires MapFrame.OnRender method.
00351     """
00352     def __init__(self, mapframe, statusbar, position = 0):
00353         SbItem.__init__(self, mapframe, statusbar, position)
00354         self.name = 'render'
00355         
00356         self.widget = wx.CheckBox(parent = self.statusbar, id = wx.ID_ANY,
00357                                   label = _("Render"))
00358         
00359         self.widget.SetValue(UserSettings.Get(group = 'display',
00360                                               key = 'autoRendering',
00361                                               subkey = 'enabled'))
00362         self.widget.Hide()
00363         self.widget.SetToolTip(wx.ToolTip (_("Enable/disable auto-rendering")))
00364                                             
00365         self.widget.Bind(wx.EVT_CHECKBOX, self.OnToggleRender)
00366         
00367     def OnToggleRender(self, event):
00368         # (other items should call self.mapFrame.IsAutoRendered())
00369         if self.GetValue():
00370             self.mapFrame.OnRender(None)
00371 
00372     def Update(self):
00373         self.Show()
00374         
00375 class SbShowRegion(SbItem):
00376     """!Checkbox to enable and disable showing of computational region.
00377     
00378     Requires MapFrame.OnRender, MapFrame.IsAutoRendered, MapFrame.GetWindow.
00379     Expects that instance returned by MapFrame.GetWindow will handle
00380     regionCoords attribute. 
00381     """
00382     def __init__(self, mapframe, statusbar, position = 0):
00383         SbItem.__init__(self, mapframe, statusbar, position)
00384         self.name = 'region'
00385         self.label = _("Show comp. extent")
00386         
00387         self.widget = wx.CheckBox(parent = self.statusbar, id = wx.ID_ANY,
00388                                   label = _("Show computational extent"))
00389         
00390         self.widget.SetValue(False)
00391         self.widget.Hide()
00392         self.widget.SetToolTip(wx.ToolTip (_("Show/hide computational "
00393                                              "region extent (set with g.region). "
00394                                              "Display region drawn as a blue box inside the "
00395                                              "computational region, "
00396                                              "computational region inside a display region "
00397                                              "as a red box).")))
00398                                             
00399         self.widget.Bind(wx.EVT_CHECKBOX, self.OnToggleShowRegion)
00400     
00401     def OnToggleShowRegion(self, event):
00402         """!Shows/Hides extent (comp. region) in map canvas.
00403         
00404         Shows or hides according to checkbox value.
00405         """
00406         if self.widget.GetValue():
00407             # show extent
00408             self.mapFrame.GetWindow().regionCoords = []
00409         elif hasattr(self.mapFrame.GetWindow(), 'regionCoords'):
00410             del self.mapFrame.GetWindow().regionCoords
00411 
00412         # redraw map if auto-rendering is enabled
00413         if self.mapFrame.IsAutoRendered():
00414             self.mapFrame.OnRender(None)
00415 
00416     def SetValue(self, value):
00417         SbItem.SetValue(self, value)
00418         if value:
00419             self.mapFrame.GetWindow().regionCoords = []
00420         elif hasattr(self.mapFrame.GetWindow(), 'regionCoords'):
00421             del self.mapFrame.GetWindow().regionCoords
00422             
00423 class SbAlignExtent(SbItem):
00424     """!Checkbox to select zoom behavior.
00425     
00426     Used by BufferedWindow (through MapFrame property).
00427     See tooltip for explanation.
00428     """
00429     def __init__(self, mapframe, statusbar, position = 0):
00430         SbItem.__init__(self, mapframe, statusbar, position)
00431         self.name = 'alignExtent'
00432         self.label = _("Display mode")
00433         
00434         self.widget = wx.CheckBox(parent = self.statusbar, id = wx.ID_ANY,
00435                                   label = _("Align region extent based on display size"))
00436         
00437         self.widget.SetValue(UserSettings.Get(group = 'display', key = 'alignExtent', subkey = 'enabled'))
00438         self.widget.Hide()
00439         self.widget.SetToolTip(wx.ToolTip (_("Align region extent based on display "
00440                                              "size from center point. "
00441                                              "Default value for new map displays can "
00442                                              "be set up in 'User GUI settings' dialog.")))      
00443         
00444 class SbResolution(SbItem):
00445     """!Checkbox to select used display resolution.
00446     
00447     Requires MapFrame.OnRender method. 
00448     """
00449     def __init__(self, mapframe, statusbar, position = 0):
00450         SbItem.__init__(self, mapframe, statusbar, position)
00451         self.name = 'resolution'
00452         self.label = _("Display resolution")
00453         
00454         self.widget = wx.CheckBox(parent = self.statusbar, id = wx.ID_ANY,
00455                                   label = _("Constrain display resolution to computational settings"))
00456         
00457         self.widget.SetValue(UserSettings.Get(group = 'display', key = 'compResolution', subkey = 'enabled'))
00458         self.widget.Hide()
00459         self.widget.SetToolTip(wx.ToolTip (_("Constrain display resolution "
00460                                              "to computational region settings. "
00461                                              "Default value for new map displays can "
00462                                              "be set up in 'User GUI settings' dialog.")))
00463                                             
00464         self.widget.Bind(wx.EVT_CHECKBOX, self.OnToggleUpdateMap)
00465         
00466     def OnToggleUpdateMap(self, event):
00467         """!Update display when toggle display mode
00468         """
00469         # redraw map if auto-rendering is enabled
00470         if self.mapFrame.IsAutoRendered():
00471             self.mapFrame.OnRender(None)
00472 
00473 
00474 class SbMapScale(SbItem):
00475     """!Editable combobox to get/set current map scale.
00476     
00477     Requires MapFrame.GetMapScale, MapFrame.SetMapScale
00478     and MapFrame.GetWindow (and GetWindow().UpdateMap()).
00479     """
00480     def __init__(self, mapframe, statusbar, position = 0):
00481         SbItem.__init__(self, mapframe, statusbar, position)
00482         self.name = 'mapscale'
00483         self.label = _("Map scale")
00484         
00485         self.widget = wx.ComboBox(parent = self.statusbar, id = wx.ID_ANY,
00486                                                     style = wx.TE_PROCESS_ENTER,
00487                                                     size = (150, -1))
00488         
00489         self.widget.SetItems(['1:1000',
00490                               '1:5000',
00491                               '1:10000',
00492                               '1:25000',
00493                               '1:50000',
00494                               '1:100000',
00495                               '1:1000000'])
00496         self.widget.Hide()
00497         self.widget.SetToolTip(wx.ToolTip (_("As everyone's monitors and resolutions "
00498                                             "are set differently these values are not "
00499                                             "true map scales, but should get you into "
00500                                             "the right neighborhood.")))
00501                                             
00502         self.widget.Bind(wx.EVT_TEXT_ENTER, self.OnChangeMapScale)
00503         self.widget.Bind(wx.EVT_COMBOBOX, self.OnChangeMapScale)
00504         
00505         self.lastMapScale = None
00506 
00507     def Update(self):
00508         scale = self.mapFrame.GetMapScale()
00509         self.statusbar.SetStatusText("")
00510         try:
00511             self.SetValue("1:%ld" % (scale + 0.5))
00512         except TypeError:
00513             pass # FIXME, why this should happen?
00514         
00515         self.lastMapScale = scale
00516         self.Show()
00517 
00518         # disable long help
00519         self.mapFrame.StatusbarEnableLongHelp(False)
00520 
00521     def OnChangeMapScale(self, event):
00522         """!Map scale changed by user
00523         """
00524         scale = event.GetString()
00525 
00526         try:
00527             if scale[:2] != '1:':
00528                 raise ValueError
00529             value = int(scale[2:])
00530         except ValueError:
00531             self.SetValue('1:%ld' % int(self.lastMapScale))
00532             return
00533         
00534         self.mapFrame.SetMapScale(value)
00535         
00536         # redraw a map
00537         self.mapFrame.GetWindow().UpdateMap()
00538         self.GetWidget().SetFocus()
00539         
00540         
00541 class SbGoTo(SbItem):
00542     """!Textctrl to set coordinates which to focus on.
00543     
00544     Requires MapFrame.GetWindow, MapWindow.GoTo method.
00545     """
00546     
00547     def __init__(self, mapframe, statusbar, position = 0):
00548         SbItem.__init__(self, mapframe, statusbar, position)
00549         self.name = 'goto'
00550         self.label = _("Go to")
00551         
00552         self.widget = wx.TextCtrl(parent = self.statusbar, id = wx.ID_ANY,
00553                                                 value = "", style = wx.TE_PROCESS_ENTER,
00554                                                 size = (300, -1))
00555         
00556         self.widget.Hide()
00557         
00558         self.widget.Bind(wx.EVT_TEXT_ENTER, self.OnGoTo)
00559     
00560     def ReprojectENToMap(self, e, n, useDefinedProjection):
00561         """!Reproject east, north from user defined projection
00562         
00563         @param e,n coordinate (for DMS string, else float or string)
00564         @param useDefinedProjection projection defined by user in settings dialog
00565         
00566         @throws SbException if useDefinedProjection is True and projection is not defined in UserSettings
00567         """
00568         if useDefinedProjection:
00569             settings = UserSettings.Get(group = 'projection', key = 'statusbar', subkey = 'proj4')
00570             if not settings:
00571                 raise SbException(_("Projection not defined (check the settings)"))
00572             else:
00573                 # reproject values
00574                 projIn = settings
00575                 projOut = RunCommand('g.proj',
00576                                      flags = 'jf',
00577                                      read = True)
00578                 proj = projIn.split(' ')[0].split('=')[1]
00579                 if proj in ('ll', 'latlong', 'longlat'):
00580                     e, n = utils.DMS2Deg(e, n)
00581                     proj, coord1 = utils.ReprojectCoordinates(coord = (e, n),
00582                                                               projIn = projIn,
00583                                                               projOut = projOut, flags = 'd')
00584                     e, n = coord1
00585                 else:
00586                     e, n = float(e), float(n)
00587                     proj, coord1 = utils.ReprojectCoordinates(coord = (e, n),
00588                                                               projIn = projIn,
00589                                                               projOut = projOut, flags = 'd')
00590                     e, n = coord1
00591         elif self.mapFrame.GetMap().projinfo['proj'] == 'll':
00592             e, n = utils.DMS2Deg(e, n)
00593         else: 
00594             e, n = float(e), float(n)
00595         return e, n
00596 
00597     def OnGoTo(self, event):
00598         """!Go to position
00599         """
00600         try:
00601             e, n = self.GetValue().split(';')
00602             e, n = self.ReprojectENToMap(e, n, self.mapFrame.GetProperty('projection'))
00603             self.mapFrame.GetWindow().GoTo(e, n)
00604             self.widget.SetFocus()
00605         except ValueError:
00606             # FIXME: move this code to MapWindow/BufferedWindow/MapFrame
00607             region = self.mapFrame.GetMap().GetCurrentRegion()
00608             precision = int(UserSettings.Get(group = 'projection', key = 'format',
00609                                              subkey = 'precision'))
00610             format = UserSettings.Get(group = 'projection', key = 'format',
00611                                       subkey = 'll')
00612             if self.mapFrame.GetMap().projinfo['proj'] == 'll' and format == 'DMS':
00613                     self.SetValue("%s" % utils.Deg2DMS(region['center_easting'], 
00614                                                                             region['center_northing'],
00615                                                                             precision = precision))
00616             else:
00617                 self.SetValue("%.*f; %.*f" % \
00618                                (precision, region['center_easting'],
00619                                 precision, region['center_northing']))
00620         except SbException, e:
00621             # FIXME: this may be useless since statusbar update checks user defined projection and this exception raises when user def proj does not exists
00622             self.statusbar.SetStatusText(str(e), 0)
00623 
00624     def GetCenterString(self, map):
00625         """!Get current map center in appropriate format"""
00626         region = map.GetCurrentRegion()
00627         precision = int(UserSettings.Get(group = 'projection', key = 'format',
00628                                          subkey = 'precision'))
00629         format = UserSettings.Get(group = 'projection', key = 'format',
00630                                   subkey = 'll')
00631         projection = UserSettings.Get(group='projection', key='statusbar', subkey='proj4')
00632         
00633         if self.mapFrame.GetProperty('projection'):
00634             if not projection:
00635                 raise SbException(_("Projection not defined (check the settings)"))
00636             else:
00637                 proj, coord  = utils.ReprojectCoordinates(coord = (region['center_easting'],
00638                                                                    region['center_northing']),
00639                                                           projOut = projection,
00640                                                           flags = 'd')
00641                 if coord:
00642                     if proj in ('ll', 'latlong', 'longlat') and format == 'DMS':
00643                         return "%s" % utils.Deg2DMS(coord[0],
00644                                                                                 coord[1],
00645                                                                                 precision = precision)
00646                     else:
00647                         return "%.*f; %.*f" % (precision, coord[0], precision, coord[1])
00648                 else:
00649                     raise SbException(_("Error in projection (check the settings)"))
00650         else:
00651             if self.mapFrame.GetMap().projinfo['proj'] == 'll' and format == 'DMS':
00652                 return "%s" % utils.Deg2DMS(region['center_easting'], region['center_northing'],
00653                                                                       precision = precision)
00654             else:
00655                 return "%.*f; %.*f" % (precision, region['center_easting'], precision, region['center_northing'])
00656 
00657 
00658     def SetCenter(self):
00659         """!Set current map center as item value"""
00660         center = self.GetCenterString(self.mapFrame.GetMap())
00661         self.SetValue(center)
00662         
00663     def Update(self):
00664         self.statusbar.SetStatusText("")
00665         
00666         try:
00667             self.SetCenter()
00668             self.Show()
00669         except SbException, e:
00670             self.statusbar.SetStatusText(str(e), 0)
00671                         
00672         # disable long help
00673         self.mapFrame.StatusbarEnableLongHelp(False)
00674         
00675 
00676 class SbProjection(SbItem):
00677     """!Checkbox to enable user defined projection (can be set in settings)"""
00678     def __init__(self, mapframe, statusbar, position = 0):
00679         SbItem.__init__(self, mapframe, statusbar, position)
00680         self.name = 'projection'
00681         self.label = _("Projection")
00682         
00683         self.defaultLabel = _("Use defined projection")
00684         
00685         self.widget = wx.CheckBox(parent = self.statusbar, id = wx.ID_ANY,
00686                                   label = self.defaultLabel)
00687         
00688         self.widget.SetValue(False)
00689         
00690         # necessary?
00691         size = self.widget.GetSize()
00692         self.widget.SetMinSize((size[0] + 150, size[1]))
00693         
00694         self.widget.Hide()
00695         self.widget.SetToolTip(wx.ToolTip (_("Reproject coordinates displayed "
00696                                              "in the statusbar. Projection can be "
00697                                              "defined in GUI preferences dialog "
00698                                              "(tab 'Projection')")))
00699                                             
00700     def Update(self):
00701         self.statusbar.SetStatusText("")
00702         epsg = UserSettings.Get(group = 'projection', key = 'statusbar', subkey = 'epsg')
00703         if epsg:
00704             label = '%s (EPSG: %s)' % (self.defaultLabel, epsg)
00705             self.widget.SetLabel(label)
00706         else:
00707             self.widget.SetLabel(self.defaultLabel)
00708         self.Show()
00709         
00710         # disable long help
00711         self.mapFrame.StatusbarEnableLongHelp(False)
00712         
00713 
00714 class SbMask(SbItem):
00715     """!StaticText to show whether mask is activated."""
00716     def __init__(self, mapframe, statusbar, position = 0):
00717         SbItem.__init__(self, mapframe, statusbar, position)
00718         self.name = 'mask'
00719         
00720         self.widget = wx.StaticText(parent = self.statusbar, id = wx.ID_ANY, label = _('MASK'))
00721         self.widget.SetForegroundColour(wx.Colour(255, 0, 0))
00722         self.widget.Hide()
00723         
00724     def Update(self):
00725         if grass.find_file(name = 'MASK', element = 'cell')['name']:
00726             self.Show()
00727         else:
00728             self.Hide()
00729         
00730 class SbTextItem(SbItem):
00731     """!Base class for items without widgets.
00732     
00733     Only sets statusbar text.
00734     """
00735     def __init__(self, mapframe, statusbar, position = 0):
00736         SbItem.__init__(self, mapframe, statusbar, position)
00737         
00738         self.text = None
00739         
00740     def Show(self):
00741         self.statusbar.SetStatusText(self.GetValue(), self.position)
00742         
00743     def Hide(self):
00744         self.statusbar.SetStatusText("", self.position)
00745         
00746     def SetValue(self, value):
00747         self.text = value
00748     
00749     def GetValue(self):
00750         return self.text
00751             
00752     def GetWidget(self):
00753         return None
00754     
00755     def Update(self):
00756         self._update(longHelp = True)
00757 
00758 class SbDisplayGeometry(SbTextItem):
00759     """!Show current display resolution."""
00760     def __init__(self, mapframe, statusbar, position = 0):
00761         SbTextItem.__init__(self, mapframe, statusbar, position)
00762         self.name = 'displayGeometry'
00763         self.label = _("Display geometry")
00764         
00765     def Show(self):
00766         region = self.mapFrame.GetMap().GetCurrentRegion()
00767         self.SetValue("rows=%d; cols=%d; nsres=%.2f; ewres=%.2f" %
00768                      (region["rows"], region["cols"],
00769                       region["nsres"], region["ewres"]))
00770         SbTextItem.Show(self)
00771 
00772 class SbCoordinates(SbTextItem):
00773     """!Show map coordinates when mouse moves.
00774     
00775     Requires MapWindow.GetLastEN method."""
00776     def __init__(self, mapframe, statusbar, position = 0):
00777         SbTextItem.__init__(self, mapframe, statusbar, position)
00778         self.name = 'coordinates'
00779         self.label = _("Coordinates")
00780         
00781     def Show(self):
00782         precision = int(UserSettings.Get(group = 'projection', key = 'format',
00783                              subkey = 'precision'))
00784         format = UserSettings.Get(group = 'projection', key = 'format',
00785                                        subkey = 'll')
00786         projection = self.mapFrame.GetProperty('projection')
00787         try:
00788             e, n = self.mapFrame.GetWindow().GetLastEN()
00789             self.SetValue(self.ReprojectENFromMap(e, n, projection, precision, format))
00790         except SbException, e:
00791             self.SetValue(e)
00792         except TypeError, e:
00793             self.SetValue("")
00794         except AttributeError:
00795             self.SetValue("") # during initialization MapFrame has no MapWindow
00796         SbTextItem.Show(self)
00797         
00798     def ReprojectENFromMap(self, e, n, useDefinedProjection, precision, format):
00799         """!Reproject east, north to user defined projection.
00800         
00801         @param e,n coordinate
00802         
00803         @throws SbException if useDefinedProjection is True and projection is not defined in UserSettings
00804         """
00805         if useDefinedProjection:
00806             settings = UserSettings.Get(group = 'projection', key = 'statusbar', subkey = 'proj4')
00807             if not settings:
00808                 raise SbException(_("Projection not defined (check the settings)"))
00809             else:
00810                 # reproject values
00811                 proj, coord  = utils.ReprojectCoordinates(coord = (e, n),
00812                                                           projOut = settings,
00813                                                           flags = 'd')
00814                 if coord:
00815                     e, n = coord
00816                     if proj in ('ll', 'latlong', 'longlat') and format == 'DMS':
00817                         return utils.Deg2DMS(e, n, precision = precision)
00818                     else:
00819                         return "%.*f; %.*f" % (precision, e, precision, n)
00820                 else:
00821                     raise SbException(_("Error in projection (check the settings)"))
00822         else:
00823             if self.mapFrame.GetMap().projinfo['proj'] == 'll' and format == 'DMS':
00824                 return utils.Deg2DMS(e, n, precision = precision)
00825             else:
00826                 return "%.*f; %.*f" % (precision, e, precision, n)
00827         
00828 class SbRegionExtent(SbTextItem):
00829     """!Shows current display region"""
00830     def __init__(self, mapframe, statusbar, position = 0):
00831         SbTextItem.__init__(self, mapframe, statusbar, position)
00832         self.name = 'displayRegion'
00833         self.label = _("Extent")
00834         
00835     def Show(self):
00836         precision = int(UserSettings.Get(group = 'projection', key = 'format',
00837                              subkey = 'precision'))
00838         format = UserSettings.Get(group = 'projection', key = 'format',
00839                                        subkey = 'll')
00840         projection = self.mapFrame.GetProperty('projection')        
00841         region = self._getRegion()
00842         try:
00843             regionReprojected = self.ReprojectRegionFromMap(region, projection, precision, format)
00844             self.SetValue(regionReprojected)
00845         except SbException, e:
00846             self.SetValue(e)
00847         SbTextItem.Show(self)
00848     
00849     def _getRegion(self):
00850         """!Get current display region"""
00851         return self.mapFrame.GetMap().GetCurrentRegion() # display region
00852         
00853     def _formatRegion(self, w, e, s, n, nsres, ewres, precision = None):
00854         """!Format display region string for statusbar
00855 
00856         @param nsres,ewres unused
00857         """
00858         if precision is not None:
00859             return "%.*f - %.*f, %.*f - %.*f" % (precision, w, precision, e,
00860                                                  precision, s, precision, n)
00861         else:
00862             return "%s - %s, %s - %s" % (w, e, s, n)
00863          
00864            
00865     def ReprojectRegionFromMap(self, region, useDefinedProjection, precision, format):
00866         """!Reproject region values
00867         
00868         @todo reorganize this method to remove code useful only for derived class SbCompRegionExtent
00869         """
00870         if useDefinedProjection:
00871             settings = UserSettings.Get(group = 'projection', key = 'statusbar', subkey = 'proj4')
00872             
00873             if not settings:
00874                 raise SbException(_("Projection not defined (check the settings)"))
00875             else:
00876                 projOut = settings
00877                 proj, coord1 = utils.ReprojectCoordinates(coord = (region["w"], region["s"]),
00878                                                           projOut = projOut, flags = 'd')
00879                 proj, coord2 = utils.ReprojectCoordinates(coord = (region["e"], region["n"]),
00880                                                           projOut = projOut, flags = 'd')
00881                 # useless, used in derived class
00882                 proj, coord3 = utils.ReprojectCoordinates(coord = (0.0, 0.0),
00883                                                           projOut = projOut, flags = 'd')
00884                 proj, coord4 = utils.ReprojectCoordinates(coord = (region["ewres"], region["nsres"]),
00885                                                           projOut = projOut, flags = 'd')
00886                 if coord1 and coord2:
00887                     if proj in ('ll', 'latlong', 'longlat') and format == 'DMS':
00888                         w, s = utils.Deg2DMS(coord1[0], coord1[1], string = False,
00889                                              precision = precision)
00890                         e, n = utils.Deg2DMS(coord2[0], coord2[1], string = False,
00891                                              precision = precision)
00892                         ewres, nsres = utils.Deg2DMS(abs(coord3[0]) - abs(coord4[0]),
00893                                                          abs(coord3[1]) - abs(coord4[1]),
00894                                                          string = False, hemisphere = False,
00895                                                          precision = precision)
00896                         return self._formatRegion(w = w, s = s, e = e, n = n, ewres = ewres, nsres = nsres)
00897                     else:
00898                         w, s = coord1
00899                         e, n = coord2
00900                         ewres, nsres = coord3
00901                         return self._formatRegion(w = w, s = s, e = e, n = n, ewres = ewres,
00902                                                   nsres = nsres, precision = precision)
00903                 else:
00904                     raise SbException(_("Error in projection (check the settings)"))
00905                 
00906         else:
00907             if self.mapFrame.GetMap().projinfo['proj'] == 'll' and format == 'DMS':
00908                 w, s = utils.Deg2DMS(region["w"], region["s"],
00909                                      string = False, precision = precision)
00910                 e, n = utils.Deg2DMS(region["e"], region["n"],
00911                                      string = False, precision = precision)
00912                 ewres, nsres = utils.Deg2DMS(region['ewres'], region['nsres'],
00913                                              string = False, precision = precision)
00914                 return self._formatRegion(w = w, s = s, e = e, n = n, ewres = ewres, nsres = nsres)
00915             else:
00916                 w, s = region["w"], region["s"]
00917                 e, n = region["e"], region["n"]
00918                 ewres, nsres = region['ewres'], region['nsres']
00919                 return self._formatRegion(w = w, s = s, e = e, n = n, ewres = ewres,
00920                                           nsres = nsres, precision = precision)
00921                                 
00922                                 
00923 class SbCompRegionExtent(SbRegionExtent):
00924     """!Shows computational region."""
00925     def __init__(self, mapframe, statusbar, position = 0):
00926         SbRegionExtent.__init__(self, mapframe, statusbar, position)
00927         self.name = 'computationalRegion'
00928         self.label = _("Comp. region")
00929         
00930     def _formatRegion(self, w, e, s, n, ewres, nsres, precision = None):
00931         """!Format computational region string for statusbar"""
00932         if precision is not None:
00933             return "%.*f - %.*f, %.*f - %.*f (%.*f, %.*f)" % (precision, w, precision, e,
00934                                                               precision, s, precision, n,
00935                                                               precision, ewres, precision, nsres)
00936         else:
00937             return "%s - %s, %s - %s (%s, %s)" % (w, e, s, n, ewres, nsres)
00938         
00939     def _getRegion(self):
00940         """!Returns computational region."""
00941         return self.mapFrame.GetMap().GetRegion() # computational region
00942         
00943         
00944 class SbProgress(SbItem):
00945     """!General progress bar to show progress.
00946     
00947     Underlaying widget is wx.Gauge.
00948     """
00949     def __init__(self, mapframe, statusbar, position = 0):
00950         SbItem.__init__(self, mapframe, statusbar, position)
00951         self.name = 'progress'
00952 
00953         # on-render gauge
00954         self.widget = wx.Gauge(parent = self.statusbar, id = wx.ID_ANY,
00955                                       range = 0, style = wx.GA_HORIZONTAL)
00956         self.widget.Hide()
00957         
00958     def GetRange(self):
00959         """!Returns progress range."""
00960         return self.widget.GetRange()
00961     
00962     def SetRange(self, range):
00963         """!Sets progress range."""
00964         self.widget.SetRange(range)
00965     
00966 
00967 class SbGoToGCP(SbItem):
00968     """!SpinCtrl to select GCP to focus on
00969     
00970     Requires MapFrame.GetSrcWindow, MapFrame.GetTgtWindow, MapFrame.GetListCtrl,
00971     MapFrame.GetMapCoordList.
00972     """
00973     
00974     def __init__(self, mapframe, statusbar, position = 0):
00975         SbItem.__init__(self, mapframe, statusbar, position)
00976         self.name = 'gotoGCP'
00977         self.label = _("Go to GCP No.")
00978 
00979         self.widget = wx.SpinCtrl(parent = self.statusbar, id = wx.ID_ANY,
00980                                                 value = "", min = 0)
00981         self.widget.Hide()
00982         
00983         self.widget.Bind(wx.EVT_TEXT_ENTER, self.OnGoToGCP)
00984         self.widget.Bind(wx.EVT_SPINCTRL, self.OnGoToGCP)
00985     
00986     def OnGoToGCP(self, event):
00987         """!Zooms to given GCP."""
00988         GCPNo = self.GetValue()
00989         mapCoords = self.mapFrame.GetMapCoordList()
00990         
00991         if GCPNo < 0 or GCPNo > len(mapCoords): # always false, spin checks it
00992             GMessage(parent = self,
00993                      message = "%s 1 - %s." % (_("Valid Range:"),
00994                                                len(mapCoords)))
00995             return
00996 
00997         if GCPNo == 0:
00998             return
00999             
01000         listCtrl = self.mapFrame.GetListCtrl()
01001         
01002         listCtrl.selectedkey = GCPNo
01003         listCtrl.selected = listCtrl.FindItemData(-1, GCPNo)
01004         listCtrl.render = False
01005         listCtrl.SetItemState(listCtrl.selected,
01006                           wx.LIST_STATE_SELECTED,
01007                           wx.LIST_STATE_SELECTED)
01008         listCtrl.render = True
01009         
01010         srcWin = self.mapFrame.GetSrcWindow()
01011         tgtWin = self.mapFrame.GetTgtWindow()
01012         
01013         # Source MapWindow:
01014         begin = (mapCoords[GCPNo][1], mapCoords[GCPNo][2])
01015         begin = srcWin.Cell2Pixel(begin)
01016         end = begin
01017         srcWin.Zoom(begin, end, 0)
01018 
01019         # redraw map
01020         srcWin.UpdateMap()
01021 
01022         if self.mapFrame.GetShowTarget():
01023             # Target MapWindow:
01024             begin = (mapCoords[GCPNo][3], mapCoords[GCPNo][4])
01025             begin = tgtWin.Cell2Pixel(begin)
01026             end = begin
01027             tgtWin.Zoom(begin, end, 0)
01028 
01029             # redraw map
01030             tgtWin.UpdateMap()
01031 
01032         self.GetWidget().SetFocus()
01033     
01034     def Update(self):
01035         self.statusbar.SetStatusText("")
01036         max = self.mapFrame.GetListCtrl().GetItemCount()
01037         if max < 1:
01038             max = 1
01039         self.widget.SetRange(0, max)
01040         self.Show()
01041                         
01042         # disable long help
01043         self.mapFrame.StatusbarEnableLongHelp(False)
01044         
01045 class SbRMSError(SbTextItem):
01046     """!Shows RMS error.
01047     
01048     Requires MapFrame.GetFwdError, MapFrame.GetBkwError.
01049     """
01050     def __init__(self, mapframe, statusbar, position = 0):
01051         SbTextItem.__init__(self, mapframe, statusbar, position)
01052         self.name = 'RMSError'
01053         self.label = _("RMS error")
01054         
01055     def Show(self):
01056         self.SetValue(_("Forward: %(forw)s, Backward: %(back)s") %
01057                                    { 'forw' : self.mapFrame.GetFwdError(),
01058                                      'back' : self.mapFrame.GetBkwError() })
01059         SbTextItem.Show(self)