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

Legend:
Removed from v.455  
changed lines
  Added in v.485

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26