/[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 990 by frank, Thu May 22 16:51:24 2003 UTC revision 1252 by jonathan, Fri Jun 20 09:28:08 2003 UTC
# 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
# Line 17  from wxPython.wx import * Line 19  from wxPython.wx import *
19  from Thuban.Model.layer import BaseLayer  from Thuban.Model.layer import BaseLayer
20  from Thuban.Model.map import Map  from Thuban.Model.map import Map
21  from Thuban.Model.classification import ClassGroup  from Thuban.Model.classification import ClassGroup
22    from Thuban.Model.proj import PROJ_UNITS_DEGREES
23    
24  from Thuban.Model.messages import \  from Thuban.Model.messages import \
25      MAP_STACKING_CHANGED, MAP_LAYERS_ADDED, MAP_LAYERS_REMOVED, LAYER_CHANGED,\      MAP_STACKING_CHANGED, MAP_LAYERS_ADDED, MAP_LAYERS_REMOVED, LAYER_CHANGED,\
# Line 39  ID_LEGEND_PROPS = 4006 Line 42  ID_LEGEND_PROPS = 4006
42  ID_LEGEND_SHOWLAYER = 4007  ID_LEGEND_SHOWLAYER = 4007
43  ID_LEGEND_HIDELAYER = 4008  ID_LEGEND_HIDELAYER = 4008
44    
45  BMP_SIZE_W = 30  BMP_SIZE_W = 15
46  BMP_SIZE_H = 15  BMP_SIZE_H = 15
47    
48  TOP_BMP = "top_layer"  TOP_BMP = "top_layer"
# Line 201  class LegendTree(wxTreeCtrl): Line 204  class LegendTree(wxTreeCtrl):
204          self.mainWindow = mainWindow          self.mainWindow = mainWindow
205          self.map = None          self.map = None
206          self.parent = parent          self.parent = parent
207          self.layer2id = {}          self.changing_selection = 0
208    
209            #
210            # The image list used by the wxTreeCtrl causes problems when
211            # we remove layers and/or change a classification because it
212            # changes the image indices if you remove images from the list.
213            # Rather than removing unused images we use this list to keep
214            # track of which indices are available in the image list
215            # (because of a previous removal) and then  replace those indices
216            # with new images rather than appending to the end of the image
217            # list (assuming there are any that are available).
218            #
219            self.availImgListIndices = []
220    
221          self.image_list = None          self.image_list = None
222          self.emptyImageIndex = 0          self.emptyImageIndex = 0
223    
224          self.previewer = ClassDataPreviewer()          self.previewer = ClassDataPreviewer()
225    
226            self.preventExpandCollapse = False
227            self.raiseProperties = False
228    
229          EVT_TREE_ITEM_ACTIVATED(self, ID_LEGEND_TREE, self._OnItemActivated)          EVT_TREE_ITEM_ACTIVATED(self, ID_LEGEND_TREE, self._OnItemActivated)
230          EVT_TREE_SEL_CHANGED(self, ID_LEGEND_TREE, self._OnSelChanged)          EVT_TREE_SEL_CHANGED(self, ID_LEGEND_TREE, self._OnSelChanged)
231            EVT_TREE_ITEM_EXPANDING(self, ID_LEGEND_TREE, self.OnItemExpandCollapse)
232            EVT_TREE_ITEM_COLLAPSING(self, ID_LEGEND_TREE, self.OnItemExpandCollapse)
233    
234          EVT_CLOSE(self, self._OnClose)          EVT_CLOSE(self, self._OnClose)
235    
236          self.SetMap(map)          self.SetMap(map)
237    
238        def find_layer(self, layer):
239            """Return the tree item for the layer"""
240            root = self.GetRootItem()
241            id, cookie = self.GetFirstChild(root, 0)
242            while id.IsOk():
243                if self.GetPyData(id) is layer:
244                    return id
245                id, cookie = self.GetNextChild(root, cookie)
246            return None
247    
248      def _OnClose(self, event):      def _OnClose(self, event):
249          self.SetMap(None)          self.SetMap(None)
250    
# Line 224  class LegendTree(wxTreeCtrl): Line 254  class LegendTree(wxTreeCtrl):
254      def SetMap(self, map):      def SetMap(self, map):
255    
256          sub_list = [(MAP_STACKING_CHANGED, self._OnMsgMapStackingChanged),          sub_list = [(MAP_STACKING_CHANGED, self._OnMsgMapStackingChanged),
257                      (MAP_LAYERS_ADDED, self._OnMsgMapLayersAddedRemoved),                      (MAP_LAYERS_ADDED, self._OnMsgMapLayersAdded),
258                      (MAP_LAYERS_REMOVED, self._OnMsgMapLayersAddedRemoved)]                      (MAP_LAYERS_REMOVED, self._OnMsgMapLayersRemoved)]
259    
260          if self.map is not None:          if self.map is not None:
261              for msg, func in sub_list: self.map.Unsubscribe(msg, func)              for msg, func in sub_list: self.map.Unsubscribe(msg, func)
# Line 236  class LegendTree(wxTreeCtrl): Line 266  class LegendTree(wxTreeCtrl):
266                      #self._OnMsgMapsChanged)                      #self._OnMsgMapsChanged)
267              #except ConnectorError:              #except ConnectorError:
268                  #pass                  #pass
269              self.__DeleteAllItems()              self.DeleteAllItems()
270                    
271          self.map = map          self.map = map
272    
# Line 252  class LegendTree(wxTreeCtrl): Line 282  class LegendTree(wxTreeCtrl):
282          layer, group = self.GetSelectedHierarchy()          layer, group = self.GetSelectedHierarchy()
283    
284          if layer is not None:          if layer is not None:
285              self.map.TopLayer(layer)              self.map.MoveLayerToTop(layer)
286          else:          else:
287              assert False, "Shouldn't be allowed."              assert False, "Shouldn't be allowed."
288              pass              pass
# Line 279  class LegendTree(wxTreeCtrl): Line 309  class LegendTree(wxTreeCtrl):
309          layer, group = self.GetSelectedHierarchy()          layer, group = self.GetSelectedHierarchy()
310    
311          if layer is not None:          if layer is not None:
312              self.map.BottomLayer(layer)              self.map.MoveLayerToBottom(layer)
313          else:          else:
314              assert False, "Shouldn't be allowed."              assert False, "Shouldn't be allowed."
315              pass              pass
# Line 296  class LegendTree(wxTreeCtrl): Line 326  class LegendTree(wxTreeCtrl):
326              return wxTreeCtrl.OnCompareItems(self, item1, item2)              return wxTreeCtrl.OnCompareItems(self, item1, item2)
327    
328      def DoOnShowLayer(self):      def DoOnShowLayer(self):
         #self.__ShowHideLayer(True)  
329          layer, group = self.GetSelectedHierarchy()          layer, group = self.GetSelectedHierarchy()
330          layer.SetVisible(True)          layer.SetVisible(True)
331    
332      def DoOnHideLayer(self):      def DoOnHideLayer(self):
         #self.__ShowHideLayer(False)  
333          layer, group = self.GetSelectedHierarchy()          layer, group = self.GetSelectedHierarchy()
334          layer.SetVisible(False)          layer.SetVisible(False)
335    
# Line 330  class LegendTree(wxTreeCtrl): Line 358  class LegendTree(wxTreeCtrl):
358          self.SetMap(self.mainWindow.Map())          self.SetMap(self.mainWindow.Map())
359                    
360      def _OnSelChanged(self, event):      def _OnSelChanged(self, event):
361            # If we change the selection from normalize_selection do nothing.
362            if self.changing_selection:
363                return
364    
365            self.normalize_selection()
366          self.__UpdateSelection()          self.__UpdateSelection()
367    
368        def normalize_selection(self):
369            """Select the layer containing currently selected item"""
370            # This is really a workaround for a bug in wx where deleting a
371            # subtree with DeleteChildren does not update the selection
372            # properly and can lead to segfaults later because the return
373            # value of GetSelection points to invalid data.
374            item = self.GetSelection()
375            while item.IsOk():
376                object = self.GetPyData(item)
377                if isinstance(object, BaseLayer):
378                    break
379                item = self.GetItemParent(item)
380            else:
381                # No layer was found in the chain of parents, so there's
382                # nothing we can do.
383                return
384    
385            self.changing_selection = 1
386            try:
387                self.SelectItem(item)
388            finally:
389                self.changing_selection = 0
390    
391    
392        def OnItemExpandCollapse(self, event):
393            if self.preventExpandCollapse:
394                event.Veto()
395                self.preventExpandCollapse = False
396    
397      def _OnItemActivated(self, event):      def _OnItemActivated(self, event):
398          self.parent.DoOnProperties()          # The following looks strange but is need under Windows to
399            # raise the Properties on double-click: The tree control
400            # always gets an Expanded / Collapsed event after the ItemActivated
401            # on double click, which raises the main window again. We add a second
402            # ItemActivated event to the queue, which simply raises the already
403            # displayed window.
404            if self.raiseProperties:
405                self.parent.DoOnProperties()
406                self.raiseProperties = False
407            else:
408                self.raiseProperties = True
409                self.preventExpandCollapse = True
410                self.parent.DoOnProperties()
411                self.AddPendingEvent(event)
412    
413      def _OnMsgLayerChanged(self, layer):      def _OnMsgLayerChanged(self, layer):
414          assert isinstance(layer, BaseLayer)          assert isinstance(layer, BaseLayer)
415    
416          id = self.layer2id[layer]          id = self.find_layer(layer)
417          assert id.IsOk()          assert id is not None
418    
419          # XXX: yikes! this is so bad, we should be doing what is          self.__FillTreeLayer(id)
         #      commented out, but there is a problem with keeping  
         #      track of the images in the image list when we replace  
         #      a layer. it ends up causing a seg fault.  
         self.__FillTree(self.map)  
420          self.__UpdateSelection()          self.__UpdateSelection()
         #self.__FillTreeLayer(id)  
421    
422      def _OnMsgMapStackingChanged(self, *args):      def _OnMsgMapStackingChanged(self, *args):
423          self.Sort()          self.Sort()
# Line 357  class LegendTree(wxTreeCtrl): Line 427  class LegendTree(wxTreeCtrl):
427              self.EnsureVisible(id)              self.EnsureVisible(id)
428          self.__UpdateSelection()          self.__UpdateSelection()
429    
430      def _OnMsgMapLayersAddedRemoved(self, map):      def _OnMsgMapLayersAdded(self, map):
431            assert map is self.map
432    
433            # Build a dict with all layers known by the the tree as keys
434            layers = {}
435            root = self.GetRootItem()
436            id, cookie = self.GetFirstChild(root, 0)
437            while id.IsOk():
438                layers[self.GetPyData(id)] = 1
439                id, cookie = self.GetNextChild(root, cookie)
440    
441            # Add layers in the map but not in the dict
442            i = 0
443            for l in map.Layers():
444                if not l in layers:
445                    self.__AddLayer(i, l)
446    
447            self.__UpdateSelection()
448    
449        def _OnMsgMapLayersRemoved(self, map):
450          assert map is self.map          assert map is self.map
451    
452          self.__FillTree(self.map)          layers = map.Layers()
453    
454            root = self.GetRootItem()
455            id, cookie = self.GetFirstChild(root, 0)
456            while id.IsOk():
457                if self.GetPyData(id) not in layers:
458                    self.__RemoveLayer(id)
459                id, cookie = self.GetNextChild(root, cookie)
460    
461    
462          self.__UpdateSelection()          self.__UpdateSelection()
463    
464      def _OnMsgLayerVisibilityChanged(self, layer):      def _OnMsgLayerVisibilityChanged(self, layer):
# Line 371  class LegendTree(wxTreeCtrl): Line 469  class LegendTree(wxTreeCtrl):
469    
470      def _OnMsgLayerTitleChanged(self, layer):      def _OnMsgLayerTitleChanged(self, layer):
471    
472          id = self.layer2id[layer]          id = self.find_layer(layer)
473          if id.IsOk():          if id.IsOk():
474              self.SetItemText(id, layer.Title())              self.SetItemText(id, layer.Title())
475          self.__UpdateSelection()          self.__UpdateSelection()
# Line 384  class LegendTree(wxTreeCtrl): Line 482  class LegendTree(wxTreeCtrl):
482    
483          self.Freeze()          self.Freeze()
484    
485          self.__DeleteAllItems()          self.DeleteAllItems()
486    
487          if map.HasLayers():          if map.HasLayers():
488                root = self.GetRootItem()
             self.image_list = wxImageList(BMP_SIZE_W, BMP_SIZE_H, False, 0)  
                                                                                   
             bmp = wxEmptyBitmap(BMP_SIZE_W, BMP_SIZE_H)  
             dc = wxMemoryDC()  
             dc.SelectObject(bmp)  
             dc.SetBrush(wxBLACK_BRUSH)  
             dc.Clear()  
             dc.SelectObject(wxNullBitmap)  
                                                                                   
             self.emptyImageIndex = \  
                 self.image_list.AddWithColourMask(bmp, wxColour(0, 0, 0))  
                                                                                   
             self.AssignImageList(self.image_list)  
   
             root = self.AddRoot("")  
   
489              for l in map.Layers():              for l in map.Layers():
490                  id = self.PrependItem(root, l.Title())                  self.__AddLayer(0, l)
                 l.Subscribe(LAYER_CHANGED, self._OnMsgLayerChanged)  
                 l.Subscribe(LAYER_VISIBILITY_CHANGED,  
                             self._OnMsgLayerVisibilityChanged)  
                 l.Subscribe(TITLE_CHANGED, self._OnMsgLayerTitleChanged)  
                 self.SetPyData(id, l)  
                 self.__SetVisibilityStyle(l.Visible(), id)  
   
                 self.layer2id[l] = id  
   
                 self.__FillTreeLayer(id)  
                 self.Expand(id)  
491    
492          self.Thaw()          self.Thaw()
493    
# Line 443  class LegendTree(wxTreeCtrl): Line 514  class LegendTree(wxTreeCtrl):
514                      bmp = self.__BuildGroupImage(g, shapeType)                      bmp = self.__BuildGroupImage(g, shapeType)
515    
516                      if bmp is None:                      if bmp is None:
517                          self.SetItemImage(id, self.emptyImageIndex)                          self.SetItemImage(id, -1)
518                            self.SetItemSelectedImage(id, -1)
519                      else:                      else:
520                          i = self.image_list.Add(bmp)                          if self.availImgListIndices:
521                                i = self.availImgListIndices.pop(0)
522                                self.image_list.Replace(i, bmp)
523                            else:
524                                i = self.image_list.Add(bmp)
525    
526                          self.SetItemImage(id, i)                          self.SetItemImage(id, i)
527                            self.SetItemSelectedImage(id, i)
528    
529          self.Thaw()          self.Thaw()
530    
# Line 462  class LegendTree(wxTreeCtrl): Line 540  class LegendTree(wxTreeCtrl):
540    
541          return bmp          return bmp
542    
543      def __DeleteAllItems(self):      def DeleteAllItems(self):
544    
545          while len(self.layer2id) > 0:          pid = self.GetRootItem()
             layer, id = self.layer2id.popitem()  
             layer.Unsubscribe(LAYER_CHANGED,  
                               self._OnMsgLayerChanged)  
             layer.Unsubscribe(LAYER_VISIBILITY_CHANGED,  
                               self._OnMsgLayerVisibilityChanged)  
             layer.Unsubscribe(TITLE_CHANGED, self._OnMsgLayerTitleChanged)  
546    
547          self.DeleteAllItems()          id, cookie = self.GetFirstChild(pid, 123)
548            while id.IsOk():
549                self.__RemoveLayer(id)
550                id, cookie = self.GetNextChild(pid, cookie)
551    
552            wxTreeCtrl.DeleteAllItems(self)
553    
554        def __AddLayer(self, before, l):
555            root = self.GetRootItem()
556            id = self.InsertItemBefore(root, before,
557                                l.Title(),
558                                self.mapImageIndex,
559                                self.mapImageIndex)
560    
561            self.SetPyData(id, l)
562            self.__SetVisibilityStyle(l.Visible(), id)
563    
564            self.__FillTreeLayer(id)
565            self.Expand(id)
566    
567            l.Subscribe(LAYER_CHANGED, self._OnMsgLayerChanged)
568            l.Subscribe(LAYER_VISIBILITY_CHANGED,
569                        self._OnMsgLayerVisibilityChanged)
570            l.Subscribe(TITLE_CHANGED, self._OnMsgLayerTitleChanged)
571    
572        def __RemoveLayer(self, id):
573            self.DeleteChildren(id)
574    
575            layer = self.GetPyData(id)
576            layer.Unsubscribe(LAYER_CHANGED,
577                              self._OnMsgLayerChanged)
578            layer.Unsubscribe(LAYER_VISIBILITY_CHANGED,
579                              self._OnMsgLayerVisibilityChanged)
580            layer.Unsubscribe(TITLE_CHANGED, self._OnMsgLayerTitleChanged)
581    
582            self.Delete(id)
583    
584        def DeleteChildren(self, pid):
585            id, cookie = self.GetFirstChild(pid, 123)
586            while id.IsOk():
587                self.availImgListIndices.append(self.GetItemImage(id))
588                id, cookie = self.GetNextChild(pid, cookie)
589            wxTreeCtrl.DeleteChildren(self, pid)
590    
591        def GetRootItem(self):
592            root = wxTreeCtrl.GetRootItem(self)
593    
594            if not root.IsOk():
595                self.image_list = wxImageList(BMP_SIZE_W, BMP_SIZE_H, False, 0)
596    
597                bmp = wxEmptyBitmap(BMP_SIZE_W, BMP_SIZE_H)
598                dc = wxMemoryDC()
599                dc.SelectObject(bmp)
600                dc.SetBrush(wxBLACK_BRUSH)
601                dc.Clear()
602                dc.SelectObject(wxNullBitmap)
603    
604                self.emptyImageIndex = \
605                    self.image_list.AddWithColourMask(bmp, wxColour(0, 0, 0))
606    
607                bmp = resource.GetBitmapResource("legend_icon_layer",
608                                                  wxBITMAP_TYPE_XPM)
609                self.mapImageIndex = \
610                    self.image_list.Add(bmp)
611    
612                self.AssignImageList(self.image_list)
613                self.availImgListIndices = []
614    
615                root = self.AddRoot("")
616    
617            return root
618    
619      def __SetVisibilityStyle(self, visible, id):      def __SetVisibilityStyle(self, visible, id):
620          font = self.GetItemFont(id)          font = self.GetItemFont(id)
# Line 489  class LegendTree(wxTreeCtrl): Line 631  class LegendTree(wxTreeCtrl):
631          self.SetItemFont(id, font)          self.SetItemFont(id, font)
632                    
633      def __ShowHideLayer(self, layer):      def __ShowHideLayer(self, layer):
634          parent = self.layer2id[layer]          parent = self.find_layer(layer)
635          assert parent.IsOk()          assert parent.IsOk()
636    
637          visible = layer.Visible()          visible = layer.Visible()
# Line 543  class ScaleBarBitmap(wxBoxSizer): Line 685  class ScaleBarBitmap(wxBoxSizer):
685          dc.SelectObject(bmp)          dc.SelectObject(bmp)
686          dc.Clear()          dc.Clear()
687    
688          self.scalebar.DrawScaleBar(scale, dc, (0,0), dc.GetSizeTuple())          if self.canvas.map is not None \
689                and self.canvas.map.projection is not None:
690    
691                # if we are using a projection with geographics coordinates
692                # we need to change the scale value based on where we are
693                # on the globe.
694                if self.canvas.map.projection.GetProjectedUnits() \
695                    == PROJ_UNITS_DEGREES:
696    
697                    width, height = self.canvas.GetSizeTuple()
698                    long, lat = self.canvas.win_to_proj(width/2, height/2)
699    
700                    # slightly inaccurate, but if we are looking at
701                    # the north/south pole we could end up dividing by zero
702                    #
703                    # it shouldn't matter for our purposes that we ignore
704                    # the original sign of lat.
705                    if fabs(lat) > 89.9: lat = 89.9
706    
707                    #
708                    # one degree is about 111,133m at the equator
709                    # we need to adjust that for latitude as
710                    # we move north/south. use the center of the map
711                    # as the point to scale the length to.
712                    #
713                    scale = scale / (111133.0 * fabs(cos(lat * pi/180)))
714    
715                self.scalebar.DrawScaleBar(scale, dc, (0,0), dc.GetSizeTuple())
716    
717          self.scalebarBitmap.SetBitmap(bmp)          self.scalebarBitmap.SetBitmap(bmp)
718    

Legend:
Removed from v.990  
changed lines
  Added in v.1252

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26