/[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 444 by jonathan, Thu Feb 27 16:02:59 2003 UTC revision 500 by jonathan, Mon Mar 10 15:11:24 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    
# Line 18  from Thuban import _ Line 21  from Thuban import _
21  from Thuban.common import *  from Thuban.common import *
22  from Thuban.UI.common import *  from Thuban.UI.common import *
23    
24  from Thuban.Model.classification import * #Classification, ClassData  from Thuban.Model.classification import *
25    
26  from Thuban.Model.color import Color  from Thuban.Model.color import Color
27    
28  from Thuban.Model.layer import SHAPETYPE_ARC, SHAPETYPE_POLYGON, SHAPETYPE_POINT  from Thuban.Model.layer import Layer, SHAPETYPE_ARC, SHAPETYPE_POLYGON, SHAPETYPE_POINT
29    
30    from dialogs import NonModalDialog
31    
32    # widget id's
33  ID_PROPERTY_SELECT = 4010  ID_PROPERTY_SELECT = 4010
34  ID_CLASS_TABLE = 40011  ID_CLASS_TABLE = 40011
35    
# Line 31  ID_CLASSIFY_OK = 4001 Line 37  ID_CLASSIFY_OK = 4001
37  ID_CLASSIFY_CANCEL = 4002  ID_CLASSIFY_CANCEL = 4002
38  ID_CLASSIFY_ADD = 4003  ID_CLASSIFY_ADD = 4003
39  ID_CLASSIFY_GENRANGE = 4004  ID_CLASSIFY_GENRANGE = 4004
40    ID_CLASSIFY_REMOVE = 4005
41    ID_CLASSIFY_MOVEUP = 4006
42    ID_CLASSIFY_MOVEDOWN = 4007
43    ID_CLASSIFY_APPLY = 4008
44    
45  COL_VISUAL = 0  # table columns
46    COL_SYMBOL = 0
47  COL_VALUE  = 1  COL_VALUE  = 1
48  COL_LABEL  = 2  COL_LABEL  = 2
49    
50    # indices into the client data lists in Classifier.fields
51    FIELD_CLASS = 0
52    FIELD_TYPE = 1
53    FIELD_NAME = 2
54    
55  #  #
56  # this is a silly work around to ensure that the table that is  # this is a silly work around to ensure that the table that is
57  # passed into SetTable is the same that is returned by GetTable  # passed into SetTable is the same that is returned by GetTable
# Line 43  COL_LABEL  = 2 Line 59  COL_LABEL  = 2
59  import weakref  import weakref
60  class ClassGrid(wxGrid):  class ClassGrid(wxGrid):
61    
62      def __init__(self, parent, layer):      def __init__(self, parent):
63          wxGrid.__init__(self, parent, ID_CLASS_TABLE, size = (300, 150))          """Constructor.
64          self.SetTable(  
65              ClassTable(layer.GetClassification(), layer.ShapeType(), self),          parent -- the parent window
66              true)  
67            clazz -- the working classification that this grid should
68                     use for display.
69            """
70    
71            #wxGrid.__init__(self, parent, ID_CLASS_TABLE, size = (340, 160))
72            wxGrid.__init__(self, parent, ID_CLASS_TABLE)
73            #self.SetTable(ClassTable(fieldData, layer.ShapeType(), self), true)
74    
75            EVT_GRID_CELL_LEFT_DCLICK(self, self._OnCellDClick)
76            EVT_GRID_RANGE_SELECT(self, self._OnSelectedRange)
77            EVT_GRID_SELECT_CELL(self, self._OnSelectedCell)
78    
79            self.currentSelection = []
80    
81        def CreateTable(self, clazz, shapeType):
82    
83            assert(isinstance(clazz, Classification))
84    
85            self.shapeType = shapeType
86            table = self.GetTable()
87            if table is None:
88                w = self.GetDefaultColSize() * 3 + self.GetDefaultRowLabelSize()
89                h = self.GetDefaultRowSize() * 4 + self.GetDefaultColLabelSize()
90                self.SetDimensions(-1, -1, w, h)
91                self.SetSizeHints(w, h, -1, -1)
92                self.SetTable(ClassTable(clazz, self.shapeType, self), true)
93            else:
94                table.Reset(clazz, self.shapeType)
95    
96            self.SetSelectionMode(wxGrid.wxGridSelectRows)
97            self.ClearSelection()
98    
99        def GetCurrentSelection(self):
100            """Return the currently highlighted rows as an increasing list
101               of row numbers."""
102            sel = copy.copy(self.currentSelection)
103            sel.sort()
104            return sel
105    
106      def SetCellRenderer(self, row, col):      def SetCellRenderer(self, row, col):
107          raise ValueError(_("Must not allow setting of renderer in ClassGrid!"))          raise ValueError(_("Must not allow setting of renderer in ClassGrid!"))
108    
109        #
110        # [Set|Get]Table is taken from http://wiki.wxpython.org
111        # they are needed as a work around to ensure that the table
112        # that is passed to SetTable is the one that is returned
113        # by GetTable.
114        #
115      def SetTable(self, object, *attributes):      def SetTable(self, object, *attributes):
116          self.tableRef = weakref.ref(object)          self.tableRef = weakref.ref(object)
117          return wxGrid.SetTable(self, object, *attributes)          return wxGrid.SetTable(self, object, *attributes)
118    
119      def GetTable(self):      def GetTable(self):
120          return self.tableRef()          try:
121                return self.tableRef()
122            except:
123                return None
124    
125        def DeleteSelectedRows(self):
126            """Deletes all highlighted rows.
127      
128            If only one row is highlighted then after it is deleted the
129            row that was below the deleted row is highlighted."""
130    
131            sel = self.GetCurrentSelection()
132    
133            # nothing to do
134            if len(sel) == 0: return
135    
136            # if only one thing is selected check if it is the default
137            # data row, because we can't remove that
138            if len(sel) == 1:
139                #group = self.GetTable().GetValueAsCustom(sel[0], COL_SYMBOL, None)
140                group = self.GetTable().GetClassGroup(sel[0])
141                if isinstance(group, ClassGroupDefault):
142                    wxMessageDialog(self,
143                                    "The Default group cannot be removed.",
144                                    style = wxOK | wxICON_EXCLAMATION).ShowModal()
145                    return
146            
147    
148            self.ClearSelection()
149    
150            # we need to remove things from the bottom up so we don't
151            # change the indexes of rows that will be deleted next
152            sel.reverse()
153    
154            #
155            # actually remove the rows
156            #
157            table = self.GetTable()
158            for row in sel:
159                table.DeleteRows(row)
160    
161            #
162            # if there was only one row selected highlight the row
163            # that was directly below it, or move up one if the
164            # deleted row was the last row.
165            #
166            if len(sel) == 1:
167                r = sel[0]
168                if r > self.GetNumberRows() - 1:
169                    r = self.GetNumberRows() - 1
170                self.SelectRow(r)
171            
172    #
173    # XXX: This isn't working, and there is no way to deselect rows wxPython!
174    #
175    #   def DeselectRow(self, row):
176    #       self.ProcessEvent(
177    #           wxGridRangeSelectEvent(-1,
178    #                                  wxEVT_GRID_RANGE_SELECT,
179    #                                  self,
180    #                                  (row, row), (row, row),
181    #                                  sel = False))
182    
183        def _OnCellDClick(self, event):
184            """Handle a double on a cell."""
185    
186            r = event.GetRow()
187            c = event.GetCol()
188            if c == COL_SYMBOL:
189                prop = self.GetTable().GetValueAsCustom(r, c, None)
190                #prop = group.GetProperties()
191    
192                # get a new ClassGroupProperties object and copy the
193                # values over to our current object
194                propDlg = SelectPropertiesDialog(NULL, prop, self.shapeType)
195                if propDlg.ShowModal() == wxID_OK:
196                    new_prop = propDlg.GetClassGroupProperties()
197                    #prop.SetProperties(new_prop)
198                    self.GetTable().SetValueAsCustom(r, c, None, new_prop)
199                propDlg.Destroy()
200    
201        #
202        # _OnSelectedRange() and _OnSelectedCell() were borrowed
203        # from http://wiki.wxpython.org to keep track of which
204        # cells are currently highlighted
205        #
206        def _OnSelectedRange(self, event):
207            """Internal update to the selection tracking list"""
208            if event.Selecting():
209                for index in range( event.GetTopRow(), event.GetBottomRow()+1):
210                    if index not in self.currentSelection:
211                        self.currentSelection.append( index )
212            else:
213                for index in range( event.GetTopRow(), event.GetBottomRow()+1):
214                    while index in self.currentSelection:
215                        self.currentSelection.remove( index )
216            #self.ConfigureForSelection()
217    
218            event.Skip()
219    
220        def _OnSelectedCell( self, event ):
221            """Internal update to the selection tracking list"""
222            self.currentSelection = [ event.GetRow() ]
223            #self.ConfigureForSelection()
224            event.Skip()
225    
226  class ClassTable(wxPyGridTableBase):  class ClassTable(wxPyGridTableBase):
227        """Represents the underlying data structure for the grid."""
228    
229      NUM_COLS = 3      NUM_COLS = 3
230    
231      __col_labels = [_("Visual"), _("Value"), _("Label")]      __col_labels = [_("Symbol"), _("Value"), _("Label")]
232    
233      def __init__(self, clazz, shapeType, view = None):      def __init__(self, clazz, shapeType, view = None):
234            """Constructor.
235    
236            shapeType -- the type of shape that the layer uses
237    
238            view -- a wxGrid object that uses this class for its table
239            """
240    
241          wxPyGridTableBase.__init__(self)          wxPyGridTableBase.__init__(self)
242    
243          self.SetView(view)          self.SetView(view)
244          self.tdata = []          self.tdata = []
245    
246          self.Reset(clazz, shapeType)          self.Reset(clazz, shapeType)
247    
248      def Reset(self, clazz, shapeType):      def Reset(self, clazz, shapeType):
249            """Reset the table with the given data.
250    
251            This is necessary because wxWindows does not allow a grid's
252            table to change once it has been intially set and so we
253            need a way of modifying the data.
254    
255            clazz -- the working classification that this table should
256                     use for display. This may be different from the
257                     classification in the layer.
258    
259            shapeType -- the type of shape that the layer uses
260            """
261    
262            assert(isinstance(clazz, Classification))
263    
264          self.GetView().BeginBatch()          self.GetView().BeginBatch()
265    
266            self.fieldType = clazz.GetFieldType()
267          self.shapeType = shapeType          self.shapeType = shapeType
         self.renderer = ClassRenderer(self.shapeType)  
268    
269          old_tdata = self.tdata          old_len = len(self.tdata)
270    
271          self.tdata = []          self.tdata = []
272    
273          if clazz is None:          #
274              clazz = Classification()          # copy the data out of the classification and into our
275            # array
276  #       p = clazz.GetDefaultGroup()          #
 #       np = ClassDataDefault(classData = p)  
 #       self.tdata.append([np, 'DEFAULT', np.GetLabel()])  
   
 #       for p in clazz.points.values():  
 #           np = ClassDataPoint(p.GetValue(), classData = p)  
 #           self.tdata.append([np, np.GetValue(), np.GetLabel()])  
   
 #       for p in clazz.ranges:  
 #           np = ClassDataRange(p.GetMin(), p.GetMax(), classData = p)  
 #           self.tdata.append([np,  
 #                              '%s - %s' % (np.GetMin(), np.GetMax()),  
 #                              np.GetLabel()])  
   
         i = 0  
277          for p in clazz:          for p in clazz:
278              np = copy.copy(p)              np = copy.deepcopy(p)
279              self.__SetRow(i, np)              self.__SetRow(-1, np)
             i += 1  
280    
281    
282          self.modified = 0          self.__Modified(-1)
283    
284            self.__NotifyRowChanges(old_len, len(self.tdata))
285    
286                
287            self.GetView().EndBatch()
288    
289        def __NotifyRowChanges(self, curRows, newRows):
290          #          #
291          # silly message processing for updates to the number of          # silly message processing for updates to the number of
292          # rows and columns          # rows and columns
293          #          #
         curRows = len(old_tdata)  
         newRows = len(self.tdata)  
294          if newRows > curRows:          if newRows > curRows:
295              msg = wxGridTableMessage(self,              msg = wxGridTableMessage(self,
296                          wxGRIDTABLE_NOTIFY_ROWS_APPENDED,                          wxGRIDTABLE_NOTIFY_ROWS_APPENDED,
# Line 128  class ClassTable(wxPyGridTableBase): Line 303  class ClassTable(wxPyGridTableBase):
303                          curRows - newRows)    # how many                          curRows - newRows)    # how many
304              self.GetView().ProcessTableMessage(msg)              self.GetView().ProcessTableMessage(msg)
305    
         self.GetView().EndBatch()  
   
306      def __SetRow(self, row, group):      def __SetRow(self, row, group):
307            """Set a row's data to that of the group.
308    
309          if isinstance(group, ClassGroupDefault):          The table is considered modified after this operation.
             data = [group, 'DEFAULT', group.GetLabel()]  
         elif isinstance(group, ClassGroupSingleton):  
             data = [group, group.GetValue(), group.GetLabel()]  
         elif isinstance(group, ClassGroupRange):  
             data = [group,  
                     '%s - %s' % (group.GetMin(), group.GetMax()),  
                     group.GetLabel()]  
310    
311          if row >= len(self.tdata):          row -- if row is -1 or greater than the current number of rows
312              self.tdata.append(data)                 then group is appended to the end.
313            """
314    
315            # either append or replace
316            if row == -1 or row >= self.GetNumberRows():
317                self.tdata.append(group)
318          else:          else:
319              self.tdata[row] = data              self.tdata[row] = group
320    
321            self.__Modified()
322    
323      def GetColLabelValue(self, col):      def GetColLabelValue(self, col):
324            """Return the label for the given column."""
325          return self.__col_labels[col]          return self.__col_labels[col]
326    
327      def GetRowLabelValue(self, row):      def GetRowLabelValue(self, row):
328          data = self.tdata[row][COL_VISUAL]          """Return the label for the given row."""
329          if isinstance(data, ClassGroupDefault): return _("Default")  
330          if isinstance(data, ClassGroupSingleton): return _("Singleton")          group = self.tdata[row]
331          if isinstance(data, ClassGroupRange): return _("Range")          if isinstance(group, ClassGroupDefault):   return _("Default")
332          if isinstance(data, ClassGroupMap): return _("Map")          if isinstance(group, ClassGroupSingleton): return _("Singleton")
333            if isinstance(group, ClassGroupRange):     return _("Range")
334            if isinstance(group, ClassGroupMap):       return _("Map")
335    
336            assert(False) # shouldn't get here
337            return _("")
338    
339      def GetNumberRows(self):      def GetNumberRows(self):
340            """Return the number of rows."""
341          return len(self.tdata)          return len(self.tdata)
342    
343      def GetNumberCols(self):      def GetNumberCols(self):
344            """Return the number of columns."""
345          return self.NUM_COLS          return self.NUM_COLS
346    
347      def IsEmptyCell(self, row, col):      def IsEmptyCell(self, row, col):
348          return 0          """Determine if a cell is empty. This is always false."""
349            return False
350    
351      def GetValue(self, row, col):      def GetValue(self, row, col):
352          return self.GetValueAsCustom(row, col, "")          """Return the object that is used to represent the given
353               cell coordinates. This may not be a string."""
354            return self.GetValueAsCustom(row, col, None)
355    
356      def SetValue(self, row, col, value):      def SetValue(self, row, col, value):
357          self.SetValueAsCustom(row, col, "", value)          """Assign 'value' to the cell specified by 'row' and 'col'.
358    
359            The table is considered modified after this operation.
360            """
361    
362            self.SetValueAsCustom(row, col, None, value)
363          self.__Modified()          self.__Modified()
364                
365      def GetValueAsCustom(self, row, col, typeName):      def GetValueAsCustom(self, row, col, typeName):
366          return self.tdata[row][col]          """Return the object that is used to represent the given
367               cell coordinates. This may not be a string.
368    
369            typeName -- unused, but needed to overload wxPyGridTableBase
370            """
371    
372            group = self.tdata[row]
373    
374            if col == COL_SYMBOL:
375                return group.GetProperties()
376    
377            if col == COL_LABEL:
378                return group.GetLabel()
379    
380            # col must be COL_VALUE
381            assert(col == COL_VALUE)
382    
383            if isinstance(group, ClassGroupDefault):
384                return _("DEFAULT")
385            elif isinstance(group, ClassGroupSingleton):
386                return group.GetValue()
387            elif isinstance(group, ClassGroupRange):
388                return _("%s - %s") % (group.GetMin(), group.GetMax())
389    
390            assert(False) # shouldn't get here
391            return None
392    
393      def __ParseInput(self, value):      def __ParseInput(self, value):
394          """Try to determine what kind of input value is          """Try to determine what kind of input value is
395             (a single number or a range)             (string, number, or range)
396    
397            Returns a tuple of length one if there is a single
398            value, or of length two if it is a range.
399          """          """
400    
401          #          type = self.fieldType
402          # first try to take the input as a single number  
403          # if there's an exception try to break it into          if type == FIELDTYPE_STRING:
404          # a range seperated by a '-'. take care to ignore              return (value,)
405          # a leading '-' as that could be for a negative number.          elif type == FIELDTYPE_INT or type == FIELDTYPE_DOUBLE:
406          # then try to parse the individual parts. if there  
407          # is an exception here, let it pass up to the calling              if type == FIELDTYPE_INT:
408          # function.                  conv = lambda p: int(float(p))
409          #              else:
410          try:                  conv = lambda p: p
411              return (Str2Num(value),)  
412          except:              #
413              i = value.find('-')              # first try to take the input as a single number
414              if i == 0:              # if there's an exception try to break it into
415                  i = value.find('-', 1)              # a range seperated by a '-'. take care to ignore
416                # a leading '-' as that could be for a negative number.
417                # then try to parse the individual parts. if there
418                # is an exception here, let it pass up to the calling
419                # function.
420                #
421                try:
422                    return (conv(Str2Num(value)),)
423                except ValueError:
424                    i = value.find('-')
425                    if i == 0:
426                        i = value.find('-', 1)
427    
428              return (Str2Num(value[:i]), Str2Num(value[i+1:]))                  return (conv(Str2Num(value[:i])), conv(Str2Num(value[i+1:])))
429    
430            assert(False) # shouldn't get here
431            return (0,)
432                            
433    
434      def SetValueAsCustom(self, row, col, typeName, value):      def SetValueAsCustom(self, row, col, typeName, value):
435          data = self.tdata[row][COL_VISUAL]          """Set the cell specified by 'row' and 'col' to 'value'.
436    
437          if col == COL_VISUAL:          If column represents the value column, the input is parsed
438              self.tdata[row][COL_VISUAL] = value          to determine if a string, number, or range was entered.
439          elif col == COL_VALUE:          A new ClassGroup may be created if the type of data changes.
             if row != 0: # DefaultData row  
440    
441                  if isinstance(data, ClassGroupMap):          The table is considered modified after this operation.
                     # something special  
                     pass  
                 else: # POINT, RANGE  
                     try:  
                         dataInfo = self.__ParseInput(value)  
                     except: pass  
                         # bad input, ignore the request  
                     else:  
442    
443                          ndata = data          typeName -- unused, but needed to overload wxPyGridTableBase
444                          if len(dataInfo) == 1:          """
                             if not isinstance(data, ClassGroupSingleton):  
                                 ndata = ClassGroupSingleton(prop = data)  
                             ndata.SetValue(dataInfo[0])  
                         elif len(dataInfo) == 2:  
                             if not isinstance(data, ClassGroupRange):  
                                 data = ClassDataRange(classData = data)  
                             data.SetRange(dataInfo[0], dataInfo[1])  
445    
446                          ndata.SetLabel(data.GetLabel())          assert(col >= 0 and col < self.GetNumberCols())
447                          self.__SetRow(row, ndata)          assert(row >= 0 and row < self.GetNumberRows())
448    
449                          #self.tdata[row][COL_VISUAL] = data          group = self.tdata[row]
450    
451                          self.GetView().Refresh()          mod = True # assume the data will change
452    
453            if col == COL_SYMBOL:
454                group.SetProperties(value)
455          elif col == COL_LABEL:          elif col == COL_LABEL:
456              data.SetLabel(value)              group.SetLabel(value)
457              self.tdata[row][COL_LABEL] = data.GetLabel()          elif col == COL_VALUE:
458                if isinstance(group, ClassGroupDefault):
459                    # not allowed to modify the default value
460                    pass
461                elif isinstance(group, ClassGroupMap):
462                    # something special
463                    pass
464                else: # SINGLETON, RANGE
465                    try:
466                        dataInfo = self.__ParseInput(value)
467                    except ValueError:
468                        # bad input, ignore the request
469                        mod = False
470                    else:
471    
472                        changed = False
473                        ngroup = group
474                        props = group.GetProperties()
475    
476                        #
477                        # try to update the values, which may include
478                        # changing the underlying group type if the
479                        # group was a singleton and a range was entered
480                        #
481                        if len(dataInfo) == 1:
482                            if not isinstance(group, ClassGroupSingleton):
483                                ngroup = ClassGroupSingleton(prop = props)
484                                changed = True
485                            ngroup.SetValue(dataInfo[0])
486                        elif len(dataInfo) == 2:
487                            if not isinstance(group, ClassGroupRange):
488                                ngroup = ClassGroupRange(prop = props)
489                                changed = True
490                            ngroup.SetRange(dataInfo[0], dataInfo[1])
491                        else:
492                            assert(False)
493                            pass
494    
495                        if changed:
496                            ngroup.SetLabel(group.GetLabel())
497                            self.SetClassGroup(row, ngroup)
498          else:          else:
499              raise ValueError(_("Invalid column request"))              assert(False) # shouldn't be here
500                pass
501    
502          self.__Modified()          if mod:
503                self.__Modified()
504                self.GetView().Refresh()
505    
506      def GetAttr(self, row, col, someExtraParameter):      def GetAttr(self, row, col, someExtraParameter):
507            """Returns the cell attributes"""
508    
509          attr = wxGridCellAttr()          attr = wxGridCellAttr()
510          #attr = wxPyGridTableBase.GetAttr(self, row, col, someExtraParameter)          #attr = wxPyGridTableBase.GetAttr(self, row, col, someExtraParameter)
511    
512          if col == COL_VISUAL:          if col == COL_SYMBOL:
513                # we need to create a new renderer each time, because
514                # SetRenderer takes control of the parameter
515              attr.SetRenderer(ClassRenderer(self.shapeType))              attr.SetRenderer(ClassRenderer(self.shapeType))
516              attr.SetReadOnly()              attr.SetReadOnly()
517    
518          return attr          return attr
519    
520      def GetClassGroup(self, row):      def GetClassGroup(self, row):
521          return self.tdata[row][COL_VISUAL]          """Return the ClassGroup object representing row 'row'."""
522    
523            return self.tdata[row] # self.GetValueAsCustom(row, COL_SYMBOL, None)
524    
525        def SetClassGroup(self, row, group):
526            self.__SetRow(row, group)
527            self.GetView().Refresh()
528    
529      def __Modified(self):      def __Modified(self, mod = True):
530          self.modified = 1          """Adjust the modified flag.
531    
532            mod -- if -1 set the modified flag to False, otherwise perform
533                   an 'or' operation with the current value of the flag and
534                   'mod'
535            """
536    
537            if mod == -1:
538                self.modified = False
539            else:
540                self.modified = mod or self.modified
541    
542      def IsModified(self):      def IsModified(self):
543            """True if this table is considered modified."""
544          return self.modified          return self.modified
545    
546      def AddNewDataRow(self):      def DeleteRows(self, pos, numRows = 1):
547          np = ClassDataPoint()          """Deletes 'numRows' beginning at row 'pos'.
548          self.tdata.append([np, np.GetValue(), np.GetLabel()])  
549          msg = wxGridTableMessage(self, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, 1)          The row representing the default group is not removed.
         self.GetView().ProcessTableMessage(msg)  
         self.GetView().Refresh()  
550    
551  class Classifier(wxDialog):          The table is considered modified if any rows are removed.
552            """
553    
554            assert(pos >= 0)
555            old_len = len(self.tdata)
556            for row in range(pos, pos - numRows, -1):
557                group = self.GetClassGroup(row)
558                if not isinstance(group, ClassGroupDefault):
559                    self.tdata.pop(row)
560                    self.__Modified()
561            
562      def __init__(self, parent, layer):          if self.IsModified():
563          wxDialog.__init__(self, parent, -1, _("Classify"),              self.__NotifyRowChanges(old_len, len(self.tdata))
564                            style = wxRESIZE_BORDER)  
565        def AppendRows(self, numRows = 1):
566            """Append 'numRows' empty rows to the end of the table.
567    
568            The table is considered modified if any rows are appended.
569            """
570    
571            old_len = len(self.tdata)
572            for i in range(numRows):
573                np = ClassGroupSingleton()
574                self.__SetRow(-1, np)
575    
576            if self.IsModified():
577                self.__NotifyRowChanges(old_len, len(self.tdata))
578    
579    
580    class Classifier(NonModalDialog):
581        
582        def __init__(self, parent, interactor, name, layer):
583            NonModalDialog.__init__(self, parent, interactor, name,
584                                    _("Classifier: %s") % layer.Title())
585    
586          self.layer = layer          self.layer = layer
587    
588            self.originalClass = self.layer.GetClassification()
589            field = self.originalClass.GetField()
590            fieldType = self.originalClass.GetFieldType()
591    
592          topBox = wxBoxSizer(wxVERTICAL)          topBox = wxBoxSizer(wxVERTICAL)
593    
594          topBox.Add(wxStaticText(self, -1, _("Layer: %s") % layer.Title()),          #topBox.Add(wxStaticText(self, -1, _("Layer: %s") % layer.Title()),
595              0, wxALIGN_LEFT | wxBOTTOM, 4)              #0, wxALIGN_LEFT | wxALL, 4)
596          topBox.Add(wxStaticText(self, -1, _("Type: %s") % layer.ShapeType()),          topBox.Add(wxStaticText(self, -1,
597              0, wxALIGN_LEFT | wxBOTTOM, 4)                                  _("Layer Type: %s") % layer.ShapeType()),
598                0, wxALIGN_LEFT | wxALL, 4)
599    
         propertyBox = wxBoxSizer(wxHORIZONTAL)  
         propertyBox.Add(wxStaticText(self, -1, _("Property: ")),  
             0, wxALIGN_CENTER | wxALL, 4)  
600    
601          self.properties = wxComboBox(self, ID_PROPERTY_SELECT, "",          #
602            # make field combo box
603            #
604            self.fields = wxComboBox(self, ID_PROPERTY_SELECT, "",
605                                       style = wxCB_READONLY)                                       style = wxCB_READONLY)
606    
607          self.num_cols = layer.table.field_count()          self.num_cols = layer.table.field_count()
608          # just assume the first field in case one hasn't been          # just assume the first field in case one hasn't been
609          # specified in the file.          # specified in the file.
610          self.__cur_prop = 0          self.__cur_field = 0
611          field = layer.GetClassification().GetField()  
612            self.fields.Append("<None>")
613            self.fields.SetClientData(0, None)
614    
615          for i in range(self.num_cols):          for i in range(self.num_cols):
616              type, name, len, decc = layer.table.field_info(i)              type, name, len, decc = layer.table.field_info(i)
617                self.fields.Append(name)
618    
619              if name == field:              if name == field:
620                  self.__cur_prop = i                  self.__cur_field = i + 1
621              self.properties.Append(name)                  self.fields.SetClientData(i + 1, self.originalClass)
622              self.properties.SetClientData(i, None)              else:
623                    self.fields.SetClientData(i + 1, None)
624          self.properties.SetSelection(self.__cur_prop)  
625          propertyBox.Add(self.properties, 1, wxGROW|wxALL, 0)  
626          EVT_COMBOBOX(self, ID_PROPERTY_SELECT, self.OnPropertySelect)          #
627            #
628            #
629    
630            self.fieldTypeText = wxStaticText(self, -1, "")
631            self.__SetFieldTypeText(self.__cur_field)
632    
633            topBox.Add(self.fieldTypeText, 0, wxALIGN_LEFT | wxALL, 4)
634            #self.fieldTypeText.SetLabel("asdfadsfs")
635    
636            propertyBox = wxBoxSizer(wxHORIZONTAL)
637            propertyBox.Add(wxStaticText(self, -1, _("Field: ")),
638                0, wxALIGN_CENTER | wxALL, 4)
639            propertyBox.Add(self.fields, 1, wxGROW|wxALL, 4)
640            EVT_COMBOBOX(self, ID_PROPERTY_SELECT, self._OnFieldSelect)
641    
642          topBox.Add(propertyBox, 0, wxGROW, 4)          topBox.Add(propertyBox, 0, wxGROW, 4)
643    
# Line 313  class Classifier(wxDialog): Line 646  class Classifier(wxDialog):
646          #          #
647    
648          controlBox = wxBoxSizer(wxHORIZONTAL)          controlBox = wxBoxSizer(wxHORIZONTAL)
649          self.classGrid = ClassGrid(self, layer)  
650            self.classGrid = ClassGrid(self)
651            self.__SetGridTable(self.__cur_field)
652    
653          controlBox.Add(self.classGrid, 1, wxGROW, 0)          controlBox.Add(self.classGrid, 1, wxGROW, 0)
654    
655          controlButtonBox = wxBoxSizer(wxVERTICAL)          controlButtonBox = wxBoxSizer(wxVERTICAL)
656          controlButtonBox.Add(wxButton(self, ID_CLASSIFY_ADD,  
657              _("Add")), 0, wxGROW | wxALL, 4)          #
658          controlButtonBox.Add(wxButton(self, ID_CLASSIFY_GENRANGE,          # Control buttons:
659              _("Generate Ranges")), 0, wxGROW | wxALL, 4)          #
660            self.controlButtons = []
661    
662            button = wxButton(self, ID_CLASSIFY_ADD, _("Add"))
663            controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)
664            self.controlButtons.append(button)
665    
666            #button = wxButton(self, ID_CLASSIFY_GENRANGE, _("Generate Ranges"))
667            #controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)
668            #self.controlButtons.append(button)
669    
670            button = wxButton(self, ID_CLASSIFY_MOVEUP, _("Move Up"))
671            controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)
672            self.controlButtons.append(button)
673    
674            button = wxButton(self, ID_CLASSIFY_MOVEDOWN, _("Move Down"))
675            controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)
676            self.controlButtons.append(button)
677    
678            controlButtonBox.Add(60, 20, 0, wxGROW | wxALL | wxALIGN_BOTTOM, 4)
679    
680            button = wxButton(self, ID_CLASSIFY_REMOVE, _("Remove"))
681            controlButtonBox.Add(button, 0, wxGROW | wxALL | wxALIGN_BOTTOM, 4)
682            self.controlButtons.append(button)
683    
684          controlBox.Add(controlButtonBox, 0, wxGROW, 10)          controlBox.Add(controlButtonBox, 0, wxGROW, 10)
685          topBox.Add(controlBox, 1, wxGROW, 10)          topBox.Add(controlBox, 1, wxGROW, 10)
686    
687          EVT_BUTTON(self, ID_CLASSIFY_ADD, self.OnAdd)          EVT_BUTTON(self, ID_CLASSIFY_ADD, self._OnAdd)
688          EVT_BUTTON(self, ID_CLASSIFY_GENRANGE, self.OnGenRange)          EVT_BUTTON(self, ID_CLASSIFY_REMOVE, self._OnRemove)
689          EVT_GRID_CELL_LEFT_DCLICK(self.classGrid, self.OnCellDClick)          EVT_BUTTON(self, ID_CLASSIFY_GENRANGE, self._OnGenRange)
690            EVT_BUTTON(self, ID_CLASSIFY_MOVEUP, self._OnMoveUp)
691            EVT_BUTTON(self, ID_CLASSIFY_MOVEDOWN, self._OnMoveDown)
692    
         #  
         # Control buttons:  
         #  
693          buttonBox = wxBoxSizer(wxHORIZONTAL)          buttonBox = wxBoxSizer(wxHORIZONTAL)
694          buttonBox.Add(wxButton(self, ID_CLASSIFY_OK, _("OK")),          buttonBox.Add(wxButton(self, ID_CLASSIFY_OK, _("OK")),
695                        0, wxALL, 4)                        0, wxALL, 4)
696            buttonBox.Add(60, 20, 0, wxALL, 4)
697            buttonBox.Add(wxButton(self, ID_CLASSIFY_APPLY, _("Apply")),
698                          0, wxALL, 4)
699            buttonBox.Add(60, 20, 0, wxALL, 4)
700          buttonBox.Add(wxButton(self, ID_CLASSIFY_CANCEL, _("Cancel")),          buttonBox.Add(wxButton(self, ID_CLASSIFY_CANCEL, _("Cancel")),
701                        0, wxALL, 4)                        0, wxALL, 4)
702          topBox.Add(buttonBox, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_BOTTOM, 10)          topBox.Add(buttonBox, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_BOTTOM, 10)
703    
704          EVT_BUTTON(self, ID_CLASSIFY_OK, self.OnOK)          EVT_BUTTON(self, ID_CLASSIFY_OK, self._OnOK)
705          EVT_BUTTON(self, ID_CLASSIFY_CANCEL, self.OnCancel)          EVT_BUTTON(self, ID_CLASSIFY_APPLY, self._OnApply)
706            EVT_BUTTON(self, ID_CLASSIFY_CANCEL, self._OnCancel)
707    
708            self.fields.SetSelection(self.__cur_field)
709            self.__SelectField(self.__cur_field)
710    
711          self.SetAutoLayout(true)          self.SetAutoLayout(true)
712          self.SetSizer(topBox)          self.SetSizer(topBox)
713          topBox.Fit(self)          topBox.Fit(self)
714          topBox.SetSizeHints(self)          topBox.SetSizeHints(self)
715    
     def __BuildClassification(self, prop):  
716    
717          clazz = Classification()      def __BuildClassification(self, fieldIndex):
         clazz.SetField(self.properties.GetStringSelection())  
718    
719          numRows = self.classGrid.GetNumberRows()          numRows = self.classGrid.GetNumberRows()
720            assert(numRows > 0) # there should always be a default row
721    
722          if numRows > 0:          clazz = Classification()
723              table = self.classGrid.GetTable()          if fieldIndex == 0:
724              clazz.SetDefaultGroup(table.GetClassGroup(0))              fieldName = None
725                fieldType = None
726            else:
727                fieldName = self.fields.GetString(fieldIndex)
728                fieldType = self.layer.GetFieldType(fieldName)
729    
730              for i in range(1, numRows):          clazz.SetField(fieldName)
731                  clazz.AddGroup(table.GetClassGroup(i))          clazz.SetFieldType(fieldType)
732    
733    
734            table = self.classGrid.GetTable()
735            clazz.SetDefaultGroup(table.GetClassGroup(0))
736    
737            for i in range(1, numRows):
738                clazz.AddGroup(table.GetClassGroup(i))
739    
740          return clazz          return clazz
741    
742      def OnPropertySelect(self, event):      def __SetGridTable(self, fieldIndex):
         self.properties.SetClientData(  
             self.__cur_prop, self.__BuildClassification(self.__cur_prop))  
743    
744          self.__cur_prop = self.properties.GetSelection()          clazz = self.fields.GetClientData(fieldIndex)
745          clazz = self.properties.GetClientData(self.__cur_prop)  
746          table = self.classGrid.GetTable()          if clazz is None:
747                clazz = Classification()
748                clazz.SetDefaultGroup(
749                    ClassGroupDefault(
750                        self.layer.GetClassification().
751                                   GetDefaultGroup().GetProperties()))
752    
753                fieldName = self.fields.GetString(fieldIndex)
754                fieldType = self.layer.GetFieldType(fieldName)
755                clazz.SetFieldType(fieldType)
756                    
757            self.classGrid.CreateTable(clazz, self.layer.ShapeType())
758    
759    
760    
761        type2string = {None:             _("None"),
762                       FIELDTYPE_STRING: _("Text"),
763                       FIELDTYPE_INT:    _("Integer"),
764                       FIELDTYPE_DOUBLE: _("Decimal")}
765    
766        def __SetFieldTypeText(self, fieldIndex):
767            fieldName = self.fields.GetString(fieldIndex)
768            fieldType = self.layer.GetFieldType(fieldName)
769    
770            assert(Classifier.type2string.has_key(fieldType))
771    
772            text = Classifier.type2string[fieldType]
773    
774            self.fieldTypeText.SetLabel(_("Field Type: %s") % text)
775    
776        def __SelectField(self, newIndex, oldIndex = -1):
777    
778            assert(oldIndex >= -1)
779    
780            if oldIndex != -1:
781                clazz = self.__BuildClassification(oldIndex)
782                self.fields.SetClientData(oldIndex, clazz)
783    
784            self.__SetGridTable(newIndex)
785    
786            enabled = newIndex != 0
787    
788          table.Reset(clazz, self.layer.ShapeType())          for b in self.controlButtons:
789                b.Enable(enabled)
790    
791      def OnOK(self, event):          self.__SetFieldTypeText(newIndex)
792    
793    
794        def _OnFieldSelect(self, event):
795            index = self.fields.GetSelection()
796            self.__SelectField(index, self.__cur_field)
797            self.__cur_field = index
798    
799        def _OnApply(self, event):
800          """Put the data from the table into a new Classification and hand          """Put the data from the table into a new Classification and hand
801             it to the layer.             it to the layer.
802          """          """
803    
804          clazz = self.properties.GetClientData(self.__cur_prop)          clazz = self.fields.GetClientData(self.__cur_field)
805    
806          #          #
807          # only build the classification if there wasn't one to          # only build the classification if there wasn't one to
808          # to begin with or it has been modified          # to begin with or it has been modified
809          #          #
810          if clazz is None or self.classGrid.GetTable().IsModified():          if clazz is None or self.classGrid.GetTable().IsModified():
811              clazz = self.__BuildClassification(self.__cur_prop)              clazz = self.__BuildClassification(self.__cur_field)
   
         clazz.SetLayer(self.layer)  
812    
813          self.layer.SetClassification(clazz)          self.layer.SetClassification(clazz)
814    
815          self.EndModal(wxID_OK)      def _OnOK(self, event):
816            self._OnApply(event)
817      def OnCancel(self, event):          self.OnClose(event)
818          """Do nothing. The layer's current classification stays the same."""  
819          self.EndModal(wxID_CANCEL)      def _OnCancel(self, event):
820            """The layer's current classification stays the same."""
821            self.layer.SetClassification(self.originalClass)
822            self.OnClose(event)
823    
824        def _OnAdd(self, event):
825            self.classGrid.AppendRows()
826    
827        def _OnRemove(self, event):
828            self.classGrid.DeleteSelectedRows()
829    
830        def _OnGenRange(self, event):
831            print "Classifier._OnGenRange()"
832    
833        def _OnMoveUp(self, event):
834            sel = self.classGrid.GetCurrentSelection()
835    
836            if len(sel) == 1:
837                i = sel[0]
838                if i > 1:
839                    table = self.classGrid.GetTable()
840                    x = table.GetClassGroup(i - 1)
841                    y = table.GetClassGroup(i)
842                    table.SetClassGroup(i - 1, y)
843                    table.SetClassGroup(i, x)
844                    self.classGrid.ClearSelection()
845                    self.classGrid.SelectRow(i - 1)
846    
847        def _OnMoveDown(self, event):
848            sel = self.classGrid.GetCurrentSelection()
849    
850      def OnAdd(self, event):          if len(sel) == 1:
851          self.classGrid.GetTable().AddNewDataRow()              i = sel[0]
852          print "Classifier.OnAdd()"              table = self.classGrid.GetTable()
853                if 0 < i < table.GetNumberRows() - 1:
854      def OnGenRange(self, event):                  x = table.GetClassGroup(i)
855          print "Classifier.OnGenRange()"                  y = table.GetClassGroup(i + 1)
856                    table.SetClassGroup(i, y)
857      def OnCellDClick(self, event):                  table.SetClassGroup(i + 1, x)
858          r = event.GetRow()                  self.classGrid.ClearSelection()
859          c = event.GetCol()                  self.classGrid.SelectRow(i + 1)
         if c == COL_VISUAL:  
             # XXX: getting the properties is only possible with non-Maps!!!  
             group = self.classGrid.GetTable().GetValueAsCustom(r, c, None)  
             prop = group.GetProperties()  
             propDlg = SelectPropertiesDialog(NULL, prop, self.layer.ShapeType())  
             if propDlg.ShowModal() == wxID_OK:  
                 new_prop = propDlg.GetClassGroupProperties()  
                 prop.SetStroke(new_prop.GetStroke())  
                 prop.SetStrokeWidth(new_prop.GetStrokeWidth())  
                 prop.SetFill(new_prop.GetFill())  
                 self.classGrid.Refresh()  
             propDlg.Destroy()  
860    
861    
862  ID_SELPROP_OK = 4001  ID_SELPROP_OK = 4001
# Line 429  ID_SELPROP_SPINCTRL = 4002 Line 865  ID_SELPROP_SPINCTRL = 4002
865  ID_SELPROP_PREVIEW = 4003  ID_SELPROP_PREVIEW = 4003
866  ID_SELPROP_STROKECLR = 4004  ID_SELPROP_STROKECLR = 4004
867  ID_SELPROP_FILLCLR = 4005  ID_SELPROP_FILLCLR = 4005
868    ID_SELPROP_STROKECLRTRANS = 4006
869    ID_SELPROP_FILLCLRTRANS = 4007
870    
871  class SelectPropertiesDialog(wxDialog):  class SelectPropertiesDialog(wxDialog):
872    
# Line 454  class SelectPropertiesDialog(wxDialog): Line 892  class SelectPropertiesDialog(wxDialog):
892    
893          # control box          # control box
894          ctrlBox = wxBoxSizer(wxVERTICAL)          ctrlBox = wxBoxSizer(wxVERTICAL)
895          ctrlBox.Add(  
896              wxButton(self, ID_SELPROP_STROKECLR, "Change Stroke Color"),          lineColorBox = wxBoxSizer(wxHORIZONTAL)
897              0, wxALIGN_CENTER_HORIZONTAL | wxALL | wxGROW, 4)          lineColorBox.Add(
898          EVT_BUTTON(self, ID_SELPROP_STROKECLR, self.OnChangeStrokeColor)              wxButton(self, ID_SELPROP_STROKECLR, _("Change Line Color")),
899                1, wxALL | wxGROW, 4)
900            EVT_BUTTON(self, ID_SELPROP_STROKECLR, self._OnChangeLineColor)
901    
902            lineColorBox.Add(
903                wxButton(self, ID_SELPROP_STROKECLRTRANS, _("Transparent")),
904                1, wxALL | wxGROW, 4)
905            EVT_BUTTON(self, ID_SELPROP_STROKECLRTRANS,
906                       self._OnChangeLineColorTrans)
907    
908            ctrlBox.Add(lineColorBox, 0,
909                        wxALIGN_CENTER_HORIZONTAL | wxALL | wxGROW, 4)
910    
911          if shapeType != SHAPETYPE_ARC:          if shapeType != SHAPETYPE_ARC:
912              ctrlBox.Add(              fillColorBox = wxBoxSizer(wxHORIZONTAL)
913                  wxButton(self, ID_SELPROP_FILLCLR, "Change Fill Color"),              fillColorBox.Add(
914                  0, wxALIGN_LEFT | wxALL | wxGROW, 4)                  wxButton(self, ID_SELPROP_FILLCLR, _("Change Fill Color")),
915              EVT_BUTTON(self, ID_SELPROP_FILLCLR, self.OnChangeFillColor)                  1, wxALL | wxGROW, 4)
916                EVT_BUTTON(self, ID_SELPROP_FILLCLR, self._OnChangeFillColor)
917                fillColorBox.Add(
918                    wxButton(self, ID_SELPROP_FILLCLRTRANS, _("Transparent")),
919                    1, wxALL | wxGROW, 4)
920                EVT_BUTTON(self, ID_SELPROP_FILLCLRTRANS,
921                           self._OnChangeFillColorTrans)
922                ctrlBox.Add(fillColorBox, 0,
923                            wxALIGN_CENTER_HORIZONTAL | wxALL | wxGROW, 4)
924    
925          spinBox = wxBoxSizer(wxHORIZONTAL)          spinBox = wxBoxSizer(wxHORIZONTAL)
926          spinBox.Add(wxStaticText(self, -1, _("Stroke Width: ")),          spinBox.Add(wxStaticText(self, -1, _("Line Width: ")),
927                  0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 4)                  0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 4)
928          self.spinCtrl = wxSpinCtrl(self, ID_SELPROP_SPINCTRL,          self.spinCtrl = wxSpinCtrl(self, ID_SELPROP_SPINCTRL,
929                                     min=1, max=10,                                     min=1, max=10,
930                                     value=str(prop.GetStrokeWidth()),                                     value=str(prop.GetLineWidth()),
931                                     initial=prop.GetStrokeWidth())                                     initial=prop.GetLineWidth())
932    
933          EVT_SPINCTRL(self, ID_SELPROP_SPINCTRL, self.OnSpin)          EVT_SPINCTRL(self, ID_SELPROP_SPINCTRL, self._OnSpin)
934    
935          spinBox.Add(self.spinCtrl, 0, wxALIGN_LEFT | wxALL, 4)          spinBox.Add(self.spinCtrl, 0, wxALIGN_LEFT | wxALL, 4)
936    
# Line 481  class SelectPropertiesDialog(wxDialog): Line 938  class SelectPropertiesDialog(wxDialog):
938          itemBox.Add(ctrlBox, 0, wxALIGN_RIGHT | wxALL | wxGROW, 0)          itemBox.Add(ctrlBox, 0, wxALIGN_RIGHT | wxALL | wxGROW, 0)
939          topBox.Add(itemBox, 1, wxALIGN_LEFT | wxALL | wxGROW, 0)          topBox.Add(itemBox, 1, wxALIGN_LEFT | wxALL | wxGROW, 0)
940    
   
941          #          #
942          # Control buttons:          # Control buttons:
943          #          #
944          buttonBox = wxBoxSizer(wxHORIZONTAL)          buttonBox = wxBoxSizer(wxHORIZONTAL)
945          buttonBox.Add(wxButton(self, ID_CLASSIFY_OK, _("OK")),          buttonBox.Add(wxButton(self, ID_SELPROP_OK, _("OK")),
946                        0, wxALL, 4)                        0, wxALL, 4)
947          buttonBox.Add(wxButton(self, ID_CLASSIFY_CANCEL, _("Cancel")),          buttonBox.Add(wxButton(self, ID_SELPROP_CANCEL, _("Cancel")),
948                        0, wxALL, 4)                        0, wxALL, 4)
949          topBox.Add(buttonBox, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_BOTTOM, 10)          topBox.Add(buttonBox, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_BOTTOM, 10)
950                                                                                                                                                                    
951          EVT_BUTTON(self, ID_SELPROP_OK, self.OnOK)          EVT_BUTTON(self, ID_SELPROP_OK, self._OnOK)
952          EVT_BUTTON(self, ID_SELPROP_CANCEL, self.OnCancel)          EVT_BUTTON(self, ID_SELPROP_CANCEL, self._OnCancel)
953                                                                                                                                                                    
954          self.SetAutoLayout(true)          self.SetAutoLayout(true)
955          self.SetSizer(topBox)          self.SetSizer(topBox)
956          topBox.Fit(self)          topBox.Fit(self)
957          topBox.SetSizeHints(self)          topBox.SetSizeHints(self)
958    
959      def OnOK(self, event):      def _OnOK(self, event):
960          self.EndModal(wxID_OK)          self.EndModal(wxID_OK)
961    
962      def OnCancel(self, event):      def _OnCancel(self, event):
963          self.EndModal(wxID_CANCEL)          self.EndModal(wxID_CANCEL)
964    
965      def OnSpin(self, event):      def _OnSpin(self, event):
966          self.prop.SetStrokeWidth(self.spinCtrl.GetValue())          self.prop.SetLineWidth(self.spinCtrl.GetValue())
967          self.previewer.Refresh()          self.previewer.Refresh()
968    
969      def __GetColor(self, cur):      def __GetColor(self, cur):
# Line 521  class SelectPropertiesDialog(wxDialog): Line 977  class SelectPropertiesDialog(wxDialog):
977    
978          return ret          return ret
979                    
980      def OnChangeStrokeColor(self, event):      def _OnChangeLineColor(self, event):
981          clr = self.__GetColor(self.prop.GetStroke())          clr = self.__GetColor(self.prop.GetLineColor())
982          if clr is not None:          if clr is not None:
983              self.prop.SetStroke(clr)              self.prop.SetLineColor(clr)
984          self.previewer.Refresh() # XXX: work around, see ClassDataPreviewer          self.previewer.Refresh() # XXX: work around, see ClassDataPreviewer
985    
986      def OnChangeFillColor(self, event):      def _OnChangeLineColorTrans(self, event):
987            self.prop.SetLineColor(Color.None)
988            self.previewer.Refresh() # XXX: work around, see ClassDataPreviewer
989            
990        def _OnChangeFillColor(self, event):
991          clr = self.__GetColor(self.prop.GetFill())          clr = self.__GetColor(self.prop.GetFill())
992          if clr is not None:          if clr is not None:
993              self.prop.SetFill(clr)              self.prop.SetFill(clr)
994          self.previewer.Refresh() # XXX: work around, see ClassDataPreviewer          self.previewer.Refresh() # XXX: work around, see ClassDataPreviewer
995    
996        def _OnChangeFillColorTrans(self, event):
997            self.prop.SetFill(Color.None)
998            self.previewer.Refresh() # XXX: work around, see ClassDataPreviewer
999    
1000      def GetClassGroupProperties(self):      def GetClassGroupProperties(self):
1001          return self.prop          return self.prop
1002    
# Line 543  class ClassDataPreviewer(wxWindow): Line 1007  class ClassDataPreviewer(wxWindow):
1007                         parent = None, id = -1, size = wxDefaultSize):                         parent = None, id = -1, size = wxDefaultSize):
1008          if parent is not None:          if parent is not None:
1009              wxWindow.__init__(self, parent, id, size=size)              wxWindow.__init__(self, parent, id, size=size)
1010              EVT_PAINT(self, self.OnPaint)              EVT_PAINT(self, self._OnPaint)
1011    
1012          self.rect = rect          self.rect = rect
1013          self.prop = prop          self.prop = prop
1014          self.shapeType = shapeType          self.shapeType = shapeType
1015    
1016      def OnPaint(self, event):      def _OnPaint(self, event):
1017          dc = wxPaintDC(self)          dc = wxPaintDC(self)
1018    
1019          # XXX: this doesn't seem to be having an effect:          # XXX: this doesn't seem to be having an effect:
# Line 571  class ClassDataPreviewer(wxWindow): Line 1035  class ClassDataPreviewer(wxWindow):
1035              w = rect.GetWidth()              w = rect.GetWidth()
1036              h = rect.GetHeight()              h = rect.GetHeight()
1037    
1038          stroke = prop.GetStroke()          stroke = prop.GetLineColor()
1039          if stroke is Color.None:          if stroke is Color.None:
1040              pen = wxTRANSPARENT_PEN              pen = wxTRANSPARENT_PEN
1041          else:          else:
1042              pen = wxPen(Color2wxColour(stroke),              pen = wxPen(Color2wxColour(stroke),
1043                          prop.GetStrokeWidth(),                          prop.GetLineWidth(),
1044                          wxSOLID)                          wxSOLID)
1045    
1046          stroke = prop.GetFill()          stroke = prop.GetFill()
# Line 598  class ClassDataPreviewer(wxWindow): Line 1062  class ClassDataPreviewer(wxWindow):
1062               shapeType == SHAPETYPE_POLYGON:               shapeType == SHAPETYPE_POLYGON:
1063    
1064              dc.DrawCircle(x + w/2, y + h/2,              dc.DrawCircle(x + w/2, y + h/2,
1065                            (min(w, h) - prop.GetStrokeWidth())/2)                            (min(w, h) - prop.GetLineWidth())/2)
1066    
1067  class ClassRenderer(wxPyGridCellRenderer):  class ClassRenderer(wxPyGridCellRenderer):
1068    
# Line 607  class ClassRenderer(wxPyGridCellRenderer Line 1071  class ClassRenderer(wxPyGridCellRenderer
1071          self.previewer = ClassDataPreviewer(None, None, shapeType)          self.previewer = ClassDataPreviewer(None, None, shapeType)
1072    
1073      def Draw(self, grid, attr, dc, rect, row, col, isSelected):      def Draw(self, grid, attr, dc, rect, row, col, isSelected):
1074          data = grid.GetTable().GetValueAsCustom(row, col, "")          data = grid.GetTable().GetClassGroup(row)
   
1075    
1076          dc.SetClippingRegion(rect.GetX(), rect.GetY(),          dc.SetClippingRegion(rect.GetX(), rect.GetY(),
1077                               rect.GetWidth(), rect.GetHeight())                               rect.GetWidth(), rect.GetHeight())

Legend:
Removed from v.444  
changed lines
  Added in v.500

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26