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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 535 - (hide annotations)
Fri Mar 14 20:42:18 2003 UTC (21 years, 11 months ago) by bh
Original Path: trunk/thuban/Thuban/UI/tree.py
File MIME type: text/x-python
File size: 8772 byte(s)
Implement multiple selected shapes

* Thuban/UI/selection.py: New module with a class to represent the
selection.

* Thuban/UI/messages.py (SELECTED_TABLE, SELECTED_MAP): Remove
these unused messages

* Thuban/UI/application.py (ThubanApplication.OnInit)
(ThubanApplication.OnExit, ThubanApplication.SetSession): The
interactor is gone now.
(ThubanApplication.CreateMainWindow): There is no interactor
anymore so we pass None as the interactor argument for now for
compatibility.

* Thuban/UI/view.py (MapCanvas.delegated_messages)
(MapCanvas.Subscribe, MapCanvas.Unsubscribe): In Subscribe and
Unsubscribe, delegate messages according to the delegated_messages
class variable.
(MapCanvas.__getattr__, MapCanvas.delegated_methods): Get some
attributes from instance variables as described with the
delegated_methods class variable.
(MapCanvas.__init__): New instance variable selection holding the
current selection
(MapCanvas.do_redraw): Deal with multiple selected shapes. Simply
pass them on to the renderer
(MapCanvas.SetMap): Clear the selection when a different map is
selected.
(MapCanvas.shape_selected): Simple force a complete redraw. The
selection class now takes care of only issueing SHAPES_SELECTED
messages when the set of selected shapes actually does change.
(MapCanvas.SelectShapeAt): The selection is now managed in
self.selection

* Thuban/UI/mainwindow.py (MainWindow.delegated_messages)
(MainWindow.Subscribe, MainWindow.Unsubscribe): In Subscribe and
Unsubscribe, delegate messages according to the delegated_messages
class variable.
(MainWindow.delegated_methods, MainWindow.__getattr__): Get some
attributes from instance variables as described with the
delegated_methods class variable.
(MainWindow.__init__): The interactor as ivar is gone. The
parameter is still there for compatibility. The selection messages
now come from the canvas.
(MainWindow.current_layer, MainWindow.has_selected_layer):
Delegate to the the canvas.
(MainWindow.LayerShowTable, MainWindow.Classify)
(MainWindow.identify_view_on_demand): The dialogs don't need the
interactor parameter anymore.

* Thuban/UI/tableview.py (TableFrame.__init__)
(LayerTableFrame.__init__, LayerTableFrame.OnClose)
(LayerTableFrame.row_selected): The interactor is gone. It's job
from the dialog's point of view is now done by the mainwindow,
i.e. the parent. Subscribe to SHAPES_SELECTED instead
of SELECTED_SHAPE

* Thuban/UI/dialogs.py (NonModalDialog.__init__): The interactor
is gone. It's job from the dialog's point of view is now done by
the mainwindow, i.e. the parent.

* Thuban/UI/classifier.py (Classifier.__init__): The interactor is
gone. It's job from the dialog's point of view is now done by the
mainwindow, i.e. the parent.

* Thuban/UI/tree.py (SessionTreeView.__init__): The interactor is
gone. It's job from the dialog's point of view is now done by the
mainwindow, i.e. the parent.
(SessionTreeCtrl.__init__): New parameter mainwindow which is
stored as self.mainwindow. The mainwindow is need so that the tree
can still subscribe to the selection messages.
(SessionTreeCtrl.__init__, SessionTreeCtrl.unsubscribe_all)
(SessionTreeCtrl.update_tree, SessionTreeCtrl.OnSelChanged): The
selection is now accessible through the mainwindow. Subscribe to
SHAPES_SELECTED instead of SELECTED_SHAPE

* Thuban/UI/identifyview.py (IdentifyView.__init__): Use the
SHAPES_SELECTED message now.
(IdentifyView.selected_shape): Now subscribed to SHAPES_SELECTED,
so deal with multiple shapes
(IdentifyView.__init__, IdentifyView.OnClose): The interactor is
gone. It's job from the dialog's point of view is now done by the
mainwindow, i.e. the parent.

* Thuban/UI/renderer.py (ScreenRenderer.RenderMap): Rename the
selected_shape parameter and ivar to selected_shapes. It's now a
list of shape ids.
(MapRenderer.draw_label_layer): Deal with multiple selected
shapes. Rearrange the code a bit so that the setup and shape type
distinctions are only executed once.

1 bh 6 #! /usr/bin/python
2 bh 535 # Copyright (c) 2001, 2002, 2003 by Intevation GmbH
3 bh 6 # 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 jonathan 383 from types import StringType, UnicodeType
13 bh 217
14 bh 6 from wxPython.wx import *
15    
16 jan 374 from Thuban import _
17 jonathan 443 from Thuban.UI.common import *
18 jan 374
19 jonathan 383 from Thuban.Model.color import Color
20    
21 bh 233 from Thuban.Model.messages import CHANGED
22     from Thuban.Model.layer import Layer
23 bh 6 from Thuban.Model.map import Map
24    
25 bh 36 from dialogs import NonModalDialog
26 bh 535 from messages import SESSION_REPLACED, LAYER_SELECTED
27 bh 6
28 jonathan 383 BMP_SIZE = 15
29 bh 6
30 bh 41 class SessionTreeCtrl(wxTreeCtrl):
31 bh 36
32 bh 217 """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 bh 535 def __init__(self, parent, ID, mainwindow, app):
53 jonathan 383
54 bh 6 # Use the WANTS_CHARS style so the panel doesn't eat the Return key.
55 bh 36 wxTreeCtrl.__init__(self, parent, ID)
56    
57 bh 535 self.mainwindow = mainwindow
58 bh 6 self.app = app
59 bh 14 # 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 bh 41 # Dictionary mapping layer id's to tree items
64     self.layer_to_item = {}
65    
66 jonathan 504 self.app.Subscribe(SESSION_REPLACED, self.session_changed)
67 bh 535 self.mainwindow.Subscribe(LAYER_SELECTED, self.layer_selected)
68 bh 151
69     # the session currently displayed in the tree
70     self.session = None
71    
72 jonathan 383
73 bh 6 # pretend the session has changed to build the initial tree
74     self.session_changed()
75    
76 bh 36 EVT_TREE_SEL_CHANGED(self, self.GetId(), self.OnSelChanged)
77 bh 6
78 bh 151 def unsubscribe_all(self):
79     if self.session is not None:
80 bh 233 self.session.Unsubscribe(CHANGED, self.update_tree)
81 bh 161 self.session = None
82 jonathan 504 self.app.Unsubscribe(SESSION_REPLACED, self.session_changed)
83 bh 535 self.mainwindow.Unsubscribe(LAYER_SELECTED, self.layer_selected)
84 bh 151
85 bh 6 def update_tree(self, *args):
86     """Clear and rebuild the tree"""
87 bh 36 self.DeleteAllItems()
88 bh 41 self.layer_to_item.clear()
89 jonathan 510 self.image_list = wxImageList(BMP_SIZE, BMP_SIZE, False, 0)
90 jonathan 521
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 jonathan 510 self.AssignImageList(self.image_list)
102 jan 104
103 bh 217 session = self.app.session
104     info = session.TreeInfo()
105 jonathan 521 root = self.AddRoot(info[0], -1, -1, None)
106     self.SetItemImage(root, self.emptyImageIndex)
107 bh 217 self.add_items(root, info[1])
108 bh 36 self.Expand(root)
109 bh 217 # select the selected layer
110 bh 535 selected_layer = self.mainwindow.current_layer()
111 bh 217 if selected_layer is not None:
112 bh 218 # 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 bh 535 # before the canvas's selection in which case selected_layer
117     # may be a layer of the old session.
118 bh 218 item = self.layer_to_item.get(id(selected_layer))
119     if item is not None:
120     self.SelectItem(item)
121 bh 6
122 bh 217 def add_items(self, parent, items):
123 jonathan 383
124     if items is None: return
125    
126 bh 217 for item in items:
127     if hasattr(item, "TreeInfo"):
128     # Supports the TreeInfo protocol
129     info = item.TreeInfo()
130 jonathan 521 treeitem = self.AppendItem(parent, info[0], -1, -1, None)
131     self.SetItemImage(treeitem, self.emptyImageIndex)
132 bh 217 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 jonathan 383 elif isinstance(item, StringType) or \
138     isinstance(item, UnicodeType):
139 bh 217 # it's a string
140 jonathan 521 treeitem = self.AppendItem(parent, item, -1, -1, None)
141     self.SetItemImage(treeitem, self.emptyImageIndex)
142 bh 217 else:
143     # assume its a sequence (title, items)
144 jonathan 383 if isinstance(item[1], Color):
145    
146 jonathan 417 treeitem = self.AppendItem(parent, "(%s)" % item[0])
147    
148 jonathan 383 bmp = wxEmptyBitmap(BMP_SIZE, BMP_SIZE)
149 jonathan 443 brush = wxBrush(Color2wxColour(item[1]), wxSOLID)
150 jonathan 383 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 jonathan 521 treeitem = self.AppendItem(parent, item[0], -1, -1, None)
163     self.SetItemImage(treeitem, self.emptyImageIndex)
164 jonathan 383 self.add_items(treeitem, item[1])
165 bh 217 self.Expand(treeitem)
166 jan 198
167 bh 6 def session_changed(self, *args):
168 bh 151 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 bh 233 self.session.Unsubscribe(CHANGED, self.update_tree)
173 bh 151 if new_session is not None:
174 bh 233 new_session.Subscribe(CHANGED, self.update_tree)
175 bh 151 self.session = new_session
176 bh 6 self.update_tree()
177    
178     def normalize_selection(self):
179     """Select the layer or map containing currently selected item"""
180 bh 36 item = self.GetSelection()
181 bh 6 while item.IsOk():
182 bh 36 object = self.GetPyData(item)
183 bh 6 if isinstance(object, Layer) or isinstance(object, Map):
184     break
185 bh 36 item = self.GetItemParent(item)
186 bh 353 else:
187     # No layer or map was found in the chain of parents, so
188     # there's nothing we can do.
189     return
190 bh 6
191 bh 14 self.changing_selection = 1
192     try:
193 bh 36 self.SelectItem(item)
194 bh 14 finally:
195     self.changing_selection = 0
196 bh 6
197     def SelectedLayer(self):
198     """Return the layer object currently selected in the tree.
199     Return None if no layer is selected"""
200 bh 36 layer = self.GetPyData(self.GetSelection())
201 bh 6 if isinstance(layer, Layer):
202     return layer
203     return None
204    
205     def OnSelChanged(self, event):
206 bh 14 if self.changing_selection:
207     # we're changing the selection ourselves (probably through
208     # self.normalize_selection(). ignore the event.
209     return
210 bh 6 self.normalize_selection()
211 bh 61 # SelectedLayer returns None if no layer is selected. Since
212 bh 535 # 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 bh 6
216     def layer_selected(self, layer):
217 bh 41 item = self.layer_to_item.get(id(layer))
218     if item is not None and item != self.GetSelection():
219     self.SelectItem(item)
220 bh 36
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 bh 535 NonModalDialog.__init__(self, parent, name, _("Session"))
228     self.tree = SessionTreeCtrl(self, -1, parent, app)
229 bh 36
230 jonathan 504 def OnClose(self, event):
231     NonModalDialog.OnClose(self, event)
232    
233 bh 151 # 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 jonathan 488

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26