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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2700 - (hide annotations)
Mon Sep 18 14:27:02 2006 UTC (18 years, 5 months ago) by dpinte
Original Path: trunk/thuban/Thuban/UI/tableview.py
File MIME type: text/x-python
File size: 22138 byte(s)
2006-09-18 Didrik Pinte <dpinte@itae.be>
    
        * wxPython 2.6 update : wx 2.4 syntax has been updated to 2.6


1 bh 535 # Copyright (c) 2001, 2002, 2003 by Intevation GmbH
2 bh 6 # Authors:
3     # Bernhard Herzog <[email protected]>
4     #
5     # This program is free software under the GPL (>=v2)
6     # Read the file COPYING coming with Thuban for details.
7    
8     __version__ = "$Revision$"
9    
10 frank 1027 import os.path
11    
12 jonathan 881 from Thuban import _
13    
14 dpinte 2700 import wx
15     from wx import grid
16 bh 6
17 bh 34 from Thuban.Lib.connector import Publisher
18 bh 6 from Thuban.Model.table import FIELDTYPE_INT, FIELDTYPE_DOUBLE, \
19 frank 1027 FIELDTYPE_STRING, table_to_dbf, table_to_csv
20 jonathan 1199 from dialogs import ThubanFrame
21 bh 6
22 bh 1068 from messages import SHAPES_SELECTED, SESSION_REPLACED
23 bh 1146 from Thuban.Model.messages import TABLE_REMOVED, MAP_LAYERS_REMOVED
24 jonathan 1276 from Thuban.UI.common import ThubanBeginBusyCursor, ThubanEndBusyCursor
25 bh 1068
26 dpinte 2700 wx_value_type_map = {FIELDTYPE_INT: grid.GRID_VALUE_NUMBER,
27     FIELDTYPE_DOUBLE: grid.GRID_VALUE_FLOAT,
28     FIELDTYPE_STRING: grid.GRID_VALUE_STRING}
29 bh 6
30 bh 34 ROW_SELECTED = "ROW_SELECTED"
31    
32 frank 979 QUERY_KEY = 'S'
33 bh 34
34 dpinte 2700 class DataTable(grid.PyGridTableBase):
35 bh 6
36 bh 34 """Wrapper around a Thuban table object suitable for a wxGrid"""
37    
38 bh 6 def __init__(self, table = None):
39 dpinte 2700 grid.PyGridTableBase.__init__(self)
40 bh 6 self.num_cols = 0
41     self.num_rows = 0
42     self.columns = []
43     self.table = None
44     self.SetTable(table)
45    
46     def SetTable(self, table):
47     self.table = table
48 bh 838 self.num_cols = table.NumColumns()
49     self.num_rows = table.NumRows()
50 bh 6
51     self.columns = []
52     for i in range(self.num_cols):
53 bh 838 col = table.Column(i)
54     self.columns.append((col.name, wx_value_type_map[col.type]))
55 bh 6
56     #
57     # required methods for the wxPyGridTableBase interface
58     #
59    
60     def GetNumberRows(self):
61     return self.num_rows
62    
63     def GetNumberCols(self):
64     return self.num_cols
65    
66     def IsEmptyCell(self, row, col):
67     return 0
68    
69     # Get/Set values in the table. The Python version of these
70     # methods can handle any data-type, (as long as the Editor and
71     # Renderer understands the type too,) not just strings as in the
72     # C++ version.
73     def GetValue(self, row, col):
74 bh 1662 record = self.table.ReadRowAsDict(row, row_is_ordinal = 1)
75 bh 6 return record[self.columns[col][0]]
76    
77     def SetValue(self, row, col, value):
78     pass
79    
80     #
81     # Some optional methods
82     #
83    
84     # Called when the grid needs to display labels
85     def GetColLabelValue(self, col):
86     return self.columns[col][0]
87    
88     # Called to determine the kind of editor/renderer to use by
89     # default, doesn't necessarily have to be the same type used
90     # nativly by the editor/renderer if they know how to convert.
91     def GetTypeName(self, row, col):
92     return self.columns[col][1]
93    
94     # Called to determine how the data can be fetched and stored by the
95     # editor and renderer. This allows you to enforce some type-safety
96     # in the grid.
97     def CanGetValueAs(self, row, col, typeName):
98     # perhaps we should allow conversion int->double?
99     return self.GetTypeName(row, col) == typeName
100    
101     def CanSetValueAs(self, row, col, typeName):
102     return self.CanGetValueAs(row, col, typeName)
103    
104    
105 bh 1662 #
106     def RowIdToOrdinal(self, rowid):
107     """Return the ordinal of the row given by its id"""
108     return self.table.RowIdToOrdinal(rowid)
109 bh 1092
110 bh 1662 def RowOrdinalToId(self, ordinal):
111     """Return the id of the row given by its ordinal"""
112     return self.table.RowOrdinalToId(ordinal)
113    
114    
115 dpinte 2700 class NullRenderer(grid.PyGridCellRenderer):
116 bh 1092
117     """Renderer that draws NULL as a gray rectangle
118    
119     Other values are delegated to a normal renderer which is given as
120     the parameter to the constructor.
121     """
122    
123     def __init__(self, non_null_renderer):
124 dpinte 2700 grid.PyGridCellRenderer.__init__(self)
125 bh 1092 self.non_null_renderer = non_null_renderer
126    
127     def Draw(self, grid, attr, dc, rect, row, col, isSelected):
128     value = grid.table.GetValue(row, col)
129     if value is None:
130 dpinte 2700 dc.SetBackgroundMode(wx.SOLID)
131     dc.SetBrush(wx.Brush(wx.Colour(192, 192, 192), wx.SOLID))
132     dc.SetPen(wx.TRANSPARENT_PEN)
133 bh 1092 dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height)
134     else:
135     self.non_null_renderer.Draw(grid, attr, dc, rect, row, col,
136     isSelected)
137    
138     def GetBestSize(self, grid, attr, dc, row, col):
139     self.non_null_renderer.GetBestSize(grid, attr, dc, row, col)
140    
141     def Clone(self):
142     return NullRenderer(self.non_null_renderer)
143    
144    
145 dpinte 2700 class TableGrid(grid.Grid, Publisher):
146 bh 6
147 bh 808 """A grid view for a Thuban table
148 bh 6
149 bh 808 When rows are selected by the user the table issues ROW_SELECTED
150     messages. wx sends selection events even when the selection is
151     manipulated by code (instead of by the user) which usually lead to
152     ROW_SELECTED messages being sent in turn. Therefore sending messages
153     can be switched on and off with the allow_messages and
154     disallow_messages methods.
155     """
156    
157 bh 6 def __init__(self, parent, table = None):
158 dpinte 2700 grid.Grid.__init__(self, parent, -1)
159 bh 6
160 bh 808 self.allow_messages_count = 0
161    
162 jonathan 1199 # keep track of which rows are selected.
163     self.rows = {}
164    
165 bh 6 self.table = DataTable(table)
166    
167     # The second parameter means that the grid is to take ownership
168     # of the table and will destroy it when done. Otherwise you
169 bh 77 # would need to keep a reference to it and call its Destroy
170 bh 6 # method later.
171 jan 1035 self.SetTable(self.table, True)
172 bh 6
173     #self.SetMargins(0,0)
174    
175 bh 173 # AutoSizeColumns would allow us to make the grid have optimal
176     # column widths automatically but it would cause a traversal of
177     # the entire table which for large .dbf files can take a very
178     # long time.
179 jan 1035 #self.AutoSizeColumns(False)
180 bh 173
181 dpinte 2700 self.SetSelectionMode(grid.Grid.wxGridSelectRows)
182 bh 278
183 jonathan 966 self.ToggleEventListeners(True)
184 dpinte 2700 self.Bind(grid.EVT_GRID_RANGE_SELECT, self.OnRangeSelect)
185     self.Bind(grid.EVT_GRID_SELECT_CELL, self.OnSelectCell)
186 jonathan 966
187 bh 1092 # Replace the normal renderers with our own versions which
188     # render NULL/None values specially
189 dpinte 2700 self.RegisterDataType(grid.GRID_VALUE_STRING,
190     NullRenderer(grid.GridCellStringRenderer()), None)
191     self.RegisterDataType(grid.GRID_VALUE_NUMBER,
192     NullRenderer(grid.GridCellNumberRenderer()), None)
193     self.RegisterDataType(grid.GRID_VALUE_FLOAT,
194     NullRenderer(grid.GridCellFloatRenderer()), None)
195 bh 1092
196 dpinte 2700 self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy)
197 bh 2032
198     def OnDestroy(self, event):
199     Publisher.Destroy(self)
200    
201 bh 6 def SetTableObject(self, table):
202     self.table.SetTable(table)
203    
204     def OnRangeSelect(self, event):
205 bh 1662 to_id = self.table.RowOrdinalToId
206 jonathan 1199 if self.handleSelectEvents:
207 bh 1662 self.rows = dict([(to_id(i), 0) for i in self.GetSelectedRows()])
208 jonathan 881
209 jonathan 1199 # if we're selecting we need to include the selected range and
210     # make sure that the current row is also included, which may
211     # not be the case if you just click on a single row!
212     if event.Selecting():
213     for i in range(event.GetTopRow(), event.GetBottomRow() + 1):
214 bh 1662 self.rows[to_id(i)] = 0
215     self.rows[to_id(event.GetTopLeftCoords().GetRow())] = 0
216    
217 jonathan 1199 self.issue(ROW_SELECTED, self.rows.keys())
218 bh 6
219 jonathan 881 event.Skip()
220    
221 bh 6 def OnSelectCell(self, event):
222 bh 1662 to_id = self.table.RowOrdinalToId
223 jonathan 1199 if self.handleSelectEvents:
224 bh 1662 self.issue(ROW_SELECTED,
225     [to_id(i) for i in self.GetSelectedRows()])
226 jonathan 881 event.Skip()
227 bh 6
228 jonathan 966 def ToggleEventListeners(self, on):
229 jonathan 1199 self.handleSelectEvents = on
230 bh 1662
231 jonathan 1199 def GetNumberSelected(self):
232     return len(self.rows)
233    
234 bh 808 def disallow_messages(self):
235     """Disallow messages to be send.
236 bh 278
237 bh 808 This method only increases a counter so that calls to
238     disallow_messages and allow_messages can be nested. Only the
239     outermost calls will actually switch message sending on and off.
240     """
241     self.allow_messages_count += 1
242    
243     def allow_messages(self):
244     """Allow messages to be send.
245    
246     This method only decreases a counter so that calls to
247     disallow_messages and allow_messages can be nested. Only the
248     outermost calls will actually switch message sending on and off.
249     """
250     self.allow_messages_count -= 1
251    
252     def issue(self, *args):
253     """Issue a message unless disallowed.
254    
255     See the allow_messages and disallow_messages methods.
256     """
257     if self.allow_messages_count == 0:
258     Publisher.issue(self, *args)
259    
260 bh 1662 def SelectRowById(self, rowid, do_select):
261     """Select row with the id rowid"""
262     self.SelectRow(self.table.RowIdToOrdinal(rowid), do_select)
263 bh 808
264 bh 1662
265 bh 278 class LayerTableGrid(TableGrid):
266    
267     """Table grid for the layer tables.
268    
269     The LayerTableGrid is basically the same as a TableGrid but it's
270     selection is usually coupled to the selected object in the map.
271     """
272    
273 jonathan 881 def select_shapes(self, layer, shapes):
274 bh 278 """Select the row corresponding to the specified shape and layer
275    
276     If layer is not the layer the table is associated with do
277     nothing. If shape or layer is None also do nothing.
278     """
279 jonathan 881 if layer is not None \
280 bh 1219 and layer.ShapeStore().Table() is self.table.table:
281 jonathan 881
282 bh 808 self.disallow_messages()
283     try:
284 jonathan 881 self.ClearSelection()
285     if len(shapes) > 0:
286 bh 1662 # keep track of the lowest id so we can make it the
287     # first visible item
288     first = -1
289 jonathan 881
290 bh 1662 to_ordinal = self.table.RowIdToOrdinal
291 jonathan 881 for shape in shapes:
292 bh 1662 row = to_ordinal(shape)
293     self.SelectRow(row, True)
294     if row < first:
295     first = row
296 jonathan 881
297     self.SetGridCursor(first, 0)
298     self.MakeCellVisible(first, 0)
299 bh 808 finally:
300     self.allow_messages()
301 bh 6
302    
303 jonathan 1199 class TableFrame(ThubanFrame):
304 bh 6
305 bh 34 """Frame that displays a Thuban table in a grid view"""
306    
307 bh 535 def __init__(self, parent, name, title, table):
308 jonathan 1199 ThubanFrame.__init__(self, parent, name, title)
309 dpinte 2700 self.panel = wx.Panel(self, -1)
310 jonathan 1202
311 bh 278 self.table = table
312     self.grid = self.make_grid(self.table)
313 bh 1068 self.app = self.parent.application
314     self.app.Subscribe(SESSION_REPLACED, self.close_on_session_replaced)
315     self.session = self.app.Session()
316     self.session.Subscribe(TABLE_REMOVED, self.close_on_table_removed)
317 bh 278
318 bh 1892 def OnDestroy(self, event):
319     """Extend inherited method to unsubscribe messages"""
320     self.app.Unsubscribe(SESSION_REPLACED, self.close_on_session_replaced)
321     self.session.Unsubscribe(TABLE_REMOVED, self.close_on_table_removed)
322     ThubanFrame.OnDestroy(self, event)
323 jonathan 1202
324 bh 278 def make_grid(self, table):
325     """Return the table grid to use in the frame.
326    
327     The default implementation returns a TableGrid instance.
328     Override in derived classes to use different grid classes.
329     """
330     return TableGrid(self, table)
331    
332 bh 1068 def close_on_session_replaced(self, *args):
333     """Subscriber for the SESSION_REPLACED messages.
334    
335     The table frame is tied to a session so close the window when
336     the session changes.
337     """
338     self.Close()
339    
340     def close_on_table_removed(self, table):
341     """Subscriber for the TABLE_REMOVED messages.
342    
343     The table frame is tied to a particular table so close the
344     window when the table is removed.
345     """
346     if table is self.table:
347     self.Close()
348    
349    
350 jonathan 881 ID_QUERY = 4001
351 jan 1013 ID_EXPORT = 4002
352 jonathan 1199 ID_COMBOVALUE = 4003
353 jonathan 1394 ID_EXPORTSEL = 4004
354 jonathan 881
355 jan 1013 class QueryTableFrame(TableFrame):
356 bh 278
357 jan 1013 """Frame that displays a table in a grid view and offers user actions
358     selection and export
359 bh 278
360 jan 1096 A QueryTableFrame is TableFrame whose selection is connected to the
361 bh 278 selected object in a map.
362     """
363    
364 jan 1013 def __init__(self, parent, name, title, table):
365 bh 535 TableFrame.__init__(self, parent, name, title, table)
366 bh 30
367 dpinte 2700 self.combo_fields = wx.ComboBox(self.panel, -1, style=wx.CB_READONLY)
368     self.choice_comp = wx.Choice(self.panel, -1,
369 jonathan 939 choices=["<", "<=", "==", "!=", ">=", ">"])
370 dpinte 2700 self.combo_value = wx.ComboBox(self.panel, ID_COMBOVALUE)
371     self.choice_action = wx.Choice(self.panel, -1,
372     choices=[_("Replace Selection"),
373     _("Refine Selection"),
374 jonathan 881 _("Add to Selection")])
375    
376 dpinte 2700 button_query = wx.Button(self.panel, ID_QUERY, _("Query"))
377     button_export = wx.Button(self.panel, ID_EXPORT, _("Export"))
378     button_exportSel = wx.Button(self.panel, ID_EXPORTSEL, _("Export Selection"))
379     button_close = wx.Button(self.panel, wx.ID_CLOSE, _("Close"))
380 jonathan 881
381 jonathan 1199 self.CreateStatusBar()
382    
383 jonathan 881 self.grid.SetSize((400, 200))
384    
385     self.combo_value.Append("")
386 jonathan 939 for i in range(table.NumColumns()):
387     name = table.Column(i).name
388 jonathan 881 self.combo_fields.Append(name)
389     self.combo_value.Append(name)
390 jonathan 939
391 jonathan 881 # assume at least one field?
392     self.combo_fields.SetSelection(0)
393     self.combo_value.SetSelection(0)
394 jonathan 1199 self.choice_action.SetSelection(0)
395     self.choice_comp.SetSelection(0)
396 jonathan 881
397 jonathan 1202 self.grid.Reparent(self.panel)
398    
399     self.UpdateStatusText()
400    
401 dpinte 2700 topBox = wx.BoxSizer(wx.VERTICAL)
402 jonathan 881
403 dpinte 2700 sizer = wx.StaticBoxSizer(wx.StaticBox(self.panel, -1,
404 frank 1066 _("Selection")),
405 dpinte 2700 wx.HORIZONTAL)
406     sizer.Add(self.combo_fields, 1, wx.EXPAND|wx.ALL, 4)
407     sizer.Add(self.choice_comp, 0, wx.ALL, 4)
408     sizer.Add(self.combo_value, 1, wx.EXPAND|wx.ALL, 4)
409     sizer.Add(self.choice_action, 0, wx.ALL, 4)
410     sizer.Add(button_query, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 4)
411     sizer.Add( (40, 20), 0, wx.ALL, 4)
412 jonathan 881
413 dpinte 2700 topBox.Add(sizer, 0, wx.EXPAND|wx.ALL, 4)
414     topBox.Add(self.grid, 1, wx.EXPAND|wx.ALL, 0)
415 jonathan 881
416 dpinte 2700 sizer = wx.BoxSizer(wx.HORIZONTAL)
417     sizer.Add(button_export, 0, wx.ALL, 4)
418     sizer.Add(button_exportSel, 0, wx.ALL, 4)
419     sizer.Add( (60, 20), 1, wx.ALL|wx.EXPAND, 4)
420     sizer.Add(button_close, 0, wx.ALL|wx.ALIGN_RIGHT, 4)
421     topBox.Add(sizer, 0, wx.ALL | wx.EXPAND, 4)
422 jonathan 1394
423 jonathan 1202 self.panel.SetAutoLayout(True)
424     self.panel.SetSizer(topBox)
425     topBox.Fit(self.panel)
426     topBox.SetSizeHints(self.panel)
427    
428 dpinte 2700 panelSizer = wx.BoxSizer(wx.VERTICAL)
429     panelSizer.Add(self.panel, 1, wx.EXPAND, 0)
430 jonathan 881 self.SetAutoLayout(True)
431 jonathan 1202 self.SetSizer(panelSizer)
432     panelSizer.Fit(self)
433     panelSizer.SetSizeHints(self)
434 jonathan 881
435 frank 979 self.grid.SetFocus()
436 jonathan 1202
437 dpinte 2700 self.Bind(wx.EVT_BUTTON, self.OnQuery, id=ID_QUERY)
438     self.Bind(wx.EVT_BUTTON, self.OnExport, id=ID_EXPORT)
439     self.Bind(wx.EVT_BUTTON, self.OnExportSel, id=ID_EXPORTSEL)
440     self.Bind(wx.EVT_BUTTON, self.OnClose, id=wx.ID_CLOSE)
441     self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown, self.grid)
442 jonathan 881
443 jonathan 1394 self.grid.Subscribe(ROW_SELECTED, self.UpdateStatusText)
444    
445     def UpdateStatusText(self, rows=None):
446 dpinte 2700 self.SetStatusText(_("%i rows (%i selected), %i columns")
447     % (self.grid.GetNumberRows(),
448 jonathan 1199 self.grid.GetNumberSelected(),
449     self.grid.GetNumberCols()))
450    
451 frank 979 def OnKeyDown(self, event):
452     """Catch query key from grid"""
453     if event.AltDown() and event.GetKeyCode() == ord(QUERY_KEY):
454     self.combo_fields.SetFocus()
455     self.combo_fields.refocus = True
456     else:
457     event.Skip()
458    
459 jonathan 881 def OnQuery(self, event):
460 jonathan 1276 ThubanBeginBusyCursor()
461 jonathan 1104 try:
462 jonathan 881
463 jonathan 1199 text = self.combo_value.GetValue()
464     if self.combo_value.GetSelection() < 1 \
465     or self.combo_value.FindString(text) == -1:
466     value = text
467 jonathan 1104 else:
468 jonathan 1199 value = self.table.Column(text)
469 jonathan 881
470 jonathan 1104 ids = self.table.SimpleQuery(
471 dpinte 2700 self.table.Column(self.combo_fields.GetStringSelection()),
472     self.choice_comp.GetStringSelection(),
473 jonathan 1104 value)
474 jonathan 881
475 jonathan 1104 choice = self.choice_action.GetSelection()
476 dpinte 2700
477 jonathan 1104 #
478     # what used to be nice code got became a bit ugly because
479     # each time we select a row a message is sent to the grid
480     # which we are listening for and then we send further
481     # messages.
482     #
483     # now, we disable those listeners select everything but
484     # the first item, reenable the listeners, and select
485     # the first element, which causes everything to be
486     # updated properly.
487     #
488 jonathan 1199 if ids:
489     self.grid.ToggleEventListeners(False)
490 jonathan 966
491 jonathan 1104 if choice == 0:
492     # Replace Selection
493     self.grid.ClearSelection()
494     elif choice == 1:
495     # Refine Selection
496     sel = self.get_selected()
497     self.grid.ClearSelection()
498     ids = filter(sel.has_key, ids)
499     elif choice == 2:
500     # Add to Selection
501     pass
502 jonathan 966
503 jonathan 1104 #
504     # select the rows (all but the first)
505     #
506     firsttime = True
507     for id in ids:
508     if firsttime:
509     firsttime = False
510     else:
511 bh 1662 self.grid.SelectRowById(id, True)
512 jonathan 881
513 jonathan 1104 self.grid.ToggleEventListeners(True)
514 jonathan 966
515 jonathan 1104 #
516     # select the first row
517     #
518     if ids:
519 bh 1662 self.grid.SelectRowById(ids[0], True)
520 jonathan 1199
521 jonathan 1104 finally:
522 jonathan 1276 ThubanEndBusyCursor()
523 dpinte 2700
524 jonathan 1394 def doExport(self, onlySelected):
525 dpinte 2700
526     dlg = wx.FileDialog(self, _("Export Table To"), ".", "",
527 jan 1013 _("DBF Files (*.dbf)|*.dbf|") +
528     _("CSV Files (*.csv)|*.csv|") +
529     _("All Files (*.*)|*.*"),
530 dpinte 2700 wx.SAVE|wx.OVERWRITE_PROMPT)
531     if dlg.ShowModal() == wx.ID_OK:
532 frank 1027 filename = dlg.GetPath()
533     type = os.path.basename(filename).split('.')[-1:][0]
534     dlg.Destroy()
535 jonathan 1394
536     if onlySelected:
537     records = self.grid.GetSelectedRows()
538     else:
539     records = None
540    
541 frank 1027 if type.upper() == "DBF":
542 jonathan 1394 table_to_dbf(self.table, filename, records)
543 frank 1027 elif type.upper() == 'CSV':
544 jonathan 1394 table_to_csv(self.table, filename, records)
545 frank 1027 else:
546 dpinte 2700 dlg = wx.MessageDialog(None, "Unsupported format: %s" % type,
547     "Table Export", wx.OK|wx.ICON_WARNING)
548 frank 1027 dlg.ShowModal()
549     dlg.Destroy()
550     else:
551     dlg.Destroy()
552 jonathan 881
553 jonathan 1394 def OnExport(self, event):
554     self.doExport(False)
555    
556     def OnExportSel(self, event):
557     self.doExport(True)
558    
559 jan 1013 def OnClose(self, event):
560     TableFrame.OnClose(self, event)
561    
562     def get_selected(self):
563     """Return a dictionary of the selected rows.
564 bh 1662
565 jonathan 1394 The dictionary has the indexes as keys."""
566 bh 1662 to_id = self.table.RowOrdinalToId
567     return dict([(to_id(i), 0) for i in self.grid.GetSelectedRows()])
568 jan 1013
569 bh 1662
570 jan 1013 class LayerTableFrame(QueryTableFrame):
571    
572     """Frame that displays a layer table in a grid view
573    
574     A LayerTableFrame is a QueryTableFrame whose selection is connected to the
575     selected object in a map.
576     """
577    
578     def __init__(self, parent, name, title, layer, table):
579     QueryTableFrame.__init__(self, parent, name, title, table)
580     self.layer = layer
581     self.grid.Subscribe(ROW_SELECTED, self.rows_selected)
582     self.parent.Subscribe(SHAPES_SELECTED, self.select_shapes)
583 bh 1146 self.map = self.parent.Map()
584     self.map.Subscribe(MAP_LAYERS_REMOVED, self.map_layers_removed)
585 jan 1013
586 jan 1032 # if there is already a selection present, update the grid
587     # accordingly
588     sel = self.get_selected().keys()
589     for i in sel:
590 bh 1662 self.grid.SelectRowById(i, True)
591 jan 1032
592 bh 1892 def OnDestroy(self, event):
593     """Extend inherited method to unsubscribe messages"""
594 bh 2032 # There's no need to unsubscribe from self.grid's messages
595     # because it will get a DESTROY event too (since destroying the
596     # frame basically means that all child windows are also
597     # destroyed) and this it will clear all subscriptions
598     # automatically. It may even have been destroyed already (this
599     # does happen on w2000 for instance) so calling any of its
600     # methods here would be an error.
601 bh 1892 self.parent.Unsubscribe(SHAPES_SELECTED, self.select_shapes)
602     self.map.Unsubscribe(MAP_LAYERS_REMOVED, self.map_layers_removed)
603     QueryTableFrame.OnDestroy(self, event)
604    
605 bh 278 def make_grid(self, table):
606     """Override the derived method to return a LayerTableGrid.
607     """
608     return LayerTableGrid(self, table)
609    
610 jan 1013 def get_selected(self):
611     """Override the derived method to return a dictionary of the selected
612     rows.
613     """
614     return dict([(i, 0) for i in self.parent.SelectedShapes()])
615    
616 jonathan 881 def select_shapes(self, layer, shapes):
617 bh 535 """Subscribed to the SHAPES_SELECTED message.
618    
619     If shapes contains exactly one shape id, select that shape in
620     the grid. Otherwise deselect all.
621     """
622 jonathan 881 self.grid.select_shapes(layer, shapes)
623 bh 34
624 jonathan 881 def rows_selected(self, rows):
625 jan 1013 """Return the selected rows of the layer as they are returned
626     by Layer.SelectShapes().
627     """
628 bh 34 if self.layer is not None:
629 jonathan 881 self.parent.SelectShapes(self.layer, rows)
630 bh 1146
631     def map_layers_removed(self, *args):
632     """Receiver for the map's MAP_LAYERS_REMOVED message
633    
634     Close the dialog if the layer whose table we're showing is not
635     in the map anymore.
636     """
637     if self.layer not in self.map.Layers():
638     self.Close()
639    

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26