/[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 610 - (hide annotations)
Fri Apr 4 13:56:59 2003 UTC (21 years, 11 months ago) by jonathan
File MIME type: text/x-python
File size: 40792 byte(s)
Rename Color.None to Color.Transparent.

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 570 self.__SelectField(self.__cur_field, group = group)
784    
785     #self.classGrid.SelectGroup(group)
786    
787     controlBox.Add(self.classGrid, 1, wxGROW, 0)
788    
789    
790    
791 jonathan 415 controlBox.Add(controlButtonBox, 0, wxGROW, 10)
792 jonathan 511 panelBox.Add(controlBox, 1, wxGROW, 10)
793 jonathan 415
794 jonathan 460 EVT_BUTTON(self, ID_CLASSIFY_ADD, self._OnAdd)
795 jonathan 606 EVT_BUTTON(self, ID_CLASSIFY_EDITPROPS, self._OnEditGroupProperties)
796 jonathan 460 EVT_BUTTON(self, ID_CLASSIFY_REMOVE, self._OnRemove)
797 jonathan 606 EVT_BUTTON(self, ID_CLASSIFY_GENCLASS, self._OnGenClass)
798 jonathan 460 EVT_BUTTON(self, ID_CLASSIFY_MOVEUP, self._OnMoveUp)
799     EVT_BUTTON(self, ID_CLASSIFY_MOVEDOWN, self._OnMoveDown)
800 jonathan 415
801 jonathan 509 ###########
802    
803 jonathan 372 buttonBox = wxBoxSizer(wxHORIZONTAL)
804 jonathan 509 buttonBox.Add(wxButton(panel, ID_CLASSIFY_OK, _("OK")),
805 jonathan 372 0, wxALL, 4)
806 jonathan 485 buttonBox.Add(60, 20, 0, wxALL, 4)
807 jonathan 509 buttonBox.Add(wxButton(panel, ID_CLASSIFY_APPLY, _("Apply")),
808 jonathan 485 0, wxALL, 4)
809     buttonBox.Add(60, 20, 0, wxALL, 4)
810 jonathan 509 buttonBox.Add(wxButton(panel, ID_CLASSIFY_CANCEL, _("Cancel")),
811 jonathan 372 0, wxALL, 4)
812 jonathan 511 panelBox.Add(buttonBox, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_BOTTOM, 0)
813 jonathan 372
814 jonathan 460 EVT_BUTTON(self, ID_CLASSIFY_OK, self._OnOK)
815 jonathan 485 EVT_BUTTON(self, ID_CLASSIFY_APPLY, self._OnApply)
816 jonathan 460 EVT_BUTTON(self, ID_CLASSIFY_CANCEL, self._OnCancel)
817 jonathan 372
818 jonathan 509 ###########
819    
820 jonathan 496
821 jonathan 509 panel.SetAutoLayout(True)
822 jonathan 511 panel.SetSizer(panelBox)
823     panelBox.SetSizeHints(panel)
824 jonathan 372
825 jonathan 606 topBox.Add(panel, 1, wxGROW, 0)
826 jonathan 511 panelBox.SetSizeHints(self)
827 jonathan 509 self.SetAutoLayout(True)
828 jonathan 511 self.SetSizer(topBox)
829 jonathan 509
830 jonathan 576 #print "1------------------"
831 jonathan 570 #self.Fit()
832 jonathan 549 ######################
833    
834     self.haveApplied = False
835    
836 jonathan 606 def EditGroupProperties(self, row):
837     table = self.classGrid.GetTable()
838     prop = table.GetValueAsCustom(row, COL_SYMBOL, None)
839    
840     # get a new ClassGroupProperties object and copy the
841     # values over to our current object
842     propDlg = SelectPropertiesDialog(NULL, prop, self.layer.ShapeType())
843     if propDlg.ShowModal() == wxID_OK:
844     new_prop = propDlg.GetClassGroupProperties()
845     table.SetValueAsCustom(row, COL_SYMBOL, None, new_prop)
846     propDlg.Destroy()
847    
848    
849 jonathan 460 def __BuildClassification(self, fieldIndex):
850 jonathan 415
851 jonathan 496 numRows = self.classGrid.GetNumberRows()
852 jonathan 606 assert numRows > 0 # there should always be a default row
853 jonathan 496
854 jonathan 415 clazz = Classification()
855 jonathan 496 if fieldIndex == 0:
856     fieldName = None
857     fieldType = None
858     else:
859     fieldName = self.fields.GetString(fieldIndex)
860     fieldType = self.layer.GetFieldType(fieldName)
861 jonathan 415
862 jonathan 460 clazz.SetField(fieldName)
863     clazz.SetFieldType(fieldType)
864    
865 jonathan 415
866 jonathan 460 table = self.classGrid.GetTable()
867     clazz.SetDefaultGroup(table.GetClassGroup(0))
868 jonathan 415
869 jonathan 460 for i in range(1, numRows):
870     clazz.AddGroup(table.GetClassGroup(i))
871    
872 jonathan 415 return clazz
873    
874 jonathan 570 def __SetGridTable(self, fieldIndex, group = None):
875 jonathan 415
876 jonathan 460 clazz = self.fields.GetClientData(fieldIndex)
877 jonathan 415
878 jonathan 460 if clazz is None:
879     clazz = Classification()
880     clazz.SetDefaultGroup(
881     ClassGroupDefault(
882 jonathan 485 self.layer.GetClassification().
883     GetDefaultGroup().GetProperties()))
884 jonathan 460
885     fieldName = self.fields.GetString(fieldIndex)
886     fieldType = self.layer.GetFieldType(fieldName)
887     clazz.SetFieldType(fieldType)
888    
889 jonathan 576 #print "6------------------"
890 jonathan 570 self.classGrid.CreateTable(clazz, self.layer.ShapeType(), group)
891 jonathan 576 #print "7------------------"
892 jonathan 460
893 jonathan 496
894    
895 jonathan 500 type2string = {None: _("None"),
896     FIELDTYPE_STRING: _("Text"),
897     FIELDTYPE_INT: _("Integer"),
898     FIELDTYPE_DOUBLE: _("Decimal")}
899 jonathan 496
900 jonathan 485 def __SetFieldTypeText(self, fieldIndex):
901     fieldName = self.fields.GetString(fieldIndex)
902     fieldType = self.layer.GetFieldType(fieldName)
903    
904 jonathan 606 assert Classifier.type2string.has_key(fieldType)
905 jonathan 485
906 jonathan 496 text = Classifier.type2string[fieldType]
907    
908 jonathan 485 self.fieldTypeText.SetLabel(_("Field Type: %s") % text)
909    
910 jonathan 570 def __SelectField(self, newIndex, oldIndex = -1, group = None):
911 jonathan 460
912 jonathan 576 #print "3------------------"
913 jonathan 570
914 jonathan 606 assert oldIndex >= -1
915 jonathan 415
916 jonathan 570 self.fields.SetSelection(newIndex)
917    
918 jonathan 498 if oldIndex != -1:
919     clazz = self.__BuildClassification(oldIndex)
920     self.fields.SetClientData(oldIndex, clazz)
921 jonathan 485
922 jonathan 576 #print "4------------------"
923 jonathan 570 self.__SetGridTable(newIndex, group)
924 jonathan 576 #print "5------------------"
925 jonathan 498
926     enabled = newIndex != 0
927    
928 jonathan 485 for b in self.controlButtons:
929     b.Enable(enabled)
930    
931 jonathan 498 self.__SetFieldTypeText(newIndex)
932 jonathan 485
933 jonathan 496
934 jonathan 606 def _OnEditGroupProperties(self, event):
935     sel = self.classGrid.GetCurrentSelection()
936    
937     if len(sel) == 1:
938     self.EditGroupProperties(sel[0])
939    
940 jonathan 496 def _OnFieldSelect(self, event):
941 jonathan 498 index = self.fields.GetSelection()
942     self.__SelectField(index, self.__cur_field)
943     self.__cur_field = index
944 jonathan 485
945     def _OnApply(self, event):
946 jonathan 415 """Put the data from the table into a new Classification and hand
947     it to the layer.
948     """
949    
950 jonathan 460 clazz = self.fields.GetClientData(self.__cur_field)
951 jonathan 415
952     #
953     # only build the classification if there wasn't one to
954     # to begin with or it has been modified
955     #
956     if clazz is None or self.classGrid.GetTable().IsModified():
957 jonathan 451 clazz = self.__BuildClassification(self.__cur_field)
958 jonathan 415
959     self.layer.SetClassification(clazz)
960    
961 jonathan 549 self.haveApplied = True
962    
963 jonathan 485 def _OnOK(self, event):
964     self._OnApply(event)
965     self.OnClose(event)
966 jonathan 415
967 jonathan 460 def _OnCancel(self, event):
968 jonathan 485 """The layer's current classification stays the same."""
969 jonathan 549 if self.haveApplied:
970     self.layer.SetClassification(self.originalClass)
971    
972 jonathan 485 self.OnClose(event)
973 jonathan 415
974 jonathan 460 def _OnAdd(self, event):
975 jonathan 451 self.classGrid.AppendRows()
976 jonathan 415
977 jonathan 460 def _OnRemove(self, event):
978 jonathan 451 self.classGrid.DeleteSelectedRows()
979    
980 jonathan 606 def _OnGenClass(self, event):
981 jonathan 415
982 jonathan 606 genDlg = ClassGenDialog(self,
983     self.layer.table,
984     self.fields.GetString(self.__cur_field))
985    
986     if genDlg.ShowModal() == wxID_OK:
987     clazz = genDlg.GetClassification()
988     self.fields.SetClientData(self.__cur_field, clazz)
989     self.classGrid.GetTable().SetClassification(clazz)
990     genDlg.Destroy()
991    
992 jonathan 460 def _OnMoveUp(self, event):
993     sel = self.classGrid.GetCurrentSelection()
994 jonathan 415
995 jonathan 576 #print "sel: ", sel
996 jonathan 570
997 jonathan 460 if len(sel) == 1:
998     i = sel[0]
999     if i > 1:
1000     table = self.classGrid.GetTable()
1001     x = table.GetClassGroup(i - 1)
1002     y = table.GetClassGroup(i)
1003     table.SetClassGroup(i - 1, y)
1004     table.SetClassGroup(i, x)
1005     self.classGrid.ClearSelection()
1006     self.classGrid.SelectRow(i - 1)
1007 jonathan 570 self.classGrid.MakeCellVisible(i - 1, 0)
1008 jonathan 460
1009     def _OnMoveDown(self, event):
1010     sel = self.classGrid.GetCurrentSelection()
1011    
1012     if len(sel) == 1:
1013     i = sel[0]
1014     table = self.classGrid.GetTable()
1015     if 0 < i < table.GetNumberRows() - 1:
1016     x = table.GetClassGroup(i)
1017     y = table.GetClassGroup(i + 1)
1018     table.SetClassGroup(i, y)
1019     table.SetClassGroup(i + 1, x)
1020     self.classGrid.ClearSelection()
1021     self.classGrid.SelectRow(i + 1)
1022 jonathan 570 self.classGrid.MakeCellVisible(i + 1, 0)
1023 jonathan 460
1024    
1025 jonathan 415 ID_SELPROP_OK = 4001
1026     ID_SELPROP_CANCEL = 4002
1027     ID_SELPROP_SPINCTRL = 4002
1028 jonathan 430 ID_SELPROP_PREVIEW = 4003
1029     ID_SELPROP_STROKECLR = 4004
1030     ID_SELPROP_FILLCLR = 4005
1031 jonathan 485 ID_SELPROP_STROKECLRTRANS = 4006
1032     ID_SELPROP_FILLCLRTRANS = 4007
1033 jonathan 415
1034     class SelectPropertiesDialog(wxDialog):
1035    
1036     def __init__(self, parent, prop, shapeType):
1037     wxDialog.__init__(self, parent, -1, _("Select Properties"),
1038 jonathan 507 style = wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
1039 jonathan 415
1040 jonathan 441 self.prop = ClassGroupProperties(prop)
1041 jonathan 415
1042 jonathan 430 topBox = wxBoxSizer(wxVERTICAL)
1043 jonathan 415
1044 jonathan 430 itemBox = wxBoxSizer(wxHORIZONTAL)
1045    
1046     # preview box
1047     previewBox = wxBoxSizer(wxVERTICAL)
1048     previewBox.Add(wxStaticText(self, -1, _("Preview:")),
1049     0, wxALIGN_LEFT | wxALL, 4)
1050 jonathan 549 self.previewWin = ClassDataPreviewWindow(None, self.prop, shapeType,
1051 jonathan 430 self, ID_SELPROP_PREVIEW, (40, 40))
1052 jonathan 549 previewBox.Add(self.previewWin, 1, wxGROW, 15)
1053 jonathan 430
1054     itemBox.Add(previewBox, 1, wxALIGN_LEFT | wxALL | wxGROW, 0)
1055    
1056     # control box
1057     ctrlBox = wxBoxSizer(wxVERTICAL)
1058 jonathan 485
1059     lineColorBox = wxBoxSizer(wxHORIZONTAL)
1060     lineColorBox.Add(
1061 jonathan 500 wxButton(self, ID_SELPROP_STROKECLR, _("Change Line Color")),
1062 jonathan 485 1, wxALL | wxGROW, 4)
1063 jonathan 460 EVT_BUTTON(self, ID_SELPROP_STROKECLR, self._OnChangeLineColor)
1064 jonathan 430
1065 jonathan 485 lineColorBox.Add(
1066 jonathan 500 wxButton(self, ID_SELPROP_STROKECLRTRANS, _("Transparent")),
1067 jonathan 485 1, wxALL | wxGROW, 4)
1068     EVT_BUTTON(self, ID_SELPROP_STROKECLRTRANS,
1069     self._OnChangeLineColorTrans)
1070    
1071     ctrlBox.Add(lineColorBox, 0,
1072     wxALIGN_CENTER_HORIZONTAL | wxALL | wxGROW, 4)
1073    
1074 jonathan 430 if shapeType != SHAPETYPE_ARC:
1075 jonathan 485 fillColorBox = wxBoxSizer(wxHORIZONTAL)
1076     fillColorBox.Add(
1077 jonathan 500 wxButton(self, ID_SELPROP_FILLCLR, _("Change Fill Color")),
1078 jonathan 485 1, wxALL | wxGROW, 4)
1079 jonathan 460 EVT_BUTTON(self, ID_SELPROP_FILLCLR, self._OnChangeFillColor)
1080 jonathan 485 fillColorBox.Add(
1081 jonathan 500 wxButton(self, ID_SELPROP_FILLCLRTRANS, _("Transparent")),
1082 jonathan 485 1, wxALL | wxGROW, 4)
1083     EVT_BUTTON(self, ID_SELPROP_FILLCLRTRANS,
1084     self._OnChangeFillColorTrans)
1085     ctrlBox.Add(fillColorBox, 0,
1086     wxALIGN_CENTER_HORIZONTAL | wxALL | wxGROW, 4)
1087 jonathan 430
1088 jonathan 415 spinBox = wxBoxSizer(wxHORIZONTAL)
1089 jonathan 460 spinBox.Add(wxStaticText(self, -1, _("Line Width: ")),
1090 jonathan 430 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 4)
1091 jonathan 415 self.spinCtrl = wxSpinCtrl(self, ID_SELPROP_SPINCTRL,
1092     min=1, max=10,
1093 jonathan 460 value=str(prop.GetLineWidth()),
1094     initial=prop.GetLineWidth())
1095 jonathan 415
1096 jonathan 460 EVT_SPINCTRL(self, ID_SELPROP_SPINCTRL, self._OnSpin)
1097 jonathan 415
1098     spinBox.Add(self.spinCtrl, 0, wxALIGN_LEFT | wxALL, 4)
1099    
1100 jonathan 430 ctrlBox.Add(spinBox, 0, wxALIGN_RIGHT | wxALL, 0)
1101     itemBox.Add(ctrlBox, 0, wxALIGN_RIGHT | wxALL | wxGROW, 0)
1102     topBox.Add(itemBox, 1, wxALIGN_LEFT | wxALL | wxGROW, 0)
1103 jonathan 415
1104     #
1105     # Control buttons:
1106     #
1107     buttonBox = wxBoxSizer(wxHORIZONTAL)
1108 jonathan 485 buttonBox.Add(wxButton(self, ID_SELPROP_OK, _("OK")),
1109 jonathan 415 0, wxALL, 4)
1110 jonathan 485 buttonBox.Add(wxButton(self, ID_SELPROP_CANCEL, _("Cancel")),
1111 jonathan 415 0, wxALL, 4)
1112     topBox.Add(buttonBox, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_BOTTOM, 10)
1113    
1114 jonathan 460 EVT_BUTTON(self, ID_SELPROP_OK, self._OnOK)
1115     EVT_BUTTON(self, ID_SELPROP_CANCEL, self._OnCancel)
1116 jonathan 415
1117 jonathan 509 self.SetAutoLayout(True)
1118 jonathan 415 self.SetSizer(topBox)
1119     topBox.Fit(self)
1120     topBox.SetSizeHints(self)
1121    
1122 jonathan 460 def _OnOK(self, event):
1123 jonathan 372 self.EndModal(wxID_OK)
1124    
1125 jonathan 460 def _OnCancel(self, event):
1126 jonathan 372 self.EndModal(wxID_CANCEL)
1127    
1128 jonathan 460 def _OnSpin(self, event):
1129     self.prop.SetLineWidth(self.spinCtrl.GetValue())
1130 jonathan 549 self.previewWin.Refresh()
1131 jonathan 392
1132 jonathan 430 def __GetColor(self, cur):
1133     dialog = wxColourDialog(self)
1134 jonathan 610 if cur is not Color.Transparent:
1135 jonathan 606 dialog.GetColourData().SetColour(Color2wxColour(cur))
1136    
1137 jonathan 430 ret = None
1138     if dialog.ShowModal() == wxID_OK:
1139     ret = wxColour2Color(dialog.GetColourData().GetColour())
1140    
1141     dialog.Destroy()
1142    
1143     return ret
1144    
1145 jonathan 460 def _OnChangeLineColor(self, event):
1146     clr = self.__GetColor(self.prop.GetLineColor())
1147 jonathan 430 if clr is not None:
1148 jonathan 460 self.prop.SetLineColor(clr)
1149 jonathan 549 self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer
1150 jonathan 430
1151 jonathan 485 def _OnChangeLineColorTrans(self, event):
1152 jonathan 610 self.prop.SetLineColor(Color.Transparent)
1153 jonathan 549 self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer
1154 jonathan 485
1155 jonathan 460 def _OnChangeFillColor(self, event):
1156 jonathan 430 clr = self.__GetColor(self.prop.GetFill())
1157     if clr is not None:
1158     self.prop.SetFill(clr)
1159 jonathan 549 self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer
1160 jonathan 430
1161 jonathan 485 def _OnChangeFillColorTrans(self, event):
1162 jonathan 610 self.prop.SetFill(Color.Transparent)
1163 jonathan 549 self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer
1164 jonathan 485
1165 jonathan 441 def GetClassGroupProperties(self):
1166 jonathan 415 return self.prop
1167 jonathan 392
1168    
1169 jonathan 549 class ClassDataPreviewWindow(wxWindow):
1170 jonathan 415
1171 jonathan 441 def __init__(self, rect, prop, shapeType,
1172 jonathan 430 parent = None, id = -1, size = wxDefaultSize):
1173     if parent is not None:
1174 jonathan 549 wxWindow.__init__(self, parent, id, (0, 0), size)
1175 jonathan 460 EVT_PAINT(self, self._OnPaint)
1176 jonathan 415
1177 jonathan 430 self.rect = rect
1178 jonathan 549
1179 jonathan 441 self.prop = prop
1180 jonathan 430 self.shapeType = shapeType
1181 jonathan 549 self.previewer = ClassDataPreviewer()
1182 jonathan 430
1183 jonathan 460 def _OnPaint(self, event):
1184 jonathan 430 dc = wxPaintDC(self)
1185    
1186     # XXX: this doesn't seem to be having an effect:
1187     dc.DestroyClippingRegion()
1188    
1189 jonathan 549 if self.rect is None:
1190     w, h = self.GetSize()
1191     rect = wxRect(0, 0, w, h)
1192     else:
1193     rect = self.rect
1194 jonathan 430
1195 jonathan 549 self.previewer.Draw(dc, rect, self.prop, self.shapeType)
1196 jonathan 430
1197 jonathan 549 class ClassDataPreviewer:
1198 jonathan 430
1199 jonathan 549 def Draw(self, dc, rect, prop, shapeType):
1200    
1201 jonathan 606 assert dc is not None
1202     assert isinstance(prop, ClassGroupProperties)
1203 jonathan 549
1204 jonathan 430 if rect is None:
1205 jonathan 549 x = 0
1206     y = 0
1207     w, h = dc.GetSize()
1208 jonathan 430 else:
1209     x = rect.GetX()
1210     y = rect.GetY()
1211     w = rect.GetWidth()
1212     h = rect.GetHeight()
1213    
1214 jonathan 460 stroke = prop.GetLineColor()
1215 jonathan 610 if stroke is Color.Transparent:
1216 jonathan 392 pen = wxTRANSPARENT_PEN
1217     else:
1218 jonathan 430 pen = wxPen(Color2wxColour(stroke),
1219 jonathan 460 prop.GetLineWidth(),
1220 jonathan 392 wxSOLID)
1221    
1222 jonathan 441 stroke = prop.GetFill()
1223 jonathan 610 if stroke is Color.Transparent:
1224 jonathan 392 brush = wxTRANSPARENT_BRUSH
1225     else:
1226 jonathan 430 brush = wxBrush(Color2wxColour(stroke), wxSOLID)
1227 jonathan 392
1228     dc.SetPen(pen)
1229     dc.SetBrush(brush)
1230    
1231 jonathan 415 if shapeType == SHAPETYPE_ARC:
1232 jonathan 430 dc.DrawSpline([wxPoint(x, y + h),
1233     wxPoint(x + w/2, y + h/4),
1234     wxPoint(x + w/2, y + h/4*3),
1235     wxPoint(x + w, y)])
1236 jonathan 392
1237 jonathan 576 elif shapeType == SHAPETYPE_POINT:
1238 jonathan 415
1239 jonathan 430 dc.DrawCircle(x + w/2, y + h/2,
1240 jonathan 460 (min(w, h) - prop.GetLineWidth())/2)
1241 jonathan 392
1242 jonathan 576 elif shapeType == SHAPETYPE_POLYGON:
1243     dc.DrawRectangle(x, y, w, h)
1244    
1245 jonathan 415 class ClassRenderer(wxPyGridCellRenderer):
1246    
1247     def __init__(self, shapeType):
1248     wxPyGridCellRenderer.__init__(self)
1249 jonathan 549 self.shapeType = shapeType
1250     self.previewer = ClassDataPreviewer()
1251 jonathan 415
1252     def Draw(self, grid, attr, dc, rect, row, col, isSelected):
1253 jonathan 485 data = grid.GetTable().GetClassGroup(row)
1254 jonathan 415
1255     dc.SetClippingRegion(rect.GetX(), rect.GetY(),
1256     rect.GetWidth(), rect.GetHeight())
1257     dc.SetPen(wxPen(wxLIGHT_GREY))
1258     dc.SetBrush(wxBrush(wxLIGHT_GREY, wxSOLID))
1259     dc.DrawRectangle(rect.GetX(), rect.GetY(),
1260     rect.GetWidth(), rect.GetHeight())
1261    
1262 jonathan 441 if not isinstance(data, ClassGroupMap):
1263 jonathan 549 self.previewer.Draw(dc, rect, data.GetProperties(), self.shapeType)
1264 jonathan 415
1265     if isSelected:
1266     dc.SetPen(wxPen(wxColour(0 * 255, 0 * 255, 0 * 255),
1267     4, wxSOLID))
1268     dc.SetBrush(wxTRANSPARENT_BRUSH)
1269     dc.DrawRectangle(rect.GetX(), rect.GetY(),
1270     rect.GetWidth(), rect.GetHeight())
1271    
1272 jonathan 392 dc.DestroyClippingRegion()
1273    

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26