示例#1
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)
示例#2
0
class EditNanotube_PropertyManager(DnaOrCnt_PropertyManager):
    """
    The NanotubeSegmenta_PropertyManager class provides a Property Manager
    for the EditNanotube_EditCommand.

    @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 = "Nanotube Properties"
    pmName = title
    iconPath = "ui/actions/Command Toolbar/BuildNanotube/EditNanotube.png"

    def __init__(self, command):
        """
        Constructor for the Cnt Segment Properties property manager.
        """

        #For model changed signal
        self.previousSelectionParams = None

        #see self.connect_or_disconnect_signals for comment about this flag
        self.isAlreadyConnected = False
        self.isAlreadyDisconnected = False

        # Initialized here. Their values will be set in
        # _update_widgets_in_PM_before_show()
        self.endPoint1 = V(0, 0, 0)
        self.endPoint2 = V(0, 0, 0)

        _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.nameLineEdit, SIGNAL("editingFinished()"),
                       self._nameChanged)

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

    def show(self):
        """
        Show this property manager. Overrides EditCommand_PM.show()
        This method also retrives the name information from the
        command's structure for its name line edit field.
        @see: EditNanotube_EditCommand.getStructureName()
        @see: self.close()
        """
        _superclass.show(self)
        #if self.command is not None:
        #name = self.command.getStructureName()
        #if name is not None:
        #self.nameLineEdit.setText(name)

    def close(self):
        """
        Close this property manager.
        Also sets the name of the self.command's structure to the one
        displayed in the line edit field.
        @see self.show()
        @see: EditNanotube_EditCommand.setStructureName
        """
        if self.command is not None:
            name = str(self.nameLineEdit.text())
            self.command.setStructureName(name)
        _superclass.close(self)

    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,
            editNanotubeEditCommand_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",
                   editNanotubeEditCommand_cursorTextCheckBox_length_prefs_key)
                 ]

        return params

    def setParameters(self, params):
        """
        This is called when entering "Nanotube Segment Properties
        (i.e. "Edit properties...") to retrieve and set parameters of the
        nanotube segment that might be modified during this command and
        are needed to regenerate the nanotube segment.

        @param params: The parameters of the nanotube segment.
                       These parameters are retreived via
                       L{NanotubeSegment.getProps()}, called from
                       L{EditNanotube_EditCommand.editStructure()}.

                       Parameters:
                       - n, m (chirality)
                       - type (i.e. carbon or boron nitride)
                       - endings (none, hydrogen, nitrogen)
                       - endpoints (endPoint1, endPoint2)
        @type params: list (n, m), type, endings, (endPoint1, endPoint2)

        @note: Any widgets in the property manager that display these
        parameters should be updated here.

        @see: L{NanotubeSegment.getProps()}

        TODO:
        - Make this a EditCommand_PM API method?
        - See also the routines GraphicsMode.setParams or object.setProps
        ..better to name them all in one style?
        """
        (self.n, self.m), self.type, self.endings,\
            (self.endPoint1, self.endPoint2) = params

        # This is needed to update the endpoints since the Nanotube segment
        # may have been moved (i.e. translated or rotated). In that case,
        # the endpoints are not updated, so we recompute them here.
        nanotubeChunk = self.command.struct.members[0]
        self.endPoint1, self.endPoint2, radius = \
            self.command.struct.nanotube.computeEndPointsFromChunk(nanotubeChunk)

        if 0:
            print "\n--------------"
            print "setParameters():"
            print "Struct=", self.command.struct
            print "N, M:", self.n, self.m
            print "type:", self.type
            print "endings:", self.endings
            print "pt1, pt2:", self.endPoint1, self.endPoint2

    def getParameters(self):
        """
        Get the parameters that the edit command will use to determine if
        any have changed. If any have, then the nanotube will be modified.
        """
        if 0:
            print "\n--------------"
            print "getParameters():"
            print "Struct=", self.command.struct
            print "N, M:", self.n, self.m
            print "type:", self.type
            print "endings:", self.endings
            print "pt1, pt2:", self.endPoint1, self.endPoint2

        return (self.n, self.m, self.type, self.endings, self.endPoint1,
                self.endPoint2)

    def _update_widgets_in_PM_before_show(self):
        """
        This is called only when user is editing an existing structure.
        Its different than self.update_widgets_in_pm_before_show. (that method
        is called just before showing the property manager)
        @see: EditNanotube_EditCommand.editStructure()

        """
        if self.command and self.command.hasValidStructure():

            self.nanotube = self.command.struct.nanotube

            self.n, self.m = self.nanotube.getChirality()
            self.type = self.nanotube.getType()
            self.endings = self.nanotube.getEndings()
            self.endPoint1, self.endPoint2 = self.nanotube.getEndPoints()
            pass

        # Note that _update_widgets_in_PM_before_show() is called in
        # self.show, before you connect the signals. So, for the
        # 'first show' we will need to manually set the value of any
        # widgets that need updated. But later, when a different
        # NanotubeSegment is clicked, (while still in
        # EditNanotube_EditCommand, the propMgr will already be connected
        # so any calls in that case is redundant.
        self.updateNameField()
        self.updateLength()
        self.updateNanotubeDiameter()
        self.updateChirality()

        return

    def _update_UI_do_updates(self):
        """
        Overrides superclass method.

        @see: Command_PropertyManager._update_UI_do_updates()
        """
        self._update_widgets_in_PM_before_show()

        if self.command.struct:
            msg = "Editing structure <b>%s</b>." % \
                self.command.getStructureName()
        else:
            msg = "Select a nanotube to edit."
        self.updateMessage(msg)
        return

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

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

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

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

        self.nameLineEdit = PM_LineEdit(pmGroupBox,
                                        label="Name:",
                                        text="",
                                        setAsDefault=False)

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

        self.ntLengthLineEdit.setDisabled(True)

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

        self.ntDiameterLineEdit.setDisabled(True)

        # Nanotube chirality. These are disabled (read-only) for now. --Mark
        self.chiralityNSpinBox = \
            PM_SpinBox( pmGroupBox,
                        label        = "Chirality (n) :",
                        minimum      =  2,
                        maximum      =  100,
                        setAsDefault = True )
        self.chiralityNSpinBox.setDisabled(True)

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

    def _addWhatsThisText(self):
        """
        Add what's this text.
        """
        pass

    def _addToolTipText(self):
        """
        Add Tooltip text
        """
        pass

    def _nameChanged(self):
        """
        Slot for "Name" field.

        @TODO: Include a validator for the name field.
        """

        _name = str(self.nameLineEdit.text())

        if not _name:  # Minimal test. Need to implement a validator.
            self.updateNameField()
            return

        self.command.setStructureName(_name)
        msg = "Editing structure <b>%s</b>." % _name
        self.updateMessage(msg)

        return

    def updateNameField(self):
        """
        Update the name field showing the name of the currently selected protein.
        clear the combobox list.
        """

        if self.command.hasValidStructure():
            self.nameLineEdit.setEnabled(True)
            self.nameLineEdit.setText(self.command.getStructureName())
        else:
            self.nameLineEdit.setDisabled(True)
            self.nameLineEdit.setText("")
        return

    def updateLength(self):
        """
        Update the nanotube Length lineEdit widget.
        """
        if self.command.hasValidStructure():
            _nanotubeLength = vlen(self.endPoint1 - self.endPoint2)
            _lengthText = "%-7.4f Angstroms" % (_nanotubeLength)
        else:
            _lengthText = ""
        self.ntLengthLineEdit.setText(_lengthText)
        return

    def updateNanotubeDiameter(self):
        """
        Update the nanotube Diameter lineEdit widget.
        """
        if self.command.hasValidStructure():
            _diameterText = "%-7.4f Angstroms" % (self.nanotube.getDiameter())
        else:
            _diameterText = ""
        self.ntDiameterLineEdit.setText(_diameterText)
        return

    def updateChirality(self):
        """
        Update the nanotube chirality spinboxes (read-only).
        """
        if self.command.hasValidStructure():
            n, m = self.nanotube.getChirality()
        else:
            n = 0
            m = 0
        self.chiralityNSpinBox.setValue(n)
        self.chiralityMSpinBox.setValue(m)
        return

    pass  # End of EditNanotube_PropertyManager class
class EditNanotube_PropertyManager( DnaOrCnt_PropertyManager ):
    """
    The NanotubeSegmenta_PropertyManager class provides a Property Manager
    for the EditNanotube_EditCommand.

    @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         =  "Nanotube Properties"
    pmName        =  title
    iconPath      =  "ui/actions/Command Toolbar/BuildNanotube/EditNanotube.png"

    def __init__( self,  command ):
        """
        Constructor for the Cnt Segment Properties property manager.
        """

        #For model changed signal
        self.previousSelectionParams = None

        #see self.connect_or_disconnect_signals for comment about this flag
        self.isAlreadyConnected = False
        self.isAlreadyDisconnected = False

        # Initialized here. Their values will be set in
        # _update_widgets_in_PM_before_show()
        self.endPoint1 = V(0, 0, 0)
        self.endPoint2 = V(0, 0, 0)

        _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.nameLineEdit,
                       SIGNAL("editingFinished()"),
                       self._nameChanged)

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

    def show(self):
        """
        Show this property manager. Overrides EditCommand_PM.show()
        This method also retrives the name information from the
        command's structure for its name line edit field.
        @see: EditNanotube_EditCommand.getStructureName()
        @see: self.close()
        """
        _superclass.show(self)
        #if self.command is not None:
            #name = self.command.getStructureName()
            #if name is not None:
                #self.nameLineEdit.setText(name)

    def close(self):
        """
        Close this property manager.
        Also sets the name of the self.command's structure to the one
        displayed in the line edit field.
        @see self.show()
        @see: EditNanotube_EditCommand.setStructureName
        """
        if self.command is not None:
            name = str(self.nameLineEdit.text())
            self.command.setStructureName(name)
        _superclass.close(self)

    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 ,
            editNanotubeEditCommand_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",
                   editNanotubeEditCommand_cursorTextCheckBox_length_prefs_key)
                 ]

        return params

    def setParameters(self, params):
        """
        This is called when entering "Nanotube Segment Properties
        (i.e. "Edit properties...") to retrieve and set parameters of the
        nanotube segment that might be modified during this command and
        are needed to regenerate the nanotube segment.

        @param params: The parameters of the nanotube segment.
                       These parameters are retreived via
                       L{NanotubeSegment.getProps()}, called from
                       L{EditNanotube_EditCommand.editStructure()}.

                       Parameters:
                       - n, m (chirality)
                       - type (i.e. carbon or boron nitride)
                       - endings (none, hydrogen, nitrogen)
                       - endpoints (endPoint1, endPoint2)
        @type params: list (n, m), type, endings, (endPoint1, endPoint2)

        @note: Any widgets in the property manager that display these
        parameters should be updated here.

        @see: L{NanotubeSegment.getProps()}

        TODO:
        - Make this a EditCommand_PM API method?
        - See also the routines GraphicsMode.setParams or object.setProps
        ..better to name them all in one style?
        """
        (self.n, self.m), self.type, self.endings,\
            (self.endPoint1, self.endPoint2) = params

        # This is needed to update the endpoints since the Nanotube segment
        # may have been moved (i.e. translated or rotated). In that case,
        # the endpoints are not updated, so we recompute them here.
        nanotubeChunk = self.command.struct.members[0]
        self.endPoint1, self.endPoint2, radius = \
            self.command.struct.nanotube.computeEndPointsFromChunk(nanotubeChunk)

        if 0:
            print "\n--------------"
            print "setParameters():"
            print "Struct=", self.command.struct
            print "N, M:", self.n, self.m
            print "type:", self.type
            print "endings:", self.endings
            print "pt1, pt2:", self.endPoint1, self.endPoint2

    def getParameters(self):
        """
        Get the parameters that the edit command will use to determine if
        any have changed. If any have, then the nanotube will be modified.
        """
        if 0:
            print "\n--------------"
            print "getParameters():"
            print "Struct=", self.command.struct
            print "N, M:", self.n, self.m
            print "type:", self.type
            print "endings:", self.endings
            print "pt1, pt2:", self.endPoint1, self.endPoint2

        return (self.n, self.m,
                self.type,
                self.endings,
                self.endPoint1, self.endPoint2)

    def _update_widgets_in_PM_before_show(self):
        """
        This is called only when user is editing an existing structure.
        Its different than self.update_widgets_in_pm_before_show. (that method
        is called just before showing the property manager)
        @see: EditNanotube_EditCommand.editStructure()

        """
        if self.command and self.command.hasValidStructure():

            self.nanotube = self.command.struct.nanotube

            self.n, self.m = self.nanotube.getChirality()
            self.type = self.nanotube.getType()
            self.endings = self.nanotube.getEndings()
            self.endPoint1, self.endPoint2 = self.nanotube.getEndPoints()
            pass

        # Note that _update_widgets_in_PM_before_show() is called in
        # self.show, before you connect the signals. So, for the
        # 'first show' we will need to manually set the value of any
        # widgets that need updated. But later, when a different
        # NanotubeSegment is clicked, (while still in
        # EditNanotube_EditCommand, the propMgr will already be connected
        # so any calls in that case is redundant.
        self.updateNameField()
        self.updateLength()
        self.updateNanotubeDiameter()
        self.updateChirality()

        return

    def _update_UI_do_updates(self):
        """
        Overrides superclass method.

        @see: Command_PropertyManager._update_UI_do_updates()
        """
        self._update_widgets_in_PM_before_show()

        if self.command.struct:
            msg = "Editing structure <b>%s</b>." % \
                self.command.getStructureName()
        else:
            msg = "Select a nanotube to edit."
        self.updateMessage(msg)
        return

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

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

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

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

        self.nameLineEdit = PM_LineEdit( pmGroupBox,
                         label         =  "Name:",
                         text          =  "",
                         setAsDefault  =  False)

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

        self.ntLengthLineEdit.setDisabled(True)

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

        self.ntDiameterLineEdit.setDisabled(True)

        # Nanotube chirality. These are disabled (read-only) for now. --Mark
        self.chiralityNSpinBox = \
            PM_SpinBox( pmGroupBox,
                        label        = "Chirality (n) :",
                        minimum      =  2,
                        maximum      =  100,
                        setAsDefault = True )
        self.chiralityNSpinBox.setDisabled(True)

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

    def _addWhatsThisText(self):
        """
        Add what's this text.
        """
        pass

    def _addToolTipText(self):
        """
        Add Tooltip text
        """
        pass

    def _nameChanged(self):
        """
        Slot for "Name" field.

        @TODO: Include a validator for the name field.
        """

        _name = str(self.nameLineEdit.text())

        if not _name: # Minimal test. Need to implement a validator.
            self.updateNameField()
            return

        self.command.setStructureName(_name)
        msg = "Editing structure <b>%s</b>." % _name
        self.updateMessage(msg)

        return

    def updateNameField(self):
        """
        Update the name field showing the name of the currently selected protein.
        clear the combobox list.
        """

        if self.command.hasValidStructure():
            self.nameLineEdit.setEnabled(True)
            self.nameLineEdit.setText(self.command.getStructureName())
        else:
            self.nameLineEdit.setDisabled(True)
            self.nameLineEdit.setText("")
        return

    def updateLength( self ):
        """
        Update the nanotube Length lineEdit widget.
        """
        if self.command.hasValidStructure():
            _nanotubeLength = vlen(self.endPoint1 - self.endPoint2)
            _lengthText = "%-7.4f Angstroms" % (_nanotubeLength)
        else:
            _lengthText = ""
        self.ntLengthLineEdit.setText(_lengthText)
        return

    def updateNanotubeDiameter(self):
        """
        Update the nanotube Diameter lineEdit widget.
        """
        if self.command.hasValidStructure():
            _diameterText = "%-7.4f Angstroms" %  (self.nanotube.getDiameter())
        else:
            _diameterText = ""
        self.ntDiameterLineEdit.setText(_diameterText)
        return

    def updateChirality( self ):
        """
        Update the nanotube chirality spinboxes (read-only).
        """
        if self.command.hasValidStructure():
            n, m = self.nanotube.getChirality()
        else:
            n = 0
            m = 0
        self.chiralityNSpinBox.setValue(n)
        self.chiralityMSpinBox.setValue(m)
        return

    pass # End of EditNanotube_PropertyManager class
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)