/[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 511 by jonathan, Tue Mar 11 16:27:52 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                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, 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      def Reset(self, fieldData, shapeType):          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 220  class ClassTable(wxPyGridTableBase): Line 296  class ClassTable(wxPyGridTableBase):
296                          wxGRIDTABLE_NOTIFY_ROWS_APPENDED,                          wxGRIDTABLE_NOTIFY_ROWS_APPENDED,
297                          newRows - curRows)    # how many                          newRows - curRows)    # how many
298              self.GetView().ProcessTableMessage(msg)              self.GetView().ProcessTableMessage(msg)
299                self.GetView().FitInside()
300          elif newRows < curRows:          elif newRows < curRows:
301              msg = wxGridTableMessage(self,              msg = wxGridTableMessage(self,
302                          wxGRIDTABLE_NOTIFY_ROWS_DELETED,                          wxGRIDTABLE_NOTIFY_ROWS_DELETED,
303                          curRows - newRows,    # position                          curRows - newRows,    # position
304                          curRows - newRows)    # how many                          curRows - newRows)    # how many
305              self.GetView().ProcessTableMessage(msg)              self.GetView().ProcessTableMessage(msg)
306                self.GetView().FitInside()
307    
308      def __SetRow(self, row, group):      def __SetRow(self, row, group):
309            """Set a row's data to that of the group.
310    
311          if isinstance(group, ClassGroupDefault):          The table is considered modified after this operation.
312              data = [group, _('DEFAULT'), group.GetLabel()]  
313          elif isinstance(group, ClassGroupSingleton):          row -- if row is -1 or greater than the current number of rows
314              data = [group, group.GetValue(), group.GetLabel()]                 then group is appended to the end.
315          elif isinstance(group, ClassGroupRange):          """
             data = [group,  
                     _('%s - %s') % (group.GetMin(), group.GetMax()),  
                     group.GetLabel()]  
316    
317          if row >= len(self.tdata):          # either append or replace
318              self.tdata.append(data)          if row == -1 or row >= self.GetNumberRows():
319                self.tdata.append(group)
320          else:          else:
321              self.tdata[row] = data              self.tdata[row] = group
322    
323            self.__Modified()
324    
325      def GetColLabelValue(self, col):      def GetColLabelValue(self, col):
326            """Return the label for the given column."""
327          return self.__col_labels[col]          return self.__col_labels[col]
328    
329      def GetRowLabelValue(self, row):      def GetRowLabelValue(self, row):
330          data = self.tdata[row][COL_VISUAL]          """Return the label for the given row."""
331          if isinstance(data, ClassGroupDefault):   return _("Default")  
332          if isinstance(data, ClassGroupSingleton): return _("Singleton")          group = self.tdata[row]
333          if isinstance(data, ClassGroupRange):     return _("Range")          if isinstance(group, ClassGroupDefault):   return _("Default")
334          if isinstance(data, ClassGroupMap):       return _("Map")          if isinstance(group, ClassGroupSingleton): return _("Singleton")
335            if isinstance(group, ClassGroupRange):     return _("Range")
336            if isinstance(group, ClassGroupMap):       return _("Map")
337    
338            assert(False) # shouldn't get here
339            return _("")
340    
341      def GetNumberRows(self):      def GetNumberRows(self):
342            """Return the number of rows."""
343          return len(self.tdata)          return len(self.tdata)
344    
345      def GetNumberCols(self):      def GetNumberCols(self):
346            """Return the number of columns."""
347          return self.NUM_COLS          return self.NUM_COLS
348    
349      def IsEmptyCell(self, row, col):      def IsEmptyCell(self, row, col):
350          return 0          """Determine if a cell is empty. This is always false."""
351            return False
352    
353      def GetValue(self, row, col):      def GetValue(self, row, col):
354          return self.GetValueAsCustom(row, col, "")          """Return the object that is used to represent the given
355               cell coordinates. This may not be a string."""
356            return self.GetValueAsCustom(row, col, None)
357    
358      def SetValue(self, row, col, value):      def SetValue(self, row, col, value):
359          self.SetValueAsCustom(row, col, "", value)          """Assign 'value' to the cell specified by 'row' and 'col'.
360    
361            The table is considered modified after this operation.
362            """
363    
364            self.SetValueAsCustom(row, col, None, value)
365          self.__Modified()          self.__Modified()
366                
367      def GetValueAsCustom(self, row, col, typeName):      def GetValueAsCustom(self, row, col, typeName):
368          return self.tdata[row][col]          """Return the object that is used to represent the given
369               cell coordinates. This may not be a string.
370    
371            typeName -- unused, but needed to overload wxPyGridTableBase
372            """
373    
374            group = self.tdata[row]
375    
376            if col == COL_SYMBOL:
377                return group.GetProperties()
378    
379            if col == COL_LABEL:
380                return group.GetLabel()
381    
382            # col must be COL_VALUE
383            assert(col == COL_VALUE)
384    
385            if isinstance(group, ClassGroupDefault):
386                return _("DEFAULT")
387            elif isinstance(group, ClassGroupSingleton):
388                return group.GetValue()
389            elif isinstance(group, ClassGroupRange):
390                return _("%s - %s") % (group.GetMin(), group.GetMax())
391    
392            assert(False) # shouldn't get here
393            return None
394    
395      def __ParseInput(self, value):      def __ParseInput(self, value):
396          """Try to determine what kind of input value is          """Try to determine what kind of input value is
397             (a single number or a range)             (string, number, or range)
398    
399            Returns a tuple of length one if there is a single
400            value, or of length two if it is a range.
401          """          """
402    
403          type = self.fieldData[FIELD_TYPE]          type = self.fieldType
404    
405          if type == FIELD_TYPE_STRING:          if type == FIELDTYPE_STRING:
406              return (value,)              return (value,)
407          elif type == FIELD_TYPE_INT or type == FIELD_TYPE_DOUBLE:          elif type == FIELDTYPE_INT or type == FIELDTYPE_DOUBLE:
408    
409                if type == FIELDTYPE_INT:
410                    conv = lambda p: int(float(p))
411                else:
412                    conv = lambda p: p
413    
414              #              #
415              # 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 421  class ClassTable(wxPyGridTableBase):
421              # function.              # function.
422              #              #
423              try:              try:
424                  return (Str2Num(value),)                  return (conv(Str2Num(value)),)
425              except:              except ValueError:
426                  i = value.find('-')                  i = value.find('-')
427                  if i == 0:                  if i == 0:
428                      i = value.find('-', 1)                      i = value.find('-', 1)
429    
430                  return (Str2Num(value[:i]), Str2Num(value[i+1:]))                  return (conv(Str2Num(value[:i])), conv(Str2Num(value[i+1:])))
431    
432            assert(False) # shouldn't get here
433            return (0,)
434                            
435    
436      def SetValueAsCustom(self, row, col, typeName, value):      def SetValueAsCustom(self, row, col, typeName, value):
437          group = self.tdata[row][COL_VISUAL]          """Set the cell specified by 'row' and 'col' to 'value'.
438    
439            If column represents the value column, the input is parsed
440            to determine if a string, number, or range was entered.
441            A new ClassGroup may be created if the type of data changes.
442    
443            The table is considered modified after this operation.
444    
445          if col == COL_VISUAL:          typeName -- unused, but needed to overload wxPyGridTableBase
446              self.tdata[row][COL_VISUAL] = value          """
447    
448            assert(col >= 0 and col < self.GetNumberCols())
449            assert(row >= 0 and row < self.GetNumberRows())
450    
451            group = self.tdata[row]
452    
453            mod = True # assume the data will change
454    
455            if col == COL_SYMBOL:
456                group.SetProperties(value)
457            elif col == COL_LABEL:
458                group.SetLabel(value)
459          elif col == COL_VALUE:          elif col == COL_VALUE:
460              if isinstance(group, ClassGroupDefault):              if isinstance(group, ClassGroupDefault):
461                  # not allowed to modify the default value                  # not allowed to modify the default value
# Line 318  class ClassTable(wxPyGridTableBase): Line 466  class ClassTable(wxPyGridTableBase):
466              else: # SINGLETON, RANGE              else: # SINGLETON, RANGE
467                  try:                  try:
468                      dataInfo = self.__ParseInput(value)                      dataInfo = self.__ParseInput(value)
469                  except:                  except ValueError:
470                      # bad input, ignore the request                      # bad input, ignore the request
471                      pass                      mod = False
472                  else:                  else:
473    
474                        changed = False
475                      ngroup = group                      ngroup = group
476                      props = group.GetProperties()                      props = group.GetProperties()
477    
478                        #
479                        # try to update the values, which may include
480                        # changing the underlying group type if the
481                        # group was a singleton and a range was entered
482                        #
483                      if len(dataInfo) == 1:                      if len(dataInfo) == 1:
484                          if not isinstance(group, ClassGroupSingleton):                          if not isinstance(group, ClassGroupSingleton):
485                              ngroup = ClassGroupSingleton(prop = props)                              ngroup = ClassGroupSingleton(prop = props)
486                                changed = True
487                          ngroup.SetValue(dataInfo[0])                          ngroup.SetValue(dataInfo[0])
488                      elif len(dataInfo) == 2:                      elif len(dataInfo) == 2:
489                          if not isinstance(group, ClassGroupRange):                          if not isinstance(group, ClassGroupRange):
490                              ngroup = ClassGroupRange(prop = props)                              ngroup = ClassGroupRange(prop = props)
491                                changed = True
492                          ngroup.SetRange(dataInfo[0], dataInfo[1])                          ngroup.SetRange(dataInfo[0], dataInfo[1])
493                      else:                      else:
494                          assert(False)                          assert(False)
495                            pass
496    
497                      ngroup.SetLabel(group.GetLabel())                      if changed:
498                      self.__SetRow(row, ngroup)                          ngroup.SetLabel(group.GetLabel())
499                            self.SetClassGroup(row, ngroup)
                     self.GetView().Refresh()  
   
         elif col == COL_LABEL:  
             group.SetLabel(value)  
             self.tdata[row][COL_LABEL] = group.GetLabel()  
500          else:          else:
501              raise ValueError(_("Invalid column request"))              assert(False) # shouldn't be here
502                pass
503    
504          self.__Modified()          if mod:
505                self.__Modified()
506                self.GetView().Refresh()
507    
508      def GetAttr(self, row, col, someExtraParameter):      def GetAttr(self, row, col, someExtraParameter):
509            """Returns the cell attributes"""
510    
511          attr = wxGridCellAttr()          attr = wxGridCellAttr()
512          #attr = wxPyGridTableBase.GetAttr(self, row, col, someExtraParameter)          #attr = wxPyGridTableBase.GetAttr(self, row, col, someExtraParameter)
513    
514          if col == COL_VISUAL:          if col == COL_SYMBOL:
515                # we need to create a new renderer each time, because
516                # SetRenderer takes control of the parameter
517              attr.SetRenderer(ClassRenderer(self.shapeType))              attr.SetRenderer(ClassRenderer(self.shapeType))
518              attr.SetReadOnly()              attr.SetReadOnly()
519    
520          return attr          return attr
521    
522      def GetClassGroup(self, row):      def GetClassGroup(self, row):
523          return self.tdata[row][COL_VISUAL]          """Return the ClassGroup object representing row 'row'."""
524    
525            return self.tdata[row] # self.GetValueAsCustom(row, COL_SYMBOL, None)
526    
527        def SetClassGroup(self, row, group):
528            self.__SetRow(row, group)
529            self.GetView().Refresh()
530    
531      def __Modified(self):      def __Modified(self, mod = True):
532          self.modified = 1          """Adjust the modified flag.
533    
534            mod -- if -1 set the modified flag to False, otherwise perform
535                   an 'or' operation with the current value of the flag and
536                   'mod'
537            """
538    
539            if mod == -1:
540                self.modified = False
541            else:
542                self.modified = mod or self.modified
543    
544      def IsModified(self):      def IsModified(self):
545            """True if this table is considered modified."""
546          return self.modified          return self.modified
547    
548      def DeleteRows(self, pos, numRows = 1):      def DeleteRows(self, pos, numRows = 1):
549            """Deletes 'numRows' beginning at row 'pos'.
550    
551            The row representing the default group is not removed.
552    
553            The table is considered modified if any rows are removed.
554            """
555    
556          assert(pos >= 0)          assert(pos >= 0)
557          old_len = len(self.tdata)          old_len = len(self.tdata)
558          for row in range(pos, pos - numRows, -1):          for row in range(pos, pos - numRows, -1):
559              group = self.GetValueAsCustom(row, COL_VISUAL, None)              group = self.GetClassGroup(row)
560              if not isinstance(group, ClassGroupDefault):              if not isinstance(group, ClassGroupDefault):
561                  self.tdata.pop(row)                  self.tdata.pop(row)
562                  self.__Modified()                  self.__Modified()
# Line 381  class ClassTable(wxPyGridTableBase): Line 565  class ClassTable(wxPyGridTableBase):
565              self.__NotifyRowChanges(old_len, len(self.tdata))              self.__NotifyRowChanges(old_len, len(self.tdata))
566    
567      def AppendRows(self, numRows = 1):      def AppendRows(self, numRows = 1):
568            """Append 'numRows' empty rows to the end of the table.
569    
570            The table is considered modified if any rows are appended.
571            """
572    
573          old_len = len(self.tdata)          old_len = len(self.tdata)
574          for i in range(numRows):          for i in range(numRows):
575              np = ClassGroupSingleton()              np = ClassGroupSingleton()
576              self.tdata.append([np, np.GetValue(), np.GetLabel()])              self.__SetRow(-1, np)
             self.__Modified()  
577    
578          if self.IsModified():          if self.IsModified():
579              self.__NotifyRowChanges(old_len, len(self.tdata))              self.__NotifyRowChanges(old_len, len(self.tdata))
580    
581    
582  class Classifier(wxDialog):  class Classifier(NonModalDialog):
583            
584      def __init__(self, parent, layer):      def __init__(self, parent, interactor, name, layer):
585          wxDialog.__init__(self, parent, -1, _("Classify"),          NonModalDialog.__init__(self, parent, interactor, name,
586                            style = wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)                                  _("Classifier: %s") % layer.Title())
587    
588            panel = wxPanel(self, -1, size=(100, 100))
589    
590          self.layer = layer          self.layer = layer
591    
592            self.originalClass = self.layer.GetClassification()
593            field = self.originalClass.GetField()
594            fieldType = self.originalClass.GetFieldType()
595    
596          topBox = wxBoxSizer(wxVERTICAL)          topBox = wxBoxSizer(wxVERTICAL)
597            panelBox = wxBoxSizer(wxVERTICAL)
598    
599          topBox.Add(wxStaticText(self, -1, _("Layer: %s") % layer.Title()),          #panelBox.Add(wxStaticText(panel, -1, _("Layer: %s") % layer.Title()),
600              0, wxALIGN_LEFT | wxALL, 4)              #0, wxALIGN_LEFT | wxALL, 4)
601          topBox.Add(wxStaticText(self, -1, _("Type: %s") % layer.ShapeType()),          panelBox.Add(wxStaticText(panel, -1,
602                                    _("Layer Type: %s") % layer.ShapeType()),
603              0, wxALIGN_LEFT | wxALL, 4)              0, wxALIGN_LEFT | wxALL, 4)
604    
         propertyBox = wxBoxSizer(wxHORIZONTAL)  
         propertyBox.Add(wxStaticText(self, -1, _("Field: ")),  
             0, wxALIGN_CENTER | wxALL, 4)  
605    
606          self.fields = wxComboBox(self, ID_PROPERTY_SELECT, "",          #
607            # make field combo box
608            #
609            self.fields = wxComboBox(panel, ID_PROPERTY_SELECT, "",
610                                       style = wxCB_READONLY)                                       style = wxCB_READONLY)
611    
612          self.num_cols = layer.table.field_count()          self.num_cols = layer.table.field_count()
613          # just assume the first field in case one hasn't been          # just assume the first field in case one hasn't been
614          # specified in the file.          # specified in the file.
615          self.__cur_field = 0          self.__cur_field = 0
616          clazz = layer.GetClassification()  
617          field = clazz.GetField()          self.fields.Append("<None>")
618            self.fields.SetClientData(0, None)
619    
620          for i in range(self.num_cols):          for i in range(self.num_cols):
621              type, name, len, decc = layer.table.field_info(i)              type, name, len, decc = layer.table.field_info(i)
622              self.fields.Append(name)              self.fields.Append(name)
623    
624              if name == field:              if name == field:
625                  self.__cur_field = i                  self.__cur_field = i + 1
626                  self.fields.SetClientData(i, [clazz, type, name, len, decc])                  self.fields.SetClientData(i + 1, self.originalClass)
627              else:              else:
628                  self.fields.SetClientData(i, [None, type, name, len, decc])                  self.fields.SetClientData(i + 1, None)
629    
         self.fields.SetSelection(self.__cur_field)  
630    
631            ###########
632    
633            self.fieldTypeText = wxStaticText(panel, -1, "")
634            panelBox.Add(self.fieldTypeText, 0, wxGROW | wxALIGN_LEFT | wxALL, 4)
635    
636            propertyBox = wxBoxSizer(wxHORIZONTAL)
637            propertyBox.Add(wxStaticText(panel, -1, _("Field: ")),
638                0, wxALIGN_LEFT | wxALL, 4)
639          propertyBox.Add(self.fields, 1, wxGROW|wxALL, 4)          propertyBox.Add(self.fields, 1, wxGROW|wxALL, 4)
640          EVT_COMBOBOX(self, ID_PROPERTY_SELECT, self.OnFieldSelect)          EVT_COMBOBOX(self, ID_PROPERTY_SELECT, self._OnFieldSelect)
641    
642          topBox.Add(propertyBox, 0, wxGROW, 4)          panelBox.Add(propertyBox, 0, wxGROW, 4)
643    
644            ###########
645          #          #
646          # Classification data table          # Classification data table
647          #          #
648    
649          controlBox = wxBoxSizer(wxHORIZONTAL)          controlBox = wxBoxSizer(wxHORIZONTAL)
650          self.classGrid = ClassGrid(self,  
651                                     layer,          self.classGrid = ClassGrid(panel)
652                                     self.fields.GetClientData(self.__cur_field))          self.__SetGridTable(self.__cur_field)
653    
654          controlBox.Add(self.classGrid, 1, wxGROW, 0)          controlBox.Add(self.classGrid, 1, wxGROW, 0)
655    
656            ###########
657            #
658            # Control buttons:
659            #
660            self.controlButtons = []
661    
662          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)  
663    
664          controlButtonBox.Add(wxButton(self, ID_CLASSIFY_REMOVE,          button = wxButton(panel, ID_CLASSIFY_ADD, _("Add"))
665              _("Remove")), 0, wxGROW | wxALL | wxALIGN_BOTTOM, 4)          controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)
666            self.controlButtons.append(button)
667    
668            #button = wxButton(panel, ID_CLASSIFY_GENRANGE, _("Generate Ranges"))
669            #controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)
670            #self.controlButtons.append(button)
671    
672            button = wxButton(panel, ID_CLASSIFY_MOVEUP, _("Move Up"))
673            controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)
674            self.controlButtons.append(button)
675    
676            button = wxButton(panel, ID_CLASSIFY_MOVEDOWN, _("Move Down"))
677            controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)
678            self.controlButtons.append(button)
679    
680            controlButtonBox.Add(60, 20, 0, wxGROW | wxALL | wxALIGN_BOTTOM, 4)
681    
682            button = wxButton(panel, ID_CLASSIFY_REMOVE, _("Remove"))
683            controlButtonBox.Add(button, 0, wxGROW | wxALL | wxALIGN_BOTTOM, 4)
684            self.controlButtons.append(button)
685    
686          controlBox.Add(controlButtonBox, 0, wxGROW, 10)          controlBox.Add(controlButtonBox, 0, wxGROW, 10)
687          topBox.Add(controlBox, 1, wxGROW, 10)          panelBox.Add(controlBox, 1, wxGROW, 10)
688    
689          EVT_BUTTON(self, ID_CLASSIFY_ADD, self.OnAdd)          EVT_BUTTON(self, ID_CLASSIFY_ADD, self._OnAdd)
690          EVT_BUTTON(self, ID_CLASSIFY_REMOVE, self.OnRemove)          EVT_BUTTON(self, ID_CLASSIFY_REMOVE, self._OnRemove)
691          EVT_BUTTON(self, ID_CLASSIFY_GENRANGE, self.OnGenRange)          EVT_BUTTON(self, ID_CLASSIFY_GENRANGE, self._OnGenRange)
692            EVT_BUTTON(self, ID_CLASSIFY_MOVEUP, self._OnMoveUp)
693            EVT_BUTTON(self, ID_CLASSIFY_MOVEDOWN, self._OnMoveDown)
694    
695            ###########
696    
         #  
         # Control buttons:  
         #  
697          buttonBox = wxBoxSizer(wxHORIZONTAL)          buttonBox = wxBoxSizer(wxHORIZONTAL)
698          buttonBox.Add(wxButton(self, ID_CLASSIFY_OK, _("OK")),          buttonBox.Add(wxButton(panel, ID_CLASSIFY_OK, _("OK")),
699                        0, wxALL, 4)                        0, wxALL, 4)
700          buttonBox.Add(wxButton(self, ID_CLASSIFY_CANCEL, _("Cancel")),          buttonBox.Add(60, 20, 0, wxALL, 4)
701            buttonBox.Add(wxButton(panel, ID_CLASSIFY_APPLY, _("Apply")),
702                        0, wxALL, 4)                        0, wxALL, 4)
703          topBox.Add(buttonBox, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_BOTTOM, 10)          buttonBox.Add(60, 20, 0, wxALL, 4)
704            buttonBox.Add(wxButton(panel, ID_CLASSIFY_CANCEL, _("Cancel")),
705                          0, wxALL, 4)
706            panelBox.Add(buttonBox, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_BOTTOM, 0)
707    
708          EVT_BUTTON(self, ID_CLASSIFY_OK, self.OnOK)          EVT_BUTTON(self, ID_CLASSIFY_OK, self._OnOK)
709          EVT_BUTTON(self, ID_CLASSIFY_CANCEL, self.OnCancel)          EVT_BUTTON(self, ID_CLASSIFY_APPLY, self._OnApply)
710            EVT_BUTTON(self, ID_CLASSIFY_CANCEL, self._OnCancel)
711    
712            ###########
713    
714            self.fields.SetSelection(self.__cur_field)
715            self.__SelectField(self.__cur_field)
716    
717          self.SetAutoLayout(true)          panel.SetAutoLayout(True)
718            panel.SetSizer(panelBox)
719            panelBox.SetSizeHints(panel)
720    
721            topBox.Add(panel, 1, wxGROW, 0)
722            panelBox.SetSizeHints(self)
723            self.SetAutoLayout(True)
724          self.SetSizer(topBox)          self.SetSizer(topBox)
         topBox.Fit(self)  
         topBox.SetSizeHints(self)  
725    
726      def __BuildClassification(self, prop):      def __BuildClassification(self, fieldIndex):
727    
728            numRows = self.classGrid.GetNumberRows()
729            assert(numRows > 0) # there should always be a default row
730    
731          clazz = Classification()          clazz = Classification()
732          clazz.SetField(self.fields.GetString(prop))          if fieldIndex == 0:
733                fieldName = None
734                fieldType = None
735            else:
736                fieldName = self.fields.GetString(fieldIndex)
737                fieldType = self.layer.GetFieldType(fieldName)
738    
739          numRows = self.classGrid.GetNumberRows()          clazz.SetField(fieldName)
740            clazz.SetFieldType(fieldType)
741    
         if numRows > 0:  
             table = self.classGrid.GetTable()  
             clazz.SetDefaultGroup(table.GetClassGroup(0))  
742    
743              for i in range(1, numRows):          table = self.classGrid.GetTable()
744                  clazz.AddGroup(table.GetClassGroup(i))          clazz.SetDefaultGroup(table.GetClassGroup(0))
745    
746            for i in range(1, numRows):
747                clazz.AddGroup(table.GetClassGroup(i))
748    
749          return clazz          return clazz
750    
751      def OnFieldSelect(self, event):      def __SetGridTable(self, fieldIndex):
752          data = self.fields.GetClientData(self.__cur_field)  
753          data[FIELD_CLASS] = self.__BuildClassification(self.__cur_field)          clazz = self.fields.GetClientData(fieldIndex)
754    
755            if clazz is None:
756                clazz = Classification()
757                clazz.SetDefaultGroup(
758                    ClassGroupDefault(
759                        self.layer.GetClassification().
760                                   GetDefaultGroup().GetProperties()))
761    
762                fieldName = self.fields.GetString(fieldIndex)
763                fieldType = self.layer.GetFieldType(fieldName)
764                clazz.SetFieldType(fieldType)
765                    
766            self.classGrid.CreateTable(clazz, self.layer.ShapeType())
767    
768    
769    
770        type2string = {None:             _("None"),
771                       FIELDTYPE_STRING: _("Text"),
772                       FIELDTYPE_INT:    _("Integer"),
773                       FIELDTYPE_DOUBLE: _("Decimal")}
774    
775        def __SetFieldTypeText(self, fieldIndex):
776            fieldName = self.fields.GetString(fieldIndex)
777            fieldType = self.layer.GetFieldType(fieldName)
778    
779            assert(Classifier.type2string.has_key(fieldType))
780    
781            text = Classifier.type2string[fieldType]
782    
783            self.fieldTypeText.SetLabel(_("Field Type: %s") % text)
784    
785        def __SelectField(self, newIndex, oldIndex = -1):
786    
787            assert(oldIndex >= -1)
788    
789            if oldIndex != -1:
790                clazz = self.__BuildClassification(oldIndex)
791                self.fields.SetClientData(oldIndex, clazz)
792    
793            self.__SetGridTable(newIndex)
794    
795          self.fields.SetClientData(self.__cur_field, data)          enabled = newIndex != 0
796    
797          self.__cur_field = self.fields.GetSelection()          for b in self.controlButtons:
798          fieldData = self.fields.GetClientData(self.__cur_field)              b.Enable(enabled)
         self.classGrid.GetTable().Reset(fieldData, self.layer.ShapeType())  
799    
800      def OnOK(self, event):          self.__SetFieldTypeText(newIndex)
801    
802    
803        def _OnFieldSelect(self, event):
804            index = self.fields.GetSelection()
805            self.__SelectField(index, self.__cur_field)
806            self.__cur_field = index
807    
808        def _OnApply(self, event):
809          """Put the data from the table into a new Classification and hand          """Put the data from the table into a new Classification and hand
810             it to the layer.             it to the layer.
811          """          """
812    
813          clazz = self.fields.GetClientData(self.__cur_field)[FIELD_CLASS]          clazz = self.fields.GetClientData(self.__cur_field)
814    
815          #          #
816          # 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 819  class Classifier(wxDialog):
819          if clazz is None or self.classGrid.GetTable().IsModified():          if clazz is None or self.classGrid.GetTable().IsModified():
820              clazz = self.__BuildClassification(self.__cur_field)              clazz = self.__BuildClassification(self.__cur_field)
821    
         clazz.SetLayer(self.layer)  
   
822          self.layer.SetClassification(clazz)          self.layer.SetClassification(clazz)
823    
824          self.EndModal(wxID_OK)      def _OnOK(self, event):
825            self._OnApply(event)
826            self.OnClose(event)
827    
828        def _OnCancel(self, event):
829            """The layer's current classification stays the same."""
830            self.layer.SetClassification(self.originalClass)
831            self.OnClose(event)
832    
833      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):  
834          self.classGrid.AppendRows()          self.classGrid.AppendRows()
835    
836      def OnRemove(self, event):      def _OnRemove(self, event):
837          self.classGrid.DeleteSelectedRows()          self.classGrid.DeleteSelectedRows()
838    
839      def OnGenRange(self, event):      def _OnGenRange(self, event):
840          print "Classifier.OnGenRange()"          print "Classifier._OnGenRange()"
841    
842        def _OnMoveUp(self, event):
843            sel = self.classGrid.GetCurrentSelection()
844    
845            if len(sel) == 1:
846                i = sel[0]
847                if i > 1:
848                    table = self.classGrid.GetTable()
849                    x = table.GetClassGroup(i - 1)
850                    y = table.GetClassGroup(i)
851                    table.SetClassGroup(i - 1, y)
852                    table.SetClassGroup(i, x)
853                    self.classGrid.ClearSelection()
854                    self.classGrid.SelectRow(i - 1)
855    
856        def _OnMoveDown(self, event):
857            sel = self.classGrid.GetCurrentSelection()
858    
859            if len(sel) == 1:
860                i = sel[0]
861                table = self.classGrid.GetTable()
862                if 0 < i < table.GetNumberRows() - 1:
863                    x = table.GetClassGroup(i)
864                    y = table.GetClassGroup(i + 1)
865                    table.SetClassGroup(i, y)
866                    table.SetClassGroup(i + 1, x)
867                    self.classGrid.ClearSelection()
868                    self.classGrid.SelectRow(i + 1)
869    
870    
871  ID_SELPROP_OK = 4001  ID_SELPROP_OK = 4001
# Line 550  ID_SELPROP_SPINCTRL = 4002 Line 874  ID_SELPROP_SPINCTRL = 4002
874  ID_SELPROP_PREVIEW = 4003  ID_SELPROP_PREVIEW = 4003
875  ID_SELPROP_STROKECLR = 4004  ID_SELPROP_STROKECLR = 4004
876  ID_SELPROP_FILLCLR = 4005  ID_SELPROP_FILLCLR = 4005
877    ID_SELPROP_STROKECLRTRANS = 4006
878    ID_SELPROP_FILLCLRTRANS = 4007
879    
880  class SelectPropertiesDialog(wxDialog):  class SelectPropertiesDialog(wxDialog):
881    
882      def __init__(self, parent, prop, shapeType):      def __init__(self, parent, prop, shapeType):
883          wxDialog.__init__(self, parent, -1, _("Select Properties"),          wxDialog.__init__(self, parent, -1, _("Select Properties"),
884                            style = wxRESIZE_BORDER)                            style = wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
885    
886          self.prop = ClassGroupProperties(prop)          self.prop = ClassGroupProperties(prop)
887    
# Line 575  class SelectPropertiesDialog(wxDialog): Line 901  class SelectPropertiesDialog(wxDialog):
901    
902          # control box          # control box
903          ctrlBox = wxBoxSizer(wxVERTICAL)          ctrlBox = wxBoxSizer(wxVERTICAL)
904          ctrlBox.Add(  
905              wxButton(self, ID_SELPROP_STROKECLR, "Change Stroke Color"),          lineColorBox = wxBoxSizer(wxHORIZONTAL)
906              1, wxALIGN_CENTER_HORIZONTAL | wxALL | wxGROW, 4)          lineColorBox.Add(
907          EVT_BUTTON(self, ID_SELPROP_STROKECLR, self.OnChangeStrokeColor)              wxButton(self, ID_SELPROP_STROKECLR, _("Change Line Color")),
908                1, wxALL | wxGROW, 4)
909            EVT_BUTTON(self, ID_SELPROP_STROKECLR, self._OnChangeLineColor)
910    
911            lineColorBox.Add(
912                wxButton(self, ID_SELPROP_STROKECLRTRANS, _("Transparent")),
913                1, wxALL | wxGROW, 4)
914            EVT_BUTTON(self, ID_SELPROP_STROKECLRTRANS,
915                       self._OnChangeLineColorTrans)
916    
917            ctrlBox.Add(lineColorBox, 0,
918                        wxALIGN_CENTER_HORIZONTAL | wxALL | wxGROW, 4)
919    
920          if shapeType != SHAPETYPE_ARC:          if shapeType != SHAPETYPE_ARC:
921              ctrlBox.Add(              fillColorBox = wxBoxSizer(wxHORIZONTAL)
922                  wxButton(self, ID_SELPROP_FILLCLR, "Change Fill Color"),              fillColorBox.Add(
923                  0, wxALIGN_LEFT | wxALL | wxGROW, 4)                  wxButton(self, ID_SELPROP_FILLCLR, _("Change Fill Color")),
924              EVT_BUTTON(self, ID_SELPROP_FILLCLR, self.OnChangeFillColor)                  1, wxALL | wxGROW, 4)
925                EVT_BUTTON(self, ID_SELPROP_FILLCLR, self._OnChangeFillColor)
926                fillColorBox.Add(
927                    wxButton(self, ID_SELPROP_FILLCLRTRANS, _("Transparent")),
928                    1, wxALL | wxGROW, 4)
929                EVT_BUTTON(self, ID_SELPROP_FILLCLRTRANS,
930                           self._OnChangeFillColorTrans)
931                ctrlBox.Add(fillColorBox, 0,
932                            wxALIGN_CENTER_HORIZONTAL | wxALL | wxGROW, 4)
933    
934          spinBox = wxBoxSizer(wxHORIZONTAL)          spinBox = wxBoxSizer(wxHORIZONTAL)
935          spinBox.Add(wxStaticText(self, -1, _("Stroke Width: ")),          spinBox.Add(wxStaticText(self, -1, _("Line Width: ")),
936                  0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 4)                  0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 4)
937          self.spinCtrl = wxSpinCtrl(self, ID_SELPROP_SPINCTRL,          self.spinCtrl = wxSpinCtrl(self, ID_SELPROP_SPINCTRL,
938                                     min=1, max=10,                                     min=1, max=10,
939                                     value=str(prop.GetStrokeWidth()),                                     value=str(prop.GetLineWidth()),
940                                     initial=prop.GetStrokeWidth())                                     initial=prop.GetLineWidth())
941    
942          EVT_SPINCTRL(self, ID_SELPROP_SPINCTRL, self.OnSpin)          EVT_SPINCTRL(self, ID_SELPROP_SPINCTRL, self._OnSpin)
943    
944          spinBox.Add(self.spinCtrl, 0, wxALIGN_LEFT | wxALL, 4)          spinBox.Add(self.spinCtrl, 0, wxALIGN_LEFT | wxALL, 4)
945    
# Line 602  class SelectPropertiesDialog(wxDialog): Line 947  class SelectPropertiesDialog(wxDialog):
947          itemBox.Add(ctrlBox, 0, wxALIGN_RIGHT | wxALL | wxGROW, 0)          itemBox.Add(ctrlBox, 0, wxALIGN_RIGHT | wxALL | wxGROW, 0)
948          topBox.Add(itemBox, 1, wxALIGN_LEFT | wxALL | wxGROW, 0)          topBox.Add(itemBox, 1, wxALIGN_LEFT | wxALL | wxGROW, 0)
949    
   
950          #          #
951          # Control buttons:          # Control buttons:
952          #          #
953          buttonBox = wxBoxSizer(wxHORIZONTAL)          buttonBox = wxBoxSizer(wxHORIZONTAL)
954          buttonBox.Add(wxButton(self, ID_CLASSIFY_OK, _("OK")),          buttonBox.Add(wxButton(self, ID_SELPROP_OK, _("OK")),
955                        0, wxALL, 4)                        0, wxALL, 4)
956          buttonBox.Add(wxButton(self, ID_CLASSIFY_CANCEL, _("Cancel")),          buttonBox.Add(wxButton(self, ID_SELPROP_CANCEL, _("Cancel")),
957                        0, wxALL, 4)                        0, wxALL, 4)
958          topBox.Add(buttonBox, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_BOTTOM, 10)          topBox.Add(buttonBox, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_BOTTOM, 10)
959                                                                                                                                                                    
960          EVT_BUTTON(self, ID_SELPROP_OK, self.OnOK)          EVT_BUTTON(self, ID_SELPROP_OK, self._OnOK)
961          EVT_BUTTON(self, ID_SELPROP_CANCEL, self.OnCancel)          EVT_BUTTON(self, ID_SELPROP_CANCEL, self._OnCancel)
962                                                                                                                                                                    
963          self.SetAutoLayout(true)          self.SetAutoLayout(True)
964          self.SetSizer(topBox)          self.SetSizer(topBox)
965          topBox.Fit(self)          topBox.Fit(self)
966          topBox.SetSizeHints(self)          topBox.SetSizeHints(self)
967    
968      def OnOK(self, event):      def _OnOK(self, event):
969          self.EndModal(wxID_OK)          self.EndModal(wxID_OK)
970    
971      def OnCancel(self, event):      def _OnCancel(self, event):
972          self.EndModal(wxID_CANCEL)          self.EndModal(wxID_CANCEL)
973    
974      def OnSpin(self, event):      def _OnSpin(self, event):
975          self.prop.SetStrokeWidth(self.spinCtrl.GetValue())          self.prop.SetLineWidth(self.spinCtrl.GetValue())
976          self.previewer.Refresh()          self.previewer.Refresh()
977    
978      def __GetColor(self, cur):      def __GetColor(self, cur):
# Line 642  class SelectPropertiesDialog(wxDialog): Line 986  class SelectPropertiesDialog(wxDialog):
986    
987          return ret          return ret
988                    
989      def OnChangeStrokeColor(self, event):      def _OnChangeLineColor(self, event):
990          clr = self.__GetColor(self.prop.GetStroke())          clr = self.__GetColor(self.prop.GetLineColor())
991          if clr is not None:          if clr is not None:
992              self.prop.SetStroke(clr)              self.prop.SetLineColor(clr)
993          self.previewer.Refresh() # XXX: work around, see ClassDataPreviewer          self.previewer.Refresh() # XXX: work around, see ClassDataPreviewer
994    
995      def OnChangeFillColor(self, event):      def _OnChangeLineColorTrans(self, event):
996            self.prop.SetLineColor(Color.None)
997            self.previewer.Refresh() # XXX: work around, see ClassDataPreviewer
998            
999        def _OnChangeFillColor(self, event):
1000          clr = self.__GetColor(self.prop.GetFill())          clr = self.__GetColor(self.prop.GetFill())
1001          if clr is not None:          if clr is not None:
1002              self.prop.SetFill(clr)              self.prop.SetFill(clr)
1003          self.previewer.Refresh() # XXX: work around, see ClassDataPreviewer          self.previewer.Refresh() # XXX: work around, see ClassDataPreviewer
1004    
1005        def _OnChangeFillColorTrans(self, event):
1006            self.prop.SetFill(Color.None)
1007            self.previewer.Refresh() # XXX: work around, see ClassDataPreviewer
1008    
1009      def GetClassGroupProperties(self):      def GetClassGroupProperties(self):
1010          return self.prop          return self.prop
1011    
# Line 664  class ClassDataPreviewer(wxWindow): Line 1016  class ClassDataPreviewer(wxWindow):
1016                         parent = None, id = -1, size = wxDefaultSize):                         parent = None, id = -1, size = wxDefaultSize):
1017          if parent is not None:          if parent is not None:
1018              wxWindow.__init__(self, parent, id, size=size)              wxWindow.__init__(self, parent, id, size=size)
1019              EVT_PAINT(self, self.OnPaint)              EVT_PAINT(self, self._OnPaint)
1020    
1021          self.rect = rect          self.rect = rect
1022          self.prop = prop          self.prop = prop
1023          self.shapeType = shapeType          self.shapeType = shapeType
1024    
1025      def OnPaint(self, event):      def _OnPaint(self, event):
1026          dc = wxPaintDC(self)          dc = wxPaintDC(self)
1027    
1028          # 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 1044  class ClassDataPreviewer(wxWindow):
1044              w = rect.GetWidth()              w = rect.GetWidth()
1045              h = rect.GetHeight()              h = rect.GetHeight()
1046    
1047          stroke = prop.GetStroke()          stroke = prop.GetLineColor()
1048          if stroke is Color.None:          if stroke is Color.None:
1049              pen = wxTRANSPARENT_PEN              pen = wxTRANSPARENT_PEN
1050          else:          else:
1051              pen = wxPen(Color2wxColour(stroke),              pen = wxPen(Color2wxColour(stroke),
1052                          prop.GetStrokeWidth(),                          prop.GetLineWidth(),
1053                          wxSOLID)                          wxSOLID)
1054    
1055          stroke = prop.GetFill()          stroke = prop.GetFill()
# Line 719  class ClassDataPreviewer(wxWindow): Line 1071  class ClassDataPreviewer(wxWindow):
1071               shapeType == SHAPETYPE_POLYGON:               shapeType == SHAPETYPE_POLYGON:
1072    
1073              dc.DrawCircle(x + w/2, y + h/2,              dc.DrawCircle(x + w/2, y + h/2,
1074                            (min(w, h) - prop.GetStrokeWidth())/2)                            (min(w, h) - prop.GetLineWidth())/2)
1075    
1076  class ClassRenderer(wxPyGridCellRenderer):  class ClassRenderer(wxPyGridCellRenderer):
1077    
# Line 728  class ClassRenderer(wxPyGridCellRenderer Line 1080  class ClassRenderer(wxPyGridCellRenderer
1080          self.previewer = ClassDataPreviewer(None, None, shapeType)          self.previewer = ClassDataPreviewer(None, None, shapeType)
1081    
1082      def Draw(self, grid, attr, dc, rect, row, col, isSelected):      def Draw(self, grid, attr, dc, rect, row, col, isSelected):
1083          data = grid.GetTable().GetValueAsCustom(row, col, None)          data = grid.GetTable().GetClassGroup(row)
1084    
1085          dc.SetClippingRegion(rect.GetX(), rect.GetY(),          dc.SetClippingRegion(rect.GetX(), rect.GetY(),
1086                               rect.GetWidth(), rect.GetHeight())                               rect.GetWidth(), rect.GetHeight())

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26