/[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 1207 by bh, Fri Jun 13 18:16:10 2003 UTC revision 2561 by bh, Tue Feb 8 20:34:29 2005 UTC
# Line 1  Line 1 
1  # Copyright (c) 2001, 2003 by Intevation GmbH  # Copyright (c) 2003-2004 by Intevation GmbH
2  # Authors:  # Authors:
3  # Jonathan Coles <[email protected]>  # Jan-Oliver Wagner <[email protected]> (2003-2004)
4    # Martin Schulze <[email protected]> (2004)
5    # Frank Koormann <[email protected]> (2003)
6    # Bernhard Herzog <[email protected]> (2003)
7    # Jonathan Coles <[email protected]> (2003)
8  #  #
9  # This program is free software under the GPL (>=v2)  # This program is free software under the GPL (>=v2)
10  # Read the file COPYING coming with Thuban for details.  # Read the file COPYING coming with Thuban for details.
# Line 8  Line 12 
12  """Dialog for classifying how layers are displayed"""  """Dialog for classifying how layers are displayed"""
13    
14  __version__ = "$Revision$"  __version__ = "$Revision$"
15    # $Source$
16    # $Id$
17    
18  import copy  import copy
19    
# Line 27  from Thuban.Model.classification import Line 33  from Thuban.Model.classification import
33      ClassGroupSingleton, ClassGroupRange, ClassGroupMap, \      ClassGroupSingleton, ClassGroupRange, ClassGroupMap, \
34      ClassGroupProperties      ClassGroupProperties
35    
36  from Thuban.Model.color import Color  from Thuban.Model.color import Transparent
37    
38  from Thuban.Model.layer import Layer, RasterLayer, \  from Thuban.Model.layer import Layer
39      SHAPETYPE_ARC, SHAPETYPE_POLYGON, SHAPETYPE_POINT  from Thuban.Model.data import SHAPETYPE_ARC, SHAPETYPE_POLYGON, SHAPETYPE_POINT
40    
41  from Thuban.UI.classgen import ClassGenDialog  from Thuban.UI.classgen import ClassGenDialog
42    from Thuban.UI.colordialog import ColorDialog
43    
44  from dialogs import NonModalNonParentDialog  from Thuban.UI.layerproperties import LayerProperties
45    from messages import MAP_REPLACED
46    
47  ID_CLASS_TABLE = 40011  ID_CLASS_TABLE = 40011
48    
# Line 84  class ClassGrid(wxGrid): Line 92  class ClassGrid(wxGrid):
92          #print "GetCellAttr ", row, col          #print "GetCellAttr ", row, col
93          #wxGrid.GetCellAttr(self, row, col)          #wxGrid.GetCellAttr(self, row, col)
94    
95      def CreateTable(self, clazz, shapeType, group = None):      def CreateTable(self, clazz, fieldType, shapeType, group = None):
96    
97          assert isinstance(clazz, Classification)          assert isinstance(clazz, Classification)
98    
# Line 104  class ClassGrid(wxGrid): Line 112  class ClassGrid(wxGrid):
112          self.SetSelectionMode(wxGrid.wxGridSelectRows)          self.SetSelectionMode(wxGrid.wxGridSelectRows)
113          self.ClearSelection()          self.ClearSelection()
114    
115          table.Reset(clazz, shapeType, group)          table.Reset(clazz, fieldType, shapeType, group)
116    
117      def GetCurrentSelection(self):      def GetCurrentSelection(self):
118          """Return the currently highlighted rows as an increasing list          """Return the currently highlighted rows as an increasing list
# Line 153  class ClassGrid(wxGrid): Line 161  class ClassGrid(wxGrid):
161              group = self.GetTable().GetClassGroup(sel[0])              group = self.GetTable().GetClassGroup(sel[0])
162              if isinstance(group, ClassGroupDefault):              if isinstance(group, ClassGroupDefault):
163                  wxMessageDialog(self,                  wxMessageDialog(self,
164                                  "The Default group cannot be removed.",                                  _("The Default group cannot be removed."),
165                                  style = wxOK | wxICON_EXCLAMATION).ShowModal()                                  style = wxOK | wxICON_EXCLAMATION).ShowModal()
166                  return                  return
167                    
# Line 258  class ClassTable(wxPyGridTableBase): Line 266  class ClassTable(wxPyGridTableBase):
266    
267    
268      def __init__(self, view = None):      def __init__(self, view = None):
     #def __init__(self, clazz, shapeType, view = None):  
269          """Constructor.          """Constructor.
270    
271          shapeType -- the type of shape that the layer uses          shapeType -- the type of shape that the layer uses
# Line 275  class ClassTable(wxPyGridTableBase): Line 282  class ClassTable(wxPyGridTableBase):
282    
283          self.SetView(view)          self.SetView(view)
284    
285      def Reset(self, clazz, shapeType, group = None):      def Reset(self, clazz, fieldType, shapeType, group = None):
286          """Reset the table with the given data.          """Reset the table with the given data.
287    
288          This is necessary because wxWindows does not allow a grid's          This is necessary because wxWindows does not allow a grid's
# Line 293  class ClassTable(wxPyGridTableBase): Line 300  class ClassTable(wxPyGridTableBase):
300    
301          self.GetView().BeginBatch()          self.GetView().BeginBatch()
302    
303          self.fieldType = clazz.GetFieldType()          self.fieldType = fieldType
304          self.shapeType = shapeType          self.shapeType = shapeType
305    
306          self.SetClassification(clazz, group)          self.SetClassification(clazz, group)
# Line 316  class ClassTable(wxPyGridTableBase): Line 323  class ClassTable(wxPyGridTableBase):
323          self.GetView().FitInside()          self.GetView().FitInside()
324    
325      def GetClassification(self):      def GetClassification(self):
326            """Return the current classification."""
327          return self.clazz          return self.clazz
328    
329      def SetClassification(self, clazz, group = None):      def SetClassification(self, clazz, group = None):
330            """Fill in the table with the given classification.
331            Select the given group if group is not None.
332            """
333    
334          self.GetView().BeginBatch()          self.GetView().BeginBatch()
335    
# Line 326  class ClassTable(wxPyGridTableBase): Line 337  class ClassTable(wxPyGridTableBase):
337    
338          row = -1          row = -1
339          self.clazz = clazz          self.clazz = clazz
340    
341          self.__NotifyRowChanges(old_len, self.GetNumberRows())          self.__NotifyRowChanges(old_len, self.GetNumberRows())
342    
343          #          #
# Line 339  class ClassTable(wxPyGridTableBase): Line 350  class ClassTable(wxPyGridTableBase):
350    
351          self.__Modified()          self.__Modified()
352    
   
353          self.GetView().EndBatch()          self.GetView().EndBatch()
354          self.GetView().FitInside()          self.GetView().FitInside()
355    
356      def __NotifyRowChanges(self, curRows, newRows):      def __NotifyRowChanges(self, curRows, newRows):
357            """Make sure table updates correctly if the number of
358            rows changes.
359            """
360          #          #
361          # silly message processing for updates to the number of          # silly message processing for updates to the number of
362          # rows and columns          # rows and columns
# Line 362  class ClassTable(wxPyGridTableBase): Line 375  class ClassTable(wxPyGridTableBase):
375              self.GetView().ProcessTableMessage(msg)              self.GetView().ProcessTableMessage(msg)
376              self.GetView().FitInside()              self.GetView().FitInside()
377    
   
378      def __SetRow(self, row, group):      def __SetRow(self, row, group):
379          """Set a row's data to that of the group.          """Set a row's data to that of the group.
380    
# Line 433  class ClassTable(wxPyGridTableBase): Line 445  class ClassTable(wxPyGridTableBase):
445          """          """
446    
447          self.SetValueAsCustom(row, col, None, value)          self.SetValueAsCustom(row, col, None, value)
448          
449      def GetValueAsCustom(self, row, col, typeName):      def GetValueAsCustom(self, row, col, typeName):
450          """Return the object that is used to represent the given          """Return the object that is used to represent the given
451             cell coordinates. This may not be a string.             cell coordinates. This may not be a string.
452    
453          typeName -- unused, but needed to overload wxPyGridTableBase          typeName -- unused, but needed to overload wxPyGridTableBase
454          """          """
455    
# Line 594  class ClassTable(wxPyGridTableBase): Line 606  class ClassTable(wxPyGridTableBase):
606              return self.clazz.GetGroup(row - 1)              return self.clazz.GetGroup(row - 1)
607    
608      def SetClassGroup(self, row, group):      def SetClassGroup(self, row, group):
609            """Set the given row to properties of group."""
610          self.__SetRow(row, group)          self.__SetRow(row, group)
611          self.GetView().Refresh()          self.GetView().Refresh()
612    
# Line 671  EB_LAYER_TITLE = 0 Line 684  EB_LAYER_TITLE = 0
684  EB_SELECT_FIELD = 1  EB_SELECT_FIELD = 1
685  EB_GEN_CLASS = 2  EB_GEN_CLASS = 2
686    
687  class Classifier(NonModalNonParentDialog):  class Classifier(LayerProperties):
688    
689      type2string = {None:             _("None"),      type2string = {None:             _("None"),
690                     FIELDTYPE_STRING: _("Text"),                     FIELDTYPE_STRING: _("Text"),
691                     FIELDTYPE_INT:    _("Integer"),                     FIELDTYPE_INT:    _("Integer"),
692                     FIELDTYPE_DOUBLE: _("Decimal")}                     FIELDTYPE_DOUBLE: _("Decimal")}
693    
694      def __init__(self, parent, name, map, layer, group = None):      def __init__(self, parent, name, layer, group = None):
695          NonModalNonParentDialog.__init__(self, parent, name, "")          """Create a Properties/Classification dialog for a layer.
696            The layer is part of map. If group is not None, select that
697          self.__SetTitle(layer.Title())          group in the classification table.
698            """
699    
700          self.layer = layer          LayerProperties.__init__(self, parent, name, layer)
         self.map = map  
701    
         self.map.Subscribe(MAP_LAYERS_REMOVED, self.map_layers_removed)  
702          self.layer.Subscribe(LAYER_SHAPESTORE_REPLACED,          self.layer.Subscribe(LAYER_SHAPESTORE_REPLACED,
703                               self.layer_shapestore_replaced)                               self.layer_shapestore_replaced)
704    
705          self.genDlg = None          self.genDlg = None
706            self.group = group
707    
708          ############################          LayerProperties.dialog_layout(self)
         # Create the controls  
         #  
709    
710          panel = wxPanel(self, -1)      def dialog_layout(self, panel, panelBox):
711    
712          text_title = wxTextCtrl(panel, ID_PROPERTY_TITLE, layer.Title())          if self.layer.HasClassification():
713          self.fieldTypeText = wxStaticText(panel, -1, "")  
714                self.fieldTypeText = wxStaticText(panel, -1, "")
715    
         if layer.HasClassification():  
716              self.originalClass = self.layer.GetClassification()              self.originalClass = self.layer.GetClassification()
717              field = self.originalClass.GetField()              self.originalClassField = self.layer.GetClassificationColumn()
718              fieldType = self.originalClass.GetFieldType()              field = self.originalClassField
719                fieldType = self.layer.GetFieldType(field)
720    
721                table = self.layer.ShapeStore().Table()
722              #              #
723              # make field choice box              # make field choice box
724              #              #
725              self.fields = wxChoice(panel, ID_PROPERTY_SELECT,)              self.fields = wxChoice(panel, ID_PROPERTY_SELECT,)
726    
727              self.num_cols = layer.table.NumColumns()              self.num_cols = table.NumColumns()
728              # just assume the first field in case one hasn't been              # just assume the first field in case one hasn't been
729              # specified in the file.              # specified in the file.
730              self.__cur_field = 0              self.__cur_field = 0
731    
732              self.fields.Append("<None>")              self.fields.Append("<None>")
733    
734              if self.originalClass.GetFieldType() is None:              if fieldType is None:
735                  self.fields.SetClientData(0, copy.deepcopy(self.originalClass))                  self.fields.SetClientData(0, copy.deepcopy(self.originalClass))
736              else:              else:
737                  self.fields.SetClientData(0, None)                  self.fields.SetClientData(0, None)
738    
739              for i in range(self.num_cols):              for i in range(self.num_cols):
740                  name = layer.table.Column(i).name                  name = table.Column(i).name
741                  self.fields.Append(name)                  self.fields.Append(name)
742    
743                  if name == field:                  if name == field:
744                      self.__cur_field = i + 1                      self.__cur_field = i + 1
745                      self.fields.SetClientData(i + 1,                      self.fields.SetClientData(i + 1,
746                                              copy.deepcopy(self.originalClass))                                                copy.deepcopy(self.originalClass))
747                  else:                  else:
748                      self.fields.SetClientData(i + 1, None)                      self.fields.SetClientData(i + 1, None)
749    
# Line 752  class Classifier(NonModalNonParentDialog Line 765  class Classifier(NonModalNonParentDialog
765              # calling __SelectField after creating the classGrid fills in the              # calling __SelectField after creating the classGrid fills in the
766              # grid with the correct information              # grid with the correct information
767              self.fields.SetSelection(self.__cur_field)              self.fields.SetSelection(self.__cur_field)
768              self.__SelectField(self.__cur_field, group = group)              self.__SelectField(self.__cur_field, group = self.group)
   
         button_try = wxButton(self, ID_PROPERTY_TRY, _("Try"))  
         button_revert = wxButton(self, ID_PROPERTY_REVERT, _("Revert"))  
         button_ok = wxButton(self, wxID_OK, _("OK"))  
         button_ok.SetDefault()  
         button_close = wxButton(self, wxID_CANCEL, _("Close"))  
   
         ############################  
         # Layout the controls  
         #  
   
         topBox = wxBoxSizer(wxVERTICAL)  
         panelBox = wxBoxSizer(wxVERTICAL)  
   
         sizer = wxBoxSizer(wxHORIZONTAL)  
         sizer.Add(wxStaticText(panel, -1, _("Title: ")),  
             0, wxALIGN_LEFT | wxALL | wxALIGN_CENTER_VERTICAL, 4)  
         sizer.Add(text_title, 1, wxGROW, 0)  
   
         panelBox.Add(sizer, 0, wxGROW, 4)  
   
         if isinstance(layer, RasterLayer):  
             type = "Image"  
         else:  
             type = layer.ShapeType()  
769    
         panelBox.Add(wxStaticText(panel, -1, _("Type: %s") % type),  
             0, wxALIGN_LEFT | wxALL, 4)  
   
         if layer.HasClassification():  
770    
771              classBox = wxStaticBoxSizer(              classBox = wxStaticBoxSizer(
772                          wxStaticBox(panel, -1, _("Classification")), wxVERTICAL)                          wxStaticBox(panel, -1, _("Classification")), wxVERTICAL)
# Line 806  class Classifier(NonModalNonParentDialog Line 790  class Classifier(NonModalNonParentDialog
790              controlButtonBox.Add(button_moveup, 0, wxGROW|wxALL, 4)              controlButtonBox.Add(button_moveup, 0, wxGROW|wxALL, 4)
791              controlButtonBox.Add(button_movedown, 0, wxGROW|wxALL, 4)              controlButtonBox.Add(button_movedown, 0, wxGROW|wxALL, 4)
792              controlButtonBox.Add(button_edit, 0, wxGROW|wxALL, 4)              controlButtonBox.Add(button_edit, 0, wxGROW|wxALL, 4)
793              controlButtonBox.Add(60, 20, 0, wxGROW|wxALL|wxALIGN_BOTTOM, 4)              controlButtonBox.Add( (60, 20), 0, wxGROW|wxALL|wxALIGN_BOTTOM, 4)
794              controlButtonBox.Add(button_remove, 0,              controlButtonBox.Add(button_remove, 0,
795                                   wxGROW|wxALL|wxALIGN_BOTTOM, 4)                                   wxGROW|wxALL|wxALIGN_BOTTOM, 4)
796    
# Line 817  class Classifier(NonModalNonParentDialog Line 801  class Classifier(NonModalNonParentDialog
801              panelBox.Add(classBox, 1, wxGROW, 0)              panelBox.Add(classBox, 1, wxGROW, 0)
802    
803    
         buttonBox = wxBoxSizer(wxHORIZONTAL)  
         buttonBox.Add(button_try, 0, wxRIGHT|wxEXPAND, 10)  
         buttonBox.Add(button_revert, 0, wxRIGHT|wxEXPAND, 10)  
         buttonBox.Add(button_ok, 0, wxRIGHT|wxEXPAND, 10)  
         buttonBox.Add(button_close, 0, wxRIGHT|wxEXPAND, 10)  
   
         panel.SetAutoLayout(True)  
         panel.SetSizer(panelBox)  
         panelBox.Fit(panel)  
         panelBox.SetSizeHints(panel)  
   
         topBox.Add(panel, 1, wxGROW | wxALL, 4)  
         topBox.Add(buttonBox, 0, wxALIGN_RIGHT|wxBOTTOM|wxTOP, 10)  
   
         self.SetAutoLayout(True)  
         self.SetSizer(topBox)  
         topBox.Fit(self)  
         topBox.SetSizeHints(self)  
         self.Layout()  
   
         ###########  
   
804          EVT_CHOICE(self, ID_PROPERTY_SELECT, self._OnFieldSelect)          EVT_CHOICE(self, ID_PROPERTY_SELECT, self._OnFieldSelect)
         EVT_TEXT(self, ID_PROPERTY_TITLE, self._OnTitleChanged)  
         EVT_BUTTON(self, wxID_OK, self._OnOK)  
         EVT_BUTTON(self, ID_PROPERTY_TRY, self._OnTry)  
         EVT_BUTTON(self, wxID_CANCEL, self._OnCloseBtn)  
         EVT_BUTTON(self, ID_PROPERTY_REVERT, self._OnRevert)  
   
805          EVT_BUTTON(self, ID_PROPERTY_ADD, self._OnAdd)          EVT_BUTTON(self, ID_PROPERTY_ADD, self._OnAdd)
806          EVT_BUTTON(self, ID_PROPERTY_EDITSYM, self._OnEditSymbol)          EVT_BUTTON(self, ID_PROPERTY_EDITSYM, self._OnEditSymbol)
807          EVT_BUTTON(self, ID_PROPERTY_REMOVE, self._OnRemove)          EVT_BUTTON(self, ID_PROPERTY_REMOVE, self._OnRemove)
# Line 853  class Classifier(NonModalNonParentDialog Line 809  class Classifier(NonModalNonParentDialog
809          EVT_BUTTON(self, ID_PROPERTY_MOVEUP, self._OnMoveUp)          EVT_BUTTON(self, ID_PROPERTY_MOVEUP, self._OnMoveUp)
810          EVT_BUTTON(self, ID_PROPERTY_MOVEDOWN, self._OnMoveDown)          EVT_BUTTON(self, ID_PROPERTY_MOVEDOWN, self._OnMoveDown)
811    
         ######################  
   
         text_title.SetFocus()  
         self.haveApplied = False  
   
812      def unsubscribe_messages(self):      def unsubscribe_messages(self):
813          self.map.Unsubscribe(MAP_LAYERS_REMOVED, self.map_layers_removed)          """Unsubscribe from all messages."""
814            LayerProperties.unsubscribe_messages(self)
815          self.layer.Unsubscribe(LAYER_SHAPESTORE_REPLACED,          self.layer.Unsubscribe(LAYER_SHAPESTORE_REPLACED,
816                                 self.layer_shapestore_replaced)                                 self.layer_shapestore_replaced)
817    
     def map_layers_removed(self, map):  
         if self.layer not in self.map.Layers():  
             self.Close()  
   
818      def layer_shapestore_replaced(self, *args):      def layer_shapestore_replaced(self, *args):
819            """Subscribed to the map's LAYER_SHAPESTORE_REPLACED message.
820            Close self.
821            """
822          self.Close()          self.Close()
823    
824      def EditSymbol(self, row):      def EditSymbol(self, row):
825            """Open up a dialog where the user can select the properties
826            for a group.
827            """
828          table = self.classGrid.GetTable()          table = self.classGrid.GetTable()
829          prop = table.GetValueAsCustom(row, COL_SYMBOL, None)          prop = table.GetValueAsCustom(row, COL_SYMBOL, None)
830    
831          # get a new ClassGroupProperties object and copy the          # get a new ClassGroupProperties object and copy the
832          # values over to our current object          # values over to our current object
833          propDlg = SelectPropertiesDialog(NULL, prop, self.layer.ShapeType())          propDlg = SelectPropertiesDialog(self, prop, self.layer.ShapeType())
834    
835          self.Enable(False)          self.Enable(False)
836          if propDlg.ShowModal() == wxID_OK:          if propDlg.ShowModal() == wxID_OK:
# Line 884  class Classifier(NonModalNonParentDialog Line 838  class Classifier(NonModalNonParentDialog
838              table.SetValueAsCustom(row, COL_SYMBOL, None, new_prop)              table.SetValueAsCustom(row, COL_SYMBOL, None, new_prop)
839          self.Enable(True)          self.Enable(True)
840          propDlg.Destroy()          propDlg.Destroy()
841            
842      def _SetClassification(self, clazz):      def _SetClassification(self, clazz):
843                    """Called from the ClassGen dialog when a new classification has
844            been created and should be set in the table.
845            """
846            # FIXME: This could be implemented using a message
847    
848          self.fields.SetClientData(self.__cur_field, clazz)          self.fields.SetClientData(self.__cur_field, clazz)
849          self.classGrid.GetTable().SetClassification(clazz)          self.classGrid.GetTable().SetClassification(clazz)
850    
851      def __BuildClassification(self, fieldIndex, copyClass = False):      def __BuildClassification(self, fieldIndex, copyClass=False, force=False):
852            """Pack the classification setting into a Classification object.
853            Returns (Classification, fieldName) where fieldName is the selected
854            field in the table that the classification should be used with.
855            """
856    
857  #       numRows = self.classGrid.GetNumberRows()  #       numRows = self.classGrid.GetNumberRows()
858  #       assert numRows > 0  # there should always be a default row  #       assert numRows > 0  # there should always be a default row
859    
 #       clazz = Classification()  
860          if fieldIndex == 0:          if fieldIndex == 0:
861              fieldName = None              fieldName = None
862              fieldType = None              fieldType = None
# Line 903  class Classifier(NonModalNonParentDialog Line 864  class Classifier(NonModalNonParentDialog
864              fieldName = self.fields.GetString(fieldIndex)              fieldName = self.fields.GetString(fieldIndex)
865              fieldType = self.layer.GetFieldType(fieldName)              fieldType = self.layer.GetFieldType(fieldName)
866    
867          clazz = self.classGrid.GetTable().GetClassification()          clazz = self.fields.GetClientData(fieldIndex)
868            if clazz is None or self.classGrid.GetTable().IsModified() or force:
869          if copyClass:              clazz = self.classGrid.GetTable().GetClassification()
870              clazz = copy.deepcopy(clazz)              if copyClass:
871                    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))  
872    
873          return clazz          return clazz, fieldName
874    
875      def __SetGridTable(self, fieldIndex, group = None):      def __SetGridTable(self, fieldIndex, group = None):
876            """Set the table with the classification associated with the
877            selected field at fieldIndex. Select the specified group
878            if group is not None.
879            """
880    
881          clazz = self.fields.GetClientData(fieldIndex)          clazz = self.fields.GetClientData(fieldIndex)
882    
# Line 931  class Classifier(NonModalNonParentDialog Line 887  class Classifier(NonModalNonParentDialog
887                      self.layer.GetClassification().                      self.layer.GetClassification().
888                                 GetDefaultGroup().GetProperties()))                                 GetDefaultGroup().GetProperties()))
889    
890              fieldName = self.fields.GetString(fieldIndex)          fieldName = self.fields.GetString(fieldIndex)
891              fieldType = self.layer.GetFieldType(fieldName)          fieldType = self.layer.GetFieldType(fieldName)
             clazz.SetFieldType(fieldType)  
892                                    
893          self.classGrid.CreateTable(clazz, self.layer.ShapeType(), group)          self.classGrid.CreateTable(clazz, fieldType,
894                                       self.layer.ShapeType(), group)
895    
896      def __SetFieldTypeText(self, fieldIndex):      def __SetFieldTypeText(self, fieldIndex):
897            """Set the field type string using the data type of the field
898            at fieldIndex.
899            """
900          fieldName = self.fields.GetString(fieldIndex)          fieldName = self.fields.GetString(fieldIndex)
901          fieldType = self.layer.GetFieldType(fieldName)          fieldType = self.layer.GetFieldType(fieldName)
902    
# Line 955  class Classifier(NonModalNonParentDialog Line 914  class Classifier(NonModalNonParentDialog
914          assert oldIndex >= -1          assert oldIndex >= -1
915    
916          if oldIndex != -1:          if oldIndex != -1:
917              clazz = self.__BuildClassification(oldIndex)              clazz, name = self.__BuildClassification(oldIndex, force = True)
918              self.fields.SetClientData(oldIndex, clazz)              self.fields.SetClientData(oldIndex, clazz)
919    
920          self.__SetGridTable(newIndex, group)          self.__SetGridTable(newIndex, group)
921    
922          self.__EnableButtons(EB_SELECT_FIELD, newIndex != 0)          self.__EnableButtons(EB_SELECT_FIELD)
923    
924          self.__SetFieldTypeText(newIndex)          self.__SetFieldTypeText(newIndex)
925    
926      def __SetTitle(self, title):      def __SetTitle(self, title):
927            """Set the title of the dialog."""
928          if title != "":          if title != "":
929              title = ": " + title              title = ": " + title
930    
931          self.SetTitle(_("Layer Properties") + title)          self.SetTitle(_("Layer Properties") + title)
932    
933      def _OnEditSymbol(self, event):      def _OnEditSymbol(self, event):
934            """Open up a dialog for the user to select group properties."""
935          sel = self.classGrid.GetCurrentSelection()          sel = self.classGrid.GetCurrentSelection()
936    
937          if len(sel) == 1:          if len(sel) == 1:
# Line 981  class Classifier(NonModalNonParentDialog Line 942  class Classifier(NonModalNonParentDialog
942          self.__SelectField(index, self.__cur_field)          self.__SelectField(index, self.__cur_field)
943          self.__cur_field = index          self.__cur_field = index
944    
945      def _OnTry(self, event):      def OnTry(self, event):
946          """Put the data from the table into a new Classification and hand          """Put the data from the table into a new Classification and hand
947             it to the layer.             it to the layer.
948          """          """
# Line 994  class Classifier(NonModalNonParentDialog Line 955  class Classifier(NonModalNonParentDialog
955              # to begin with or it has been modified              # to begin with or it has been modified
956              #              #
957              self.classGrid.SaveEditControlValue()              self.classGrid.SaveEditControlValue()
958              if clazz is None or self.classGrid.GetTable().IsModified():              clazz, name = self.__BuildClassification(self.__cur_field, True)
                 clazz = self.__BuildClassification(self.__cur_field, True)  
959    
960                self.layer.SetClassificationColumn(name)
961              self.layer.SetClassification(clazz)              self.layer.SetClassification(clazz)
962    
963          self.haveApplied = True          self.haveApplied = True
964    
965      def _OnOK(self, event):      def OnOK(self, event):
966          self._OnTry(event)          self.OnTry(event)
         self.Close()  
   
     def OnClose(self, event):  
         self.unsubscribe_messages()  
         NonModalNonParentDialog.OnClose(self, event)  
   
     def _OnCloseBtn(self, event):  
         """Close is similar to Cancel except that any changes that were  
         made and applied remain applied, but the currently displayed  
         classification is discarded.  
         """  
   
967          self.Close()          self.Close()
968    
969      def _OnRevert(self, event):      def OnRevert(self, event):
970          """The layer's current classification stays the same."""          """The layer's current classification stays the same."""
971          if self.haveApplied:          if self.haveApplied and self.layer.HasClassification():
972                self.layer.SetClassificationColumn(self.originalClassField)
973              self.layer.SetClassification(self.originalClass)              self.layer.SetClassification(self.originalClass)
974    
975          #self.Close()          #self.Close()
# Line 1031  class Classifier(NonModalNonParentDialog Line 981  class Classifier(NonModalNonParentDialog
981          self.classGrid.DeleteSelectedRows()          self.classGrid.DeleteSelectedRows()
982    
983      def _OnGenClass(self, event):      def _OnGenClass(self, event):
984            """Open up a dialog for the user to generate classifications."""
985    
986          self.genDlg = ClassGenDialog(self, self.layer,          self.genDlg = ClassGenDialog(self, self.layer,
987                            self.fields.GetString(self.__cur_field))                            self.fields.GetString(self.__cur_field))
988    
989          EVT_CLOSE(self.genDlg, self._OnGenDialogClose)          EVT_CLOSE(self.genDlg, self._OnGenDialogClose)
990    
991          self.__EnableButtons(EB_GEN_CLASS, False)          self.__EnableButtons(EB_GEN_CLASS)
992    
993          self.genDlg.Show()          self.genDlg.Show()
994    
995      def _OnGenDialogClose(self, event):      def _OnGenDialogClose(self, event):
996            """Reenable buttons after the generate classification
997            dialog is closed.
998            """
999          self.genDlg.Destroy()          self.genDlg.Destroy()
1000          self.__EnableButtons(EB_GEN_CLASS, True)          self.genDlg = None
1001            self.__EnableButtons(EB_GEN_CLASS)
1002    
1003      def _OnMoveUp(self, event):      def _OnMoveUp(self, event):
1004            """When the user clicks MoveUp, try to move a group up one row."""
1005          sel = self.classGrid.GetCurrentSelection()          sel = self.classGrid.GetCurrentSelection()
1006    
1007          if len(sel) == 1:          if len(sel) == 1:
# Line 1061  class Classifier(NonModalNonParentDialog Line 1017  class Classifier(NonModalNonParentDialog
1017                  self.classGrid.MakeCellVisible(i - 1, 0)                  self.classGrid.MakeCellVisible(i - 1, 0)
1018    
1019      def _OnMoveDown(self, event):      def _OnMoveDown(self, event):
1020            """When the user clicks MoveDown, try to move a group down one row."""
1021          sel = self.classGrid.GetCurrentSelection()          sel = self.classGrid.GetCurrentSelection()
1022    
1023          if len(sel) == 1:          if len(sel) == 1:
# Line 1076  class Classifier(NonModalNonParentDialog Line 1033  class Classifier(NonModalNonParentDialog
1033                  self.classGrid.MakeCellVisible(i + 1, 0)                  self.classGrid.MakeCellVisible(i + 1, 0)
1034    
1035      def _OnTitleChanged(self, event):      def _OnTitleChanged(self, event):
1036            """Update the dialog title when the user changed the layer name."""
1037          obj = event.GetEventObject()          obj = event.GetEventObject()
1038    
1039          self.layer.SetTitle(obj.GetValue())          self.layer.SetTitle(obj.GetValue())
1040          self.__SetTitle(self.layer.Title())          self.__SetTitle(self.layer.Title())
1041    
1042          self.__EnableButtons(EB_LAYER_TITLE, self.layer.Title() != "")          self.__EnableButtons(EB_LAYER_TITLE)
1043    
1044        def __EnableButtons(self, case):
1045            """Helper method that enables/disables the appropriate buttons
1046            based on the case provided. Cases are constants beginning with EB_.
1047            """
1048    
1049      def __EnableButtons(self, case, enable):          list = {wxID_OK                 : True,
1050                    wxID_CANCEL             : True,
1051                    ID_PROPERTY_ADD         : True,
1052                    ID_PROPERTY_MOVEUP      : True,
1053                    ID_PROPERTY_MOVEDOWN    : True,
1054                    ID_PROPERTY_REMOVE      : True,
1055                    ID_PROPERTY_SELECT      : True,
1056                    ID_PROPERTY_FIELDTEXT   : True,
1057                    ID_PROPERTY_GENCLASS    : True,
1058                    ID_PROPERTY_EDITSYM     : True}
1059    
1060          if case == EB_LAYER_TITLE:            if case == EB_LAYER_TITLE:  
1061              list = (wxID_OK,              if self.layer.Title() == "":
1062                      wxID_CANCEL)                  list[wxID_OK] = False
1063                    list[wxID_CANCEL] = False
1064    
1065          elif case == EB_SELECT_FIELD:          elif case == EB_SELECT_FIELD:
1066              list = (ID_PROPERTY_GENCLASS,              if self.fields.GetSelection() == 0:
1067                      ID_PROPERTY_ADD,                  list[ID_PROPERTY_GENCLASS] = False
1068                      ID_PROPERTY_MOVEUP,                  list[ID_PROPERTY_ADD] = False
1069                      ID_PROPERTY_MOVEDOWN,                  list[ID_PROPERTY_MOVEUP] = False
1070                      ID_PROPERTY_EDITSYM,                  list[ID_PROPERTY_MOVEDOWN] = False
1071                      ID_PROPERTY_REMOVE)                  list[ID_PROPERTY_REMOVE] = False
1072    
1073          elif case == EB_GEN_CLASS:          elif case == EB_GEN_CLASS:
1074              list = (ID_PROPERTY_SELECT,              if self.genDlg is not None:
1075                      ID_PROPERTY_FIELDTEXT,                  list[ID_PROPERTY_SELECT] = False
1076                      ID_PROPERTY_GENCLASS,                  list[ID_PROPERTY_FIELDTEXT] = False
1077                      ID_PROPERTY_EDITSYM)                  list[ID_PROPERTY_GENCLASS] = False
1078    
1079          for id in list:          for id, enable in list.items():
1080              self.FindWindowById(id).Enable(enable)              win = self.FindWindowById(id)
1081                if win:
1082                    win.Enable(enable)
1083    
1084  ID_SELPROP_SPINCTRL = 4002  ID_SELPROP_SPINCTRL_LINEWIDTH = 4002
1085  ID_SELPROP_PREVIEW = 4003  ID_SELPROP_PREVIEW = 4003
1086  ID_SELPROP_STROKECLR = 4004  ID_SELPROP_STROKECLR = 4004
1087  ID_SELPROP_FILLCLR = 4005  ID_SELPROP_FILLCLR = 4005
1088  ID_SELPROP_STROKECLRTRANS = 4006  ID_SELPROP_STROKECLRTRANS = 4006
1089  ID_SELPROP_FILLCLRTRANS = 4007  ID_SELPROP_FILLCLRTRANS = 4007
1090    ID_SELPROP_SPINCTRL_SIZE = 4008
1091    
1092  class SelectPropertiesDialog(wxDialog):  class SelectPropertiesDialog(wxDialog):
1093        """Dialog that allows the user to select group properties."""
1094    
1095      def __init__(self, parent, prop, shapeType):      def __init__(self, parent, prop, shapeType):
1096            """Open the dialog with the initial prop properties and shapeType."""
1097    
1098          wxDialog.__init__(self, parent, -1, _("Select Properties"),          wxDialog.__init__(self, parent, -1, _("Select Properties"),
1099                            style = wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)                            style = wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
1100    
# Line 1172  class SelectPropertiesDialog(wxDialog): Line 1151  class SelectPropertiesDialog(wxDialog):
1151              ctrlBox.Add(fillColorBox, 0,              ctrlBox.Add(fillColorBox, 0,
1152                          wxALIGN_CENTER_HORIZONTAL | wxALL | wxGROW, 4)                          wxALIGN_CENTER_HORIZONTAL | wxALL | wxGROW, 4)
1153    
1154            # Line width selection
1155          spinBox = wxBoxSizer(wxHORIZONTAL)          spinBox = wxBoxSizer(wxHORIZONTAL)
1156          spinBox.Add(wxStaticText(self, -1, _("Line Width: ")),          spinBox.Add(wxStaticText(self, -1, _("Line Width: ")),
1157                  0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 4)                  0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 4)
1158          self.spinCtrl = wxSpinCtrl(self, ID_SELPROP_SPINCTRL,          self.spinCtrl_linewidth = wxSpinCtrl(self,
1159                                     min=1, max=10,                                               ID_SELPROP_SPINCTRL_LINEWIDTH,
1160                                     value=str(prop.GetLineWidth()),                                               min=1, max=10,
1161                                     initial=prop.GetLineWidth())                                               value=str(prop.GetLineWidth()),
1162                                                 initial=prop.GetLineWidth())
1163    
1164          EVT_SPINCTRL(self, ID_SELPROP_SPINCTRL, self._OnSpin)          EVT_SPINCTRL(self, ID_SELPROP_SPINCTRL_LINEWIDTH,
1165                         self._OnSpinLineWidth)
         spinBox.Add(self.spinCtrl, 0, wxALIGN_LEFT | wxALL, 4)  
1166    
1167            spinBox.Add(self.spinCtrl_linewidth, 0, wxALIGN_LEFT | wxALL, 4)
1168          ctrlBox.Add(spinBox, 0, wxALIGN_RIGHT | wxALL, 0)          ctrlBox.Add(spinBox, 0, wxALIGN_RIGHT | wxALL, 0)
1169    
1170            # Size selection
1171            if shapeType == SHAPETYPE_POINT:
1172                spinBox = wxBoxSizer(wxHORIZONTAL)
1173                spinBox.Add(wxStaticText(self, -1, _("Size: ")),
1174                            0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 4)
1175                self.spinCtrl_size = wxSpinCtrl(self, ID_SELPROP_SPINCTRL_SIZE,
1176                                                min=1, max=100,
1177                                                value=str(prop.GetSize()),
1178                                                initial=prop.GetSize())
1179    
1180                EVT_SPINCTRL(self, ID_SELPROP_SPINCTRL_SIZE, self._OnSpinSize)
1181    
1182                spinBox.Add(self.spinCtrl_size, 0, wxALIGN_LEFT | wxALL, 4)
1183                ctrlBox.Add(spinBox, 0, wxALIGN_RIGHT | wxALL, 0)
1184    
1185    
1186          itemBox.Add(ctrlBox, 0, wxALIGN_RIGHT | wxALL | wxGROW, 0)          itemBox.Add(ctrlBox, 0, wxALIGN_RIGHT | wxALL | wxGROW, 0)
1187          topBox.Add(itemBox, 1, wxALIGN_LEFT | wxALL | wxGROW, 0)          topBox.Add(itemBox, 1, wxALIGN_LEFT | wxALL | wxGROW, 0)
1188    
# Line 1193  class SelectPropertiesDialog(wxDialog): Line 1191  class SelectPropertiesDialog(wxDialog):
1191          #          #
1192          buttonBox = wxBoxSizer(wxHORIZONTAL)          buttonBox = wxBoxSizer(wxHORIZONTAL)
1193          button_ok = wxButton(self, wxID_OK, _("OK"))          button_ok = wxButton(self, wxID_OK, _("OK"))
         button_ok.SetDefault()  
1194          buttonBox.Add(button_ok, 0, wxRIGHT|wxEXPAND, 10)          buttonBox.Add(button_ok, 0, wxRIGHT|wxEXPAND, 10)
1195          buttonBox.Add(wxButton(self, wxID_CANCEL, _("Cancel")),          buttonBox.Add(wxButton(self, wxID_CANCEL, _("Cancel")),
1196                        0, wxRIGHT|wxEXPAND, 10)                        0, wxRIGHT|wxEXPAND, 10)
1197          topBox.Add(buttonBox, 0, wxALIGN_RIGHT|wxBOTTOM|wxTOP, 10)          topBox.Add(buttonBox, 0, wxALIGN_RIGHT|wxBOTTOM|wxTOP, 10)
1198                                                                                    
1199            button_ok.SetDefault()
1200    
1201          #EVT_BUTTON(self, wxID_OK, self._OnOK)          #EVT_BUTTON(self, wxID_OK, self._OnOK)
1202          #EVT_BUTTON(self, ID_SELPROP_CANCEL, self._OnCancel)          #EVT_BUTTON(self, ID_SELPROP_CANCEL, self._OnCancel)
1203                                                                                    
1204          self.SetAutoLayout(True)          self.SetAutoLayout(True)
1205          self.SetSizer(topBox)          self.SetSizer(topBox)
1206          topBox.Fit(self)          topBox.Fit(self)
# Line 1213  class SelectPropertiesDialog(wxDialog): Line 1212  class SelectPropertiesDialog(wxDialog):
1212      def OnCancel(self, event):      def OnCancel(self, event):
1213          self.EndModal(wxID_CANCEL)          self.EndModal(wxID_CANCEL)
1214    
1215      def _OnSpin(self, event):      def _OnSpinLineWidth(self, event):
1216          self.prop.SetLineWidth(self.spinCtrl.GetValue())          self.prop.SetLineWidth(self.spinCtrl_linewidth.GetValue())
1217            self.previewWin.Refresh()
1218    
1219        def _OnSpinSize(self, event):
1220            self.prop.SetSize(self.spinCtrl_size.GetValue())
1221          self.previewWin.Refresh()          self.previewWin.Refresh()
1222    
1223      def __GetColor(self, cur):      def __GetColor(self, cur):
1224          dialog = wxColourDialog(self)          dialog = ColorDialog(self)
1225          if cur is not Color.Transparent:          dialog.SetColor(cur)
             dialog.GetColourData().SetColour(Color2wxColour(cur))  
1226    
1227          ret = None          ret = None
1228          if dialog.ShowModal() == wxID_OK:          if dialog.ShowModal() == wxID_OK:
1229              ret = wxColour2Color(dialog.GetColourData().GetColour())              ret = dialog.GetColor()
1230    
1231          dialog.Destroy()          dialog.Destroy()
1232    
1233          return ret          return ret
1234            
1235      def _OnChangeLineColor(self, event):      def _OnChangeLineColor(self, event):
1236          clr = self.__GetColor(self.prop.GetLineColor())          clr = self.__GetColor(self.prop.GetLineColor())
1237          if clr is not None:          if clr is not None:
# Line 1237  class SelectPropertiesDialog(wxDialog): Line 1239  class SelectPropertiesDialog(wxDialog):
1239          self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer          self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer
1240    
1241      def _OnChangeLineColorTrans(self, event):      def _OnChangeLineColorTrans(self, event):
1242          self.prop.SetLineColor(Color.Transparent)          self.prop.SetLineColor(Transparent)
1243          self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer          self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer
1244            
1245      def _OnChangeFillColor(self, event):      def _OnChangeFillColor(self, event):
1246          clr = self.__GetColor(self.prop.GetFill())          clr = self.__GetColor(self.prop.GetFill())
1247          if clr is not None:          if clr is not None:
# Line 1247  class SelectPropertiesDialog(wxDialog): Line 1249  class SelectPropertiesDialog(wxDialog):
1249          self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer          self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer
1250    
1251      def _OnChangeFillColorTrans(self, event):      def _OnChangeFillColorTrans(self, event):
1252          self.prop.SetFill(Color.Transparent)          self.prop.SetFill(Transparent)
1253          self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer          self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer
1254    
1255      def GetClassGroupProperties(self):      def GetClassGroupProperties(self):
# Line 1255  class SelectPropertiesDialog(wxDialog): Line 1257  class SelectPropertiesDialog(wxDialog):
1257    
1258    
1259  class ClassDataPreviewWindow(wxWindow):  class ClassDataPreviewWindow(wxWindow):
1260        """A custom window that draws group properties using the correct shape."""
1261    
1262      def __init__(self, rect, prop, shapeType,      def __init__(self, rect, prop, shapeType,
1263                         parent = None, id = -1, size = wxDefaultSize):                         parent = None, id = -1, size = wxDefaultSize):
1264            """Draws the appropriate shape as specified with shapeType using
1265            prop properities.
1266            """
1267          if parent is not None:          if parent is not None:
1268              wxWindow.__init__(self, parent, id, (0, 0), size)              wxWindow.__init__(self, parent, id, (0, 0), size)
1269              EVT_PAINT(self, self._OnPaint)              EVT_PAINT(self, self._OnPaint)
# Line 1286  class ClassDataPreviewWindow(wxWindow): Line 1292  class ClassDataPreviewWindow(wxWindow):
1292          self.previewer.Draw(dc, rect, self.prop, self.shapeType)          self.previewer.Draw(dc, rect, self.prop, self.shapeType)
1293    
1294  class ClassDataPreviewer:  class ClassDataPreviewer:
1295        """Class that actually draws a group property preview."""
1296    
1297      def Draw(self, dc, rect, prop, shapeType):      def Draw(self, dc, rect, prop, shapeType):
1298            """Draw the property.
1299    
1300            returns: (w, h) as adapted extend if the drawing size
1301            exceeded the given rect. This can only be the case
1302            for point symbols. If the symbol fits the given rect,
1303            None is returned.
1304            """
1305    
1306          assert dc is not None          assert dc is not None
1307          assert isinstance(prop, ClassGroupProperties)          assert isinstance(prop, ClassGroupProperties)
# Line 1303  class ClassDataPreviewer: Line 1317  class ClassDataPreviewer:
1317              h = rect.GetHeight()              h = rect.GetHeight()
1318    
1319          stroke = prop.GetLineColor()          stroke = prop.GetLineColor()
1320          if stroke is Color.Transparent:          if stroke is Transparent:
1321              pen = wxTRANSPARENT_PEN              pen = wxTRANSPARENT_PEN
1322          else:          else:
1323              pen = wxPen(Color2wxColour(stroke),              pen = wxPen(Color2wxColour(stroke),
# Line 1311  class ClassDataPreviewer: Line 1325  class ClassDataPreviewer:
1325                          wxSOLID)                          wxSOLID)
1326    
1327          stroke = prop.GetFill()          stroke = prop.GetFill()
1328          if stroke is Color.Transparent:          if stroke is Transparent:
1329              brush = wxTRANSPARENT_BRUSH              brush = wxTRANSPARENT_BRUSH
1330          else:          else:
1331              brush = wxBrush(Color2wxColour(stroke), wxSOLID)              brush = wxBrush(Color2wxColour(stroke), wxSOLID)
# Line 1327  class ClassDataPreviewer: Line 1341  class ClassDataPreviewer:
1341    
1342          elif shapeType == SHAPETYPE_POINT:          elif shapeType == SHAPETYPE_POINT:
1343    
1344              dc.DrawCircle(x + w/2, y + h/2,              dc.DrawCircle(x + w/2, y + h/2, prop.GetSize())
1345                            (min(w, h) - prop.GetLineWidth())/2)              circle_size =  prop.GetSize() * 2 + prop.GetLineWidth() * 2
1346                new_h = h
1347                new_w = w
1348                if h < circle_size: new_h = circle_size
1349                if w < circle_size: new_w = circle_size
1350                if new_h > h or new_w > w:
1351                    return (new_w, new_h)
1352    
1353          elif shapeType == SHAPETYPE_POLYGON:          elif shapeType == SHAPETYPE_POLYGON:
1354              dc.DrawRectangle(x, y, w, h)              dc.DrawRectangle(x, y, w, h)
1355    
1356            return None
1357    
1358  class ClassRenderer(wxPyGridCellRenderer):  class ClassRenderer(wxPyGridCellRenderer):
1359        """A wrapper class that can be used to draw group properties in a
1360        grid table.
1361        """
1362    
1363      def __init__(self, shapeType):      def __init__(self, shapeType):
1364          wxPyGridCellRenderer.__init__(self)          wxPyGridCellRenderer.__init__(self)
# Line 1351  class ClassRenderer(wxPyGridCellRenderer Line 1376  class ClassRenderer(wxPyGridCellRenderer
1376                           rect.GetWidth(), rect.GetHeight())                           rect.GetWidth(), rect.GetHeight())
1377    
1378          if not isinstance(data, ClassGroupMap):          if not isinstance(data, ClassGroupMap):
1379              self.previewer.Draw(dc, rect, data.GetProperties(), self.shapeType)              new_size = self.previewer.Draw(dc, rect, data.GetProperties(),
1380                                               self.shapeType)
1381                if new_size is not None:
1382                    (new_w, new_h) = new_size
1383                    grid.SetRowSize(row, new_h)
1384                    grid.SetColSize(col, new_h)
1385                    grid.ForceRefresh()
1386    
1387                    # now that we know the height, redraw everything
1388                    rect.SetHeight(new_h)
1389                    rect.SetWidth(new_w)
1390                    dc.DestroyClippingRegion()
1391                    dc.SetClippingRegion(rect.GetX(), rect.GetY(),
1392                                         rect.GetWidth(), rect.GetHeight())
1393                    dc.SetPen(wxPen(wxLIGHT_GREY))
1394                    dc.SetBrush(wxBrush(wxLIGHT_GREY, wxSOLID))
1395                    dc.DrawRectangle(rect.GetX(), rect.GetY(),
1396                                     rect.GetWidth(), rect.GetHeight())
1397                    self.previewer.Draw(dc, rect, data.GetProperties(),
1398                                        self.shapeType)
1399    
1400          if isSelected:          if isSelected:
1401              dc.SetPen(wxPen(wxBLACK, 1, wxSOLID))              dc.SetPen(wxPen(wxBLACK, 1, wxSOLID))
# Line 1363  class ClassRenderer(wxPyGridCellRenderer Line 1407  class ClassRenderer(wxPyGridCellRenderer
1407          dc.DestroyClippingRegion()          dc.DestroyClippingRegion()
1408    
1409    
1410  class ClassGroupPropertiesCtrl(wxWindow, wxControl):  class ClassGroupPropertiesCtrl(wxControl):
1411        """A custom window and control that draw a preview of group properties
1412        and can open a dialog to modify the properties if the user double-clicks
1413        it.
1414        """
1415    
1416      def __init__(self, parent, id, props, shapeType,      def __init__(self, parent, id, props, shapeType,
1417                   size = wxDefaultSize, style = 0):                   size = wxDefaultSize, style = 0):
1418            wxControl.__init__(self, parent, id, size = size, style = style)
1419    
1420          wxWindow.__init__(self, parent, id, size = size, style = style)          self.parent = parent
1421    
1422          self.SetProperties(props)          self.SetProperties(props)
1423          self.SetShapeType(shapeType)          self.SetShapeType(shapeType)
# Line 1408  class ClassGroupPropertiesCtrl(wxWindow, Line 1457  class ClassGroupPropertiesCtrl(wxWindow,
1457          self.Refresh()          self.Refresh()
1458    
1459      def AllowEdit(self, allow):      def AllowEdit(self, allow):
1460            """Allow/Disallow double-clicking on the control."""
1461          self.allowEdit = allow          self.allowEdit = allow
1462    
1463      def DoEdit(self):      def DoEdit(self):
1464            """Open the properties selector dialog."""
1465    
1466          if not self.allowEdit: return          if not self.allowEdit: return
1467    
1468          propDlg = SelectPropertiesDialog(NULL,          propDlg = SelectPropertiesDialog(self.parent,
1469                                           self.GetProperties(),                                           self.GetProperties(),
1470                                           self.GetShapeType())                                           self.GetShapeType())
1471    
# Line 1426  class ClassGroupPropertiesCtrl(wxWindow, Line 1478  class ClassGroupPropertiesCtrl(wxWindow,
1478    
1479      def _OnLeftDClick(self, event):      def _OnLeftDClick(self, event):
1480          self.DoEdit()          self.DoEdit()
1481    

Legend:
Removed from v.1207  
changed lines
  Added in v.2561

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26