/[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 1892 - (hide annotations)
Thu Oct 30 18:16:53 2003 UTC (21 years, 4 months ago) by bh
Original Path: trunk/thuban/Thuban/UI/tableview.py
File MIME type: text/x-python
File size: 21507 byte(s)
(TableFrame.OnDestroy, LayerTableFrame.OnDestroy): New.
Unsubscribe the messages here not in OnClose because that might
get called multiple times. Fixes RT #2196
(TableFrame.OnClose, LayerTableFrame.OnClose): Removed. Not needed
anymore.

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 bh 6 from wxPython.wx import *
15     from wxPython.grid import *
16    
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 bh 6 wx_value_type_map = {FIELDTYPE_INT: wxGRID_VALUE_NUMBER,
27     FIELDTYPE_DOUBLE: wxGRID_VALUE_FLOAT,
28     FIELDTYPE_STRING: wxGRID_VALUE_STRING}
29    
30 bh 34 ROW_SELECTED = "ROW_SELECTED"
31    
32 frank 979 QUERY_KEY = 'S'
33 bh 34
34 bh 6 class DataTable(wxPyGridTableBase):
35    
36 bh 34 """Wrapper around a Thuban table object suitable for a wxGrid"""
37    
38 bh 6 def __init__(self, table = None):
39     wxPyGridTableBase.__init__(self)
40     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 bh 1092 class NullRenderer(wxPyGridCellRenderer):
116    
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     wxPyGridCellRenderer.__init__(self)
125     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     dc.SetBackgroundMode(wxSOLID)
131     dc.SetBrush(wxBrush(wxColour(192, 192, 192), wxSOLID))
132     dc.SetPen(wxTRANSPARENT_PEN)
133     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 bh 34 class TableGrid(wxGrid, 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     wxGrid.__init__(self, parent, -1)
159    
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 bh 6 self.SetSelectionMode(wxGrid.wxGridSelectRows)
182 bh 278
183 jonathan 966 self.ToggleEventListeners(True)
184 jonathan 1199 EVT_GRID_RANGE_SELECT(self, self.OnRangeSelect)
185     EVT_GRID_SELECT_CELL(self, self.OnSelectCell)
186 jonathan 966
187 bh 1092 # Replace the normal renderers with our own versions which
188     # render NULL/None values specially
189     self.RegisterDataType(wxGRID_VALUE_STRING,
190     NullRenderer(wxGridCellStringRenderer()), None)
191     self.RegisterDataType(wxGRID_VALUE_NUMBER,
192     NullRenderer(wxGridCellNumberRenderer()), None)
193     self.RegisterDataType(wxGRID_VALUE_FLOAT,
194     NullRenderer(wxGridCellFloatRenderer()), None)
195    
196 bh 6 def SetTableObject(self, table):
197     self.table.SetTable(table)
198    
199     def OnRangeSelect(self, event):
200 bh 1662 to_id = self.table.RowOrdinalToId
201 jonathan 1199 if self.handleSelectEvents:
202 bh 1662 self.rows = dict([(to_id(i), 0) for i in self.GetSelectedRows()])
203 jonathan 881
204 jonathan 1199 # if we're selecting we need to include the selected range and
205     # make sure that the current row is also included, which may
206     # not be the case if you just click on a single row!
207     if event.Selecting():
208     for i in range(event.GetTopRow(), event.GetBottomRow() + 1):
209 bh 1662 self.rows[to_id(i)] = 0
210     self.rows[to_id(event.GetTopLeftCoords().GetRow())] = 0
211    
212 jonathan 1199 self.issue(ROW_SELECTED, self.rows.keys())
213 bh 6
214 jonathan 881 event.Skip()
215    
216 bh 6 def OnSelectCell(self, event):
217 bh 1662 to_id = self.table.RowOrdinalToId
218 jonathan 1199 if self.handleSelectEvents:
219 bh 1662 self.issue(ROW_SELECTED,
220     [to_id(i) for i in self.GetSelectedRows()])
221 jonathan 881 event.Skip()
222 bh 6
223 jonathan 966 def ToggleEventListeners(self, on):
224 jonathan 1199 self.handleSelectEvents = on
225 bh 1662
226 jonathan 1199 def GetNumberSelected(self):
227     return len(self.rows)
228    
229 bh 808 def disallow_messages(self):
230     """Disallow messages to be send.
231 bh 278
232 bh 808 This method only increases a counter so that calls to
233     disallow_messages and allow_messages can be nested. Only the
234     outermost calls will actually switch message sending on and off.
235     """
236     self.allow_messages_count += 1
237    
238     def allow_messages(self):
239     """Allow messages to be send.
240    
241     This method only decreases a counter so that calls to
242     disallow_messages and allow_messages can be nested. Only the
243     outermost calls will actually switch message sending on and off.
244     """
245     self.allow_messages_count -= 1
246    
247     def issue(self, *args):
248     """Issue a message unless disallowed.
249    
250     See the allow_messages and disallow_messages methods.
251     """
252     if self.allow_messages_count == 0:
253     Publisher.issue(self, *args)
254    
255 bh 1662 def SelectRowById(self, rowid, do_select):
256     """Select row with the id rowid"""
257     self.SelectRow(self.table.RowIdToOrdinal(rowid), do_select)
258 bh 808
259 bh 1662
260 bh 278 class LayerTableGrid(TableGrid):
261    
262     """Table grid for the layer tables.
263    
264     The LayerTableGrid is basically the same as a TableGrid but it's
265     selection is usually coupled to the selected object in the map.
266     """
267    
268 jonathan 881 def select_shapes(self, layer, shapes):
269 bh 278 """Select the row corresponding to the specified shape and layer
270    
271     If layer is not the layer the table is associated with do
272     nothing. If shape or layer is None also do nothing.
273     """
274 jonathan 881 if layer is not None \
275 bh 1219 and layer.ShapeStore().Table() is self.table.table:
276 jonathan 881
277 bh 808 self.disallow_messages()
278     try:
279 jonathan 881 self.ClearSelection()
280     if len(shapes) > 0:
281 bh 1662 # keep track of the lowest id so we can make it the
282     # first visible item
283     first = -1
284 jonathan 881
285 bh 1662 to_ordinal = self.table.RowIdToOrdinal
286 jonathan 881 for shape in shapes:
287 bh 1662 row = to_ordinal(shape)
288     self.SelectRow(row, True)
289     if row < first:
290     first = row
291 jonathan 881
292     self.SetGridCursor(first, 0)
293     self.MakeCellVisible(first, 0)
294 bh 808 finally:
295     self.allow_messages()
296 bh 6
297    
298 jonathan 1199 class TableFrame(ThubanFrame):
299 bh 6
300 bh 34 """Frame that displays a Thuban table in a grid view"""
301    
302 bh 535 def __init__(self, parent, name, title, table):
303 jonathan 1199 ThubanFrame.__init__(self, parent, name, title)
304 jonathan 1202 self.panel = wxPanel(self, -1)
305    
306 bh 278 self.table = table
307     self.grid = self.make_grid(self.table)
308 bh 1068 self.app = self.parent.application
309     self.app.Subscribe(SESSION_REPLACED, self.close_on_session_replaced)
310     self.session = self.app.Session()
311     self.session.Subscribe(TABLE_REMOVED, self.close_on_table_removed)
312 bh 278
313 bh 1892 def OnDestroy(self, event):
314     """Extend inherited method to unsubscribe messages"""
315     self.app.Unsubscribe(SESSION_REPLACED, self.close_on_session_replaced)
316     self.session.Unsubscribe(TABLE_REMOVED, self.close_on_table_removed)
317     ThubanFrame.OnDestroy(self, event)
318 jonathan 1202
319 bh 278 def make_grid(self, table):
320     """Return the table grid to use in the frame.
321    
322     The default implementation returns a TableGrid instance.
323     Override in derived classes to use different grid classes.
324     """
325     return TableGrid(self, table)
326    
327 bh 1068 def close_on_session_replaced(self, *args):
328     """Subscriber for the SESSION_REPLACED messages.
329    
330     The table frame is tied to a session so close the window when
331     the session changes.
332     """
333     self.Close()
334    
335     def close_on_table_removed(self, table):
336     """Subscriber for the TABLE_REMOVED messages.
337    
338     The table frame is tied to a particular table so close the
339     window when the table is removed.
340     """
341     if table is self.table:
342     self.Close()
343    
344    
345 jonathan 881 ID_QUERY = 4001
346 jan 1013 ID_EXPORT = 4002
347 jonathan 1199 ID_COMBOVALUE = 4003
348 jonathan 1394 ID_EXPORTSEL = 4004
349 jonathan 881
350 jan 1013 class QueryTableFrame(TableFrame):
351 bh 278
352 jan 1013 """Frame that displays a table in a grid view and offers user actions
353     selection and export
354 bh 278
355 jan 1096 A QueryTableFrame is TableFrame whose selection is connected to the
356 bh 278 selected object in a map.
357     """
358    
359 jan 1013 def __init__(self, parent, name, title, table):
360 bh 535 TableFrame.__init__(self, parent, name, title, table)
361 bh 30
362 jonathan 1202 self.combo_fields = wxComboBox(self.panel, -1, style=wxCB_READONLY)
363     self.choice_comp = wxChoice(self.panel, -1,
364 jonathan 939 choices=["<", "<=", "==", "!=", ">=", ">"])
365 jonathan 1202 self.combo_value = wxComboBox(self.panel, ID_COMBOVALUE)
366     self.choice_action = wxChoice(self.panel, -1,
367 jonathan 881 choices=[_("Replace Selection"),
368     _("Refine Selection"),
369     _("Add to Selection")])
370    
371 jonathan 1202 button_query = wxButton(self.panel, ID_QUERY, _("Query"))
372 jonathan 1394 button_export = wxButton(self.panel, ID_EXPORT, _("Export"))
373     button_exportSel = wxButton(self.panel, ID_EXPORTSEL, _("Export Selection"))
374     button_close = wxButton(self.panel, wxID_CLOSE, _("Close"))
375 jonathan 881
376 jonathan 1199 self.CreateStatusBar()
377    
378 jonathan 881 self.grid.SetSize((400, 200))
379    
380     self.combo_value.Append("")
381 jonathan 939 for i in range(table.NumColumns()):
382     name = table.Column(i).name
383 jonathan 881 self.combo_fields.Append(name)
384     self.combo_value.Append(name)
385 jonathan 939
386 jonathan 881 # assume at least one field?
387     self.combo_fields.SetSelection(0)
388     self.combo_value.SetSelection(0)
389 jonathan 1199 self.choice_action.SetSelection(0)
390     self.choice_comp.SetSelection(0)
391 jonathan 881
392 jonathan 1202 self.grid.Reparent(self.panel)
393    
394     self.UpdateStatusText()
395    
396 jonathan 881 topBox = wxBoxSizer(wxVERTICAL)
397    
398 jonathan 1202 sizer = wxStaticBoxSizer(wxStaticBox(self.panel, -1,
399 frank 1066 _("Selection")),
400 jonathan 881 wxHORIZONTAL)
401     sizer.Add(self.combo_fields, 1, wxEXPAND|wxALL, 4)
402     sizer.Add(self.choice_comp, 0, wxALL, 4)
403     sizer.Add(self.combo_value, 1, wxEXPAND|wxALL, 4)
404     sizer.Add(self.choice_action, 0, wxALL, 4)
405 frank 979 sizer.Add(button_query, 0, wxALL | wxALIGN_CENTER_VERTICAL, 4)
406 jonathan 881 sizer.Add(40, 20, 0, wxALL, 4)
407    
408     topBox.Add(sizer, 0, wxEXPAND|wxALL, 4)
409     topBox.Add(self.grid, 1, wxEXPAND|wxALL, 0)
410    
411 jonathan 1394 sizer = wxBoxSizer(wxHORIZONTAL)
412     sizer.Add(button_export, 0, wxALL, 4)
413     sizer.Add(button_exportSel, 0, wxALL, 4)
414     sizer.Add(60, 20, 1, wxALL|wxEXPAND, 4)
415     sizer.Add(button_close, 0, wxALL|wxALIGN_RIGHT, 4)
416     topBox.Add(sizer, 0, wxALL | wxEXPAND, 4)
417    
418 jonathan 1202 self.panel.SetAutoLayout(True)
419     self.panel.SetSizer(topBox)
420     topBox.Fit(self.panel)
421     topBox.SetSizeHints(self.panel)
422    
423     panelSizer = wxBoxSizer(wxVERTICAL)
424     panelSizer.Add(self.panel, 1, wxEXPAND, 0)
425 jonathan 881 self.SetAutoLayout(True)
426 jonathan 1202 self.SetSizer(panelSizer)
427     panelSizer.Fit(self)
428     panelSizer.SetSizeHints(self)
429 jonathan 881
430 frank 979 self.grid.SetFocus()
431 jonathan 1202
432 jonathan 881 EVT_BUTTON(self, ID_QUERY, self.OnQuery)
433 jonathan 1394 EVT_BUTTON(self, ID_EXPORT, self.OnExport)
434     EVT_BUTTON(self, ID_EXPORTSEL, self.OnExportSel)
435     EVT_BUTTON(self, wxID_CLOSE, self.OnClose)
436 frank 979 EVT_KEY_DOWN(self.grid, self.OnKeyDown)
437 jonathan 881
438 jonathan 1394 self.grid.Subscribe(ROW_SELECTED, self.UpdateStatusText)
439    
440     def UpdateStatusText(self, rows=None):
441 jonathan 1199 self.SetStatusText(_("%i rows (%i selected), %i columns")
442     % (self.grid.GetNumberRows(),
443     self.grid.GetNumberSelected(),
444     self.grid.GetNumberCols()))
445    
446 frank 979 def OnKeyDown(self, event):
447     """Catch query key from grid"""
448     if event.AltDown() and event.GetKeyCode() == ord(QUERY_KEY):
449     self.combo_fields.SetFocus()
450     self.combo_fields.refocus = True
451     else:
452     event.Skip()
453    
454 jonathan 881 def OnQuery(self, event):
455 jonathan 1276 ThubanBeginBusyCursor()
456 jonathan 1104 try:
457 jonathan 881
458 jonathan 1199 text = self.combo_value.GetValue()
459     if self.combo_value.GetSelection() < 1 \
460     or self.combo_value.FindString(text) == -1:
461     value = text
462 jonathan 1104 else:
463 jonathan 1199 value = self.table.Column(text)
464 jonathan 881
465 jonathan 1104 ids = self.table.SimpleQuery(
466     self.table.Column(self.combo_fields.GetStringSelection()),
467     self.choice_comp.GetStringSelection(),
468     value)
469 jonathan 881
470 jonathan 1104 choice = self.choice_action.GetSelection()
471 jonathan 881
472 jonathan 1104 #
473     # what used to be nice code got became a bit ugly because
474     # each time we select a row a message is sent to the grid
475     # which we are listening for and then we send further
476     # messages.
477     #
478     # now, we disable those listeners select everything but
479     # the first item, reenable the listeners, and select
480     # the first element, which causes everything to be
481     # updated properly.
482     #
483 jonathan 1199 if ids:
484     self.grid.ToggleEventListeners(False)
485 jonathan 966
486 jonathan 1104 if choice == 0:
487     # Replace Selection
488     self.grid.ClearSelection()
489     elif choice == 1:
490     # Refine Selection
491     sel = self.get_selected()
492     self.grid.ClearSelection()
493     ids = filter(sel.has_key, ids)
494     elif choice == 2:
495     # Add to Selection
496     pass
497 jonathan 966
498 jonathan 1104 #
499     # select the rows (all but the first)
500     #
501     firsttime = True
502     for id in ids:
503     if firsttime:
504     firsttime = False
505     else:
506 bh 1662 self.grid.SelectRowById(id, True)
507 jonathan 881
508 jonathan 1104 self.grid.ToggleEventListeners(True)
509 jonathan 966
510 jonathan 1104 #
511     # select the first row
512     #
513     if ids:
514 bh 1662 self.grid.SelectRowById(ids[0], True)
515 jonathan 1199
516 jonathan 1104 finally:
517 jonathan 1276 ThubanEndBusyCursor()
518 jonathan 881
519 jonathan 1394 def doExport(self, onlySelected):
520    
521 jan 1013 dlg = wxFileDialog(self, _("Export Table To"), ".", "",
522     _("DBF Files (*.dbf)|*.dbf|") +
523     _("CSV Files (*.csv)|*.csv|") +
524     _("All Files (*.*)|*.*"),
525 jonathan 881 wxSAVE|wxOVERWRITE_PROMPT)
526     if dlg.ShowModal() == wxID_OK:
527 frank 1027 filename = dlg.GetPath()
528     type = os.path.basename(filename).split('.')[-1:][0]
529     dlg.Destroy()
530 jonathan 1394
531     if onlySelected:
532     records = self.grid.GetSelectedRows()
533     else:
534     records = None
535    
536 frank 1027 if type.upper() == "DBF":
537 jonathan 1394 table_to_dbf(self.table, filename, records)
538 frank 1027 elif type.upper() == 'CSV':
539 jonathan 1394 table_to_csv(self.table, filename, records)
540 frank 1027 else:
541     dlg = wxMessageDialog(None, "Unsupported format: %s" % type,
542     "Table Export", wxOK|wxICON_WARNING)
543     dlg.ShowModal()
544     dlg.Destroy()
545     else:
546     dlg.Destroy()
547 jonathan 881
548 jonathan 1394 def OnExport(self, event):
549     self.doExport(False)
550    
551     def OnExportSel(self, event):
552     self.doExport(True)
553    
554 jan 1013 def OnClose(self, event):
555     TableFrame.OnClose(self, event)
556    
557     def get_selected(self):
558     """Return a dictionary of the selected rows.
559 bh 1662
560 jonathan 1394 The dictionary has the indexes as keys."""
561 bh 1662 to_id = self.table.RowOrdinalToId
562     return dict([(to_id(i), 0) for i in self.grid.GetSelectedRows()])
563 jan 1013
564 bh 1662
565 jan 1013 class LayerTableFrame(QueryTableFrame):
566    
567     """Frame that displays a layer table in a grid view
568    
569     A LayerTableFrame is a QueryTableFrame whose selection is connected to the
570     selected object in a map.
571     """
572    
573     def __init__(self, parent, name, title, layer, table):
574     QueryTableFrame.__init__(self, parent, name, title, table)
575     self.layer = layer
576     self.grid.Subscribe(ROW_SELECTED, self.rows_selected)
577     self.parent.Subscribe(SHAPES_SELECTED, self.select_shapes)
578 bh 1146 self.map = self.parent.Map()
579     self.map.Subscribe(MAP_LAYERS_REMOVED, self.map_layers_removed)
580 jan 1013
581 jan 1032 # if there is already a selection present, update the grid
582     # accordingly
583     sel = self.get_selected().keys()
584     for i in sel:
585 bh 1662 self.grid.SelectRowById(i, True)
586 jan 1032
587 bh 1892 def OnDestroy(self, event):
588     """Extend inherited method to unsubscribe messages"""
589     self.parent.Unsubscribe(SHAPES_SELECTED, self.select_shapes)
590     self.grid.Unsubscribe(ROW_SELECTED, self.rows_selected)
591     self.map.Unsubscribe(MAP_LAYERS_REMOVED, self.map_layers_removed)
592     QueryTableFrame.OnDestroy(self, event)
593    
594 bh 278 def make_grid(self, table):
595     """Override the derived method to return a LayerTableGrid.
596     """
597     return LayerTableGrid(self, table)
598    
599 jan 1013 def get_selected(self):
600     """Override the derived method to return a dictionary of the selected
601     rows.
602     """
603     return dict([(i, 0) for i in self.parent.SelectedShapes()])
604    
605 jonathan 881 def select_shapes(self, layer, shapes):
606 bh 535 """Subscribed to the SHAPES_SELECTED message.
607    
608     If shapes contains exactly one shape id, select that shape in
609     the grid. Otherwise deselect all.
610     """
611 jonathan 881 self.grid.select_shapes(layer, shapes)
612 bh 34
613 jonathan 881 def rows_selected(self, rows):
614 jan 1013 """Return the selected rows of the layer as they are returned
615     by Layer.SelectShapes().
616     """
617 bh 34 if self.layer is not None:
618 jonathan 881 self.parent.SelectShapes(self.layer, rows)
619 bh 1146
620     def map_layers_removed(self, *args):
621     """Receiver for the map's MAP_LAYERS_REMOVED message
622    
623     Close the dialog if the layer whose table we're showing is not
624     in the map anymore.
625     """
626     if self.layer not in self.map.Layers():
627     self.Close()
628    

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26