/[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 34 by bh, Thu Sep 6 15:32:56 2001 UTC revision 2718 by dpinte, Fri Jan 5 23:43:49 2007 UTC
# Line 1  Line 1 
1  # Copyright (c) 2001 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)          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      """A grid view for a Thuban table"""      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
157    
158        When rows are selected by the user the table issues ROW_SELECTED
159        messages. wx sends selection events even when the selection is
160        manipulated by code (instead of by the user) which usually lead to
161        ROW_SELECTED messages being sent in turn. Therefore sending messages
162        can be switched on and off with the allow_messages and
163        disallow_messages methods.
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
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 it's 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)
         self.AutoSizeColumns(false)  
183    
184          self.SetSelectionMode(wxGrid.wxGridSelectRows)          # AutoSizeColumns would allow us to make the grid have optimal
185                    # column widths automatically but it would cause a traversal of
186          EVT_GRID_RANGE_SELECT(self, self.OnRangeSelect)          # the entire table which for large .dbf files can take a very
187          EVT_GRID_SELECT_CELL(self, self.OnSelectCell)          # long time.
188            #self.AutoSizeColumns(False)
189    
190            self.SetSelectionMode(grid.Grid.wxGridSelectRows)
191    
192            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            self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy)
206    
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      def OnSelectCell(self, event):              self.issue(ROW_SELECTED, self.rows.keys())
         self.issue(ROW_SELECTED, event.GetRow())  
227    
228      def select_shape(self, layer, shape):          event.Skip()
229          if layer is not None and layer.table is self.table.table \  
230             and shape is not None:      def OnSelectCell(self, event):
231              self.SelectRow(shape)          to_id = self.table.RowOrdinalToId
232              self.SetGridCursor(shape, 0)          if self.handleSelectEvents:
233              self.MakeCellVisible(shape, 0)              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):
244            """Disallow messages to be send.
245    
246            This method only increases 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 allow_messages(self):
253            """Allow messages to be send.
254    
255            This method only decreases a counter so that calls to
256            disallow_messages and allow_messages can be nested. Only the
257            outermost calls will actually switch message sending on and off.
258            """
259            self.allow_messages_count -= 1
260    
261        def issue(self, *args):
262            """Issue a message unless disallowed.
263    
264            See the allow_messages and disallow_messages methods.
265            """
266            if self.allow_messages_count == 0:
267                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):
275    
276        """Table grid for the layer tables.
277    
278        The LayerTableGrid is basically the same as a TableGrid but it's
279        selection is usually coupled to the selected object in the map.
280        """
281    
282        def select_shapes(self, layer, shapes):
283            """Select the row corresponding to the specified shape and layer
284    
285            If layer is not the layer the table is associated with do
286            nothing. If shape or layer is None also do nothing.
287            """
288            if layer is not None \
289                and layer.ShapeStore().Table() is self.table.table:
290    
291                self.disallow_messages()
292                try:
293                    self.ClearSelection()
294                    if len(shapes) > 0:
295                        # 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:
309                    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, interactor, name, title, layer = None,      def __init__(self, parent, name, title, table):
317                   table = None):          ThubanFrame.__init__(self, parent, name, title)
318          NonModalDialog.__init__(self, parent, interactor, name, title)          self.panel = wx.Panel(self, -1)
319          self.layer = layer  
320          self.table = table          self.table = table
321          self.grid = TableGrid(self, table)          self.grid = self.make_grid(self.table)
322          self.grid.Subscribe(ROW_SELECTED, self.row_selected)          self.app = self.parent.application
323          self.interactor.Subscribe(SELECTED_SHAPE, self.select_shape)          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):
334            """Return the table grid to use in the frame.
335    
336            The default implementation returns a TableGrid instance.
337            Override in derived classes to use different grid classes.
338            """
339            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      def OnClose(self, event):      def OnClose(self, event):
569          self.interactor.Unsubscribe(SELECTED_SHAPE, self.select_shape)          TableFrame.OnClose(self, event)
         NonModalDialog.OnClose(self, event)  
570    
571      def select_shape(self, layer, shape):      def get_selected(self):
572          self.grid.select_shape(layer, shape)          """Return a dictionary of the selected rows.
573    
574      def row_selected(self, row):          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
582    
583        A LayerTableFrame is a QueryTableFrame whose selection is connected to the
584        selected object in a map.
585        """
586    
587        def __init__(self, parent, name, title, layer, table):
588            QueryTableFrame.__init__(self, parent, name, title, table)
589            self.layer = layer
590            self.grid.Subscribe(ROW_SELECTED, self.rows_selected)
591            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):
615            """Override the derived method to return a LayerTableGrid.
616            """
617            return LayerTableGrid(self, table)
618    
619        def get_selected(self):
620            """Override the derived method to return a dictionary of the selected
621            rows.
622            """
623            return dict([(i, 0) for i in self.parent.SelectedShapes()])
624    
625        def select_shapes(self, layer, shapes):
626            """Subscribed to the SHAPES_SELECTED message.
627    
628            If shapes contains exactly one shape id, select that shape in
629            the grid. Otherwise deselect all.
630            """
631            self.grid.select_shapes(layer, shapes)
632    
633        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.interactor.SelectLayerAndShape(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.34  
changed lines
  Added in v.2718

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26