/[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 878 by jonathan, Fri May 9 16:32:31 2003 UTC revision 2386 by jan, Thu Oct 7 14:43:45 2004 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 20  from wxPython.grid import * Line 26  from wxPython.grid import *
26  from Thuban import _  from Thuban import _
27  from Thuban.UI.common import Color2wxColour, wxColour2Color  from Thuban.UI.common import Color2wxColour, wxColour2Color
28    
29    from Thuban.Model.messages import MAP_LAYERS_REMOVED, LAYER_SHAPESTORE_REPLACED
30  from Thuban.Model.range import Range  from Thuban.Model.range import Range
31  from Thuban.Model.classification import \  from Thuban.Model.classification import \
32      Classification, ClassGroupDefault, \      Classification, ClassGroupDefault, \
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, \  from Thuban.Model.layer import Layer, RasterLayer
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, ClassGenerator  from Thuban.UI.classgen import ClassGenDialog
42    from Thuban.UI.colordialog import ColorDialog
43    
44  from dialogs import NonModalDialog  from dialogs import NonModalNonParentDialog
45    from messages import MAP_REPLACED
46    
47  ID_CLASS_TABLE = 40011  ID_CLASS_TABLE = 40011
48    
# Line 83  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 103  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 257  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 274  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 292  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 315  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 325  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 338  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 361  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 432  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 593  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 670  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(NonModalDialog):  class Classifier(NonModalNonParentDialog):
688    
689      type2string = {None:             _("None"),      type2string = {None:             _("None"),
690                     FIELDTYPE_STRING: _("Text"),                     FIELDTYPE_STRING: _("Text"),
# Line 678  class Classifier(NonModalDialog): Line 692  class Classifier(NonModalDialog):
692                     FIELDTYPE_DOUBLE: _("Decimal")}                     FIELDTYPE_DOUBLE: _("Decimal")}
693    
694      def __init__(self, parent, name, layer, group = None):      def __init__(self, parent, name, layer, group = None):
695          NonModalDialog.__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            group in the classification table.
698            """
699    
700            NonModalNonParentDialog.__init__(self, parent, name, "")
701    
702          self.__SetTitle(layer.Title())          self.__SetTitle(layer.Title())
703    
704            self.parent.Subscribe(MAP_REPLACED, self.map_replaced)
705          self.layer = layer          self.layer = layer
706            self.map = parent.Map()
707    
708          self.originalClass = self.layer.GetClassification()          self.map.Subscribe(MAP_LAYERS_REMOVED, self.map_layers_removed)
709          field = self.originalClass.GetField()          self.layer.Subscribe(LAYER_SHAPESTORE_REPLACED,
710          fieldType = self.originalClass.GetFieldType()                               self.layer_shapestore_replaced)
711    
712          self.genDlg = None          self.genDlg = None
713    
# Line 697  class Classifier(NonModalDialog): Line 718  class Classifier(NonModalDialog):
718          panel = wxPanel(self, -1)          panel = wxPanel(self, -1)
719    
720          text_title = wxTextCtrl(panel, ID_PROPERTY_TITLE, layer.Title())          text_title = wxTextCtrl(panel, ID_PROPERTY_TITLE, layer.Title())
721          #          self.fieldTypeText = wxStaticText(panel, -1, "")
         # make field choice box  
         #  
         self.fields = wxChoice(panel, ID_PROPERTY_SELECT,)  
   
         self.num_cols = layer.table.NumColumns()  
         # just assume the first field in case one hasn't been  
         # specified in the file.  
         self.__cur_field = 0  
   
         self.fields.Append("<None>")  
722    
723          if self.originalClass.GetFieldType() is None:          if layer.HasClassification():
724              self.fields.SetClientData(0, copy.deepcopy(self.originalClass))              self.originalClass = self.layer.GetClassification()
725          else:              self.originalClassField = self.layer.GetClassificationColumn()
726              self.fields.SetClientData(0, None)              field = self.originalClassField
727                fieldType = self.layer.GetFieldType(field)
728    
729          for i in range(self.num_cols):              table = layer.ShapeStore().Table()
730              name = layer.table.Column(i).name              #
731              self.fields.Append(name)              # make field choice box
732                #
733              if name == field:              self.fields = wxChoice(panel, ID_PROPERTY_SELECT,)
                 self.__cur_field = i + 1  
                 self.fields.SetClientData(i + 1,  
                                           copy.deepcopy(self.originalClass))  
             else:  
                 self.fields.SetClientData(i + 1, None)  
734    
735                self.num_cols = table.NumColumns()
736                # just assume the first field in case one hasn't been
737                # specified in the file.
738                self.__cur_field = 0
739    
740          self.fieldTypeText = wxStaticText(panel, -1, "")              self.fields.Append("<None>")
741    
742          button_gen = wxButton(panel, ID_PROPERTY_GENCLASS, _("Generate Class"))              if fieldType is None:
743                    self.fields.SetClientData(0, copy.deepcopy(self.originalClass))
744                else:
745                    self.fields.SetClientData(0, None)
746    
747          button_add = wxButton(panel, ID_PROPERTY_ADD, _("Add"))              for i in range(self.num_cols):
748          button_moveup = wxButton(panel, ID_PROPERTY_MOVEUP, _("Move Up"))                  name = table.Column(i).name
749          button_movedown = wxButton(panel, ID_PROPERTY_MOVEDOWN, _("Move Down"))                  self.fields.Append(name)
750          button_edit = wxButton(panel, ID_PROPERTY_EDITSYM, _("Edit Symbol"))  
751          button_remove = wxButton(panel, ID_PROPERTY_REMOVE, _("Remove"))                  if name == field:
752                        self.__cur_field = i + 1
753                        self.fields.SetClientData(i + 1,
754                                                  copy.deepcopy(self.originalClass))
755                    else:
756                        self.fields.SetClientData(i + 1, None)
757    
758                button_gen = wxButton(panel, ID_PROPERTY_GENCLASS,
759                    _("Generate Class"))
760                button_add = wxButton(panel, ID_PROPERTY_ADD,
761                    _("Add"))
762                button_moveup = wxButton(panel, ID_PROPERTY_MOVEUP,
763                    _("Move Up"))
764                button_movedown = wxButton(panel, ID_PROPERTY_MOVEDOWN,
765                    _("Move Down"))
766                button_edit = wxButton(panel, ID_PROPERTY_EDITSYM,
767                    _("Edit Symbol"))
768                button_remove = wxButton(panel, ID_PROPERTY_REMOVE,
769                    _("Remove"))
770    
771                self.classGrid = ClassGrid(panel, self)
772    
773                # calling __SelectField after creating the classGrid fills in the
774                # grid with the correct information
775                self.fields.SetSelection(self.__cur_field)
776                self.__SelectField(self.__cur_field, group = group)
777    
778          button_try = wxButton(panel, ID_PROPERTY_TRY, _("Try"))          button_try = wxButton(self, ID_PROPERTY_TRY, _("Try"))
779          button_revert = wxButton(panel, ID_PROPERTY_REVERT, _("Revert"))          button_revert = wxButton(self, ID_PROPERTY_REVERT, _("Revert"))
780          button_ok = wxButton(panel, wxID_OK, _("OK"))          button_ok = wxButton(self, wxID_OK, _("OK"))
781            button_close = wxButton(self, wxID_CANCEL, _("Close"))
782          button_ok.SetDefault()          button_ok.SetDefault()
         button_close = wxButton(panel, wxID_CANCEL, _("Close"))  
   
         self.classGrid = ClassGrid(panel, self)  
   
         # calling __SelectField after creating the classGrid fills in the  
         # grid with the correct information  
         self.fields.SetSelection(self.__cur_field)  
         self.__SelectField(self.__cur_field, group = group)  
783    
784          ############################          ############################
785          # Layout the controls          # Layout the controls
# Line 764  class Classifier(NonModalDialog): Line 795  class Classifier(NonModalDialog):
795    
796          panelBox.Add(sizer, 0, wxGROW, 4)          panelBox.Add(sizer, 0, wxGROW, 4)
797    
798          panelBox.Add(wxStaticText(panel, -1,          if isinstance(layer, RasterLayer):
799                                  _("Type: %s") % layer.ShapeType()),              type = "Image"
800            else:
801                type = layer.ShapeType()
802    
803            panelBox.Add(wxStaticText(panel, -1, _("Type: %s") % type),
804              0, wxALIGN_LEFT | wxALL, 4)              0, wxALIGN_LEFT | wxALL, 4)
805    
806          classBox = wxStaticBoxSizer(          if layer.HasClassification():
                     wxStaticBox(panel, -1, _("Classification")), wxVERTICAL)  
807    
808                classBox = wxStaticBoxSizer(
809                            wxStaticBox(panel, -1, _("Classification")), wxVERTICAL)
810    
         sizer = wxBoxSizer(wxHORIZONTAL)  
         sizer.Add(wxStaticText(panel, ID_PROPERTY_FIELDTEXT, _("Field: ")),  
             0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 4)  
         sizer.Add(self.fields, 1, wxGROW | wxALL, 4)  
   
         classBox.Add(sizer, 0, wxGROW, 4)  
   
         classBox.Add(self.fieldTypeText, 0,  
                      wxGROW | wxALIGN_LEFT | wxALL | wxADJUST_MINSIZE, 4)  
   
         controlBox = wxBoxSizer(wxHORIZONTAL)  
         controlButtonBox = wxBoxSizer(wxVERTICAL)  
   
         controlButtonBox.Add(button_gen, 0, wxGROW|wxALL, 4)  
         controlButtonBox.Add(button_add, 0, wxGROW|wxALL, 4)  
         controlButtonBox.Add(button_moveup, 0, wxGROW|wxALL, 4)  
         controlButtonBox.Add(button_movedown, 0, wxGROW|wxALL, 4)  
         controlButtonBox.Add(button_edit, 0, wxGROW|wxALL, 4)  
         controlButtonBox.Add(60, 20, 0, wxGROW|wxALL|wxALIGN_BOTTOM, 4)  
         controlButtonBox.Add(button_remove, 0, wxGROW|wxALL|wxALIGN_BOTTOM, 4)  
811    
812          controlBox.Add(self.classGrid, 1, wxGROW, 0)              sizer = wxBoxSizer(wxHORIZONTAL)
813          controlBox.Add(controlButtonBox, 0, wxGROW, 10)              sizer.Add(wxStaticText(panel, ID_PROPERTY_FIELDTEXT, _("Field: ")),
814                    0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 4)
815                sizer.Add(self.fields, 1, wxGROW | wxALL, 4)
816    
817                classBox.Add(sizer, 0, wxGROW, 4)
818    
819          classBox.Add(controlBox, 1, wxGROW, 10)              classBox.Add(self.fieldTypeText, 0,
820          panelBox.Add(classBox, 1, wxGROW, 0)                          wxGROW | wxALIGN_LEFT | wxALL | wxADJUST_MINSIZE, 4)
821    
822                controlBox = wxBoxSizer(wxHORIZONTAL)
823                controlButtonBox = wxBoxSizer(wxVERTICAL)
824    
825                controlButtonBox.Add(button_gen, 0, wxGROW|wxALL, 4)
826                controlButtonBox.Add(button_add, 0, wxGROW|wxALL, 4)
827                controlButtonBox.Add(button_moveup, 0, wxGROW|wxALL, 4)
828                controlButtonBox.Add(button_movedown, 0, wxGROW|wxALL, 4)
829                controlButtonBox.Add(button_edit, 0, wxGROW|wxALL, 4)
830                controlButtonBox.Add(60, 20, 0, wxGROW|wxALL|wxALIGN_BOTTOM, 4)
831                controlButtonBox.Add(button_remove, 0,
832                                     wxGROW|wxALL|wxALIGN_BOTTOM, 4)
833    
834                controlBox.Add(self.classGrid, 1, wxGROW, 0)
835                controlBox.Add(controlButtonBox, 0, wxGROW, 10)
836    
837                classBox.Add(controlBox, 1, wxGROW, 10)
838                panelBox.Add(classBox, 1, wxGROW, 0)
839    
840    
841          buttonBox = wxBoxSizer(wxHORIZONTAL)          buttonBox = wxBoxSizer(wxHORIZONTAL)
842          buttonBox.Add(button_try, 0, wxALL, 4)          buttonBox.Add(button_try, 0, wxRIGHT|wxEXPAND, 10)
843          buttonBox.Add(60, 20, 0, wxALL, 4)          buttonBox.Add(button_revert, 0, wxRIGHT|wxEXPAND, 10)
844          buttonBox.Add(button_revert, 0, wxALL, 4)          buttonBox.Add(button_ok, 0, wxRIGHT|wxEXPAND, 10)
845          buttonBox.Add(60, 20, 0, wxALL, 4)          buttonBox.Add(button_close, 0, wxRIGHT|wxEXPAND, 10)
         buttonBox.Add(button_ok, 0, wxALL, 4)  
         buttonBox.Add(60, 20, 0, wxALL, 4)  
         buttonBox.Add(button_close, 0, wxALL, 4)  
         panelBox.Add(buttonBox, 0,  
             wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_BOTTOM, 0)  
846    
847          panel.SetAutoLayout(True)          panel.SetAutoLayout(True)
848          panel.SetSizer(panelBox)          panel.SetSizer(panelBox)
# Line 817  class Classifier(NonModalDialog): Line 850  class Classifier(NonModalDialog):
850          panelBox.SetSizeHints(panel)          panelBox.SetSizeHints(panel)
851    
852          topBox.Add(panel, 1, wxGROW | wxALL, 4)          topBox.Add(panel, 1, wxGROW | wxALL, 4)
853            topBox.Add(buttonBox, 0, wxALIGN_RIGHT|wxBOTTOM|wxTOP, 10)
854    
855          self.SetAutoLayout(True)          self.SetAutoLayout(True)
856          self.SetSizer(topBox)          self.SetSizer(topBox)
# Line 842  class Classifier(NonModalDialog): Line 876  class Classifier(NonModalDialog):
876    
877          ######################          ######################
878    
879          self.fields.SetFocus()          text_title.SetFocus()
880          self.haveApplied = False          self.haveApplied = False
881    
882        def unsubscribe_messages(self):
883            """Unsubscribe from all messages."""
884            self.parent.Unsubscribe(MAP_REPLACED, self.map_replaced)
885            self.map.Unsubscribe(MAP_LAYERS_REMOVED, self.map_layers_removed)
886            self.layer.Unsubscribe(LAYER_SHAPESTORE_REPLACED,
887                                   self.layer_shapestore_replaced)
888    
889        def map_layers_removed(self, map):
890            """Subscribed to MAP_LAYERS_REMOVED. If this layer was removed,
891            Close self.
892            """
893            if self.layer not in self.map.Layers():
894                self.Close()
895    
896        def layer_shapestore_replaced(self, *args):
897            """Subscribed to the map's LAYER_SHAPESTORE_REPLACED message.
898    
899            Close self.
900            """
901            self.Close()
902    
903        def map_replaced(self, *args):
904            """Subscribed to the mainwindow's MAP_REPLACED message. Close self."""
905            self.Close()
906    
907      def EditSymbol(self, row):      def EditSymbol(self, row):
908            """Open up a dialog where the user can select the properties
909            for a group.
910            """
911          table = self.classGrid.GetTable()          table = self.classGrid.GetTable()
912          prop = table.GetValueAsCustom(row, COL_SYMBOL, None)          prop = table.GetValueAsCustom(row, COL_SYMBOL, None)
913    
914          # get a new ClassGroupProperties object and copy the          # get a new ClassGroupProperties object and copy the
915          # values over to our current object          # values over to our current object
916          propDlg = SelectPropertiesDialog(NULL, prop, self.layer.ShapeType())          propDlg = SelectPropertiesDialog(self, prop, self.layer.ShapeType())
917    
918          self.Enable(False)          self.Enable(False)
919          if propDlg.ShowModal() == wxID_OK:          if propDlg.ShowModal() == wxID_OK:
# Line 859  class Classifier(NonModalDialog): Line 921  class Classifier(NonModalDialog):
921              table.SetValueAsCustom(row, COL_SYMBOL, None, new_prop)              table.SetValueAsCustom(row, COL_SYMBOL, None, new_prop)
922          self.Enable(True)          self.Enable(True)
923          propDlg.Destroy()          propDlg.Destroy()
924            
925      def _SetClassification(self, clazz):      def _SetClassification(self, clazz):
926                    """Called from the ClassGen dialog when a new classification has
927            been created and should be set in the table.
928            """
929            # FIXME: This could be implemented using a message
930    
931          self.fields.SetClientData(self.__cur_field, clazz)          self.fields.SetClientData(self.__cur_field, clazz)
932          self.classGrid.GetTable().SetClassification(clazz)          self.classGrid.GetTable().SetClassification(clazz)
933    
934      def __BuildClassification(self, fieldIndex, copyClass = False):      def __BuildClassification(self, fieldIndex, copyClass=False, force=False):
935            """Pack the classification setting into a Classification object.
936            Returns (Classification, fieldName) where fieldName is the selected
937            field in the table that the classification should be used with.
938            """
939    
940  #       numRows = self.classGrid.GetNumberRows()  #       numRows = self.classGrid.GetNumberRows()
941  #       assert numRows > 0  # there should always be a default row  #       assert numRows > 0  # there should always be a default row
942    
 #       clazz = Classification()  
943          if fieldIndex == 0:          if fieldIndex == 0:
944              fieldName = None              fieldName = None
945              fieldType = None              fieldType = None
# Line 878  class Classifier(NonModalDialog): Line 947  class Classifier(NonModalDialog):
947              fieldName = self.fields.GetString(fieldIndex)              fieldName = self.fields.GetString(fieldIndex)
948              fieldType = self.layer.GetFieldType(fieldName)              fieldType = self.layer.GetFieldType(fieldName)
949    
950          clazz = self.classGrid.GetTable().GetClassification()          clazz = self.fields.GetClientData(fieldIndex)
951            if clazz is None or self.classGrid.GetTable().IsModified() or force:
952          if copyClass:              clazz = self.classGrid.GetTable().GetClassification()
953              clazz = copy.deepcopy(clazz)              if copyClass:
954                    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))  
955    
956          return clazz          return clazz, fieldName
957    
958      def __SetGridTable(self, fieldIndex, group = None):      def __SetGridTable(self, fieldIndex, group = None):
959            """Set the table with the classification associated with the
960            selected field at fieldIndex. Select the specified group
961            if group is not None.
962            """
963    
964          clazz = self.fields.GetClientData(fieldIndex)          clazz = self.fields.GetClientData(fieldIndex)
965    
# Line 906  class Classifier(NonModalDialog): Line 970  class Classifier(NonModalDialog):
970                      self.layer.GetClassification().                      self.layer.GetClassification().
971                                 GetDefaultGroup().GetProperties()))                                 GetDefaultGroup().GetProperties()))
972    
973              fieldName = self.fields.GetString(fieldIndex)          fieldName = self.fields.GetString(fieldIndex)
974              fieldType = self.layer.GetFieldType(fieldName)          fieldType = self.layer.GetFieldType(fieldName)
             clazz.SetFieldType(fieldType)  
975                                    
976          self.classGrid.CreateTable(clazz, self.layer.ShapeType(), group)          self.classGrid.CreateTable(clazz, fieldType,
977                                       self.layer.ShapeType(), group)
978    
979      def __SetFieldTypeText(self, fieldIndex):      def __SetFieldTypeText(self, fieldIndex):
980            """Set the field type string using the data type of the field
981            at fieldIndex.
982            """
983          fieldName = self.fields.GetString(fieldIndex)          fieldName = self.fields.GetString(fieldIndex)
984          fieldType = self.layer.GetFieldType(fieldName)          fieldType = self.layer.GetFieldType(fieldName)
985    
# Line 930  class Classifier(NonModalDialog): Line 997  class Classifier(NonModalDialog):
997          assert oldIndex >= -1          assert oldIndex >= -1
998    
999          if oldIndex != -1:          if oldIndex != -1:
1000              clazz = self.__BuildClassification(oldIndex)              clazz, name = self.__BuildClassification(oldIndex, force = True)
1001              self.fields.SetClientData(oldIndex, clazz)              self.fields.SetClientData(oldIndex, clazz)
1002    
1003          self.__SetGridTable(newIndex, group)          self.__SetGridTable(newIndex, group)
1004    
1005          self.__EnableButtons(EB_SELECT_FIELD, newIndex != 0)          self.__EnableButtons(EB_SELECT_FIELD)
1006    
1007          self.__SetFieldTypeText(newIndex)          self.__SetFieldTypeText(newIndex)
1008    
1009      def __SetTitle(self, title):      def __SetTitle(self, title):
1010            """Set the title of the dialog."""
1011          if title != "":          if title != "":
1012              title = ": " + title              title = ": " + title
1013    
1014          self.SetTitle(_("Layer Properties") + title)          self.SetTitle(_("Layer Properties") + title)
1015    
1016      def _OnEditSymbol(self, event):      def _OnEditSymbol(self, event):
1017            """Open up a dialog for the user to select group properties."""
1018          sel = self.classGrid.GetCurrentSelection()          sel = self.classGrid.GetCurrentSelection()
1019    
1020          if len(sel) == 1:          if len(sel) == 1:
# Line 961  class Classifier(NonModalDialog): Line 1030  class Classifier(NonModalDialog):
1030             it to the layer.             it to the layer.
1031          """          """
1032    
1033          clazz = self.fields.GetClientData(self.__cur_field)          if self.layer.HasClassification():
1034                clazz = self.fields.GetClientData(self.__cur_field)
1035    
1036          #              #
1037          # only build the classification if there wasn't one to              # only build the classification if there wasn't one to
1038          # to begin with or it has been modified              # to begin with or it has been modified
1039          #              #
1040          self.classGrid.SaveEditControlValue()              self.classGrid.SaveEditControlValue()
1041          if clazz is None or self.classGrid.GetTable().IsModified():              clazz, name = self.__BuildClassification(self.__cur_field, True)
             clazz = self.__BuildClassification(self.__cur_field, True)  
1042    
1043          self.layer.SetClassification(clazz)              self.layer.SetClassificationColumn(name)
1044                self.layer.SetClassification(clazz)
1045    
1046          self.haveApplied = True          self.haveApplied = True
1047    
# Line 980  class Classifier(NonModalDialog): Line 1050  class Classifier(NonModalDialog):
1050          self.Close()          self.Close()
1051    
1052      def OnClose(self, event):      def OnClose(self, event):
1053          NonModalDialog.OnClose(self, event)          self.unsubscribe_messages()
1054            NonModalNonParentDialog.OnClose(self, event)
1055    
1056      def _OnCloseBtn(self, event):      def _OnCloseBtn(self, event):
1057          """Close is similar to Cancel except that any changes that were          """Close is similar to Cancel except that any changes that were
# Line 993  class Classifier(NonModalDialog): Line 1064  class Classifier(NonModalDialog):
1064      def _OnRevert(self, event):      def _OnRevert(self, event):
1065          """The layer's current classification stays the same."""          """The layer's current classification stays the same."""
1066          if self.haveApplied:          if self.haveApplied:
1067                self.layer.SetClassificationColumn(self.originalClassField)
1068              self.layer.SetClassification(self.originalClass)              self.layer.SetClassification(self.originalClass)
1069    
1070          #self.Close()          #self.Close()
# Line 1004  class Classifier(NonModalDialog): Line 1076  class Classifier(NonModalDialog):
1076          self.classGrid.DeleteSelectedRows()          self.classGrid.DeleteSelectedRows()
1077    
1078      def _OnGenClass(self, event):      def _OnGenClass(self, event):
1079            """Open up a dialog for the user to generate classifications."""
1080    
1081          self.genDlg = ClassGenDialog(self, self.layer,          self.genDlg = ClassGenDialog(self, self.layer,
1082                            self.fields.GetString(self.__cur_field))                            self.fields.GetString(self.__cur_field))
1083    
1084          EVT_CLOSE(self.genDlg, self._OnGenDialogClose)          EVT_CLOSE(self.genDlg, self._OnGenDialogClose)
1085    
1086          self.__EnableButtons(EB_GEN_CLASS, False)          self.__EnableButtons(EB_GEN_CLASS)
1087    
1088          self.genDlg.Show()          self.genDlg.Show()
1089    
1090      def _OnGenDialogClose(self, event):      def _OnGenDialogClose(self, event):
1091            """Reenable buttons after the generate classification
1092            dialog is closed.
1093            """
1094          self.genDlg.Destroy()          self.genDlg.Destroy()
1095          self.__EnableButtons(EB_GEN_CLASS, True)          self.genDlg = None
1096            self.__EnableButtons(EB_GEN_CLASS)
1097    
1098      def _OnMoveUp(self, event):      def _OnMoveUp(self, event):
1099            """When the user clicks MoveUp, try to move a group up one row."""
1100          sel = self.classGrid.GetCurrentSelection()          sel = self.classGrid.GetCurrentSelection()
1101    
1102          if len(sel) == 1:          if len(sel) == 1:
# Line 1034  class Classifier(NonModalDialog): Line 1112  class Classifier(NonModalDialog):
1112                  self.classGrid.MakeCellVisible(i - 1, 0)                  self.classGrid.MakeCellVisible(i - 1, 0)
1113    
1114      def _OnMoveDown(self, event):      def _OnMoveDown(self, event):
1115            """When the user clicks MoveDown, try to move a group down one row."""
1116          sel = self.classGrid.GetCurrentSelection()          sel = self.classGrid.GetCurrentSelection()
1117    
1118          if len(sel) == 1:          if len(sel) == 1:
# Line 1049  class Classifier(NonModalDialog): Line 1128  class Classifier(NonModalDialog):
1128                  self.classGrid.MakeCellVisible(i + 1, 0)                  self.classGrid.MakeCellVisible(i + 1, 0)
1129    
1130      def _OnTitleChanged(self, event):      def _OnTitleChanged(self, event):
1131            """Update the dialog title when the user changed the layer name."""
1132          obj = event.GetEventObject()          obj = event.GetEventObject()
1133    
1134          self.layer.SetTitle(obj.GetValue())          self.layer.SetTitle(obj.GetValue())
1135          self.__SetTitle(self.layer.Title())          self.__SetTitle(self.layer.Title())
1136    
1137          self.__EnableButtons(EB_LAYER_TITLE, self.layer.Title() != "")          self.__EnableButtons(EB_LAYER_TITLE)
1138    
1139        def __EnableButtons(self, case):
1140            """Helper method that enables/disables the appropriate buttons
1141            based on the case provided. Cases are constants beginning with EB_.
1142            """
1143    
1144      def __EnableButtons(self, case, enable):          list = {wxID_OK                 : True,
1145                    wxID_CANCEL             : True,
1146                    ID_PROPERTY_ADD         : True,
1147                    ID_PROPERTY_MOVEUP      : True,
1148                    ID_PROPERTY_MOVEDOWN    : True,
1149                    ID_PROPERTY_REMOVE      : True,
1150                    ID_PROPERTY_SELECT      : True,
1151                    ID_PROPERTY_FIELDTEXT   : True,
1152                    ID_PROPERTY_GENCLASS    : True,
1153                    ID_PROPERTY_EDITSYM     : True}
1154    
1155          if case == EB_LAYER_TITLE:            if case == EB_LAYER_TITLE:  
1156              list = (wxID_OK,              if self.layer.Title() == "":
1157                      wxID_CANCEL)                  list[wxID_OK] = False
1158                    list[wxID_CANCEL] = False
1159    
1160          elif case == EB_SELECT_FIELD:          elif case == EB_SELECT_FIELD:
1161              list = (ID_PROPERTY_GENCLASS,              if self.fields.GetSelection() == 0:
1162                      ID_PROPERTY_ADD,                  list[ID_PROPERTY_GENCLASS] = False
1163                      ID_PROPERTY_MOVEUP,                  list[ID_PROPERTY_ADD] = False
1164                      ID_PROPERTY_MOVEDOWN,                  list[ID_PROPERTY_MOVEUP] = False
1165                      ID_PROPERTY_EDITSYM,                  list[ID_PROPERTY_MOVEDOWN] = False
1166                      ID_PROPERTY_REMOVE)                  list[ID_PROPERTY_REMOVE] = False
1167    
1168          elif case == EB_GEN_CLASS:          elif case == EB_GEN_CLASS:
1169              list = (ID_PROPERTY_SELECT,              if self.genDlg is not None:
1170                      ID_PROPERTY_FIELDTEXT,                  list[ID_PROPERTY_SELECT] = False
1171                      ID_PROPERTY_GENCLASS,                  list[ID_PROPERTY_FIELDTEXT] = False
1172                      ID_PROPERTY_EDITSYM)                  list[ID_PROPERTY_GENCLASS] = False
1173    
1174            for id, enable in list.items():
1175                win = self.FindWindowById(id)
1176                if win:
1177                    win.Enable(enable)
1178    
1179          for id in list:  ID_SELPROP_SPINCTRL_LINEWIDTH = 4002
             self.FindWindowById(id).Enable(enable)  
   
 ID_SELPROP_SPINCTRL = 4002  
1180  ID_SELPROP_PREVIEW = 4003  ID_SELPROP_PREVIEW = 4003
1181  ID_SELPROP_STROKECLR = 4004  ID_SELPROP_STROKECLR = 4004
1182  ID_SELPROP_FILLCLR = 4005  ID_SELPROP_FILLCLR = 4005
1183  ID_SELPROP_STROKECLRTRANS = 4006  ID_SELPROP_STROKECLRTRANS = 4006
1184  ID_SELPROP_FILLCLRTRANS = 4007  ID_SELPROP_FILLCLRTRANS = 4007
1185    ID_SELPROP_SPINCTRL_SIZE = 4008
1186    
1187  class SelectPropertiesDialog(wxDialog):  class SelectPropertiesDialog(wxDialog):
1188        """Dialog that allows the user to select group properties."""
1189    
1190      def __init__(self, parent, prop, shapeType):      def __init__(self, parent, prop, shapeType):
1191            """Open the dialog with the initial prop properties and shapeType."""
1192    
1193          wxDialog.__init__(self, parent, -1, _("Select Properties"),          wxDialog.__init__(self, parent, -1, _("Select Properties"),
1194                            style = wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)                            style = wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
1195    
# Line 1145  class SelectPropertiesDialog(wxDialog): Line 1246  class SelectPropertiesDialog(wxDialog):
1246              ctrlBox.Add(fillColorBox, 0,              ctrlBox.Add(fillColorBox, 0,
1247                          wxALIGN_CENTER_HORIZONTAL | wxALL | wxGROW, 4)                          wxALIGN_CENTER_HORIZONTAL | wxALL | wxGROW, 4)
1248    
1249            # Line width selection
1250          spinBox = wxBoxSizer(wxHORIZONTAL)          spinBox = wxBoxSizer(wxHORIZONTAL)
1251          spinBox.Add(wxStaticText(self, -1, _("Line Width: ")),          spinBox.Add(wxStaticText(self, -1, _("Line Width: ")),
1252                  0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 4)                  0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 4)
1253          self.spinCtrl = wxSpinCtrl(self, ID_SELPROP_SPINCTRL,          self.spinCtrl_linewidth = wxSpinCtrl(self,
1254                                     min=1, max=10,                                               ID_SELPROP_SPINCTRL_LINEWIDTH,
1255                                     value=str(prop.GetLineWidth()),                                               min=1, max=10,
1256                                     initial=prop.GetLineWidth())                                               value=str(prop.GetLineWidth()),
1257                                                 initial=prop.GetLineWidth())
         EVT_SPINCTRL(self, ID_SELPROP_SPINCTRL, self._OnSpin)  
1258    
1259          spinBox.Add(self.spinCtrl, 0, wxALIGN_LEFT | wxALL, 4)          EVT_SPINCTRL(self, ID_SELPROP_SPINCTRL_LINEWIDTH,
1260                         self._OnSpinLineWidth)
1261    
1262            spinBox.Add(self.spinCtrl_linewidth, 0, wxALIGN_LEFT | wxALL, 4)
1263          ctrlBox.Add(spinBox, 0, wxALIGN_RIGHT | wxALL, 0)          ctrlBox.Add(spinBox, 0, wxALIGN_RIGHT | wxALL, 0)
1264    
1265            # Size selection
1266            if shapeType == SHAPETYPE_POINT:
1267                spinBox = wxBoxSizer(wxHORIZONTAL)
1268                spinBox.Add(wxStaticText(self, -1, _("Size: ")),
1269                            0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 4)
1270                self.spinCtrl_size = wxSpinCtrl(self, ID_SELPROP_SPINCTRL_SIZE,
1271                                                min=1, max=100,
1272                                                value=str(prop.GetSize()),
1273                                                initial=prop.GetSize())
1274    
1275                EVT_SPINCTRL(self, ID_SELPROP_SPINCTRL_SIZE, self._OnSpinSize)
1276    
1277                spinBox.Add(self.spinCtrl_size, 0, wxALIGN_LEFT | wxALL, 4)
1278                ctrlBox.Add(spinBox, 0, wxALIGN_RIGHT | wxALL, 0)
1279    
1280    
1281          itemBox.Add(ctrlBox, 0, wxALIGN_RIGHT | wxALL | wxGROW, 0)          itemBox.Add(ctrlBox, 0, wxALIGN_RIGHT | wxALL | wxGROW, 0)
1282          topBox.Add(itemBox, 1, wxALIGN_LEFT | wxALL | wxGROW, 0)          topBox.Add(itemBox, 1, wxALIGN_LEFT | wxALL | wxGROW, 0)
1283    
# Line 1166  class SelectPropertiesDialog(wxDialog): Line 1286  class SelectPropertiesDialog(wxDialog):
1286          #          #
1287          buttonBox = wxBoxSizer(wxHORIZONTAL)          buttonBox = wxBoxSizer(wxHORIZONTAL)
1288          button_ok = wxButton(self, wxID_OK, _("OK"))          button_ok = wxButton(self, wxID_OK, _("OK"))
1289          button_ok.SetDefault()          buttonBox.Add(button_ok, 0, wxRIGHT|wxEXPAND, 10)
         buttonBox.Add(button_ok, 0, wxALL, 4)  
1290          buttonBox.Add(wxButton(self, wxID_CANCEL, _("Cancel")),          buttonBox.Add(wxButton(self, wxID_CANCEL, _("Cancel")),
1291                        0, wxALL, 4)                        0, wxRIGHT|wxEXPAND, 10)
1292          topBox.Add(buttonBox, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_BOTTOM, 10)          topBox.Add(buttonBox, 0, wxALIGN_RIGHT|wxBOTTOM|wxTOP, 10)
1293                                                                                    
1294            button_ok.SetDefault()
1295    
1296          #EVT_BUTTON(self, wxID_OK, self._OnOK)          #EVT_BUTTON(self, wxID_OK, self._OnOK)
1297          #EVT_BUTTON(self, ID_SELPROP_CANCEL, self._OnCancel)          #EVT_BUTTON(self, ID_SELPROP_CANCEL, self._OnCancel)
1298                                                                                    
1299          self.SetAutoLayout(True)          self.SetAutoLayout(True)
1300          self.SetSizer(topBox)          self.SetSizer(topBox)
1301          topBox.Fit(self)          topBox.Fit(self)
# Line 1186  class SelectPropertiesDialog(wxDialog): Line 1307  class SelectPropertiesDialog(wxDialog):
1307      def OnCancel(self, event):      def OnCancel(self, event):
1308          self.EndModal(wxID_CANCEL)          self.EndModal(wxID_CANCEL)
1309    
1310      def _OnSpin(self, event):      def _OnSpinLineWidth(self, event):
1311          self.prop.SetLineWidth(self.spinCtrl.GetValue())          self.prop.SetLineWidth(self.spinCtrl_linewidth.GetValue())
1312            self.previewWin.Refresh()
1313    
1314        def _OnSpinSize(self, event):
1315            self.prop.SetSize(self.spinCtrl_size.GetValue())
1316          self.previewWin.Refresh()          self.previewWin.Refresh()
1317    
1318      def __GetColor(self, cur):      def __GetColor(self, cur):
1319          dialog = wxColourDialog(self)          dialog = ColorDialog(self)
1320          if cur is not Color.Transparent:          dialog.SetColor(cur)
             dialog.GetColourData().SetColour(Color2wxColour(cur))  
1321    
1322          ret = None          ret = None
1323          if dialog.ShowModal() == wxID_OK:          if dialog.ShowModal() == wxID_OK:
1324              ret = wxColour2Color(dialog.GetColourData().GetColour())              ret = dialog.GetColor()
1325    
1326          dialog.Destroy()          dialog.Destroy()
1327    
1328          return ret          return ret
1329            
1330      def _OnChangeLineColor(self, event):      def _OnChangeLineColor(self, event):
1331          clr = self.__GetColor(self.prop.GetLineColor())          clr = self.__GetColor(self.prop.GetLineColor())
1332          if clr is not None:          if clr is not None:
# Line 1210  class SelectPropertiesDialog(wxDialog): Line 1334  class SelectPropertiesDialog(wxDialog):
1334          self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer          self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer
1335    
1336      def _OnChangeLineColorTrans(self, event):      def _OnChangeLineColorTrans(self, event):
1337          self.prop.SetLineColor(Color.Transparent)          self.prop.SetLineColor(Transparent)
1338          self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer          self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer
1339            
1340      def _OnChangeFillColor(self, event):      def _OnChangeFillColor(self, event):
1341          clr = self.__GetColor(self.prop.GetFill())          clr = self.__GetColor(self.prop.GetFill())
1342          if clr is not None:          if clr is not None:
# Line 1220  class SelectPropertiesDialog(wxDialog): Line 1344  class SelectPropertiesDialog(wxDialog):
1344          self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer          self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer
1345    
1346      def _OnChangeFillColorTrans(self, event):      def _OnChangeFillColorTrans(self, event):
1347          self.prop.SetFill(Color.Transparent)          self.prop.SetFill(Transparent)
1348          self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer          self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer
1349    
1350      def GetClassGroupProperties(self):      def GetClassGroupProperties(self):
# Line 1228  class SelectPropertiesDialog(wxDialog): Line 1352  class SelectPropertiesDialog(wxDialog):
1352    
1353    
1354  class ClassDataPreviewWindow(wxWindow):  class ClassDataPreviewWindow(wxWindow):
1355        """A custom window that draws group properties using the correct shape."""
1356    
1357      def __init__(self, rect, prop, shapeType,      def __init__(self, rect, prop, shapeType,
1358                         parent = None, id = -1, size = wxDefaultSize):                         parent = None, id = -1, size = wxDefaultSize):
1359            """Draws the appropriate shape as specified with shapeType using
1360            prop properities.
1361            """
1362          if parent is not None:          if parent is not None:
1363              wxWindow.__init__(self, parent, id, (0, 0), size)              wxWindow.__init__(self, parent, id, (0, 0), size)
1364              EVT_PAINT(self, self._OnPaint)              EVT_PAINT(self, self._OnPaint)
# Line 1259  class ClassDataPreviewWindow(wxWindow): Line 1387  class ClassDataPreviewWindow(wxWindow):
1387          self.previewer.Draw(dc, rect, self.prop, self.shapeType)          self.previewer.Draw(dc, rect, self.prop, self.shapeType)
1388    
1389  class ClassDataPreviewer:  class ClassDataPreviewer:
1390        """Class that actually draws a group property preview."""
1391    
1392      def Draw(self, dc, rect, prop, shapeType):      def Draw(self, dc, rect, prop, shapeType):
1393            """Draw the property.
1394    
1395            returns: (w, h) as adapted extend if the drawing size
1396            exceeded the given rect. This can only be the case
1397            for point symbols. If the symbol fits the given rect,
1398            None is returned.
1399            """
1400    
1401          assert dc is not None          assert dc is not None
1402          assert isinstance(prop, ClassGroupProperties)          assert isinstance(prop, ClassGroupProperties)
# Line 1276  class ClassDataPreviewer: Line 1412  class ClassDataPreviewer:
1412              h = rect.GetHeight()              h = rect.GetHeight()
1413    
1414          stroke = prop.GetLineColor()          stroke = prop.GetLineColor()
1415          if stroke is Color.Transparent:          if stroke is Transparent:
1416              pen = wxTRANSPARENT_PEN              pen = wxTRANSPARENT_PEN
1417          else:          else:
1418              pen = wxPen(Color2wxColour(stroke),              pen = wxPen(Color2wxColour(stroke),
# Line 1284  class ClassDataPreviewer: Line 1420  class ClassDataPreviewer:
1420                          wxSOLID)                          wxSOLID)
1421    
1422          stroke = prop.GetFill()          stroke = prop.GetFill()
1423          if stroke is Color.Transparent:          if stroke is Transparent:
1424              brush = wxTRANSPARENT_BRUSH              brush = wxTRANSPARENT_BRUSH
1425          else:          else:
1426              brush = wxBrush(Color2wxColour(stroke), wxSOLID)              brush = wxBrush(Color2wxColour(stroke), wxSOLID)
# Line 1300  class ClassDataPreviewer: Line 1436  class ClassDataPreviewer:
1436    
1437          elif shapeType == SHAPETYPE_POINT:          elif shapeType == SHAPETYPE_POINT:
1438    
1439              dc.DrawCircle(x + w/2, y + h/2,              dc.DrawCircle(x + w/2, y + h/2, prop.GetSize())
1440                            (min(w, h) - prop.GetLineWidth())/2)              circle_size =  prop.GetSize() * 2 + prop.GetLineWidth() * 2
1441                new_h = h
1442                new_w = w
1443                if h < circle_size: new_h = circle_size
1444                if w < circle_size: new_w = circle_size
1445                if new_h > h or new_w > w:
1446                    return (new_w, new_h)
1447    
1448          elif shapeType == SHAPETYPE_POLYGON:          elif shapeType == SHAPETYPE_POLYGON:
1449              dc.DrawRectangle(x, y, w, h)              dc.DrawRectangle(x, y, w, h)
1450    
1451            return None
1452    
1453  class ClassRenderer(wxPyGridCellRenderer):  class ClassRenderer(wxPyGridCellRenderer):
1454        """A wrapper class that can be used to draw group properties in a
1455        grid table.
1456        """
1457    
1458      def __init__(self, shapeType):      def __init__(self, shapeType):
1459          wxPyGridCellRenderer.__init__(self)          wxPyGridCellRenderer.__init__(self)
# Line 1324  class ClassRenderer(wxPyGridCellRenderer Line 1471  class ClassRenderer(wxPyGridCellRenderer
1471                           rect.GetWidth(), rect.GetHeight())                           rect.GetWidth(), rect.GetHeight())
1472    
1473          if not isinstance(data, ClassGroupMap):          if not isinstance(data, ClassGroupMap):
1474              self.previewer.Draw(dc, rect, data.GetProperties(), self.shapeType)              new_size = self.previewer.Draw(dc, rect, data.GetProperties(),
1475                                               self.shapeType)
1476                if new_size is not None:
1477                    (new_w, new_h) = new_size
1478                    grid.SetRowSize(row, new_h)
1479                    grid.SetColSize(col, new_h)
1480                    grid.ForceRefresh()
1481    
1482                    # now that we know the height, redraw everything
1483                    rect.SetHeight(new_h)
1484                    rect.SetWidth(new_w)
1485                    dc.DestroyClippingRegion()
1486                    dc.SetClippingRegion(rect.GetX(), rect.GetY(),
1487                                         rect.GetWidth(), rect.GetHeight())
1488                    dc.SetPen(wxPen(wxLIGHT_GREY))
1489                    dc.SetBrush(wxBrush(wxLIGHT_GREY, wxSOLID))
1490                    dc.DrawRectangle(rect.GetX(), rect.GetY(),
1491                                     rect.GetWidth(), rect.GetHeight())
1492                    self.previewer.Draw(dc, rect, data.GetProperties(),
1493                                        self.shapeType)
1494    
1495          if isSelected:          if isSelected:
1496              dc.SetPen(wxPen(wxBLACK, 1, wxSOLID))              dc.SetPen(wxPen(wxBLACK, 1, wxSOLID))
# Line 1337  class ClassRenderer(wxPyGridCellRenderer Line 1503  class ClassRenderer(wxPyGridCellRenderer
1503    
1504    
1505  class ClassGroupPropertiesCtrl(wxWindow, wxControl):  class ClassGroupPropertiesCtrl(wxWindow, wxControl):
1506        """A custom window and control that draw a preview of group properties
1507        and can open a dialog to modify the properties if the user double-clicks
1508        it.
1509        """
1510    
1511      def __init__(self, parent, id, props, shapeType,      def __init__(self, parent, id, props, shapeType,
1512                   size = wxDefaultSize, style = 0):                   size = wxDefaultSize, style = 0):
1513    
1514          wxWindow.__init__(self, parent, id, size = size, style = style)          wxWindow.__init__(self, parent, id, size = size, style = style)
1515    
1516            self.parent = parent
1517    
1518          self.SetProperties(props)          self.SetProperties(props)
1519          self.SetShapeType(shapeType)          self.SetShapeType(shapeType)
1520          self.AllowEdit(True)          self.AllowEdit(True)
# Line 1381  class ClassGroupPropertiesCtrl(wxWindow, Line 1553  class ClassGroupPropertiesCtrl(wxWindow,
1553          self.Refresh()          self.Refresh()
1554    
1555      def AllowEdit(self, allow):      def AllowEdit(self, allow):
1556            """Allow/Disallow double-clicking on the control."""
1557          self.allowEdit = allow          self.allowEdit = allow
1558    
1559      def DoEdit(self):      def DoEdit(self):
1560            """Open the properties selector dialog."""
1561    
1562          if not self.allowEdit: return          if not self.allowEdit: return
1563    
1564          propDlg = SelectPropertiesDialog(NULL,          propDlg = SelectPropertiesDialog(self.parent,
1565                                           self.GetProperties(),                                           self.GetProperties(),
1566                                           self.GetShapeType())                                           self.GetShapeType())
1567    
# Line 1399  class ClassGroupPropertiesCtrl(wxWindow, Line 1574  class ClassGroupPropertiesCtrl(wxWindow,
1574    
1575      def _OnLeftDClick(self, event):      def _OnLeftDClick(self, event):
1576          self.DoEdit()          self.DoEdit()
1577    
1578    from Thuban.UI.mainwindow import layer_properties_dialogs
1579    layer_properties_dialogs.add(Layer, Classifier)
1580    layer_properties_dialogs.add(RasterLayer, Classifier)

Legend:
Removed from v.878  
changed lines
  Added in v.2386

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26