/[thuban]/trunk/thuban/Thuban/UI/classifier.py
ViewVC logotype

Annotation of /trunk/thuban/Thuban/UI/classifier.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 611 - (hide annotations)
Fri Apr 4 16:34:46 2003 UTC (21 years, 11 months ago) by jonathan
File MIME type: text/x-python
File size: 40941 byte(s)
(Classifier.__SelectField): Move the
    call to SetSelection out of the method and before the call
    to __SelectField in __init__. This prevents a recursion of events
    when _OnFieldSelect is triggered by the user.

1 bh 476 # Copyright (c) 2001, 2003 by Intevation GmbH
2 jonathan 372 # Authors:
3     # Jonathan Coles <[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     """Dialog for classifying how layers are displayed"""
9    
10     __version__ = "$Revision$"
11    
12 jonathan 376 import copy
13    
14 jonathan 473 from Thuban.Model.table import FIELDTYPE_INT, FIELDTYPE_DOUBLE, \
15     FIELDTYPE_STRING
16    
17 jonathan 372 from wxPython.wx import *
18     from wxPython.grid import *
19    
20 jan 374 from Thuban import _
21 jonathan 415 from Thuban.common import *
22 jonathan 441 from Thuban.UI.common import *
23 jan 374
24 jonathan 451 from Thuban.Model.classification import *
25 jonathan 392
26 jonathan 415 from Thuban.Model.color import Color
27    
28 jonathan 460 from Thuban.Model.layer import Layer, SHAPETYPE_ARC, SHAPETYPE_POLYGON, SHAPETYPE_POINT
29 jonathan 392
30 jonathan 606 from Thuban.UI.classgen import ClassGenDialog, ClassGenerator
31    
32 jonathan 485 from dialogs import NonModalDialog
33    
34 jonathan 460 # widget id's
35 jonathan 372 ID_PROPERTY_SELECT = 4010
36     ID_CLASS_TABLE = 40011
37    
38     ID_CLASSIFY_OK = 4001
39     ID_CLASSIFY_CANCEL = 4002
40 jonathan 415 ID_CLASSIFY_ADD = 4003
41 jonathan 606 ID_CLASSIFY_GENCLASS = 4004
42 jonathan 451 ID_CLASSIFY_REMOVE = 4005
43 jonathan 460 ID_CLASSIFY_MOVEUP = 4006
44     ID_CLASSIFY_MOVEDOWN = 4007
45 jonathan 485 ID_CLASSIFY_APPLY = 4008
46 jonathan 606 ID_CLASSIFY_EDITPROPS = 4009
47 jonathan 372
48 jonathan 460 # table columns
49     COL_SYMBOL = 0
50 jonathan 415 COL_VALUE = 1
51     COL_LABEL = 2
52    
53 jonathan 460 # indices into the client data lists in Classifier.fields
54 jonathan 451 FIELD_CLASS = 0
55     FIELD_TYPE = 1
56     FIELD_NAME = 2
57    
58 jonathan 415 #
59     # this is a silly work around to ensure that the table that is
60     # passed into SetTable is the same that is returned by GetTable
61     #
62     import weakref
63     class ClassGrid(wxGrid):
64    
65 jonathan 570
66 jonathan 606 def __init__(self, parent, classifier):
67 jonathan 460 """Constructor.
68    
69     parent -- the parent window
70    
71     clazz -- the working classification that this grid should
72     use for display.
73     """
74    
75 jonathan 485 #wxGrid.__init__(self, parent, ID_CLASS_TABLE, size = (340, 160))
76     wxGrid.__init__(self, parent, ID_CLASS_TABLE)
77 jonathan 509 #self.SetTable(ClassTable(fieldData, layer.ShapeType(), self), True)
78 jonathan 415
79 jonathan 606 self.classifier = classifier
80    
81 jonathan 570 self.currentSelection = []
82    
83 jonathan 460 EVT_GRID_CELL_LEFT_DCLICK(self, self._OnCellDClick)
84 jonathan 451 EVT_GRID_RANGE_SELECT(self, self._OnSelectedRange)
85     EVT_GRID_SELECT_CELL(self, self._OnSelectedCell)
86 jonathan 606 EVT_GRID_COL_SIZE(self, self._OnCellResize)
87     EVT_GRID_ROW_SIZE(self, self._OnCellResize)
88 jonathan 451
89 jonathan 576 #print "123123123: ", ('Show' in dir(self))
90 jonathan 451
91 jonathan 576 #def Show(self):
92     #print "SHOW!"
93 jonathan 460
94 jonathan 576 #def Refresh(self):
95     #self.Show()
96     #def Update(self):
97     #self.Show()
98 jonathan 570
99     def CreateTable(self, clazz, shapeType, group = None):
100    
101 jonathan 606 assert isinstance(clazz, Classification)
102 jonathan 460
103     table = self.GetTable()
104     if table is None:
105 jonathan 500 w = self.GetDefaultColSize() * 3 + self.GetDefaultRowLabelSize()
106     h = self.GetDefaultRowSize() * 4 + self.GetDefaultColLabelSize()
107     self.SetDimensions(-1, -1, w, h)
108     self.SetSizeHints(w, h, -1, -1)
109 jonathan 570 table = ClassTable(self)
110     self.SetTable(table, True)
111 jonathan 460
112 jonathan 570
113 bh 476 self.SetSelectionMode(wxGrid.wxGridSelectRows)
114 jonathan 460 self.ClearSelection()
115    
116 jonathan 576 #print "8------------------"
117 jonathan 606 table.Reset(clazz, shapeType, group)
118 jonathan 576 #print "9------------------"
119 jonathan 570
120     # def Show(self, show = True):
121     # print "SHOW!"
122     # wxGrid.Show(self, show)
123    
124     # sel = self.GetCurrentSelection()
125    
126     # print "( 1"
127     # if len(sel) == 1:
128     # print "( 2"
129     # self.MakeCellVisible(sel[0], 0)
130    
131 jonathan 451 def GetCurrentSelection(self):
132 jonathan 460 """Return the currently highlighted rows as an increasing list
133     of row numbers."""
134 jonathan 576 #print "@@ ", self.currentSelection
135 jonathan 451 sel = copy.copy(self.currentSelection)
136     sel.sort()
137     return sel
138    
139 jonathan 570 def GetSelectedRows(self):
140     return self.GetCurrentSelection()
141    
142 jonathan 415 def SetCellRenderer(self, row, col):
143     raise ValueError(_("Must not allow setting of renderer in ClassGrid!"))
144    
145 jonathan 460 #
146     # [Set|Get]Table is taken from http://wiki.wxpython.org
147     # they are needed as a work around to ensure that the table
148     # that is passed to SetTable is the one that is returned
149     # by GetTable.
150     #
151 jonathan 415 def SetTable(self, object, *attributes):
152     self.tableRef = weakref.ref(object)
153     return wxGrid.SetTable(self, object, *attributes)
154    
155     def GetTable(self):
156 jonathan 460 try:
157     return self.tableRef()
158     except:
159     return None
160 jonathan 415
161 jonathan 451 def DeleteSelectedRows(self):
162 jonathan 460 """Deletes all highlighted rows.
163    
164     If only one row is highlighted then after it is deleted the
165     row that was below the deleted row is highlighted."""
166    
167 jonathan 451 sel = self.GetCurrentSelection()
168 jonathan 415
169 jonathan 460 # nothing to do
170     if len(sel) == 0: return
171    
172     # if only one thing is selected check if it is the default
173     # data row, because we can't remove that
174 jonathan 451 if len(sel) == 1:
175 jonathan 485 #group = self.GetTable().GetValueAsCustom(sel[0], COL_SYMBOL, None)
176     group = self.GetTable().GetClassGroup(sel[0])
177 jonathan 451 if isinstance(group, ClassGroupDefault):
178     wxMessageDialog(self,
179     "The Default group cannot be removed.",
180     style = wxOK | wxICON_EXCLAMATION).ShowModal()
181     return
182    
183 jonathan 460
184 jonathan 451 self.ClearSelection()
185    
186 jonathan 460 # we need to remove things from the bottom up so we don't
187     # change the indexes of rows that will be deleted next
188 jonathan 451 sel.reverse()
189 jonathan 460
190     #
191     # actually remove the rows
192     #
193 jonathan 451 table = self.GetTable()
194     for row in sel:
195     table.DeleteRows(row)
196    
197 jonathan 460 #
198     # if there was only one row selected highlight the row
199     # that was directly below it, or move up one if the
200     # deleted row was the last row.
201     #
202 jonathan 451 if len(sel) == 1:
203     r = sel[0]
204     if r > self.GetNumberRows() - 1:
205     r = self.GetNumberRows() - 1
206     self.SelectRow(r)
207    
208 jonathan 570
209     def SelectGroup(self, group, makeVisible = True):
210     if group is None: return
211    
212 jonathan 606 assert isinstance(group, ClassGroup)
213 jonathan 570
214     table = self.GetTable()
215    
216 jonathan 606 assert table is not None
217 jonathan 570
218    
219 jonathan 576 #print "-- ", group
220 jonathan 570 for i in range(table.GetNumberRows()):
221     g = table.GetClassGroup(i)
222 jonathan 576 #print "1", g
223 jonathan 570 if g is group:
224 jonathan 576 #print "2"
225 jonathan 570 self.SelectRow(i)
226     if makeVisible:
227 jonathan 576 #print "3"
228 jonathan 570 self.MakeCellVisible(i, 0)
229     break
230    
231    
232    
233 jonathan 451 #
234     # XXX: This isn't working, and there is no way to deselect rows wxPython!
235     #
236     # def DeselectRow(self, row):
237     # self.ProcessEvent(
238     # wxGridRangeSelectEvent(-1,
239     # wxEVT_GRID_RANGE_SELECT,
240     # self,
241     # (row, row), (row, row),
242     # sel = False))
243    
244 jonathan 460 def _OnCellDClick(self, event):
245     """Handle a double on a cell."""
246    
247 jonathan 451 r = event.GetRow()
248     c = event.GetCol()
249 jonathan 460 if c == COL_SYMBOL:
250 jonathan 606 self.classifier.EditGroupProperties(r)
251 jonathan 460
252 jonathan 451
253     #
254     # _OnSelectedRange() and _OnSelectedCell() were borrowed
255 jonathan 460 # from http://wiki.wxpython.org to keep track of which
256     # cells are currently highlighted
257 jonathan 451 #
258     def _OnSelectedRange(self, event):
259     """Internal update to the selection tracking list"""
260     if event.Selecting():
261     for index in range( event.GetTopRow(), event.GetBottomRow()+1):
262     if index not in self.currentSelection:
263 jonathan 576 #print " ", index
264 jonathan 451 self.currentSelection.append( index )
265     else:
266     for index in range( event.GetTopRow(), event.GetBottomRow()+1):
267     while index in self.currentSelection:
268 jonathan 576 #print " ", index
269 jonathan 451 self.currentSelection.remove( index )
270     #self.ConfigureForSelection()
271    
272 jonathan 576 #print self.GetCurrentSelection()
273 jonathan 451 event.Skip()
274    
275     def _OnSelectedCell( self, event ):
276     """Internal update to the selection tracking list"""
277 jonathan 576 #print "selecting cell: ", event.GetRow()
278 jonathan 451 self.currentSelection = [ event.GetRow() ]
279     #self.ConfigureForSelection()
280     event.Skip()
281    
282 jonathan 606 def _OnCellResize(self, event):
283     self.FitInside()
284    
285 jonathan 376 class ClassTable(wxPyGridTableBase):
286 jonathan 460 """Represents the underlying data structure for the grid."""
287 jonathan 376
288 jonathan 415 NUM_COLS = 3
289    
290 jonathan 451 __col_labels = [_("Symbol"), _("Value"), _("Label")]
291 jonathan 415
292 jonathan 570
293     def __init__(self, view = None):
294     #def __init__(self, clazz, shapeType, view = None):
295 jonathan 460 """Constructor.
296    
297     shapeType -- the type of shape that the layer uses
298    
299     view -- a wxGrid object that uses this class for its table
300     """
301    
302 jonathan 376 wxPyGridTableBase.__init__(self)
303 jonathan 485
304 jonathan 415 self.SetView(view)
305     self.tdata = []
306 jonathan 376
307 jonathan 570 #self.Reset(clazz, shapeType)
308 jonathan 415
309 jonathan 570 def Reset(self, clazz, shapeType, group = None):
310 jonathan 460 """Reset the table with the given data.
311 jonathan 415
312 jonathan 460 This is necessary because wxWindows does not allow a grid's
313     table to change once it has been intially set and so we
314     need a way of modifying the data.
315    
316     clazz -- the working classification that this table should
317     use for display. This may be different from the
318     classification in the layer.
319    
320     shapeType -- the type of shape that the layer uses
321     """
322    
323 jonathan 606 assert isinstance(clazz, Classification)
324 jonathan 460
325 jonathan 415 self.GetView().BeginBatch()
326    
327 jonathan 485 self.fieldType = clazz.GetFieldType()
328 jonathan 415 self.shapeType = shapeType
329    
330 jonathan 606 self.SetClassification(clazz, group)
331     self.__Modified(-1)
332     #print "11------------------"
333 jonathan 415
334 jonathan 606 self.GetView().EndBatch()
335     self.GetView().FitInside()
336    
337     def SetClassification(self, clazz, group = None):
338    
339     self.GetView().BeginBatch()
340    
341     old_len = self.GetNumberRows()
342 jonathan 376 self.tdata = []
343    
344 jonathan 576 #print "9------------------"
345 jonathan 460 #
346     # copy the data out of the classification and into our
347     # array
348     #
349 jonathan 570 row = -1
350     for g in clazz:
351     ng = copy.deepcopy(g)
352 jonathan 606 self.__SetRow(None, ng)
353 jonathan 570 if g is group:
354     row = self.GetNumberRows() - 1
355 jonathan 576 #print "selecting row..."
356 jonathan 441
357 jonathan 576 #print "10------------------"
358 jonathan 441
359 jonathan 606 self.__NotifyRowChanges(old_len, self.GetNumberRows())
360 jonathan 415
361 jonathan 570 if row > -1:
362     self.GetView().ClearSelection()
363     self.GetView().SelectRow(row)
364     self.GetView().MakeCellVisible(row, 0)
365 jonathan 606
366 jonathan 451 self.GetView().EndBatch()
367 jonathan 606 self.GetView().FitInside()
368 jonathan 451
369     def __NotifyRowChanges(self, curRows, newRows):
370 jonathan 415 #
371     # silly message processing for updates to the number of
372     # rows and columns
373     #
374     if newRows > curRows:
375     msg = wxGridTableMessage(self,
376     wxGRIDTABLE_NOTIFY_ROWS_APPENDED,
377     newRows - curRows) # how many
378     self.GetView().ProcessTableMessage(msg)
379 jonathan 519 self.GetView().FitInside()
380 jonathan 415 elif newRows < curRows:
381     msg = wxGridTableMessage(self,
382     wxGRIDTABLE_NOTIFY_ROWS_DELETED,
383 jonathan 606 curRows, # position
384 jonathan 415 curRows - newRows) # how many
385     self.GetView().ProcessTableMessage(msg)
386 jonathan 519 self.GetView().FitInside()
387 jonathan 415
388 jonathan 441 def __SetRow(self, row, group):
389 jonathan 460 """Set a row's data to that of the group.
390 jonathan 441
391 jonathan 485 The table is considered modified after this operation.
392    
393 jonathan 606 row -- if row is < 0 'group' is inserted at the top of the table
394     if row is >= GetNumberRows() or None 'group' is append to
395     the end of the table.
396     otherwise 'group' replaces row 'row'
397 jonathan 460 """
398 jonathan 441
399 jonathan 460 # either append or replace
400 jonathan 606 if row is None or row >= self.GetNumberRows():
401 jonathan 460 self.tdata.append(group)
402 jonathan 606 elif row < 0:
403     self.tdata.insert(0, group)
404 jonathan 441 else:
405 jonathan 460 self.tdata[row] = group
406 jonathan 441
407 jonathan 460 self.__Modified()
408    
409 jonathan 415 def GetColLabelValue(self, col):
410 jonathan 460 """Return the label for the given column."""
411 jonathan 415 return self.__col_labels[col]
412    
413     def GetRowLabelValue(self, row):
414 jonathan 460 """Return the label for the given row."""
415 jonathan 415
416 jonathan 460 group = self.tdata[row]
417     if isinstance(group, ClassGroupDefault): return _("Default")
418     if isinstance(group, ClassGroupSingleton): return _("Singleton")
419     if isinstance(group, ClassGroupRange): return _("Range")
420     if isinstance(group, ClassGroupMap): return _("Map")
421    
422 jonathan 606 assert False # shouldn't get here
423 jonathan 460 return _("")
424    
425 jonathan 376 def GetNumberRows(self):
426 jonathan 460 """Return the number of rows."""
427 jonathan 376 return len(self.tdata)
428    
429     def GetNumberCols(self):
430 jonathan 460 """Return the number of columns."""
431 jonathan 415 return self.NUM_COLS
432 jonathan 376
433     def IsEmptyCell(self, row, col):
434 jonathan 460 """Determine if a cell is empty. This is always false."""
435     return False
436 jonathan 376
437     def GetValue(self, row, col):
438 jonathan 460 """Return the object that is used to represent the given
439     cell coordinates. This may not be a string."""
440     return self.GetValueAsCustom(row, col, None)
441 jonathan 376
442     def SetValue(self, row, col, value):
443 jonathan 460 """Assign 'value' to the cell specified by 'row' and 'col'.
444    
445     The table is considered modified after this operation.
446     """
447    
448     self.SetValueAsCustom(row, col, None, value)
449 jonathan 415 self.__Modified()
450    
451 jonathan 392 def GetValueAsCustom(self, row, col, typeName):
452 jonathan 460 """Return the object that is used to represent the given
453     cell coordinates. This may not be a string.
454    
455     typeName -- unused, but needed to overload wxPyGridTableBase
456     """
457 jonathan 376
458 jonathan 460 group = self.tdata[row]
459    
460     if col == COL_SYMBOL:
461 jonathan 485 return group.GetProperties()
462 jonathan 460
463     if col == COL_LABEL:
464     return group.GetLabel()
465    
466     # col must be COL_VALUE
467 jonathan 606 assert col == COL_VALUE
468 jonathan 460
469     if isinstance(group, ClassGroupDefault):
470     return _("DEFAULT")
471     elif isinstance(group, ClassGroupSingleton):
472     return group.GetValue()
473     elif isinstance(group, ClassGroupRange):
474     return _("%s - %s") % (group.GetMin(), group.GetMax())
475    
476 jonathan 606 assert False # shouldn't get here
477 jonathan 460 return None
478    
479 jonathan 415 def __ParseInput(self, value):
480     """Try to determine what kind of input value is
481 jonathan 460 (string, number, or range)
482    
483     Returns a tuple of length one if there is a single
484     value, or of length two if it is a range.
485 jonathan 415 """
486 jonathan 392
487 jonathan 485 type = self.fieldType
488 jonathan 415
489 jonathan 460 if type == FIELDTYPE_STRING:
490 jonathan 451 return (value,)
491 jonathan 460 elif type == FIELDTYPE_INT or type == FIELDTYPE_DOUBLE:
492 jonathan 451
493 jonathan 460 if type == FIELDTYPE_INT:
494     conv = lambda p: int(float(p))
495     else:
496     conv = lambda p: p
497    
498 jonathan 451 #
499     # first try to take the input as a single number
500     # if there's an exception try to break it into
501     # a range seperated by a '-'. take care to ignore
502     # a leading '-' as that could be for a negative number.
503     # then try to parse the individual parts. if there
504     # is an exception here, let it pass up to the calling
505     # function.
506     #
507     try:
508 jonathan 460 return (conv(Str2Num(value)),)
509     except ValueError:
510 jonathan 451 i = value.find('-')
511     if i == 0:
512     i = value.find('-', 1)
513    
514 jonathan 460 return (conv(Str2Num(value[:i])), conv(Str2Num(value[i+1:])))
515    
516 jonathan 606 assert False # shouldn't get here
517 jonathan 485 return (0,)
518 jonathan 415
519    
520     def SetValueAsCustom(self, row, col, typeName, value):
521 jonathan 460 """Set the cell specified by 'row' and 'col' to 'value'.
522 jonathan 415
523 jonathan 460 If column represents the value column, the input is parsed
524     to determine if a string, number, or range was entered.
525     A new ClassGroup may be created if the type of data changes.
526    
527     The table is considered modified after this operation.
528    
529     typeName -- unused, but needed to overload wxPyGridTableBase
530     """
531    
532 jonathan 606 assert col >= 0 and col < self.GetNumberCols()
533     assert row >= 0 and row < self.GetNumberRows()
534 jonathan 460
535     group = self.tdata[row]
536    
537 jonathan 485 mod = True # assume the data will change
538 jonathan 460
539     if col == COL_SYMBOL:
540 jonathan 485 group.SetProperties(value)
541     elif col == COL_LABEL:
542     group.SetLabel(value)
543 jonathan 415 elif col == COL_VALUE:
544 jonathan 451 if isinstance(group, ClassGroupDefault):
545     # not allowed to modify the default value
546     pass
547     elif isinstance(group, ClassGroupMap):
548     # something special
549     pass
550     else: # SINGLETON, RANGE
551     try:
552     dataInfo = self.__ParseInput(value)
553 jonathan 460 except ValueError:
554 jonathan 451 # bad input, ignore the request
555 jonathan 485 mod = False
556 jonathan 451 else:
557 jonathan 415
558 jonathan 485 changed = False
559 jonathan 451 ngroup = group
560     props = group.GetProperties()
561 jonathan 460
562     #
563     # try to update the values, which may include
564     # changing the underlying group type if the
565     # group was a singleton and a range was entered
566     #
567 jonathan 451 if len(dataInfo) == 1:
568     if not isinstance(group, ClassGroupSingleton):
569     ngroup = ClassGroupSingleton(prop = props)
570 jonathan 485 changed = True
571 jonathan 451 ngroup.SetValue(dataInfo[0])
572     elif len(dataInfo) == 2:
573     if not isinstance(group, ClassGroupRange):
574     ngroup = ClassGroupRange(prop = props)
575 jonathan 485 changed = True
576 jonathan 451 ngroup.SetRange(dataInfo[0], dataInfo[1])
577 jonathan 415 else:
578 jonathan 606 assert False
579 jonathan 485 pass
580 jonathan 415
581 jonathan 485 if changed:
582     ngroup.SetLabel(group.GetLabel())
583     self.SetClassGroup(row, ngroup)
584     else:
585 jonathan 606 assert False # shouldn't be here
586 jonathan 485 pass
587 jonathan 460
588 jonathan 485 if mod:
589 jonathan 460 self.__Modified()
590     self.GetView().Refresh()
591 jonathan 415
592     def GetAttr(self, row, col, someExtraParameter):
593 jonathan 460 """Returns the cell attributes"""
594    
595 jonathan 415 attr = wxGridCellAttr()
596     #attr = wxPyGridTableBase.GetAttr(self, row, col, someExtraParameter)
597    
598 jonathan 460 if col == COL_SYMBOL:
599 jonathan 485 # we need to create a new renderer each time, because
600     # SetRenderer takes control of the parameter
601 jonathan 415 attr.SetRenderer(ClassRenderer(self.shapeType))
602     attr.SetReadOnly()
603    
604     return attr
605    
606 jonathan 441 def GetClassGroup(self, row):
607 jonathan 460 """Return the ClassGroup object representing row 'row'."""
608 jonathan 415
609 jonathan 485 return self.tdata[row] # self.GetValueAsCustom(row, COL_SYMBOL, None)
610 jonathan 415
611 jonathan 460 def SetClassGroup(self, row, group):
612 jonathan 485 self.__SetRow(row, group)
613     self.GetView().Refresh()
614 jonathan 460
615     def __Modified(self, mod = True):
616 jonathan 485 """Adjust the modified flag.
617 jonathan 460
618 jonathan 485 mod -- if -1 set the modified flag to False, otherwise perform
619     an 'or' operation with the current value of the flag and
620     'mod'
621     """
622    
623     if mod == -1:
624     self.modified = False
625     else:
626     self.modified = mod or self.modified
627    
628 jonathan 415 def IsModified(self):
629 jonathan 460 """True if this table is considered modified."""
630 jonathan 415 return self.modified
631    
632 jonathan 451 def DeleteRows(self, pos, numRows = 1):
633 jonathan 485 """Deletes 'numRows' beginning at row 'pos'.
634 jonathan 460
635 jonathan 485 The row representing the default group is not removed.
636    
637     The table is considered modified if any rows are removed.
638 jonathan 460 """
639    
640 jonathan 606 assert pos >= 0
641 jonathan 451 old_len = len(self.tdata)
642     for row in range(pos, pos - numRows, -1):
643 jonathan 485 group = self.GetClassGroup(row)
644 jonathan 451 if not isinstance(group, ClassGroupDefault):
645     self.tdata.pop(row)
646     self.__Modified()
647    
648     if self.IsModified():
649     self.__NotifyRowChanges(old_len, len(self.tdata))
650 jonathan 415
651 jonathan 451 def AppendRows(self, numRows = 1):
652 jonathan 485 """Append 'numRows' empty rows to the end of the table.
653 jonathan 460
654 jonathan 485 The table is considered modified if any rows are appended.
655     """
656    
657 jonathan 451 old_len = len(self.tdata)
658     for i in range(numRows):
659     np = ClassGroupSingleton()
660 jonathan 606 self.__SetRow(None, np)
661 jonathan 451
662     if self.IsModified():
663     self.__NotifyRowChanges(old_len, len(self.tdata))
664    
665    
666 jonathan 485 class Classifier(NonModalDialog):
667 bh 535
668 jonathan 570 def __init__(self, parent, name, layer, group = None):
669 bh 535 NonModalDialog.__init__(self, parent, name,
670 jonathan 485 _("Classifier: %s") % layer.Title())
671 jonathan 372
672 jonathan 511 panel = wxPanel(self, -1, size=(100, 100))
673 jonathan 509
674 jonathan 415 self.layer = layer
675    
676 jonathan 485 self.originalClass = self.layer.GetClassification()
677     field = self.originalClass.GetField()
678     fieldType = self.originalClass.GetFieldType()
679    
680 jonathan 372 topBox = wxBoxSizer(wxVERTICAL)
681 jonathan 511 panelBox = wxBoxSizer(wxVERTICAL)
682 jonathan 372
683 jonathan 511 #panelBox.Add(wxStaticText(panel, -1, _("Layer: %s") % layer.Title()),
684 jonathan 485 #0, wxALIGN_LEFT | wxALL, 4)
685 jonathan 511 panelBox.Add(wxStaticText(panel, -1,
686 jonathan 485 _("Layer Type: %s") % layer.ShapeType()),
687 jonathan 451 0, wxALIGN_LEFT | wxALL, 4)
688 jonathan 415
689 jonathan 372
690 jonathan 485 #
691     # make field combo box
692     #
693 jonathan 509 self.fields = wxComboBox(panel, ID_PROPERTY_SELECT, "",
694 jonathan 372 style = wxCB_READONLY)
695    
696     self.num_cols = layer.table.field_count()
697 jonathan 441 # just assume the first field in case one hasn't been
698     # specified in the file.
699 jonathan 451 self.__cur_field = 0
700 jonathan 460
701     self.fields.Append("<None>")
702     self.fields.SetClientData(0, None)
703    
704 jonathan 372 for i in range(self.num_cols):
705     type, name, len, decc = layer.table.field_info(i)
706 jonathan 451 self.fields.Append(name)
707    
708 jonathan 415 if name == field:
709 jonathan 460 self.__cur_field = i + 1
710 jonathan 485 self.fields.SetClientData(i + 1, self.originalClass)
711 jonathan 451 else:
712 jonathan 460 self.fields.SetClientData(i + 1, None)
713 jonathan 372
714    
715 jonathan 509 ###########
716 jonathan 485
717 jonathan 509 self.fieldTypeText = wxStaticText(panel, -1, "")
718 jonathan 560 panelBox.Add(self.fieldTypeText, 0,
719     wxGROW | wxALIGN_LEFT | wxALL | wxADJUST_MINSIZE, 4)
720 jonathan 485
721     propertyBox = wxBoxSizer(wxHORIZONTAL)
722 jonathan 509 propertyBox.Add(wxStaticText(panel, -1, _("Field: ")),
723 jonathan 506 0, wxALIGN_LEFT | wxALL, 4)
724 jonathan 451 propertyBox.Add(self.fields, 1, wxGROW|wxALL, 4)
725 jonathan 460 EVT_COMBOBOX(self, ID_PROPERTY_SELECT, self._OnFieldSelect)
726 jonathan 451
727 jonathan 511 panelBox.Add(propertyBox, 0, wxGROW, 4)
728 jonathan 372
729 jonathan 570
730 jonathan 372 #
731 jonathan 570 # Control Box
732 jonathan 372 #
733 jonathan 415 controlBox = wxBoxSizer(wxHORIZONTAL)
734 jonathan 485
735 jonathan 460
736 jonathan 509 ###########
737 jonathan 485 #
738     # Control buttons:
739     #
740     self.controlButtons = []
741 jonathan 460
742 jonathan 509 controlButtonBox = wxBoxSizer(wxVERTICAL)
743    
744     button = wxButton(panel, ID_CLASSIFY_ADD, _("Add"))
745 jonathan 485 controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)
746     self.controlButtons.append(button)
747 jonathan 451
748 jonathan 606 button = wxButton(panel, ID_CLASSIFY_EDITPROPS, _("Edit Properties"))
749 jonathan 570 controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)
750     self.controlButtons.append(button)
751 jonathan 485
752 jonathan 606 button = wxButton(panel, ID_CLASSIFY_GENCLASS, _("Generate Class"))
753     controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)
754     self.controlButtons.append(button)
755    
756 jonathan 509 button = wxButton(panel, ID_CLASSIFY_MOVEUP, _("Move Up"))
757 jonathan 485 controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)
758     self.controlButtons.append(button)
759    
760 jonathan 509 button = wxButton(panel, ID_CLASSIFY_MOVEDOWN, _("Move Down"))
761 jonathan 485 controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)
762     self.controlButtons.append(button)
763    
764     controlButtonBox.Add(60, 20, 0, wxGROW | wxALL | wxALIGN_BOTTOM, 4)
765    
766 jonathan 509 button = wxButton(panel, ID_CLASSIFY_REMOVE, _("Remove"))
767 jonathan 485 controlButtonBox.Add(button, 0, wxGROW | wxALL | wxALIGN_BOTTOM, 4)
768     self.controlButtons.append(button)
769    
770 jonathan 570
771     ###########
772     #
773     # Classification data table
774     #
775    
776 jonathan 606 self.classGrid = ClassGrid(panel, self)
777 jonathan 570 #self.__SetGridTable(self.__cur_field, group)
778     #self.fields.SetSelection(self.__cur_field)
779    
780     # calling __SelectField after creating the classGrid fills in the
781     # grid with the correct information
782 jonathan 576 #print "2------------------"
783 jonathan 611 self.fields.SetSelection(self.__cur_field)
784 jonathan 570 self.__SelectField(self.__cur_field, group = group)
785    
786     #self.classGrid.SelectGroup(group)
787    
788     controlBox.Add(self.classGrid, 1, wxGROW, 0)
789    
790    
791    
792 jonathan 415 controlBox.Add(controlButtonBox, 0, wxGROW, 10)
793 jonathan 511 panelBox.Add(controlBox, 1, wxGROW, 10)
794 jonathan 415
795 jonathan 460 EVT_BUTTON(self, ID_CLASSIFY_ADD, self._OnAdd)
796 jonathan 606 EVT_BUTTON(self, ID_CLASSIFY_EDITPROPS, self._OnEditGroupProperties)
797 jonathan 460 EVT_BUTTON(self, ID_CLASSIFY_REMOVE, self._OnRemove)
798 jonathan 606 EVT_BUTTON(self, ID_CLASSIFY_GENCLASS, self._OnGenClass)
799 jonathan 460 EVT_BUTTON(self, ID_CLASSIFY_MOVEUP, self._OnMoveUp)
800     EVT_BUTTON(self, ID_CLASSIFY_MOVEDOWN, self._OnMoveDown)
801 jonathan 415
802 jonathan 509 ###########
803    
804 jonathan 372 buttonBox = wxBoxSizer(wxHORIZONTAL)
805 jonathan 509 buttonBox.Add(wxButton(panel, ID_CLASSIFY_OK, _("OK")),
806 jonathan 372 0, wxALL, 4)
807 jonathan 485 buttonBox.Add(60, 20, 0, wxALL, 4)
808 jonathan 509 buttonBox.Add(wxButton(panel, ID_CLASSIFY_APPLY, _("Apply")),
809 jonathan 485 0, wxALL, 4)
810     buttonBox.Add(60, 20, 0, wxALL, 4)
811 jonathan 509 buttonBox.Add(wxButton(panel, ID_CLASSIFY_CANCEL, _("Cancel")),
812 jonathan 372 0, wxALL, 4)
813 jonathan 511 panelBox.Add(buttonBox, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_BOTTOM, 0)
814 jonathan 372
815 jonathan 460 EVT_BUTTON(self, ID_CLASSIFY_OK, self._OnOK)
816 jonathan 485 EVT_BUTTON(self, ID_CLASSIFY_APPLY, self._OnApply)
817 jonathan 460 EVT_BUTTON(self, ID_CLASSIFY_CANCEL, self._OnCancel)
818 jonathan 372
819 jonathan 509 ###########
820    
821 jonathan 496
822 jonathan 509 panel.SetAutoLayout(True)
823 jonathan 511 panel.SetSizer(panelBox)
824     panelBox.SetSizeHints(panel)
825 jonathan 372
826 jonathan 606 topBox.Add(panel, 1, wxGROW, 0)
827 jonathan 511 panelBox.SetSizeHints(self)
828 jonathan 509 self.SetAutoLayout(True)
829 jonathan 511 self.SetSizer(topBox)
830 jonathan 509
831 jonathan 576 #print "1------------------"
832 jonathan 570 #self.Fit()
833 jonathan 549 ######################
834    
835     self.haveApplied = False
836    
837 jonathan 606 def EditGroupProperties(self, row):
838     table = self.classGrid.GetTable()
839     prop = table.GetValueAsCustom(row, COL_SYMBOL, None)
840    
841     # get a new ClassGroupProperties object and copy the
842     # values over to our current object
843     propDlg = SelectPropertiesDialog(NULL, prop, self.layer.ShapeType())
844     if propDlg.ShowModal() == wxID_OK:
845     new_prop = propDlg.GetClassGroupProperties()
846     table.SetValueAsCustom(row, COL_SYMBOL, None, new_prop)
847     propDlg.Destroy()
848    
849    
850 jonathan 460 def __BuildClassification(self, fieldIndex):
851 jonathan 415
852 jonathan 496 numRows = self.classGrid.GetNumberRows()
853 jonathan 606 assert numRows > 0 # there should always be a default row
854 jonathan 496
855 jonathan 415 clazz = Classification()
856 jonathan 496 if fieldIndex == 0:
857     fieldName = None
858     fieldType = None
859     else:
860     fieldName = self.fields.GetString(fieldIndex)
861     fieldType = self.layer.GetFieldType(fieldName)
862 jonathan 415
863 jonathan 460 clazz.SetField(fieldName)
864     clazz.SetFieldType(fieldType)
865    
866 jonathan 415
867 jonathan 460 table = self.classGrid.GetTable()
868     clazz.SetDefaultGroup(table.GetClassGroup(0))
869 jonathan 415
870 jonathan 460 for i in range(1, numRows):
871     clazz.AddGroup(table.GetClassGroup(i))
872    
873 jonathan 415 return clazz
874    
875 jonathan 570 def __SetGridTable(self, fieldIndex, group = None):
876 jonathan 415
877 jonathan 460 clazz = self.fields.GetClientData(fieldIndex)
878 jonathan 415
879 jonathan 460 if clazz is None:
880     clazz = Classification()
881     clazz.SetDefaultGroup(
882     ClassGroupDefault(
883 jonathan 485 self.layer.GetClassification().
884     GetDefaultGroup().GetProperties()))
885 jonathan 460
886     fieldName = self.fields.GetString(fieldIndex)
887     fieldType = self.layer.GetFieldType(fieldName)
888     clazz.SetFieldType(fieldType)
889    
890 jonathan 576 #print "6------------------"
891 jonathan 570 self.classGrid.CreateTable(clazz, self.layer.ShapeType(), group)
892 jonathan 576 #print "7------------------"
893 jonathan 460
894 jonathan 496
895    
896 jonathan 500 type2string = {None: _("None"),
897     FIELDTYPE_STRING: _("Text"),
898     FIELDTYPE_INT: _("Integer"),
899     FIELDTYPE_DOUBLE: _("Decimal")}
900 jonathan 496
901 jonathan 485 def __SetFieldTypeText(self, fieldIndex):
902     fieldName = self.fields.GetString(fieldIndex)
903     fieldType = self.layer.GetFieldType(fieldName)
904    
905 jonathan 606 assert Classifier.type2string.has_key(fieldType)
906 jonathan 485
907 jonathan 496 text = Classifier.type2string[fieldType]
908    
909 jonathan 485 self.fieldTypeText.SetLabel(_("Field Type: %s") % text)
910    
911 jonathan 570 def __SelectField(self, newIndex, oldIndex = -1, group = None):
912 jonathan 611 """This method assumes that the current selection for the
913     combo has already been set by a call to SetSelection().
914     """
915 jonathan 460
916 jonathan 576 #print "3------------------"
917 jonathan 570
918 jonathan 606 assert oldIndex >= -1
919 jonathan 415
920 jonathan 498 if oldIndex != -1:
921     clazz = self.__BuildClassification(oldIndex)
922     self.fields.SetClientData(oldIndex, clazz)
923 jonathan 485
924 jonathan 576 #print "4------------------"
925 jonathan 570 self.__SetGridTable(newIndex, group)
926 jonathan 576 #print "5------------------"
927 jonathan 498
928     enabled = newIndex != 0
929    
930 jonathan 485 for b in self.controlButtons:
931     b.Enable(enabled)
932    
933 jonathan 498 self.__SetFieldTypeText(newIndex)
934 jonathan 485
935 jonathan 496
936 jonathan 606 def _OnEditGroupProperties(self, event):
937     sel = self.classGrid.GetCurrentSelection()
938    
939     if len(sel) == 1:
940     self.EditGroupProperties(sel[0])
941    
942 jonathan 496 def _OnFieldSelect(self, event):
943 jonathan 498 index = self.fields.GetSelection()
944     self.__SelectField(index, self.__cur_field)
945     self.__cur_field = index
946 jonathan 485
947     def _OnApply(self, event):
948 jonathan 415 """Put the data from the table into a new Classification and hand
949     it to the layer.
950     """
951    
952 jonathan 460 clazz = self.fields.GetClientData(self.__cur_field)
953 jonathan 415
954     #
955     # only build the classification if there wasn't one to
956     # to begin with or it has been modified
957     #
958     if clazz is None or self.classGrid.GetTable().IsModified():
959 jonathan 451 clazz = self.__BuildClassification(self.__cur_field)
960 jonathan 415
961     self.layer.SetClassification(clazz)
962    
963 jonathan 549 self.haveApplied = True
964    
965 jonathan 485 def _OnOK(self, event):
966     self._OnApply(event)
967     self.OnClose(event)
968 jonathan 415
969 jonathan 460 def _OnCancel(self, event):
970 jonathan 485 """The layer's current classification stays the same."""
971 jonathan 549 if self.haveApplied:
972     self.layer.SetClassification(self.originalClass)
973    
974 jonathan 485 self.OnClose(event)
975 jonathan 415
976 jonathan 460 def _OnAdd(self, event):
977 jonathan 451 self.classGrid.AppendRows()
978 jonathan 415
979 jonathan 460 def _OnRemove(self, event):
980 jonathan 451 self.classGrid.DeleteSelectedRows()
981    
982 jonathan 606 def _OnGenClass(self, event):
983 jonathan 415
984 jonathan 606 genDlg = ClassGenDialog(self,
985     self.layer.table,
986     self.fields.GetString(self.__cur_field))
987    
988     if genDlg.ShowModal() == wxID_OK:
989     clazz = genDlg.GetClassification()
990     self.fields.SetClientData(self.__cur_field, clazz)
991     self.classGrid.GetTable().SetClassification(clazz)
992     genDlg.Destroy()
993    
994 jonathan 460 def _OnMoveUp(self, event):
995     sel = self.classGrid.GetCurrentSelection()
996 jonathan 415
997 jonathan 576 #print "sel: ", sel
998 jonathan 570
999 jonathan 460 if len(sel) == 1:
1000     i = sel[0]
1001     if i > 1:
1002     table = self.classGrid.GetTable()
1003     x = table.GetClassGroup(i - 1)
1004     y = table.GetClassGroup(i)
1005     table.SetClassGroup(i - 1, y)
1006     table.SetClassGroup(i, x)
1007     self.classGrid.ClearSelection()
1008     self.classGrid.SelectRow(i - 1)
1009 jonathan 570 self.classGrid.MakeCellVisible(i - 1, 0)
1010 jonathan 460
1011     def _OnMoveDown(self, event):
1012     sel = self.classGrid.GetCurrentSelection()
1013    
1014     if len(sel) == 1:
1015     i = sel[0]
1016     table = self.classGrid.GetTable()
1017     if 0 < i < table.GetNumberRows() - 1:
1018     x = table.GetClassGroup(i)
1019     y = table.GetClassGroup(i + 1)
1020     table.SetClassGroup(i, y)
1021     table.SetClassGroup(i + 1, x)
1022     self.classGrid.ClearSelection()
1023     self.classGrid.SelectRow(i + 1)
1024 jonathan 570 self.classGrid.MakeCellVisible(i + 1, 0)
1025 jonathan 460
1026    
1027 jonathan 415 ID_SELPROP_OK = 4001
1028     ID_SELPROP_CANCEL = 4002
1029     ID_SELPROP_SPINCTRL = 4002
1030 jonathan 430 ID_SELPROP_PREVIEW = 4003
1031     ID_SELPROP_STROKECLR = 4004
1032     ID_SELPROP_FILLCLR = 4005
1033 jonathan 485 ID_SELPROP_STROKECLRTRANS = 4006
1034     ID_SELPROP_FILLCLRTRANS = 4007
1035 jonathan 415
1036     class SelectPropertiesDialog(wxDialog):
1037    
1038     def __init__(self, parent, prop, shapeType):
1039     wxDialog.__init__(self, parent, -1, _("Select Properties"),
1040 jonathan 507 style = wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
1041 jonathan 415
1042 jonathan 441 self.prop = ClassGroupProperties(prop)
1043 jonathan 415
1044 jonathan 430 topBox = wxBoxSizer(wxVERTICAL)
1045 jonathan 415
1046 jonathan 430 itemBox = wxBoxSizer(wxHORIZONTAL)
1047    
1048     # preview box
1049     previewBox = wxBoxSizer(wxVERTICAL)
1050     previewBox.Add(wxStaticText(self, -1, _("Preview:")),
1051     0, wxALIGN_LEFT | wxALL, 4)
1052 jonathan 549 self.previewWin = ClassDataPreviewWindow(None, self.prop, shapeType,
1053 jonathan 430 self, ID_SELPROP_PREVIEW, (40, 40))
1054 jonathan 549 previewBox.Add(self.previewWin, 1, wxGROW, 15)
1055 jonathan 430
1056     itemBox.Add(previewBox, 1, wxALIGN_LEFT | wxALL | wxGROW, 0)
1057    
1058     # control box
1059     ctrlBox = wxBoxSizer(wxVERTICAL)
1060 jonathan 485
1061     lineColorBox = wxBoxSizer(wxHORIZONTAL)
1062     lineColorBox.Add(
1063 jonathan 500 wxButton(self, ID_SELPROP_STROKECLR, _("Change Line Color")),
1064 jonathan 485 1, wxALL | wxGROW, 4)
1065 jonathan 460 EVT_BUTTON(self, ID_SELPROP_STROKECLR, self._OnChangeLineColor)
1066 jonathan 430
1067 jonathan 485 lineColorBox.Add(
1068 jonathan 500 wxButton(self, ID_SELPROP_STROKECLRTRANS, _("Transparent")),
1069 jonathan 485 1, wxALL | wxGROW, 4)
1070     EVT_BUTTON(self, ID_SELPROP_STROKECLRTRANS,
1071     self._OnChangeLineColorTrans)
1072    
1073     ctrlBox.Add(lineColorBox, 0,
1074     wxALIGN_CENTER_HORIZONTAL | wxALL | wxGROW, 4)
1075    
1076 jonathan 430 if shapeType != SHAPETYPE_ARC:
1077 jonathan 485 fillColorBox = wxBoxSizer(wxHORIZONTAL)
1078     fillColorBox.Add(
1079 jonathan 500 wxButton(self, ID_SELPROP_FILLCLR, _("Change Fill Color")),
1080 jonathan 485 1, wxALL | wxGROW, 4)
1081 jonathan 460 EVT_BUTTON(self, ID_SELPROP_FILLCLR, self._OnChangeFillColor)
1082 jonathan 485 fillColorBox.Add(
1083 jonathan 500 wxButton(self, ID_SELPROP_FILLCLRTRANS, _("Transparent")),
1084 jonathan 485 1, wxALL | wxGROW, 4)
1085     EVT_BUTTON(self, ID_SELPROP_FILLCLRTRANS,
1086     self._OnChangeFillColorTrans)
1087     ctrlBox.Add(fillColorBox, 0,
1088     wxALIGN_CENTER_HORIZONTAL | wxALL | wxGROW, 4)
1089 jonathan 430
1090 jonathan 415 spinBox = wxBoxSizer(wxHORIZONTAL)
1091 jonathan 460 spinBox.Add(wxStaticText(self, -1, _("Line Width: ")),
1092 jonathan 430 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 4)
1093 jonathan 415 self.spinCtrl = wxSpinCtrl(self, ID_SELPROP_SPINCTRL,
1094     min=1, max=10,
1095 jonathan 460 value=str(prop.GetLineWidth()),
1096     initial=prop.GetLineWidth())
1097 jonathan 415
1098 jonathan 460 EVT_SPINCTRL(self, ID_SELPROP_SPINCTRL, self._OnSpin)
1099 jonathan 415
1100     spinBox.Add(self.spinCtrl, 0, wxALIGN_LEFT | wxALL, 4)
1101    
1102 jonathan 430 ctrlBox.Add(spinBox, 0, wxALIGN_RIGHT | wxALL, 0)
1103     itemBox.Add(ctrlBox, 0, wxALIGN_RIGHT | wxALL | wxGROW, 0)
1104     topBox.Add(itemBox, 1, wxALIGN_LEFT | wxALL | wxGROW, 0)
1105 jonathan 415
1106     #
1107     # Control buttons:
1108     #
1109     buttonBox = wxBoxSizer(wxHORIZONTAL)
1110 jonathan 485 buttonBox.Add(wxButton(self, ID_SELPROP_OK, _("OK")),
1111 jonathan 415 0, wxALL, 4)
1112 jonathan 485 buttonBox.Add(wxButton(self, ID_SELPROP_CANCEL, _("Cancel")),
1113 jonathan 415 0, wxALL, 4)
1114     topBox.Add(buttonBox, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_BOTTOM, 10)
1115    
1116 jonathan 460 EVT_BUTTON(self, ID_SELPROP_OK, self._OnOK)
1117     EVT_BUTTON(self, ID_SELPROP_CANCEL, self._OnCancel)
1118 jonathan 415
1119 jonathan 509 self.SetAutoLayout(True)
1120 jonathan 415 self.SetSizer(topBox)
1121     topBox.Fit(self)
1122     topBox.SetSizeHints(self)
1123    
1124 jonathan 460 def _OnOK(self, event):
1125 jonathan 372 self.EndModal(wxID_OK)
1126    
1127 jonathan 460 def _OnCancel(self, event):
1128 jonathan 372 self.EndModal(wxID_CANCEL)
1129    
1130 jonathan 460 def _OnSpin(self, event):
1131     self.prop.SetLineWidth(self.spinCtrl.GetValue())
1132 jonathan 549 self.previewWin.Refresh()
1133 jonathan 392
1134 jonathan 430 def __GetColor(self, cur):
1135     dialog = wxColourDialog(self)
1136 jonathan 610 if cur is not Color.Transparent:
1137 jonathan 606 dialog.GetColourData().SetColour(Color2wxColour(cur))
1138    
1139 jonathan 430 ret = None
1140     if dialog.ShowModal() == wxID_OK:
1141     ret = wxColour2Color(dialog.GetColourData().GetColour())
1142    
1143     dialog.Destroy()
1144    
1145     return ret
1146    
1147 jonathan 460 def _OnChangeLineColor(self, event):
1148     clr = self.__GetColor(self.prop.GetLineColor())
1149 jonathan 430 if clr is not None:
1150 jonathan 460 self.prop.SetLineColor(clr)
1151 jonathan 549 self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer
1152 jonathan 430
1153 jonathan 485 def _OnChangeLineColorTrans(self, event):
1154 jonathan 610 self.prop.SetLineColor(Color.Transparent)
1155 jonathan 549 self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer
1156 jonathan 485
1157 jonathan 460 def _OnChangeFillColor(self, event):
1158 jonathan 430 clr = self.__GetColor(self.prop.GetFill())
1159     if clr is not None:
1160     self.prop.SetFill(clr)
1161 jonathan 549 self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer
1162 jonathan 430
1163 jonathan 485 def _OnChangeFillColorTrans(self, event):
1164 jonathan 610 self.prop.SetFill(Color.Transparent)
1165 jonathan 549 self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer
1166 jonathan 485
1167 jonathan 441 def GetClassGroupProperties(self):
1168 jonathan 415 return self.prop
1169 jonathan 392
1170    
1171 jonathan 549 class ClassDataPreviewWindow(wxWindow):
1172 jonathan 415
1173 jonathan 441 def __init__(self, rect, prop, shapeType,
1174 jonathan 430 parent = None, id = -1, size = wxDefaultSize):
1175     if parent is not None:
1176 jonathan 549 wxWindow.__init__(self, parent, id, (0, 0), size)
1177 jonathan 460 EVT_PAINT(self, self._OnPaint)
1178 jonathan 415
1179 jonathan 430 self.rect = rect
1180 jonathan 549
1181 jonathan 441 self.prop = prop
1182 jonathan 430 self.shapeType = shapeType
1183 jonathan 549 self.previewer = ClassDataPreviewer()
1184 jonathan 430
1185 jonathan 460 def _OnPaint(self, event):
1186 jonathan 430 dc = wxPaintDC(self)
1187    
1188     # XXX: this doesn't seem to be having an effect:
1189     dc.DestroyClippingRegion()
1190    
1191 jonathan 549 if self.rect is None:
1192     w, h = self.GetSize()
1193     rect = wxRect(0, 0, w, h)
1194     else:
1195     rect = self.rect
1196 jonathan 430
1197 jonathan 549 self.previewer.Draw(dc, rect, self.prop, self.shapeType)
1198 jonathan 430
1199 jonathan 549 class ClassDataPreviewer:
1200 jonathan 430
1201 jonathan 549 def Draw(self, dc, rect, prop, shapeType):
1202    
1203 jonathan 606 assert dc is not None
1204     assert isinstance(prop, ClassGroupProperties)
1205 jonathan 549
1206 jonathan 430 if rect is None:
1207 jonathan 549 x = 0
1208     y = 0
1209     w, h = dc.GetSize()
1210 jonathan 430 else:
1211     x = rect.GetX()
1212     y = rect.GetY()
1213     w = rect.GetWidth()
1214     h = rect.GetHeight()
1215    
1216 jonathan 460 stroke = prop.GetLineColor()
1217 jonathan 610 if stroke is Color.Transparent:
1218 jonathan 392 pen = wxTRANSPARENT_PEN
1219     else:
1220 jonathan 430 pen = wxPen(Color2wxColour(stroke),
1221 jonathan 460 prop.GetLineWidth(),
1222 jonathan 392 wxSOLID)
1223    
1224 jonathan 441 stroke = prop.GetFill()
1225 jonathan 610 if stroke is Color.Transparent:
1226 jonathan 392 brush = wxTRANSPARENT_BRUSH
1227     else:
1228 jonathan 430 brush = wxBrush(Color2wxColour(stroke), wxSOLID)
1229 jonathan 392
1230     dc.SetPen(pen)
1231     dc.SetBrush(brush)
1232    
1233 jonathan 415 if shapeType == SHAPETYPE_ARC:
1234 jonathan 430 dc.DrawSpline([wxPoint(x, y + h),
1235     wxPoint(x + w/2, y + h/4),
1236     wxPoint(x + w/2, y + h/4*3),
1237     wxPoint(x + w, y)])
1238 jonathan 392
1239 jonathan 576 elif shapeType == SHAPETYPE_POINT:
1240 jonathan 415
1241 jonathan 430 dc.DrawCircle(x + w/2, y + h/2,
1242 jonathan 460 (min(w, h) - prop.GetLineWidth())/2)
1243 jonathan 392
1244 jonathan 576 elif shapeType == SHAPETYPE_POLYGON:
1245     dc.DrawRectangle(x, y, w, h)
1246    
1247 jonathan 415 class ClassRenderer(wxPyGridCellRenderer):
1248    
1249     def __init__(self, shapeType):
1250     wxPyGridCellRenderer.__init__(self)
1251 jonathan 549 self.shapeType = shapeType
1252     self.previewer = ClassDataPreviewer()
1253 jonathan 415
1254     def Draw(self, grid, attr, dc, rect, row, col, isSelected):
1255 jonathan 485 data = grid.GetTable().GetClassGroup(row)
1256 jonathan 415
1257     dc.SetClippingRegion(rect.GetX(), rect.GetY(),
1258     rect.GetWidth(), rect.GetHeight())
1259     dc.SetPen(wxPen(wxLIGHT_GREY))
1260     dc.SetBrush(wxBrush(wxLIGHT_GREY, wxSOLID))
1261     dc.DrawRectangle(rect.GetX(), rect.GetY(),
1262     rect.GetWidth(), rect.GetHeight())
1263    
1264 jonathan 441 if not isinstance(data, ClassGroupMap):
1265 jonathan 549 self.previewer.Draw(dc, rect, data.GetProperties(), self.shapeType)
1266 jonathan 415
1267     if isSelected:
1268     dc.SetPen(wxPen(wxColour(0 * 255, 0 * 255, 0 * 255),
1269     4, wxSOLID))
1270     dc.SetBrush(wxTRANSPARENT_BRUSH)
1271     dc.DrawRectangle(rect.GetX(), rect.GetY(),
1272     rect.GetWidth(), rect.GetHeight())
1273    
1274 jonathan 392 dc.DestroyClippingRegion()
1275    

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26