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

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

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

revision 6 by bh, Tue Aug 28 15:41:52 2001 UTC revision 353 by bh, Tue Dec 3 17:35:30 2002 UTC
# Line 1  Line 1 
1  #! /usr/bin/python  #! /usr/bin/python
2  # Copyright (c) 2001 by Intevation GmbH  # Copyright (c) 2001, 2002 by Intevation GmbH
3  # Authors:  # Authors:
4  # Jan-Oliver Wagner <[email protected]>  # Jan-Oliver Wagner <[email protected]>
5  # Bernhard Herzog <[email protected]>  # Bernhard Herzog <[email protected]>
# Line 9  Line 9 
9    
10  __version__ = "$Revision$"  __version__ = "$Revision$"
11    
12    from types import StringType
13    
14  from wxPython.wx import *  from wxPython.wx import *
15    
16  from Thuban.Model.messages import MAPS_CHANGED, MAP_PROJECTION_CHANGED, \  from Thuban.Model.messages import CHANGED
17       LAYERS_CHANGED, LAYER_LEGEND_CHANGED, LAYER_VISIBILITY_CHANGED  from Thuban.Model.layer import Layer
 from Thuban.Model.layer import Layer, shapetype_names  
18  from Thuban.Model.map import Map  from Thuban.Model.map import Map
 import view  
19    
20    from dialogs import NonModalDialog
21  from messages import SESSION_CHANGED, SELECTED_LAYER  from messages import SESSION_CHANGED, SELECTED_LAYER
22    
 def color_string(color):  
     if color is None:  
         return "None"  
     return "(%.3f, %.3f, %.3f)" % (color.red, color.green, color.blue)  
23    
24  class myTreeCtrlPanel(wxPanel):  class SessionTreeCtrl(wxTreeCtrl):
25    
26        """Widget to display a tree view of the session.
27    
28        The tree view is created recursively from the session object. The
29        tree view calls the session's TreeInfo method which should return a
30        pair (<title>, <item>) where <title> ist the title of the session
31        item in the tree view and <items> is a list of objects to use as the
32        children of the session in the tree view.
33    
34        The items list can contain three types of items:
35    
36           1. a string. The string is used as the title for a leaf item in
37              the tree view.
38    
39      def __init__(self, parent, app):         2. an object with a TreeInfo method. This method is called and
40              should return a pair just like the session's TreeInfo method.
41    
42           3. a pair (<title>, <item>) which is treated like the return
43              value of TreeInfo.
44        """
45    
46        def __init__(self, parent, ID, app):
47          # Use the WANTS_CHARS style so the panel doesn't eat the Return key.          # Use the WANTS_CHARS style so the panel doesn't eat the Return key.
48          wxPanel.__init__(self, parent, -1, style=wxWANTS_CHARS)          wxTreeCtrl.__init__(self, parent, ID)
49    
50          self.app = app          self.app = app
51            # boolean to indicate that we manipulate the selection ourselves
52            # so that we can ignore the selection events generated
53            self.changing_selection = 0
54    
55          EVT_SIZE(self, self.OnSize)          # Dictionary mapping layer id's to tree items
56          self.tree = wxTreeCtrl(self, -1)          self.layer_to_item = {}
57    
58          self.app.Subscribe(SESSION_CHANGED, self.session_changed)          self.app.Subscribe(SESSION_CHANGED, self.session_changed)
59          self.app.interactor.Subscribe(SELECTED_LAYER, self.layer_selected)          self.app.interactor.Subscribe(SELECTED_LAYER, self.layer_selected)
60    
61            # the session currently displayed in the tree
62            self.session = None
63    
64          # pretend the session has changed to build the initial tree          # pretend the session has changed to build the initial tree
65          self.session_changed()          self.session_changed()
66    
67          EVT_TREE_SEL_CHANGED(self, self.tree.GetId(), self.OnSelChanged)          EVT_TREE_SEL_CHANGED(self, self.GetId(), self.OnSelChanged)
68    
69        def unsubscribe_all(self):
70            if self.session is not None:
71                self.session.Unsubscribe(CHANGED, self.update_tree)
72                self.session = None
73            self.app.Unsubscribe(SESSION_CHANGED, self.session_changed)
74            self.app.interactor.Unsubscribe(SELECTED_LAYER, self.layer_selected)
75    
76      def update_tree(self, *args):      def update_tree(self, *args):
77          """Clear and rebuild the tree"""          """Clear and rebuild the tree"""
78          self.tree.DeleteAllItems()          self.DeleteAllItems()
79            self.layer_to_item.clear()
80    
81          session = self.app.session          session = self.app.session
82          root = self.tree.AddRoot("Session: %s" % session.title)          info = session.TreeInfo()
83          for map in session.Maps():          root = self.AddRoot(info[0])
84              mapitem = self.tree.AppendItem(root, "Map: %s" % map.title)          self.add_items(root, info[1])
85              self.tree.SetPyData(mapitem, map)          self.Expand(root)
86              if map.projection and len(map.projection.params) > 0:          # select the selected layer
87                  projectionitem = self.tree.AppendItem(mapitem, "Projection")          selected_layer = self.app.interactor.selected_layer
88                  for param in map.projection.params:          if selected_layer is not None:
89                      parameteritem = self.tree.AppendItem(projectionitem,              # One would expect that the selected_layer's id is in
90                                                           str(param))              # layer_to_item at this point as we've just rebuilt that
91                  self.tree.Expand(projectionitem)              # mapping completely. However, when a new session is loaded
92                # for instance, it can happen that the tree view is updated
93              layers = map.Layers()              # before the interactor in which case selected_layer may be
94              for layer_index in range(len(layers) - 1, -1, -1):              # a layer of the old session.
95                  layer = layers[layer_index]              item = self.layer_to_item.get(id(selected_layer))
96                  idata = wxTreeItemData()              if item is not None:
97                  idata.SetData(layer)                  self.SelectItem(item)
98                  layeritem = self.tree.AppendItem(mapitem,  
99                                                   "Layer '%s'" % layer.Title(),      def add_items(self, parent, items):
100                                                   data = idata)          for item in items:
101                  if layer is self.app.interactor.selected_layer:              if hasattr(item, "TreeInfo"):
102                      self.tree.SelectItem(layeritem)                  # Supports the TreeInfo protocol
103                  if isinstance(layer, Layer):                  info = item.TreeInfo()
104                      if layer.Visible():                  treeitem = self.AppendItem(parent, info[0])
105                          text = "Shown"                  self.SetPyData(treeitem, item)
106                      else:                  self.add_items(treeitem, info[1])
107                          text = "Hidden"                  self.Expand(treeitem)
108                      self.tree.AppendItem(layeritem, text)                  if isinstance(item, Layer):
109                      self.tree.AppendItem(layeritem,                      self.layer_to_item[id(item)] = treeitem
110                                           "Shapes: %d" % layer.NumShapes())              elif isinstance(item, StringType):
111                      self.tree.AppendItem(layeritem,                  # it's a string
112                                           ("Extents: (%g, %g, %g, %g)"                  # FIXME: What to do about UNICODE
113                                            % layer.LatLongBoundingBox()))                  self.AppendItem(parent, item)
114                      self.tree.AppendItem(layeritem,              else:
115                                           "Shapetype: %s" %                  # assume its a sequence (title, items)
116                                           shapetype_names[layer.ShapeType()])                  treeitem = self.AppendItem(parent, item[0])
117                      self.tree.AppendItem(layeritem,                  self.add_items(treeitem, item[1])
118                                           "Fill: " + color_string(layer.fill))                  self.Expand(treeitem)
                     self.tree.AppendItem(layeritem,  
                                       "Outline: " + color_string(layer.stroke))  
                 self.tree.Expand(layeritem)  
             self.tree.Expand(mapitem)  
         self.tree.Expand(root)  
119    
120      def session_changed(self, *args):      def session_changed(self, *args):
121          for channel in (MAPS_CHANGED,          new_session = self.app.session
122                          MAP_PROJECTION_CHANGED,          # if the session has changed subscribe/unsubscribe
123                          LAYERS_CHANGED,          if self.session is not new_session:
124                          LAYER_LEGEND_CHANGED,              if self.session is not None:
125                          LAYER_VISIBILITY_CHANGED):                  self.session.Unsubscribe(CHANGED, self.update_tree)
126              self.app.session.Subscribe(channel, self.update_tree)              if new_session is not None:
127                    new_session.Subscribe(CHANGED, self.update_tree)
128                self.session = new_session
129          self.update_tree()          self.update_tree()
130    
     def OnSize(self, event):  
         w,h = self.GetClientSizeTuple()  
         self.tree.SetDimensions(0, 0, w, h)  
   
131      def normalize_selection(self):      def normalize_selection(self):
132          """Select the layer or map containing currently selected item"""          """Select the layer or map containing currently selected item"""
133          tree = self.tree          item = self.GetSelection()
         item = self.tree.GetSelection()  
134          while item.IsOk():          while item.IsOk():
135              object = tree.GetPyData(item)              object = self.GetPyData(item)
136              if isinstance(object, Layer) or isinstance(object, Map):              if isinstance(object, Layer) or isinstance(object, Map):
137                  break                  break
138              item = tree.GetItemParent(item)              item = self.GetItemParent(item)
139            else:
140          self.tree.SelectItem(item)              # No layer or map was found in the chain of parents, so
141                # there's nothing we can do.
142                return
143    
144            self.changing_selection = 1
145            try:
146                self.SelectItem(item)
147            finally:
148                self.changing_selection = 0
149    
150      def SelectedLayer(self):      def SelectedLayer(self):
151          """Return the layer object currently selected in the tree.          """Return the layer object currently selected in the tree.
152          Return None if no layer is selected"""          Return None if no layer is selected"""
153          tree = self.tree          layer = self.GetPyData(self.GetSelection())
         layer = tree.GetPyData(tree.GetSelection())  
154          if isinstance(layer, Layer):          if isinstance(layer, Layer):
155              return layer              return layer
156          return None          return None
157    
158      def OnSelChanged(self, event):      def OnSelChanged(self, event):
159            if self.changing_selection:
160                # we're changing the selection ourselves (probably through
161                # self.normalize_selection(). ignore the event.
162                return
163          self.normalize_selection()          self.normalize_selection()
164          layer = self.SelectedLayer()          # SelectedLayer returns None if no layer is selected. Since
165          if layer is not None:          # passing None to interactor.SelectLayer deselects the layer we
166              self.app.interactor.SelectLayer(layer)          # can simply pass the result of SelectedLayer on in all cases
167            self.app.interactor.SelectLayer(self.SelectedLayer())
168    
169      def layer_selected(self, layer):      def layer_selected(self, layer):
170          pass          item = self.layer_to_item.get(id(layer))
171            if item is not None and item != self.GetSelection():
172                self.SelectItem(item)
173    
174    
175    class SessionTreeView(NonModalDialog):
176    
177        """Non modal dialog showing the session as a tree"""
178    
179        def __init__(self, parent, app, name):
180            NonModalDialog.__init__(self, parent, app.interactor, name, "Session")
181            self.tree = SessionTreeCtrl(self, -1, app)
182    
183        def OnClose(self, event):
184            #self.interactor.Unsubscribe(SELECTED_SHAPE, self.select_shape)
185            NonModalDialog.OnClose(self, event)
186    
187            # if there were a way to get notified when the tree control
188            # itself is destroyed we could use that to unsubscribe instead
189            # of doing it here. (EVT_WINDOW_DESTROY doesn't seem to sent at
190            # all)
191            self.tree.unsubscribe_all()

Legend:
Removed from v.6  
changed lines
  Added in v.353

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26