/[thuban]/branches/WIP-pyshapelib-bramz/Thuban/UI/legend.py
ViewVC logotype

Diff of /branches/WIP-pyshapelib-bramz/Thuban/UI/legend.py

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1113 by bh, Fri May 30 15:59:49 2003 UTC revision 2560 by bh, Tue Feb 8 20:25:22 2005 UTC
# Line 1  Line 1 
1  # Copyright (c) 2001, 2002, 2003 by Intevation GmbH  # Copyright (c) 2001, 2002, 2003, 2005 by Intevation GmbH
2  # Authors:  # Authors:
3  # Jonathan Coles <[email protected]>  # Jonathan Coles <[email protected]>
4  # Frank Koormann <[email protected]>  # Frank Koormann <[email protected]>
# Line 8  Line 8 
8    
9  __version__ = "$Revision$"  __version__ = "$Revision$"
10    
11    from  math import fabs, cos, pi
12    
13  from Thuban import _  from Thuban import _
14    
15  import resource  import resource
16    
17  from wxPython.wx import *  from wxPython.wx import *
18    import wxPython
19    
20  from Thuban.Model.layer import BaseLayer  from Thuban.Model.layer import BaseLayer
21  from Thuban.Model.map import Map  from Thuban.Model.map import Map
22  from Thuban.Model.classification import ClassGroup  from Thuban.Model.classification import ClassGroup
23    from Thuban.Model.proj import PROJ_UNITS_DEGREES
24    
25  from Thuban.Model.messages import \  from Thuban.Model.messages import \
26      MAP_STACKING_CHANGED, MAP_LAYERS_ADDED, MAP_LAYERS_REMOVED, LAYER_CHANGED,\      MAP_STACKING_CHANGED, MAP_LAYERS_ADDED, MAP_LAYERS_REMOVED, LAYER_CHANGED,\
# Line 28  from Thuban.UI.classifier import ClassDa Line 32  from Thuban.UI.classifier import ClassDa
32  from Thuban.UI.dock import DockPanel  from Thuban.UI.dock import DockPanel
33  from Thuban.UI.scalebar import ScaleBar  from Thuban.UI.scalebar import ScaleBar
34    
35    from Thuban.UI.menu import Menu
36    
37  from Thuban.Lib.connector import ConnectorError  from Thuban.Lib.connector import ConnectorError
38    
39  ID_LEGEND_TOP = 4001  ID_LEGEND_TOP = 4001
# Line 50  SHOW_BMP  = "show_layer" Line 56  SHOW_BMP  = "show_layer"
56  HIDE_BMP  = "hide_layer"  HIDE_BMP  = "hide_layer"
57  PROPS_BMP = "layer_properties"  PROPS_BMP = "layer_properties"
58    
   
59  class LegendPanel(DockPanel):  class LegendPanel(DockPanel):
60    
61      def __init__(self, parent, map, mainWindow):      def __init__(self, parent, map, mainWindow):
# Line 179  class LegendPanel(DockPanel): Line 184  class LegendPanel(DockPanel):
184          self.tree.DoOnHideLayer()          self.tree.DoOnHideLayer()
185          pass          pass
186    
187        def _OnToggleVisibility(self, event):
188            self.tree.ToggleVisibility()
189    
190        def _OnProjection(self, event):
191            self.tree.LayerProjection()
192    
193        def _OnRemoveLayer(self, event):
194            self.mainWindow.RemoveLayer()
195    
196        def _OnShowTable(self, event):
197            self.mainWindow.LayerShowTable()
198    
199      def __EnableButtons(self, on):      def __EnableButtons(self, on):
200          self.toolBar.EnableTool(ID_LEGEND_TOP, on)          self.toolBar.EnableTool(ID_LEGEND_TOP, on)
201          self.toolBar.EnableTool(ID_LEGEND_RAISE, on)          self.toolBar.EnableTool(ID_LEGEND_RAISE, on)
# Line 201  class LegendTree(wxTreeCtrl): Line 218  class LegendTree(wxTreeCtrl):
218          self.mainWindow = mainWindow          self.mainWindow = mainWindow
219          self.map = None          self.map = None
220          self.parent = parent          self.parent = parent
         self.layer2id = {}  
221          self.changing_selection = 0          self.changing_selection = 0
222    
223          #          #
# Line 221  class LegendTree(wxTreeCtrl): Line 237  class LegendTree(wxTreeCtrl):
237    
238          self.previewer = ClassDataPreviewer()          self.previewer = ClassDataPreviewer()
239    
240            self.preventExpandCollapse = False
241            self.raiseProperties = False
242    
243          EVT_TREE_ITEM_ACTIVATED(self, ID_LEGEND_TREE, self._OnItemActivated)          EVT_TREE_ITEM_ACTIVATED(self, ID_LEGEND_TREE, self._OnItemActivated)
244          EVT_TREE_SEL_CHANGED(self, ID_LEGEND_TREE, self._OnSelChanged)          EVT_TREE_SEL_CHANGED(self, ID_LEGEND_TREE, self._OnSelChanged)
245            EVT_TREE_ITEM_EXPANDING(self, ID_LEGEND_TREE, self.OnItemExpandCollapse)
246            EVT_TREE_ITEM_COLLAPSING(self, ID_LEGEND_TREE, self.OnItemExpandCollapse)
247            EVT_TREE_ITEM_RIGHT_CLICK(self, ID_LEGEND_TREE, self._OnRightClick)
248    
249          EVT_CLOSE(self, self._OnClose)          EVT_CLOSE(self, self._OnClose)
250    
251          self.SetMap(map)          self.SetMap(map)
252    
253        def _OnRightClick(self, event):
254            """Select item and pop up a context menu"""
255    
256            # The pop up menu is related to the legend tree, so we have direct
257            # access on the tree items. The events issued by the menu are handled
258            # by the legend panel, since most of the handlers are already
259            # implemented there.
260    
261            # Update item selection to the right click
262            item = event.GetItem()
263            self.SelectItem(item)
264    
265            # Define the menu
266            popup_menu = Menu("PopUp", "",
267                              [ "layer_visibility",
268                                None,
269                                "layer_properties",
270                                "layer_projection",
271                                "layer_remove",
272                                "layer_show_table",
273                                None,
274                                "layer_to_top",
275                                "layer_raise",
276                                "layer_lower",
277                                "layer_to_bottom"
278                                ])
279    
280            # Display the menu
281            pos = event.GetPoint()
282            shift = self.ClientToScreen((0,0))
283            self.PopupMenu(self.mainWindow.build_menu(popup_menu), pos)
284    
285        def find_layer(self, layer):
286            """Return the tree item for the layer"""
287            root = self.GetRootItem()
288            id, cookie = self.GetFirstChild(root)
289            while id.IsOk():
290                if self.GetPyData(id) is layer:
291                    return id
292                id, cookie = self.GetNextChild(root, cookie)
293            return None
294    
295      def _OnClose(self, event):      def _OnClose(self, event):
296          self.SetMap(None)          self.SetMap(None)
297    
# Line 316  class LegendTree(wxTreeCtrl): Line 380  class LegendTree(wxTreeCtrl):
380          layer, group = self.GetSelectedHierarchy()          layer, group = self.GetSelectedHierarchy()
381          layer.SetVisible(False)          layer.SetVisible(False)
382    
383        def ToggleVisibility(self):
384            layer, group = self.GetSelectedHierarchy()
385    
386            layer.SetVisible(not layer.Visible())
387    
388        def LayerProjection(self):
389            self.parent.mainWindow.LayerProjection()
390    
391      def Sort(self):      def Sort(self):
392          self.SortChildren(self.GetRootItem())          self.SortChildren(self.GetRootItem())
393    
# Line 372  class LegendTree(wxTreeCtrl): Line 444  class LegendTree(wxTreeCtrl):
444              self.changing_selection = 0              self.changing_selection = 0
445    
446    
447        def OnItemExpandCollapse(self, event):
448            if self.preventExpandCollapse:
449                event.Veto()
450                self.preventExpandCollapse = False
451    
452      def _OnItemActivated(self, event):      def _OnItemActivated(self, event):
453          self.parent.DoOnProperties()          # The following looks strange but is need under Windows to
454            # raise the Properties on double-click: The tree control
455            # always gets an Expanded / Collapsed event after the ItemActivated
456            # on double click, which raises the main window again. We add a second
457            # ItemActivated event to the queue, which simply raises the already
458            # displayed window.
459            if self.raiseProperties:
460                self.parent.DoOnProperties()
461                self.raiseProperties = False
462            else:
463                self.raiseProperties = True
464                self.preventExpandCollapse = True
465                self.parent.DoOnProperties()
466                self.AddPendingEvent(event)
467    
468      def _OnMsgLayerChanged(self, layer):      def _OnMsgLayerChanged(self, layer):
469          assert isinstance(layer, BaseLayer)          assert isinstance(layer, BaseLayer)
470    
471          id = self.layer2id[layer]          id = self.find_layer(layer)
472          assert id.IsOk()          assert id is not None
473    
474          self.__FillTreeLayer(id)          self.__FillTreeLayer(id)
475          self.__UpdateSelection()          self.__UpdateSelection()
# Line 395  class LegendTree(wxTreeCtrl): Line 485  class LegendTree(wxTreeCtrl):
485      def _OnMsgMapLayersAdded(self, map):      def _OnMsgMapLayersAdded(self, map):
486          assert map is self.map          assert map is self.map
487    
488            # Build a dict with all layers known by the the tree as keys
489            layers = {}
490          root = self.GetRootItem()          root = self.GetRootItem()
491            id, cookie = self.GetFirstChild(root)
492            while id.IsOk():
493                layers[self.GetPyData(id)] = 1
494                id, cookie = self.GetNextChild(root, cookie)
495    
496            # Add layers in the map but not in the dict
497          i = 0          i = 0
498          for l in map.Layers():          for l in map.Layers():
499              if not self.layer2id.has_key(l):              if not l in layers:
500                  self.__AddLayer(i, l)                  self.__AddLayer(i, l)
501    
502          self.__UpdateSelection()          self.__UpdateSelection()
# Line 407  class LegendTree(wxTreeCtrl): Line 504  class LegendTree(wxTreeCtrl):
504      def _OnMsgMapLayersRemoved(self, map):      def _OnMsgMapLayersRemoved(self, map):
505          assert map is self.map          assert map is self.map
506    
         layer, group = self.GetSelectedHierarchy()  
   
         if layer is None:  
             assert False, "Shouldn't be allowed."  
             return  
   
507          layers = map.Layers()          layers = map.Layers()
508    
509          for layer, id in self.layer2id.items():          root = self.GetRootItem()
510              if layer not in layers:          id, cookie = self.GetFirstChild(root)
511                  if id.IsOk():          while id.IsOk():
512                      self.__RemoveLayer(id)              if self.GetPyData(id) not in layers:
513                    self.__RemoveLayer(id)
514                id, cookie = self.GetNextChild(root, cookie)
515    
516    
517          self.__UpdateSelection()          self.__UpdateSelection()
518    
# Line 430  class LegendTree(wxTreeCtrl): Line 524  class LegendTree(wxTreeCtrl):
524    
525      def _OnMsgLayerTitleChanged(self, layer):      def _OnMsgLayerTitleChanged(self, layer):
526    
527          id = self.layer2id[layer]          id = self.find_layer(layer)
528          if id.IsOk():          if id.IsOk():
529              self.SetItemText(id, layer.Title())              self.SetItemText(id, layer.Title())
530          self.__UpdateSelection()          self.__UpdateSelection()
# Line 505  class LegendTree(wxTreeCtrl): Line 599  class LegendTree(wxTreeCtrl):
599    
600          pid = self.GetRootItem()          pid = self.GetRootItem()
601    
602          id, cookie = self.GetFirstChild(pid, 123)          id, cookie = self.GetFirstChild(pid)
603          while id.IsOk():          while id.IsOk():
604              self.__RemoveLayer(id)              self.__RemoveLayer(id)
605              id, cookie = self.GetNextChild(pid, cookie)              id, cookie = self.GetNextChild(pid, cookie)
# Line 522  class LegendTree(wxTreeCtrl): Line 616  class LegendTree(wxTreeCtrl):
616          self.SetPyData(id, l)          self.SetPyData(id, l)
617          self.__SetVisibilityStyle(l.Visible(), id)          self.__SetVisibilityStyle(l.Visible(), id)
618    
         self.layer2id[l] = id  
   
619          self.__FillTreeLayer(id)          self.__FillTreeLayer(id)
620          self.Expand(id)          self.Expand(id)
621    
# Line 543  class LegendTree(wxTreeCtrl): Line 635  class LegendTree(wxTreeCtrl):
635          layer.Unsubscribe(TITLE_CHANGED, self._OnMsgLayerTitleChanged)          layer.Unsubscribe(TITLE_CHANGED, self._OnMsgLayerTitleChanged)
636    
637          self.Delete(id)          self.Delete(id)
         del self.layer2id[layer]  
638    
639      def DeleteChildren(self, pid):      def DeleteChildren(self, pid):
640          id, cookie = self.GetFirstChild(pid, 123)          id, cookie = self.GetFirstChild(pid)
641          while id.IsOk():          while id.IsOk():
642              self.availImgListIndices.append(self.GetItemImage(id))              self.availImgListIndices.append(self.GetItemImage(id))
643              id, cookie = self.GetNextChild(pid, cookie)              id, cookie = self.GetNextChild(pid, cookie)
# Line 557  class LegendTree(wxTreeCtrl): Line 648  class LegendTree(wxTreeCtrl):
648    
649          if not root.IsOk():          if not root.IsOk():
650              self.image_list = wxImageList(BMP_SIZE_W, BMP_SIZE_H, False, 0)              self.image_list = wxImageList(BMP_SIZE_W, BMP_SIZE_H, False, 0)
651                                                                                    
652              bmp = wxEmptyBitmap(BMP_SIZE_W, BMP_SIZE_H)              bmp = wxEmptyBitmap(BMP_SIZE_W, BMP_SIZE_H)
653              dc = wxMemoryDC()              dc = wxMemoryDC()
654              dc.SelectObject(bmp)              dc.SelectObject(bmp)
655              dc.SetBrush(wxBLACK_BRUSH)              dc.SetBrush(wxBLACK_BRUSH)
656              dc.Clear()              dc.Clear()
657              dc.SelectObject(wxNullBitmap)              dc.SelectObject(wxNullBitmap)
658                                                                                    
659              self.emptyImageIndex = \              self.emptyImageIndex = \
660                  self.image_list.AddWithColourMask(bmp, wxColour(0, 0, 0))                  self.image_list.AddWithColourMask(bmp, wxColour(0, 0, 0))
661                                                                                    
662              bmp = resource.GetBitmapResource("legend_icon_layer",              bmp = resource.GetBitmapResource("legend_icon_layer",
663                                                wxBITMAP_TYPE_XPM)                                                wxBITMAP_TYPE_XPM)
664              self.mapImageIndex = \              self.mapImageIndex = \
665                  self.image_list.Add(bmp)                  self.image_list.Add(bmp)
666    
667              self.AssignImageList(self.image_list)              self.AssignImageList(self.image_list)
668                self.availImgListIndices = []
669    
670              root = self.AddRoot("")              root = self.AddRoot("")
671    
# Line 594  class LegendTree(wxTreeCtrl): Line 686  class LegendTree(wxTreeCtrl):
686          self.SetItemFont(id, font)          self.SetItemFont(id, font)
687                    
688      def __ShowHideLayer(self, layer):      def __ShowHideLayer(self, layer):
689          parent = self.layer2id[layer]          parent = self.find_layer(layer)
690          assert parent.IsOk()          assert parent.IsOk()
691    
692          visible = layer.Visible()          visible = layer.Visible()
693    
694          self.__SetVisibilityStyle(visible, parent)          self.__SetVisibilityStyle(visible, parent)
695    
696          id, cookie = self.GetFirstChild(parent, 123)          id, cookie = self.GetFirstChild(parent)
697    
698          while id.IsOk():          while id.IsOk():
699              self.__SetVisibilityStyle(visible, id)              self.__SetVisibilityStyle(visible, id)
700              id, cookie = self.GetNextChild(parent, cookie)              id, cookie = self.GetNextChild(parent, cookie)
701                
702        # In wxPython 2.4 the GetFirstChild method has to be called with a
703        # second argument and in 2.5 it must not.  Reading the code of
704        # wxPython 2.4 it seems that the second parameter was intended to be
705        # optional there but due to a bug in the C++ code it doesn't work
706        # and omitting the second argument leads to a segfault.  To cope
707        # with this and to make the code usable with both 2.5 and 2.4 we
708        # overwrite the inherited method when running with 2.4 to provide a
709        # default value for the second argument.
710        if map(int, wxPython.__version__.split(".")[:2]) < [2, 5]:
711            def GetFirstChild(self, item):
712                return wxTreeCtrl.GetFirstChild(self, item, 0)
713    
714    
715  class ScaleBarBitmap(wxBoxSizer):  class ScaleBarBitmap(wxBoxSizer):
716    
717      def __init__(self, parent, map, mainWindow):      def __init__(self, parent, map, mainWindow):
# Line 648  class ScaleBarBitmap(wxBoxSizer): Line 753  class ScaleBarBitmap(wxBoxSizer):
753          dc.SelectObject(bmp)          dc.SelectObject(bmp)
754          dc.Clear()          dc.Clear()
755    
756          self.scalebar.DrawScaleBar(scale, dc, (0,0), dc.GetSizeTuple())          if self.canvas.map is not None \
757                and self.canvas.map.projection is not None:
758    
759                # if we are using a projection with geographics coordinates
760                # we need to change the scale value based on where we are
761                # on the globe.
762                if self.canvas.map.projection.GetProjectedUnits() \
763                    == PROJ_UNITS_DEGREES:
764    
765                    width, height = self.canvas.GetSizeTuple()
766                    long, lat = self.canvas.win_to_proj(width/2, height/2)
767    
768                    # slightly inaccurate, but if we are looking at
769                    # the north/south pole we could end up dividing by zero
770                    #
771                    # it shouldn't matter for our purposes that we ignore
772                    # the original sign of lat.
773                    if fabs(lat) > 89.9: lat = 89.9
774    
775                    #
776                    # one degree is about 111,133m at the equator
777                    # we need to adjust that for latitude as
778                    # we move north/south. use the center of the map
779                    # as the point to scale the length to.
780                    #
781                    scale = scale / (111133.0 * fabs(cos(lat * pi/180)))
782    
783                self.scalebar.DrawScaleBar(scale, dc, (0,0), dc.GetSizeTuple())
784    
785          self.scalebarBitmap.SetBitmap(bmp)          self.scalebarBitmap.SetBitmap(bmp)
786    

Legend:
Removed from v.1113  
changed lines
  Added in v.2560

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26