/[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 615 - (hide annotations)
Mon Apr 7 08:57:20 2003 UTC (21 years, 11 months ago) by jonathan
File MIME type: text/x-python
File size: 42348 byte(s)
Now that we can depend on the order in
        a Classification and have methods to manipulate that order we don't
        need to use our own data structures in the grid. We can simply make
        the grid/table access the information they need from a copy of
        the classification object.
(Classifier._OnCloseBtn): Event handler for when the user clicks
        'Close'. This is needed so if the user applies changes and then
        continues to change the table the user has the option of discarding
        the most recent changes and keeping what they applied.

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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26