/[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 1058 - (show annotations)
Tue May 27 11:30:29 2003 UTC (21 years, 9 months ago) by frank
Original Path: trunk/thuban/Thuban/UI/tree.py
File MIME type: text/x-python
File size: 8821 byte(s)
Dialog derived from NonModalNonParentDialog

1 #! /usr/bin/python
2 # Copyright (c) 2001, 2002, 2003 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, UnicodeType
13
14 from wxPython.wx import *
15
16 from Thuban import _
17 from Thuban.UI.common import Color2wxColour
18
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
24
25 from dialogs import NonModalNonParentDialog
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 The items list can contain three types of items:
41
42 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
54 # Use the WANTS_CHARS style so the panel doesn't eat the Return key.
55 wxTreeCtrl.__init__(self, parent, ID)
56
57 self.mainwindow = mainwindow
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_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
73 # pretend the session has changed to build the initial tree
74 self.session_changed()
75
76 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):
86 """Clear and rebuild the tree"""
87 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
104 info = session.TreeInfo()
105 root = self.AddRoot(info[0], -1, -1, None)
106 self.SetItemImage(root, self.emptyImageIndex)
107 self.add_items(root, info[1])
108 self.Expand(root)
109 # select the selected layer
110 selected_layer = self.mainwindow.current_layer()
111 if selected_layer is not None:
112 # One would expect that the selected_layer's id is in
113 # layer_to_item at this point as we've just rebuilt that
114 # mapping completely. However, when a new session is loaded
115 # for instance, it can happen that the tree view is updated
116 # before the canvas's selection in which case selected_layer
117 # may be a layer of the old session.
118 item = self.layer_to_item.get(id(selected_layer))
119 if item is not None:
120 self.SelectItem(item)
121
122 def add_items(self, parent, items):
123
124 if items is None: return
125
126 for item in items:
127 if hasattr(item, "TreeInfo"):
128 # Supports the TreeInfo protocol
129 info = item.TreeInfo()
130 treeitem = self.AppendItem(parent, info[0], -1, -1, None)
131 self.SetItemImage(treeitem, self.emptyImageIndex)
132 self.SetPyData(treeitem, item)
133 self.add_items(treeitem, info[1])
134 self.Expand(treeitem)
135 if isinstance(item, Layer):
136 self.layer_to_item[id(item)] = treeitem
137 elif isinstance(item, StringType) or \
138 isinstance(item, UnicodeType):
139 # it's a string
140 treeitem = self.AppendItem(parent, item, -1, -1, None)
141 self.SetItemImage(treeitem, self.emptyImageIndex)
142 else:
143 # assume its a sequence (title, items)
144 if isinstance(item[1], Color):
145
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):
168 new_session = self.app.session
169 # if the session has changed subscribe/unsubscribe
170 if self.session is not new_session:
171 if self.session is not None:
172 self.session.Unsubscribe(CHANGED, self.update_tree)
173 if new_session is not None:
174 new_session.Subscribe(CHANGED, self.update_tree)
175 self.session = new_session
176 self.update_tree()
177
178 def normalize_selection(self):
179 """Select the layer or map containing currently selected item"""
180 item = self.GetSelection()
181 while item.IsOk():
182 object = self.GetPyData(item)
183 if isinstance(object, Layer) or isinstance(object, Map):
184 break
185 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
192 try:
193 self.SelectItem(item)
194 finally:
195 self.changing_selection = 0
196
197 def SelectedLayer(self):
198 """Return the layer object currently selected in the tree.
199 Return None if no layer is selected"""
200 layer = self.GetPyData(self.GetSelection())
201 if isinstance(layer, Layer):
202 return layer
203 return None
204
205 def OnSelChanged(self, event):
206 if self.changing_selection:
207 # we're changing the selection ourselves (probably through
208 # self.normalize_selection(). ignore the event.
209 return
210 self.normalize_selection()
211 # SelectedLayer returns None if no layer is selected. Since
212 # passing None to SelectLayer deselects the layer we can simply
213 # pass the result of SelectedLayer on in all cases
214 self.mainwindow.SelectLayer(self.SelectedLayer())
215
216 def layer_selected(self, layer):
217 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(NonModalNonParentDialog):
223
224 """Non modal dialog showing the session as a tree"""
225
226 def __init__(self, parent, app, name):
227 NonModalNonParentDialog.__init__(self, parent, name, _("Session"))
228 self.tree = SessionTreeCtrl(self, -1, parent, app)
229
230 def OnClose(self, event):
231 NonModalNonParentDialog.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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26