/[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 513 by jonathan, Tue Mar 11 16:42:38 2003 UTC revision 782 by jonathan, Tue Apr 29 16:53:55 2003 UTC
# Line 27  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  from dialogs import NonModalDialog
33    
 # widget id's  
 ID_PROPERTY_SELECT = 4010  
34  ID_CLASS_TABLE = 40011  ID_CLASS_TABLE = 40011
35    
 ID_CLASSIFY_OK = 4001  
 ID_CLASSIFY_CANCEL = 4002  
 ID_CLASSIFY_ADD = 4003  
 ID_CLASSIFY_GENRANGE = 4004  
 ID_CLASSIFY_REMOVE = 4005  
 ID_CLASSIFY_MOVEUP = 4006  
 ID_CLASSIFY_MOVEDOWN = 4007  
 ID_CLASSIFY_APPLY = 4008  
36    
37  # table columns  # table columns
38  COL_SYMBOL = 0  COL_VISIBLE = 0
39  COL_VALUE  = 1  COL_SYMBOL  = 1
40  COL_LABEL  = 2  COL_VALUE   = 2
41    COL_LABEL   = 3
42    NUM_COLS    = 4
43    
44  # indices into the client data lists in Classifier.fields  # indices into the client data lists in Classifier.fields
45  FIELD_CLASS = 0  FIELD_CLASS = 0
# Line 59  FIELD_NAME = 2 Line 53  FIELD_NAME = 2
53  import weakref  import weakref
54  class ClassGrid(wxGrid):  class ClassGrid(wxGrid):
55    
56      def __init__(self, parent):  
57        def __init__(self, parent, classifier):
58          """Constructor.          """Constructor.
59    
60          parent -- the parent window          parent -- the parent window
# Line 68  class ClassGrid(wxGrid): Line 63  class ClassGrid(wxGrid):
63                   use for display.                   use for display.
64          """          """
65    
         #wxGrid.__init__(self, parent, ID_CLASS_TABLE, size = (340, 160))  
66          wxGrid.__init__(self, parent, ID_CLASS_TABLE)          wxGrid.__init__(self, parent, ID_CLASS_TABLE)
67          #self.SetTable(ClassTable(fieldData, layer.ShapeType(), self), True)  
68            self.classifier = classifier
69    
70            self.currentSelection = []
71    
72          EVT_GRID_CELL_LEFT_DCLICK(self, self._OnCellDClick)          EVT_GRID_CELL_LEFT_DCLICK(self, self._OnCellDClick)
73          EVT_GRID_RANGE_SELECT(self, self._OnSelectedRange)          EVT_GRID_RANGE_SELECT(self, self._OnSelectedRange)
74          EVT_GRID_SELECT_CELL(self, self._OnSelectedCell)          EVT_GRID_SELECT_CELL(self, self._OnSelectedCell)
75            EVT_GRID_COL_SIZE(self, self._OnCellResize)
76            EVT_GRID_ROW_SIZE(self, self._OnCellResize)
77    
78          self.currentSelection = []      #def GetCellAttr(self, row, col):
79            #print "GetCellAttr ", row, col
80            #wxGrid.GetCellAttr(self, row, col)
81    
82      def CreateTable(self, clazz, shapeType):      def CreateTable(self, clazz, shapeType, group = None):
83    
84          assert(isinstance(clazz, Classification))          assert isinstance(clazz, Classification)
85    
         self.shapeType = shapeType  
86          table = self.GetTable()          table = self.GetTable()
87          if table is None:          if table is None:
88              w = self.GetDefaultColSize() * 3 + self.GetDefaultRowLabelSize()              w = self.GetDefaultColSize() * NUM_COLS \
89              h = self.GetDefaultRowSize() * 4 + self.GetDefaultColLabelSize()                  + self.GetDefaultRowLabelSize()
90                h = self.GetDefaultRowSize() * 4 \
91                    + self.GetDefaultColLabelSize()
92    
93              self.SetDimensions(-1, -1, w, h)              self.SetDimensions(-1, -1, w, h)
94              self.SetSizeHints(w, h, -1, -1)              self.SetSizeHints(w, h, -1, -1)
95              self.SetTable(ClassTable(clazz, self.shapeType, self), True)              table = ClassTable(self)
96          else:              self.SetTable(table, True)
97              table.Reset(clazz, self.shapeType)  
98    
99          self.SetSelectionMode(wxGrid.wxGridSelectRows)          self.SetSelectionMode(wxGrid.wxGridSelectRows)
100          self.ClearSelection()          self.ClearSelection()
101    
102            table.Reset(clazz, shapeType, group)
103    
104      def GetCurrentSelection(self):      def GetCurrentSelection(self):
105          """Return the currently highlighted rows as an increasing list          """Return the currently highlighted rows as an increasing list
106             of row numbers."""             of row numbers."""
# Line 103  class ClassGrid(wxGrid): Line 108  class ClassGrid(wxGrid):
108          sel.sort()          sel.sort()
109          return sel          return sel
110    
111      def SetCellRenderer(self, row, col):      def GetSelectedRows(self):
112          raise ValueError(_("Must not allow setting of renderer in ClassGrid!"))          return self.GetCurrentSelection()
113    
114        #def SetCellRenderer(self, row, col, renderer):
115            #raise ValueError(_("Must not allow setting of renderer in ClassGrid!"))
116    
117      #      #
118      # [Set|Get]Table is taken from http://wiki.wxpython.org      # [Set|Get]Table is taken from http://wiki.wxpython.org
# Line 169  class ClassGrid(wxGrid): Line 177  class ClassGrid(wxGrid):
177                  r = self.GetNumberRows() - 1                  r = self.GetNumberRows() - 1
178              self.SelectRow(r)              self.SelectRow(r)
179                    
180    
181        def SelectGroup(self, group, makeVisible = True):
182            if group is None: return
183    
184            assert isinstance(group, ClassGroup)
185    
186            table = self.GetTable()
187    
188            assert table is not None
189    
190            for i in range(table.GetNumberRows()):
191                g = table.GetClassGroup(i)
192                if g is group:
193                    self.SelectRow(i)
194                    if makeVisible:
195                        self.MakeCellVisible(i, 0)
196                    break
197    
198  #  #
199  # 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!
200  #  #
# Line 181  class ClassGrid(wxGrid): Line 207  class ClassGrid(wxGrid):
207  #                                  sel = False))  #                                  sel = False))
208    
209      def _OnCellDClick(self, event):      def _OnCellDClick(self, event):
210          """Handle a double on a cell."""          """Handle a double click on a cell."""
211    
212          r = event.GetRow()          r = event.GetRow()
213          c = event.GetCol()          c = event.GetCol()
         if c == COL_SYMBOL:  
             prop = self.GetTable().GetValueAsCustom(r, c, None)  
             #prop = group.GetProperties()  
214    
215              # get a new ClassGroupProperties object and copy the          if c == COL_SYMBOL:
216              # values over to our current object              self.classifier.EditSymbol(r)
217              propDlg = SelectPropertiesDialog(NULL, prop, self.shapeType)          else:
218              if propDlg.ShowModal() == wxID_OK:              event.Skip()
                 new_prop = propDlg.GetClassGroupProperties()  
                 #prop.SetProperties(new_prop)  
                 self.GetTable().SetValueAsCustom(r, c, None, new_prop)  
             propDlg.Destroy()  
219    
220      #      #
221      # _OnSelectedRange() and _OnSelectedCell() were borrowed      # _OnSelectedRange() and _OnSelectedCell() were borrowed
# Line 223  class ClassGrid(wxGrid): Line 242  class ClassGrid(wxGrid):
242          #self.ConfigureForSelection()          #self.ConfigureForSelection()
243          event.Skip()          event.Skip()
244    
245        def _OnCellResize(self, event):
246            self.FitInside()
247    
248  class ClassTable(wxPyGridTableBase):  class ClassTable(wxPyGridTableBase):
249      """Represents the underlying data structure for the grid."""      """Represents the underlying data structure for the grid."""
250    
251      NUM_COLS = 3      __col_labels = [_("Visible"), _("Symbol"), _("Value"), _("Label")]
252    
     __col_labels = [_("Symbol"), _("Value"), _("Label")]  
253    
254      def __init__(self, clazz, shapeType, view = None):      def __init__(self, view = None):
255        #def __init__(self, clazz, shapeType, view = None):
256          """Constructor.          """Constructor.
257    
258          shapeType -- the type of shape that the layer uses          shapeType -- the type of shape that the layer uses
# Line 240  class ClassTable(wxPyGridTableBase): Line 262  class ClassTable(wxPyGridTableBase):
262    
263          wxPyGridTableBase.__init__(self)          wxPyGridTableBase.__init__(self)
264    
265          self.SetView(view)          assert len(ClassTable.__col_labels) == NUM_COLS
266          self.tdata = []  
267            self.clazz = None
268            self.__colAttr = {}
269    
270          self.Reset(clazz, shapeType)          self.SetView(view)
271    
272      def Reset(self, clazz, shapeType):      def Reset(self, clazz, shapeType, group = None):
273          """Reset the table with the given data.          """Reset the table with the given data.
274    
275          This is necessary because wxWindows does not allow a grid's          This is necessary because wxWindows does not allow a grid's
# Line 259  class ClassTable(wxPyGridTableBase): Line 283  class ClassTable(wxPyGridTableBase):
283          shapeType -- the type of shape that the layer uses          shapeType -- the type of shape that the layer uses
284          """          """
285    
286          assert(isinstance(clazz, Classification))          assert isinstance(clazz, Classification)
287    
288          self.GetView().BeginBatch()          self.GetView().BeginBatch()
289    
290          self.fieldType = clazz.GetFieldType()          self.fieldType = clazz.GetFieldType()
291          self.shapeType = shapeType          self.shapeType = shapeType
292    
293          old_len = len(self.tdata)          self.SetClassification(clazz, group)
294            self.__Modified(-1)
295    
296            self.__colAttr = {}
297    
298            attr = wxGridCellAttr()
299            attr.SetEditor(wxGridCellBoolEditor())
300            attr.SetRenderer(wxGridCellBoolRenderer())
301            attr.SetAlignment(wxALIGN_CENTER, wxALIGN_CENTER)
302            self.__colAttr[COL_VISIBLE] = attr
303    
304            attr = wxGridCellAttr()
305            attr.SetRenderer(ClassRenderer(self.shapeType))
306            attr.SetReadOnly()
307            self.__colAttr[COL_SYMBOL] = attr
308    
309            self.GetView().EndBatch()
310            self.GetView().FitInside()
311    
312        def GetClassification(self):
313            return self.clazz
314    
315        def SetClassification(self, clazz, group = None):
316    
317            self.GetView().BeginBatch()
318    
319          self.tdata = []          old_len = self.GetNumberRows()
320    
321            row = -1
322            self.clazz = clazz
323    
324            self.__NotifyRowChanges(old_len, self.GetNumberRows())
325    
326          #          #
327          # copy the data out of the classification and into our          # XXX: this is dead code at the moment
         # array  
328          #          #
329          for p in clazz:          if row > -1:
330              np = copy.deepcopy(p)              self.GetView().ClearSelection()
331              self.__SetRow(-1, np)              self.GetView().SelectRow(row)
332                self.GetView().MakeCellVisible(row, 0)
333    
334            self.__Modified()
         self.__Modified(-1)  
335    
         self.__NotifyRowChanges(old_len, len(self.tdata))  
336    
               
337          self.GetView().EndBatch()          self.GetView().EndBatch()
338            self.GetView().FitInside()
339    
340      def __NotifyRowChanges(self, curRows, newRows):      def __NotifyRowChanges(self, curRows, newRows):
341          #          #
# Line 296  class ClassTable(wxPyGridTableBase): Line 347  class ClassTable(wxPyGridTableBase):
347                          wxGRIDTABLE_NOTIFY_ROWS_APPENDED,                          wxGRIDTABLE_NOTIFY_ROWS_APPENDED,
348                          newRows - curRows)    # how many                          newRows - curRows)    # how many
349              self.GetView().ProcessTableMessage(msg)              self.GetView().ProcessTableMessage(msg)
350              #self.GetView().FitInside() # XXX: only with wxWindows2.4              self.GetView().FitInside()
351          elif newRows < curRows:          elif newRows < curRows:
352              msg = wxGridTableMessage(self,              msg = wxGridTableMessage(self,
353                          wxGRIDTABLE_NOTIFY_ROWS_DELETED,                          wxGRIDTABLE_NOTIFY_ROWS_DELETED,
354                          curRows - newRows,    # position                          curRows,              # position
355                          curRows - newRows)    # how many                          curRows - newRows)    # how many
356              self.GetView().ProcessTableMessage(msg)              self.GetView().ProcessTableMessage(msg)
357              #self.GetView().FitInside() # XXX: only with wxWindows2.4              self.GetView().FitInside()
358    
359    
360      def __SetRow(self, row, group):      def __SetRow(self, row, group):
361          """Set a row's data to that of the group.          """Set a row's data to that of the group.
362    
363          The table is considered modified after this operation.          The table is considered modified after this operation.
364    
365          row -- if row is -1 or greater than the current number of rows          row -- if row is < 0 'group' is inserted at the top of the table
366                 then group is appended to the end.                 if row is >= GetNumberRows() or None 'group' is append to
367                        the end of the table.
368                   otherwise 'group' replaces row 'row'
369          """          """
370    
371          # either append or replace          # either append or replace
372          if row == -1 or row >= self.GetNumberRows():          if row is None or row >= self.GetNumberRows():
373              self.tdata.append(group)              self.clazz.AppendGroup(group)
374            elif row < 0:
375                self.clazz.InsertGroup(0, group)
376          else:          else:
377              self.tdata[row] = group              if row == 0:
378                    self.clazz.SetDefaultGroup(group)
379                else:
380                    self.clazz.ReplaceGroup(row - 1, group)
381    
382          self.__Modified()          self.__Modified()
383    
# Line 329  class ClassTable(wxPyGridTableBase): Line 388  class ClassTable(wxPyGridTableBase):
388      def GetRowLabelValue(self, row):      def GetRowLabelValue(self, row):
389          """Return the label for the given row."""          """Return the label for the given row."""
390    
391          group = self.tdata[row]          if row == 0:
392          if isinstance(group, ClassGroupDefault):   return _("Default")              return _("Default")
393          if isinstance(group, ClassGroupSingleton): return _("Singleton")          else:
394          if isinstance(group, ClassGroupRange):     return _("Range")              group = self.clazz.GetGroup(row - 1)
395          if isinstance(group, ClassGroupMap):       return _("Map")              if isinstance(group, ClassGroupDefault):   return _("Default")
396                if isinstance(group, ClassGroupSingleton): return _("Singleton")
397                if isinstance(group, ClassGroupRange):     return _("Range")
398                if isinstance(group, ClassGroupMap):       return _("Map")
399    
400          assert(False) # shouldn't get here          assert False # shouldn't get here
401          return _("")          return ""
402    
403      def GetNumberRows(self):      def GetNumberRows(self):
404          """Return the number of rows."""          """Return the number of rows."""
405          return len(self.tdata)          if self.clazz is None:
406                return 0
407    
408            return self.clazz.GetNumGroups() + 1 # +1 for default group
409    
410      def GetNumberCols(self):      def GetNumberCols(self):
411          """Return the number of columns."""          """Return the number of columns."""
412          return self.NUM_COLS          return NUM_COLS
413    
414      def IsEmptyCell(self, row, col):      def IsEmptyCell(self, row, col):
415          """Determine if a cell is empty. This is always false."""          """Determine if a cell is empty. This is always false."""
# Line 362  class ClassTable(wxPyGridTableBase): Line 427  class ClassTable(wxPyGridTableBase):
427          """          """
428    
429          self.SetValueAsCustom(row, col, None, value)          self.SetValueAsCustom(row, col, None, value)
         self.__Modified()  
430                
431      def GetValueAsCustom(self, row, col, typeName):      def GetValueAsCustom(self, row, col, typeName):
432          """Return the object that is used to represent the given          """Return the object that is used to represent the given
# Line 371  class ClassTable(wxPyGridTableBase): Line 435  class ClassTable(wxPyGridTableBase):
435          typeName -- unused, but needed to overload wxPyGridTableBase          typeName -- unused, but needed to overload wxPyGridTableBase
436          """          """
437    
438          group = self.tdata[row]          if row == 0:
439                group = self.clazz.GetDefaultGroup()
440            else:
441                group = self.clazz.GetGroup(row - 1)
442    
443    
444            if col == COL_VISIBLE:
445                return group.IsVisible()
446    
447          if col == COL_SYMBOL:          if col == COL_SYMBOL:
448              return group.GetProperties()              return group.GetProperties()
# Line 380  class ClassTable(wxPyGridTableBase): Line 451  class ClassTable(wxPyGridTableBase):
451              return group.GetLabel()              return group.GetLabel()
452    
453          # col must be COL_VALUE          # col must be COL_VALUE
454          assert(col == COL_VALUE)          assert col == COL_VALUE
455    
456          if isinstance(group, ClassGroupDefault):          if isinstance(group, ClassGroupDefault):
457              return _("DEFAULT")              return _("DEFAULT")
# Line 404  class ClassTable(wxPyGridTableBase): Line 475  class ClassTable(wxPyGridTableBase):
475    
476          if type == FIELDTYPE_STRING:          if type == FIELDTYPE_STRING:
477              return (value,)              return (value,)
478          elif type == FIELDTYPE_INT or type == FIELDTYPE_DOUBLE:          elif type in (FIELDTYPE_INT, FIELDTYPE_DOUBLE):
479    
480              if type == FIELDTYPE_INT:              if type == FIELDTYPE_INT:
481                    # the float call allows the user to enter 1.0 for 1
482                  conv = lambda p: int(float(p))                  conv = lambda p: int(float(p))
483              else:              else:
484                  conv = lambda p: p                  conv = lambda p: p
# Line 421  class ClassTable(wxPyGridTableBase): Line 493  class ClassTable(wxPyGridTableBase):
493              # function.              # function.
494              #              #
495              try:              try:
496                  return (conv(Str2Num(value)),)                  return (conv(value),)
497              except ValueError:              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 (conv(Str2Num(value[:i])), conv(Str2Num(value[i+1:])))                  return (conv(value[:i]), conv(value[i+1:]))
503    
504          assert(False) # shouldn't get here          assert False  # shouldn't get here
505          return (0,)          return (0,)
506                            
507    
# Line 445  class ClassTable(wxPyGridTableBase): Line 517  class ClassTable(wxPyGridTableBase):
517          typeName -- unused, but needed to overload wxPyGridTableBase          typeName -- unused, but needed to overload wxPyGridTableBase
518          """          """
519    
520          assert(col >= 0 and col < self.GetNumberCols())          assert 0 <= col < self.GetNumberCols()
521          assert(row >= 0 and row < self.GetNumberRows())          assert 0 <= row < self.GetNumberRows()
522    
523          group = self.tdata[row]          if row == 0:
524                group = self.clazz.GetDefaultGroup()
525            else:
526                group = self.clazz.GetGroup(row - 1)
527    
528          mod = True # assume the data will change          mod = True # assume the data will change
529    
530          if col == COL_SYMBOL:          if col == COL_VISIBLE:
531                group.SetVisible(value)
532            elif col == COL_SYMBOL:
533              group.SetProperties(value)              group.SetProperties(value)
534          elif col == COL_LABEL:          elif col == COL_LABEL:
535              group.SetLabel(value)              group.SetLabel(value)
# Line 482  class ClassTable(wxPyGridTableBase): Line 559  class ClassTable(wxPyGridTableBase):
559                      #                      #
560                      if len(dataInfo) == 1:                      if len(dataInfo) == 1:
561                          if not isinstance(group, ClassGroupSingleton):                          if not isinstance(group, ClassGroupSingleton):
562                              ngroup = ClassGroupSingleton(prop = props)                              ngroup = ClassGroupSingleton(props = props)
563                              changed = True                              changed = True
564                          ngroup.SetValue(dataInfo[0])                          ngroup.SetValue(dataInfo[0])
565                      elif len(dataInfo) == 2:                      elif len(dataInfo) == 2:
566                          if not isinstance(group, ClassGroupRange):                          if not isinstance(group, ClassGroupRange):
567                              ngroup = ClassGroupRange(prop = props)                              ngroup = ClassGroupRange(props = props)
568                              changed = True                              changed = True
569                          ngroup.SetRange(dataInfo[0], dataInfo[1])                          ngroup.SetRange(dataInfo[0], dataInfo[1])
570                      else:                      else:
571                          assert(False)                          assert False
572                          pass                          pass
573    
574                      if changed:                      if changed:
575                          ngroup.SetLabel(group.GetLabel())                          ngroup.SetLabel(group.GetLabel())
576                          self.SetClassGroup(row, ngroup)                          self.SetClassGroup(row, ngroup)
577          else:          else:
578              assert(False) # shouldn't be here              assert False # shouldn't be here
579              pass              pass
580    
581          if mod:          if mod:
# Line 508  class ClassTable(wxPyGridTableBase): Line 585  class ClassTable(wxPyGridTableBase):
585      def GetAttr(self, row, col, someExtraParameter):      def GetAttr(self, row, col, someExtraParameter):
586          """Returns the cell attributes"""          """Returns the cell attributes"""
587    
588          attr = wxGridCellAttr()          return self.__colAttr.get(col, wxGridCellAttr()).Clone()
         #attr = wxPyGridTableBase.GetAttr(self, row, col, someExtraParameter)  
   
         if col == COL_SYMBOL:  
             # we need to create a new renderer each time, because  
             # SetRenderer takes control of the parameter  
             attr.SetRenderer(ClassRenderer(self.shapeType))  
             attr.SetReadOnly()  
   
         return attr  
589    
590      def GetClassGroup(self, row):      def GetClassGroup(self, row):
591          """Return the ClassGroup object representing row 'row'."""          """Return the ClassGroup object representing row 'row'."""
592    
593          return self.tdata[row] # self.GetValueAsCustom(row, COL_SYMBOL, None)          #return self.GetValueAsCustom(row, COL_SYMBOL, None)
594            if row == 0:
595                return self.clazz.GetDefaultGroup()
596            else:
597                return self.clazz.GetGroup(row - 1)
598    
599      def SetClassGroup(self, row, group):      def SetClassGroup(self, row, group):
600          self.__SetRow(row, group)          self.__SetRow(row, group)
# Line 553  class ClassTable(wxPyGridTableBase): Line 625  class ClassTable(wxPyGridTableBase):
625          The table is considered modified if any rows are removed.          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 = self.GetNumberRows()
630          for row in range(pos, pos - numRows, -1):          for row in range(pos, pos - numRows, -1):
631              group = self.GetClassGroup(row)              group = self.GetClassGroup(row)
632              if not isinstance(group, ClassGroupDefault):              if row != 0:
633                  self.tdata.pop(row)                  self.clazz.RemoveGroup(row - 1)
634                  self.__Modified()                  self.__Modified()
635            
636          if self.IsModified():          if self.IsModified():
637              self.__NotifyRowChanges(old_len, len(self.tdata))              self.__NotifyRowChanges(old_len, self.GetNumberRows())
638    
639      def AppendRows(self, numRows = 1):      def AppendRows(self, numRows = 1):
640          """Append 'numRows' empty rows to the end of the table.          """Append 'numRows' empty rows to the end of the table.
# Line 570  class ClassTable(wxPyGridTableBase): Line 642  class ClassTable(wxPyGridTableBase):
642          The table is considered modified if any rows are appended.          The table is considered modified if any rows are appended.
643          """          """
644    
645          old_len = len(self.tdata)          old_len = self.GetNumberRows()
646          for i in range(numRows):          for i in range(numRows):
647              np = ClassGroupSingleton()              np = ClassGroupSingleton()
648              self.__SetRow(-1, np)              self.__SetRow(None, np)
649    
650          if self.IsModified():          if self.IsModified():
651              self.__NotifyRowChanges(old_len, len(self.tdata))              self.__NotifyRowChanges(old_len, self.GetNumberRows())
652    
653    
654    ID_PROPERTY_OK = 4001
655    ID_PROPERTY_REVERT = 4002
656    ID_PROPERTY_ADD = 4003
657    ID_PROPERTY_GENCLASS = 4004
658    ID_PROPERTY_REMOVE = 4005
659    ID_PROPERTY_MOVEUP = 4006
660    ID_PROPERTY_MOVEDOWN = 4007
661    ID_PROPERTY_TRY = 4008
662    ID_PROPERTY_EDITSYM = 4009
663    ID_PROPERTY_CLOSE = 4010
664    ID_PROPERTY_SELECT = 4011
665    ID_PROPERTY_TITLE = 4012
666    ID_PROPERTY_FIELDTEXT = 4013
667    
668    BTN_ADD = 0
669    BTN_EDIT = 1
670    BTN_GEN = 2
671    BTN_UP = 3
672    BTN_DOWN = 4
673    BTN_RM = 5
674    
675    EB_LAYER_TITLE = 0
676    EB_SELECT_FIELD = 1
677    EB_GEN_CLASS = 2
678    
679  class Classifier(NonModalDialog):  class Classifier(NonModalDialog):
       
     def __init__(self, parent, interactor, name, layer):  
         NonModalDialog.__init__(self, parent, interactor, name,  
                                 _("Classifier: %s") % layer.Title())  
680    
681          panel = wxPanel(self, -1, size=(100, 100))      type2string = {None:             _("None"),
682                       FIELDTYPE_STRING: _("Text"),
683                       FIELDTYPE_INT:    _("Integer"),
684                       FIELDTYPE_DOUBLE: _("Decimal")}
685    
686        def __init__(self, parent, name, layer, group = None):
687            NonModalDialog.__init__(self, parent, name, "")
688    
689            self.__SetTitle(layer.Title())
690    
691          self.layer = layer          self.layer = layer
692    
# Line 593  class Classifier(NonModalDialog): Line 694  class Classifier(NonModalDialog):
694          field = self.originalClass.GetField()          field = self.originalClass.GetField()
695          fieldType = self.originalClass.GetFieldType()          fieldType = self.originalClass.GetFieldType()
696    
697            self.genDlg = None
698    
699          topBox = wxBoxSizer(wxVERTICAL)          topBox = wxBoxSizer(wxVERTICAL)
700    
701            panel = wxPanel(self, -1, size=(100, 100))
702    
703          panelBox = wxBoxSizer(wxVERTICAL)          panelBox = wxBoxSizer(wxVERTICAL)
704    
705          #panelBox.Add(wxStaticText(panel, -1, _("Layer: %s") % layer.Title()),          sizer = wxBoxSizer(wxHORIZONTAL)
706              #0, wxALIGN_LEFT | wxALL, 4)          sizer.Add(wxStaticText(panel, -1, _("Title: ")),
707                0, wxALIGN_LEFT | wxALL | wxALIGN_CENTER_VERTICAL, 4)
708            sizer.Add(wxTextCtrl(panel, ID_PROPERTY_TITLE, layer.Title()),
709                      1, wxGROW | wxALL, 4)
710            EVT_TEXT(self, ID_PROPERTY_TITLE, self._OnTitleChanged)
711    
712            panelBox.Add(sizer, 0, wxGROW, 4)
713    
714          panelBox.Add(wxStaticText(panel, -1,          panelBox.Add(wxStaticText(panel, -1,
715                                  _("Layer Type: %s") % layer.ShapeType()),                                  _("Type: %s") % layer.ShapeType()),
716              0, wxALIGN_LEFT | wxALL, 4)              0, wxALIGN_LEFT | wxALL, 4)
717    
718    
719            #####################
720    
721            #panelBox = wxBoxSizer(wxVERTICAL)
722            classBox = wxStaticBoxSizer(
723                        wxStaticBox(panel, -1, _("Classification")), wxVERTICAL)
724    
725    
726          #          #
727          # make field combo box          # make field choice box
728          #          #
729          self.fields = wxComboBox(panel, ID_PROPERTY_SELECT, "",          self.fields = wxChoice(panel, ID_PROPERTY_SELECT,)
730                                       style = wxCB_READONLY)          #self.fields = wxComboBox(panel, ID_PROPERTY_SELECT, "",
731            #                             style = wxCB_READONLY)
732    
733          self.num_cols = layer.table.field_count()          self.num_cols = layer.table.field_count()
734          # just assume the first field in case one hasn't been          # just assume the first field in case one hasn't been
# Line 615  class Classifier(NonModalDialog): Line 736  class Classifier(NonModalDialog):
736          self.__cur_field = 0          self.__cur_field = 0
737    
738          self.fields.Append("<None>")          self.fields.Append("<None>")
739          self.fields.SetClientData(0, None)  
740            if self.originalClass.GetFieldType() is None:
741                self.fields.SetClientData(0, copy.deepcopy(self.originalClass))
742            else:
743                self.fields.SetClientData(0, None)
744    
745          for i in range(self.num_cols):          for i in range(self.num_cols):
746              type, name, len, decc = layer.table.field_info(i)              type, name, len, decc = layer.table.field_info(i)
# Line 623  class Classifier(NonModalDialog): Line 748  class Classifier(NonModalDialog):
748    
749              if name == field:              if name == field:
750                  self.__cur_field = i + 1                  self.__cur_field = i + 1
751                  self.fields.SetClientData(i + 1, self.originalClass)                  self.fields.SetClientData(i + 1,
752                                              copy.deepcopy(self.originalClass))
753              else:              else:
754                  self.fields.SetClientData(i + 1, None)                  self.fields.SetClientData(i + 1, None)
755    
756    
757          ###########          ###########
758    
         self.fieldTypeText = wxStaticText(panel, -1, "")  
         panelBox.Add(self.fieldTypeText, 0, wxGROW | wxALIGN_LEFT | wxALL, 4)  
759    
760          propertyBox = wxBoxSizer(wxHORIZONTAL)          sizer = wxBoxSizer(wxHORIZONTAL)
761          propertyBox.Add(wxStaticText(panel, -1, _("Field: ")),          sizer.Add(wxStaticText(panel, ID_PROPERTY_FIELDTEXT, _("Field: ")),
762              0, wxALIGN_LEFT | wxALL, 4)              0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 4)
763          propertyBox.Add(self.fields, 1, wxGROW|wxALL, 4)          sizer.Add(self.fields, 1, wxGROW | wxALL, 4)
764          EVT_COMBOBOX(self, ID_PROPERTY_SELECT, self._OnFieldSelect)          EVT_CHOICE(self, ID_PROPERTY_SELECT, self._OnFieldSelect)
765            #EVT_COMBOBOX(self, ID_PROPERTY_SELECT, self._OnFieldSelect)
766    
767            classBox.Add(sizer, 0, wxGROW, 4)
768    
769            self.fieldTypeText = wxStaticText(panel, -1, "")
770            classBox.Add(self.fieldTypeText, 0,
771                         wxGROW | wxALIGN_LEFT | wxALL | wxADJUST_MINSIZE, 4)
772    
         panelBox.Add(propertyBox, 0, wxGROW, 4)  
773    
         ###########  
774          #          #
775          # Classification data table          # Control Box
776          #          #
   
777          controlBox = wxBoxSizer(wxHORIZONTAL)          controlBox = wxBoxSizer(wxHORIZONTAL)
778    
         self.classGrid = ClassGrid(panel)  
         self.__SetGridTable(self.__cur_field)  
   
         controlBox.Add(self.classGrid, 1, wxGROW, 0)  
779    
780          ###########          ###########
781          #          #
782          # Control buttons:          # Control buttons:
783          #          #
         self.controlButtons = []  
   
784          controlButtonBox = wxBoxSizer(wxVERTICAL)          controlButtonBox = wxBoxSizer(wxVERTICAL)
785    
786          button = wxButton(panel, ID_CLASSIFY_ADD, _("Add"))          button = wxButton(panel, ID_PROPERTY_GENCLASS, _("Generate Class"))
787            controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)
788    
789            button = wxButton(panel, ID_PROPERTY_ADD, _("Add"))
790          controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)          controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)
         self.controlButtons.append(button)  
791    
792          #button = wxButton(panel, ID_CLASSIFY_GENRANGE, _("Generate Ranges"))          button = wxButton(panel, ID_PROPERTY_MOVEUP, _("Move Up"))
793          #controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)          controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)
         #self.controlButtons.append(button)  
794    
795          button = wxButton(panel, ID_CLASSIFY_MOVEUP, _("Move Up"))          button = wxButton(panel, ID_PROPERTY_MOVEDOWN, _("Move Down"))
796          controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)          controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)
         self.controlButtons.append(button)  
797    
798          button = wxButton(panel, ID_CLASSIFY_MOVEDOWN, _("Move Down"))          button = wxButton(panel, ID_PROPERTY_EDITSYM, _("Edit Symbol"))
799          controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)          controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)
         self.controlButtons.append(button)  
800    
801          controlButtonBox.Add(60, 20, 0, wxGROW | wxALL | wxALIGN_BOTTOM, 4)          controlButtonBox.Add(60, 20, 0, wxGROW | wxALL | wxALIGN_BOTTOM, 4)
802    
803          button = wxButton(panel, ID_CLASSIFY_REMOVE, _("Remove"))          button = wxButton(panel, ID_PROPERTY_REMOVE, _("Remove"))
804          controlButtonBox.Add(button, 0, wxGROW | wxALL | wxALIGN_BOTTOM, 4)          controlButtonBox.Add(button, 0, wxGROW | wxALL | wxALIGN_BOTTOM, 4)
         self.controlButtons.append(button)  
805    
806    
807            ###########
808            #
809            # Classification data table
810            #
811    
812            self.classGrid = ClassGrid(panel, self)
813    
814            # calling __SelectField after creating the classGrid fills in the
815            # grid with the correct information
816            self.fields.SetSelection(self.__cur_field)
817            self.__SelectField(self.__cur_field, group = group)
818    
819            controlBox.Add(self.classGrid, 1, wxGROW, 0)
820          controlBox.Add(controlButtonBox, 0, wxGROW, 10)          controlBox.Add(controlButtonBox, 0, wxGROW, 10)
         panelBox.Add(controlBox, 1, wxGROW, 10)  
821    
822          EVT_BUTTON(self, ID_CLASSIFY_ADD, self._OnAdd)          classBox.Add(controlBox, 1, wxGROW, 10)
823          EVT_BUTTON(self, ID_CLASSIFY_REMOVE, self._OnRemove)          panelBox.Add(classBox, 1, wxGROW, 0)
824          EVT_BUTTON(self, ID_CLASSIFY_GENRANGE, self._OnGenRange)  
825          EVT_BUTTON(self, ID_CLASSIFY_MOVEUP, self._OnMoveUp)          EVT_BUTTON(self, ID_PROPERTY_ADD, self._OnAdd)
826          EVT_BUTTON(self, ID_CLASSIFY_MOVEDOWN, self._OnMoveDown)          EVT_BUTTON(self, ID_PROPERTY_EDITSYM, self._OnEditSymbol)
827            EVT_BUTTON(self, ID_PROPERTY_REMOVE, self._OnRemove)
828            EVT_BUTTON(self, ID_PROPERTY_GENCLASS, self._OnGenClass)
829            EVT_BUTTON(self, ID_PROPERTY_MOVEUP, self._OnMoveUp)
830            EVT_BUTTON(self, ID_PROPERTY_MOVEDOWN, self._OnMoveDown)
831    
832            ###########
833    
834    
835            panel.SetAutoLayout(True)
836            panel.SetSizer(panelBox)
837            panelBox.SetSizeHints(panel)
838    
839            topBox.Add(panel, 1, wxGROW | wxALL, 4)
840    
841          ###########          ###########
842    
843          buttonBox = wxBoxSizer(wxHORIZONTAL)          buttonBox = wxBoxSizer(wxHORIZONTAL)
844          buttonBox.Add(wxButton(panel, ID_CLASSIFY_OK, _("OK")),          buttonBox.Add(wxButton(self, ID_PROPERTY_TRY, _("Try")),
845                          0, wxALL, 4)
846            buttonBox.Add(60, 20, 0, wxALL, 4)
847            buttonBox.Add(wxButton(self, ID_PROPERTY_REVERT, _("Revert")),
848                        0, wxALL, 4)                        0, wxALL, 4)
849          buttonBox.Add(60, 20, 0, wxALL, 4)          buttonBox.Add(60, 20, 0, wxALL, 4)
850          buttonBox.Add(wxButton(panel, ID_CLASSIFY_APPLY, _("Apply")),          buttonBox.Add(wxButton(self, ID_PROPERTY_OK, _("OK")),
851                        0, wxALL, 4)                        0, wxALL, 4)
852          buttonBox.Add(60, 20, 0, wxALL, 4)          buttonBox.Add(60, 20, 0, wxALL, 4)
853          buttonBox.Add(wxButton(panel, ID_CLASSIFY_CANCEL, _("Cancel")),          buttonBox.Add(wxButton(self, ID_PROPERTY_CLOSE, _("Close")),
854                        0, wxALL, 4)                        0, wxALL, 4)
855          panelBox.Add(buttonBox, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_BOTTOM, 0)          topBox.Add(buttonBox, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_BOTTOM, 0)
856    
857          EVT_BUTTON(self, ID_CLASSIFY_OK, self._OnOK)          EVT_BUTTON(self, ID_PROPERTY_OK, self._OnOK)
858          EVT_BUTTON(self, ID_CLASSIFY_APPLY, self._OnApply)          EVT_BUTTON(self, ID_PROPERTY_TRY, self._OnTry)
859          EVT_BUTTON(self, ID_CLASSIFY_CANCEL, self._OnCancel)          EVT_BUTTON(self, ID_PROPERTY_CLOSE, self._OnCloseBtn)
860            EVT_BUTTON(self, ID_PROPERTY_REVERT, self._OnRevert)
861    
862          ###########          ###########
863    
864          self.fields.SetSelection(self.__cur_field)          topBox.SetSizeHints(self)
         self.__SelectField(self.__cur_field)  
   
         panel.SetAutoLayout(True)  
         panel.SetSizer(panelBox)  
         panelBox.SetSizeHints(panel)  
   
         topBox.Add(panel, 1, wxGROW, 0)  
         panelBox.SetSizeHints(self)  
865          self.SetAutoLayout(True)          self.SetAutoLayout(True)
866          self.SetSizer(topBox)          self.SetSizer(topBox)
867    
868      def __BuildClassification(self, fieldIndex):          #self.Fit()
869            ######################
870    
871            self.haveApplied = False
872    
873        def EditSymbol(self, row):
874            table = self.classGrid.GetTable()
875            prop = table.GetValueAsCustom(row, COL_SYMBOL, None)
876    
877            # get a new ClassGroupProperties object and copy the
878            # values over to our current object
879            propDlg = SelectPropertiesDialog(NULL, prop, self.layer.ShapeType())
880    
881            self.Enable(False)
882            if propDlg.ShowModal() == wxID_OK:
883                new_prop = propDlg.GetClassGroupProperties()
884                table.SetValueAsCustom(row, COL_SYMBOL, None, new_prop)
885            self.Enable(True)
886            propDlg.Destroy()
887            
888        def _SetClassification(self, clazz):
889            
890            self.fields.SetClientData(self.__cur_field, clazz)
891            self.classGrid.GetTable().SetClassification(clazz)
892    
893          numRows = self.classGrid.GetNumberRows()      def __BuildClassification(self, fieldIndex, copyClass = False):
         assert(numRows > 0) # there should always be a default row  
894    
895          clazz = Classification()  #       numRows = self.classGrid.GetNumberRows()
896    #       assert numRows > 0  # there should always be a default row
897    
898    #       clazz = Classification()
899          if fieldIndex == 0:          if fieldIndex == 0:
900              fieldName = None              fieldName = None
901              fieldType = None              fieldType = None
# Line 736  class Classifier(NonModalDialog): Line 903  class Classifier(NonModalDialog):
903              fieldName = self.fields.GetString(fieldIndex)              fieldName = self.fields.GetString(fieldIndex)
904              fieldType = self.layer.GetFieldType(fieldName)              fieldType = self.layer.GetFieldType(fieldName)
905    
906            clazz = self.classGrid.GetTable().GetClassification()
907    
908            if copyClass:
909                clazz = copy.deepcopy(clazz)
910    
911          clazz.SetField(fieldName)          clazz.SetField(fieldName)
912          clazz.SetFieldType(fieldType)          clazz.SetFieldType(fieldType)
913    
914    
915          table = self.classGrid.GetTable()  #       table = self.classGrid.GetTable()
916          clazz.SetDefaultGroup(table.GetClassGroup(0))  #       clazz.SetDefaultGroup(table.GetClassGroup(0))
917    
918          for i in range(1, numRows):  #       for i in range(1, numRows):
919              clazz.AddGroup(table.GetClassGroup(i))  #           clazz.AppendGroup(table.GetClassGroup(i))
920    
921          return clazz          return clazz
922    
923      def __SetGridTable(self, fieldIndex):      def __SetGridTable(self, fieldIndex, group = None):
924    
925          clazz = self.fields.GetClientData(fieldIndex)          clazz = self.fields.GetClientData(fieldIndex)
926    
# Line 763  class Classifier(NonModalDialog): Line 935  class Classifier(NonModalDialog):
935              fieldType = self.layer.GetFieldType(fieldName)              fieldType = self.layer.GetFieldType(fieldName)
936              clazz.SetFieldType(fieldType)              clazz.SetFieldType(fieldType)
937                                    
938          self.classGrid.CreateTable(clazz, self.layer.ShapeType())          self.classGrid.CreateTable(clazz, self.layer.ShapeType(), group)
   
   
   
     type2string = {None:             _("None"),  
                    FIELDTYPE_STRING: _("Text"),  
                    FIELDTYPE_INT:    _("Integer"),  
                    FIELDTYPE_DOUBLE: _("Decimal")}  
939    
940      def __SetFieldTypeText(self, fieldIndex):      def __SetFieldTypeText(self, fieldIndex):
941          fieldName = self.fields.GetString(fieldIndex)          fieldName = self.fields.GetString(fieldIndex)
942          fieldType = self.layer.GetFieldType(fieldName)          fieldType = self.layer.GetFieldType(fieldName)
943    
944          assert(Classifier.type2string.has_key(fieldType))          assert Classifier.type2string.has_key(fieldType)
945    
946          text = Classifier.type2string[fieldType]          text = Classifier.type2string[fieldType]
947    
948          self.fieldTypeText.SetLabel(_("Field Type: %s") % text)          self.fieldTypeText.SetLabel(_("Data Type: %s") % text)
949    
950      def __SelectField(self, newIndex, oldIndex = -1):      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          assert(oldIndex >= -1)          assert oldIndex >= -1
956    
957          if oldIndex != -1:          if oldIndex != -1:
958              clazz = self.__BuildClassification(oldIndex)              clazz = self.__BuildClassification(oldIndex)
959              self.fields.SetClientData(oldIndex, clazz)              self.fields.SetClientData(oldIndex, clazz)
960    
961          self.__SetGridTable(newIndex)          self.__SetGridTable(newIndex, group)
962    
963          enabled = newIndex != 0          self.__EnableButtons(EB_SELECT_FIELD, newIndex != 0)
   
         for b in self.controlButtons:  
             b.Enable(enabled)  
964    
965          self.__SetFieldTypeText(newIndex)          self.__SetFieldTypeText(newIndex)
966    
967        def __SetTitle(self, title):
968            if title != "":
969                title = ": " + title
970    
971            self.SetTitle(_("Layer Properties") + title)
972    
973        def _OnEditSymbol(self, event):
974            sel = self.classGrid.GetCurrentSelection()
975    
976            if len(sel) == 1:
977                self.EditSymbol(sel[0])
978    
979      def _OnFieldSelect(self, event):      def _OnFieldSelect(self, event):
980          index = self.fields.GetSelection()          index = self.fields.GetSelection()
981          self.__SelectField(index, self.__cur_field)          self.__SelectField(index, self.__cur_field)
982          self.__cur_field = index          self.__cur_field = index
983    
984      def _OnApply(self, event):      def _OnTry(self, event):
985          """Put the data from the table into a new Classification and hand          """Put the data from the table into a new Classification and hand
986             it to the layer.             it to the layer.
987          """          """
# Line 817  class Classifier(NonModalDialog): Line 993  class Classifier(NonModalDialog):
993          # to begin with or it has been modified          # to begin with or it has been modified
994          #          #
995          if clazz is None or self.classGrid.GetTable().IsModified():          if clazz is None or self.classGrid.GetTable().IsModified():
996              clazz = self.__BuildClassification(self.__cur_field)              clazz = self.__BuildClassification(self.__cur_field, True)
997    
998          self.layer.SetClassification(clazz)          self.layer.SetClassification(clazz)
999    
1000            self.haveApplied = True
1001    
1002      def _OnOK(self, event):      def _OnOK(self, event):
1003          self._OnApply(event)          self._OnTry(event)
1004          self.OnClose(event)          self.Close()
1005    
1006      def _OnCancel(self, event):      def _OnCloseBtn(self, event):
1007            """Close is similar to Cancel except that any changes that were
1008            made and applied remain applied, but the currently displayed
1009            classification is discarded.
1010            """
1011    
1012            self.Close()
1013    
1014        def _OnRevert(self, event):
1015          """The layer's current classification stays the same."""          """The layer's current classification stays the same."""
1016          self.layer.SetClassification(self.originalClass)          if self.haveApplied:
1017          self.OnClose(event)              self.layer.SetClassification(self.originalClass)
1018    
1019            #self.Close()
1020    
1021      def _OnAdd(self, event):      def _OnAdd(self, event):
1022          self.classGrid.AppendRows()          self.classGrid.AppendRows()
# Line 836  class Classifier(NonModalDialog): Line 1024  class Classifier(NonModalDialog):
1024      def _OnRemove(self, event):      def _OnRemove(self, event):
1025          self.classGrid.DeleteSelectedRows()          self.classGrid.DeleteSelectedRows()
1026    
1027      def _OnGenRange(self, event):      def _OnGenClass(self, event):
1028          print "Classifier._OnGenRange()"  
1029            self.genDlg = ClassGenDialog(self, self.layer,
1030                              self.fields.GetString(self.__cur_field))
1031    
1032            EVT_CLOSE(self.genDlg, self._OnGenDialogClose)
1033    
1034            self.__EnableButtons(EB_GEN_CLASS, False)
1035    
1036            self.genDlg.Show()
1037    
1038        def _OnGenDialogClose(self, event):
1039            self.genDlg.Destroy()
1040            self.__EnableButtons(EB_GEN_CLASS, True)
1041    
1042      def _OnMoveUp(self, event):      def _OnMoveUp(self, event):
1043          sel = self.classGrid.GetCurrentSelection()          sel = self.classGrid.GetCurrentSelection()
# Line 852  class Classifier(NonModalDialog): Line 1052  class Classifier(NonModalDialog):
1052                  table.SetClassGroup(i, x)                  table.SetClassGroup(i, x)
1053                  self.classGrid.ClearSelection()                  self.classGrid.ClearSelection()
1054                  self.classGrid.SelectRow(i - 1)                  self.classGrid.SelectRow(i - 1)
1055                    self.classGrid.MakeCellVisible(i - 1, 0)
1056    
1057      def _OnMoveDown(self, event):      def _OnMoveDown(self, event):
1058          sel = self.classGrid.GetCurrentSelection()          sel = self.classGrid.GetCurrentSelection()
# Line 866  class Classifier(NonModalDialog): Line 1067  class Classifier(NonModalDialog):
1067                  table.SetClassGroup(i + 1, x)                  table.SetClassGroup(i + 1, x)
1068                  self.classGrid.ClearSelection()                  self.classGrid.ClearSelection()
1069                  self.classGrid.SelectRow(i + 1)                  self.classGrid.SelectRow(i + 1)
1070                    self.classGrid.MakeCellVisible(i + 1, 0)
1071    
1072        def _OnTitleChanged(self, event):
1073            obj = event.GetEventObject()
1074    
1075            self.layer.SetTitle(obj.GetValue())
1076            self.__SetTitle(self.layer.Title())
1077    
1078            self.__EnableButtons(EB_LAYER_TITLE, self.layer.Title() != "")
1079    
1080        def __EnableButtons(self, case, enable):
1081    
1082            if case == EB_LAYER_TITLE:  
1083                list = (ID_PROPERTY_OK,
1084                        ID_PROPERTY_CLOSE)
1085    
1086            elif case == EB_SELECT_FIELD:
1087                list = (ID_PROPERTY_GENCLASS,
1088                        ID_PROPERTY_ADD,
1089                        ID_PROPERTY_MOVEUP,
1090                        ID_PROPERTY_MOVEDOWN,
1091                        ID_PROPERTY_EDITSYM,
1092                        ID_PROPERTY_REMOVE)
1093    
1094            elif case == EB_GEN_CLASS:
1095                list = (ID_PROPERTY_SELECT,
1096                        ID_PROPERTY_FIELDTEXT,
1097                        ID_PROPERTY_GENCLASS,
1098                        ID_PROPERTY_EDITSYM)
1099    
1100            for id in list:
1101                self.FindWindowById(id).Enable(enable)
1102    
1103  ID_SELPROP_OK = 4001  ID_SELPROP_OK = 4001
1104  ID_SELPROP_CANCEL = 4002  ID_SELPROP_CANCEL = 4002
# Line 893  class SelectPropertiesDialog(wxDialog): Line 1125  class SelectPropertiesDialog(wxDialog):
1125          previewBox = wxBoxSizer(wxVERTICAL)          previewBox = wxBoxSizer(wxVERTICAL)
1126          previewBox.Add(wxStaticText(self, -1, _("Preview:")),          previewBox.Add(wxStaticText(self, -1, _("Preview:")),
1127              0, wxALIGN_LEFT | wxALL, 4)              0, wxALIGN_LEFT | wxALL, 4)
1128          self.previewer = ClassDataPreviewer(None, self.prop, shapeType,  
1129                                              self, ID_SELPROP_PREVIEW, (40, 40))          self.previewWin = ClassGroupPropertiesCtrl(
1130          previewBox.Add(self.previewer, 1, wxGROW, 15)              self, ID_SELPROP_PREVIEW, self.prop, shapeType,
1131                (40, 40), wxSIMPLE_BORDER)
1132    
1133            self.previewWin.AllowEdit(False)
1134    
1135            previewBox.Add(self.previewWin, 1, wxGROW | wxALL, 4)
1136    
1137          itemBox.Add(previewBox, 1, wxALIGN_LEFT | wxALL | wxGROW, 0)          itemBox.Add(previewBox, 1, wxALIGN_LEFT | wxALL | wxGROW, 0)
1138    
# Line 973  class SelectPropertiesDialog(wxDialog): Line 1210  class SelectPropertiesDialog(wxDialog):
1210    
1211      def _OnSpin(self, event):      def _OnSpin(self, event):
1212          self.prop.SetLineWidth(self.spinCtrl.GetValue())          self.prop.SetLineWidth(self.spinCtrl.GetValue())
1213          self.previewer.Refresh()          self.previewWin.Refresh()
1214    
1215      def __GetColor(self, cur):      def __GetColor(self, cur):
1216          dialog = wxColourDialog(self)          dialog = wxColourDialog(self)
1217          dialog.GetColourData().SetColour(Color2wxColour(cur))          if cur is not Color.Transparent:
1218                dialog.GetColourData().SetColour(Color2wxColour(cur))
1219    
1220          ret = None          ret = None
1221          if dialog.ShowModal() == wxID_OK:          if dialog.ShowModal() == wxID_OK:
1222              ret = wxColour2Color(dialog.GetColourData().GetColour())              ret = wxColour2Color(dialog.GetColourData().GetColour())
# Line 990  class SelectPropertiesDialog(wxDialog): Line 1229  class SelectPropertiesDialog(wxDialog):
1229          clr = self.__GetColor(self.prop.GetLineColor())          clr = self.__GetColor(self.prop.GetLineColor())
1230          if clr is not None:          if clr is not None:
1231              self.prop.SetLineColor(clr)              self.prop.SetLineColor(clr)
1232          self.previewer.Refresh() # XXX: work around, see ClassDataPreviewer          self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer
1233    
1234      def _OnChangeLineColorTrans(self, event):      def _OnChangeLineColorTrans(self, event):
1235          self.prop.SetLineColor(Color.None)          self.prop.SetLineColor(Color.Transparent)
1236          self.previewer.Refresh() # XXX: work around, see ClassDataPreviewer          self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer
1237                    
1238      def _OnChangeFillColor(self, event):      def _OnChangeFillColor(self, event):
1239          clr = self.__GetColor(self.prop.GetFill())          clr = self.__GetColor(self.prop.GetFill())
1240          if clr is not None:          if clr is not None:
1241              self.prop.SetFill(clr)              self.prop.SetFill(clr)
1242          self.previewer.Refresh() # XXX: work around, see ClassDataPreviewer          self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer
1243    
1244      def _OnChangeFillColorTrans(self, event):      def _OnChangeFillColorTrans(self, event):
1245          self.prop.SetFill(Color.None)          self.prop.SetFill(Color.Transparent)
1246          self.previewer.Refresh() # XXX: work around, see ClassDataPreviewer          self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer
1247    
1248      def GetClassGroupProperties(self):      def GetClassGroupProperties(self):
1249          return self.prop          return self.prop
1250    
1251    
1252  class ClassDataPreviewer(wxWindow):  class ClassDataPreviewWindow(wxWindow):
1253    
1254      def __init__(self, rect, prop, shapeType,      def __init__(self, rect, prop, shapeType,
1255                         parent = None, id = -1, size = wxDefaultSize):                         parent = None, id = -1, size = wxDefaultSize):
1256          if parent is not None:          if parent is not None:
1257              wxWindow.__init__(self, parent, id, size=size)              wxWindow.__init__(self, parent, id, (0, 0), size)
1258              EVT_PAINT(self, self._OnPaint)              EVT_PAINT(self, self._OnPaint)
1259    
1260          self.rect = rect          self.rect = rect
1261    
1262          self.prop = prop          self.prop = prop
1263          self.shapeType = shapeType          self.shapeType = shapeType
1264            self.previewer = ClassDataPreviewer()
1265    
1266        def GetProperties():
1267            return self.prop
1268    
1269      def _OnPaint(self, event):      def _OnPaint(self, event):
1270          dc = wxPaintDC(self)          dc = wxPaintDC(self)
# Line 1028  class ClassDataPreviewer(wxWindow): Line 1272  class ClassDataPreviewer(wxWindow):
1272          # XXX: this doesn't seem to be having an effect:          # XXX: this doesn't seem to be having an effect:
1273          dc.DestroyClippingRegion()          dc.DestroyClippingRegion()
1274    
1275          self.Draw(dc, None)          if self.rect is None:
1276                w, h = self.GetSize()
1277                rect = wxRect(0, 0, w, h)
1278            else:
1279                rect = self.rect
1280    
1281            self.previewer.Draw(dc, rect, self.prop, self.shapeType)
1282    
1283    class ClassDataPreviewer:
1284    
1285      def Draw(self, dc, rect, prop = None, shapeType = None):      def Draw(self, dc, rect, prop, shapeType):
1286    
1287          if prop is None: prop = self.prop          assert dc is not None
1288          if shapeType is None: shapeType = self.shapeType          assert isinstance(prop, ClassGroupProperties)
1289    
1290          if rect is None:          if rect is None:
1291              x = y = 0              x = 0
1292              w, h = self.GetClientSizeTuple()              y = 0
1293                w, h = dc.GetSize()
1294          else:          else:
1295              x = rect.GetX()              x = rect.GetX()
1296              y = rect.GetY()              y = rect.GetY()
# Line 1045  class ClassDataPreviewer(wxWindow): Line 1298  class ClassDataPreviewer(wxWindow):
1298              h = rect.GetHeight()              h = rect.GetHeight()
1299    
1300          stroke = prop.GetLineColor()          stroke = prop.GetLineColor()
1301          if stroke is Color.None:          if stroke is Color.Transparent:
1302              pen = wxTRANSPARENT_PEN              pen = wxTRANSPARENT_PEN
1303          else:          else:
1304              pen = wxPen(Color2wxColour(stroke),              pen = wxPen(Color2wxColour(stroke),
# Line 1053  class ClassDataPreviewer(wxWindow): Line 1306  class ClassDataPreviewer(wxWindow):
1306                          wxSOLID)                          wxSOLID)
1307    
1308          stroke = prop.GetFill()          stroke = prop.GetFill()
1309          if stroke is Color.None:          if stroke is Color.Transparent:
1310              brush = wxTRANSPARENT_BRUSH              brush = wxTRANSPARENT_BRUSH
1311          else:          else:
1312              brush = wxBrush(Color2wxColour(stroke), wxSOLID)              brush = wxBrush(Color2wxColour(stroke), wxSOLID)
# Line 1067  class ClassDataPreviewer(wxWindow): Line 1320  class ClassDataPreviewer(wxWindow):
1320                             wxPoint(x + w/2, y + h/4*3),                             wxPoint(x + w/2, y + h/4*3),
1321                             wxPoint(x + w, y)])                             wxPoint(x + w, y)])
1322    
1323          elif shapeType == SHAPETYPE_POINT or \          elif shapeType == SHAPETYPE_POINT:
              shapeType == SHAPETYPE_POLYGON:  
1324    
1325              dc.DrawCircle(x + w/2, y + h/2,              dc.DrawCircle(x + w/2, y + h/2,
1326                            (min(w, h) - prop.GetLineWidth())/2)                            (min(w, h) - prop.GetLineWidth())/2)
1327    
1328            elif shapeType == SHAPETYPE_POLYGON:
1329                dc.DrawRectangle(x, y, w, h)
1330    
1331  class ClassRenderer(wxPyGridCellRenderer):  class ClassRenderer(wxPyGridCellRenderer):
1332    
1333      def __init__(self, shapeType):      def __init__(self, shapeType):
1334          wxPyGridCellRenderer.__init__(self)          wxPyGridCellRenderer.__init__(self)
1335          self.previewer = ClassDataPreviewer(None, None, shapeType)          self.shapeType = shapeType
1336            self.previewer = ClassDataPreviewer()
1337    
1338      def Draw(self, grid, attr, dc, rect, row, col, isSelected):      def Draw(self, grid, attr, dc, rect, row, col, isSelected):
1339          data = grid.GetTable().GetClassGroup(row)          data = grid.GetTable().GetClassGroup(row)
# Line 1090  class ClassRenderer(wxPyGridCellRenderer Line 1346  class ClassRenderer(wxPyGridCellRenderer
1346                           rect.GetWidth(), rect.GetHeight())                           rect.GetWidth(), rect.GetHeight())
1347    
1348          if not isinstance(data, ClassGroupMap):          if not isinstance(data, ClassGroupMap):
1349              self.previewer.Draw(dc, rect, data.GetProperties())              self.previewer.Draw(dc, rect, data.GetProperties(), self.shapeType)
1350    
1351          if isSelected:          if isSelected:
1352              dc.SetPen(wxPen(wxColour(0 * 255, 0 * 255, 0 * 255),              dc.SetPen(wxPen(wxBLACK, 1, wxSOLID))
                       4, wxSOLID))  
1353              dc.SetBrush(wxTRANSPARENT_BRUSH)              dc.SetBrush(wxTRANSPARENT_BRUSH)
1354    
1355              dc.DrawRectangle(rect.GetX(), rect.GetY(),              dc.DrawRectangle(rect.GetX(), rect.GetY(),
1356                               rect.GetWidth(), rect.GetHeight())                               rect.GetWidth(), rect.GetHeight())
1357    
1358          dc.DestroyClippingRegion()          dc.DestroyClippingRegion()
1359    
1360    
1361    class ClassGroupPropertiesCtrl(wxWindow, wxControl):
1362    
1363        def __init__(self, parent, id, props, shapeType,
1364                     size = wxDefaultSize, style = 0):
1365    
1366            wxWindow.__init__(self, parent, id, size = size, style = style)
1367    
1368            self.SetProperties(props)
1369            self.SetShapeType(shapeType)
1370            self.AllowEdit(True)
1371    
1372            EVT_PAINT(self, self._OnPaint)
1373            EVT_LEFT_DCLICK(self, self._OnLeftDClick)
1374    
1375            self.previewer = ClassDataPreviewer()
1376    
1377        def _OnPaint(self, event):
1378            dc = wxPaintDC(self)
1379    
1380            # XXX: this doesn't seem to be having an effect:
1381            dc.DestroyClippingRegion()
1382    
1383            w, h = self.GetClientSize()
1384    
1385            self.previewer.Draw(dc,
1386                                wxRect(0, 0, w, h),
1387                                self.GetProperties(),
1388                                self.GetShapeType())
1389    
1390    
1391        def GetProperties(self):
1392            return self.props
1393    
1394        def SetProperties(self, props):
1395            self.props = props
1396            self.Refresh()
1397    
1398        def GetShapeType(self):
1399            return self.shapeType
1400    
1401        def SetShapeType(self, shapeType):
1402            self.shapeType = shapeType
1403            self.Refresh()
1404    
1405        def AllowEdit(self, allow):
1406            self.allowEdit = allow
1407    
1408        def DoEdit(self):
1409            if not self.allowEdit: return
1410    
1411            propDlg = SelectPropertiesDialog(NULL,
1412                                             self.GetProperties(),
1413                                             self.GetShapeType())
1414    
1415            if propDlg.ShowModal() == wxID_OK:
1416                new_prop = propDlg.GetClassGroupProperties()
1417                self.SetProperties(new_prop)
1418                self.Refresh()
1419    
1420            propDlg.Destroy()
1421    
1422        def _OnLeftDClick(self, event):
1423            self.DoEdit()

Legend:
Removed from v.513  
changed lines
  Added in v.782

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26