/[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 1452 by bh, Fri Jul 18 12:57:59 2003 UTC revision 2597 by bh, Thu Apr 7 19:46:29 2005 UTC
# Line 1  Line 1 
1  # Copyright (c) 2001, 2003 by Intevation GmbH  # Copyright (c) 2003-2005 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 29  from Thuban.Model.classification import Line 35  from Thuban.Model.classification import
35    
36  from Thuban.Model.color import Transparent  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
 ID_CLASS_TABLE = 40011  
46    
47    
48  # table columns  # table columns
# Line 67  class ClassGrid(wxGrid): Line 73  class ClassGrid(wxGrid):
73          clazz -- the working classification that this grid should          clazz -- the working classification that this grid should
74                   use for display.                   use for display.
75          """          """
76            wxGrid.__init__(self, parent, -1, style = 0)
         wxGrid.__init__(self, parent, ID_CLASS_TABLE, style = 0)  
77    
78          self.classifier = classifier          self.classifier = classifier
79    
# Line 153  class ClassGrid(wxGrid): Line 158  class ClassGrid(wxGrid):
158              group = self.GetTable().GetClassGroup(sel[0])              group = self.GetTable().GetClassGroup(sel[0])
159              if isinstance(group, ClassGroupDefault):              if isinstance(group, ClassGroupDefault):
160                  wxMessageDialog(self,                  wxMessageDialog(self,
161                                  "The Default group cannot be removed.",                                  _("The Default group cannot be removed."),
162                                  style = wxOK | wxICON_EXCLAMATION).ShowModal()                                  style = wxOK | wxICON_EXCLAMATION).ShowModal()
163                  return                  return
164                    
# Line 315  class ClassTable(wxPyGridTableBase): Line 320  class ClassTable(wxPyGridTableBase):
320          self.GetView().FitInside()          self.GetView().FitInside()
321    
322      def GetClassification(self):      def GetClassification(self):
323            """Return the current classification."""
324          return self.clazz          return self.clazz
325    
326      def SetClassification(self, clazz, group = None):      def SetClassification(self, clazz, group = None):
327            """Fill in the table with the given classification.
328            Select the given group if group is not None.
329            """
330    
331          self.GetView().BeginBatch()          self.GetView().BeginBatch()
332    
# Line 325  class ClassTable(wxPyGridTableBase): Line 334  class ClassTable(wxPyGridTableBase):
334    
335          row = -1          row = -1
336          self.clazz = clazz          self.clazz = clazz
337    
338          self.__NotifyRowChanges(old_len, self.GetNumberRows())          self.__NotifyRowChanges(old_len, self.GetNumberRows())
339    
340          #          #
# Line 338  class ClassTable(wxPyGridTableBase): Line 347  class ClassTable(wxPyGridTableBase):
347    
348          self.__Modified()          self.__Modified()
349    
   
350          self.GetView().EndBatch()          self.GetView().EndBatch()
351          self.GetView().FitInside()          self.GetView().FitInside()
352    
353      def __NotifyRowChanges(self, curRows, newRows):      def __NotifyRowChanges(self, curRows, newRows):
354            """Make sure table updates correctly if the number of
355            rows changes.
356            """
357          #          #
358          # silly message processing for updates to the number of          # silly message processing for updates to the number of
359          # rows and columns          # rows and columns
# Line 361  class ClassTable(wxPyGridTableBase): Line 372  class ClassTable(wxPyGridTableBase):
372              self.GetView().ProcessTableMessage(msg)              self.GetView().ProcessTableMessage(msg)
373              self.GetView().FitInside()              self.GetView().FitInside()
374    
   
375      def __SetRow(self, row, group):      def __SetRow(self, row, group):
376          """Set a row's data to that of the group.          """Set a row's data to that of the group.
377    
# Line 432  class ClassTable(wxPyGridTableBase): Line 442  class ClassTable(wxPyGridTableBase):
442          """          """
443    
444          self.SetValueAsCustom(row, col, None, value)          self.SetValueAsCustom(row, col, None, value)
445          
446      def GetValueAsCustom(self, row, col, typeName):      def GetValueAsCustom(self, row, col, typeName):
447          """Return the object that is used to represent the given          """Return the object that is used to represent the given
448             cell coordinates. This may not be a string.             cell coordinates. This may not be a string.
449    
450          typeName -- unused, but needed to overload wxPyGridTableBase          typeName -- unused, but needed to overload wxPyGridTableBase
451          """          """
452    
# Line 593  class ClassTable(wxPyGridTableBase): Line 603  class ClassTable(wxPyGridTableBase):
603              return self.clazz.GetGroup(row - 1)              return self.clazz.GetGroup(row - 1)
604    
605      def SetClassGroup(self, row, group):      def SetClassGroup(self, row, group):
606            """Set the given row to properties of group."""
607          self.__SetRow(row, group)          self.__SetRow(row, group)
608          self.GetView().Refresh()          self.GetView().Refresh()
609    
# Line 670  EB_LAYER_TITLE = 0 Line 681  EB_LAYER_TITLE = 0
681  EB_SELECT_FIELD = 1  EB_SELECT_FIELD = 1
682  EB_GEN_CLASS = 2  EB_GEN_CLASS = 2
683    
684  class Classifier(NonModalNonParentDialog):  class Classifier(LayerProperties):
685    
686      type2string = {None:             _("None"),      type2string = {None:             _("None"),
687                     FIELDTYPE_STRING: _("Text"),                     FIELDTYPE_STRING: _("Text"),
688                     FIELDTYPE_INT:    _("Integer"),                     FIELDTYPE_INT:    _("Integer"),
689                     FIELDTYPE_DOUBLE: _("Decimal")}                     FIELDTYPE_DOUBLE: _("Decimal")}
690    
691      def __init__(self, parent, name, map, layer, group = None):      def __init__(self, parent, name, layer, group = None):
692          NonModalNonParentDialog.__init__(self, parent, name, "")          """Create a Properties/Classification dialog for a layer.
693            The layer is part of map. If group is not None, select that
694          self.__SetTitle(layer.Title())          group in the classification table.
695            """
696    
697          self.layer = layer          LayerProperties.__init__(self, parent, name, layer)
         self.map = map  
698    
         self.map.Subscribe(MAP_LAYERS_REMOVED, self.map_layers_removed)  
699          self.layer.Subscribe(LAYER_SHAPESTORE_REPLACED,          self.layer.Subscribe(LAYER_SHAPESTORE_REPLACED,
700                               self.layer_shapestore_replaced)                               self.layer_shapestore_replaced)
701    
702          self.genDlg = None          self.genDlg = None
703            self.group = group
704    
705          ############################          LayerProperties.dialog_layout(self)
         # Create the controls  
         #  
706    
707          panel = wxPanel(self, -1)      def dialog_layout(self, panel, panelBox):
708    
709            if self.layer.HasClassification():
710    
711          text_title = wxTextCtrl(panel, ID_PROPERTY_TITLE, layer.Title())              self.fieldTypeText = wxStaticText(panel, -1, "")
         self.fieldTypeText = wxStaticText(panel, -1, "")  
712    
         if layer.HasClassification():  
713              self.originalClass = self.layer.GetClassification()              self.originalClass = self.layer.GetClassification()
714              self.originalClassField = self.layer.GetClassificationColumn()              self.originalClassField = self.layer.GetClassificationColumn()
715              field = self.originalClassField              field = self.originalClassField
716              fieldType = self.layer.GetFieldType(field)              fieldType = self.layer.GetFieldType(field)
717    
718              table = layer.ShapeStore().Table()              table = self.layer.ShapeStore().Table()
719              #              #
720              # make field choice box              # make field choice box
721              #              #
# Line 753  class Classifier(NonModalNonParentDialog Line 762  class Classifier(NonModalNonParentDialog
762              # calling __SelectField after creating the classGrid fills in the              # calling __SelectField after creating the classGrid fills in the
763              # grid with the correct information              # grid with the correct information
764              self.fields.SetSelection(self.__cur_field)              self.fields.SetSelection(self.__cur_field)
765              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_close = wxButton(self, wxID_CANCEL, _("Close"))  
         button_ok.SetDefault()  
   
         ############################  
         # Layout the controls  
         #  
766    
         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()  
   
         panelBox.Add(wxStaticText(panel, -1, _("Type: %s") % type),  
             0, wxALIGN_LEFT | wxALL, 4)  
   
         if layer.HasClassification():  
767    
768              classBox = wxStaticBoxSizer(              classBox = wxStaticBoxSizer(
769                          wxStaticBox(panel, -1, _("Classification")), wxVERTICAL)                          wxStaticBox(panel, -1, _("Classification")), wxVERTICAL)
# Line 807  class Classifier(NonModalNonParentDialog Line 787  class Classifier(NonModalNonParentDialog
787              controlButtonBox.Add(button_moveup, 0, wxGROW|wxALL, 4)              controlButtonBox.Add(button_moveup, 0, wxGROW|wxALL, 4)
788              controlButtonBox.Add(button_movedown, 0, wxGROW|wxALL, 4)              controlButtonBox.Add(button_movedown, 0, wxGROW|wxALL, 4)
789              controlButtonBox.Add(button_edit, 0, wxGROW|wxALL, 4)              controlButtonBox.Add(button_edit, 0, wxGROW|wxALL, 4)
790              controlButtonBox.Add(60, 20, 0, wxGROW|wxALL|wxALIGN_BOTTOM, 4)              controlButtonBox.Add( (60, 20), 0, wxGROW|wxALL|wxALIGN_BOTTOM, 4)
791              controlButtonBox.Add(button_remove, 0,              controlButtonBox.Add(button_remove, 0,
792                                   wxGROW|wxALL|wxALIGN_BOTTOM, 4)                                   wxGROW|wxALL|wxALIGN_BOTTOM, 4)
793    
# Line 818  class Classifier(NonModalNonParentDialog Line 798  class Classifier(NonModalNonParentDialog
798              panelBox.Add(classBox, 1, wxGROW, 0)              panelBox.Add(classBox, 1, wxGROW, 0)
799    
800    
         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()  
   
         ###########  
   
801          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)  
   
802          EVT_BUTTON(self, ID_PROPERTY_ADD, self._OnAdd)          EVT_BUTTON(self, ID_PROPERTY_ADD, self._OnAdd)
803          EVT_BUTTON(self, ID_PROPERTY_EDITSYM, self._OnEditSymbol)          EVT_BUTTON(self, ID_PROPERTY_EDITSYM, self._OnEditSymbol)
804          EVT_BUTTON(self, ID_PROPERTY_REMOVE, self._OnRemove)          EVT_BUTTON(self, ID_PROPERTY_REMOVE, self._OnRemove)
# Line 854  class Classifier(NonModalNonParentDialog Line 806  class Classifier(NonModalNonParentDialog
806          EVT_BUTTON(self, ID_PROPERTY_MOVEUP, self._OnMoveUp)          EVT_BUTTON(self, ID_PROPERTY_MOVEUP, self._OnMoveUp)
807          EVT_BUTTON(self, ID_PROPERTY_MOVEDOWN, self._OnMoveDown)          EVT_BUTTON(self, ID_PROPERTY_MOVEDOWN, self._OnMoveDown)
808    
         ######################  
   
         text_title.SetFocus()  
         self.haveApplied = False  
   
809      def unsubscribe_messages(self):      def unsubscribe_messages(self):
810          self.map.Unsubscribe(MAP_LAYERS_REMOVED, self.map_layers_removed)          """Unsubscribe from all messages."""
811            LayerProperties.unsubscribe_messages(self)
812          self.layer.Unsubscribe(LAYER_SHAPESTORE_REPLACED,          self.layer.Unsubscribe(LAYER_SHAPESTORE_REPLACED,
813                                 self.layer_shapestore_replaced)                                 self.layer_shapestore_replaced)
814    
     def map_layers_removed(self, map):  
         if self.layer not in self.map.Layers():  
             self.Close()  
   
815      def layer_shapestore_replaced(self, *args):      def layer_shapestore_replaced(self, *args):
816            """Subscribed to the map's LAYER_SHAPESTORE_REPLACED message.
817            Close self.
818            """
819          self.Close()          self.Close()
820    
821      def EditSymbol(self, row):      def EditSymbol(self, row):
822            """Open up a dialog where the user can select the properties
823            for a group.
824            """
825          table = self.classGrid.GetTable()          table = self.classGrid.GetTable()
826          prop = table.GetValueAsCustom(row, COL_SYMBOL, None)          prop = table.GetValueAsCustom(row, COL_SYMBOL, None)
827    
# Line 885  class Classifier(NonModalNonParentDialog Line 835  class Classifier(NonModalNonParentDialog
835              table.SetValueAsCustom(row, COL_SYMBOL, None, new_prop)              table.SetValueAsCustom(row, COL_SYMBOL, None, new_prop)
836          self.Enable(True)          self.Enable(True)
837          propDlg.Destroy()          propDlg.Destroy()
838            
839      def _SetClassification(self, clazz):      def _SetClassification(self, clazz):
840                    """Called from the ClassGen dialog when a new classification has
841            been created and should be set in the table.
842            """
843            # FIXME: This could be implemented using a message
844    
845          self.fields.SetClientData(self.__cur_field, clazz)          self.fields.SetClientData(self.__cur_field, clazz)
846          self.classGrid.GetTable().SetClassification(clazz)          self.classGrid.GetTable().SetClassification(clazz)
847    
848      def __BuildClassification(self, fieldIndex, copyClass=False, force=False):      def __BuildClassification(self, fieldIndex, copyClass=False, force=False):
849            """Pack the classification setting into a Classification object.
850            Returns (Classification, fieldName) where fieldName is the selected
851            field in the table that the classification should be used with.
852            """
853    
854  #       numRows = self.classGrid.GetNumberRows()  #       numRows = self.classGrid.GetNumberRows()
855  #       assert numRows > 0  # there should always be a default row  #       assert numRows > 0  # there should always be a default row
# Line 912  class Classifier(NonModalNonParentDialog Line 870  class Classifier(NonModalNonParentDialog
870          return clazz, fieldName          return clazz, fieldName
871    
872      def __SetGridTable(self, fieldIndex, group = None):      def __SetGridTable(self, fieldIndex, group = None):
873            """Set the table with the classification associated with the
874            selected field at fieldIndex. Select the specified group
875            if group is not None.
876            """
877    
878          clazz = self.fields.GetClientData(fieldIndex)          clazz = self.fields.GetClientData(fieldIndex)
879    
# Line 929  class Classifier(NonModalNonParentDialog Line 891  class Classifier(NonModalNonParentDialog
891                                     self.layer.ShapeType(), group)                                     self.layer.ShapeType(), group)
892    
893      def __SetFieldTypeText(self, fieldIndex):      def __SetFieldTypeText(self, fieldIndex):
894            """Set the field type string using the data type of the field
895            at fieldIndex.
896            """
897          fieldName = self.fields.GetString(fieldIndex)          fieldName = self.fields.GetString(fieldIndex)
898          fieldType = self.layer.GetFieldType(fieldName)          fieldType = self.layer.GetFieldType(fieldName)
899    
# Line 956  class Classifier(NonModalNonParentDialog Line 921  class Classifier(NonModalNonParentDialog
921          self.__SetFieldTypeText(newIndex)          self.__SetFieldTypeText(newIndex)
922    
923      def __SetTitle(self, title):      def __SetTitle(self, title):
924            """Set the title of the dialog."""
925          if title != "":          if title != "":
926              title = ": " + title              title = ": " + title
927    
928          self.SetTitle(_("Layer Properties") + title)          self.SetTitle(_("Layer Properties") + title)
929    
930      def _OnEditSymbol(self, event):      def _OnEditSymbol(self, event):
931            """Open up a dialog for the user to select group properties."""
932          sel = self.classGrid.GetCurrentSelection()          sel = self.classGrid.GetCurrentSelection()
933    
934          if len(sel) == 1:          if len(sel) == 1:
# Line 972  class Classifier(NonModalNonParentDialog Line 939  class Classifier(NonModalNonParentDialog
939          self.__SelectField(index, self.__cur_field)          self.__SelectField(index, self.__cur_field)
940          self.__cur_field = index          self.__cur_field = index
941    
942      def _OnTry(self, event):      def OnTry(self, event):
943          """Put the data from the table into a new Classification and hand          """Put the data from the table into a new Classification and hand
944             it to the layer.             it to the layer.
945          """          """
# Line 992  class Classifier(NonModalNonParentDialog Line 959  class Classifier(NonModalNonParentDialog
959    
960          self.haveApplied = True          self.haveApplied = True
961    
962      def _OnOK(self, event):      def OnOK(self, event):
963          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.  
         """  
   
964          self.Close()          self.Close()
965    
966      def _OnRevert(self, event):      def OnRevert(self, event):
967          """The layer's current classification stays the same."""          """The layer's current classification stays the same."""
968          if self.haveApplied:          if self.haveApplied and self.layer.HasClassification():
969              self.layer.SetClassificationColumn(self.originalClassField)              self.layer.SetClassificationColumn(self.originalClassField)
970              self.layer.SetClassification(self.originalClass)              self.layer.SetClassification(self.originalClass)
971    
# Line 1023  class Classifier(NonModalNonParentDialog Line 978  class Classifier(NonModalNonParentDialog
978          self.classGrid.DeleteSelectedRows()          self.classGrid.DeleteSelectedRows()
979    
980      def _OnGenClass(self, event):      def _OnGenClass(self, event):
981            """Open up a dialog for the user to generate classifications."""
982    
983          self.genDlg = ClassGenDialog(self, self.layer,          self.genDlg = ClassGenDialog(self, self.layer,
984                            self.fields.GetString(self.__cur_field))                            self.fields.GetString(self.__cur_field))
# Line 1034  class Classifier(NonModalNonParentDialog Line 990  class Classifier(NonModalNonParentDialog
990          self.genDlg.Show()          self.genDlg.Show()
991    
992      def _OnGenDialogClose(self, event):      def _OnGenDialogClose(self, event):
993            """Reenable buttons after the generate classification
994            dialog is closed.
995            """
996          self.genDlg.Destroy()          self.genDlg.Destroy()
997          self.genDlg = None          self.genDlg = None
998          self.__EnableButtons(EB_GEN_CLASS)          self.__EnableButtons(EB_GEN_CLASS)
999    
1000      def _OnMoveUp(self, event):      def _OnMoveUp(self, event):
1001            """When the user clicks MoveUp, try to move a group up one row."""
1002          sel = self.classGrid.GetCurrentSelection()          sel = self.classGrid.GetCurrentSelection()
1003    
1004          if len(sel) == 1:          if len(sel) == 1:
# Line 1054  class Classifier(NonModalNonParentDialog Line 1014  class Classifier(NonModalNonParentDialog
1014                  self.classGrid.MakeCellVisible(i - 1, 0)                  self.classGrid.MakeCellVisible(i - 1, 0)
1015    
1016      def _OnMoveDown(self, event):      def _OnMoveDown(self, event):
1017            """When the user clicks MoveDown, try to move a group down one row."""
1018          sel = self.classGrid.GetCurrentSelection()          sel = self.classGrid.GetCurrentSelection()
1019    
1020          if len(sel) == 1:          if len(sel) == 1:
# Line 1069  class Classifier(NonModalNonParentDialog Line 1030  class Classifier(NonModalNonParentDialog
1030                  self.classGrid.MakeCellVisible(i + 1, 0)                  self.classGrid.MakeCellVisible(i + 1, 0)
1031    
1032      def _OnTitleChanged(self, event):      def _OnTitleChanged(self, event):
1033            """Update the dialog title when the user changed the layer name."""
1034          obj = event.GetEventObject()          obj = event.GetEventObject()
1035    
1036          self.layer.SetTitle(obj.GetValue())          self.layer.SetTitle(obj.GetValue())
# Line 1077  class Classifier(NonModalNonParentDialog Line 1039  class Classifier(NonModalNonParentDialog
1039          self.__EnableButtons(EB_LAYER_TITLE)          self.__EnableButtons(EB_LAYER_TITLE)
1040    
1041      def __EnableButtons(self, case):      def __EnableButtons(self, case):
1042            """Helper method that enables/disables the appropriate buttons
1043            based on the case provided. Cases are constants beginning with EB_.
1044            """
1045    
1046          list = {wxID_OK                 : True,          list = {wxID_OK                 : True,
1047                  wxID_CANCEL             : True,                  wxID_CANCEL             : True,
# Line 1113  class Classifier(NonModalNonParentDialog Line 1078  class Classifier(NonModalNonParentDialog
1078              if win:              if win:
1079                  win.Enable(enable)                  win.Enable(enable)
1080    
1081  ID_SELPROP_SPINCTRL = 4002  ID_SELPROP_SPINCTRL_LINEWIDTH = 4002
1082  ID_SELPROP_PREVIEW = 4003  ID_SELPROP_PREVIEW = 4003
1083  ID_SELPROP_STROKECLR = 4004  ID_SELPROP_STROKECLR = 4004
1084  ID_SELPROP_FILLCLR = 4005  ID_SELPROP_FILLCLR = 4005
1085  ID_SELPROP_STROKECLRTRANS = 4006  ID_SELPROP_STROKECLRTRANS = 4006
1086  ID_SELPROP_FILLCLRTRANS = 4007  ID_SELPROP_FILLCLRTRANS = 4007
1087    ID_SELPROP_SPINCTRL_SIZE = 4008
1088    
1089  class SelectPropertiesDialog(wxDialog):  class SelectPropertiesDialog(wxDialog):
1090        """Dialog that allows the user to select group properties."""
1091    
1092      def __init__(self, parent, prop, shapeType):      def __init__(self, parent, prop, shapeType):
1093            """Open the dialog with the initial prop properties and shapeType."""
1094    
1095          wxDialog.__init__(self, parent, -1, _("Select Properties"),          wxDialog.__init__(self, parent, -1, _("Select Properties"),
1096                            style = wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)                            style = wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
1097    
# Line 1179  class SelectPropertiesDialog(wxDialog): Line 1148  class SelectPropertiesDialog(wxDialog):
1148              ctrlBox.Add(fillColorBox, 0,              ctrlBox.Add(fillColorBox, 0,
1149                          wxALIGN_CENTER_HORIZONTAL | wxALL | wxGROW, 4)                          wxALIGN_CENTER_HORIZONTAL | wxALL | wxGROW, 4)
1150    
1151            # Line width selection
1152          spinBox = wxBoxSizer(wxHORIZONTAL)          spinBox = wxBoxSizer(wxHORIZONTAL)
1153          spinBox.Add(wxStaticText(self, -1, _("Line Width: ")),          spinBox.Add(wxStaticText(self, -1, _("Line Width: ")),
1154                  0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 4)                  0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 4)
1155          self.spinCtrl = wxSpinCtrl(self, ID_SELPROP_SPINCTRL,          self.spinCtrl_linewidth = wxSpinCtrl(self,
1156                                     min=1, max=10,                                               ID_SELPROP_SPINCTRL_LINEWIDTH,
1157                                     value=str(prop.GetLineWidth()),                                               min=1, max=10,
1158                                     initial=prop.GetLineWidth())                                               value=str(prop.GetLineWidth()),
1159                                                 initial=prop.GetLineWidth())
         EVT_SPINCTRL(self, ID_SELPROP_SPINCTRL, self._OnSpin)  
1160    
1161          spinBox.Add(self.spinCtrl, 0, wxALIGN_LEFT | wxALL, 4)          EVT_SPINCTRL(self, ID_SELPROP_SPINCTRL_LINEWIDTH,
1162                         self._OnSpinLineWidth)
1163    
1164            spinBox.Add(self.spinCtrl_linewidth, 0, wxALIGN_LEFT | wxALL, 4)
1165          ctrlBox.Add(spinBox, 0, wxALIGN_RIGHT | wxALL, 0)          ctrlBox.Add(spinBox, 0, wxALIGN_RIGHT | wxALL, 0)
1166    
1167            # Size selection
1168            if shapeType == SHAPETYPE_POINT:
1169                spinBox = wxBoxSizer(wxHORIZONTAL)
1170                spinBox.Add(wxStaticText(self, -1, _("Size: ")),
1171                            0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 4)
1172                self.spinCtrl_size = wxSpinCtrl(self, ID_SELPROP_SPINCTRL_SIZE,
1173                                                min=1, max=100,
1174                                                value=str(prop.GetSize()),
1175                                                initial=prop.GetSize())
1176    
1177                EVT_SPINCTRL(self, ID_SELPROP_SPINCTRL_SIZE, self._OnSpinSize)
1178    
1179                spinBox.Add(self.spinCtrl_size, 0, wxALIGN_LEFT | wxALL, 4)
1180                ctrlBox.Add(spinBox, 0, wxALIGN_RIGHT | wxALL, 0)
1181    
1182    
1183          itemBox.Add(ctrlBox, 0, wxALIGN_RIGHT | wxALL | wxGROW, 0)          itemBox.Add(ctrlBox, 0, wxALIGN_RIGHT | wxALL | wxGROW, 0)
1184          topBox.Add(itemBox, 1, wxALIGN_LEFT | wxALL | wxGROW, 0)          topBox.Add(itemBox, 1, wxALIGN_LEFT | wxALL | wxGROW, 0)
1185    
# Line 1206  class SelectPropertiesDialog(wxDialog): Line 1194  class SelectPropertiesDialog(wxDialog):
1194          topBox.Add(buttonBox, 0, wxALIGN_RIGHT|wxBOTTOM|wxTOP, 10)          topBox.Add(buttonBox, 0, wxALIGN_RIGHT|wxBOTTOM|wxTOP, 10)
1195    
1196          button_ok.SetDefault()          button_ok.SetDefault()
1197                                                                                    
1198          #EVT_BUTTON(self, wxID_OK, self._OnOK)          #EVT_BUTTON(self, wxID_OK, self._OnOK)
1199          #EVT_BUTTON(self, ID_SELPROP_CANCEL, self._OnCancel)          #EVT_BUTTON(self, ID_SELPROP_CANCEL, self._OnCancel)
1200                                                                                    
1201          self.SetAutoLayout(True)          self.SetAutoLayout(True)
1202          self.SetSizer(topBox)          self.SetSizer(topBox)
1203          topBox.Fit(self)          topBox.Fit(self)
# Line 1221  class SelectPropertiesDialog(wxDialog): Line 1209  class SelectPropertiesDialog(wxDialog):
1209      def OnCancel(self, event):      def OnCancel(self, event):
1210          self.EndModal(wxID_CANCEL)          self.EndModal(wxID_CANCEL)
1211    
1212      def _OnSpin(self, event):      def _OnSpinLineWidth(self, event):
1213          self.prop.SetLineWidth(self.spinCtrl.GetValue())          self.prop.SetLineWidth(self.spinCtrl_linewidth.GetValue())
1214            self.previewWin.Refresh()
1215    
1216        def _OnSpinSize(self, event):
1217            self.prop.SetSize(self.spinCtrl_size.GetValue())
1218          self.previewWin.Refresh()          self.previewWin.Refresh()
1219    
1220      def __GetColor(self, cur):      def __GetColor(self, cur):
1221          dialog = wxColourDialog(self)          dialog = ColorDialog(self)
1222          if cur is not Transparent:          dialog.SetColor(cur)
             dialog.GetColourData().SetColour(Color2wxColour(cur))  
1223    
1224          ret = None          ret = None
1225          if dialog.ShowModal() == wxID_OK:          if dialog.ShowModal() == wxID_OK:
1226              ret = wxColour2Color(dialog.GetColourData().GetColour())              ret = dialog.GetColor()
1227    
1228          dialog.Destroy()          dialog.Destroy()
1229    
1230          return ret          return ret
1231            
1232      def _OnChangeLineColor(self, event):      def _OnChangeLineColor(self, event):
1233          clr = self.__GetColor(self.prop.GetLineColor())          clr = self.__GetColor(self.prop.GetLineColor())
1234          if clr is not None:          if clr is not None:
# Line 1247  class SelectPropertiesDialog(wxDialog): Line 1238  class SelectPropertiesDialog(wxDialog):
1238      def _OnChangeLineColorTrans(self, event):      def _OnChangeLineColorTrans(self, event):
1239          self.prop.SetLineColor(Transparent)          self.prop.SetLineColor(Transparent)
1240          self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer          self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer
1241            
1242      def _OnChangeFillColor(self, event):      def _OnChangeFillColor(self, event):
1243          clr = self.__GetColor(self.prop.GetFill())          clr = self.__GetColor(self.prop.GetFill())
1244          if clr is not None:          if clr is not None:
# Line 1263  class SelectPropertiesDialog(wxDialog): Line 1254  class SelectPropertiesDialog(wxDialog):
1254    
1255    
1256  class ClassDataPreviewWindow(wxWindow):  class ClassDataPreviewWindow(wxWindow):
1257        """A custom window that draws group properties using the correct shape."""
1258    
1259      def __init__(self, rect, prop, shapeType,      def __init__(self, rect, prop, shapeType,
1260                         parent = None, id = -1, size = wxDefaultSize):                         parent = None, id = -1, size = wxDefaultSize):
1261            """Draws the appropriate shape as specified with shapeType using
1262            prop properities.
1263            """
1264          if parent is not None:          if parent is not None:
1265              wxWindow.__init__(self, parent, id, (0, 0), size)              wxWindow.__init__(self, parent, id, (0, 0), size)
1266              EVT_PAINT(self, self._OnPaint)              EVT_PAINT(self, self._OnPaint)
# Line 1294  class ClassDataPreviewWindow(wxWindow): Line 1289  class ClassDataPreviewWindow(wxWindow):
1289          self.previewer.Draw(dc, rect, self.prop, self.shapeType)          self.previewer.Draw(dc, rect, self.prop, self.shapeType)
1290    
1291  class ClassDataPreviewer:  class ClassDataPreviewer:
1292        """Class that actually draws a group property preview."""
1293    
1294      def Draw(self, dc, rect, prop, shapeType):      def Draw(self, dc, rect, prop, shapeType):
1295            """Draw the property.
1296    
1297            returns: (w, h) as adapted extend if the drawing size
1298            exceeded the given rect. This can only be the case
1299            for point symbols. If the symbol fits the given rect,
1300            None is returned.
1301            """
1302    
1303          assert dc is not None          assert dc is not None
1304          assert isinstance(prop, ClassGroupProperties)          assert isinstance(prop, ClassGroupProperties)
# Line 1335  class ClassDataPreviewer: Line 1338  class ClassDataPreviewer:
1338    
1339          elif shapeType == SHAPETYPE_POINT:          elif shapeType == SHAPETYPE_POINT:
1340    
1341              dc.DrawCircle(x + w/2, y + h/2,              dc.DrawCircle(x + w/2, y + h/2, prop.GetSize())
1342                            (min(w, h) - prop.GetLineWidth())/2)              circle_size =  prop.GetSize() * 2 + prop.GetLineWidth() * 2
1343                new_h = h
1344                new_w = w
1345                if h < circle_size: new_h = circle_size
1346                if w < circle_size: new_w = circle_size
1347                if new_h > h or new_w > w:
1348                    return (new_w, new_h)
1349    
1350          elif shapeType == SHAPETYPE_POLYGON:          elif shapeType == SHAPETYPE_POLYGON:
1351              dc.DrawRectangle(x, y, w, h)              dc.DrawRectangle(x, y, w, h)
1352    
1353            return None
1354    
1355  class ClassRenderer(wxPyGridCellRenderer):  class ClassRenderer(wxPyGridCellRenderer):
1356        """A wrapper class that can be used to draw group properties in a
1357        grid table.
1358        """
1359    
1360      def __init__(self, shapeType):      def __init__(self, shapeType):
1361          wxPyGridCellRenderer.__init__(self)          wxPyGridCellRenderer.__init__(self)
# Line 1359  class ClassRenderer(wxPyGridCellRenderer Line 1373  class ClassRenderer(wxPyGridCellRenderer
1373                           rect.GetWidth(), rect.GetHeight())                           rect.GetWidth(), rect.GetHeight())
1374    
1375          if not isinstance(data, ClassGroupMap):          if not isinstance(data, ClassGroupMap):
1376              self.previewer.Draw(dc, rect, data.GetProperties(), self.shapeType)              new_size = self.previewer.Draw(dc, rect, data.GetProperties(),
1377                                               self.shapeType)
1378                if new_size is not None:
1379                    (new_w, new_h) = new_size
1380                    grid.SetRowSize(row, new_h)
1381                    grid.SetColSize(col, new_h)
1382                    grid.ForceRefresh()
1383    
1384                    # now that we know the height, redraw everything
1385                    rect.SetHeight(new_h)
1386                    rect.SetWidth(new_w)
1387                    dc.DestroyClippingRegion()
1388                    dc.SetClippingRegion(rect.GetX(), rect.GetY(),
1389                                         rect.GetWidth(), rect.GetHeight())
1390                    dc.SetPen(wxPen(wxLIGHT_GREY))
1391                    dc.SetBrush(wxBrush(wxLIGHT_GREY, wxSOLID))
1392                    dc.DrawRectangle(rect.GetX(), rect.GetY(),
1393                                     rect.GetWidth(), rect.GetHeight())
1394                    self.previewer.Draw(dc, rect, data.GetProperties(),
1395                                        self.shapeType)
1396    
1397          if isSelected:          if isSelected:
1398              dc.SetPen(wxPen(wxBLACK, 1, wxSOLID))              dc.SetPen(wxPen(wxBLACK, 1, wxSOLID))
# Line 1371  class ClassRenderer(wxPyGridCellRenderer Line 1404  class ClassRenderer(wxPyGridCellRenderer
1404          dc.DestroyClippingRegion()          dc.DestroyClippingRegion()
1405    
1406    
1407  class ClassGroupPropertiesCtrl(wxWindow, wxControl):  class ClassGroupPropertiesCtrl(wxControl):
1408        """A custom window and control that draw a preview of group properties
1409        and can open a dialog to modify the properties if the user double-clicks
1410        it.
1411        """
1412    
1413      def __init__(self, parent, id, props, shapeType,      def __init__(self, parent, id, props, shapeType,
1414                   size = wxDefaultSize, style = 0):                   size = wxDefaultSize, style = 0):
1415            wxControl.__init__(self, parent, id, size = size, style = style)
         wxWindow.__init__(self, parent, id, size = size, style = style)  
1416    
1417          self.parent = parent          self.parent = parent
1418    
# Line 1418  class ClassGroupPropertiesCtrl(wxWindow, Line 1454  class ClassGroupPropertiesCtrl(wxWindow,
1454          self.Refresh()          self.Refresh()
1455    
1456      def AllowEdit(self, allow):      def AllowEdit(self, allow):
1457            """Allow/Disallow double-clicking on the control."""
1458          self.allowEdit = allow          self.allowEdit = allow
1459    
1460      def DoEdit(self):      def DoEdit(self):
1461            """Open the properties selector dialog."""
1462    
1463          if not self.allowEdit: return          if not self.allowEdit: return
1464    
1465          propDlg = SelectPropertiesDialog(self.parent,          propDlg = SelectPropertiesDialog(self.parent,
# Line 1436  class ClassGroupPropertiesCtrl(wxWindow, Line 1475  class ClassGroupPropertiesCtrl(wxWindow,
1475    
1476      def _OnLeftDClick(self, event):      def _OnLeftDClick(self, event):
1477          self.DoEdit()          self.DoEdit()
1478    

Legend:
Removed from v.1452  
changed lines
  Added in v.2597

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26