/[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 881 by jonathan, Fri May 9 16:34:15 2003 UTC revision 2032 by bh, Mon Dec 22 14:54:47 2003 UTC
# Line 7  Line 7 
7    
8  __version__ = "$Revision$"  __version__ = "$Revision$"
9    
10    import os.path
11    
12  from Thuban import _  from Thuban import _
13    
14  from wxPython.wx import *  from wxPython.wx import *
# Line 14  from wxPython.grid import * Line 16  from wxPython.grid import *
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    from Thuban.UI.common import ThubanBeginBusyCursor, ThubanEndBusyCursor
25    
26  wx_value_type_map = {FIELDTYPE_INT: wxGRID_VALUE_NUMBER,  wx_value_type_map = {FIELDTYPE_INT: wxGRID_VALUE_NUMBER,
27                       FIELDTYPE_DOUBLE: wxGRID_VALUE_FLOAT,                       FIELDTYPE_DOUBLE: wxGRID_VALUE_FLOAT,
# Line 25  wx_value_type_map = {FIELDTYPE_INT: wxGR Line 29  wx_value_type_map = {FIELDTYPE_INT: wxGR
29    
30  ROW_SELECTED = "ROW_SELECTED"  ROW_SELECTED = "ROW_SELECTED"
31    
32    QUERY_KEY = 'S'
33    
34  class DataTable(wxPyGridTableBase):  class DataTable(wxPyGridTableBase):
35    
# Line 66  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.ReadRowAsDict(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 97  class DataTable(wxPyGridTableBase): Line 102  class DataTable(wxPyGridTableBase):
102          return self.CanGetValueAs(row, col, typeName)          return self.CanGetValueAs(row, col, typeName)
103    
104    
105        #
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(wxPyGridCellRenderer):
116    
117        """Renderer that draws NULL as a gray rectangle
118    
119        Other values are delegated to a normal renderer which is given as
120        the parameter to the constructor.
121        """
122    
123        def __init__(self, non_null_renderer):
124            wxPyGridCellRenderer.__init__(self)
125            self.non_null_renderer = non_null_renderer
126    
127        def Draw(self, grid, attr, dc, rect, row, col, isSelected):
128            value = grid.table.GetValue(row, col)
129            if value is None:
130                dc.SetBackgroundMode(wxSOLID)
131                dc.SetBrush(wxBrush(wxColour(192, 192, 192), wxSOLID))
132                dc.SetPen(wxTRANSPARENT_PEN)
133                dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height)
134            else:
135                self.non_null_renderer.Draw(grid, attr, dc, rect, row, col,
136                                            isSelected)
137    
138        def GetBestSize(self, grid, attr, dc, row, col):
139            self.non_null_renderer.GetBestSize(grid, attr, dc, row, col)
140    
141        def Clone(self):
142            return NullRenderer(self.non_null_renderer)
143    
144    
145  class TableGrid(wxGrid, Publisher):  class TableGrid(wxGrid, Publisher):
146    
147      """A grid view for a Thuban table      """A grid view for a Thuban table
# Line 114  class TableGrid(wxGrid, Publisher): Line 159  class TableGrid(wxGrid, Publisher):
159    
160          self.allow_messages_count = 0          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    
167          # The second parameter means that the grid is to take ownership          # The second parameter means that the grid is to take ownership
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)
174    
# Line 128  class TableGrid(wxGrid, Publisher): Line 176  class TableGrid(wxGrid, Publisher):
176          # column widths automatically but it would cause a traversal of          # column widths automatically but it would cause a traversal of
177          # the entire table which for large .dbf files can take a very          # the entire table which for large .dbf files can take a very
178          # long time.          # long time.
179          #self.AutoSizeColumns(false)          #self.AutoSizeColumns(False)
180    
181          self.SetSelectionMode(wxGrid.wxGridSelectRows)          self.SetSelectionMode(wxGrid.wxGridSelectRows)
182    
183            self.ToggleEventListeners(True)
184          EVT_GRID_RANGE_SELECT(self, self.OnRangeSelect)          EVT_GRID_RANGE_SELECT(self, self.OnRangeSelect)
185          EVT_GRID_SELECT_CELL(self, self.OnSelectCell)          EVT_GRID_SELECT_CELL(self, self.OnSelectCell)
186    
187            # Replace the normal renderers with our own versions which
188            # render NULL/None values specially
189            self.RegisterDataType(wxGRID_VALUE_STRING,
190                                  NullRenderer(wxGridCellStringRenderer()), None)
191            self.RegisterDataType(wxGRID_VALUE_NUMBER,
192                                  NullRenderer(wxGridCellNumberRenderer()), None)
193            self.RegisterDataType(wxGRID_VALUE_FLOAT,
194                                  NullRenderer(wxGridCellFloatRenderer()), None)
195    
196            EVT_WINDOW_DESTROY(self, 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          rows = dict([(i, 0) for i in self.GetSelectedRows()])          to_id = self.table.RowOrdinalToId
206            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          # if we're selecting we need to include the selected range and              self.issue(ROW_SELECTED, self.rows.keys())
         # make sure that the current row is also included, which may  
         # not be the case if you just click on a single row!  
         if event.Selecting():  
             for i in range(event.GetTopRow(), event.GetBottomRow() + 1):  
                 rows[i] = 0  
             rows[event.GetTopLeftCoords().GetRow()] = 0  
218    
         self.issue(ROW_SELECTED, rows.keys())  
219          event.Skip()          event.Skip()
220    
221      def OnSelectCell(self, event):      def OnSelectCell(self, event):
222          self.issue(ROW_SELECTED, self.GetSelectedRows())          to_id = self.table.RowOrdinalToId
223            if self.handleSelectEvents:
224                self.issue(ROW_SELECTED,
225                           [to_id(i) for i in self.GetSelectedRows()])
226          event.Skip()          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):      def disallow_messages(self):
235          """Disallow messages to be send.          """Disallow messages to be send.
236    
# Line 182  class TableGrid(wxGrid, Publisher): Line 257  class TableGrid(wxGrid, Publisher):
257          if self.allow_messages_count == 0:          if self.allow_messages_count == 0:
258              Publisher.issue(self, *args)              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):  class LayerTableGrid(TableGrid):
266    
# Line 198  class LayerTableGrid(TableGrid): Line 277  class LayerTableGrid(TableGrid):
277          nothing. If shape or layer is None also do nothing.          nothing. If shape or layer is None also do nothing.
278          """          """
279          if layer is not None \          if layer is not None \
280              and layer.table is self.table.table:              and layer.ShapeStore().Table() is self.table.table:
281    
282              self.disallow_messages()              self.disallow_messages()
283              try:              try:
284                  self.ClearSelection()                  self.ClearSelection()
285                  if len(shapes) > 0:                  if len(shapes) > 0:
286                      #                      # keep track of the lowest id so we can make it the
287                      # keep track of the lowest id so we can make it                      # first visible item
288                      # the first visible item                      first = -1
                     #  
                     first = shapes[0]  
289    
290                        to_ordinal = self.table.RowIdToOrdinal
291                      for shape in shapes:                      for shape in shapes:
292                          self.SelectRow(shape, True)                          row = to_ordinal(shape)
293                          if shape < first:                          self.SelectRow(row, True)
294                              first = shape                          if row < first:
295                                first = row
296    
297                      self.SetGridCursor(first, 0)                      self.SetGridCursor(first, 0)
298                      self.MakeCellVisible(first, 0)                      self.MakeCellVisible(first, 0)
# Line 221  class LayerTableGrid(TableGrid): Line 300  class LayerTableGrid(TableGrid):
300                  self.allow_messages()                  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, name, title, table):      def __init__(self, parent, name, title, table):
308          NonModalDialog.__init__(self, parent, name, title)          ThubanFrame.__init__(self, parent, name, title)
309            self.panel = wxPanel(self, -1)
310    
311          self.table = table          self.table = table
312          self.grid = self.make_grid(self.table)          self.grid = self.make_grid(self.table)
313            self.app = self.parent.application
314            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):      def make_grid(self, table):
325          """Return the table grid to use in the frame.          """Return the table grid to use in the frame.
# Line 238  class TableFrame(NonModalDialog): Line 329  class TableFrame(NonModalDialog):
329          """          """
330          return TableGrid(self, table)          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  ID_QUERY = 4001
351  ID_SAVEAS = 4002  ID_EXPORT = 4002
352    ID_COMBOVALUE = 4003
353    ID_EXPORTSEL = 4004
354    
355  class LayerTableFrame(TableFrame):  class QueryTableFrame(TableFrame):
356    
357      """Frame that displays a layer table in a grid view      """Frame that displays a table in a grid view and offers user actions
358        selection and export
359    
360      A LayerTableFrame is TableFrame whose selection is connected to the      A QueryTableFrame is TableFrame whose selection is connected to the
361      selected object in a map.      selected object in a map.
362      """      """
363    
364      def __init__(self, parent, name, title, layer, table):      def __init__(self, parent, name, title, table):
365          TableFrame.__init__(self, parent, name, title, table)          TableFrame.__init__(self, parent, name, title, table)
         self.layer = layer  
         self.grid.Subscribe(ROW_SELECTED, self.rows_selected)  
         self.parent.Subscribe(SHAPES_SELECTED, self.select_shapes)  
366    
367          self.combo_fields = wxComboBox(self, -1, style=wxCB_READONLY)          self.combo_fields = wxComboBox(self.panel, -1, style=wxCB_READONLY)
368          self.choice_comp = wxChoice(self, -1,          self.choice_comp = wxChoice(self.panel, -1,
369                                choices=["<", "<=", "=", "<>", ">=", ">"])                                choices=["<", "<=", "==", "!=", ">=", ">"])
370          self.combo_value = wxComboBox(self, -1)          self.combo_value = wxComboBox(self.panel, ID_COMBOVALUE)
371          self.choice_action = wxChoice(self, -1,          self.choice_action = wxChoice(self.panel, -1,
372                                  choices=[_("Replace Selection"),                                  choices=[_("Replace Selection"),
373                                          _("Refine Selection"),                                          _("Refine Selection"),
374                                          _("Add to Selection")])                                          _("Add to Selection")])
375    
376          button_query = wxButton(self, ID_QUERY, _("Query"))          button_query = wxButton(self.panel, ID_QUERY, _("Query"))
377          button_saveas = wxButton(self, ID_SAVEAS, _("Save As..."))          button_export = wxButton(self.panel, ID_EXPORT, _("Export"))
378            button_exportSel = wxButton(self.panel, ID_EXPORTSEL, _("Export Selection"))
379            button_close = wxButton(self.panel, wxID_CLOSE, _("Close"))
380    
381            self.CreateStatusBar()
382    
383          self.grid.SetSize((400, 200))          self.grid.SetSize((400, 200))
384    
385          self.combo_value.Append("")          self.combo_value.Append("")
386          for i in range(table.field_count()):          for i in range(table.NumColumns()):
387              type, name, len, decc = layer.table.field_info(i)              name = table.Column(i).name
388              self.combo_fields.Append(name)              self.combo_fields.Append(name)
389              self.combo_value.Append(name)              self.combo_value.Append(name)
390                                                                                    
391          # assume at least one field?          # assume at least one field?
392          self.combo_fields.SetSelection(0)          self.combo_fields.SetSelection(0)
393          self.combo_value.SetSelection(0)          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 = wxBoxSizer(wxVERTICAL)          topBox = wxBoxSizer(wxVERTICAL)
402    
403          sizer = wxStaticBoxSizer(wxStaticBox(self, -1, _("Selections")),          sizer = wxStaticBoxSizer(wxStaticBox(self.panel, -1,
404                                      _("Selection")),
405                                    wxHORIZONTAL)                                    wxHORIZONTAL)
406          sizer.Add(self.combo_fields, 1, wxEXPAND|wxALL, 4)          sizer.Add(self.combo_fields, 1, wxEXPAND|wxALL, 4)
407          sizer.Add(self.choice_comp, 0, wxALL, 4)          sizer.Add(self.choice_comp, 0, wxALL, 4)
408          sizer.Add(self.combo_value, 1, wxEXPAND|wxALL, 4)          sizer.Add(self.combo_value, 1, wxEXPAND|wxALL, 4)
409          sizer.Add(self.choice_action, 0, wxALL, 4)          sizer.Add(self.choice_action, 0, wxALL, 4)
410          sizer.Add(button_query, 0, wxALL, 4)          sizer.Add(button_query, 0, wxALL | wxALIGN_CENTER_VERTICAL, 4)
411          sizer.Add(40, 20, 0, wxALL, 4)          sizer.Add(40, 20, 0, wxALL, 4)
         sizer.Add(button_saveas, 0, wxALL, 4)  
412    
413          topBox.Add(sizer, 0, wxEXPAND|wxALL, 4)          topBox.Add(sizer, 0, wxEXPAND|wxALL, 4)
414          topBox.Add(self.grid, 1, wxEXPAND|wxALL, 0)          topBox.Add(self.grid, 1, wxEXPAND|wxALL, 0)
415    
416            sizer = wxBoxSizer(wxHORIZONTAL)
417            sizer.Add(button_export, 0, wxALL, 4)
418            sizer.Add(button_exportSel, 0, wxALL, 4)
419            sizer.Add(60, 20, 1, wxALL|wxEXPAND, 4)
420            sizer.Add(button_close, 0, wxALL|wxALIGN_RIGHT, 4)
421            topBox.Add(sizer, 0, wxALL | wxEXPAND, 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 = wxBoxSizer(wxVERTICAL)
429            panelSizer.Add(self.panel, 1, wxEXPAND, 0)
430          self.SetAutoLayout(True)          self.SetAutoLayout(True)
431          self.SetSizer(topBox)          self.SetSizer(panelSizer)
432          topBox.Fit(self)          panelSizer.Fit(self)
433          topBox.SetSizeHints(self)          panelSizer.SetSizeHints(self)
434    
435            self.grid.SetFocus()
436    
437          EVT_BUTTON(self, ID_QUERY, self.OnQuery)          EVT_BUTTON(self, ID_QUERY, self.OnQuery)
438          EVT_BUTTON(self, ID_SAVEAS, self.OnSaveAs)          EVT_BUTTON(self, ID_EXPORT, self.OnExport)
439            EVT_BUTTON(self, ID_EXPORTSEL, self.OnExportSel)
440            EVT_BUTTON(self, wxID_CLOSE, self.OnClose)
441            EVT_KEY_DOWN(self.grid, self.OnKeyDown)
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):      def OnQuery(self, event):
460          wxBeginBusyCursor()          ThubanBeginBusyCursor()
461            try:
         if self.combo_value.GetSelection() < 1:  
             value = self.combo_value.GetValue()  
             print value  
         else:  
             value = self.table.Column(self.combo_value.GetValue())  
462    
463          #ids = self.table.Query(              text = self.combo_value.GetValue()
464                  #self.table.Column(self.combo_fields.GetStringSelection()),              if self.combo_value.GetSelection() < 1 \
465                  #self.choice_comp.GetStringSelection(),                  or self.combo_value.FindString(text) == -1:
466                  #value)                  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()              choice = self.choice_action.GetSelection()
476                            
477          if choice == 0:              #
478              ids = [1, 2, 3, 4, 5]              # what used to be nice code got became a bit ugly because
479              # Replace Selection              # each time we select a row a message is sent to the grid
480              self.grid.ClearSelection()              # 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:              for id in ids:
508                  self.grid.SelectRow(id, True)                  if firsttime:
509          elif choice == 1:                      firsttime = False
510              ids = [1, 3, 5]                  else:
511              # Refine Selection                      self.grid.SelectRowById(id, True)
512              sel = dict([(i, 0) for i in self.parent.SelectedShapes()])  
513              self.grid.ClearSelection()              self.grid.ToggleEventListeners(True)
514              for id in filter(sel.has_key, ids):  
515                  self.grid.SelectRow(id, True)              #
516          elif choice == 2:              # select the first row
517              ids = [2, 4]              #
518              # Add to Selection              if ids:
519              for id in ids:                  self.grid.SelectRowById(ids[0], True)
                 self.grid.SelectRow(id, True)  
520    
521          wxEndBusyCursor()          finally:
522                ThubanEndBusyCursor()
523            
524        def doExport(self, onlySelected):
525                    
526      def OnSaveAs(self, event):          dlg = wxFileDialog(self, _("Export Table To"), ".", "",
527          dlg = wxFileDialog(self, _("Save Table As"), ".", "",                             _("DBF Files (*.dbf)|*.dbf|") +
528                             "DBF Files (*.dbf)|*.dbf|" +                             _("CSV Files (*.csv)|*.csv|") +
529                             "CSV Files (*.csv)|*.csv|" +                             _("All Files (*.*)|*.*"),
                            "All Files (*.*)|*.*",  
530                             wxSAVE|wxOVERWRITE_PROMPT)                             wxSAVE|wxOVERWRITE_PROMPT)
531          if dlg.ShowModal() == wxID_OK:          if dlg.ShowModal() == wxID_OK:
532              pass              filename = dlg.GetPath()
533                                                                                                type = os.path.basename(filename).split('.')[-1:][0]
534          dlg.Destroy()              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 = wxMessageDialog(None, "Unsupported format: %s" % type,
547                                          "Table Export", wxOK|wxICON_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):
560            TableFrame.OnClose(self, event)
561    
562        def get_selected(self):
563            """Return a dictionary of the selected rows.
564    
565            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):      def make_grid(self, table):
606          """Override the derived method to return a LayerTableGrid.          """Override the derived method to return a LayerTableGrid.
607          """          """
608          return LayerTableGrid(self, table)          return LayerTableGrid(self, table)
609    
610      def OnClose(self, event):      def get_selected(self):
611          self.parent.Unsubscribe(SHAPES_SELECTED, self.select_shapes)          """Override the derived method to return a dictionary of the selected
612          TableFrame.OnClose(self, event)          rows.
613            """
614            return dict([(i, 0) for i in self.parent.SelectedShapes()])
615    
616      def select_shapes(self, layer, shapes):      def select_shapes(self, layer, shapes):
617          """Subscribed to the SHAPES_SELECTED message.          """Subscribed to the SHAPES_SELECTED message.
# Line 369  class LayerTableFrame(TableFrame): Line 622  class LayerTableFrame(TableFrame):
622          self.grid.select_shapes(layer, shapes)          self.grid.select_shapes(layer, shapes)
623    
624      def rows_selected(self, rows):      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.parent.SelectShapes(self.layer, rows)              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.881  
changed lines
  Added in v.2032

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26