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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 400 by jonathan, Tue Feb 11 14:29:09 2003 UTC revision 615 by jonathan, Mon Apr 7 08:57:20 2003 UTC
# Line 1  Line 1 
1  # Copyright (c) 2001 by Intevation GmbH  # Copyright (c) 2001, 2003 by Intevation GmbH
2  # Authors:  # Authors:
3  # Jonathan Coles <[email protected]>  # Jonathan Coles <[email protected]>
4  #  #
# Line 11  __version__ = "$Revision$" Line 11  __version__ = "$Revision$"
11    
12  import copy  import copy
13    
14    from Thuban.Model.table import FIELDTYPE_INT, FIELDTYPE_DOUBLE, \
15         FIELDTYPE_STRING
16    
17  from wxPython.wx import *  from wxPython.wx import *
18  from wxPython.grid import *  from wxPython.grid import *
19    
20  from Thuban import _  from Thuban import _
21    from Thuban.common import *
22    from Thuban.UI.common import *
23    
24    from Thuban.Model.classification import *
25    
26    from Thuban.Model.color import Color
27    
28    from Thuban.Model.layer import Layer, SHAPETYPE_ARC, SHAPETYPE_POLYGON, SHAPETYPE_POINT
29    
30  from Thuban.Model.classification import Classification  from Thuban.UI.classgen import ClassGenDialog, ClassGenerator
31    
32  from Thuban.Model.layer import SHAPETYPE_ARC, SHAPETYPE_POLYGON, SHAPETYPE_POINT  from dialogs import NonModalDialog
33    
34    # widget id's
35  ID_PROPERTY_SELECT = 4010  ID_PROPERTY_SELECT = 4010
36  ID_CLASS_TABLE = 40011  ID_CLASS_TABLE = 40011
37    
38  ID_CLASSIFY_OK = 4001  ID_CLASSIFY_OK = 4001
39  ID_CLASSIFY_CANCEL = 4002  ID_CLASSIFY_CANCEL = 4002
40    ID_CLASSIFY_ADD = 4003
41    ID_CLASSIFY_GENCLASS = 4004
42    ID_CLASSIFY_REMOVE = 4005
43    ID_CLASSIFY_MOVEUP = 4006
44    ID_CLASSIFY_MOVEDOWN = 4007
45    ID_CLASSIFY_APPLY = 4008
46    ID_CLASSIFY_EDITPROPS = 4009
47    ID_CLASSIFY_CLOSE = 4010
48    
49    # table columns
50    COL_SYMBOL = 0
51    COL_VALUE  = 1
52    COL_LABEL  = 2
53    
54    # indices into the client data lists in Classifier.fields
55    FIELD_CLASS = 0
56    FIELD_TYPE = 1
57    FIELD_NAME = 2
58    
59    #
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    
67        def __init__(self, parent, classifier):
68            """Constructor.
69    
70            parent -- the parent window
71    
72            clazz -- the working classification that this grid should
73                     use for display.
74            """
75    
76            #wxGrid.__init__(self, parent, ID_CLASS_TABLE, size = (340, 160))
77            wxGrid.__init__(self, parent, ID_CLASS_TABLE)
78            #self.SetTable(ClassTable(fieldData, layer.ShapeType(), self), True)
79    
80            self.classifier = classifier
81    
82            self.currentSelection = []
83    
84            EVT_GRID_CELL_LEFT_DCLICK(self, self._OnCellDClick)
85            EVT_GRID_RANGE_SELECT(self, self._OnSelectedRange)
86            EVT_GRID_SELECT_CELL(self, self._OnSelectedCell)
87            EVT_GRID_COL_SIZE(self, self._OnCellResize)
88            EVT_GRID_ROW_SIZE(self, self._OnCellResize)
89    
90            #print "123123123: ", ('Show' in dir(self))
91    
92        #def Show(self):
93            #print "SHOW!"
94    
95        #def Refresh(self):
96            #self.Show()
97        #def Update(self):
98            #self.Show()
99    
100        def CreateTable(self, clazz, shapeType, group = None):
101    
102            assert isinstance(clazz, Classification)
103    
104            table = self.GetTable()
105            if table is None:
106                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                table = ClassTable(self)
111                self.SetTable(table, True)
112    
113    
114            self.SetSelectionMode(wxGrid.wxGridSelectRows)
115            self.ClearSelection()
116    
117            #print "8------------------"
118            table.Reset(clazz, shapeType, group)
119            #print "9------------------"
120    
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        def GetCurrentSelection(self):
133            """Return the currently highlighted rows as an increasing list
134               of row numbers."""
135            #print "@@ ", self.currentSelection
136            sel = copy.copy(self.currentSelection)
137            sel.sort()
138            return sel
139    
140        def GetSelectedRows(self):
141            return self.GetCurrentSelection()
142    
143        def SetCellRenderer(self, row, col):
144            raise ValueError(_("Must not allow setting of renderer in ClassGrid!"))
145    
146        #
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        def SetTable(self, object, *attributes):
153            self.tableRef = weakref.ref(object)
154            return wxGrid.SetTable(self, object, *attributes)
155    
156        def GetTable(self):
157            try:
158                return self.tableRef()
159            except:
160                return None
161    
162        def DeleteSelectedRows(self):
163            """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            sel = self.GetCurrentSelection()
169    
170            # 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            if len(sel) == 1:
176                #group = self.GetTable().GetValueAsCustom(sel[0], COL_SYMBOL, None)
177                group = self.GetTable().GetClassGroup(sel[0])
178                if isinstance(group, ClassGroupDefault):
179                    wxMessageDialog(self,
180                                    "The Default group cannot be removed.",
181                                    style = wxOK | wxICON_EXCLAMATION).ShowModal()
182                    return
183            
184    
185            self.ClearSelection()
186    
187            # 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            sel.reverse()
190    
191            #
192            # actually remove the rows
193            #
194            table = self.GetTable()
195            for row in sel:
196                table.DeleteRows(row)
197    
198            #
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            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    
210        def SelectGroup(self, group, makeVisible = True):
211            if group is None: return
212    
213            assert isinstance(group, ClassGroup)
214    
215            table = self.GetTable()
216    
217            assert table is not None
218    
219    
220            #print "-- ", group
221            for i in range(table.GetNumberRows()):
222                g = table.GetClassGroup(i)
223                #print "1", g
224                if g is group:
225                    #print "2"
226                    self.SelectRow(i)
227                    if makeVisible:
228                        #print "3"
229                        self.MakeCellVisible(i, 0)
230                    break
231    
232            
233    
234    #
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        def _OnCellDClick(self, event):
246            """Handle a double on a cell."""
247    
248            r = event.GetRow()
249            c = event.GetCol()
250            if c == COL_SYMBOL:
251                self.classifier.EditGroupProperties(r)
252    
253    
254        #
255        # _OnSelectedRange() and _OnSelectedCell() were borrowed
256        # from http://wiki.wxpython.org to keep track of which
257        # cells are currently highlighted
258        #
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                        #print "    ", index
265                        self.currentSelection.append( index )
266            else:
267                for index in range( event.GetTopRow(), event.GetBottomRow()+1):
268                    while index in self.currentSelection:
269                        #print "    ", index
270                        self.currentSelection.remove( index )
271            #self.ConfigureForSelection()
272    
273            #print self.GetCurrentSelection()
274            event.Skip()
275    
276        def _OnSelectedCell( self, event ):
277            """Internal update to the selection tracking list"""
278            #print "selecting cell: ", event.GetRow()
279            self.currentSelection = [ event.GetRow() ]
280            #self.ConfigureForSelection()
281            event.Skip()
282    
283        def _OnCellResize(self, event):
284            self.FitInside()
285    
286  class ClassTable(wxPyGridTableBase):  class ClassTable(wxPyGridTableBase):
287        """Represents the underlying data structure for the grid."""
288    
289        NUM_COLS = 3
290    
291        __col_labels = [_("Symbol"), _("Value"), _("Label")]
292    
293    
294        def __init__(self, view = None):
295        #def __init__(self, clazz, shapeType, view = None):
296            """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    
     def __init__(self, clinfo):  
303          wxPyGridTableBase.__init__(self)          wxPyGridTableBase.__init__(self)
304    
305          self.tdata = []          self.SetView(view)
306            self.clazz = None
307    
308          self.tdata.append([clinfo.DefaultData, 'DEFAULT'])          #self.Reset(clazz, shapeType)
309    
310          for value, data in clinfo.points.items():      def Reset(self, clazz, shapeType, group = None):
311              self.tdata.append([data, value])          """Reset the table with the given data.
312    
313          for range in clinfo.ranges:          This is necessary because wxWindows does not allow a grid's
314              self.tdata.append([range[2], '%s-%s' % range[0], range[1]])          table to change once it has been intially set and so we
315            need a way of modifying the data.
316    
317          self.SetColLabelValue(1, _("Data Values"))          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            assert isinstance(clazz, Classification)
325    
326            self.GetView().BeginBatch()
327    
328            self.fieldType = clazz.GetFieldType()
329            self.shapeType = shapeType
330    
331            self.SetClassification(clazz, group)
332            self.__Modified(-1)
333            #print "11------------------"
334    
335            self.GetView().EndBatch()
336            self.GetView().FitInside()
337    
338        def GetClassification(self):
339            return self.clazz
340    
341        def SetClassification(self, clazz, group = None):
342    
343            self.GetView().BeginBatch()
344    
345            old_len = self.GetNumberRows()
346    
347            #print "9------------------"
348            #
349            # copy the data out of the classification and into our
350            # array
351            #
352            row = -1
353    #       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    
360            #print "10------------------"
361    
362            #self.clazz = copy.deepcopy(clazz)
363            self.clazz = clazz
364    
365            self.__NotifyRowChanges(old_len, self.GetNumberRows())
366    
367            if row > -1:
368                self.GetView().ClearSelection()
369                self.GetView().SelectRow(row)
370                self.GetView().MakeCellVisible(row, 0)
371    
372            self.__Modified()
373    
374            self.GetView().EndBatch()
375            self.GetView().FitInside()
376    
377        def __NotifyRowChanges(self, curRows, newRows):
378            #
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                self.GetView().FitInside()
388            elif newRows < curRows:
389                msg = wxGridTableMessage(self,
390                            wxGRIDTABLE_NOTIFY_ROWS_DELETED,
391                            curRows,              # position
392                            curRows - newRows)    # how many
393                self.GetView().ProcessTableMessage(msg)
394                self.GetView().FitInside()
395    
396    
397        def __SetRow(self, row, group):
398            """Set a row's data to that of the group.
399    
400            The table is considered modified after this operation.
401    
402            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            """
407    
408            # either append or replace
409            if row is None or row >= self.GetNumberRows():
410                self.clazz.AppendGroup(group)
411            elif row < 0:
412                self.clazz.InsertGroup(0, group)
413            else:
414                if row == 0:
415                    self.clazz.SetDefaultGroup(group)
416                else:
417                    self.clazz.ReplaceGroup(row - 1, group)
418    
419            self.__Modified()
420    
421        def GetColLabelValue(self, col):
422            """Return the label for the given column."""
423            return self.__col_labels[col]
424    
425        def GetRowLabelValue(self, row):
426            """Return the label for the given row."""
427    
428            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    
437            assert False # shouldn't get here
438            return _("")
439    
440      def GetNumberRows(self):      def GetNumberRows(self):
441          return len(self.tdata)          """Return the number of rows."""
442            if self.clazz is None:
443                return 0
444    
445            return self.clazz.GetNumGroups() + 1 # +1 for default group
446    
447      def GetNumberCols(self):      def GetNumberCols(self):
448          return 2          """Return the number of columns."""
449            return self.NUM_COLS
450    
451      def IsEmptyCell(self, row, col):      def IsEmptyCell(self, row, col):
452          return false          """Determine if a cell is empty. This is always false."""
453            return False
454    
455      def GetValue(self, row, col):      def GetValue(self, row, col):
456          return self.tdata[row][col]          """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    
460      def SetValue(self, row, col, value):      def SetValue(self, row, col, value):
461          self.tdata[row][col] = value          """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            self.__Modified()
468          
469      def GetValueAsCustom(self, row, col, typeName):      def GetValueAsCustom(self, row, col, typeName):
470          return self.tdata[row][col]          """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    
476            if row == 0:
477                group = self.clazz.GetDefaultGroup()
478            else:
479                group = self.clazz.GetGroup(row - 1)
480    
481    
482            if col == COL_SYMBOL:
483                return group.GetProperties()
484    
485            if col == COL_LABEL:
486                return group.GetLabel()
487    
488            # col must be COL_VALUE
489            assert col == COL_VALUE
490    
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            assert(False) # shouldn't get here
499            return None
500    
501        def __ParseInput(self, value):
502            """Try to determine what kind of input value is
503               (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            """
508    
509            type = self.fieldType
510    
511            if type == FIELDTYPE_STRING:
512                return (value,)
513            elif type == FIELDTYPE_INT or type == FIELDTYPE_DOUBLE:
514    
515                if type == FIELDTYPE_INT:
516                    conv = lambda p: int(float(p))
517                else:
518                    conv = lambda p: p
519    
520                #
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                    return (conv(Str2Num(value)),)
531                except ValueError:
532                    i = value.find('-')
533                    if i == 0:
534                        i = value.find('-', 1)
535    
536                    return (conv(Str2Num(value[:i])), conv(Str2Num(value[i+1:])))
537    
538            assert False  # shouldn't get here
539            return (0,)
540                
541    
542        def SetValueAsCustom(self, row, col, typeName, value):
543            """Set the cell specified by 'row' and 'col' to 'value'.
544    
545            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            assert col >= 0 and col < self.GetNumberCols()
555            assert row >= 0 and row < self.GetNumberRows()
556    
557            if row == 0:
558                group = self.clazz.GetDefaultGroup()
559            else:
560                group = self.clazz.GetGroup(row - 1)
561    
562            mod = True # assume the data will change
563    
564  class Classifier(wxDialog):          if col == COL_SYMBOL:
565                group.SetProperties(value)
566            elif col == COL_LABEL:
567                group.SetLabel(value)
568            elif col == COL_VALUE:
569                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                    except ValueError:
579                        # bad input, ignore the request
580                        mod = False
581                    else:
582    
583                        changed = False
584                        ngroup = group
585                        props = group.GetProperties()
586    
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                        if len(dataInfo) == 1:
593                            if not isinstance(group, ClassGroupSingleton):
594                                ngroup = ClassGroupSingleton(prop = props)
595                                changed = True
596                            ngroup.SetValue(dataInfo[0])
597                        elif len(dataInfo) == 2:
598                            if not isinstance(group, ClassGroupRange):
599                                ngroup = ClassGroupRange(prop = props)
600                                changed = True
601                            ngroup.SetRange(dataInfo[0], dataInfo[1])
602                        else:
603                            assert False
604                            pass
605    
606                        if changed:
607                            ngroup.SetLabel(group.GetLabel())
608                            self.SetClassGroup(row, ngroup)
609            else:
610                assert False # shouldn't be here
611                pass
612    
613            if mod:
614                self.__Modified()
615                self.GetView().Refresh()
616    
617        def GetAttr(self, row, col, someExtraParameter):
618            """Returns the cell attributes"""
619    
620            attr = wxGridCellAttr()
621            #attr = wxPyGridTableBase.GetAttr(self, row, col, someExtraParameter)
622    
623            if col == COL_SYMBOL:
624                # we need to create a new renderer each time, because
625                # SetRenderer takes control of the parameter
626                attr.SetRenderer(ClassRenderer(self.shapeType))
627                attr.SetReadOnly()
628    
629            return attr
630    
631        def GetClassGroup(self, row):
632            """Return the ClassGroup object representing row 'row'."""
633    
634            #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    
640        def SetClassGroup(self, row, group):
641            self.__SetRow(row, group)
642            self.GetView().Refresh()
643    
644        def __Modified(self, mod = True):
645            """Adjust the modified flag.
646    
647            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        def IsModified(self):
658            """True if this table is considered modified."""
659            return self.modified
660    
661        def DeleteRows(self, pos, numRows = 1):
662            """Deletes 'numRows' beginning at row 'pos'.
663    
664            The row representing the default group is not removed.
665    
666            The table is considered modified if any rows are removed.
667            """
668    
669            assert pos >= 0
670            old_len = self.GetNumberRows()
671            for row in range(pos, pos - numRows, -1):
672                group = self.GetClassGroup(row)
673                if row != 0:
674                    self.clazz.RemoveGroup(row - 1)
675                    self.__Modified()
676            
677      def __init__(self, parent, layer):          if self.IsModified():
678          wxDialog.__init__(self, parent, -1, _("Classify"),              self.__NotifyRowChanges(old_len, self.GetNumberRows())
679                            style = wxRESIZE_BORDER)  
680        def AppendRows(self, numRows = 1):
681            """Append 'numRows' empty rows to the end of the table.
682    
683            The table is considered modified if any rows are appended.
684            """
685    
686            old_len = self.GetNumberRows()
687            for i in range(numRows):
688                np = ClassGroupSingleton()
689                self.__SetRow(None, np)
690    
691            if self.IsModified():
692                self.__NotifyRowChanges(old_len, self.GetNumberRows())
693    
694    
695    class Classifier(NonModalDialog):
696    
697        def __init__(self, parent, name, layer, group = None):
698            NonModalDialog.__init__(self, parent, name,
699                                    _("Classifier: %s") % layer.Title())
700    
701            panel = wxPanel(self, -1, size=(100, 100))
702    
703            self.layer = layer
704    
705            self.originalClass = self.layer.GetClassification()
706            field = self.originalClass.GetField()
707            fieldType = self.originalClass.GetFieldType()
708    
709          topBox = wxBoxSizer(wxVERTICAL)          topBox = wxBoxSizer(wxVERTICAL)
710            panelBox = wxBoxSizer(wxVERTICAL)
711    
712            #panelBox.Add(wxStaticText(panel, -1, _("Layer: %s") % layer.Title()),
713                #0, wxALIGN_LEFT | wxALL, 4)
714            panelBox.Add(wxStaticText(panel, -1,
715                                    _("Layer Type: %s") % layer.ShapeType()),
716                0, wxALIGN_LEFT | wxALL, 4)
717    
         propertyBox = wxBoxSizer(wxHORIZONTAL)  
         propertyBox.Add(wxStaticText(self, -1, _("Property")),  
             0, wxALIGN_CENTER | wxALL, 4)  
718    
719          self.properties = wxComboBox(self, ID_PROPERTY_SELECT, "",          #
720            # make field combo box
721            #
722            self.fields = wxComboBox(panel, ID_PROPERTY_SELECT, "",
723                                       style = wxCB_READONLY)                                       style = wxCB_READONLY)
724    
725          self.num_cols = layer.table.field_count()          self.num_cols = layer.table.field_count()
726          cur_hilight = 0          # just assume the first field in case one hasn't been
727            # specified in the file.
728            self.__cur_field = 0
729    
730            self.fields.Append("<None>")
731            self.fields.SetClientData(0, None)
732    
733          for i in range(self.num_cols):          for i in range(self.num_cols):
734              type, name, len, decc = layer.table.field_info(i)              type, name, len, decc = layer.table.field_info(i)
735              if name == layer.classification.field:              self.fields.Append(name)
736                  cur_hilight = i  
737              self.properties.Append(name)              if name == field:
738                    self.__cur_field = i + 1
739          self.properties.SetSelection(cur_hilight)                  self.fields.SetClientData(i + 1,
740          propertyBox.Add(self.properties, 1, wxGROW, 4)                                            copy.deepcopy(self.originalClass))
741          EVT_COMBOBOX(self, ID_PROPERTY_SELECT, self.OnPropertySelect)              else:
742                    self.fields.SetClientData(i + 1, None)
743    
744    
745            ###########
746    
747            self.fieldTypeText = wxStaticText(panel, -1, "")
748            panelBox.Add(self.fieldTypeText, 0,
749                         wxGROW | wxALIGN_LEFT | wxALL | wxADJUST_MINSIZE, 4)
750    
751            propertyBox = wxBoxSizer(wxHORIZONTAL)
752            propertyBox.Add(wxStaticText(panel, -1, _("Field: ")),
753                0, wxALIGN_LEFT | wxALL, 4)
754            propertyBox.Add(self.fields, 1, wxGROW|wxALL, 4)
755            EVT_COMBOBOX(self, ID_PROPERTY_SELECT, self._OnFieldSelect)
756    
757            panelBox.Add(propertyBox, 0, wxGROW, 4)
758    
759    
760            #
761            # Control Box
762            #
763            controlBox = wxBoxSizer(wxHORIZONTAL)
764    
765    
766            ###########
767            #
768            # Control buttons:
769            #
770            self.controlButtons = []
771    
772            controlButtonBox = wxBoxSizer(wxVERTICAL)
773    
774            button = wxButton(panel, ID_CLASSIFY_ADD, _("Add"))
775            controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)
776            self.controlButtons.append(button)
777    
778            button = wxButton(panel, ID_CLASSIFY_EDITPROPS, _("Edit Properties"))
779            controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)
780            self.controlButtons.append(button)
781    
782            button = wxButton(panel, ID_CLASSIFY_GENCLASS, _("Generate Class"))
783            controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)
784            self.controlButtons.append(button)
785    
786            button = wxButton(panel, ID_CLASSIFY_MOVEUP, _("Move Up"))
787            controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)
788            self.controlButtons.append(button)
789    
790          topBox.Add(propertyBox, 0, wxGROW, 4)          button = wxButton(panel, ID_CLASSIFY_MOVEDOWN, _("Move Down"))
791            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            button = wxButton(panel, ID_CLASSIFY_REMOVE, _("Remove"))
797            controlButtonBox.Add(button, 0, wxGROW | wxALL | wxALIGN_BOTTOM, 4)
798            self.controlButtons.append(button)
799    
800    
801            ###########
802          #          #
803          # Classification data table          # Classification data table
804          #          #
805    
806          self.classTable = wxGrid(self, ID_CLASS_TABLE, size=(300, 150))          self.classGrid = ClassGrid(panel, self)
807            #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            #print "2------------------"
813            self.fields.SetSelection(self.__cur_field)
814            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            controlBox.Add(controlButtonBox, 0, wxGROW, 10)
823            panelBox.Add(controlBox, 1, wxGROW, 10)
824    
825            EVT_BUTTON(self, ID_CLASSIFY_ADD, self._OnAdd)
826            EVT_BUTTON(self, ID_CLASSIFY_EDITPROPS, self._OnEditGroupProperties)
827            EVT_BUTTON(self, ID_CLASSIFY_REMOVE, self._OnRemove)
828            EVT_BUTTON(self, ID_CLASSIFY_GENCLASS, self._OnGenClass)
829            EVT_BUTTON(self, ID_CLASSIFY_MOVEUP, self._OnMoveUp)
830            EVT_BUTTON(self, ID_CLASSIFY_MOVEDOWN, self._OnMoveDown)
831    
832            ###########
833    
834            buttonBox = wxBoxSizer(wxHORIZONTAL)
835            buttonBox.Add(wxButton(panel, ID_CLASSIFY_OK, _("OK")),
836                          0, wxALL, 4)
837            buttonBox.Add(60, 20, 0, wxALL, 4)
838            buttonBox.Add(wxButton(panel, ID_CLASSIFY_APPLY, _("Apply")),
839                          0, wxALL, 4)
840            buttonBox.Add(60, 20, 0, wxALL, 4)
841            buttonBox.Add(wxButton(panel, ID_CLASSIFY_CLOSE, _("Close")),
842                          0, wxALL, 4)
843            buttonBox.Add(60, 20, 0, wxALL, 4)
844            buttonBox.Add(wxButton(panel, ID_CLASSIFY_CANCEL, _("Cancel")),
845                          0, wxALL, 4)
846            panelBox.Add(buttonBox, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_BOTTOM, 0)
847    
848            EVT_BUTTON(self, ID_CLASSIFY_OK, self._OnOK)
849            EVT_BUTTON(self, ID_CLASSIFY_APPLY, self._OnApply)
850            EVT_BUTTON(self, ID_CLASSIFY_CLOSE, self._OnCloseBtn)
851            EVT_BUTTON(self, ID_CLASSIFY_CANCEL, self._OnCancel)
852    
853            ###########
854    
855    
856            panel.SetAutoLayout(True)
857            panel.SetSizer(panelBox)
858            panelBox.SetSizeHints(panel)
859    
860            topBox.Add(panel, 1, wxGROW, 0)
861            panelBox.SetSizeHints(self)
862            self.SetAutoLayout(True)
863            self.SetSizer(topBox)
864    
865            #print "1------------------"
866            #self.Fit()
867            ######################
868    
869            self.haveApplied = False
870    
871        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        def __BuildClassification(self, fieldIndex, copyClass = False):
885    
886    #       numRows = self.classGrid.GetNumberRows()
887    #       assert numRows > 0  # there should always be a default row
888    
889    #       clazz = Classification()
890            if fieldIndex == 0:
891                fieldName = None
892                fieldType = None
893            else:
894                fieldName = self.fields.GetString(fieldIndex)
895                fieldType = self.layer.GetFieldType(fieldName)
896    
897            clazz = self.classGrid.GetTable().GetClassification()
898    
899            if copyClass:
900                clazz = copy.deepcopy(clazz)
901    
902            clazz.SetField(fieldName)
903            clazz.SetFieldType(fieldType)
904    
905    
906    #       table = self.classGrid.GetTable()
907    #       clazz.SetDefaultGroup(table.GetClassGroup(0))
908    
909    #       for i in range(1, numRows):
910    #           clazz.AppendGroup(table.GetClassGroup(i))
911    
912            return clazz
913    
914        def __SetGridTable(self, fieldIndex, group = None):
915    
916            clazz = self.fields.GetClientData(fieldIndex)
917    
918            if clazz is None:
919                clazz = Classification()
920                clazz.SetDefaultGroup(
921                    ClassGroupDefault(
922                        self.layer.GetClassification().
923                                   GetDefaultGroup().GetProperties()))
924    
925                fieldName = self.fields.GetString(fieldIndex)
926                fieldType = self.layer.GetFieldType(fieldName)
927                clazz.SetFieldType(fieldType)
928                    
929            #print "6------------------"
930            self.classGrid.CreateTable(clazz, self.layer.ShapeType(), group)
931            #print "7------------------"
932    
933    
934    
935        type2string = {None:             _("None"),
936                       FIELDTYPE_STRING: _("Text"),
937                       FIELDTYPE_INT:    _("Integer"),
938                       FIELDTYPE_DOUBLE: _("Decimal")}
939    
940        def __SetFieldTypeText(self, fieldIndex):
941            fieldName = self.fields.GetString(fieldIndex)
942            fieldType = self.layer.GetFieldType(fieldName)
943    
944            assert Classifier.type2string.has_key(fieldType)
945    
946            text = Classifier.type2string[fieldType]
947    
948            self.fieldTypeText.SetLabel(_("Field Type: %s") % text)
949    
950        def __SelectField(self, newIndex, oldIndex = -1, group = None):
951            """This method assumes that the current selection for the
952            combo has already been set by a call to SetSelection().
953            """
954    
955            #print "3------------------"
956    
957            assert oldIndex >= -1
958    
959            if oldIndex != -1:
960                clazz = self.__BuildClassification(oldIndex)
961                self.fields.SetClientData(oldIndex, clazz)
962    
963            #print "4------------------"
964            self.__SetGridTable(newIndex, group)
965            #print "5------------------"
966    
967          table = ClassTable(layer.classification)          enabled = newIndex != 0
         self.classTable.SetTable(table, true)  
         self.classTable.EnableEditing(false)  
         cr = ClassRenderer(layer.ShapeType())  
         for i in range(self.classTable.GetNumberRows()):  
             self.classTable.SetCellRenderer(i, 0, cr)  
968    
969          topBox.Add(self.classTable, 1, wxGROW, 0)          for b in self.controlButtons:
970                b.Enable(enabled)
971    
972            self.__SetFieldTypeText(newIndex)
973    
974    
975        def _OnEditGroupProperties(self, event):
976            sel = self.classGrid.GetCurrentSelection()
977    
978            if len(sel) == 1:
979                self.EditGroupProperties(sel[0])
980    
981        def _OnFieldSelect(self, event):
982            index = self.fields.GetSelection()
983            self.__SelectField(index, self.__cur_field)
984            self.__cur_field = index
985    
986        def _OnApply(self, event):
987            """Put the data from the table into a new Classification and hand
988               it to the layer.
989            """
990    
991            clazz = self.fields.GetClientData(self.__cur_field)
992    
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                clazz = self.__BuildClassification(self.__cur_field, True)
999    
1000            self.layer.SetClassification(clazz)
1001    
1002            self.haveApplied = True
1003    
1004        def _OnOK(self, event):
1005            self._OnApply(event)
1006            self.Close()
1007    
1008        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        def _OnCancel(self, event):
1017            """The layer's current classification stays the same."""
1018            if self.haveApplied:
1019                self.layer.SetClassification(self.originalClass)
1020    
1021            self.Close()
1022    
1023        def _OnAdd(self, event):
1024            self.classGrid.AppendRows()
1025    
1026        def _OnRemove(self, event):
1027            self.classGrid.DeleteSelectedRows()
1028    
1029        def _OnGenClass(self, event):
1030    
1031            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        def _OnMoveUp(self, event):
1042            sel = self.classGrid.GetCurrentSelection()
1043    
1044            #print "sel: ", sel
1045    
1046            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                    self.classGrid.MakeCellVisible(i - 1, 0)
1057    
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                    self.classGrid.MakeCellVisible(i + 1, 0)
1072    
1073    
1074    ID_SELPROP_OK = 4001
1075    ID_SELPROP_CANCEL = 4002
1076    ID_SELPROP_SPINCTRL = 4002
1077    ID_SELPROP_PREVIEW = 4003
1078    ID_SELPROP_STROKECLR = 4004
1079    ID_SELPROP_FILLCLR = 4005
1080    ID_SELPROP_STROKECLRTRANS = 4006
1081    ID_SELPROP_FILLCLRTRANS = 4007
1082    
1083    class SelectPropertiesDialog(wxDialog):
1084    
1085        def __init__(self, parent, prop, shapeType):
1086            wxDialog.__init__(self, parent, -1, _("Select Properties"),
1087                              style = wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
1088    
1089            self.prop = ClassGroupProperties(prop)
1090    
1091            topBox = wxBoxSizer(wxVERTICAL)
1092    
1093            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            self.previewWin = ClassDataPreviewWindow(None, self.prop, shapeType,
1100                                                self, ID_SELPROP_PREVIEW, (40, 40))
1101            previewBox.Add(self.previewWin, 1, wxGROW | wxALL, 4)
1102    
1103            itemBox.Add(previewBox, 1, wxALIGN_LEFT | wxALL | wxGROW, 0)
1104    
1105            # control box
1106            ctrlBox = wxBoxSizer(wxVERTICAL)
1107    
1108            lineColorBox = wxBoxSizer(wxHORIZONTAL)
1109            lineColorBox.Add(
1110                wxButton(self, ID_SELPROP_STROKECLR, _("Change Line Color")),
1111                1, wxALL | wxGROW, 4)
1112            EVT_BUTTON(self, ID_SELPROP_STROKECLR, self._OnChangeLineColor)
1113    
1114            lineColorBox.Add(
1115                wxButton(self, ID_SELPROP_STROKECLRTRANS, _("Transparent")),
1116                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            if shapeType != SHAPETYPE_ARC:
1124                fillColorBox = wxBoxSizer(wxHORIZONTAL)
1125                fillColorBox.Add(
1126                    wxButton(self, ID_SELPROP_FILLCLR, _("Change Fill Color")),
1127                    1, wxALL | wxGROW, 4)
1128                EVT_BUTTON(self, ID_SELPROP_FILLCLR, self._OnChangeFillColor)
1129                fillColorBox.Add(
1130                    wxButton(self, ID_SELPROP_FILLCLRTRANS, _("Transparent")),
1131                    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    
1137            spinBox = wxBoxSizer(wxHORIZONTAL)
1138            spinBox.Add(wxStaticText(self, -1, _("Line Width: ")),
1139                    0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 4)
1140            self.spinCtrl = wxSpinCtrl(self, ID_SELPROP_SPINCTRL,
1141                                       min=1, max=10,
1142                                       value=str(prop.GetLineWidth()),
1143                                       initial=prop.GetLineWidth())
1144    
1145            EVT_SPINCTRL(self, ID_SELPROP_SPINCTRL, self._OnSpin)
1146    
1147            spinBox.Add(self.spinCtrl, 0, wxALIGN_LEFT | wxALL, 4)
1148    
1149            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    
1153          #          #
1154          # Control buttons:          # Control buttons:
1155          #          #
1156          buttonBox = wxBoxSizer(wxHORIZONTAL)          buttonBox = wxBoxSizer(wxHORIZONTAL)
1157          buttonBox.Add(wxButton(self, ID_CLASSIFY_OK, _("OK")),          buttonBox.Add(wxButton(self, ID_SELPROP_OK, _("OK")),
1158                        0, wxALL, 4)                        0, wxALL, 4)
1159          buttonBox.Add(wxButton(self, ID_CLASSIFY_CANCEL, _("Cancel")),          buttonBox.Add(wxButton(self, ID_SELPROP_CANCEL, _("Cancel")),
1160                        0, wxALL, 4)                        0, wxALL, 4)
1161          topBox.Add(buttonBox, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_BOTTOM, 10)          topBox.Add(buttonBox, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_BOTTOM, 10)
1162                                                                                    
1163          EVT_BUTTON(self, ID_CLASSIFY_OK, self.OnOK)          EVT_BUTTON(self, ID_SELPROP_OK, self._OnOK)
1164          EVT_BUTTON(self, ID_CLASSIFY_CANCEL, self.OnCancel)          EVT_BUTTON(self, ID_SELPROP_CANCEL, self._OnCancel)
1165                                                                                    
1166          self.SetAutoLayout(true)          self.SetAutoLayout(True)
1167          self.SetSizer(topBox)          self.SetSizer(topBox)
1168          topBox.Fit(self)          topBox.Fit(self)
1169          topBox.SetSizeHints(self)          topBox.SetSizeHints(self)
1170    
1171      def OnPropertySelect(self, event): pass      def _OnOK(self, event):
   
     def OnOK(self, event):  
1172          self.EndModal(wxID_OK)          self.EndModal(wxID_OK)
1173    
1174      def OnCancel(self, event):      def _OnCancel(self, event):
1175          self.EndModal(wxID_CANCEL)          self.EndModal(wxID_CANCEL)
1176    
1177        def _OnSpin(self, event):
1178            self.prop.SetLineWidth(self.spinCtrl.GetValue())
1179            self.previewWin.Refresh()
1180    
1181        def __GetColor(self, cur):
1182            dialog = wxColourDialog(self)
1183            if cur is not Color.Transparent:
1184                dialog.GetColourData().SetColour(Color2wxColour(cur))
1185    
1186            ret = None
1187            if dialog.ShowModal() == wxID_OK:
1188                ret = wxColour2Color(dialog.GetColourData().GetColour())
1189    
1190            dialog.Destroy()
1191    
1192            return ret
1193            
1194        def _OnChangeLineColor(self, event):
1195            clr = self.__GetColor(self.prop.GetLineColor())
1196            if clr is not None:
1197                self.prop.SetLineColor(clr)
1198            self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer
1199    
1200        def _OnChangeLineColorTrans(self, event):
1201            self.prop.SetLineColor(Color.Transparent)
1202            self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer
1203            
1204        def _OnChangeFillColor(self, event):
1205            clr = self.__GetColor(self.prop.GetFill())
1206            if clr is not None:
1207                self.prop.SetFill(clr)
1208            self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer
1209    
1210        def _OnChangeFillColorTrans(self, event):
1211            self.prop.SetFill(Color.Transparent)
1212            self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer
1213    
1214        def GetClassGroupProperties(self):
1215            return self.prop
1216    
1217    
1218    class ClassDataPreviewWindow(wxWindow):
1219    
1220        def __init__(self, rect, prop, shapeType,
1221                           parent = None, id = -1, size = wxDefaultSize):
1222            if parent is not None:
1223                wxWindow.__init__(self, parent, id, (0, 0), size)
1224                EVT_PAINT(self, self._OnPaint)
1225    
1226  class ClassRenderer(wxPyGridCellRenderer):          self.rect = rect
1227    
1228      def __init__(self, shapeType):          self.prop = prop
         wxPyGridCellRenderer.__init__(self)  
1229          self.shapeType = shapeType          self.shapeType = shapeType
1230            self.previewer = ClassDataPreviewer()
1231    
1232      def Draw(self, grid, attr, dc, rect, row, col, isSelected):      def _OnPaint(self, event):
1233          value = grid.GetTable().GetValueAsCustom(row, col, "")          dc = wxPaintDC(self)
1234          # XXX: check if value is a dictionary  
1235          stroke = value.GetStroke()          # XXX: this doesn't seem to be having an effect:
1236          if stroke is None:          dc.DestroyClippingRegion()
1237    
1238            if self.rect is None:
1239                w, h = self.GetSize()
1240                rect = wxRect(0, 0, w, h)
1241            else:
1242                rect = self.rect
1243    
1244            self.previewer.Draw(dc, rect, self.prop, self.shapeType)
1245    
1246    class ClassDataPreviewer:
1247    
1248        def Draw(self, dc, rect, prop, shapeType):
1249    
1250            assert dc is not None
1251            assert isinstance(prop, ClassGroupProperties)
1252    
1253            if rect is None:
1254                x = 0
1255                y = 0
1256                w, h = dc.GetSize()
1257            else:
1258                x = rect.GetX()
1259                y = rect.GetY()
1260                w = rect.GetWidth()
1261                h = rect.GetHeight()
1262    
1263            stroke = prop.GetLineColor()
1264            if stroke is Color.Transparent:
1265              pen = wxTRANSPARENT_PEN              pen = wxTRANSPARENT_PEN
1266          else:          else:
1267              pen = wxPen(wxColour(stroke.red * 255,              pen = wxPen(Color2wxColour(stroke),
1268                                   stroke.green * 255,                          prop.GetLineWidth(),
                                  stroke.blue * 255),  
                         value.GetStrokeWidth(),  
1269                          wxSOLID)                          wxSOLID)
1270    
1271          stroke = value.GetFill()          stroke = prop.GetFill()
1272          if stroke is None:          if stroke is Color.Transparent:
1273              brush = wxTRANSPARENT_BRUSH              brush = wxTRANSPARENT_BRUSH
1274          else:          else:
1275              brush = wxBrush(wxColour(stroke.red * 255,              brush = wxBrush(Color2wxColour(stroke), wxSOLID)
1276                                       stroke.green * 255,  
1277                                       stroke.blue * 255), wxSOLID)          dc.SetPen(pen)
1278            dc.SetBrush(brush)
1279    
1280            if shapeType == SHAPETYPE_ARC:
1281                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    
1286            elif shapeType == SHAPETYPE_POINT:
1287    
1288                dc.DrawCircle(x + w/2, y + h/2,
1289                              (min(w, h) - prop.GetLineWidth())/2)
1290    
1291            elif shapeType == SHAPETYPE_POLYGON:
1292                dc.DrawRectangle(x, y, w, h)
1293    
1294    class ClassRenderer(wxPyGridCellRenderer):
1295    
1296        def __init__(self, shapeType):
1297            wxPyGridCellRenderer.__init__(self)
1298            self.shapeType = shapeType
1299            self.previewer = ClassDataPreviewer()
1300    
1301        def Draw(self, grid, attr, dc, rect, row, col, isSelected):
1302            data = grid.GetTable().GetClassGroup(row)
1303    
1304          dc.SetClippingRegion(rect.GetX(), rect.GetY(),          dc.SetClippingRegion(rect.GetX(), rect.GetY(),
1305                               rect.GetWidth(), rect.GetHeight())                               rect.GetWidth(), rect.GetHeight())
# Line 167  class ClassRenderer(wxPyGridCellRenderer Line 1308  class ClassRenderer(wxPyGridCellRenderer
1308          dc.DrawRectangle(rect.GetX(), rect.GetY(),          dc.DrawRectangle(rect.GetX(), rect.GetY(),
1309                           rect.GetWidth(), rect.GetHeight())                           rect.GetWidth(), rect.GetHeight())
1310    
1311          dc.SetPen(pen)          if not isinstance(data, ClassGroupMap):
1312          dc.SetBrush(brush)              self.previewer.Draw(dc, rect, data.GetProperties(), self.shapeType)
1313    
1314          if self.shapeType == SHAPETYPE_ARC:          if isSelected:
1315              dc.DrawSpline([wxPoint(rect.GetX(), rect.GetY() + rect.GetHeight()),              dc.SetPen(wxPen(wxBLACK, 1, wxSOLID))
1316                             wxPoint(rect.GetX() + rect.GetWidth()/2,              dc.SetBrush(wxTRANSPARENT_BRUSH)
                                    rect.GetY() + rect.GetHeight()/4),  
                            wxPoint(rect.GetX() + rect.GetWidth()/2,  
                                    rect.GetY() + rect.GetHeight()/4*3),  
                            wxPoint(rect.GetX() + rect.GetWidth(), rect.GetY())])  
   
         elif self.shapeType == SHAPETYPE_POINT or self.shapeType == SHAPETYPE_POLYGON:  
             dc.DrawCircle(rect.GetX() + rect.GetWidth()/2,  
                           rect.GetY() + rect.GetHeight()/2,  
                           (min(rect.GetWidth(), rect.GetHeight())  
                            - value.GetStrokeWidth())/2)  
1317    
1318          dc.DestroyClippingRegion()              dc.DrawRectangle(rect.GetX(), rect.GetY(),
1319                                 rect.GetWidth(), rect.GetHeight())
1320    
1321            dc.DestroyClippingRegion()
1322    

Legend:
Removed from v.400  
changed lines
  Added in v.615

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26