/[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 519 by jonathan, Tue Mar 11 22:27:35 2003 UTC revision 650 by jonathan, Fri Apr 11 14:27:41 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 300  class ClassTable(wxPyGridTableBase): Line 351  class ClassTable(wxPyGridTableBase):
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()              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                  conv = lambda p: int(float(p))                  conv = lambda p: int(float(p))
# Line 429  class ClassTable(wxPyGridTableBase): Line 500  class ClassTable(wxPyGridTableBase):
500    
501                  return (conv(Str2Num(value[:i])), conv(Str2Num(value[i+1:])))                  return (conv(Str2Num(value[:i])), conv(Str2Num(value[i+1:])))
502    
503          assert(False) # shouldn't get here          assert False  # shouldn't get here
504          return (0,)          return (0,)
505                            
506    
# Line 445  class ClassTable(wxPyGridTableBase): Line 516  class ClassTable(wxPyGridTableBase):
516          typeName -- unused, but needed to overload wxPyGridTableBase          typeName -- unused, but needed to overload wxPyGridTableBase
517          """          """
518    
519          assert(col >= 0 and col < self.GetNumberCols())          assert 0 <= col < self.GetNumberCols()
520          assert(row >= 0 and row < self.GetNumberRows())          assert 0 <= row < self.GetNumberRows()
521    
522          group = self.tdata[row]          if row == 0:
523                group = self.clazz.GetDefaultGroup()
524            else:
525                group = self.clazz.GetGroup(row - 1)
526    
527          mod = True # assume the data will change          mod = True # assume the data will change
528    
529          if col == COL_SYMBOL:          if col == COL_VISIBLE:
530                group.SetVisible(value)
531            elif col == COL_SYMBOL:
532              group.SetProperties(value)              group.SetProperties(value)
533          elif col == COL_LABEL:          elif col == COL_LABEL:
534              group.SetLabel(value)              group.SetLabel(value)
# Line 491  class ClassTable(wxPyGridTableBase): Line 567  class ClassTable(wxPyGridTableBase):
567                              changed = True                              changed = True
568                          ngroup.SetRange(dataInfo[0], dataInfo[1])                          ngroup.SetRange(dataInfo[0], dataInfo[1])
569                      else:                      else:
570                          assert(False)                          assert False
571                          pass                          pass
572    
573                      if changed:                      if changed:
574                          ngroup.SetLabel(group.GetLabel())                          ngroup.SetLabel(group.GetLabel())
575                          self.SetClassGroup(row, ngroup)                          self.SetClassGroup(row, ngroup)
576          else:          else:
577              assert(False) # shouldn't be here              assert False # shouldn't be here
578              pass              pass
579    
580          if mod:          if mod:
# Line 508  class ClassTable(wxPyGridTableBase): Line 584  class ClassTable(wxPyGridTableBase):
584      def GetAttr(self, row, col, someExtraParameter):      def GetAttr(self, row, col, someExtraParameter):
585          """Returns the cell attributes"""          """Returns the cell attributes"""
586    
587          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  
588    
589      def GetClassGroup(self, row):      def GetClassGroup(self, row):
590          """Return the ClassGroup object representing row 'row'."""          """Return the ClassGroup object representing row 'row'."""
591    
592          return self.tdata[row] # self.GetValueAsCustom(row, COL_SYMBOL, None)          #return self.GetValueAsCustom(row, COL_SYMBOL, None)
593            if row == 0:
594                return self.clazz.GetDefaultGroup()
595            else:
596                return self.clazz.GetGroup(row - 1)
597    
598      def SetClassGroup(self, row, group):      def SetClassGroup(self, row, group):
599          self.__SetRow(row, group)          self.__SetRow(row, group)
# Line 553  class ClassTable(wxPyGridTableBase): Line 624  class ClassTable(wxPyGridTableBase):
624          The table is considered modified if any rows are removed.          The table is considered modified if any rows are removed.
625          """          """
626    
627          assert(pos >= 0)          assert pos >= 0
628          old_len = len(self.tdata)          old_len = self.GetNumberRows()
629          for row in range(pos, pos - numRows, -1):          for row in range(pos, pos - numRows, -1):
630              group = self.GetClassGroup(row)              group = self.GetClassGroup(row)
631              if not isinstance(group, ClassGroupDefault):              if row != 0:
632                  self.tdata.pop(row)                  self.clazz.RemoveGroup(row - 1)
633                  self.__Modified()                  self.__Modified()
634            
635          if self.IsModified():          if self.IsModified():
636              self.__NotifyRowChanges(old_len, len(self.tdata))              self.__NotifyRowChanges(old_len, self.GetNumberRows())
637    
638      def AppendRows(self, numRows = 1):      def AppendRows(self, numRows = 1):
639          """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 641  class ClassTable(wxPyGridTableBase):
641          The table is considered modified if any rows are appended.          The table is considered modified if any rows are appended.
642          """          """
643    
644          old_len = len(self.tdata)          old_len = self.GetNumberRows()
645          for i in range(numRows):          for i in range(numRows):
646              np = ClassGroupSingleton()              np = ClassGroupSingleton()
647              self.__SetRow(-1, np)              self.__SetRow(None, np)
648    
649          if self.IsModified():          if self.IsModified():
650              self.__NotifyRowChanges(old_len, len(self.tdata))              self.__NotifyRowChanges(old_len, self.GetNumberRows())
651    
652    
653    ID_PROPERTY_OK = 4001
654    ID_PROPERTY_REVERT = 4002
655    ID_PROPERTY_ADD = 4003
656    ID_PROPERTY_GENCLASS = 4004
657    ID_PROPERTY_REMOVE = 4005
658    ID_PROPERTY_MOVEUP = 4006
659    ID_PROPERTY_MOVEDOWN = 4007
660    ID_PROPERTY_TRY = 4008
661    ID_PROPERTY_EDITSYM = 4009
662    ID_PROPERTY_CLOSE = 4010
663    ID_PROPERTY_SELECT = 4011
664    ID_PROPERTY_TITLE = 4012
665    ID_PROPERTY_FIELDTEXT = 4013
666    
667    BTN_ADD = 0
668    BTN_EDIT = 1
669    BTN_GEN = 2
670    BTN_UP = 3
671    BTN_DOWN = 4
672    BTN_RM = 5
673    
674    EB_LAYER_TITLE = 0
675    EB_SELECT_FIELD = 1
676    EB_GEN_CLASS = 2
677    
678  class Classifier(NonModalDialog):  class Classifier(NonModalDialog):
       
     def __init__(self, parent, interactor, name, layer):  
         NonModalDialog.__init__(self, parent, interactor, name,  
                                 _("Classifier: %s") % layer.Title())  
679    
680          panel = wxPanel(self, -1, size=(100, 100))      type2string = {None:             _("None"),
681                       FIELDTYPE_STRING: _("Text"),
682                       FIELDTYPE_INT:    _("Integer"),
683                       FIELDTYPE_DOUBLE: _("Decimal")}
684    
685        def __init__(self, parent, name, layer, group = None):
686            NonModalDialog.__init__(self, parent, name, "")
687    
688            self.__SetTitle(layer.Title())
689    
690          self.layer = layer          self.layer = layer
691    
# Line 593  class Classifier(NonModalDialog): Line 693  class Classifier(NonModalDialog):
693          field = self.originalClass.GetField()          field = self.originalClass.GetField()
694          fieldType = self.originalClass.GetFieldType()          fieldType = self.originalClass.GetFieldType()
695    
696            self.genDlg = None
697    
698          topBox = wxBoxSizer(wxVERTICAL)          topBox = wxBoxSizer(wxVERTICAL)
         panelBox = wxBoxSizer(wxVERTICAL)  
699    
700          #panelBox.Add(wxStaticText(panel, -1, _("Layer: %s") % layer.Title()),          sizer = wxBoxSizer(wxHORIZONTAL)
701              #0, wxALIGN_LEFT | wxALL, 4)          sizer.Add(wxStaticText(self, -1, _("Title: ")),
702          panelBox.Add(wxStaticText(panel, -1,              0, wxALIGN_LEFT | wxALL | wxALIGN_CENTER_VERTICAL, 4)
703                                  _("Layer Type: %s") % layer.ShapeType()),          sizer.Add(wxTextCtrl(self, ID_PROPERTY_TITLE, layer.Title()),
704                      1, wxGROW | wxALL, 4)
705            EVT_TEXT(self, ID_PROPERTY_TITLE, self._OnTitleChanged)
706    
707            topBox.Add(sizer, 0, wxGROW, 4)
708    
709            topBox.Add(wxStaticText(self, -1,
710                                    _("Type: %s") % layer.ShapeType()),
711              0, wxALIGN_LEFT | wxALL, 4)              0, wxALIGN_LEFT | wxALL, 4)
712    
713            panel = wxPanel(self, -1, size=(100, 100))
714    
715            #####################
716    
717            #panelBox = wxBoxSizer(wxVERTICAL)
718            panelBox = wxStaticBoxSizer(
719                        wxStaticBox(panel, -1, _("Classification")), wxVERTICAL)
720    
721    
722          #          #
723          # make field combo box          # make field combo box
# Line 615  class Classifier(NonModalDialog): Line 731  class Classifier(NonModalDialog):
731          self.__cur_field = 0          self.__cur_field = 0
732    
733          self.fields.Append("<None>")          self.fields.Append("<None>")
734          self.fields.SetClientData(0, None)  
735            if self.originalClass.GetFieldType() is None:
736                self.fields.SetClientData(0, copy.deepcopy(self.originalClass))
737            else:
738                self.fields.SetClientData(0, None)
739    
740          for i in range(self.num_cols):          for i in range(self.num_cols):
741              type, name, len, decc = layer.table.field_info(i)              type, name, len, decc = layer.table.field_info(i)
# Line 623  class Classifier(NonModalDialog): Line 743  class Classifier(NonModalDialog):
743    
744              if name == field:              if name == field:
745                  self.__cur_field = i + 1                  self.__cur_field = i + 1
746                  self.fields.SetClientData(i + 1, self.originalClass)                  self.fields.SetClientData(i + 1,
747                                              copy.deepcopy(self.originalClass))
748              else:              else:
749                  self.fields.SetClientData(i + 1, None)                  self.fields.SetClientData(i + 1, None)
750    
751    
752          ###########          ###########
753    
         self.fieldTypeText = wxStaticText(panel, -1, "")  
         panelBox.Add(self.fieldTypeText, 0, wxGROW | wxALIGN_LEFT | wxALL, 4)  
754    
755          propertyBox = wxBoxSizer(wxHORIZONTAL)          sizer = wxBoxSizer(wxHORIZONTAL)
756          propertyBox.Add(wxStaticText(panel, -1, _("Field: ")),          sizer.Add(wxStaticText(panel, ID_PROPERTY_FIELDTEXT, _("Field: ")),
757              0, wxALIGN_LEFT | wxALL, 4)              0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 4)
758          propertyBox.Add(self.fields, 1, wxGROW|wxALL, 4)          sizer.Add(self.fields, 1, wxGROW | wxALL, 4)
759          EVT_COMBOBOX(self, ID_PROPERTY_SELECT, self._OnFieldSelect)          EVT_COMBOBOX(self, ID_PROPERTY_SELECT, self._OnFieldSelect)
760    
761          panelBox.Add(propertyBox, 0, wxGROW, 4)          panelBox.Add(sizer, 0, wxGROW, 4)
762    
763            self.fieldTypeText = wxStaticText(panel, -1, "")
764            panelBox.Add(self.fieldTypeText, 0,
765                         wxGROW | wxALIGN_LEFT | wxALL | wxADJUST_MINSIZE, 4)
766    
767    
         ###########  
768          #          #
769          # Classification data table          # Control Box
770          #          #
   
771          controlBox = wxBoxSizer(wxHORIZONTAL)          controlBox = wxBoxSizer(wxHORIZONTAL)
772    
         self.classGrid = ClassGrid(panel)  
         self.__SetGridTable(self.__cur_field)  
   
         controlBox.Add(self.classGrid, 1, wxGROW, 0)  
773    
774          ###########          ###########
775          #          #
776          # Control buttons:          # Control buttons:
777          #          #
         self.controlButtons = []  
   
778          controlButtonBox = wxBoxSizer(wxVERTICAL)          controlButtonBox = wxBoxSizer(wxVERTICAL)
779    
780          button = wxButton(panel, ID_CLASSIFY_ADD, _("Add"))          button = wxButton(panel, ID_PROPERTY_GENCLASS, _("Generate Class"))
781          controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)          controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)
         self.controlButtons.append(button)  
782    
783          #button = wxButton(panel, ID_CLASSIFY_GENRANGE, _("Generate Ranges"))          button = wxButton(panel, ID_PROPERTY_ADD, _("Add"))
784          #controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)          controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)
785          #self.controlButtons.append(button)  
786            button = wxButton(panel, ID_PROPERTY_MOVEUP, _("Move Up"))
787            controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)
788    
789          button = wxButton(panel, ID_CLASSIFY_MOVEUP, _("Move Up"))          button = wxButton(panel, ID_PROPERTY_MOVEDOWN, _("Move Down"))
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_MOVEDOWN, _("Move Down"))          button = wxButton(panel, ID_PROPERTY_EDITSYM, _("Edit Symbol"))
793          controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)          controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)
         self.controlButtons.append(button)  
794    
795          controlButtonBox.Add(60, 20, 0, wxGROW | wxALL | wxALIGN_BOTTOM, 4)          controlButtonBox.Add(60, 20, 0, wxGROW | wxALL | wxALIGN_BOTTOM, 4)
796    
797          button = wxButton(panel, ID_CLASSIFY_REMOVE, _("Remove"))          button = wxButton(panel, ID_PROPERTY_REMOVE, _("Remove"))
798          controlButtonBox.Add(button, 0, wxGROW | wxALL | wxALIGN_BOTTOM, 4)          controlButtonBox.Add(button, 0, wxGROW | wxALL | wxALIGN_BOTTOM, 4)
799          self.controlButtons.append(button)  
800    
801            ###########
802            #
803            # Classification data table
804            #
805    
806            self.classGrid = ClassGrid(panel, self)
807    
808            # calling __SelectField after creating the classGrid fills in the
809            # grid with the correct information
810            self.fields.SetSelection(self.__cur_field)
811            self.__SelectField(self.__cur_field, group = group)
812    
813            controlBox.Add(self.classGrid, 1, wxGROW, 0)
814    
815          controlBox.Add(controlButtonBox, 0, wxGROW, 10)          controlBox.Add(controlButtonBox, 0, wxGROW, 10)
816          panelBox.Add(controlBox, 1, wxGROW, 10)          panelBox.Add(controlBox, 1, wxGROW, 10)
817    
818          EVT_BUTTON(self, ID_CLASSIFY_ADD, self._OnAdd)          EVT_BUTTON(self, ID_PROPERTY_ADD, self._OnAdd)
819          EVT_BUTTON(self, ID_CLASSIFY_REMOVE, self._OnRemove)          EVT_BUTTON(self, ID_PROPERTY_EDITSYM, self._OnEditSymbol)
820          EVT_BUTTON(self, ID_CLASSIFY_GENRANGE, self._OnGenRange)          EVT_BUTTON(self, ID_PROPERTY_REMOVE, self._OnRemove)
821          EVT_BUTTON(self, ID_CLASSIFY_MOVEUP, self._OnMoveUp)          EVT_BUTTON(self, ID_PROPERTY_GENCLASS, self._OnGenClass)
822          EVT_BUTTON(self, ID_CLASSIFY_MOVEDOWN, self._OnMoveDown)          EVT_BUTTON(self, ID_PROPERTY_MOVEUP, self._OnMoveUp)
823            EVT_BUTTON(self, ID_PROPERTY_MOVEDOWN, self._OnMoveDown)
824    
825            ###########
826    
827            panel.SetAutoLayout(True)
828            panel.SetSizer(panelBox)
829            panelBox.SetSizeHints(panel)
830    
831            topBox.Add(panel, 1, wxGROW | wxALL, 4)
832    
833          ###########          ###########
834    
835          buttonBox = wxBoxSizer(wxHORIZONTAL)          buttonBox = wxBoxSizer(wxHORIZONTAL)
836          buttonBox.Add(wxButton(panel, ID_CLASSIFY_OK, _("OK")),          buttonBox.Add(wxButton(self, ID_PROPERTY_TRY, _("Try")),
837                        0, wxALL, 4)                        0, wxALL, 4)
838          buttonBox.Add(60, 20, 0, wxALL, 4)          buttonBox.Add(60, 20, 0, wxALL, 4)
839          buttonBox.Add(wxButton(panel, ID_CLASSIFY_APPLY, _("Apply")),          buttonBox.Add(wxButton(self, ID_PROPERTY_REVERT, _("Revert")),
840                        0, wxALL, 4)                        0, wxALL, 4)
841          buttonBox.Add(60, 20, 0, wxALL, 4)          buttonBox.Add(60, 20, 0, wxALL, 4)
842          buttonBox.Add(wxButton(panel, ID_CLASSIFY_CANCEL, _("Cancel")),          buttonBox.Add(wxButton(self, ID_PROPERTY_OK, _("OK")),
843                        0, wxALL, 4)                        0, wxALL, 4)
844          panelBox.Add(buttonBox, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_BOTTOM, 0)          buttonBox.Add(60, 20, 0, wxALL, 4)
845            buttonBox.Add(wxButton(self, ID_PROPERTY_CLOSE, _("Close")),
846                          0, wxALL, 4)
847            topBox.Add(buttonBox, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_BOTTOM, 0)
848    
849          EVT_BUTTON(self, ID_CLASSIFY_OK, self._OnOK)          EVT_BUTTON(self, ID_PROPERTY_OK, self._OnOK)
850          EVT_BUTTON(self, ID_CLASSIFY_APPLY, self._OnApply)          EVT_BUTTON(self, ID_PROPERTY_TRY, self._OnTry)
851          EVT_BUTTON(self, ID_CLASSIFY_CANCEL, self._OnCancel)          EVT_BUTTON(self, ID_PROPERTY_CLOSE, self._OnCloseBtn)
852            EVT_BUTTON(self, ID_PROPERTY_REVERT, self._OnRevert)
853    
854          ###########          ###########
855    
856          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)  
857          self.SetAutoLayout(True)          self.SetAutoLayout(True)
858          self.SetSizer(topBox)          self.SetSizer(topBox)
859    
860      def __BuildClassification(self, fieldIndex):          #self.Fit()
861            ######################
862    
863            self.haveApplied = False
864    
865          numRows = self.classGrid.GetNumberRows()      def EditSymbol(self, row):
866          assert(numRows > 0) # there should always be a default row          table = self.classGrid.GetTable()
867            prop = table.GetValueAsCustom(row, COL_SYMBOL, None)
868    
869          clazz = Classification()          # get a new ClassGroupProperties object and copy the
870            # values over to our current object
871            propDlg = SelectPropertiesDialog(NULL, prop, self.layer.ShapeType())
872    
873            self.Enable(False)
874            if propDlg.ShowModal() == wxID_OK:
875                new_prop = propDlg.GetClassGroupProperties()
876                table.SetValueAsCustom(row, COL_SYMBOL, None, new_prop)
877            self.Enable(True)
878            propDlg.Destroy()
879            
880        def _SetClassification(self, clazz):
881            
882            self.fields.SetClientData(self.__cur_field, clazz)
883            self.classGrid.GetTable().SetClassification(clazz)
884    
885        def __BuildClassification(self, fieldIndex, copyClass = False):
886    
887    #       numRows = self.classGrid.GetNumberRows()
888    #       assert numRows > 0  # there should always be a default row
889    
890    #       clazz = Classification()
891          if fieldIndex == 0:          if fieldIndex == 0:
892              fieldName = None              fieldName = None
893              fieldType = None              fieldType = None
# Line 736  class Classifier(NonModalDialog): Line 895  class Classifier(NonModalDialog):
895              fieldName = self.fields.GetString(fieldIndex)              fieldName = self.fields.GetString(fieldIndex)
896              fieldType = self.layer.GetFieldType(fieldName)              fieldType = self.layer.GetFieldType(fieldName)
897    
898            clazz = self.classGrid.GetTable().GetClassification()
899    
900            if copyClass:
901                clazz = copy.deepcopy(clazz)
902    
903          clazz.SetField(fieldName)          clazz.SetField(fieldName)
904          clazz.SetFieldType(fieldType)          clazz.SetFieldType(fieldType)
905    
906    
907          table = self.classGrid.GetTable()  #       table = self.classGrid.GetTable()
908          clazz.SetDefaultGroup(table.GetClassGroup(0))  #       clazz.SetDefaultGroup(table.GetClassGroup(0))
909    
910          for i in range(1, numRows):  #       for i in range(1, numRows):
911              clazz.AddGroup(table.GetClassGroup(i))  #           clazz.AppendGroup(table.GetClassGroup(i))
912    
913          return clazz          return clazz
914    
915      def __SetGridTable(self, fieldIndex):      def __SetGridTable(self, fieldIndex, group = None):
916    
917          clazz = self.fields.GetClientData(fieldIndex)          clazz = self.fields.GetClientData(fieldIndex)
918    
# Line 763  class Classifier(NonModalDialog): Line 927  class Classifier(NonModalDialog):
927              fieldType = self.layer.GetFieldType(fieldName)              fieldType = self.layer.GetFieldType(fieldName)
928              clazz.SetFieldType(fieldType)              clazz.SetFieldType(fieldType)
929                                    
930          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")}  
931    
932      def __SetFieldTypeText(self, fieldIndex):      def __SetFieldTypeText(self, fieldIndex):
933          fieldName = self.fields.GetString(fieldIndex)          fieldName = self.fields.GetString(fieldIndex)
934          fieldType = self.layer.GetFieldType(fieldName)          fieldType = self.layer.GetFieldType(fieldName)
935    
936          assert(Classifier.type2string.has_key(fieldType))          assert Classifier.type2string.has_key(fieldType)
937    
938          text = Classifier.type2string[fieldType]          text = Classifier.type2string[fieldType]
939    
940          self.fieldTypeText.SetLabel(_("Field Type: %s") % text)          self.fieldTypeText.SetLabel(_("Data Type: %s") % text)
941    
942      def __SelectField(self, newIndex, oldIndex = -1):      def __SelectField(self, newIndex, oldIndex = -1, group = None):
943            """This method assumes that the current selection for the
944            combo has already been set by a call to SetSelection().
945            """
946    
947          assert(oldIndex >= -1)          assert oldIndex >= -1
948    
949          if oldIndex != -1:          if oldIndex != -1:
950              clazz = self.__BuildClassification(oldIndex)              clazz = self.__BuildClassification(oldIndex)
951              self.fields.SetClientData(oldIndex, clazz)              self.fields.SetClientData(oldIndex, clazz)
952    
953          self.__SetGridTable(newIndex)          self.__SetGridTable(newIndex, group)
   
         enabled = newIndex != 0  
954    
955          for b in self.controlButtons:          self.__EnableButtons(EB_SELECT_FIELD, newIndex != 0)
             b.Enable(enabled)  
956    
957          self.__SetFieldTypeText(newIndex)          self.__SetFieldTypeText(newIndex)
958    
959        def __SetTitle(self, title):
960            if title != "":
961                title = ": " + title
962    
963            self.SetTitle(_("Layer Properties") + title)
964    
965        def _OnEditSymbol(self, event):
966            sel = self.classGrid.GetCurrentSelection()
967    
968            if len(sel) == 1:
969                self.EditSymbol(sel[0])
970    
971      def _OnFieldSelect(self, event):      def _OnFieldSelect(self, event):
972          index = self.fields.GetSelection()          index = self.fields.GetSelection()
973          self.__SelectField(index, self.__cur_field)          self.__SelectField(index, self.__cur_field)
974          self.__cur_field = index          self.__cur_field = index
975    
976      def _OnApply(self, event):      def _OnTry(self, event):
977          """Put the data from the table into a new Classification and hand          """Put the data from the table into a new Classification and hand
978             it to the layer.             it to the layer.
979          """          """
# Line 817  class Classifier(NonModalDialog): Line 985  class Classifier(NonModalDialog):
985          # to begin with or it has been modified          # to begin with or it has been modified
986          #          #
987          if clazz is None or self.classGrid.GetTable().IsModified():          if clazz is None or self.classGrid.GetTable().IsModified():
988              clazz = self.__BuildClassification(self.__cur_field)              clazz = self.__BuildClassification(self.__cur_field, True)
989    
990          self.layer.SetClassification(clazz)          self.layer.SetClassification(clazz)
991    
992            self.haveApplied = True
993    
994      def _OnOK(self, event):      def _OnOK(self, event):
995          self._OnApply(event)          self._OnTry(event)
996          self.OnClose(event)          self.Close()
997    
998      def _OnCancel(self, event):      def _OnCloseBtn(self, event):
999            """Close is similar to Cancel except that any changes that were
1000            made and applied remain applied, but the currently displayed
1001            classification is discarded.
1002            """
1003    
1004            self.Close()
1005    
1006        def _OnRevert(self, event):
1007          """The layer's current classification stays the same."""          """The layer's current classification stays the same."""
1008          self.layer.SetClassification(self.originalClass)          if self.haveApplied:
1009          self.OnClose(event)              self.layer.SetClassification(self.originalClass)
1010    
1011            #self.Close()
1012    
1013      def _OnAdd(self, event):      def _OnAdd(self, event):
1014          self.classGrid.AppendRows()          self.classGrid.AppendRows()
# Line 836  class Classifier(NonModalDialog): Line 1016  class Classifier(NonModalDialog):
1016      def _OnRemove(self, event):      def _OnRemove(self, event):
1017          self.classGrid.DeleteSelectedRows()          self.classGrid.DeleteSelectedRows()
1018    
1019      def _OnGenRange(self, event):      def _OnGenClass(self, event):
1020          print "Classifier._OnGenRange()"  
1021            self.genDlg = ClassGenDialog(self, self.layer,
1022                              self.fields.GetString(self.__cur_field))
1023    
1024            EVT_CLOSE(self.genDlg, self._OnGenDialogClose)
1025    
1026            self.__EnableButtons(EB_GEN_CLASS, False)
1027    
1028            self.genDlg.Show()
1029    
1030        def _OnGenDialogClose(self, event):
1031            self.genDlg.Destroy()
1032            self.__EnableButtons(EB_GEN_CLASS, True)
1033    
1034      def _OnMoveUp(self, event):      def _OnMoveUp(self, event):
1035          sel = self.classGrid.GetCurrentSelection()          sel = self.classGrid.GetCurrentSelection()
# Line 852  class Classifier(NonModalDialog): Line 1044  class Classifier(NonModalDialog):
1044                  table.SetClassGroup(i, x)                  table.SetClassGroup(i, x)
1045                  self.classGrid.ClearSelection()                  self.classGrid.ClearSelection()
1046                  self.classGrid.SelectRow(i - 1)                  self.classGrid.SelectRow(i - 1)
1047                    self.classGrid.MakeCellVisible(i - 1, 0)
1048    
1049      def _OnMoveDown(self, event):      def _OnMoveDown(self, event):
1050          sel = self.classGrid.GetCurrentSelection()          sel = self.classGrid.GetCurrentSelection()
# Line 866  class Classifier(NonModalDialog): Line 1059  class Classifier(NonModalDialog):
1059                  table.SetClassGroup(i + 1, x)                  table.SetClassGroup(i + 1, x)
1060                  self.classGrid.ClearSelection()                  self.classGrid.ClearSelection()
1061                  self.classGrid.SelectRow(i + 1)                  self.classGrid.SelectRow(i + 1)
1062                    self.classGrid.MakeCellVisible(i + 1, 0)
1063    
1064        def _OnTitleChanged(self, event):
1065            obj = event.GetEventObject()
1066    
1067            self.layer.SetTitle(obj.GetValue())
1068            self.__SetTitle(self.layer.Title())
1069    
1070            self.__EnableButtons(EB_LAYER_TITLE, self.layer.Title() != "")
1071    
1072        def __EnableButtons(self, case, enable):
1073    
1074            if case == EB_LAYER_TITLE:  
1075                list = (ID_PROPERTY_OK,
1076                        ID_PROPERTY_CLOSE)
1077    
1078            elif case == EB_SELECT_FIELD:
1079                list = (ID_PROPERTY_GENCLASS,
1080                        ID_PROPERTY_ADD,
1081                        ID_PROPERTY_MOVEUP,
1082                        ID_PROPERTY_MOVEDOWN,
1083                        ID_PROPERTY_EDITSYM,
1084                        ID_PROPERTY_REMOVE)
1085    
1086            elif case == EB_GEN_CLASS:
1087                list = (ID_PROPERTY_SELECT,
1088                        ID_PROPERTY_FIELDTEXT,
1089                        ID_PROPERTY_GENCLASS,
1090                        ID_PROPERTY_EDITSYM)
1091    
1092            for id in list:
1093                self.FindWindowById(id).Enable(enable)
1094    
1095  ID_SELPROP_OK = 4001  ID_SELPROP_OK = 4001
1096  ID_SELPROP_CANCEL = 4002  ID_SELPROP_CANCEL = 4002
# Line 893  class SelectPropertiesDialog(wxDialog): Line 1117  class SelectPropertiesDialog(wxDialog):
1117          previewBox = wxBoxSizer(wxVERTICAL)          previewBox = wxBoxSizer(wxVERTICAL)
1118          previewBox.Add(wxStaticText(self, -1, _("Preview:")),          previewBox.Add(wxStaticText(self, -1, _("Preview:")),
1119              0, wxALIGN_LEFT | wxALL, 4)              0, wxALIGN_LEFT | wxALL, 4)
1120          self.previewer = ClassDataPreviewer(None, self.prop, shapeType,  
1121                                              self, ID_SELPROP_PREVIEW, (40, 40))          self.previewWin = ClassGroupPropertiesCtrl(
1122          previewBox.Add(self.previewer, 1, wxGROW, 15)              self, ID_SELPROP_PREVIEW, self.prop, shapeType,
1123                (40, 40), wxSIMPLE_BORDER)
1124    
1125            self.previewWin.AllowEdit(False)
1126    
1127            previewBox.Add(self.previewWin, 1, wxGROW | wxALL, 4)
1128    
1129          itemBox.Add(previewBox, 1, wxALIGN_LEFT | wxALL | wxGROW, 0)          itemBox.Add(previewBox, 1, wxALIGN_LEFT | wxALL | wxGROW, 0)
1130    
# Line 973  class SelectPropertiesDialog(wxDialog): Line 1202  class SelectPropertiesDialog(wxDialog):
1202    
1203      def _OnSpin(self, event):      def _OnSpin(self, event):
1204          self.prop.SetLineWidth(self.spinCtrl.GetValue())          self.prop.SetLineWidth(self.spinCtrl.GetValue())
1205          self.previewer.Refresh()          self.previewWin.Refresh()
1206    
1207      def __GetColor(self, cur):      def __GetColor(self, cur):
1208          dialog = wxColourDialog(self)          dialog = wxColourDialog(self)
1209          dialog.GetColourData().SetColour(Color2wxColour(cur))          if cur is not Color.Transparent:
1210                dialog.GetColourData().SetColour(Color2wxColour(cur))
1211    
1212          ret = None          ret = None
1213          if dialog.ShowModal() == wxID_OK:          if dialog.ShowModal() == wxID_OK:
1214              ret = wxColour2Color(dialog.GetColourData().GetColour())              ret = wxColour2Color(dialog.GetColourData().GetColour())
# Line 990  class SelectPropertiesDialog(wxDialog): Line 1221  class SelectPropertiesDialog(wxDialog):
1221          clr = self.__GetColor(self.prop.GetLineColor())          clr = self.__GetColor(self.prop.GetLineColor())
1222          if clr is not None:          if clr is not None:
1223              self.prop.SetLineColor(clr)              self.prop.SetLineColor(clr)
1224          self.previewer.Refresh() # XXX: work around, see ClassDataPreviewer          self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer
1225    
1226      def _OnChangeLineColorTrans(self, event):      def _OnChangeLineColorTrans(self, event):
1227          self.prop.SetLineColor(Color.None)          self.prop.SetLineColor(Color.Transparent)
1228          self.previewer.Refresh() # XXX: work around, see ClassDataPreviewer          self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer
1229                    
1230      def _OnChangeFillColor(self, event):      def _OnChangeFillColor(self, event):
1231          clr = self.__GetColor(self.prop.GetFill())          clr = self.__GetColor(self.prop.GetFill())
1232          if clr is not None:          if clr is not None:
1233              self.prop.SetFill(clr)              self.prop.SetFill(clr)
1234          self.previewer.Refresh() # XXX: work around, see ClassDataPreviewer          self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer
1235    
1236      def _OnChangeFillColorTrans(self, event):      def _OnChangeFillColorTrans(self, event):
1237          self.prop.SetFill(Color.None)          self.prop.SetFill(Color.Transparent)
1238          self.previewer.Refresh() # XXX: work around, see ClassDataPreviewer          self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer
1239    
1240      def GetClassGroupProperties(self):      def GetClassGroupProperties(self):
1241          return self.prop          return self.prop
1242    
1243    
1244  class ClassDataPreviewer(wxWindow):  class ClassDataPreviewWindow(wxWindow):
1245    
1246      def __init__(self, rect, prop, shapeType,      def __init__(self, rect, prop, shapeType,
1247                         parent = None, id = -1, size = wxDefaultSize):                         parent = None, id = -1, size = wxDefaultSize):
1248          if parent is not None:          if parent is not None:
1249              wxWindow.__init__(self, parent, id, size=size)              wxWindow.__init__(self, parent, id, (0, 0), size)
1250              EVT_PAINT(self, self._OnPaint)              EVT_PAINT(self, self._OnPaint)
1251    
1252          self.rect = rect          self.rect = rect
1253    
1254          self.prop = prop          self.prop = prop
1255          self.shapeType = shapeType          self.shapeType = shapeType
1256            self.previewer = ClassDataPreviewer()
1257    
1258        def GetProperties():
1259            return self.prop
1260    
1261      def _OnPaint(self, event):      def _OnPaint(self, event):
1262          dc = wxPaintDC(self)          dc = wxPaintDC(self)
# Line 1028  class ClassDataPreviewer(wxWindow): Line 1264  class ClassDataPreviewer(wxWindow):
1264          # XXX: this doesn't seem to be having an effect:          # XXX: this doesn't seem to be having an effect:
1265          dc.DestroyClippingRegion()          dc.DestroyClippingRegion()
1266    
1267          self.Draw(dc, None)          if self.rect is None:
1268                w, h = self.GetSize()
1269                rect = wxRect(0, 0, w, h)
1270            else:
1271                rect = self.rect
1272    
1273            self.previewer.Draw(dc, rect, self.prop, self.shapeType)
1274    
1275      def Draw(self, dc, rect, prop = None, shapeType = None):  class ClassDataPreviewer:
1276    
1277          if prop is None: prop = self.prop      def Draw(self, dc, rect, prop, shapeType):
1278          if shapeType is None: shapeType = self.shapeType  
1279            assert dc is not None
1280            assert isinstance(prop, ClassGroupProperties)
1281    
1282          if rect is None:          if rect is None:
1283              x = y = 0              x = 0
1284              w, h = self.GetClientSizeTuple()              y = 0
1285                w, h = dc.GetSize()
1286          else:          else:
1287              x = rect.GetX()              x = rect.GetX()
1288              y = rect.GetY()              y = rect.GetY()
# Line 1045  class ClassDataPreviewer(wxWindow): Line 1290  class ClassDataPreviewer(wxWindow):
1290              h = rect.GetHeight()              h = rect.GetHeight()
1291    
1292          stroke = prop.GetLineColor()          stroke = prop.GetLineColor()
1293          if stroke is Color.None:          if stroke is Color.Transparent:
1294              pen = wxTRANSPARENT_PEN              pen = wxTRANSPARENT_PEN
1295          else:          else:
1296              pen = wxPen(Color2wxColour(stroke),              pen = wxPen(Color2wxColour(stroke),
# Line 1053  class ClassDataPreviewer(wxWindow): Line 1298  class ClassDataPreviewer(wxWindow):
1298                          wxSOLID)                          wxSOLID)
1299    
1300          stroke = prop.GetFill()          stroke = prop.GetFill()
1301          if stroke is Color.None:          if stroke is Color.Transparent:
1302              brush = wxTRANSPARENT_BRUSH              brush = wxTRANSPARENT_BRUSH
1303          else:          else:
1304              brush = wxBrush(Color2wxColour(stroke), wxSOLID)              brush = wxBrush(Color2wxColour(stroke), wxSOLID)
# Line 1067  class ClassDataPreviewer(wxWindow): Line 1312  class ClassDataPreviewer(wxWindow):
1312                             wxPoint(x + w/2, y + h/4*3),                             wxPoint(x + w/2, y + h/4*3),
1313                             wxPoint(x + w, y)])                             wxPoint(x + w, y)])
1314    
1315          elif shapeType == SHAPETYPE_POINT or \          elif shapeType == SHAPETYPE_POINT:
              shapeType == SHAPETYPE_POLYGON:  
1316    
1317              dc.DrawCircle(x + w/2, y + h/2,              dc.DrawCircle(x + w/2, y + h/2,
1318                            (min(w, h) - prop.GetLineWidth())/2)                            (min(w, h) - prop.GetLineWidth())/2)
1319    
1320            elif shapeType == SHAPETYPE_POLYGON:
1321                dc.DrawRectangle(x, y, w, h)
1322    
1323  class ClassRenderer(wxPyGridCellRenderer):  class ClassRenderer(wxPyGridCellRenderer):
1324    
1325      def __init__(self, shapeType):      def __init__(self, shapeType):
1326          wxPyGridCellRenderer.__init__(self)          wxPyGridCellRenderer.__init__(self)
1327          self.previewer = ClassDataPreviewer(None, None, shapeType)          self.shapeType = shapeType
1328            self.previewer = ClassDataPreviewer()
1329    
1330      def Draw(self, grid, attr, dc, rect, row, col, isSelected):      def Draw(self, grid, attr, dc, rect, row, col, isSelected):
1331          data = grid.GetTable().GetClassGroup(row)          data = grid.GetTable().GetClassGroup(row)
# Line 1090  class ClassRenderer(wxPyGridCellRenderer Line 1338  class ClassRenderer(wxPyGridCellRenderer
1338                           rect.GetWidth(), rect.GetHeight())                           rect.GetWidth(), rect.GetHeight())
1339    
1340          if not isinstance(data, ClassGroupMap):          if not isinstance(data, ClassGroupMap):
1341              self.previewer.Draw(dc, rect, data.GetProperties())              self.previewer.Draw(dc, rect, data.GetProperties(), self.shapeType)
1342    
1343          if isSelected:          if isSelected:
1344              dc.SetPen(wxPen(wxColour(0 * 255, 0 * 255, 0 * 255),              dc.SetPen(wxPen(wxBLACK, 1, wxSOLID))
                       4, wxSOLID))  
1345              dc.SetBrush(wxTRANSPARENT_BRUSH)              dc.SetBrush(wxTRANSPARENT_BRUSH)
1346    
1347              dc.DrawRectangle(rect.GetX(), rect.GetY(),              dc.DrawRectangle(rect.GetX(), rect.GetY(),
1348                               rect.GetWidth(), rect.GetHeight())                               rect.GetWidth(), rect.GetHeight())
1349    
1350          dc.DestroyClippingRegion()          dc.DestroyClippingRegion()
1351    
1352    
1353    class ClassGroupPropertiesCtrl(wxWindow, wxControl):
1354    
1355        def __init__(self, parent, id, props, shapeType,
1356                     size = wxDefaultSize, style = 0):
1357    
1358            wxWindow.__init__(self, parent, id, size = size, style = style)
1359    
1360            self.SetProperties(props)
1361            self.SetShapeType(shapeType)
1362            self.AllowEdit(True)
1363    
1364            EVT_PAINT(self, self._OnPaint)
1365            EVT_LEFT_DCLICK(self, self._OnLeftDClick)
1366    
1367            self.previewer = ClassDataPreviewer()
1368    
1369        def _OnPaint(self, event):
1370            dc = wxPaintDC(self)
1371    
1372            # XXX: this doesn't seem to be having an effect:
1373            dc.DestroyClippingRegion()
1374    
1375            w, h = self.GetClientSize()
1376    
1377            self.previewer.Draw(dc,
1378                                wxRect(0, 0, w, h),
1379                                self.GetProperties(),
1380                                self.GetShapeType())
1381    
1382    
1383        def GetProperties(self):
1384            return self.props
1385    
1386        def SetProperties(self, props):
1387            self.props = props
1388            self.Refresh()
1389    
1390        def GetShapeType(self):
1391            return self.shapeType
1392    
1393        def SetShapeType(self, shapeType):
1394            self.shapeType = shapeType
1395            self.Refresh()
1396    
1397        def AllowEdit(self, allow):
1398            self.allowEdit = allow
1399    
1400        def DoEdit(self):
1401            if not self.allowEdit: return
1402    
1403            propDlg = SelectPropertiesDialog(NULL,
1404                                             self.GetProperties(),
1405                                             self.GetShapeType())
1406    
1407            if propDlg.ShowModal() == wxID_OK:
1408                new_prop = propDlg.GetClassGroupProperties()
1409                self.SetProperties(new_prop)
1410                self.Refresh()
1411    
1412            propDlg.Destroy()
1413    
1414        def _OnLeftDClick(self, event):
1415            self.DoEdit()

Legend:
Removed from v.519  
changed lines
  Added in v.650

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26