/[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 562 by jonathan, Wed Mar 26 11:06:22 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    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.UI.classifier import ClassDataPreviewer  from Thuban.Model.messages import \
26  from Thuban.UI.dock import DockPanel      MAP_STACKING_CHANGED, MAP_LAYERS_ADDED, MAP_LAYERS_REMOVED, LAYER_CHANGED,\
27        LAYER_VISIBILITY_CHANGED, TITLE_CHANGED
 ID_LEGEND_MOVEUP = 4001  
 ID_LEGEND_MOVEDOWN = 4002  
 ID_LEGEND_TREE = 4003  
 ID_LEGEND_CLASSIFY = 4004  
 ID_LEGEND_SHOWLAYER = 4005  
 ID_LEGEND_HIDELAYER = 4006  
 ID_LEGEND_DOCK = 4007  
 ID_LEGEND_UNDOCK = 4008  
   
 BMP_SIZE_W = 30  
 BMP_SIZE_H = 15  
   
 #class LegendDialog(NonModalDialog):  
   
     #def __init__(self, parent, name, panel):  
         #NonModalDialog.__init__(self, parent, name,  
                                 #_("Legend: %s") % map.Title())  
   
         ##topBox = wxBoxSizer(wxVERTICAL)  
   
         #panel = LegendPanel(self, map)  
28    
29          #self.panel = panel  from Thuban.UI.messages import SCALE_CHANGED
30    
31          #topBox.Add(panel, 1, wxGROW, 4)  from Thuban.UI.classifier import ClassDataPreviewer
32    from Thuban.UI.dock import DockPanel
33    from Thuban.UI.scalebar import ScaleBar
34    
35          ##self.SetAutoLayout(True)  from Thuban.UI.menu import Menu
         ##self.SetSizer(topBox)  
36    
37      #def GetLegendPanel(self):  from Thuban.Lib.connector import ConnectorError
         #return self.panel  
38    
39      #def OnClose(self, event):  ID_LEGEND_TOP = 4001
40          #NonModalDialog.OnClose(self, event)  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    
         #self.panel.SetMap(None)  
       
59  class LegendPanel(DockPanel):  class LegendPanel(DockPanel):
60    
61      def __init__(self, parent, map, mainWindow):      def __init__(self, parent, map, mainWindow):
# Line 64  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)  
   
 #       button = wxButton(self, ID_LEGEND_DOCK, _("Dock"))  
 #       buttonBox.Add(button, 0, wxGROW | wxLEFT | wxRIGHT, 0)  
 #       self.buttons.append(button)  
   
 #       button = wxButton(self, ID_LEGEND_UNDOCK, _("Undock"))  
 #       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)  
         #EVT_BUTTON(self, ID_LEGEND_DOCK, self._OnDock)  
         #EVT_BUTTON(self, ID_LEGEND_UNDOCK, self._OnUndock)  
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            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)
132    
133    
134      def GetMap(self):      def GetMap(self):
135          return self.tree.GetMap()          return self.tree.GetMap()
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):
142    
143            ok = isinstance(layer, BaseLayer)
144            self.__EnableButtons(ok)
145    
146      def DoOnSelChanged(self):          self.mainWindow.SelectLayer(layer)
         self.__EnableButtons(self.tree.GetSelection().IsOk())  
147    
148      def _OnClassify(self, event):      def DoOnProperties(self):
149          self.tree.DoOnClassify()          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 Destroy(self):
156            self.__Close()
157    
158        def _OnProperties(self, event):
159            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 _OnDock(self, event):      def _OnToggleVisibility(self, event):
188          self.Dock()          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 _OnUndock(self, event):      def _OnShowTable(self, event):
197          self.UnDock()          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    
# Line 164  class LegendTree(wxTreeCtrl): Line 215  class LegendTree(wxTreeCtrl):
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          self.map = None
220          self.parent = parent          self.parent = parent
221          self.layer2id = None          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)
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):
296            self.SetMap(None)
297    
298      def GetMap(self):      def GetMap(self):
299          return self.map          return self.map
300    
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)
309              self.__DeleteAllItems()              #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          self.map = map
319    
320          if self.map is not None:          if self.map is not None:
321              for msg, func in sub_list: self.map.Subscribe(msg, func)              for msg, func in sub_list: self.map.Subscribe(msg, func)
322                #self.mainWindow.application.session.Subscribe(MAPS_CHANGED,
323                    #self._OnMsgMapsChanged)
324                #self.mainWindow.application.Subscribe(SESSION_REPLACED,
325                    #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())  
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())  
         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          # XXX: THIS IS SUCH AWFUL STYLE! YUCK!      def LayerProjection(self):
389          self.parent.mainWindow.OpenClassifier(item)          self.parent.mainWindow.LayerProjection()
         #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):
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()
# Line 290  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(id(map) == id(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            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      def __FillTree(self, 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          assert(isinstance(map, Map))          self.__UpdateSelection()
503    
504          self.Freeze()      def _OnMsgMapLayersRemoved(self, map):
505            assert map is self.map
506    
507          self.__DeleteAllItems()          layers = map.Layers()
508    
509          if map.HasLayers():          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    
             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)  
516    
517              root = self.AddRoot("")          self.__UpdateSelection()
518    
519              for l in map.Layers():      def _OnMsgLayerVisibilityChanged(self, layer):
520                  id = self.PrependItem(root, l.Title())          assert isinstance(layer, BaseLayer)
                 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)  
521    
522                  self.layer2id[l] = id          self.__ShowHideLayer(layer)
523            self.__UpdateSelection()
524    
525                  self.__FillTreeLayer(id)      def _OnMsgLayerTitleChanged(self, layer):
526                  self.Expand(id)  
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 378  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.562  
changed lines
  Added in v.2588

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26