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

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26