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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

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

Legend:
Removed from v.808  
changed lines
  Added in v.2734

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26