/[thuban]/branches/WIP-pyshapelib-bramz/Thuban/UI/tableview.py
ViewVC logotype

Annotation of /branches/WIP-pyshapelib-bramz/Thuban/UI/tableview.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 881 - (hide annotations)
Fri May 9 16:34:15 2003 UTC (21 years, 10 months ago) by jonathan
Original Path: trunk/thuban/Thuban/UI/tableview.py
File MIME type: text/x-python
File size: 12451 byte(s)
(TableGrid.OnRangeSelect): Fix some issues
        with correctly selecting the rows and issuing the right events.
        Be sure to call Skip() to allow the grid to do some of its own
        handling which allows the rows to actually be selected.
(LayerTableGrid.select_shapes): Rename from select_shape. Supports
        selecting multiple shapes.
(LayerTableFrame): Support for building Queries.
(LayerTableFrame.select_shapes): Allow multiple shapes to be selected.

1 bh 535 # Copyright (c) 2001, 2002, 2003 by Intevation GmbH
2 bh 6 # Authors:
3     # Bernhard Herzog <[email protected]>
4     #
5     # This program is free software under the GPL (>=v2)
6     # Read the file COPYING coming with Thuban for details.
7    
8     __version__ = "$Revision$"
9    
10 jonathan 881 from Thuban import _
11    
12 bh 6 from wxPython.wx import *
13     from wxPython.grid import *
14    
15 bh 34 from Thuban.Lib.connector import Publisher
16 bh 6 from Thuban.Model.table import FIELDTYPE_INT, FIELDTYPE_DOUBLE, \
17     FIELDTYPE_STRING
18     import view
19 bh 30 from dialogs import NonModalDialog
20 bh 535 from messages import SHAPES_SELECTED
21 bh 6
22     wx_value_type_map = {FIELDTYPE_INT: wxGRID_VALUE_NUMBER,
23     FIELDTYPE_DOUBLE: wxGRID_VALUE_FLOAT,
24     FIELDTYPE_STRING: wxGRID_VALUE_STRING}
25    
26 bh 34 ROW_SELECTED = "ROW_SELECTED"
27    
28    
29 bh 6 class DataTable(wxPyGridTableBase):
30    
31 bh 34 """Wrapper around a Thuban table object suitable for a wxGrid"""
32    
33 bh 6 def __init__(self, table = None):
34     wxPyGridTableBase.__init__(self)
35     self.num_cols = 0
36     self.num_rows = 0
37     self.columns = []
38     self.table = None
39     self.SetTable(table)
40    
41     def SetTable(self, table):
42     self.table = table
43 bh 838 self.num_cols = table.NumColumns()
44     self.num_rows = table.NumRows()
45 bh 6
46     self.columns = []
47     for i in range(self.num_cols):
48 bh 838 col = table.Column(i)
49     self.columns.append((col.name, wx_value_type_map[col.type]))
50 bh 6
51     #
52     # required methods for the wxPyGridTableBase interface
53     #
54    
55     def GetNumberRows(self):
56     return self.num_rows
57    
58     def GetNumberCols(self):
59     return self.num_cols
60    
61     def IsEmptyCell(self, row, col):
62     return 0
63    
64     # Get/Set values in the table. The Python version of these
65     # methods can handle any data-type, (as long as the Editor and
66     # Renderer understands the type too,) not just strings as in the
67     # C++ version.
68     def GetValue(self, row, col):
69 bh 838 record = self.table.ReadRowAsDict(row)
70 bh 6 return record[self.columns[col][0]]
71    
72     def SetValue(self, row, col, value):
73     pass
74    
75     #
76     # Some optional methods
77     #
78    
79     # Called when the grid needs to display labels
80     def GetColLabelValue(self, col):
81     return self.columns[col][0]
82    
83     # Called to determine the kind of editor/renderer to use by
84     # default, doesn't necessarily have to be the same type used
85     # nativly by the editor/renderer if they know how to convert.
86     def GetTypeName(self, row, col):
87     return self.columns[col][1]
88    
89     # Called to determine how the data can be fetched and stored by the
90     # editor and renderer. This allows you to enforce some type-safety
91     # in the grid.
92     def CanGetValueAs(self, row, col, typeName):
93     # perhaps we should allow conversion int->double?
94     return self.GetTypeName(row, col) == typeName
95    
96     def CanSetValueAs(self, row, col, typeName):
97     return self.CanGetValueAs(row, col, typeName)
98    
99    
100 bh 34 class TableGrid(wxGrid, Publisher):
101 bh 6
102 bh 808 """A grid view for a Thuban table
103 bh 6
104 bh 808 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 bh 6 def __init__(self, parent, table = None):
113     wxGrid.__init__(self, parent, -1)
114    
115 bh 808 self.allow_messages_count = 0
116    
117 bh 6 self.table = DataTable(table)
118    
119     # The second parameter means that the grid is to take ownership
120     # of the table and will destroy it when done. Otherwise you
121 bh 77 # would need to keep a reference to it and call its Destroy
122 bh 6 # method later.
123     self.SetTable(self.table, true)
124    
125     #self.SetMargins(0,0)
126    
127 bh 173 # 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 bh 6 self.SetSelectionMode(wxGrid.wxGridSelectRows)
134 bh 278
135 bh 6 EVT_GRID_RANGE_SELECT(self, self.OnRangeSelect)
136     EVT_GRID_SELECT_CELL(self, self.OnSelectCell)
137    
138     def SetTableObject(self, table):
139     self.table.SetTable(table)
140    
141     def OnRangeSelect(self, event):
142 jonathan 881 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 bh 6 if event.Selecting():
148 jonathan 881 for i in range(event.GetTopRow(), event.GetBottomRow() + 1):
149     rows[i] = 0
150     rows[event.GetTopLeftCoords().GetRow()] = 0
151 bh 6
152 jonathan 881 self.issue(ROW_SELECTED, rows.keys())
153     event.Skip()
154    
155 bh 6 def OnSelectCell(self, event):
156 jonathan 881 self.issue(ROW_SELECTED, self.GetSelectedRows())
157     event.Skip()
158 bh 6
159 bh 808 def disallow_messages(self):
160     """Disallow messages to be send.
161 bh 278
162 bh 808 This method only increases a counter so that calls to
163     disallow_messages and allow_messages can be nested. Only the
164     outermost calls will actually switch message sending on and off.
165     """
166     self.allow_messages_count += 1
167    
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 bh 278 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 jonathan 881 def select_shapes(self, layer, shapes):
195 bh 278 """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 jonathan 881 if layer is not None \
201     and layer.table is self.table.table:
202    
203 bh 808 self.disallow_messages()
204     try:
205 jonathan 881 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 bh 808 finally:
221     self.allow_messages()
222 bh 6
223    
224 bh 30 class TableFrame(NonModalDialog):
225 bh 6
226 bh 34 """Frame that displays a Thuban table in a grid view"""
227    
228 bh 535 def __init__(self, parent, name, title, table):
229     NonModalDialog.__init__(self, parent, name, title)
230 bh 278 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 jonathan 881 ID_QUERY = 4001
243     ID_SAVEAS = 4002
244    
245 bh 278 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 bh 535 def __init__(self, parent, name, title, layer, table):
254     TableFrame.__init__(self, parent, name, title, table)
255 bh 34 self.layer = layer
256 jonathan 881 self.grid.Subscribe(ROW_SELECTED, self.rows_selected)
257     self.parent.Subscribe(SHAPES_SELECTED, self.select_shapes)
258 bh 30
259 jonathan 881 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 bh 278 def make_grid(self, table):
355     """Override the derived method to return a LayerTableGrid.
356     """
357     return LayerTableGrid(self, table)
358    
359 bh 30 def OnClose(self, event):
360 jonathan 881 self.parent.Unsubscribe(SHAPES_SELECTED, self.select_shapes)
361 bh 278 TableFrame.OnClose(self, event)
362 bh 30
363 jonathan 881 def select_shapes(self, layer, shapes):
364 bh 535 """Subscribed to the SHAPES_SELECTED message.
365    
366     If shapes contains exactly one shape id, select that shape in
367     the grid. Otherwise deselect all.
368     """
369 jonathan 881 self.grid.select_shapes(layer, shapes)
370 bh 34
371 jonathan 881 def rows_selected(self, rows):
372 bh 34 if self.layer is not None:
373 jonathan 881 self.parent.SelectShapes(self.layer, rows)

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26