/[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 979 by frank, Thu May 22 11:40:59 2003 UTC revision 2718 by dpinte, Fri Jan 5 23:43:49 2007 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 *  import wx
15  from wxPython.grid import *  from wx import grid
16    
17  from Thuban.Lib.connector import Publisher  from Thuban.Lib.connector import Publisher
18  from Thuban.Model.table import FIELDTYPE_INT, FIELDTYPE_DOUBLE, \  from Thuban.Model.table import FIELDTYPE_INT, FIELDTYPE_DOUBLE, \
19       FIELDTYPE_STRING       FIELDTYPE_STRING, table_to_dbf, table_to_csv
20  import view  from dialogs import ThubanFrame
21  from dialogs import NonModalDialog  
22  from messages import SHAPES_SELECTED  from messages import SHAPES_SELECTED, SESSION_REPLACED
23    from Thuban.Model.messages import TABLE_REMOVED, MAP_LAYERS_REMOVED
24  wx_value_type_map = {FIELDTYPE_INT: wxGRID_VALUE_NUMBER,  from Thuban.UI.common import ThubanBeginBusyCursor, ThubanEndBusyCursor
25                       FIELDTYPE_DOUBLE: wxGRID_VALUE_FLOAT,  
26                       FIELDTYPE_STRING: wxGRID_VALUE_STRING}  wx_value_type_map = {FIELDTYPE_INT: grid.GRID_VALUE_NUMBER,
27                         FIELDTYPE_DOUBLE: grid.GRID_VALUE_FLOAT,
28                         FIELDTYPE_STRING: grid.GRID_VALUE_STRING}
29    
30  ROW_SELECTED = "ROW_SELECTED"  ROW_SELECTED = "ROW_SELECTED"
31    
32  QUERY_KEY = 'S'  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 67  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)          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 98  class DataTable(wxPyGridTableBase): Line 111  class DataTable(wxPyGridTableBase):
111          return self.CanGetValueAs(row, col, typeName)          return self.CanGetValueAs(row, col, typeName)
112    
113    
114  class TableGrid(wxGrid, Publisher):      #
115        def RowIdToOrdinal(self, rowid):
116            """Return the ordinal of the row given by its id"""
117            return self.table.RowIdToOrdinal(rowid)
118    
119        def RowOrdinalToId(self, ordinal):
120            """Return the id of the row given by its ordinal"""
121            return self.table.RowOrdinalToId(ordinal)
122    
123    
124    class NullRenderer(grid.PyGridCellRenderer):
125    
126        """Renderer that draws NULL as a gray rectangle
127    
128        Other values are delegated to a normal renderer which is given as
129        the parameter to the constructor.
130        """
131    
132        def __init__(self, non_null_renderer):
133            grid.PyGridCellRenderer.__init__(self)
134            self.non_null_renderer = non_null_renderer
135    
136        def Draw(self, grid, attr, dc, rect, row, col, isSelected):
137            value = grid.table.GetValue(row, col)
138            if value is None:
139                dc.SetBackgroundMode(wx.SOLID)
140                dc.SetBrush(wx.Brush(wx.Colour(192, 192, 192), wx.SOLID))
141                dc.SetPen(wx.TRANSPARENT_PEN)
142                dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height)
143            else:
144                self.non_null_renderer.Draw(grid, attr, dc, rect, row, col,
145                                            isSelected)
146    
147        def GetBestSize(self, grid, attr, dc, row, col):
148            self.non_null_renderer.GetBestSize(grid, attr, dc, row, col)
149    
150        def Clone(self):
151            return NullRenderer(self.non_null_renderer)
152    
153    
154    class TableGrid(grid.Grid, Publisher):
155    
156      """A grid view for a Thuban table      """A grid view for a Thuban table
157    
# Line 111  class TableGrid(wxGrid, Publisher): Line 164  class TableGrid(wxGrid, Publisher):
164      """      """
165    
166      def __init__(self, parent, table = None):      def __init__(self, parent, table = None):
167          wxGrid.__init__(self, parent, -1)          grid.Grid.__init__(self, parent, -1)
168    
169          self.allow_messages_count = 0          self.allow_messages_count = 0
170    
171            # keep track of which rows are selected.
172            self.rows = {}
173    
174          self.table = DataTable(table)          self.table = DataTable(table)
175    
176          # The second parameter means that the grid is to take ownership          # The second parameter means that the grid is to take ownership
177          # of the table and will destroy it when done. Otherwise you          # of the table and will destroy it when done. Otherwise you
178          # would need to keep a reference to it and call its Destroy          # would need to keep a reference to it and call its Destroy
179          # method later.          # method later.
180          self.SetTable(self.table, true)          self.SetTable(self.table, True)
181    
182          #self.SetMargins(0,0)          #self.SetMargins(0,0)
183    
# Line 129  class TableGrid(wxGrid, Publisher): Line 185  class TableGrid(wxGrid, Publisher):
185          # column widths automatically but it would cause a traversal of          # column widths automatically but it would cause a traversal of
186          # the entire table which for large .dbf files can take a very          # the entire table which for large .dbf files can take a very
187          # long time.          # long time.
188          #self.AutoSizeColumns(false)          #self.AutoSizeColumns(False)
   
         self.SetSelectionMode(wxGrid.wxGridSelectRows)  
189    
190          #EVT_GRID_RANGE_SELECT(self, None)          self.SetSelectionMode(grid.Grid.wxGridSelectRows)
         #EVT_GRID_SELECT_CELL(self, None)  
         #EVT_GRID_RANGE_SELECT(self, self.OnRangeSelect)  
         #EVT_GRID_SELECT_CELL(self, self.OnSelectCell)  
191    
192          self.ToggleEventListeners(True)          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          rows = dict([(i, 0) for i in self.GetSelectedRows()])          to_id = self.table.RowOrdinalToId
215            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          # 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  
227    
         self.issue(ROW_SELECTED, rows.keys())  
228          event.Skip()          event.Skip()
229    
230      def OnSelectCell(self, event):      def OnSelectCell(self, event):
231          self.issue(ROW_SELECTED, self.GetSelectedRows())          to_id = self.table.RowOrdinalToId
232            if self.handleSelectEvents:
233                self.issue(ROW_SELECTED,
234                           [to_id(i) for i in self.GetSelectedRows()])
235          event.Skip()          event.Skip()
236    
237      def ToggleEventListeners(self, on):      def ToggleEventListeners(self, on):
238          if on:          self.handleSelectEvents = on
239              EVT_GRID_RANGE_SELECT(self, self.OnRangeSelect)  
240              EVT_GRID_SELECT_CELL(self, self.OnSelectCell)      def GetNumberSelected(self):
241          else:          return len(self.rows)
242              EVT_GRID_RANGE_SELECT(self, None)  
             EVT_GRID_SELECT_CELL(self, None)  
               
243      def disallow_messages(self):      def disallow_messages(self):
244          """Disallow messages to be send.          """Disallow messages to be send.
245    
# Line 195  class TableGrid(wxGrid, Publisher): Line 266  class TableGrid(wxGrid, Publisher):
266          if self.allow_messages_count == 0:          if self.allow_messages_count == 0:
267              Publisher.issue(self, *args)              Publisher.issue(self, *args)
268    
269        def SelectRowById(self, rowid, do_select):
270            """Select row with the id rowid"""
271            self.SelectRow(self.table.RowIdToOrdinal(rowid), do_select)
272    
273    
274  class LayerTableGrid(TableGrid):  class LayerTableGrid(TableGrid):
275    
# Line 211  class LayerTableGrid(TableGrid): Line 286  class LayerTableGrid(TableGrid):
286          nothing. If shape or layer is None also do nothing.          nothing. If shape or layer is None also do nothing.
287          """          """
288          if layer is not None \          if layer is not None \
289              and layer.table is self.table.table:              and layer.ShapeStore().Table() is self.table.table:
290    
291              self.disallow_messages()              self.disallow_messages()
292              try:              try:
293                  self.ClearSelection()                  self.ClearSelection()
294                  if len(shapes) > 0:                  if len(shapes) > 0:
295                      #                      # keep track of the lowest id so we can make it the
296                      # keep track of the lowest id so we can make it                      # first visible item
297                      # the first visible item                      first = -1
                     #  
                     first = shapes[0]  
298    
299                        to_ordinal = self.table.RowIdToOrdinal
300                      for shape in shapes:                      for shape in shapes:
301                          self.SelectRow(shape, True)                          row = to_ordinal(shape)
302                          if shape < first:                          self.SelectRow(row, True)
303                              first = shape                          if row < first:
304                                first = row
305    
306                      self.SetGridCursor(first, 0)                      self.SetGridCursor(first, 0)
307                      self.MakeCellVisible(first, 0)                      self.MakeCellVisible(first, 0)
# Line 234  class LayerTableGrid(TableGrid): Line 309  class LayerTableGrid(TableGrid):
309                  self.allow_messages()                  self.allow_messages()
310    
311    
312  class TableFrame(NonModalDialog):  class TableFrame(ThubanFrame):
313    
314      """Frame that displays a Thuban table in a grid view"""      """Frame that displays a Thuban table in a grid view"""
315    
316      def __init__(self, parent, name, title, table):      def __init__(self, parent, name, title, table):
317          NonModalDialog.__init__(self, parent, name, title)          ThubanFrame.__init__(self, parent, name, title)
318            self.panel = wx.Panel(self, -1)
319    
320          self.table = table          self.table = table
321          self.grid = self.make_grid(self.table)          self.grid = self.make_grid(self.table)
322            self.app = self.parent.application
323            self.app.Subscribe(SESSION_REPLACED, self.close_on_session_replaced)
324            self.session = self.app.Session()
325            self.session.Subscribe(TABLE_REMOVED, self.close_on_table_removed)
326    
327        def OnDestroy(self, event):
328            """Extend inherited method to unsubscribe messages"""
329            self.app.Unsubscribe(SESSION_REPLACED, self.close_on_session_replaced)
330            self.session.Unsubscribe(TABLE_REMOVED, self.close_on_table_removed)
331            ThubanFrame.OnDestroy(self, event)
332    
333      def make_grid(self, table):      def make_grid(self, table):
334          """Return the table grid to use in the frame.          """Return the table grid to use in the frame.
# Line 251  class TableFrame(NonModalDialog): Line 338  class TableFrame(NonModalDialog):
338          """          """
339          return TableGrid(self, table)          return TableGrid(self, table)
340    
341        def close_on_session_replaced(self, *args):
342            """Subscriber for the SESSION_REPLACED messages.
343    
344            The table frame is tied to a session so close the window when
345            the session changes.
346            """
347            self.Close()
348    
349        def close_on_table_removed(self, table):
350            """Subscriber for the TABLE_REMOVED messages.
351    
352            The table frame is tied to a particular table so close the
353            window when the table is removed.
354            """
355            if table is self.table:
356                self.Close()
357    
358    
359  ID_QUERY = 4001  ID_QUERY = 4001
360  ID_SAVEAS = 4002  ID_EXPORT = 4002
361    ID_COMBOVALUE = 4003
362    ID_EXPORTSEL = 4004
363    
364  class LayerTableFrame(TableFrame):  class QueryTableFrame(TableFrame):
365    
366      """Frame that displays a layer table in a grid view      """Frame that displays a table in a grid view and offers user actions
367        selection and export
368    
369      A LayerTableFrame is TableFrame whose selection is connected to the      A QueryTableFrame is TableFrame whose selection is connected to the
370      selected object in a map.      selected object in a map.
371      """      """
372    
373      def __init__(self, parent, name, title, layer, table):      def __init__(self, parent, name, title, table):
374          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)  
375    
376          self.combo_fields = wxComboBox(self, -1, style=wxCB_READONLY)          self.combo_fields = wx.ComboBox(self.panel, -1, style=wx.CB_READONLY)
377          self.choice_comp = wxChoice(self, -1,          self.choice_comp = wx.Choice(self.panel, -1,
378                                choices=["<", "<=", "==", "!=", ">=", ">"])                                choices=["<", "<=", "==", "!=", ">=", ">"])
379          self.combo_value = wxComboBox(self, -1)          self.combo_value = wx.ComboBox(self.panel, ID_COMBOVALUE)
380          self.choice_action = wxChoice(self, -1,          self.choice_action = wx.Choice(self.panel, -1,
381                                  choices=[_("Replace Selection"),                                  choices=[_("Replace Selection"),
382                                          _("Refine Selection"),                                          _("Refine Selection"),
383                                          _("Add to Selection")])                                          _("Add to Selection")])
384    
385          button_query = wxButton(self, ID_QUERY, _("Query"))          button_query = wx.Button(self.panel, ID_QUERY, _("Query"))
386          button_saveas = wxButton(self, ID_SAVEAS, _("Export"))          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))          self.grid.SetSize((400, 200))
393    
# Line 292  class LayerTableFrame(TableFrame): Line 400  class LayerTableFrame(TableFrame):
400          # assume at least one field?          # assume at least one field?
401          self.combo_fields.SetSelection(0)          self.combo_fields.SetSelection(0)
402          self.combo_value.SetSelection(0)          self.combo_value.SetSelection(0)
403            self.choice_action.SetSelection(0)
404            self.choice_comp.SetSelection(0)
405    
406          topBox = wxBoxSizer(wxVERTICAL)          self.grid.Reparent(self.panel)
407    
408          sizer = wxStaticBoxSizer(wxStaticBox(self, -1, _("Selections")),          self.UpdateStatusText()
                                   wxHORIZONTAL)  
         sizer.Add(self.combo_fields, 1, wxEXPAND|wxALL, 4)  
         sizer.Add(self.choice_comp, 0, wxALL, 4)  
         sizer.Add(self.combo_value, 1, wxEXPAND|wxALL, 4)  
         sizer.Add(self.choice_action, 0, wxALL, 4)  
         sizer.Add(button_query, 0, wxALL | wxALIGN_CENTER_VERTICAL, 4)  
         sizer.Add(40, 20, 0, wxALL, 4)  
         sizer.Add(button_saveas, 0, wxALL | wxALIGN_CENTER_VERTICAL, 4)  
409    
410          topBox.Add(sizer, 0, wxEXPAND|wxALL, 4)          topBox = wx.BoxSizer(wx.VERTICAL)
         topBox.Add(self.grid, 1, wxEXPAND|wxALL, 0)  
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)          self.SetAutoLayout(True)
440          self.SetSizer(topBox)          self.SetSizer(panelSizer)
441          topBox.Fit(self)          panelSizer.Fit(self)
442          topBox.SetSizeHints(self)          panelSizer.SetSizeHints(self)
443    
444          self.grid.SetFocus()          self.grid.SetFocus()
445          EVT_BUTTON(self, ID_QUERY, self.OnQuery)  
446          EVT_BUTTON(self, ID_SAVEAS, self.OnSaveAs)          self.Bind(wx.EVT_BUTTON, self.OnQuery, id=ID_QUERY)
447          EVT_KEY_DOWN(self.grid, self.OnKeyDown)          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):      def OnKeyDown(self, event):
461          """Catch query key from grid"""          """Catch query key from grid"""
         print "In OnKeyDown"  
462          if event.AltDown() and event.GetKeyCode() == ord(QUERY_KEY):          if event.AltDown() and event.GetKeyCode() == ord(QUERY_KEY):
             print "Got the Key!"  
463              self.combo_fields.SetFocus()              self.combo_fields.SetFocus()
464              self.combo_fields.refocus = True              self.combo_fields.refocus = True
465          else:          else:
466              event.Skip()              event.Skip()
467    
   
468      def OnQuery(self, event):      def OnQuery(self, event):
469          wxBeginBusyCursor()          ThubanBeginBusyCursor()
470            try:
471    
472          if self.combo_value.GetSelection() < 1:              text = self.combo_value.GetValue()
473              value = self.combo_value.GetValue()              if self.combo_value.GetSelection() < 1 \
474          else:                  or self.combo_value.FindString(text) == -1:
475              value = self.table.Column(self.combo_value.GetValue())                  value = text
476                else:
477                    value = self.table.Column(text)
478    
479          ids = self.table.SimpleQuery(              ids = self.table.SimpleQuery(
480                  self.table.Column(self.combo_fields.GetStringSelection()),                      self.table.Column(self.combo_fields.GetStringSelection()),
481                  self.choice_comp.GetStringSelection(),                      self.choice_comp.GetStringSelection(),
482                  value)                      value)
483    
484          choice = self.choice_action.GetSelection()              choice = self.choice_action.GetSelection()
485                
486          #              #
487          # what used to be nice code got became a bit ugly because              # 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              # each time we select a row a message is sent to the grid
489          # which we are listening for and then we send further              # which we are listening for and then we send further
490          # messages.              # messages.
491          #              #
492          # now, we disable those listeners select everything but              # now, we disable those listeners select everything but
493          # the first item, reenable the listeners, and select              # the first item, reenable the listeners, and select
494          # the first element, which causes everything to be              # the first element, which causes everything to be
495          # updated properly.              # updated properly.
496          #              #
497          self.grid.ToggleEventListeners(False)              if ids:
498                    self.grid.ToggleEventListeners(False)
499          if choice == 0:  
500              # Replace Selection              if choice == 0:
501              self.grid.ClearSelection()                  # Replace Selection
502          elif choice == 1:                  self.grid.ClearSelection()
503              # Refine Selection              elif choice == 1:
504              sel = dict([(i, 0) for i in self.parent.SelectedShapes()])                  # Refine Selection
505              self.grid.ClearSelection()                  sel = self.get_selected()
506              ids = filter(sel.has_key, ids)                  self.grid.ClearSelection()
507          elif choice == 2:                  ids = filter(sel.has_key, ids)
508              # Add to Selection              elif choice == 2:
509              pass                  # Add to Selection
510                    pass
511          #  
512          # select the rows (all but the first)              #
513          #              # select the rows (all but the first)
514          firsttime = True              #
515          for id in ids:              firsttime = True
516              if firsttime:              for id in ids:
517                  firsttime = False                  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:              else:
548                  self.grid.SelectRow(id, True)                  records = None
549    
550          self.grid.ToggleEventListeners(True)              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          # select the first row          self.doExport(False)
564          #  
565          if ids:      def OnExportSel(self, event):
566              self.grid.SelectRow(ids[0], True)          self.doExport(True)
567    
568          wxEndBusyCursor()      def OnClose(self, event):
569                    TableFrame.OnClose(self, event)
570      def OnSaveAs(self, event):  
571          dlg = wxFileDialog(self, _("Save Table As"), ".", "",      def get_selected(self):
572                             "DBF Files (*.dbf)|*.dbf|" +          """Return a dictionary of the selected rows.
573                             "CSV Files (*.csv)|*.csv|" +  
574                             "All Files (*.*)|*.*",          The dictionary has the indexes as keys."""
575                             wxSAVE|wxOVERWRITE_PROMPT)          to_id = self.table.RowOrdinalToId
576          if dlg.ShowModal() == wxID_OK:          return dict([(to_id(i), 0) for i in self.grid.GetSelectedRows()])
577              pass  
578                                                                                    
579          dlg.Destroy()  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):      def make_grid(self, table):
615          """Override the derived method to return a LayerTableGrid.          """Override the derived method to return a LayerTableGrid.
616          """          """
617          return LayerTableGrid(self, table)          return LayerTableGrid(self, table)
618    
619      def OnClose(self, event):      def get_selected(self):
620          self.parent.Unsubscribe(SHAPES_SELECTED, self.select_shapes)          """Override the derived method to return a dictionary of the selected
621          TableFrame.OnClose(self, event)          rows.
622            """
623            return dict([(i, 0) for i in self.parent.SelectedShapes()])
624    
625      def select_shapes(self, layer, shapes):      def select_shapes(self, layer, shapes):
626          """Subscribed to the SHAPES_SELECTED message.          """Subscribed to the SHAPES_SELECTED message.
# Line 418  class LayerTableFrame(TableFrame): Line 631  class LayerTableFrame(TableFrame):
631          self.grid.select_shapes(layer, shapes)          self.grid.select_shapes(layer, shapes)
632    
633      def rows_selected(self, rows):      def rows_selected(self, rows):
634            """Return the selected rows of the layer as they are returned
635            by Layer.SelectShapes().
636            """
637          if self.layer is not None:          if self.layer is not None:
638              self.parent.SelectShapes(self.layer, rows)              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.979  
changed lines
  Added in v.2718

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26