/[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 542 by jonathan, Thu Mar 20 09:43:16 2003 UTC revision 2588 by bh, Tue Mar 29 18:05:01 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]>
5  #  #
6  # This program is free software under the GPL (>=v2)  # This program is free software under the GPL (>=v2)
7  # Read the file COPYING coming with Thuban for details.  # Read the file COPYING coming with Thuban for details.
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
16    
17  from wxPython.wx import *  from wxPython.wx import *
18  from dialogs import NonModalDialog  import wxPython
19    
20  from Thuban.Model.layer import Layer  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
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,\
27        LAYER_VISIBILITY_CHANGED, TITLE_CHANGED
28    
29  from Thuban.Model.classification import ClassGroup  from Thuban.UI.messages import SCALE_CHANGED
30    
31  from Thuban.UI.classifier import ClassDataPreviewer  from Thuban.UI.classifier import ClassDataPreviewer
32    from Thuban.UI.dock import DockPanel
33    from Thuban.UI.scalebar import ScaleBar
34    
35  ID_LEGEND_MOVEUP = 4001  from Thuban.UI.menu import Menu
 ID_LEGEND_MOVEDOWN = 4002  
 ID_LEGEND_TREE = 4003  
 ID_LEGEND_CLASSIFY = 4004  
 ID_LEGEND_SHOWLAYER = 4005  
 ID_LEGEND_HIDELAYER = 4006  
   
 BMP_SIZE_W = 30  
 BMP_SIZE_H = 15  
   
 class Legend(NonModalDialog):  
   
     def __init__(self, parent, name, map):  
         NonModalDialog.__init__(self, parent, name,  
                                 _("Legend: %s") % map.Title())  
36    
37          self.parent = parent  from Thuban.Lib.connector import ConnectorError
38    
39    ID_LEGEND_TOP = 4001
40    ID_LEGEND_RAISE = 4002
41    ID_LEGEND_LOWER = 4003
42    ID_LEGEND_BOTTOM = 4004
43    ID_LEGEND_TREE = 4005
44    ID_LEGEND_PROPS = 4006
45    ID_LEGEND_SHOWLAYER = 4007
46    ID_LEGEND_HIDELAYER = 4008
47    
48    BMP_SIZE_W = 16
49    BMP_SIZE_H = 16
50    
51    TOP_BMP = "top_layer"
52    RAISE_BMP = "raise_layer"
53    LOWER_BMP = "lower_layer"
54    BOTTOM_BMP = "bottom_layer"
55    SHOW_BMP  = "show_layer"
56    HIDE_BMP  = "hide_layer"
57    PROPS_BMP = "layer_properties"
58    
59          panel = wxPanel(self, -1)  class LegendPanel(DockPanel):
60    
61          topBox = wxBoxSizer(wxVERTICAL)      def __init__(self, parent, map, mainWindow):
62          panelBox = wxBoxSizer(wxVERTICAL)          DockPanel.__init__(self, parent, -1)
63    
64          buttonBox = wxGridSizer(2, 3, 0, 0)          self.mainWindow = mainWindow
65            self.parent = parent
66    
67          self.buttons = []          self.buttons = []
68    
69          button = wxButton(self, ID_LEGEND_MOVEUP, _("Move Up"))          panelBox = wxBoxSizer(wxVERTICAL)
70          buttonBox.Add(button, 0, wxGROW | wxLEFT | wxRIGHT, 0)  
71          self.buttons.append(button)          self.toolBar = wxToolBar(self, -1)
72            self.toolBar.SetToolBitmapSize(wxSize(24, 24))
73    
74          button = wxButton(self, ID_LEGEND_SHOWLAYER, _("Show Layer"))          bmp = resource.GetBitmapResource(TOP_BMP, wxBITMAP_TYPE_XPM)
75          buttonBox.Add(button, 0, wxGROW | wxLEFT | wxRIGHT, 0)          self.toolBar.AddTool(ID_LEGEND_TOP, bmp,
76          self.buttons.append(button)              shortHelpString=_("Top Layer"))
77    
78            bmp = resource.GetBitmapResource(RAISE_BMP, wxBITMAP_TYPE_XPM)
79            self.toolBar.AddTool(ID_LEGEND_RAISE, bmp,
80                shortHelpString=_("Raise Layer"))
81    
82            bmp = resource.GetBitmapResource(LOWER_BMP, wxBITMAP_TYPE_XPM)
83            self.toolBar.AddTool(ID_LEGEND_LOWER, bmp,
84                shortHelpString=_("Lower Layer"))
85    
86            bmp = resource.GetBitmapResource(BOTTOM_BMP, wxBITMAP_TYPE_XPM)
87            self.toolBar.AddTool(ID_LEGEND_BOTTOM, bmp,
88                shortHelpString=_("Bottom Layer"))
89    
90            bmp = resource.GetBitmapResource(SHOW_BMP, wxBITMAP_TYPE_XPM)
91            self.toolBar.AddTool(ID_LEGEND_SHOWLAYER, bmp,
92                shortHelpString=_("Show Layer"))
93    
94            bmp = resource.GetBitmapResource(HIDE_BMP, wxBITMAP_TYPE_XPM)
95            self.toolBar.AddTool(ID_LEGEND_HIDELAYER, bmp,
96                shortHelpString=_("Hide Layer"))
97    
98            bmp = resource.GetBitmapResource(PROPS_BMP, wxBITMAP_TYPE_XPM)
99            self.toolBar.AddTool(ID_LEGEND_PROPS, bmp,
100                shortHelpString=_("Edit Layer Properties"))
101    
102            self.toolBar.Realize()
103            panelBox.Add(self.toolBar, 0, wxGROW, 0)
104    
105            EVT_TOOL(self, ID_LEGEND_TOP, self._OnMoveTop)
106            EVT_TOOL(self, ID_LEGEND_RAISE, self._OnMoveUp)
107            EVT_TOOL(self, ID_LEGEND_LOWER, self._OnMoveDown)
108            EVT_TOOL(self, ID_LEGEND_BOTTOM, self._OnMoveBottom)
109            EVT_TOOL(self, ID_LEGEND_PROPS, self._OnProperties)
110            EVT_TOOL(self, ID_LEGEND_SHOWLAYER, self._OnShowLayer)
111            EVT_TOOL(self, ID_LEGEND_HIDELAYER, self._OnHideLayer)
112    
113          button = wxButton(self, ID_LEGEND_CLASSIFY, _("Classify"))          self.tree = LegendTree(self, ID_LEGEND_TREE, map, mainWindow)
         buttonBox.Add(button, 0, wxGROW | wxLEFT | wxRIGHT, 0)  
         self.buttons.append(button)  
114    
115          button = wxButton(self, ID_LEGEND_MOVEDOWN, _("Move Down"))          panelBox.Add(self.tree, 1, wxGROW, 0)
         buttonBox.Add(button, 0, wxGROW | wxLEFT | wxRIGHT, 0)  
         self.buttons.append(button)  
116    
117          button = wxButton(self, ID_LEGEND_HIDELAYER, _("Hide Layer"))          self.scalebarbitmap = ScaleBarBitmap(self, map, mainWindow)
118          buttonBox.Add(button, 0, wxGROW | wxLEFT | wxRIGHT, 0)          panelBox.Add(self.scalebarbitmap, 0, wxGROW, 0)
         self.buttons.append(button)  
119    
120            self.SetAutoLayout(True)
121            self.SetSizer(panelBox)
122            panelBox.SetSizeHints(self)
123    
         EVT_BUTTON(self, ID_LEGEND_MOVEUP, self._OnMoveUp)  
         EVT_BUTTON(self, ID_LEGEND_MOVEDOWN, self._OnMoveDown)  
         EVT_BUTTON(self, ID_LEGEND_CLASSIFY, self._OnClassify)  
         EVT_BUTTON(self, ID_LEGEND_SHOWLAYER, self._OnShowLayer)  
         EVT_BUTTON(self, ID_LEGEND_HIDELAYER, self._OnHideLayer)  
124    
125          panelBox.Add(buttonBox, 0, 0, 4)          self.panelBox = panelBox
126    
127          self.tree = LegendTree(self, ID_LEGEND_TREE, map)          self.__EnableButtons(False)
128    
129          panelBox.Add(self.tree, 1, wxGROW, 4)          self.Create()
130    
131          panel.SetAutoLayout(True)          EVT_CLOSE(self, self._OnClose)
         panel.SetSizer(panelBox)  
         panelBox.SetSizeHints(panel)  
132    
         topBox.Add(panel, 1, wxGROW, 0)  
         panelBox.SetSizeHints(self)  
133    
134          self.SetAutoLayout(True)      def GetMap(self):
135          self.SetSizer(topBox)          return self.tree.GetMap()
136    
137        def SetMap(self, map):
138            self.tree.SetMap(map)
139            self.scalebarbitmap.SetCanvas(self.mainWindow.canvas)
140    
141        def DoOnSelChanged(self, layer, group):
142    
143            ok = isinstance(layer, BaseLayer)
144            self.__EnableButtons(ok)
145    
146            self.mainWindow.SelectLayer(layer)
147    
148        def DoOnProperties(self):
149            list = self.tree.GetSelectedHierarchy()
150    
151            ok = isinstance(list[0], BaseLayer)
152            if ok:
153                self.mainWindow.OpenLayerProperties(list[0], list[1])
154    
155      def DoOnSelChanged(self):      def Destroy(self):
156          self.__EnableButtons(self.tree.GetSelection().IsOk())          self.__Close()
157    
158      def _OnClassify(self, event):      def _OnProperties(self, event):
159          self.tree.DoOnClassify()          self.DoOnProperties()
160    
161        def _OnMoveTop(self, event):
162            self.tree.MoveCurrentItemTop()
163            
164      def _OnMoveUp(self, event):      def _OnMoveUp(self, event):
165          self.tree.MoveCurrentItemUp()          self.tree.MoveCurrentItemUp()
166    
167      def _OnMoveDown(self, event):      def _OnMoveDown(self, event):
168          self.tree.MoveCurrentItemDown()          self.tree.MoveCurrentItemDown()
169    
170        def _OnMoveBottom(self, event):
171            self.tree.MoveCurrentItemBottom()
172    
173      def _OnShowLayer(self, event):      def _OnShowLayer(self, event):
174          self.tree.DoOnShowLayer()          self.tree.DoOnShowLayer()
175          pass          pass
176    
177        #def Close(self, force = False):
178            #DockPanel.Close(self, force)
179            
180        def _OnClose(self, event):
181            self.__Close()
182    
183      def _OnHideLayer(self, event):      def _OnHideLayer(self, event):
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          for b in self.buttons:          self.toolBar.EnableTool(ID_LEGEND_TOP, on)
201              b.Enable(on)          self.toolBar.EnableTool(ID_LEGEND_RAISE, on)
202            self.toolBar.EnableTool(ID_LEGEND_LOWER, on)
203            self.toolBar.EnableTool(ID_LEGEND_BOTTOM, on)
204            self.toolBar.EnableTool(ID_LEGEND_SHOWLAYER,  on)
205            self.toolBar.EnableTool(ID_LEGEND_HIDELAYER,  on)
206            self.toolBar.EnableTool(ID_LEGEND_PROPS, on)
207    
208        def __Close(self):
209            self.tree.Close()
210    
211  class LegendTree(wxTreeCtrl):  class LegendTree(wxTreeCtrl):
212    
213      def __init__(self, parent, id, map):      def __init__(self, parent, id, map, mainWindow):
214          wxTreeCtrl.__init__(self, parent, id,          wxTreeCtrl.__init__(self, parent, id,
215                              style = wxTR_DEFAULT_STYLE | wxTR_HIDE_ROOT,                              style = wxTR_DEFAULT_STYLE | wxTR_HIDE_ROOT,
216                              size = (200, 200))                              size = (200, 200))
217    
218            self.mainWindow = mainWindow
219            self.map = None
220          self.parent = parent          self.parent = parent
221          self.map = map          self.changing_selection = 0
         self.layer2id = None  
222    
223            #
224            # The image list used by the wxTreeCtrl causes problems when
225            # we remove layers and/or change a classification because it
226            # changes the image indices if you remove images from the list.
227            # Rather than removing unused images we use this list to keep
228            # track of which indices are available in the image list
229            # (because of a previous removal) and then  replace those indices
230            # with new images rather than appending to the end of the image
231            # list (assuming there are any that are available).
232            #
233            self.availImgListIndices = []
234    
235          self.image_list = None          self.image_list = None
236          self.emptyImageIndex = 0          self.emptyImageIndex = 0
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)
250    
251            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):
296            self.SetMap(None)
297    
298        def GetMap(self):
299            return self.map
300    
301        def SetMap(self, map):
302    
303            sub_list = [(MAP_STACKING_CHANGED, self._OnMsgMapStackingChanged),
304                        (MAP_LAYERS_ADDED, self._OnMsgMapLayersAdded),
305                        (MAP_LAYERS_REMOVED, self._OnMsgMapLayersRemoved)]
306    
307            if self.map is not None:
308                for msg, func in sub_list: self.map.Unsubscribe(msg, func)
309                #self.mainWindow.application.Unsubscribe(SESSION_REPLACED,
310                    #self._OnMsgMapsChanged)
311                #try:
312                    #self.mainWindow.application.session.Unsubscribe(MAPS_CHANGED,
313                        #self._OnMsgMapsChanged)
314                #except ConnectorError:
315                    #pass
316                self.DeleteAllItems()
317            
318            self.map = map
319    
320          map.Subscribe(MAP_STACKING_CHANGED, self._OnMsgMapStackingChanged)          if self.map is not None:
321          map.Subscribe(MAP_LAYERS_CHANGED, self._OnMsgMapLayersChanged)              for msg, func in sub_list: self.map.Subscribe(msg, func)
322                #self.mainWindow.application.session.Subscribe(MAPS_CHANGED,
323          self.__FillTree(map)                  #self._OnMsgMapsChanged)
324                #self.mainWindow.application.Subscribe(SESSION_REPLACED,
325      def MoveCurrentItemUp(self):                  #self._OnMsgMapsChanged)
326          cur_id = self.GetSelection()              self.__FillTree(self.map)
         assert(cur_id.IsOk())  
327    
328          cur_data = self.GetPyData(cur_id)      def MoveCurrentItemTop(self):
329            layer, group = self.GetSelectedHierarchy()
330    
331          #prev_id = self.GetPrevSibling(cur_id)          if layer is not None:
332                self.map.MoveLayerToTop(layer)
333            else:
334                assert False, "Shouldn't be allowed."
335                pass
336    
337          #      def MoveCurrentItemUp(self):
338          # Get out if there's nowhere to go          layer, group = self.GetSelectedHierarchy()
         #  
         #if prev_id == INVALID_TREE_ID: return  
339    
340          if isinstance(cur_data, Layer):          if layer is not None:
341              self.map.RaiseLayer(cur_data)              self.map.RaiseLayer(layer)
         elif isinstance(cur_data, ClassGroup):  
             pass  
342          else:          else:
343              assert(False, "Shouldn't be here.")              assert False, "Shouldn't be allowed."
344              pass              pass
345    
346      def MoveCurrentItemDown(self):      def MoveCurrentItemDown(self):
347          cur_id = self.GetSelection()          layer, group = self.GetSelectedHierarchy()
         assert(cur_id.IsOk())  
348    
349          cur_data = self.GetPyData(cur_id)          if layer is not None:
350                self.map.LowerLayer(layer)
         if isinstance(cur_data, Layer):  
             self.map.LowerLayer(cur_data)  
         elif isinstance(cur_data, ClassGroup):  
             pass  
351          else:          else:
352              assert(False, "Shouldn't be here.")              assert False, "Shouldn't be allowed."
353              pass              pass
354    
355        def MoveCurrentItemBottom(self):
356            layer, group = self.GetSelectedHierarchy()
357    
358            if layer is not None:
359                self.map.MoveLayerToBottom(layer)
360            else:
361                assert False, "Shouldn't be allowed."
362                pass
363    
364      def OnCompareItems(self, item1, item2):      def OnCompareItems(self, item1, item2):
365    
366          data1 = self.GetPyData(item1)          data1 = self.GetPyData(item1)
367          data2 = self.GetPyData(item2)          data2 = self.GetPyData(item2)
368    
369          if isinstance(data1, Layer):          if isinstance(data1, BaseLayer):
370              layers = self.map.Layers()              layers = self.map.Layers()
371              return layers.index(data2) - layers.index(data1)              return layers.index(data2) - layers.index(data1)
372          else:          else:
373              return wxTreeCtrl.OnCompareItems(self, item1, item2)              return wxTreeCtrl.OnCompareItems(self, item1, item2)
374    
   
375      def DoOnShowLayer(self):      def DoOnShowLayer(self):
376          self.__ShowHideLayer(True)          layer, group = self.GetSelectedHierarchy()
377            layer.SetVisible(True)
378    
379      def DoOnHideLayer(self):      def DoOnHideLayer(self):
380          self.__ShowHideLayer(False)          layer, group = self.GetSelectedHierarchy()
381            layer.SetVisible(False)
382    
383      def DoOnClassify(self):      def ToggleVisibility(self):
384          id = self.GetSelection()          layer, group = self.GetSelectedHierarchy()
         assert(id.IsOk())  
385    
386          item = self.GetPyData(id)          layer.SetVisible(not layer.Visible())
         if isinstance(item, ClassGroup):  
             id = self.GetItemParent(id)  
             assert(id.IsOk())  
             item = self.GetPyData(id)  
387    
388          self.parent.parent.OpenClassifier(item)      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    
394        def GetSelectedHierarchy(self):
395            id = self.GetSelection()
396    
397            if not id.IsOk():
398                return (None, None)
399    
400            layer = self.GetPyData(id)
401            group = None
402    
403            if isinstance(layer, ClassGroup):
404                id = self.GetItemParent(id)
405                assert id.IsOk()
406                group = layer
407                layer = self.GetPyData(id)
408    
409            return (layer, group)
410    
411        def _OnMsgMapsChanged(self):
412            #print self.map is self.mainWindow.Map()
413            self.SetMap(self.mainWindow.Map())
414            
415      def _OnSelChanged(self, event):      def _OnSelChanged(self, event):
416          self.parent.DoOnSelChanged()          # If we change the selection from normalize_selection do nothing.
417            if self.changing_selection:
418                return
419    
420            self.normalize_selection()
421            self.__UpdateSelection()
422    
423        def normalize_selection(self):
424            """Select the layer containing currently selected item"""
425            # This is really a workaround for a bug in wx where deleting a
426            # subtree with DeleteChildren does not update the selection
427            # properly and can lead to segfaults later because the return
428            # value of GetSelection points to invalid data.
429            item = self.GetSelection()
430            while item.IsOk():
431                object = self.GetPyData(item)
432                if isinstance(object, BaseLayer):
433                    break
434                item = self.GetItemParent(item)
435            else:
436                # No layer was found in the chain of parents, so there's
437                # nothing we can do.
438                return
439    
440            self.changing_selection = 1
441            try:
442                self.SelectItem(item)
443            finally:
444                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.DoOnClassify()          # 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, Layer))          assert isinstance(layer, BaseLayer)
470    
471          id = self.layer2id[layer]          id = self.find_layer(layer)
472            assert id is not None
473    
474          self.__FillTreeLayer(id)          self.__FillTreeLayer(id)
475            self.__UpdateSelection()
476    
477      def _OnMsgMapStackingChanged(self, *args):      def _OnMsgMapStackingChanged(self, *args):
478          self.Sort()          self.Sort()
479            id = self.GetSelection()
480    
481      def _OnMsgMapLayersChanged(self, map):          if id.IsOk():
482          assert(id(map) == id(self.map))              self.EnsureVisible(id)
483            self.__UpdateSelection()
484    
485          self.__FillTree(self.map)      def _OnMsgMapLayersAdded(self, map):
486            assert map is self.map
487    
488      def __FillTree(self, map):          # Build a dict with all layers known by the the tree as keys
489            layers = {}
490            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          assert(isinstance(map, Map))          # Add layers in the map but not in the dict
497            i = 0
498            for l in map.Layers():
499                if not l in layers:
500                    self.__AddLayer(i, l)
501    
502          self.Freeze()          self.__UpdateSelection()
503    
504          self.__DeleteAllItems()      def _OnMsgMapLayersRemoved(self, map):
505            assert map is self.map
506    
507          if map.HasLayers():          layers = map.Layers()
508    
509              self.image_list = wxImageList(BMP_SIZE_W, BMP_SIZE_H, False, 0)          root = self.GetRootItem()
510                                                                                            id, cookie = self.GetFirstChild(root)
511              bmp = wxEmptyBitmap(BMP_SIZE_W, BMP_SIZE_H)          while id.IsOk():
512              dc = wxMemoryDC()              if self.GetPyData(id) not in layers:
513              dc.SelectObject(bmp)                  self.__RemoveLayer(id)
514              dc.SetBrush(wxBLACK_BRUSH)              id, cookie = self.GetNextChild(root, cookie)
             dc.Clear()  
             dc.SelectObject(wxNullBitmap)  
                                                                                   
             self.emptyImageIndex = \  
                 self.image_list.AddWithColourMask(bmp, wxColour(0, 0, 0))  
                                                                                   
             self.AssignImageList(self.image_list)  
515    
             root = self.AddRoot("")  
516    
517              for l in map.Layers():          self.__UpdateSelection()
                 id = self.PrependItem(root, l.Title())  
                 l.Subscribe(LAYER_CHANGED, self._OnMsgLayerChanged)  
                 self.SetPyData(id, l)  
                 font = self.GetItemFont(id)  
                 if not l.Visible():  
                     font.SetStyle(wxITALIC)  
                     self.SetItemFont(id, font)  
518    
519                  self.layer2id[l] = id      def _OnMsgLayerVisibilityChanged(self, layer):
520            assert isinstance(layer, BaseLayer)
521    
522                  self.__FillTreeLayer(id)          self.__ShowHideLayer(layer)
523                  self.Expand(id)          self.__UpdateSelection()
524    
525        def _OnMsgLayerTitleChanged(self, layer):
526    
527            id = self.find_layer(layer)
528            if id.IsOk():
529                self.SetItemText(id, layer.Title())
530            self.__UpdateSelection()
531    
532        def __UpdateSelection(self):
533            layer, group = self.GetSelectedHierarchy()
534            self.parent.DoOnSelChanged(layer, group)
535            
536        def __FillTree(self, map):
537    
538            self.Freeze()
539    
540            self.DeleteAllItems()
541    
542            if map.HasLayers():
543                root = self.GetRootItem()
544                for l in map.Layers():
545                    self.__AddLayer(0, l)
546    
547          self.Thaw()          self.Thaw()
548    
549      def __FillTreeLayer(self, pid):      def __FillTreeLayer(self, pid):
550    
551          layer = self.GetPyData(pid)          layer = self.GetPyData(pid)
552    
553          self.Freeze()          self.Freeze()
554    
555          self.DeleteChildren(pid)          self.DeleteChildren(pid)
556    
557          clazz = layer.GetClassification()          if layer.HasClassification():
   
         shapeType = layer.ShapeType()  
   
         for g in clazz:  
             id = self.AppendItem(pid, g.GetDisplayText())  
             self.SetPyData(id, g)  
558    
559              bmp = self.__BuildGroupImage(g, shapeType)              clazz = layer.GetClassification()
560    
561              if bmp is None:              shapeType = layer.ShapeType()
                 self.SetItemImage(id, self.emptyImageIndex)  
             else:  
                 i = self.image_list.Add(bmp)  
                 self.SetItemImage(id, i)  
562    
563              #self.layer2id[g] = id              show = layer.Visible()
564                for g in clazz:
565                    if g.IsVisible():
566                        id = self.AppendItem(pid, g.GetDisplayText())
567                        self.SetPyData(id, g)
568                        self.__SetVisibilityStyle(show, id)
569    
570                        bmp = self.__BuildGroupImage(g, shapeType)
571    
572                        if bmp is None:
573                            self.SetItemImage(id, -1, wxTreeItemIcon_Normal)
574                            self.SetItemImage(id, -1, wxTreeItemIcon_Selected)
575                            #self.SetItemSelectedImage(id, -1)
576                        else:
577                            if self.availImgListIndices:
578                                i = self.availImgListIndices.pop(0)
579                                self.image_list.Replace(i, bmp)
580                            else:
581                                i = self.image_list.Add(bmp)
582    
583                            self.SetItemImage(id, i, wxTreeItemIcon_Normal)
584                            self.SetItemImage(id, i, wxTreeItemIcon_Selected)
585                            #self.SetItemlectedImage(id, i)
586    
587          self.Thaw()          self.Thaw()
588    
589      def __BuildGroupImage(self, group, shapeType):      def __BuildGroupImage(self, group, shapeType):
         assert(isinstance(group, ClassGroup))  
590    
591          bmp = wxEmptyBitmap(BMP_SIZE_W, BMP_SIZE_H)          bmp = wxEmptyBitmap(BMP_SIZE_W, BMP_SIZE_H)
592          #brush = wxBrush(Color2wxColour(item[1]), wxSOLID)          #brush = wxBrush(Color2wxColour(item[1]), wxSOLID)
# Line 316  class LegendTree(wxTreeCtrl): Line 598  class LegendTree(wxTreeCtrl):
598    
599          return bmp          return bmp
600    
601      def __DeleteAllItems(self):      def DeleteAllItems(self):
         self.DeleteAllItems()  
         self.layer2id = {}  
602    
603            pid = self.GetRootItem()
604    
605      def __ShowHideLayer(self, show):          id, cookie = self.GetFirstChild(pid)
606          id = self.GetSelection()          while id.IsOk():
607          assert(id.IsOk())              self.__RemoveLayer(id)
608                id, cookie = self.GetNextChild(pid, cookie)
609    
610            wxTreeCtrl.DeleteAllItems(self)
611    
612        def __AddLayer(self, before, l):
613            root = self.GetRootItem()
614            id = self.InsertItemBefore(root, before,
615                                l.Title(),
616                                self.mapImageIndex,
617                                self.mapImageIndex)
618    
619            self.SetPyData(id, l)
620            self.__SetVisibilityStyle(l.Visible(), id)
621    
622            self.__FillTreeLayer(id)
623            self.Expand(id)
624    
625            l.Subscribe(LAYER_CHANGED, self._OnMsgLayerChanged)
626            l.Subscribe(LAYER_VISIBILITY_CHANGED,
627                        self._OnMsgLayerVisibilityChanged)
628            l.Subscribe(TITLE_CHANGED, self._OnMsgLayerTitleChanged)
629    
630        def __RemoveLayer(self, id):
631            self.DeleteChildren(id)
632    
633            layer = self.GetPyData(id)
634            layer.Unsubscribe(LAYER_CHANGED,
635                              self._OnMsgLayerChanged)
636            layer.Unsubscribe(LAYER_VISIBILITY_CHANGED,
637                              self._OnMsgLayerVisibilityChanged)
638            layer.Unsubscribe(TITLE_CHANGED, self._OnMsgLayerTitleChanged)
639    
640            self.Delete(id)
641    
642        def DeleteChildren(self, pid):
643            id, cookie = self.GetFirstChild(pid)
644            while id.IsOk():
645                self.availImgListIndices.append(self.GetItemImage(id))
646                id, cookie = self.GetNextChild(pid, cookie)
647            wxTreeCtrl.DeleteChildren(self, pid)
648    
649        def GetRootItem(self):
650            root = wxTreeCtrl.GetRootItem(self)
651    
652            if not root.IsOk():
653                self.image_list = wxImageList(BMP_SIZE_W, BMP_SIZE_H, False, 0)
654    
655                bmp = wxEmptyBitmap(BMP_SIZE_W, BMP_SIZE_H)
656                dc = wxMemoryDC()
657                dc.SelectObject(bmp)
658                dc.SetBrush(wxBLACK_BRUSH)
659                dc.Clear()
660                dc.SelectObject(wxNullBitmap)
661    
662                self.emptyImageIndex = \
663                    self.image_list.AddWithColourMask(bmp, wxColour(0, 0, 0))
664    
665                bmp = resource.GetBitmapResource("legend_icon_layer",
666                                                  wxBITMAP_TYPE_XPM)
667                self.mapImageIndex = \
668                    self.image_list.Add(bmp)
669    
670                self.AssignImageList(self.image_list)
671                self.availImgListIndices = []
672    
673                root = self.AddRoot("")
674    
675            return root
676    
677        def __SetVisibilityStyle(self, visible, id):
678            font = self.GetItemFont(id)
679    
680            if visible:
681                font.SetStyle(wxNORMAL)
682                color = wxBLACK
683            else:
684                #font.SetStyle(wxITALIC)
685                font.SetStyle(wxNORMAL)
686                color = wxLIGHT_GREY
687    
688            self.SetItemTextColour(id, color)
689            self.SetItemFont(id, font)
690                    
691          item = self.GetPyData(id)      def __ShowHideLayer(self, layer):
692          if isinstance(item, ClassGroup):          parent = self.find_layer(layer)
693              id = self.GetItemParent(id)          assert parent.IsOk()
694              assert(id.IsOk())  
695              item = self.GetPyData(id)          visible = layer.Visible()
696    
697            self.__SetVisibilityStyle(visible, parent)
698    
699          if show != item.Visible():          id, cookie = self.GetFirstChild(parent)
700    
701            while id.IsOk():
702                self.__SetVisibilityStyle(visible, id)
703                id, cookie = self.GetNextChild(parent, cookie)
704    
705        # In wxPython 2.4 the GetFirstChild method has to be called with a
706        # second argument and in 2.5 it must not.  Reading the code of
707        # wxPython 2.4 it seems that the second parameter was intended to be
708        # optional there but due to a bug in the C++ code it doesn't work
709        # and omitting the second argument leads to a segfault.  To cope
710        # with this and to make the code usable with both 2.5 and 2.4 we
711        # overwrite the inherited method when running with 2.4 to provide a
712        # default value for the second argument.
713        if map(int, wxPython.__version__.split(".")[:2]) < [2, 5]:
714            def GetFirstChild(self, item):
715                return wxTreeCtrl.GetFirstChild(self, item, 0)
716    
717    
718    class ScaleBarBitmap(wxBoxSizer):
719    
720        def __init__(self, parent, map, mainWindow):
721            # While the width is fixed, get the height _now_.
722            dc = wxMemoryDC()
723            textwidth, textheight = dc.GetTextExtent("%d"%0)
724            self.width = 210
725            self.height = textheight + 3*2 + 8
726    
727            wxBoxSizer.__init__(self, wxVERTICAL)
728            bmp=wxEmptyBitmap(self.width, self.height)
729            self.scalebarBitmap = wxStaticBitmap(parent, -1, bmp)
730            self.Add(self.scalebarBitmap, 0, wxALIGN_CENTER|wxLEFT|wxTOP|wxRIGHT, 1)
731    
732            self.mainWindow = mainWindow
733            self.parent = parent
734            self.canvas = None
735            self.SetCanvas(self.mainWindow.canvas)
736    
737        def SetCanvas(self, canvas):
738            sub_list = [(SCALE_CHANGED, self._OnMsgScaleChanged)]
739    
740            if self.canvas is not None:
741                for msg, func in sub_list: self.canvas.Unsubscribe(msg, func)
742            
743            self.canvas = canvas
744            self.scalebar = ScaleBar(canvas.map)
745    
746            if self.canvas is not None:
747                for msg, func in sub_list: self.canvas.Subscribe(msg, func)
748                self.__SetScale(self.canvas.scale)
749    
750        def _OnMsgScaleChanged(self, scale):
751            self.__SetScale(scale)
752    
753        def __SetScale(self, scale):
754            bmp = wxEmptyBitmap(self.width, self.height)
755            dc = wxMemoryDC()
756            dc.SelectObject(bmp)
757            dc.Clear()
758    
759              item.SetVisible(show)          if self.canvas.map is not None \
760                and self.canvas.map.projection is not None:
761    
762              font = self.GetItemFont(id)              # if we are using a projection with geographics coordinates
763              if show:              # we need to change the scale value based on where we are
764                  font.SetStyle(wxNORMAL)              # on the globe.
765                  self.SetItemFont(id, font)              if self.canvas.map.projection.GetProjectedUnits() \
766              else:                  == PROJ_UNITS_DEGREES:
767                  font.SetStyle(wxITALIC)  
768                  self.SetItemFont(id, font)                  width, height = self.canvas.GetSizeTuple()
769                    long, lat = self.canvas.win_to_proj(width/2, height/2)
770    
771                    # slightly inaccurate, but if we are looking at
772                    # the north/south pole we could end up dividing by zero
773                    #
774                    # it shouldn't matter for our purposes that we ignore
775                    # the original sign of lat.
776                    if fabs(lat) > 89.9: lat = 89.9
777    
778                    #
779                    # one degree is about 111,133m at the equator
780                    # we need to adjust that for latitude as
781                    # we move north/south. use the center of the map
782                    # as the point to scale the length to.
783                    #
784                    scale = scale / (111133.0 * fabs(cos(lat * pi/180)))
785    
786                self.scalebar.DrawScaleBar(scale, dc, (0,0), dc.GetSizeTuple())
787    
788            self.scalebarBitmap.SetBitmap(bmp)
789    

Legend:
Removed from v.542  
changed lines
  Added in v.2588

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26