/[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 30 by bh, Thu Sep 6 13:31:57 2001 UTC revision 881 by jonathan, Fri May 9 16:34:15 2003 UTC
# Line 1  Line 1 
1  # Copyright (c) 2001 by Intevation GmbH  # Copyright (c) 2001, 2002, 2003 by Intevation GmbH
2  # Authors:  # Authors:
3  # Bernhard Herzog <[email protected]>  # Bernhard Herzog <[email protected]>
4  #  #
# Line 7  Line 7 
7    
8  __version__ = "$Revision$"  __version__ = "$Revision$"
9    
10    from Thuban import _
11    
12  from wxPython.wx import *  from wxPython.wx import *
13  from wxPython.grid import *  from wxPython.grid import *
14    
15    from Thuban.Lib.connector import Publisher
16  from Thuban.Model.table import FIELDTYPE_INT, FIELDTYPE_DOUBLE, \  from Thuban.Model.table import FIELDTYPE_INT, FIELDTYPE_DOUBLE, \
17       FIELDTYPE_STRING       FIELDTYPE_STRING
18  import view  import view
19  from dialogs import NonModalDialog  from dialogs import NonModalDialog
20  from messages import SELECTED_SHAPE  from messages import SHAPES_SELECTED
21    
22  wx_value_type_map = {FIELDTYPE_INT: wxGRID_VALUE_NUMBER,  wx_value_type_map = {FIELDTYPE_INT: wxGRID_VALUE_NUMBER,
23                       FIELDTYPE_DOUBLE: wxGRID_VALUE_FLOAT,                       FIELDTYPE_DOUBLE: wxGRID_VALUE_FLOAT,
24                       FIELDTYPE_STRING: wxGRID_VALUE_STRING}                       FIELDTYPE_STRING: wxGRID_VALUE_STRING}
25    
26    ROW_SELECTED = "ROW_SELECTED"
27    
28    
29  class DataTable(wxPyGridTableBase):  class DataTable(wxPyGridTableBase):
30    
31        """Wrapper around a Thuban table object suitable for a wxGrid"""
32    
33      def __init__(self, table = None):      def __init__(self, table = None):
34          wxPyGridTableBase.__init__(self)          wxPyGridTableBase.__init__(self)
35          self.num_cols = 0          self.num_cols = 0
# Line 32  class DataTable(wxPyGridTableBase): Line 40  class DataTable(wxPyGridTableBase):
40    
41      def SetTable(self, table):      def SetTable(self, table):
42          self.table = table          self.table = table
43          self.num_cols = table.field_count()          self.num_cols = table.NumColumns()
44          self.num_rows = table.record_count()          self.num_rows = table.NumRows()
45    
46          self.columns = []          self.columns = []
47          for i in range(self.num_cols):          for i in range(self.num_cols):
48              type, name, len, decc = table.field_info(i)              col = table.Column(i)
49              self.columns.append((name, wx_value_type_map[type], len, decc))              self.columns.append((col.name, wx_value_type_map[col.type]))
50    
51      #      #
52      # required methods for the wxPyGridTableBase interface      # required methods for the wxPyGridTableBase interface
# Line 58  class DataTable(wxPyGridTableBase): Line 66  class DataTable(wxPyGridTableBase):
66      # Renderer understands the type too,) not just strings as in the      # Renderer understands the type too,) not just strings as in the
67      # C++ version.      # C++ version.
68      def GetValue(self, row, col):      def GetValue(self, row, col):
69          record = self.table.read_record(row)          record = self.table.ReadRowAsDict(row)
70          return record[self.columns[col][0]]          return record[self.columns[col][0]]
71    
72      def SetValue(self, row, col, value):      def SetValue(self, row, col, value):
# Line 89  class DataTable(wxPyGridTableBase): Line 97  class DataTable(wxPyGridTableBase):
97          return self.CanGetValueAs(row, col, typeName)          return self.CanGetValueAs(row, col, typeName)
98    
99    
100      # Thuban stuff  class TableGrid(wxGrid, Publisher):
     def SelectRow(self, row):  
         import main  
         interactor = main.app.interactor  
         return interactor.SelectShape(self.table, row)  
101    
102        """A grid view for a Thuban table
103    
104  class TableGrid(wxGrid):      When rows are selected by the user the table issues ROW_SELECTED
105        messages. wx sends selection events even when the selection is
106        manipulated by code (instead of by the user) which usually lead to
107        ROW_SELECTED messages being sent in turn. Therefore sending messages
108        can be switched on and off with the allow_messages and
109        disallow_messages methods.
110        """
111    
112      def __init__(self, parent, table = None):      def __init__(self, parent, table = None):
113          wxGrid.__init__(self, parent, -1)          wxGrid.__init__(self, parent, -1)
114    
115            self.allow_messages_count = 0
116    
117          self.table = DataTable(table)          self.table = DataTable(table)
118    
119          # The second parameter means that the grid is to take ownership          # The second parameter means that the grid is to take ownership
120          # of the table and will destroy it when done. Otherwise you          # of the table and will destroy it when done. Otherwise you
121          # would need to keep a reference to it and call it's Destroy          # would need to keep a reference to it and call its Destroy
122          # method later.          # method later.
123          self.SetTable(self.table, true)          self.SetTable(self.table, true)
124    
125          #self.SetMargins(0,0)          #self.SetMargins(0,0)
126          self.AutoSizeColumns(false)  
127            # AutoSizeColumns would allow us to make the grid have optimal
128            # column widths automatically but it would cause a traversal of
129            # the entire table which for large .dbf files can take a very
130            # long time.
131            #self.AutoSizeColumns(false)
132    
133          self.SetSelectionMode(wxGrid.wxGridSelectRows)          self.SetSelectionMode(wxGrid.wxGridSelectRows)
134            
135          EVT_GRID_RANGE_SELECT(self, self.OnRangeSelect)          EVT_GRID_RANGE_SELECT(self, self.OnRangeSelect)
136          EVT_GRID_SELECT_CELL(self, self.OnSelectCell)          EVT_GRID_SELECT_CELL(self, self.OnSelectCell)
137    
# Line 121  class TableGrid(wxGrid): Line 139  class TableGrid(wxGrid):
139          self.table.SetTable(table)          self.table.SetTable(table)
140    
141      def OnRangeSelect(self, event):      def OnRangeSelect(self, event):
142            rows = dict([(i, 0) for i in self.GetSelectedRows()])
143    
144            # if we're selecting we need to include the selected range and
145            # make sure that the current row is also included, which may
146            # not be the case if you just click on a single row!
147          if event.Selecting():          if event.Selecting():
148              if not self.table.SelectRow(event.GetTopLeftCoords().GetRow()):              for i in range(event.GetTopRow(), event.GetBottomRow() + 1):
149                  event.Skip()                  rows[i] = 0
150                rows[event.GetTopLeftCoords().GetRow()] = 0
151    
152            self.issue(ROW_SELECTED, rows.keys())
153            event.Skip()
154    
155      def OnSelectCell(self, event):      def OnSelectCell(self, event):
156          if not self.table.SelectRow(event.GetRow()):          self.issue(ROW_SELECTED, self.GetSelectedRows())
157              event.Skip()          event.Skip()
158    
159        def disallow_messages(self):
160            """Disallow messages to be send.
161    
162      def select_shape(self, layer, shape):          This method only increases a counter so that calls to
163          if layer is not None and layer.table is self.table.table \          disallow_messages and allow_messages can be nested. Only the
164             and shape is not None:          outermost calls will actually switch message sending on and off.
165              self.SelectRow(shape)          """
166              self.SetGridCursor(shape, 0)          self.allow_messages_count += 1
167              self.MakeCellVisible(shape, 0)  
168        def allow_messages(self):
169            """Allow messages to be send.
170    
171            This method only decreases a counter so that calls to
172            disallow_messages and allow_messages can be nested. Only the
173            outermost calls will actually switch message sending on and off.
174            """
175            self.allow_messages_count -= 1
176    
177        def issue(self, *args):
178            """Issue a message unless disallowed.
179    
180            See the allow_messages and disallow_messages methods.
181            """
182            if self.allow_messages_count == 0:
183                Publisher.issue(self, *args)
184    
185    
186    class LayerTableGrid(TableGrid):
187    
188        """Table grid for the layer tables.
189    
190        The LayerTableGrid is basically the same as a TableGrid but it's
191        selection is usually coupled to the selected object in the map.
192        """
193    
194        def select_shapes(self, layer, shapes):
195            """Select the row corresponding to the specified shape and layer
196    
197            If layer is not the layer the table is associated with do
198            nothing. If shape or layer is None also do nothing.
199            """
200            if layer is not None \
201                and layer.table is self.table.table:
202    
203                self.disallow_messages()
204                try:
205                    self.ClearSelection()
206                    if len(shapes) > 0:
207                        #
208                        # keep track of the lowest id so we can make it
209                        # the first visible item
210                        #
211                        first = shapes[0]
212    
213                        for shape in shapes:
214                            self.SelectRow(shape, True)
215                            if shape < first:
216                                first = shape
217    
218                        self.SetGridCursor(first, 0)
219                        self.MakeCellVisible(first, 0)
220                finally:
221                    self.allow_messages()
222    
223    
224  class TableFrame(NonModalDialog):  class TableFrame(NonModalDialog):
225    
226      def __init__(self, parent, interactor, name, title, table = None):      """Frame that displays a Thuban table in a grid view"""
227          NonModalDialog.__init__(self, parent, interactor, name, title)  
228          self.grid = TableGrid(self, table)      def __init__(self, parent, name, title, table):
229          self.interactor.Subscribe(SELECTED_SHAPE, self.select_shape)          NonModalDialog.__init__(self, parent, name, title)
230            self.table = table
231            self.grid = self.make_grid(self.table)
232    
233        def make_grid(self, table):
234            """Return the table grid to use in the frame.
235    
236            The default implementation returns a TableGrid instance.
237            Override in derived classes to use different grid classes.
238            """
239            return TableGrid(self, table)
240    
241    
242    ID_QUERY = 4001
243    ID_SAVEAS = 4002
244    
245    class LayerTableFrame(TableFrame):
246    
247        """Frame that displays a layer table in a grid view
248    
249        A LayerTableFrame is TableFrame whose selection is connected to the
250        selected object in a map.
251        """
252    
253        def __init__(self, parent, name, title, layer, table):
254            TableFrame.__init__(self, parent, name, title, table)
255            self.layer = layer
256            self.grid.Subscribe(ROW_SELECTED, self.rows_selected)
257            self.parent.Subscribe(SHAPES_SELECTED, self.select_shapes)
258    
259            self.combo_fields = wxComboBox(self, -1, style=wxCB_READONLY)
260            self.choice_comp = wxChoice(self, -1,
261                                  choices=["<", "<=", "=", "<>", ">=", ">"])
262            self.combo_value = wxComboBox(self, -1)
263            self.choice_action = wxChoice(self, -1,
264                                    choices=[_("Replace Selection"),
265                                            _("Refine Selection"),
266                                            _("Add to Selection")])
267    
268            button_query = wxButton(self, ID_QUERY, _("Query"))
269            button_saveas = wxButton(self, ID_SAVEAS, _("Save As..."))
270    
271            self.grid.SetSize((400, 200))
272    
273            self.combo_value.Append("")
274            for i in range(table.field_count()):
275                type, name, len, decc = layer.table.field_info(i)
276                self.combo_fields.Append(name)
277                self.combo_value.Append(name)
278                                                                                    
279            # assume at least one field?
280            self.combo_fields.SetSelection(0)
281            self.combo_value.SetSelection(0)
282    
283            topBox = wxBoxSizer(wxVERTICAL)
284    
285            sizer = wxStaticBoxSizer(wxStaticBox(self, -1, _("Selections")),
286                                      wxHORIZONTAL)
287            sizer.Add(self.combo_fields, 1, wxEXPAND|wxALL, 4)
288            sizer.Add(self.choice_comp, 0, wxALL, 4)
289            sizer.Add(self.combo_value, 1, wxEXPAND|wxALL, 4)
290            sizer.Add(self.choice_action, 0, wxALL, 4)
291            sizer.Add(button_query, 0, wxALL, 4)
292            sizer.Add(40, 20, 0, wxALL, 4)
293            sizer.Add(button_saveas, 0, wxALL, 4)
294    
295            topBox.Add(sizer, 0, wxEXPAND|wxALL, 4)
296            topBox.Add(self.grid, 1, wxEXPAND|wxALL, 0)
297    
298            self.SetAutoLayout(True)
299            self.SetSizer(topBox)
300            topBox.Fit(self)
301            topBox.SetSizeHints(self)
302    
303            EVT_BUTTON(self, ID_QUERY, self.OnQuery)
304            EVT_BUTTON(self, ID_SAVEAS, self.OnSaveAs)
305    
306        def OnQuery(self, event):
307            wxBeginBusyCursor()
308    
309            if self.combo_value.GetSelection() < 1:
310                value = self.combo_value.GetValue()
311                print value
312            else:
313                value = self.table.Column(self.combo_value.GetValue())
314    
315            #ids = self.table.Query(
316                    #self.table.Column(self.combo_fields.GetStringSelection()),
317                    #self.choice_comp.GetStringSelection(),
318                    #value)
319    
320            choice = self.choice_action.GetSelection()
321                
322            if choice == 0:
323                ids = [1, 2, 3, 4, 5]
324                # Replace Selection
325                self.grid.ClearSelection()
326                for id in ids:
327                    self.grid.SelectRow(id, True)
328            elif choice == 1:
329                ids = [1, 3, 5]
330                # Refine Selection
331                sel = dict([(i, 0) for i in self.parent.SelectedShapes()])
332                self.grid.ClearSelection()
333                for id in filter(sel.has_key, ids):
334                    self.grid.SelectRow(id, True)
335            elif choice == 2:
336                ids = [2, 4]
337                # Add to Selection
338                for id in ids:
339                    self.grid.SelectRow(id, True)
340    
341            wxEndBusyCursor()
342            
343        def OnSaveAs(self, event):
344            dlg = wxFileDialog(self, _("Save Table As"), ".", "",
345                               "DBF Files (*.dbf)|*.dbf|" +
346                               "CSV Files (*.csv)|*.csv|" +
347                               "All Files (*.*)|*.*",
348                               wxSAVE|wxOVERWRITE_PROMPT)
349            if dlg.ShowModal() == wxID_OK:
350                pass
351                                                                                    
352            dlg.Destroy()
353    
354        def make_grid(self, table):
355            """Override the derived method to return a LayerTableGrid.
356            """
357            return LayerTableGrid(self, table)
358    
359      def OnClose(self, event):      def OnClose(self, event):
360          self.interactor.Unsubscribe(SELECTED_SHAPE, self.select_shape)          self.parent.Unsubscribe(SHAPES_SELECTED, self.select_shapes)
361          NonModalDialog.OnClose(self, event)          TableFrame.OnClose(self, event)
362    
363        def select_shapes(self, layer, shapes):
364            """Subscribed to the SHAPES_SELECTED message.
365    
366      def select_shape(self, layer, shape):          If shapes contains exactly one shape id, select that shape in
367          self.grid.select_shape(layer, shape)          the grid. Otherwise deselect all.
368            """
369            self.grid.select_shapes(layer, shapes)
370    
371        def rows_selected(self, rows):
372            if self.layer is not None:
373                self.parent.SelectShapes(self.layer, rows)

Legend:
Removed from v.30  
changed lines
  Added in v.881

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26