/[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 535 by bh, Fri Mar 14 20:42:18 2003 UTC
# Line 1  Line 1 
1  #! /usr/bin/python  #! /usr/bin/python
2  # Copyright (c) 2001 by Intevation GmbH  # Copyright (c) 2001, 2002, 2003 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, LAYER_SELECTED
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, mainwindow, 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.mainwindow = mainwindow
58            self.app = app
59          # boolean to indicate that we manipulate the selection ourselves          # boolean to indicate that we manipulate the selection ourselves
60          # so that we can ignore the selection events generated          # so that we can ignore the selection events generated
61          self.changing_selection = 0          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_REPLACED, self.session_changed)
67            self.mainwindow.Subscribe(LAYER_SELECTED, self.layer_selected)
68    
69            # the session currently displayed in the tree
70            self.session = None
71    
72    
         self.app.Subscribe(SESSION_CHANGED, self.session_changed)  
         self.app.interactor.Subscribe(SELECTED_LAYER, self.layer_selected)  
73          # pretend the session has changed to build the initial tree          # pretend the session has changed to build the initial tree
74          self.session_changed()          self.session_changed()
75    
76          EVT_TREE_SEL_CHANGED(self, self.tree.GetId(), self.OnSelChanged)          EVT_TREE_SEL_CHANGED(self, self.GetId(), self.OnSelChanged)
77    
78        def unsubscribe_all(self):
79            if self.session is not None:
80                self.session.Unsubscribe(CHANGED, self.update_tree)
81                self.session = None
82            self.app.Unsubscribe(SESSION_REPLACED, self.session_changed)
83            self.mainwindow.Unsubscribe(LAYER_SELECTED, 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            self.image_list = wxImageList(BMP_SIZE, BMP_SIZE, False, 0)
90    
91            bmp = wxEmptyBitmap(BMP_SIZE, BMP_SIZE)
92            dc = wxMemoryDC()
93            dc.SelectObject(bmp)
94            dc.SetBrush(wxBLACK_BRUSH)
95            dc.Clear()
96            dc.SelectObject(wxNullBitmap)
97    
98            self.emptyImageIndex = \
99                self.image_list.AddWithColourMask(bmp, wxColour(0, 0, 0))
100    
101            self.AssignImageList(self.image_list)
102    
103          session = self.app.session          session = self.app.session
104          root = self.tree.AddRoot("Session: %s" % session.title)          info = session.TreeInfo()
105          for map in session.Maps():          root = self.AddRoot(info[0], -1, -1, None)
106              mapitem = self.tree.AppendItem(root, "Map: %s" % map.title)          self.SetItemImage(root, self.emptyImageIndex)
107              self.tree.SetPyData(mapitem, map)          self.add_items(root, info[1])
108              if map.projection and len(map.projection.params) > 0:          self.Expand(root)
109                  projectionitem = self.tree.AppendItem(mapitem, "Projection")          # select the selected layer
110                  for param in map.projection.params:          selected_layer = self.mainwindow.current_layer()
111                      parameteritem = self.tree.AppendItem(projectionitem,          if selected_layer is not None:
112                                                           str(param))              # One would expect that the selected_layer's id is in
113                  self.tree.Expand(projectionitem)              # layer_to_item at this point as we've just rebuilt that
114                # mapping completely. However, when a new session is loaded
115              layers = map.Layers()              # for instance, it can happen that the tree view is updated
116              for layer_index in range(len(layers) - 1, -1, -1):              # before the canvas's selection in which case selected_layer
117                  layer = layers[layer_index]              # may be a layer of the old session.
118                  idata = wxTreeItemData()              item = self.layer_to_item.get(id(selected_layer))
119                  idata.SetData(layer)              if item is not None:
120                  layeritem = self.tree.AppendItem(mapitem,                  self.SelectItem(item)
121                                                   "Layer '%s'" % layer.Title(),  
122                                                   data = idata)      def add_items(self, parent, items):
123                  if layer is self.app.interactor.selected_layer:  
124                      self.tree.SelectItem(layeritem)          if items is None: return
125                  if isinstance(layer, Layer):  
126                      if layer.Visible():          for item in items:
127                          text = "Shown"              if hasattr(item, "TreeInfo"):
128                      else:                  # Supports the TreeInfo protocol
129                          text = "Hidden"                  info = item.TreeInfo()
130                      self.tree.AppendItem(layeritem, text)                  treeitem = self.AppendItem(parent, info[0], -1, -1, None)
131                      self.tree.AppendItem(layeritem,                  self.SetItemImage(treeitem, self.emptyImageIndex)
132                                           "Shapes: %d" % layer.NumShapes())                  self.SetPyData(treeitem, item)
133                      self.tree.AppendItem(layeritem,                  self.add_items(treeitem, info[1])
134                                           ("Extents: (%g, %g, %g, %g)"                  self.Expand(treeitem)
135                                            % layer.LatLongBoundingBox()))                  if isinstance(item, Layer):
136                      self.tree.AppendItem(layeritem,                      self.layer_to_item[id(item)] = treeitem
137                                           "Shapetype: %s" %              elif isinstance(item, StringType) or \
138                                           shapetype_names[layer.ShapeType()])                   isinstance(item, UnicodeType):
139                      self.tree.AppendItem(layeritem,                  # it's a string
140                                           "Fill: " + color_string(layer.fill))                  treeitem = self.AppendItem(parent, item, -1, -1, None)
141                      self.tree.AppendItem(layeritem,                  self.SetItemImage(treeitem, self.emptyImageIndex)
142                                        "Outline: " + color_string(layer.stroke))              else:
143                  self.tree.Expand(layeritem)                  # assume its a sequence (title, items)
144              self.tree.Expand(mapitem)                  if isinstance(item[1], Color):
145          self.tree.Expand(root)  
146                        treeitem = self.AppendItem(parent, "(%s)" % item[0])
147    
148                        bmp = wxEmptyBitmap(BMP_SIZE, BMP_SIZE)
149                        brush = wxBrush(Color2wxColour(item[1]), wxSOLID)
150                        dc = wxMemoryDC()
151                        dc.SelectObject(bmp)
152                        dc.SetBrush(brush)
153                        dc.Clear()
154                        dc.DrawRoundedRectangle(0, 0,
155                                                bmp.GetWidth(), bmp.GetHeight(),
156                                                4)
157                        dc.SelectObject(wxNullBitmap)
158    
159                        i = self.image_list.Add(bmp)
160                        self.SetItemImage(treeitem, i)
161                    else:
162                        treeitem = self.AppendItem(parent, item[0], -1, -1, None)
163                        self.SetItemImage(treeitem, self.emptyImageIndex)
164                        self.add_items(treeitem, item[1])
165                    self.Expand(treeitem)
166    
167      def session_changed(self, *args):      def session_changed(self, *args):
168          for channel in (MAPS_CHANGED,          new_session = self.app.session
169                          MAP_PROJECTION_CHANGED,          # if the session has changed subscribe/unsubscribe
170                          LAYERS_CHANGED,          if self.session is not new_session:
171                          LAYER_LEGEND_CHANGED,              if self.session is not None:
172                          LAYER_VISIBILITY_CHANGED):                  self.session.Unsubscribe(CHANGED, self.update_tree)
173              self.app.session.Subscribe(channel, self.update_tree)              if new_session is not None:
174                    new_session.Subscribe(CHANGED, self.update_tree)
175                self.session = new_session
176          self.update_tree()          self.update_tree()
177    
     def OnSize(self, event):  
         w,h = self.GetClientSizeTuple()  
         self.tree.SetDimensions(0, 0, w, h)  
   
178      def normalize_selection(self):      def normalize_selection(self):
179          """Select the layer or map containing currently selected item"""          """Select the layer or map containing currently selected item"""
180          tree = self.tree          item = self.GetSelection()
         item = self.tree.GetSelection()  
181          while item.IsOk():          while item.IsOk():
182              object = tree.GetPyData(item)              object = self.GetPyData(item)
183              if isinstance(object, Layer) or isinstance(object, Map):              if isinstance(object, Layer) or isinstance(object, Map):
184                  break                  break
185              item = tree.GetItemParent(item)              item = self.GetItemParent(item)
186            else:
187                # No layer or map was found in the chain of parents, so
188                # there's nothing we can do.
189                return
190    
191          self.changing_selection = 1          self.changing_selection = 1
192          try:          try:
193              self.tree.SelectItem(item)              self.SelectItem(item)
194          finally:          finally:
195              self.changing_selection = 0              self.changing_selection = 0
196    
197      def SelectedLayer(self):      def SelectedLayer(self):
198          """Return the layer object currently selected in the tree.          """Return the layer object currently selected in the tree.
199          Return None if no layer is selected"""          Return None if no layer is selected"""
200          tree = self.tree          layer = self.GetPyData(self.GetSelection())
         layer = tree.GetPyData(tree.GetSelection())  
201          if isinstance(layer, Layer):          if isinstance(layer, Layer):
202              return layer              return layer
203          return None          return None
# Line 136  class myTreeCtrlPanel(wxPanel): Line 208  class myTreeCtrlPanel(wxPanel):
208              # self.normalize_selection(). ignore the event.              # self.normalize_selection(). ignore the event.
209              return              return
210          self.normalize_selection()          self.normalize_selection()
211          layer = self.SelectedLayer()          # SelectedLayer returns None if no layer is selected. Since
212          if layer is not None:          # passing None to SelectLayer deselects the layer we can simply
213              self.app.interactor.SelectLayer(layer)          # pass the result of SelectedLayer on in all cases
214            self.mainwindow.SelectLayer(self.SelectedLayer())
215    
216      def layer_selected(self, layer):      def layer_selected(self, layer):
217          pass          item = self.layer_to_item.get(id(layer))
218            if item is not None and item != self.GetSelection():
219                self.SelectItem(item)
220    
221    
222    class SessionTreeView(NonModalDialog):
223    
224        """Non modal dialog showing the session as a tree"""
225    
226        def __init__(self, parent, app, name):
227            NonModalDialog.__init__(self, parent, name, _("Session"))
228            self.tree = SessionTreeCtrl(self, -1, parent, 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.535

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26