/[thuban]/branches/WIP-pyshapelib-bramz/Thuban/UI/classifier.py
ViewVC logotype

Diff of /branches/WIP-pyshapelib-bramz/Thuban/UI/classifier.py

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 630 by jonathan, Wed Apr 9 10:10:06 2003 UTC revision 1527 by jonathan, Wed Jul 30 15:43:28 2003 UTC
# Line 18  from wxPython.wx import * Line 18  from wxPython.wx import *
18  from wxPython.grid import *  from wxPython.grid import *
19    
20  from Thuban import _  from Thuban import _
21  from Thuban.common import *  from Thuban.UI.common import Color2wxColour, wxColour2Color
 from Thuban.UI.common import *  
22    
23  from Thuban.Model.classification import *  from Thuban.Model.messages import MAP_LAYERS_REMOVED, LAYER_SHAPESTORE_REPLACED
24    from Thuban.Model.range import Range
25    from Thuban.Model.classification import \
26        Classification, ClassGroupDefault, \
27        ClassGroupSingleton, ClassGroupRange, ClassGroupMap, \
28        ClassGroupProperties
29    
30  from Thuban.Model.color import Color  from Thuban.Model.color import Transparent
31    
32  from Thuban.Model.layer import Layer, SHAPETYPE_ARC, SHAPETYPE_POLYGON, SHAPETYPE_POINT  from Thuban.Model.layer import Layer, RasterLayer, \
33        SHAPETYPE_ARC, SHAPETYPE_POLYGON, SHAPETYPE_POINT
34    
35  from Thuban.UI.classgen import ClassGenDialog, ClassGenerator  from Thuban.UI.classgen import ClassGenDialog
36    
37  from dialogs import NonModalDialog  from dialogs import NonModalNonParentDialog
38    from messages import MAP_REPLACED
39    
 # widget id's  
 ID_PROPERTY_SELECT = 4010  
40  ID_CLASS_TABLE = 40011  ID_CLASS_TABLE = 40011
41    
42    
43  # table columns  # table columns
44  COL_SYMBOL = 0  COL_VISIBLE = 0
45  COL_VALUE  = 1  COL_SYMBOL  = 1
46  COL_LABEL  = 2  COL_VALUE   = 2
47    COL_LABEL   = 3
48    NUM_COLS    = 4
49    
50  # indices into the client data lists in Classifier.fields  # indices into the client data lists in Classifier.fields
51  FIELD_CLASS = 0  FIELD_CLASS = 0
# Line 63  class ClassGrid(wxGrid): Line 69  class ClassGrid(wxGrid):
69                   use for display.                   use for display.
70          """          """
71    
72          #wxGrid.__init__(self, parent, ID_CLASS_TABLE, size = (340, 160))          wxGrid.__init__(self, parent, ID_CLASS_TABLE, style = 0)
         wxGrid.__init__(self, parent, ID_CLASS_TABLE)  
         #self.SetTable(ClassTable(fieldData, layer.ShapeType(), self), True)  
73    
74          self.classifier = classifier          self.classifier = classifier
75    
# Line 77  class ClassGrid(wxGrid): Line 81  class ClassGrid(wxGrid):
81          EVT_GRID_COL_SIZE(self, self._OnCellResize)          EVT_GRID_COL_SIZE(self, self._OnCellResize)
82          EVT_GRID_ROW_SIZE(self, self._OnCellResize)          EVT_GRID_ROW_SIZE(self, self._OnCellResize)
83    
84      def CreateTable(self, clazz, shapeType, group = None):      #def GetCellAttr(self, row, col):
85            #print "GetCellAttr ", row, col
86            #wxGrid.GetCellAttr(self, row, col)
87    
88        def CreateTable(self, clazz, fieldType, shapeType, group = None):
89    
90          assert isinstance(clazz, Classification)          assert isinstance(clazz, Classification)
91    
92          table = self.GetTable()          table = self.GetTable()
93          if table is None:          if table is None:
94              w = self.GetDefaultColSize() * 3 + self.GetDefaultRowLabelSize()              w = self.GetDefaultColSize() * NUM_COLS \
95              h = self.GetDefaultRowSize() * 4 + self.GetDefaultColLabelSize()                  + self.GetDefaultRowLabelSize()
96                h = self.GetDefaultRowSize() * 4 \
97                    + self.GetDefaultColLabelSize()
98    
99              self.SetDimensions(-1, -1, w, h)              self.SetDimensions(-1, -1, w, h)
100              self.SetSizeHints(w, h, -1, -1)              self.SetSizeHints(w, h, -1, -1)
101              table = ClassTable(self)              table = ClassTable(self)
# Line 94  class ClassGrid(wxGrid): Line 105  class ClassGrid(wxGrid):
105          self.SetSelectionMode(wxGrid.wxGridSelectRows)          self.SetSelectionMode(wxGrid.wxGridSelectRows)
106          self.ClearSelection()          self.ClearSelection()
107    
108          table.Reset(clazz, shapeType, group)          table.Reset(clazz, fieldType, shapeType, group)
109    
110      def GetCurrentSelection(self):      def GetCurrentSelection(self):
111          """Return the currently highlighted rows as an increasing list          """Return the currently highlighted rows as an increasing list
# Line 106  class ClassGrid(wxGrid): Line 117  class ClassGrid(wxGrid):
117      def GetSelectedRows(self):      def GetSelectedRows(self):
118          return self.GetCurrentSelection()          return self.GetCurrentSelection()
119    
120      def SetCellRenderer(self, row, col):      #def SetCellRenderer(self, row, col, renderer):
121          raise ValueError(_("Must not allow setting of renderer in ClassGrid!"))          #raise ValueError(_("Must not allow setting of renderer in ClassGrid!"))
122    
123      #      #
124      # [Set|Get]Table is taken from http://wiki.wxpython.org      # [Set|Get]Table is taken from http://wiki.wxpython.org
# Line 202  class ClassGrid(wxGrid): Line 213  class ClassGrid(wxGrid):
213  #                                  sel = False))  #                                  sel = False))
214    
215      def _OnCellDClick(self, event):      def _OnCellDClick(self, event):
216          """Handle a double on a cell."""          """Handle a double click on a cell."""
217    
218          r = event.GetRow()          r = event.GetRow()
219          c = event.GetCol()          c = event.GetCol()
         if c == COL_SYMBOL:  
             self.classifier.EditGroupProperties(r)  
220    
221            if c == COL_SYMBOL:
222                self.classifier.EditSymbol(r)
223            else:
224                event.Skip()
225    
226      #      #
227      # _OnSelectedRange() and _OnSelectedCell() were borrowed      # _OnSelectedRange() and _OnSelectedCell() were borrowed
# Line 237  class ClassGrid(wxGrid): Line 250  class ClassGrid(wxGrid):
250    
251      def _OnCellResize(self, event):      def _OnCellResize(self, event):
252          self.FitInside()          self.FitInside()
253            event.Skip()
254    
255  class ClassTable(wxPyGridTableBase):  class ClassTable(wxPyGridTableBase):
256      """Represents the underlying data structure for the grid."""      """Represents the underlying data structure for the grid."""
257    
258      NUM_COLS = 3      __col_labels = [_("Visible"), _("Symbol"), _("Value"), _("Label")]
   
     __col_labels = [_("Symbol"), _("Value"), _("Label")]  
259    
260    
261      def __init__(self, view = None):      def __init__(self, view = None):
     #def __init__(self, clazz, shapeType, view = None):  
262          """Constructor.          """Constructor.
263    
264          shapeType -- the type of shape that the layer uses          shapeType -- the type of shape that the layer uses
# Line 257  class ClassTable(wxPyGridTableBase): Line 268  class ClassTable(wxPyGridTableBase):
268    
269          wxPyGridTableBase.__init__(self)          wxPyGridTableBase.__init__(self)
270    
271          self.SetView(view)          assert len(ClassTable.__col_labels) == NUM_COLS
272    
273          self.clazz = None          self.clazz = None
274            self.__colAttr = {}
275    
276          #self.Reset(clazz, shapeType)          self.SetView(view)
277    
278      def Reset(self, clazz, shapeType, group = None):      def Reset(self, clazz, fieldType, shapeType, group = None):
279          """Reset the table with the given data.          """Reset the table with the given data.
280    
281          This is necessary because wxWindows does not allow a grid's          This is necessary because wxWindows does not allow a grid's
# Line 280  class ClassTable(wxPyGridTableBase): Line 293  class ClassTable(wxPyGridTableBase):
293    
294          self.GetView().BeginBatch()          self.GetView().BeginBatch()
295    
296          self.fieldType = clazz.GetFieldType()          self.fieldType = fieldType
297          self.shapeType = shapeType          self.shapeType = shapeType
298    
299          self.SetClassification(clazz, group)          self.SetClassification(clazz, group)
300          self.__Modified(-1)          self.__Modified(-1)
301    
302            self.__colAttr = {}
303    
304            attr = wxGridCellAttr()
305            attr.SetEditor(wxGridCellBoolEditor())
306            attr.SetRenderer(wxGridCellBoolRenderer())
307            attr.SetAlignment(wxALIGN_CENTER, wxALIGN_CENTER)
308            self.__colAttr[COL_VISIBLE] = attr
309    
310            attr = wxGridCellAttr()
311            attr.SetRenderer(ClassRenderer(self.shapeType))
312            attr.SetReadOnly()
313            self.__colAttr[COL_SYMBOL] = attr
314    
315          self.GetView().EndBatch()          self.GetView().EndBatch()
316          self.GetView().FitInside()          self.GetView().FitInside()
317    
318      def GetClassification(self):      def GetClassification(self):
319            """Return the current classification."""
320          return self.clazz          return self.clazz
321    
322      def SetClassification(self, clazz, group = None):      def SetClassification(self, clazz, group = None):
323            """Fill in the table with the given classification.
324            Select the given group if group is not None.
325            """
326    
327          self.GetView().BeginBatch()          self.GetView().BeginBatch()
328    
329          old_len = self.GetNumberRows()          old_len = self.GetNumberRows()
330    
         #  
         # copy the data out of the classification and into our  
         # array  
         #  
331          row = -1          row = -1
 #       for g in clazz:  
 #           ng = copy.deepcopy(g)  
 #           self.__SetRow(None, ng)  
 #           if g is group:  
 #               row = self.GetNumberRows() - 1  
 #               #print "selecting row..."  
   
   
         #self.clazz = copy.deepcopy(clazz)  
332          self.clazz = clazz          self.clazz = clazz
333    
334          self.__NotifyRowChanges(old_len, self.GetNumberRows())          self.__NotifyRowChanges(old_len, self.GetNumberRows())
335    
336            #
337            # XXX: this is dead code at the moment
338            #
339          if row > -1:          if row > -1:
340              self.GetView().ClearSelection()              self.GetView().ClearSelection()
341              self.GetView().SelectRow(row)              self.GetView().SelectRow(row)
# Line 327  class ClassTable(wxPyGridTableBase): Line 347  class ClassTable(wxPyGridTableBase):
347          self.GetView().FitInside()          self.GetView().FitInside()
348    
349      def __NotifyRowChanges(self, curRows, newRows):      def __NotifyRowChanges(self, curRows, newRows):
350            """Make sure table updates correctly if the number of
351            rows changes.
352            """
353          #          #
354          # silly message processing for updates to the number of          # silly message processing for updates to the number of
355          # rows and columns          # rows and columns
# Line 345  class ClassTable(wxPyGridTableBase): Line 368  class ClassTable(wxPyGridTableBase):
368              self.GetView().ProcessTableMessage(msg)              self.GetView().ProcessTableMessage(msg)
369              self.GetView().FitInside()              self.GetView().FitInside()
370    
   
371      def __SetRow(self, row, group):      def __SetRow(self, row, group):
372          """Set a row's data to that of the group.          """Set a row's data to that of the group.
373    
# Line 387  class ClassTable(wxPyGridTableBase): Line 409  class ClassTable(wxPyGridTableBase):
409              if isinstance(group, ClassGroupMap):       return _("Map")              if isinstance(group, ClassGroupMap):       return _("Map")
410    
411          assert False # shouldn't get here          assert False # shouldn't get here
412          return _("")          return ""
413    
414      def GetNumberRows(self):      def GetNumberRows(self):
415          """Return the number of rows."""          """Return the number of rows."""
# Line 398  class ClassTable(wxPyGridTableBase): Line 420  class ClassTable(wxPyGridTableBase):
420    
421      def GetNumberCols(self):      def GetNumberCols(self):
422          """Return the number of columns."""          """Return the number of columns."""
423          return self.NUM_COLS          return NUM_COLS
424    
425      def IsEmptyCell(self, row, col):      def IsEmptyCell(self, row, col):
426          """Determine if a cell is empty. This is always false."""          """Determine if a cell is empty. This is always false."""
# Line 416  class ClassTable(wxPyGridTableBase): Line 438  class ClassTable(wxPyGridTableBase):
438          """          """
439    
440          self.SetValueAsCustom(row, col, None, value)          self.SetValueAsCustom(row, col, None, value)
         self.__Modified()  
441                
442      def GetValueAsCustom(self, row, col, typeName):      def GetValueAsCustom(self, row, col, typeName):
443          """Return the object that is used to represent the given          """Return the object that is used to represent the given
# Line 431  class ClassTable(wxPyGridTableBase): Line 452  class ClassTable(wxPyGridTableBase):
452              group = self.clazz.GetGroup(row - 1)              group = self.clazz.GetGroup(row - 1)
453    
454    
455            if col == COL_VISIBLE:
456                return group.IsVisible()
457    
458          if col == COL_SYMBOL:          if col == COL_SYMBOL:
459              return group.GetProperties()              return group.GetProperties()
460    
# Line 445  class ClassTable(wxPyGridTableBase): Line 469  class ClassTable(wxPyGridTableBase):
469          elif isinstance(group, ClassGroupSingleton):          elif isinstance(group, ClassGroupSingleton):
470              return group.GetValue()              return group.GetValue()
471          elif isinstance(group, ClassGroupRange):          elif isinstance(group, ClassGroupRange):
472              return _("%s - %s") % (group.GetMin(), group.GetMax())              return group.GetRange()
473    
474          assert(False) # shouldn't get here          assert False # shouldn't get here
475          return None          return None
476    
477      def __ParseInput(self, value):      def __ParseInput(self, value):
478          """Try to determine what kind of input value is          """Try to determine what kind of input value is
479             (string, number, or range)             (string, number, or range)
480    
481          Returns a tuple of length one if there is a single          Returns a tuple (type, data) where type is 0 if data is
482          value, or of length two if it is a range.          a singleton value, or 1 if is a range
483          """          """
484    
485          type = self.fieldType          type = self.fieldType
486    
487          if type == FIELDTYPE_STRING:          if type == FIELDTYPE_STRING:
488              return (value,)              return (0, value)
489          elif type in (FIELDTYPE_INT, FIELDTYPE_DOUBLE):          elif type in (FIELDTYPE_INT, FIELDTYPE_DOUBLE):
   
490              if type == FIELDTYPE_INT:              if type == FIELDTYPE_INT:
491                    # the float call allows the user to enter 1.0 for 1
492                  conv = lambda p: int(float(p))                  conv = lambda p: int(float(p))
493              else:              else:
494                  conv = lambda p: p                  conv = float
495    
496              #              #
497              # first try to take the input as a single number              # first try to take the input as a single number
498              # if there's an exception try to break it into              # if there's an exception try to break it into
499              # a range seperated by a '-'. take care to ignore              # a range. if there is an exception here, let it
500              # a leading '-' as that could be for a negative number.              # pass up to the calling function.
             # then try to parse the individual parts. if there  
             # is an exception here, let it pass up to the calling  
             # function.  
501              #              #
502              try:              try:
503                  return (conv(Str2Num(value)),)                  return (0, conv(value))
504              except ValueError:              except ValueError:
505                  i = value.find('-')                  return (1, Range(value))
                 if i == 0:  
                     i = value.find('-', 1)  
   
                 return (conv(Str2Num(value[:i])), conv(Str2Num(value[i+1:])))  
506    
507          assert False  # shouldn't get here          assert False  # shouldn't get here
508          return (0,)          return (0,None)
               
509    
510      def SetValueAsCustom(self, row, col, typeName, value):      def SetValueAsCustom(self, row, col, typeName, value):
511          """Set the cell specified by 'row' and 'col' to 'value'.          """Set the cell specified by 'row' and 'col' to 'value'.
# Line 503  class ClassTable(wxPyGridTableBase): Line 519  class ClassTable(wxPyGridTableBase):
519          typeName -- unused, but needed to overload wxPyGridTableBase          typeName -- unused, but needed to overload wxPyGridTableBase
520          """          """
521    
522          assert col >= 0 and col < self.GetNumberCols()          assert 0 <= col < self.GetNumberCols()
523          assert row >= 0 and row < self.GetNumberRows()          assert 0 <= row < self.GetNumberRows()
524    
525          if row == 0:          if row == 0:
526              group = self.clazz.GetDefaultGroup()              group = self.clazz.GetDefaultGroup()
# Line 513  class ClassTable(wxPyGridTableBase): Line 529  class ClassTable(wxPyGridTableBase):
529    
530          mod = True # assume the data will change          mod = True # assume the data will change
531    
532          if col == COL_SYMBOL:          if col == COL_VISIBLE:
533                group.SetVisible(value)
534            elif col == COL_SYMBOL:
535              group.SetProperties(value)              group.SetProperties(value)
536          elif col == COL_LABEL:          elif col == COL_LABEL:
537              group.SetLabel(value)              group.SetLabel(value)
# Line 541  class ClassTable(wxPyGridTableBase): Line 559  class ClassTable(wxPyGridTableBase):
559                      # changing the underlying group type if the                      # changing the underlying group type if the
560                      # group was a singleton and a range was entered                      # group was a singleton and a range was entered
561                      #                      #
562                      if len(dataInfo) == 1:                      if dataInfo[0] == 0:
563                          if not isinstance(group, ClassGroupSingleton):                          if not isinstance(group, ClassGroupSingleton):
564                              ngroup = ClassGroupSingleton(prop = props)                              ngroup = ClassGroupSingleton(props = props)
565                              changed = True                              changed = True
566                          ngroup.SetValue(dataInfo[0])                          ngroup.SetValue(dataInfo[1])
567                      elif len(dataInfo) == 2:                      elif dataInfo[0] == 1:
568                          if not isinstance(group, ClassGroupRange):                          if not isinstance(group, ClassGroupRange):
569                              ngroup = ClassGroupRange(prop = props)                              ngroup = ClassGroupRange(props = props)
570                              changed = True                              changed = True
571                          ngroup.SetRange(dataInfo[0], dataInfo[1])                          ngroup.SetRange(dataInfo[1])
572                      else:                      else:
573                          assert False                          assert False
574                          pass                          pass
# Line 569  class ClassTable(wxPyGridTableBase): Line 587  class ClassTable(wxPyGridTableBase):
587      def GetAttr(self, row, col, someExtraParameter):      def GetAttr(self, row, col, someExtraParameter):
588          """Returns the cell attributes"""          """Returns the cell attributes"""
589    
590          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  
591    
592      def GetClassGroup(self, row):      def GetClassGroup(self, row):
593          """Return the ClassGroup object representing row 'row'."""          """Return the ClassGroup object representing row 'row'."""
# Line 590  class ClassTable(wxPyGridTableBase): Line 599  class ClassTable(wxPyGridTableBase):
599              return self.clazz.GetGroup(row - 1)              return self.clazz.GetGroup(row - 1)
600    
601      def SetClassGroup(self, row, group):      def SetClassGroup(self, row, group):
602            """Set the given row to properties of group."""
603          self.__SetRow(row, group)          self.__SetRow(row, group)
604          self.GetView().Refresh()          self.GetView().Refresh()
605    
# Line 644  class ClassTable(wxPyGridTableBase): Line 654  class ClassTable(wxPyGridTableBase):
654              self.__NotifyRowChanges(old_len, self.GetNumberRows())              self.__NotifyRowChanges(old_len, self.GetNumberRows())
655    
656    
657  ID_CLASSIFY_OK = 4001  ID_PROPERTY_REVERT = 4002
658  ID_CLASSIFY_CANCEL = 4002  ID_PROPERTY_ADD = 4003
659  ID_CLASSIFY_ADD = 4003  ID_PROPERTY_GENCLASS = 4004
660  ID_CLASSIFY_GENCLASS = 4004  ID_PROPERTY_REMOVE = 4005
661  ID_CLASSIFY_REMOVE = 4005  ID_PROPERTY_MOVEUP = 4006
662  ID_CLASSIFY_MOVEUP = 4006  ID_PROPERTY_MOVEDOWN = 4007
663  ID_CLASSIFY_MOVEDOWN = 4007  ID_PROPERTY_TRY = 4008
664  ID_CLASSIFY_APPLY = 4008  ID_PROPERTY_EDITSYM = 4009
665  ID_CLASSIFY_EDITPROPS = 4009  ID_PROPERTY_SELECT = 4011
666  ID_CLASSIFY_CLOSE = 4010  ID_PROPERTY_TITLE = 4012
667    ID_PROPERTY_FIELDTEXT = 4013
668    
669  BTN_ADD = 0  BTN_ADD = 0
670  BTN_EDIT = 1  BTN_EDIT = 1
# Line 662  BTN_UP = 3 Line 673  BTN_UP = 3
673  BTN_DOWN = 4  BTN_DOWN = 4
674  BTN_RM = 5  BTN_RM = 5
675    
676  class Classifier(NonModalDialog):  EB_LAYER_TITLE = 0
677    EB_SELECT_FIELD = 1
678    EB_GEN_CLASS = 2
679    
680    class Classifier(NonModalNonParentDialog):
681    
682      type2string = {None:             _("None"),      type2string = {None:             _("None"),
683                     FIELDTYPE_STRING: _("Text"),                     FIELDTYPE_STRING: _("Text"),
684                     FIELDTYPE_INT:    _("Integer"),                     FIELDTYPE_INT:    _("Integer"),
685                     FIELDTYPE_DOUBLE: _("Decimal")}                     FIELDTYPE_DOUBLE: _("Decimal")}
686    
687      def __init__(self, parent, name, layer, group = None):      def __init__(self, parent, name, map, layer, group = None):
688          NonModalDialog.__init__(self, parent, name,          """Create a Properties/Classification dialog for a layer.
689                                  _("Classifier: %s") % layer.Title())          The layer is part of map. If group is not None, select that
690            group in the classification table.
691            """
692    
693            NonModalNonParentDialog.__init__(self, parent, name, "")
694    
695          panel = wxPanel(self, -1, size=(100, 100))          self.__SetTitle(layer.Title())
696    
697            self.parent.Subscribe(MAP_REPLACED, self.map_replaced)
698          self.layer = layer          self.layer = layer
699            self.map = map
700    
701          self.originalClass = self.layer.GetClassification()          self.map.Subscribe(MAP_LAYERS_REMOVED, self.map_layers_removed)
702          field = self.originalClass.GetField()          self.layer.Subscribe(LAYER_SHAPESTORE_REPLACED,
703          fieldType = self.originalClass.GetFieldType()                               self.layer_shapestore_replaced)
704    
705          self.genDlg = None          self.genDlg = None
706    
707          topBox = wxBoxSizer(wxVERTICAL)          ############################
708          panelBox = wxBoxSizer(wxVERTICAL)          # Create the controls
   
         #panelBox.Add(wxStaticText(panel, -1, _("Layer: %s") % layer.Title()),  
             #0, wxALIGN_LEFT | wxALL, 4)  
         panelBox.Add(wxStaticText(panel, -1,  
                                 _("Layer Type: %s") % layer.ShapeType()),  
             0, wxALIGN_LEFT | wxALL, 4)  
   
   
         #  
         # make field combo box  
709          #          #
         self.fields = wxComboBox(panel, ID_PROPERTY_SELECT, "",  
                                      style = wxCB_READONLY)  
   
         self.num_cols = layer.table.field_count()  
         # just assume the first field in case one hasn't been  
         # specified in the file.  
         self.__cur_field = 0  
   
         self.fields.Append("<None>")  
         self.fields.SetClientData(0, None)  
   
         for i in range(self.num_cols):  
             type, name, len, decc = layer.table.field_info(i)  
             self.fields.Append(name)  
   
             if name == field:  
                 self.__cur_field = i + 1  
                 self.fields.SetClientData(i + 1,  
                                           copy.deepcopy(self.originalClass))  
             else:  
                 self.fields.SetClientData(i + 1, None)  
   
710    
711          ###########          panel = wxPanel(self, -1)
712    
713            text_title = wxTextCtrl(panel, ID_PROPERTY_TITLE, layer.Title())
714          self.fieldTypeText = wxStaticText(panel, -1, "")          self.fieldTypeText = wxStaticText(panel, -1, "")
         panelBox.Add(self.fieldTypeText, 0,  
                      wxGROW | wxALIGN_LEFT | wxALL | wxADJUST_MINSIZE, 4)  
   
         propertyBox = wxBoxSizer(wxHORIZONTAL)  
         propertyBox.Add(wxStaticText(panel, -1, _("Field: ")),  
             0, wxALIGN_LEFT | wxALL, 4)  
         propertyBox.Add(self.fields, 1, wxGROW|wxALL, 4)  
         EVT_COMBOBOX(self, ID_PROPERTY_SELECT, self._OnFieldSelect)  
715    
716          panelBox.Add(propertyBox, 0, wxGROW, 4)          if layer.HasClassification():
717                self.originalClass = self.layer.GetClassification()
718                self.originalClassField = self.layer.GetClassificationColumn()
719                field = self.originalClassField
720                fieldType = self.layer.GetFieldType(field)
721    
722                table = layer.ShapeStore().Table()
723                #
724                # make field choice box
725                #
726                self.fields = wxChoice(panel, ID_PROPERTY_SELECT,)
727    
728          #              self.num_cols = table.NumColumns()
729          # Control Box              # just assume the first field in case one hasn't been
730          #              # specified in the file.
731          controlBox = wxBoxSizer(wxHORIZONTAL)              self.__cur_field = 0
732    
733                self.fields.Append("<None>")
734    
735          ###########              if fieldType is None:
736          #                  self.fields.SetClientData(0, copy.deepcopy(self.originalClass))
737          # Control buttons:              else:
738          #                  self.fields.SetClientData(0, None)
         self.controlButtons = []  
739    
740          controlButtonBox = wxBoxSizer(wxVERTICAL)              for i in range(self.num_cols):
741                    name = table.Column(i).name
742                    self.fields.Append(name)
743    
744                    if name == field:
745                        self.__cur_field = i + 1
746                        self.fields.SetClientData(i + 1,
747                                                  copy.deepcopy(self.originalClass))
748                    else:
749                        self.fields.SetClientData(i + 1, None)
750    
751          button = wxButton(panel, ID_CLASSIFY_ADD, _("Add"))              button_gen = wxButton(panel, ID_PROPERTY_GENCLASS,
752          controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)                  _("Generate Class"))
753          self.controlButtons.append(button)              button_add = wxButton(panel, ID_PROPERTY_ADD,
754                    _("Add"))
755                button_moveup = wxButton(panel, ID_PROPERTY_MOVEUP,
756                    _("Move Up"))
757                button_movedown = wxButton(panel, ID_PROPERTY_MOVEDOWN,
758                    _("Move Down"))
759                button_edit = wxButton(panel, ID_PROPERTY_EDITSYM,
760                    _("Edit Symbol"))
761                button_remove = wxButton(panel, ID_PROPERTY_REMOVE,
762                    _("Remove"))
763    
764                self.classGrid = ClassGrid(panel, self)
765    
766                # calling __SelectField after creating the classGrid fills in the
767                # grid with the correct information
768                self.fields.SetSelection(self.__cur_field)
769                self.__SelectField(self.__cur_field, group = group)
770    
771            button_try = wxButton(self, ID_PROPERTY_TRY, _("Try"))
772            button_revert = wxButton(self, ID_PROPERTY_REVERT, _("Revert"))
773            button_ok = wxButton(self, wxID_OK, _("OK"))
774            button_close = wxButton(self, wxID_CANCEL, _("Close"))
775            button_ok.SetDefault()
776    
777          button = wxButton(panel, ID_CLASSIFY_EDITPROPS, _("Edit Properties"))          ############################
778          controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)          # Layout the controls
779          self.controlButtons.append(button)          #
780    
781          button = wxButton(panel, ID_CLASSIFY_GENCLASS, _("Generate Class"))          topBox = wxBoxSizer(wxVERTICAL)
782          controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)          panelBox = wxBoxSizer(wxVERTICAL)
         self.controlButtons.append(button)  
783    
784          button = wxButton(panel, ID_CLASSIFY_MOVEUP, _("Move Up"))          sizer = wxBoxSizer(wxHORIZONTAL)
785          controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)          sizer.Add(wxStaticText(panel, -1, _("Title: ")),
786          self.controlButtons.append(button)              0, wxALIGN_LEFT | wxALL | wxALIGN_CENTER_VERTICAL, 4)
787            sizer.Add(text_title, 1, wxGROW, 0)
788    
789          button = wxButton(panel, ID_CLASSIFY_MOVEDOWN, _("Move Down"))          panelBox.Add(sizer, 0, wxGROW, 4)
         controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)  
         self.controlButtons.append(button)  
790    
791          controlButtonBox.Add(60, 20, 0, wxGROW | wxALL | wxALIGN_BOTTOM, 4)          if isinstance(layer, RasterLayer):
792                type = "Image"
793            else:
794                type = layer.ShapeType()
795    
796          button = wxButton(panel, ID_CLASSIFY_REMOVE, _("Remove"))          panelBox.Add(wxStaticText(panel, -1, _("Type: %s") % type),
797          controlButtonBox.Add(button, 0, wxGROW | wxALL | wxALIGN_BOTTOM, 4)              0, wxALIGN_LEFT | wxALL, 4)
         self.controlButtons.append(button)  
798    
799            if layer.HasClassification():
800    
801          ###########              classBox = wxStaticBoxSizer(
802          #                          wxStaticBox(panel, -1, _("Classification")), wxVERTICAL)
         # Classification data table  
         #  
803    
         self.classGrid = ClassGrid(panel, self)  
         #self.__SetGridTable(self.__cur_field, group)  
         #self.fields.SetSelection(self.__cur_field)  
804    
805          # calling __SelectField after creating the classGrid fills in the              sizer = wxBoxSizer(wxHORIZONTAL)
806          # grid with the correct information              sizer.Add(wxStaticText(panel, ID_PROPERTY_FIELDTEXT, _("Field: ")),
807          self.fields.SetSelection(self.__cur_field)                  0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 4)
808          self.__SelectField(self.__cur_field, group = group)              sizer.Add(self.fields, 1, wxGROW | wxALL, 4)
809    
810          #self.classGrid.SelectGroup(group)              classBox.Add(sizer, 0, wxGROW, 4)
811    
812          controlBox.Add(self.classGrid, 1, wxGROW, 0)              classBox.Add(self.fieldTypeText, 0,
813                            wxGROW | wxALIGN_LEFT | wxALL | wxADJUST_MINSIZE, 4)
814    
815                controlBox = wxBoxSizer(wxHORIZONTAL)
816                controlButtonBox = wxBoxSizer(wxVERTICAL)
817    
818                controlButtonBox.Add(button_gen, 0, wxGROW|wxALL, 4)
819                controlButtonBox.Add(button_add, 0, wxGROW|wxALL, 4)
820                controlButtonBox.Add(button_moveup, 0, wxGROW|wxALL, 4)
821                controlButtonBox.Add(button_movedown, 0, wxGROW|wxALL, 4)
822                controlButtonBox.Add(button_edit, 0, wxGROW|wxALL, 4)
823                controlButtonBox.Add(60, 20, 0, wxGROW|wxALL|wxALIGN_BOTTOM, 4)
824                controlButtonBox.Add(button_remove, 0,
825                                     wxGROW|wxALL|wxALIGN_BOTTOM, 4)
826    
827          controlBox.Add(controlButtonBox, 0, wxGROW, 10)              controlBox.Add(self.classGrid, 1, wxGROW, 0)
828          panelBox.Add(controlBox, 1, wxGROW, 10)              controlBox.Add(controlButtonBox, 0, wxGROW, 10)
829    
830          EVT_BUTTON(self, ID_CLASSIFY_ADD, self._OnAdd)              classBox.Add(controlBox, 1, wxGROW, 10)
831          EVT_BUTTON(self, ID_CLASSIFY_EDITPROPS, self._OnEditGroupProperties)              panelBox.Add(classBox, 1, wxGROW, 0)
         EVT_BUTTON(self, ID_CLASSIFY_REMOVE, self._OnRemove)  
         EVT_BUTTON(self, ID_CLASSIFY_GENCLASS, self._OnGenClass)  
         EVT_BUTTON(self, ID_CLASSIFY_MOVEUP, self._OnMoveUp)  
         EVT_BUTTON(self, ID_CLASSIFY_MOVEDOWN, self._OnMoveDown)  
832    
         ###########  
833    
834          buttonBox = wxBoxSizer(wxHORIZONTAL)          buttonBox = wxBoxSizer(wxHORIZONTAL)
835          buttonBox.Add(wxButton(panel, ID_CLASSIFY_OK, _("OK")),          buttonBox.Add(button_try, 0, wxRIGHT|wxEXPAND, 10)
836                        0, wxALL, 4)          buttonBox.Add(button_revert, 0, wxRIGHT|wxEXPAND, 10)
837          buttonBox.Add(60, 20, 0, wxALL, 4)          buttonBox.Add(button_ok, 0, wxRIGHT|wxEXPAND, 10)
838          buttonBox.Add(wxButton(panel, ID_CLASSIFY_APPLY, _("Apply")),          buttonBox.Add(button_close, 0, wxRIGHT|wxEXPAND, 10)
                       0, wxALL, 4)  
         buttonBox.Add(60, 20, 0, wxALL, 4)  
         buttonBox.Add(wxButton(panel, ID_CLASSIFY_CLOSE, _("Close")),  
                       0, wxALL, 4)  
         buttonBox.Add(60, 20, 0, wxALL, 4)  
         buttonBox.Add(wxButton(panel, ID_CLASSIFY_CANCEL, _("Cancel")),  
                       0, wxALL, 4)  
         panelBox.Add(buttonBox, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_BOTTOM, 0)  
   
         EVT_BUTTON(self, ID_CLASSIFY_OK, self._OnOK)  
         EVT_BUTTON(self, ID_CLASSIFY_APPLY, self._OnApply)  
         EVT_BUTTON(self, ID_CLASSIFY_CLOSE, self._OnCloseBtn)  
         EVT_BUTTON(self, ID_CLASSIFY_CANCEL, self._OnCancel)  
   
         ###########  
   
839    
840          panel.SetAutoLayout(True)          panel.SetAutoLayout(True)
841          panel.SetSizer(panelBox)          panel.SetSizer(panelBox)
842            panelBox.Fit(panel)
843          panelBox.SetSizeHints(panel)          panelBox.SetSizeHints(panel)
844    
845          topBox.Add(panel, 1, wxGROW, 0)          topBox.Add(panel, 1, wxGROW | wxALL, 4)
846          panelBox.SetSizeHints(self)          topBox.Add(buttonBox, 0, wxALIGN_RIGHT|wxBOTTOM|wxTOP, 10)
847    
848          self.SetAutoLayout(True)          self.SetAutoLayout(True)
849          self.SetSizer(topBox)          self.SetSizer(topBox)
850            topBox.Fit(self)
851            topBox.SetSizeHints(self)
852            self.Layout()
853    
854            ###########
855    
856            EVT_CHOICE(self, ID_PROPERTY_SELECT, self._OnFieldSelect)
857            EVT_TEXT(self, ID_PROPERTY_TITLE, self._OnTitleChanged)
858            EVT_BUTTON(self, wxID_OK, self._OnOK)
859            EVT_BUTTON(self, ID_PROPERTY_TRY, self._OnTry)
860            EVT_BUTTON(self, wxID_CANCEL, self._OnCloseBtn)
861            EVT_BUTTON(self, ID_PROPERTY_REVERT, self._OnRevert)
862    
863            EVT_BUTTON(self, ID_PROPERTY_ADD, self._OnAdd)
864            EVT_BUTTON(self, ID_PROPERTY_EDITSYM, self._OnEditSymbol)
865            EVT_BUTTON(self, ID_PROPERTY_REMOVE, self._OnRemove)
866            EVT_BUTTON(self, ID_PROPERTY_GENCLASS, self._OnGenClass)
867            EVT_BUTTON(self, ID_PROPERTY_MOVEUP, self._OnMoveUp)
868            EVT_BUTTON(self, ID_PROPERTY_MOVEDOWN, self._OnMoveDown)
869    
         #self.Fit()  
870          ######################          ######################
871    
872            text_title.SetFocus()
873          self.haveApplied = False          self.haveApplied = False
874    
875      def EditGroupProperties(self, row):      def unsubscribe_messages(self):
876            """Unsubscribe from all messages."""
877            self.parent.Unsubscribe(MAP_REPLACED, self.map_replaced)
878            self.map.Unsubscribe(MAP_LAYERS_REMOVED, self.map_layers_removed)
879            self.layer.Unsubscribe(LAYER_SHAPESTORE_REPLACED,
880                                   self.layer_shapestore_replaced)
881    
882        def map_layers_removed(self, map):
883            """Subscribed to MAP_LAYERS_REMOVED. If this layer was removed,
884            Close self.
885            """
886            if self.layer not in self.map.Layers():
887                self.Close()
888    
889        def layer_shapestore_replaced(self, *args):
890            """Subscribed to the map's LAYER_SHAPESTORE_REPLACED message.
891    
892            Close self.
893            """
894            self.Close()
895    
896        def map_replaced(self, *args):
897            """Subscribed to the mainwindow's MAP_REPLACED message. Close self."""
898            self.Close()
899    
900        def EditSymbol(self, row):
901            """Open up a dialog where the user can select the properties
902            for a group.
903            """
904          table = self.classGrid.GetTable()          table = self.classGrid.GetTable()
905          prop = table.GetValueAsCustom(row, COL_SYMBOL, None)          prop = table.GetValueAsCustom(row, COL_SYMBOL, None)
906    
907          # get a new ClassGroupProperties object and copy the          # get a new ClassGroupProperties object and copy the
908          # values over to our current object          # values over to our current object
909          propDlg = SelectPropertiesDialog(NULL, prop, self.layer.ShapeType())          propDlg = SelectPropertiesDialog(self, prop, self.layer.ShapeType())
910    
911          self.Enable(False)          self.Enable(False)
912          if propDlg.ShowModal() == wxID_OK:          if propDlg.ShowModal() == wxID_OK:
# Line 859  class Classifier(NonModalDialog): Line 916  class Classifier(NonModalDialog):
916          propDlg.Destroy()          propDlg.Destroy()
917                    
918      def _SetClassification(self, clazz):      def _SetClassification(self, clazz):
919            """Called from the ClassGen dialog when a new classification has
920            been created and should be set in the table.
921            """
922            # FIXME: This could be implemented using a message
923                    
924          self.fields.SetClientData(self.__cur_field, clazz)          self.fields.SetClientData(self.__cur_field, clazz)
925          self.classGrid.GetTable().SetClassification(clazz)          self.classGrid.GetTable().SetClassification(clazz)
926    
927      def __BuildClassification(self, fieldIndex, copyClass = False):      def __BuildClassification(self, fieldIndex, copyClass=False, force=False):
928            """Pack the classification setting into a Classification object.
929            Returns (Classification, fieldName) where fieldName is the selected
930            field in the table that the classification should be used with.
931            """
932    
933  #       numRows = self.classGrid.GetNumberRows()  #       numRows = self.classGrid.GetNumberRows()
934  #       assert numRows > 0  # there should always be a default row  #       assert numRows > 0  # there should always be a default row
935    
 #       clazz = Classification()  
936          if fieldIndex == 0:          if fieldIndex == 0:
937              fieldName = None              fieldName = None
938              fieldType = None              fieldType = None
# Line 876  class Classifier(NonModalDialog): Line 940  class Classifier(NonModalDialog):
940              fieldName = self.fields.GetString(fieldIndex)              fieldName = self.fields.GetString(fieldIndex)
941              fieldType = self.layer.GetFieldType(fieldName)              fieldType = self.layer.GetFieldType(fieldName)
942    
943          clazz = self.classGrid.GetTable().GetClassification()          clazz = self.fields.GetClientData(fieldIndex)
944            if clazz is None or self.classGrid.GetTable().IsModified() or force:
945          if copyClass:              clazz = self.classGrid.GetTable().GetClassification()
946              clazz = copy.deepcopy(clazz)              if copyClass:
947                    clazz = copy.deepcopy(clazz)
         clazz.SetField(fieldName)  
         clazz.SetFieldType(fieldType)  
   
   
 #       table = self.classGrid.GetTable()  
 #       clazz.SetDefaultGroup(table.GetClassGroup(0))  
   
 #       for i in range(1, numRows):  
 #           clazz.AppendGroup(table.GetClassGroup(i))  
948    
949          return clazz          return clazz, fieldName
950    
951      def __SetGridTable(self, fieldIndex, group = None):      def __SetGridTable(self, fieldIndex, group = None):
952            """Set the table with the classification associated with the
953            selected field at fieldIndex. Select the specified group
954            if group is not None.
955            """
956    
957          clazz = self.fields.GetClientData(fieldIndex)          clazz = self.fields.GetClientData(fieldIndex)
958    
# Line 904  class Classifier(NonModalDialog): Line 963  class Classifier(NonModalDialog):
963                      self.layer.GetClassification().                      self.layer.GetClassification().
964                                 GetDefaultGroup().GetProperties()))                                 GetDefaultGroup().GetProperties()))
965    
966              fieldName = self.fields.GetString(fieldIndex)          fieldName = self.fields.GetString(fieldIndex)
967              fieldType = self.layer.GetFieldType(fieldName)          fieldType = self.layer.GetFieldType(fieldName)
             clazz.SetFieldType(fieldType)  
968                                    
969          self.classGrid.CreateTable(clazz, self.layer.ShapeType(), group)          self.classGrid.CreateTable(clazz, fieldType,
970                                       self.layer.ShapeType(), group)
971    
972      def __SetFieldTypeText(self, fieldIndex):      def __SetFieldTypeText(self, fieldIndex):
973            """Set the field type string using the data type of the field
974            at fieldIndex.
975            """
976          fieldName = self.fields.GetString(fieldIndex)          fieldName = self.fields.GetString(fieldIndex)
977          fieldType = self.layer.GetFieldType(fieldName)          fieldType = self.layer.GetFieldType(fieldName)
978    
# Line 918  class Classifier(NonModalDialog): Line 980  class Classifier(NonModalDialog):
980    
981          text = Classifier.type2string[fieldType]          text = Classifier.type2string[fieldType]
982    
983          self.fieldTypeText.SetLabel(_("Field Type: %s") % text)          self.fieldTypeText.SetLabel(_("Data Type: %s") % text)
984    
985      def __SelectField(self, newIndex, oldIndex = -1, group = None):      def __SelectField(self, newIndex, oldIndex = -1, group = None):
986          """This method assumes that the current selection for the          """This method assumes that the current selection for the
# Line 928  class Classifier(NonModalDialog): Line 990  class Classifier(NonModalDialog):
990          assert oldIndex >= -1          assert oldIndex >= -1
991    
992          if oldIndex != -1:          if oldIndex != -1:
993              clazz = self.__BuildClassification(oldIndex)              clazz, name = self.__BuildClassification(oldIndex, force = True)
994              self.fields.SetClientData(oldIndex, clazz)              self.fields.SetClientData(oldIndex, clazz)
995    
996          self.__SetGridTable(newIndex, group)          self.__SetGridTable(newIndex, group)
997    
998          enabled = newIndex != 0          self.__EnableButtons(EB_SELECT_FIELD)
   
         for b in self.controlButtons:  
             b.Enable(enabled)  
999    
1000          self.__SetFieldTypeText(newIndex)          self.__SetFieldTypeText(newIndex)
1001    
1002        def __SetTitle(self, title):
1003            """Set the title of the dialog."""
1004            if title != "":
1005                title = ": " + title
1006    
1007            self.SetTitle(_("Layer Properties") + title)
1008    
1009      def _OnEditGroupProperties(self, event):      def _OnEditSymbol(self, event):
1010            """Open up a dialog for the user to select group properties."""
1011          sel = self.classGrid.GetCurrentSelection()          sel = self.classGrid.GetCurrentSelection()
1012    
1013          if len(sel) == 1:          if len(sel) == 1:
1014              self.EditGroupProperties(sel[0])              self.EditSymbol(sel[0])
1015    
1016      def _OnFieldSelect(self, event):      def _OnFieldSelect(self, event):
1017          index = self.fields.GetSelection()          index = self.fields.GetSelection()
1018          self.__SelectField(index, self.__cur_field)          self.__SelectField(index, self.__cur_field)
1019          self.__cur_field = index          self.__cur_field = index
1020    
1021      def _OnApply(self, event):      def _OnTry(self, event):
1022          """Put the data from the table into a new Classification and hand          """Put the data from the table into a new Classification and hand
1023             it to the layer.             it to the layer.
1024          """          """
1025    
1026          clazz = self.fields.GetClientData(self.__cur_field)          if self.layer.HasClassification():
1027                clazz = self.fields.GetClientData(self.__cur_field)
1028    
1029          #              #
1030          # only build the classification if there wasn't one to              # only build the classification if there wasn't one to
1031          # to begin with or it has been modified              # to begin with or it has been modified
1032          #              #
1033          if clazz is None or self.classGrid.GetTable().IsModified():              self.classGrid.SaveEditControlValue()
1034              clazz = self.__BuildClassification(self.__cur_field, True)              clazz, name = self.__BuildClassification(self.__cur_field, True)
1035    
1036          self.layer.SetClassification(clazz)              self.layer.SetClassificationColumn(name)
1037                self.layer.SetClassification(clazz)
1038    
1039          self.haveApplied = True          self.haveApplied = True
1040    
1041      def _OnOK(self, event):      def _OnOK(self, event):
1042          self._OnApply(event)          self._OnTry(event)
1043          self.Close()          self.Close()
1044    
1045        def OnClose(self, event):
1046            self.unsubscribe_messages()
1047            NonModalNonParentDialog.OnClose(self, event)
1048    
1049      def _OnCloseBtn(self, event):      def _OnCloseBtn(self, event):
1050          """Close is similar to Cancel except that any changes that were          """Close is similar to Cancel except that any changes that were
1051          made and applied remain applied, but the currently displayed          made and applied remain applied, but the currently displayed
# Line 982  class Classifier(NonModalDialog): Line 1054  class Classifier(NonModalDialog):
1054    
1055          self.Close()          self.Close()
1056    
1057      def _OnCancel(self, event):      def _OnRevert(self, event):
1058          """The layer's current classification stays the same."""          """The layer's current classification stays the same."""
1059          if self.haveApplied:          if self.haveApplied:
1060                self.layer.SetClassificationColumn(self.originalClassField)
1061              self.layer.SetClassification(self.originalClass)              self.layer.SetClassification(self.originalClass)
1062    
1063          self.Close()          #self.Close()
1064    
1065      def _OnAdd(self, event):      def _OnAdd(self, event):
1066          self.classGrid.AppendRows()          self.classGrid.AppendRows()
# Line 996  class Classifier(NonModalDialog): Line 1069  class Classifier(NonModalDialog):
1069          self.classGrid.DeleteSelectedRows()          self.classGrid.DeleteSelectedRows()
1070    
1071      def _OnGenClass(self, event):      def _OnGenClass(self, event):
1072            """Open up a dialog for the user to generate classifications."""
1073    
         #if self.genDlg is None:  
1074          self.genDlg = ClassGenDialog(self, self.layer,          self.genDlg = ClassGenDialog(self, self.layer,
1075                            self.fields.GetString(self.__cur_field))                            self.fields.GetString(self.__cur_field))
1076    
1077          EVT_CLOSE(self.genDlg, self._OnGenDialogClose)          EVT_CLOSE(self.genDlg, self._OnGenDialogClose)
1078    
1079          self.fields.Enable(False)          self.__EnableButtons(EB_GEN_CLASS)
         self.controlButtons[BTN_EDIT].Enable(False)  
         self.controlButtons[BTN_GEN].Enable(False)  
1080    
1081          self.genDlg.Show()          self.genDlg.Show()
         #if self.genDlg.ShowModal() == wxID_OK:  
         #    clazz = self.genDlg.GetClassification()  
         #    self.fields.SetClientData(self.__cur_field, clazz)  
         #    self.classGrid.GetTable().SetClassification(clazz)  
         #self.Enable(True)  
         #self.genDlg.Destroy()  
1082    
1083      def _OnGenDialogClose(self, event):      def _OnGenDialogClose(self, event):
1084            """Reenable buttons after the generate classification
1085            dialog is closed.
1086            """
1087          self.genDlg.Destroy()          self.genDlg.Destroy()
1088            self.genDlg = None
1089          self.fields.Enable(True)          self.__EnableButtons(EB_GEN_CLASS)
         self.controlButtons[BTN_EDIT].Enable(True)  
         self.controlButtons[BTN_GEN].Enable(True)  
1090    
1091      def _OnMoveUp(self, event):      def _OnMoveUp(self, event):
1092            """When the user clicks MoveUp, try to move a group up one row."""
1093          sel = self.classGrid.GetCurrentSelection()          sel = self.classGrid.GetCurrentSelection()
1094    
1095          if len(sel) == 1:          if len(sel) == 1:
# Line 1038  class Classifier(NonModalDialog): Line 1105  class Classifier(NonModalDialog):
1105                  self.classGrid.MakeCellVisible(i - 1, 0)                  self.classGrid.MakeCellVisible(i - 1, 0)
1106    
1107      def _OnMoveDown(self, event):      def _OnMoveDown(self, event):
1108            """When the user clicks MoveDown, try to move a group down one row."""
1109          sel = self.classGrid.GetCurrentSelection()          sel = self.classGrid.GetCurrentSelection()
1110    
1111          if len(sel) == 1:          if len(sel) == 1:
# Line 1052  class Classifier(NonModalDialog): Line 1120  class Classifier(NonModalDialog):
1120                  self.classGrid.SelectRow(i + 1)                  self.classGrid.SelectRow(i + 1)
1121                  self.classGrid.MakeCellVisible(i + 1, 0)                  self.classGrid.MakeCellVisible(i + 1, 0)
1122    
1123        def _OnTitleChanged(self, event):
1124            """Update the dialog title when the user changed the layer name."""
1125            obj = event.GetEventObject()
1126    
1127            self.layer.SetTitle(obj.GetValue())
1128            self.__SetTitle(self.layer.Title())
1129    
1130            self.__EnableButtons(EB_LAYER_TITLE)
1131    
1132        def __EnableButtons(self, case):
1133            """Helper method that enables/disables the appropriate buttons
1134            based on the case provided. Cases are constants beginning with EB_.
1135            """
1136    
1137            list = {wxID_OK                 : True,
1138                    wxID_CANCEL             : True,
1139                    ID_PROPERTY_ADD         : True,
1140                    ID_PROPERTY_MOVEUP      : True,
1141                    ID_PROPERTY_MOVEDOWN    : True,
1142                    ID_PROPERTY_REMOVE      : True,
1143                    ID_PROPERTY_SELECT      : True,
1144                    ID_PROPERTY_FIELDTEXT   : True,
1145                    ID_PROPERTY_GENCLASS    : True,
1146                    ID_PROPERTY_EDITSYM     : True}
1147    
1148            if case == EB_LAYER_TITLE:  
1149                if self.layer.Title() == "":
1150                    list[wxID_OK] = False
1151                    list[wxID_CANCEL] = False
1152    
1153            elif case == EB_SELECT_FIELD:
1154                if self.fields.GetSelection() == 0:
1155                    list[ID_PROPERTY_GENCLASS] = False
1156                    list[ID_PROPERTY_ADD] = False
1157                    list[ID_PROPERTY_MOVEUP] = False
1158                    list[ID_PROPERTY_MOVEDOWN] = False
1159                    list[ID_PROPERTY_REMOVE] = False
1160    
1161            elif case == EB_GEN_CLASS:
1162                if self.genDlg is not None:
1163                    list[ID_PROPERTY_SELECT] = False
1164                    list[ID_PROPERTY_FIELDTEXT] = False
1165                    list[ID_PROPERTY_GENCLASS] = False
1166    
1167            for id, enable in list.items():
1168                win = self.FindWindowById(id)
1169                if win:
1170                    win.Enable(enable)
1171    
 ID_SELPROP_OK = 4001  
 ID_SELPROP_CANCEL = 4002  
1172  ID_SELPROP_SPINCTRL = 4002  ID_SELPROP_SPINCTRL = 4002
1173  ID_SELPROP_PREVIEW = 4003  ID_SELPROP_PREVIEW = 4003
1174  ID_SELPROP_STROKECLR = 4004  ID_SELPROP_STROKECLR = 4004
# Line 1063  ID_SELPROP_STROKECLRTRANS = 4006 Line 1177  ID_SELPROP_STROKECLRTRANS = 4006
1177  ID_SELPROP_FILLCLRTRANS = 4007  ID_SELPROP_FILLCLRTRANS = 4007
1178    
1179  class SelectPropertiesDialog(wxDialog):  class SelectPropertiesDialog(wxDialog):
1180        """Dialog that allows the user to select group properties."""
1181    
1182      def __init__(self, parent, prop, shapeType):      def __init__(self, parent, prop, shapeType):
1183            """Open the dialog with the initial prop properties and shapeType."""
1184    
1185          wxDialog.__init__(self, parent, -1, _("Select Properties"),          wxDialog.__init__(self, parent, -1, _("Select Properties"),
1186                            style = wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)                            style = wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
1187    
# Line 1093  class SelectPropertiesDialog(wxDialog): Line 1210  class SelectPropertiesDialog(wxDialog):
1210          ctrlBox = wxBoxSizer(wxVERTICAL)          ctrlBox = wxBoxSizer(wxVERTICAL)
1211    
1212          lineColorBox = wxBoxSizer(wxHORIZONTAL)          lineColorBox = wxBoxSizer(wxHORIZONTAL)
1213          lineColorBox.Add(          button = wxButton(self, ID_SELPROP_STROKECLR, _("Change Line Color"))
1214              wxButton(self, ID_SELPROP_STROKECLR, _("Change Line Color")),          button.SetFocus()
1215              1, wxALL | wxGROW, 4)          lineColorBox.Add(button, 1, wxALL | wxGROW, 4)
1216          EVT_BUTTON(self, ID_SELPROP_STROKECLR, self._OnChangeLineColor)          EVT_BUTTON(self, ID_SELPROP_STROKECLR, self._OnChangeLineColor)
1217    
1218          lineColorBox.Add(          lineColorBox.Add(
# Line 1141  class SelectPropertiesDialog(wxDialog): Line 1258  class SelectPropertiesDialog(wxDialog):
1258          # Control buttons:          # Control buttons:
1259          #          #
1260          buttonBox = wxBoxSizer(wxHORIZONTAL)          buttonBox = wxBoxSizer(wxHORIZONTAL)
1261          buttonBox.Add(wxButton(self, ID_SELPROP_OK, _("OK")),          button_ok = wxButton(self, wxID_OK, _("OK"))
1262                        0, wxALL, 4)          buttonBox.Add(button_ok, 0, wxRIGHT|wxEXPAND, 10)
1263          buttonBox.Add(wxButton(self, ID_SELPROP_CANCEL, _("Cancel")),          buttonBox.Add(wxButton(self, wxID_CANCEL, _("Cancel")),
1264                        0, wxALL, 4)                        0, wxRIGHT|wxEXPAND, 10)
1265          topBox.Add(buttonBox, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_BOTTOM, 10)          topBox.Add(buttonBox, 0, wxALIGN_RIGHT|wxBOTTOM|wxTOP, 10)
1266    
1267            button_ok.SetDefault()
1268                                                                                                                                                                    
1269          EVT_BUTTON(self, ID_SELPROP_OK, self._OnOK)          #EVT_BUTTON(self, wxID_OK, self._OnOK)
1270          EVT_BUTTON(self, ID_SELPROP_CANCEL, self._OnCancel)          #EVT_BUTTON(self, ID_SELPROP_CANCEL, self._OnCancel)
1271                                                                                                                                                                    
1272          self.SetAutoLayout(True)          self.SetAutoLayout(True)
1273          self.SetSizer(topBox)          self.SetSizer(topBox)
1274          topBox.Fit(self)          topBox.Fit(self)
1275          topBox.SetSizeHints(self)          topBox.SetSizeHints(self)
1276    
1277      def _OnOK(self, event):      def OnOK(self, event):
1278          self.EndModal(wxID_OK)          self.EndModal(wxID_OK)
1279    
1280      def _OnCancel(self, event):      def OnCancel(self, event):
1281          self.EndModal(wxID_CANCEL)          self.EndModal(wxID_CANCEL)
1282    
1283      def _OnSpin(self, event):      def _OnSpin(self, event):
# Line 1167  class SelectPropertiesDialog(wxDialog): Line 1286  class SelectPropertiesDialog(wxDialog):
1286    
1287      def __GetColor(self, cur):      def __GetColor(self, cur):
1288          dialog = wxColourDialog(self)          dialog = wxColourDialog(self)
1289          if cur is not Color.Transparent:          if cur is not Transparent:
1290              dialog.GetColourData().SetColour(Color2wxColour(cur))              dialog.GetColourData().SetColour(Color2wxColour(cur))
1291    
1292          ret = None          ret = None
# Line 1185  class SelectPropertiesDialog(wxDialog): Line 1304  class SelectPropertiesDialog(wxDialog):
1304          self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer          self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer
1305    
1306      def _OnChangeLineColorTrans(self, event):      def _OnChangeLineColorTrans(self, event):
1307          self.prop.SetLineColor(Color.Transparent)          self.prop.SetLineColor(Transparent)
1308          self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer          self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer
1309                    
1310      def _OnChangeFillColor(self, event):      def _OnChangeFillColor(self, event):
# Line 1195  class SelectPropertiesDialog(wxDialog): Line 1314  class SelectPropertiesDialog(wxDialog):
1314          self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer          self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer
1315    
1316      def _OnChangeFillColorTrans(self, event):      def _OnChangeFillColorTrans(self, event):
1317          self.prop.SetFill(Color.Transparent)          self.prop.SetFill(Transparent)
1318          self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer          self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer
1319    
1320      def GetClassGroupProperties(self):      def GetClassGroupProperties(self):
# Line 1203  class SelectPropertiesDialog(wxDialog): Line 1322  class SelectPropertiesDialog(wxDialog):
1322    
1323    
1324  class ClassDataPreviewWindow(wxWindow):  class ClassDataPreviewWindow(wxWindow):
1325        """A custom window that draws group properties using the correct shape."""
1326    
1327      def __init__(self, rect, prop, shapeType,      def __init__(self, rect, prop, shapeType,
1328                         parent = None, id = -1, size = wxDefaultSize):                         parent = None, id = -1, size = wxDefaultSize):
1329            """Draws the appropriate shape as specified with shapeType using
1330            prop properities.
1331            """
1332          if parent is not None:          if parent is not None:
1333              wxWindow.__init__(self, parent, id, (0, 0), size)              wxWindow.__init__(self, parent, id, (0, 0), size)
1334              EVT_PAINT(self, self._OnPaint)              EVT_PAINT(self, self._OnPaint)
# Line 1234  class ClassDataPreviewWindow(wxWindow): Line 1357  class ClassDataPreviewWindow(wxWindow):
1357          self.previewer.Draw(dc, rect, self.prop, self.shapeType)          self.previewer.Draw(dc, rect, self.prop, self.shapeType)
1358    
1359  class ClassDataPreviewer:  class ClassDataPreviewer:
1360        """Class that actually draws a group property preview."""
1361    
1362      def Draw(self, dc, rect, prop, shapeType):      def Draw(self, dc, rect, prop, shapeType):
1363    
# Line 1251  class ClassDataPreviewer: Line 1375  class ClassDataPreviewer:
1375              h = rect.GetHeight()              h = rect.GetHeight()
1376    
1377          stroke = prop.GetLineColor()          stroke = prop.GetLineColor()
1378          if stroke is Color.Transparent:          if stroke is Transparent:
1379              pen = wxTRANSPARENT_PEN              pen = wxTRANSPARENT_PEN
1380          else:          else:
1381              pen = wxPen(Color2wxColour(stroke),              pen = wxPen(Color2wxColour(stroke),
# Line 1259  class ClassDataPreviewer: Line 1383  class ClassDataPreviewer:
1383                          wxSOLID)                          wxSOLID)
1384    
1385          stroke = prop.GetFill()          stroke = prop.GetFill()
1386          if stroke is Color.Transparent:          if stroke is Transparent:
1387              brush = wxTRANSPARENT_BRUSH              brush = wxTRANSPARENT_BRUSH
1388          else:          else:
1389              brush = wxBrush(Color2wxColour(stroke), wxSOLID)              brush = wxBrush(Color2wxColour(stroke), wxSOLID)
# Line 1282  class ClassDataPreviewer: Line 1406  class ClassDataPreviewer:
1406              dc.DrawRectangle(x, y, w, h)              dc.DrawRectangle(x, y, w, h)
1407    
1408  class ClassRenderer(wxPyGridCellRenderer):  class ClassRenderer(wxPyGridCellRenderer):
1409        """A wrapper class that can be used to draw group properties in a
1410        grid table.
1411        """
1412    
1413      def __init__(self, shapeType):      def __init__(self, shapeType):
1414          wxPyGridCellRenderer.__init__(self)          wxPyGridCellRenderer.__init__(self)
# Line 1312  class ClassRenderer(wxPyGridCellRenderer Line 1439  class ClassRenderer(wxPyGridCellRenderer
1439    
1440    
1441  class ClassGroupPropertiesCtrl(wxWindow, wxControl):  class ClassGroupPropertiesCtrl(wxWindow, wxControl):
1442        """A custom window and control that draw a preview of group properties
1443        and can open a dialog to modify the properties if the user double-clicks
1444        it.
1445        """
1446    
1447      def __init__(self, parent, id, props, shapeType,      def __init__(self, parent, id, props, shapeType,
1448                   size = wxDefaultSize, style = 0):                   size = wxDefaultSize, style = 0):
1449    
1450          wxWindow.__init__(self, parent, id, size = size, style = style)          wxWindow.__init__(self, parent, id, size = size, style = style)
1451    
1452            self.parent = parent
1453    
1454          self.SetProperties(props)          self.SetProperties(props)
1455          self.SetShapeType(shapeType)          self.SetShapeType(shapeType)
1456          self.AllowEdit(True)          self.AllowEdit(True)
# Line 1356  class ClassGroupPropertiesCtrl(wxWindow, Line 1489  class ClassGroupPropertiesCtrl(wxWindow,
1489          self.Refresh()          self.Refresh()
1490    
1491      def AllowEdit(self, allow):      def AllowEdit(self, allow):
1492            """Allow/Disallow double-clicking on the control."""
1493          self.allowEdit = allow          self.allowEdit = allow
1494    
1495      def DoEdit(self):      def DoEdit(self):
1496            """Open the properties selector dialog."""
1497    
1498          if not self.allowEdit: return          if not self.allowEdit: return
1499    
1500          propDlg = SelectPropertiesDialog(NULL,          propDlg = SelectPropertiesDialog(self.parent,
1501                                           self.GetProperties(),                                           self.GetProperties(),
1502                                           self.GetShapeType())                                           self.GetShapeType())
1503    

Legend:
Removed from v.630  
changed lines
  Added in v.1527

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26