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

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26