/[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 521 by jonathan, Wed Mar 12 13:18:50 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, UnicodeType
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  from Thuban.UI.common import *
18  from Thuban.Model.layer import Layer, shapetype_names  
19    from Thuban.Model.color import Color
20    
21    from Thuban.Model.messages import CHANGED
22    from Thuban.Model.layer import Layer
23  from Thuban.Model.map import Map  from Thuban.Model.map import Map
 import view  
24    
25  from messages import SESSION_CHANGED, SELECTED_LAYER  from dialogs import NonModalDialog
26    from messages import SESSION_REPLACED, SELECTED_LAYER
27    
28    BMP_SIZE = 15
29    
30    class SessionTreeCtrl(wxTreeCtrl):
31    
32        """Widget to display a tree view of the session.
33    
34        The tree view is created recursively from the session object. The
35        tree view calls the session's TreeInfo method which should return a
36        pair (<title>, <item>) where <title> ist the title of the session
37        item in the tree view and <items> is a list of objects to use as the
38        children of the session in the tree view.
39    
40  def color_string(color):      The items list can contain three types of items:
     if color is None:  
         return "None"  
     return "(%.3f, %.3f, %.3f)" % (color.red, color.green, color.blue)  
41    
42  class myTreeCtrlPanel(wxPanel):         1. a string. The string is used as the title for a leaf item in
43              the tree view.
44    
45           2. an object with a TreeInfo method. This method is called and
46              should return a pair just like the session's TreeInfo method.
47    
48           3. a pair (<title>, <item>) which is treated like the return
49              value of TreeInfo.
50        """
51    
52        def __init__(self, parent, ID, app):
53    
     def __init__(self, parent, app):  
54          # 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.
55          wxPanel.__init__(self, parent, -1, style=wxWANTS_CHARS)          wxTreeCtrl.__init__(self, parent, ID)
         self.app = app  
56    
57            self.app = app
58          # boolean to indicate that we manipulate the selection ourselves          # boolean to indicate that we manipulate the selection ourselves
59          # so that we can ignore the selection events generated          # so that we can ignore the selection events generated
60          self.changing_selection = 0          self.changing_selection = 0
61    
62          EVT_SIZE(self, self.OnSize)          # Dictionary mapping layer id's to tree items
63          self.tree = wxTreeCtrl(self, -1)          self.layer_to_item = {}
64    
65          self.app.Subscribe(SESSION_CHANGED, self.session_changed)          self.app.Subscribe(SESSION_REPLACED, self.session_changed)
66          self.app.interactor.Subscribe(SELECTED_LAYER, self.layer_selected)          self.app.interactor.Subscribe(SELECTED_LAYER, self.layer_selected)
67    
68            # the session currently displayed in the tree
69            self.session = None
70    
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                self.session.Unsubscribe(CHANGED, self.update_tree)
80                self.session = None
81            self.app.Unsubscribe(SESSION_REPLACED, self.session_changed)
82            self.app.interactor.Unsubscribe(SELECTED_LAYER, self.layer_selected)
83    
84      def update_tree(self, *args):      def update_tree(self, *args):
85          """Clear and rebuild the tree"""          """Clear and rebuild the tree"""
86          self.tree.DeleteAllItems()          self.DeleteAllItems()
87            self.layer_to_item.clear()
88            self.image_list = wxImageList(BMP_SIZE, BMP_SIZE, False, 0)
89    
90            bmp = wxEmptyBitmap(BMP_SIZE, BMP_SIZE)
91            dc = wxMemoryDC()
92            dc.SelectObject(bmp)
93            dc.SetBrush(wxBLACK_BRUSH)
94            dc.Clear()
95            dc.SelectObject(wxNullBitmap)
96    
97            self.emptyImageIndex = \
98                self.image_list.AddWithColourMask(bmp, wxColour(0, 0, 0))
99    
100            self.AssignImageList(self.image_list)
101    
102          session = self.app.session          session = self.app.session
103          root = self.tree.AddRoot("Session: %s" % session.title)          info = session.TreeInfo()
104          for map in session.Maps():          root = self.AddRoot(info[0], -1, -1, None)
105              mapitem = self.tree.AppendItem(root, "Map: %s" % map.title)          self.SetItemImage(root, self.emptyImageIndex)
106              self.tree.SetPyData(mapitem, map)          self.add_items(root, info[1])
107              if map.projection and len(map.projection.params) > 0:          self.Expand(root)
108                  projectionitem = self.tree.AppendItem(mapitem, "Projection")          # select the selected layer
109                  for param in map.projection.params:          selected_layer = self.app.interactor.selected_layer
110                      parameteritem = self.tree.AppendItem(projectionitem,          if selected_layer is not None:
111                                                           str(param))              # One would expect that the selected_layer's id is in
112                  self.tree.Expand(projectionitem)              # layer_to_item at this point as we've just rebuilt that
113                # mapping completely. However, when a new session is loaded
114              layers = map.Layers()              # for instance, it can happen that the tree view is updated
115              for layer_index in range(len(layers) - 1, -1, -1):              # before the interactor in which case selected_layer may be
116                  layer = layers[layer_index]              # a layer of the old session.
117                  idata = wxTreeItemData()              item = self.layer_to_item.get(id(selected_layer))
118                  idata.SetData(layer)              if item is not None:
119                  layeritem = self.tree.AppendItem(mapitem,                  self.SelectItem(item)
120                                                   "Layer '%s'" % layer.Title(),  
121                                                   data = idata)      def add_items(self, parent, items):
122                  if layer is self.app.interactor.selected_layer:  
123                      self.tree.SelectItem(layeritem)          if items is None: return
124                  if isinstance(layer, Layer):  
125                      if layer.Visible():          for item in items:
126                          text = "Shown"              if hasattr(item, "TreeInfo"):
127                      else:                  # Supports the TreeInfo protocol
128                          text = "Hidden"                  info = item.TreeInfo()
129                      self.tree.AppendItem(layeritem, text)                  treeitem = self.AppendItem(parent, info[0], -1, -1, None)
130                      self.tree.AppendItem(layeritem,                  self.SetItemImage(treeitem, self.emptyImageIndex)
131                                           "Shapes: %d" % layer.NumShapes())                  self.SetPyData(treeitem, item)
132                      self.tree.AppendItem(layeritem,                  self.add_items(treeitem, info[1])
133                                           ("Extents: (%g, %g, %g, %g)"                  self.Expand(treeitem)
134                                            % layer.LatLongBoundingBox()))                  if isinstance(item, Layer):
135                      self.tree.AppendItem(layeritem,                      self.layer_to_item[id(item)] = treeitem
136                                           "Shapetype: %s" %              elif isinstance(item, StringType) or \
137                                           shapetype_names[layer.ShapeType()])                   isinstance(item, UnicodeType):
138                      self.tree.AppendItem(layeritem,                  # it's a string
139                                           "Fill: " + color_string(layer.fill))                  treeitem = self.AppendItem(parent, item, -1, -1, None)
140                      self.tree.AppendItem(layeritem,                  self.SetItemImage(treeitem, self.emptyImageIndex)
141                                        "Outline: " + color_string(layer.stroke))              else:
142                  self.tree.Expand(layeritem)                  # assume its a sequence (title, items)
143              self.tree.Expand(mapitem)                  if isinstance(item[1], Color):
144          self.tree.Expand(root)  
145                        treeitem = self.AppendItem(parent, "(%s)" % item[0])
146    
147                        bmp = wxEmptyBitmap(BMP_SIZE, BMP_SIZE)
148                        brush = wxBrush(Color2wxColour(item[1]), wxSOLID)
149                        dc = wxMemoryDC()
150                        dc.SelectObject(bmp)
151                        dc.SetBrush(brush)
152                        dc.Clear()
153                        dc.DrawRoundedRectangle(0, 0,
154                                                bmp.GetWidth(), bmp.GetHeight(),
155                                                4)
156                        dc.SelectObject(wxNullBitmap)
157    
158                        i = self.image_list.Add(bmp)
159                        self.SetItemImage(treeitem, i)
160                    else:
161                        treeitem = self.AppendItem(parent, item[0], -1, -1, None)
162                        self.SetItemImage(treeitem, self.emptyImageIndex)
163                        self.add_items(treeitem, item[1])
164                    self.Expand(treeitem)
165    
166      def session_changed(self, *args):      def session_changed(self, *args):
167          for channel in (MAPS_CHANGED,          new_session = self.app.session
168                          MAP_PROJECTION_CHANGED,          # if the session has changed subscribe/unsubscribe
169                          LAYERS_CHANGED,          if self.session is not new_session:
170                          LAYER_LEGEND_CHANGED,              if self.session is not None:
171                          LAYER_VISIBILITY_CHANGED):                  self.session.Unsubscribe(CHANGED, self.update_tree)
172              self.app.session.Subscribe(channel, self.update_tree)              if new_session is not None:
173                    new_session.Subscribe(CHANGED, self.update_tree)
174                self.session = new_session
175          self.update_tree()          self.update_tree()
176    
     def OnSize(self, event):  
         w,h = self.GetClientSizeTuple()  
         self.tree.SetDimensions(0, 0, w, h)  
   
177      def normalize_selection(self):      def normalize_selection(self):
178          """Select the layer or map containing currently selected item"""          """Select the layer or map containing currently selected item"""
179          tree = self.tree          item = self.GetSelection()
         item = self.tree.GetSelection()  
180          while item.IsOk():          while item.IsOk():
181              object = tree.GetPyData(item)              object = self.GetPyData(item)
182              if isinstance(object, Layer) or isinstance(object, Map):              if isinstance(object, Layer) or isinstance(object, Map):
183                  break                  break
184              item = tree.GetItemParent(item)              item = self.GetItemParent(item)
185            else:
186                # No layer or map was found in the chain of parents, so
187                # there's nothing we can do.
188                return
189    
190          self.changing_selection = 1          self.changing_selection = 1
191          try:          try:
192              self.tree.SelectItem(item)              self.SelectItem(item)
193          finally:          finally:
194              self.changing_selection = 0              self.changing_selection = 0
195    
196      def SelectedLayer(self):      def SelectedLayer(self):
197          """Return the layer object currently selected in the tree.          """Return the layer object currently selected in the tree.
198          Return None if no layer is selected"""          Return None if no layer is selected"""
199          tree = self.tree          layer = self.GetPyData(self.GetSelection())
         layer = tree.GetPyData(tree.GetSelection())  
200          if isinstance(layer, Layer):          if isinstance(layer, Layer):
201              return layer              return layer
202          return None          return None
# Line 136  class myTreeCtrlPanel(wxPanel): Line 207  class myTreeCtrlPanel(wxPanel):
207              # self.normalize_selection(). ignore the event.              # self.normalize_selection(). ignore the event.
208              return              return
209          self.normalize_selection()          self.normalize_selection()
210          layer = self.SelectedLayer()          # SelectedLayer returns None if no layer is selected. Since
211          if layer is not None:          # passing None to interactor.SelectLayer deselects the layer we
212              self.app.interactor.SelectLayer(layer)          # can simply pass the result of SelectedLayer on in all cases
213            self.app.interactor.SelectLayer(self.SelectedLayer())
214    
215      def layer_selected(self, layer):      def layer_selected(self, layer):
216          pass          item = self.layer_to_item.get(id(layer))
217            if item is not None and item != self.GetSelection():
218                self.SelectItem(item)
219    
220    
221    class SessionTreeView(NonModalDialog):
222    
223        """Non modal dialog showing the session as a tree"""
224    
225        def __init__(self, parent, app, name):
226            NonModalDialog.__init__(self, parent, app.interactor, name,
227                                    _("Session"))
228            self.tree = SessionTreeCtrl(self, -1, app)
229    
230        def OnClose(self, event):
231            NonModalDialog.OnClose(self, event)
232    
233            # if there were a way to get notified when the tree control
234            # itself is destroyed we could use that to unsubscribe instead
235            # of doing it here. (EVT_WINDOW_DESTROY doesn't seem to sent at
236            # all)
237            self.tree.unsubscribe_all()
238    

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26