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

Legend:
Removed from v.6  
changed lines
  Added in v.2755

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26