/[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

revision 77 by bh, Mon Feb 4 19:27:13 2002 UTC revision 2700 by dpinte, Mon Sep 18 14:27:02 2006 UTC
# Line 1  Line 1 
1  # Copyright (c) 2001, 2002 by Intevation GmbH  # Copyright (c) 2001, 2002, 2003 by Intevation GmbH
2  # Authors:  # Authors:
3  # Bernhard Herzog <[email protected]>  # Bernhard Herzog <[email protected]>
4  #  #
# 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 SELECTED_SHAPE  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)          record = self.table.ReadRowAsDict(row, row_is_ordinal = 1)
75          return record[self.columns[col][0]]          return record[self.columns[col][0]]
76    
77      def SetValue(self, row, col, value):      def SetValue(self, row, col, value):
# Line 95  class DataTable(wxPyGridTableBase): Line 102  class DataTable(wxPyGridTableBase):
102          return self.CanGetValueAs(row, col, typeName)          return self.CanGetValueAs(row, col, typeName)
103    
104    
105  class TableGrid(wxGrid, Publisher):      #
106        def RowIdToOrdinal(self, rowid):
107            """Return the ordinal of the row given by its id"""
108            return self.table.RowIdToOrdinal(rowid)
109    
110        def RowOrdinalToId(self, ordinal):
111            """Return the id of the row given by its ordinal"""
112            return self.table.RowOrdinalToId(ordinal)
113    
114    
115    class NullRenderer(grid.PyGridCellRenderer):
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      """A grid view for a Thuban table"""      def __init__(self, non_null_renderer):
124            grid.PyGridCellRenderer.__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(wx.SOLID)
131                dc.SetBrush(wx.Brush(wx.Colour(192, 192, 192), wx.SOLID))
132                dc.SetPen(wx.TRANSPARENT_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    class TableGrid(grid.Grid, Publisher):
146    
147        """A grid view for a Thuban table
148    
149        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      def __init__(self, parent, table = None):      def __init__(self, parent, table = None):
158          wxGrid.__init__(self, parent, -1)          grid.Grid.__init__(self, parent, -1)
159    
160            self.allow_messages_count = 0
161    
162            # keep track of which rows are selected.
163            self.rows = {}
164    
165          self.table = DataTable(table)          self.table = DataTable(table)
166    
# Line 108  class TableGrid(wxGrid, Publisher): Line 168  class TableGrid(wxGrid, Publisher):
168          # of the table and will destroy it when done. Otherwise you          # of the table and will destroy it when done. Otherwise you
169          # would need to keep a reference to it and call its Destroy          # would need to keep a reference to it and call its Destroy
170          # method later.          # method later.
171          self.SetTable(self.table, true)          self.SetTable(self.table, True)
172    
173          #self.SetMargins(0,0)          #self.SetMargins(0,0)
         self.AutoSizeColumns(false)  
174    
175          self.SetSelectionMode(wxGrid.wxGridSelectRows)          # AutoSizeColumns would allow us to make the grid have optimal
176                    # column widths automatically but it would cause a traversal of
177          EVT_GRID_RANGE_SELECT(self, self.OnRangeSelect)          # the entire table which for large .dbf files can take a very
178          EVT_GRID_SELECT_CELL(self, self.OnSelectCell)          # long time.
179            #self.AutoSizeColumns(False)
180    
181            self.SetSelectionMode(grid.Grid.wxGridSelectRows)
182    
183            self.ToggleEventListeners(True)
184            self.Bind(grid.EVT_GRID_RANGE_SELECT, self.OnRangeSelect)
185            self.Bind(grid.EVT_GRID_SELECT_CELL, self.OnSelectCell)
186    
187            # Replace the normal renderers with our own versions which
188            # render NULL/None values specially
189            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    
196            self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy)
197    
198        def OnDestroy(self, event):
199            Publisher.Destroy(self)
200    
201      def SetTableObject(self, table):      def SetTableObject(self, table):
202          self.table.SetTable(table)          self.table.SetTable(table)
203    
204      def OnRangeSelect(self, event):      def OnRangeSelect(self, event):
205          if event.Selecting():          to_id = self.table.RowOrdinalToId
206              self.issue(ROW_SELECTED, event.GetTopLeftCoords().GetRow())          if self.handleSelectEvents:
207                self.rows = dict([(to_id(i), 0) for i in self.GetSelectedRows()])
208    
209                # 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                        self.rows[to_id(i)] = 0
215                    self.rows[to_id(event.GetTopLeftCoords().GetRow())] = 0
216    
217      def OnSelectCell(self, event):              self.issue(ROW_SELECTED, self.rows.keys())
         self.issue(ROW_SELECTED, event.GetRow())  
218    
219      def select_shape(self, layer, shape):          event.Skip()
220          if layer is not None and layer.table is self.table.table \  
221             and shape is not None:      def OnSelectCell(self, event):
222              self.SelectRow(shape)          to_id = self.table.RowOrdinalToId
223              self.SetGridCursor(shape, 0)          if self.handleSelectEvents:
224              self.MakeCellVisible(shape, 0)              self.issue(ROW_SELECTED,
225                           [to_id(i) for i in self.GetSelectedRows()])
226            event.Skip()
227    
228        def ToggleEventListeners(self, on):
229            self.handleSelectEvents = on
230    
231        def GetNumberSelected(self):
232            return len(self.rows)
233    
234        def disallow_messages(self):
235            """Disallow messages to be send.
236    
237            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        def SelectRowById(self, rowid, do_select):
261            """Select row with the id rowid"""
262            self.SelectRow(self.table.RowIdToOrdinal(rowid), do_select)
263    
264    
265    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        def select_shapes(self, layer, shapes):
274            """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            if layer is not None \
280                and layer.ShapeStore().Table() is self.table.table:
281    
282                self.disallow_messages()
283                try:
284                    self.ClearSelection()
285                    if len(shapes) > 0:
286                        # keep track of the lowest id so we can make it the
287                        # first visible item
288                        first = -1
289    
290                        to_ordinal = self.table.RowIdToOrdinal
291                        for shape in shapes:
292                            row = to_ordinal(shape)
293                            self.SelectRow(row, True)
294                            if row < first:
295                                first = row
296    
297                        self.SetGridCursor(first, 0)
298                        self.MakeCellVisible(first, 0)
299                finally:
300                    self.allow_messages()
301    
302    
303  class TableFrame(NonModalDialog):  class TableFrame(ThubanFrame):
304    
305      """Frame that displays a Thuban table in a grid view"""      """Frame that displays a Thuban table in a grid view"""
306    
307      def __init__(self, parent, interactor, name, title, layer = None,      def __init__(self, parent, name, title, table):
308                   table = None):          ThubanFrame.__init__(self, parent, name, title)
309          NonModalDialog.__init__(self, parent, interactor, name, title)          self.panel = wx.Panel(self, -1)
310          self.layer = layer  
311          self.table = table          self.table = table
312          self.grid = TableGrid(self, table)          self.grid = self.make_grid(self.table)
313          self.grid.Subscribe(ROW_SELECTED, self.row_selected)          self.app = self.parent.application
314          self.interactor.Subscribe(SELECTED_SHAPE, self.select_shape)          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    
318        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    
324        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        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    ID_QUERY = 4001
351    ID_EXPORT = 4002
352    ID_COMBOVALUE = 4003
353    ID_EXPORTSEL = 4004
354    
355    class QueryTableFrame(TableFrame):
356    
357        """Frame that displays a table in a grid view and offers user actions
358        selection and export
359    
360        A QueryTableFrame is TableFrame whose selection is connected to the
361        selected object in a map.
362        """
363    
364        def __init__(self, parent, name, title, table):
365            TableFrame.__init__(self, parent, name, title, table)
366    
367            self.combo_fields = wx.ComboBox(self.panel, -1, style=wx.CB_READONLY)
368            self.choice_comp = wx.Choice(self.panel, -1,
369                                  choices=["<", "<=", "==", "!=", ">=", ">"])
370            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                                            _("Add to Selection")])
375    
376            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    
381            self.CreateStatusBar()
382    
383            self.grid.SetSize((400, 200))
384    
385            self.combo_value.Append("")
386            for i in range(table.NumColumns()):
387                name = table.Column(i).name
388                self.combo_fields.Append(name)
389                self.combo_value.Append(name)
390    
391            # assume at least one field?
392            self.combo_fields.SetSelection(0)
393            self.combo_value.SetSelection(0)
394            self.choice_action.SetSelection(0)
395            self.choice_comp.SetSelection(0)
396    
397            self.grid.Reparent(self.panel)
398    
399            self.UpdateStatusText()
400    
401            topBox = wx.BoxSizer(wx.VERTICAL)
402    
403            sizer = wx.StaticBoxSizer(wx.StaticBox(self.panel, -1,
404                                      _("Selection")),
405                                      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    
413            topBox.Add(sizer, 0, wx.EXPAND|wx.ALL, 4)
414            topBox.Add(self.grid, 1, wx.EXPAND|wx.ALL, 0)
415    
416            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    
423            self.panel.SetAutoLayout(True)
424            self.panel.SetSizer(topBox)
425            topBox.Fit(self.panel)
426            topBox.SetSizeHints(self.panel)
427    
428            panelSizer = wx.BoxSizer(wx.VERTICAL)
429            panelSizer.Add(self.panel, 1, wx.EXPAND, 0)
430            self.SetAutoLayout(True)
431            self.SetSizer(panelSizer)
432            panelSizer.Fit(self)
433            panelSizer.SetSizeHints(self)
434    
435            self.grid.SetFocus()
436    
437            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    
443            self.grid.Subscribe(ROW_SELECTED, self.UpdateStatusText)
444    
445        def UpdateStatusText(self, rows=None):
446            self.SetStatusText(_("%i rows (%i selected), %i columns")
447                % (self.grid.GetNumberRows(),
448                   self.grid.GetNumberSelected(),
449                   self.grid.GetNumberCols()))
450    
451        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        def OnQuery(self, event):
460            ThubanBeginBusyCursor()
461            try:
462    
463                text = self.combo_value.GetValue()
464                if self.combo_value.GetSelection() < 1 \
465                    or self.combo_value.FindString(text) == -1:
466                    value = text
467                else:
468                    value = self.table.Column(text)
469    
470                ids = self.table.SimpleQuery(
471                        self.table.Column(self.combo_fields.GetStringSelection()),
472                        self.choice_comp.GetStringSelection(),
473                        value)
474    
475                choice = self.choice_action.GetSelection()
476    
477                #
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                if ids:
489                    self.grid.ToggleEventListeners(False)
490    
491                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    
503                #
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                        self.grid.SelectRowById(id, True)
512    
513                self.grid.ToggleEventListeners(True)
514    
515                #
516                # select the first row
517                #
518                if ids:
519                    self.grid.SelectRowById(ids[0], True)
520    
521            finally:
522                ThubanEndBusyCursor()
523    
524        def doExport(self, onlySelected):
525    
526            dlg = wx.FileDialog(self, _("Export Table To"), ".", "",
527                               _("DBF Files (*.dbf)|*.dbf|") +
528                               _("CSV Files (*.csv)|*.csv|") +
529                               _("All Files (*.*)|*.*"),
530                               wx.SAVE|wx.OVERWRITE_PROMPT)
531            if dlg.ShowModal() == wx.ID_OK:
532                filename = dlg.GetPath()
533                type = os.path.basename(filename).split('.')[-1:][0]
534                dlg.Destroy()
535    
536                if onlySelected:
537                    records = self.grid.GetSelectedRows()
538                else:
539                    records = None
540    
541                if type.upper() == "DBF":
542                    table_to_dbf(self.table, filename, records)
543                elif type.upper() == 'CSV':
544                    table_to_csv(self.table, filename, records)
545                else:
546                    dlg = wx.MessageDialog(None, "Unsupported format: %s" % type,
547                                          "Table Export", wx.OK|wx.ICON_WARNING)
548                    dlg.ShowModal()
549                    dlg.Destroy()
550            else:
551                dlg.Destroy()
552    
553        def OnExport(self, event):
554            self.doExport(False)
555    
556        def OnExportSel(self, event):
557            self.doExport(True)
558    
559      def OnClose(self, event):      def OnClose(self, event):
560          self.interactor.Unsubscribe(SELECTED_SHAPE, self.select_shape)          TableFrame.OnClose(self, event)
         NonModalDialog.OnClose(self, event)  
561    
562      def select_shape(self, layer, shape):      def get_selected(self):
563          self.grid.select_shape(layer, shape)          """Return a dictionary of the selected rows.
564    
565      def row_selected(self, row):          The dictionary has the indexes as keys."""
566            to_id = self.table.RowOrdinalToId
567            return dict([(to_id(i), 0) for i in self.grid.GetSelectedRows()])
568    
569    
570    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            self.map = self.parent.Map()
584            self.map.Subscribe(MAP_LAYERS_REMOVED, self.map_layers_removed)
585    
586            # if there is already a selection present, update the grid
587            # accordingly
588            sel = self.get_selected().keys()
589            for i in sel:
590                self.grid.SelectRowById(i, True)
591    
592        def OnDestroy(self, event):
593            """Extend inherited method to unsubscribe messages"""
594            # 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            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        def make_grid(self, table):
606            """Override the derived method to return a LayerTableGrid.
607            """
608            return LayerTableGrid(self, table)
609    
610        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        def select_shapes(self, layer, shapes):
617            """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            self.grid.select_shapes(layer, shapes)
623    
624        def rows_selected(self, rows):
625            """Return the selected rows of the layer as they are returned
626            by Layer.SelectShapes().
627            """
628          if self.layer is not None:          if self.layer is not None:
629              self.interactor.SelectLayerAndShape(self.layer, row)              self.parent.SelectShapes(self.layer, rows)
630    
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    

Legend:
Removed from v.77  
changed lines
  Added in v.2700

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26