/[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 1092 by bh, Wed May 28 17:10:04 2003 UTC revision 1394 by jonathan, Thu Jul 10 14:54:58 2003 UTC
# Line 17  from wxPython.grid import * Line 17  from wxPython.grid import *
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
 from dialogs import NonModalNonParentDialog  
21    
22  from messages import SHAPES_SELECTED, SESSION_REPLACED  from messages import SHAPES_SELECTED, SESSION_REPLACED
23  from Thuban.Model.messages import TABLE_REMOVED  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 150  class TableGrid(wxGrid, Publisher): Line 150  class TableGrid(wxGrid, Publisher):
150    
151          self.allow_messages_count = 0          self.allow_messages_count = 0
152    
153            # keep track of which rows are selected.
154            self.rows = {}
155    
156          self.table = DataTable(table)          self.table = DataTable(table)
157    
158          # The second parameter means that the grid is to take ownership          # The second parameter means that the grid is to take ownership
# Line 169  class TableGrid(wxGrid, Publisher): Line 172  class TableGrid(wxGrid, Publisher):
172          self.SetSelectionMode(wxGrid.wxGridSelectRows)          self.SetSelectionMode(wxGrid.wxGridSelectRows)
173    
174          self.ToggleEventListeners(True)          self.ToggleEventListeners(True)
175            EVT_GRID_RANGE_SELECT(self, self.OnRangeSelect)
176            EVT_GRID_SELECT_CELL(self, self.OnSelectCell)
177    
178          # Replace the normal renderers with our own versions which          # Replace the normal renderers with our own versions which
179          # render NULL/None values specially          # render NULL/None values specially
# Line 183  class TableGrid(wxGrid, Publisher): Line 188  class TableGrid(wxGrid, Publisher):
188          self.table.SetTable(table)          self.table.SetTable(table)
189    
190      def OnRangeSelect(self, event):      def OnRangeSelect(self, event):
191          rows = dict([(i, 0) for i in self.GetSelectedRows()])          if self.handleSelectEvents:
192                self.rows = dict([(i, 0) for i in self.GetSelectedRows()])
193    
194          # if we're selecting we need to include the selected range and              # if we're selecting we need to include the selected range and
195          # make sure that the current row is also included, which may              # make sure that the current row is also included, which may
196          # not be the case if you just click on a single row!              # not be the case if you just click on a single row!
197          if event.Selecting():              if event.Selecting():
198              for i in range(event.GetTopRow(), event.GetBottomRow() + 1):                  for i in range(event.GetTopRow(), event.GetBottomRow() + 1):
199                  rows[i] = 0                      self.rows[i] = 0
200              rows[event.GetTopLeftCoords().GetRow()] = 0                  self.rows[event.GetTopLeftCoords().GetRow()] = 0
201        
202                self.issue(ROW_SELECTED, self.rows.keys())
203    
         self.issue(ROW_SELECTED, rows.keys())  
204          event.Skip()          event.Skip()
205    
206      def OnSelectCell(self, event):      def OnSelectCell(self, event):
207          self.issue(ROW_SELECTED, self.GetSelectedRows())          if self.handleSelectEvents:
208                self.issue(ROW_SELECTED, self.GetSelectedRows())
209          event.Skip()          event.Skip()
210    
211      def ToggleEventListeners(self, on):      def ToggleEventListeners(self, on):
212          if on:          self.handleSelectEvents = on
             EVT_GRID_RANGE_SELECT(self, self.OnRangeSelect)  
             EVT_GRID_SELECT_CELL(self, self.OnSelectCell)  
         else:  
             EVT_GRID_RANGE_SELECT(self, None)  
             EVT_GRID_SELECT_CELL(self, None)  
213                            
214        def GetNumberSelected(self):
215            return len(self.rows)
216    
217      def disallow_messages(self):      def disallow_messages(self):
218          """Disallow messages to be send.          """Disallow messages to be send.
219    
# Line 250  class LayerTableGrid(TableGrid): Line 256  class LayerTableGrid(TableGrid):
256          nothing. If shape or layer is None also do nothing.          nothing. If shape or layer is None also do nothing.
257          """          """
258          if layer is not None \          if layer is not None \
259              and layer.table is self.table.table:              and layer.ShapeStore().Table() is self.table.table:
260    
261              self.disallow_messages()              self.disallow_messages()
262              try:              try:
# Line 273  class LayerTableGrid(TableGrid): Line 279  class LayerTableGrid(TableGrid):
279                  self.allow_messages()                  self.allow_messages()
280    
281    
282  class TableFrame(NonModalNonParentDialog):  class TableFrame(ThubanFrame):
283    
284      """Frame that displays a Thuban table in a grid view"""      """Frame that displays a Thuban table in a grid view"""
285    
286      def __init__(self, parent, name, title, table):      def __init__(self, parent, name, title, table):
287          NonModalNonParentDialog.__init__(self, parent, name, title)          ThubanFrame.__init__(self, parent, name, title)
288            self.panel = wxPanel(self, -1)
289    
290          self.table = table          self.table = table
291          self.grid = self.make_grid(self.table)          self.grid = self.make_grid(self.table)
292          self.app = self.parent.application          self.app = self.parent.application
# Line 286  class TableFrame(NonModalNonParentDialog Line 294  class TableFrame(NonModalNonParentDialog
294          self.session = self.app.Session()          self.session = self.app.Session()
295          self.session.Subscribe(TABLE_REMOVED, self.close_on_table_removed)          self.session.Subscribe(TABLE_REMOVED, self.close_on_table_removed)
296    
297    
298      def make_grid(self, table):      def make_grid(self, table):
299          """Return the table grid to use in the frame.          """Return the table grid to use in the frame.
300    
# Line 297  class TableFrame(NonModalNonParentDialog Line 306  class TableFrame(NonModalNonParentDialog
306      def OnClose(self, event):      def OnClose(self, event):
307          self.app.Unsubscribe(SESSION_REPLACED, self.close_on_session_replaced)          self.app.Unsubscribe(SESSION_REPLACED, self.close_on_session_replaced)
308          self.session.Unsubscribe(TABLE_REMOVED, self.close_on_table_removed)          self.session.Unsubscribe(TABLE_REMOVED, self.close_on_table_removed)
309          NonModalNonParentDialog.OnClose(self, event)          ThubanFrame.OnClose(self, event)
310    
311      def close_on_session_replaced(self, *args):      def close_on_session_replaced(self, *args):
312          """Subscriber for the SESSION_REPLACED messages.          """Subscriber for the SESSION_REPLACED messages.
# Line 319  class TableFrame(NonModalNonParentDialog Line 328  class TableFrame(NonModalNonParentDialog
328    
329  ID_QUERY = 4001  ID_QUERY = 4001
330  ID_EXPORT = 4002  ID_EXPORT = 4002
331    ID_COMBOVALUE = 4003
332    ID_EXPORTSEL = 4004
333    
334  class QueryTableFrame(TableFrame):  class QueryTableFrame(TableFrame):
335    
336      """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
337      selection and export      selection and export
338    
339      A LayerTableFrame is TableFrame whose selection is connected to the      A QueryTableFrame is TableFrame whose selection is connected to the
340      selected object in a map.      selected object in a map.
341      """      """
342    
343      def __init__(self, parent, name, title, table):      def __init__(self, parent, name, title, table):
344          TableFrame.__init__(self, parent, name, title, table)          TableFrame.__init__(self, parent, name, title, table)
345    
346          self.combo_fields = wxComboBox(self, -1, style=wxCB_READONLY)          self.combo_fields = wxComboBox(self.panel, -1, style=wxCB_READONLY)
347          self.choice_comp = wxChoice(self, -1,          self.choice_comp = wxChoice(self.panel, -1,
348                                choices=["<", "<=", "==", "!=", ">=", ">"])                                choices=["<", "<=", "==", "!=", ">=", ">"])
349          self.combo_value = wxComboBox(self, -1)          self.combo_value = wxComboBox(self.panel, ID_COMBOVALUE)
350          self.choice_action = wxChoice(self, -1,          self.choice_action = wxChoice(self.panel, -1,
351                                  choices=[_("Replace Selection"),                                  choices=[_("Replace Selection"),
352                                          _("Refine Selection"),                                          _("Refine Selection"),
353                                          _("Add to Selection")])                                          _("Add to Selection")])
354    
355          button_query = wxButton(self, ID_QUERY, _("Query"))          button_query = wxButton(self.panel, ID_QUERY, _("Query"))
356          button_saveas = wxButton(self, ID_EXPORT, _("Export"))          button_export = wxButton(self.panel, ID_EXPORT, _("Export"))
357            button_exportSel = wxButton(self.panel, ID_EXPORTSEL, _("Export Selection"))
358            button_close = wxButton(self.panel, wxID_CLOSE, _("Close"))
359    
360            self.CreateStatusBar()
361    
362          self.grid.SetSize((400, 200))          self.grid.SetSize((400, 200))
363    
# Line 355  class QueryTableFrame(TableFrame): Line 370  class QueryTableFrame(TableFrame):
370          # assume at least one field?          # assume at least one field?
371          self.combo_fields.SetSelection(0)          self.combo_fields.SetSelection(0)
372          self.combo_value.SetSelection(0)          self.combo_value.SetSelection(0)
373            self.choice_action.SetSelection(0)
374            self.choice_comp.SetSelection(0)
375    
376            self.grid.Reparent(self.panel)
377    
378            self.UpdateStatusText()
379    
380          topBox = wxBoxSizer(wxVERTICAL)          topBox = wxBoxSizer(wxVERTICAL)
381    
382          sizer = wxStaticBoxSizer(wxStaticBox(self, -1,          sizer = wxStaticBoxSizer(wxStaticBox(self.panel, -1,
383                                    _("Selection")),                                    _("Selection")),
384                                    wxHORIZONTAL)                                    wxHORIZONTAL)
385          sizer.Add(self.combo_fields, 1, wxEXPAND|wxALL, 4)          sizer.Add(self.combo_fields, 1, wxEXPAND|wxALL, 4)
# Line 367  class QueryTableFrame(TableFrame): Line 388  class QueryTableFrame(TableFrame):
388          sizer.Add(self.choice_action, 0, wxALL, 4)          sizer.Add(self.choice_action, 0, wxALL, 4)
389          sizer.Add(button_query, 0, wxALL | wxALIGN_CENTER_VERTICAL, 4)          sizer.Add(button_query, 0, wxALL | wxALIGN_CENTER_VERTICAL, 4)
390          sizer.Add(40, 20, 0, wxALL, 4)          sizer.Add(40, 20, 0, wxALL, 4)
         sizer.Add(button_saveas, 0, wxALL | wxALIGN_CENTER_VERTICAL, 4)  
391    
392          topBox.Add(sizer, 0, wxEXPAND|wxALL, 4)          topBox.Add(sizer, 0, wxEXPAND|wxALL, 4)
393          topBox.Add(self.grid, 1, wxEXPAND|wxALL, 0)          topBox.Add(self.grid, 1, wxEXPAND|wxALL, 0)
394    
395            sizer = wxBoxSizer(wxHORIZONTAL)
396            sizer.Add(button_export, 0, wxALL, 4)
397            sizer.Add(button_exportSel, 0, wxALL, 4)
398            sizer.Add(60, 20, 1, wxALL|wxEXPAND, 4)
399            sizer.Add(button_close, 0, wxALL|wxALIGN_RIGHT, 4)
400            topBox.Add(sizer, 0, wxALL | wxEXPAND, 4)
401    
402            self.panel.SetAutoLayout(True)
403            self.panel.SetSizer(topBox)
404            topBox.Fit(self.panel)
405            topBox.SetSizeHints(self.panel)
406    
407            panelSizer = wxBoxSizer(wxVERTICAL)
408            panelSizer.Add(self.panel, 1, wxEXPAND, 0)
409          self.SetAutoLayout(True)          self.SetAutoLayout(True)
410          self.SetSizer(topBox)          self.SetSizer(panelSizer)
411          topBox.Fit(self)          panelSizer.Fit(self)
412          topBox.SetSizeHints(self)          panelSizer.SetSizeHints(self)
413    
414          self.grid.SetFocus()          self.grid.SetFocus()
415    
416          EVT_BUTTON(self, ID_QUERY, self.OnQuery)          EVT_BUTTON(self, ID_QUERY, self.OnQuery)
417          EVT_BUTTON(self, ID_EXPORT, self.OnSaveAs)          EVT_BUTTON(self, ID_EXPORT, self.OnExport)
418            EVT_BUTTON(self, ID_EXPORTSEL, self.OnExportSel)
419            EVT_BUTTON(self, wxID_CLOSE, self.OnClose)
420          EVT_KEY_DOWN(self.grid, self.OnKeyDown)          EVT_KEY_DOWN(self.grid, self.OnKeyDown)
421    
422            self.grid.Subscribe(ROW_SELECTED, self.UpdateStatusText)
423    
424        def UpdateStatusText(self, rows=None):
425            self.SetStatusText(_("%i rows (%i selected), %i columns")
426                % (self.grid.GetNumberRows(),
427                   self.grid.GetNumberSelected(),
428                   self.grid.GetNumberCols()))
429    
430      def OnKeyDown(self, event):      def OnKeyDown(self, event):
431          """Catch query key from grid"""          """Catch query key from grid"""
432          if event.AltDown() and event.GetKeyCode() == ord(QUERY_KEY):          if event.AltDown() and event.GetKeyCode() == ord(QUERY_KEY):
# Line 390  class QueryTableFrame(TableFrame): Line 435  class QueryTableFrame(TableFrame):
435          else:          else:
436              event.Skip()              event.Skip()
437    
   
438      def OnQuery(self, event):      def OnQuery(self, event):
439          wxBeginBusyCursor()          ThubanBeginBusyCursor()
440            try:
         if self.combo_value.GetSelection() < 1:  
             value = self.combo_value.GetValue()  
         else:  
             value = self.table.Column(self.combo_value.GetValue())  
441    
442          ids = self.table.SimpleQuery(              text = self.combo_value.GetValue()
443                  self.table.Column(self.combo_fields.GetStringSelection()),              if self.combo_value.GetSelection() < 1 \
444                  self.choice_comp.GetStringSelection(),                  or self.combo_value.FindString(text) == -1:
445                  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  
446              else:              else:
447                  self.grid.SelectRow(id, True)                  value = self.table.Column(text)
448    
449          self.grid.ToggleEventListeners(True)              ids = self.table.SimpleQuery(
450                        self.table.Column(self.combo_fields.GetStringSelection()),
451                        self.choice_comp.GetStringSelection(),
452                        value)
453    
454          #              choice = self.choice_action.GetSelection()
455          # select the first row              
456          #              #
457          if ids:              # what used to be nice code got became a bit ugly because
458              self.grid.SelectRow(ids[0], True)              # each time we select a row a message is sent to the grid
459                # which we are listening for and then we send further
460                # messages.
461                #
462                # now, we disable those listeners select everything but
463                # the first item, reenable the listeners, and select
464                # the first element, which causes everything to be
465                # updated properly.
466                #
467                if ids:
468                    self.grid.ToggleEventListeners(False)
469    
470                if choice == 0:
471                    # Replace Selection
472                    self.grid.ClearSelection()
473                elif choice == 1:
474                    # Refine Selection
475                    sel = self.get_selected()
476                    self.grid.ClearSelection()
477                    ids = filter(sel.has_key, ids)
478                elif choice == 2:
479                    # Add to Selection
480                    pass
481    
482                #
483                # select the rows (all but the first)
484                #
485                firsttime = True
486                for id in ids:
487                    if firsttime:
488                        firsttime = False
489                    else:
490                        self.grid.SelectRow(id, True)
491    
492                self.grid.ToggleEventListeners(True)
493    
494                #
495                # select the first row
496                #
497                if ids:
498                    self.grid.SelectRow(ids[0], True)
499    
500          wxEndBusyCursor()          finally:
501                ThubanEndBusyCursor()
502            
503        def doExport(self, onlySelected):
504                    
     def OnSaveAs(self, event):  
505          dlg = wxFileDialog(self, _("Export Table To"), ".", "",          dlg = wxFileDialog(self, _("Export Table To"), ".", "",
506                             _("DBF Files (*.dbf)|*.dbf|") +                             _("DBF Files (*.dbf)|*.dbf|") +
507                             _("CSV Files (*.csv)|*.csv|") +                             _("CSV Files (*.csv)|*.csv|") +
# Line 461  class QueryTableFrame(TableFrame): Line 511  class QueryTableFrame(TableFrame):
511              filename = dlg.GetPath()              filename = dlg.GetPath()
512              type = os.path.basename(filename).split('.')[-1:][0]              type = os.path.basename(filename).split('.')[-1:][0]
513              dlg.Destroy()              dlg.Destroy()
514    
515                if onlySelected:
516                    records = self.grid.GetSelectedRows()
517                else:
518                    records = None
519    
520              if type.upper() == "DBF":              if type.upper() == "DBF":
521                  table_to_dbf(self.table, filename)                  table_to_dbf(self.table, filename, records)
522              elif type.upper() == 'CSV':              elif type.upper() == 'CSV':
523                  table_to_csv(self.table, filename)                  table_to_csv(self.table, filename, records)
524              else:              else:
525                  dlg = wxMessageDialog(None, "Unsupported format: %s" % type,                  dlg = wxMessageDialog(None, "Unsupported format: %s" % type,
526                                        "Table Export", wxOK|wxICON_WARNING)                                        "Table Export", wxOK|wxICON_WARNING)
# Line 473  class QueryTableFrame(TableFrame): Line 529  class QueryTableFrame(TableFrame):
529          else:          else:
530              dlg.Destroy()              dlg.Destroy()
531    
532        def OnExport(self, event):
533            self.doExport(False)
534    
535        def OnExportSel(self, event):
536            self.doExport(True)
537    
538      def OnClose(self, event):      def OnClose(self, event):
539          TableFrame.OnClose(self, event)          TableFrame.OnClose(self, event)
540    
541      def get_selected(self):      def get_selected(self):
542          """Return a dictionary of the selected rows.          """Return a dictionary of the selected rows.
543                    
544          The dictionary has sthe indexes as keys."""          The dictionary has the indexes as keys."""
545          return dict([(i, 0) for i in self.grid.GetSelectedRows()])          return dict([(i, 0) for i in self.grid.GetSelectedRows()])
546    
547  class LayerTableFrame(QueryTableFrame):  class LayerTableFrame(QueryTableFrame):
# Line 495  class LayerTableFrame(QueryTableFrame): Line 557  class LayerTableFrame(QueryTableFrame):
557          self.layer = layer          self.layer = layer
558          self.grid.Subscribe(ROW_SELECTED, self.rows_selected)          self.grid.Subscribe(ROW_SELECTED, self.rows_selected)
559          self.parent.Subscribe(SHAPES_SELECTED, self.select_shapes)          self.parent.Subscribe(SHAPES_SELECTED, self.select_shapes)
560            self.map = self.parent.Map()
561            self.map.Subscribe(MAP_LAYERS_REMOVED, self.map_layers_removed)
562    
563          # if there is already a selection present, update the grid          # if there is already a selection present, update the grid
564          # accordingly          # accordingly
# Line 516  class LayerTableFrame(QueryTableFrame): Line 580  class LayerTableFrame(QueryTableFrame):
580      def OnClose(self, event):      def OnClose(self, event):
581          """Override the derived method to first unsubscribed."""          """Override the derived method to first unsubscribed."""
582          self.parent.Unsubscribe(SHAPES_SELECTED, self.select_shapes)          self.parent.Unsubscribe(SHAPES_SELECTED, self.select_shapes)
583            self.grid.Unsubscribe(ROW_SELECTED, self.rows_selected)
584            self.map.Unsubscribe(MAP_LAYERS_REMOVED, self.map_layers_removed)
585          QueryTableFrame.OnClose(self, event)          QueryTableFrame.OnClose(self, event)
586    
587      def select_shapes(self, layer, shapes):      def select_shapes(self, layer, shapes):
# Line 532  class LayerTableFrame(QueryTableFrame): Line 598  class LayerTableFrame(QueryTableFrame):
598          """          """
599          if self.layer is not None:          if self.layer is not None:
600              self.parent.SelectShapes(self.layer, rows)              self.parent.SelectShapes(self.layer, rows)
601    
602        def map_layers_removed(self, *args):
603            """Receiver for the map's MAP_LAYERS_REMOVED message
604    
605            Close the dialog if the layer whose table we're showing is not
606            in the map anymore.
607            """
608            if self.layer not in self.map.Layers():
609                self.Close()
610    

Legend:
Removed from v.1092  
changed lines
  Added in v.1394

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26