/[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 476 by bh, Thu Mar 6 15:03:37 2003 UTC revision 712 by jonathan, Wed Apr 23 08:46:40 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  # widget id's  from Thuban.UI.classgen import ClassGenDialog, ClassGenerator
31  ID_PROPERTY_SELECT = 4010  
32    from dialogs import NonModalDialog
33    
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  
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 56  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 65  class ClassGrid(wxGrid): Line 63  class ClassGrid(wxGrid):
63                   use for display.                   use for display.
64          """          """
65    
66          wxGrid.__init__(self, parent, ID_CLASS_TABLE, size = (340, 160))          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              self.SetTable(ClassTable(clazz, self.shapeType, self), true)              w = self.GetDefaultColSize() * NUM_COLS \
89          else:                  + self.GetDefaultRowLabelSize()
90              table.Reset(clazz, self.shapeType)              h = self.GetDefaultRowSize() * 4 \
91                    + self.GetDefaultColLabelSize()
92    
93                self.SetDimensions(-1, -1, w, h)
94                self.SetSizeHints(w, h, -1, -1)
95                table = ClassTable(self)
96                self.SetTable(table, True)
97    
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 95  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 128  class ClassGrid(wxGrid): Line 144  class ClassGrid(wxGrid):
144          # if only one thing is selected check if it is the default          # if only one thing is selected check if it is the default
145          # data row, because we can't remove that          # data row, because we can't remove that
146          if len(sel) == 1:          if len(sel) == 1:
147              group = self.GetTable().GetValueAsCustom(sel[0], COL_SYMBOL, None)              #group = self.GetTable().GetValueAsCustom(sel[0], COL_SYMBOL, None)
148                group = self.GetTable().GetClassGroup(sel[0])
149              if isinstance(group, ClassGroupDefault):              if isinstance(group, ClassGroupDefault):
150                  wxMessageDialog(self,                  wxMessageDialog(self,
151                                  "The Default group cannot be removed.",                                  "The Default group cannot be removed.",
# Line 160  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 172  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:  
             group = 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.Refresh()  
             propDlg.Destroy()  
219    
220      #      #
221      # _OnSelectedRange() and _OnSelectedCell() were borrowed      # _OnSelectedRange() and _OnSelectedCell() were borrowed
# Line 214  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 230  class ClassTable(wxPyGridTableBase): Line 261  class ClassTable(wxPyGridTableBase):
261          """          """
262    
263          wxPyGridTableBase.__init__(self)          wxPyGridTableBase.__init__(self)
         self.SetView(view)  
         self.tdata = []  
264    
265          self.Reset(clazz, shapeType)          assert len(ClassTable.__col_labels) == NUM_COLS
266    
267      def Reset(self, clazz, shapeType):          self.clazz = None
268            self.__colAttr = {}
269    
270            self.SetView(view)
271    
272        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 249  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.clazz = clazz          self.fieldType = clazz.GetFieldType()
291          self.shapeType = shapeType          self.shapeType = shapeType
         self.renderer = ClassRenderer(self.shapeType)  
292    
293          old_len = len(self.tdata)          self.SetClassification(clazz, group)
294            self.__Modified(-1)
295    
296          self.tdata = []          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            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 self.clazz:          if row > -1:
330              np = copy.copy(p)              self.GetView().ClearSelection()
331              self.__SetRow(-1, np)              self.GetView().SelectRow(row)
332                self.GetView().MakeCellVisible(row, 0)
333    
334            self.__Modified()
335    
   
         self.__Modified(False)  
336    
         self.__NotifyRowChanges(old_len, len(self.tdata))  
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 285  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()
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()
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          row -- if row is -1 or greater than the current number of rows          The table is considered modified after this operation.
364                 then group is appended to the end.  
365            row -- if row is < 0 'group' is inserted at the top of the table
366                   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 314  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 347  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 356  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              return group.GetProperties()
449    
450          if col == COL_LABEL:          if col == COL_LABEL:
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 385  class ClassTable(wxPyGridTableBase): Line 471  class ClassTable(wxPyGridTableBase):
471          value, or of length two if it is a range.          value, or of length two if it is a range.
472          """          """
473    
474          type = self.clazz.GetFieldType()          type = self.fieldType
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 414  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,)
505                            
506    
507      def SetValueAsCustom(self, row, col, typeName, value):      def SetValueAsCustom(self, row, col, typeName, value):
# Line 429  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 = False          mod = True # assume the data will change
528    
529          if col == COL_SYMBOL:          if col == COL_VISIBLE:
530              self.__SetRow(row, value)              group.SetVisible(value)
531              mod = True          elif col == COL_SYMBOL:
532                group.SetProperties(value)
533            elif col == COL_LABEL:
534                group.SetLabel(value)
535          elif col == COL_VALUE:          elif col == COL_VALUE:
536              if isinstance(group, ClassGroupDefault):              if isinstance(group, ClassGroupDefault):
537                  # not allowed to modify the default value                  # not allowed to modify the default value
# Line 451  class ClassTable(wxPyGridTableBase): Line 544  class ClassTable(wxPyGridTableBase):
544                      dataInfo = self.__ParseInput(value)                      dataInfo = self.__ParseInput(value)
545                  except ValueError:                  except ValueError:
546                      # bad input, ignore the request                      # bad input, ignore the request
547                      pass                      mod = False
548                  else:                  else:
549    
550                        changed = False
551                      ngroup = group                      ngroup = group
552                      props = group.GetProperties()                      props = group.GetProperties()
553    
# Line 465  class ClassTable(wxPyGridTableBase): Line 559  class ClassTable(wxPyGridTableBase):
559                      if len(dataInfo) == 1:                      if len(dataInfo) == 1:
560                          if not isinstance(group, ClassGroupSingleton):                          if not isinstance(group, ClassGroupSingleton):
561                              ngroup = ClassGroupSingleton(prop = props)                              ngroup = ClassGroupSingleton(prop = props)
562                                changed = True
563                          ngroup.SetValue(dataInfo[0])                          ngroup.SetValue(dataInfo[0])
564                      elif len(dataInfo) == 2:                      elif len(dataInfo) == 2:
565                          if not isinstance(group, ClassGroupRange):                          if not isinstance(group, ClassGroupRange):
566                              ngroup = ClassGroupRange(prop = props)                              ngroup = ClassGroupRange(prop = props)
567                                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
572    
573                      ngroup.SetLabel(group.GetLabel())                      if changed:
574                            ngroup.SetLabel(group.GetLabel())
575                      self.__SetRow(row, ngroup)                          self.SetClassGroup(row, ngroup)
576            else:
577                      mod = True              assert False # shouldn't be here
578                pass
   
         elif col == COL_LABEL:  
             group.SetLabel(value)  
             mod = True  
579    
580          if mod:          if mod:
581              self.__Modified()              self.__Modified()
582              self.GetView().Refresh()              self.GetView().Refresh()
583    
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:  
             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.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.SetValueAsCustom(row, COL_SYMBOL, None, group)          self.__SetRow(row, group)
600            self.GetView().Refresh()
601    
602      def __Modified(self, mod = True):      def __Modified(self, mod = True):
603          """Set the modified flag."""          """Adjust the modified flag.
604          self.modified = mod  
605            mod -- if -1 set the modified flag to False, otherwise perform
606                   an 'or' operation with the current value of the flag and
607                   'mod'
608            """
609    
610            if mod == -1:
611                self.modified = False
612            else:
613                self.modified = mod or self.modified
614    
615      def IsModified(self):      def IsModified(self):
616          """True if this table is considered modified."""          """True if this table is considered modified."""
617          return self.modified          return self.modified
618    
619      def DeleteRows(self, pos, numRows = 1):      def DeleteRows(self, pos, numRows = 1):
620          """Deletes 'numRows' beginning at row 'pos'.          """Deletes 'numRows' beginning at row 'pos'.
621    
622          The table is considered modified after this operation.          The row representing the default group is not removed.
623    
624            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.GetValueAsCustom(row, COL_SYMBOL, None)              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.
640    
641            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)
             #self.tdata.append([np, np.GetValue(), np.GetLabel()])  
             self.__Modified()  
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  class Classifier(wxDialog):  ID_PROPERTY_OK = 4001
654        ID_PROPERTY_REVERT = 4002
655      def __init__(self, parent, layer):  ID_PROPERTY_ADD = 4003
656          wxDialog.__init__(self, parent, -1, _("Classify"),  ID_PROPERTY_GENCLASS = 4004
657                            style = wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)  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):
679    
680        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    
692            self.originalClass = self.layer.GetClassification()
693            field = self.originalClass.GetField()
694            fieldType = self.originalClass.GetFieldType()
695    
696            self.genDlg = None
697    
698          topBox = wxBoxSizer(wxVERTICAL)          topBox = wxBoxSizer(wxVERTICAL)
699    
700          topBox.Add(wxStaticText(self, -1, _("Layer: %s") % layer.Title()),          panel = wxPanel(self, -1, size=(100, 100))
701              0, wxALIGN_LEFT | wxALL, 4)  
702          topBox.Add(wxStaticText(self, -1, _("Type: %s") % layer.ShapeType()),          panelBox = wxBoxSizer(wxVERTICAL)
703    
704            sizer = wxBoxSizer(wxHORIZONTAL)
705            sizer.Add(wxStaticText(panel, -1, _("Title: ")),
706                0, wxALIGN_LEFT | wxALL | wxALIGN_CENTER_VERTICAL, 4)
707            sizer.Add(wxTextCtrl(panel, ID_PROPERTY_TITLE, layer.Title()),
708                      1, wxGROW | wxALL, 4)
709            EVT_TEXT(self, ID_PROPERTY_TITLE, self._OnTitleChanged)
710    
711            panelBox.Add(sizer, 0, wxGROW, 4)
712    
713            panelBox.Add(wxStaticText(panel, -1,
714                                    _("Type: %s") % layer.ShapeType()),
715              0, wxALIGN_LEFT | wxALL, 4)              0, wxALIGN_LEFT | wxALL, 4)
716    
         propertyBox = wxBoxSizer(wxHORIZONTAL)  
         propertyBox.Add(wxStaticText(self, -1, _("Field: ")),  
             0, wxALIGN_CENTER | wxALL, 4)  
717    
718          self.fields = wxComboBox(self, ID_PROPERTY_SELECT, "",          #####################
719                                       style = wxCB_READONLY)  
720            #panelBox = wxBoxSizer(wxVERTICAL)
721            classBox = wxStaticBoxSizer(
722                        wxStaticBox(panel, -1, _("Classification")), wxVERTICAL)
723    
724    
725            #
726            # make field choice box
727            #
728            self.fields = wxChoice(panel, ID_PROPERTY_SELECT,)
729            #self.fields = wxComboBox(panel, ID_PROPERTY_SELECT, "",
730            #                             style = wxCB_READONLY)
731    
732          self.num_cols = layer.table.field_count()          self.num_cols = layer.table.field_count()
733          # just assume the first field in case one hasn't been          # just assume the first field in case one hasn't been
734          # specified in the file.          # specified in the file.
735          self.__cur_field = 0          self.__cur_field = 0
         clazz = layer.GetClassification()  
         field = clazz.GetField()  
736    
737          self.fields.Append("<None>")          self.fields.Append("<None>")
738          self.fields.SetClientData(0, None)  
739            if self.originalClass.GetFieldType() is None:
740                self.fields.SetClientData(0, copy.deepcopy(self.originalClass))
741            else:
742                self.fields.SetClientData(0, None)
743    
744          for i in range(self.num_cols):          for i in range(self.num_cols):
745              type, name, len, decc = layer.table.field_info(i)              type, name, len, decc = layer.table.field_info(i)
# Line 586  class Classifier(wxDialog): Line 747  class Classifier(wxDialog):
747    
748              if name == field:              if name == field:
749                  self.__cur_field = i + 1                  self.__cur_field = i + 1
750                  self.fields.SetClientData(i + 1, clazz)                  self.fields.SetClientData(i + 1,
751                                              copy.deepcopy(self.originalClass))
752              else:              else:
753                  self.fields.SetClientData(i + 1, None)                  self.fields.SetClientData(i + 1, None)
754    
         self.fields.SetSelection(self.__cur_field)  
755    
756          propertyBox.Add(self.fields, 1, wxGROW|wxALL, 4)          ###########
757          EVT_COMBOBOX(self, ID_PROPERTY_SELECT, self._OnFieldSelect)  
758    
759            sizer = wxBoxSizer(wxHORIZONTAL)
760            sizer.Add(wxStaticText(panel, ID_PROPERTY_FIELDTEXT, _("Field: ")),
761                0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 4)
762            sizer.Add(self.fields, 1, wxGROW | wxALL, 4)
763            EVT_CHOICE(self, ID_PROPERTY_SELECT, self._OnFieldSelect)
764            #EVT_COMBOBOX(self, ID_PROPERTY_SELECT, self._OnFieldSelect)
765    
766            classBox.Add(sizer, 0, wxGROW, 4)
767    
768            self.fieldTypeText = wxStaticText(panel, -1, "")
769            classBox.Add(self.fieldTypeText, 0,
770                         wxGROW | wxALIGN_LEFT | wxALL | wxADJUST_MINSIZE, 4)
771    
         topBox.Add(propertyBox, 0, wxGROW, 4)  
772    
773          #          #
774          # Classification data table          # Control Box
775          #          #
   
776          controlBox = wxBoxSizer(wxHORIZONTAL)          controlBox = wxBoxSizer(wxHORIZONTAL)
         self.classGrid = ClassGrid(self)  
   
         self.__SetGridTable(self.__cur_field)  
777    
         controlBox.Add(self.classGrid, 1, wxGROW, 0)  
778    
779            ###########
780            #
781            # Control buttons:
782            #
783          controlButtonBox = wxBoxSizer(wxVERTICAL)          controlButtonBox = wxBoxSizer(wxVERTICAL)
         controlButtonBox.Add(wxButton(self, ID_CLASSIFY_ADD,  
             _("Add")), 0, wxGROW | wxALL, 4)  
         controlButtonBox.Add(wxButton(self, ID_CLASSIFY_GENRANGE,  
             _("Generate Ranges")), 0, wxGROW | wxALL, 4)  
   
         controlButtonBox.Add(wxButton(self, ID_CLASSIFY_MOVEUP,  
             _("Move Up")), 0, wxGROW | wxALL, 4)  
         controlButtonBox.Add(wxButton(self, ID_CLASSIFY_MOVEDOWN,  
             _("Move Down")), 0, wxGROW | wxALL, 4)  
784    
785          controlButtonBox.Add(wxButton(self, ID_CLASSIFY_REMOVE,          button = wxButton(panel, ID_PROPERTY_GENCLASS, _("Generate Class"))
786              _("Remove")), 0, wxGROW | wxALL | wxALIGN_BOTTOM, 4)          controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)
787    
788          controlBox.Add(controlButtonBox, 0, wxGROW, 10)          button = wxButton(panel, ID_PROPERTY_ADD, _("Add"))
789          topBox.Add(controlBox, 1, wxGROW, 10)          controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)
790    
791            button = wxButton(panel, ID_PROPERTY_MOVEUP, _("Move Up"))
792            controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)
793    
794            button = wxButton(panel, ID_PROPERTY_MOVEDOWN, _("Move Down"))
795            controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)
796    
797            button = wxButton(panel, ID_PROPERTY_EDITSYM, _("Edit Symbol"))
798            controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)
799    
800          EVT_BUTTON(self, ID_CLASSIFY_ADD, self._OnAdd)          controlButtonBox.Add(60, 20, 0, wxGROW | wxALL | wxALIGN_BOTTOM, 4)
         EVT_BUTTON(self, ID_CLASSIFY_REMOVE, self._OnRemove)  
         EVT_BUTTON(self, ID_CLASSIFY_GENRANGE, self._OnGenRange)  
         EVT_BUTTON(self, ID_CLASSIFY_MOVEUP, self._OnMoveUp)  
         EVT_BUTTON(self, ID_CLASSIFY_MOVEDOWN, self._OnMoveDown)  
801    
802            button = wxButton(panel, ID_PROPERTY_REMOVE, _("Remove"))
803            controlButtonBox.Add(button, 0, wxGROW | wxALL | wxALIGN_BOTTOM, 4)
804    
805    
806            ###########
807          #          #
808          # Control buttons:          # Classification data table
809          #          #
810    
811            self.classGrid = ClassGrid(panel, self)
812    
813            # calling __SelectField after creating the classGrid fills in the
814            # grid with the correct information
815            self.fields.SetSelection(self.__cur_field)
816            self.__SelectField(self.__cur_field, group = group)
817    
818            controlBox.Add(self.classGrid, 1, wxGROW, 0)
819            controlBox.Add(controlButtonBox, 0, wxGROW, 10)
820    
821            classBox.Add(controlBox, 1, wxGROW, 10)
822            panelBox.Add(classBox, 1, wxGROW, 0)
823    
824            EVT_BUTTON(self, ID_PROPERTY_ADD, self._OnAdd)
825            EVT_BUTTON(self, ID_PROPERTY_EDITSYM, self._OnEditSymbol)
826            EVT_BUTTON(self, ID_PROPERTY_REMOVE, self._OnRemove)
827            EVT_BUTTON(self, ID_PROPERTY_GENCLASS, self._OnGenClass)
828            EVT_BUTTON(self, ID_PROPERTY_MOVEUP, self._OnMoveUp)
829            EVT_BUTTON(self, ID_PROPERTY_MOVEDOWN, self._OnMoveDown)
830    
831            ###########
832    
833    
834            panel.SetAutoLayout(True)
835            panel.SetSizer(panelBox)
836            panelBox.SetSizeHints(panel)
837    
838            topBox.Add(panel, 1, wxGROW | wxALL, 4)
839    
840            ###########
841    
842          buttonBox = wxBoxSizer(wxHORIZONTAL)          buttonBox = wxBoxSizer(wxHORIZONTAL)
843          buttonBox.Add(wxButton(self, ID_CLASSIFY_OK, _("OK")),          buttonBox.Add(wxButton(self, ID_PROPERTY_TRY, _("Try")),
844                        0, wxALL, 4)                        0, wxALL, 4)
845          buttonBox.Add(wxButton(self, ID_CLASSIFY_CANCEL, _("Cancel")),          buttonBox.Add(60, 20, 0, wxALL, 4)
846            buttonBox.Add(wxButton(self, ID_PROPERTY_REVERT, _("Revert")),
847                        0, wxALL, 4)                        0, wxALL, 4)
848          topBox.Add(buttonBox, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_BOTTOM, 10)          buttonBox.Add(60, 20, 0, wxALL, 4)
849            buttonBox.Add(wxButton(self, ID_PROPERTY_OK, _("OK")),
850          EVT_BUTTON(self, ID_CLASSIFY_OK, self._OnOK)                        0, wxALL, 4)
851          EVT_BUTTON(self, ID_CLASSIFY_CANCEL, self._OnCancel)          buttonBox.Add(60, 20, 0, wxALL, 4)
852            buttonBox.Add(wxButton(self, ID_PROPERTY_CLOSE, _("Close")),
853                          0, wxALL, 4)
854            topBox.Add(buttonBox, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_BOTTOM, 0)
855    
856            EVT_BUTTON(self, ID_PROPERTY_OK, self._OnOK)
857            EVT_BUTTON(self, ID_PROPERTY_TRY, self._OnTry)
858            EVT_BUTTON(self, ID_PROPERTY_CLOSE, self._OnCloseBtn)
859            EVT_BUTTON(self, ID_PROPERTY_REVERT, self._OnRevert)
860    
861            ###########
862    
863          self.SetAutoLayout(true)          topBox.SetSizeHints(self)
864            self.SetAutoLayout(True)
865          self.SetSizer(topBox)          self.SetSizer(topBox)
         topBox.Fit(self)  
         topBox.SetSizeHints(self)  
866    
867      def __BuildClassification(self, fieldIndex):          #self.Fit()
868            ######################
869    
870          clazz = Classification()          self.haveApplied = False
871          fieldName = self.fields.GetString(fieldIndex)  
872          fieldType = self.layer.GetFieldType(fieldName)      def EditSymbol(self, row):
873            table = self.classGrid.GetTable()
874            prop = table.GetValueAsCustom(row, COL_SYMBOL, None)
875    
876            # get a new ClassGroupProperties object and copy the
877            # values over to our current object
878            propDlg = SelectPropertiesDialog(NULL, prop, self.layer.ShapeType())
879    
880            self.Enable(False)
881            if propDlg.ShowModal() == wxID_OK:
882                new_prop = propDlg.GetClassGroupProperties()
883                table.SetValueAsCustom(row, COL_SYMBOL, None, new_prop)
884            self.Enable(True)
885            propDlg.Destroy()
886            
887        def _SetClassification(self, clazz):
888            
889            self.fields.SetClientData(self.__cur_field, clazz)
890            self.classGrid.GetTable().SetClassification(clazz)
891    
892        def __BuildClassification(self, fieldIndex, copyClass = False):
893    
894    #       numRows = self.classGrid.GetNumberRows()
895    #       assert numRows > 0  # there should always be a default row
896    
897    #       clazz = Classification()
898            if fieldIndex == 0:
899                fieldName = None
900                fieldType = None
901            else:
902                fieldName = self.fields.GetString(fieldIndex)
903                fieldType = self.layer.GetFieldType(fieldName)
904    
905            clazz = self.classGrid.GetTable().GetClassification()
906    
907            if copyClass:
908                clazz = copy.deepcopy(clazz)
909    
910          clazz.SetField(fieldName)          clazz.SetField(fieldName)
911          clazz.SetFieldType(fieldType)          clazz.SetFieldType(fieldType)
912    
         numRows = self.classGrid.GetNumberRows()  
913    
914          assert(numRows > 0) # there should always be a default row  #       table = self.classGrid.GetTable()
915    #       clazz.SetDefaultGroup(table.GetClassGroup(0))
         table = self.classGrid.GetTable()  
         clazz.SetDefaultGroup(table.GetClassGroup(0))  
916    
917          for i in range(1, numRows):  #       for i in range(1, numRows):
918              clazz.AddGroup(table.GetClassGroup(i))  #           clazz.AppendGroup(table.GetClassGroup(i))
919    
920          return clazz          return clazz
921    
922      def __SetGridTable(self, fieldIndex):      def __SetGridTable(self, fieldIndex, group = None):
923    
924          clazz = self.fields.GetClientData(fieldIndex)          clazz = self.fields.GetClientData(fieldIndex)
925    
# Line 680  class Classifier(wxDialog): Line 927  class Classifier(wxDialog):
927              clazz = Classification()              clazz = Classification()
928              clazz.SetDefaultGroup(              clazz.SetDefaultGroup(
929                  ClassGroupDefault(                  ClassGroupDefault(
930                      self.layer.GetClassification().GetDefaultGroup().GetProperties()))                      self.layer.GetClassification().
931                                   GetDefaultGroup().GetProperties()))
932    
933              fieldName = self.fields.GetString(fieldIndex)              fieldName = self.fields.GetString(fieldIndex)
934              fieldType = self.layer.GetFieldType(fieldName)              fieldType = self.layer.GetFieldType(fieldName)
935              clazz.SetFieldType(fieldType)              clazz.SetFieldType(fieldType)
936                                    
937          self.classGrid.CreateTable(clazz, self.layer.ShapeType())          self.classGrid.CreateTable(clazz, self.layer.ShapeType(), group)
938    
939      def _OnFieldSelect(self, event):      def __SetFieldTypeText(self, fieldIndex):
940          clazz = self.__BuildClassification(self.__cur_field)          fieldName = self.fields.GetString(fieldIndex)
941          self.fields.SetClientData(self.__cur_field, clazz)          fieldType = self.layer.GetFieldType(fieldName)
942    
943          self.__cur_field = self.fields.GetSelection()          assert Classifier.type2string.has_key(fieldType)
         self.__SetGridTable(self.__cur_field)  
944    
945      def _OnOK(self, event):          text = Classifier.type2string[fieldType]
946    
947            self.fieldTypeText.SetLabel(_("Data Type: %s") % text)
948    
949        def __SelectField(self, newIndex, oldIndex = -1, group = None):
950            """This method assumes that the current selection for the
951            combo has already been set by a call to SetSelection().
952            """
953    
954            assert oldIndex >= -1
955    
956            if oldIndex != -1:
957                clazz = self.__BuildClassification(oldIndex)
958                self.fields.SetClientData(oldIndex, clazz)
959    
960            self.__SetGridTable(newIndex, group)
961    
962            self.__EnableButtons(EB_SELECT_FIELD, newIndex != 0)
963    
964            self.__SetFieldTypeText(newIndex)
965    
966        def __SetTitle(self, title):
967            if title != "":
968                title = ": " + title
969    
970            self.SetTitle(_("Layer Properties") + title)
971    
972        def _OnEditSymbol(self, event):
973            sel = self.classGrid.GetCurrentSelection()
974    
975            if len(sel) == 1:
976                self.EditSymbol(sel[0])
977    
978        def _OnFieldSelect(self, event):
979            index = self.fields.GetSelection()
980            self.__SelectField(index, self.__cur_field)
981            self.__cur_field = index
982    
983        def _OnTry(self, event):
984          """Put the data from the table into a new Classification and hand          """Put the data from the table into a new Classification and hand
985             it to the layer.             it to the layer.
986          """          """
# Line 707  class Classifier(wxDialog): Line 992  class Classifier(wxDialog):
992          # to begin with or it has been modified          # to begin with or it has been modified
993          #          #
994          if clazz is None or self.classGrid.GetTable().IsModified():          if clazz is None or self.classGrid.GetTable().IsModified():
995              clazz = self.__BuildClassification(self.__cur_field)              clazz = self.__BuildClassification(self.__cur_field, True)
   
         clazz.SetLayer(self.layer)  
996    
997          self.layer.SetClassification(clazz)          self.layer.SetClassification(clazz)
998    
999          self.EndModal(wxID_OK)          self.haveApplied = True
1000    
1001      def _OnCancel(self, event):      def _OnOK(self, event):
1002          """Do nothing. The layer's current classification stays the same."""          self._OnTry(event)
1003          self.EndModal(wxID_CANCEL)          self.Close()
1004    
1005        def _OnCloseBtn(self, event):
1006            """Close is similar to Cancel except that any changes that were
1007            made and applied remain applied, but the currently displayed
1008            classification is discarded.
1009            """
1010    
1011            self.Close()
1012    
1013        def _OnRevert(self, event):
1014            """The layer's current classification stays the same."""
1015            if self.haveApplied:
1016                self.layer.SetClassification(self.originalClass)
1017    
1018            #self.Close()
1019    
1020      def _OnAdd(self, event):      def _OnAdd(self, event):
1021          self.classGrid.AppendRows()          self.classGrid.AppendRows()
# Line 725  class Classifier(wxDialog): Line 1023  class Classifier(wxDialog):
1023      def _OnRemove(self, event):      def _OnRemove(self, event):
1024          self.classGrid.DeleteSelectedRows()          self.classGrid.DeleteSelectedRows()
1025    
1026      def _OnGenRange(self, event):      def _OnGenClass(self, event):
1027          print "Classifier._OnGenRange()"  
1028            self.genDlg = ClassGenDialog(self, self.layer,
1029                              self.fields.GetString(self.__cur_field))
1030    
1031            EVT_CLOSE(self.genDlg, self._OnGenDialogClose)
1032    
1033            self.__EnableButtons(EB_GEN_CLASS, False)
1034    
1035            self.genDlg.Show()
1036    
1037        def _OnGenDialogClose(self, event):
1038            self.genDlg.Destroy()
1039            self.__EnableButtons(EB_GEN_CLASS, True)
1040    
1041      def _OnMoveUp(self, event):      def _OnMoveUp(self, event):
1042          sel = self.classGrid.GetCurrentSelection()          sel = self.classGrid.GetCurrentSelection()
# Line 741  class Classifier(wxDialog): Line 1051  class Classifier(wxDialog):
1051                  table.SetClassGroup(i, x)                  table.SetClassGroup(i, x)
1052                  self.classGrid.ClearSelection()                  self.classGrid.ClearSelection()
1053                  self.classGrid.SelectRow(i - 1)                  self.classGrid.SelectRow(i - 1)
1054                    self.classGrid.MakeCellVisible(i - 1, 0)
1055    
1056      def _OnMoveDown(self, event):      def _OnMoveDown(self, event):
1057          sel = self.classGrid.GetCurrentSelection()          sel = self.classGrid.GetCurrentSelection()
# Line 755  class Classifier(wxDialog): Line 1066  class Classifier(wxDialog):
1066                  table.SetClassGroup(i + 1, x)                  table.SetClassGroup(i + 1, x)
1067                  self.classGrid.ClearSelection()                  self.classGrid.ClearSelection()
1068                  self.classGrid.SelectRow(i + 1)                  self.classGrid.SelectRow(i + 1)
1069                    self.classGrid.MakeCellVisible(i + 1, 0)
1070    
1071        def _OnTitleChanged(self, event):
1072            obj = event.GetEventObject()
1073    
1074            self.layer.SetTitle(obj.GetValue())
1075            self.__SetTitle(self.layer.Title())
1076    
1077            self.__EnableButtons(EB_LAYER_TITLE, self.layer.Title() != "")
1078    
1079        def __EnableButtons(self, case, enable):
1080    
1081            if case == EB_LAYER_TITLE:  
1082                list = (ID_PROPERTY_OK,
1083                        ID_PROPERTY_CLOSE)
1084    
1085            elif case == EB_SELECT_FIELD:
1086                list = (ID_PROPERTY_GENCLASS,
1087                        ID_PROPERTY_ADD,
1088                        ID_PROPERTY_MOVEUP,
1089                        ID_PROPERTY_MOVEDOWN,
1090                        ID_PROPERTY_EDITSYM,
1091                        ID_PROPERTY_REMOVE)
1092    
1093            elif case == EB_GEN_CLASS:
1094                list = (ID_PROPERTY_SELECT,
1095                        ID_PROPERTY_FIELDTEXT,
1096                        ID_PROPERTY_GENCLASS,
1097                        ID_PROPERTY_EDITSYM)
1098    
1099            for id in list:
1100                self.FindWindowById(id).Enable(enable)
1101    
1102  ID_SELPROP_OK = 4001  ID_SELPROP_OK = 4001
1103  ID_SELPROP_CANCEL = 4002  ID_SELPROP_CANCEL = 4002
# Line 763  ID_SELPROP_SPINCTRL = 4002 Line 1105  ID_SELPROP_SPINCTRL = 4002
1105  ID_SELPROP_PREVIEW = 4003  ID_SELPROP_PREVIEW = 4003
1106  ID_SELPROP_STROKECLR = 4004  ID_SELPROP_STROKECLR = 4004
1107  ID_SELPROP_FILLCLR = 4005  ID_SELPROP_FILLCLR = 4005
1108    ID_SELPROP_STROKECLRTRANS = 4006
1109    ID_SELPROP_FILLCLRTRANS = 4007
1110    
1111  class SelectPropertiesDialog(wxDialog):  class SelectPropertiesDialog(wxDialog):
1112    
1113      def __init__(self, parent, prop, shapeType):      def __init__(self, parent, prop, shapeType):
1114          wxDialog.__init__(self, parent, -1, _("Select Properties"),          wxDialog.__init__(self, parent, -1, _("Select Properties"),
1115                            style = wxRESIZE_BORDER)                            style = wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
1116    
1117          self.prop = ClassGroupProperties(prop)          self.prop = ClassGroupProperties(prop)
1118    
# Line 780  class SelectPropertiesDialog(wxDialog): Line 1124  class SelectPropertiesDialog(wxDialog):
1124          previewBox = wxBoxSizer(wxVERTICAL)          previewBox = wxBoxSizer(wxVERTICAL)
1125          previewBox.Add(wxStaticText(self, -1, _("Preview:")),          previewBox.Add(wxStaticText(self, -1, _("Preview:")),
1126              0, wxALIGN_LEFT | wxALL, 4)              0, wxALIGN_LEFT | wxALL, 4)
1127          self.previewer = ClassDataPreviewer(None, self.prop, shapeType,  
1128                                              self, ID_SELPROP_PREVIEW, (40, 40))          self.previewWin = ClassGroupPropertiesCtrl(
1129          previewBox.Add(self.previewer, 1, wxGROW, 15)              self, ID_SELPROP_PREVIEW, self.prop, shapeType,
1130                (40, 40), wxSIMPLE_BORDER)
1131    
1132            self.previewWin.AllowEdit(False)
1133    
1134            previewBox.Add(self.previewWin, 1, wxGROW | wxALL, 4)
1135    
1136          itemBox.Add(previewBox, 1, wxALIGN_LEFT | wxALL | wxGROW, 0)          itemBox.Add(previewBox, 1, wxALIGN_LEFT | wxALL | wxGROW, 0)
1137    
1138          # control box          # control box
1139          ctrlBox = wxBoxSizer(wxVERTICAL)          ctrlBox = wxBoxSizer(wxVERTICAL)
1140          ctrlBox.Add(  
1141              wxButton(self, ID_SELPROP_STROKECLR, "Change Line Color"),          lineColorBox = wxBoxSizer(wxHORIZONTAL)
1142              0, wxALIGN_CENTER_HORIZONTAL | wxALL | wxGROW, 4)          lineColorBox.Add(
1143                wxButton(self, ID_SELPROP_STROKECLR, _("Change Line Color")),
1144                1, wxALL | wxGROW, 4)
1145          EVT_BUTTON(self, ID_SELPROP_STROKECLR, self._OnChangeLineColor)          EVT_BUTTON(self, ID_SELPROP_STROKECLR, self._OnChangeLineColor)
1146    
1147            lineColorBox.Add(
1148                wxButton(self, ID_SELPROP_STROKECLRTRANS, _("Transparent")),
1149                1, wxALL | wxGROW, 4)
1150            EVT_BUTTON(self, ID_SELPROP_STROKECLRTRANS,
1151                       self._OnChangeLineColorTrans)
1152    
1153            ctrlBox.Add(lineColorBox, 0,
1154                        wxALIGN_CENTER_HORIZONTAL | wxALL | wxGROW, 4)
1155    
1156          if shapeType != SHAPETYPE_ARC:          if shapeType != SHAPETYPE_ARC:
1157              ctrlBox.Add(              fillColorBox = wxBoxSizer(wxHORIZONTAL)
1158                  wxButton(self, ID_SELPROP_FILLCLR, "Change Fill Color"),              fillColorBox.Add(
1159                  0, wxALIGN_LEFT | wxALL | wxGROW, 4)                  wxButton(self, ID_SELPROP_FILLCLR, _("Change Fill Color")),
1160                    1, wxALL | wxGROW, 4)
1161              EVT_BUTTON(self, ID_SELPROP_FILLCLR, self._OnChangeFillColor)              EVT_BUTTON(self, ID_SELPROP_FILLCLR, self._OnChangeFillColor)
1162                fillColorBox.Add(
1163                    wxButton(self, ID_SELPROP_FILLCLRTRANS, _("Transparent")),
1164                    1, wxALL | wxGROW, 4)
1165                EVT_BUTTON(self, ID_SELPROP_FILLCLRTRANS,
1166                           self._OnChangeFillColorTrans)
1167                ctrlBox.Add(fillColorBox, 0,
1168                            wxALIGN_CENTER_HORIZONTAL | wxALL | wxGROW, 4)
1169    
1170          spinBox = wxBoxSizer(wxHORIZONTAL)          spinBox = wxBoxSizer(wxHORIZONTAL)
1171          spinBox.Add(wxStaticText(self, -1, _("Line Width: ")),          spinBox.Add(wxStaticText(self, -1, _("Line Width: ")),
# Line 815  class SelectPropertiesDialog(wxDialog): Line 1183  class SelectPropertiesDialog(wxDialog):
1183          itemBox.Add(ctrlBox, 0, wxALIGN_RIGHT | wxALL | wxGROW, 0)          itemBox.Add(ctrlBox, 0, wxALIGN_RIGHT | wxALL | wxGROW, 0)
1184          topBox.Add(itemBox, 1, wxALIGN_LEFT | wxALL | wxGROW, 0)          topBox.Add(itemBox, 1, wxALIGN_LEFT | wxALL | wxGROW, 0)
1185    
   
1186          #          #
1187          # Control buttons:          # Control buttons:
1188          #          #
1189          buttonBox = wxBoxSizer(wxHORIZONTAL)          buttonBox = wxBoxSizer(wxHORIZONTAL)
1190          buttonBox.Add(wxButton(self, ID_CLASSIFY_OK, _("OK")),          buttonBox.Add(wxButton(self, ID_SELPROP_OK, _("OK")),
1191                        0, wxALL, 4)                        0, wxALL, 4)
1192          buttonBox.Add(wxButton(self, ID_CLASSIFY_CANCEL, _("Cancel")),          buttonBox.Add(wxButton(self, ID_SELPROP_CANCEL, _("Cancel")),
1193                        0, wxALL, 4)                        0, wxALL, 4)
1194          topBox.Add(buttonBox, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_BOTTOM, 10)          topBox.Add(buttonBox, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_BOTTOM, 10)
1195                                                                                                                                                                    
1196          EVT_BUTTON(self, ID_SELPROP_OK, self._OnOK)          EVT_BUTTON(self, ID_SELPROP_OK, self._OnOK)
1197          EVT_BUTTON(self, ID_SELPROP_CANCEL, self._OnCancel)          EVT_BUTTON(self, ID_SELPROP_CANCEL, self._OnCancel)
1198                                                                                                                                                                    
1199          self.SetAutoLayout(true)          self.SetAutoLayout(True)
1200          self.SetSizer(topBox)          self.SetSizer(topBox)
1201          topBox.Fit(self)          topBox.Fit(self)
1202          topBox.SetSizeHints(self)          topBox.SetSizeHints(self)
# Line 842  class SelectPropertiesDialog(wxDialog): Line 1209  class SelectPropertiesDialog(wxDialog):
1209    
1210      def _OnSpin(self, event):      def _OnSpin(self, event):
1211          self.prop.SetLineWidth(self.spinCtrl.GetValue())          self.prop.SetLineWidth(self.spinCtrl.GetValue())
1212          self.previewer.Refresh()          self.previewWin.Refresh()
1213    
1214      def __GetColor(self, cur):      def __GetColor(self, cur):
1215          dialog = wxColourDialog(self)          dialog = wxColourDialog(self)
1216          dialog.GetColourData().SetColour(Color2wxColour(cur))          if cur is not Color.Transparent:
1217                dialog.GetColourData().SetColour(Color2wxColour(cur))
1218    
1219          ret = None          ret = None
1220          if dialog.ShowModal() == wxID_OK:          if dialog.ShowModal() == wxID_OK:
1221              ret = wxColour2Color(dialog.GetColourData().GetColour())              ret = wxColour2Color(dialog.GetColourData().GetColour())
# Line 859  class SelectPropertiesDialog(wxDialog): Line 1228  class SelectPropertiesDialog(wxDialog):
1228          clr = self.__GetColor(self.prop.GetLineColor())          clr = self.__GetColor(self.prop.GetLineColor())
1229          if clr is not None:          if clr is not None:
1230              self.prop.SetLineColor(clr)              self.prop.SetLineColor(clr)
1231          self.previewer.Refresh() # XXX: work around, see ClassDataPreviewer          self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer
1232    
1233        def _OnChangeLineColorTrans(self, event):
1234            self.prop.SetLineColor(Color.Transparent)
1235            self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer
1236            
1237      def _OnChangeFillColor(self, event):      def _OnChangeFillColor(self, event):
1238          clr = self.__GetColor(self.prop.GetFill())          clr = self.__GetColor(self.prop.GetFill())
1239          if clr is not None:          if clr is not None:
1240              self.prop.SetFill(clr)              self.prop.SetFill(clr)
1241          self.previewer.Refresh() # XXX: work around, see ClassDataPreviewer          self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer
1242    
1243        def _OnChangeFillColorTrans(self, event):
1244            self.prop.SetFill(Color.Transparent)
1245            self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer
1246    
1247      def GetClassGroupProperties(self):      def GetClassGroupProperties(self):
1248          return self.prop          return self.prop
1249    
1250    
1251  class ClassDataPreviewer(wxWindow):  class ClassDataPreviewWindow(wxWindow):
1252    
1253      def __init__(self, rect, prop, shapeType,      def __init__(self, rect, prop, shapeType,
1254                         parent = None, id = -1, size = wxDefaultSize):                         parent = None, id = -1, size = wxDefaultSize):
1255          if parent is not None:          if parent is not None:
1256              wxWindow.__init__(self, parent, id, size=size)              wxWindow.__init__(self, parent, id, (0, 0), size)
1257              EVT_PAINT(self, self._OnPaint)              EVT_PAINT(self, self._OnPaint)
1258    
1259          self.rect = rect          self.rect = rect
1260    
1261          self.prop = prop          self.prop = prop
1262          self.shapeType = shapeType          self.shapeType = shapeType
1263            self.previewer = ClassDataPreviewer()
1264    
1265        def GetProperties():
1266            return self.prop
1267    
1268      def _OnPaint(self, event):      def _OnPaint(self, event):
1269          dc = wxPaintDC(self)          dc = wxPaintDC(self)
# Line 889  class ClassDataPreviewer(wxWindow): Line 1271  class ClassDataPreviewer(wxWindow):
1271          # XXX: this doesn't seem to be having an effect:          # XXX: this doesn't seem to be having an effect:
1272          dc.DestroyClippingRegion()          dc.DestroyClippingRegion()
1273    
1274          self.Draw(dc, None)          if self.rect is None:
1275                w, h = self.GetSize()
1276                rect = wxRect(0, 0, w, h)
1277            else:
1278                rect = self.rect
1279    
1280            self.previewer.Draw(dc, rect, self.prop, self.shapeType)
1281    
1282      def Draw(self, dc, rect, prop = None, shapeType = None):  class ClassDataPreviewer:
1283    
1284          if prop is None: prop = self.prop      def Draw(self, dc, rect, prop, shapeType):
1285          if shapeType is None: shapeType = self.shapeType  
1286            assert dc is not None
1287            assert isinstance(prop, ClassGroupProperties)
1288    
1289          if rect is None:          if rect is None:
1290              x = y = 0              x = 0
1291              w, h = self.GetClientSizeTuple()              y = 0
1292                w, h = dc.GetSize()
1293          else:          else:
1294              x = rect.GetX()              x = rect.GetX()
1295              y = rect.GetY()              y = rect.GetY()
# Line 906  class ClassDataPreviewer(wxWindow): Line 1297  class ClassDataPreviewer(wxWindow):
1297              h = rect.GetHeight()              h = rect.GetHeight()
1298    
1299          stroke = prop.GetLineColor()          stroke = prop.GetLineColor()
1300          if stroke is Color.None:          if stroke is Color.Transparent:
1301              pen = wxTRANSPARENT_PEN              pen = wxTRANSPARENT_PEN
1302          else:          else:
1303              pen = wxPen(Color2wxColour(stroke),              pen = wxPen(Color2wxColour(stroke),
# Line 914  class ClassDataPreviewer(wxWindow): Line 1305  class ClassDataPreviewer(wxWindow):
1305                          wxSOLID)                          wxSOLID)
1306    
1307          stroke = prop.GetFill()          stroke = prop.GetFill()
1308          if stroke is Color.None:          if stroke is Color.Transparent:
1309              brush = wxTRANSPARENT_BRUSH              brush = wxTRANSPARENT_BRUSH
1310          else:          else:
1311              brush = wxBrush(Color2wxColour(stroke), wxSOLID)              brush = wxBrush(Color2wxColour(stroke), wxSOLID)
# Line 928  class ClassDataPreviewer(wxWindow): Line 1319  class ClassDataPreviewer(wxWindow):
1319                             wxPoint(x + w/2, y + h/4*3),                             wxPoint(x + w/2, y + h/4*3),
1320                             wxPoint(x + w, y)])                             wxPoint(x + w, y)])
1321    
1322          elif shapeType == SHAPETYPE_POINT or \          elif shapeType == SHAPETYPE_POINT:
              shapeType == SHAPETYPE_POLYGON:  
1323    
1324              dc.DrawCircle(x + w/2, y + h/2,              dc.DrawCircle(x + w/2, y + h/2,
1325                            (min(w, h) - prop.GetLineWidth())/2)                            (min(w, h) - prop.GetLineWidth())/2)
1326    
1327            elif shapeType == SHAPETYPE_POLYGON:
1328                dc.DrawRectangle(x, y, w, h)
1329    
1330  class ClassRenderer(wxPyGridCellRenderer):  class ClassRenderer(wxPyGridCellRenderer):
1331    
1332      def __init__(self, shapeType):      def __init__(self, shapeType):
1333          wxPyGridCellRenderer.__init__(self)          wxPyGridCellRenderer.__init__(self)
1334          self.previewer = ClassDataPreviewer(None, None, shapeType)          self.shapeType = shapeType
1335            self.previewer = ClassDataPreviewer()
1336    
1337      def Draw(self, grid, attr, dc, rect, row, col, isSelected):      def Draw(self, grid, attr, dc, rect, row, col, isSelected):
1338          data = grid.GetTable().GetValueAsCustom(row, col, None)          data = grid.GetTable().GetClassGroup(row)
1339    
1340          dc.SetClippingRegion(rect.GetX(), rect.GetY(),          dc.SetClippingRegion(rect.GetX(), rect.GetY(),
1341                               rect.GetWidth(), rect.GetHeight())                               rect.GetWidth(), rect.GetHeight())
# Line 951  class ClassRenderer(wxPyGridCellRenderer Line 1345  class ClassRenderer(wxPyGridCellRenderer
1345                           rect.GetWidth(), rect.GetHeight())                           rect.GetWidth(), rect.GetHeight())
1346    
1347          if not isinstance(data, ClassGroupMap):          if not isinstance(data, ClassGroupMap):
1348              self.previewer.Draw(dc, rect, data.GetProperties())              self.previewer.Draw(dc, rect, data.GetProperties(), self.shapeType)
1349    
1350          if isSelected:          if isSelected:
1351              dc.SetPen(wxPen(wxColour(0 * 255, 0 * 255, 0 * 255),              dc.SetPen(wxPen(wxBLACK, 1, wxSOLID))
                       4, wxSOLID))  
1352              dc.SetBrush(wxTRANSPARENT_BRUSH)              dc.SetBrush(wxTRANSPARENT_BRUSH)
1353    
1354              dc.DrawRectangle(rect.GetX(), rect.GetY(),              dc.DrawRectangle(rect.GetX(), rect.GetY(),
1355                               rect.GetWidth(), rect.GetHeight())                               rect.GetWidth(), rect.GetHeight())
1356    
1357          dc.DestroyClippingRegion()          dc.DestroyClippingRegion()
1358    
1359    
1360    class ClassGroupPropertiesCtrl(wxWindow, wxControl):
1361    
1362        def __init__(self, parent, id, props, shapeType,
1363                     size = wxDefaultSize, style = 0):
1364    
1365            wxWindow.__init__(self, parent, id, size = size, style = style)
1366    
1367            self.SetProperties(props)
1368            self.SetShapeType(shapeType)
1369            self.AllowEdit(True)
1370    
1371            EVT_PAINT(self, self._OnPaint)
1372            EVT_LEFT_DCLICK(self, self._OnLeftDClick)
1373    
1374            self.previewer = ClassDataPreviewer()
1375    
1376        def _OnPaint(self, event):
1377            dc = wxPaintDC(self)
1378    
1379            # XXX: this doesn't seem to be having an effect:
1380            dc.DestroyClippingRegion()
1381    
1382            w, h = self.GetClientSize()
1383    
1384            self.previewer.Draw(dc,
1385                                wxRect(0, 0, w, h),
1386                                self.GetProperties(),
1387                                self.GetShapeType())
1388    
1389    
1390        def GetProperties(self):
1391            return self.props
1392    
1393        def SetProperties(self, props):
1394            self.props = props
1395            self.Refresh()
1396    
1397        def GetShapeType(self):
1398            return self.shapeType
1399    
1400        def SetShapeType(self, shapeType):
1401            self.shapeType = shapeType
1402            self.Refresh()
1403    
1404        def AllowEdit(self, allow):
1405            self.allowEdit = allow
1406    
1407        def DoEdit(self):
1408            if not self.allowEdit: return
1409    
1410            propDlg = SelectPropertiesDialog(NULL,
1411                                             self.GetProperties(),
1412                                             self.GetShapeType())
1413    
1414            if propDlg.ShowModal() == wxID_OK:
1415                new_prop = propDlg.GetClassGroupProperties()
1416                self.SetProperties(new_prop)
1417                self.Refresh()
1418    
1419            propDlg.Destroy()
1420    
1421        def _OnLeftDClick(self, event):
1422            self.DoEdit()

Legend:
Removed from v.476  
changed lines
  Added in v.712

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26