/[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 451 by jonathan, Tue Mar 4 10:33:56 2003 UTC revision 509 by jonathan, Tue Mar 11 09:45:59 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.SetSelectionMode(wxGrid.wxGridSelectRows)  
65          self.SetTable(ClassTable(fieldData, layer.ShapeType(), self), true)          parent -- the parent window
66          EVT_GRID_CELL_LEFT_DCLICK(self, self.OnCellDClick)  
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                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):      def GetCurrentSelection(self):
100            """Return the currently highlighted rows as an increasing list
101               of row numbers."""
102          sel = copy.copy(self.currentSelection)          sel = copy.copy(self.currentSelection)
103          sel.sort()          sel.sort()
104          return sel          return sel
# Line 72  class ClassGrid(wxGrid): Line 106  class ClassGrid(wxGrid):
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):      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()          sel = self.GetCurrentSelection()
132    
133          if len(sel) == 0: return          # 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:          if len(sel) == 1:
139              group = self.GetTable().GetValueAsCustom(sel[0], COL_VISUAL, None)              #group = self.GetTable().GetValueAsCustom(sel[0], COL_SYMBOL, None)
140                group = self.GetTable().GetClassGroup(sel[0])
141              if isinstance(group, ClassGroupDefault):              if isinstance(group, ClassGroupDefault):
142                  wxMessageDialog(self,                  wxMessageDialog(self,
143                                  "The Default group cannot be removed.",                                  "The Default group cannot be removed.",
144                                  style = wxOK | wxICON_EXCLAMATION).ShowModal()                                  style = wxOK | wxICON_EXCLAMATION).ShowModal()
145                  return                  return
146                    
147    
148          self.ClearSelection()          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()          sel.reverse()
153    
154            #
155            # actually remove the rows
156            #
157          table = self.GetTable()          table = self.GetTable()
158          for row in sel:          for row in sel:
159              table.DeleteRows(row)              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:          if len(sel) == 1:
167              r = sel[0]              r = sel[0]
168              if r > self.GetNumberRows() - 1:              if r > self.GetNumberRows() - 1:
# Line 115  class ClassGrid(wxGrid): Line 180  class ClassGrid(wxGrid):
180  #                                  (row, row), (row, row),  #                                  (row, row), (row, row),
181  #                                  sel = False))  #                                  sel = False))
182    
183      def OnCellDClick(self, event):      def _OnCellDClick(self, event):
184            """Handle a double on a cell."""
185    
186          r = event.GetRow()          r = event.GetRow()
187          c = event.GetCol()          c = event.GetCol()
188          if c == COL_VISUAL:          if c == COL_SYMBOL:
189              # XXX: getting the properties is only possible with non-Maps!!!              prop = self.GetTable().GetValueAsCustom(r, c, None)
190              group = self.GetTable().GetValueAsCustom(r, c, None)              #prop = group.GetProperties()
191              prop = group.GetProperties()  
192              propDlg = SelectPropertiesDialog(NULL, prop, self.layer.ShapeType())              # 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:              if propDlg.ShowModal() == wxID_OK:
196                  new_prop = propDlg.GetClassGroupProperties()                  new_prop = propDlg.GetClassGroupProperties()
197                  prop.SetStroke(new_prop.GetStroke())                  #prop.SetProperties(new_prop)
198                  prop.SetStrokeWidth(new_prop.GetStrokeWidth())                  self.GetTable().SetValueAsCustom(r, c, None, new_prop)
                 prop.SetFill(new_prop.GetFill())  
                 self.Refresh()  
199              propDlg.Destroy()              propDlg.Destroy()
200    
201      #      #
202      # _OnSelectedRange() and _OnSelectedCell() were borrowed      # _OnSelectedRange() and _OnSelectedCell() were borrowed
203      # from http://wiki.wxpython.org      # from http://wiki.wxpython.org to keep track of which
204        # cells are currently highlighted
205      #      #
206      def _OnSelectedRange(self, event):      def _OnSelectedRange(self, event):
207          """Internal update to the selection tracking list"""          """Internal update to the selection tracking list"""
# Line 156  class ClassGrid(wxGrid): Line 224  class ClassGrid(wxGrid):
224          event.Skip()          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 = [_("Symbol"), _("Value"), _("Label")]      __col_labels = [_("Symbol"), _("Value"), _("Label")]
232    
233      def __init__(self, fieldData, 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(fieldData, shapeType)          self.Reset(clazz, shapeType)
247    
248      def Reset(self, fieldData, 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.fieldData = fieldData          self.fieldType = clazz.GetFieldType()
267          self.shapeType = shapeType          self.shapeType = shapeType
         self.renderer = ClassRenderer(self.shapeType)  
268    
269          old_len = len(self.tdata)          old_len = len(self.tdata)
270    
271          self.tdata = []          self.tdata = []
272    
273          clazz = fieldData[FIELD_CLASS]          #
274          if clazz is None:          # copy the data out of the classification and into our
275              clazz = Classification()          # 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))          self.__NotifyRowChanges(old_len, len(self.tdata))
285    
286                
287          self.GetView().EndBatch()          self.GetView().EndBatch()
288    
289      def __NotifyRowChanges(self, curRows, newRows):      def __NotifyRowChanges(self, curRows, newRows):
# Line 227  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    
   
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.fieldData[FIELD_TYPE]          type = self.fieldType
402    
403          if type == FIELD_TYPE_STRING:          if type == FIELDTYPE_STRING:
404              return (value,)              return (value,)
405          elif type == FIELD_TYPE_INT or type == FIELD_TYPE_DOUBLE:          elif type == FIELDTYPE_INT or type == FIELDTYPE_DOUBLE:
406    
407                if type == FIELDTYPE_INT:
408                    conv = lambda p: int(float(p))
409                else:
410                    conv = lambda p: p
411    
412              #              #
413              # 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 419  class ClassTable(wxPyGridTableBase):
419              # function.              # function.
420              #              #
421              try:              try:
422                  return (Str2Num(value),)                  return (conv(Str2Num(value)),)
423              except:              except ValueError:
424                  i = value.find('-')                  i = value.find('-')
425                  if i == 0:                  if i == 0:
426                      i = value.find('-', 1)                      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          group = self.tdata[row][COL_VISUAL]          """Set the cell specified by 'row' and 'col' to 'value'.
436    
437            If column represents the value column, the input is parsed
438            to determine if a string, number, or range was entered.
439            A new ClassGroup may be created if the type of data changes.
440    
441            The table is considered modified after this operation.
442    
443            typeName -- unused, but needed to overload wxPyGridTableBase
444            """
445    
446          if col == COL_VISUAL:          assert(col >= 0 and col < self.GetNumberCols())
447              self.tdata[row][COL_VISUAL] = value          assert(row >= 0 and row < self.GetNumberRows())
448    
449            group = self.tdata[row]
450    
451            mod = True # assume the data will change
452    
453            if col == COL_SYMBOL:
454                group.SetProperties(value)
455            elif col == COL_LABEL:
456                group.SetLabel(value)
457          elif col == COL_VALUE:          elif col == COL_VALUE:
458              if isinstance(group, ClassGroupDefault):              if isinstance(group, ClassGroupDefault):
459                  # not allowed to modify the default value                  # not allowed to modify the default value
# Line 318  class ClassTable(wxPyGridTableBase): Line 464  class ClassTable(wxPyGridTableBase):
464              else: # SINGLETON, RANGE              else: # SINGLETON, RANGE
465                  try:                  try:
466                      dataInfo = self.__ParseInput(value)                      dataInfo = self.__ParseInput(value)
467                  except:                  except ValueError:
468                      # bad input, ignore the request                      # bad input, ignore the request
469                      pass                      mod = False
470                  else:                  else:
471    
472                        changed = False
473                      ngroup = group                      ngroup = group
474                      props = group.GetProperties()                      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:                      if len(dataInfo) == 1:
482                          if not isinstance(group, ClassGroupSingleton):                          if not isinstance(group, ClassGroupSingleton):
483                              ngroup = ClassGroupSingleton(prop = props)                              ngroup = ClassGroupSingleton(prop = props)
484                                changed = True
485                          ngroup.SetValue(dataInfo[0])                          ngroup.SetValue(dataInfo[0])
486                      elif len(dataInfo) == 2:                      elif len(dataInfo) == 2:
487                          if not isinstance(group, ClassGroupRange):                          if not isinstance(group, ClassGroupRange):
488                              ngroup = ClassGroupRange(prop = props)                              ngroup = ClassGroupRange(prop = props)
489                                changed = True
490                          ngroup.SetRange(dataInfo[0], dataInfo[1])                          ngroup.SetRange(dataInfo[0], dataInfo[1])
491                      else:                      else:
492                          assert(False)                          assert(False)
493                            pass
494    
495                      ngroup.SetLabel(group.GetLabel())                      if changed:
496                      self.__SetRow(row, ngroup)                          ngroup.SetLabel(group.GetLabel())
497                            self.SetClassGroup(row, ngroup)
                     self.GetView().Refresh()  
   
         elif col == COL_LABEL:  
             group.SetLabel(value)  
             self.tdata[row][COL_LABEL] = group.GetLabel()  
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, mod = True):
530            """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      def __Modified(self):          if mod == -1:
538          self.modified = 1              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 DeleteRows(self, pos, numRows = 1):      def DeleteRows(self, pos, numRows = 1):
547            """Deletes 'numRows' beginning at row 'pos'.
548    
549            The row representing the default group is not removed.
550    
551            The table is considered modified if any rows are removed.
552            """
553    
554          assert(pos >= 0)          assert(pos >= 0)
555          old_len = len(self.tdata)          old_len = len(self.tdata)
556          for row in range(pos, pos - numRows, -1):          for row in range(pos, pos - numRows, -1):
557              group = self.GetValueAsCustom(row, COL_VISUAL, None)              group = self.GetClassGroup(row)
558              if not isinstance(group, ClassGroupDefault):              if not isinstance(group, ClassGroupDefault):
559                  self.tdata.pop(row)                  self.tdata.pop(row)
560                  self.__Modified()                  self.__Modified()
# Line 381  class ClassTable(wxPyGridTableBase): Line 563  class ClassTable(wxPyGridTableBase):
563              self.__NotifyRowChanges(old_len, len(self.tdata))              self.__NotifyRowChanges(old_len, len(self.tdata))
564    
565      def AppendRows(self, numRows = 1):      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)          old_len = len(self.tdata)
572          for i in range(numRows):          for i in range(numRows):
573              np = ClassGroupSingleton()              np = ClassGroupSingleton()
574              self.tdata.append([np, np.GetValue(), np.GetLabel()])              self.__SetRow(-1, np)
             self.__Modified()  
575    
576          if self.IsModified():          if self.IsModified():
577              self.__NotifyRowChanges(old_len, len(self.tdata))              self.__NotifyRowChanges(old_len, len(self.tdata))
578    
579    
580  class Classifier(wxDialog):  class Classifier(NonModalDialog):
581            
582      def __init__(self, parent, layer):      def __init__(self, parent, interactor, name, layer):
583          wxDialog.__init__(self, parent, -1, _("Classify"),          NonModalDialog.__init__(self, parent, interactor, name,
584                            style = wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)                                  _("Classifier: %s") % layer.Title())
585    
586            panel = wxPanel(self, -1)
587    
588          self.layer = layer          self.layer = layer
589    
590            self.originalClass = self.layer.GetClassification()
591            field = self.originalClass.GetField()
592            fieldType = self.originalClass.GetFieldType()
593    
594          topBox = wxBoxSizer(wxVERTICAL)          topBox = wxBoxSizer(wxVERTICAL)
595    
596          topBox.Add(wxStaticText(self, -1, _("Layer: %s") % layer.Title()),          #topBox.Add(wxStaticText(panel, -1, _("Layer: %s") % layer.Title()),
597              0, wxALIGN_LEFT | wxALL, 4)              #0, wxALIGN_LEFT | wxALL, 4)
598          topBox.Add(wxStaticText(self, -1, _("Type: %s") % layer.ShapeType()),          topBox.Add(wxStaticText(panel, -1,
599                                    _("Layer Type: %s") % layer.ShapeType()),
600              0, wxALIGN_LEFT | wxALL, 4)              0, wxALIGN_LEFT | wxALL, 4)
601    
         propertyBox = wxBoxSizer(wxHORIZONTAL)  
         propertyBox.Add(wxStaticText(self, -1, _("Field: ")),  
             0, wxALIGN_CENTER | wxALL, 4)  
602    
603          self.fields = wxComboBox(self, ID_PROPERTY_SELECT, "",          #
604            # make field combo box
605            #
606            self.fields = wxComboBox(panel, ID_PROPERTY_SELECT, "",
607                                       style = wxCB_READONLY)                                       style = wxCB_READONLY)
608    
609          self.num_cols = layer.table.field_count()          self.num_cols = layer.table.field_count()
610          # just assume the first field in case one hasn't been          # just assume the first field in case one hasn't been
611          # specified in the file.          # specified in the file.
612          self.__cur_field = 0          self.__cur_field = 0
613          clazz = layer.GetClassification()  
614          field = clazz.GetField()          self.fields.Append("<None>")
615            self.fields.SetClientData(0, None)
616    
617          for i in range(self.num_cols):          for i in range(self.num_cols):
618              type, name, len, decc = layer.table.field_info(i)              type, name, len, decc = layer.table.field_info(i)
619              self.fields.Append(name)              self.fields.Append(name)
620    
621              if name == field:              if name == field:
622                  self.__cur_field = i                  self.__cur_field = i + 1
623                  self.fields.SetClientData(i, [clazz, type, name, len, decc])                  self.fields.SetClientData(i + 1, self.originalClass)
624              else:              else:
625                  self.fields.SetClientData(i, [None, type, name, len, decc])                  self.fields.SetClientData(i + 1, None)
626    
         self.fields.SetSelection(self.__cur_field)  
627    
628            ###########
629    
630            self.fieldTypeText = wxStaticText(panel, -1, "")
631            topBox.Add(self.fieldTypeText, 0, wxGROW | wxALIGN_LEFT | wxALL, 4)
632    
633            propertyBox = wxBoxSizer(wxHORIZONTAL)
634            propertyBox.Add(wxStaticText(panel, -1, _("Field: ")),
635                0, wxALIGN_LEFT | wxALL, 4)
636          propertyBox.Add(self.fields, 1, wxGROW|wxALL, 4)          propertyBox.Add(self.fields, 1, wxGROW|wxALL, 4)
637          EVT_COMBOBOX(self, ID_PROPERTY_SELECT, self.OnFieldSelect)          EVT_COMBOBOX(self, ID_PROPERTY_SELECT, self._OnFieldSelect)
638    
639          topBox.Add(propertyBox, 0, wxGROW, 4)          topBox.Add(propertyBox, 0, wxGROW, 4)
640    
641            ###########
642          #          #
643          # Classification data table          # Classification data table
644          #          #
645    
646          controlBox = wxBoxSizer(wxHORIZONTAL)          controlBox = wxBoxSizer(wxHORIZONTAL)
647          self.classGrid = ClassGrid(self,  
648                                     layer,          self.classGrid = ClassGrid(self)
649                                     self.fields.GetClientData(self.__cur_field))          self.__SetGridTable(self.__cur_field)
650    
651          controlBox.Add(self.classGrid, 1, wxGROW, 0)          controlBox.Add(self.classGrid, 1, wxGROW, 0)
652    
653            ###########
654            #
655            # Control buttons:
656            #
657            self.controlButtons = []
658    
659          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)  
660    
661          controlButtonBox.Add(wxButton(self, ID_CLASSIFY_REMOVE,          button = wxButton(panel, ID_CLASSIFY_ADD, _("Add"))
662              _("Remove")), 0, wxGROW | wxALL | wxALIGN_BOTTOM, 4)          controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)
663            self.controlButtons.append(button)
664    
665            #button = wxButton(panel, ID_CLASSIFY_GENRANGE, _("Generate Ranges"))
666            #controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)
667            #self.controlButtons.append(button)
668    
669            button = wxButton(panel, ID_CLASSIFY_MOVEUP, _("Move Up"))
670            controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)
671            self.controlButtons.append(button)
672    
673            button = wxButton(panel, ID_CLASSIFY_MOVEDOWN, _("Move Down"))
674            controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)
675            self.controlButtons.append(button)
676    
677            controlButtonBox.Add(60, 20, 0, wxGROW | wxALL | wxALIGN_BOTTOM, 4)
678    
679            button = wxButton(panel, ID_CLASSIFY_REMOVE, _("Remove"))
680            controlButtonBox.Add(button, 0, wxGROW | wxALL | wxALIGN_BOTTOM, 4)
681            self.controlButtons.append(button)
682    
683          controlBox.Add(controlButtonBox, 0, wxGROW, 10)          controlBox.Add(controlButtonBox, 0, wxGROW, 10)
684          topBox.Add(controlBox, 1, wxGROW, 10)          topBox.Add(controlBox, 0, wxGROW, 10)
685    
686          EVT_BUTTON(self, ID_CLASSIFY_ADD, self.OnAdd)          EVT_BUTTON(self, ID_CLASSIFY_ADD, self._OnAdd)
687          EVT_BUTTON(self, ID_CLASSIFY_REMOVE, self.OnRemove)          EVT_BUTTON(self, ID_CLASSIFY_REMOVE, self._OnRemove)
688          EVT_BUTTON(self, ID_CLASSIFY_GENRANGE, self.OnGenRange)          EVT_BUTTON(self, ID_CLASSIFY_GENRANGE, self._OnGenRange)
689            EVT_BUTTON(self, ID_CLASSIFY_MOVEUP, self._OnMoveUp)
690            EVT_BUTTON(self, ID_CLASSIFY_MOVEDOWN, self._OnMoveDown)
691    
692            ###########
693    
         #  
         # Control buttons:  
         #  
694          buttonBox = wxBoxSizer(wxHORIZONTAL)          buttonBox = wxBoxSizer(wxHORIZONTAL)
695          buttonBox.Add(wxButton(self, ID_CLASSIFY_OK, _("OK")),          buttonBox.Add(wxButton(panel, ID_CLASSIFY_OK, _("OK")),
696                        0, wxALL, 4)                        0, wxALL, 4)
697          buttonBox.Add(wxButton(self, ID_CLASSIFY_CANCEL, _("Cancel")),          buttonBox.Add(60, 20, 0, wxALL, 4)
698            buttonBox.Add(wxButton(panel, ID_CLASSIFY_APPLY, _("Apply")),
699                        0, wxALL, 4)                        0, wxALL, 4)
700          topBox.Add(buttonBox, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_BOTTOM, 10)          buttonBox.Add(60, 20, 0, wxALL, 4)
701            buttonBox.Add(wxButton(panel, ID_CLASSIFY_CANCEL, _("Cancel")),
702                          0, wxALL, 4)
703            topBox.Add(buttonBox, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_BOTTOM, 0)
704    
705          EVT_BUTTON(self, ID_CLASSIFY_OK, self.OnOK)          EVT_BUTTON(self, ID_CLASSIFY_OK, self._OnOK)
706          EVT_BUTTON(self, ID_CLASSIFY_CANCEL, self.OnCancel)          EVT_BUTTON(self, ID_CLASSIFY_APPLY, self._OnApply)
707            EVT_BUTTON(self, ID_CLASSIFY_CANCEL, self._OnCancel)
708    
709            ###########
710    
711            self.fields.SetSelection(self.__cur_field)
712            self.__SelectField(self.__cur_field)
713    
714          self.SetAutoLayout(true)          panel.SetAutoLayout(True)
715          self.SetSizer(topBox)          panel.SetSizer(topBox)
         topBox.Fit(self)  
         topBox.SetSizeHints(self)  
716    
717      def __BuildClassification(self, prop):          topBox.SetSizeHints(panel)
718            topBox.Fit(panel)
719    
720            self.SetAutoLayout(True)
721            self.Fit()
722    
723          clazz = Classification()  
724          clazz.SetField(self.fields.GetString(prop))      def __BuildClassification(self, fieldIndex):
725    
726          numRows = self.classGrid.GetNumberRows()          numRows = self.classGrid.GetNumberRows()
727            assert(numRows > 0) # there should always be a default row
728    
729            clazz = Classification()
730            if fieldIndex == 0:
731                fieldName = None
732                fieldType = None
733            else:
734                fieldName = self.fields.GetString(fieldIndex)
735                fieldType = self.layer.GetFieldType(fieldName)
736    
737            clazz.SetField(fieldName)
738            clazz.SetFieldType(fieldType)
739    
         if numRows > 0:  
             table = self.classGrid.GetTable()  
             clazz.SetDefaultGroup(table.GetClassGroup(0))  
740    
741              for i in range(1, numRows):          table = self.classGrid.GetTable()
742                  clazz.AddGroup(table.GetClassGroup(i))          clazz.SetDefaultGroup(table.GetClassGroup(0))
743    
744            for i in range(1, numRows):
745                clazz.AddGroup(table.GetClassGroup(i))
746    
747          return clazz          return clazz
748    
749      def OnFieldSelect(self, event):      def __SetGridTable(self, fieldIndex):
750          data = self.fields.GetClientData(self.__cur_field)  
751          data[FIELD_CLASS] = self.__BuildClassification(self.__cur_field)          clazz = self.fields.GetClientData(fieldIndex)
752    
753            if clazz is None:
754                clazz = Classification()
755                clazz.SetDefaultGroup(
756                    ClassGroupDefault(
757                        self.layer.GetClassification().
758                                   GetDefaultGroup().GetProperties()))
759    
760                fieldName = self.fields.GetString(fieldIndex)
761                fieldType = self.layer.GetFieldType(fieldName)
762                clazz.SetFieldType(fieldType)
763                    
764            self.classGrid.CreateTable(clazz, self.layer.ShapeType())
765    
766    
767    
768        type2string = {None:             _("None"),
769                       FIELDTYPE_STRING: _("Text"),
770                       FIELDTYPE_INT:    _("Integer"),
771                       FIELDTYPE_DOUBLE: _("Decimal")}
772    
773        def __SetFieldTypeText(self, fieldIndex):
774            fieldName = self.fields.GetString(fieldIndex)
775            fieldType = self.layer.GetFieldType(fieldName)
776    
777            assert(Classifier.type2string.has_key(fieldType))
778    
779            text = Classifier.type2string[fieldType]
780    
781            self.fieldTypeText.SetLabel(_("Field Type: %s") % text)
782    
783        def __SelectField(self, newIndex, oldIndex = -1):
784    
785            assert(oldIndex >= -1)
786    
787            if oldIndex != -1:
788                clazz = self.__BuildClassification(oldIndex)
789                self.fields.SetClientData(oldIndex, clazz)
790    
791            self.__SetGridTable(newIndex)
792    
793          self.fields.SetClientData(self.__cur_field, data)          enabled = newIndex != 0
794    
795          self.__cur_field = self.fields.GetSelection()          for b in self.controlButtons:
796          fieldData = self.fields.GetClientData(self.__cur_field)              b.Enable(enabled)
         self.classGrid.GetTable().Reset(fieldData, self.layer.ShapeType())  
797    
798      def OnOK(self, event):          self.__SetFieldTypeText(newIndex)
799    
800    
801        def _OnFieldSelect(self, event):
802            index = self.fields.GetSelection()
803            self.__SelectField(index, self.__cur_field)
804            self.__cur_field = index
805    
806        def _OnApply(self, event):
807          """Put the data from the table into a new Classification and hand          """Put the data from the table into a new Classification and hand
808             it to the layer.             it to the layer.
809          """          """
810    
811          clazz = self.fields.GetClientData(self.__cur_field)[FIELD_CLASS]          clazz = self.fields.GetClientData(self.__cur_field)
812    
813          #          #
814          # 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 817  class Classifier(wxDialog):
817          if clazz is None or self.classGrid.GetTable().IsModified():          if clazz is None or self.classGrid.GetTable().IsModified():
818              clazz = self.__BuildClassification(self.__cur_field)              clazz = self.__BuildClassification(self.__cur_field)
819    
         clazz.SetLayer(self.layer)  
   
820          self.layer.SetClassification(clazz)          self.layer.SetClassification(clazz)
821    
822          self.EndModal(wxID_OK)      def _OnOK(self, event):
823            self._OnApply(event)
824            self.OnClose(event)
825    
826        def _OnCancel(self, event):
827            """The layer's current classification stays the same."""
828            self.layer.SetClassification(self.originalClass)
829            self.OnClose(event)
830    
831      def OnCancel(self, event):      def _OnAdd(self, event):
         """Do nothing. The layer's current classification stays the same."""  
         self.EndModal(wxID_CANCEL)  
   
     def OnAdd(self, event):  
832          self.classGrid.AppendRows()          self.classGrid.AppendRows()
833    
834      def OnRemove(self, event):      def _OnRemove(self, event):
835          self.classGrid.DeleteSelectedRows()          self.classGrid.DeleteSelectedRows()
836    
837      def OnGenRange(self, event):      def _OnGenRange(self, event):
838          print "Classifier.OnGenRange()"          print "Classifier._OnGenRange()"
839    
840        def _OnMoveUp(self, event):
841            sel = self.classGrid.GetCurrentSelection()
842    
843            if len(sel) == 1:
844                i = sel[0]
845                if i > 1:
846                    table = self.classGrid.GetTable()
847                    x = table.GetClassGroup(i - 1)
848                    y = table.GetClassGroup(i)
849                    table.SetClassGroup(i - 1, y)
850                    table.SetClassGroup(i, x)
851                    self.classGrid.ClearSelection()
852                    self.classGrid.SelectRow(i - 1)
853    
854        def _OnMoveDown(self, event):
855            sel = self.classGrid.GetCurrentSelection()
856    
857            if len(sel) == 1:
858                i = sel[0]
859                table = self.classGrid.GetTable()
860                if 0 < i < table.GetNumberRows() - 1:
861                    x = table.GetClassGroup(i)
862                    y = table.GetClassGroup(i + 1)
863                    table.SetClassGroup(i, y)
864                    table.SetClassGroup(i + 1, x)
865                    self.classGrid.ClearSelection()
866                    self.classGrid.SelectRow(i + 1)
867    
868    
869  ID_SELPROP_OK = 4001  ID_SELPROP_OK = 4001
# Line 550  ID_SELPROP_SPINCTRL = 4002 Line 872  ID_SELPROP_SPINCTRL = 4002
872  ID_SELPROP_PREVIEW = 4003  ID_SELPROP_PREVIEW = 4003
873  ID_SELPROP_STROKECLR = 4004  ID_SELPROP_STROKECLR = 4004
874  ID_SELPROP_FILLCLR = 4005  ID_SELPROP_FILLCLR = 4005
875    ID_SELPROP_STROKECLRTRANS = 4006
876    ID_SELPROP_FILLCLRTRANS = 4007
877    
878  class SelectPropertiesDialog(wxDialog):  class SelectPropertiesDialog(wxDialog):
879    
880      def __init__(self, parent, prop, shapeType):      def __init__(self, parent, prop, shapeType):
881          wxDialog.__init__(self, parent, -1, _("Select Properties"),          wxDialog.__init__(self, parent, -1, _("Select Properties"),
882                            style = wxRESIZE_BORDER)                            style = wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
883    
884          self.prop = ClassGroupProperties(prop)          self.prop = ClassGroupProperties(prop)
885    
# Line 575  class SelectPropertiesDialog(wxDialog): Line 899  class SelectPropertiesDialog(wxDialog):
899    
900          # control box          # control box
901          ctrlBox = wxBoxSizer(wxVERTICAL)          ctrlBox = wxBoxSizer(wxVERTICAL)
902          ctrlBox.Add(  
903              wxButton(self, ID_SELPROP_STROKECLR, "Change Stroke Color"),          lineColorBox = wxBoxSizer(wxHORIZONTAL)
904              1, wxALIGN_CENTER_HORIZONTAL | wxALL | wxGROW, 4)          lineColorBox.Add(
905          EVT_BUTTON(self, ID_SELPROP_STROKECLR, self.OnChangeStrokeColor)              wxButton(self, ID_SELPROP_STROKECLR, _("Change Line Color")),
906                1, wxALL | wxGROW, 4)
907            EVT_BUTTON(self, ID_SELPROP_STROKECLR, self._OnChangeLineColor)
908    
909            lineColorBox.Add(
910                wxButton(self, ID_SELPROP_STROKECLRTRANS, _("Transparent")),
911                1, wxALL | wxGROW, 4)
912            EVT_BUTTON(self, ID_SELPROP_STROKECLRTRANS,
913                       self._OnChangeLineColorTrans)
914    
915            ctrlBox.Add(lineColorBox, 0,
916                        wxALIGN_CENTER_HORIZONTAL | wxALL | wxGROW, 4)
917    
918          if shapeType != SHAPETYPE_ARC:          if shapeType != SHAPETYPE_ARC:
919              ctrlBox.Add(              fillColorBox = wxBoxSizer(wxHORIZONTAL)
920                  wxButton(self, ID_SELPROP_FILLCLR, "Change Fill Color"),              fillColorBox.Add(
921                  0, wxALIGN_LEFT | wxALL | wxGROW, 4)                  wxButton(self, ID_SELPROP_FILLCLR, _("Change Fill Color")),
922              EVT_BUTTON(self, ID_SELPROP_FILLCLR, self.OnChangeFillColor)                  1, wxALL | wxGROW, 4)
923                EVT_BUTTON(self, ID_SELPROP_FILLCLR, self._OnChangeFillColor)
924                fillColorBox.Add(
925                    wxButton(self, ID_SELPROP_FILLCLRTRANS, _("Transparent")),
926                    1, wxALL | wxGROW, 4)
927                EVT_BUTTON(self, ID_SELPROP_FILLCLRTRANS,
928                           self._OnChangeFillColorTrans)
929                ctrlBox.Add(fillColorBox, 0,
930                            wxALIGN_CENTER_HORIZONTAL | wxALL | wxGROW, 4)
931    
932          spinBox = wxBoxSizer(wxHORIZONTAL)          spinBox = wxBoxSizer(wxHORIZONTAL)
933          spinBox.Add(wxStaticText(self, -1, _("Stroke Width: ")),          spinBox.Add(wxStaticText(self, -1, _("Line Width: ")),
934                  0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 4)                  0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 4)
935          self.spinCtrl = wxSpinCtrl(self, ID_SELPROP_SPINCTRL,          self.spinCtrl = wxSpinCtrl(self, ID_SELPROP_SPINCTRL,
936                                     min=1, max=10,                                     min=1, max=10,
937                                     value=str(prop.GetStrokeWidth()),                                     value=str(prop.GetLineWidth()),
938                                     initial=prop.GetStrokeWidth())                                     initial=prop.GetLineWidth())
939    
940          EVT_SPINCTRL(self, ID_SELPROP_SPINCTRL, self.OnSpin)          EVT_SPINCTRL(self, ID_SELPROP_SPINCTRL, self._OnSpin)
941    
942          spinBox.Add(self.spinCtrl, 0, wxALIGN_LEFT | wxALL, 4)          spinBox.Add(self.spinCtrl, 0, wxALIGN_LEFT | wxALL, 4)
943    
# Line 602  class SelectPropertiesDialog(wxDialog): Line 945  class SelectPropertiesDialog(wxDialog):
945          itemBox.Add(ctrlBox, 0, wxALIGN_RIGHT | wxALL | wxGROW, 0)          itemBox.Add(ctrlBox, 0, wxALIGN_RIGHT | wxALL | wxGROW, 0)
946          topBox.Add(itemBox, 1, wxALIGN_LEFT | wxALL | wxGROW, 0)          topBox.Add(itemBox, 1, wxALIGN_LEFT | wxALL | wxGROW, 0)
947    
   
948          #          #
949          # Control buttons:          # Control buttons:
950          #          #
951          buttonBox = wxBoxSizer(wxHORIZONTAL)          buttonBox = wxBoxSizer(wxHORIZONTAL)
952          buttonBox.Add(wxButton(self, ID_CLASSIFY_OK, _("OK")),          buttonBox.Add(wxButton(self, ID_SELPROP_OK, _("OK")),
953                        0, wxALL, 4)                        0, wxALL, 4)
954          buttonBox.Add(wxButton(self, ID_CLASSIFY_CANCEL, _("Cancel")),          buttonBox.Add(wxButton(self, ID_SELPROP_CANCEL, _("Cancel")),
955                        0, wxALL, 4)                        0, wxALL, 4)
956          topBox.Add(buttonBox, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_BOTTOM, 10)          topBox.Add(buttonBox, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_BOTTOM, 10)
957                                                                                                                                                                    
958          EVT_BUTTON(self, ID_SELPROP_OK, self.OnOK)          EVT_BUTTON(self, ID_SELPROP_OK, self._OnOK)
959          EVT_BUTTON(self, ID_SELPROP_CANCEL, self.OnCancel)          EVT_BUTTON(self, ID_SELPROP_CANCEL, self._OnCancel)
960                                                                                                                                                                    
961          self.SetAutoLayout(true)          self.SetAutoLayout(True)
962          self.SetSizer(topBox)          self.SetSizer(topBox)
963          topBox.Fit(self)          topBox.Fit(self)
964          topBox.SetSizeHints(self)          topBox.SetSizeHints(self)
965    
966      def OnOK(self, event):      def _OnOK(self, event):
967          self.EndModal(wxID_OK)          self.EndModal(wxID_OK)
968    
969      def OnCancel(self, event):      def _OnCancel(self, event):
970          self.EndModal(wxID_CANCEL)          self.EndModal(wxID_CANCEL)
971    
972      def OnSpin(self, event):      def _OnSpin(self, event):
973          self.prop.SetStrokeWidth(self.spinCtrl.GetValue())          self.prop.SetLineWidth(self.spinCtrl.GetValue())
974          self.previewer.Refresh()          self.previewer.Refresh()
975    
976      def __GetColor(self, cur):      def __GetColor(self, cur):
# Line 642  class SelectPropertiesDialog(wxDialog): Line 984  class SelectPropertiesDialog(wxDialog):
984    
985          return ret          return ret
986                    
987      def OnChangeStrokeColor(self, event):      def _OnChangeLineColor(self, event):
988          clr = self.__GetColor(self.prop.GetStroke())          clr = self.__GetColor(self.prop.GetLineColor())
989          if clr is not None:          if clr is not None:
990              self.prop.SetStroke(clr)              self.prop.SetLineColor(clr)
991          self.previewer.Refresh() # XXX: work around, see ClassDataPreviewer          self.previewer.Refresh() # XXX: work around, see ClassDataPreviewer
992    
993      def OnChangeFillColor(self, event):      def _OnChangeLineColorTrans(self, event):
994            self.prop.SetLineColor(Color.None)
995            self.previewer.Refresh() # XXX: work around, see ClassDataPreviewer
996            
997        def _OnChangeFillColor(self, event):
998          clr = self.__GetColor(self.prop.GetFill())          clr = self.__GetColor(self.prop.GetFill())
999          if clr is not None:          if clr is not None:
1000              self.prop.SetFill(clr)              self.prop.SetFill(clr)
1001          self.previewer.Refresh() # XXX: work around, see ClassDataPreviewer          self.previewer.Refresh() # XXX: work around, see ClassDataPreviewer
1002    
1003        def _OnChangeFillColorTrans(self, event):
1004            self.prop.SetFill(Color.None)
1005            self.previewer.Refresh() # XXX: work around, see ClassDataPreviewer
1006    
1007      def GetClassGroupProperties(self):      def GetClassGroupProperties(self):
1008          return self.prop          return self.prop
1009    
# Line 664  class ClassDataPreviewer(wxWindow): Line 1014  class ClassDataPreviewer(wxWindow):
1014                         parent = None, id = -1, size = wxDefaultSize):                         parent = None, id = -1, size = wxDefaultSize):
1015          if parent is not None:          if parent is not None:
1016              wxWindow.__init__(self, parent, id, size=size)              wxWindow.__init__(self, parent, id, size=size)
1017              EVT_PAINT(self, self.OnPaint)              EVT_PAINT(self, self._OnPaint)
1018    
1019          self.rect = rect          self.rect = rect
1020          self.prop = prop          self.prop = prop
1021          self.shapeType = shapeType          self.shapeType = shapeType
1022    
1023      def OnPaint(self, event):      def _OnPaint(self, event):
1024          dc = wxPaintDC(self)          dc = wxPaintDC(self)
1025    
1026          # 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 1042  class ClassDataPreviewer(wxWindow):
1042              w = rect.GetWidth()              w = rect.GetWidth()
1043              h = rect.GetHeight()              h = rect.GetHeight()
1044    
1045          stroke = prop.GetStroke()          stroke = prop.GetLineColor()
1046          if stroke is Color.None:          if stroke is Color.None:
1047              pen = wxTRANSPARENT_PEN              pen = wxTRANSPARENT_PEN
1048          else:          else:
1049              pen = wxPen(Color2wxColour(stroke),              pen = wxPen(Color2wxColour(stroke),
1050                          prop.GetStrokeWidth(),                          prop.GetLineWidth(),
1051                          wxSOLID)                          wxSOLID)
1052    
1053          stroke = prop.GetFill()          stroke = prop.GetFill()
# Line 719  class ClassDataPreviewer(wxWindow): Line 1069  class ClassDataPreviewer(wxWindow):
1069               shapeType == SHAPETYPE_POLYGON:               shapeType == SHAPETYPE_POLYGON:
1070    
1071              dc.DrawCircle(x + w/2, y + h/2,              dc.DrawCircle(x + w/2, y + h/2,
1072                            (min(w, h) - prop.GetStrokeWidth())/2)                            (min(w, h) - prop.GetLineWidth())/2)
1073    
1074  class ClassRenderer(wxPyGridCellRenderer):  class ClassRenderer(wxPyGridCellRenderer):
1075    
# Line 728  class ClassRenderer(wxPyGridCellRenderer Line 1078  class ClassRenderer(wxPyGridCellRenderer
1078          self.previewer = ClassDataPreviewer(None, None, shapeType)          self.previewer = ClassDataPreviewer(None, None, shapeType)
1079    
1080      def Draw(self, grid, attr, dc, rect, row, col, isSelected):      def Draw(self, grid, attr, dc, rect, row, col, isSelected):
1081          data = grid.GetTable().GetValueAsCustom(row, col, None)          data = grid.GetTable().GetClassGroup(row)
1082    
1083          dc.SetClippingRegion(rect.GetX(), rect.GetY(),          dc.SetClippingRegion(rect.GetX(), rect.GetY(),
1084                               rect.GetWidth(), rect.GetHeight())                               rect.GetWidth(), rect.GetHeight())

Legend:
Removed from v.451  
changed lines
  Added in v.509

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26