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" )
Exemple #2
0
    def _loadGroupBox1(self, pmGroupBox):
        """
        Load widgets in group box 1.
        @param pmGroupBox: group box that contains protein name combo box and 
                        number of amino acids spin box
        @see: L{PM_GroupBox}                
        """
        self._updateProteinList()
        if len(self.protein_name_list) >= 1:
            self.set_current_protein_chunk_name(self.protein_name_list[0])
        self.structureComboBox = PM_ComboBox(pmGroupBox,
                                             label="Name:",
                                             choices=self.protein_name_list,
                                             setAsDefault=False)

        #Urmi 20080713: May be useful to set the minimum value to not zero
        #Now it does not matter, since its disabled. But zero as the minimum
        #value in a spinbox does not work otherwise.
        self.numberOfAASpinBox = \
            PM_SpinBox( pmGroupBox,
                        label         =  "Amino Acids:",
                        value         =  0,
                        setAsDefault  =  False,
                        minimum       =  0,
                        maximum       =  10000 )
        #for now we do not allow changing number of residues
        self.numberOfAASpinBox.setEnabled(False)
        self.editPropertiesPushButton = PM_PushButton(pmGroupBox,
                                                      text="Edit Sequence",
                                                      setAsDefault=True)
    def _loadGroupBox1(self, pmGroupBox):
        """
        Load widgets in group box 1.
        """

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

        self.numberOfBasesSpinBox = \
            PM_SpinBox( pmGroupBox,
                        label         =  "Number of bases:",
                        value         =  self._numberOfBases,
                        setAsDefault  =  False,
                        minimum       =  2,
                        maximum       =  10000 )

        self.disableStructHighlightingCheckbox = \
            PM_CheckBox( pmGroupBox,
                         text         = "Don't highlight while editing DNA",
                         widgetColumn  = 0,
                         state        = Qt.Unchecked,
                         setAsDefault = True,
                         spanWidth = True
                         )

        #As of 2008-03-31, the properties such as number of bases will be
        #editable only by using the resize handles.
        self.numberOfBasesSpinBox.setEnabled(False)
        return
Exemple #4
0
    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)
Exemple #5
0
    def _loadGroupBox1(self, pmGroupBox):
        """
        Load widgets in group box 4.
        """

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

        self.numberOfBasesSpinBox = \
            PM_SpinBox( pmGroupBox,
                        label         =  "Number of bases:",
                        value         =  self._numberOfBases,
                        setAsDefault  =  False,
                        minimum       =  2,
                        maximum       =  10000 )

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

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

        self.disableStructHighlightingCheckbox = \
            PM_CheckBox( pmGroupBox,
                         text         = "Don't highlight while editing DNA",
                         widgetColumn  = 0,
                         state        = Qt.Unchecked,
                         setAsDefault = True,
                         spanWidth = True
                         )

        #As of 2008-03-31, the properties such as number of bases will be
        #editable only by using the resize handles. post FNANO we will support
        #the
        self.numberOfBasesSpinBox.setEnabled(False)
        self.basesPerTurnDoubleSpinBox.setEnabled(False)
        self.duplexRiseDoubleSpinBox.setEnabled(False)
    def _loadProductSpecsGroupBox(self, inPmGroupBox):
        """
        Load widgets in the Product specifications group box.
        @param inPmGroupBox: The roduct specifications box in the PM
        @type  inPmGroupBox: L{PM_GroupBox}
        """

        productChoices = ['Rod', 'Ring']

        self.extrude_productTypeComboBox = \
            PM_ComboBox( inPmGroupBox,
                         label        = 'Final product:',
                         labelColumn  = 0,
                         choices      = productChoices,
                         index        = 0,
                         setAsDefault = True,
                         spanWidth    = False )

        # names used in the code, same order
        #if you comment out items from combobox, you also have to remove them
        # from this list unless they are at the end!!!
        self.extrude_productTypeComboBox_ptypes = ["straight rod", \
                                                   "closed ring", \
                                                   "corkscrew"]

        self.extrudeSpinBox_n = \
            PM_SpinBox( inPmGroupBox,
                        label         =  "Number of copies:",
                        labelColumn   =  0,
                        value         =  3,
                        minimum       =  1,
                        maximum       =  99
                    )
        #@WARNING: This method initializes some instance varaiables for various
        #checkboxes. (Example: self.mergeCopiesCheckBox.default = False).
        #These values are needed in extrudemode.py. This
        #won't be needed once extrudeMode.py is cleaned up. -- ninad 2007-09-10

        self.extrudeBondCriterionSlider =  \
            PM_Slider( inPmGroupBox,
                       currentValue = 100,
                       minimum      = 0,
                       maximum      = 300,
                       label        = 'Tolerence'
                   )
        self.extrudeBondCriterionLabel = \
            self.extrudeBondCriterionSlider.labelWidget

        self.extrudeBondCriterionSlider_dflt = 100
        self.extrudeBondCriterionSlider.setPageStep(5)

        self.makeBondsCheckBox = \
            PM_CheckBox(inPmGroupBox,
                        text         = 'Make bonds' ,
                        widgetColumn = 0,
                        state        = Qt.Checked
                    )
        self.makeBondsCheckBox.default = True
        self.makeBondsCheckBox.attr = 'whendone_make_bonds'
        self.makeBondsCheckBox.repaintQ = False
    def _loadGroupBox1(self, pmGroupBox):
        """
        Load widgets in group box 1.
        @param pmGroupBox: group box that contains protein name combo box and
                        number of amino acids spin box
        @see: L{PM_GroupBox}
        """
        self._updateProteinList()
        if len(self.protein_name_list) >= 1:
            self.set_current_protein_chunk_name(self.protein_name_list[0])
        self.structureComboBox = PM_ComboBox( pmGroupBox,
                                 label         =  "Name:",
                                 choices       =  self.protein_name_list,
                                 setAsDefault  =  False)

        #Urmi 20080713: May be useful to set the minimum value to not zero
        #Now it does not matter, since its disabled. But zero as the minimum
        #value in a spinbox does not work otherwise.
        self.numberOfAASpinBox = \
            PM_SpinBox( pmGroupBox,
                        label         =  "Amino Acids:",
                        value         =  0,
                        setAsDefault  =  False,
                        minimum       =  0,
                        maximum       =  10000 )
        #for now we do not allow changing number of residues
        self.numberOfAASpinBox.setEnabled(False)
        self.editPropertiesPushButton = PM_PushButton( pmGroupBox,
            text       =  "Edit Sequence",
            setAsDefault  =  True
            )
    def _loadGroupBox1(self, pmGroupBox):
        """
        Load widgets in group box 1.
        """

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

        self.numberOfBasesSpinBox = \
            PM_SpinBox( pmGroupBox,
                        label         =  "Number of bases:",
                        value         =  self._numberOfBases,
                        setAsDefault  =  False,
                        minimum       =  2,
                        maximum       =  10000 )

        self.disableStructHighlightingCheckbox = \
            PM_CheckBox( pmGroupBox,
                         text         = "Don't highlight while editing DNA",
                         widgetColumn  = 0,
                         state        = Qt.Unchecked,
                         setAsDefault = True,
                         spanWidth = True
                         )

        #As of 2008-03-31, the properties such as number of bases will be
        #editable only by using the resize handles.
        self.numberOfBasesSpinBox.setEnabled(False)
        return
Exemple #9
0
 def _loadGroupBox3(self, inPmGroupBox):
     """
     Load widgets in group box 3.
     """
     
     # "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.mwntSpacingField = \
         PM_DoubleSpinBox( inPmGroupBox,
                           label        = "Spacing :", 
                           value        = 2.46, 
                           setAsDefault = True,
                           minimum      = 1.0, 
                           maximum      = 10.0, 
                           singleStep   = 0.1, 
                           decimals     = 3, 
                           suffix       = " Angstroms" )
Exemple #10
0
    def _loadBreakOptionsGroupbox(self, pmGroupBox):
        """
        Load widgets in this group box.
        """

        self.assignColorToBrokenDnaStrandsCheckBox = \
            PM_CheckBox(pmGroupBox ,
                        text         = 'Assign new color to broken strands',
                        widgetColumn = 0,
                        spanWidth = True)

        connect_checkbox_with_boolean_pref(
            self.assignColorToBrokenDnaStrandsCheckBox,
            assignColorToBrokenDnaStrands_prefs_key)



        self.basesBeforeNextBreakSpinBox = \
            PM_SpinBox( pmGroupBox,
                        label         =  "Break Every:",
                        value         =  3,
                        setAsDefault  =  False,
                        minimum       =  1,
                        maximum       =  10000,
                        suffix       = " bases"
                        )

        connect_spinBox_with_pref(
            self.basesBeforeNextBreakSpinBox,
            breakStrandsCommand_numberOfBasesBeforeNextBreak_prefs_key)

        self.breakAllStrandsButton = PM_PushButton(pmGroupBox,
                                                   label="",
                                                   text="do it")

        self._dnaStrandChooserGroupBox = PM_ObjectChooser(
            pmGroupBox,
            self.command,
            modelObjectType=self.win.assy.DnaStrand,
            title="Choose strands ")

        if not DEBUG_BREAK_OPTIONS_FEATURE:
            self._dnaStrandChooserGroupBox.hide()
            self.breakAllStrandsButton.hide()
            self.basesBeforeNextBreakSpinBox.hide()
Exemple #11
0
 def _loadGroupBox2(self, inPmGroupBox):
     """
     Load widgets in group box 2.
     """
     
     self.zDistortionField = \
         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.xyDistortionField = \
         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" )
Exemple #12
0
    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 _loadGroupBox1(self, pmGroupBox):
        """
        Load widgets in group box 4.
        """

        self.nameLineEdit = PM_LineEdit(pmGroupBox,
                                        label="Protein chunk name:",
                                        text="",
                                        setAsDefault=False)

        #Urmi 20080713: May be useful to set the minimum value to not zero
        self.numberOfAASpinBox = \
            PM_SpinBox( pmGroupBox,
                        label         =  "Number of amino acids:",
                        value         =  0,
                        setAsDefault  =  False,
                        minimum       =  0,
                        maximum       =  10000 )
        self.numberOfAASpinBox.setEnabled(False)
    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 _loadLayerPropertiesGroupBox(self, inPmGroupBox):
        """
        Load widgets in the Layer Properties group box.
        @param inPmGroupBox: The Layer Properties groupbox in the PM
        @type  inPmGroupBox: L{PM_GroupBox} 
        """

        self.currentLayerComboBox = \
            PM_ComboBox( inPmGroupBox,
                         index     = 0,
                         spanWidth = True
                        )

        self.addLayerButton = PM_PushButton(inPmGroupBox)
        self.addLayerButton.setIcon(
            geticon('ui/actions/Properties Manager/addlayer.png'))
        self.addLayerButton.setFixedSize(QSize(26, 26))
        self.addLayerButton.setIconSize(QSize(22, 22))

        # A widget list to create a widget row.
        # Format:
        # - Widget type,
        # - widget object,
        # - column

        firstRowWidgetList = [('PM_ComboBox', self.currentLayerComboBox, 1),
                              ('PM_PushButton', self.addLayerButton, 2)]

        widgetRow = PM_WidgetRow(
            inPmGroupBox,
            title='',
            widgetList=firstRowWidgetList,
            label="Layer:",
            labelColumn=0,
        )

        self.layerCellsSpinBox = \
             PM_SpinBox( inPmGroupBox,
                        label         =  "Lattice cells:",
                        labelColumn   =  0,
                        value         =  2,
                        minimum       =  1,
                        maximum       =  25
                      )

        self.layerThicknessLineEdit = PM_LineEdit(inPmGroupBox,
                                                  label="Thickness:",
                                                  text="",
                                                  setAsDefault=False,
                                                  spanWidth=False)

        #self.layerThicknessLineEdit.setReadOnly(True)
        self.layerThicknessLineEdit.setDisabled(True)
        tooltip = "Thickness of layer in Angstroms"
        self.layerThicknessLineEdit.setToolTip(tooltip)
 def _loadGroupBox1(self, pmGroupBox):
     """
     Load widgets in group box 4.
     """
     
     self.nameLineEdit = PM_LineEdit( pmGroupBox,
                      label         =  "Strand name:",
                      text          =  "",
                      setAsDefault  =  False)
     
     self.numberOfBasesSpinBox = \
         PM_SpinBox( pmGroupBox, 
                     label         =  "Number of bases:", 
                     value         =  self._numberOfBases,
                     setAsDefault  =  False,
                     minimum       =  2,
                     maximum       =  10000 )
     
     self.basesPerTurnDoubleSpinBox  =  \
         PM_DoubleSpinBox( pmGroupBox,
                           label         =  "Bases per turn:",
                           value         =  self.basesPerTurn,
                           setAsDefault  =  True,
                           minimum       =  8.0,
                           maximum       =  20.0,
                           decimals      =  2,
                           singleStep    =  0.1 )
     
     self.duplexRiseDoubleSpinBox  =  \
         PM_DoubleSpinBox( pmGroupBox,
                           label         =  "Rise:",
                           value         =  self.duplexRise,
                           setAsDefault  =  True,
                           minimum       =  2.0,
                           maximum       =  4.0,
                           decimals      =  3,
                           singleStep    =  0.01 )
     
     self.disableStructHighlightingCheckbox = \
         PM_CheckBox( pmGroupBox,
                      text         = "Don't highlight while editing DNA",
                      widgetColumn  = 0,
                      state        = Qt.Unchecked,
                      setAsDefault = True,
                      spanWidth = True
                      )
     
     #As of 2008-03-31, the properties such as number of bases will be 
     #editable only by using the resize handles. post FNANO we will support 
     #the 
     self.numberOfBasesSpinBox.setEnabled(False)
     self.basesPerTurnDoubleSpinBox.setEnabled(False)
     self.duplexRiseDoubleSpinBox.setEnabled(False)
 def _loadMovieOptionsGroupBox(self, inPmGroupBox):
     """
     Load widgets in the Movie Options group box.
     @param inPmGroupBox: The Movie Options groupbox in the PM
     @type  inPmGroupBox: L{PM_GroupBox} 
     """
     
     self.frameNumberSpinBox = PM_SpinBox(inPmGroupBox,
                                          label         =  "Go To Frame:",
                                          labelColumn   =  0,
                                          value         =  0,
                                          minimum       =  1,
                                          maximum       =  999999)
     
     self.frameSkipSpinBox = PM_SpinBox(inPmGroupBox,
                                       label         =  "Skip:",
                                       labelColumn   =  0,
                                       value         =  0,
                                       minimum       =  1,
                                       maximum       =  9999,
                                       suffix        = ' Frame(s)')
Exemple #18
0
 def _loadPM_SpinBox(self, inPmGroupBox):
     """
     PM_SpinBox widgets.
     """
     
     self.spinBox = \
         PM_SpinBox( inPmGroupBox, 
                     label        = "Spinbox:", 
                     value        = 5, 
                     setAsDefault = True,
                     minimum      = 2, 
                     maximum      = 10, 
                     suffix       = ' things',
                     spanWidth    = True )
Exemple #19
0
    def _loadGroupBox1(self, pmGroupBox):
        """
        Load widgets in group box 4.
        """

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

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

        self.basesPerTurnDoubleSpinBox  =  \
            PM_DoubleSpinBox( pmGroupBox,
                              label         =  "Bases per turn:",
                              value         =  self.basesPerTurn,
                              setAsDefault  =  True,
                              minimum       =  8.0,
                              maximum       =  20.0,
                              decimals      =  2,
                              singleStep    =  0.1 )
        self.basesPerTurnDoubleSpinBox.setDisabled(True)

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

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

        self.duplexLengthLineEdit.setDisabled(True)
    def _loadBreakOptionsGroupbox(self, pmGroupBox):
        """
        Load widgets in this group box.
        """

        self.assignColorToBrokenDnaStrandsCheckBox = \
            PM_CheckBox(pmGroupBox ,
                        text         = 'Assign new color to broken strands',
                        widgetColumn = 0,
                        spanWidth = True)

        connect_checkbox_with_boolean_pref(
            self.assignColorToBrokenDnaStrandsCheckBox,
            assignColorToBrokenDnaStrands_prefs_key )



        self.basesBeforeNextBreakSpinBox = \
            PM_SpinBox( pmGroupBox,
                        label         =  "Break Every:",
                        value         =  3,
                        setAsDefault  =  False,
                        minimum       =  1,
                        maximum       =  10000,
                        suffix       = " bases"
                        )

        connect_spinBox_with_pref(
            self.basesBeforeNextBreakSpinBox,
            breakStrandsCommand_numberOfBasesBeforeNextBreak_prefs_key)

        self.breakAllStrandsButton = PM_PushButton(
            pmGroupBox,
            label = "",
            text  = "do it" )


        self._dnaStrandChooserGroupBox = PM_ObjectChooser(
            pmGroupBox,
            self.command,
            modelObjectType = self.win.assy.DnaStrand,
            title = "Choose strands " )

        if not DEBUG_BREAK_OPTIONS_FEATURE:
            self._dnaStrandChooserGroupBox.hide()
            self.breakAllStrandsButton.hide()
            self.basesBeforeNextBreakSpinBox.hide()
 def _loadGroupBox1(self, pmGroupBox):
     """
     Load widgets in group box 4.
     """
     
     self.nameLineEdit = PM_LineEdit( pmGroupBox,
                      label         =  "Protein chunk name:",
                      text          =  "",
                      setAsDefault  =  False)
     
     #Urmi 20080713: May be useful to set the minimum value to not zero
     self.numberOfAASpinBox = \
         PM_SpinBox( pmGroupBox, 
                     label         =  "Number of amino acids:", 
                     value         =  0,
                     setAsDefault  =  False,
                     minimum       =  0,
                     maximum       =  10000 )
     self.numberOfAASpinBox.setEnabled(False)
Exemple #22
0
class DnaStrand_PropertyManager(DnaOrCnt_PropertyManager):
    """
    The DnaStrand_PropertyManager class provides a Property Manager 
    for the DnaStrand_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 = "DnaStrand Properties"
    pmName = title
    iconPath = "ui/actions/Properties Manager/Strand.png"

    def __init__(self, win, editCommand):
        """
        Constructor for the Build DNA 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

        self.sequenceEditor = None

        self._numberOfBases = 0
        self._conformation = 'B-DNA'
        self.duplexRise = 3.18
        self.basesPerTurn = 10
        self.dnaModel = 'PAM3'

        _superclass.__init__(self, win, editCommand)



        self.showTopRowButtons( PM_DONE_BUTTON | \
                                PM_WHATS_THIS_BUTTON)

        self._loadSequenceEditor()

        msg = "Use resize handles to resize the strand. Use sequence editor"\
                   "to assign a new sequence or the current one to a file."
        self.updateMessage(msg)

    def _addGroupBoxes(self):
        """
        Add the DNA 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="Strand name:",
                                        text="",
                                        setAsDefault=False)

        self.numberOfBasesSpinBox = \
            PM_SpinBox( pmGroupBox,
                        label         =  "Number of bases:",
                        value         =  self._numberOfBases,
                        setAsDefault  =  False,
                        minimum       =  2,
                        maximum       =  10000 )

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

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

        self.disableStructHighlightingCheckbox = \
            PM_CheckBox( pmGroupBox,
                         text         = "Don't highlight while editing DNA",
                         widgetColumn  = 0,
                         state        = Qt.Unchecked,
                         setAsDefault = True,
                         spanWidth = True
                         )

        #As of 2008-03-31, the properties such as number of bases will be
        #editable only by using the resize handles. post FNANO we will support
        #the
        self.numberOfBasesSpinBox.setEnabled(False)
        self.basesPerTurnDoubleSpinBox.setEnabled(False)
        self.duplexRiseDoubleSpinBox.setEnabled(False)

    def _loadSequenceEditor(self):
        """
        Temporary code  that shows the Sequence editor ..a doc widget docked
        at the bottom of the mainwindow. The implementation is going to change
        before 'rattleSnake' product release.
        As of 2007-11-20: This feature (sequence editor) is waiting 
        for the ongoing dna model work to complete.
        """
        self.sequenceEditor = self.win.createDnaSequenceEditorIfNeeded()
        self.sequenceEditor.hide()

    def _loadDisplayOptionsGroupBox(self, pmGroupBox):
        """
        Overrides superclass method. 
        Also loads the color chooser widget. 
        """
        self._loadColorChooser(pmGroupBox)
        _superclass._loadDisplayOptionsGroupBox(self, pmGroupBox)

    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,
            dnaStrandEditCommand_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 bases",
                   dnaStrandEditCommand_cursorTextCheckBox_numberOfBases_prefs_key),

                  ("Number of bases to be changed",
                   dnaStrandEditCommand_cursorTextCheckBox_changedBases_prefs_key)
                 ]

        return params

    def getParameters(self):
        numberOfBases = self.numberOfBasesSpinBox.value()
        dnaForm = self._conformation
        dnaModel = self.dnaModel
        basesPerTurn = self.basesPerTurn
        duplexRise = self.duplexRise
        color = self._colorChooser.getColor()

        return (numberOfBases, dnaForm, dnaModel, basesPerTurn, duplexRise,
                color)

    def setParameters(self, params):
        """
        This is usually called when you are editing an existing structure. 
        Some property manager ui elements then display the information 
        obtained from the object being edited. 
        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?  
        """
        #Set the duplex rise and bases per turn spinbox values.

        numberOfBases, \
                     dnaForm, \
                     dnaModel, \
                     basesPerTurn, \
                     duplexRise, \
                     color  = params

        if numberOfBases is not None:
            self.numberOfBasesSpinBox.setValue(numberOfBases)
        if dnaForm is not None:
            self._conformation = dnaForm
        if dnaModel is not None:
            self.dnaModel = dnaModel
        if duplexRise is not None:
            self.duplexRiseDoubleSpinBox.setValue(duplexRise)
        if basesPerTurn is not None:
            self.basesPerTurnDoubleSpinBox.setValue(basesPerTurn)
        if color is not None:
            self._colorChooser.setColor(color)

    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
        """
        #TODO: This is a temporary fix for a bug. When you invoke a temporary
        # mode Entering such a temporary mode keeps the signals of
        #PM from the previous mode connected (
        #but while exiting that temporary mode and reentering the
        #previous mode, it atucally reconnects the signal! This gives rise to
        #lots  of bugs. This needs more general fix in Temporary mode API.
        # -- Ninad 2008-01-09 (similar comment exists in MovePropertyManager.py

        if isConnect and self.isAlreadyConnected:
            if debug_flags.atom_debug:
                print_compact_stack("warning: attempt to connect widgets"\
                                    "in this PM that are already connected." )
            return

        if not isConnect and self.isAlreadyDisconnected:
            if debug_flags.atom_debug:
                print_compact_stack("warning: attempt to disconnect widgets"\
                                    "in this PM that are already disconnected.")
            return

        self.isAlreadyConnected = isConnect
        self.isAlreadyDisconnected = not isConnect

        if isConnect:
            change_connect = self.win.connect
        else:
            change_connect = self.win.disconnect

        if self.sequenceEditor:
            self.sequenceEditor.connect_or_disconnect_signals(isConnect)

        _superclass.connect_or_disconnect_signals(self, isConnect)

        change_connect(self.disableStructHighlightingCheckbox,
                       SIGNAL('stateChanged(int)'),
                       self.change_struct_highlightPolicy)

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

    def model_changed(self):
        """
        @see: DnaStrand_EditCommand.model_changed()
        @see: DnaStrand_EditCommand.hasResizableStructure()
        """
        isStructResizable, why_not = self.editCommand.hasResizableStructure()
        if not isStructResizable:
            #disable all widgets
            if self._pmGroupBox1.isEnabled():
                self._pmGroupBox1.setEnabled(False)
                msg1 = ("Viewing properties of %s <br>") % (
                    self.editCommand.struct.name)
                msg2 = redmsg("DnaStrand is not resizable. Reason: %s" %
                              (why_not))
                self.updateMessage(msg1 + msg2)
        else:
            if not self._pmGroupBox1.isEnabled():
                self._pmGroupBox1.setEnabled(True)
                msg1 = ("Viewing properties of %s <br>") % (
                    self.editCommand.struct.name)
                msg2 = "Use resize handles to resize the strand. Use sequence editor"\
                    "to assign a new sequence or the current one to a file."
                self.updateMessage(msg1 + msg2)

    def show(self):
        """
        Show this PM 
        As of 2007-11-20, it also shows the Sequence Editor widget and hides 
        the history widget. This implementation may change in the near future
        This method also retrives the name information from the 
        editCommand's structure for its name line edit field. 
        @see: DnaStrand_EditCommand.getStructureName()
        @see: self.close()
        """
        _superclass.show(self)
        self._showSequenceEditor()

        if self.editCommand is not None:
            name = self.editCommand.getStructureName()
            if name is not None:
                self.nameLineEdit.setText(name)

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

        if self.sequenceEditor:
            self.sequenceEditor.close()

        _superclass.close(self)

    def _showSequenceEditor(self):
        if self.sequenceEditor:
            if not self.sequenceEditor.isVisible():
                #Show the sequence editor
                #ATTENTION: the sequence editor also closes (temporarily) the
                #reports dockwidget (if visible) Its state is later restored when
                #the sequuence Editor is closed.
                self.sequenceEditor.show()

            self.updateSequence()

    def updateSequence(self):
        """
        Update the sequence string in the sequence editor
        @see: DnaSequenceEditor.setSequence()
        @see DnaSequenceEditor._determine_complementSequence()
        @see: DnaSequenceEditor.setComplementSequence()
        @see: DnaStrand.getStrandSequenceAndItsComplement()
        """
        #Read in the strand sequence of the selected strand and
        #show it in the text edit in the sequence editor.
        ##strand = self.strandListWidget.getPickedItem()

        if not self.editCommand.hasValidStructure():
            return

        strand = self.editCommand.struct

        titleString = 'Sequence Editor for ' + strand.name

        self.sequenceEditor.setWindowTitle(titleString)
        sequenceString, complementSequenceString = strand.getStrandSequenceAndItsComplement(
        )
        if sequenceString:
            sequenceString = QString(sequenceString)
            sequenceString = sequenceString.toUpper()
            #Set the initial sequence (read in from the file)
            self.sequenceEditor.setSequence(sequenceString)

            #Set the initial complement sequence for DnaSequence editor.
            #do this independently because 'complementSequenceString' may have
            #some characters (such as * ) that denote a missing base on the
            #complementary strand. this information is used by the sequence
            #editor. See DnaSequenceEditor._determine_complementSequence()
            #for more details. See also bug 2787
            self.sequenceEditor.setComplementSequence(complementSequenceString)

    def change_struct_highlightPolicy(self, checkedState=False):
        """
        Change the 'highlight policy' of the structure being edited 
        (i.e. self.editCommand.struct) . 
        @param checkedState: The checked state of the checkbox that says 
                             'Don't highlight while editing DNA'. So, it 
                             its True, the structure being edited won't get
                             highlighted. 
        @see: DnaStrand.setHighlightPolicy for more comments        
        """
        if self.editCommand and self.editCommand.hasValidStructure():
            highlight = not checkedState
            self.editCommand.struct.setHighlightPolicy(highlight=highlight)

    def _addWhatsThisText(self):
        """
        Add what's this text. 
        Abstract method.
        """
        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
Exemple #24
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)
Exemple #25
0
    def _loadMenuWidgets(self):
        """
        Load the various menu widgets (e.g. Open, save sequence options, 
        Find and replace widgets etc. 
        """
        #Note: Find and replace widgets might be moved to their own class.

        self.searchTypeComboBox  = \
            PM_ComboBox( self,
                         label         =  "Search options:",
                         choices       =  ["By node name", "By # of bases (DNA only)"],
                         setAsDefault  =  True)

        #Find  widgets --
        self._nucleotidesSpinBox_1 = PM_SpinBox(self,
                                                label="",
                                                value=10,
                                                setAsDefault=False,
                                                singleStep=10,
                                                minimum=1,
                                                maximum=50000)

        self._nucleotidesSpinBox_2 = PM_SpinBox(self,
                                                label="",
                                                value=50,
                                                setAsDefault=False,
                                                singleStep=10,
                                                minimum=1,
                                                maximum=50000)


        self.findLineEdit = \
            PM_LineEdit( self,
                         label        = "",
                         spanWidth    = False)

        self.findLineEdit.setMaximumWidth(80)

        self.findOptionsToolButton = PM_ToolButton(self)
        self.findOptionsToolButton.setMaximumWidth(12)
        self.findOptionsToolButton.setAutoRaise(True)

        ##self.findOptionsToolButton.setPopupMode(QToolButton.MenuButtonPopup)

        ##self._setFindOptionsToolButtonMenu()

        self.searchToolButton = PM_ToolButton(
            self, iconPath="ui/actions/Properties Manager/Find_Next.png")
        self.searchToolButton.setAutoRaise(False)

        self.warningSign = QLabel(self)
        self.warningSign.setPixmap(
            getpixmap('ui/actions/Properties Manager/Warning.png'))
        self.warningSign.hide()

        self.phraseNotFoundLabel = QLabel(self)
        self.phraseNotFoundLabel.setText("Not Found")
        self.phraseNotFoundLabel.hide()

        # NOTE: Following needs cleanup in the PM_WidgetRow/ PM_WidgetGrid
        # but this explanation is sufficient  until thats done --

        # When the widget type starts with the word 'PM_' , the
        # PM_WidgetRow treats it as a well defined widget and thus doesn't try
        # to create a QWidget object (or its subclasses)
        # This is the reason why qLabels such as self.warningSign and
        # self.phraseNotFoundLabel  are defined as PM_Labels and not 'QLabels'
        # If they were defined as 'QLabel'(s) then PM_WidgetRow would have
        # recreated the label. Since we want to show/hide the above mentioned
        # labels (and if they were recreated as mentioned above),
        # we would have needed to define  those something like this:
        # self.phraseNotFoundLabel = widgetRow._widgetList[-2]
        #Cleanup in PM_widgetGrid could be to check if the widget starts with
        #'Q'  instead of 'PM_'

        #Widgets to include in the widget row.

        widgetList1 = [('QLabel', "     Search for name:", 1),
                       ('PM_LineEdit', self.findLineEdit, 2),
                       ('PM_ToolButton', self.findOptionsToolButton, 3),
                       ('PM_ToolButton', self.searchToolButton, 4),
                       ('PM_Label', self.warningSign, 5),
                       ('PM_Label', self.phraseNotFoundLabel, 6),
                       ('QSpacerItem', 5, 5, 7)]

        widgetList2 = [('QLabel', "     Number of bases: >=", 1),
                       ('PM_SpinBox', self._nucleotidesSpinBox_1, 2),
                       ('QLabel', "     <=", 3),
                       ('PM_SpinBox', self._nucleotidesSpinBox_2, 4),
                       ('QSpacerItem', 5, 5, 5)]

        widgetList3 = [('QSpacerItem', 5, 5, 1),
                       ('PM_ToolButton', self.searchToolButton, 2),
                       ('PM_Label', self.warningSign, 3),
                       ('PM_Label', self.phraseNotFoundLabel, 4),
                       ('QSpacerItem', 5, 5, 5)]

        self._widgetRow1 = PM_WidgetRow(self,
                                        title='',
                                        widgetList=widgetList1,
                                        label="",
                                        spanWidth=True)

        self._widgetRow2 = PM_WidgetRow(self,
                                        title='',
                                        widgetList=widgetList2,
                                        label="",
                                        spanWidth=True)

        self._widgetRow3 = PM_WidgetRow(self,
                                        title='',
                                        widgetList=widgetList3,
                                        label="",
                                        spanWidth=True)
class DnaGeneratorPropertyManager( PM_Dialog, DebugMenuMixin ):
    """
    The DnaGeneratorPropertyManager class provides a Property Manager
    for the "Build > Atoms" 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

    @ivar validSymbols: Miscellaneous symbols that may appear in the sequence
                        (but are ignored). The hyphen '-' is a special case
                        that must be dealt with individually; it is not
                        included because it can confuse regular expressions.
    @type validSymbols: QString
    """

    title         =  "DNA"
    pmName        =  title
    iconPath      =  "ui/actions/Tools/Build Structures/DNA.png"
    validSymbols  =  QString(' <>~!@#%&_+`=$*()[]{}|^\'"\\.;:,/?')

    # The following class variables guarantee the UI's menu items
    # are synchronized with their action code.  The arrays should
    # not be changed, unless an item is removed or inserted.
    # Changes should be made via only the _action... variables.
    # e.g., Change _action_Complement from "Complement"
    #       to "Complement Sequences". The menu item will
    #       change and its related code will need no update.
    _action_Complement           =  "Complement"
    _action_Reverse              =  "Reverse"
    _action_RemoveUnrecognized   =  'Remove unrecognized letters'
    _action_ConvertUnrecognized  =  'Convert unrecognized letters to "N"'

    _actionChoices       =  [ "Action",
                              "---",
                              _action_Complement,
                              _action_Reverse,
                              _action_RemoveUnrecognized,
                              _action_ConvertUnrecognized ]

    _modeltype_PAM3       =  "PAM3"
    _modeltype_PAM5       =  "PAM5"
    _modeltype_Atomistic  =  "Atomistic" # deprecated
    _modelChoices          =  [ _modeltype_PAM3,
                                _modeltype_PAM5 ]

    def __init__( self ):
        """
        Constructor for the DNA Generator property manager.
        """
        PM_Dialog.__init__( self, self.pmName, self.iconPath, self.title )
        DebugMenuMixin._init1( self )


        msg = "Edit the DNA parameters and select <b>Preview</b> to \
        preview the structure. Click <b>Done</b> to insert it into \
        the model."

        # This causes the "Message" box to be displayed as well.
        # setAsDefault=True causes this message to be reset whenever
        # this PM is (re)displayed via show(). Mark 2007-06-01.
        self.MessageGroupBox.insertHtmlMessage( msg, setAsDefault  =  True )

    def _addGroupBoxes( self ):
        """
        Add the DNA Property Manager group boxes.
        """
        self._pmGroupBox1 = PM_GroupBox( self, title = "Strand Sequence" )
        self._loadGroupBox1( self._pmGroupBox1 )

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

        self._pmGroupBox3 = PM_GroupBox( self, title = "Endpoints" )
        self._loadGroupBox3( self._pmGroupBox3 )

    def _loadGroupBox1(self, pmGroupBox):
        """
        Load widgets in group box 1.
        """
        # Duplex Length
        self.duplexLengthSpinBox  =  \
            PM_DoubleSpinBox( pmGroupBox,
                              label         =  "Duplex Length: ",
                              value         =  0,
                              setAsDefault  =  False,
                              minimum       =  0,
                              maximum       =  34000,
                              singleStep    =  self.getDuplexRise("B-DNA"),
                              decimals      =  3,
                              suffix        =  ' Angstroms')

        self.connect( self.duplexLengthSpinBox,
                      SIGNAL("valueChanged(double)"),
                      self.duplexLengthChanged )

        # Strand Length
        self.strandLengthSpinBox = \
            PM_SpinBox( pmGroupBox,
                        label         =  "Strand Length :",
                        value         =  0,
                        setAsDefault  =  False,
                        minimum       =  0,
                        maximum       =  10000,
                        suffix        =  ' bases' )

        self.connect( self.strandLengthSpinBox,
                      SIGNAL("valueChanged(int)"),
                      self.strandLengthChanged )
        # New Base choices
        newBaseChoices  =  []
        for theBase in basesDict.keys():
            newBaseChoices  =  newBaseChoices \
                            + [ theBase + ' (' \
                            + basesDict[theBase]['Name'] + ')' ]

        try:
            defaultBaseChoice = basesDict.keys().index('N')
        except:
            defaultBaseChoice = 0

        # Strand Sequence
        self.sequenceTextEdit = \
            PM_TextEdit( pmGroupBox,
                         label      =  "",
                         spanWidth  =  True )

        self.sequenceTextEdit.setCursorWidth(2)
        self.sequenceTextEdit.setWordWrapMode( QTextOption.WrapAnywhere )

        self.connect( self.sequenceTextEdit,
                      SIGNAL("textChanged()"),
                      self.sequenceChanged )

        self.connect( self.sequenceTextEdit,
                      SIGNAL("cursorPositionChanged()"),
                      self.cursorPosChanged )

        # Actions
        self.actionsComboBox  = \
            PM_ComboBox( pmGroupBox,
                         label         =  '',
                         choices       =  self._actionChoices,
                         index         =  0,
                         setAsDefault  =  True,
                         spanWidth     =  True )

        # If SIGNAL("activate(const QString&)") is used, we get a TypeError.
        # This is a bug that needs Bruce. Using currentIndexChanged(int) as
        # a workaround, but there is still a bug when the "Reverse" action
        # is selected. Mark 2007-08-15
        self.connect( self.actionsComboBox,
                      SIGNAL("currentIndexChanged(int)"),
                      self.actionsComboBoxChanged )

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

        self.modelComboBox  = \
            PM_ComboBox( pmGroupBox,
                         label         =  "Model :",
                         choices       =  self._modelChoices,
                         setAsDefault  =  True)

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

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

        self.basesPerTurnComboBox= \
            PM_ComboBox( pmGroupBox,
                         label         =  "Bases Per Turn :",
                         choices       =  ["10.0", "10.5", "10.67"],
                         setAsDefault  =  True)

        # I may decide to reintroduce "base-pair chunks" at a later time.
        # Please talk to me if you have a strong feeling about including
        # this. Mark 2007-08-19.
        createChoices        =  ["Strand chunks", \
                                 "Single chunk" ]
                                 #@ "Base-pair chunks"]

        self.createComboBox  = \
            PM_ComboBox( pmGroupBox,
                         label         =  "Create :",
                         choices       =  createChoices,
                         index         =  0,
                         setAsDefault  =  True,
                         spanWidth     =  False )

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

        self._endPoint1GroupBox = PM_GroupBox( pmGroupBox, title = "Endpoint1" )
        self._endPoint2GroupBox = PM_GroupBox( pmGroupBox, title = "Endpoint2" )

        # Point 1
        self.x1SpinBox  =  \
            PM_DoubleSpinBox( self._endPoint1GroupBox,
                              label         =  \
                              "ui/actions/Properties Manager/X_Coordinate.png",
                              value         =  0,
                              setAsDefault  =  True,
                              minimum       =  -100.0,
                              maximum       =   100.0,
                              decimals      =  3,
                              suffix        =  ' Angstroms')

        self.y1SpinBox  =  \
            PM_DoubleSpinBox( self._endPoint1GroupBox,
                              label         =  \
                              "ui/actions/Properties Manager/Y_Coordinate.png",
                              value         =  0,
                              setAsDefault  =  True,
                              minimum       =  -100.0,
                              maximum       =   100.0,
                              decimals      =  3,
                              suffix        =  ' Angstroms')

        self.z1SpinBox  =  \
            PM_DoubleSpinBox( self._endPoint1GroupBox,
                              label         =  \
                              "ui/actions/Properties Manager/Z_Coordinate.png",
                              value         =  0,
                              setAsDefault  =  True,
                              minimum       =  -100.0,
                              maximum       =   100.0,
                              decimals      =  3,
                              suffix        =  ' Angstroms')

        # Point 2
        self.x2SpinBox  =  \
            PM_DoubleSpinBox( self._endPoint2GroupBox,
                              label         =  \
                              "ui/actions/Properties Manager/X_Coordinate.png",
                              value         =  10.0,
                              setAsDefault  =  True,
                              minimum       =  -100.0,
                              maximum       =   100.0,
                              decimals      =  3,
                              suffix        =  ' Angstroms')

        self.y2SpinBox  =  \
            PM_DoubleSpinBox( self._endPoint2GroupBox,
                              label         =  \
                              "ui/actions/Properties Manager/Y_Coordinate.png",
                              value         =  0,
                              setAsDefault  =  True,
                              minimum       =  -100.0,
                              maximum       =   100.0,
                              decimals      =  3,
                              suffix        =  ' Angstroms')

        self.z2SpinBox  =  \
            PM_DoubleSpinBox( self._endPoint2GroupBox,
                              label         =  \
                              "ui/actions/Properties Manager/Z_Coordinate.png",
                              value         =  0,
                              setAsDefault  =  True,
                              minimum       =  -100.0,
                              maximum       =   100.0,
                              decimals      =  3,
                              suffix        =  ' Angstroms')

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

        @note: Many PM widgets are still missing their "What's This" text.
        """

        self.conformationComboBox.setWhatsThis("""<b>Conformation</b>
        <p>There are three DNA geometries, A-DNA, B-DNA,
        and Z-DNA. Only B-DNA and Z-DNA are currently supported.</p>""")

        self.sequenceTextEdit.setWhatsThis("""<b>Strand Sequence</b>
        <p>Type in the strand sequence you want to generate here (5' => 3')<br>
        <br>
        Recognized base letters:<br>
        <br>
        A = Adenosine<br>
        C = Cytosine<br>
        G = Guanosine<br>
        T = Thymidine<br>
        N = aNy base<br>
        X = Unassigned<br>
        <br>
        Other base letters currently recognized:<br>
        <br>
        B = C,G, or T<br>
        D = A,G, or T<br>
        H = A,C, or T<br>
        V = A,C, or G<br>
        R = A or G (puRine)<br>
        Y = C or T (pYrimidine)<br>
        K = G or T (Keto)<br>
        M = A or C (aMino)<br>
        S = G or C (Strong -3H bonds)<br>
        W = A or T (Weak - 2H bonds)<br>
        </p>""")

        self.actionsComboBox.setWhatsThis("""<b>Action</b>
        <p>Select an action to perform on the sequence.</p>""")

    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
        """
        self.basesPerTurnComboBox.clear()
        conformation  =  self.conformationComboBox.currentText()

        if conformation == "B-DNA":
            self.basesPerTurnComboBox.insertItem(0, "10.0")
            self.basesPerTurnComboBox.insertItem(1, "10.5")
            self.basesPerTurnComboBox.insertItem(2, "10.67")

            #10.5 is the default value for Bases per turn.
            #So set the current index to 1
            self.basesPerTurnComboBox.setCurrentIndex(1)

        elif conformation == "Z-DNA":
            self.basesPerTurnComboBox.insertItem(0, "12.0")

        elif inIndex == -1:
            # Caused by clear(). This is tolerable for now. Mark 2007-05-24.
            conformation = "B-DNA" # Workaround for "Restore Defaults".
            pass

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

        self.duplexLengthSpinBox.setSingleStep(
                self.getDuplexRise(conformation) )

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

        @param inIndex: The new index.
        @type  inIndex: int
        """
        conformation  =  self._modelChoices[ inIndex ]

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

        self.conformationComboBox.clear() # Generates signal!

        if conformation == self._modeltype_PAM3:
            self.conformationComboBox.addItem("B-DNA")

        elif conformation == self._modeltype_PAM5:
            self.conformationComboBox.addItem("B-DNA")

        elif conformation == self._modeltype_Atomistic:
            self.conformationComboBox.addItem("B-DNA")
            self.conformationComboBox.addItem("Z-DNA")

        elif inIndex == -1:
            # Caused by clear(). This is tolerable for now. Mark 2007-05-24.
            pass

        else:
            msg = "Error - unknown model representation. Index = " + inIndex
            env.history.message(redmsg(msg))

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

    # GroupBox3 slots (and other methods) supporting the Strand Sequence groupbox.

    def getDuplexRise( self, inConformation ):
        """
        Return the 'rise' between base pairs of the
        specified DNA type (conformation).

        @param inConformation: The current conformation.
        @type  inConformation: int
        """
        return dnaDict[str(inConformation)]['DuplexRise']

    def synchronizeLengths( self ):
        """
        Guarantees the values of the duplex length and strand length
        spinboxes agree with the strand sequence (textedit).
        """
        self.updateStrandLength()
        self.updateDuplexLength()
        return

        # Added :jbirac 20070613:
    def duplexLengthChanged( self, inDuplexLength ):
        """
        Slot for the duplex length spinbox, called whenever the value of the
        Duplex Length spinbox changes.

        @param inDuplexLength: The duplex length.
        @type  inDuplexLength: float
        """

        conformation     =  self.conformationComboBox.currentText()
        duplexRise       =  self.getDuplexRise( conformation )
        newStrandLength  =  inDuplexLength / duplexRise + 0.5
        newStrandLength  =  int( newStrandLength )
        self.strandLengthChanged( newStrandLength )

    def updateDuplexLength( self ):    # Added :jbirac 20070615:
        """
        Update the Duplex Length spinbox; always the length of the
        strand sequence multiplied by the 'rise' of the duplex.  This
        method is called by slots of other controls (i.e., this itself
        is not a slot.)
        """
        conformation     =  self.conformationComboBox.currentText()
        newDuplexLength  =  self.getDuplexRise( conformation ) \
                          * self.getSequenceLength()

        self.disconnect( self.duplexLengthSpinBox,
                         SIGNAL("valueChanged(double)"),
                         self.duplexLengthChanged)

        self.duplexLengthSpinBox.setValue( newDuplexLength )

        self.connect( self.duplexLengthSpinBox,
                      SIGNAL("valueChanged(double)"),
                      self.duplexLengthChanged)

    # Renamed from length_changed :jbirac 20070613:
    def strandLengthChanged( self, inStrandLength ):
        """
        Slot for the Strand Length spin box, called whenever the value of the
        Strand Length spin box changes.

        @param inStrandLength: The number of bases in the strand sequence.
        @type  inStrandLength: int
        """

        theSequence   =  self.getPlainSequence()
        sequenceLen   =  len( theSequence )
        lengthChange  =  inStrandLength - self.getSequenceLength()

        # Preserve the cursor's position/selection
        cursor          =  self.sequenceTextEdit.textCursor()
        #cursorPosition  =  cursor.position()
        selectionStart  =  cursor.selectionStart()
        selectionEnd    =  cursor.selectionEnd()

        if inStrandLength < 0:
            return # Should never happen.

        if lengthChange < 0:
            # If length is less than the previous length,
            # simply truncate the current sequence.
            theSequence.chop( -lengthChange )

        elif lengthChange > 0:
            # If length has increased, add the correct number of base
            # letters to the current strand sequence.
            numNewBases  =  lengthChange

            # Get current base selected in combobox.
            chosenBase  =  'X' # Unassigned.

            basesToAdd  =  chosenBase * numNewBases
            theSequence.append( basesToAdd )

        else:
            env.history.message(
                orangemsg( "strandLengthChanged(): Length has not changed." ))

        self.setSequence( theSequence )

        return

    # Renamed from updateLength :jbirac 20070613:
    def updateStrandLength( self ):
        """
        Update the Strand Length spinbox; always the length of the strand
        sequence.
        """

        self.disconnect( self.strandLengthSpinBox,
                         SIGNAL("valueChanged(int)"),
                         self.strandLengthChanged )

        self.strandLengthSpinBox.setValue( self.getSequenceLength() )

        self.connect( self.strandLengthSpinBox,
                      SIGNAL("valueChanged(int)"),
                      self.strandLengthChanged )
        return

    def sequenceChanged( self ):
        """
        Slot for the Strand Sequence textedit widget.
        Assumes the sequence changed directly by user's keystroke in the
        textedit.  Other methods...
        """
        cursorPosition  =  self.getCursorPosition()
        theSequence     =  self.getPlainSequence()

        # Disconnect while we edit the sequence.
        self.disconnect( self.sequenceTextEdit,
                         SIGNAL("textChanged()"),
                         self.sequenceChanged )

        # How has the text changed?
        if theSequence.length() == 0:  # There is no sequence.
            self.updateStrandLength()
            self.updateDuplexLength()
        else:
            # Insert the sequence; it will be "stylized" by setSequence().
            self.setSequence( theSequence )

        # Reconnect to respond when the sequence is changed.
        self.connect( self.sequenceTextEdit,
                      SIGNAL("textChanged()"),
                      self.sequenceChanged )

        self.synchronizeLengths()
        return

    def getPlainSequence( self, inOmitSymbols = False ):
        """
        Returns a plain text QString (without HTML stylization)
        of the current sequence.  All characters are preserved (unless
        specified explicitly), including valid base letters, punctuation
        symbols, whitespace and invalid letters.

        @param inOmitSymbols: Omits characters listed in self.validSymbols.
        @type  inOmitSymbols: bool

        @return: The current DNA sequence in the PM.
        @rtype:  QString
        """
        outSequence  =  self.sequenceTextEdit.toPlainText()

        if inOmitSymbols:
            # This may look like a sloppy piece of code, but Qt's QRegExp
            # class makes it pretty tricky to remove all punctuation.
            theString  =  '[<>' \
                           + str( QRegExp.escape(self.validSymbols) ) \
                           + ']|-'

            outSequence.remove(QRegExp( theString ))

        return outSequence

    def stylizeSequence( self, inSequence ):
        """
        Converts a plain text string of a sequence (including optional
        symbols) to an HTML rich text string.

        @param inSequence: A DNA sequence.
        @type  inSequence: QString

        @return: The sequence.
        @rtype: QString
        """
        outSequence  =  str(inSequence)
        # Verify that all characters (bases) in the sequence are "valid".
        invalidSequence   =  False
        basePosition      =  0
        sequencePosition  =  0
        invalidStartTag   =  "<b><font color=black>"
        invalidEndTag     =  "</b>"
        previousChar      =  chr(1)  # Null character; may be revised.

        # Some characters must be substituted to preserve
        # whitespace and tags in HTML code.
        substituteDict    =  { ' ':'&#032;', '<':'&lt;', '>':'&gt;' }

        while basePosition < len(outSequence):

            theSeqChar  =  outSequence[basePosition]

            if ( theSeqChar in basesDict
                 or theSeqChar in self.validSymbols ):

                # Close any preceding invalid sequence segment.
                if invalidSequence == True:
                    outSequence      =  outSequence[:basePosition] \
                                      + invalidEndTag \
                                      + outSequence[basePosition:]
                    basePosition    +=  len(invalidEndTag)
                    invalidSequence  =  False

                # Color the valid characters.
                if theSeqChar != previousChar:
                    # We only need to insert 'color' tags in places where
                    # the adjacent characters are different.
                    if theSeqChar in basesDict:
                        theTag  =  '<font color=' \
                                + basesDict[ theSeqChar ]['Color'] \
                                + '>'
                    elif not previousChar in self.validSymbols:
                        # The character is a 'valid' symbol to be greyed
                        # out.  Only one 'color' tag is needed for a
                        # group of adjacent symbols.
                        theTag  =  '<font color=dimgrey>'
                    else:
                        theTag  =  ''

                    outSequence   =  outSequence[:basePosition] \
                                   + theTag + outSequence[basePosition:]

                    basePosition +=  len(theTag)

                    # Any <space> character must be substituted with an
                    # ASCII code tag because the HTML engine will collapse
                    # whitespace to a single <space> character; whitespace
                    # is truncated from the end of HTML by default.
                    # Also, many symbol characters must be substituted
                    # because they confuse the HTML syntax.
                    #if str( outSequence[basePosition] ) in substituteDict:
                    if outSequence[basePosition] in substituteDict:
                        #theTag = substituteDict[theSeqChar]
                        theTag = substituteDict[ outSequence[basePosition] ]
                        outSequence   =  outSequence[:basePosition] \
                                       + theTag \
                                       + outSequence[basePosition + 1:]
                        basePosition +=  len(theTag) - 1


            else:
                # The sequence character is invalid (but permissible).
                # Tags (e.g., <b> and </b>) must be inserted at both the
                # beginning and end of a segment of invalid characters.
                if invalidSequence == False:
                    outSequence      =  outSequence[:basePosition] \
                                      + invalidStartTag \
                                      + outSequence[basePosition:]
                    basePosition    +=  len(invalidStartTag)
                    invalidSequence  =  True

            basePosition +=  1
            previousChar  =  theSeqChar
            #basePosition +=  1

        # Specify that theSequence is definitely HTML format, because
        # Qt can get confused between HTML and Plain Text.
        outSequence  =  "<html>" + outSequence
        outSequence +=  "</html>"

        return outSequence

    def setSequence( self,
                     inSequence,
                     inStylize        =  True,
                     inRestoreCursor  =  True ):
        """
        Replace the current strand sequence with the new sequence text.

        @param inSequence: The new sequence.
        @type  inSequence: QString

        @param inStylize: If True, inSequence will be converted from a plain
                          text string (including optional symbols) to an HTML
                          rich text string.
        @type  inStylize: bool

        @param inRestoreCursor: Not implemented yet.
        @type  inRestoreCursor: bool

        @attention: Signals/slots must be managed before calling this method.
        The textChanged() signal will be sent to any connected widgets.
        """
        cursor          =  self.sequenceTextEdit.textCursor()
        selectionStart  =  cursor.selectionStart()
        selectionEnd    =  cursor.selectionEnd()

        if inStylize:
            inSequence  =  self.stylizeSequence( inSequence )

        self.sequenceTextEdit.insertHtml( inSequence )

        if inRestoreCursor:
            cursor.setPosition( min(selectionStart, self.getSequenceLength()),
                                QTextCursor.MoveAnchor )
            cursor.setPosition( min(selectionEnd, self.getSequenceLength()),
                                 QTextCursor.KeepAnchor )
            self.sequenceTextEdit.setTextCursor( cursor )
        return

    def getSequenceLength( self ):
        """
        Returns the number of characters in
        the strand sequence textedit widget.
        """
        theSequence  =  self.getPlainSequence( inOmitSymbols = True )
        outLength    =  theSequence.length()

        return outLength

    def getCursorPosition( self ):
        """
        Returns the cursor position in the
        strand sequence textedit widget.
        """
        cursor  =  self.sequenceTextEdit.textCursor()
        return cursor.position()

    def cursorPosChanged( self ):
        """
        Slot called when the cursor position changes.
        """
        cursor  =  self.sequenceTextEdit.textCursor()

        if 0:
            env.history.message( greenmsg( "cursorPosChanged: Selection ("
                                           + str(cursor.selectionStart())
                                           + " thru "
                                           + str(cursor.selectionEnd())+')' ) )
        return

    def actionsComboBoxChanged( self, inIndex ):
        """
        Slot for the Actions combobox. It is called whenever the
        Action choice is changed.

        @param inIndex: The index of the selected action choice.
        @type  inIndex: int
        """
        if inIndex == 0: # Very important.
            return

        actionName = str(self.actionsComboBox.currentText())
        self.actionsComboBox.setCurrentIndex( 0 ) # Generates signal!
        self.invokeAction( actionName )
        return

    def invokeAction( self, inActionName ):
        """
        Applies an action on the current sequence displayed in the PM.

        @param inActionName: The action name.
        @type  inActionName: str

        @return: The sequence after the action has been applied.
        @rtype:  str
        """
        sequence, allKnown = self._getSequence()
        outResult  =  ""

        if inActionName == self._action_Complement:
            outResult  =  getComplementSequence(sequence)
        elif inActionName == self._action_Reverse:
            outResult  =  getReverseSequence(sequence)
        elif inActionName == self._action_ConvertUnrecognized:
            outResult  =  replaceUnrecognized(sequence, replaceBase = 'N')
            self.setSequence( outResult )
        elif inActionName == self._action_RemoveUnrecognized:
            outResult  =  replaceUnrecognized(sequence, replaceBase = '')

        self.setSequence( outResult )

        return
Exemple #27
0
 def _loadGroupBox1(self, pmGroupBox):
     """
     Load widgets in group box.
     """
     
     self.numSimSpinBox = PM_SpinBox( pmGroupBox,
                                      labelColumn  = 0,
                                      label = "Number of simulations:",
                                      minimum = 1,
                                      maximum = 999,
                                      setAsDefault  =  False,
                                      spanWidth = False)
     
     self.ex1Checkbox = PM_CheckBox(pmGroupBox,
                                    text = "Expand rotamer library for chi1 angle",
                                    state = Qt.Unchecked,
                                    setAsDefault  =  False,
                                    widgetColumn  = 0,
                                    spanWidth = True)
     
     self.ex1aroCheckbox = PM_CheckBox(pmGroupBox,
                                       text = "Use large chi1 library for aromatic residues",
                                       state = Qt.Unchecked,
                                       setAsDefault  =  False,
                                       widgetColumn  = 0,
                                       spanWidth = True)
     
     self.ex2Checkbox = PM_CheckBox(pmGroupBox,
                                    text = "Expand rotamer library for chi2 angle",
                                    state = Qt.Unchecked,
                                    setAsDefault  =  False,
                                    widgetColumn  = 0,
                                    spanWidth = True)
     
     self.ex2aroOnlyCheckbox = PM_CheckBox(pmGroupBox,
                                           text = "Use large chi2 library only for aromatic residues",
                                           state = Qt.Unchecked,
                                           setAsDefault  =  False,
                                           widgetColumn  = 0,
                                           spanWidth = True)
                                           
     self.ex3Checkbox = PM_CheckBox(pmGroupBox,
                                  text = "Expand rotamer library for chi3 angle",
                                  state = Qt.Unchecked,
                                  setAsDefault  =  False,
                                  widgetColumn  = 0,
                                  spanWidth = True)
     
     self.ex4Checkbox = PM_CheckBox(pmGroupBox,
                                    text ="Expand rotamer library for chi4 angle",
                                    state = Qt.Unchecked,
                                    setAsDefault  =  False,
                                    widgetColumn  = 0,
                                    spanWidth = True)
     
     self.rotOptCheckbox = PM_CheckBox(pmGroupBox,
                                       text ="Optimize one-body energy",
                                       state = Qt.Unchecked,
                                       setAsDefault  =  False,
                                       widgetColumn  = 0,
                                       spanWidth = True)
     
     self.tryBothHisTautomersCheckbox = PM_CheckBox(pmGroupBox,
                                                    text ="Try both histidine tautomers",
                                                    state = Qt.Unchecked,
                                                    setAsDefault  =  False,
                                                    widgetColumn  = 0,
                                                    spanWidth = True)
     
     self.softRepDesignCheckbox = PM_CheckBox(pmGroupBox,
                                              text ="Use softer Lennard-Jones repulsive term",
                                              state = Qt.Unchecked,
                                              setAsDefault  =  False,
                                              widgetColumn  = 0,
                                              spanWidth = True)
     
     self.useElecRepCheckbox = PM_CheckBox(pmGroupBox,
                                           text ="Use electrostatic repulsion",
                                           state = Qt.Unchecked,
                                           setAsDefault  =  False,
                                           widgetColumn  = 0,
                                           spanWidth = True)
     
     self.norepackDisulfCheckbox = PM_CheckBox(pmGroupBox,
                                               text ="Don't re-pack disulphide bonds",
                                               state = Qt.Unchecked,
                                               setAsDefault  =  False,
                                               widgetColumn  = 0,
                                               spanWidth = True)
     
     
     self.otherCommandLineOptions = PM_TextEdit(pmGroupBox,
                                                label = "Command line options:",
                                                spanWidth = True)
     self.otherCommandLineOptions.setFixedHeight(80)
     
     self.okButton = PM_PushButton( pmGroupBox,
                      text         =  "Launch Rosetta",
                      setAsDefault  =  True,
                      spanWidth = True)
     return
    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 )
Exemple #29
0
    def _loadGroupBox1(self, pmGroupBox):
        """
        Load widgets in group box 1.
        """
        # Duplex Length
        self.duplexLengthSpinBox  =  \
            PM_DoubleSpinBox( pmGroupBox,
                              label         =  "Duplex Length: ",
                              value         =  0,
                              setAsDefault  =  False,
                              minimum       =  0,
                              maximum       =  34000,
                              singleStep    =  self.getDuplexRise("B-DNA"),
                              decimals      =  3,
                              suffix        =  ' Angstroms')

        self.connect(self.duplexLengthSpinBox, SIGNAL("valueChanged(double)"),
                     self.duplexLengthChanged)

        # Strand Length
        self.strandLengthSpinBox = \
            PM_SpinBox( pmGroupBox,
                        label         =  "Strand Length :",
                        value         =  0,
                        setAsDefault  =  False,
                        minimum       =  0,
                        maximum       =  10000,
                        suffix        =  ' bases' )

        self.connect(self.strandLengthSpinBox, SIGNAL("valueChanged(int)"),
                     self.strandLengthChanged)
        # New Base choices
        newBaseChoices = []
        for theBase in basesDict.keys():
            newBaseChoices  =  newBaseChoices \
                            + [ theBase + ' (' \
                            + basesDict[theBase]['Name'] + ')' ]

        try:
            defaultBaseChoice = basesDict.keys().index('N')
        except:
            defaultBaseChoice = 0

        # Strand Sequence
        self.sequenceTextEdit = \
            PM_TextEdit( pmGroupBox,
                         label      =  "",
                         spanWidth  =  True )

        self.sequenceTextEdit.setCursorWidth(2)
        self.sequenceTextEdit.setWordWrapMode(QTextOption.WrapAnywhere)

        self.connect(self.sequenceTextEdit, SIGNAL("textChanged()"),
                     self.sequenceChanged)

        self.connect(self.sequenceTextEdit, SIGNAL("cursorPositionChanged()"),
                     self.cursorPosChanged)

        # Actions
        self.actionsComboBox  = \
            PM_ComboBox( pmGroupBox,
                         label         =  '',
                         choices       =  self._actionChoices,
                         index         =  0,
                         setAsDefault  =  True,
                         spanWidth     =  True )

        # If SIGNAL("activate(const QString&)") is used, we get a TypeError.
        # This is a bug that needs Bruce. Using currentIndexChanged(int) as
        # a workaround, but there is still a bug when the "Reverse" action
        # is selected. Mark 2007-08-15
        self.connect(self.actionsComboBox, SIGNAL("currentIndexChanged(int)"),
                     self.actionsComboBoxChanged)
class DnaStrand_PropertyManager( DnaOrCnt_PropertyManager):
    """
    The DnaStrand_PropertyManager class provides a Property Manager
    for the DnaStrand_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         =  "DnaStrand Properties"
    iconPath      =  "ui/actions/Properties Manager/Strand.png"

    def __init__( self, command ):
        """
        Constructor for the Build DNA property manager.
        """

        self.sequenceEditor = None

        self._numberOfBases = 0
        self._conformation = 'B-DNA'
        self.dnaModel = 'PAM3'

        _superclass.__init__( self, command)

        self.showTopRowButtons( PM_DONE_BUTTON | \
                                PM_WHATS_THIS_BUTTON)
        return

    def _addGroupBoxes( self ):
        """
        Add group boxes to this PM.
        """

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

        #Sequence Editor. This is NOT a groupbox, needs cleanup. Doing it here
        #so that the sequence editor gets connected! Perhaps
        #superclass should define _loadAdditionalWidgets. -- Ninad2008-10-03
        self._loadSequenceEditor()
        return

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

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

        self.numberOfBasesSpinBox = \
            PM_SpinBox( pmGroupBox,
                        label         =  "Number of bases:",
                        value         =  self._numberOfBases,
                        setAsDefault  =  False,
                        minimum       =  2,
                        maximum       =  10000 )

        self.disableStructHighlightingCheckbox = \
            PM_CheckBox( pmGroupBox,
                         text         = "Don't highlight while editing DNA",
                         widgetColumn  = 0,
                         state        = Qt.Unchecked,
                         setAsDefault = True,
                         spanWidth = True
                         )

        #As of 2008-03-31, the properties such as number of bases will be
        #editable only by using the resize handles.
        self.numberOfBasesSpinBox.setEnabled(False)
        return

    def _loadSequenceEditor(self):
        """
        Temporary code  that shows the Sequence editor ..a doc widget docked
        at the bottom of the mainwindow. The implementation is going to change
        before 'rattleSnake' product release.
        As of 2007-11-20: This feature (sequence editor) is waiting
        for the ongoing dna model work to complete.
        """
        self.sequenceEditor = self.win.createDnaSequenceEditorIfNeeded()
        self.sequenceEditor.hide()
        return

    def _loadDisplayOptionsGroupBox(self, pmGroupBox):
        """
        Overrides superclass method.
        Also loads the color chooser widget.
        """
        self._loadColorChooser(pmGroupBox)
        _superclass._loadDisplayOptionsGroupBox(self, pmGroupBox)
        return

    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 ,
            dnaStrandEditCommand_showCursorTextCheckBox_prefs_key)
        return


    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 bases",
                   dnaStrandEditCommand_cursorTextCheckBox_numberOfBases_prefs_key),

                  ("Number of bases to be changed",
                   dnaStrandEditCommand_cursorTextCheckBox_changedBases_prefs_key)
                 ]

        return params


    def getParameters(self):
        name = self.nameLineEdit.text()
        numberOfBases = self.numberOfBasesSpinBox.value()
        dnaForm  = self._conformation
        dnaModel = self.dnaModel
        color = self._colorChooser.getColor()

        return (numberOfBases,
                dnaForm,
                dnaModel,
                color,
                name
                )

    def setParameters(self, params):
        """
        This is usually called when you are editing an existing structure.
        It also gets called when selecting a new strand (within this command).
        Some property manager ui elements then display the information
        obtained from the object being edited.
        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?
        """
        numberOfBases, \
            dnaForm, \
            dnaModel, \
            color, \
            name = params

        if numberOfBases is not None:
            self.numberOfBasesSpinBox.setValue(numberOfBases)
        if dnaForm is not None:
            self._conformation = dnaForm
        if dnaModel is not None:
            self.dnaModel = dnaModel

        if color is not None:
            self._colorChooser.setColor(color)

        if name:  # Minimal test. Should add a validator. --Mark 2008-12-16
            self.nameLineEdit.setText(name)

        # This gets called when we enter the command *and* when selecting a new
        # strand. In either case, we must update the sequence in the sequenece
        # editor. Fixes bug 2951. --Mark 2008-12-16
        if self.command and self.command.hasValidStructure():
            #print "setParameters(): loading sequence in sequence editor for ", name
            self.updateSequence(strand = self.command.struct)
        return

    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
        """
        #TODO: This is a temporary fix for a bug. When you invoke a temporary
        # mode Entering such a temporary mode keeps the signals of
        #PM from the previous mode connected (
        #but while exiting that temporary mode and reentering the
        #previous mode, it atucally reconnects the signal! This gives rise to
        #lots  of bugs. This needs more general fix in Temporary mode API.
        # -- Ninad 2008-01-09 (similar comment exists in MovePropertyManager.py

        if isConnect and self.isAlreadyConnected:
            if debug_flags.atom_debug:
                print_compact_stack("warning: attempt to connect widgets"\
                                    "in this PM that are already connected." )
            return

        if not isConnect and self.isAlreadyDisconnected:
            if debug_flags.atom_debug:
                print_compact_stack("warning: attempt to disconnect widgets"\
                                    "in this PM that are already disconnected.")
            return

        self.isAlreadyConnected = isConnect
        self.isAlreadyDisconnected = not isConnect

        if isConnect:
            change_connect = self.win.connect
        else:
            change_connect = self.win.disconnect


        if self.sequenceEditor:
            self.sequenceEditor.connect_or_disconnect_signals(isConnect)

        _superclass.connect_or_disconnect_signals(self, isConnect)


        change_connect(self.disableStructHighlightingCheckbox,
                       SIGNAL('stateChanged(int)'),
                       self.change_struct_highlightPolicy)

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

        change_connect(self.nameLineEdit,
                       SIGNAL("editingFinished()"),
                       self._nameChanged)
        return

    def _update_UI_do_updates(self):
        """
        @see: Command_PropertyManager. _update_UI_do_updates()
        @see: DnaStrand_EditCommand.command_update_UI()
        @see: DnaStrand_EditCommand.hasResizableStructure()
        """
        if not self.command.hasValidStructure():
            print "DnaStrand not a valid structure."
            self._pmGroupBox1.setEnabled(False)
            self._displayOptionsGroupBox.setEnabled(False)
            self.sequenceEditor.updateSequence(strand = " ")
            self.sequenceEditor.setEnabled(False)
            self.nameLineEdit.setText("")
            self.numberOfBasesSpinBox.setValue(0)
            return
        else:
            self._pmGroupBox1.setEnabled(True)
            self._displayOptionsGroupBox.setEnabled(True)
            self.sequenceEditor.setEnabled(True)

        isStructResizable, why_not = self.command.hasResizableStructure()
        if not isStructResizable:
            #disable all widgets
            if self._pmGroupBox1.isEnabled():
                self._pmGroupBox1.setEnabled(False)
                msg1 = ("Attention: ") % (self.command.struct.name)
                msg2 = redmsg("DnaStrand <b>%s</b> is not resizable. Reason: %s" % \
                              (self.command.struct.name, why_not))
                self.updateMessage(msg1 + msg2)
        else:
            if not self._pmGroupBox1.isEnabled():
                self._pmGroupBox1.setEnabled(True)
            msg1 = ("Editing <b>%s</b>. ") % (self.command.struct.name)
            msg2 = "Use resize handles to resize the strand. "\
                 "Use the <i>Sequence Editor</i> to edit the sequence."
            self.updateMessage(msg1 + msg2)
        return

    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: DnaSegment_EditCommand.setStructureName
        """
        if self.command is not None:
            name = str(self.nameLineEdit.text())
            self.command.setStructureName(name)

        if self.sequenceEditor:
            self.sequenceEditor.close()

        _superclass.close(self)
        return

    def updateSequence(self, strand = None):
        """
        Public method provided for convenience. If any callers outside of this
        command need to update the sequence in the sequence editor, they can simply
        do DnaStrand_ProprtyManager.updateSequence() rather than
        DnaStrand_ProprtyManager.sequenceEditor.updateSequence()
        @see: Ui_DnaSequenceEditor.updateSequence()
        """
        if self.sequenceEditor:
            self.sequenceEditor.updateSequence(strand = strand)
        return

    def change_struct_highlightPolicy(self,checkedState = False):
        """
        Change the 'highlight policy' of the structure being edited
        (i.e. self.command.struct) .
        @param checkedState: The checked state of the checkbox that says
                             'Don't highlight while editing DNA'. So, it
                             its True, the structure being edited won't get
                             highlighted.
        @see: DnaStrand.setHighlightPolicy for more comments
        """
        if self.command and self.command.hasValidStructure():
            highlight = not checkedState
            self.command.struct.setHighlightPolicy(highlight = highlight)
        return

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

    def _nameChanged(self): # Added by Mark. 2008-12-16
        """
        Slot for "Name" field. Changes the name of the strand if the user types
        in a new name.

        @warning: this lacks a validator. User can type in a name with invalid
                  characters.
        """
        if not self.command.hasValidStructure():
            return

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

        if not name: # Minimal test. Should add a validator. Ask Bruce for example validator code somewhere. --Mark 2008-12-16
            if self.command.hasValidStructure():
                self.nameLineEdit.setText(self.command.getStructureName())

            return

        self.command.setStructureName(name)

        self._update_UI_do_updates() # Updates the message box.

        return
Exemple #31
0
    def loadTestWidgets1(self, inPmGroupBox):
        """
        Adds widgets to <inPmGroupBox>.
        Used for testing purposes. Mark 2007-05-24
        """

        # I intend to create a special PropMgr to display all widget types
        # for testing purposes. For now, I just add them to the end of the
        # Graphene Sheet property manager. Mark 2007-05-22

        self.spinBox = \
            PM_SpinBox( inPmGroupBox,
                        label        = "Spinbox:",
                        value        = 5,
                        setAsDefault = True,
                        minimum      = 2,
                        maximum      = 10,
                        suffix       = ' things',
                        spanWidth    = True )

        self.doubleSpinBox = \
            PM_DoubleSpinBox( inPmGroupBox,
                              #label="Spanning DoubleSpinBox :",
                              label        = "", # No label
                              value        = 5.0,
                              setAsDefault = True,
                              minimum      = 1.0,
                              maximum      = 10.0,
                              singleStep   = 1.0,
                              decimals     = 1,
                              suffix       = ' Suffix',
                              spanWidth    = True )

        # Add a prefix example.
        self.doubleSpinBox.setPrefix("Prefix ")

        choices = [ "First", "Second", "Third (Default)", "Forth" ]

        self.comboBox1= \
            PM_ComboBox( inPmGroupBox,
                         label        = 'Choices: ',
                         choices      = choices,
                         index        = 2,
                         setAsDefault = True,
                         spanWidth    = False )

        self.comboBox2= \
            PM_ComboBox( inPmGroupBox,
                         label        = ' :Choices',
                         labelColumn  = 1,
                         choices      = choices,
                         index        = 2,
                         setAsDefault = True,
                         spanWidth    = False )

        self.comboBox3= \
            PM_ComboBox( inPmGroupBox,
                         label        = ' Choices (SpanWidth = True):',
                         labelColumn  = 1,
                         choices      = choices,
                         index        = 2,
                         setAsDefault = True,
                         spanWidth    = True )

        self.textEdit = \
            PM_TextEdit( inPmGroupBox,
                         label     = "TextEdit:",
                         spanWidth = False )


        self.spanTextEdit = \
            PM_TextEdit( inPmGroupBox,
                         label     = "",
                         spanWidth = True )


        self.groupBox = \
            PM_GroupBox( inPmGroupBox,
                         title          = "Group Box Title" )

        self.comboBox2= \
            PM_ComboBox( self.groupBox,
                         label        = "Choices:",
                         choices      = choices,
                         index        = 2,
                         setAsDefault = True,
                         spanWidth    = False )

        self.groupBox2 = \
            PM_GroupBox( inPmGroupBox,
                         title          = "Group Box Title" )

        self.comboBox3= \
            PM_ComboBox( self.groupBox2,
                         label        = "Choices:",
                         choices      = choices,
                         index        = 2,
                         setAsDefault = True,
                         spanWidth    = True )

        self.pushButton1 = \
            PM_PushButton( inPmGroupBox,
                           label = "",
                           text  = "PushButton1" )

        self.pushButton2 = \
            PM_PushButton( inPmGroupBox,
                           label     = "",
                           text      = "PushButton2",
                           spanWidth = True )
Exemple #32
0
class BreakStrands_PropertyManager(BreakOrJoinStrands_PropertyManager):
    """
    The BreakStrands_PropertyManager class provides a Property Manager 
    for the B{Break Strands} command on the flyout toolbar in the 
    Build > Dna 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
    """

    title = "Break Strands"
    pmName = title
    iconPath = "ui/actions/Command Toolbar/BuildDna/BreakStrand.png"

    def __init__(self, command):
        """
        Constructor for the property manager.
        """
        self._previous_model_changed_params = None
        #see self.connect_or_disconnect_signals for comment about this flag
        self.isAlreadyConnected = False
        self.isAlreadyDisconnected = False

        _superclass.__init__(self, command)

        msg = "Click on a strand's backbone bond to break a strand."
        self.updateMessage(msg)

    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
        """
        #TODO: This is a temporary fix for a bug. When you invoke a temporary mode
        # entering such a temporary mode keeps the signals of
        #PM from the previous mode connected (
        #but while exiting that temporary mode and reentering the
        #previous mode, it atucally reconnects the signal! This gives rise to
        #lots  of bugs. This needs more general fix in Temporary mode API.
        # -- Ninad 2008-01-09 (similar comment exists in MovePropertyManager.py

        if isConnect and self.isAlreadyConnected:
            if debug_flags.atom_debug:
                print_compact_stack("warning: attempt to connect widgets"\
                                    "in this PM that are already connected." )
            return

        if not isConnect and self.isAlreadyDisconnected:
            if debug_flags.atom_debug:
                print_compact_stack("warning: attempt to disconnect widgets"\
                                    "in this PM that are already disconnected.")
            return

        self.isAlreadyConnected = isConnect
        self.isAlreadyDisconnected = not isConnect

        if isConnect:
            change_connect = self.win.connect
        else:
            change_connect = self.win.disconnect

        _superclass.connect_or_disconnect_signals(self, isConnect=isConnect)

        if DEBUG_BREAK_OPTIONS_FEATURE:

            self._dnaStrandChooserGroupBox.connect_or_disconnect_signals(
                isConnect=isConnect)

            change_connect(self.breakAllStrandsButton, SIGNAL("clicked()"),
                           self.command.breakStrandBonds)

            change_connect(self.basesBeforeNextBreakSpinBox,
                           SIGNAL("valueChanged(int)"),
                           self.valueChanged_basesBeforeNextBreak)

    def _update_UI_do_updates(self):
        """
        Overrides superclass method. 
        @see: Command_PropertyManager._update_UI_do_updates()
        @see: DnaSegment_EditCommand.hasResizableStructure()
        @see: self._current_model_changed_params()
        """
        if not DEBUG_BREAK_OPTIONS_FEATURE:
            return

        currentParams = self._current_model_changed_params()

        #Optimization. Return from the model_changed method if the
        #params are the same.
        if same_vals(currentParams, self._previous_model_changed_params):
            return

        basesBeforeNextBreak = currentParams

        #update the self._previous_model_changed_params with this new param set.
        self._previous_model_changed_params = currentParams
        self.command.updateBreakSites()

    def _current_model_changed_params(self):
        """
        Returns a tuple containing the parameters that will be compared
        against the previously stored parameters. This provides a quick test
        to determine whether to do more things in self.model_changed()
        @see: self.model_changed() which calls this
        @see: self._previous_model_changed_params attr. 
        """
        params = None

        if self.command:
            params = (env.prefs[
                breakStrandsCommand_numberOfBasesBeforeNextBreak_prefs_key])

        return params

    def valueChanged_basesBeforeNextBreak(self, val):
        self.win.glpane.gl_update()

    def getNumberOfBasesBeforeNextBreak(self):
        return self.basesBeforeNextBreakSpinBox.value()

    def _addGroupBoxes(self):
        """
        Add the Property Manager group boxes.
        """
        self._breakOptionsGroupbox = PM_GroupBox(self, title="Break Options")
        self._loadBreakOptionsGroupbox(self._breakOptionsGroupbox)

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

        self._baseNumberLabelGroupBox = PM_GroupBox(self,
                                                    title="Base Number Labels")
        self._loadBaseNumberLabelGroupBox(self._baseNumberLabelGroupBox)

    def _loadBreakOptionsGroupbox(self, pmGroupBox):
        """
        Load widgets in this group box.
        """

        self.assignColorToBrokenDnaStrandsCheckBox = \
            PM_CheckBox(pmGroupBox ,
                        text         = 'Assign new color to broken strands',
                        widgetColumn = 0,
                        spanWidth = True)

        connect_checkbox_with_boolean_pref(
            self.assignColorToBrokenDnaStrandsCheckBox,
            assignColorToBrokenDnaStrands_prefs_key)



        self.basesBeforeNextBreakSpinBox = \
            PM_SpinBox( pmGroupBox,
                        label         =  "Break Every:",
                        value         =  3,
                        setAsDefault  =  False,
                        minimum       =  1,
                        maximum       =  10000,
                        suffix       = " bases"
                        )

        connect_spinBox_with_pref(
            self.basesBeforeNextBreakSpinBox,
            breakStrandsCommand_numberOfBasesBeforeNextBreak_prefs_key)

        self.breakAllStrandsButton = PM_PushButton(pmGroupBox,
                                                   label="",
                                                   text="do it")

        self._dnaStrandChooserGroupBox = PM_ObjectChooser(
            pmGroupBox,
            self.command,
            modelObjectType=self.win.assy.DnaStrand,
            title="Choose strands ")

        if not DEBUG_BREAK_OPTIONS_FEATURE:
            self._dnaStrandChooserGroupBox.hide()
            self.breakAllStrandsButton.hide()
            self.basesBeforeNextBreakSpinBox.hide()

    #Return varius prefs_keys for arrowhead display options ui elements =======
    def _prefs_key_arrowsOnThreePrimeEnds(self):
        """
        Return the appropriate KEY of the preference for whether to
        draw arrows on 3' strand ends of PAM DNA.
        """
        return breakStrandsCommand_arrowsOnThreePrimeEnds_prefs_key

    def _prefs_key_arrowsOnFivePrimeEnds(self):
        """
        Return the appropriate KEY of the preference for whether to
        draw arrows on 5' strand ends of PAM DNA.
        """
        return breakStrandsCommand_arrowsOnFivePrimeEnds_prefs_key

    def _prefs_key_useCustomColorForThreePrimeArrowheads(self):
        """
        Return the appropriate KEY of the preference for whether to use a
        custom color for 3' arrowheads (if they are drawn)
        or for 3' strand end atoms (if arrowheads are not drawn)
        """
        return breakStrandsCommand_useCustomColorForThreePrimeArrowheads_prefs_key

    def _prefs_key_useCustomColorForFivePrimeArrowheads(self):
        """
        Return the appropriate KEY of the preference for whether to use a
        custom color for 5' arrowheads (if they are drawn)
        or for 5' strand end atoms (if arrowheads are not drawn).        
        """
        return breakStrandsCommand_useCustomColorForFivePrimeArrowheads_prefs_key

    def _prefs_key_dnaStrandThreePrimeArrowheadsCustomColor(self):
        """
        Return the appropriate KEY of the preference for what custom color
        to use when drawing 3' arrowheads (if they are drawn)
        or 3' strand end atoms (if arrowheads are not drawn).
        """
        return breakStrandsCommand_dnaStrandThreePrimeArrowheadsCustomColor_prefs_key

    def _prefs_key_dnaStrandFivePrimeArrowheadsCustomColor(self):
        """
        Return the appropriate KEY of the preference for what custom color
        to use when drawing 5' arrowheads (if they are drawn)
        or 5' strand end atoms (if arrowheads are not drawn).
        """
        return breakStrandsCommand_dnaStrandFivePrimeArrowheadsCustomColor_prefs_key

    def _addWhatsThisText(self):
        """
        What's This text for widgets in the DNA Property Manager.  
        """
        pass

    def _addToolTipText(self):
        """
        Tool Tip text for widgets in the DNA Property Manager.  
        """
        pass
class BreakStrands_PropertyManager( BreakOrJoinStrands_PropertyManager):
    """
    The BreakStrands_PropertyManager class provides a Property Manager
    for the B{Break Strands} command on the flyout toolbar in the
    Build > Dna 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
    """

    title         =  "Break Strands"
    pmName        =  title
    iconPath      =  "ui/actions/Command Toolbar/BuildDna/BreakStrand.png"


    def __init__( self, command ):
        """
        Constructor for the property manager.
        """
        self._previous_model_changed_params = None
        #see self.connect_or_disconnect_signals for comment about this flag
        self.isAlreadyConnected = False
        self.isAlreadyDisconnected = False

        _superclass.__init__(self, command)

        msg = "Click on a strand's backbone bond to break a strand."
        self.updateMessage(msg)

    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
        """
        #TODO: This is a temporary fix for a bug. When you invoke a temporary mode
        # entering such a temporary mode keeps the signals of
        #PM from the previous mode connected (
        #but while exiting that temporary mode and reentering the
        #previous mode, it atucally reconnects the signal! This gives rise to
        #lots  of bugs. This needs more general fix in Temporary mode API.
        # -- Ninad 2008-01-09 (similar comment exists in MovePropertyManager.py

        if isConnect and self.isAlreadyConnected:
            if debug_flags.atom_debug:
                print_compact_stack("warning: attempt to connect widgets"\
                                    "in this PM that are already connected." )
            return

        if not isConnect and self.isAlreadyDisconnected:
            if debug_flags.atom_debug:
                print_compact_stack("warning: attempt to disconnect widgets"\
                                    "in this PM that are already disconnected.")
            return

        self.isAlreadyConnected = isConnect
        self.isAlreadyDisconnected = not isConnect

        if isConnect:
            change_connect = self.win.connect
        else:
            change_connect = self.win.disconnect

        _superclass.connect_or_disconnect_signals(self, isConnect = isConnect)


        if DEBUG_BREAK_OPTIONS_FEATURE:

            self._dnaStrandChooserGroupBox.connect_or_disconnect_signals(isConnect = isConnect)

            change_connect(self.breakAllStrandsButton,
                          SIGNAL("clicked()"),
                          self.command.breakStrandBonds)

            change_connect(self.basesBeforeNextBreakSpinBox,
                           SIGNAL("valueChanged(int)"),
                           self.valueChanged_basesBeforeNextBreak)


    def _update_UI_do_updates(self):
        """
        Overrides superclass method.
        @see: Command_PropertyManager._update_UI_do_updates()
        @see: DnaSegment_EditCommand.hasResizableStructure()
        @see: self._current_model_changed_params()
        """
        if not DEBUG_BREAK_OPTIONS_FEATURE:
            return



        currentParams = self._current_model_changed_params()

        #Optimization. Return from the model_changed method if the
        #params are the same.
        if same_vals(currentParams, self._previous_model_changed_params):
            return

        basesBeforeNextBreak = currentParams

        #update the self._previous_model_changed_params with this new param set.
        self._previous_model_changed_params = currentParams
        self.command.updateBreakSites()

    def _current_model_changed_params(self):
        """
        Returns a tuple containing the parameters that will be compared
        against the previously stored parameters. This provides a quick test
        to determine whether to do more things in self.model_changed()
        @see: self.model_changed() which calls this
        @see: self._previous_model_changed_params attr.
        """
        params = None

        if self.command:
            params = (env.prefs[breakStrandsCommand_numberOfBasesBeforeNextBreak_prefs_key])

        return params

    def valueChanged_basesBeforeNextBreak(self, val):
        self.win.glpane.gl_update()

    def getNumberOfBasesBeforeNextBreak(self):
        return self.basesBeforeNextBreakSpinBox.value()

    def _addGroupBoxes( self ):
        """
        Add the Property Manager group boxes.
        """
        self._breakOptionsGroupbox = PM_GroupBox( self, title = "Break Options" )
        self._loadBreakOptionsGroupbox( self._breakOptionsGroupbox )


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

        self._baseNumberLabelGroupBox = PM_GroupBox( self, title = "Base Number Labels" )
        self._loadBaseNumberLabelGroupBox(self._baseNumberLabelGroupBox)


    def _loadBreakOptionsGroupbox(self, pmGroupBox):
        """
        Load widgets in this group box.
        """

        self.assignColorToBrokenDnaStrandsCheckBox = \
            PM_CheckBox(pmGroupBox ,
                        text         = 'Assign new color to broken strands',
                        widgetColumn = 0,
                        spanWidth = True)

        connect_checkbox_with_boolean_pref(
            self.assignColorToBrokenDnaStrandsCheckBox,
            assignColorToBrokenDnaStrands_prefs_key )



        self.basesBeforeNextBreakSpinBox = \
            PM_SpinBox( pmGroupBox,
                        label         =  "Break Every:",
                        value         =  3,
                        setAsDefault  =  False,
                        minimum       =  1,
                        maximum       =  10000,
                        suffix       = " bases"
                        )

        connect_spinBox_with_pref(
            self.basesBeforeNextBreakSpinBox,
            breakStrandsCommand_numberOfBasesBeforeNextBreak_prefs_key)

        self.breakAllStrandsButton = PM_PushButton(
            pmGroupBox,
            label = "",
            text  = "do it" )


        self._dnaStrandChooserGroupBox = PM_ObjectChooser(
            pmGroupBox,
            self.command,
            modelObjectType = self.win.assy.DnaStrand,
            title = "Choose strands " )

        if not DEBUG_BREAK_OPTIONS_FEATURE:
            self._dnaStrandChooserGroupBox.hide()
            self.breakAllStrandsButton.hide()
            self.basesBeforeNextBreakSpinBox.hide()



    #Return varius prefs_keys for arrowhead display options ui elements =======
    def _prefs_key_arrowsOnThreePrimeEnds(self):
        """
        Return the appropriate KEY of the preference for whether to
        draw arrows on 3' strand ends of PAM DNA.
        """
        return breakStrandsCommand_arrowsOnThreePrimeEnds_prefs_key

    def _prefs_key_arrowsOnFivePrimeEnds(self):
        """
        Return the appropriate KEY of the preference for whether to
        draw arrows on 5' strand ends of PAM DNA.
        """
        return breakStrandsCommand_arrowsOnFivePrimeEnds_prefs_key

    def _prefs_key_useCustomColorForThreePrimeArrowheads(self):
        """
        Return the appropriate KEY of the preference for whether to use a
        custom color for 3' arrowheads (if they are drawn)
        or for 3' strand end atoms (if arrowheads are not drawn)
        """
        return breakStrandsCommand_useCustomColorForThreePrimeArrowheads_prefs_key

    def _prefs_key_useCustomColorForFivePrimeArrowheads(self):
        """
        Return the appropriate KEY of the preference for whether to use a
        custom color for 5' arrowheads (if they are drawn)
        or for 5' strand end atoms (if arrowheads are not drawn).
        """
        return breakStrandsCommand_useCustomColorForFivePrimeArrowheads_prefs_key

    def _prefs_key_dnaStrandThreePrimeArrowheadsCustomColor(self):
        """
        Return the appropriate KEY of the preference for what custom color
        to use when drawing 3' arrowheads (if they are drawn)
        or 3' strand end atoms (if arrowheads are not drawn).
        """
        return breakStrandsCommand_dnaStrandThreePrimeArrowheadsCustomColor_prefs_key

    def _prefs_key_dnaStrandFivePrimeArrowheadsCustomColor(self):
        """
        Return the appropriate KEY of the preference for what custom color
        to use when drawing 5' arrowheads (if they are drawn)
        or 5' strand end atoms (if arrowheads are not drawn).
        """
        return breakStrandsCommand_dnaStrandFivePrimeArrowheadsCustomColor_prefs_key


    def _addWhatsThisText( self ):
        """
        What's This text for widgets in the DNA Property Manager.
        """
        pass

    def _addToolTipText(self):
        """
        Tool Tip text for widgets in the DNA Property Manager.
        """
        pass
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)
    def _loadGroupBox1(self, pmGroupBox):
        """
        Load widgets in group box.
        """

        self.numSimSpinBox = PM_SpinBox(pmGroupBox,
                                        labelColumn=0,
                                        label="Number of trials:",
                                        minimum=1000,
                                        maximum=1000000,
                                        singleStep=1000,
                                        setAsDefault=False,
                                        spanWidth=False)

        self.ex1Checkbox = PM_CheckBox(
            pmGroupBox,
            text="Expand rotamer library for chi1 angle",
            state=Qt.Unchecked,
            setAsDefault=False,
            widgetColumn=0,
            spanWidth=True)

        self.ex1aroCheckbox = PM_CheckBox(
            pmGroupBox,
            text="Use large chi1 library for aromatic residues",
            state=Qt.Unchecked,
            setAsDefault=False,
            widgetColumn=0,
            spanWidth=True)

        self.ex2Checkbox = PM_CheckBox(
            pmGroupBox,
            text="Expand rotamer library for chi2 angle",
            state=Qt.Unchecked,
            setAsDefault=False,
            widgetColumn=0,
            spanWidth=True)

        self.ex2aroOnlyCheckbox = PM_CheckBox(
            pmGroupBox,
            text="Use large chi2 library only for aromatic residues",
            state=Qt.Unchecked,
            setAsDefault=False,
            widgetColumn=0,
            spanWidth=True)

        self.ex3Checkbox = PM_CheckBox(
            pmGroupBox,
            text="Expand rotamer library for chi3 angle",
            state=Qt.Unchecked,
            setAsDefault=False,
            widgetColumn=0,
            spanWidth=True)

        self.ex4Checkbox = PM_CheckBox(
            pmGroupBox,
            text="Expand rotamer library for chi4 angle",
            state=Qt.Unchecked,
            setAsDefault=False,
            widgetColumn=0,
            spanWidth=True)

        self.rotOptCheckbox = PM_CheckBox(pmGroupBox,
                                          text="Optimize one-body energy",
                                          state=Qt.Unchecked,
                                          setAsDefault=False,
                                          widgetColumn=0,
                                          spanWidth=True)

        self.tryBothHisTautomersCheckbox = PM_CheckBox(
            pmGroupBox,
            text="Try both histidine tautomers",
            state=Qt.Unchecked,
            setAsDefault=False,
            widgetColumn=0,
            spanWidth=True)

        self.softRepDesignCheckbox = PM_CheckBox(
            pmGroupBox,
            text="Use softer Lennard-Jones repulsive term",
            state=Qt.Unchecked,
            setAsDefault=False,
            widgetColumn=0,
            spanWidth=True)

        self.useElecRepCheckbox = PM_CheckBox(
            pmGroupBox,
            text="Use electrostatic repulsion",
            state=Qt.Unchecked,
            setAsDefault=False,
            widgetColumn=0,
            spanWidth=True)

        self.norepackDisulfCheckbox = PM_CheckBox(
            pmGroupBox,
            text="Don't re-pack disulphide bonds",
            state=Qt.Unchecked,
            setAsDefault=False,
            widgetColumn=0,
            spanWidth=True)

        self.otherCommandLineOptions = PM_TextEdit(
            pmGroupBox, label="Command line options:", spanWidth=True)
        self.otherCommandLineOptions.setFixedHeight(80)

        self.okButton = PM_PushButton(pmGroupBox,
                                      text="Run Rosetta",
                                      setAsDefault=True,
                                      spanWidth=True)
        return
Exemple #36
0
class DnaGeneratorPropertyManager(PM_Dialog, DebugMenuMixin):
    """
    The DnaGeneratorPropertyManager class provides a Property Manager 
    for the "Build > Atoms" 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
    
    @ivar validSymbols: Miscellaneous symbols that may appear in the sequence 
                        (but are ignored). The hyphen '-' is a special case
                        that must be dealt with individually; it is not 
                        included because it can confuse regular expressions.
    @type validSymbols: QString
    """

    title = "DNA"
    pmName = title
    iconPath = "ui/actions/Tools/Build Structures/DNA.png"
    validSymbols = QString(' <>~!@#%&_+`=$*()[]{}|^\'"\\.;:,/?')

    # The following class variables guarantee the UI's menu items
    # are synchronized with their action code.  The arrays should
    # not be changed, unless an item is removed or inserted.
    # Changes should be made via only the _action... variables.
    # e.g., Change _action_Complement from "Complement"
    #       to "Complement Sequences". The menu item will
    #       change and its related code will need no update.
    _action_Complement = "Complement"
    _action_Reverse = "Reverse"
    _action_RemoveUnrecognized = 'Remove unrecognized letters'
    _action_ConvertUnrecognized = 'Convert unrecognized letters to "N"'

    _actionChoices = [
        "Action", "---", _action_Complement, _action_Reverse,
        _action_RemoveUnrecognized, _action_ConvertUnrecognized
    ]

    _modeltype_PAM3 = "PAM3"
    _modeltype_PAM5 = "PAM5"
    _modeltype_Atomistic = "Atomistic"  # deprecated
    _modelChoices = [_modeltype_PAM3, _modeltype_PAM5]

    def __init__(self):
        """
        Constructor for the DNA Generator property manager.
        """
        PM_Dialog.__init__(self, self.pmName, self.iconPath, self.title)
        DebugMenuMixin._init1(self)

        msg = "Edit the DNA parameters and select <b>Preview</b> to \
        preview the structure. Click <b>Done</b> to insert it into \
        the model."

        # This causes the "Message" box to be displayed as well.
        # setAsDefault=True causes this message to be reset whenever
        # this PM is (re)displayed via show(). Mark 2007-06-01.
        self.MessageGroupBox.insertHtmlMessage(msg, setAsDefault=True)

    def _addGroupBoxes(self):
        """
        Add the DNA Property Manager group boxes.
        """
        self._pmGroupBox1 = PM_GroupBox(self, title="Strand Sequence")
        self._loadGroupBox1(self._pmGroupBox1)

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

        self._pmGroupBox3 = PM_GroupBox(self, title="Endpoints")
        self._loadGroupBox3(self._pmGroupBox3)

    def _loadGroupBox1(self, pmGroupBox):
        """
        Load widgets in group box 1.
        """
        # Duplex Length
        self.duplexLengthSpinBox  =  \
            PM_DoubleSpinBox( pmGroupBox,
                              label         =  "Duplex Length: ",
                              value         =  0,
                              setAsDefault  =  False,
                              minimum       =  0,
                              maximum       =  34000,
                              singleStep    =  self.getDuplexRise("B-DNA"),
                              decimals      =  3,
                              suffix        =  ' Angstroms')

        self.connect(self.duplexLengthSpinBox, SIGNAL("valueChanged(double)"),
                     self.duplexLengthChanged)

        # Strand Length
        self.strandLengthSpinBox = \
            PM_SpinBox( pmGroupBox,
                        label         =  "Strand Length :",
                        value         =  0,
                        setAsDefault  =  False,
                        minimum       =  0,
                        maximum       =  10000,
                        suffix        =  ' bases' )

        self.connect(self.strandLengthSpinBox, SIGNAL("valueChanged(int)"),
                     self.strandLengthChanged)
        # New Base choices
        newBaseChoices = []
        for theBase in basesDict.keys():
            newBaseChoices  =  newBaseChoices \
                            + [ theBase + ' (' \
                            + basesDict[theBase]['Name'] + ')' ]

        try:
            defaultBaseChoice = basesDict.keys().index('N')
        except:
            defaultBaseChoice = 0

        # Strand Sequence
        self.sequenceTextEdit = \
            PM_TextEdit( pmGroupBox,
                         label      =  "",
                         spanWidth  =  True )

        self.sequenceTextEdit.setCursorWidth(2)
        self.sequenceTextEdit.setWordWrapMode(QTextOption.WrapAnywhere)

        self.connect(self.sequenceTextEdit, SIGNAL("textChanged()"),
                     self.sequenceChanged)

        self.connect(self.sequenceTextEdit, SIGNAL("cursorPositionChanged()"),
                     self.cursorPosChanged)

        # Actions
        self.actionsComboBox  = \
            PM_ComboBox( pmGroupBox,
                         label         =  '',
                         choices       =  self._actionChoices,
                         index         =  0,
                         setAsDefault  =  True,
                         spanWidth     =  True )

        # If SIGNAL("activate(const QString&)") is used, we get a TypeError.
        # This is a bug that needs Bruce. Using currentIndexChanged(int) as
        # a workaround, but there is still a bug when the "Reverse" action
        # is selected. Mark 2007-08-15
        self.connect(self.actionsComboBox, SIGNAL("currentIndexChanged(int)"),
                     self.actionsComboBoxChanged)

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

        self.modelComboBox  = \
            PM_ComboBox( pmGroupBox,
                         label         =  "Model :",
                         choices       =  self._modelChoices,
                         setAsDefault  =  True)

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

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

        self.basesPerTurnComboBox= \
            PM_ComboBox( pmGroupBox,
                         label         =  "Bases Per Turn :",
                         choices       =  ["10.0", "10.5", "10.67"],
                         setAsDefault  =  True)

        # I may decide to reintroduce "base-pair chunks" at a later time.
        # Please talk to me if you have a strong feeling about including
        # this. Mark 2007-08-19.
        createChoices        =  ["Strand chunks", \
                                 "Single chunk" ]
        #@ "Base-pair chunks"]

        self.createComboBox  = \
            PM_ComboBox( pmGroupBox,
                         label         =  "Create :",
                         choices       =  createChoices,
                         index         =  0,
                         setAsDefault  =  True,
                         spanWidth     =  False )

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

        self._endPoint1GroupBox = PM_GroupBox(pmGroupBox, title="Endpoint1")
        self._endPoint2GroupBox = PM_GroupBox(pmGroupBox, title="Endpoint2")

        # Point 1
        self.x1SpinBox  =  \
            PM_DoubleSpinBox( self._endPoint1GroupBox,
                              label         =  \
                              "ui/actions/Properties Manager/X_Coordinate.png",
                              value         =  0,
                              setAsDefault  =  True,
                              minimum       =  -100.0,
                              maximum       =   100.0,
                              decimals      =  3,
                              suffix        =  ' Angstroms')

        self.y1SpinBox  =  \
            PM_DoubleSpinBox( self._endPoint1GroupBox,
                              label         =  \
                              "ui/actions/Properties Manager/Y_Coordinate.png",
                              value         =  0,
                              setAsDefault  =  True,
                              minimum       =  -100.0,
                              maximum       =   100.0,
                              decimals      =  3,
                              suffix        =  ' Angstroms')

        self.z1SpinBox  =  \
            PM_DoubleSpinBox( self._endPoint1GroupBox,
                              label         =  \
                              "ui/actions/Properties Manager/Z_Coordinate.png",
                              value         =  0,
                              setAsDefault  =  True,
                              minimum       =  -100.0,
                              maximum       =   100.0,
                              decimals      =  3,
                              suffix        =  ' Angstroms')

        # Point 2
        self.x2SpinBox  =  \
            PM_DoubleSpinBox( self._endPoint2GroupBox,
                              label         =  \
                              "ui/actions/Properties Manager/X_Coordinate.png",
                              value         =  10.0,
                              setAsDefault  =  True,
                              minimum       =  -100.0,
                              maximum       =   100.0,
                              decimals      =  3,
                              suffix        =  ' Angstroms')

        self.y2SpinBox  =  \
            PM_DoubleSpinBox( self._endPoint2GroupBox,
                              label         =  \
                              "ui/actions/Properties Manager/Y_Coordinate.png",
                              value         =  0,
                              setAsDefault  =  True,
                              minimum       =  -100.0,
                              maximum       =   100.0,
                              decimals      =  3,
                              suffix        =  ' Angstroms')

        self.z2SpinBox  =  \
            PM_DoubleSpinBox( self._endPoint2GroupBox,
                              label         =  \
                              "ui/actions/Properties Manager/Z_Coordinate.png",
                              value         =  0,
                              setAsDefault  =  True,
                              minimum       =  -100.0,
                              maximum       =   100.0,
                              decimals      =  3,
                              suffix        =  ' Angstroms')

    def _addWhatsThisText(self):
        """
        What's This text for some of the widgets in the 
        DNA Property Manager.  
        
        @note: Many PM widgets are still missing their "What's This" text.
        """

        self.conformationComboBox.setWhatsThis("""<b>Conformation</b>
        <p>There are three DNA geometries, A-DNA, B-DNA,
        and Z-DNA. Only B-DNA and Z-DNA are currently supported.</p>""")

        self.sequenceTextEdit.setWhatsThis("""<b>Strand Sequence</b>
        <p>Type in the strand sequence you want to generate here (5' => 3')<br>
        <br>
        Recognized base letters:<br>
        <br>
        A = Adenosine<br>
        C = Cytosine<br> 
        G = Guanosine<br>
        T = Thymidine<br>
        N = aNy base<br>
        X = Unassigned<br>
        <br>
        Other base letters currently recognized:<br>
        <br>
        B = C,G, or T<br>
        D = A,G, or T<br>
        H = A,C, or T<br>
        V = A,C, or G<br>
        R = A or G (puRine)<br>
        Y = C or T (pYrimidine)<br>
        K = G or T (Keto)<br>
        M = A or C (aMino)<br>
        S = G or C (Strong -3H bonds)<br>
        W = A or T (Weak - 2H bonds)<br>
        </p>""")

        self.actionsComboBox.setWhatsThis("""<b>Action</b>
        <p>Select an action to perform on the sequence.</p>""")

    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
        """
        self.basesPerTurnComboBox.clear()
        conformation = self.conformationComboBox.currentText()

        if conformation == "B-DNA":
            self.basesPerTurnComboBox.insertItem(0, "10.0")
            self.basesPerTurnComboBox.insertItem(1, "10.5")
            self.basesPerTurnComboBox.insertItem(2, "10.67")

            #10.5 is the default value for Bases per turn.
            #So set the current index to 1
            self.basesPerTurnComboBox.setCurrentIndex(1)

        elif conformation == "Z-DNA":
            self.basesPerTurnComboBox.insertItem(0, "12.0")

        elif inIndex == -1:
            # Caused by clear(). This is tolerable for now. Mark 2007-05-24.
            conformation = "B-DNA"  # Workaround for "Restore Defaults".
            pass

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

        self.duplexLengthSpinBox.setSingleStep(
            self.getDuplexRise(conformation))

    def modelComboBoxChanged(self, inIndex):
        """
        Slot for the Model combobox. It is called whenever the
        Model choice is changed.
        
        @param inIndex: The new index.
        @type  inIndex: int
        """
        conformation = self._modelChoices[inIndex]

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

        self.conformationComboBox.clear()  # Generates signal!

        if conformation == self._modeltype_PAM3:
            self.conformationComboBox.addItem("B-DNA")

        elif conformation == self._modeltype_PAM5:
            self.conformationComboBox.addItem("B-DNA")

        elif conformation == self._modeltype_Atomistic:
            self.conformationComboBox.addItem("B-DNA")
            self.conformationComboBox.addItem("Z-DNA")

        elif inIndex == -1:
            # Caused by clear(). This is tolerable for now. Mark 2007-05-24.
            pass

        else:
            msg = "Error - unknown model representation. Index = " + inIndex
            env.history.message(redmsg(msg))

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

    # GroupBox3 slots (and other methods) supporting the Strand Sequence groupbox.

    def getDuplexRise(self, inConformation):
        """
        Return the 'rise' between base pairs of the 
        specified DNA type (conformation).
        
        @param inConformation: The current conformation.
        @type  inConformation: int
        """
        return dnaDict[str(inConformation)]['DuplexRise']

    def synchronizeLengths(self):
        """
        Guarantees the values of the duplex length and strand length 
        spinboxes agree with the strand sequence (textedit).
        """
        self.updateStrandLength()
        self.updateDuplexLength()
        return

        # Added :jbirac 20070613:
    def duplexLengthChanged(self, inDuplexLength):
        """
        Slot for the duplex length spinbox, called whenever the value of the 
        Duplex Length spinbox changes.
        
        @param inDuplexLength: The duplex length.
        @type  inDuplexLength: float
        """

        conformation = self.conformationComboBox.currentText()
        duplexRise = self.getDuplexRise(conformation)
        newStrandLength = inDuplexLength / duplexRise + 0.5
        newStrandLength = int(newStrandLength)
        self.strandLengthChanged(newStrandLength)

    def updateDuplexLength(self):  # Added :jbirac 20070615:
        """
        Update the Duplex Length spinbox; always the length of the 
        strand sequence multiplied by the 'rise' of the duplex.  This
        method is called by slots of other controls (i.e., this itself
        is not a slot.)
        """
        conformation = self.conformationComboBox.currentText()
        newDuplexLength  =  self.getDuplexRise( conformation ) \
                          * self.getSequenceLength()

        self.disconnect(self.duplexLengthSpinBox,
                        SIGNAL("valueChanged(double)"),
                        self.duplexLengthChanged)

        self.duplexLengthSpinBox.setValue(newDuplexLength)

        self.connect(self.duplexLengthSpinBox, SIGNAL("valueChanged(double)"),
                     self.duplexLengthChanged)

    # Renamed from length_changed :jbirac 20070613:
    def strandLengthChanged(self, inStrandLength):
        """
        Slot for the Strand Length spin box, called whenever the value of the 
        Strand Length spin box changes.
        
        @param inStrandLength: The number of bases in the strand sequence.
        @type  inStrandLength: int
        """

        theSequence = self.getPlainSequence()
        sequenceLen = len(theSequence)
        lengthChange = inStrandLength - self.getSequenceLength()

        # Preserve the cursor's position/selection
        cursor = self.sequenceTextEdit.textCursor()
        #cursorPosition  =  cursor.position()
        selectionStart = cursor.selectionStart()
        selectionEnd = cursor.selectionEnd()

        if inStrandLength < 0:
            return  # Should never happen.

        if lengthChange < 0:
            # If length is less than the previous length,
            # simply truncate the current sequence.
            theSequence.chop(-lengthChange)

        elif lengthChange > 0:
            # If length has increased, add the correct number of base
            # letters to the current strand sequence.
            numNewBases = lengthChange

            # Get current base selected in combobox.
            chosenBase = 'X'  # Unassigned.

            basesToAdd = chosenBase * numNewBases
            theSequence.append(basesToAdd)

        else:
            env.history.message(
                orangemsg("strandLengthChanged(): Length has not changed."))

        self.setSequence(theSequence)

        return

    # Renamed from updateLength :jbirac 20070613:
    def updateStrandLength(self):
        """
        Update the Strand Length spinbox; always the length of the strand 
        sequence.
        """

        self.disconnect(self.strandLengthSpinBox, SIGNAL("valueChanged(int)"),
                        self.strandLengthChanged)

        self.strandLengthSpinBox.setValue(self.getSequenceLength())

        self.connect(self.strandLengthSpinBox, SIGNAL("valueChanged(int)"),
                     self.strandLengthChanged)
        return

    def sequenceChanged(self):
        """
        Slot for the Strand Sequence textedit widget.
        Assumes the sequence changed directly by user's keystroke in the 
        textedit.  Other methods...
        """
        cursorPosition = self.getCursorPosition()
        theSequence = self.getPlainSequence()

        # Disconnect while we edit the sequence.
        self.disconnect(self.sequenceTextEdit, SIGNAL("textChanged()"),
                        self.sequenceChanged)

        # How has the text changed?
        if theSequence.length() == 0:  # There is no sequence.
            self.updateStrandLength()
            self.updateDuplexLength()
        else:
            # Insert the sequence; it will be "stylized" by setSequence().
            self.setSequence(theSequence)

        # Reconnect to respond when the sequence is changed.
        self.connect(self.sequenceTextEdit, SIGNAL("textChanged()"),
                     self.sequenceChanged)

        self.synchronizeLengths()
        return

    def getPlainSequence(self, inOmitSymbols=False):
        """
        Returns a plain text QString (without HTML stylization)
        of the current sequence.  All characters are preserved (unless
        specified explicitly), including valid base letters, punctuation 
        symbols, whitespace and invalid letters.
        
        @param inOmitSymbols: Omits characters listed in self.validSymbols.
        @type  inOmitSymbols: bool
        
        @return: The current DNA sequence in the PM.
        @rtype:  QString
        """
        outSequence = self.sequenceTextEdit.toPlainText()

        if inOmitSymbols:
            # This may look like a sloppy piece of code, but Qt's QRegExp
            # class makes it pretty tricky to remove all punctuation.
            theString  =  '[<>' \
                           + str( QRegExp.escape(self.validSymbols) ) \
                           + ']|-'

            outSequence.remove(QRegExp(theString))

        return outSequence

    def stylizeSequence(self, inSequence):
        """
        Converts a plain text string of a sequence (including optional 
        symbols) to an HTML rich text string.
        
        @param inSequence: A DNA sequence.
        @type  inSequence: QString
        
        @return: The sequence.
        @rtype: QString
        """
        outSequence = str(inSequence)
        # Verify that all characters (bases) in the sequence are "valid".
        invalidSequence = False
        basePosition = 0
        sequencePosition = 0
        invalidStartTag = "<b><font color=black>"
        invalidEndTag = "</b>"
        previousChar = chr(1)  # Null character; may be revised.

        # Some characters must be substituted to preserve
        # whitespace and tags in HTML code.
        substituteDict = {' ': '&#032;', '<': '&lt;', '>': '&gt;'}

        while basePosition < len(outSequence):

            theSeqChar = outSequence[basePosition]

            if (theSeqChar in basesDict or theSeqChar in self.validSymbols):

                # Close any preceding invalid sequence segment.
                if invalidSequence == True:
                    outSequence      =  outSequence[:basePosition] \
                                      + invalidEndTag \
                                      + outSequence[basePosition:]
                    basePosition += len(invalidEndTag)
                    invalidSequence = False

                # Color the valid characters.
                if theSeqChar != previousChar:
                    # We only need to insert 'color' tags in places where
                    # the adjacent characters are different.
                    if theSeqChar in basesDict:
                        theTag  =  '<font color=' \
                                + basesDict[ theSeqChar ]['Color'] \
                                + '>'
                    elif not previousChar in self.validSymbols:
                        # The character is a 'valid' symbol to be greyed
                        # out.  Only one 'color' tag is needed for a
                        # group of adjacent symbols.
                        theTag = '<font color=dimgrey>'
                    else:
                        theTag = ''

                    outSequence   =  outSequence[:basePosition] \
                                   + theTag + outSequence[basePosition:]

                    basePosition += len(theTag)

                    # Any <space> character must be substituted with an
                    # ASCII code tag because the HTML engine will collapse
                    # whitespace to a single <space> character; whitespace
                    # is truncated from the end of HTML by default.
                    # Also, many symbol characters must be substituted
                    # because they confuse the HTML syntax.
                    #if str( outSequence[basePosition] ) in substituteDict:
                    if outSequence[basePosition] in substituteDict:
                        #theTag = substituteDict[theSeqChar]
                        theTag = substituteDict[outSequence[basePosition]]
                        outSequence   =  outSequence[:basePosition] \
                                       + theTag \
                                       + outSequence[basePosition + 1:]
                        basePosition += len(theTag) - 1

            else:
                # The sequence character is invalid (but permissible).
                # Tags (e.g., <b> and </b>) must be inserted at both the
                # beginning and end of a segment of invalid characters.
                if invalidSequence == False:
                    outSequence      =  outSequence[:basePosition] \
                                      + invalidStartTag \
                                      + outSequence[basePosition:]
                    basePosition += len(invalidStartTag)
                    invalidSequence = True

            basePosition += 1
            previousChar = theSeqChar
            #basePosition +=  1

        # Specify that theSequence is definitely HTML format, because
        # Qt can get confused between HTML and Plain Text.
        outSequence = "<html>" + outSequence
        outSequence += "</html>"

        return outSequence

    def setSequence(self, inSequence, inStylize=True, inRestoreCursor=True):
        """ 
        Replace the current strand sequence with the new sequence text.
        
        @param inSequence: The new sequence.
        @type  inSequence: QString
        
        @param inStylize: If True, inSequence will be converted from a plain
                          text string (including optional symbols) to an HTML 
                          rich text string.
        @type  inStylize: bool
        
        @param inRestoreCursor: Not implemented yet.
        @type  inRestoreCursor: bool
        
        @attention: Signals/slots must be managed before calling this method.  
        The textChanged() signal will be sent to any connected widgets.
        """
        cursor = self.sequenceTextEdit.textCursor()
        selectionStart = cursor.selectionStart()
        selectionEnd = cursor.selectionEnd()

        if inStylize:
            inSequence = self.stylizeSequence(inSequence)

        self.sequenceTextEdit.insertHtml(inSequence)

        if inRestoreCursor:
            cursor.setPosition(min(selectionStart, self.getSequenceLength()),
                               QTextCursor.MoveAnchor)
            cursor.setPosition(min(selectionEnd, self.getSequenceLength()),
                               QTextCursor.KeepAnchor)
            self.sequenceTextEdit.setTextCursor(cursor)
        return

    def getSequenceLength(self):
        """
        Returns the number of characters in 
        the strand sequence textedit widget.
        """
        theSequence = self.getPlainSequence(inOmitSymbols=True)
        outLength = theSequence.length()

        return outLength

    def getCursorPosition(self):
        """
        Returns the cursor position in the 
        strand sequence textedit widget.
        """
        cursor = self.sequenceTextEdit.textCursor()
        return cursor.position()

    def cursorPosChanged(self):
        """
        Slot called when the cursor position changes.
        """
        cursor = self.sequenceTextEdit.textCursor()

        if 0:
            env.history.message(
                greenmsg("cursorPosChanged: Selection (" +
                         str(cursor.selectionStart()) + " thru " +
                         str(cursor.selectionEnd()) + ')'))
        return

    def actionsComboBoxChanged(self, inIndex):
        """
        Slot for the Actions combobox. It is called whenever the
        Action choice is changed.
        
        @param inIndex: The index of the selected action choice.
        @type  inIndex: int
        """
        if inIndex == 0:  # Very important.
            return

        actionName = str(self.actionsComboBox.currentText())
        self.actionsComboBox.setCurrentIndex(0)  # Generates signal!
        self.invokeAction(actionName)
        return

    def invokeAction(self, inActionName):
        """
        Applies an action on the current sequence displayed in the PM.

        @param inActionName: The action name.
        @type  inActionName: str

        @return: The sequence after the action has been applied.
        @rtype:  str
        """
        sequence, allKnown = self._getSequence()
        outResult = ""

        if inActionName == self._action_Complement:
            outResult = getComplementSequence(sequence)
        elif inActionName == self._action_Reverse:
            outResult = getReverseSequence(sequence)
        elif inActionName == self._action_ConvertUnrecognized:
            outResult = replaceUnrecognized(sequence, replaceBase='N')
            self.setSequence(outResult)
        elif inActionName == self._action_RemoveUnrecognized:
            outResult = replaceUnrecognized(sequence, replaceBase='')

        self.setSequence(outResult)

        return
class BuildProtein_PropertyManager( EditCommand_PM, DebugMenuMixin ):
    """
    The BuildDna_PropertyManager class provides a Property Manager 
    for the B{Build > 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         =  "Build Protein"
    pmName        =  title
    #change this ico path later
    iconPath      =  "ui/actions/Tools/Build Structures/Peptide.png"

    def __init__( self, win, editCommand ):
        """
        Constructor for the Build DNA property manager.
        """
        
        #For model changed signal
        self.previousSelectionParams = None
         
        #Urmi 20080713: set the protein chunk name and its length
        #for the first available chunk and not the selected one, that's
        #not implemented as yet
        
        #self.showProteinParametersAndSequenceEditorForInit(win)
        
        #see self.connect_or_disconnect_signals for comment about this flag
        self.isAlreadyConnected = False
        self.isAlreadyDisconnected = False           
        
        EditCommand_PM.__init__( self, 
                                    win,
                                    editCommand)


        DebugMenuMixin._init1( self )

        self.showTopRowButtons( PM_DONE_BUTTON | \
                                PM_CANCEL_BUTTON | \
                                PM_WHATS_THIS_BUTTON)
        
        
    def show(self):
        self.showProteinParametersAndSequenceEditor(self.win)
        EditCommand_PM.show(self)        
        
        return
    
    def close(self):
        self.sequenceEditor.hide() 
        env.history.statusbar_msg("")
        EditCommand_PM.close(self)
        return
    
    
    
    def showProteinParametersAndSequenceEditor(self, win):
        """
        Show/ Hide protein parameters and sequence editor based
        """
        part = win.assy.part
        from simulation.ROSETTA.rosetta_commandruns import checkIfProteinChunkInPart
        proteinExists, proteinChunk = checkIfProteinChunkInPart(part)
        if proteinExists:
            self._proteinChunkName = proteinChunk.protein.get_pdb_id() + proteinChunk.protein.get_chain_id()
            self._numberOfAA = len(proteinChunk.protein.get_sequence_string())
        else:
            self._proteinChunkName = ''
            self._numberOfAA = 0
            
        self.nameLineEdit.setText(self._proteinChunkName)
        self.numberOfAASpinBox.setValue(self._numberOfAA)
        if proteinExists:
            self.nameLineEdit.setEnabled(True)
        else:
            self.nameLineEdit.setEnabled(False)
            
        self.sequenceEditor = win.createProteinSequenceEditorIfNeeded() 
        #get the sequence for this protein chunk
        if proteinExists:
            sequence = proteinChunk.protein.get_sequence_string()
            self.sequenceEditor.setSequence(sequence)
            secStructure = proteinChunk.protein.get_secondary_structure_string()
            self.sequenceEditor.setSecondaryStructure(secStructure)
            self.sequenceEditor.setRuler(len(secStructure))
            self.sequenceEditor.show()    
        else:
            self.sequenceEditor.hide()   
            
    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 and self.isAlreadyConnected:
            return 
        
        if not isConnect and self.isAlreadyDisconnected:
            return
        
        self.isAlreadyConnected = isConnect
        self.isAlreadyDisconnected = not isConnect
        
        if isConnect:
            change_connect = self.win.connect     
        else:
            change_connect = self.win.disconnect 
        
        
    
    def enable_or_disable_gui_actions(self, bool_enable = False):
        """
        Enable or disable some gui actions when this property manager is 
        opened or closed, depending on the bool_enable. 
        
        """
        #TODO: This is bad. It would have been much better to enable/disable 
        #gui actions using a API method in command/commandSequencer which gets 
        #called when you enter another command exiting or suspending the 
        #previous one. . At present. it doesn't exist (first needs cleanup in 
        #command/command sequencer (Done and other methods._)-- Ninad 2008-01-09
        if hasattr(self.editCommand, 'flyoutToolbar') and \
           self.editCommand.flyoutToolbar:            
            self.editCommand.flyoutToolbar.exitProteinAction.setEnabled(not bool_enable)
        
      
                      
    
    
  
    def ok_btn_clicked(self):
        """
        Slot for the OK button
        """   
        
        self.win.toolsDone()
    
    def cancel_btn_clicked(self):
        """
        Slot for the Cancel button.
        """
                  
        self.win.toolsCancel()
    
    def _addWhatsThisText( self ):
        """
        What's This text for widgets in the DNA Property Manager.  
        """
        pass
                
    def _addToolTipText(self):
        """
        Tool Tip text for widgets in the DNA Property Manager.  
        """
        pass

    def _addGroupBoxes( self ):
        """
        Add the DNA Property Manager group boxes.
        """
        """
        Add the DNA Property Manager group boxes.
        """        
                
        self._pmGroupBox1 = PM_GroupBox( self, title = "Parameters" )
        self._loadGroupBox1( self._pmGroupBox1 )
        
        pass
    
    def _loadGroupBox1(self, pmGroupBox):
        """
        Load widgets in group box 4.
        """
        
        self.nameLineEdit = PM_LineEdit( pmGroupBox,
                         label         =  "Protein chunk name:",
                         text          =  "",
                         setAsDefault  =  False)
        
        #Urmi 20080713: May be useful to set the minimum value to not zero
        self.numberOfAASpinBox = \
            PM_SpinBox( pmGroupBox, 
                        label         =  "Number of amino acids:", 
                        value         =  0,
                        setAsDefault  =  False,
                        minimum       =  0,
                        maximum       =  10000 )
        self.numberOfAASpinBox.setEnabled(False)
Exemple #38
0
class FixedBBProteinSim_PropertyManager(Command_PropertyManager):
    """
    The FixedBBProteinSim_PropertyManager class provides a Property Manager 
    for the B{Fixed backbone Protein Sequence Design} command on the flyout toolbar in the 
    Build > Protein > Simulate 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
    """

    title         =  "Fixed Backbone Design"
    pmName        =  title
    iconPath      = "ui/actions/Command Toolbar/BuildProtein/FixedBackbone.png"

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

        _superclass.__init__(self, command)

        self.showTopRowButtons( PM_DONE_BUTTON | \
                                PM_WHATS_THIS_BUTTON)

        msg = "Choose from the various options below to design "\
            "an optimized <b>fixed backbone protein sequence</b> with Rosetta."
        self.updateMessage(msg)            
        return
    

    def connect_or_disconnect_signals(self, isConnect = True):
        """
        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.ex1Checkbox, SIGNAL("stateChanged(int)"), self.update_ex1)
        change_connect(self.ex1aroCheckbox, SIGNAL("stateChanged(int)"), self.update_ex1aro)
        change_connect(self.ex2Checkbox, SIGNAL("stateChanged(int)"), self.update_ex2)
        change_connect(self.ex2aroOnlyCheckbox, SIGNAL("stateChanged(int)"), self.update_ex2aro_only)
        change_connect(self.ex3Checkbox, SIGNAL("stateChanged(int)"), self.update_ex3)
        change_connect(self.ex4Checkbox, SIGNAL("stateChanged(int)"), self.update_ex4)
        change_connect(self.rotOptCheckbox, SIGNAL("stateChanged(int)"), self.update_rot_opt)
        change_connect(self.tryBothHisTautomersCheckbox, SIGNAL("stateChanged(int)"), self.update_try_both_his_tautomers)
        change_connect(self.softRepDesignCheckbox, SIGNAL("stateChanged(int)"), self.update_soft_rep_design)
        change_connect(self.useElecRepCheckbox, SIGNAL("stateChanged(int)"), self.update_use_elec_rep)
        change_connect(self.norepackDisulfCheckbox, SIGNAL("stateChanged(int)"), self.update_norepack_disulf)
        #signal slot connections for the push buttons
        change_connect(self.okButton, SIGNAL("clicked()"), self.runRosettaFixedBBSim)
        return
        
    #Protein Display methods         

    
    def show(self):
        """
        Shows the Property Manager. 
        """
        #@REVIEW: Why does it create sequence editor here? Also, is it
        #required to be done before the superclass.show call? Similar code 
        #found in CompareProteins_PM and some other files --Ninad 2008-10-02
        
        self.sequenceEditor = self.win.createProteinSequenceEditorIfNeeded()
        self.sequenceEditor.hide()
        
        _superclass.show(self)
        return
        
    def _addGroupBoxes( self ):
        """
        Add the Property Manager group boxes.
        """
        self._pmGroupBox1 = PM_GroupBox( self,
                                         title = "Rosetta Fixed backbone sequence design")
        self._loadGroupBox1( self._pmGroupBox1 )
        return
    
        
    def _loadGroupBox1(self, pmGroupBox):
        """
        Load widgets in group box.
        """
        
        self.numSimSpinBox = PM_SpinBox( pmGroupBox,
                                         labelColumn  = 0,
                                         label = "Number of simulations:",
                                         minimum = 1,
                                         maximum = 999,
                                         setAsDefault  =  False,
                                         spanWidth = False)
        
        self.ex1Checkbox = PM_CheckBox(pmGroupBox,
                                       text = "Expand rotamer library for chi1 angle",
                                       state = Qt.Unchecked,
                                       setAsDefault  =  False,
                                       widgetColumn  = 0,
                                       spanWidth = True)
        
        self.ex1aroCheckbox = PM_CheckBox(pmGroupBox,
                                          text = "Use large chi1 library for aromatic residues",
                                          state = Qt.Unchecked,
                                          setAsDefault  =  False,
                                          widgetColumn  = 0,
                                          spanWidth = True)
        
        self.ex2Checkbox = PM_CheckBox(pmGroupBox,
                                       text = "Expand rotamer library for chi2 angle",
                                       state = Qt.Unchecked,
                                       setAsDefault  =  False,
                                       widgetColumn  = 0,
                                       spanWidth = True)
        
        self.ex2aroOnlyCheckbox = PM_CheckBox(pmGroupBox,
                                              text = "Use large chi2 library only for aromatic residues",
                                              state = Qt.Unchecked,
                                              setAsDefault  =  False,
                                              widgetColumn  = 0,
                                              spanWidth = True)
                                              
        self.ex3Checkbox = PM_CheckBox(pmGroupBox,
                                     text = "Expand rotamer library for chi3 angle",
                                     state = Qt.Unchecked,
                                     setAsDefault  =  False,
                                     widgetColumn  = 0,
                                     spanWidth = True)
        
        self.ex4Checkbox = PM_CheckBox(pmGroupBox,
                                       text ="Expand rotamer library for chi4 angle",
                                       state = Qt.Unchecked,
                                       setAsDefault  =  False,
                                       widgetColumn  = 0,
                                       spanWidth = True)
        
        self.rotOptCheckbox = PM_CheckBox(pmGroupBox,
                                          text ="Optimize one-body energy",
                                          state = Qt.Unchecked,
                                          setAsDefault  =  False,
                                          widgetColumn  = 0,
                                          spanWidth = True)
        
        self.tryBothHisTautomersCheckbox = PM_CheckBox(pmGroupBox,
                                                       text ="Try both histidine tautomers",
                                                       state = Qt.Unchecked,
                                                       setAsDefault  =  False,
                                                       widgetColumn  = 0,
                                                       spanWidth = True)
        
        self.softRepDesignCheckbox = PM_CheckBox(pmGroupBox,
                                                 text ="Use softer Lennard-Jones repulsive term",
                                                 state = Qt.Unchecked,
                                                 setAsDefault  =  False,
                                                 widgetColumn  = 0,
                                                 spanWidth = True)
        
        self.useElecRepCheckbox = PM_CheckBox(pmGroupBox,
                                              text ="Use electrostatic repulsion",
                                              state = Qt.Unchecked,
                                              setAsDefault  =  False,
                                              widgetColumn  = 0,
                                              spanWidth = True)
        
        self.norepackDisulfCheckbox = PM_CheckBox(pmGroupBox,
                                                  text ="Don't re-pack disulphide bonds",
                                                  state = Qt.Unchecked,
                                                  setAsDefault  =  False,
                                                  widgetColumn  = 0,
                                                  spanWidth = True)
        
        
        self.otherCommandLineOptions = PM_TextEdit(pmGroupBox,
                                                   label = "Command line options:",
                                                   spanWidth = True)
        self.otherCommandLineOptions.setFixedHeight(80)
        
        self.okButton = PM_PushButton( pmGroupBox,
                         text         =  "Launch Rosetta",
                         setAsDefault  =  True,
                         spanWidth = True)
        return
    
    def _addWhatsThisText( self ):
        """
        What's This text for widgets in this Property Manager.  
        """
        pass
                
    def _addToolTipText(self):
        """
        Tool Tip text for widgets in this Property Manager.  
        """
        pass
    
    def update_ex1(self, state):
        """
        Update the command text edit depending on the state of the update_ex1
        checkbox
        @param state:state of the update_ex1 checkbox
        @type state: int
        """
        otherOptionsText = str(self.otherCommandLineOptions.toPlainText())
        if self.ex1Checkbox.isChecked() == True:
            otherOptionsText = otherOptionsText + ' -ex1 '
        else:
            otherOptionsText = otherOptionsText.replace(' -ex1 ', '')
        self.otherCommandLineOptions.setText(otherOptionsText)    
        return
    
    def update_ex1aro(self, state):
        """
        Update the command text edit depending on the state of the update_ex1aro
        checkbox
        @param state:state of the update_ex1aro checkbox
        @type state: int
        """
        otherOptionsText = str(self.otherCommandLineOptions.toPlainText())
        if self.ex1aroCheckbox.isChecked() == True:
            otherOptionsText = otherOptionsText + ' -ex1aro '
        else:
            otherOptionsText = otherOptionsText.replace(' -ex1aro ', '')
        self.otherCommandLineOptions.setText(otherOptionsText)    
        return
    
    def update_ex2(self, state):
        """
        Update the command text edit depending on the state of the update_ex2
        checkbox
        @param state:state of the update_ex2 checkbox
        @type state: int
        """
        otherOptionsText = str(self.otherCommandLineOptions.toPlainText())
        if self.ex2Checkbox.isChecked() == True:
            otherOptionsText = otherOptionsText + ' -ex2 '
        else:
            otherOptionsText = otherOptionsText.replace(' -ex2 ', '')
        self.otherCommandLineOptions.setText(otherOptionsText)    
        return
    
    def update_ex2aro_only(self, state):
        """
        Update the command text edit depending on the state of the update_ex2aro_only
        checkbox
        @param state:state of the update_ex2aro_only checkbox
        @type state: int
        """
        otherOptionsText = str(self.otherCommandLineOptions.toPlainText())
        if self.ex2aroOnlyCheckbox.isChecked() == True:
            otherOptionsText = otherOptionsText + ' -ex2aro_only '
        else:
            otherOptionsText = otherOptionsText.replace(' -ex2aro_only ', '')    
            
        self.otherCommandLineOptions.setText(otherOptionsText)    
        return
    
    def update_ex3(self, state):
        """
        Update the command text edit depending on the state of the update_ex3
        checkbox
        @param state:state of the update_ex3 checkbox
        @type state: int
        """
        otherOptionsText = str(self.otherCommandLineOptions.toPlainText())
        if self.ex3Checkbox.isChecked() == True:
            otherOptionsText = otherOptionsText + ' -ex3 '
        else:
            otherOptionsText = otherOptionsText.replace(' -ex3 ', '')
        
        self.otherCommandLineOptions.setText(otherOptionsText)    
        return
    
    def update_ex4(self, state):
        """
        Update the command text edit depending on the state of the update_ex4
        checkbox
        @param state:state of the update_ex4 checkbox
        @type state: int
        """
        otherOptionsText = str(self.otherCommandLineOptions.toPlainText())
        if self.ex4Checkbox.isChecked() == True:
            otherOptionsText = otherOptionsText + ' -ex4 '
        else:
            otherOptionsText = otherOptionsText.replace(' -ex4 ', '')
        self.otherCommandLineOptions.setText(otherOptionsText)    
        return
    
    def update_rot_opt(self, state):
        """
        Update the command text edit depending on the state of the update_rot_opt
        checkbox
        @param state:state of the update_rot_opt checkbox
        @type state: int
        """
        otherOptionsText = str(self.otherCommandLineOptions.toPlainText())
        if self.rotOptCheckbox.isChecked() == True:
            otherOptionsText = otherOptionsText + ' -rot_opt '
        else:
            otherOptionsText = otherOptionsText.replace(' -rot_opt ', '')
        self.otherCommandLineOptions.setText(otherOptionsText)    
        return
    
    def update_try_both_his_tautomers(self, state):
        """
        Update the command text edit depending on the state of the update_try_both_his_tautomers
        checkbox
        @param state:state of the update_try_both_his_tautomers checkbox
        @type state: int
        """
        otherOptionsText = str(self.otherCommandLineOptions.toPlainText())
        if self.tryBothHisTautomersCheckbox.isChecked() == True:
            otherOptionsText = otherOptionsText + ' -try_both_his_tautomers '
        else:
            otherOptionsText = otherOptionsText.replace(' -try_both_his_tautomers ', '')
        self.otherCommandLineOptions.setText(otherOptionsText)    
        return
    
    def update_soft_rep_design(self, state):
        """
        Update the command text edit depending on the state of the update_soft_rep_design
        checkbox
        @param state:state of the update_soft_rep_design checkbox
        @type state: int
        """
        otherOptionsText = str(self.otherCommandLineOptions.toPlainText())
        if self.softRepDesignCheckbox.isChecked() == True:
            otherOptionsText = otherOptionsText + ' -soft_rep_design '
        else:
            otherOptionsText = otherOptionsText.replace(' -soft_rep_design ', '')
        self.otherCommandLineOptions.setText(otherOptionsText)    
        return
    
    def update_use_elec_rep(self, state):
        """
        Update the command text edit depending on the state of the update_use_elec_rep
        checkbox
        @param state:state of the update_use_elec_rep checkbox
        @type state: int
        """
        otherOptionsText = str(self.otherCommandLineOptions.toPlainText())
        if self.useElecRepCheckbox.isChecked() == True:
            otherOptionsText = otherOptionsText + ' -use_electrostatic_repulsion '
        else:
            otherOptionsText = otherOptionsText.replace(' -use_electrostatic_repulsion ', '')    
        self.otherCommandLineOptions.setText(otherOptionsText)        
        return
    
    def update_norepack_disulf(self, state):
        """
        Update the command text edit depending on the state of the update_no_repack
        checkbox
        @param state:state of the update_no_repack checkbox
        @type state: int
        """
        otherOptionsText = str(self.otherCommandLineOptions.toPlainText())
        if self.norepackDisulfCheckbox.isChecked() == True:
            otherOptionsText = otherOptionsText + ' -norepack_disulf '
        else:
            otherOptionsText = otherOptionsText.replace(' -norepack_disulf ', '')      
        self.otherCommandLineOptions.setText(otherOptionsText)        
        return
    
    def runRosettaFixedBBSim(self):
        """
        Get all the parameters from the PM and run a rosetta simulation.
        """
        proteinChunk = self.win.assy.getSelectedProteinChunk()
        if not proteinChunk:
            msg = "You must select a single protein to run a Rosetta <i>Fixed Backbone</i> simulation."
            self.updateMessage(msg)
            return
        otherOptionsText = str(self.otherCommandLineOptions.toPlainText())
        numSim = self.numSimSpinBox.value()
        argList = [numSim, otherOptionsText, proteinChunk.name]
        
        from simulation.ROSETTA.rosetta_commandruns import rosettaSetup_CommandRun
        if argList[0] > 0:
            cmdrun = rosettaSetup_CommandRun(self.win, argList, "ROSETTA_FIXED_BACKBONE_SEQUENCE_DESIGN")
            cmdrun.run() 
        return    
Exemple #39
0
class BackrubProteinSim_PropertyManager(Command_PropertyManager):
    """
    The BackrubProteinSim_PropertyManager class provides a Property Manager 
    for the B{Fixed backbone Protein Sequence Design} command on the flyout toolbar in the 
    Build > Protein > Simulate 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
    """

    title         =  "Backrub Motion"
    pmName        =  title
    iconPath      = "ui/actions/Command Toolbar/BuildProtein/Backrub.png"

    
    def __init__( self, command ):
        """
        Constructor for the property manager.
        """                  
        _superclass.__init__(self, command)
        self.showTopRowButtons( PM_DONE_BUTTON | \
                                PM_WHATS_THIS_BUTTON)
        msg = "Choose various parameters from below to design an optimized" \
            " protein sequence with Rosetta with backrub motion allowed."
        self.updateMessage(msg)
        
    def connect_or_disconnect_signals(self, isConnect = True):
        """
        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.ex1Checkbox, SIGNAL("stateChanged(int)"), self.update_ex1)
        change_connect(self.ex1aroCheckbox, SIGNAL("stateChanged(int)"), self.update_ex1aro)
        change_connect(self.ex2Checkbox, SIGNAL("stateChanged(int)"), self.update_ex2)
        change_connect(self.ex2aroOnlyCheckbox, SIGNAL("stateChanged(int)"), self.update_ex2aro_only)
        change_connect(self.ex3Checkbox, SIGNAL("stateChanged(int)"), self.update_ex3)
        change_connect(self.ex4Checkbox, SIGNAL("stateChanged(int)"), self.update_ex4)
        change_connect(self.rotOptCheckbox, SIGNAL("stateChanged(int)"), self.update_rot_opt)
        change_connect(self.tryBothHisTautomersCheckbox, SIGNAL("stateChanged(int)"), self.update_try_both_his_tautomers)
        change_connect(self.softRepDesignCheckbox, SIGNAL("stateChanged(int)"), self.update_soft_rep_design)
        change_connect(self.useElecRepCheckbox, SIGNAL("stateChanged(int)"), self.update_use_elec_rep)
        change_connect(self.norepackDisulfCheckbox, SIGNAL("stateChanged(int)"), self.update_norepack_disulf)
        #signal slot connections for the push buttons
        change_connect(self.okButton, SIGNAL("clicked()"), self.runRosettaBackrubSim)
        return
    
    #Protein Display methods         

    def show(self):
        """
        Shows the Property Manager. Exends superclass method. 
        """
        self.sequenceEditor = self.win.createProteinSequenceEditorIfNeeded()
        self.sequenceEditor.hide()
        #update the min and max residues spinbox max values based on the length
        #of the current protein
        numResidues = self._getNumResiduesForCurrentProtein()
        if numResidues == 0:
            self.minresSpinBox.setMaximum(numResidues + 2)
            self.maxresSpinBox.setMaximum(numResidues + 2)
        else:    
            self.minresSpinBox.setMaximum(numResidues)
            self.maxresSpinBox.setMaximum(numResidues)
        
        _superclass.show(self)       
       
        return

    def _addGroupBoxes( self ):
        """
        Add the Property Manager group boxes.
        """
        self._pmGroupBox2 = PM_GroupBox( self,
                                         title = "Backrub Specific Parameters")
        self._loadGroupBox2( self._pmGroupBox2 )
        
        self._pmGroupBox1 = PM_GroupBox( self,
                                         title = "Rosetta Sequence Design Parameters")
        self._loadGroupBox1( self._pmGroupBox1 )
        
        return
    
    def _loadGroupBox2(self, pmGroupBox):
        """
        Load widgets in group box.
        """
        self.bondAngleWeightSimSpinBox = PM_DoubleSpinBox( pmGroupBox,
                                         labelColumn  = 0,
                                         label = "Bond angle weight:",
                                         minimum = 0.01,
                                         decimals     = 2, 
                                         maximum = 1.0,
                                         singleStep = 0.01,
                                         value = 1.0,
                                         setAsDefault  =  False,
                                         spanWidth = False)
        
        bond_angle_param_list = ['Amber', 'Charmm']
        
        self.bondAngleParamComboBox = PM_ComboBox( pmGroupBox,
                                                   label         =  "Bond angle parameters:",
                                                   choices       =  bond_angle_param_list,
                                                   setAsDefault  =  False)
        
        self.onlybbSpinBox = PM_DoubleSpinBox( pmGroupBox,
                                         labelColumn  = 0,
                                         label = "Only backbone rotation:",
                                         minimum  = 0.01,
                                         maximum  = 1.0,
                                         value    = 0.75, 
                                         decimals = 2, 
                                         singleStep = 0.01,
                                         setAsDefault  =  False,
                                         spanWidth = False)
        
        self.onlyrotSpinBox = PM_DoubleSpinBox( pmGroupBox,
                                         labelColumn  = 0,
                                         label = "Only rotamer rotation:",
                                         minimum  = 0.01,
                                         maximum  = 1.0,
                                         decimals = 2, 
                                         value    = 0.25, 
                                         singleStep = 0.01,
                                         setAsDefault  =  False,
                                         spanWidth = False)
        
        self.mctempSpinBox = PM_DoubleSpinBox( pmGroupBox,
                                         labelColumn  = 0,
                                         label = "MC simulation temperature:",
                                         minimum  = 0.1,
                                         value    = 0.6, 
                                         maximum  = 1.0,
                                         decimals = 2, 
                                         singleStep = 0.1,
                                         setAsDefault  =  False,
                                         spanWidth = False)
        
        numResidues = self._getNumResiduesForCurrentProtein()
        self.minresSpinBox = PM_SpinBox( pmGroupBox,
                                         labelColumn  = 0,
                                         label = "Minimum number of residues:",
                                         minimum = 2,
                                         maximum = numResidues,
                                         singleStep = 1,
                                         setAsDefault  =  False,
                                         spanWidth = False)
        
        self.maxresSpinBox = PM_SpinBox( pmGroupBox,
                                         labelColumn  = 0,
                                         label = "Maximum number of residues:",
                                         minimum = 2,
                                         maximum = numResidues,
                                         singleStep = 1,
                                         setAsDefault  =  False,
                                         spanWidth = False)
        if numResidues == 0:
            self.minresSpinBox.setMaximum(numResidues + 2)
            self.maxresSpinBox.setMaximum(numResidues + 2)
        return
    
    
    def _addWhatsThisText( self ):
        """
        What's This text for widgets in this Property Manager.  
        """
        pass
                
    def _addToolTipText(self):
        """
        Tool Tip text for widgets in this Property Manager.  
        """
        pass
    
    def _getNumResiduesForCurrentProtein(self):
        """
        Get number of residues for the current protein
        """
        _current_protein = self.win.assy.getSelectedProteinChunk()
        if _current_protein:
            return len(_current_protein.protein.get_sequence_string())
        return 0
    
    def _loadGroupBox1(self, pmGroupBox):
        """
        Load widgets in group box.
        """
        
        self.numSimSpinBox = PM_SpinBox( pmGroupBox,
                                         labelColumn  = 0,
                                         label = "Number of trials:",
                                         minimum = 1000,
                                         maximum = 1000000,
                                         singleStep = 1000,
                                         setAsDefault  =  False,
                                         spanWidth = False)
        
        self.ex1Checkbox = PM_CheckBox(pmGroupBox,
                                       text = "Expand rotamer library for chi1 angle",
                                       state = Qt.Unchecked,
                                       setAsDefault  =  False,
                                       widgetColumn  = 0,
                                       spanWidth = True)
        
        self.ex1aroCheckbox = PM_CheckBox(pmGroupBox,
                                          text = "Use large chi1 library for aromatic residues",
                                          state = Qt.Unchecked,
                                          setAsDefault  =  False,
                                          widgetColumn  = 0,
                                          spanWidth = True)
        
        self.ex2Checkbox = PM_CheckBox(pmGroupBox,
                                       text = "Expand rotamer library for chi2 angle",
                                       state = Qt.Unchecked,
                                       setAsDefault  =  False,
                                       widgetColumn  = 0,
                                       spanWidth = True)
        
        self.ex2aroOnlyCheckbox = PM_CheckBox(pmGroupBox,
                                              text = "Use large chi2 library only for aromatic residues",
                                              state = Qt.Unchecked,
                                              setAsDefault  =  False,
                                              widgetColumn  = 0,
                                              spanWidth = True)
                                              
        self.ex3Checkbox = PM_CheckBox(pmGroupBox,
                                     text = "Expand rotamer library for chi3 angle",
                                     state = Qt.Unchecked,
                                     setAsDefault  =  False,
                                     widgetColumn  = 0,
                                     spanWidth = True)
        
        self.ex4Checkbox = PM_CheckBox(pmGroupBox,
                                       text ="Expand rotamer library for chi4 angle",
                                       state = Qt.Unchecked,
                                       setAsDefault  =  False,
                                       widgetColumn  = 0,
                                       spanWidth = True)
        
        self.rotOptCheckbox = PM_CheckBox(pmGroupBox,
                                          text ="Optimize one-body energy",
                                          state = Qt.Unchecked,
                                          setAsDefault  =  False,
                                          widgetColumn  = 0,
                                          spanWidth = True)
        
        self.tryBothHisTautomersCheckbox = PM_CheckBox(pmGroupBox,
                                                       text ="Try both histidine tautomers",
                                                       state = Qt.Unchecked,
                                                       setAsDefault  =  False,
                                                       widgetColumn  = 0,
                                                       spanWidth = True)
        
        self.softRepDesignCheckbox = PM_CheckBox(pmGroupBox,
                                                 text ="Use softer Lennard-Jones repulsive term",
                                                 state = Qt.Unchecked,
                                                 setAsDefault  =  False,
                                                 widgetColumn  = 0,
                                                 spanWidth = True)
        
        self.useElecRepCheckbox = PM_CheckBox(pmGroupBox,
                                              text ="Use electrostatic repulsion",
                                              state = Qt.Unchecked,
                                              setAsDefault  =  False,
                                              widgetColumn  = 0,
                                              spanWidth = True)
        
        self.norepackDisulfCheckbox = PM_CheckBox(pmGroupBox,
                                                  text ="Don't re-pack disulphide bonds",
                                                  state = Qt.Unchecked,
                                                  setAsDefault  =  False,
                                                  widgetColumn  = 0,
                                                  spanWidth = True)
        
        
        self.otherCommandLineOptions = PM_TextEdit(pmGroupBox,
                                                   label = "Command line options:",
                                                   spanWidth = True)
        self.otherCommandLineOptions.setFixedHeight(80)
        
        self.okButton = PM_PushButton( pmGroupBox,
                         text         =  "Run Rosetta",
                         setAsDefault  =  True,
                         spanWidth = True)
        return
    
    
    def update_ex1(self, state):
        """
        Update the command text edit depending on the state of the update_ex1
        checkbox
        @param state:state of the update_ex1 checkbox
        @type state: int
        """
        otherOptionsText = str(self.otherCommandLineOptions.toPlainText())
        if self.ex1Checkbox.isChecked() == True:
            otherOptionsText = otherOptionsText + ' -ex1 '
        else:
            otherOptionsText = otherOptionsText.replace(' -ex1 ', '')
        self.otherCommandLineOptions.setText(otherOptionsText)    
        return
    
    def update_ex1aro(self, state):
        """
        Update the command text edit depending on the state of the update_ex1aro
        checkbox
        @param state:state of the update_ex1aro checkbox
        @type state: int
        """
        otherOptionsText = str(self.otherCommandLineOptions.toPlainText())
        if self.ex1aroCheckbox.isChecked() == True:
            otherOptionsText = otherOptionsText + ' -ex1aro '
        else:
            otherOptionsText = otherOptionsText.replace(' -ex1aro ', '')
        self.otherCommandLineOptions.setText(otherOptionsText)    
        return
    
    def update_ex2(self, state):
        """
        Update the command text edit depending on the state of the update_ex2
        checkbox
        @param state:state of the update_ex2 checkbox
        @type state: int
        """
        otherOptionsText = str(self.otherCommandLineOptions.toPlainText())
        if self.ex2Checkbox.isChecked() == True:
            otherOptionsText = otherOptionsText + ' -ex2 '
        else:
            otherOptionsText = otherOptionsText.replace(' -ex2 ', '')
        self.otherCommandLineOptions.setText(otherOptionsText)    
        return
    
    def update_ex2aro_only(self, state):
        """
        Update the command text edit depending on the state of the update_ex2aro_only
        checkbox
        @param state:state of the update_ex2aro_only checkbox
        @type state: int
        """
        otherOptionsText = str(self.otherCommandLineOptions.toPlainText())
        if self.ex2aroOnlyCheckbox.isChecked() == True:
            otherOptionsText = otherOptionsText + ' -ex2aro_only '
        else:
            otherOptionsText = otherOptionsText.replace(' -ex2aro_only ', '')    
            
        self.otherCommandLineOptions.setText(otherOptionsText)    
        return
    
    def update_ex3(self, state):
        """
        Update the command text edit depending on the state of the update_ex3
        checkbox
        @param state:state of the update_ex3 checkbox
        @type state: int
        """
        otherOptionsText = str(self.otherCommandLineOptions.toPlainText())
        if self.ex3Checkbox.isChecked() == True:
            otherOptionsText = otherOptionsText + ' -ex3 '
        else:
            otherOptionsText = otherOptionsText.replace(' -ex3 ', '')
        
        self.otherCommandLineOptions.setText(otherOptionsText)    
        return
    
    def update_ex4(self, state):
        """
        Update the command text edit depending on the state of the update_ex4
        checkbox
        @param state:state of the update_ex4 checkbox
        @type state: int
        """
        otherOptionsText = str(self.otherCommandLineOptions.toPlainText())
        if self.ex4Checkbox.isChecked() == True:
            otherOptionsText = otherOptionsText + ' -ex4 '
        else:
            otherOptionsText = otherOptionsText.replace(' -ex4 ', '')
        self.otherCommandLineOptions.setText(otherOptionsText)    
        return
    
    def update_rot_opt(self, state):
        """
        Update the command text edit depending on the state of the update_rot_opt
        checkbox
        @param state:state of the update_rot_opt checkbox
        @type state: int
        """
        otherOptionsText = str(self.otherCommandLineOptions.toPlainText())
        if self.rotOptCheckbox.isChecked() == True:
            otherOptionsText = otherOptionsText + ' -rot_opt '
        else:
            otherOptionsText = otherOptionsText.replace(' -rot_opt ', '')
        self.otherCommandLineOptions.setText(otherOptionsText)    
        return
    
    def update_try_both_his_tautomers(self, state):
        """
        Update the command text edit depending on the state of the update_try_both_his_tautomers
        checkbox
        @param state:state of the update_try_both_his_tautomers checkbox
        @type state: int
        """
        otherOptionsText = str(self.otherCommandLineOptions.toPlainText())
        if self.tryBothHisTautomersCheckbox.isChecked() == True:
            otherOptionsText = otherOptionsText + ' -try_both_his_tautomers '
        else:
            otherOptionsText = otherOptionsText.replace(' -try_both_his_tautomers ', '')
        self.otherCommandLineOptions.setText(otherOptionsText)    
        return
    
    def update_soft_rep_design(self, state):
        """
        Update the command text edit depending on the state of the update_soft_rep_design
        checkbox
        @param state:state of the update_soft_rep_design checkbox
        @type state: int
        """
        otherOptionsText = str(self.otherCommandLineOptions.toPlainText())
        if self.softRepDesignCheckbox.isChecked() == True:
            otherOptionsText = otherOptionsText + ' -soft_rep_design '
        else:
            otherOptionsText = otherOptionsText.replace(' -soft_rep_design ', '')
        self.otherCommandLineOptions.setText(otherOptionsText)    
        return
    
    def update_use_elec_rep(self, state):
        """
        Update the command text edit depending on the state of the update_use_elec_rep
        checkbox
        @param state:state of the update_use_elec_rep checkbox
        @type state: int
        """
        otherOptionsText = str(self.otherCommandLineOptions.toPlainText())
        if self.useElecRepCheckbox.isChecked() == True:
            otherOptionsText = otherOptionsText + ' -use_electrostatic_repulsion '
        else:
            otherOptionsText = otherOptionsText.replace(' -use_electrostatic_repulsion ', '')    
        self.otherCommandLineOptions.setText(otherOptionsText)        
        return
    
    def update_norepack_disulf(self, state):
        """
        Update the command text edit depending on the state of the update_no_repack
        checkbox
        @param state:state of the update_no_repack checkbox
        @type state: int
        """
        otherOptionsText = str(self.otherCommandLineOptions.toPlainText())
        if self.norepackDisulfCheckbox.isChecked() == True:
            otherOptionsText = otherOptionsText + ' -norepack_disulf '
        else:
            otherOptionsText = otherOptionsText.replace(' -norepack_disulf ', '')      
        self.otherCommandLineOptions.setText(otherOptionsText)        
        return
    
    def runRosettaBackrubSim(self):
        """
        Get all the parameters from the PM and run a rosetta simulation
        """
        proteinChunk = self.win.assy.getSelectedProteinChunk()
        if not proteinChunk:
            msg = "You must select a single protein to run a Rosetta <i>Backrub</i> simulation."
            self.updateMessage(msg)
            return
        otherOptionsText = str(self.otherCommandLineOptions.toPlainText())
        numSim = self.numSimSpinBox.value()
        argList = [numSim, otherOptionsText, proteinChunk.name]
        backrubSpecificArgList = self.getBackrubSpecificArgumentList()
        from simulation.ROSETTA.rosetta_commandruns import rosettaSetup_CommandRun
        if argList[0] > 0:
            env.prefs[rosetta_backrub_enabled_prefs_key] = True
            cmdrun = rosettaSetup_CommandRun(self.win, argList, "BACKRUB_PROTEIN_SEQUENCE_DESIGN", backrubSpecificArgList)
            cmdrun.run() 
        return    
    
    def getBackrubSpecificArgumentList(self):
        """
        get list of backrub specific parameters from PM
        """
        listOfArgs = []
        
        bond_angle_weight = str(self.bondAngleWeightSimSpinBox.value())
        listOfArgs.append('-bond_angle_weight')
        listOfArgs.append( bond_angle_weight)
        
        if self.bondAngleParamComboBox.currentIndex() == 0:
            bond_angle_params = 'bond_angle_amber_rosetta'
        else:
            bond_angle_params = 'bond_angle_charmm_rosetta'
            
        listOfArgs.append('-bond_angle_params')            
        listOfArgs.append(bond_angle_params)    
        
        only_bb = str(self.onlybbSpinBox.value())
        listOfArgs.append('-only_bb')
        listOfArgs.append( only_bb)
        
        only_rot = str(self.onlyrotSpinBox.value())
        listOfArgs.append('-only_rot')
        listOfArgs.append( only_rot)
        
        mc_temp = str(self.mctempSpinBox.value())
        listOfArgs.append('-mc_temp')
        listOfArgs.append( mc_temp)
        
        min_res = self.minresSpinBox.value()
        max_res = self.maxresSpinBox.value()
        if max_res < min_res:
            msg = redmsg("Maximum number of residues for rosetta simulation with backrub" \
                " motion cannot be less than minimum number of residues."\
                " Neglecting this parameter for this simulation.")
            
            env.history.message("BACKRUB SIMULATION: " + msg)
        else:
            listOfArgs.append('-min_res')
            listOfArgs.append( str(min_res))
            listOfArgs.append('-max_res')
            listOfArgs.append( str(max_res))
        
        return listOfArgs
    def _loadCrystalSpecsGroupBox(self, inPmGroupBox):
        """
        Load widgets in the Crystal Specifications group box.
        @param inPmGroupBox: The Crystal Specifications groupbox in the PM
        @type  inPmGroupBox: L{PM_GroupBox} 
        """
        latticeChoices = ["Diamond", "Lonsdaleite"]

        self.latticeCBox = \
            PM_ComboBox( inPmGroupBox,
                         label        = 'Lattice:',
                         labelColumn  = 0,
                         choices      = latticeChoices,
                         index        = 0,
                         setAsDefault = True,
                         spanWidth    = False )

        # Button list to create a toolbutton row.
        # Format:
        # - buttonType,
        # - buttonId,
        # - buttonText ,
        # - iconPath
        # - tooltip
        # - shortcut
        # - column
        BUTTON_LIST = [("QToolButton", 0, "Surface 100",
                        "ui/actions/Properties Manager/Surface100.png",
                        "Surface 100", "", 0),
                       ("QToolButton", 1, "Surface 110",
                        "ui/actions/Properties Manager/Surface110.png",
                        "Surface 110", "", 1),
                       ("QToolButton", 2, "Surface 111",
                        "ui/actions/Properties Manager/Surface111.png",
                        "Surface 110", "", 2)]
        self.gridOrientationButtonRow = \
            PM_ToolButtonRow(inPmGroupBox,
                               title        = "",
                               label        = "Orientation:",
                               buttonList   = BUTTON_LIST,
                               checkedId    = 0,
                               setAsDefault = True,
                               spanWidth   = False
                               )

        self.orientButtonGroup = self.gridOrientationButtonRow.buttonGroup
        self.surface100_btn = self.gridOrientationButtonRow.getButtonById(0)
        self.surface110_btn = self.gridOrientationButtonRow.getButtonById(1)
        self.surface111_btn = self.gridOrientationButtonRow.getButtonById(2)

        self.rotateGridByAngleSpinBox = \
            PM_SpinBox( inPmGroupBox,
                        label         =  "Rotate by: ",
                        labelColumn   =  0,
                        value         =  45,
                        minimum       =  0,
                        maximum       =  360,
                        singleStep    =  5,
                        suffix        = " degrees")

        GRID_ANGLE_BUTTONS = [
            ("QToolButton", 0, "Anticlockwise",
             "ui/actions/Properties Manager/rotate_minus.png", "", "+", 0),
            ("QToolButton", 1, "Clockwise",
             "ui/actions/Properties Manager/rotate_plus.png", "", "-", 1)
        ]

        self.gridRotateButtonRow = \
            PM_ToolButtonRow( inPmGroupBox,
                              title        = "",
                              buttonList   = GRID_ANGLE_BUTTONS,
                              label        = 'Rotate grid:',
                              isAutoRaise  =  False,
                              isCheckable  =  False
                            )
        self.rotGridAntiClockwiseButton = \
            self.gridRotateButtonRow.getButtonById(0)
        self.rotGridClockwiseButton = \
            self.gridRotateButtonRow.getButtonById(1)
class DnaStrand_PropertyManager( DnaOrCnt_PropertyManager):
    """
    The DnaStrand_PropertyManager class provides a Property Manager 
    for the DnaStrand_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         =  "DnaStrand Properties"
    pmName        =  title
    iconPath      =  "ui/actions/Properties Manager/Strand.png"

    def __init__( self, win, editCommand ):
        """
        Constructor for the Build DNA 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
        
        self.sequenceEditor = None      
        
        self._numberOfBases = 0 
        self._conformation = 'B-DNA'
        self.duplexRise = 3.18
        self.basesPerTurn = 10
        self.dnaModel = 'PAM3'
        
        
        _superclass.__init__( self, 
                                    win,
                                    editCommand)


        
        self.showTopRowButtons( PM_DONE_BUTTON | \
                                PM_WHATS_THIS_BUTTON)
        
        self._loadSequenceEditor()
        
        msg = "Use resize handles to resize the strand. Use sequence editor"\
                   "to assign a new sequence or the current one to a file."
        self.updateMessage(msg)
        
               
    
    def _addGroupBoxes( self ):
        """
        Add the DNA 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         =  "Strand name:",
                         text          =  "",
                         setAsDefault  =  False)
        
        self.numberOfBasesSpinBox = \
            PM_SpinBox( pmGroupBox, 
                        label         =  "Number of bases:", 
                        value         =  self._numberOfBases,
                        setAsDefault  =  False,
                        minimum       =  2,
                        maximum       =  10000 )
        
        self.basesPerTurnDoubleSpinBox  =  \
            PM_DoubleSpinBox( pmGroupBox,
                              label         =  "Bases per turn:",
                              value         =  self.basesPerTurn,
                              setAsDefault  =  True,
                              minimum       =  8.0,
                              maximum       =  20.0,
                              decimals      =  2,
                              singleStep    =  0.1 )
        
        self.duplexRiseDoubleSpinBox  =  \
            PM_DoubleSpinBox( pmGroupBox,
                              label         =  "Rise:",
                              value         =  self.duplexRise,
                              setAsDefault  =  True,
                              minimum       =  2.0,
                              maximum       =  4.0,
                              decimals      =  3,
                              singleStep    =  0.01 )
        
        self.disableStructHighlightingCheckbox = \
            PM_CheckBox( pmGroupBox,
                         text         = "Don't highlight while editing DNA",
                         widgetColumn  = 0,
                         state        = Qt.Unchecked,
                         setAsDefault = True,
                         spanWidth = True
                         )
        
        #As of 2008-03-31, the properties such as number of bases will be 
        #editable only by using the resize handles. post FNANO we will support 
        #the 
        self.numberOfBasesSpinBox.setEnabled(False)
        self.basesPerTurnDoubleSpinBox.setEnabled(False)
        self.duplexRiseDoubleSpinBox.setEnabled(False)
        
    
            
    def _loadSequenceEditor(self):
        """
        Temporary code  that shows the Sequence editor ..a doc widget docked
        at the bottom of the mainwindow. The implementation is going to change
        before 'rattleSnake' product release.
        As of 2007-11-20: This feature (sequence editor) is waiting 
        for the ongoing dna model work to complete.
        """
        self.sequenceEditor = self.win.createDnaSequenceEditorIfNeeded() 
        self.sequenceEditor.hide()
        
        
    def _loadDisplayOptionsGroupBox(self, pmGroupBox):
        """
        Overrides superclass method. 
        Also loads the color chooser widget. 
        """
        self._loadColorChooser(pmGroupBox)
        _superclass._loadDisplayOptionsGroupBox(self, pmGroupBox)
        
         
    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 , 
            dnaStrandEditCommand_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 bases", 
                   dnaStrandEditCommand_cursorTextCheckBox_numberOfBases_prefs_key),

                  ("Number of bases to be changed",
                   dnaStrandEditCommand_cursorTextCheckBox_changedBases_prefs_key) 
                 ]

        return params
    
        
    def getParameters(self):
        numberOfBases = self.numberOfBasesSpinBox.value()
        dnaForm  = self._conformation
        dnaModel = self.dnaModel
        basesPerTurn = self.basesPerTurn
        duplexRise = self.duplexRise
        color = self._colorChooser.getColor()
              
        return (numberOfBases, 
                dnaForm,
                dnaModel,
                basesPerTurn,
                duplexRise, 
                color
                )
    
    def setParameters(self, params):
        """
        This is usually called when you are editing an existing structure. 
        Some property manager ui elements then display the information 
        obtained from the object being edited. 
        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?  
        """
        #Set the duplex rise and bases per turn spinbox values. 
        
        numberOfBases, \
                     dnaForm, \
                     dnaModel, \
                     basesPerTurn, \
                     duplexRise, \
                     color  = params 
        
        if numberOfBases is not None:
            self.numberOfBasesSpinBox.setValue(numberOfBases)
        if dnaForm is not None:
            self._conformation = dnaForm
        if dnaModel is not None:
            self.dnaModel = dnaModel
        if duplexRise is not None:
            self.duplexRiseDoubleSpinBox.setValue(duplexRise)
        if basesPerTurn is not None:
            self.basesPerTurnDoubleSpinBox.setValue(basesPerTurn)    
        if color is not None:
            self._colorChooser.setColor(color)
    
    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
        """
        #TODO: This is a temporary fix for a bug. When you invoke a temporary
        # mode Entering such a temporary mode keeps the signals of 
        #PM from the previous mode connected (
        #but while exiting that temporary mode and reentering the 
        #previous mode, it atucally reconnects the signal! This gives rise to 
        #lots  of bugs. This needs more general fix in Temporary mode API. 
        # -- Ninad 2008-01-09 (similar comment exists in MovePropertyManager.py
                
        if isConnect and self.isAlreadyConnected:
            if debug_flags.atom_debug:
                print_compact_stack("warning: attempt to connect widgets"\
                                    "in this PM that are already connected." )
            return 
        
        if not isConnect and self.isAlreadyDisconnected:
            if debug_flags.atom_debug:
                print_compact_stack("warning: attempt to disconnect widgets"\
                                    "in this PM that are already disconnected.")
            return
        
        self.isAlreadyConnected = isConnect
        self.isAlreadyDisconnected = not isConnect
        
        if isConnect:
            change_connect = self.win.connect     
        else:
            change_connect = self.win.disconnect 
          
                
        if self.sequenceEditor:
            self.sequenceEditor.connect_or_disconnect_signals(isConnect)
            
        _superclass.connect_or_disconnect_signals(self, isConnect)
            
        
        change_connect(self.disableStructHighlightingCheckbox, 
                       SIGNAL('stateChanged(int)'), 
                       self.change_struct_highlightPolicy)
        
        change_connect(self.showCursorTextCheckBox, 
                       SIGNAL('stateChanged(int)'), 
                       self._update_state_of_cursorTextGroupBox)
        
    def model_changed(self): 
        """
        @see: DnaStrand_EditCommand.model_changed()
        @see: DnaStrand_EditCommand.hasResizableStructure()
        """
        isStructResizable, why_not = self.editCommand.hasResizableStructure()
        if not isStructResizable:
            #disable all widgets
            if self._pmGroupBox1.isEnabled():
                self._pmGroupBox1.setEnabled(False)
                msg1 = ("Viewing properties of %s <br>") %(self.editCommand.struct.name) 
                msg2 = redmsg("DnaStrand is not resizable. Reason: %s"%(why_not))                    
                self.updateMessage(msg1 + msg2)
        else:
            if not self._pmGroupBox1.isEnabled():
                self._pmGroupBox1.setEnabled(True)
                msg1 = ("Viewing properties of %s <br>") %(self.editCommand.struct.name) 
                msg2 = "Use resize handles to resize the strand. Use sequence editor"\
                    "to assign a new sequence or the current one to a file."
                self.updateMessage(msg1 + msg2)
        
    def show(self):
        """
        Show this PM 
        As of 2007-11-20, it also shows the Sequence Editor widget and hides 
        the history widget. This implementation may change in the near future
        This method also retrives the name information from the 
        editCommand's structure for its name line edit field. 
        @see: DnaStrand_EditCommand.getStructureName()
        @see: self.close()
        """
        _superclass.show(self) 
        self._showSequenceEditor()
    
        if self.editCommand is not None:
            name = self.editCommand.getStructureName()
            if name is not None:
                self.nameLineEdit.setText(name)     
           
    def close(self):
        """
        Close this property manager. 
        Also sets the name of the self.editCommand's structure to the one 
        displayed in the line edit field.
        @see self.show()
        @see: DnaSegment_EditCommand.setStructureName
        """
        if self.editCommand is not None:
            name = str(self.nameLineEdit.text())
            self.editCommand.setStructureName(name)
            
        if self.sequenceEditor:
            self.sequenceEditor.close()
                            
        _superclass.close(self)
            
    def _showSequenceEditor(self):
        if self.sequenceEditor:
            if not self.sequenceEditor.isVisible():
                #Show the sequence editor
                #ATTENTION: the sequence editor also closes (temporarily) the
                #reports dockwidget (if visible) Its state is later restored when
                #the sequuence Editor is closed. 
                self.sequenceEditor.show()     
                                              
            self.updateSequence()

        
    def updateSequence(self):
        """
        Update the sequence string in the sequence editor
        @see: DnaSequenceEditor.setSequence()
        @see DnaSequenceEditor._determine_complementSequence()
        @see: DnaSequenceEditor.setComplementSequence()
        @see: DnaStrand.getStrandSequenceAndItsComplement()
        """
        #Read in the strand sequence of the selected strand and 
        #show it in the text edit in the sequence editor.
        ##strand = self.strandListWidget.getPickedItem()
        
        if not self.editCommand.hasValidStructure():
            return
        
        strand = self.editCommand.struct
        
        titleString = 'Sequence Editor for ' + strand.name
                           
        self.sequenceEditor.setWindowTitle(titleString)
        sequenceString, complementSequenceString = strand.getStrandSequenceAndItsComplement()
        if sequenceString:
            sequenceString = QString(sequenceString) 
            sequenceString = sequenceString.toUpper()
            #Set the initial sequence (read in from the file)
            self.sequenceEditor.setSequence(sequenceString)
            
            #Set the initial complement sequence for DnaSequence editor. 
            #do this independently because 'complementSequenceString' may have
            #some characters (such as * ) that denote a missing base on the 
            #complementary strand. this information is used by the sequence
            #editor. See DnaSequenceEditor._determine_complementSequence() 
            #for more details. See also bug 2787
            self.sequenceEditor.setComplementSequence(complementSequenceString)

            
    def change_struct_highlightPolicy(self,checkedState = False):
        """
        Change the 'highlight policy' of the structure being edited 
        (i.e. self.editCommand.struct) . 
        @param checkedState: The checked state of the checkbox that says 
                             'Don't highlight while editing DNA'. So, it 
                             its True, the structure being edited won't get
                             highlighted. 
        @see: DnaStrand.setHighlightPolicy for more comments        
        """        
        if self.editCommand and self.editCommand.hasValidStructure():
            highlight = not checkedState
            self.editCommand.struct.setHighlightPolicy(highlight = highlight)

    def _addWhatsThisText(self):
        """
        Add what's this text. 
        Abstract method.
        """
        pass
    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 _loadGroupBox1(self, pmGroupBox):
        """
        Load widgets in group box 1.
        """
        # Duplex Length
        self.duplexLengthSpinBox  =  \
            PM_DoubleSpinBox( pmGroupBox,
                              label         =  "Duplex Length: ",
                              value         =  0,
                              setAsDefault  =  False,
                              minimum       =  0,
                              maximum       =  34000,
                              singleStep    =  self.getDuplexRise("B-DNA"),
                              decimals      =  3,
                              suffix        =  ' Angstroms')

        self.connect( self.duplexLengthSpinBox,
                      SIGNAL("valueChanged(double)"),
                      self.duplexLengthChanged )

        # Strand Length
        self.strandLengthSpinBox = \
            PM_SpinBox( pmGroupBox,
                        label         =  "Strand Length :",
                        value         =  0,
                        setAsDefault  =  False,
                        minimum       =  0,
                        maximum       =  10000,
                        suffix        =  ' bases' )

        self.connect( self.strandLengthSpinBox,
                      SIGNAL("valueChanged(int)"),
                      self.strandLengthChanged )
        # New Base choices
        newBaseChoices  =  []
        for theBase in basesDict.keys():
            newBaseChoices  =  newBaseChoices \
                            + [ theBase + ' (' \
                            + basesDict[theBase]['Name'] + ')' ]

        try:
            defaultBaseChoice = basesDict.keys().index('N')
        except:
            defaultBaseChoice = 0

        # Strand Sequence
        self.sequenceTextEdit = \
            PM_TextEdit( pmGroupBox,
                         label      =  "",
                         spanWidth  =  True )

        self.sequenceTextEdit.setCursorWidth(2)
        self.sequenceTextEdit.setWordWrapMode( QTextOption.WrapAnywhere )

        self.connect( self.sequenceTextEdit,
                      SIGNAL("textChanged()"),
                      self.sequenceChanged )

        self.connect( self.sequenceTextEdit,
                      SIGNAL("cursorPositionChanged()"),
                      self.cursorPosChanged )

        # Actions
        self.actionsComboBox  = \
            PM_ComboBox( pmGroupBox,
                         label         =  '',
                         choices       =  self._actionChoices,
                         index         =  0,
                         setAsDefault  =  True,
                         spanWidth     =  True )

        # If SIGNAL("activate(const QString&)") is used, we get a TypeError.
        # This is a bug that needs Bruce. Using currentIndexChanged(int) as
        # a workaround, but there is still a bug when the "Reverse" action
        # is selected. Mark 2007-08-15
        self.connect( self.actionsComboBox,
                      SIGNAL("currentIndexChanged(int)"),
                      self.actionsComboBoxChanged )
    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 )
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 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 DnaStrand_PropertyManager(DnaOrCnt_PropertyManager):
    """
    The DnaStrand_PropertyManager class provides a Property Manager
    for the DnaStrand_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 = "DnaStrand Properties"
    iconPath = "ui/actions/Properties Manager/Strand.png"

    def __init__(self, command):
        """
        Constructor for the Build DNA property manager.
        """

        self.sequenceEditor = None

        self._numberOfBases = 0
        self._conformation = 'B-DNA'
        self.dnaModel = 'PAM3'

        _superclass.__init__(self, command)

        self.showTopRowButtons( PM_DONE_BUTTON | \
                                PM_WHATS_THIS_BUTTON)
        return

    def _addGroupBoxes(self):
        """
        Add group boxes to this PM.
        """

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

        #Sequence Editor. This is NOT a groupbox, needs cleanup. Doing it here
        #so that the sequence editor gets connected! Perhaps
        #superclass should define _loadAdditionalWidgets. -- Ninad2008-10-03
        self._loadSequenceEditor()
        return

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

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

        self.numberOfBasesSpinBox = \
            PM_SpinBox( pmGroupBox,
                        label         =  "Number of bases:",
                        value         =  self._numberOfBases,
                        setAsDefault  =  False,
                        minimum       =  2,
                        maximum       =  10000 )

        self.disableStructHighlightingCheckbox = \
            PM_CheckBox( pmGroupBox,
                         text         = "Don't highlight while editing DNA",
                         widgetColumn  = 0,
                         state        = Qt.Unchecked,
                         setAsDefault = True,
                         spanWidth = True
                         )

        #As of 2008-03-31, the properties such as number of bases will be
        #editable only by using the resize handles.
        self.numberOfBasesSpinBox.setEnabled(False)
        return

    def _loadSequenceEditor(self):
        """
        Temporary code  that shows the Sequence editor ..a doc widget docked
        at the bottom of the mainwindow. The implementation is going to change
        before 'rattleSnake' product release.
        As of 2007-11-20: This feature (sequence editor) is waiting
        for the ongoing dna model work to complete.
        """
        self.sequenceEditor = self.win.createDnaSequenceEditorIfNeeded()
        self.sequenceEditor.hide()
        return

    def _loadDisplayOptionsGroupBox(self, pmGroupBox):
        """
        Overrides superclass method.
        Also loads the color chooser widget.
        """
        self._loadColorChooser(pmGroupBox)
        _superclass._loadDisplayOptionsGroupBox(self, pmGroupBox)
        return

    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,
            dnaStrandEditCommand_showCursorTextCheckBox_prefs_key)
        return

    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 bases",
                   dnaStrandEditCommand_cursorTextCheckBox_numberOfBases_prefs_key),

                  ("Number of bases to be changed",
                   dnaStrandEditCommand_cursorTextCheckBox_changedBases_prefs_key)
                 ]

        return params

    def getParameters(self):
        name = self.nameLineEdit.text()
        numberOfBases = self.numberOfBasesSpinBox.value()
        dnaForm = self._conformation
        dnaModel = self.dnaModel
        color = self._colorChooser.getColor()

        return (numberOfBases, dnaForm, dnaModel, color, name)

    def setParameters(self, params):
        """
        This is usually called when you are editing an existing structure.
        It also gets called when selecting a new strand (within this command).
        Some property manager ui elements then display the information
        obtained from the object being edited.
        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?
        """
        numberOfBases, \
            dnaForm, \
            dnaModel, \
            color, \
            name = params

        if numberOfBases is not None:
            self.numberOfBasesSpinBox.setValue(numberOfBases)
        if dnaForm is not None:
            self._conformation = dnaForm
        if dnaModel is not None:
            self.dnaModel = dnaModel

        if color is not None:
            self._colorChooser.setColor(color)

        if name:  # Minimal test. Should add a validator. --Mark 2008-12-16
            self.nameLineEdit.setText(name)

        # This gets called when we enter the command *and* when selecting a new
        # strand. In either case, we must update the sequence in the sequenece
        # editor. Fixes bug 2951. --Mark 2008-12-16
        if self.command and self.command.hasValidStructure():
            #print "setParameters(): loading sequence in sequence editor for ", name
            self.updateSequence(strand=self.command.struct)
        return

    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
        """
        #TODO: This is a temporary fix for a bug. When you invoke a temporary
        # mode Entering such a temporary mode keeps the signals of
        #PM from the previous mode connected (
        #but while exiting that temporary mode and reentering the
        #previous mode, it atucally reconnects the signal! This gives rise to
        #lots  of bugs. This needs more general fix in Temporary mode API.
        # -- Ninad 2008-01-09 (similar comment exists in MovePropertyManager.py

        if isConnect and self.isAlreadyConnected:
            if debug_flags.atom_debug:
                print_compact_stack("warning: attempt to connect widgets"\
                                    "in this PM that are already connected." )
            return

        if not isConnect and self.isAlreadyDisconnected:
            if debug_flags.atom_debug:
                print_compact_stack("warning: attempt to disconnect widgets"\
                                    "in this PM that are already disconnected.")
            return

        self.isAlreadyConnected = isConnect
        self.isAlreadyDisconnected = not isConnect

        if isConnect:
            change_connect = self.win.connect
        else:
            change_connect = self.win.disconnect

        if self.sequenceEditor:
            self.sequenceEditor.connect_or_disconnect_signals(isConnect)

        _superclass.connect_or_disconnect_signals(self, isConnect)

        change_connect(self.disableStructHighlightingCheckbox,
                       SIGNAL('stateChanged(int)'),
                       self.change_struct_highlightPolicy)

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

        change_connect(self.nameLineEdit, SIGNAL("editingFinished()"),
                       self._nameChanged)
        return

    def _update_UI_do_updates(self):
        """
        @see: Command_PropertyManager. _update_UI_do_updates()
        @see: DnaStrand_EditCommand.command_update_UI()
        @see: DnaStrand_EditCommand.hasResizableStructure()
        """
        if not self.command.hasValidStructure():
            print "DnaStrand not a valid structure."
            self._pmGroupBox1.setEnabled(False)
            self._displayOptionsGroupBox.setEnabled(False)
            self.sequenceEditor.updateSequence(strand=" ")
            self.sequenceEditor.setEnabled(False)
            self.nameLineEdit.setText("")
            self.numberOfBasesSpinBox.setValue(0)
            return
        else:
            self._pmGroupBox1.setEnabled(True)
            self._displayOptionsGroupBox.setEnabled(True)
            self.sequenceEditor.setEnabled(True)

        isStructResizable, why_not = self.command.hasResizableStructure()
        if not isStructResizable:
            #disable all widgets
            if self._pmGroupBox1.isEnabled():
                self._pmGroupBox1.setEnabled(False)
                msg1 = ("Attention: ") % (self.command.struct.name)
                msg2 = redmsg("DnaStrand <b>%s</b> is not resizable. Reason: %s" % \
                              (self.command.struct.name, why_not))
                self.updateMessage(msg1 + msg2)
        else:
            if not self._pmGroupBox1.isEnabled():
                self._pmGroupBox1.setEnabled(True)
            msg1 = ("Editing <b>%s</b>. ") % (self.command.struct.name)
            msg2 = "Use resize handles to resize the strand. "\
                 "Use the <i>Sequence Editor</i> to edit the sequence."
            self.updateMessage(msg1 + msg2)
        return

    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: DnaSegment_EditCommand.setStructureName
        """
        if self.command is not None:
            name = str(self.nameLineEdit.text())
            self.command.setStructureName(name)

        if self.sequenceEditor:
            self.sequenceEditor.close()

        _superclass.close(self)
        return

    def updateSequence(self, strand=None):
        """
        Public method provided for convenience. If any callers outside of this
        command need to update the sequence in the sequence editor, they can simply
        do DnaStrand_ProprtyManager.updateSequence() rather than
        DnaStrand_ProprtyManager.sequenceEditor.updateSequence()
        @see: Ui_DnaSequenceEditor.updateSequence()
        """
        if self.sequenceEditor:
            self.sequenceEditor.updateSequence(strand=strand)
        return

    def change_struct_highlightPolicy(self, checkedState=False):
        """
        Change the 'highlight policy' of the structure being edited
        (i.e. self.command.struct) .
        @param checkedState: The checked state of the checkbox that says
                             'Don't highlight while editing DNA'. So, it
                             its True, the structure being edited won't get
                             highlighted.
        @see: DnaStrand.setHighlightPolicy for more comments
        """
        if self.command and self.command.hasValidStructure():
            highlight = not checkedState
            self.command.struct.setHighlightPolicy(highlight=highlight)
        return

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

    def _nameChanged(self):  # Added by Mark. 2008-12-16
        """
        Slot for "Name" field. Changes the name of the strand if the user types
        in a new name.

        @warning: this lacks a validator. User can type in a name with invalid
                  characters.
        """
        if not self.command.hasValidStructure():
            return

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

        if not name:  # Minimal test. Should add a validator. Ask Bruce for example validator code somewhere. --Mark 2008-12-16
            if self.command.hasValidStructure():
                self.nameLineEdit.setText(self.command.getStructureName())

            return

        self.command.setStructureName(name)

        self._update_UI_do_updates()  # Updates the message box.

        return
class BuildProtein_PropertyManager(EditCommand_PM):
    """
    The BuildDna_PropertyManager class provides a Property Manager
    for the B{Build > Protein } 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         =  "Build Protein"
    pmName        =  title
    #change this icon path later
    iconPath      =  "ui/actions/Tools/Build Structures/Protein.png"

    def __init__( self, command ):
        """
        Constructor for the Build DNA property manager.
        """

        self.current_protein = ""
        self.sequenceEditor = command.win.createProteinSequenceEditorIfNeeded()

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

        EditCommand_PM.__init__( self, command)

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

    def _updateProteinListForShow(self):
        """
        Update the list of proteins in the combo box in the PM.
        """
        #first remove from combo box all the proteins that do not exist in NE-1
        #part anymore
        currentProteinNameList = []
        for mol in self.win.assy.molecules:
            currentProteinNameList.append(mol.name)

        for name in self.protein_name_list:
            try:
                index = currentProteinNameList.index(name)
            except ValueError:
                #protein does not exist any more, need to remove it
                i = self.protein_name_list.index(name)
                self.protein_chunk_list.pop(i)
                self.protein_name_list.pop(i)
                j = self.structureComboBox.findText(name)
                self.structureComboBox.removeItem(j)

        for mol in self.win.assy.molecules:
            #if molecules does not already exist in combo box list, need to add
            #them
            if mol.isProteinChunk():
                try:
                    self.protein_name_list.index(mol.name)
                except ValueError:
                    self.protein_chunk_list.append(mol)
                    self.protein_name_list.append(mol.name)
                    self.structureComboBox.addItem(mol.name)
        return

    def show(self):
        """
        Overrides superclass show method
        """
        env.history.statusbar_msg("")
        self._updateProteinListForShow()
        self._showProteinParametersAndSequenceEditor()
        EditCommand_PM.show(self)
        self.updateMessage()
        return

    def close(self):
        """
        Overrides superclass close method
        """
        self.sequenceEditor.hide()
        env.history.statusbar_msg("")
        EditCommand_PM.close(self)
        return

    def _updateProteinList(self):
        """
        Update the list of proteins so that the protein name combo box in this
        PM can be populated.
        """
        self.protein_chunk_list = []
        self.protein_name_list = []
        for mol in self.win.assy.molecules:
            if mol.isProteinChunk():
                self.protein_chunk_list.append(mol)
                self.protein_name_list.append(mol.name)
        return


    def _showProteinParametersAndSequenceEditor(self):
        """
        Show/ Hide protein parameters and sequence editor based on if there's
        any protein in NE-1 part.
        """
        part = self.win.assy.part
        proteinExists, proteinChunk = checkIfProteinChunkInPart(part)
        if proteinExists:
            #check to see if current_protein is still in part, otherwise set
            # this to first available protein
            try:
                index = self.structureComboBox.findText(self.current_protein)
                index1 = self.protein_name_list.index(self.current_protein)
            except ValueError:
                index = 0
                index1 = 0
                self.set_current_protein_chunk_name(self.protein_name_list[index1])

            self.structureComboBox.setCurrentIndex(index)
            proteinChunk = self.protein_chunk_list[index1]
            self._numberOfAA = len(proteinChunk.protein.get_sequence_string())
        else:
            #remove all items from the combo box
            count = self.structureComboBox.count()
            for i in range(count):
                self.structureComboBox.removeItem(0)
            self._numberOfAA = 0
            self.set_current_protein_chunk_name("")
        self.numberOfAASpinBox.setValue(self._numberOfAA)


        #get the sequence for this protein chunk
        if proteinExists:
            sequence = proteinChunk.protein.get_sequence_string()
            self.sequenceEditor.setSequence(sequence)
            secStructure = proteinChunk.protein.get_secondary_structure_string()
            self.sequenceEditor.setSecondaryStructure(secStructure)
            self.sequenceEditor.setRuler(len(secStructure))
            self.editPropertiesPushButton.setEnabled(True)
        else:
            self.editPropertiesPushButton.setEnabled(False)
        self.sequenceEditor.hide()
        return

    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 and self.isAlreadyConnected:
            return

        if not isConnect and self.isAlreadyDisconnected:
            return

        self.isAlreadyConnected = isConnect
        self.isAlreadyDisconnected = not isConnect

        if isConnect:
            change_connect = self.win.connect
        else:
            change_connect = self.win.disconnect
        change_connect(self.structureComboBox,
                      SIGNAL("currentIndexChanged(int)"),
                       self._updateProteinParameters)
        change_connect(self.editPropertiesPushButton,
                       SIGNAL("clicked()"),
                       self._showSeqEditor)

    def _showSeqEditor(self):
        """
        Show sequence editor
        """
        if self.editPropertiesPushButton.isEnabled():
            self.sequenceEditor.show()
        return

    def _updateProteinParameters(self, index):
        """
        Update number of amino acids and sequence editor, as well as set the
        current protein pdb id which will be used in the child commands and for
        rosetta simulation from inside the build protein mode.
        @param index: index of the protein combo box
        @type index: int
        """
        for mol in self.protein_chunk_list:
            if  mol.name == self.structureComboBox.currentText():
                self._numberOfAA = len(mol.protein.get_sequence_string())
                self.numberOfAASpinBox.setValue(self._numberOfAA)
                sequence = mol.protein.get_sequence_string()
                self.sequenceEditor.setSequence(sequence)
                secStructure = mol.protein.get_secondary_structure_string()
                self.sequenceEditor.setSecondaryStructure(secStructure)
                self.sequenceEditor.setRuler(len(secStructure))
                break
        self.set_current_protein_chunk_name(mol.name)
        env.history.statusbar_msg("")
        return

    def set_current_protein_chunk_name(self, name):
        """
        Sets the current protein name
        @param name: pdb id of the protein currently selected in the combo box
        @type name: str
        """
        self.current_protein = name
        return


    def get_current_protein_chunk_name(self):
        """
        gets the current protein name
        @return: pdb id of the protein currently selected in the combo box
        """
        return self.current_protein


    def enable_or_disable_gui_actions(self, bool_enable = False):
        """
        Enable or disable some gui actions when this property manager is
        opened or closed, depending on the bool_enable.
        @param bool_enable: enables/disables some gui action
        @type bool_enable: bool

        """
        if hasattr(self.command, 'flyoutToolbar') and \
           self.command.flyoutToolbar:
            self.command.flyoutToolbar.exitProteinAction.setEnabled(not bool_enable)


    def _addWhatsThisText( self ):
        """
        What's This text for widgets in the DNA Property Manager.
        """
        pass

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

    def _addGroupBoxes(self):
        """
        Add the DNA Property Manager group boxes.
        """
        self._pmGroupBox1 = PM_GroupBox(self, title = "Parameters")
        self._loadGroupBox1(self._pmGroupBox1)
        return

    def _loadGroupBox1(self, pmGroupBox):
        """
        Load widgets in group box 1.
        @param pmGroupBox: group box that contains protein name combo box and
                        number of amino acids spin box
        @see: L{PM_GroupBox}
        """
        self._updateProteinList()
        if len(self.protein_name_list) >= 1:
            self.set_current_protein_chunk_name(self.protein_name_list[0])
        self.structureComboBox = PM_ComboBox( pmGroupBox,
                                 label         =  "Name:",
                                 choices       =  self.protein_name_list,
                                 setAsDefault  =  False)

        #Urmi 20080713: May be useful to set the minimum value to not zero
        #Now it does not matter, since its disabled. But zero as the minimum
        #value in a spinbox does not work otherwise.
        self.numberOfAASpinBox = \
            PM_SpinBox( pmGroupBox,
                        label         =  "Amino Acids:",
                        value         =  0,
                        setAsDefault  =  False,
                        minimum       =  0,
                        maximum       =  10000 )
        #for now we do not allow changing number of residues
        self.numberOfAASpinBox.setEnabled(False)
        self.editPropertiesPushButton = PM_PushButton( pmGroupBox,
            text       =  "Edit Sequence",
            setAsDefault  =  True
            )
Exemple #49
0
class NanotubeGeneratorPropertyManager(PM_Dialog):
    """
    The NanotubeGeneratorPropertyManager class provides a Property Manager 
    for the "Build > Nanotube" command.
    """
    # The title that appears in the property manager header.
    title = "Nanotube"
    # The name of this property manager. This will be set to
    # the name of the PropMgr (this) object via setObjectName().
    pmName = title
    # The relative path to PNG file that appears in the header.
    iconPath = "ui/actions/Tools/Build Structures/Nanotube.png"
    
    def __init__(self):
        """Construct the Graphene Property Manager.
        """
        PM_Dialog.__init__(self, self.pmName, self.iconPath, self.title)
        #@self.addGroupBoxes()
        #@self.add_whats_this_text()
        self.updateMessageGroupBox()
        
    def updateMessageGroupBox(self):
        msg = ""

        # A (4, 4) tube is stable, but a (3, 3) has not been seen in
        # isolation.  Circumference of a (4, 4) tube is about 6.93.
        xOffset = self.n + self.m * math.cos(math.pi/3.0)
        yOffset = self.m * math.sin(math.pi/3.0)
        circumference = math.sqrt(xOffset * xOffset + yOffset * yOffset)
        if (circumference < 6.5):
            msg = "Warning: Small diameter nanotubes may be unstable, \
            and may give unexpected results when minimized.<p>"

        msg = msg + "Edit the Nanotube parameters and select <b>Preview</b> to \
        preview the structure. Click <b>Done</b> to insert it into the model."
        
        # This causes the "Message" box to be displayed as well.
        # setAsDefault=True causes this message to be reset whenever
        # this PropMgr is (re)displayed via show(). Mark 2007-06-01.
        self.MessageGroupBox.insertHtmlMessage(msg, setAsDefault=True)

        
    def _addGroupBoxes(self):
        """
        Add the 3 group boxes to the Nanotube Property Manager dialog.
        """
        self.pmGroupBox1 = \
            PM_GroupBox( self, 
                         title          = "Nanotube Parameters" )
                
        self.pmGroupBox2 = \
            PM_GroupBox( self, 
                         title          = "Nanotube Distortion" )
                
        self.pmGroupBox3 = \
            PM_GroupBox( self, 
                         title          = "Multi-Walled Nanotubes" )

        # Add group box widgets.
        self._loadGroupBox1(self.pmGroupBox1)
        self._loadGroupBox2(self.pmGroupBox2)
        self._loadGroupBox3(self.pmGroupBox3)
        
    def _loadGroupBox1(self, inPmGroupBox):
        """
        Load widgets in group box 1.
        """
        
        memberChoices = ["Carbon", "Boron Nitride"]
        self.typeComboBox= \
            PM_ComboBox( inPmGroupBox,
                         label        = "Type :", 
                         choices      = memberChoices, 
                         index        = 0, 
                         setAsDefault = True,
                         spanWidth    = False )
        
        self.connect( self.typeComboBox,
                      SIGNAL("currentIndexChanged(int)"),
                      self.nt_type_changed)
            
        self.lengthField = \
            PM_DoubleSpinBox( inPmGroupBox, 
                              label        = "Length :", 
                              value        = 20.0, 
                              setAsDefault = True,
                              minimum      = 1.0, 
                              maximum      = 1000.0, 
                              singleStep   = 1.0, 
                              decimals     = 3, 
                              suffix       = " Angstroms" )
        
        self.n = 5
        
        self.chiralityNSpinBox = \
            PM_SpinBox( inPmGroupBox, 
                        label        = "Chirality (n) :", 
                        value        = self.n, 
                        setAsDefault = True )
        
        self.connect(self.chiralityNSpinBox,
                     SIGNAL("valueChanged(int)"),
                     self.chirality_fixup)
        
        self.m = 5
        
        self.chiralityMSpinBox = \
            PM_SpinBox( inPmGroupBox, 
                        label        = "Chirality (m) :", 
                        value        = self.m, 
                        setAsDefault = True )
        
        self.connect(self.chiralityMSpinBox,
                     SIGNAL("valueChanged(int)"),
                     self.chirality_fixup)
        
        self.bondLengthField = \
            PM_DoubleSpinBox( inPmGroupBox,
                              label        = "Bond Length :", 
                              value        = CC_GRAPHITIC_BONDLENGTH, 
                              setAsDefault = True,
                              minimum      = 1.0, 
                              maximum      = 3.0, 
                              singleStep   = 0.1, 
                              decimals     = 3, 
                              suffix       = " Angstroms" )
        
        endingChoices = ["None", "Hydrogen", "Nitrogen"]
        
        self.endingsComboBox= \
            PM_ComboBox( inPmGroupBox,
                         label        = "Endings :", 
                         choices      = endingChoices, 
                         index        = 0, 
                         setAsDefault = True,
                         spanWidth    = False )
        
    def _loadGroupBox2(self, inPmGroupBox):
        """
        Load widgets in group box 2.
        """
        
        self.zDistortionField = \
            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.xyDistortionField = \
            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 _loadGroupBox3(self, inPmGroupBox):
        """
        Load widgets in group box 3.
        """
        
        # "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.mwntSpacingField = \
            PM_DoubleSpinBox( inPmGroupBox,
                              label        = "Spacing :", 
                              value        = 2.46, 
                              setAsDefault = True,
                              minimum      = 1.0, 
                              maximum      = 10.0, 
                              singleStep   = 0.1, 
                              decimals     = 3, 
                              suffix       = " Angstroms" )
    
    def _addWhatsThisText(self):
        """
        What's This text for widgets in this Property Manager.  
        """
        from ne1_ui.WhatsThisText_for_PropertyManagers import whatsThis_NanotubeGeneratorPropertyManager
        whatsThis_NanotubeGeneratorPropertyManager(self)
        
    def _addToolTipText(self):
        """
        Tool Tip text for widgets in this Property Manager.  
        """
        from ne1_ui.ToolTipText_for_PropertyManagers import ToolTip_NanotubeGeneratorPropertyManager
        ToolTip_NanotubeGeneratorPropertyManager(self)
        
    def chirality_fixup(self, spinBoxValueJunk = None):
        """
        Slot for several validators for different parameters.
        This gets called each time a user types anything into a widget or 
        changes a spinbox.
        @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  
        """
                
        if not hasattr(self, 'n'):
            print_compact_traceback("Bug: no attr 'n' ") # mark 2007-05-24
            return
        
        n_previous = int(self.n)
        m_previous = int(self.m)
        n = self.chiralityNSpinBox.value()
        m = self.chiralityMSpinBox.value()
        # Two restrictions to maintain
        # n >= 2
        # 0 <= m <= n
        if n < 2:
            n = 2
        if m != self.m:
            # The user changed m. If m became larger than n, make n bigger.
            if m > n:
                n = m
        elif n != self.n:
            # The user changed n. If n became smaller than m, make m smaller.
            if m > n:
                m = n
        self.chiralityNSpinBox.setValue(n)
        self.chiralityMSpinBox.setValue(m)
        self.m, self.n = m, n
        self.updateMessageGroupBox()

    def nt_type_changed(self, idx):
        """
        Slot for Nanotube Type combobox.
        Update the bond length field when the type changes.
        """
        self.bondLengthField.setValue(ntBondLengths[idx])
    def _loadGroupBox2(self, pmGroupBox):
        """
        Load widgets in group box.
        """
        self.bondAngleWeightSimSpinBox = PM_DoubleSpinBox(
            pmGroupBox,
            labelColumn=0,
            label="Bond angle weight:",
            minimum=0.01,
            decimals=2,
            maximum=1.0,
            singleStep=0.01,
            value=1.0,
            setAsDefault=False,
            spanWidth=False)

        bond_angle_param_list = ['Amber', 'Charmm']

        self.bondAngleParamComboBox = PM_ComboBox(
            pmGroupBox,
            label="Bond angle parameters:",
            choices=bond_angle_param_list,
            setAsDefault=False)

        self.onlybbSpinBox = PM_DoubleSpinBox(pmGroupBox,
                                              labelColumn=0,
                                              label="Only backbone rotation:",
                                              minimum=0.01,
                                              maximum=1.0,
                                              value=0.75,
                                              decimals=2,
                                              singleStep=0.01,
                                              setAsDefault=False,
                                              spanWidth=False)

        self.onlyrotSpinBox = PM_DoubleSpinBox(pmGroupBox,
                                               labelColumn=0,
                                               label="Only rotamer rotation:",
                                               minimum=0.01,
                                               maximum=1.0,
                                               decimals=2,
                                               value=0.25,
                                               singleStep=0.01,
                                               setAsDefault=False,
                                               spanWidth=False)

        self.mctempSpinBox = PM_DoubleSpinBox(
            pmGroupBox,
            labelColumn=0,
            label="MC simulation temperature:",
            minimum=0.1,
            value=0.6,
            maximum=1.0,
            decimals=2,
            singleStep=0.1,
            setAsDefault=False,
            spanWidth=False)

        numResidues = self._getNumResiduesForCurrentProtein()
        self.minresSpinBox = PM_SpinBox(pmGroupBox,
                                        labelColumn=0,
                                        label="Minimum number of residues:",
                                        minimum=2,
                                        maximum=numResidues,
                                        singleStep=1,
                                        setAsDefault=False,
                                        spanWidth=False)

        self.maxresSpinBox = PM_SpinBox(pmGroupBox,
                                        labelColumn=0,
                                        label="Maximum number of residues:",
                                        minimum=2,
                                        maximum=numResidues,
                                        singleStep=1,
                                        setAsDefault=False,
                                        spanWidth=False)
        if numResidues == 0:
            self.minresSpinBox.setMaximum(numResidues + 2)
            self.maxresSpinBox.setMaximum(numResidues + 2)
        return
Exemple #51
0
 def _loadGroupBox1(self, inPmGroupBox):
     """
     Load widgets in group box 1.
     """
     
     memberChoices = ["Carbon", "Boron Nitride"]
     self.typeComboBox= \
         PM_ComboBox( inPmGroupBox,
                      label        = "Type :", 
                      choices      = memberChoices, 
                      index        = 0, 
                      setAsDefault = True,
                      spanWidth    = False )
     
     self.connect( self.typeComboBox,
                   SIGNAL("currentIndexChanged(int)"),
                   self.nt_type_changed)
         
     self.lengthField = \
         PM_DoubleSpinBox( inPmGroupBox, 
                           label        = "Length :", 
                           value        = 20.0, 
                           setAsDefault = True,
                           minimum      = 1.0, 
                           maximum      = 1000.0, 
                           singleStep   = 1.0, 
                           decimals     = 3, 
                           suffix       = " Angstroms" )
     
     self.n = 5
     
     self.chiralityNSpinBox = \
         PM_SpinBox( inPmGroupBox, 
                     label        = "Chirality (n) :", 
                     value        = self.n, 
                     setAsDefault = True )
     
     self.connect(self.chiralityNSpinBox,
                  SIGNAL("valueChanged(int)"),
                  self.chirality_fixup)
     
     self.m = 5
     
     self.chiralityMSpinBox = \
         PM_SpinBox( inPmGroupBox, 
                     label        = "Chirality (m) :", 
                     value        = self.m, 
                     setAsDefault = True )
     
     self.connect(self.chiralityMSpinBox,
                  SIGNAL("valueChanged(int)"),
                  self.chirality_fixup)
     
     self.bondLengthField = \
         PM_DoubleSpinBox( inPmGroupBox,
                           label        = "Bond Length :", 
                           value        = CC_GRAPHITIC_BONDLENGTH, 
                           setAsDefault = True,
                           minimum      = 1.0, 
                           maximum      = 3.0, 
                           singleStep   = 0.1, 
                           decimals     = 3, 
                           suffix       = " Angstroms" )
     
     endingChoices = ["None", "Hydrogen", "Nitrogen"]
     
     self.endingsComboBox= \
         PM_ComboBox( inPmGroupBox,
                      label        = "Endings :", 
                      choices      = endingChoices, 
                      index        = 0, 
                      setAsDefault = True,
                      spanWidth    = False )
class BackrubProteinSim_PropertyManager(Command_PropertyManager):
    """
    The BackrubProteinSim_PropertyManager class provides a Property Manager
    for the B{Fixed backbone Protein Sequence Design} command on the flyout toolbar in the
    Build > Protein > Simulate 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
    """

    title = "Backrub Motion"
    pmName = title
    iconPath = "ui/actions/Command Toolbar/BuildProtein/Backrub.png"

    def __init__(self, command):
        """
        Constructor for the property manager.
        """
        _superclass.__init__(self, command)
        self.showTopRowButtons( PM_DONE_BUTTON | \
                                PM_WHATS_THIS_BUTTON)
        msg = "Choose various parameters from below to design an optimized" \
            " protein sequence with Rosetta with backrub motion allowed."
        self.updateMessage(msg)

    def connect_or_disconnect_signals(self, isConnect=True):
        """
        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.ex1Checkbox, SIGNAL("stateChanged(int)"),
                       self.update_ex1)
        change_connect(self.ex1aroCheckbox, SIGNAL("stateChanged(int)"),
                       self.update_ex1aro)
        change_connect(self.ex2Checkbox, SIGNAL("stateChanged(int)"),
                       self.update_ex2)
        change_connect(self.ex2aroOnlyCheckbox, SIGNAL("stateChanged(int)"),
                       self.update_ex2aro_only)
        change_connect(self.ex3Checkbox, SIGNAL("stateChanged(int)"),
                       self.update_ex3)
        change_connect(self.ex4Checkbox, SIGNAL("stateChanged(int)"),
                       self.update_ex4)
        change_connect(self.rotOptCheckbox, SIGNAL("stateChanged(int)"),
                       self.update_rot_opt)
        change_connect(self.tryBothHisTautomersCheckbox,
                       SIGNAL("stateChanged(int)"),
                       self.update_try_both_his_tautomers)
        change_connect(self.softRepDesignCheckbox, SIGNAL("stateChanged(int)"),
                       self.update_soft_rep_design)
        change_connect(self.useElecRepCheckbox, SIGNAL("stateChanged(int)"),
                       self.update_use_elec_rep)
        change_connect(self.norepackDisulfCheckbox,
                       SIGNAL("stateChanged(int)"),
                       self.update_norepack_disulf)
        #signal slot connections for the push buttons
        change_connect(self.okButton, SIGNAL("clicked()"),
                       self.runRosettaBackrubSim)
        return

    #Protein Display methods

    def show(self):
        """
        Shows the Property Manager. Exends superclass method.
        """
        self.sequenceEditor = self.win.createProteinSequenceEditorIfNeeded()
        self.sequenceEditor.hide()
        #update the min and max residues spinbox max values based on the length
        #of the current protein
        numResidues = self._getNumResiduesForCurrentProtein()
        if numResidues == 0:
            self.minresSpinBox.setMaximum(numResidues + 2)
            self.maxresSpinBox.setMaximum(numResidues + 2)
        else:
            self.minresSpinBox.setMaximum(numResidues)
            self.maxresSpinBox.setMaximum(numResidues)

        _superclass.show(self)

        return

    def _addGroupBoxes(self):
        """
        Add the Property Manager group boxes.
        """
        self._pmGroupBox2 = PM_GroupBox(self,
                                        title="Backrub Specific Parameters")
        self._loadGroupBox2(self._pmGroupBox2)

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

        return

    def _loadGroupBox2(self, pmGroupBox):
        """
        Load widgets in group box.
        """
        self.bondAngleWeightSimSpinBox = PM_DoubleSpinBox(
            pmGroupBox,
            labelColumn=0,
            label="Bond angle weight:",
            minimum=0.01,
            decimals=2,
            maximum=1.0,
            singleStep=0.01,
            value=1.0,
            setAsDefault=False,
            spanWidth=False)

        bond_angle_param_list = ['Amber', 'Charmm']

        self.bondAngleParamComboBox = PM_ComboBox(
            pmGroupBox,
            label="Bond angle parameters:",
            choices=bond_angle_param_list,
            setAsDefault=False)

        self.onlybbSpinBox = PM_DoubleSpinBox(pmGroupBox,
                                              labelColumn=0,
                                              label="Only backbone rotation:",
                                              minimum=0.01,
                                              maximum=1.0,
                                              value=0.75,
                                              decimals=2,
                                              singleStep=0.01,
                                              setAsDefault=False,
                                              spanWidth=False)

        self.onlyrotSpinBox = PM_DoubleSpinBox(pmGroupBox,
                                               labelColumn=0,
                                               label="Only rotamer rotation:",
                                               minimum=0.01,
                                               maximum=1.0,
                                               decimals=2,
                                               value=0.25,
                                               singleStep=0.01,
                                               setAsDefault=False,
                                               spanWidth=False)

        self.mctempSpinBox = PM_DoubleSpinBox(
            pmGroupBox,
            labelColumn=0,
            label="MC simulation temperature:",
            minimum=0.1,
            value=0.6,
            maximum=1.0,
            decimals=2,
            singleStep=0.1,
            setAsDefault=False,
            spanWidth=False)

        numResidues = self._getNumResiduesForCurrentProtein()
        self.minresSpinBox = PM_SpinBox(pmGroupBox,
                                        labelColumn=0,
                                        label="Minimum number of residues:",
                                        minimum=2,
                                        maximum=numResidues,
                                        singleStep=1,
                                        setAsDefault=False,
                                        spanWidth=False)

        self.maxresSpinBox = PM_SpinBox(pmGroupBox,
                                        labelColumn=0,
                                        label="Maximum number of residues:",
                                        minimum=2,
                                        maximum=numResidues,
                                        singleStep=1,
                                        setAsDefault=False,
                                        spanWidth=False)
        if numResidues == 0:
            self.minresSpinBox.setMaximum(numResidues + 2)
            self.maxresSpinBox.setMaximum(numResidues + 2)
        return

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

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

    def _getNumResiduesForCurrentProtein(self):
        """
        Get number of residues for the current protein
        """
        _current_protein = self.win.assy.getSelectedProteinChunk()
        if _current_protein:
            return len(_current_protein.protein.get_sequence_string())
        return 0

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

        self.numSimSpinBox = PM_SpinBox(pmGroupBox,
                                        labelColumn=0,
                                        label="Number of trials:",
                                        minimum=1000,
                                        maximum=1000000,
                                        singleStep=1000,
                                        setAsDefault=False,
                                        spanWidth=False)

        self.ex1Checkbox = PM_CheckBox(
            pmGroupBox,
            text="Expand rotamer library for chi1 angle",
            state=Qt.Unchecked,
            setAsDefault=False,
            widgetColumn=0,
            spanWidth=True)

        self.ex1aroCheckbox = PM_CheckBox(
            pmGroupBox,
            text="Use large chi1 library for aromatic residues",
            state=Qt.Unchecked,
            setAsDefault=False,
            widgetColumn=0,
            spanWidth=True)

        self.ex2Checkbox = PM_CheckBox(
            pmGroupBox,
            text="Expand rotamer library for chi2 angle",
            state=Qt.Unchecked,
            setAsDefault=False,
            widgetColumn=0,
            spanWidth=True)

        self.ex2aroOnlyCheckbox = PM_CheckBox(
            pmGroupBox,
            text="Use large chi2 library only for aromatic residues",
            state=Qt.Unchecked,
            setAsDefault=False,
            widgetColumn=0,
            spanWidth=True)

        self.ex3Checkbox = PM_CheckBox(
            pmGroupBox,
            text="Expand rotamer library for chi3 angle",
            state=Qt.Unchecked,
            setAsDefault=False,
            widgetColumn=0,
            spanWidth=True)

        self.ex4Checkbox = PM_CheckBox(
            pmGroupBox,
            text="Expand rotamer library for chi4 angle",
            state=Qt.Unchecked,
            setAsDefault=False,
            widgetColumn=0,
            spanWidth=True)

        self.rotOptCheckbox = PM_CheckBox(pmGroupBox,
                                          text="Optimize one-body energy",
                                          state=Qt.Unchecked,
                                          setAsDefault=False,
                                          widgetColumn=0,
                                          spanWidth=True)

        self.tryBothHisTautomersCheckbox = PM_CheckBox(
            pmGroupBox,
            text="Try both histidine tautomers",
            state=Qt.Unchecked,
            setAsDefault=False,
            widgetColumn=0,
            spanWidth=True)

        self.softRepDesignCheckbox = PM_CheckBox(
            pmGroupBox,
            text="Use softer Lennard-Jones repulsive term",
            state=Qt.Unchecked,
            setAsDefault=False,
            widgetColumn=0,
            spanWidth=True)

        self.useElecRepCheckbox = PM_CheckBox(
            pmGroupBox,
            text="Use electrostatic repulsion",
            state=Qt.Unchecked,
            setAsDefault=False,
            widgetColumn=0,
            spanWidth=True)

        self.norepackDisulfCheckbox = PM_CheckBox(
            pmGroupBox,
            text="Don't re-pack disulphide bonds",
            state=Qt.Unchecked,
            setAsDefault=False,
            widgetColumn=0,
            spanWidth=True)

        self.otherCommandLineOptions = PM_TextEdit(
            pmGroupBox, label="Command line options:", spanWidth=True)
        self.otherCommandLineOptions.setFixedHeight(80)

        self.okButton = PM_PushButton(pmGroupBox,
                                      text="Run Rosetta",
                                      setAsDefault=True,
                                      spanWidth=True)
        return

    def update_ex1(self, state):
        """
        Update the command text edit depending on the state of the update_ex1
        checkbox
        @param state:state of the update_ex1 checkbox
        @type state: int
        """
        otherOptionsText = str(self.otherCommandLineOptions.toPlainText())
        if self.ex1Checkbox.isChecked() == True:
            otherOptionsText = otherOptionsText + ' -ex1 '
        else:
            otherOptionsText = otherOptionsText.replace(' -ex1 ', '')
        self.otherCommandLineOptions.setText(otherOptionsText)
        return

    def update_ex1aro(self, state):
        """
        Update the command text edit depending on the state of the update_ex1aro
        checkbox
        @param state:state of the update_ex1aro checkbox
        @type state: int
        """
        otherOptionsText = str(self.otherCommandLineOptions.toPlainText())
        if self.ex1aroCheckbox.isChecked() == True:
            otherOptionsText = otherOptionsText + ' -ex1aro '
        else:
            otherOptionsText = otherOptionsText.replace(' -ex1aro ', '')
        self.otherCommandLineOptions.setText(otherOptionsText)
        return

    def update_ex2(self, state):
        """
        Update the command text edit depending on the state of the update_ex2
        checkbox
        @param state:state of the update_ex2 checkbox
        @type state: int
        """
        otherOptionsText = str(self.otherCommandLineOptions.toPlainText())
        if self.ex2Checkbox.isChecked() == True:
            otherOptionsText = otherOptionsText + ' -ex2 '
        else:
            otherOptionsText = otherOptionsText.replace(' -ex2 ', '')
        self.otherCommandLineOptions.setText(otherOptionsText)
        return

    def update_ex2aro_only(self, state):
        """
        Update the command text edit depending on the state of the update_ex2aro_only
        checkbox
        @param state:state of the update_ex2aro_only checkbox
        @type state: int
        """
        otherOptionsText = str(self.otherCommandLineOptions.toPlainText())
        if self.ex2aroOnlyCheckbox.isChecked() == True:
            otherOptionsText = otherOptionsText + ' -ex2aro_only '
        else:
            otherOptionsText = otherOptionsText.replace(' -ex2aro_only ', '')

        self.otherCommandLineOptions.setText(otherOptionsText)
        return

    def update_ex3(self, state):
        """
        Update the command text edit depending on the state of the update_ex3
        checkbox
        @param state:state of the update_ex3 checkbox
        @type state: int
        """
        otherOptionsText = str(self.otherCommandLineOptions.toPlainText())
        if self.ex3Checkbox.isChecked() == True:
            otherOptionsText = otherOptionsText + ' -ex3 '
        else:
            otherOptionsText = otherOptionsText.replace(' -ex3 ', '')

        self.otherCommandLineOptions.setText(otherOptionsText)
        return

    def update_ex4(self, state):
        """
        Update the command text edit depending on the state of the update_ex4
        checkbox
        @param state:state of the update_ex4 checkbox
        @type state: int
        """
        otherOptionsText = str(self.otherCommandLineOptions.toPlainText())
        if self.ex4Checkbox.isChecked() == True:
            otherOptionsText = otherOptionsText + ' -ex4 '
        else:
            otherOptionsText = otherOptionsText.replace(' -ex4 ', '')
        self.otherCommandLineOptions.setText(otherOptionsText)
        return

    def update_rot_opt(self, state):
        """
        Update the command text edit depending on the state of the update_rot_opt
        checkbox
        @param state:state of the update_rot_opt checkbox
        @type state: int
        """
        otherOptionsText = str(self.otherCommandLineOptions.toPlainText())
        if self.rotOptCheckbox.isChecked() == True:
            otherOptionsText = otherOptionsText + ' -rot_opt '
        else:
            otherOptionsText = otherOptionsText.replace(' -rot_opt ', '')
        self.otherCommandLineOptions.setText(otherOptionsText)
        return

    def update_try_both_his_tautomers(self, state):
        """
        Update the command text edit depending on the state of the update_try_both_his_tautomers
        checkbox
        @param state:state of the update_try_both_his_tautomers checkbox
        @type state: int
        """
        otherOptionsText = str(self.otherCommandLineOptions.toPlainText())
        if self.tryBothHisTautomersCheckbox.isChecked() == True:
            otherOptionsText = otherOptionsText + ' -try_both_his_tautomers '
        else:
            otherOptionsText = otherOptionsText.replace(
                ' -try_both_his_tautomers ', '')
        self.otherCommandLineOptions.setText(otherOptionsText)
        return

    def update_soft_rep_design(self, state):
        """
        Update the command text edit depending on the state of the update_soft_rep_design
        checkbox
        @param state:state of the update_soft_rep_design checkbox
        @type state: int
        """
        otherOptionsText = str(self.otherCommandLineOptions.toPlainText())
        if self.softRepDesignCheckbox.isChecked() == True:
            otherOptionsText = otherOptionsText + ' -soft_rep_design '
        else:
            otherOptionsText = otherOptionsText.replace(
                ' -soft_rep_design ', '')
        self.otherCommandLineOptions.setText(otherOptionsText)
        return

    def update_use_elec_rep(self, state):
        """
        Update the command text edit depending on the state of the update_use_elec_rep
        checkbox
        @param state:state of the update_use_elec_rep checkbox
        @type state: int
        """
        otherOptionsText = str(self.otherCommandLineOptions.toPlainText())
        if self.useElecRepCheckbox.isChecked() == True:
            otherOptionsText = otherOptionsText + ' -use_electrostatic_repulsion '
        else:
            otherOptionsText = otherOptionsText.replace(
                ' -use_electrostatic_repulsion ', '')
        self.otherCommandLineOptions.setText(otherOptionsText)
        return

    def update_norepack_disulf(self, state):
        """
        Update the command text edit depending on the state of the update_no_repack
        checkbox
        @param state:state of the update_no_repack checkbox
        @type state: int
        """
        otherOptionsText = str(self.otherCommandLineOptions.toPlainText())
        if self.norepackDisulfCheckbox.isChecked() == True:
            otherOptionsText = otherOptionsText + ' -norepack_disulf '
        else:
            otherOptionsText = otherOptionsText.replace(
                ' -norepack_disulf ', '')
        self.otherCommandLineOptions.setText(otherOptionsText)
        return

    def runRosettaBackrubSim(self):
        """
        Get all the parameters from the PM and run a rosetta simulation
        """
        proteinChunk = self.win.assy.getSelectedProteinChunk()
        if not proteinChunk:
            msg = "You must select a single protein to run a Rosetta <i>Backrub</i> simulation."
            self.updateMessage(msg)
            return
        otherOptionsText = str(self.otherCommandLineOptions.toPlainText())
        numSim = self.numSimSpinBox.value()
        argList = [numSim, otherOptionsText, proteinChunk.name]
        backrubSpecificArgList = self.getBackrubSpecificArgumentList()
        from simulation.ROSETTA.rosetta_commandruns import rosettaSetup_CommandRun
        if argList[0] > 0:
            env.prefs[rosetta_backrub_enabled_prefs_key] = True
            cmdrun = rosettaSetup_CommandRun(
                self.win, argList, "BACKRUB_PROTEIN_SEQUENCE_DESIGN",
                backrubSpecificArgList)
            cmdrun.run()
        return

    def getBackrubSpecificArgumentList(self):
        """
        get list of backrub specific parameters from PM
        """
        listOfArgs = []

        bond_angle_weight = str(self.bondAngleWeightSimSpinBox.value())
        listOfArgs.append('-bond_angle_weight')
        listOfArgs.append(bond_angle_weight)

        if self.bondAngleParamComboBox.currentIndex() == 0:
            bond_angle_params = 'bond_angle_amber_rosetta'
        else:
            bond_angle_params = 'bond_angle_charmm_rosetta'

        listOfArgs.append('-bond_angle_params')
        listOfArgs.append(bond_angle_params)

        only_bb = str(self.onlybbSpinBox.value())
        listOfArgs.append('-only_bb')
        listOfArgs.append(only_bb)

        only_rot = str(self.onlyrotSpinBox.value())
        listOfArgs.append('-only_rot')
        listOfArgs.append(only_rot)

        mc_temp = str(self.mctempSpinBox.value())
        listOfArgs.append('-mc_temp')
        listOfArgs.append(mc_temp)

        min_res = self.minresSpinBox.value()
        max_res = self.maxresSpinBox.value()
        if max_res < min_res:
            msg = redmsg("Maximum number of residues for rosetta simulation with backrub" \
                " motion cannot be less than minimum number of residues."\
                " Neglecting this parameter for this simulation.")

            env.history.message("BACKRUB SIMULATION: " + msg)
        else:
            listOfArgs.append('-min_res')
            listOfArgs.append(str(min_res))
            listOfArgs.append('-max_res')
            listOfArgs.append(str(max_res))

        return listOfArgs
Exemple #53
0
 def _loadGroupBox2(self, pmGroupBox):
     """
     Load widgets in group box.
     """
     self.bondAngleWeightSimSpinBox = PM_DoubleSpinBox( pmGroupBox,
                                      labelColumn  = 0,
                                      label = "Bond angle weight:",
                                      minimum = 0.01,
                                      decimals     = 2, 
                                      maximum = 1.0,
                                      singleStep = 0.01,
                                      value = 1.0,
                                      setAsDefault  =  False,
                                      spanWidth = False)
     
     bond_angle_param_list = ['Amber', 'Charmm']
     
     self.bondAngleParamComboBox = PM_ComboBox( pmGroupBox,
                                                label         =  "Bond angle parameters:",
                                                choices       =  bond_angle_param_list,
                                                setAsDefault  =  False)
     
     self.onlybbSpinBox = PM_DoubleSpinBox( pmGroupBox,
                                      labelColumn  = 0,
                                      label = "Only backbone rotation:",
                                      minimum  = 0.01,
                                      maximum  = 1.0,
                                      value    = 0.75, 
                                      decimals = 2, 
                                      singleStep = 0.01,
                                      setAsDefault  =  False,
                                      spanWidth = False)
     
     self.onlyrotSpinBox = PM_DoubleSpinBox( pmGroupBox,
                                      labelColumn  = 0,
                                      label = "Only rotamer rotation:",
                                      minimum  = 0.01,
                                      maximum  = 1.0,
                                      decimals = 2, 
                                      value    = 0.25, 
                                      singleStep = 0.01,
                                      setAsDefault  =  False,
                                      spanWidth = False)
     
     self.mctempSpinBox = PM_DoubleSpinBox( pmGroupBox,
                                      labelColumn  = 0,
                                      label = "MC simulation temperature:",
                                      minimum  = 0.1,
                                      value    = 0.6, 
                                      maximum  = 1.0,
                                      decimals = 2, 
                                      singleStep = 0.1,
                                      setAsDefault  =  False,
                                      spanWidth = False)
     
     numResidues = self._getNumResiduesForCurrentProtein()
     self.minresSpinBox = PM_SpinBox( pmGroupBox,
                                      labelColumn  = 0,
                                      label = "Minimum number of residues:",
                                      minimum = 2,
                                      maximum = numResidues,
                                      singleStep = 1,
                                      setAsDefault  =  False,
                                      spanWidth = False)
     
     self.maxresSpinBox = PM_SpinBox( pmGroupBox,
                                      labelColumn  = 0,
                                      label = "Maximum number of residues:",
                                      minimum = 2,
                                      maximum = numResidues,
                                      singleStep = 1,
                                      setAsDefault  =  False,
                                      spanWidth = False)
     if numResidues == 0:
         self.minresSpinBox.setMaximum(numResidues + 2)
         self.maxresSpinBox.setMaximum(numResidues + 2)
     return