/[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 605 by jonathan, Fri Apr 4 12:16:13 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]>
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    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
 from Thuban.Model.messages import *  
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 \
26        MAP_STACKING_CHANGED, MAP_LAYERS_ADDED, MAP_LAYERS_REMOVED, LAYER_CHANGED,\
27        LAYER_VISIBILITY_CHANGED, TITLE_CHANGED
28    
29    from Thuban.UI.messages import SCALE_CHANGED
30    
 from Thuban.UI.messages import *  
31  from Thuban.UI.classifier import ClassDataPreviewer  from Thuban.UI.classifier import ClassDataPreviewer
32  from Thuban.UI.dock import DockPanel  from Thuban.UI.dock import DockPanel
33    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_MOVEUP = 4001  ID_LEGEND_TOP = 4001
40  ID_LEGEND_MOVEDOWN = 4002  ID_LEGEND_RAISE = 4002
41  ID_LEGEND_TREE = 4003  ID_LEGEND_LOWER = 4003
42  ID_LEGEND_CLASSIFY = 4004  ID_LEGEND_BOTTOM = 4004
43  ID_LEGEND_SHOWLAYER = 4005  ID_LEGEND_TREE = 4005
44  ID_LEGEND_HIDELAYER = 4006  ID_LEGEND_PROPS = 4006
45    ID_LEGEND_SHOWLAYER = 4007
46    ID_LEGEND_HIDELAYER = 4008
47    
48  BMP_SIZE_W = 30  BMP_SIZE_W = 15
49  BMP_SIZE_H = 15  BMP_SIZE_H = 15
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  class LegendPanel(DockPanel):  class LegendPanel(DockPanel):
60    
61      def __init__(self, parent, map, mainWindow):      def __init__(self, parent, map, mainWindow):
# Line 40  class LegendPanel(DockPanel): Line 64  class LegendPanel(DockPanel):
64          self.mainWindow = mainWindow          self.mainWindow = mainWindow
65          self.parent = parent          self.parent = parent
66    
         panelBox = wxBoxSizer(wxVERTICAL)  
   
         buttonBox = wxGridSizer(2, 3, 0, 0)  
   
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))
         button = wxButton(self, ID_LEGEND_SHOWLAYER, _("Show Layer"))  
         buttonBox.Add(button, 0, wxGROW | wxLEFT | wxRIGHT, 0)  
         self.buttons.append(button)  
   
         button = wxButton(self, ID_LEGEND_CLASSIFY, _("Classify"))  
         buttonBox.Add(button, 0, wxGROW | wxLEFT | wxRIGHT, 0)  
         self.buttons.append(button)  
   
         button = wxButton(self, ID_LEGEND_MOVEDOWN, _("Move Down"))  
         buttonBox.Add(button, 0, wxGROW | wxLEFT | wxRIGHT, 0)  
         self.buttons.append(button)  
   
         button = wxButton(self, ID_LEGEND_HIDELAYER, _("Hide Layer"))  
         buttonBox.Add(button, 0, wxGROW | wxLEFT | wxRIGHT, 0)  
         self.buttons.append(button)  
   
         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)  
73    
74          panelBox.Add(buttonBox, 0, 0, 4)          bmp = resource.GetBitmapResource(TOP_BMP, wxBITMAP_TYPE_XPM)
75            self.toolBar.AddTool(ID_LEGEND_TOP, bmp,
76                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          self.tree = LegendTree(self, ID_LEGEND_TREE, map, mainWindow)          self.tree = LegendTree(self, ID_LEGEND_TREE, map, mainWindow)
114    
115          panelBox.Add(self.tree, 1, wxGROW, 4)          panelBox.Add(self.tree, 1, wxGROW, 0)
116    
117          panelBox.Fit(self)          self.scalebarbitmap = ScaleBarBitmap(self, map, mainWindow)
118            panelBox.Add(self.scalebarbitmap, 0, wxGROW, 0)
119    
120          self.SetAutoLayout(True)          self.SetAutoLayout(True)
121          self.SetSizer(panelBox)          self.SetSizer(panelBox)
122          panelBox.SetSizeHints(self)          panelBox.SetSizeHints(self)
123    
         #panelBox.SetSizeHints(self.parent)  
124    
125          self.panelBox = panelBox          self.panelBox = panelBox
126    
127            self.__EnableButtons(False)
128    
129            self.Create()
130    
131          EVT_CLOSE(self, self._OnClose)          EVT_CLOSE(self, self._OnClose)
132    
133    
# Line 96  class LegendPanel(DockPanel): Line 136  class LegendPanel(DockPanel):
136    
137      def SetMap(self, map):      def SetMap(self, map):
138          self.tree.SetMap(map)          self.tree.SetMap(map)
139            self.scalebarbitmap.SetCanvas(self.mainWindow.canvas)
140    
141      def DoOnSelChanged(self, layer, group):      def DoOnSelChanged(self, layer, group):
142    
143          ok = isinstance(layer, Layer)          ok = isinstance(layer, BaseLayer)
144          self.__EnableButtons(ok)          self.__EnableButtons(ok)
145    
146          if ok:          self.mainWindow.SelectLayer(layer)
             self.mainWindow.SelectLayer(layer)  
147    
148      def DoOnClassify(self):      def DoOnProperties(self):
149          list = self.tree.GetSelectedHierarchy()          list = self.tree.GetSelectedHierarchy()
150    
151          ok = isinstance(list[0], Layer)          ok = isinstance(list[0], BaseLayer)
152          if ok:          if ok:
153              self.mainWindow.OpenClassifier(list[0], list[1])              self.mainWindow.OpenLayerProperties(list[0], list[1])
154    
155      def Destroy(self):      def Destroy(self):
156          self.__Close()          self.__Close()
157    
158      def _OnClassify(self, event):      def _OnProperties(self, event):
159          self.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
# Line 138  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          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):      def __Close(self):
209          self.tree.Close()          self.tree.Close()
# Line 155  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
221          self.layer2id = {}          self.changing_selection = 0
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)          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 178  class LegendTree(wxTreeCtrl): Line 301  class LegendTree(wxTreeCtrl):
301      def SetMap(self, map):      def SetMap(self, map):
302    
303          sub_list = [(MAP_STACKING_CHANGED, self._OnMsgMapStackingChanged),          sub_list = [(MAP_STACKING_CHANGED, self._OnMsgMapStackingChanged),
304                      (MAP_LAYERS_ADDED, self._OnMsgMapLayersAddedRemoved),                      (MAP_LAYERS_ADDED, self._OnMsgMapLayersAdded),
305                      (MAP_LAYERS_REMOVED, self._OnMsgMapLayersAddedRemoved)]                      (MAP_LAYERS_REMOVED, self._OnMsgMapLayersRemoved)]
306    
307          if self.map is not None:          if self.map is not None:
308              for msg, func in sub_list: self.map.Unsubscribe(msg, func)              for msg, func in sub_list: self.map.Unsubscribe(msg, func)
# Line 190  class LegendTree(wxTreeCtrl): Line 313  class LegendTree(wxTreeCtrl):
313                      #self._OnMsgMapsChanged)                      #self._OnMsgMapsChanged)
314              #except ConnectorError:              #except ConnectorError:
315                  #pass                  #pass
316              self.__DeleteAllItems()              self.DeleteAllItems()
317                    
318          self.map = map          self.map = map
319    
# Line 202  class LegendTree(wxTreeCtrl): Line 325  class LegendTree(wxTreeCtrl):
325                  #self._OnMsgMapsChanged)                  #self._OnMsgMapsChanged)
326              self.__FillTree(self.map)              self.__FillTree(self.map)
327    
328                    def MoveCurrentItemTop(self):
329      def MoveCurrentItemUp(self):          layer, group = self.GetSelectedHierarchy()
         cur_id = self.GetSelection()  
         assert cur_id.IsOk()  
   
         cur_data = self.GetPyData(cur_id)  
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()  
   
         cur_data = self.GetPyData(cur_id)  
348    
349          if isinstance(cur_data, Layer):          if layer is not None:
350              self.map.LowerLayer(cur_data)              self.map.LowerLayer(layer)
         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):
         #self.__ShowHideLayer(True)  
376          layer, group = self.GetSelectedHierarchy()          layer, group = self.GetSelectedHierarchy()
377          layer.SetVisible(True)          layer.SetVisible(True)
378    
379      def DoOnHideLayer(self):      def DoOnHideLayer(self):
         #self.__ShowHideLayer(False)  
380          layer, group = self.GetSelectedHierarchy()          layer, group = self.GetSelectedHierarchy()
381          layer.SetVisible(False)          layer.SetVisible(False)
382    
383  #   def DoOnClassify(self):      def ToggleVisibility(self):
384  #       id = self.GetSelection()          layer, group = self.GetSelectedHierarchy()
385  #       assert id.IsOk()  
386            layer.SetVisible(not layer.Visible())
387  #       item = self.GetPyData(id)  
388  #       if isinstance(item, ClassGroup):      def LayerProjection(self):
389  #           id = self.GetItemParent(id)          self.parent.mainWindow.LayerProjection()
 #           assert id.IsOk()  
 #           item = self.GetPyData(id)  
   
 #       # XXX: THIS IS SUCH AWFUL STYLE! YUCK!  
 #       self.parent.mainWindow.OpenClassifier(item)  
 #       #assert False, "XXX: FIXME HERE"  
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):      def _OnMsgMapsChanged(self):
412          print "ADfsadfsadfsadfsa"          #print self.map is self.mainWindow.Map()
         print self.map is self.mainWindow.Map()  
413          self.SetMap(self.mainWindow.Map())          self.SetMap(self.mainWindow.Map())
414                    
415      def _OnSelChanged(self, event):      def _OnSelChanged(self, event):
416            # 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          layer, group = self.GetSelectedHierarchy()  
447          self.parent.DoOnSelChanged(layer, group)      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.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.IsOk()          assert id is not None
473    
474          # XXX: yikes! this is so bad, we should be doing what is          self.__FillTreeLayer(id)
475          #      commented out, but there is a problem with keeping          self.__UpdateSelection()
         #      track of the images in the image list when we replace  
         #      a layer. it ends up causing a seg fault.  
         self.__FillTree(self.map)  
         #self.__FillTreeLayer(id)  
476    
477      def _OnMsgMapStackingChanged(self, *args):      def _OnMsgMapStackingChanged(self, *args):
478          self.Sort()          self.Sort()
# Line 310  class LegendTree(wxTreeCtrl): Line 480  class LegendTree(wxTreeCtrl):
480    
481          if id.IsOk():          if id.IsOk():
482              self.EnsureVisible(id)              self.EnsureVisible(id)
483            self.__UpdateSelection()
484    
485      def _OnMsgMapLayersAddedRemoved(self, map):      def _OnMsgMapLayersAdded(self, map):
486          assert map is self.map          assert map is self.map
487    
488          self.__FillTree(self.map)          # Build a dict with all layers known by the the tree as keys
489            layers = {}
490      def _OnMsgLayerVisibilityChanged(self, layer):          root = self.GetRootItem()
491          assert isinstance(layer, Layer)          id, cookie = self.GetFirstChild(root)
492            while id.IsOk():
493                layers[self.GetPyData(id)] = 1
494                id, cookie = self.GetNextChild(root, cookie)
495    
496          self.__ShowHideLayer(layer)          # 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      def GetSelectedHierarchy(self):          self.__UpdateSelection()
         id = self.GetSelection()  
         assert id.IsOk()  
503    
504          layer = self.GetPyData(id)      def _OnMsgMapLayersRemoved(self, map):
505          group = None          assert map is self.map
506    
507          if isinstance(layer, ClassGroup):          layers = map.Layers()
             id = self.GetItemParent(id)  
             assert id.IsOk()  
             group = layer  
             layer = self.GetPyData(id)  
508    
509          return (layer, group)          root = self.GetRootItem()
510            id, cookie = self.GetFirstChild(root)
511            while id.IsOk():
512                if self.GetPyData(id) not in layers:
513                    self.__RemoveLayer(id)
514                id, cookie = self.GetNextChild(root, cookie)
515    
     def __FillTree(self, map):  
516    
517          assert isinstance(map, Map)          self.__UpdateSelection()
518    
519          self.Freeze()      def _OnMsgLayerVisibilityChanged(self, layer):
520            assert isinstance(layer, BaseLayer)
521    
522          self.__DeleteAllItems()          self.__ShowHideLayer(layer)
523            self.__UpdateSelection()
524    
525          if map.HasLayers():      def _OnMsgLayerTitleChanged(self, layer):
526    
527              self.image_list = wxImageList(BMP_SIZE_W, BMP_SIZE_H, False, 0)          id = self.find_layer(layer)
528                                                                                            if id.IsOk():
529              bmp = wxEmptyBitmap(BMP_SIZE_W, BMP_SIZE_H)              self.SetItemText(id, layer.Title())
530              dc = wxMemoryDC()          self.__UpdateSelection()
             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)  
531    
532              root = self.AddRoot("")      def __UpdateSelection(self):
533            layer, group = self.GetSelectedHierarchy()
534            self.parent.DoOnSelChanged(layer, group)
535            
536        def __FillTree(self, map):
537    
538              for l in map.Layers():          self.Freeze()
                 id = self.PrependItem(root, l.Title())  
                 l.Subscribe(LAYER_CHANGED, self._OnMsgLayerChanged)  
                 l.Subscribe(LAYER_VISIBILITY_CHANGED,  
                             self._OnMsgLayerVisibilityChanged)  
                 self.SetPyData(id, l)  
                 font = self.GetItemFont(id)  
                 if not l.Visible():  
                     font.SetStyle(wxITALIC)  
                     self.SetItemFont(id, font)  
539    
540                  self.layer2id[l] = id          self.DeleteAllItems()
541    
542                  self.__FillTreeLayer(id)          if map.HasLayers():
543                  self.Expand(id)              root = self.GetRootItem()
544                for l in map.Layers():
545                    self.__AddLayer(0, l)
546    
547          self.Thaw()          self.Thaw()
548    
# Line 387  class LegendTree(wxTreeCtrl): Line 553  class LegendTree(wxTreeCtrl):
553    
554          self.DeleteChildren(pid)          self.DeleteChildren(pid)
555    
556          clazz = layer.GetClassification()          if layer.HasClassification():
557    
558          shapeType = layer.ShapeType()              clazz = layer.GetClassification()
559    
560          for g in clazz:              shapeType = layer.ShapeType()
             id = self.AppendItem(pid, g.GetDisplayText())  
             self.SetPyData(id, g)  
561    
562              bmp = self.__BuildGroupImage(g, shapeType)              show = layer.Visible()
563                for g in clazz:
564                    if g.IsVisible():
565                        id = self.AppendItem(pid, g.GetDisplayText())
566                        self.SetPyData(id, g)
567                        self.__SetVisibilityStyle(show, id)
568    
569                        bmp = self.__BuildGroupImage(g, shapeType)
570    
571                        if bmp is None:
572                            self.SetItemImage(id, -1)
573                            self.SetItemSelectedImage(id, -1)
574                        else:
575                            if self.availImgListIndices:
576                                i = self.availImgListIndices.pop(0)
577                                self.image_list.Replace(i, bmp)
578                            else:
579                                i = self.image_list.Add(bmp)
580    
581              if bmp is None:                          self.SetItemImage(id, i)
582                  self.SetItemImage(id, self.emptyImageIndex)                          self.SetItemSelectedImage(id, i)
             else:  
                 i = self.image_list.Add(bmp)  
                 self.SetItemImage(id, i)  
583    
584          self.Thaw()          self.Thaw()
585    
586      def __BuildGroupImage(self, group, shapeType):      def __BuildGroupImage(self, group, shapeType):
         assert isinstance(group, ClassGroup)  
587    
588          bmp = wxEmptyBitmap(BMP_SIZE_W, BMP_SIZE_H)          bmp = wxEmptyBitmap(BMP_SIZE_W, BMP_SIZE_H)
589          #brush = wxBrush(Color2wxColour(item[1]), wxSOLID)          #brush = wxBrush(Color2wxColour(item[1]), wxSOLID)
# Line 418  class LegendTree(wxTreeCtrl): Line 595  class LegendTree(wxTreeCtrl):
595    
596          return bmp          return bmp
597    
598      def __DeleteAllItems(self):      def DeleteAllItems(self):
599    
600          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)  
601    
602          self.DeleteAllItems()          id, cookie = self.GetFirstChild(pid)
603            while id.IsOk():
604                self.__RemoveLayer(id)
605                id, cookie = self.GetNextChild(pid, cookie)
606    
607            wxTreeCtrl.DeleteAllItems(self)
608    
609        def __AddLayer(self, before, l):
610            root = self.GetRootItem()
611            id = self.InsertItemBefore(root, before,
612                                l.Title(),
613                                self.mapImageIndex,
614                                self.mapImageIndex)
615    
616            self.SetPyData(id, l)
617            self.__SetVisibilityStyle(l.Visible(), id)
618    
619            self.__FillTreeLayer(id)
620            self.Expand(id)
621    
622            l.Subscribe(LAYER_CHANGED, self._OnMsgLayerChanged)
623            l.Subscribe(LAYER_VISIBILITY_CHANGED,
624                        self._OnMsgLayerVisibilityChanged)
625            l.Subscribe(TITLE_CHANGED, self._OnMsgLayerTitleChanged)
626    
627        def __RemoveLayer(self, id):
628            self.DeleteChildren(id)
629    
630            layer = self.GetPyData(id)
631            layer.Unsubscribe(LAYER_CHANGED,
632                              self._OnMsgLayerChanged)
633            layer.Unsubscribe(LAYER_VISIBILITY_CHANGED,
634                              self._OnMsgLayerVisibilityChanged)
635            layer.Unsubscribe(TITLE_CHANGED, self._OnMsgLayerTitleChanged)
636    
637            self.Delete(id)
638    
639        def DeleteChildren(self, pid):
640            id, cookie = self.GetFirstChild(pid)
641            while id.IsOk():
642                self.availImgListIndices.append(self.GetItemImage(id))
643                id, cookie = self.GetNextChild(pid, cookie)
644            wxTreeCtrl.DeleteChildren(self, pid)
645    
646        def GetRootItem(self):
647            root = wxTreeCtrl.GetRootItem(self)
648    
649            if not root.IsOk():
650                self.image_list = wxImageList(BMP_SIZE_W, BMP_SIZE_H, False, 0)
651    
652      def __ShowHideHelper(self, show, id):              bmp = wxEmptyBitmap(BMP_SIZE_W, BMP_SIZE_H)
653                dc = wxMemoryDC()
654                dc.SelectObject(bmp)
655                dc.SetBrush(wxBLACK_BRUSH)
656                dc.Clear()
657                dc.SelectObject(wxNullBitmap)
658    
659                self.emptyImageIndex = \
660                    self.image_list.AddWithColourMask(bmp, wxColour(0, 0, 0))
661    
662                bmp = resource.GetBitmapResource("legend_icon_layer",
663                                                  wxBITMAP_TYPE_XPM)
664                self.mapImageIndex = \
665                    self.image_list.Add(bmp)
666    
667                self.AssignImageList(self.image_list)
668                self.availImgListIndices = []
669    
670                root = self.AddRoot("")
671    
672            return root
673    
674        def __SetVisibilityStyle(self, visible, id):
675          font = self.GetItemFont(id)          font = self.GetItemFont(id)
676    
677          if show:          if visible:
678              font.SetStyle(wxNORMAL)              font.SetStyle(wxNORMAL)
679              color = wxBLACK              color = wxBLACK
680          else:          else:
681              font.SetStyle(wxITALIC)              #font.SetStyle(wxITALIC)
682                font.SetStyle(wxNORMAL)
683              color = wxLIGHT_GREY              color = wxLIGHT_GREY
684    
685          self.SetItemTextColour(id, color)          self.SetItemTextColour(id, color)
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          show = layer.Visible()          visible = layer.Visible()
   
693    
694          self.__ShowHideHelper(show, 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.__ShowHideHelper(show, 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):
716    
717        def __init__(self, parent, map, mainWindow):
718            # While the width is fixed, get the height _now_.
719            dc = wxMemoryDC()
720            textwidth, textheight = dc.GetTextExtent("%d"%0)
721            self.width = 210
722            self.height = textheight + 3*2 + 8
723    
724            wxBoxSizer.__init__(self, wxVERTICAL)
725            bmp=wxEmptyBitmap(self.width, self.height)
726            self.scalebarBitmap = wxStaticBitmap(parent, -1, bmp)
727            self.Add(self.scalebarBitmap, 0, wxALIGN_CENTER|wxLEFT|wxTOP|wxRIGHT, 1)
728    
729            self.mainWindow = mainWindow
730            self.parent = parent
731            self.canvas = None
732            self.SetCanvas(self.mainWindow.canvas)
733    
734        def SetCanvas(self, canvas):
735            sub_list = [(SCALE_CHANGED, self._OnMsgScaleChanged)]
736    
737            if self.canvas is not None:
738                for msg, func in sub_list: self.canvas.Unsubscribe(msg, func)
739            
740            self.canvas = canvas
741            self.scalebar = ScaleBar(canvas.map)
742    
743            if self.canvas is not None:
744                for msg, func in sub_list: self.canvas.Subscribe(msg, func)
745                self.__SetScale(self.canvas.scale)
746    
747        def _OnMsgScaleChanged(self, scale):
748            self.__SetScale(scale)
749    
750        def __SetScale(self, scale):
751            bmp = wxEmptyBitmap(self.width, self.height)
752            dc = wxMemoryDC()
753            dc.SelectObject(bmp)
754            dc.Clear()
755    
756            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)
786    

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26