/[thuban]/branches/WIP-pyshapelib-bramz/Thuban/UI/legend.py
ViewVC logotype

Diff of /branches/WIP-pyshapelib-bramz/Thuban/UI/legend.py

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 542 by jonathan, Thu Mar 20 09:43:16 2003 UTC revision 2187 by jan, Sun Apr 18 20:37:45 2004 UTC
# Line 1  Line 1 
1  # Copyright (c) 2001, 2002, 2003 by Intevation GmbH  # Copyright (c) 2001, 2002, 2003 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 *
 from dialogs import NonModalDialog  
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
21    from Thuban.Model.classification import ClassGroup
22    from Thuban.Model.proj import PROJ_UNITS_DEGREES
23    
24  from Thuban.Model.messages import *  from Thuban.Model.messages import \
25        MAP_STACKING_CHANGED, MAP_LAYERS_ADDED, MAP_LAYERS_REMOVED, LAYER_CHANGED,\
26        LAYER_VISIBILITY_CHANGED, TITLE_CHANGED
27    
28  from Thuban.Model.classification import ClassGroup  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
32    from Thuban.UI.scalebar import ScaleBar
33    
34    from Thuban.UI.menu import Menu
35    
36  ID_LEGEND_MOVEUP = 4001  from Thuban.Lib.connector import ConnectorError
 ID_LEGEND_MOVEDOWN = 4002  
 ID_LEGEND_TREE = 4003  
 ID_LEGEND_CLASSIFY = 4004  
 ID_LEGEND_SHOWLAYER = 4005  
 ID_LEGEND_HIDELAYER = 4006  
37    
38  BMP_SIZE_W = 30  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 = 15
48  BMP_SIZE_H = 15  BMP_SIZE_H = 15
49    
50  class Legend(NonModalDialog):  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      def __init__(self, parent, name, map):  class LegendPanel(DockPanel):
         NonModalDialog.__init__(self, parent, name,  
                                 _("Legend: %s") % map.Title())  
59    
60          self.parent = parent      def __init__(self, parent, map, mainWindow):
61            DockPanel.__init__(self, parent, -1)
62    
63            self.mainWindow = mainWindow
64            self.parent = parent
65    
66          panel = wxPanel(self, -1)          self.buttons = []
67    
         topBox = wxBoxSizer(wxVERTICAL)  
68          panelBox = wxBoxSizer(wxVERTICAL)          panelBox = wxBoxSizer(wxVERTICAL)
69    
70          buttonBox = wxGridSizer(2, 3, 0, 0)          self.toolBar = wxToolBar(self, -1)
71            self.toolBar.SetToolBitmapSize(wxSize(24, 24))
72    
73          self.buttons = []          bmp = resource.GetBitmapResource(TOP_BMP, wxBITMAP_TYPE_XPM)
74            self.toolBar.AddTool(ID_LEGEND_TOP, bmp,
75                shortHelpString=_("Top Layer"))
76    
77            bmp = resource.GetBitmapResource(RAISE_BMP, wxBITMAP_TYPE_XPM)
78            self.toolBar.AddTool(ID_LEGEND_RAISE, bmp,
79                shortHelpString=_("Raise Layer"))
80    
81            bmp = resource.GetBitmapResource(LOWER_BMP, wxBITMAP_TYPE_XPM)
82            self.toolBar.AddTool(ID_LEGEND_LOWER, bmp,
83                shortHelpString=_("Lower Layer"))
84    
85            bmp = resource.GetBitmapResource(BOTTOM_BMP, wxBITMAP_TYPE_XPM)
86            self.toolBar.AddTool(ID_LEGEND_BOTTOM, bmp,
87                shortHelpString=_("Bottom Layer"))
88    
89            bmp = resource.GetBitmapResource(SHOW_BMP, wxBITMAP_TYPE_XPM)
90            self.toolBar.AddTool(ID_LEGEND_SHOWLAYER, bmp,
91                shortHelpString=_("Show Layer"))
92    
93            bmp = resource.GetBitmapResource(HIDE_BMP, wxBITMAP_TYPE_XPM)
94            self.toolBar.AddTool(ID_LEGEND_HIDELAYER, bmp,
95                shortHelpString=_("Hide Layer"))
96    
97            bmp = resource.GetBitmapResource(PROPS_BMP, wxBITMAP_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, wxGROW, 0)
103    
104            EVT_TOOL(self, ID_LEGEND_TOP, self._OnMoveTop)
105            EVT_TOOL(self, ID_LEGEND_RAISE, self._OnMoveUp)
106            EVT_TOOL(self, ID_LEGEND_LOWER, self._OnMoveDown)
107            EVT_TOOL(self, ID_LEGEND_BOTTOM, self._OnMoveBottom)
108            EVT_TOOL(self, ID_LEGEND_PROPS, self._OnProperties)
109            EVT_TOOL(self, ID_LEGEND_SHOWLAYER, self._OnShowLayer)
110            EVT_TOOL(self, ID_LEGEND_HIDELAYER, self._OnHideLayer)
111    
112          button = wxButton(self, ID_LEGEND_MOVEUP, _("Move Up"))          self.tree = LegendTree(self, ID_LEGEND_TREE, map, mainWindow)
         buttonBox.Add(button, 0, wxGROW | wxLEFT | wxRIGHT, 0)  
         self.buttons.append(button)  
113    
114          button = wxButton(self, ID_LEGEND_SHOWLAYER, _("Show Layer"))          panelBox.Add(self.tree, 1, wxGROW, 0)
         buttonBox.Add(button, 0, wxGROW | wxLEFT | wxRIGHT, 0)  
         self.buttons.append(button)  
115    
116          button = wxButton(self, ID_LEGEND_CLASSIFY, _("Classify"))          self.scalebarbitmap = ScaleBarBitmap(self, map, mainWindow)
117          buttonBox.Add(button, 0, wxGROW | wxLEFT | wxRIGHT, 0)          panelBox.Add(self.scalebarbitmap, 0, wxGROW, 0)
         self.buttons.append(button)  
118    
119          button = wxButton(self, ID_LEGEND_MOVEDOWN, _("Move Down"))          self.SetAutoLayout(True)
120          buttonBox.Add(button, 0, wxGROW | wxLEFT | wxRIGHT, 0)          self.SetSizer(panelBox)
121          self.buttons.append(button)          panelBox.SetSizeHints(self)
122    
         button = wxButton(self, ID_LEGEND_HIDELAYER, _("Hide Layer"))  
         buttonBox.Add(button, 0, wxGROW | wxLEFT | wxRIGHT, 0)  
         self.buttons.append(button)  
123    
124            self.panelBox = panelBox
125    
126          EVT_BUTTON(self, ID_LEGEND_MOVEUP, self._OnMoveUp)          self.__EnableButtons(False)
         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)  
127    
128          panelBox.Add(buttonBox, 0, 0, 4)          self.Create()
129    
130          self.tree = LegendTree(self, ID_LEGEND_TREE, map)          EVT_CLOSE(self, self._OnClose)
131    
         panelBox.Add(self.tree, 1, wxGROW, 4)  
132    
133          panel.SetAutoLayout(True)      def GetMap(self):
134          panel.SetSizer(panelBox)          return self.tree.GetMap()
         panelBox.SetSizeHints(panel)  
135    
136          topBox.Add(panel, 1, wxGROW, 0)      def SetMap(self, map):
137          panelBox.SetSizeHints(self)          self.tree.SetMap(map)
138            self.scalebarbitmap.SetCanvas(self.mainWindow.canvas)
139    
140          self.SetAutoLayout(True)      def DoOnSelChanged(self, layer, group):
141          self.SetSizer(topBox)  
142            ok = isinstance(layer, BaseLayer)
143            self.__EnableButtons(ok)
144    
145            self.mainWindow.SelectLayer(layer)
146    
147        def DoOnProperties(self):
148            list = self.tree.GetSelectedHierarchy()
149    
150            ok = isinstance(list[0], BaseLayer)
151            if ok:
152                self.mainWindow.OpenLayerProperties(list[0], list[1])
153    
154      def DoOnSelChanged(self):      def Destroy(self):
155          self.__EnableButtons(self.tree.GetSelection().IsOk())          self.__Close()
156    
157      def _OnClassify(self, event):      def _OnProperties(self, event):
158          self.tree.DoOnClassify()          self.DoOnProperties()
159    
160        def _OnMoveTop(self, event):
161            self.tree.MoveCurrentItemTop()
162            
163      def _OnMoveUp(self, event):      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(wxTreeCtrl):
211    
212      def __init__(self, parent, id, map):      def __init__(self, parent, id, map, mainWindow):
213          wxTreeCtrl.__init__(self, parent, id,          wxTreeCtrl.__init__(self, parent, id,
214                              style = wxTR_DEFAULT_STYLE | wxTR_HIDE_ROOT,                              style = wxTR_DEFAULT_STYLE | wxTR_HIDE_ROOT,
215                              size = (200, 200))                              size = (200, 200))
216    
217            self.mainWindow = mainWindow
218            self.map = None
219          self.parent = parent          self.parent = parent
220          self.map = map          self.changing_selection = 0
         self.layer2id = None  
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            self.preventExpandCollapse = False
240            self.raiseProperties = False
241    
242          EVT_TREE_ITEM_ACTIVATED(self, ID_LEGEND_TREE, self._OnItemActivated)          EVT_TREE_ITEM_ACTIVATED(self, ID_LEGEND_TREE, self._OnItemActivated)
243          EVT_TREE_SEL_CHANGED(self, ID_LEGEND_TREE, self._OnSelChanged)          EVT_TREE_SEL_CHANGED(self, ID_LEGEND_TREE, self._OnSelChanged)
244            EVT_TREE_ITEM_EXPANDING(self, ID_LEGEND_TREE, self.OnItemExpandCollapse)
245            EVT_TREE_ITEM_COLLAPSING(self, ID_LEGEND_TREE, self.OnItemExpandCollapse)
246            EVT_TREE_ITEM_RIGHT_CLICK(self, ID_LEGEND_TREE, self._OnRightClick)
247    
248            EVT_CLOSE(self, self._OnClose)
249    
250            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, 0)
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):
298            return self.map
299    
300        def SetMap(self, map):
301    
302            sub_list = [(MAP_STACKING_CHANGED, self._OnMsgMapStackingChanged),
303                        (MAP_LAYERS_ADDED, self._OnMsgMapLayersAdded),
304                        (MAP_LAYERS_REMOVED, self._OnMsgMapLayersRemoved)]
305    
306            if self.map is not None:
307                for msg, func in sub_list: self.map.Unsubscribe(msg, func)
308                #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
318    
319          map.Subscribe(MAP_STACKING_CHANGED, self._OnMsgMapStackingChanged)          if self.map is not None:
320          map.Subscribe(MAP_LAYERS_CHANGED, self._OnMsgMapLayersChanged)              for msg, func in sub_list: self.map.Subscribe(msg, func)
321                #self.mainWindow.application.session.Subscribe(MAPS_CHANGED,
322          self.__FillTree(map)                  #self._OnMsgMapsChanged)
323                #self.mainWindow.application.Subscribe(SESSION_REPLACED,
324      def MoveCurrentItemUp(self):                  #self._OnMsgMapsChanged)
325          cur_id = self.GetSelection()              self.__FillTree(self.map)
         assert(cur_id.IsOk())  
326    
327          cur_data = self.GetPyData(cur_id)      def MoveCurrentItemTop(self):
328            layer, group = self.GetSelectedHierarchy()
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())  
   
         cur_data = self.GetPyData(cur_id)  
347    
348          if isinstance(cur_data, Layer):          if layer is not None:
349              self.map.LowerLayer(cur_data)              self.map.LowerLayer(layer)
         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 wxTreeCtrl.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          self.parent.parent.OpenClassifier(item)      def LayerProjection(self):
388            self.parent.mainWindow.LayerProjection()
389    
390      def Sort(self):      def Sort(self):
391          self.SortChildren(self.GetRootItem())          self.SortChildren(self.GetRootItem())
392    
393        def GetSelectedHierarchy(self):
394            id = self.GetSelection()
395    
396            if not id.IsOk():
397                return (None, None)
398    
399            layer = self.GetPyData(id)
400            group = None
401    
402            if isinstance(layer, ClassGroup):
403                id = self.GetItemParent(id)
404                assert id.IsOk()
405                group = layer
406                layer = self.GetPyData(id)
407    
408            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):      def _OnSelChanged(self, event):
415          self.parent.DoOnSelChanged()          # 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()
478            id = self.GetSelection()
479    
480      def _OnMsgMapLayersChanged(self, map):          if id.IsOk():
481          assert(id(map) == id(self.map))              self.EnsureVisible(id)
482            self.__UpdateSelection()
483    
484          self.__FillTree(self.map)      def _OnMsgMapLayersAdded(self, map):
485            assert map is self.map
486    
487      def __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, 0)
491            while id.IsOk():
492                layers[self.GetPyData(id)] = 1
493                id, cookie = self.GetNextChild(root, cookie)
494    
495          assert(isinstance(map, 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          self.Freeze()          self.__UpdateSelection()
502    
503          self.__DeleteAllItems()      def _OnMsgMapLayersRemoved(self, map):
504            assert map is self.map
505    
506          if map.HasLayers():          layers = map.Layers()
507    
508              self.image_list = wxImageList(BMP_SIZE_W, BMP_SIZE_H, False, 0)          root = self.GetRootItem()
509                                                                                            id, cookie = self.GetFirstChild(root, 0)
510              bmp = wxEmptyBitmap(BMP_SIZE_W, BMP_SIZE_H)          while id.IsOk():
511              dc = wxMemoryDC()              if self.GetPyData(id) not in layers:
512              dc.SelectObject(bmp)                  self.__RemoveLayer(id)
513              dc.SetBrush(wxBLACK_BRUSH)              id, cookie = self.GetNextChild(root, cookie)
             dc.Clear()  
             dc.SelectObject(wxNullBitmap)  
                                                                                   
             self.emptyImageIndex = \  
                 self.image_list.AddWithColourMask(bmp, wxColour(0, 0, 0))  
                                                                                   
             self.AssignImageList(self.image_list)  
514    
             root = self.AddRoot("")  
515    
516              for l in map.Layers():          self.__UpdateSelection()
517                  id = self.PrependItem(root, l.Title())  
518                  l.Subscribe(LAYER_CHANGED, self._OnMsgLayerChanged)      def _OnMsgLayerVisibilityChanged(self, layer):
519                  self.SetPyData(id, l)          assert isinstance(layer, BaseLayer)
520                  font = self.GetItemFont(id)  
521                  if not l.Visible():          self.__ShowHideLayer(layer)
522                      font.SetStyle(wxITALIC)          self.__UpdateSelection()
                     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    
# Line 283  class LegendTree(wxTreeCtrl): Line 552  class LegendTree(wxTreeCtrl):
552    
553          self.DeleteChildren(pid)          self.DeleteChildren(pid)
554    
555          clazz = layer.GetClassification()          if layer.HasClassification():
556    
557          shapeType = layer.ShapeType()              clazz = layer.GetClassification()
558    
559          for g in clazz:              shapeType = layer.ShapeType()
             id = self.AppendItem(pid, g.GetDisplayText())  
             self.SetPyData(id, g)  
560    
561              bmp = self.__BuildGroupImage(g, shapeType)              show = layer.Visible()
562                for g in clazz:
563                    if g.IsVisible():
564                        id = self.AppendItem(pid, g.GetDisplayText())
565                        self.SetPyData(id, g)
566                        self.__SetVisibilityStyle(show, id)
567    
568                        bmp = self.__BuildGroupImage(g, shapeType)
569    
570                        if bmp is None:
571                            self.SetItemImage(id, -1)
572                            self.SetItemSelectedImage(id, -1)
573                        else:
574                            if self.availImgListIndices:
575                                i = self.availImgListIndices.pop(0)
576                                self.image_list.Replace(i, bmp)
577                            else:
578                                i = self.image_list.Add(bmp)
579    
580              if bmp is None:                          self.SetItemImage(id, i)
581                  self.SetItemImage(id, self.emptyImageIndex)                          self.SetItemSelectedImage(id, i)
             else:  
                 i = self.image_list.Add(bmp)  
                 self.SetItemImage(id, i)  
   
             #self.layer2id[g] = id  
582    
583          self.Thaw()          self.Thaw()
584    
585      def __BuildGroupImage(self, group, shapeType):      def __BuildGroupImage(self, group, shapeType):
         assert(isinstance(group, ClassGroup))  
586    
587          bmp = wxEmptyBitmap(BMP_SIZE_W, BMP_SIZE_H)          bmp = wxEmptyBitmap(BMP_SIZE_W, BMP_SIZE_H)
588          #brush = wxBrush(Color2wxColour(item[1]), wxSOLID)          #brush = wxBrush(Color2wxColour(item[1]), wxSOLID)
# Line 316  class LegendTree(wxTreeCtrl): Line 594  class LegendTree(wxTreeCtrl):
594    
595          return bmp          return bmp
596    
597      def __DeleteAllItems(self):      def DeleteAllItems(self):
         self.DeleteAllItems()  
         self.layer2id = {}  
598    
599            pid = self.GetRootItem()
600    
601      def __ShowHideLayer(self, show):          id, cookie = self.GetFirstChild(pid, 123)
602          id = self.GetSelection()          while id.IsOk():
603          assert(id.IsOk())              self.__RemoveLayer(id)
604                id, cookie = self.GetNextChild(pid, cookie)
605    
606            wxTreeCtrl.DeleteAllItems(self)
607    
608        def __AddLayer(self, before, l):
609            root = self.GetRootItem()
610            id = self.InsertItemBefore(root, before,
611                                l.Title(),
612                                self.mapImageIndex,
613                                self.mapImageIndex)
614    
615            self.SetPyData(id, l)
616            self.__SetVisibilityStyle(l.Visible(), id)
617    
618            self.__FillTreeLayer(id)
619            self.Expand(id)
620    
621            l.Subscribe(LAYER_CHANGED, self._OnMsgLayerChanged)
622            l.Subscribe(LAYER_VISIBILITY_CHANGED,
623                        self._OnMsgLayerVisibilityChanged)
624            l.Subscribe(TITLE_CHANGED, self._OnMsgLayerTitleChanged)
625    
626        def __RemoveLayer(self, id):
627            self.DeleteChildren(id)
628    
629            layer = self.GetPyData(id)
630            layer.Unsubscribe(LAYER_CHANGED,
631                              self._OnMsgLayerChanged)
632            layer.Unsubscribe(LAYER_VISIBILITY_CHANGED,
633                              self._OnMsgLayerVisibilityChanged)
634            layer.Unsubscribe(TITLE_CHANGED, self._OnMsgLayerTitleChanged)
635    
636            self.Delete(id)
637    
638        def DeleteChildren(self, pid):
639            id, cookie = self.GetFirstChild(pid, 123)
640            while id.IsOk():
641                self.availImgListIndices.append(self.GetItemImage(id))
642                id, cookie = self.GetNextChild(pid, cookie)
643            wxTreeCtrl.DeleteChildren(self, pid)
644    
645        def GetRootItem(self):
646            root = wxTreeCtrl.GetRootItem(self)
647    
648            if not root.IsOk():
649                self.image_list = wxImageList(BMP_SIZE_W, BMP_SIZE_H, False, 0)
650    
651                bmp = wxEmptyBitmap(BMP_SIZE_W, BMP_SIZE_H)
652                dc = wxMemoryDC()
653                dc.SelectObject(bmp)
654                dc.SetBrush(wxBLACK_BRUSH)
655                dc.Clear()
656                dc.SelectObject(wxNullBitmap)
657    
658                self.emptyImageIndex = \
659                    self.image_list.AddWithColourMask(bmp, wxColour(0, 0, 0))
660    
661                bmp = resource.GetBitmapResource("legend_icon_layer",
662                                                  wxBITMAP_TYPE_XPM)
663                self.mapImageIndex = \
664                    self.image_list.Add(bmp)
665    
666                self.AssignImageList(self.image_list)
667                self.availImgListIndices = []
668    
669                root = self.AddRoot("")
670    
671            return root
672    
673        def __SetVisibilityStyle(self, visible, id):
674            font = self.GetItemFont(id)
675    
676            if visible:
677                font.SetStyle(wxNORMAL)
678                color = wxBLACK
679            else:
680                #font.SetStyle(wxITALIC)
681                font.SetStyle(wxNORMAL)
682                color = wxLIGHT_GREY
683    
684            self.SetItemTextColour(id, color)
685            self.SetItemFont(id, font)
686                    
687          item = self.GetPyData(id)      def __ShowHideLayer(self, layer):
688          if isinstance(item, ClassGroup):          parent = self.find_layer(layer)
689              id = self.GetItemParent(id)          assert parent.IsOk()
690              assert(id.IsOk())  
691              item = self.GetPyData(id)          visible = layer.Visible()
692    
693            self.__SetVisibilityStyle(visible, parent)
694    
695            id, cookie = self.GetFirstChild(parent, 123)
696    
697            while id.IsOk():
698                self.__SetVisibilityStyle(visible, id)
699                id, cookie = self.GetNextChild(parent, cookie)
700                
701    class ScaleBarBitmap(wxBoxSizer):
702    
703        def __init__(self, parent, map, mainWindow):
704            # While the width is fixed, get the height _now_.
705            dc = wxMemoryDC()
706            textwidth, textheight = dc.GetTextExtent("%d"%0)
707            self.width = 210
708            self.height = textheight + 3*2 + 8
709    
710            wxBoxSizer.__init__(self, wxVERTICAL)
711            bmp=wxEmptyBitmap(self.width, self.height)
712            self.scalebarBitmap = wxStaticBitmap(parent, -1, bmp)
713            self.Add(self.scalebarBitmap, 0, wxALIGN_CENTER|wxLEFT|wxTOP|wxRIGHT, 1)
714    
715            self.mainWindow = mainWindow
716            self.parent = parent
717            self.canvas = None
718            self.SetCanvas(self.mainWindow.canvas)
719    
720        def SetCanvas(self, canvas):
721            sub_list = [(SCALE_CHANGED, self._OnMsgScaleChanged)]
722    
723            if self.canvas is not None:
724                for msg, func in sub_list: self.canvas.Unsubscribe(msg, func)
725            
726            self.canvas = canvas
727            self.scalebar = ScaleBar(canvas.map)
728    
729            if self.canvas is not None:
730                for msg, func in sub_list: self.canvas.Subscribe(msg, func)
731                self.__SetScale(self.canvas.scale)
732    
733          if show != item.Visible():      def _OnMsgScaleChanged(self, scale):
734            self.__SetScale(scale)
735    
736        def __SetScale(self, scale):
737            bmp = wxEmptyBitmap(self.width, self.height)
738            dc = wxMemoryDC()
739            dc.SelectObject(bmp)
740            dc.Clear()
741    
742              item.SetVisible(show)          if self.canvas.map is not None \
743                and self.canvas.map.projection is not None:
744    
745              font = self.GetItemFont(id)              # if we are using a projection with geographics coordinates
746              if show:              # we need to change the scale value based on where we are
747                  font.SetStyle(wxNORMAL)              # on the globe.
748                  self.SetItemFont(id, font)              if self.canvas.map.projection.GetProjectedUnits() \
749              else:                  == PROJ_UNITS_DEGREES:
750                  font.SetStyle(wxITALIC)  
751                  self.SetItemFont(id, font)                  width, height = self.canvas.GetSizeTuple()
752                    long, lat = self.canvas.win_to_proj(width/2, height/2)
753    
754                    # slightly inaccurate, but if we are looking at
755                    # the north/south pole we could end up dividing by zero
756                    #
757                    # it shouldn't matter for our purposes that we ignore
758                    # the original sign of lat.
759                    if fabs(lat) > 89.9: lat = 89.9
760    
761                    #
762                    # one degree is about 111,133m at the equator
763                    # we need to adjust that for latitude as
764                    # we move north/south. use the center of the map
765                    # as the point to scale the length to.
766                    #
767                    scale = scale / (111133.0 * fabs(cos(lat * pi/180)))
768    
769                self.scalebar.DrawScaleBar(scale, dc, (0,0), dc.GetSizeTuple())
770    
771            self.scalebarBitmap.SetBitmap(bmp)
772    

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26