class Ui_MovePropertyManager(Command_PropertyManager):

    # The title that appears in the Property Manager header
    title = "Move"
    # The name of this Property Manager. This will be set to
    # the name of the PM_Dialog object via setObjectName().
    pmName = title
    # The relative path to the PNG file that appears in the header
    iconPath = "ui/actions/Properties Manager/Translate_Components.png"

    # The title(s) that appear in the property manager header.
    # (these are changed depending on the active group box)
    translateTitle = "Translate"
    rotateTitle = "Rotate"

    # The full path to PNG file(s) that appears in the header.
    translateIconPath = "ui/actions/Properties Manager/Translate_Components.png"
    rotateIconPath = "ui/actions/Properties Manager/Rotate_Components.png"

    def __init__(self, command):
        _superclass.__init__(self, command)
        self.showTopRowButtons(PM_DONE_BUTTON | PM_WHATS_THIS_BUTTON)

    def _addGroupBoxes(self):
        """
        Add groupboxes to the Property Manager dialog. 
        """

        self.translateGroupBox = PM_GroupBox(self,
                                             title="Translate",
                                             connectTitleButton=False)
        self.translateGroupBox.titleButton.setShortcut('T')
        self._loadTranslateGroupBox(self.translateGroupBox)

        self.rotateGroupBox = PM_GroupBox(self,
                                          title="Rotate",
                                          connectTitleButton=False)
        self.rotateGroupBox.titleButton.setShortcut('R')
        self._loadRotateGroupBox(self.rotateGroupBox)

        self.translateGroupBox.collapse()
        self.rotateGroupBox.collapse()

    # == Begin Translate Group Box =====================

    def _loadTranslateGroupBox(self, inPmGroupBox):
        """
        Load widgets in the Translate group box.
        @param inPmGroupBox: The Translate group box in the PM
        @type  inPmGroupBox: L{PM_GroupBox}
        """

        translateChoices = ["Free Drag", "By Delta XYZ", "To XYZ Position"]

        self.translateComboBox = \
            PM_ComboBox( inPmGroupBox,
                         label        = '',
                         choices      = translateChoices,
                         index        = 0,
                         setAsDefault = False,
                         spanWidth    = True )

        self.freeDragTranslateGroupBox = PM_GroupBox(inPmGroupBox)
        self._loadFreeDragTranslateGroupBox(self.freeDragTranslateGroupBox)

        self.byDeltaGroupBox = PM_GroupBox(inPmGroupBox)
        self._loadByDeltaGroupBox(self.byDeltaGroupBox)

        self.toPositionGroupBox = PM_GroupBox(inPmGroupBox)
        self._loadToPositionGroupBox(self.toPositionGroupBox)

        self.updateTranslateGroupBoxes(0)

    def _loadFreeDragTranslateGroupBox(self, inPmGroupBox):
        """
        Load widgets in the Free Drag Translate group box, which is present 
        within the Translate groupbox.
        @param inPmGroupBox: The Free Drag Translate group box in the Translate 
                             group box. 
        @type  inPmGroupBox: L{PM_GroupBox}
        """
        # Button list to create a toolbutton row.
        # Format:
        # - buttonId,
        # - buttonText ,
        # - iconPath
        # - tooltip
        # - shortcut
        # - column


        BUTTON_LIST = [
            ( "QToolButton", 1,  "MOVEDEFAULT",
              "ui/actions/Properties Manager/Move_Free.png", "", "F", 0),
            ( "QToolButton", 2,  "TRANSX",
              "ui/actions/Properties Manager/TranslateX.png", "", "X", 1),
            ( "QToolButton", 3,  "TRANSY",
              "ui/actions/Properties Manager/TranslateY.png", "", "Y", 2),
            ( "QToolButton", 4,  "TRANSZ",
              "ui/actions/Properties Manager/TranslateZ.png", "", "Z", 3),
            ( "QToolButton", 5,  "ROT_TRANS_ALONG_AXIS",
              "ui/actions/Properties Manager/translate+rotate-A.png", "", \
              "A", 4)

            ]

        self.freeDragTranslateButtonGroup = \
            PM_ToolButtonRow( inPmGroupBox,
                               title        = "",
                               buttonList   = BUTTON_LIST,
                               checkedId    = 1,
                               setAsDefault = True,
                               )
        self.transFreeButton = self.freeDragTranslateButtonGroup.getButtonById(
            1)
        self.transXButton = self.freeDragTranslateButtonGroup.getButtonById(2)
        self.transYButton = self.freeDragTranslateButtonGroup.getButtonById(3)
        self.transZButton = self.freeDragTranslateButtonGroup.getButtonById(4)
        self.transAlongAxisButton = \
            self.freeDragTranslateButtonGroup.getButtonById(5)

        self.moveFromToButton = PM_ToolButton(
                    inPmGroupBox,
                    text = "Translate from/to",
                    iconPath  = "ui/actions/Properties Manager"\
                    "/Translate_Components.png",
                    spanWidth = True

                    )
        self.moveFromToButton.setCheckable(True)
        self.moveFromToButton.setAutoRaise(True)
        self.moveFromToButton.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)


        self.startCoordLineEdit = PM_LineEdit(
            inPmGroupBox,
            label        = "ui/actions/Properties Manager"\
                    "/Move_Start_Point.png",
            text         = "Define 'from' and 'to' points",
            setAsDefault = False,
            )
        self.startCoordLineEdit.setReadOnly(True)
        self.startCoordLineEdit.setEnabled(False)

    def _loadByDeltaGroupBox(self, inPmGroupBox):
        """
        Load widgets in the translate By Delta group box, which is present 
        within the Translate groupbox.
        @param inPmGroupBox: The Translate By Delta group box in the translate 
                             group box. 
        @type  inPmGroupBox: L{PM_GroupBox}
        """

        self.moveDeltaXSpinBox = \
            PM_DoubleSpinBox(
                inPmGroupBox,
                label        = "ui/actions/Properties Manager/Delta_X.png",
                value        = 0.0,
                setAsDefault = True,
                minimum      = -100.0,
                maximum      =  100.0,
                singleStep   = 1.0,
                decimals     = 3,
                suffix       = ' Angstroms',
                spanWidth    = False )

        self.moveDeltaYSpinBox = \
            PM_DoubleSpinBox(
                inPmGroupBox,
                label        = "ui/actions/Properties Manager/Delta_Y.png",
                value        = 0.0,
                setAsDefault = True,
                minimum      = -100.0,
                maximum      =  100.0,
                singleStep   = 1.0,
                decimals     = 3,
                suffix       = ' Angstroms',
                spanWidth    = False )

        self.moveDeltaZSpinBox = \
            PM_DoubleSpinBox(
                inPmGroupBox,
                label        = "ui/actions/Properties Manager/Delta_Z.png",
                value        = 0.0,
                setAsDefault = True,
                minimum      = -100.0,
                maximum      =  100.0,
                singleStep   = 1.0,
                decimals     = 3,
                suffix       = ' Angstroms',
                spanWidth    = False )

        DELTA_BUTTONS = [
            ("QToolButton", 1, "Delta Plus",
             "ui/actions/Properties Manager/Move_Delta_Plus.png", "", "+", 0),
            ("QToolButton", 2, "Delta Minus",
             "ui/actions/Properties Manager/Move_Delta_Minus.png", "", "-", 1)
        ]

        self.translateDeltaButtonRow = \
            PM_ToolButtonRow( inPmGroupBox,
                              title        = "",
                              buttonList   = DELTA_BUTTONS,
                              label        = 'Translate:',
                              isAutoRaise  =  True,
                              isCheckable  =  False
                            )
        self.transDeltaPlusButton = \
            self.translateDeltaButtonRow.getButtonById(1)
        self.transDeltaMinusButton = \
            self.translateDeltaButtonRow.getButtonById(2)

    def _loadToPositionGroupBox(self, inPmGroupBox):
        """
        Load widgets in the Translate To a given Position group box, which is 
        present within the Translate groupbox.
        @param inPmGroupBox: Translate To Position group box in the Translate 
                             group box.
        @type  inPmGroupBox: L{PM_GroupBox}
        """

        self.toPositionspinboxes = PM_CoordinateSpinBoxes(inPmGroupBox)

        self.moveXSpinBox = self.toPositionspinboxes.xSpinBox
        self.moveYSpinBox = self.toPositionspinboxes.ySpinBox
        self.moveZSpinBox = self.toPositionspinboxes.zSpinBox


        self.moveAbsoluteButton = \
            PM_PushButton( inPmGroupBox,
                           label     = "",
                           text      = "Move Selection",
                           spanWidth = True )

    # == Begin Rotate Group Box =====================
    def _loadRotateGroupBox(self, inPmGroupBox):
        """
        Load widgets in the Rotate group box, 
        @param inPmGroupBox: The Rotate GroupBox in the PM
        @type  inPmGroupBox: L{PM_GroupBox}
        """

        rotateChoices = ["Free Drag", "By Specified Angle"]

        self.rotateComboBox = \
            PM_ComboBox( inPmGroupBox,
                         label        = '',
                         choices      = rotateChoices,
                         index        = 0,
                         setAsDefault = False,
                         spanWidth    = True )

        self.rotateAsUnitCB = \
            PM_CheckBox( inPmGroupBox,
                         text         = 'Rotate as a unit' ,
                         widgetColumn = 0,
                         state        = Qt.Checked )

        self.freeDragRotateGroupBox = PM_GroupBox(inPmGroupBox)
        self._loadFreeDragRotateGroupBox(self.freeDragRotateGroupBox)

        self.bySpecifiedAngleGroupBox = PM_GroupBox(inPmGroupBox)
        self._loadBySpecifiedAngleGroupBox(self.bySpecifiedAngleGroupBox)

        self.updateRotateGroupBoxes(0)

    def _loadFreeDragRotateGroupBox(self, inPmGroupBox):
        """
        Load widgets in the Free Drag Rotate group box, which is 
        present within the Rotate groupbox.
        @param inPmGroupBox: The Free Drag Rotate group box in the Rotate 
                             group box.
        @type  inPmGroupBox: L{PM_GroupBox}
        """
        # Button list to create a toolbutton row.
        # Format:
        # - buttonId,
        # - buttonText ,
        # - iconPath
        # - tooltip
        # - shortcut
        # - column

        BUTTON_LIST = [
            ( "QToolButton", 1,  "ROTATEDEFAULT",
              "ui/actions/Properties Manager/Rotate_Free.png", "", "F", 0 ),

            ( "QToolButton", 2,  "ROTATEX",
              "ui/actions/Properties Manager/RotateX.png", "", "X", 1 ),

            ( "QToolButton", 3,  "ROTATEY",
              "ui/actions/Properties Manager/RotateY.png", "", "Y", 2 ),

            ( "QToolButton", 4,  "ROTATEZ",
              "ui/actions/Properties Manager/RotateZ.png", "", "Z", 3 ),

            ( "QToolButton", 5,  "ROT_TRANS_ALONG_AXIS",
              "ui/actions/Properties Manager/translate+rotate-A.png", "", \
              "A", 4 )

            ]

        self.freeDragRotateButtonGroup = \
            PM_ToolButtonRow( inPmGroupBox,
                               title        = "",
                               buttonList   = BUTTON_LIST,
                               spanWidth = True,
                               checkedId    = 1,
                               setAsDefault = True,
                            )

        self.rotateFreeButton = self.freeDragRotateButtonGroup.getButtonById(1)
        self.rotateXButton = self.freeDragRotateButtonGroup.getButtonById(2)
        self.rotateYButton = self.freeDragRotateButtonGroup.getButtonById(3)
        self.rotateZButton = self.freeDragRotateButtonGroup.getButtonById(4)
        self.rotAlongAxisButton = \
            self.freeDragRotateButtonGroup.getButtonById(5)

        inPmGroupBox.setStyleSheet(
            self.freeDragRotateButtonGroup._getStyleSheet())

        X_ROW_LABELS = [("QLabel", "Delta Theta X:", 0), ("QLabel", "", 1),
                        ("QLabel", "0.00", 2), ("QLabel", "Degrees", 3)]

        Y_ROW_LABELS = [("QLabel", "Delta Theta Y:", 0), ("QLabel", "", 1),
                        ("QLabel", "0.00", 2), ("QLabel", "Degrees", 3)]

        Z_ROW_LABELS = [("QLabel", "Delta Theta Z:", 0), ("QLabel", "", 1),
                        ("QLabel", "0.00", 2), ("QLabel", "Degrees", 3)]

        self.rotateXLabelRow = PM_LabelRow(inPmGroupBox,
                                           title="",
                                           labelList=X_ROW_LABELS)
        self.deltaThetaX_lbl = self.rotateXLabelRow.labels[2]

        self.rotateYLabelRow = PM_LabelRow(inPmGroupBox,
                                           title="",
                                           labelList=Y_ROW_LABELS)
        self.deltaThetaY_lbl = self.rotateYLabelRow.labels[2]

        self.rotateZLabelRow = PM_LabelRow(inPmGroupBox,
                                           title="",
                                           labelList=Z_ROW_LABELS)
        self.deltaThetaZ_lbl = self.rotateZLabelRow.labels[2]

        self.rotateAboutPointButton = PM_ToolButton(
                    inPmGroupBox,
                    text = "Rotate selection about a point",
                    iconPath  = "ui/actions/Properties Manager"\
                    "/Rotate_Components.png",
                    spanWidth = True
                    )
        self.rotateAboutPointButton.setCheckable(True)
        self.rotateAboutPointButton.setAutoRaise(True)
        self.rotateAboutPointButton.setToolButtonStyle(
            Qt.ToolButtonTextBesideIcon)


        self.rotateStartCoordLineEdit = PM_LineEdit(
            inPmGroupBox,
            label        = "ui/actions/Properties Manager"\
                    "/Move_Start_Point.png",
            text         = "Define 3 points",
            setAsDefault = False,
            )
        self.rotateStartCoordLineEdit.setReadOnly(True)
        self.rotateStartCoordLineEdit.setEnabled(False)

    def _loadBySpecifiedAngleGroupBox(self, inPmGroupBox):
        """
        Load widgets in the Rotate By Specified Angle group box, which is 
        present within the Rotate groupbox.
        @param inPmGroupBox: Rotate By Specified Angle group box in the Rotate 
                             group box.
        @type  inPmGroupBox: L{PM_GroupBox}
        """
        # Button list to create a toolbutton row.
        # Format:
        # - buttonId,
        # - buttonText ,
        # - iconPath
        # - tooltip
        # - shortcut
        # - column

        BUTTON_LIST = [
            ("QToolButton", 1, "ROTATEX",
             "ui/actions/Properties Manager/RotateX.png",
             "Rotate about X axis", "X", 0),
            ("QToolButton", 2, "ROTATEY",
             "ui/actions/Properties Manager/RotateY.png",
             "Rotate about Y axis", "Y", 1),
            ("QToolButton", 3, "ROTATEZ",
             "ui/actions/Properties Manager/RotateZ.png",
             "Rotate about Z axis", "Z", 2),
        ]



        self.rotateAroundAxisButtonRow = \
            PM_ToolButtonRow( inPmGroupBox,
                              title        = "",
                              buttonList   = BUTTON_LIST,
                              alignment    = 'Right',
                              label        = 'Rotate Around:'
                            )
        self.rotXaxisButton = \
            self.rotateAroundAxisButtonRow.getButtonById(1)

        self.rotYaxisButton = \
            self.rotateAroundAxisButtonRow.getButtonById(2)

        self.rotZaxisButton = \
            self.rotateAroundAxisButtonRow.getButtonById(3)



        self.rotateThetaSpinBox = \
            PM_DoubleSpinBox(inPmGroupBox,
                             label        = "Rotate By:",
                             value        = 0.0,
                             setAsDefault = True,
                             minimum      = 0,
                             maximum      = 360.0,
                             singleStep   = 1.0,
                             decimals     = 2,
                             suffix       = ' Degrees')

        THETA_BUTTONS = [
            ("QToolButton", 1, "Theta Plus",
             "ui/actions/Properties Manager/Move_Theta_Plus.png", "", "+", 0),
            ("QToolButton", 2, "Theta Minus",
             "ui/actions/Properties Manager/Move_Theta_Minus.png", "", "-", 1)
        ]

        self.rotateThetaButtonRow = \
            PM_ToolButtonRow( inPmGroupBox,
                              title        = "",
                              buttonList   = THETA_BUTTONS,
                              label        = 'Direction:',
                              isAutoRaise  =  True,
                              isCheckable  =  False
                            )
        self.rotateThetaPlusButton = self.rotateThetaButtonRow.getButtonById(1)
        self.rotateThetaMinusButton = self.rotateThetaButtonRow.getButtonById(
            2)

    # == End Rotate Group Box =====================

    # == Slots for Translate group box
    def _hideAllTranslateGroupBoxes(self):
        """
        Hides all Translate group boxes.
        """
        self.toPositionGroupBox.hide()
        self.byDeltaGroupBox.hide()
        self.freeDragTranslateGroupBox.hide()

    def updateTranslateGroupBoxes(self, id):
        """
        Update the translate group boxes displayed based on the translate
        option selected.
        @param id: Integer value corresponding to the combobox item in the 
                   Translate group box. 
        @type  id: int
        """
        self._hideAllTranslateGroupBoxes()

        if id is 0:
            self.freeDragTranslateGroupBox.show()

        if id is 1:
            self.byDeltaGroupBox.show()
        if id is 2:
            self.toPositionGroupBox.show()

        self.updateMessage()

    def changeMoveOption(self, button):
        """
        Subclasses should reimplement this method.
        
        @param button: QToolButton that decides the type of translate operation 
        to be set.
        @type  button: QToolButton 
                       L{http://doc.trolltech.com/4.2/qtoolbutton.html}
        @see: B{MovePropertyManager.changeMoveOption} which overrides this
              method
        """
        pass

    # == Slots for Rotate group box
    def updateRotateGroupBoxes(self, id):
        """
        Update the translate group boxes displayed based on the translate
        option selected.
        @param id: Integer value corresponding to the combobox item in the 
                   Rotate group box. 
        @type  id: int
        """
        if id is 0:
            self.bySpecifiedAngleGroupBox.hide()
            self.freeDragRotateGroupBox.show()
        if id is 1:
            self.freeDragRotateGroupBox.hide()
            self.bySpecifiedAngleGroupBox.show()

        self.updateMessage()

    def changeRotateOption(self, button):
        """
        Subclasses should reimplement this method. 
        
        @param button: QToolButton that decides the type of rotate operation 
        to be set.
        @type  button: QToolButton 
                       L{http://doc.trolltech.com/4.2/qtoolbutton.html}
        @see: B{MovePropertyManage.changeRotateOption} which overrides this 
             method
        """
        pass

    def _addWhatsThisText(self):
        """
        What's This text for some of the widgets in this Property Manager.  

        """
        from ne1_ui.WhatsThisText_for_PropertyManagers import whatsThis_MovePropertyManager
        whatsThis_MovePropertyManager(self)

    def _addToolTipText(self):
        """
        Tool Tip text for widgets in this Property Manager.  
        """
        from ne1_ui.ToolTipText_for_PropertyManagers import ToolTip_MovePropertyManager
        ToolTip_MovePropertyManager(self)
class Ui_BuildAtomsPropertyManager(Command_PropertyManager):
    """
    The Ui_BuildAtomsPropertyManager class defines UI elements for the Property 
    Manager of the B{Build Atoms mode}.
    
    @ivar title: The title that appears in the property manager header.
    @type title: str
    
    @ivar pmName: The name of this property manager. This is used to set
                  the name of the PM_Dialog object via setObjectName().
    @type name: str
    
    @ivar iconPath: The relative path to the PNG file that contains a
                    22 x 22 icon image that appears in the PM header.
    @type iconPath: str
    """

    # The title that appears in the Property Manager header
    title = "Build Atoms"
    # The name of this Property Manager. This will be set to
    # the name of the PM_Dialog object via setObjectName().
    pmName = title
    # The relative path to the PNG file that appears in the header
    iconPath = "ui/actions/Tools/Build Structures/BuildAtoms.png"

    def __init__(self, command):
        """
        Constructor for the B{Build Atoms} property manager class that defines 
        its UI.
        
        @param command: The parent mode where this Property Manager is used
        @type  command: L{depositMode}        
        """

        self.previewGroupBox = None
        self.regularElementChooser = None
        self.PAM5Chooser = None
        self.PAM3Chooser = None
        self.elementChooser = None
        self.advancedOptionsGroupBox = None
        self.bondToolsGroupBox = None

        self.selectionFilterCheckBox = None
        self.filterlistLE = None
        self.selectedAtomInfoLabel = None

        #Initialize the following to None. (subclasses may not define this)
        #Make sure you initialize it before adding groupboxes!
        self.selectedAtomPosGroupBox = None
        self.showSelectedAtomInfoCheckBox = None

        _superclass.__init__(self, command)

        self.showTopRowButtons(PM_DONE_BUTTON | PM_WHATS_THIS_BUTTON)
        msg = ''
        self.MessageGroupBox.insertHtmlMessage(msg, setAsDefault=False)

    def _addGroupBoxes(self):
        """
        Add various group boxes to the Build Atoms Property manager. 
        """
        self._addPreviewGroupBox()
        self._addAtomChooserGroupBox()
        self._addBondToolsGroupBox()

        #@@@TODO HIDE the bonds tool groupbox initially as the
        #by default, the atoms tool is active when BuildAtoms command is
        #finist invoked.
        self.bondToolsGroupBox.hide()

        self._addSelectionOptionsGroupBox()
        self._addAdvancedOptionsGroupBox()

    def _addPreviewGroupBox(self):
        """
        Adde the preview groupbox that shows the element selected in the 
        element chooser. 
        """
        self.previewGroupBox = PM_PreviewGroupBox(self, glpane=self.o)

    def _addAtomChooserGroupBox(self):
        """
        Add the Atom Chooser groupbox. This groupbox displays one of the 
        following three groupboxes depending on the choice selected in the 
        combobox:
          a) Periodic Table Elements L{self.regularElementChooser}
          b) PAM5 Atoms  L{self.PAM5Chooser}
          c) PAM3 Atoms  L{self.PAM3Chooser}
        @see: L{self.__updateAtomChooserGroupBoxes}
        """
        self.atomChooserGroupBox = \
            PM_GroupBox(self, title = "Atom Chooser")
        self._loadAtomChooserGroupBox(self.atomChooserGroupBox)

        self._updateAtomChooserGroupBoxes(currentIndex=0)

    def _addElementChooserGroupBox(self, inPmGroupBox):
        """
        Add the 'Element Chooser' groupbox. (present within the 
        Atom Chooser Groupbox) 
        """
        if not self.previewGroupBox:
            return

        elementViewer = self.previewGroupBox.elementViewer
        self.regularElementChooser = \
            PM_ElementChooser( inPmGroupBox,
                               parentPropMgr = self,
                               elementViewer = elementViewer)

    def _add_PAM5_AtomChooserGroupBox(self, inPmGroupBox):
        """
        Add the 'PAM5 Atom Chooser' groupbox (present within the 
        Atom Chooser Groupbox) 
        """
        if not self.previewGroupBox:
            return

        elementViewer = self.previewGroupBox.elementViewer
        self.PAM5Chooser = \
            PM_PAM5_AtomChooser( inPmGroupBox,
                                 parentPropMgr = self,
                                 elementViewer = elementViewer)

    def _add_PAM3_AtomChooserGroupBox(self, inPmGroupBox):
        """
        Add the 'PAM3 Atom Chooser' groupbox (present within the 
        Atom Chooser Groupbox)
        """
        if not self.previewGroupBox:
            return

        elementViewer = self.previewGroupBox.elementViewer
        self.PAM3Chooser = \
            PM_PAM3_AtomChooser( inPmGroupBox,
                                 parentPropMgr = self,
                                 elementViewer = elementViewer)

    def _hideAllAtomChooserGroupBoxes(self):
        """
        Hides all Atom Chooser group boxes.
        """
        if self.regularElementChooser:
            self.regularElementChooser.hide()
        if self.PAM5Chooser:
            self.PAM5Chooser.hide()
        if self.PAM3Chooser:
            self.PAM3Chooser.hide()

    def _addBondToolsGroupBox(self):
        """
        Add the 'Bond Tools' groupbox.
        """
        self.bondToolsGroupBox = \
            PM_GroupBox( self, title = "Bond Tools")

        self._loadBondToolsGroupBox(self.bondToolsGroupBox)

    def _addSelectionOptionsGroupBox(self):
        """
        Add 'Selection Options' groupbox
        """
        self.selectionOptionsGroupBox = \
            PM_GroupBox( self, title = "Selection Options" )

        self._loadSelectionOptionsGroupBox(self.selectionOptionsGroupBox)

    def _loadAtomChooserGroupBox(self, inPmGroupBox):
        """
        Load the widgets inside the Atom Chooser groupbox.
        @param inPmGroupBox: The Atom Chooser box in the PM
        @type  inPmGroupBox: L{PM_GroupBox} 
        """
        atomChooserChoices = [
            "Periodic Table Elements", "PAM5 Atoms", "PAM3 Atoms"
        ]

        self.atomChooserComboBox = \
            PM_ComboBox( inPmGroupBox,
                         label        = '',
                         choices      = atomChooserChoices,
                         index        = 0,
                         setAsDefault = False,
                         spanWidth    = True )

        #Following fixes bug 2550
        self.atomChooserComboBox.setFocusPolicy(Qt.NoFocus)

        self._addElementChooserGroupBox(inPmGroupBox)
        self._add_PAM5_AtomChooserGroupBox(inPmGroupBox)
        self._add_PAM3_AtomChooserGroupBox(inPmGroupBox)

    def _loadSelectionOptionsGroupBox(self, inPmGroupBox):
        """
        Load widgets in the Selection Options group box.
        @param inPmGroupBox: The Selection Options box in the PM
        @type  inPmGroupBox: L{PM_GroupBox} 
        """

        self.selectionFilterCheckBox = \
            PM_CheckBox( inPmGroupBox,
                         text  = "Enable atom selection filter",
                         widgetColumn = 0,
                         state        = Qt.Unchecked  )
        self.selectionFilterCheckBox.setDefaultValue(False)

        self.filterlistLE = PM_LineEdit(inPmGroupBox,
                                        label="",
                                        text="",
                                        setAsDefault=False,
                                        spanWidth=True)
        self.filterlistLE.setReadOnly(True)

        if self.selectionFilterCheckBox.isChecked():
            self.filterlistLE.setEnabled(True)
        else:
            self.filterlistLE.setEnabled(False)

        self.showSelectedAtomInfoCheckBox = \
            PM_CheckBox(
                inPmGroupBox,
                text  = "Show Selected Atom Info",
                widgetColumn = 0,
                state        = Qt.Unchecked)

        self.selectedAtomPosGroupBox = \
            PM_GroupBox( inPmGroupBox, title = "")
        self._loadSelectedAtomPosGroupBox(self.selectedAtomPosGroupBox)

        self.toggle_selectedAtomPosGroupBox(show=0)
        self.enable_or_disable_selectedAtomPosGroupBox(bool_enable=False)

        self.reshapeSelectionCheckBox = \
            PM_CheckBox( inPmGroupBox,
                         text         = 'Dragging reshapes selection',
                         widgetColumn = 0,
                         state        = Qt.Unchecked  )

        connect_checkbox_with_boolean_pref(self.reshapeSelectionCheckBox,
                                           reshapeAtomsSelection_prefs_key)

        env.prefs[reshapeAtomsSelection_prefs_key] = False

        self.waterCheckBox = \
            PM_CheckBox( inPmGroupBox,
                         text         = "Z depth filter (water surface)",
                         widgetColumn = 0,
                         state        = Qt.Unchecked  )

    def _loadSelectedAtomPosGroupBox(self, inPmGroupBox):
        """
        Load the selected Atoms position groupbox It is a sub-gropbox of 
        L{self.selectionOptionsGroupBox)
        @param inPmGroupBox: 'The Selected Atom Position Groupbox'
        @type  inPmGroupBox: L{PM_GroupBox} 
        """

        self.selectedAtomLineEdit = PM_LineEdit(inPmGroupBox,
                                                label="Selected Atom:",
                                                text="",
                                                setAsDefault=False,
                                                spanWidth=False)

        self.selectedAtomLineEdit.setReadOnly(True)
        self.selectedAtomLineEdit.setEnabled(False)

        self.coordinateSpinboxes = PM_CoordinateSpinBoxes(inPmGroupBox)

        # User input to specify x-coordinate
        self.xCoordOfSelectedAtom = self.coordinateSpinboxes.xSpinBox
        # User input to specify y-coordinate
        self.yCoordOfSelectedAtom = self.coordinateSpinboxes.ySpinBox
        # User input to specify z-coordinate
        self.zCoordOfSelectedAtom = self.coordinateSpinboxes.zSpinBox

    def _addAdvancedOptionsGroupBox(self):
        """
        Add 'Advanced Options' groupbox
        """
        self.advancedOptionsGroupBox = \
            PM_GroupBox( self, title = "Advanced Options" )

        self._loadAdvancedOptionsGroupBox(self.advancedOptionsGroupBox)

    def _loadAdvancedOptionsGroupBox(self, inPmGroupBox):
        """
        Load widgets in the Advanced Options group box.
        @param inPmGroupBox: The Advanced Options box in the PM
        @type  inPmGroupBox: L{PM_GroupBox} 
        """

        self.autoBondCheckBox = \
            PM_CheckBox( inPmGroupBox,
                         text         = 'Auto bond',
                         widgetColumn = 0,
                         state        = Qt.Checked  )

        self.highlightingCheckBox = \
            PM_CheckBox( inPmGroupBox,
                         text         = "Hover highlighting",
                         widgetColumn = 0,
                         state        = Qt.Checked )

    def _loadBondToolsGroupBox(self, inPmGroupBox):
        """
        Load widgets in the Bond Tools group box.
        @param inPmGroupBox: The Bond Tools box in the PM
        @type  inPmGroupBox: L{PM_GroupBox}        
        """
        # Button list to create a toolbutton row.
        # Format:
        # - buttonId,
        # - buttonText ,
        # - iconPath
        # - tooltip
        # - shortcut
        # - column
        BOND_TOOL_BUTTONS = \
                          [ ( "QToolButton", 0,  "SINGLE",    "", "", None, 0),
                            ( "QToolButton", 1,  "DOUBLE",    "", "", None, 1),
                            ( "QToolButton", 2,  "TRIPLE",    "", "", None, 2),
                            ( "QToolButton", 3,  "AROMATIC",  "", "", None, 3),
                            ( "QToolButton", 4,  "GRAPHITIC", "", "", None, 4),
                            ( "QToolButton", 5,  "CUTBONDS",  "", "", None, 5)
                          ]


        self.bondToolButtonRow = \
            PM_ToolButtonRow(
                inPmGroupBox,
                title        = "",
                buttonList   = BOND_TOOL_BUTTONS,
                checkedId    = None,
                setAsDefault = True )

    def _addWhatsThisText(self):
        """
        "What's This" text for widgets in this Property Manager.
        """
        from ne1_ui.WhatsThisText_for_PropertyManagers import whatsThis_BuildAtomsPropertyManager
        whatsThis_BuildAtomsPropertyManager(self)

    def _addToolTipText(self):
        """
        Tool Tip text for widgets in this Property Manager.  
        """
        from ne1_ui.ToolTipText_for_PropertyManagers import ToolTip_BuildAtomsPropertyManager
        ToolTip_BuildAtomsPropertyManager(self)

    def toggle_selectedAtomPosGroupBox(self, show=0):
        """
        Show or hide L{self.selectedAtomPosGroupBox} depending on the state of
        the checkbox (L{self.showSelectedAtomInfoCheckBox}) 
        @param show: Flag that shows or hides the groupbox (can have values 
                     0 or 1
        @type  show: int
        """
        if show:
            self.selectedAtomPosGroupBox.show()
        else:
            self.selectedAtomPosGroupBox.hide()

    def enable_or_disable_selectedAtomPosGroupBox(self, bool_enable=False):
        """
        Enable or disable Selected AtomPosGroupBox present within 
        'selection options' and also the checkbox that shows or hide this 
        groupbox. These two widgets are enabled when only a single atom is 
        selected from the 3D workspace. 
        @param bool_enable: Flag that enables or disables widgets
        @type  bool_enable: boolean
        """
        if self.showSelectedAtomInfoCheckBox:
            self.showSelectedAtomInfoCheckBox.setEnabled(bool_enable)
        if self.selectedAtomPosGroupBox:
            self.selectedAtomPosGroupBox.setEnabled(bool_enable)

    def _updateAtomChooserGroupBoxes(self, currentIndex):
        """
        Updates the Atom Chooser Groupbox. It displays one of the 
        following three groupboxes depending on the choice selected in the 
        combobox:
          a) Periodic Table Elements L{self.regularElementChooser}
          b) PAM5 Atoms  L{self.PAM5Chooser}
          c) PAM3 Atoms  L{self.PAM3Chooser}
        It also sets self.elementChooser to the current active Atom chooser 
        and updates the display accordingly in the Preview groupbox.
        """
        self._hideAllAtomChooserGroupBoxes()

        if currentIndex is 0:
            self.elementChooser = self.regularElementChooser
            self.regularElementChooser.show()
        if currentIndex is 1:
            self.elementChooser = self.PAM5Chooser
            self.PAM5Chooser.show()
        if currentIndex is 2:
            self.elementChooser = self.PAM3Chooser
            self.PAM3Chooser.show()

        if self.elementChooser:
            self.elementChooser.updateElementViewer()

        self.updateMessage()

    def updateMessage(self):
        """
        Update the Message groupbox with informative message. 
        Subclasses should override this.
        """
        pass
class InsertNanotube_PropertyManager(DnaOrCnt_PropertyManager):
    """
    The InsertNanotube_PropertyManager class provides a Property Manager
    for the B{Build > Nanotube > CNT} command.

    @ivar title: The title that appears in the property manager header.
    @type title: str

    @ivar pmName: The name of this property manager. This is used to set
                  the name of the PM_Dialog object via setObjectName().
    @type name: str

    @ivar iconPath: The relative path to the PNG file that contains a
                    22 x 22 icon image that appears in the PM header.
    @type iconPath: str
    """

    title = "Insert Nanotube"
    pmName = title
    iconPath = "ui/actions/Tools/Build Structures/InsertNanotube.png"

    def __init__(self, win, editCommand):
        """
        Constructor for the Nanotube property manager.
        """
        self.endPoint1 = None
        self.endPoint2 = None

        self.nanotube = Nanotube()  # A 5x5 CNT.

        _superclass.__init__(self, win, editCommand)

        self.showTopRowButtons( PM_DONE_BUTTON | \
                                PM_CANCEL_BUTTON | \
                                PM_WHATS_THIS_BUTTON)

    def connect_or_disconnect_signals(self, isConnect):
        """
        Connect or disconnect widget signals sent to their slot methods.
        This can be overridden in subclasses. By default it does nothing.
        @param isConnect: If True the widget will send the signals to the slot
                          method.
        @type  isConnect: boolean
        """
        if isConnect:
            change_connect = self.win.connect
        else:
            change_connect = self.win.disconnect

        change_connect(self.ntTypeComboBox,
                       SIGNAL("currentIndexChanged(const QString&)"),
                       self._ntTypeComboBoxChanged)

        change_connect(self.chiralityNSpinBox, SIGNAL("valueChanged(int)"),
                       self._chiralityFixup)

        change_connect(self.chiralityMSpinBox, SIGNAL("valueChanged(int)"),
                       self._chiralityFixup)

        change_connect(self.endingsComboBox,
                       SIGNAL("currentIndexChanged(const QString&)"),
                       self._endingsComboBoxChanged)

        # This spin box is currently hidden.
        change_connect(self.bondLengthDoubleSpinBox,
                       SIGNAL("valueChanged(double)"), self._bondLengthChanged)

        change_connect(self.showCursorTextCheckBox,
                       SIGNAL('stateChanged(int)'),
                       self._update_state_of_cursorTextGroupBox)

    def ok_btn_clicked(self):
        """
        Slot for the OK button
        """
        if self.editCommand:
            self.editCommand.preview_or_finalize_structure(previewing=False)
            ##env.history.message(self.editCommand.logMessage)
        self.win.toolsDone()

    def cancel_btn_clicked(self):
        """
        Slot for the Cancel button.
        """
        if self.editCommand:
            self.editCommand.cancelStructure()
        self.win.toolsCancel()

    def _update_widgets_in_PM_before_show(self):
        """
        Update various widgets in this Property manager.
        Overrides MotorPropertyManager._update_widgets_in_PM_before_show.
        The various  widgets , (e.g. spinboxes) will get values from the
        structure for which this propMgr is constructed for
        (self.editcCntroller.struct)

        @see: MotorPropertyManager._update_widgets_in_PM_before_show
        @see: self.show where it is called.
        """
        pass

    def getFlyoutActionList(self):
        """
        Returns custom actionlist that will be used in a specific mode
        or editing a feature etc Example: while in movie mode,
        the _createFlyoutToolBar method calls this.
        """
        #'allActionsList' returns all actions in the flyout toolbar
        #including the subcontrolArea actions
        allActionsList = []

        #Action List for  subcontrol Area buttons.
        #In this mode there is really no subcontrol area.
        #We will treat subcontrol area same as 'command area'
        #(subcontrol area buttons will have an empty list as their command area
        #list). We will set  the Comamnd Area palette background color to the
        #subcontrol area.

        subControlAreaActionList = []

        self.exitEditCommandAction.setChecked(True)
        subControlAreaActionList.append(self.exitEditCommandAction)

        separator = QAction(self.w)
        separator.setSeparator(True)
        subControlAreaActionList.append(separator)

        allActionsList.extend(subControlAreaActionList)

        #Empty actionlist for the 'Command Area'
        commandActionLists = []

        #Append empty 'lists' in 'commandActionLists equal to the
        #number of actions in subControlArea
        for i in range(len(subControlAreaActionList)):
            lst = []
            commandActionLists.append(lst)

        params = (subControlAreaActionList, commandActionLists, allActionsList)

        return params

    def _addGroupBoxes(self):
        """
        Add the Insert Nanotube Property Manager group boxes.
        """

        self._pmGroupBox1 = PM_GroupBox(self, title="Endpoints")
        self._loadGroupBox1(self._pmGroupBox1)
        self._pmGroupBox1.hide()

        self._pmGroupBox2 = PM_GroupBox(self, title="Parameters")
        self._loadGroupBox2(self._pmGroupBox2)

        self._displayOptionsGroupBox = PM_GroupBox(self,
                                                   title="Display Options")
        self._loadDisplayOptionsGroupBox(self._displayOptionsGroupBox)

        self._pmGroupBox3 = PM_GroupBox(self, title="Nanotube Distortion")
        self._loadGroupBox3(self._pmGroupBox3)
        self._pmGroupBox3.hide()  #@ Temporary.

        self._pmGroupBox4 = PM_GroupBox(self, title="Multi-Walled CNTs")
        self._loadGroupBox4(self._pmGroupBox4)
        self._pmGroupBox4.hide()  #@ Temporary.

        self._pmGroupBox5 = PM_GroupBox(self, title="Advanced Options")
        self._loadGroupBox5(self._pmGroupBox5)
        self._pmGroupBox5.hide()  #@ Temporary.

    def _loadGroupBox1(self, pmGroupBox):
        """
        Load widgets in group box 1.
        """
        #Following toolbutton facilitates entering a temporary NanotubeLineMode
        #to create a CNT using endpoints of the specified line.
        self.specifyCntLineButton = PM_ToolButton(
            pmGroupBox,
            text="Specify Endpoints",
            iconPath="ui/actions/Properties Manager/Pencil.png",
            spanWidth=True)
        self.specifyCntLineButton.setCheckable(True)
        self.specifyCntLineButton.setAutoRaise(True)
        self.specifyCntLineButton.setToolButtonStyle(
            Qt.ToolButtonTextBesideIcon)

        #EndPoint1 and endPoint2 coordinates. These widgets are hidden
        # as of 2007- 12 - 05
        self._endPoint1SpinBoxes = PM_CoordinateSpinBoxes(pmGroupBox,
                                                          label="End Point 1")
        self.x1SpinBox = self._endPoint1SpinBoxes.xSpinBox
        self.y1SpinBox = self._endPoint1SpinBoxes.ySpinBox
        self.z1SpinBox = self._endPoint1SpinBoxes.zSpinBox

        self._endPoint2SpinBoxes = PM_CoordinateSpinBoxes(pmGroupBox,
                                                          label="End Point 2")
        self.x2SpinBox = self._endPoint2SpinBoxes.xSpinBox
        self.y2SpinBox = self._endPoint2SpinBoxes.ySpinBox
        self.z2SpinBox = self._endPoint2SpinBoxes.zSpinBox

        self._endPoint1SpinBoxes.hide()
        self._endPoint2SpinBoxes.hide()

    def _loadGroupBox2(self, pmGroupBox):
        """
        Load widgets in group box 2.
        """

        _ntTypeChoices = ['Carbon', 'Boron Nitride']
        self.ntTypeComboBox  = \
            PM_ComboBox( pmGroupBox,
                         label         =  "Type:",
                         choices       =  _ntTypeChoices,
                         setAsDefault  =  True)

        self.ntRiseDoubleSpinBox  =  \
            PM_DoubleSpinBox( pmGroupBox,
                              label         =  "Rise:",
                              value         =  self.nanotube.getRise(),
                              setAsDefault  =  True,
                              minimum       =  2.0,
                              maximum       =  4.0,
                              decimals      =  3,
                              singleStep    =  0.01 )

        self.ntRiseDoubleSpinBox.hide()

        # Nanotube Length
        self.ntLengthLineEdit  =  \
            PM_LineEdit( pmGroupBox,
                         label         =  "Nanotube Length: ",
                         text          =  "0.0 Angstroms",
                         setAsDefault  =  False)

        self.ntLengthLineEdit.setDisabled(True)
        self.ntLengthLineEdit.hide()

        # Nanotube diameter
        self.ntDiameterLineEdit  =  \
            PM_LineEdit( pmGroupBox,
                         label         =  "Diameter: ",
                         setAsDefault  =  False)

        self.ntDiameterLineEdit.setDisabled(True)
        self.updateNanotubeDiameter()

        self.chiralityNSpinBox = \
            PM_SpinBox( pmGroupBox,
                        label        = "Chirality (n):",
                        value        = self.nanotube.getChiralityN(),
                        minimum      =  2,
                        maximum      =  100,
                        setAsDefault = True )

        self.chiralityMSpinBox = \
            PM_SpinBox( pmGroupBox,
                        label        = "Chirality (m):",
                        value        = self.nanotube.getChiralityM(),
                        minimum      =  0,
                        maximum      =  100,
                        setAsDefault = True )

        # How about having user prefs for CNT and BNNT bond lengths?
        # I'm guessing that if the user wants to set these values, they will
        # do it once and would like those bond length values persist forever.
        # Need to discuss with others to determine if this spinbox comes out.
        # --Mark 2008-03-29
        self.bondLengthDoubleSpinBox = \
            PM_DoubleSpinBox( pmGroupBox,
                              label        = "Bond length:",
                              value        = self.nanotube.getBondLength(),
                              setAsDefault = True,
                              minimum      = 1.0,
                              maximum      = 3.0,
                              singleStep   = 0.1,
                              decimals     = 3,
                              suffix       = " Angstroms" )

        #self.bondLengthDoubleSpinBox.hide()

        endingChoices = ["Hydrogen", "None"]  # Removed:, "Nitrogen"]

        self.endingsComboBox= \
            PM_ComboBox( pmGroupBox,
                         label        = "Endings:",
                         choices      = endingChoices,
                         index        = 0,
                         setAsDefault = True,
                         spanWidth    = False )

    def _loadGroupBox3(self, inPmGroupBox):
        """
        Load widgets in group box 3.
        """

        self.zDistortionDoubleSpinBox = \
            PM_DoubleSpinBox( inPmGroupBox,
                              label        = "Z-distortion:",
                              value        = 0.0,
                              setAsDefault = True,
                              minimum      = 0.0,
                              maximum      = 10.0,
                              singleStep   = 0.1,
                              decimals     = 3,
                              suffix       = " Angstroms" )

        self.xyDistortionDoubleSpinBox = \
            PM_DoubleSpinBox( inPmGroupBox,
                              label        = "XY-distortion:",
                              value        = 0.0,
                              setAsDefault = True,
                              minimum      = 0.0,
                              maximum      = 2.0,
                              singleStep   = 0.1,
                              decimals     = 3,
                              suffix       = " Angstroms" )

        self.twistSpinBox = \
            PM_SpinBox( inPmGroupBox,
                        label        = "Twist:",
                        value        = 0,
                        setAsDefault = True,
                        minimum      = 0,
                        maximum      = 100, # What should maximum be?
                        suffix       = " deg/A" )

        self.bendSpinBox = \
            PM_SpinBox( inPmGroupBox,
                        label        = "Bend:",
                        value        = 0,
                        setAsDefault = True,
                        minimum      = 0,
                        maximum      = 360,
                        suffix       = " deg" )

    def _loadGroupBox4(self, inPmGroupBox):
        """
        Load widgets in group box 4.
        """

        # "Number of Nanotubes" SpinBox
        self.mwntCountSpinBox = \
            PM_SpinBox( inPmGroupBox,
                        label        = "Number:",
                        value        = 1,
                        setAsDefault = True,
                        minimum      = 1,
                        maximum      = 10,
                        suffix       = " nanotubes" )

        self.mwntCountSpinBox.setSpecialValueText("SWNT")

        # "Spacing" lineedit.
        self.mwntSpacingDoubleSpinBox = \
            PM_DoubleSpinBox( inPmGroupBox,
                              label        = "Spacing:",
                              value        = 2.46,
                              setAsDefault = True,
                              minimum      = 1.0,
                              maximum      = 10.0,
                              singleStep   = 0.1,
                              decimals     = 3,
                              suffix       = " Angstroms" )

    def _loadGroupBox5(self, pmGroupBox):
        """
        Load widgets in group box 5.
        """
        self._rubberbandLineGroupBox = PM_GroupBox(pmGroupBox,
                                                   title='Rubber band Line:')

        ntLineChoices = ['Ladder']
        self.ntRubberBandLineDisplayComboBox = \
            PM_ComboBox( self._rubberbandLineGroupBox ,
                         label         =  " Display as:",
                         choices       =  ntLineChoices,
                         setAsDefault  =  True)

        self.lineSnapCheckBox = \
            PM_CheckBox(self._rubberbandLineGroupBox ,
                        text         = 'Enable line snap' ,
                        widgetColumn = 1,
                        state        = Qt.Checked
                        )

    def _connect_showCursorTextCheckBox(self):
        """
        Connect the show cursor text checkbox with user prefs_key.
        Overrides
        DnaOrCnt_PropertyManager._connect_showCursorTextCheckBox
        """
        connect_checkbox_with_boolean_pref(
            self.showCursorTextCheckBox,
            insertNanotubeEditCommand_showCursorTextCheckBox_prefs_key)

    def _params_for_creating_cursorTextCheckBoxes(self):
        """
        Returns params needed to create various cursor text checkboxes connected
        to prefs_keys  that allow custom cursor texts.
        @return: A list containing tuples in the following format:
                ('checkBoxTextString' , preference_key). PM_PrefsCheckBoxes
                uses this data to create checkboxes with the the given names and
                connects them to the provided preference keys. (Note that
                PM_PrefsCheckBoxes puts thes within a GroupBox)
        @rtype: list
        @see: PM_PrefsCheckBoxes
        @see: self._loadDisplayOptionsGroupBox where this list is used.
        @see: Superclass method which is overridden here --
        DnaOrCnt_PropertyManager._params_for_creating_cursorTextCheckBoxes()
        """
        params = \
               [  #Format: (" checkbox text", prefs_key)

                   ("Nanotube length",
                    insertNanotubeEditCommand_cursorTextCheckBox_length_prefs_key ),

                    ("Angle",
                     insertNanotubeEditCommand_cursorTextCheckBox_angle_prefs_key )
                 ]

        return params

    def _addToolTipText(self):
        """
        Tool Tip text for widgets in the Insert Nanotube Property Manager.
        """
        pass

    def _setEndPoints(self):
        """
        Set the two endpoints of the nanotube using the values from the
        X, Y, Z coordinate spinboxes in the property manager.

        @note: The group box containing the 2 sets of XYZ spin boxes are
        currently hidden.
        """
        # First endpoint (origin) of nanotube
        x1 = self.x1SpinBox.value()
        y1 = self.y1SpinBox.value()
        z1 = self.z1SpinBox.value()

        # Second endpoint (direction vector/axis) of nanotube.
        x2 = self.x2SpinBox.value()
        y2 = self.y2SpinBox.value()
        z2 = self.z2SpinBox.value()

        if not self.endPoint1:
            self.endPoint1 = V(x1, y1, z1)
        if not self.endPoint2:
            self.endPoint2 = V(x2, y2, z2)

        self.nanotube.setEndPoints(self.endPoint1, self.endPoint2)
        # Need arg "recompute=True", which will recompute the second
        # endpoint (endPoint2) using the nanotube rise.

    def getParameters(self):
        """
        Return the parameters from this property manager to be used to create
        the nanotube.

        @return: A nanotube instance with its attrs set to the current
                 parameters in the property manager.
        @rtype: L{Nanotube}

        @see: L{InsertNanotube_EditCommand._gatherParameters} where this is used
        """
        self._setEndPoints()
        return (self.nanotube)

    def _ntTypeComboBoxChanged(self, type):
        """
        Slot for the Type combobox. It is called whenever the
        Type choice is changed.

        @param inIndex: The new index.
        @type  inIndex: int
        """
        self.nanotube.setType(str(type))
        print "Bond Length =", self.nanotube.getBondLength()
        self.bondLengthDoubleSpinBox.setValue(self.nanotube.getBondLength())
        #self.bondLengthDoubleSpinBox.setValue(ntBondLengths[inIndex])

    def _bondLengthChanged(self, bondLength):
        """
        Slot for the B{Bond Length} spinbox.
        """
        self.nanotube.setBondLength(bondLength)
        self.updateNanotubeDiameter()
        return

    def _chiralityFixup(self, spinBoxValueJunk=None):
        """
        Slot for several validators for different parameters.
        This gets called whenever the user changes the n, m chirality values.

        @param spinBoxValueJunk: This is the Spinbox value from the valueChanged
                                 signal. It is not used. We just want to know
                                 that the spinbox value has changed.
        @type  spinBoxValueJunk: double or None
        """
        _n, _m = self.nanotube.setChirality(self.chiralityNSpinBox.value(),
                                            self.chiralityMSpinBox.value())

        #self.n, self.m = self.nanotube.getChirality()

        self.connect_or_disconnect_signals(isConnect=False)
        self.chiralityNSpinBox.setValue(_n)
        self.chiralityMSpinBox.setValue(_m)
        self.connect_or_disconnect_signals(isConnect=True)

        self.updateNanotubeDiameter()

    def updateNanotubeDiameter(self):
        """
        Update the nanotube Diameter lineEdit widget.
        """
        diameterText = "%-7.4f Angstroms" % (self.nanotube.getDiameter())
        self.ntDiameterLineEdit.setText(diameterText)

        # ntRiseDoubleSpinBox is currently hidden.
        self.ntRiseDoubleSpinBox.setValue(self.nanotube.getRise())

    def _endingsComboBoxChanged(self, endings):
        """
        Slot for the B{Ending} combobox.

        @param endings: The option's text.
        @type  endings: string
        """
        self.nanotube.setEndings(str(endings))
        return

    def _addWhatsThisText(self):
        """
        What's This text for widgets in this Property Manager.
        """
        whatsThis_InsertNanotube_PropertyManager(self)
        return
class Ui_MovePropertyManager(Command_PropertyManager):
    
       
    # The title that appears in the Property Manager header        
    title = "Move"
    # The name of this Property Manager. This will be set to
    # the name of the PM_Dialog object via setObjectName().
    pmName = title
    # The relative path to the PNG file that appears in the header
    iconPath = "ui/actions/Properties Manager/Translate_Components.png"
    
    # The title(s) that appear in the property manager header.
    # (these are changed depending on the active group box) 
    translateTitle = "Translate"
    rotateTitle = "Rotate"

    # The full path to PNG file(s) that appears in the header.
    translateIconPath = "ui/actions/Properties Manager/Translate_Components.png"
    rotateIconPath = "ui/actions/Properties Manager/Rotate_Components.png"
    
    def __init__(self, command):  
        _superclass.__init__(self, command)       
        self.showTopRowButtons(PM_DONE_BUTTON | PM_WHATS_THIS_BUTTON)
    
    def _addGroupBoxes(self):
        """
        Add groupboxes to the Property Manager dialog. 
        """
        
        self.translateGroupBox = PM_GroupBox( self, 
                                              title = "Translate",
                                              connectTitleButton = False)
        self.translateGroupBox.titleButton.setShortcut('T')
        self._loadTranslateGroupBox(self.translateGroupBox)
        
        self.rotateGroupBox = PM_GroupBox( self, 
                                           title = "Rotate",
                                           connectTitleButton = False)
        self.rotateGroupBox.titleButton.setShortcut('R')
        self._loadRotateGroupBox(self.rotateGroupBox)
        
        self.translateGroupBox.collapse()
        self.rotateGroupBox.collapse()
            
    # == Begin Translate Group Box =====================
    
    def _loadTranslateGroupBox(self, inPmGroupBox):
        """
        Load widgets in the Translate group box.
        @param inPmGroupBox: The Translate group box in the PM
        @type  inPmGroupBox: L{PM_GroupBox}
        """
        
        translateChoices = [ "Free Drag", 
                             "By Delta XYZ", 
                             "To XYZ Position" ]
        
        self.translateComboBox = \
            PM_ComboBox( inPmGroupBox,
                         label        = '', 
                         choices      = translateChoices, 
                         index        = 0, 
                         setAsDefault = False,
                         spanWidth    = True )
        
        self.freeDragTranslateGroupBox = PM_GroupBox( inPmGroupBox )
        self._loadFreeDragTranslateGroupBox(self.freeDragTranslateGroupBox)
                
        self.byDeltaGroupBox = PM_GroupBox( inPmGroupBox )
        self._loadByDeltaGroupBox(self.byDeltaGroupBox)
        
        self.toPositionGroupBox = PM_GroupBox( inPmGroupBox )
        self._loadToPositionGroupBox(self.toPositionGroupBox)
        
        self.updateTranslateGroupBoxes(0)
    
    def _loadFreeDragTranslateGroupBox(self, inPmGroupBox):
        """
        Load widgets in the Free Drag Translate group box, which is present 
        within the Translate groupbox.
        @param inPmGroupBox: The Free Drag Translate group box in the Translate 
                             group box. 
        @type  inPmGroupBox: L{PM_GroupBox}
        """
        # Button list to create a toolbutton row.
        # Format: 
        # - buttonId, 
        # - buttonText , 
        # - iconPath
        # - tooltip
        # - shortcut
        # - column
        
         
        BUTTON_LIST = [ 
            ( "QToolButton", 1,  "MOVEDEFAULT", 
              "ui/actions/Properties Manager/Move_Free.png", "", "F", 0),
            ( "QToolButton", 2,  "TRANSX", 
              "ui/actions/Properties Manager/TranslateX.png", "", "X", 1),
            ( "QToolButton", 3,  "TRANSY",  
              "ui/actions/Properties Manager/TranslateY.png", "", "Y", 2),
            ( "QToolButton", 4,  "TRANSZ",  
              "ui/actions/Properties Manager/TranslateZ.png", "", "Z", 3),
            ( "QToolButton", 5,  "ROT_TRANS_ALONG_AXIS",  
              "ui/actions/Properties Manager/translate+rotate-A.png", "", \
              "A", 4)
                        
            ]
            
        self.freeDragTranslateButtonGroup = \
            PM_ToolButtonRow( inPmGroupBox, 
                               title        = "",
                               buttonList   = BUTTON_LIST,
                               checkedId    = 1,
                               setAsDefault = True,
                               )
        self.transFreeButton =self.freeDragTranslateButtonGroup.getButtonById(1)
        self.transXButton = self.freeDragTranslateButtonGroup.getButtonById(2)
        self.transYButton = self.freeDragTranslateButtonGroup.getButtonById(3)
        self.transZButton = self.freeDragTranslateButtonGroup.getButtonById(4)
        self.transAlongAxisButton = \
            self.freeDragTranslateButtonGroup.getButtonById(5)
        
        self.moveFromToButton = PM_ToolButton(
                    inPmGroupBox, 
                    text = "Translate from/to",
                    iconPath  = "ui/actions/Properties Manager"\
                    "/Translate_Components.png",
                    spanWidth = True
                    
                    )
        self.moveFromToButton.setCheckable(True)
        self.moveFromToButton.setAutoRaise(True)
        self.moveFromToButton.setToolButtonStyle(
            Qt.ToolButtonTextBesideIcon)
        
        
        self.startCoordLineEdit = PM_LineEdit( 
            inPmGroupBox, 
            label        = "ui/actions/Properties Manager"\
                    "/Move_Start_Point.png",
            text         = "Define 'from' and 'to' points",
            setAsDefault = False,
            )
        self.startCoordLineEdit.setReadOnly(True)
        self.startCoordLineEdit.setEnabled(False)
        
    def _loadByDeltaGroupBox(self, inPmGroupBox):
        """
        Load widgets in the translate By Delta group box, which is present 
        within the Translate groupbox.
        @param inPmGroupBox: The Translate By Delta group box in the translate 
                             group box. 
        @type  inPmGroupBox: L{PM_GroupBox}
        """

        self.moveDeltaXSpinBox = \
            PM_DoubleSpinBox( 
                inPmGroupBox, 
                label        = "ui/actions/Properties Manager/Delta_X.png",
                value        = 0.0, 
                setAsDefault = True,
                minimum      = -100.0, 
                maximum      =  100.0, 
                singleStep   = 1.0, 
                decimals     = 3, 
                suffix       = ' Angstroms',
                spanWidth    = False )
        
        self.moveDeltaYSpinBox = \
            PM_DoubleSpinBox( 
                inPmGroupBox, 
                label        = "ui/actions/Properties Manager/Delta_Y.png",
                value        = 0.0, 
                setAsDefault = True,
                minimum      = -100.0, 
                maximum      =  100.0, 
                singleStep   = 1.0, 
                decimals     = 3, 
                suffix       = ' Angstroms',
                spanWidth    = False )
        
        self.moveDeltaZSpinBox = \
            PM_DoubleSpinBox( 
                inPmGroupBox, 
                label        = "ui/actions/Properties Manager/Delta_Z.png",
                value        = 0.0, 
                setAsDefault = True,
                minimum      = -100.0, 
                maximum      =  100.0, 
                singleStep   = 1.0, 
                decimals     = 3, 
                suffix       = ' Angstroms',
                spanWidth    = False )
        
        DELTA_BUTTONS = [
                        ("QToolButton",1,  "Delta Plus", 
                         "ui/actions/Properties Manager/Move_Delta_Plus.png", 
                         "", "+", 0 ),
            
                        ( "QToolButton", 2,  "Delta Minus",  
                          "ui/actions/Properties Manager/Move_Delta_Minus.png", 
                          "", "-", 1 )
                        ]
        
        self.translateDeltaButtonRow = \
            PM_ToolButtonRow( inPmGroupBox, 
                              title        = "",
                              buttonList   = DELTA_BUTTONS,
                              label        = 'Translate:',
                              isAutoRaise  =  True,
                              isCheckable  =  False                           
                            )
        self.transDeltaPlusButton = \
            self.translateDeltaButtonRow.getButtonById(1)
        self.transDeltaMinusButton = \
            self.translateDeltaButtonRow.getButtonById(2)
        
            
    def _loadToPositionGroupBox(self, inPmGroupBox):
        """
        Load widgets in the Translate To a given Position group box, which is 
        present within the Translate groupbox.
        @param inPmGroupBox: Translate To Position group box in the Translate 
                             group box.
        @type  inPmGroupBox: L{PM_GroupBox}
        """
        
        self.toPositionspinboxes = PM_CoordinateSpinBoxes(inPmGroupBox)
        
        self.moveXSpinBox = self.toPositionspinboxes.xSpinBox
        self.moveYSpinBox = self.toPositionspinboxes.ySpinBox
        self.moveZSpinBox = self.toPositionspinboxes.zSpinBox
        
        
        self.moveAbsoluteButton = \
            PM_PushButton( inPmGroupBox,
                           label     = "",
                           text      = "Move Selection",
                           spanWidth = True )
            
    # == Begin Rotate Group Box =====================
    def _loadRotateGroupBox(self, inPmGroupBox):
        """
        Load widgets in the Rotate group box, 
        @param inPmGroupBox: The Rotate GroupBox in the PM
        @type  inPmGroupBox: L{PM_GroupBox}
        """
        
        rotateChoices = [ "Free Drag", "By Specified Angle"]
        
        self.rotateComboBox = \
            PM_ComboBox( inPmGroupBox,
                         label        = '', 
                         choices      = rotateChoices, 
                         index        = 0, 
                         setAsDefault = False,
                         spanWidth    = True )
        
        self.rotateAsUnitCB = \
            PM_CheckBox( inPmGroupBox,
                         text         = 'Rotate as a unit' ,
                         widgetColumn = 0,
                         state        = Qt.Checked )
        
               
        self.freeDragRotateGroupBox = PM_GroupBox( inPmGroupBox )
        self._loadFreeDragRotateGroupBox(self.freeDragRotateGroupBox)
        
        self.bySpecifiedAngleGroupBox = PM_GroupBox( inPmGroupBox )
        self._loadBySpecifiedAngleGroupBox(self.bySpecifiedAngleGroupBox)
        
        self.updateRotateGroupBoxes(0)    
        
    def _loadFreeDragRotateGroupBox(self, inPmGroupBox):
        """
        Load widgets in the Free Drag Rotate group box, which is 
        present within the Rotate groupbox.
        @param inPmGroupBox: The Free Drag Rotate group box in the Rotate 
                             group box.
        @type  inPmGroupBox: L{PM_GroupBox}
        """
        # Button list to create a toolbutton row.
        # Format: 
        # - buttonId, 
        # - buttonText , 
        # - iconPath
        # - tooltip
        # - shortcut
        # - column
        
        BUTTON_LIST = [ 
            ( "QToolButton", 1,  "ROTATEDEFAULT", 
              "ui/actions/Properties Manager/Rotate_Free.png", "", "F", 0 ),
            
            ( "QToolButton", 2,  "ROTATEX", 
              "ui/actions/Properties Manager/RotateX.png", "", "X", 1 ),
            
            ( "QToolButton", 3,  "ROTATEY",  
              "ui/actions/Properties Manager/RotateY.png", "", "Y", 2 ),
            
            ( "QToolButton", 4,  "ROTATEZ",  
              "ui/actions/Properties Manager/RotateZ.png", "", "Z", 3 ),
            
            ( "QToolButton", 5,  "ROT_TRANS_ALONG_AXIS",  
              "ui/actions/Properties Manager/translate+rotate-A.png", "", \
              "A", 4 )
                        
            ]
            
        self.freeDragRotateButtonGroup = \
            PM_ToolButtonRow( inPmGroupBox, 
                               title        = "",
                               buttonList   = BUTTON_LIST,
                               spanWidth = True,
                               checkedId    = 1,
                               setAsDefault = True,
                            )
                
        self.rotateFreeButton = self.freeDragRotateButtonGroup.getButtonById(1)
        self.rotateXButton    = self.freeDragRotateButtonGroup.getButtonById(2)
        self.rotateYButton    = self.freeDragRotateButtonGroup.getButtonById(3)
        self.rotateZButton    = self.freeDragRotateButtonGroup.getButtonById(4)
        self.rotAlongAxisButton = \
            self.freeDragRotateButtonGroup.getButtonById(5)
        
        inPmGroupBox.setStyleSheet(
            self.freeDragRotateButtonGroup._getStyleSheet())
                
        X_ROW_LABELS = [("QLabel", "Delta Theta X:", 0),
                        ("QLabel", "", 1),
                        ("QLabel", "0.00", 2),
                        ("QLabel", "Degrees", 3)]
        
        Y_ROW_LABELS = [("QLabel", "Delta Theta Y:", 0),
                        ("QLabel", "", 1),
                        ("QLabel", "0.00", 2),
                        ("QLabel", "Degrees", 3)]
        
        Z_ROW_LABELS = [("QLabel", "Delta Theta Z:", 0),
                        ("QLabel", "", 1),
                        ("QLabel", "0.00", 2),
                        ("QLabel", "Degrees", 3)]
        
        self.rotateXLabelRow = PM_LabelRow( inPmGroupBox,
                                            title = "",
                                            labelList = X_ROW_LABELS )  
        self.deltaThetaX_lbl = self.rotateXLabelRow.labels[2]
                                           
        self.rotateYLabelRow = PM_LabelRow( inPmGroupBox,
                                            title = "",
                                            labelList = Y_ROW_LABELS )
        self.deltaThetaY_lbl = self.rotateYLabelRow.labels[2]
                                          
        self.rotateZLabelRow = PM_LabelRow( inPmGroupBox,
                                            title = "",
                                            labelList = Z_ROW_LABELS )  
        self.deltaThetaZ_lbl = self.rotateZLabelRow.labels[2]    
        
        self.rotateAboutPointButton = PM_ToolButton(
                    inPmGroupBox, 
                    text = "Rotate selection about a point",
                    iconPath  = "ui/actions/Properties Manager"\
                    "/Rotate_Components.png",
                    spanWidth = True                    
                    )
        self.rotateAboutPointButton.setCheckable(True)
        self.rotateAboutPointButton.setAutoRaise(True)
        self.rotateAboutPointButton.setToolButtonStyle(
            Qt.ToolButtonTextBesideIcon)
        
        
        self.rotateStartCoordLineEdit = PM_LineEdit( 
            inPmGroupBox, 
            label        = "ui/actions/Properties Manager"\
                    "/Move_Start_Point.png",
            text         = "Define 3 points",
            setAsDefault = False,
            )
        self.rotateStartCoordLineEdit.setReadOnly(True)
        self.rotateStartCoordLineEdit.setEnabled(False)
            
            
    def _loadBySpecifiedAngleGroupBox(self, inPmGroupBox):
        """
        Load widgets in the Rotate By Specified Angle group box, which is 
        present within the Rotate groupbox.
        @param inPmGroupBox: Rotate By Specified Angle group box in the Rotate 
                             group box.
        @type  inPmGroupBox: L{PM_GroupBox}
        """
        # Button list to create a toolbutton row.
        # Format: 
        # - buttonId, 
        # - buttonText , 
        # - iconPath
        # - tooltip
        # - shortcut
        # - column
        
        BUTTON_LIST = [ 
            ( "QToolButton", 1,  "ROTATEX", 
              "ui/actions/Properties Manager/RotateX.png", 
              "Rotate about X axis", "X", 0 ),
            
            ( "QToolButton", 2,  "ROTATEY",  
              "ui/actions/Properties Manager/RotateY.png", 
              "Rotate about Y axis", "Y", 1 ),
            
            ( "QToolButton", 3,  "ROTATEZ",  
              "ui/actions/Properties Manager/RotateZ.png", 
              "Rotate about Z axis","Z", 2 ),
            ]
        
        
        
        self.rotateAroundAxisButtonRow = \
            PM_ToolButtonRow( inPmGroupBox, 
                              title        = "",
                              buttonList   = BUTTON_LIST,
                              alignment    = 'Right',
                              label        = 'Rotate Around:'
                            )
        self.rotXaxisButton = \
            self.rotateAroundAxisButtonRow.getButtonById(1)
        
        self.rotYaxisButton = \
            self.rotateAroundAxisButtonRow.getButtonById(2)
        
        self.rotZaxisButton = \
            self.rotateAroundAxisButtonRow.getButtonById(3)
        
        

        self.rotateThetaSpinBox = \
            PM_DoubleSpinBox(inPmGroupBox,
                             label        = "Rotate By:",
                             value        = 0.0, 
                             setAsDefault = True,
                             minimum      = 0, 
                             maximum      = 360.0,
                             singleStep   = 1.0, 
                             decimals     = 2, 
                             suffix       = ' Degrees')
        
        
        THETA_BUTTONS = [ 
            ( "QToolButton", 1,  "Theta Plus", 
              "ui/actions/Properties Manager/Move_Theta_Plus.png", "", "+", 0 ),
            
            ( "QToolButton", 2,  "Theta Minus",  
              "ui/actions/Properties Manager/Move_Theta_Minus.png", "", "-", 1 )
            ]
        
        self.rotateThetaButtonRow = \
            PM_ToolButtonRow( inPmGroupBox, 
                              title        = "",
                              buttonList   = THETA_BUTTONS,
                              label        = 'Direction:',
                              isAutoRaise  =  True,
                              isCheckable  =  False                           
                            )
        self.rotateThetaPlusButton =  self.rotateThetaButtonRow.getButtonById(1)
        self.rotateThetaMinusButton = self.rotateThetaButtonRow.getButtonById(2)
    
    # == End Rotate Group Box =====================
        
    # == Slots for Translate group box
    def _hideAllTranslateGroupBoxes(self):
        """
        Hides all Translate group boxes.
        """
        self.toPositionGroupBox.hide()
        self.byDeltaGroupBox.hide()
        self.freeDragTranslateGroupBox.hide()
            
    def updateTranslateGroupBoxes(self, id):
        """
        Update the translate group boxes displayed based on the translate
        option selected.
        @param id: Integer value corresponding to the combobox item in the 
                   Translate group box. 
        @type  id: int
        """
        self._hideAllTranslateGroupBoxes()
        
        if id is 0:
            self.freeDragTranslateGroupBox.show()
                               
        if id is 1:
            self.byDeltaGroupBox.show()                    
        if id is 2:
            self.toPositionGroupBox.show()
           
        self.updateMessage()
    
    def changeMoveOption(self, button):
        """
        Subclasses should reimplement this method.
        
        @param button: QToolButton that decides the type of translate operation 
        to be set.
        @type  button: QToolButton 
                       L{http://doc.trolltech.com/4.2/qtoolbutton.html}
        @see: B{MovePropertyManager.changeMoveOption} which overrides this
              method
        """
        pass
    
    # == Slots for Rotate group box
    def updateRotateGroupBoxes(self, id):
        """
        Update the translate group boxes displayed based on the translate
        option selected.
        @param id: Integer value corresponding to the combobox item in the 
                   Rotate group box. 
        @type  id: int
        """
        if id is 0:
            self.bySpecifiedAngleGroupBox.hide()
            self.freeDragRotateGroupBox.show()   
        if id is 1:
            self.freeDragRotateGroupBox.hide()
            self.bySpecifiedAngleGroupBox.show()
            
        self.updateMessage()
            
    def changeRotateOption(self, button):
        """
        Subclasses should reimplement this method. 
        
        @param button: QToolButton that decides the type of rotate operation 
        to be set.
        @type  button: QToolButton 
                       L{http://doc.trolltech.com/4.2/qtoolbutton.html}
        @see: B{MovePropertyManage.changeRotateOption} which overrides this 
             method
        """
        pass
    
    def _addWhatsThisText(self):
        """
        What's This text for some of the widgets in this Property Manager.  

        """
        from ne1_ui.WhatsThisText_for_PropertyManagers import whatsThis_MovePropertyManager
        whatsThis_MovePropertyManager(self)
        
    def _addToolTipText(self):
        """
        Tool Tip text for widgets in this Property Manager.  
        """
        from ne1_ui.ToolTipText_for_PropertyManagers import ToolTip_MovePropertyManager
        ToolTip_MovePropertyManager(self)
class Ui_BuildAtomsPropertyManager(Command_PropertyManager):
    """
    The Ui_BuildAtomsPropertyManager class defines UI elements for the Property
    Manager of the B{Build Atoms mode}.

    @ivar title: The title that appears in the property manager header.
    @type title: str

    @ivar pmName: The name of this property manager. This is used to set
                  the name of the PM_Dialog object via setObjectName().
    @type name: str

    @ivar iconPath: The relative path to the PNG file that contains a
                    22 x 22 icon image that appears in the PM header.
    @type iconPath: str
    """

    # The title that appears in the Property Manager header
    title = "Build Atoms"
    # The name of this Property Manager. This will be set to
    # the name of the PM_Dialog object via setObjectName().
    pmName = title
    # The relative path to the PNG file that appears in the header
    iconPath = "ui/actions/Tools/Build Structures/BuildAtoms.png"

    def __init__(self, command):
        """
        Constructor for the B{Build Atoms} property manager class that defines
        its UI.

        @param command: The parent mode where this Property Manager is used
        @type  command: L{depositMode}
        """

        self.previewGroupBox = None
        self.regularElementChooser = None
        self.PAM5Chooser = None
        self.PAM3Chooser = None
        self.elementChooser = None
        self.advancedOptionsGroupBox = None
        self.bondToolsGroupBox = None

        self.selectionFilterCheckBox = None
        self.filterlistLE = None
        self.selectedAtomInfoLabel = None

        #Initialize the following to None. (subclasses may not define this)
        #Make sure you initialize it before adding groupboxes!
        self.selectedAtomPosGroupBox = None
        self.showSelectedAtomInfoCheckBox = None

        _superclass.__init__(self, command)

        self.showTopRowButtons(PM_DONE_BUTTON | PM_WHATS_THIS_BUTTON)
        msg = ''
        self.MessageGroupBox.insertHtmlMessage(msg, setAsDefault=False)

    def _addGroupBoxes(self):
        """
        Add various group boxes to the Build Atoms Property manager.
        """
        self._addPreviewGroupBox()
        self._addAtomChooserGroupBox()
        self._addBondToolsGroupBox()

        #@@@TODO HIDE the bonds tool groupbox initially as the
        #by default, the atoms tool is active when BuildAtoms command is
        #finist invoked.
        self.bondToolsGroupBox.hide()

        self._addSelectionOptionsGroupBox()
        self._addAdvancedOptionsGroupBox()

    def _addPreviewGroupBox(self):
        """
        Adde the preview groupbox that shows the element selected in the
        element chooser.
        """
        self.previewGroupBox = PM_PreviewGroupBox( self, glpane = self.o )

    def _addAtomChooserGroupBox(self):
        """
        Add the Atom Chooser groupbox. This groupbox displays one of the
        following three groupboxes depending on the choice selected in the
        combobox:
          a) Periodic Table Elements L{self.regularElementChooser}
          b) PAM5 Atoms  L{self.PAM5Chooser}
          c) PAM3 Atoms  L{self.PAM3Chooser}
        @see: L{self.__updateAtomChooserGroupBoxes}
        """
        self.atomChooserGroupBox = \
            PM_GroupBox(self, title = "Atom Chooser")
        self._loadAtomChooserGroupBox(self.atomChooserGroupBox)

        self._updateAtomChooserGroupBoxes(currentIndex = 0)

    def _addElementChooserGroupBox(self, inPmGroupBox):
        """
        Add the 'Element Chooser' groupbox. (present within the
        Atom Chooser Groupbox)
        """
        if not self.previewGroupBox:
            return

        elementViewer = self.previewGroupBox.elementViewer
        self.regularElementChooser = \
            PM_ElementChooser( inPmGroupBox,
                               parentPropMgr = self,
                               elementViewer = elementViewer)


    def _add_PAM5_AtomChooserGroupBox(self, inPmGroupBox):
        """
        Add the 'PAM5 Atom Chooser' groupbox (present within the
        Atom Chooser Groupbox)
        """
        if not self.previewGroupBox:
            return

        elementViewer = self.previewGroupBox.elementViewer
        self.PAM5Chooser = \
            PM_PAM5_AtomChooser( inPmGroupBox,
                                 parentPropMgr = self,
                                 elementViewer = elementViewer)

    def _add_PAM3_AtomChooserGroupBox(self, inPmGroupBox):
        """
        Add the 'PAM3 Atom Chooser' groupbox (present within the
        Atom Chooser Groupbox)
        """
        if not self.previewGroupBox:
            return

        elementViewer = self.previewGroupBox.elementViewer
        self.PAM3Chooser = \
            PM_PAM3_AtomChooser( inPmGroupBox,
                                 parentPropMgr = self,
                                 elementViewer = elementViewer)

    def _hideAllAtomChooserGroupBoxes(self):
        """
        Hides all Atom Chooser group boxes.
        """
        if self.regularElementChooser:
            self.regularElementChooser.hide()
        if self.PAM5Chooser:
            self.PAM5Chooser.hide()
        if self.PAM3Chooser:
            self.PAM3Chooser.hide()

    def _addBondToolsGroupBox(self):
        """
        Add the 'Bond Tools' groupbox.
        """
        self.bondToolsGroupBox = \
            PM_GroupBox( self, title = "Bond Tools")

        self._loadBondToolsGroupBox(self.bondToolsGroupBox)

    def _addSelectionOptionsGroupBox(self):
        """
        Add 'Selection Options' groupbox
        """
        self.selectionOptionsGroupBox = \
            PM_GroupBox( self, title = "Selection Options" )

        self._loadSelectionOptionsGroupBox(self.selectionOptionsGroupBox)

    def _loadAtomChooserGroupBox(self, inPmGroupBox):
        """
        Load the widgets inside the Atom Chooser groupbox.
        @param inPmGroupBox: The Atom Chooser box in the PM
        @type  inPmGroupBox: L{PM_GroupBox}
        """
        atomChooserChoices = [ "Periodic Table Elements",
                             "PAM5 Atoms",
                             "PAM3 Atoms" ]

        self.atomChooserComboBox = \
            PM_ComboBox( inPmGroupBox,
                         label        = '',
                         choices      = atomChooserChoices,
                         index        = 0,
                         setAsDefault = False,
                         spanWidth    = True )

        #Following fixes bug 2550
        self.atomChooserComboBox.setFocusPolicy(Qt.NoFocus)

        self._addElementChooserGroupBox(inPmGroupBox)
        self._add_PAM5_AtomChooserGroupBox(inPmGroupBox)
        self._add_PAM3_AtomChooserGroupBox(inPmGroupBox)

    def _loadSelectionOptionsGroupBox(self, inPmGroupBox):
        """
        Load widgets in the Selection Options group box.
        @param inPmGroupBox: The Selection Options box in the PM
        @type  inPmGroupBox: L{PM_GroupBox}
        """

        self.selectionFilterCheckBox = \
            PM_CheckBox( inPmGroupBox,
                         text  = "Enable atom selection filter",
                         widgetColumn = 0,
                         state        = Qt.Unchecked  )
        self.selectionFilterCheckBox.setDefaultValue(False)

        self.filterlistLE = PM_LineEdit( inPmGroupBox,
                                         label        = "",
                                         text         = "",
                                         setAsDefault = False,
                                         spanWidth    = True )
        self.filterlistLE.setReadOnly(True)

        if self.selectionFilterCheckBox.isChecked():
            self.filterlistLE.setEnabled(True)
        else:
            self.filterlistLE.setEnabled(False)

        self.showSelectedAtomInfoCheckBox = \
            PM_CheckBox(
                inPmGroupBox,
                text  = "Show Selected Atom Info",
                widgetColumn = 0,
                state        = Qt.Unchecked)

        self.selectedAtomPosGroupBox = \
            PM_GroupBox( inPmGroupBox, title = "")
        self._loadSelectedAtomPosGroupBox(self.selectedAtomPosGroupBox)

        self.toggle_selectedAtomPosGroupBox(show = 0)
        self.enable_or_disable_selectedAtomPosGroupBox( bool_enable = False)

        self.reshapeSelectionCheckBox = \
            PM_CheckBox( inPmGroupBox,
                         text         = 'Dragging reshapes selection',
                         widgetColumn = 0,
                         state        = Qt.Unchecked  )

        connect_checkbox_with_boolean_pref( self.reshapeSelectionCheckBox,
                                            reshapeAtomsSelection_prefs_key )

        env.prefs[reshapeAtomsSelection_prefs_key] = False

        self.waterCheckBox = \
            PM_CheckBox( inPmGroupBox,
                         text         = "Z depth filter (water surface)",
                         widgetColumn = 0,
                         state        = Qt.Unchecked  )

    def _loadSelectedAtomPosGroupBox(self, inPmGroupBox):
        """
        Load the selected Atoms position groupbox It is a sub-gropbox of
        L{self.selectionOptionsGroupBox)
        @param inPmGroupBox: 'The Selected Atom Position Groupbox'
        @type  inPmGroupBox: L{PM_GroupBox}
        """

        self.selectedAtomLineEdit = PM_LineEdit( inPmGroupBox,
                                         label        = "Selected Atom:",
                                         text         = "",
                                         setAsDefault = False,
                                         spanWidth    = False )

        self.selectedAtomLineEdit.setReadOnly(True)
        self.selectedAtomLineEdit.setEnabled(False)

        self.coordinateSpinboxes = PM_CoordinateSpinBoxes(inPmGroupBox)

        # User input to specify x-coordinate
        self.xCoordOfSelectedAtom  =  self.coordinateSpinboxes.xSpinBox
        # User input to specify y-coordinate
        self.yCoordOfSelectedAtom  =  self.coordinateSpinboxes.ySpinBox
        # User input to specify z-coordinate
        self.zCoordOfSelectedAtom  =  self.coordinateSpinboxes.zSpinBox

    def _addAdvancedOptionsGroupBox(self):
        """
        Add 'Advanced Options' groupbox
        """
        self.advancedOptionsGroupBox = \
            PM_GroupBox( self, title = "Advanced Options" )

        self._loadAdvancedOptionsGroupBox(self.advancedOptionsGroupBox)

    def _loadAdvancedOptionsGroupBox(self, inPmGroupBox):
        """
        Load widgets in the Advanced Options group box.
        @param inPmGroupBox: The Advanced Options box in the PM
        @type  inPmGroupBox: L{PM_GroupBox}
        """

        self.autoBondCheckBox = \
            PM_CheckBox( inPmGroupBox,
                         text         = 'Auto bond',
                         widgetColumn = 0,
                         state        = Qt.Checked  )

        self.highlightingCheckBox = \
            PM_CheckBox( inPmGroupBox,
                         text         = "Hover highlighting",
                         widgetColumn = 0,
                         state        = Qt.Checked )

    def _loadBondToolsGroupBox(self, inPmGroupBox):
        """
        Load widgets in the Bond Tools group box.
        @param inPmGroupBox: The Bond Tools box in the PM
        @type  inPmGroupBox: L{PM_GroupBox}
        """
        # Button list to create a toolbutton row.
        # Format:
        # - buttonId,
        # - buttonText ,
        # - iconPath
        # - tooltip
        # - shortcut
        # - column
        BOND_TOOL_BUTTONS = \
                          [ ( "QToolButton", 0,  "SINGLE",    "", "", None, 0),
                            ( "QToolButton", 1,  "DOUBLE",    "", "", None, 1),
                            ( "QToolButton", 2,  "TRIPLE",    "", "", None, 2),
                            ( "QToolButton", 3,  "AROMATIC",  "", "", None, 3),
                            ( "QToolButton", 4,  "GRAPHITIC", "", "", None, 4),
                            ( "QToolButton", 5,  "CUTBONDS",  "", "", None, 5)
                          ]


        self.bondToolButtonRow = \
            PM_ToolButtonRow(
                inPmGroupBox,
                title        = "",
                buttonList   = BOND_TOOL_BUTTONS,
                checkedId    = None,
                setAsDefault = True )

    def _addWhatsThisText(self):
        """
        "What's This" text for widgets in this Property Manager.
        """
        from ne1_ui.WhatsThisText_for_PropertyManagers import whatsThis_BuildAtomsPropertyManager
        whatsThis_BuildAtomsPropertyManager(self)

    def _addToolTipText(self):
        """
        Tool Tip text for widgets in this Property Manager.
        """
        from ne1_ui.ToolTipText_for_PropertyManagers import ToolTip_BuildAtomsPropertyManager
        ToolTip_BuildAtomsPropertyManager(self)

    def toggle_selectedAtomPosGroupBox(self, show = 0):
        """
        Show or hide L{self.selectedAtomPosGroupBox} depending on the state of
        the checkbox (L{self.showSelectedAtomInfoCheckBox})
        @param show: Flag that shows or hides the groupbox (can have values
                     0 or 1
        @type  show: int
        """
        if show:
            self.selectedAtomPosGroupBox.show()
        else:
            self.selectedAtomPosGroupBox.hide()

    def enable_or_disable_selectedAtomPosGroupBox(self, bool_enable = False):
        """
        Enable or disable Selected AtomPosGroupBox present within
        'selection options' and also the checkbox that shows or hide this
        groupbox. These two widgets are enabled when only a single atom is
        selected from the 3D workspace.
        @param bool_enable: Flag that enables or disables widgets
        @type  bool_enable: boolean
        """
        if self.showSelectedAtomInfoCheckBox:
            self.showSelectedAtomInfoCheckBox.setEnabled(bool_enable)
        if self.selectedAtomPosGroupBox:
            self.selectedAtomPosGroupBox.setEnabled(bool_enable)

    def _updateAtomChooserGroupBoxes(self, currentIndex):
        """
        Updates the Atom Chooser Groupbox. It displays one of the
        following three groupboxes depending on the choice selected in the
        combobox:
          a) Periodic Table Elements L{self.regularElementChooser}
          b) PAM5 Atoms  L{self.PAM5Chooser}
          c) PAM3 Atoms  L{self.PAM3Chooser}
        It also sets self.elementChooser to the current active Atom chooser
        and updates the display accordingly in the Preview groupbox.
        """
        self._hideAllAtomChooserGroupBoxes()

        if currentIndex is 0:
            self.elementChooser = self.regularElementChooser
            self.regularElementChooser.show()
        if currentIndex is 1:
            self.elementChooser = self.PAM5Chooser
            self.PAM5Chooser.show()
        if currentIndex is 2:
            self.elementChooser = self.PAM3Chooser
            self.PAM3Chooser.show()

        if self.elementChooser:
            self.elementChooser.updateElementViewer()

        self.updateMessage()


    def updateMessage(self):
        """
        Update the Message groupbox with informative message.
        Subclasses should override this.
        """
        pass
示例#6
0
class InsertDna_PropertyManager(DnaOrCnt_PropertyManager):
    """
    The InsertDna_PropertyManager class provides a Property Manager
    for the B{Insert Dna} command.

    @ivar title: The title that appears in the property manager header.
    @type title: str

    @ivar pmName: The name of this property manager. This is used to set
                  the name of the PM_Dialog object via setObjectName().
    @type name: str

    @ivar iconPath: The relative path to the PNG file that contains a
                    22 x 22 icon image that appears in the PM header.
    @type iconPath: str
    """

    title = "Insert DNA"
    pmName = title
    iconPath = "ui/actions/Command Toolbar/BuildDna/InsertDna.png"

    def __init__(self, command):
        """
        Constructor for the DNA Duplex property manager.
        """
        self.endPoint1 = None
        self.endPoint2 = None

        self._conformation = "B-DNA"
        self._numberOfBases = 0
        self._basesPerTurn = getDuplexBasesPerTurn(self._conformation)
        self._duplexRise = getDuplexRise(self._conformation)
        self._duplexLength = getDuplexLength(self._conformation,
                                             self._numberOfBases)

        _superclass.__init__(self, command)

        self.showTopRowButtons( PM_DONE_BUTTON | \
                                PM_CANCEL_BUTTON | \
                                PM_WHATS_THIS_BUTTON)

    def connect_or_disconnect_signals(self, isConnect):
        """
        Connect or disconnect widget signals sent to their slot methods.
        This can be overridden in subclasses. By default it does nothing.
        @param isConnect: If True the widget will send the signals to the slot
                          method.
        @type  isConnect: boolean
        """
        if isConnect:
            change_connect = self.win.connect
        else:
            change_connect = self.win.disconnect

        change_connect(self._placementOptions.buttonGroup,
                       SIGNAL("buttonClicked(int)"),
                       self.activateSpecifyReferencePlaneTool)

        change_connect(self.conformationComboBox,
                       SIGNAL("currentIndexChanged(int)"),
                       self.conformationComboBoxChanged)

        change_connect(self.numberOfBasePairsSpinBox,
                       SIGNAL("valueChanged(int)"), self.numberOfBasesChanged)

        change_connect(self.basesPerTurnDoubleSpinBox,
                       SIGNAL("valueChanged(double)"),
                       self.basesPerTurnChanged)

        change_connect(self.duplexRiseDoubleSpinBox,
                       SIGNAL("valueChanged(double)"), self.duplexRiseChanged)

        change_connect(self.showCursorTextCheckBox,
                       SIGNAL('stateChanged(int)'),
                       self._update_state_of_cursorTextGroupBox)

        self.duplexRiseDoubleSpinBox.connectWithState(
            Preferences_StateRef_double(bdnaRise_prefs_key,
                                        env.prefs[bdnaRise_prefs_key]))

        self.basesPerTurnDoubleSpinBox.connectWithState(
            Preferences_StateRef_double(bdnaBasesPerTurn_prefs_key,
                                        env.prefs[bdnaBasesPerTurn_prefs_key]))

    def show(self):
        _superclass.show(self)
        self.updateMessage("Specify the DNA parameters below, then click "\
                           "two endpoints in the graphics area to insert a DNA duplex.")

    def _addGroupBoxes(self):
        """
        Add the DNA Property Manager group boxes.
        """
        self._pmReferencePlaneGroupBox = PM_GroupBox(self,
                                                     title="Placement Options")
        self._loadReferencePlaneGroupBox(self._pmReferencePlaneGroupBox)

        self._pmGroupBox1 = PM_GroupBox(self, title="Endpoints")
        self._loadGroupBox1(self._pmGroupBox1)

        self._pmGroupBox1.hide()

        self._pmGroupBox2 = PM_GroupBox(self, title="Parameters")
        self._loadGroupBox2(self._pmGroupBox2)

        self._displayOptionsGroupBox = PM_GroupBox(self,
                                                   title="Display Options")
        self._loadDisplayOptionsGroupBox(self._displayOptionsGroupBox)

    def _loadGroupBox1(self, pmGroupBox):
        """
        Load widgets in group box 3.
        """
        #Folllowing toolbutton facilitates entering a temporary DnaLineMode
        #to create a DNA using endpoints of the specified line.
        self.specifyDnaLineButton = PM_ToolButton(
            pmGroupBox,
            text="Specify Endpoints",
            iconPath="ui/actions/Properties Manager/Pencil.png",
            spanWidth=True)
        self.specifyDnaLineButton.setCheckable(True)
        self.specifyDnaLineButton.setAutoRaise(True)
        self.specifyDnaLineButton.setToolButtonStyle(
            Qt.ToolButtonTextBesideIcon)

        #EndPoint1 and endPoint2 coordinates. These widgets are hidden
        # as of 2007- 12 - 05
        self._endPoint1SpinBoxes = PM_CoordinateSpinBoxes(pmGroupBox,
                                                          label="End Point 1")
        self.x1SpinBox = self._endPoint1SpinBoxes.xSpinBox
        self.y1SpinBox = self._endPoint1SpinBoxes.ySpinBox
        self.z1SpinBox = self._endPoint1SpinBoxes.zSpinBox

        self._endPoint2SpinBoxes = PM_CoordinateSpinBoxes(pmGroupBox,
                                                          label="End Point 2")
        self.x2SpinBox = self._endPoint2SpinBoxes.xSpinBox
        self.y2SpinBox = self._endPoint2SpinBoxes.ySpinBox
        self.z2SpinBox = self._endPoint2SpinBoxes.zSpinBox

        self._endPoint1SpinBoxes.hide()
        self._endPoint2SpinBoxes.hide()

    def _loadGroupBox2(self, pmGroupBox):
        """
        Load widgets in group box 4.
        """

        self.conformationComboBox  = \
            PM_ComboBox( pmGroupBox,
                         label         =  "Conformation:",
                         choices       =  ["B-DNA"],
                         setAsDefault  =  True)

        dnaModelChoices = ['PAM3', 'PAM5']
        self.dnaModelComboBox = \
            PM_ComboBox( pmGroupBox,
                         label         =  "Model:",
                         choices       =  dnaModelChoices,
                         setAsDefault  =  True)


        self.basesPerTurnDoubleSpinBox  =  \
            PM_DoubleSpinBox( pmGroupBox,
                              label         =  "Bases per turn:",
                              value         =  env.prefs[bdnaBasesPerTurn_prefs_key],
                              setAsDefault  =  True,
                              minimum       =  8.0,
                              maximum       =  20.0,
                              decimals      =  2,
                              singleStep    =  0.1 )


        self.duplexRiseDoubleSpinBox  =  \
            PM_DoubleSpinBox( pmGroupBox,
                              label         =  "Rise:",
                              value         =  env.prefs[bdnaRise_prefs_key],
                              setAsDefault  =  True,
                              minimum       =  2.0,
                              maximum       =  4.0,
                              decimals      =  3,
                              singleStep    =  0.01 )

        # Strand Length (i.e. the number of bases)
        self.numberOfBasePairsSpinBox = \
            PM_SpinBox( pmGroupBox,
                        label         =  "Base pairs:",
                        value         =  self._numberOfBases,
                        setAsDefault  =  False,
                        minimum       =  0,
                        maximum       =  10000 )

        self.numberOfBasePairsSpinBox.setDisabled(True)

        # Duplex Length
        self.duplexLengthLineEdit  =  \
            PM_LineEdit( pmGroupBox,
                         label         =  "Duplex length: ",
                         text          =  "0.0 Angstroms",
                         setAsDefault  =  False)

        self.duplexLengthLineEdit.setDisabled(True)

    def _loadDisplayOptionsGroupBox(self, pmGroupBox):
        """
        Load widgets in the Display Options GroupBox
        @see: DnaOrCnt_PropertyManager. _loadDisplayOptionsGroupBox
        """
        #Call the superclass method that loads the cursor text checkboxes.
        #Note, as of 2008-05-19, the superclass, DnaOrCnt_PropertyManager
        #only loads the cursor text groupboxes. Subclasses like this can
        #call custom methods like self._loadCursorTextCheckBoxes etc if they
        #don't need all groupboxes that the superclass loads.
        _superclass._loadDisplayOptionsGroupBox(self, pmGroupBox)

        self._rubberbandLineGroupBox = PM_GroupBox(pmGroupBox,
                                                   title='Rubber band line:')

        dnaLineChoices = ['Ribbons', 'Ladder']
        self.dnaRubberBandLineDisplayComboBox = \
            PM_ComboBox( self._rubberbandLineGroupBox ,
                         label         =  " Display as:",
                         choices       =  dnaLineChoices,
                         setAsDefault  =  True)

        self.lineSnapCheckBox = \
            PM_CheckBox(self._rubberbandLineGroupBox ,
                        text         = 'Enable line snap' ,
                        widgetColumn = 1,
                        state        = Qt.Checked
                    )

    def _connect_showCursorTextCheckBox(self):
        """
        Connect the show cursor text checkbox with user prefs_key.
        Overrides
        DnaOrCnt_PropertyManager._connect_showCursorTextCheckBox
        """
        connect_checkbox_with_boolean_pref(
            self.showCursorTextCheckBox,
            dnaDuplexEditCommand_showCursorTextCheckBox_prefs_key)

    def _params_for_creating_cursorTextCheckBoxes(self):
        """
        Returns params needed to create various cursor text checkboxes connected
        to prefs_keys  that allow custom cursor texts.
        @return: A list containing tuples in the following format:
                ('checkBoxTextString' , preference_key). PM_PrefsCheckBoxes
                uses this data to create checkboxes with the the given names and
                connects them to the provided preference keys. (Note that
                PM_PrefsCheckBoxes puts thes within a GroupBox)
        @rtype: list
        @see: PM_PrefsCheckBoxes
        @see: self._loadDisplayOptionsGroupBox where this list is used.
        @see: Superclass method which is overridden here --
        DnaOrCnt_PropertyManager._params_for_creating_cursorTextCheckBoxes()
        """
        params = \
        [  #Format: (" checkbox text", prefs_key)
            ("Number of base pairs",
             dnaDuplexEditCommand_cursorTextCheckBox_numberOfBasePairs_prefs_key),

            ("Number of turns",
             dnaDuplexEditCommand_cursorTextCheckBox_numberOfTurns_prefs_key),

            ("Duplex length",
             dnaDuplexEditCommand_cursorTextCheckBox_length_prefs_key),

            ("Angle",
             dnaDuplexEditCommand_cursorTextCheckBox_angle_prefs_key) ]

        return params

    def _addToolTipText(self):
        """
        Tool Tip text for widgets in the DNA Property Manager.
        """
        pass

    def conformationComboBoxChanged(self, inIndex):
        """
        Slot for the Conformation combobox. It is called whenever the
        Conformation choice is changed.

        @param inIndex: The new index.
        @type  inIndex: int
        """
        conformation = self.conformationComboBox.currentText()

        if conformation == "B-DNA":
            self.basesPerTurnDoubleSpinBox.setValue("10.0")

        elif conformation == "Z-DNA":
            self.basesPerTurnDoubleSpinBox.setValue("12.0")

        else:
            msg = redmsg("conformationComboBoxChanged(): \
                         Error - unknown DNA conformation. Index = " + inIndex)
            env.history.message(msg)

        self.duplexLengthSpinBox.setSingleStep(getDuplexRise(conformation))

    def numberOfBasesChanged(self, numberOfBases):
        """
        Slot for the B{Number of Bases} spinbox.
        """
        # Update the Duplex Length lineEdit widget.
        text = str(getDuplexLength(self._conformation,
                                   numberOfBases,
                                   self._duplexRise)) \
             + " Angstroms"
        self.duplexLengthLineEdit.setText(text)
        return

    def basesPerTurnChanged(self, basesPerTurn):
        """
        Slot for the B{Bases per turn} spinbox.
        """
        self.command.basesPerTurn = basesPerTurn
        self._basesPerTurn = basesPerTurn
        return

    def duplexRiseChanged(self, rise):
        """
        Slot for the B{Rise} spinbox.
        """
        self.command.duplexRise = rise
        self._duplexRise = rise
        return

    def getParameters(self):
        """
        Return the parameters from this property manager
        to be used to create the DNA duplex.
        @return: A tuple containing the parameters
        @rtype: tuple
        @see: L{InsertDna_EditCommand._gatherParameters} where this is used
        """
        numberOfBases = self.numberOfBasePairsSpinBox.value()
        dnaForm = str(self.conformationComboBox.currentText())
        basesPerTurn = self.basesPerTurnDoubleSpinBox.value()
        duplexRise = self.duplexRiseDoubleSpinBox.value()

        dnaModel = str(self.dnaModelComboBox.currentText())

        # First endpoint (origin) of DNA duplex
        x1 = self.x1SpinBox.value()
        y1 = self.y1SpinBox.value()
        z1 = self.z1SpinBox.value()

        # Second endpoint (direction vector/axis) of DNA duplex.
        x2 = self.x2SpinBox.value()
        y2 = self.y2SpinBox.value()
        z2 = self.z2SpinBox.value()

        if not self.endPoint1:
            self.endPoint1 = V(x1, y1, z1)
        if not self.endPoint2:
            self.endPoint2 = V(x2, y2, z2)

        return (numberOfBases, dnaForm, dnaModel, basesPerTurn, duplexRise,
                self.endPoint1, self.endPoint2)

    def _addWhatsThisText(self):
        """
        What's This text for widgets in this Property Manager.
        """
        whatsThis_InsertDna_PropertyManager(self)
class InsertNanotube_PropertyManager( DnaOrCnt_PropertyManager):
    """
    The InsertNanotube_PropertyManager class provides a Property Manager
    for the B{Build > Nanotube > CNT} command.

    @ivar title: The title that appears in the property manager header.
    @type title: str

    @ivar pmName: The name of this property manager. This is used to set
                  the name of the PM_Dialog object via setObjectName().
    @type name: str

    @ivar iconPath: The relative path to the PNG file that contains a
                    22 x 22 icon image that appears in the PM header.
    @type iconPath: str
    """

    title         =  "Insert Nanotube"
    pmName        =  title
    iconPath      =  "ui/actions/Tools/Build Structures/InsertNanotube.png"

    def __init__( self, win, editCommand ):
        """
        Constructor for the Nanotube property manager.
        """
        self.endPoint1 = None
        self.endPoint2 = None

        self.nanotube = Nanotube() # A 5x5 CNT.

        _superclass.__init__( self,
                                 win,
                                 editCommand)

        self.showTopRowButtons( PM_DONE_BUTTON | \
                                PM_CANCEL_BUTTON | \
                                PM_WHATS_THIS_BUTTON)

    def connect_or_disconnect_signals(self, isConnect):
        """
        Connect or disconnect widget signals sent to their slot methods.
        This can be overridden in subclasses. By default it does nothing.
        @param isConnect: If True the widget will send the signals to the slot
                          method.
        @type  isConnect: boolean
        """
        if isConnect:
            change_connect = self.win.connect
        else:
            change_connect = self.win.disconnect

        change_connect( self.ntTypeComboBox,
                      SIGNAL("currentIndexChanged(const QString&)"),
                      self._ntTypeComboBoxChanged )

        change_connect(self.chiralityNSpinBox,
                       SIGNAL("valueChanged(int)"),
                       self._chiralityFixup)

        change_connect(self.chiralityMSpinBox,
                       SIGNAL("valueChanged(int)"),
                       self._chiralityFixup)

        change_connect(self.endingsComboBox,
                       SIGNAL("currentIndexChanged(const QString&)"),
                       self._endingsComboBoxChanged )

        # This spin box is currently hidden.
        change_connect(self.bondLengthDoubleSpinBox,
                       SIGNAL("valueChanged(double)"),
                       self._bondLengthChanged)

        change_connect(self.showCursorTextCheckBox,
                       SIGNAL('stateChanged(int)'),
                       self._update_state_of_cursorTextGroupBox)

    def ok_btn_clicked(self):
        """
        Slot for the OK button
        """
        if self.editCommand:
            self.editCommand.preview_or_finalize_structure(previewing = False)
            ##env.history.message(self.editCommand.logMessage)
        self.win.toolsDone()

    def cancel_btn_clicked(self):
        """
        Slot for the Cancel button.
        """
        if self.editCommand:
            self.editCommand.cancelStructure()
        self.win.toolsCancel()


    def _update_widgets_in_PM_before_show(self):
        """
        Update various widgets in this Property manager.
        Overrides MotorPropertyManager._update_widgets_in_PM_before_show.
        The various  widgets , (e.g. spinboxes) will get values from the
        structure for which this propMgr is constructed for
        (self.editcCntroller.struct)

        @see: MotorPropertyManager._update_widgets_in_PM_before_show
        @see: self.show where it is called.
        """
        pass

    def getFlyoutActionList(self):
        """
        Returns custom actionlist that will be used in a specific mode
        or editing a feature etc Example: while in movie mode,
        the _createFlyoutToolBar method calls this.
        """
        #'allActionsList' returns all actions in the flyout toolbar
        #including the subcontrolArea actions
        allActionsList = []

        #Action List for  subcontrol Area buttons.
        #In this mode there is really no subcontrol area.
        #We will treat subcontrol area same as 'command area'
        #(subcontrol area buttons will have an empty list as their command area
        #list). We will set  the Comamnd Area palette background color to the
        #subcontrol area.

        subControlAreaActionList =[]

        self.exitEditCommandAction.setChecked(True)
        subControlAreaActionList.append(self.exitEditCommandAction)

        separator = QAction(self.w)
        separator.setSeparator(True)
        subControlAreaActionList.append(separator)


        allActionsList.extend(subControlAreaActionList)

        #Empty actionlist for the 'Command Area'
        commandActionLists = []

        #Append empty 'lists' in 'commandActionLists equal to the
        #number of actions in subControlArea
        for i in range(len(subControlAreaActionList)):
            lst = []
            commandActionLists.append(lst)

        params = (subControlAreaActionList, commandActionLists, allActionsList)

        return params

    def _addGroupBoxes( self ):
        """
        Add the Insert Nanotube Property Manager group boxes.
        """

        self._pmGroupBox1 = PM_GroupBox( self, title = "Endpoints" )
        self._loadGroupBox1( self._pmGroupBox1 )
        self._pmGroupBox1.hide()

        self._pmGroupBox2 = PM_GroupBox( self, title = "Parameters" )
        self._loadGroupBox2( self._pmGroupBox2 )

        self._displayOptionsGroupBox = PM_GroupBox( self,
                                                    title = "Display Options" )
        self._loadDisplayOptionsGroupBox( self._displayOptionsGroupBox )

        self._pmGroupBox3 = PM_GroupBox( self, title = "Nanotube Distortion" )
        self._loadGroupBox3( self._pmGroupBox3 )
        self._pmGroupBox3.hide() #@ Temporary.

        self._pmGroupBox4 = PM_GroupBox( self, title = "Multi-Walled CNTs" )
        self._loadGroupBox4( self._pmGroupBox4 )
        self._pmGroupBox4.hide() #@ Temporary.

        self._pmGroupBox5 = PM_GroupBox( self, title = "Advanced Options" )
        self._loadGroupBox5( self._pmGroupBox5 )
        self._pmGroupBox5.hide() #@ Temporary.

    def _loadGroupBox1(self, pmGroupBox):
        """
        Load widgets in group box 1.
        """
        #Following toolbutton facilitates entering a temporary NanotubeLineMode
        #to create a CNT using endpoints of the specified line.
        self.specifyCntLineButton = PM_ToolButton(
            pmGroupBox,
            text = "Specify Endpoints",
            iconPath  = "ui/actions/Properties Manager/Pencil.png",
            spanWidth = True
        )
        self.specifyCntLineButton.setCheckable(True)
        self.specifyCntLineButton.setAutoRaise(True)
        self.specifyCntLineButton.setToolButtonStyle(
            Qt.ToolButtonTextBesideIcon)

        #EndPoint1 and endPoint2 coordinates. These widgets are hidden
        # as of 2007- 12 - 05
        self._endPoint1SpinBoxes = PM_CoordinateSpinBoxes(pmGroupBox,
                                                label = "End Point 1")
        self.x1SpinBox = self._endPoint1SpinBoxes.xSpinBox
        self.y1SpinBox = self._endPoint1SpinBoxes.ySpinBox
        self.z1SpinBox = self._endPoint1SpinBoxes.zSpinBox

        self._endPoint2SpinBoxes = PM_CoordinateSpinBoxes(pmGroupBox,
                                                label = "End Point 2")
        self.x2SpinBox = self._endPoint2SpinBoxes.xSpinBox
        self.y2SpinBox = self._endPoint2SpinBoxes.ySpinBox
        self.z2SpinBox = self._endPoint2SpinBoxes.zSpinBox

        self._endPoint1SpinBoxes.hide()
        self._endPoint2SpinBoxes.hide()

    def _loadGroupBox2(self, pmGroupBox):
        """
        Load widgets in group box 2.
        """

        _ntTypeChoices = ['Carbon',
                          'Boron Nitride']
        self.ntTypeComboBox  = \
            PM_ComboBox( pmGroupBox,
                         label         =  "Type:",
                         choices       =  _ntTypeChoices,
                         setAsDefault  =  True)

        self.ntRiseDoubleSpinBox  =  \
            PM_DoubleSpinBox( pmGroupBox,
                              label         =  "Rise:",
                              value         =  self.nanotube.getRise(),
                              setAsDefault  =  True,
                              minimum       =  2.0,
                              maximum       =  4.0,
                              decimals      =  3,
                              singleStep    =  0.01 )

        self.ntRiseDoubleSpinBox.hide()

        # Nanotube Length
        self.ntLengthLineEdit  =  \
            PM_LineEdit( pmGroupBox,
                         label         =  "Nanotube Length: ",
                         text          =  "0.0 Angstroms",
                         setAsDefault  =  False)

        self.ntLengthLineEdit.setDisabled(True)
        self.ntLengthLineEdit.hide()

        # Nanotube diameter
        self.ntDiameterLineEdit  =  \
            PM_LineEdit( pmGroupBox,
                         label         =  "Diameter: ",
                         setAsDefault  =  False)

        self.ntDiameterLineEdit.setDisabled(True)
        self.updateNanotubeDiameter()

        self.chiralityNSpinBox = \
            PM_SpinBox( pmGroupBox,
                        label        = "Chirality (n):",
                        value        = self.nanotube.getChiralityN(),
                        minimum      =  2,
                        maximum      =  100,
                        setAsDefault = True )

        self.chiralityMSpinBox = \
            PM_SpinBox( pmGroupBox,
                        label        = "Chirality (m):",
                        value        = self.nanotube.getChiralityM(),
                        minimum      =  0,
                        maximum      =  100,
                        setAsDefault = True )

        # How about having user prefs for CNT and BNNT bond lengths?
        # I'm guessing that if the user wants to set these values, they will
        # do it once and would like those bond length values persist forever.
        # Need to discuss with others to determine if this spinbox comes out.
        # --Mark 2008-03-29
        self.bondLengthDoubleSpinBox = \
            PM_DoubleSpinBox( pmGroupBox,
                              label        = "Bond length:",
                              value        = self.nanotube.getBondLength(),
                              setAsDefault = True,
                              minimum      = 1.0,
                              maximum      = 3.0,
                              singleStep   = 0.1,
                              decimals     = 3,
                              suffix       = " Angstroms" )

        #self.bondLengthDoubleSpinBox.hide()

        endingChoices = ["Hydrogen", "None"] # Removed:, "Nitrogen"]

        self.endingsComboBox= \
            PM_ComboBox( pmGroupBox,
                         label        = "Endings:",
                         choices      = endingChoices,
                         index        = 0,
                         setAsDefault = True,
                         spanWidth    = False )

    def _loadGroupBox3(self, inPmGroupBox):
        """
        Load widgets in group box 3.
        """

        self.zDistortionDoubleSpinBox = \
            PM_DoubleSpinBox( inPmGroupBox,
                              label        = "Z-distortion:",
                              value        = 0.0,
                              setAsDefault = True,
                              minimum      = 0.0,
                              maximum      = 10.0,
                              singleStep   = 0.1,
                              decimals     = 3,
                              suffix       = " Angstroms" )

        self.xyDistortionDoubleSpinBox = \
            PM_DoubleSpinBox( inPmGroupBox,
                              label        = "XY-distortion:",
                              value        = 0.0,
                              setAsDefault = True,
                              minimum      = 0.0,
                              maximum      = 2.0,
                              singleStep   = 0.1,
                              decimals     = 3,
                              suffix       = " Angstroms" )

        self.twistSpinBox = \
            PM_SpinBox( inPmGroupBox,
                        label        = "Twist:",
                        value        = 0,
                        setAsDefault = True,
                        minimum      = 0,
                        maximum      = 100, # What should maximum be?
                        suffix       = " deg/A" )

        self.bendSpinBox = \
            PM_SpinBox( inPmGroupBox,
                        label        = "Bend:",
                        value        = 0,
                        setAsDefault = True,
                        minimum      = 0,
                        maximum      = 360,
                        suffix       = " deg" )

    def _loadGroupBox4(self, inPmGroupBox):
        """
        Load widgets in group box 4.
        """

        # "Number of Nanotubes" SpinBox
        self.mwntCountSpinBox = \
            PM_SpinBox( inPmGroupBox,
                        label        = "Number:",
                        value        = 1,
                        setAsDefault = True,
                        minimum      = 1,
                        maximum      = 10,
                        suffix       = " nanotubes" )

        self.mwntCountSpinBox.setSpecialValueText("SWNT")

        # "Spacing" lineedit.
        self.mwntSpacingDoubleSpinBox = \
            PM_DoubleSpinBox( inPmGroupBox,
                              label        = "Spacing:",
                              value        = 2.46,
                              setAsDefault = True,
                              minimum      = 1.0,
                              maximum      = 10.0,
                              singleStep   = 0.1,
                              decimals     = 3,
                              suffix       = " Angstroms" )

    def _loadGroupBox5(self, pmGroupBox):
        """
        Load widgets in group box 5.
        """
        self._rubberbandLineGroupBox = PM_GroupBox(
            pmGroupBox,
            title = 'Rubber band Line:')

        ntLineChoices = ['Ladder']
        self.ntRubberBandLineDisplayComboBox = \
            PM_ComboBox( self._rubberbandLineGroupBox ,
                         label         =  " Display as:",
                         choices       =  ntLineChoices,
                         setAsDefault  =  True)

        self.lineSnapCheckBox = \
            PM_CheckBox(self._rubberbandLineGroupBox ,
                        text         = 'Enable line snap' ,
                        widgetColumn = 1,
                        state        = Qt.Checked
                        )


    def _connect_showCursorTextCheckBox(self):
        """
        Connect the show cursor text checkbox with user prefs_key.
        Overrides
        DnaOrCnt_PropertyManager._connect_showCursorTextCheckBox
        """
        connect_checkbox_with_boolean_pref(
            self.showCursorTextCheckBox ,
            insertNanotubeEditCommand_showCursorTextCheckBox_prefs_key )


    def _params_for_creating_cursorTextCheckBoxes(self):
        """
        Returns params needed to create various cursor text checkboxes connected
        to prefs_keys  that allow custom cursor texts.
        @return: A list containing tuples in the following format:
                ('checkBoxTextString' , preference_key). PM_PrefsCheckBoxes
                uses this data to create checkboxes with the the given names and
                connects them to the provided preference keys. (Note that
                PM_PrefsCheckBoxes puts thes within a GroupBox)
        @rtype: list
        @see: PM_PrefsCheckBoxes
        @see: self._loadDisplayOptionsGroupBox where this list is used.
        @see: Superclass method which is overridden here --
        DnaOrCnt_PropertyManager._params_for_creating_cursorTextCheckBoxes()
        """
        params = \
               [  #Format: (" checkbox text", prefs_key)

                   ("Nanotube length",
                    insertNanotubeEditCommand_cursorTextCheckBox_length_prefs_key ),

                    ("Angle",
                     insertNanotubeEditCommand_cursorTextCheckBox_angle_prefs_key )
                 ]

        return params


    def _addToolTipText(self):
        """
        Tool Tip text for widgets in the Insert Nanotube Property Manager.
        """
        pass

    def _setEndPoints(self):
        """
        Set the two endpoints of the nanotube using the values from the
        X, Y, Z coordinate spinboxes in the property manager.

        @note: The group box containing the 2 sets of XYZ spin boxes are
        currently hidden.
        """
        # First endpoint (origin) of nanotube
        x1 = self.x1SpinBox.value()
        y1 = self.y1SpinBox.value()
        z1 = self.z1SpinBox.value()

        # Second endpoint (direction vector/axis) of nanotube.
        x2 = self.x2SpinBox.value()
        y2 = self.y2SpinBox.value()
        z2 = self.z2SpinBox.value()

        if not self.endPoint1:
            self.endPoint1 = V(x1, y1, z1)
        if not self.endPoint2:
            self.endPoint2 = V(x2, y2, z2)

        self.nanotube.setEndPoints(self.endPoint1, self.endPoint2)
            # Need arg "recompute=True", which will recompute the second
            # endpoint (endPoint2) using the nanotube rise.

    def getParameters(self):
        """
        Return the parameters from this property manager to be used to create
        the nanotube.

        @return: A nanotube instance with its attrs set to the current
                 parameters in the property manager.
        @rtype: L{Nanotube}

        @see: L{InsertNanotube_EditCommand._gatherParameters} where this is used
        """
        self._setEndPoints()
        return (self.nanotube)

    def _ntTypeComboBoxChanged( self, type ):
        """
        Slot for the Type combobox. It is called whenever the
        Type choice is changed.

        @param inIndex: The new index.
        @type  inIndex: int
        """
        self.nanotube.setType(str(type))
        print "Bond Length =", self.nanotube.getBondLength()
        self.bondLengthDoubleSpinBox.setValue(self.nanotube.getBondLength())
        #self.bondLengthDoubleSpinBox.setValue(ntBondLengths[inIndex])

    def _bondLengthChanged(self, bondLength):
        """
        Slot for the B{Bond Length} spinbox.
        """
        self.nanotube.setBondLength(bondLength)
        self.updateNanotubeDiameter()
        return

    def _chiralityFixup(self, spinBoxValueJunk = None):
        """
        Slot for several validators for different parameters.
        This gets called whenever the user changes the n, m chirality values.

        @param spinBoxValueJunk: This is the Spinbox value from the valueChanged
                                 signal. It is not used. We just want to know
                                 that the spinbox value has changed.
        @type  spinBoxValueJunk: double or None
        """
        _n, _m = self.nanotube.setChirality(self.chiralityNSpinBox.value(),
                                            self.chiralityMSpinBox.value())

        #self.n, self.m = self.nanotube.getChirality()

        self.connect_or_disconnect_signals(isConnect = False)
        self.chiralityNSpinBox.setValue(_n)
        self.chiralityMSpinBox.setValue(_m)
        self.connect_or_disconnect_signals(isConnect = True)

        self.updateNanotubeDiameter()

    def updateNanotubeDiameter(self):
        """
        Update the nanotube Diameter lineEdit widget.
        """
        diameterText = "%-7.4f Angstroms" %  (self.nanotube.getDiameter())
        self.ntDiameterLineEdit.setText(diameterText)

        # ntRiseDoubleSpinBox is currently hidden.
        self.ntRiseDoubleSpinBox.setValue(self.nanotube.getRise())

    def _endingsComboBoxChanged(self, endings):
        """
        Slot for the B{Ending} combobox.

        @param endings: The option's text.
        @type  endings: string
        """
        self.nanotube.setEndings(str(endings))
        return

    def _addWhatsThisText(self):
        """
        What's This text for widgets in this Property Manager.
        """
        whatsThis_InsertNanotube_PropertyManager(self)
        return
class DnaDuplexPropertyManager( DnaOrCnt_PropertyManager ):
    """
    The DnaDuplexPropertyManager class provides a Property Manager
    for the B{Build > DNA > Duplex} command.

    @ivar title: The title that appears in the property manager header.
    @type title: str

    @ivar pmName: The name of this property manager. This is used to set
                  the name of the PM_Dialog object via setObjectName().
    @type name: str

    @ivar iconPath: The relative path to the PNG file that contains a
                    22 x 22 icon image that appears in the PM header.
    @type iconPath: str
    """

    title         =  "Insert DNA"
    pmName        =  title
    iconPath      =  "ui/actions/Tools/Build Structures/InsertDsDna.png"

    def __init__( self, win, editCommand ):
        """
        Constructor for the DNA Duplex property manager.
        """
        self.endPoint1 = None
        self.endPoint2 = None

        self._conformation  = "B-DNA"
        self._numberOfBases = 0
        self._basesPerTurn  = getDuplexBasesPerTurn(self._conformation)
        self._duplexRise    = getDuplexRise(self._conformation)
        self._duplexLength  = getDuplexLength(self._conformation,
                                              self._numberOfBases)


        _superclass.__init__( self,
                              win,
                              editCommand)

        self.showTopRowButtons( PM_DONE_BUTTON | \
                                PM_CANCEL_BUTTON | \
                                PM_WHATS_THIS_BUTTON)


    def connect_or_disconnect_signals(self, isConnect):
        """
        Connect or disconnect widget signals sent to their slot methods.
        This can be overridden in subclasses. By default it does nothing.
        @param isConnect: If True the widget will send the signals to the slot
                          method.
        @type  isConnect: boolean
        """
        if isConnect:
            change_connect = self.win.connect
        else:
            change_connect = self.win.disconnect


        change_connect(self._placementOptions.buttonGroup,
                       SIGNAL("buttonClicked(int)"),
                       self.activateSpecifyReferencePlaneTool)

        change_connect( self.conformationComboBox,
                        SIGNAL("currentIndexChanged(int)"),
                        self.conformationComboBoxChanged )

        change_connect( self.numberOfBasePairsSpinBox,
                        SIGNAL("valueChanged(int)"),
                        self.numberOfBasesChanged )

        change_connect( self.basesPerTurnDoubleSpinBox,
                        SIGNAL("valueChanged(double)"),
                        self.basesPerTurnChanged )

        change_connect( self.duplexRiseDoubleSpinBox,
                        SIGNAL("valueChanged(double)"),
                        self.duplexRiseChanged )

        change_connect(self.showCursorTextCheckBox,
                       SIGNAL('stateChanged(int)'),
                       self._update_state_of_cursorTextGroupBox)
        
        self.duplexRiseDoubleSpinBox.connectWithState(
            Preferences_StateRef_double( bdnaRise_prefs_key, 
                                         env.prefs[bdnaRise_prefs_key] )
            )
        
        self.basesPerTurnDoubleSpinBox.connectWithState(
            Preferences_StateRef_double( bdnaBasesPerTurn_prefs_key, 
                                         env.prefs[bdnaBasesPerTurn_prefs_key] )
            )

        
                
 
    def ok_btn_clicked(self):
        """
        Slot for the OK button
        """
        if self.editCommand:
            self.editCommand.preview_or_finalize_structure(previewing = False)
            ##env.history.message(self.editCommand.logMessage)
        self.win.toolsDone()

    def cancel_btn_clicked(self):
        """
        Slot for the Cancel button.
        """
        if self.editCommand:
            self.editCommand.cancelStructure()
        self.win.toolsCancel()


    def _update_widgets_in_PM_before_show(self):
        """
        Update various widgets  in this Property manager.
        Overrides superclass method

        @see: MotorPropertyManager._update_widgets_in_PM_before_show
        @see: self.show where it is called.
        """
        pass

    def getFlyoutActionList(self):
        """ returns custom actionlist that will be used in a specific mode
        or editing a feature etc Example: while in movie mode,
        the _createFlyoutToolBar method calls
        this """


        #'allActionsList' returns all actions in the flyout toolbar
        #including the subcontrolArea actions
        allActionsList = []

        #Action List for  subcontrol Area buttons.
        #In this mode there is really no subcontrol area.
        #We will treat subcontrol area same as 'command area'
        #(subcontrol area buttons will have an empty list as their command area
        #list). We will set  the Comamnd Area palette background color to the
        #subcontrol area.

        subControlAreaActionList =[]

        self.exitEditCommandAction.setChecked(True)
        subControlAreaActionList.append(self.exitEditCommandAction)

        separator = QAction(self.w)
        separator.setSeparator(True)
        subControlAreaActionList.append(separator)


        allActionsList.extend(subControlAreaActionList)

        #Empty actionlist for the 'Command Area'
        commandActionLists = []

        #Append empty 'lists' in 'commandActionLists equal to the
        #number of actions in subControlArea
        for i in range(len(subControlAreaActionList)):
            lst = []
            commandActionLists.append(lst)

        params = (subControlAreaActionList, commandActionLists, allActionsList)

        return params

    def _addGroupBoxes( self ):
        """
        Add the DNA Property Manager group boxes.
        """
        self._pmReferencePlaneGroupBox = PM_GroupBox( self,
                                                      title = "Placement Options" )
        self._loadReferencePlaneGroupBox( self._pmReferencePlaneGroupBox )

        self._pmGroupBox1 = PM_GroupBox( self, title = "Endpoints" )
        self._loadGroupBox1( self._pmGroupBox1 )

        self._pmGroupBox1.hide()

        self._pmGroupBox2 = PM_GroupBox( self, title = "Parameters" )
        self._loadGroupBox2( self._pmGroupBox2 )

        self._displayOptionsGroupBox = PM_GroupBox( self,
                                                    title = "Display Options" )
        self._loadDisplayOptionsGroupBox( self._displayOptionsGroupBox )


    def _loadGroupBox1(self, pmGroupBox):
        """
        Load widgets in group box 3.
        """
        #Folllowing toolbutton facilitates entering a temporary DnaLineMode
        #to create a DNA using endpoints of the specified line.
        self.specifyDnaLineButton = PM_ToolButton(
            pmGroupBox,
            text = "Specify Endpoints",
            iconPath  = "ui/actions/Properties Manager/Pencil.png",
            spanWidth = True
        )
        self.specifyDnaLineButton.setCheckable(True)
        self.specifyDnaLineButton.setAutoRaise(True)
        self.specifyDnaLineButton.setToolButtonStyle(
            Qt.ToolButtonTextBesideIcon)

        #EndPoint1 and endPoint2 coordinates. These widgets are hidden
        # as of 2007- 12 - 05
        self._endPoint1SpinBoxes = PM_CoordinateSpinBoxes(pmGroupBox,
                                                          label = "End Point 1")
        self.x1SpinBox = self._endPoint1SpinBoxes.xSpinBox
        self.y1SpinBox = self._endPoint1SpinBoxes.ySpinBox
        self.z1SpinBox = self._endPoint1SpinBoxes.zSpinBox

        self._endPoint2SpinBoxes = PM_CoordinateSpinBoxes(pmGroupBox,
                                                          label = "End Point 2")
        self.x2SpinBox = self._endPoint2SpinBoxes.xSpinBox
        self.y2SpinBox = self._endPoint2SpinBoxes.ySpinBox
        self.z2SpinBox = self._endPoint2SpinBoxes.zSpinBox

        self._endPoint1SpinBoxes.hide()
        self._endPoint2SpinBoxes.hide()

    def _loadGroupBox2(self, pmGroupBox):
        """
        Load widgets in group box 4.
        """

        self.conformationComboBox  = \
            PM_ComboBox( pmGroupBox,
                         label         =  "Conformation:",
                         choices       =  ["B-DNA"],
                         setAsDefault  =  True)

        dnaModelChoices = ['PAM3', 'PAM5']
        self.dnaModelComboBox = \
            PM_ComboBox( pmGroupBox,
                         label         =  "Model:",
                         choices       =  dnaModelChoices,
                         setAsDefault  =  True)


        self.basesPerTurnDoubleSpinBox  =  \
            PM_DoubleSpinBox( pmGroupBox,
                              label         =  "Bases per turn:",
                              value         =  env.prefs[bdnaBasesPerTurn_prefs_key],
                              setAsDefault  =  True,
                              minimum       =  8.0,
                              maximum       =  20.0,
                              decimals      =  2,
                              singleStep    =  0.1 )
        
        
        self.duplexRiseDoubleSpinBox  =  \
            PM_DoubleSpinBox( pmGroupBox,
                              label         =  "Rise:",
                              value         =  env.prefs[bdnaRise_prefs_key],
                              setAsDefault  =  True,
                              minimum       =  2.0,
                              maximum       =  4.0,
                              decimals      =  3,
                              singleStep    =  0.01 )
        
        
        

        # Strand Length (i.e. the number of bases)
        self.numberOfBasePairsSpinBox = \
            PM_SpinBox( pmGroupBox,
                        label         =  "Base pairs:",
                        value         =  self._numberOfBases,
                        setAsDefault  =  False,
                        minimum       =  0,
                        maximum       =  10000 )

        self.numberOfBasePairsSpinBox.setDisabled(True)

        # Duplex Length
        self.duplexLengthLineEdit  =  \
            PM_LineEdit( pmGroupBox,
                         label         =  "Duplex length: ",
                         text          =  "0.0 Angstroms",
                         setAsDefault  =  False)

        self.duplexLengthLineEdit.setDisabled(True)


    def _loadDisplayOptionsGroupBox(self, pmGroupBox):
        """
        Load widgets in the Display Options GroupBox
        @see: DnaOrCnt_PropertyManager. _loadDisplayOptionsGroupBox
        """
        #Call the superclass method that loads the cursor text checkboxes.
        #Note, as of 2008-05-19, the superclass, DnaOrCnt_PropertyManager
        #only loads the cursor text groupboxes. Subclasses like this can
        #call custom methods like self._loadCursorTextCheckBoxes etc if they
        #don't need all groupboxes that the superclass loads.
        _superclass._loadDisplayOptionsGroupBox(self, pmGroupBox)

        self._rubberbandLineGroupBox = PM_GroupBox(
            pmGroupBox,
            title = 'Rubber band line:')

        dnaLineChoices = ['Ribbons', 'Ladder']
        self.dnaRubberBandLineDisplayComboBox = \
            PM_ComboBox( self._rubberbandLineGroupBox ,
                         label         =  " Display as:",
                         choices       =  dnaLineChoices,
                         setAsDefault  =  True)

        self.lineSnapCheckBox = \
            PM_CheckBox(self._rubberbandLineGroupBox ,
                        text         = 'Enable line snap' ,
                        widgetColumn = 1,
                        state        = Qt.Checked
                    )

    def _connect_showCursorTextCheckBox(self):
        """
        Connect the show cursor text checkbox with user prefs_key.
        Overrides
        DnaOrCnt_PropertyManager._connect_showCursorTextCheckBox
        """
        connect_checkbox_with_boolean_pref(
            self.showCursorTextCheckBox ,
            dnaDuplexEditCommand_showCursorTextCheckBox_prefs_key)


    def _params_for_creating_cursorTextCheckBoxes(self):
        """
        Returns params needed to create various cursor text checkboxes connected
        to prefs_keys  that allow custom cursor texts.
        @return: A list containing tuples in the following format:
                ('checkBoxTextString' , preference_key). PM_PrefsCheckBoxes
                uses this data to create checkboxes with the the given names and
                connects them to the provided preference keys. (Note that
                PM_PrefsCheckBoxes puts thes within a GroupBox)
        @rtype: list
        @see: PM_PrefsCheckBoxes
        @see: self._loadDisplayOptionsGroupBox where this list is used.
        @see: Superclass method which is overridden here --
        DnaOrCnt_PropertyManager._params_for_creating_cursorTextCheckBoxes()
        """
        params = \
        [  #Format: (" checkbox text", prefs_key)
            ("Number of base pairs",
             dnaDuplexEditCommand_cursorTextCheckBox_numberOfBasePairs_prefs_key),

            ("Number of turns",
             dnaDuplexEditCommand_cursorTextCheckBox_numberOfTurns_prefs_key),

            ("Duplex length",
             dnaDuplexEditCommand_cursorTextCheckBox_length_prefs_key),

            ("Angle",
             dnaDuplexEditCommand_cursorTextCheckBox_angle_prefs_key) ]

        return params


    def _addToolTipText(self):
        """
        Tool Tip text for widgets in the DNA Property Manager.
        """
        pass


    def conformationComboBoxChanged( self, inIndex ):
        """
        Slot for the Conformation combobox. It is called whenever the
        Conformation choice is changed.

        @param inIndex: The new index.
        @type  inIndex: int
        """
        conformation  =  self.conformationComboBox.currentText()

        if conformation == "B-DNA":
            self.basesPerTurnDoubleSpinBox.setValue("10.0")

        elif conformation == "Z-DNA":
            self.basesPerTurnDoubleSpinBox.setValue("12.0")

        else:
            msg = redmsg("conformationComboBoxChanged(): \
                         Error - unknown DNA conformation. Index = "+ inIndex)
            env.history.message(msg)

        self.duplexLengthSpinBox.setSingleStep(getDuplexRise(conformation))

    def numberOfBasesChanged( self, numberOfBases ):
        """
        Slot for the B{Number of Bases} spinbox.
        """
        # Update the Duplex Length lineEdit widget.
        text = str(getDuplexLength(self._conformation,
                                   numberOfBases,
                                   self._duplexRise)) \
             + " Angstroms"
        self.duplexLengthLineEdit.setText(text)
        return

    def basesPerTurnChanged( self, basesPerTurn ):
        """
        Slot for the B{Bases per turn} spinbox.
        """
        self.editCommand.basesPerTurn = basesPerTurn
        self._basesPerTurn = basesPerTurn
        return

    def duplexRiseChanged( self, rise ):
        """
        Slot for the B{Rise} spinbox.
        """
        self.editCommand.duplexRise = rise
        self._duplexRise = rise
        return

    def getParameters(self):
        """
        Return the parameters from this property manager
        to be used to create the DNA duplex.
        @return: A tuple containing the parameters
        @rtype: tuple
        @see: L{DnaDuplex_EditCommand._gatherParameters} where this is used
        """
        numberOfBases = self.numberOfBasePairsSpinBox.value()
        dnaForm  = str(self.conformationComboBox.currentText())
        basesPerTurn = self.basesPerTurnDoubleSpinBox.value()
        duplexRise = self.duplexRiseDoubleSpinBox.value()

        dnaModel = str(self.dnaModelComboBox.currentText())

        # First endpoint (origin) of DNA duplex
        x1 = self.x1SpinBox.value()
        y1 = self.y1SpinBox.value()
        z1 = self.z1SpinBox.value()

        # Second endpoint (direction vector/axis) of DNA duplex.
        x2 = self.x2SpinBox.value()
        y2 = self.y2SpinBox.value()
        z2 = self.z2SpinBox.value()

        if not self.endPoint1:
            self.endPoint1 = V(x1, y1, z1)
        if not self.endPoint2:
            self.endPoint2 = V(x2, y2, z2)

        return (numberOfBases,
                dnaForm,
                dnaModel,
                basesPerTurn,
                duplexRise,
                self.endPoint1,
                self.endPoint2)

    def _addWhatsThisText(self):
        """
        What's This text for widgets in this Property Manager.
        """
        whatsThis_DnaDuplexPropertyManager(self)