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

Legend:
Removed from v.14  
changed lines
  Added in v.374

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26