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

Legend:
Removed from v.568  
changed lines
  Added in v.2700

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26