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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 218 - (show annotations)
Thu Jul 18 12:54:48 2002 UTC (22 years, 7 months ago) by bh
Original Path: trunk/thuban/Thuban/UI/tree.py
File MIME type: text/x-python
File size: 7660 byte(s)
	* Thuban/UI/tree.py (SessionTreeCtrl.update_tree): The
	interactor's selected_layer may not be a layer of the current
	session when the tree is updated while a new session is being set.

1 #! /usr/bin/python
2 # Copyright (c) 2001, 2002 by Intevation GmbH
3 # Authors:
4 # Jan-Oliver Wagner <[email protected]>
5 # Bernhard Herzog <[email protected]>
6 #
7 # This program is free software under the GPL (>=v2)
8 # Read the file COPYING coming with Thuban for details.
9
10 __version__ = "$Revision$"
11
12 from types import StringType
13
14 from wxPython.wx import *
15
16 from Thuban.Model.messages import MAPS_CHANGED, MAP_PROJECTION_CHANGED, \
17 LAYERS_CHANGED, LAYER_LEGEND_CHANGED, LAYER_VISIBILITY_CHANGED, \
18 EXTENSIONS_CHANGED, EXTENSION_OBJECTS_CHANGED
19 from Thuban.Model.layer import Layer, shapetype_names
20 from Thuban.Model.map import Map
21
22 from dialogs import NonModalDialog
23 from messages import SESSION_CHANGED, SELECTED_LAYER
24
25
26 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 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.
56 wxTreeCtrl.__init__(self, parent, ID)
57
58 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 # Dictionary mapping layer id's to tree items
64 self.layer_to_item = {}
65
66 self.app.Subscribe(SESSION_CHANGED, self.session_changed)
67 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
73 self.session_changed()
74
75 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):
86 """Clear and rebuild the tree"""
87 self.DeleteAllItems()
88 self.layer_to_item.clear()
89
90 session = self.app.session
91 info = session.TreeInfo()
92 root = self.AddRoot(info[0])
93 self.add_items(root, info[1])
94 self.Expand(root)
95 # select the selected layer
96 selected_layer = self.app.interactor.selected_layer
97 if selected_layer is not None:
98 # One would expect that the selected_layer's id is in
99 # layer_to_item at this point as we've just rebuilt that
100 # mapping completely. However, when a new session is loaded
101 # for instance, it can happen that the tree view is updated
102 # before the interactor in which case selected_layer may be
103 # a layer of the old session.
104 item = self.layer_to_item.get(id(selected_layer))
105 if item is not None:
106 self.SelectItem(item)
107
108 def add_items(self, parent, items):
109 for item in items:
110 if hasattr(item, "TreeInfo"):
111 # Supports the TreeInfo protocol
112 info = item.TreeInfo()
113 treeitem = self.AppendItem(parent, info[0])
114 self.SetPyData(treeitem, item)
115 self.add_items(treeitem, info[1])
116 self.Expand(treeitem)
117 if isinstance(item, Layer):
118 self.layer_to_item[id(item)] = treeitem
119 elif isinstance(item, StringType):
120 # it's a string
121 # FIXME: What to do about UNICODE
122 self.AppendItem(parent, item)
123 else:
124 # assume its a sequence (title, items)
125 treeitem = self.AppendItem(parent, item[0])
126 self.add_items(treeitem, item[1])
127 self.Expand(treeitem)
128
129 def session_changed(self, *args):
130 new_session = self.app.session
131 # if the session has changed subscribe/unsubscribe
132 if self.session is not new_session:
133 if self.session is not None:
134 for channel in self.session_channels:
135 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()
141
142 def normalize_selection(self):
143 """Select the layer or map containing currently selected item"""
144 item = self.GetSelection()
145 while item.IsOk():
146 object = self.GetPyData(item)
147 if isinstance(object, Layer) or isinstance(object, Map):
148 break
149 item = self.GetItemParent(item)
150
151 self.changing_selection = 1
152 try:
153 self.SelectItem(item)
154 finally:
155 self.changing_selection = 0
156
157 def SelectedLayer(self):
158 """Return the layer object currently selected in the tree.
159 Return None if no layer is selected"""
160 layer = self.GetPyData(self.GetSelection())
161 if isinstance(layer, Layer):
162 return layer
163 return None
164
165 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()
171 # SelectedLayer returns None if no layer is selected. Since
172 # passing None to interactor.SelectLayer deselects the layer we
173 # 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):
177 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()

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26