/[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 460 by jonathan, Wed Mar 5 18:16:28 2003 UTC revision 615 by jonathan, Mon Apr 7 08:57:20 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 24  from Thuban.Model.color import Color Line 27  from Thuban.Model.color import Color
27    
28  from Thuban.Model.layer import Layer, SHAPETYPE_ARC, SHAPETYPE_POLYGON, SHAPETYPE_POINT  from Thuban.Model.layer import Layer, SHAPETYPE_ARC, SHAPETYPE_POLYGON, SHAPETYPE_POINT
29    
30    from Thuban.UI.classgen import ClassGenDialog, ClassGenerator
31    
32    from dialogs import NonModalDialog
33    
34  # widget id's  # widget id's
35  ID_PROPERTY_SELECT = 4010  ID_PROPERTY_SELECT = 4010
36  ID_CLASS_TABLE = 40011  ID_CLASS_TABLE = 40011
# Line 31  ID_CLASS_TABLE = 40011 Line 38  ID_CLASS_TABLE = 40011
38  ID_CLASSIFY_OK = 4001  ID_CLASSIFY_OK = 4001
39  ID_CLASSIFY_CANCEL = 4002  ID_CLASSIFY_CANCEL = 4002
40  ID_CLASSIFY_ADD = 4003  ID_CLASSIFY_ADD = 4003
41  ID_CLASSIFY_GENRANGE = 4004  ID_CLASSIFY_GENCLASS = 4004
42  ID_CLASSIFY_REMOVE = 4005  ID_CLASSIFY_REMOVE = 4005
43  ID_CLASSIFY_MOVEUP = 4006  ID_CLASSIFY_MOVEUP = 4006
44  ID_CLASSIFY_MOVEDOWN = 4007  ID_CLASSIFY_MOVEDOWN = 4007
45    ID_CLASSIFY_APPLY = 4008
46    ID_CLASSIFY_EDITPROPS = 4009
47    ID_CLASSIFY_CLOSE = 4010
48    
49  # table columns  # table columns
50  COL_SYMBOL = 0  COL_SYMBOL = 0
# Line 53  FIELD_NAME = 2 Line 63  FIELD_NAME = 2
63  import weakref  import weakref
64  class ClassGrid(wxGrid):  class ClassGrid(wxGrid):
65    
66      def __init__(self, parent):  
67        def __init__(self, parent, classifier):
68          """Constructor.          """Constructor.
69    
70          parent -- the parent window          parent -- the parent window
# Line 62  class ClassGrid(wxGrid): Line 73  class ClassGrid(wxGrid):
73                   use for display.                   use for display.
74          """          """
75    
76          wxGrid.__init__(self, parent, ID_CLASS_TABLE, size = (340, 160))          #wxGrid.__init__(self, parent, ID_CLASS_TABLE, size = (340, 160))
77          self.SetTable(ClassTable(fieldData, layer.ShapeType(), self), true)          wxGrid.__init__(self, parent, ID_CLASS_TABLE)
78          self.SetSelectionMode(wxGrid.wxGridSelectRows)          #self.SetTable(ClassTable(fieldData, layer.ShapeType(), self), True)
79    
80            self.classifier = classifier
81    
82            self.currentSelection = []
83    
84          EVT_GRID_CELL_LEFT_DCLICK(self, self._OnCellDClick)          EVT_GRID_CELL_LEFT_DCLICK(self, self._OnCellDClick)
85          EVT_GRID_RANGE_SELECT(self, self._OnSelectedRange)          EVT_GRID_RANGE_SELECT(self, self._OnSelectedRange)
86          EVT_GRID_SELECT_CELL(self, self._OnSelectedCell)          EVT_GRID_SELECT_CELL(self, self._OnSelectedCell)
87            EVT_GRID_COL_SIZE(self, self._OnCellResize)
88            EVT_GRID_ROW_SIZE(self, self._OnCellResize)
89    
90          self.currentSelection = []          #print "123123123: ", ('Show' in dir(self))
91    
92      def CreateTable(self, clazz, shapeType):      #def Show(self):
93            #print "SHOW!"
94    
95          assert(isinstance(clazz, Classification))      #def Refresh(self):
96            #self.Show()
97        #def Update(self):
98            #self.Show()
99    
100        def CreateTable(self, clazz, shapeType, group = None):
101    
102            assert isinstance(clazz, Classification)
103    
         self.shapeType = shapeType  
104          table = self.GetTable()          table = self.GetTable()
105          if table is None:          if table is None:
106              self.SetTable(ClassTable(clazz, self.shapeType, self), true)              w = self.GetDefaultColSize() * 3 + self.GetDefaultRowLabelSize()
107          else:              h = self.GetDefaultRowSize() * 4 + self.GetDefaultColLabelSize()
108              table.Reset(clazz, self.shapeType)              self.SetDimensions(-1, -1, w, h)
109                self.SetSizeHints(w, h, -1, -1)
110                table = ClassTable(self)
111                self.SetTable(table, True)
112    
113    
114            self.SetSelectionMode(wxGrid.wxGridSelectRows)
115          self.ClearSelection()          self.ClearSelection()
116    
117            #print "8------------------"
118            table.Reset(clazz, shapeType, group)
119            #print "9------------------"
120    
121    #   def Show(self, show = True):
122    #       print "SHOW!"
123    #       wxGrid.Show(self, show)
124    
125    #       sel = self.GetCurrentSelection()
126    
127    #       print "( 1"
128    #       if len(sel) == 1:
129    #           print "( 2"
130    #           self.MakeCellVisible(sel[0], 0)
131    
132      def GetCurrentSelection(self):      def GetCurrentSelection(self):
133          """Return the currently highlighted rows as an increasing list          """Return the currently highlighted rows as an increasing list
134             of row numbers."""             of row numbers."""
135            #print "@@ ", self.currentSelection
136          sel = copy.copy(self.currentSelection)          sel = copy.copy(self.currentSelection)
137          sel.sort()          sel.sort()
138          return sel          return sel
139    
140        def GetSelectedRows(self):
141            return self.GetCurrentSelection()
142    
143      def SetCellRenderer(self, row, col):      def SetCellRenderer(self, row, col):
144          raise ValueError(_("Must not allow setting of renderer in ClassGrid!"))          raise ValueError(_("Must not allow setting of renderer in ClassGrid!"))
145    
# Line 125  class ClassGrid(wxGrid): Line 173  class ClassGrid(wxGrid):
173          # if only one thing is selected check if it is the default          # if only one thing is selected check if it is the default
174          # data row, because we can't remove that          # data row, because we can't remove that
175          if len(sel) == 1:          if len(sel) == 1:
176              group = self.GetTable().GetValueAsCustom(sel[0], COL_SYMBOL, None)              #group = self.GetTable().GetValueAsCustom(sel[0], COL_SYMBOL, None)
177                group = self.GetTable().GetClassGroup(sel[0])
178              if isinstance(group, ClassGroupDefault):              if isinstance(group, ClassGroupDefault):
179                  wxMessageDialog(self,                  wxMessageDialog(self,
180                                  "The Default group cannot be removed.",                                  "The Default group cannot be removed.",
# Line 157  class ClassGrid(wxGrid): Line 206  class ClassGrid(wxGrid):
206                  r = self.GetNumberRows() - 1                  r = self.GetNumberRows() - 1
207              self.SelectRow(r)              self.SelectRow(r)
208                    
209    
210        def SelectGroup(self, group, makeVisible = True):
211            if group is None: return
212    
213            assert isinstance(group, ClassGroup)
214    
215            table = self.GetTable()
216    
217            assert table is not None
218    
219    
220            #print "-- ", group
221            for i in range(table.GetNumberRows()):
222                g = table.GetClassGroup(i)
223                #print "1", g
224                if g is group:
225                    #print "2"
226                    self.SelectRow(i)
227                    if makeVisible:
228                        #print "3"
229                        self.MakeCellVisible(i, 0)
230                    break
231    
232            
233    
234  #  #
235  # 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!
236  #  #
# Line 174  class ClassGrid(wxGrid): Line 248  class ClassGrid(wxGrid):
248          r = event.GetRow()          r = event.GetRow()
249          c = event.GetCol()          c = event.GetCol()
250          if c == COL_SYMBOL:          if c == COL_SYMBOL:
251              group = self.GetTable().GetValueAsCustom(r, c, None)              self.classifier.EditGroupProperties(r)
             prop = group.GetProperties()  
252    
             # get a new ClassGroupProperties object and copy the  
             # values over to our current object  
             propDlg = SelectPropertiesDialog(NULL, prop, self.shapeType)  
             if propDlg.ShowModal() == wxID_OK:  
                 new_prop = propDlg.GetClassGroupProperties()  
                 prop.SetProperties(new_prop)  
                 self.Refresh()  
             propDlg.Destroy()  
253    
254      #      #
255      # _OnSelectedRange() and _OnSelectedCell() were borrowed      # _OnSelectedRange() and _OnSelectedCell() were borrowed
# Line 196  class ClassGrid(wxGrid): Line 261  class ClassGrid(wxGrid):
261          if event.Selecting():          if event.Selecting():
262              for index in range( event.GetTopRow(), event.GetBottomRow()+1):              for index in range( event.GetTopRow(), event.GetBottomRow()+1):
263                  if index not in self.currentSelection:                  if index not in self.currentSelection:
264                        #print "    ", index
265                      self.currentSelection.append( index )                      self.currentSelection.append( index )
266          else:          else:
267              for index in range( event.GetTopRow(), event.GetBottomRow()+1):              for index in range( event.GetTopRow(), event.GetBottomRow()+1):
268                  while index in self.currentSelection:                  while index in self.currentSelection:
269                        #print "    ", index
270                      self.currentSelection.remove( index )                      self.currentSelection.remove( index )
271          #self.ConfigureForSelection()          #self.ConfigureForSelection()
272    
273            #print self.GetCurrentSelection()
274          event.Skip()          event.Skip()
275    
276      def _OnSelectedCell( self, event ):      def _OnSelectedCell( self, event ):
277          """Internal update to the selection tracking list"""          """Internal update to the selection tracking list"""
278            #print "selecting cell: ", event.GetRow()
279          self.currentSelection = [ event.GetRow() ]          self.currentSelection = [ event.GetRow() ]
280          #self.ConfigureForSelection()          #self.ConfigureForSelection()
281          event.Skip()          event.Skip()
282    
283        def _OnCellResize(self, event):
284            self.FitInside()
285    
286  class ClassTable(wxPyGridTableBase):  class ClassTable(wxPyGridTableBase):
287      """Represents the underlying data structure for the grid."""      """Represents the underlying data structure for the grid."""
288    
# Line 218  class ClassTable(wxPyGridTableBase): Line 290  class ClassTable(wxPyGridTableBase):
290    
291      __col_labels = [_("Symbol"), _("Value"), _("Label")]      __col_labels = [_("Symbol"), _("Value"), _("Label")]
292    
293      def __init__(self, clazz, shapeType, view = None):  
294        def __init__(self, view = None):
295        #def __init__(self, clazz, shapeType, view = None):
296          """Constructor.          """Constructor.
297    
298          shapeType -- the type of shape that the layer uses          shapeType -- the type of shape that the layer uses
# Line 227  class ClassTable(wxPyGridTableBase): Line 301  class ClassTable(wxPyGridTableBase):
301          """          """
302    
303          wxPyGridTableBase.__init__(self)          wxPyGridTableBase.__init__(self)
304    
305          self.SetView(view)          self.SetView(view)
306          self.tdata = []          self.clazz = None
307    
308          self.Reset(clazz, shapeType)          #self.Reset(clazz, shapeType)
309    
310      def Reset(self, clazz, shapeType):      def Reset(self, clazz, shapeType, group = None):
311          """Reset the table with the given data.          """Reset the table with the given data.
312    
313          This is necessary because wxWindows does not allow a grid's          This is necessary because wxWindows does not allow a grid's
# Line 246  class ClassTable(wxPyGridTableBase): Line 321  class ClassTable(wxPyGridTableBase):
321          shapeType -- the type of shape that the layer uses          shapeType -- the type of shape that the layer uses
322          """          """
323    
324          assert(isinstance(clazz, Classification))          assert isinstance(clazz, Classification)
325    
326          self.GetView().BeginBatch()          self.GetView().BeginBatch()
327    
328          self.clazz = clazz          self.fieldType = clazz.GetFieldType()
329          self.shapeType = shapeType          self.shapeType = shapeType
         self.renderer = ClassRenderer(self.shapeType)  
330    
331          old_len = len(self.tdata)          self.SetClassification(clazz, group)
332            self.__Modified(-1)
333            #print "11------------------"
334    
335            self.GetView().EndBatch()
336            self.GetView().FitInside()
337    
338        def GetClassification(self):
339            return self.clazz
340    
341          self.tdata = []      def SetClassification(self, clazz, group = None):
342    
343            self.GetView().BeginBatch()
344    
345            old_len = self.GetNumberRows()
346    
347            #print "9------------------"
348          #          #
349          # copy the data out of the classification and into our          # copy the data out of the classification and into our
350          # array          # array
351          #          #
352          for p in self.clazz:          row = -1
353              np = copy.copy(p)  #       for g in clazz:
354              self.__SetRow(-1, np)  #           ng = copy.deepcopy(g)
355    #           self.__SetRow(None, ng)
356    #           if g is group:
357    #               row = self.GetNumberRows() - 1
358    #               #print "selecting row..."
359    
360            #print "10------------------"
361    
362            #self.clazz = copy.deepcopy(clazz)
363            self.clazz = clazz
364    
365          self.__Modified(False)          self.__NotifyRowChanges(old_len, self.GetNumberRows())
366    
367            if row > -1:
368                self.GetView().ClearSelection()
369                self.GetView().SelectRow(row)
370                self.GetView().MakeCellVisible(row, 0)
371    
372            self.__Modified()
373    
         self.__NotifyRowChanges(old_len, len(self.tdata))  
374          self.GetView().EndBatch()          self.GetView().EndBatch()
375            self.GetView().FitInside()
376    
377      def __NotifyRowChanges(self, curRows, newRows):      def __NotifyRowChanges(self, curRows, newRows):
378          #          #
# Line 282  class ClassTable(wxPyGridTableBase): Line 384  class ClassTable(wxPyGridTableBase):
384                          wxGRIDTABLE_NOTIFY_ROWS_APPENDED,                          wxGRIDTABLE_NOTIFY_ROWS_APPENDED,
385                          newRows - curRows)    # how many                          newRows - curRows)    # how many
386              self.GetView().ProcessTableMessage(msg)              self.GetView().ProcessTableMessage(msg)
387                self.GetView().FitInside()
388          elif newRows < curRows:          elif newRows < curRows:
389              msg = wxGridTableMessage(self,              msg = wxGridTableMessage(self,
390                          wxGRIDTABLE_NOTIFY_ROWS_DELETED,                          wxGRIDTABLE_NOTIFY_ROWS_DELETED,
391                          curRows - newRows,    # position                          curRows,              # position
392                          curRows - newRows)    # how many                          curRows - newRows)    # how many
393              self.GetView().ProcessTableMessage(msg)              self.GetView().ProcessTableMessage(msg)
394                self.GetView().FitInside()
395    
396    
397      def __SetRow(self, row, group):      def __SetRow(self, row, group):
398          """Set a row's data to that of the group.          """Set a row's data to that of the group.
399    
400          row -- if row is -1 or greater than the current number of rows          The table is considered modified after this operation.
401                 then group is appended to the end.  
402            row -- if row is < 0 'group' is inserted at the top of the table
403                   if row is >= GetNumberRows() or None 'group' is append to
404                        the end of the table.
405                   otherwise 'group' replaces row 'row'
406          """          """
407    
408          # either append or replace          # either append or replace
409          if row == -1 or row >= self.GetNumberRows():          if row is None or row >= self.GetNumberRows():
410              self.tdata.append(group)              self.clazz.AppendGroup(group)
411            elif row < 0:
412                self.clazz.InsertGroup(0, group)
413          else:          else:
414              self.tdata[row] = group              if row == 0:
415                    self.clazz.SetDefaultGroup(group)
416                else:
417                    self.clazz.ReplaceGroup(row - 1, group)
418    
419          self.__Modified()          self.__Modified()
420    
# Line 311  class ClassTable(wxPyGridTableBase): Line 425  class ClassTable(wxPyGridTableBase):
425      def GetRowLabelValue(self, row):      def GetRowLabelValue(self, row):
426          """Return the label for the given row."""          """Return the label for the given row."""
427    
428          group = self.tdata[row]          if row == 0:
429          if isinstance(group, ClassGroupDefault):   return _("Default")              return _("Default")
430          if isinstance(group, ClassGroupSingleton): return _("Singleton")          else:
431          if isinstance(group, ClassGroupRange):     return _("Range")              group = self.clazz.GetGroup(row - 1)
432          if isinstance(group, ClassGroupMap):       return _("Map")              if isinstance(group, ClassGroupDefault):   return _("Default")
433                if isinstance(group, ClassGroupSingleton): return _("Singleton")
434                if isinstance(group, ClassGroupRange):     return _("Range")
435                if isinstance(group, ClassGroupMap):       return _("Map")
436    
437          assert(False) # shouldn't get here          assert False # shouldn't get here
438          return _("")          return _("")
439    
440      def GetNumberRows(self):      def GetNumberRows(self):
441          """Return the number of rows."""          """Return the number of rows."""
442          return len(self.tdata)          if self.clazz is None:
443                return 0
444    
445            return self.clazz.GetNumGroups() + 1 # +1 for default group
446    
447      def GetNumberCols(self):      def GetNumberCols(self):
448          """Return the number of columns."""          """Return the number of columns."""
# Line 353  class ClassTable(wxPyGridTableBase): Line 473  class ClassTable(wxPyGridTableBase):
473          typeName -- unused, but needed to overload wxPyGridTableBase          typeName -- unused, but needed to overload wxPyGridTableBase
474          """          """
475    
476          group = self.tdata[row]          if row == 0:
477                group = self.clazz.GetDefaultGroup()
478            else:
479                group = self.clazz.GetGroup(row - 1)
480    
481    
482          if col == COL_SYMBOL:          if col == COL_SYMBOL:
483              return group              return group.GetProperties()
484    
485          if col == COL_LABEL:          if col == COL_LABEL:
486              return group.GetLabel()              return group.GetLabel()
487    
488          # col must be COL_VALUE          # col must be COL_VALUE
489          assert(col == COL_VALUE)          assert col == COL_VALUE
490    
491          if isinstance(group, ClassGroupDefault):          if isinstance(group, ClassGroupDefault):
492              return _("DEFAULT")              return _("DEFAULT")
# Line 382  class ClassTable(wxPyGridTableBase): Line 506  class ClassTable(wxPyGridTableBase):
506          value, or of length two if it is a range.          value, or of length two if it is a range.
507          """          """
508    
509          type = self.clazz.GetFieldType()          type = self.fieldType
510    
511          if type == FIELDTYPE_STRING:          if type == FIELDTYPE_STRING:
512              return (value,)              return (value,)
# Line 411  class ClassTable(wxPyGridTableBase): Line 535  class ClassTable(wxPyGridTableBase):
535    
536                  return (conv(Str2Num(value[:i])), conv(Str2Num(value[i+1:])))                  return (conv(Str2Num(value[:i])), conv(Str2Num(value[i+1:])))
537    
538          assert(False) # shouldn't get here          assert False  # shouldn't get here
539            return (0,)
540                            
541    
542      def SetValueAsCustom(self, row, col, typeName, value):      def SetValueAsCustom(self, row, col, typeName, value):
# Line 426  class ClassTable(wxPyGridTableBase): Line 551  class ClassTable(wxPyGridTableBase):
551          typeName -- unused, but needed to overload wxPyGridTableBase          typeName -- unused, but needed to overload wxPyGridTableBase
552          """          """
553    
554          assert(col >= 0 and col < self.GetNumberCols())          assert col >= 0 and col < self.GetNumberCols()
555          assert(row >= 0 and row < self.GetNumberRows())          assert row >= 0 and row < self.GetNumberRows()
556    
557          group = self.tdata[row]          if row == 0:
558                group = self.clazz.GetDefaultGroup()
559            else:
560                group = self.clazz.GetGroup(row - 1)
561    
562          mod = False          mod = True # assume the data will change
563    
564          if col == COL_SYMBOL:          if col == COL_SYMBOL:
565              self.__SetRow(row, value)              group.SetProperties(value)
566              mod = True          elif col == COL_LABEL:
567                group.SetLabel(value)
568          elif col == COL_VALUE:          elif col == COL_VALUE:
569              if isinstance(group, ClassGroupDefault):              if isinstance(group, ClassGroupDefault):
570                  # not allowed to modify the default value                  # not allowed to modify the default value
# Line 448  class ClassTable(wxPyGridTableBase): Line 577  class ClassTable(wxPyGridTableBase):
577                      dataInfo = self.__ParseInput(value)                      dataInfo = self.__ParseInput(value)
578                  except ValueError:                  except ValueError:
579                      # bad input, ignore the request                      # bad input, ignore the request
580                      pass                      mod = False
581                  else:                  else:
582    
583                        changed = False
584                      ngroup = group                      ngroup = group
585                      props = group.GetProperties()                      props = group.GetProperties()
586    
# Line 462  class ClassTable(wxPyGridTableBase): Line 592  class ClassTable(wxPyGridTableBase):
592                      if len(dataInfo) == 1:                      if len(dataInfo) == 1:
593                          if not isinstance(group, ClassGroupSingleton):                          if not isinstance(group, ClassGroupSingleton):
594                              ngroup = ClassGroupSingleton(prop = props)                              ngroup = ClassGroupSingleton(prop = props)
595                                changed = True
596                          ngroup.SetValue(dataInfo[0])                          ngroup.SetValue(dataInfo[0])
597                      elif len(dataInfo) == 2:                      elif len(dataInfo) == 2:
598                          if not isinstance(group, ClassGroupRange):                          if not isinstance(group, ClassGroupRange):
599                              ngroup = ClassGroupRange(prop = props)                              ngroup = ClassGroupRange(prop = props)
600                                changed = True
601                          ngroup.SetRange(dataInfo[0], dataInfo[1])                          ngroup.SetRange(dataInfo[0], dataInfo[1])
602                      else:                      else:
603                          assert(False)                          assert False
604                            pass
                     ngroup.SetLabel(group.GetLabel())  
   
                     self.__SetRow(row, ngroup)  
   
                     mod = True  
605    
606                        if changed:
607                            ngroup.SetLabel(group.GetLabel())
608                            self.SetClassGroup(row, ngroup)
609            else:
610                assert False # shouldn't be here
611                pass
612    
613          elif col == COL_LABEL:          if mod:
             group.SetLabel(value)  
             mod = True  
   
         if mod:  
614              self.__Modified()              self.__Modified()
615              self.GetView().Refresh()              self.GetView().Refresh()
616    
# Line 492  class ClassTable(wxPyGridTableBase): Line 621  class ClassTable(wxPyGridTableBase):
621          #attr = wxPyGridTableBase.GetAttr(self, row, col, someExtraParameter)          #attr = wxPyGridTableBase.GetAttr(self, row, col, someExtraParameter)
622    
623          if col == COL_SYMBOL:          if col == COL_SYMBOL:
624                # we need to create a new renderer each time, because
625                # SetRenderer takes control of the parameter
626              attr.SetRenderer(ClassRenderer(self.shapeType))              attr.SetRenderer(ClassRenderer(self.shapeType))
627              attr.SetReadOnly()              attr.SetReadOnly()
628    
# Line 500  class ClassTable(wxPyGridTableBase): Line 631  class ClassTable(wxPyGridTableBase):
631      def GetClassGroup(self, row):      def GetClassGroup(self, row):
632          """Return the ClassGroup object representing row 'row'."""          """Return the ClassGroup object representing row 'row'."""
633    
634          return self.GetValueAsCustom(row, COL_SYMBOL, None)          #return self.GetValueAsCustom(row, COL_SYMBOL, None)
635            if row == 0:
636                return self.clazz.GetDefaultGroup()
637            else:
638                return self.clazz.GetGroup(row - 1)
639    
640      def SetClassGroup(self, row, group):      def SetClassGroup(self, row, group):
641          self.SetValueAsCustom(row, COL_SYMBOL, None, group)          self.__SetRow(row, group)
642            self.GetView().Refresh()
643    
644      def __Modified(self, mod = True):      def __Modified(self, mod = True):
645          """Set the modified flag."""          """Adjust the modified flag.
646          self.modified = mod  
647            mod -- if -1 set the modified flag to False, otherwise perform
648                   an 'or' operation with the current value of the flag and
649                   'mod'
650            """
651    
652            if mod == -1:
653                self.modified = False
654            else:
655                self.modified = mod or self.modified
656    
657      def IsModified(self):      def IsModified(self):
658          """True if this table is considered modified."""          """True if this table is considered modified."""
659          return self.modified          return self.modified
660    
661      def DeleteRows(self, pos, numRows = 1):      def DeleteRows(self, pos, numRows = 1):
662          """Deletes 'numRows' beginning at row 'pos'.          """Deletes 'numRows' beginning at row 'pos'.
663    
664          The table is considered modified after this operation.          The row representing the default group is not removed.
665    
666            The table is considered modified if any rows are removed.
667          """          """
668    
669          assert(pos >= 0)          assert pos >= 0
670          old_len = len(self.tdata)          old_len = self.GetNumberRows()
671          for row in range(pos, pos - numRows, -1):          for row in range(pos, pos - numRows, -1):
672              group = self.GetValueAsCustom(row, COL_SYMBOL, None)              group = self.GetClassGroup(row)
673              if not isinstance(group, ClassGroupDefault):              if row != 0:
674                  self.tdata.pop(row)                  self.clazz.RemoveGroup(row - 1)
675                  self.__Modified()                  self.__Modified()
676            
677          if self.IsModified():          if self.IsModified():
678              self.__NotifyRowChanges(old_len, len(self.tdata))              self.__NotifyRowChanges(old_len, self.GetNumberRows())
679    
680      def AppendRows(self, numRows = 1):      def AppendRows(self, numRows = 1):
681          """Append 'numRows' empty rows to the end of the table."""          """Append 'numRows' empty rows to the end of the table.
682    
683          old_len = len(self.tdata)          The table is considered modified if any rows are appended.
684            """
685    
686            old_len = self.GetNumberRows()
687          for i in range(numRows):          for i in range(numRows):
688              np = ClassGroupSingleton()              np = ClassGroupSingleton()
689              self.__SetRow(-1, np)              self.__SetRow(None, np)
             #self.tdata.append([np, np.GetValue(), np.GetLabel()])  
             self.__Modified()  
690    
691          if self.IsModified():          if self.IsModified():
692              self.__NotifyRowChanges(old_len, len(self.tdata))              self.__NotifyRowChanges(old_len, self.GetNumberRows())
693    
694    
695  class Classifier(wxDialog):  class Classifier(NonModalDialog):
696        
697      def __init__(self, parent, layer):      def __init__(self, parent, name, layer, group = None):
698          wxDialog.__init__(self, parent, -1, _("Classify"),          NonModalDialog.__init__(self, parent, name,
699                            style = wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)                                  _("Classifier: %s") % layer.Title())
700    
701            panel = wxPanel(self, -1, size=(100, 100))
702    
703          self.layer = layer          self.layer = layer
704    
705            self.originalClass = self.layer.GetClassification()
706            field = self.originalClass.GetField()
707            fieldType = self.originalClass.GetFieldType()
708    
709          topBox = wxBoxSizer(wxVERTICAL)          topBox = wxBoxSizer(wxVERTICAL)
710            panelBox = wxBoxSizer(wxVERTICAL)
711    
712          topBox.Add(wxStaticText(self, -1, _("Layer: %s") % layer.Title()),          #panelBox.Add(wxStaticText(panel, -1, _("Layer: %s") % layer.Title()),
713              0, wxALIGN_LEFT | wxALL, 4)              #0, wxALIGN_LEFT | wxALL, 4)
714          topBox.Add(wxStaticText(self, -1, _("Type: %s") % layer.ShapeType()),          panelBox.Add(wxStaticText(panel, -1,
715                                    _("Layer Type: %s") % layer.ShapeType()),
716              0, wxALIGN_LEFT | wxALL, 4)              0, wxALIGN_LEFT | wxALL, 4)
717    
         propertyBox = wxBoxSizer(wxHORIZONTAL)  
         propertyBox.Add(wxStaticText(self, -1, _("Field: ")),  
             0, wxALIGN_CENTER | wxALL, 4)  
718    
719          self.fields = wxComboBox(self, ID_PROPERTY_SELECT, "",          #
720            # make field combo box
721            #
722            self.fields = wxComboBox(panel, ID_PROPERTY_SELECT, "",
723                                       style = wxCB_READONLY)                                       style = wxCB_READONLY)
724    
725          self.num_cols = layer.table.field_count()          self.num_cols = layer.table.field_count()
726          # just assume the first field in case one hasn't been          # just assume the first field in case one hasn't been
727          # specified in the file.          # specified in the file.
728          self.__cur_field = 0          self.__cur_field = 0
         clazz = layer.GetClassification()  
         field = clazz.GetField()  
729    
730          self.fields.Append("<None>")          self.fields.Append("<None>")
731          self.fields.SetClientData(0, None)          self.fields.SetClientData(0, None)
# Line 583  class Classifier(wxDialog): Line 736  class Classifier(wxDialog):
736    
737              if name == field:              if name == field:
738                  self.__cur_field = i + 1                  self.__cur_field = i + 1
739                  self.fields.SetClientData(i + 1, clazz)                  self.fields.SetClientData(i + 1,
740                                              copy.deepcopy(self.originalClass))
741              else:              else:
742                  self.fields.SetClientData(i + 1, None)                  self.fields.SetClientData(i + 1, None)
743    
         self.fields.SetSelection(self.__cur_field)  
744    
745            ###########
746    
747            self.fieldTypeText = wxStaticText(panel, -1, "")
748            panelBox.Add(self.fieldTypeText, 0,
749                         wxGROW | wxALIGN_LEFT | wxALL | wxADJUST_MINSIZE, 4)
750    
751            propertyBox = wxBoxSizer(wxHORIZONTAL)
752            propertyBox.Add(wxStaticText(panel, -1, _("Field: ")),
753                0, wxALIGN_LEFT | wxALL, 4)
754          propertyBox.Add(self.fields, 1, wxGROW|wxALL, 4)          propertyBox.Add(self.fields, 1, wxGROW|wxALL, 4)
755          EVT_COMBOBOX(self, ID_PROPERTY_SELECT, self._OnFieldSelect)          EVT_COMBOBOX(self, ID_PROPERTY_SELECT, self._OnFieldSelect)
756    
757          topBox.Add(propertyBox, 0, wxGROW, 4)          panelBox.Add(propertyBox, 0, wxGROW, 4)
758    
759    
760            #
761            # Control Box
762            #
763            controlBox = wxBoxSizer(wxHORIZONTAL)
764    
765    
766            ###########
767            #
768            # Control buttons:
769            #
770            self.controlButtons = []
771    
772            controlButtonBox = wxBoxSizer(wxVERTICAL)
773    
774            button = wxButton(panel, ID_CLASSIFY_ADD, _("Add"))
775            controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)
776            self.controlButtons.append(button)
777    
778            button = wxButton(panel, ID_CLASSIFY_EDITPROPS, _("Edit Properties"))
779            controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)
780            self.controlButtons.append(button)
781    
782            button = wxButton(panel, ID_CLASSIFY_GENCLASS, _("Generate Class"))
783            controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)
784            self.controlButtons.append(button)
785    
786            button = wxButton(panel, ID_CLASSIFY_MOVEUP, _("Move Up"))
787            controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)
788            self.controlButtons.append(button)
789    
790            button = wxButton(panel, ID_CLASSIFY_MOVEDOWN, _("Move Down"))
791            controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)
792            self.controlButtons.append(button)
793    
794            controlButtonBox.Add(60, 20, 0, wxGROW | wxALL | wxALIGN_BOTTOM, 4)
795    
796            button = wxButton(panel, ID_CLASSIFY_REMOVE, _("Remove"))
797            controlButtonBox.Add(button, 0, wxGROW | wxALL | wxALIGN_BOTTOM, 4)
798            self.controlButtons.append(button)
799    
800    
801            ###########
802          #          #
803          # Classification data table          # Classification data table
804          #          #
805    
806          controlBox = wxBoxSizer(wxHORIZONTAL)          self.classGrid = ClassGrid(panel, self)
807          self.classGrid = ClassGrid(self)          #self.__SetGridTable(self.__cur_field, group)
808            #self.fields.SetSelection(self.__cur_field)
809    
810            # calling __SelectField after creating the classGrid fills in the
811            # grid with the correct information
812            #print "2------------------"
813            self.fields.SetSelection(self.__cur_field)
814            self.__SelectField(self.__cur_field, group = group)
815    
816          self.__SetGridTable(self.__cur_field)          #self.classGrid.SelectGroup(group)
817    
818          controlBox.Add(self.classGrid, 1, wxGROW, 0)          controlBox.Add(self.classGrid, 1, wxGROW, 0)
819    
         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)  
   
         controlButtonBox.Add(wxButton(self, ID_CLASSIFY_MOVEUP,  
             _("Move Up")), 0, wxGROW | wxALL, 4)  
         controlButtonBox.Add(wxButton(self, ID_CLASSIFY_MOVEDOWN,  
             _("Move Down")), 0, wxGROW | wxALL, 4)  
820    
         controlButtonBox.Add(wxButton(self, ID_CLASSIFY_REMOVE,  
             _("Remove")), 0, wxGROW | wxALL | wxALIGN_BOTTOM, 4)  
821    
822          controlBox.Add(controlButtonBox, 0, wxGROW, 10)          controlBox.Add(controlButtonBox, 0, wxGROW, 10)
823          topBox.Add(controlBox, 1, wxGROW, 10)          panelBox.Add(controlBox, 1, wxGROW, 10)
824    
825          EVT_BUTTON(self, ID_CLASSIFY_ADD, self._OnAdd)          EVT_BUTTON(self, ID_CLASSIFY_ADD, self._OnAdd)
826            EVT_BUTTON(self, ID_CLASSIFY_EDITPROPS, self._OnEditGroupProperties)
827          EVT_BUTTON(self, ID_CLASSIFY_REMOVE, self._OnRemove)          EVT_BUTTON(self, ID_CLASSIFY_REMOVE, self._OnRemove)
828          EVT_BUTTON(self, ID_CLASSIFY_GENRANGE, self._OnGenRange)          EVT_BUTTON(self, ID_CLASSIFY_GENCLASS, self._OnGenClass)
829          EVT_BUTTON(self, ID_CLASSIFY_MOVEUP, self._OnMoveUp)          EVT_BUTTON(self, ID_CLASSIFY_MOVEUP, self._OnMoveUp)
830          EVT_BUTTON(self, ID_CLASSIFY_MOVEDOWN, self._OnMoveDown)          EVT_BUTTON(self, ID_CLASSIFY_MOVEDOWN, self._OnMoveDown)
831    
832          #          ###########
833          # Control buttons:  
         #  
834          buttonBox = wxBoxSizer(wxHORIZONTAL)          buttonBox = wxBoxSizer(wxHORIZONTAL)
835          buttonBox.Add(wxButton(self, ID_CLASSIFY_OK, _("OK")),          buttonBox.Add(wxButton(panel, ID_CLASSIFY_OK, _("OK")),
836                        0, wxALL, 4)                        0, wxALL, 4)
837          buttonBox.Add(wxButton(self, ID_CLASSIFY_CANCEL, _("Cancel")),          buttonBox.Add(60, 20, 0, wxALL, 4)
838            buttonBox.Add(wxButton(panel, ID_CLASSIFY_APPLY, _("Apply")),
839                        0, wxALL, 4)                        0, wxALL, 4)
840          topBox.Add(buttonBox, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_BOTTOM, 10)          buttonBox.Add(60, 20, 0, wxALL, 4)
841            buttonBox.Add(wxButton(panel, ID_CLASSIFY_CLOSE, _("Close")),
842                          0, wxALL, 4)
843            buttonBox.Add(60, 20, 0, wxALL, 4)
844            buttonBox.Add(wxButton(panel, ID_CLASSIFY_CANCEL, _("Cancel")),
845                          0, wxALL, 4)
846            panelBox.Add(buttonBox, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_BOTTOM, 0)
847    
848          EVT_BUTTON(self, ID_CLASSIFY_OK, self._OnOK)          EVT_BUTTON(self, ID_CLASSIFY_OK, self._OnOK)
849            EVT_BUTTON(self, ID_CLASSIFY_APPLY, self._OnApply)
850            EVT_BUTTON(self, ID_CLASSIFY_CLOSE, self._OnCloseBtn)
851          EVT_BUTTON(self, ID_CLASSIFY_CANCEL, self._OnCancel)          EVT_BUTTON(self, ID_CLASSIFY_CANCEL, self._OnCancel)
852    
853            ###########
854    
855    
856          self.SetAutoLayout(true)          panel.SetAutoLayout(True)
857            panel.SetSizer(panelBox)
858            panelBox.SetSizeHints(panel)
859    
860            topBox.Add(panel, 1, wxGROW, 0)
861            panelBox.SetSizeHints(self)
862            self.SetAutoLayout(True)
863          self.SetSizer(topBox)          self.SetSizer(topBox)
         topBox.Fit(self)  
         topBox.SetSizeHints(self)  
864    
865      def __BuildClassification(self, fieldIndex):          #print "1------------------"
866            #self.Fit()
867            ######################
868    
869          clazz = Classification()          self.haveApplied = False
870          fieldName = self.fields.GetString(fieldIndex)  
871          fieldType = self.layer.GetFieldType(fieldName)      def EditGroupProperties(self, row):
872            table = self.classGrid.GetTable()
873            prop = table.GetValueAsCustom(row, COL_SYMBOL, None)
874    
875            # get a new ClassGroupProperties object and copy the
876            # values over to our current object
877            propDlg = SelectPropertiesDialog(NULL, prop, self.layer.ShapeType())
878            if propDlg.ShowModal() == wxID_OK:
879                new_prop = propDlg.GetClassGroupProperties()
880                table.SetValueAsCustom(row, COL_SYMBOL, None, new_prop)
881            propDlg.Destroy()
882            
883    
884        def __BuildClassification(self, fieldIndex, copyClass = False):
885    
886    #       numRows = self.classGrid.GetNumberRows()
887    #       assert numRows > 0  # there should always be a default row
888    
889    #       clazz = Classification()
890            if fieldIndex == 0:
891                fieldName = None
892                fieldType = None
893            else:
894                fieldName = self.fields.GetString(fieldIndex)
895                fieldType = self.layer.GetFieldType(fieldName)
896    
897            clazz = self.classGrid.GetTable().GetClassification()
898    
899            if copyClass:
900                clazz = copy.deepcopy(clazz)
901    
902          clazz.SetField(fieldName)          clazz.SetField(fieldName)
903          clazz.SetFieldType(fieldType)          clazz.SetFieldType(fieldType)
904    
         numRows = self.classGrid.GetNumberRows()  
   
         assert(numRows > 0) # there should always be a default row  
905    
906          table = self.classGrid.GetTable()  #       table = self.classGrid.GetTable()
907          clazz.SetDefaultGroup(table.GetClassGroup(0))  #       clazz.SetDefaultGroup(table.GetClassGroup(0))
908    
909          for i in range(1, numRows):  #       for i in range(1, numRows):
910              clazz.AddGroup(table.GetClassGroup(i))  #           clazz.AppendGroup(table.GetClassGroup(i))
911    
912          return clazz          return clazz
913    
914      def __SetGridTable(self, fieldIndex):      def __SetGridTable(self, fieldIndex, group = None):
915    
916          clazz = self.fields.GetClientData(fieldIndex)          clazz = self.fields.GetClientData(fieldIndex)
917    
# Line 677  class Classifier(wxDialog): Line 919  class Classifier(wxDialog):
919              clazz = Classification()              clazz = Classification()
920              clazz.SetDefaultGroup(              clazz.SetDefaultGroup(
921                  ClassGroupDefault(                  ClassGroupDefault(
922                      self.layer.GetClassification().GetDefaultGroup().GetProperties()))                      self.layer.GetClassification().
923                                   GetDefaultGroup().GetProperties()))
924    
925              fieldName = self.fields.GetString(fieldIndex)              fieldName = self.fields.GetString(fieldIndex)
926              fieldType = self.layer.GetFieldType(fieldName)              fieldType = self.layer.GetFieldType(fieldName)
927              clazz.SetFieldType(fieldType)              clazz.SetFieldType(fieldType)
928                                    
929          self.classGrid.CreateTable(clazz, self.layer.ShapeType())          #print "6------------------"
930            self.classGrid.CreateTable(clazz, self.layer.ShapeType(), group)
931            #print "7------------------"
932    
     def _OnFieldSelect(self, event):  
         clazz = self.__BuildClassification(self.__cur_field)  
         self.fields.SetClientData(self.__cur_field, clazz)  
933    
         self.__cur_field = self.fields.GetSelection()  
         self.__SetGridTable(self.__cur_field)  
934    
935      def _OnOK(self, event):      type2string = {None:             _("None"),
936                       FIELDTYPE_STRING: _("Text"),
937                       FIELDTYPE_INT:    _("Integer"),
938                       FIELDTYPE_DOUBLE: _("Decimal")}
939    
940        def __SetFieldTypeText(self, fieldIndex):
941            fieldName = self.fields.GetString(fieldIndex)
942            fieldType = self.layer.GetFieldType(fieldName)
943    
944            assert Classifier.type2string.has_key(fieldType)
945    
946            text = Classifier.type2string[fieldType]
947    
948            self.fieldTypeText.SetLabel(_("Field Type: %s") % text)
949    
950        def __SelectField(self, newIndex, oldIndex = -1, group = None):
951            """This method assumes that the current selection for the
952            combo has already been set by a call to SetSelection().
953            """
954    
955            #print "3------------------"
956    
957            assert oldIndex >= -1
958    
959            if oldIndex != -1:
960                clazz = self.__BuildClassification(oldIndex)
961                self.fields.SetClientData(oldIndex, clazz)
962    
963            #print "4------------------"
964            self.__SetGridTable(newIndex, group)
965            #print "5------------------"
966    
967            enabled = newIndex != 0
968    
969            for b in self.controlButtons:
970                b.Enable(enabled)
971    
972            self.__SetFieldTypeText(newIndex)
973    
974    
975        def _OnEditGroupProperties(self, event):
976            sel = self.classGrid.GetCurrentSelection()
977    
978            if len(sel) == 1:
979                self.EditGroupProperties(sel[0])
980    
981        def _OnFieldSelect(self, event):
982            index = self.fields.GetSelection()
983            self.__SelectField(index, self.__cur_field)
984            self.__cur_field = index
985    
986        def _OnApply(self, event):
987          """Put the data from the table into a new Classification and hand          """Put the data from the table into a new Classification and hand
988             it to the layer.             it to the layer.
989          """          """
# Line 704  class Classifier(wxDialog): Line 995  class Classifier(wxDialog):
995          # to begin with or it has been modified          # to begin with or it has been modified
996          #          #
997          if clazz is None or self.classGrid.GetTable().IsModified():          if clazz is None or self.classGrid.GetTable().IsModified():
998              clazz = self.__BuildClassification(self.__cur_field)              clazz = self.__BuildClassification(self.__cur_field, True)
   
         clazz.SetLayer(self.layer)  
999    
1000          self.layer.SetClassification(clazz)          self.layer.SetClassification(clazz)
1001    
1002          self.EndModal(wxID_OK)          self.haveApplied = True
1003    
1004        def _OnOK(self, event):
1005            self._OnApply(event)
1006            self.Close()
1007    
1008        def _OnCloseBtn(self, event):
1009            """Close is similar to Cancel except that any changes that were
1010            made and applied remain applied, but the currently displayed
1011            classification is discarded.
1012            """
1013    
1014            self.Close()
1015    
1016      def _OnCancel(self, event):      def _OnCancel(self, event):
1017          """Do nothing. The layer's current classification stays the same."""          """The layer's current classification stays the same."""
1018          self.EndModal(wxID_CANCEL)          if self.haveApplied:
1019                self.layer.SetClassification(self.originalClass)
1020    
1021            self.Close()
1022    
1023      def _OnAdd(self, event):      def _OnAdd(self, event):
1024          self.classGrid.AppendRows()          self.classGrid.AppendRows()
# Line 722  class Classifier(wxDialog): Line 1026  class Classifier(wxDialog):
1026      def _OnRemove(self, event):      def _OnRemove(self, event):
1027          self.classGrid.DeleteSelectedRows()          self.classGrid.DeleteSelectedRows()
1028    
1029      def _OnGenRange(self, event):      def _OnGenClass(self, event):
1030          print "Classifier._OnGenRange()"  
1031            genDlg = ClassGenDialog(self,
1032                                    self.layer.table,
1033                                    self.fields.GetString(self.__cur_field))
1034    
1035            if genDlg.ShowModal() == wxID_OK:
1036                clazz = genDlg.GetClassification()
1037                self.fields.SetClientData(self.__cur_field, clazz)
1038                self.classGrid.GetTable().SetClassification(clazz)
1039            genDlg.Destroy()
1040    
1041      def _OnMoveUp(self, event):      def _OnMoveUp(self, event):
1042          sel = self.classGrid.GetCurrentSelection()          sel = self.classGrid.GetCurrentSelection()
1043    
1044            #print "sel: ", sel
1045    
1046          if len(sel) == 1:          if len(sel) == 1:
1047              i = sel[0]              i = sel[0]
1048              if i > 1:              if i > 1:
# Line 738  class Classifier(wxDialog): Line 1053  class Classifier(wxDialog):
1053                  table.SetClassGroup(i, x)                  table.SetClassGroup(i, x)
1054                  self.classGrid.ClearSelection()                  self.classGrid.ClearSelection()
1055                  self.classGrid.SelectRow(i - 1)                  self.classGrid.SelectRow(i - 1)
1056                    self.classGrid.MakeCellVisible(i - 1, 0)
1057    
1058      def _OnMoveDown(self, event):      def _OnMoveDown(self, event):
1059          sel = self.classGrid.GetCurrentSelection()          sel = self.classGrid.GetCurrentSelection()
# Line 752  class Classifier(wxDialog): Line 1068  class Classifier(wxDialog):
1068                  table.SetClassGroup(i + 1, x)                  table.SetClassGroup(i + 1, x)
1069                  self.classGrid.ClearSelection()                  self.classGrid.ClearSelection()
1070                  self.classGrid.SelectRow(i + 1)                  self.classGrid.SelectRow(i + 1)
1071                    self.classGrid.MakeCellVisible(i + 1, 0)
1072    
1073    
1074  ID_SELPROP_OK = 4001  ID_SELPROP_OK = 4001
# Line 760  ID_SELPROP_SPINCTRL = 4002 Line 1077  ID_SELPROP_SPINCTRL = 4002
1077  ID_SELPROP_PREVIEW = 4003  ID_SELPROP_PREVIEW = 4003
1078  ID_SELPROP_STROKECLR = 4004  ID_SELPROP_STROKECLR = 4004
1079  ID_SELPROP_FILLCLR = 4005  ID_SELPROP_FILLCLR = 4005
1080    ID_SELPROP_STROKECLRTRANS = 4006
1081    ID_SELPROP_FILLCLRTRANS = 4007
1082    
1083  class SelectPropertiesDialog(wxDialog):  class SelectPropertiesDialog(wxDialog):
1084    
1085      def __init__(self, parent, prop, shapeType):      def __init__(self, parent, prop, shapeType):
1086          wxDialog.__init__(self, parent, -1, _("Select Properties"),          wxDialog.__init__(self, parent, -1, _("Select Properties"),
1087                            style = wxRESIZE_BORDER)                            style = wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
1088    
1089          self.prop = ClassGroupProperties(prop)          self.prop = ClassGroupProperties(prop)
1090    
# Line 777  class SelectPropertiesDialog(wxDialog): Line 1096  class SelectPropertiesDialog(wxDialog):
1096          previewBox = wxBoxSizer(wxVERTICAL)          previewBox = wxBoxSizer(wxVERTICAL)
1097          previewBox.Add(wxStaticText(self, -1, _("Preview:")),          previewBox.Add(wxStaticText(self, -1, _("Preview:")),
1098              0, wxALIGN_LEFT | wxALL, 4)              0, wxALIGN_LEFT | wxALL, 4)
1099          self.previewer = ClassDataPreviewer(None, self.prop, shapeType,          self.previewWin = ClassDataPreviewWindow(None, self.prop, shapeType,
1100                                              self, ID_SELPROP_PREVIEW, (40, 40))                                              self, ID_SELPROP_PREVIEW, (40, 40))
1101          previewBox.Add(self.previewer, 1, wxGROW, 15)          previewBox.Add(self.previewWin, 1, wxGROW | wxALL, 4)
1102    
1103          itemBox.Add(previewBox, 1, wxALIGN_LEFT | wxALL | wxGROW, 0)          itemBox.Add(previewBox, 1, wxALIGN_LEFT | wxALL | wxGROW, 0)
1104    
1105          # control box          # control box
1106          ctrlBox = wxBoxSizer(wxVERTICAL)          ctrlBox = wxBoxSizer(wxVERTICAL)
1107          ctrlBox.Add(  
1108              wxButton(self, ID_SELPROP_STROKECLR, "Change Line Color"),          lineColorBox = wxBoxSizer(wxHORIZONTAL)
1109              0, wxALIGN_CENTER_HORIZONTAL | wxALL | wxGROW, 4)          lineColorBox.Add(
1110                wxButton(self, ID_SELPROP_STROKECLR, _("Change Line Color")),
1111                1, wxALL | wxGROW, 4)
1112          EVT_BUTTON(self, ID_SELPROP_STROKECLR, self._OnChangeLineColor)          EVT_BUTTON(self, ID_SELPROP_STROKECLR, self._OnChangeLineColor)
1113    
1114            lineColorBox.Add(
1115                wxButton(self, ID_SELPROP_STROKECLRTRANS, _("Transparent")),
1116                1, wxALL | wxGROW, 4)
1117            EVT_BUTTON(self, ID_SELPROP_STROKECLRTRANS,
1118                       self._OnChangeLineColorTrans)
1119    
1120            ctrlBox.Add(lineColorBox, 0,
1121                        wxALIGN_CENTER_HORIZONTAL | wxALL | wxGROW, 4)
1122    
1123          if shapeType != SHAPETYPE_ARC:          if shapeType != SHAPETYPE_ARC:
1124              ctrlBox.Add(              fillColorBox = wxBoxSizer(wxHORIZONTAL)
1125                  wxButton(self, ID_SELPROP_FILLCLR, "Change Fill Color"),              fillColorBox.Add(
1126                  0, wxALIGN_LEFT | wxALL | wxGROW, 4)                  wxButton(self, ID_SELPROP_FILLCLR, _("Change Fill Color")),
1127                    1, wxALL | wxGROW, 4)
1128              EVT_BUTTON(self, ID_SELPROP_FILLCLR, self._OnChangeFillColor)              EVT_BUTTON(self, ID_SELPROP_FILLCLR, self._OnChangeFillColor)
1129                fillColorBox.Add(
1130                    wxButton(self, ID_SELPROP_FILLCLRTRANS, _("Transparent")),
1131                    1, wxALL | wxGROW, 4)
1132                EVT_BUTTON(self, ID_SELPROP_FILLCLRTRANS,
1133                           self._OnChangeFillColorTrans)
1134                ctrlBox.Add(fillColorBox, 0,
1135                            wxALIGN_CENTER_HORIZONTAL | wxALL | wxGROW, 4)
1136    
1137          spinBox = wxBoxSizer(wxHORIZONTAL)          spinBox = wxBoxSizer(wxHORIZONTAL)
1138          spinBox.Add(wxStaticText(self, -1, _("Line Width: ")),          spinBox.Add(wxStaticText(self, -1, _("Line Width: ")),
# Line 812  class SelectPropertiesDialog(wxDialog): Line 1150  class SelectPropertiesDialog(wxDialog):
1150          itemBox.Add(ctrlBox, 0, wxALIGN_RIGHT | wxALL | wxGROW, 0)          itemBox.Add(ctrlBox, 0, wxALIGN_RIGHT | wxALL | wxGROW, 0)
1151          topBox.Add(itemBox, 1, wxALIGN_LEFT | wxALL | wxGROW, 0)          topBox.Add(itemBox, 1, wxALIGN_LEFT | wxALL | wxGROW, 0)
1152    
   
1153          #          #
1154          # Control buttons:          # Control buttons:
1155          #          #
1156          buttonBox = wxBoxSizer(wxHORIZONTAL)          buttonBox = wxBoxSizer(wxHORIZONTAL)
1157          buttonBox.Add(wxButton(self, ID_CLASSIFY_OK, _("OK")),          buttonBox.Add(wxButton(self, ID_SELPROP_OK, _("OK")),
1158                        0, wxALL, 4)                        0, wxALL, 4)
1159          buttonBox.Add(wxButton(self, ID_CLASSIFY_CANCEL, _("Cancel")),          buttonBox.Add(wxButton(self, ID_SELPROP_CANCEL, _("Cancel")),
1160                        0, wxALL, 4)                        0, wxALL, 4)
1161          topBox.Add(buttonBox, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_BOTTOM, 10)          topBox.Add(buttonBox, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_BOTTOM, 10)
1162                                                                                                                                                                    
1163          EVT_BUTTON(self, ID_SELPROP_OK, self._OnOK)          EVT_BUTTON(self, ID_SELPROP_OK, self._OnOK)
1164          EVT_BUTTON(self, ID_SELPROP_CANCEL, self._OnCancel)          EVT_BUTTON(self, ID_SELPROP_CANCEL, self._OnCancel)
1165                                                                                                                                                                    
1166          self.SetAutoLayout(true)          self.SetAutoLayout(True)
1167          self.SetSizer(topBox)          self.SetSizer(topBox)
1168          topBox.Fit(self)          topBox.Fit(self)
1169          topBox.SetSizeHints(self)          topBox.SetSizeHints(self)
# Line 839  class SelectPropertiesDialog(wxDialog): Line 1176  class SelectPropertiesDialog(wxDialog):
1176    
1177      def _OnSpin(self, event):      def _OnSpin(self, event):
1178          self.prop.SetLineWidth(self.spinCtrl.GetValue())          self.prop.SetLineWidth(self.spinCtrl.GetValue())
1179          self.previewer.Refresh()          self.previewWin.Refresh()
1180    
1181      def __GetColor(self, cur):      def __GetColor(self, cur):
1182          dialog = wxColourDialog(self)          dialog = wxColourDialog(self)
1183          dialog.GetColourData().SetColour(Color2wxColour(cur))          if cur is not Color.Transparent:
1184                dialog.GetColourData().SetColour(Color2wxColour(cur))
1185    
1186          ret = None          ret = None
1187          if dialog.ShowModal() == wxID_OK:          if dialog.ShowModal() == wxID_OK:
1188              ret = wxColour2Color(dialog.GetColourData().GetColour())              ret = wxColour2Color(dialog.GetColourData().GetColour())
# Line 856  class SelectPropertiesDialog(wxDialog): Line 1195  class SelectPropertiesDialog(wxDialog):
1195          clr = self.__GetColor(self.prop.GetLineColor())          clr = self.__GetColor(self.prop.GetLineColor())
1196          if clr is not None:          if clr is not None:
1197              self.prop.SetLineColor(clr)              self.prop.SetLineColor(clr)
1198          self.previewer.Refresh() # XXX: work around, see ClassDataPreviewer          self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer
1199    
1200        def _OnChangeLineColorTrans(self, event):
1201            self.prop.SetLineColor(Color.Transparent)
1202            self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer
1203            
1204      def _OnChangeFillColor(self, event):      def _OnChangeFillColor(self, event):
1205          clr = self.__GetColor(self.prop.GetFill())          clr = self.__GetColor(self.prop.GetFill())
1206          if clr is not None:          if clr is not None:
1207              self.prop.SetFill(clr)              self.prop.SetFill(clr)
1208          self.previewer.Refresh() # XXX: work around, see ClassDataPreviewer          self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer
1209    
1210        def _OnChangeFillColorTrans(self, event):
1211            self.prop.SetFill(Color.Transparent)
1212            self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer
1213    
1214      def GetClassGroupProperties(self):      def GetClassGroupProperties(self):
1215          return self.prop          return self.prop
1216    
1217    
1218  class ClassDataPreviewer(wxWindow):  class ClassDataPreviewWindow(wxWindow):
1219    
1220      def __init__(self, rect, prop, shapeType,      def __init__(self, rect, prop, shapeType,
1221                         parent = None, id = -1, size = wxDefaultSize):                         parent = None, id = -1, size = wxDefaultSize):
1222          if parent is not None:          if parent is not None:
1223              wxWindow.__init__(self, parent, id, size=size)              wxWindow.__init__(self, parent, id, (0, 0), size)
1224              EVT_PAINT(self, self._OnPaint)              EVT_PAINT(self, self._OnPaint)
1225    
1226          self.rect = rect          self.rect = rect
1227    
1228          self.prop = prop          self.prop = prop
1229          self.shapeType = shapeType          self.shapeType = shapeType
1230            self.previewer = ClassDataPreviewer()
1231    
1232      def _OnPaint(self, event):      def _OnPaint(self, event):
1233          dc = wxPaintDC(self)          dc = wxPaintDC(self)
# Line 886  class ClassDataPreviewer(wxWindow): Line 1235  class ClassDataPreviewer(wxWindow):
1235          # XXX: this doesn't seem to be having an effect:          # XXX: this doesn't seem to be having an effect:
1236          dc.DestroyClippingRegion()          dc.DestroyClippingRegion()
1237    
1238          self.Draw(dc, None)          if self.rect is None:
1239                w, h = self.GetSize()
1240                rect = wxRect(0, 0, w, h)
1241            else:
1242                rect = self.rect
1243    
1244      def Draw(self, dc, rect, prop = None, shapeType = None):          self.previewer.Draw(dc, rect, self.prop, self.shapeType)
1245    
1246          if prop is None: prop = self.prop  class ClassDataPreviewer:
1247          if shapeType is None: shapeType = self.shapeType  
1248        def Draw(self, dc, rect, prop, shapeType):
1249    
1250            assert dc is not None
1251            assert isinstance(prop, ClassGroupProperties)
1252    
1253          if rect is None:          if rect is None:
1254              x = y = 0              x = 0
1255              w, h = self.GetClientSizeTuple()              y = 0
1256                w, h = dc.GetSize()
1257          else:          else:
1258              x = rect.GetX()              x = rect.GetX()
1259              y = rect.GetY()              y = rect.GetY()
# Line 903  class ClassDataPreviewer(wxWindow): Line 1261  class ClassDataPreviewer(wxWindow):
1261              h = rect.GetHeight()              h = rect.GetHeight()
1262    
1263          stroke = prop.GetLineColor()          stroke = prop.GetLineColor()
1264          if stroke is Color.None:          if stroke is Color.Transparent:
1265              pen = wxTRANSPARENT_PEN              pen = wxTRANSPARENT_PEN
1266          else:          else:
1267              pen = wxPen(Color2wxColour(stroke),              pen = wxPen(Color2wxColour(stroke),
# Line 911  class ClassDataPreviewer(wxWindow): Line 1269  class ClassDataPreviewer(wxWindow):
1269                          wxSOLID)                          wxSOLID)
1270    
1271          stroke = prop.GetFill()          stroke = prop.GetFill()
1272          if stroke is Color.None:          if stroke is Color.Transparent:
1273              brush = wxTRANSPARENT_BRUSH              brush = wxTRANSPARENT_BRUSH
1274          else:          else:
1275              brush = wxBrush(Color2wxColour(stroke), wxSOLID)              brush = wxBrush(Color2wxColour(stroke), wxSOLID)
# Line 925  class ClassDataPreviewer(wxWindow): Line 1283  class ClassDataPreviewer(wxWindow):
1283                             wxPoint(x + w/2, y + h/4*3),                             wxPoint(x + w/2, y + h/4*3),
1284                             wxPoint(x + w, y)])                             wxPoint(x + w, y)])
1285    
1286          elif shapeType == SHAPETYPE_POINT or \          elif shapeType == SHAPETYPE_POINT:
              shapeType == SHAPETYPE_POLYGON:  
1287    
1288              dc.DrawCircle(x + w/2, y + h/2,              dc.DrawCircle(x + w/2, y + h/2,
1289                            (min(w, h) - prop.GetLineWidth())/2)                            (min(w, h) - prop.GetLineWidth())/2)
1290    
1291            elif shapeType == SHAPETYPE_POLYGON:
1292                dc.DrawRectangle(x, y, w, h)
1293    
1294  class ClassRenderer(wxPyGridCellRenderer):  class ClassRenderer(wxPyGridCellRenderer):
1295    
1296      def __init__(self, shapeType):      def __init__(self, shapeType):
1297          wxPyGridCellRenderer.__init__(self)          wxPyGridCellRenderer.__init__(self)
1298          self.previewer = ClassDataPreviewer(None, None, shapeType)          self.shapeType = shapeType
1299            self.previewer = ClassDataPreviewer()
1300    
1301      def Draw(self, grid, attr, dc, rect, row, col, isSelected):      def Draw(self, grid, attr, dc, rect, row, col, isSelected):
1302          data = grid.GetTable().GetValueAsCustom(row, col, None)          data = grid.GetTable().GetClassGroup(row)
1303    
1304          dc.SetClippingRegion(rect.GetX(), rect.GetY(),          dc.SetClippingRegion(rect.GetX(), rect.GetY(),
1305                               rect.GetWidth(), rect.GetHeight())                               rect.GetWidth(), rect.GetHeight())
# Line 948  class ClassRenderer(wxPyGridCellRenderer Line 1309  class ClassRenderer(wxPyGridCellRenderer
1309                           rect.GetWidth(), rect.GetHeight())                           rect.GetWidth(), rect.GetHeight())
1310    
1311          if not isinstance(data, ClassGroupMap):          if not isinstance(data, ClassGroupMap):
1312              self.previewer.Draw(dc, rect, data.GetProperties())              self.previewer.Draw(dc, rect, data.GetProperties(), self.shapeType)
1313    
1314          if isSelected:          if isSelected:
1315              dc.SetPen(wxPen(wxColour(0 * 255, 0 * 255, 0 * 255),              dc.SetPen(wxPen(wxBLACK, 1, wxSOLID))
                       4, wxSOLID))  
1316              dc.SetBrush(wxTRANSPARENT_BRUSH)              dc.SetBrush(wxTRANSPARENT_BRUSH)
1317    
1318              dc.DrawRectangle(rect.GetX(), rect.GetY(),              dc.DrawRectangle(rect.GetX(), rect.GetY(),
1319                               rect.GetWidth(), rect.GetHeight())                               rect.GetWidth(), rect.GetHeight())
1320    

Legend:
Removed from v.460  
changed lines
  Added in v.615

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26