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

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26