/[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 1066 by frank, Tue May 27 14:18:05 2003 UTC branches/WIP-pyshapelib-bramz/Thuban/UI/tableview.py revision 2755 by dpinte, Thu Apr 12 09:21:58 2007 UTC
# Line 11  import os.path Line 11  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, table_to_dbf, table_to_csv       FIELDTYPE_STRING, table_to_dbf, table_to_csv
20  import view  from dialogs import ThubanFrame
21  from dialogs import NonModalNonParentDialog  
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 69  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                    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 100  class DataTable(wxPyGridTableBase): Line 108  class DataTable(wxPyGridTableBase):
108          return self.CanGetValueAs(row, col, typeName)          return self.CanGetValueAs(row, col, typeName)
109    
110    
111  class TableGrid(wxGrid, Publisher):      #
112        def RowIdToOrdinal(self, rowid):
113            """Return the ordinal of the row given by its id"""
114            return self.table.RowIdToOrdinal(rowid)
115    
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(grid.Grid, Publisher):
152    
153      """A grid view for a Thuban table      """A grid view for a Thuban table
154    
# Line 113  class TableGrid(wxGrid, Publisher): Line 161  class TableGrid(wxGrid, Publisher):
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          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
# Line 133  class TableGrid(wxGrid, Publisher): Line 184  class TableGrid(wxGrid, Publisher):
184          # long time.          # long time.
185          #self.AutoSizeColumns(False)          #self.AutoSizeColumns(False)
186    
187          self.SetSelectionMode(wxGrid.wxGridSelectRows)          self.SetSelectionMode(grid.Grid.wxGridSelectRows)
   
         #EVT_GRID_RANGE_SELECT(self, None)  
         #EVT_GRID_SELECT_CELL(self, None)  
         #EVT_GRID_RANGE_SELECT(self, self.OnRangeSelect)  
         #EVT_GRID_SELECT_CELL(self, self.OnSelectCell)  
188    
189          self.ToggleEventListeners(True)          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          rows = dict([(i, 0) for i in self.GetSelectedRows()])          to_id = self.table.RowOrdinalToId
212            if self.handleSelectEvents:
213                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          # 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  
224    
         self.issue(ROW_SELECTED, rows.keys())  
225          event.Skip()          event.Skip()
226    
227      def OnSelectCell(self, event):      def OnSelectCell(self, event):
228          self.issue(ROW_SELECTED, self.GetSelectedRows())          to_id = self.table.RowOrdinalToId
229            if self.handleSelectEvents:
230                self.issue(ROW_SELECTED,
231                           [to_id(i) for i in self.GetSelectedRows()])
232          event.Skip()          event.Skip()
233    
234      def ToggleEventListeners(self, on):      def ToggleEventListeners(self, on):
235          if on:          self.handleSelectEvents = on
236              EVT_GRID_RANGE_SELECT(self, self.OnRangeSelect)  
237              EVT_GRID_SELECT_CELL(self, self.OnSelectCell)      def GetNumberSelected(self):
238          else:          return len(self.rows)
239              EVT_GRID_RANGE_SELECT(self, None)  
             EVT_GRID_SELECT_CELL(self, None)  
               
240      def disallow_messages(self):      def disallow_messages(self):
241          """Disallow messages to be send.          """Disallow messages to be send.
242    
# Line 197  class TableGrid(wxGrid, Publisher): Line 263  class TableGrid(wxGrid, Publisher):
263          if self.allow_messages_count == 0:          if self.allow_messages_count == 0:
264              Publisher.issue(self, *args)              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):  class LayerTableGrid(TableGrid):
272    
# Line 213  class LayerTableGrid(TableGrid): Line 283  class LayerTableGrid(TableGrid):
283          nothing. If shape or layer is None also do nothing.          nothing. If shape or layer is None also do nothing.
284          """          """
285          if layer is not None \          if layer is not None \
286              and layer.table is self.table.table:              and layer.ShapeStore().Table() is self.table.table:
287    
288              self.disallow_messages()              self.disallow_messages()
289              try:              try:
290                  self.ClearSelection()                  self.ClearSelection()
291                  if len(shapes) > 0:                  if len(shapes) > 0:
292                      #                      # keep track of the lowest id so we can make it the
293                      # keep track of the lowest id so we can make it                      # first visible item
294                      # the first visible item                      first = -1
                     #  
                     first = shapes[0]  
295    
296                        to_ordinal = self.table.RowIdToOrdinal
297                      for shape in shapes:                      for shape in shapes:
298                          self.SelectRow(shape, True)                          row = to_ordinal(shape)
299                          if shape < first:                          self.SelectRow(row, True)
300                              first = shape                          if row < first:
301                                first = row
302    
303                      self.SetGridCursor(first, 0)                      self.SetGridCursor(first, 0)
304                      self.MakeCellVisible(first, 0)                      self.MakeCellVisible(first, 0)
# Line 236  class LayerTableGrid(TableGrid): Line 306  class LayerTableGrid(TableGrid):
306                  self.allow_messages()                  self.allow_messages()
307    
308    
309  class TableFrame(NonModalNonParentDialog):  class TableFrame(ThubanFrame):
310    
311      """Frame that displays a Thuban table in a grid view"""      """Frame that displays a Thuban table in a grid view"""
312    
313      def __init__(self, parent, name, title, table):      def __init__(self, parent, name, title, table):
314          NonModalNonParentDialog.__init__(self, parent, name, title)          ThubanFrame.__init__(self, parent, name, title)
315            self.panel = wx.Panel(self, -1)
316    
317          self.table = table          self.table = table
318          self.grid = self.make_grid(self.table)          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):      def make_grid(self, table):
331          """Return the table grid to use in the frame.          """Return the table grid to use in the frame.
# Line 253  class TableFrame(NonModalNonParentDialog Line 335  class TableFrame(NonModalNonParentDialog
335          """          """
336          return TableGrid(self, table)          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  ID_QUERY = 4001
357  ID_EXPORT = 4002  ID_EXPORT = 4002
358    ID_COMBOVALUE = 4003
359    ID_EXPORTSEL = 4004
360    
361  class QueryTableFrame(TableFrame):  class QueryTableFrame(TableFrame):
362    
363      """Frame that displays a table in a grid view and offers user actions      """Frame that displays a table in a grid view and offers user actions
364      selection and export      selection and export
365    
366      A LayerTableFrame is TableFrame whose selection is connected to the      A QueryTableFrame is TableFrame whose selection is connected to the
367      selected object in a map.      selected object in a map.
368      """      """
369    
370      def __init__(self, parent, name, title, table):      def __init__(self, parent, name, title, table):
371          TableFrame.__init__(self, parent, name, title, table)          TableFrame.__init__(self, parent, name, title, table)
372    
373          self.combo_fields = wxComboBox(self, -1, style=wxCB_READONLY)          self.combo_fields = wx.ComboBox(self.panel, -1, style=wx.CB_READONLY)
374          self.choice_comp = wxChoice(self, -1,          self.choice_comp = wx.Choice(self.panel, -1,
375                                choices=["<", "<=", "==", "!=", ">=", ">"])                                choices=["<", "<=", "==", "!=", ">=", ">"])
376          self.combo_value = wxComboBox(self, -1)          self.combo_value = wx.ComboBox(self.panel, ID_COMBOVALUE)
377          self.choice_action = wxChoice(self, -1,          self.choice_action = wx.Choice(self.panel, -1,
378                                  choices=[_("Replace Selection"),                                  choices=[_("Replace Selection"),
379                                          _("Refine Selection"),                                          _("Refine Selection"),
380                                          _("Add to Selection")])                                          _("Add to Selection")])
381    
382          button_query = wxButton(self, ID_QUERY, _("Query"))          button_query = wx.Button(self.panel, ID_QUERY, _("Query"))
383          button_saveas = wxButton(self, ID_EXPORT, _("Export"))          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))          self.grid.SetSize((400, 200))
390    
# Line 292  class QueryTableFrame(TableFrame): Line 397  class QueryTableFrame(TableFrame):
397          # assume at least one field?          # assume at least one field?
398          self.combo_fields.SetSelection(0)          self.combo_fields.SetSelection(0)
399          self.combo_value.SetSelection(0)          self.combo_value.SetSelection(0)
400            self.choice_action.SetSelection(0)
401            self.choice_comp.SetSelection(0)
402    
403          topBox = wxBoxSizer(wxVERTICAL)          self.grid.Reparent(self.panel)
404    
405          sizer = wxStaticBoxSizer(wxStaticBox(self, -1,          self.UpdateStatusText()
                                   _("Selection")),  
                                   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)  
406    
407          topBox.Add(sizer, 0, wxEXPAND|wxALL, 4)          topBox = wx.BoxSizer(wx.VERTICAL)
         topBox.Add(self.grid, 1, wxEXPAND|wxALL, 0)  
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)          self.SetAutoLayout(True)
437          self.SetSizer(topBox)          self.SetSizer(panelSizer)
438          topBox.Fit(self)          panelSizer.Fit(self)
439          topBox.SetSizeHints(self)          panelSizer.SetSizeHints(self)
440    
441          self.grid.SetFocus()          self.grid.SetFocus()
442          EVT_BUTTON(self, ID_QUERY, self.OnQuery)  
443          EVT_BUTTON(self, ID_EXPORT, self.OnSaveAs)          self.Bind(wx.EVT_BUTTON, self.OnQuery, id=ID_QUERY)
444          EVT_KEY_DOWN(self.grid, self.OnKeyDown)          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):      def OnKeyDown(self, event):
458          """Catch query key from grid"""          """Catch query key from grid"""
# Line 327  class QueryTableFrame(TableFrame): Line 462  class QueryTableFrame(TableFrame):
462          else:          else:
463              event.Skip()              event.Skip()
464    
   
465      def OnQuery(self, event):      def OnQuery(self, event):
466          wxBeginBusyCursor()          ThubanBeginBusyCursor()
467            try:
         if self.combo_value.GetSelection() < 1:  
             value = self.combo_value.GetValue()  
         else:  
             value = self.table.Column(self.combo_value.GetValue())  
468    
469          ids = self.table.SimpleQuery(              text = self.combo_value.GetValue()
470                  self.table.Column(self.combo_fields.GetStringSelection()),              if self.combo_value.GetSelection() < 1 \
471                  self.choice_comp.GetStringSelection(),                  or self.combo_value.FindString(text) == -1:
472                  value)                  value = text
   
         choice = self.choice_action.GetSelection()  
               
         #  
         # what used to be nice code got became a bit ugly because  
         # each time we select a row a message is sent to the grid  
         # which we are listening for and then we send further  
         # messages.  
         #  
         # now, we disable those listeners select everything but  
         # the first item, reenable the listeners, and select  
         # the first element, which causes everything to be  
         # updated properly.  
         #  
         self.grid.ToggleEventListeners(False)  
   
         if choice == 0:  
             # Replace Selection  
             self.grid.ClearSelection()  
         elif choice == 1:  
             # Refine Selection  
             sel = self.get_selected()  
             self.grid.ClearSelection()  
             ids = filter(sel.has_key, ids)  
         elif choice == 2:  
             # Add to Selection  
             pass  
   
         #  
         # select the rows (all but the first)  
         #  
         firsttime = True  
         for id in ids:  
             if firsttime:  
                 firsttime = False  
473              else:              else:
474                  self.grid.SelectRow(id, True)                  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          self.grid.ToggleEventListeners(True)          finally:
528                ThubanEndBusyCursor()
529    
530          #      def doExport(self, onlySelected):
531          # select the first row  
532          #          dlg = wx.FileDialog(self, _("Export Table To"), ".", "",
         if ids:  
             self.grid.SelectRow(ids[0], True)  
   
         wxEndBusyCursor()  
           
     def OnSaveAs(self, event):  
         dlg = wxFileDialog(self, _("Export Table To"), ".", "",  
533                             _("DBF Files (*.dbf)|*.dbf|") +                             _("DBF Files (*.dbf)|*.dbf|") +
534                             _("CSV Files (*.csv)|*.csv|") +                             _("CSV Files (*.csv)|*.csv|") +
535                             _("All Files (*.*)|*.*"),                             _("All Files (*.*)|*.*"),
536                             wxSAVE|wxOVERWRITE_PROMPT)                             wx.SAVE|wx.OVERWRITE_PROMPT)
537          if dlg.ShowModal() == wxID_OK:          if dlg.ShowModal() == wx.ID_OK:
538              filename = dlg.GetPath()              filename = dlg.GetPath()
539              type = os.path.basename(filename).split('.')[-1:][0]              type = os.path.basename(filename).split('.')[-1:][0]
540              dlg.Destroy()              dlg.Destroy()
541    
542                if onlySelected:
543                    records = self.grid.GetSelectedRows()
544                else:
545                    records = None
546    
547              if type.upper() == "DBF":              if type.upper() == "DBF":
548                  table_to_dbf(self.table, filename)                  table_to_dbf(self.table, filename, records)
549              elif type.upper() == 'CSV':              elif type.upper() == 'CSV':
550                  table_to_csv(self.table, filename)                  table_to_csv(self.table, filename, records)
551              else:              else:
552                  dlg = wxMessageDialog(None, "Unsupported format: %s" % type,                  dlg = wx.MessageDialog(None, "Unsupported format: %s" % type,
553                                        "Table Export", wxOK|wxICON_WARNING)                                        "Table Export", wx.OK|wx.ICON_WARNING)
554                  dlg.ShowModal()                  dlg.ShowModal()
555                  dlg.Destroy()                  dlg.Destroy()
556          else:          else:
557              dlg.Destroy()              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):      def OnClose(self, event):
566          TableFrame.OnClose(self, event)          TableFrame.OnClose(self, event)
567    
568      def get_selected(self):      def get_selected(self):
569          """Return a dictionary of the selected rows.          """Return a dictionary of the selected rows.
570            
571          The dictionary has sthe indexes as keys."""          The dictionary has the indexes as keys."""
572          return dict([(i, 0) for i in self.grid.GetSelectedRows()])          to_id = self.table.RowOrdinalToId
573            return dict([(to_id(i), 0) for i in self.grid.GetSelectedRows()])
574    
575    
576  class LayerTableFrame(QueryTableFrame):  class LayerTableFrame(QueryTableFrame):
577    
# Line 432  class LayerTableFrame(QueryTableFrame): Line 586  class LayerTableFrame(QueryTableFrame):
586          self.layer = layer          self.layer = layer
587          self.grid.Subscribe(ROW_SELECTED, self.rows_selected)          self.grid.Subscribe(ROW_SELECTED, self.rows_selected)
588          self.parent.Subscribe(SHAPES_SELECTED, self.select_shapes)          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          # if there is already a selection present, update the grid
593          # accordingly          # accordingly
594          sel = self.get_selected().keys()          sel = self.get_selected().keys()
595          for i in sel:          for i in sel:
596              self.grid.SelectRow(i, True)              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):      def make_grid(self, table):
612          """Override the derived method to return a LayerTableGrid.          """Override the derived method to return a LayerTableGrid.
# Line 450  class LayerTableFrame(QueryTableFrame): Line 619  class LayerTableFrame(QueryTableFrame):
619          """          """
620          return dict([(i, 0) for i in self.parent.SelectedShapes()])          return dict([(i, 0) for i in self.parent.SelectedShapes()])
621    
     def OnClose(self, event):  
         """Override the derived method to first unsubscribed."""  
         self.parent.Unsubscribe(SHAPES_SELECTED, self.select_shapes)  
         QueryTableFrame.OnClose(self, event)  
   
622      def select_shapes(self, layer, shapes):      def select_shapes(self, layer, shapes):
623          """Subscribed to the SHAPES_SELECTED message.          """Subscribed to the SHAPES_SELECTED message.
624    
# Line 469  class LayerTableFrame(QueryTableFrame): Line 633  class LayerTableFrame(QueryTableFrame):
633          """          """
634          if self.layer is not None:          if self.layer is not None:
635              self.parent.SelectShapes(self.layer, rows)              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    

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26