def _loadTextEditWidget(self):
        """
        Load the SequenceTexteditWidgets.         
        """
        self.sequenceTextEdit = \
            PM_TextEdit( self,
                         label = " Sequence: ",
                         spanWidth = False,
                         permit_enter_keystroke = False)
        self.sequenceTextEdit.setCursorWidth(2)
        self.sequenceTextEdit.setWordWrapMode(QTextOption.WrapAnywhere)
        self.sequenceTextEdit.setFixedHeight(20)

        #The StrandSequence 'Mate' it is a read only etxtedit that shows
        #the complementary strand sequence.
        self.sequenceTextEdit_mate = \
            PM_TextEdit(self,
                        label = "",
                        spanWidth = False,
                        permit_enter_keystroke = False
                        )
        palette = getPalette(None, QPalette.Base,
                             sequenceEditStrandMateBaseColor)
        self.sequenceTextEdit_mate.setPalette(palette)
        self.sequenceTextEdit_mate.setFixedHeight(20)
        self.sequenceTextEdit_mate.setReadOnly(True)
        self.sequenceTextEdit_mate.setWordWrapMode(QTextOption.WrapAnywhere)

        #Important to make sure that the horizontal and vertical scrollbars
        #for these text edits are never displayed.
        for textEdit in (self.sequenceTextEdit, self.sequenceTextEdit_mate):
            textEdit.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
            textEdit.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        return
    def _loadTextEditWidget(self):
        """
        Load the SequenceTexteditWidgets.         
        """        
        self.sequenceTextEdit = \
            PM_TextEdit( self, 
                         label = " Sequence: ", 
                         spanWidth = False,
                         permit_enter_keystroke = False)        
        self.sequenceTextEdit.setCursorWidth(2)
        self.sequenceTextEdit.setWordWrapMode( QTextOption.WrapAnywhere )
        self.sequenceTextEdit.setFixedHeight(20)

        #The StrandSequence 'Mate' it is a read only etxtedit that shows
        #the complementary strand sequence.         
        self.sequenceTextEdit_mate = \
            PM_TextEdit(self, 
                        label = "", 
                        spanWidth = False,
                        permit_enter_keystroke = False
                        )        
        palette = getPalette(None, 
                             QPalette.Base, 
                             sequenceEditStrandMateBaseColor)
        self.sequenceTextEdit_mate.setPalette(palette)        
        self.sequenceTextEdit_mate.setFixedHeight(20)
        self.sequenceTextEdit_mate.setReadOnly(True)
        self.sequenceTextEdit_mate.setWordWrapMode(QTextOption.WrapAnywhere)

        #Important to make sure that the horizontal and vertical scrollbars 
        #for these text edits are never displayed. 
        for textEdit in (self.sequenceTextEdit, self.sequenceTextEdit_mate):
            textEdit.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
            textEdit.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
    def _loadTextEditWidget(self):
        """
        Load the SequenceTexteditWidgets.
        """
        self.aaRulerTextEdit = \
            PM_TextEdit( self,
                         label = "",
                         spanWidth = False,
                         permit_enter_keystroke = False)

        palette = getPalette(None,
                             QPalette.Base,
                             pmGrpBoxColor)
        self.aaRulerTextEdit.setPalette(palette)
        self.aaRulerTextEdit.setWordWrapMode( QTextOption.WrapAnywhere )
        self.aaRulerTextEdit.setFixedHeight(20)
        self.aaRulerTextEdit.setReadOnly(True)

        self.sequenceTextEdit = \
            PM_TextEdit( self,
                         label = " Sequence: ",
                         spanWidth = False,
                         permit_enter_keystroke = False)
        #self.sequenceTextEdit.setReadOnly(True) #@@@

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

        self.secStrucTextEdit = \
            PM_TextEdit( self,
                         label = " Secondary structure: ",
                         spanWidth = False,
                         permit_enter_keystroke = False)

        palette = getPalette(None,
                             QPalette.Base,
                             sequenceEditStrandMateBaseColor)
        self.secStrucTextEdit.setPalette(palette)
        self.secStrucTextEdit.setWordWrapMode( QTextOption.WrapAnywhere )
        self.secStrucTextEdit.setFixedHeight(20)
        self.secStrucTextEdit.setReadOnly(True)

        #Important to make sure that the horizontal and vertical scrollbars
        #for these text edits are never displayed.

        self.sequenceTextEdit.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.sequenceTextEdit.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.secStrucTextEdit.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.secStrucTextEdit.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.aaRulerTextEdit.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.aaRulerTextEdit.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        return
Example #4
0
 def _loadPM_TextEdit(self, inPmGroupBox):
     """
     PM_TextEdit widgets.
     """
     
     self.textEdit = \
         PM_TextEdit( inPmGroupBox, 
                      label     = "TextEdit:", 
                      spanWidth = False )
     
     self.spanTextEdit = \
         PM_TextEdit( inPmGroupBox, 
                      label     = "PM_TextEdit with label on top:", 
                      spanWidth = True )
Example #5
0
    def _loadTextEditWidget(self):
        """
        Load the SequenceTexteditWidgets.
        """
        self.aaRulerTextEdit = \
            PM_TextEdit( self,
                         label = "",
                         spanWidth = False,
                         permit_enter_keystroke = False)

        palette = getPalette(None, QPalette.Base, pmGrpBoxColor)
        self.aaRulerTextEdit.setPalette(palette)
        self.aaRulerTextEdit.setWordWrapMode(QTextOption.WrapAnywhere)
        self.aaRulerTextEdit.setFixedHeight(20)
        self.aaRulerTextEdit.setReadOnly(True)

        self.sequenceTextEdit = \
            PM_TextEdit( self,
                         label = " Sequence: ",
                         spanWidth = False,
                         permit_enter_keystroke = False)
        #self.sequenceTextEdit.setReadOnly(True) #@@@

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

        self.secStrucTextEdit = \
            PM_TextEdit( self,
                         label = " Secondary structure: ",
                         spanWidth = False,
                         permit_enter_keystroke = False)

        palette = getPalette(None, QPalette.Base,
                             sequenceEditStrandMateBaseColor)
        self.secStrucTextEdit.setPalette(palette)
        self.secStrucTextEdit.setWordWrapMode(QTextOption.WrapAnywhere)
        self.secStrucTextEdit.setFixedHeight(20)
        self.secStrucTextEdit.setReadOnly(True)

        #Important to make sure that the horizontal and vertical scrollbars
        #for these text edits are never displayed.

        self.sequenceTextEdit.setHorizontalScrollBarPolicy(
            Qt.ScrollBarAlwaysOff)
        self.sequenceTextEdit.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.secStrucTextEdit.setHorizontalScrollBarPolicy(
            Qt.ScrollBarAlwaysOff)
        self.secStrucTextEdit.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.aaRulerTextEdit.setHorizontalScrollBarPolicy(
            Qt.ScrollBarAlwaysOff)
        self.aaRulerTextEdit.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        return
Example #6
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 )
Example #7
0
class PeptideGeneratorPropertyManager(PM_Dialog):
    """
    The PeptideGeneratorPropertyManager class provides a Property Manager 
    for the "Build > Peptide" command.
    """
    # The title that appears in the property manager header.
    title = "Peptide Generator"
    # 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/Peptide.png"

    def __init__(self):
        """Construct the Peptide Property Manager.
        """
        PM_Dialog.__init__(self, self.pmName, self.iconPath, self.title)

        # phi psi angles will define the secondary structure of the peptide chain
        self.phi = -57.0
        self.psi = -47.0
        self.chirality = 1
        self.ss_idx = 1
        self.peptide_cache = []

        self.updateMessageGroupBox()

    def updateMessageGroupBox(self):
        msg = ""

        msg = msg + "Click on the Amino Acid buttons to add a new residuum to\
            the polypeptide chain. Click <b>Done</b> to insert it into the project."

        # 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 group boxe to the Peptide Property Manager dialog.
        """
        self.pmGroupBox1 = \
            PM_GroupBox( self,
                         title          = "Peptide Parameters" )

        # Add group box widgets.
        self._loadGroupBox1(self.pmGroupBox1)

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

        memberChoices = [
            "Custom", "Alpha helix", "Beta strand", "Pi helix", "3_10 helix",
            "Polyproline-II helix", "Fully extended"
        ]

        self.aaTypeComboBox= \
            PM_ComboBox( inPmGroupBox,
                         label        = "Conformation :",
                         choices      = memberChoices,
                         index        = 1,
                         setAsDefault = True,
                         spanWidth    = False )

        self.connect(self.aaTypeComboBox, SIGNAL("currentIndexChanged(int)"),
                     self._aaTypeChanged)

        self.phiAngleField = \
            PM_DoubleSpinBox( inPmGroupBox,
                              label        = "Phi angle :",
                              value        = -57.0,
                              setAsDefault = True,
                              minimum      = -180.0,
                              maximum      = 180.0,
                              singleStep   = 1.0,
                              decimals     = 1,
                              suffix       = " degrees")

        self.connect(self.phiAngleField, SIGNAL("valueChanged(double)"),
                     self._aaPhiAngleChanged)

        self.phiAngleField.setEnabled(False)

        self.psiAngleField = \
            PM_DoubleSpinBox( inPmGroupBox,
                              label        = "Psi angle :",
                              value        = -47.0,
                              setAsDefault = True,
                              minimum      = -180.0,
                              maximum      = 180.0,
                              singleStep   = 1.0,
                              decimals     = 1,
                              suffix       = " degrees" )

        self.connect(self.psiAngleField, SIGNAL("valueChanged(double)"),
                     self._aaPsiAngleChanged)

        self.psiAngleField.setEnabled(False)


        self.invertChiralityPushButton = \
            PM_PushButton( inPmGroupBox,
                           text         = 'Invert chirality' ,
                           spanWidth    = False
                       )

        self.connect(self.invertChiralityPushButton, SIGNAL("clicked()"),
                     self._aaChiralityChanged)

        self.aaTypesButtonGroup = \
            PM_ToolButtonGrid( inPmGroupBox,
                               buttonList = AA_BUTTON_LIST,
                               label      = "Amino acids :",
                               checkedId  = 0,
                               setAsDefault = True )

        self.connect(self.aaTypesButtonGroup.buttonGroup,
                     SIGNAL("buttonClicked(int)"), self._setAminoAcidType)

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

        self.sequenceEditor.insertHtml("", False, 4, 10, True)

        self.sequenceEditor.setReadOnly(True)

        self.startOverButton = \
            PM_PushButton( inPmGroupBox,
                           label     = "",
                           text      = "Start Over",
                           spanWidth = True,
                           setAsDefault = True )

        self.connect(self.startOverButton, SIGNAL("clicked()"),
                     self._startOverClicked)

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

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

    def _aaChiralityChanged(self):
        """
        Set chirality of the peptide chain.
        """
        self.psi *= -1
        self.phi *= -1

        self.phiAngleField.setValue(self.phi)
        self.psiAngleField.setValue(self.psi)

    def _aaTypeChanged(self, idx):
        """
        Slot for Peptide Structure Type combobox.
        Changes phi/psi angles for secondary structure.
        """
        self.ss_idx = idx

        if idx == 0:
            self.phiAngleField.setEnabled(True)
            self.psiAngleField.setEnabled(True)
        else:
            self.phiAngleField.setEnabled(False)
            self.psiAngleField.setEnabled(False)

        if idx == 1:  # alpha helix
            self.phi = -57.0
            self.psi = -47.0
        elif idx == 2:  # beta strand
            self.phi = -135.0
            self.psi = 135.0
        elif idx == 3:  # 3-10 helix
            self.phi = -55.0
            self.psi = -70.0
        elif idx == 4:  # pi helix
            self.phi = -49.0
            self.psi = -26.0
        elif idx == 5:  # polyprolin-II
            self.phi = -75.0
            self.psi = 150.0
        elif idx == 6:  # fully extended
            self.phi = -180.0
            self.psi = 180.0
        else:
            self.phi = self.phiAngleField.value()
            self.psi = self.psiAngleField.value()

        self.phi *= self.chirality
        self.psi *= self.chirality

        self.phiAngleField.setValue(self.phi)
        self.psiAngleField.setValue(self.psi)
        pass

    def _aaPhiAngleChanged(self, phi):
        self.phi = self.phiAngleField.value()
        pass

    def _aaPsiAngleChanged(self, psi):
        self.psi = self.psiAngleField.value()
        pass

    def _setAminoAcidType(self, aaTypeIndex):
        """
        Adds a new amino acid to the peptide molecule.
        """
        button, idx, short_name, dum, name, symbol, x, y = AA_BUTTON_LIST[
            aaTypeIndex]
        if self.ss_idx == 1:
            aa_txt = "<font color=red>"
        elif self.ss_idx == 2:
            aa_txt = "<font color=blue>"
        elif self.ss_idx == 3:
            aa_txt = "<font color=green>"
        elif self.ss_idx == 4:
            aa_txt = "<font color=orange>"
        elif self.ss_idx == 5:
            aa_txt = "<font color=magenta>"
        elif self.ss_idx == 6:
            aa_txt = "<font color=darkblue>"
        else:
            aa_txt = "<font color=black>"

        aa_txt += symbol + "</font>"
        self.sequenceEditor.insertHtml(aa_txt, False, 4, 10, False)
        self.addAminoAcid(aaTypeIndex)
        pass

    def _startOverClicked(self):
        """
        Resets a sequence in the sequence editor window.
        """
        self.sequenceEditor.clear()
        self.peptide_cache = []
        pass
class Ui_DnaSequenceEditor(PM_DockWidget):
    """
    The Ui_DnaSequenceEditor class defines UI elements for the Sequence Editor
    object. The sequence editor is usually visible while in DNA edit mode.
    It is a DockWidget that is doced at the bottom of the MainWindow
    """
    _title         =  "Sequence Editor"
    _groupBoxCount = 0
    _lastGroupBox = None

    def __init__(self, win):
        """
        Constructor for the Ui_DnaSequenceEditor 
        @param win: The parentWidget (MainWindow) for the sequence editor 
        """
        
        self.win = win
        # Should parentWidget for a docwidget always be win? 
        #Not necessary but most likely it will be the case.        
        parentWidget = win 
        
        _superclass.__init__(self, parentWidget, title = self._title)
        
        #A flag used to restore the state of the Reports dock widget 
        #(which can be accessed through View  >  Reports) see self.show() and
        #self.closeEvent() for more details. 
        self._reportsDockWidget_closed_in_show_method = False
        self.setFixedHeight(90)

    def show(self):
        """
        Shows the sequence editor. While doing this, it also closes the reports
        dock widget (if visible) the state of the reports dockwidget will be
        restored when the sequence editor is closed. 
        @see:self.closeEvent()
        """
        self._reportsDockWidget_closed_in_show_method = False
        #hide the history widget first
        #(It will be shown back during self.close)
        #The history widget is hidden or shown only when both 
        # 'View > Full Screen' and View > Semi Full Screen actions 
        # are *unchecked*
        #Thus show or close methods won't do anything to history widget
        # if either of the above mentioned actions is checked.
        if self.win.viewFullScreenAction.isChecked() or \
           self.win.viewSemiFullScreenAction.isChecked():
            pass
        else:
            if self.win.reportsDockWidget.isVisible():
                self.win.reportsDockWidget.close()
                self._reportsDockWidget_closed_in_show_method = True

        _superclass.show(self)  
        
    def closeEvent(self, event):
        """
        Overrides close event. Makes sure that the visible state of the reports
        widgetis restored when the sequence editor is closed. 
        @see: self.show()
        """
        _superclass.closeEvent(self, event)
       
        if self.win.viewFullScreenAction.isChecked() or \
           self.win.viewSemiFullScreenAction.isChecked():
            pass
        else:
            if self._reportsDockWidget_closed_in_show_method:
                self.win.viewReportsAction.setChecked(True) 
                self._reportsDockWidget_closed_in_show_method = False

    def _loadWidgets(self):
        """
        Overrides PM.PM_DockWidget._loadWidgets. Loads the widget in this
        dockwidget.
        """
        self._loadMenuWidgets()
        self._loadTextEditWidget()


    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.loadSequenceButton = PM_ToolButton(
            self,
            iconPath = "ui/actions/Properties Manager/Open.png")  

        self.saveSequenceButton = PM_ToolButton(
            self, 
            iconPath = "ui/actions/Properties Manager/Save_Strand_Sequence.png") 

        self.loadSequenceButton.setAutoRaise(True)
        self.saveSequenceButton.setAutoRaise(True)

        editDirectionChoices = ["5' to 3'", "3' to 5'"]
        self.baseDirectionChoiceComboBox = \
            PM_ComboBox( self,
                         choices = editDirectionChoices,
                         index     = 0, 
                         spanWidth = False )   

        #Find and replace widgets --
        self.findLineEdit = \
            PM_LineEdit( self, 
                         label        = "",
                         spanWidth    = False)
        self.findLineEdit.setMaximumWidth(60)


        self.replaceLineEdit = \
            PM_LineEdit( self, 
                         label        = "",
                         spanWidth    = False)
        self.replaceLineEdit.setMaximumWidth(60)

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

        self.findOptionsToolButton.setPopupMode(QToolButton.MenuButtonPopup)

        self._setFindOptionsToolButtonMenu()

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

        self.findPreviousToolButton = PM_ToolButton(
            self,
            iconPath = "ui/actions/Properties Manager/Find_Previous.png")
        self.findPreviousToolButton.setAutoRaise(True)

        self.replacePushButton = PM_PushButton(self, text = "Replace")

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

        self.phraseNotFoundLabel = QLabel(self)
        self.phraseNotFoundLabel.setText("Sequence 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. 
        widgetList = [('PM_ToolButton', self.loadSequenceButton, 0),
                      ('PM_ToolButton', self.saveSequenceButton, 1),
                      ('QLabel', "     Sequence direction:", 2),
                      ('PM_ComboBox',  self.baseDirectionChoiceComboBox , 3),
                      ('QLabel', "     Find:", 4),
                      ('PM_LineEdit', self.findLineEdit, 5),
                      ('PM_ToolButton', self.findOptionsToolButton, 6),
                      ('PM_ToolButton', self.findPreviousToolButton, 7),
                      ('PM_ToolButton', self.findNextToolButton, 8), 
                      ('QLabel', "     Replace:", 9),
                      ('PM_TextEdit', self.replaceLineEdit, 10), 
                      ('PM_PushButton', self.replacePushButton, 11),
                      ('PM_Label', self.warningSign, 12),
                      ('PM_Label', self.phraseNotFoundLabel, 13),
                      ('QSpacerItem', 5, 5, 14) ]

        widgetRow = PM_WidgetRow(self,
                                 title     = '',
                                 widgetList = widgetList,
                                 label = "",
                                 spanWidth = True )

    def _loadTextEditWidget(self):
        """
        Load the SequenceTexteditWidgets.         
        """        
        self.sequenceTextEdit = \
            PM_TextEdit( self, 
                         label = " Sequence: ", 
                         spanWidth = False,
                         permit_enter_keystroke = False)        
        self.sequenceTextEdit.setCursorWidth(2)
        self.sequenceTextEdit.setWordWrapMode( QTextOption.WrapAnywhere )
        self.sequenceTextEdit.setFixedHeight(20)

        #The StrandSequence 'Mate' it is a read only etxtedit that shows
        #the complementary strand sequence.         
        self.sequenceTextEdit_mate = \
            PM_TextEdit(self, 
                        label = "", 
                        spanWidth = False,
                        permit_enter_keystroke = False
                        )        
        palette = getPalette(None, 
                             QPalette.Base, 
                             sequenceEditStrandMateBaseColor)
        self.sequenceTextEdit_mate.setPalette(palette)        
        self.sequenceTextEdit_mate.setFixedHeight(20)
        self.sequenceTextEdit_mate.setReadOnly(True)
        self.sequenceTextEdit_mate.setWordWrapMode(QTextOption.WrapAnywhere)

        #Important to make sure that the horizontal and vertical scrollbars 
        #for these text edits are never displayed. 
        for textEdit in (self.sequenceTextEdit, self.sequenceTextEdit_mate):
            textEdit.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
            textEdit.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)


    def _getFindLineEditStyleSheet(self):
        """
        Return the style sheet for the findLineEdit. This sets the following 
        properties only:
         - background-color

        This style is set whenever the searchStrig can't be found (sets
        a light red color background to the lineedit when this happens)   

        @return: The line edit style sheet.
        @rtype:  str

        """
        styleSheet = \
                   "QLineEdit {\
                   background-color: rgb(255, 102, 102)\
                   }"
        #Not used:
        #  background-color: rgb(217, 255, 216)\       

        return styleSheet

    def _setFindOptionsToolButtonMenu(self):
        """
        Sets the menu for the findOptionstoolbutton that appears a small 
        menu button next to the findLineEdit.
        """
        self.findOptionsMenu = QMenu(self.findOptionsToolButton)

        self.caseSensitiveFindAction = QAction(self.findOptionsToolButton)
        self.caseSensitiveFindAction.setText('Match Case')
        self.caseSensitiveFindAction.setCheckable(True)
        self.caseSensitiveFindAction.setChecked(False)

        self.findOptionsMenu.addAction(self.caseSensitiveFindAction)
        self.findOptionsMenu.addSeparator()

        self.findOptionsToolButton.setMenu(self.findOptionsMenu)

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

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

            """
        from ne1_ui.WhatsThisText_for_PropertyManagers import whatsThis_SequenceEditor
        whatsThis_SequenceEditor(self)
Example #9
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
Example #10
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    
Example #11
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)
Example #12
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
    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
Example #14
0
    def _loadGroupBox1(self, inPmGroupBox):
        """
        Load widgets in the group box.
        """

        memberChoices = [
            "Custom", "Alpha helix", "Beta strand", "Pi helix", "3_10 helix",
            "Polyproline-II helix", "Fully extended"
        ]

        self.aaTypeComboBox= \
            PM_ComboBox( inPmGroupBox,
                         label        = "Conformation :",
                         choices      = memberChoices,
                         index        = 1,
                         setAsDefault = True,
                         spanWidth    = False )

        self.connect(self.aaTypeComboBox, SIGNAL("currentIndexChanged(int)"),
                     self._aaTypeChanged)

        self.phiAngleField = \
            PM_DoubleSpinBox( inPmGroupBox,
                              label        = "Phi angle :",
                              value        = -57.0,
                              setAsDefault = True,
                              minimum      = -180.0,
                              maximum      = 180.0,
                              singleStep   = 1.0,
                              decimals     = 1,
                              suffix       = " degrees")

        self.connect(self.phiAngleField, SIGNAL("valueChanged(double)"),
                     self._aaPhiAngleChanged)

        self.phiAngleField.setEnabled(False)

        self.psiAngleField = \
            PM_DoubleSpinBox( inPmGroupBox,
                              label        = "Psi angle :",
                              value        = -47.0,
                              setAsDefault = True,
                              minimum      = -180.0,
                              maximum      = 180.0,
                              singleStep   = 1.0,
                              decimals     = 1,
                              suffix       = " degrees" )

        self.connect(self.psiAngleField, SIGNAL("valueChanged(double)"),
                     self._aaPsiAngleChanged)

        self.psiAngleField.setEnabled(False)


        self.invertChiralityPushButton = \
            PM_PushButton( inPmGroupBox,
                           text         = 'Invert chirality' ,
                           spanWidth    = False
                       )

        self.connect(self.invertChiralityPushButton, SIGNAL("clicked()"),
                     self._aaChiralityChanged)

        self.aaTypesButtonGroup = \
            PM_ToolButtonGrid( inPmGroupBox,
                               buttonList = AA_BUTTON_LIST,
                               label      = "Amino acids :",
                               checkedId  = 0,
                               setAsDefault = True )

        self.connect(self.aaTypesButtonGroup.buttonGroup,
                     SIGNAL("buttonClicked(int)"), self._setAminoAcidType)

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

        self.sequenceEditor.insertHtml("", False, 4, 10, True)

        self.sequenceEditor.setReadOnly(True)

        self.startOverButton = \
            PM_PushButton( inPmGroupBox,
                           label     = "",
                           text      = "Start Over",
                           spanWidth = True,
                           setAsDefault = True )

        self.connect(self.startOverButton, SIGNAL("clicked()"),
                     self._startOverClicked)
    def _loadGroupBox1(self, inPmGroupBox):
        """
        Load widgets in the group box.
        """

        memberChoices = ["Custom", 
                         "Alpha helix", 
                         "Beta strand",
                         "Pi helix", 
                         "3_10 helix", 
                         "Polyproline-II helix",
                         "Fully extended"]

        self.aaTypeComboBox= \
            PM_ComboBox( inPmGroupBox,
                         label        = "Conformation :", 
                         choices      = memberChoices, 
                         index        = 1, 
                         setAsDefault = True,
                         spanWidth    = False )

        self.connect( self.aaTypeComboBox,
                      SIGNAL("currentIndexChanged(int)"),
                      self._aaTypeChanged)

        self.phiAngleField = \
            PM_DoubleSpinBox( inPmGroupBox,
                              label        = "Phi angle :", 
                              value        = -57.0, 
                              setAsDefault = True,
                              minimum      = -180.0, 
                              maximum      = 180.0, 
                              singleStep   = 1.0, 
                              decimals     = 1, 
                              suffix       = " degrees")

        self.connect( self.phiAngleField,
                      SIGNAL("valueChanged(double)"),
                      self._aaPhiAngleChanged)

        self.phiAngleField.setEnabled(False)

        self.psiAngleField = \
            PM_DoubleSpinBox( inPmGroupBox,
                              label        = "Psi angle :", 
                              value        = -47.0, 
                              setAsDefault = True,
                              minimum      = -180.0, 
                              maximum      = 180.0, 
                              singleStep   = 1.0, 
                              decimals     = 1, 
                              suffix       = " degrees" )

        self.connect( self.psiAngleField,
                      SIGNAL("valueChanged(double)"),
                      self._aaPsiAngleChanged)

        self.psiAngleField.setEnabled(False)        


        self.invertChiralityPushButton = \
            PM_PushButton( inPmGroupBox,
                           text         = 'Invert chirality' ,
                           spanWidth    = False
                       )

        self.connect(self.invertChiralityPushButton,
                     SIGNAL("clicked()"),
                     self._aaChiralityChanged)

        self.aaTypesButtonGroup = \
            PM_ToolButtonGrid( inPmGroupBox, 
                               buttonList = AA_BUTTON_LIST,
                               label      = "Amino acids :",
                               checkedId  = 0,
                               setAsDefault = True )

        self.connect( self.aaTypesButtonGroup.buttonGroup,
                      SIGNAL("buttonClicked(int)"),
                      self._setAminoAcidType)

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

        self.sequenceEditor.insertHtml("", False, 4, 10, True)

        self.sequenceEditor.setReadOnly(True)

        self.startOverButton = \
            PM_PushButton( inPmGroupBox,
                           label     = "",
                           text      = "Start Over",
                           spanWidth = True,
                           setAsDefault = True )

        self.connect( self.startOverButton,
                      SIGNAL("clicked()"),
                      self._startOverClicked)
Example #16
0
class PM_MessageGroupBox(PM_GroupBox):
    """
    The PM_MessageGroupBox widget provides a message box with a 
    collapse/expand button and a title.
    """
    def __init__(self, parentWidget, title="Message"):
        """
        PM_MessageGroupBox constructor.

        @param parentWidget: the PM_Dialog containing this message groupbox.
        @type  parentWidget: PM_Dialog

        @param title: The title on the collapse button
        @type  title: str
        """

        PM_GroupBox.__init__(self, parentWidget, title)

        self.vBoxLayout.setMargin(0)
        self.vBoxLayout.setSpacing(0)

        self.gridLayout.setMargin(0)
        self.gridLayout.setSpacing(0)

        self.MessageTextEdit = PM_TextEdit(
            self,
            label='',
            spanWidth=True,
            addToParent=False,
            ##cursorPosition = 'beginning'
        )
        # We pass addToParent = False to suppress the usual call by
        # PM_TextEdit.__init__ of self.addPmWidget(new textedit widget),
        # since we need to add it to self in a different way (below).
        # [bruce 071103 refactored this from what used to be a special case
        #  in PM_TextEdit.__init__ based on self being an instance of
        #  PM_MessageGroupBox.]

        # Needed for Intel MacOS. Otherwise, the horizontal scrollbar
        # is displayed in the MessageGroupBox. Mark 2007-05-24.
        # Shouldn't be needed with _setHeight() in PM_TextEdit.

        #Note 2008-06-17: We now permit a vertical scrollbar in message groupbox
        #--Ninad

        self.MessageTextEdit.setHorizontalScrollBarPolicy(
            Qt.ScrollBarAlwaysOff)

        # Add self.MessageTextEdit to self's vBoxLayout.
        self.vBoxLayout.addWidget(self.MessageTextEdit)
        # We should be calling the PM's getMessageTextEditPalette() method,
        # but that will take some extra work which I will do soon. Mark 2007-06-21
        self.MessageTextEdit.setPalette(
            getPalette(None, QPalette.Base, pmMessageBoxColor))
        self.MessageTextEdit.setReadOnly(True)
        #@self.MessageTextEdit.labelWidget = None # Never has one. Mark 2007-05-31
        self._widgetList.append(self.MessageTextEdit)
        self._rowCount += 1

        # wrapWrapMode seems to be set to QTextOption.WrapAnywhere on MacOS,
        # so let's force it here. Mark 2007-05-22.
        self.MessageTextEdit.setWordWrapMode(QTextOption.WordWrap)

        parentWidget.MessageTextEdit = self.MessageTextEdit

        # These two policies very important. Mark 2007-05-22
        self.setSizePolicy(
            QSizePolicy(QSizePolicy.Policy(QSizePolicy.Preferred),
                        QSizePolicy.Policy(QSizePolicy.Fixed)))

        self.MessageTextEdit.setSizePolicy(
            QSizePolicy(QSizePolicy.Policy(QSizePolicy.Preferred),
                        QSizePolicy.Policy(QSizePolicy.Fixed)))

        self.setWhatsThis("""<b>Messages</b>
                          <p>This prompts the user for a requisite operation and/or displays 
helpful messages to the user.</p>""")

        # Hide until insertHtmlMessage() loads a message.
        self.hide()

    def expand(self):
        """
        Expand this group box i.e. show all its contents and change the look 
        and feel of the groupbox button. It also sets the gridlayout margin and
        spacing to 0. (necessary to get rid of the extra space inside the 
        groupbox.)       

        @see: L{PM_GroupBox.expand}
        """
        PM_GroupBox.expand(self)
        # If we don't do this, we get a small space b/w the
        # title button and the MessageTextEdit widget.
        # Extra code unnecessary, but more readable.
        # Mark 2007-05-21
        self.gridLayout.setMargin(0)
        self.gridLayout.setSpacing(0)

    def insertHtmlMessage(self,
                          text,
                          setAsDefault=False,
                          minLines=4,
                          maxLines=10,
                          replace=True,
                          scrolltoTop=True):
        """
        Insert text (HTML) into the message box. Displays the message box if it is hidden.

        Arguments:

        @param minLines: the minimum number of lines (of text) to display in the TextEdit.
            if <minLines>=0 the TextEdit will fit its own height to fit <text>. The
            default height is 4 (lines of text).
        @type  minLines: int

        @param maxLines: The maximum number of lines to display in the TextEdit widget.
        @type  maxLines: int

        @param replace: should be set to False if you do not wish to replace 
            the current text. It will append <text> instead.
        @type  replace: int

        @note: Displays the message box if it is hidden.
        """
        self.MessageTextEdit.insertHtml(text,
                                        setAsDefault,
                                        minLines=minLines,
                                        maxLines=maxLines,
                                        replace=True)
        if scrolltoTop:
            cursor = self.MessageTextEdit.textCursor()
            cursor.setPosition(0, QTextCursor.MoveAnchor)
            self.MessageTextEdit.setTextCursor(cursor)
            self.MessageTextEdit.ensureCursorVisible()

            ##self.MessageTextEdit.moveCursor(QTextCursor.Start)
            ##self.MessageTextEdit.ensureCursorVisible()
            #text2 = self.MessageTextEdit.toPlainText()
            #print "***PM = %s, len(text) =%s"%(self.parentWidget, len(text))
            #if len(text2) > 16:
            #anchorText = text2[:16]
            #print "***anchorText =", anchorText
            #self.MessageTextEdit.scrollToAnchor(anchorText)
            #self.MessageTextEdit.ensureCursorVisible()

        self.show()
class PeptideGeneratorPropertyManager(PM_Dialog):
    """
    The PeptideGeneratorPropertyManager class provides a Property Manager 
    for the "Build > Peptide" command.
    """
    # The title that appears in the property manager header.
    title = "Peptide Generator"
    # 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/Peptide.png"

    def __init__(self):
        """Construct the Peptide Property Manager.
        """
        PM_Dialog.__init__(self, self.pmName, self.iconPath, self.title)

        # phi psi angles will define the secondary structure of the peptide chain
        self.phi = -57.0
        self.psi = -47.0
        self.chirality = 1
        self.ss_idx = 1
        self.peptide_cache = []

        self.updateMessageGroupBox()

    def updateMessageGroupBox(self):
        msg = ""

        msg = msg + "Click on the Amino Acid buttons to add a new residuum to\
            the polypeptide chain. Click <b>Done</b> to insert it into the project."

        # 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 group boxe to the Peptide Property Manager dialog.
        """
        self.pmGroupBox1 = \
            PM_GroupBox( self, 
                         title          = "Peptide Parameters" )

        # Add group box widgets.
        self._loadGroupBox1(self.pmGroupBox1)

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

        memberChoices = ["Custom", 
                         "Alpha helix", 
                         "Beta strand",
                         "Pi helix", 
                         "3_10 helix", 
                         "Polyproline-II helix",
                         "Fully extended"]

        self.aaTypeComboBox= \
            PM_ComboBox( inPmGroupBox,
                         label        = "Conformation :", 
                         choices      = memberChoices, 
                         index        = 1, 
                         setAsDefault = True,
                         spanWidth    = False )

        self.connect( self.aaTypeComboBox,
                      SIGNAL("currentIndexChanged(int)"),
                      self._aaTypeChanged)

        self.phiAngleField = \
            PM_DoubleSpinBox( inPmGroupBox,
                              label        = "Phi angle :", 
                              value        = -57.0, 
                              setAsDefault = True,
                              minimum      = -180.0, 
                              maximum      = 180.0, 
                              singleStep   = 1.0, 
                              decimals     = 1, 
                              suffix       = " degrees")

        self.connect( self.phiAngleField,
                      SIGNAL("valueChanged(double)"),
                      self._aaPhiAngleChanged)

        self.phiAngleField.setEnabled(False)

        self.psiAngleField = \
            PM_DoubleSpinBox( inPmGroupBox,
                              label        = "Psi angle :", 
                              value        = -47.0, 
                              setAsDefault = True,
                              minimum      = -180.0, 
                              maximum      = 180.0, 
                              singleStep   = 1.0, 
                              decimals     = 1, 
                              suffix       = " degrees" )

        self.connect( self.psiAngleField,
                      SIGNAL("valueChanged(double)"),
                      self._aaPsiAngleChanged)

        self.psiAngleField.setEnabled(False)        


        self.invertChiralityPushButton = \
            PM_PushButton( inPmGroupBox,
                           text         = 'Invert chirality' ,
                           spanWidth    = False
                       )

        self.connect(self.invertChiralityPushButton,
                     SIGNAL("clicked()"),
                     self._aaChiralityChanged)

        self.aaTypesButtonGroup = \
            PM_ToolButtonGrid( inPmGroupBox, 
                               buttonList = AA_BUTTON_LIST,
                               label      = "Amino acids :",
                               checkedId  = 0,
                               setAsDefault = True )

        self.connect( self.aaTypesButtonGroup.buttonGroup,
                      SIGNAL("buttonClicked(int)"),
                      self._setAminoAcidType)

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

        self.sequenceEditor.insertHtml("", False, 4, 10, True)

        self.sequenceEditor.setReadOnly(True)

        self.startOverButton = \
            PM_PushButton( inPmGroupBox,
                           label     = "",
                           text      = "Start Over",
                           spanWidth = True,
                           setAsDefault = True )

        self.connect( self.startOverButton,
                      SIGNAL("clicked()"),
                      self._startOverClicked)

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

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

    def _aaChiralityChanged(self):
        """
        Set chirality of the peptide chain.
        """
        self.psi *= -1
        self.phi *= -1

        self.phiAngleField.setValue(self.phi)
        self.psiAngleField.setValue(self.psi)

    def _aaTypeChanged(self, idx):
        """
        Slot for Peptide Structure Type combobox.
        Changes phi/psi angles for secondary structure.
        """
        self.ss_idx = idx

        if idx == 0:
            self.phiAngleField.setEnabled(True)
            self.psiAngleField.setEnabled(True)
        else:
            self.phiAngleField.setEnabled(False)
            self.psiAngleField.setEnabled(False)

        if idx == 1: # alpha helix
            self.phi = -57.0
            self.psi = -47.0
        elif idx == 2: # beta strand
            self.phi = -135.0
            self.psi = 135.0
        elif idx == 3: # 3-10 helix
            self.phi = -55.0
            self.psi = -70.0
        elif idx == 4: # pi helix
            self.phi = -49.0
            self.psi = -26.0
        elif idx == 5: # polyprolin-II
            self.phi = -75.0
            self.psi = 150.0
        elif idx == 6: # fully extended
            self.phi = -180.0
            self.psi = 180.0
        else:
            self.phi = self.phiAngleField.value()
            self.psi = self.psiAngleField.value()

        self.phi *= self.chirality
        self.psi *= self.chirality

        self.phiAngleField.setValue(self.phi)
        self.psiAngleField.setValue(self.psi)
        pass

    def _aaPhiAngleChanged(self, phi):
        self.phi = self.phiAngleField.value()
        pass


    def _aaPsiAngleChanged(self, psi):
        self.psi = self.psiAngleField.value()
        pass        

    def _setAminoAcidType(self, aaTypeIndex):
        """
        Adds a new amino acid to the peptide molecule.
        """
        button, idx, short_name, dum, name, symbol, x, y = AA_BUTTON_LIST[aaTypeIndex]
        if self.ss_idx==1:
            aa_txt = "<font color=red>"
        elif self.ss_idx==2:
            aa_txt = "<font color=blue>"
        elif self.ss_idx==3:
            aa_txt = "<font color=green>"
        elif self.ss_idx==4:
            aa_txt = "<font color=orange>"
        elif self.ss_idx==5:
            aa_txt = "<font color=magenta>"
        elif self.ss_idx==6:
            aa_txt = "<font color=darkblue>"
        else:
            aa_txt = "<font color=black>"

        aa_txt += symbol+"</font>"
        self.sequenceEditor.insertHtml(aa_txt, False, 4, 10, False)
        self.addAminoAcid(aaTypeIndex)
        pass

    def _startOverClicked(self):
        """
        Resets a sequence in the sequence editor window.
        """
        self.sequenceEditor.clear()
        self.peptide_cache = []
        pass
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
    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 __init__(self,
                 parentWidget,
                 title = "Message"
                 ):
        """
        PM_MessageGroupBox constructor.

        @param parentWidget: the PM_Dialog containing this message groupbox.
        @type  parentWidget: PM_Dialog

        @param title: The title on the collapse button
        @type  title: str
        """

        PM_GroupBox.__init__(self, parentWidget, title)

        self.vBoxLayout.setMargin(0)
        self.vBoxLayout.setSpacing(0)

        self.gridLayout.setMargin(0)
        self.gridLayout.setSpacing(0)


        self.MessageTextEdit = PM_TextEdit(self,
                                           label='',
                                           spanWidth = True,
                                           addToParent = False,
                                           ##cursorPosition = 'beginning'
                                       )
            # We pass addToParent = False to suppress the usual call by
            # PM_TextEdit.__init__ of self.addPmWidget(new textedit widget),
            # since we need to add it to self in a different way (below).
            # [bruce 071103 refactored this from what used to be a special case
            #  in PM_TextEdit.__init__ based on self being an instance of
            #  PM_MessageGroupBox.]

        # Needed for Intel MacOS. Otherwise, the horizontal scrollbar
        # is displayed in the MessageGroupBox. Mark 2007-05-24.
        # Shouldn't be needed with _setHeight() in PM_TextEdit.

        #Note 2008-06-17: We now permit a vertical scrollbar in message groupbox
        #--Ninad

        self.MessageTextEdit.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)

        # Add self.MessageTextEdit to self's vBoxLayout.
        self.vBoxLayout.addWidget(self.MessageTextEdit)
        # We should be calling the PM's getMessageTextEditPalette() method,
        # but that will take some extra work which I will do soon. Mark 2007-06-21
        self.MessageTextEdit.setPalette(getPalette( None,
                                                    QPalette.Base,
                                                    pmMessageBoxColor))
        self.MessageTextEdit.setReadOnly(True)
        #@self.MessageTextEdit.labelWidget = None # Never has one. Mark 2007-05-31
        self._widgetList.append(self.MessageTextEdit)
        self._rowCount += 1


        # wrapWrapMode seems to be set to QTextOption.WrapAnywhere on MacOS,
        # so let's force it here. Mark 2007-05-22.
        self.MessageTextEdit.setWordWrapMode(QTextOption.WordWrap)

        parentWidget.MessageTextEdit = self.MessageTextEdit

        # These two policies very important. Mark 2007-05-22
        self.setSizePolicy(
            QSizePolicy(QSizePolicy.Policy(QSizePolicy.Preferred),
                        QSizePolicy.Policy(QSizePolicy.Fixed)))

        self.MessageTextEdit.setSizePolicy(
            QSizePolicy(QSizePolicy.Policy(QSizePolicy.Preferred),
                        QSizePolicy.Policy(QSizePolicy.Fixed)))

        self.setWhatsThis("""<b>Messages</b>
                          <p>This prompts the user for a requisite operation and/or displays
helpful messages to the user.</p>""")

        # Hide until insertHtmlMessage() loads a message.
        self.hide()
class PM_MessageGroupBox( PM_GroupBox ):
    """
    The PM_MessageGroupBox widget provides a message box with a
    collapse/expand button and a title.
    """

    def __init__(self,
                 parentWidget,
                 title = "Message"
                 ):
        """
        PM_MessageGroupBox constructor.

        @param parentWidget: the PM_Dialog containing this message groupbox.
        @type  parentWidget: PM_Dialog

        @param title: The title on the collapse button
        @type  title: str
        """

        PM_GroupBox.__init__(self, parentWidget, title)

        self.vBoxLayout.setMargin(0)
        self.vBoxLayout.setSpacing(0)

        self.gridLayout.setMargin(0)
        self.gridLayout.setSpacing(0)


        self.MessageTextEdit = PM_TextEdit(self,
                                           label='',
                                           spanWidth = True,
                                           addToParent = False,
                                           ##cursorPosition = 'beginning'
                                       )
            # We pass addToParent = False to suppress the usual call by
            # PM_TextEdit.__init__ of self.addPmWidget(new textedit widget),
            # since we need to add it to self in a different way (below).
            # [bruce 071103 refactored this from what used to be a special case
            #  in PM_TextEdit.__init__ based on self being an instance of
            #  PM_MessageGroupBox.]

        # Needed for Intel MacOS. Otherwise, the horizontal scrollbar
        # is displayed in the MessageGroupBox. Mark 2007-05-24.
        # Shouldn't be needed with _setHeight() in PM_TextEdit.

        #Note 2008-06-17: We now permit a vertical scrollbar in message groupbox
        #--Ninad

        self.MessageTextEdit.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)

        # Add self.MessageTextEdit to self's vBoxLayout.
        self.vBoxLayout.addWidget(self.MessageTextEdit)
        # We should be calling the PM's getMessageTextEditPalette() method,
        # but that will take some extra work which I will do soon. Mark 2007-06-21
        self.MessageTextEdit.setPalette(getPalette( None,
                                                    QPalette.Base,
                                                    pmMessageBoxColor))
        self.MessageTextEdit.setReadOnly(True)
        #@self.MessageTextEdit.labelWidget = None # Never has one. Mark 2007-05-31
        self._widgetList.append(self.MessageTextEdit)
        self._rowCount += 1


        # wrapWrapMode seems to be set to QTextOption.WrapAnywhere on MacOS,
        # so let's force it here. Mark 2007-05-22.
        self.MessageTextEdit.setWordWrapMode(QTextOption.WordWrap)

        parentWidget.MessageTextEdit = self.MessageTextEdit

        # These two policies very important. Mark 2007-05-22
        self.setSizePolicy(
            QSizePolicy(QSizePolicy.Policy(QSizePolicy.Preferred),
                        QSizePolicy.Policy(QSizePolicy.Fixed)))

        self.MessageTextEdit.setSizePolicy(
            QSizePolicy(QSizePolicy.Policy(QSizePolicy.Preferred),
                        QSizePolicy.Policy(QSizePolicy.Fixed)))

        self.setWhatsThis("""<b>Messages</b>
                          <p>This prompts the user for a requisite operation and/or displays
helpful messages to the user.</p>""")

        # Hide until insertHtmlMessage() loads a message.
        self.hide()

    def expand(self):
        """
        Expand this group box i.e. show all its contents and change the look
        and feel of the groupbox button. It also sets the gridlayout margin and
        spacing to 0. (necessary to get rid of the extra space inside the
        groupbox.)

        @see: L{PM_GroupBox.expand}
        """
        PM_GroupBox.expand(self)
        # If we don't do this, we get a small space b/w the
        # title button and the MessageTextEdit widget.
        # Extra code unnecessary, but more readable.
        # Mark 2007-05-21
        self.gridLayout.setMargin(0)
        self.gridLayout.setSpacing(0)


    def insertHtmlMessage(self,
                          text,
                          setAsDefault = False,
                          minLines     = 4,
                          maxLines     = 10,
                          replace      = True,
                          scrolltoTop =  True):
        """
        Insert text (HTML) into the message box. Displays the message box if it is hidden.

        Arguments:

        @param minLines: the minimum number of lines (of text) to display in the TextEdit.
            if <minLines>=0 the TextEdit will fit its own height to fit <text>. The
            default height is 4 (lines of text).
        @type  minLines: int

        @param maxLines: The maximum number of lines to display in the TextEdit widget.
        @type  maxLines: int

        @param replace: should be set to False if you do not wish to replace
            the current text. It will append <text> instead.
        @type  replace: int

        @note: Displays the message box if it is hidden.
        """
        self.MessageTextEdit.insertHtml( text,
                                         setAsDefault,
                                         minLines = minLines,
                                         maxLines = maxLines,
                                         replace  = True )
        if scrolltoTop:
            cursor  =  self.MessageTextEdit.textCursor()
            cursor.setPosition( 0,
                                QTextCursor.MoveAnchor )
            self.MessageTextEdit.setTextCursor( cursor )
            self.MessageTextEdit.ensureCursorVisible()

            ##self.MessageTextEdit.moveCursor(QTextCursor.Start)
            ##self.MessageTextEdit.ensureCursorVisible()
            #text2 = self.MessageTextEdit.toPlainText()
            #print "***PM = %s, len(text) =%s"%(self.parentWidget, len(text))
            #if len(text2) > 16:
                #anchorText = text2[:16]
                #print "***anchorText =", anchorText
                #self.MessageTextEdit.scrollToAnchor(anchorText)
                #self.MessageTextEdit.ensureCursorVisible()

        self.show()
class Ui_DnaSequenceEditor(PM_DockWidget):
    """
    The Ui_DnaSequenceEditor class defines UI elements for the Sequence Editor
    object. The sequence editor is usually visible while in while editing
    a DnaStrand.
    
    It is a DockWidget that is docked at the bottom of the MainWindow.
    """
    _title = "Sequence Editor"
    _groupBoxCount = 0
    _lastGroupBox = None

    def __init__(self, win):
        """
        Constructor for the Ui_DnaSequenceEditor 
        @param win: The parentWidget (MainWindow) for the sequence editor 
        """

        self.win = win
        # Should parentWidget for a docwidget always be win?
        #Not necessary but most likely it will be the case.
        parentWidget = win

        _superclass.__init__(self, parentWidget, title=self._title)

        #A flag used to restore the state of the Reports dock widget
        #(which can be accessed through View  >  Reports) see self.show() and
        #self.closeEvent() for more details.
        self._reportsDockWidget_closed_in_show_method = False
        self.setFixedHeight(90)
        return

    def show(self):
        """
        Shows the sequence editor. While doing this, it also closes the reports
        dock widget (if visible) the state of the reports dockwidget will be
        restored when the sequence editor is closed. 
        @see:self.closeEvent()
        """
        self._reportsDockWidget_closed_in_show_method = False
        #hide the history widget first
        #(It will be shown back during self.close)
        #The history widget is hidden or shown only when both
        # 'View > Full Screen' and View > Semi Full Screen actions
        # are *unchecked*
        #Thus show or close methods won't do anything to history widget
        # if either of the above mentioned actions is checked.
        if self.win.viewFullScreenAction.isChecked() or \
           self.win.viewSemiFullScreenAction.isChecked():
            pass
        else:
            if self.win.reportsDockWidget.isVisible():
                self.win.reportsDockWidget.close()
                self._reportsDockWidget_closed_in_show_method = True

        _superclass.show(self)
        return

    def closeEvent(self, event):
        """
        Overrides close event. Makes sure that the visible state of the reports
        widgetis restored when the sequence editor is closed. 
        @see: self.show()
        """
        _superclass.closeEvent(self, event)

        if self.win.viewFullScreenAction.isChecked() or \
           self.win.viewSemiFullScreenAction.isChecked():
            pass
        else:
            if self._reportsDockWidget_closed_in_show_method:
                self.win.viewReportsAction.setChecked(True)
                self._reportsDockWidget_closed_in_show_method = False
        return

    def _loadWidgets(self):
        """
        Overrides PM.PM_DockWidget._loadWidgets. Loads the widget in this
        dockwidget.
        """
        self._loadMenuWidgets()
        self._loadTextEditWidget()
        return

    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.loadSequenceButton = PM_ToolButton(
            self, iconPath="ui/actions/Properties Manager/Open.png")

        self.saveSequenceButton = PM_ToolButton(
            self,
            iconPath="ui/actions/Properties Manager/Save_Strand_Sequence.png")

        self.loadSequenceButton.setAutoRaise(True)
        self.saveSequenceButton.setAutoRaise(True)

        # Only supporting 5' to 3' direction until bug 2956 is fixed.
        # Mark 2008-12-19
        editDirectionChoices = ["5' to 3'"]  # , "3' to 5'"]
        self.baseDirectionChoiceComboBox = \
            PM_ComboBox( self,
                         choices = editDirectionChoices,
                         index     = 0,
                         spanWidth = False )

        #Find and replace widgets --
        self.findLineEdit = \
            PM_LineEdit( self,
                         label        = "",
                         spanWidth    = False)
        self.findLineEdit.setMaximumWidth(60)


        self.replaceLineEdit = \
            PM_LineEdit( self,
                         label        = "",
                         spanWidth    = False)
        self.replaceLineEdit.setMaximumWidth(60)

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

        self.findOptionsToolButton.setPopupMode(QToolButton.MenuButtonPopup)

        self._setFindOptionsToolButtonMenu()

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

        self.findPreviousToolButton = PM_ToolButton(
            self, iconPath="ui/actions/Properties Manager/Find_Previous.png")
        self.findPreviousToolButton.setAutoRaise(True)

        self.replacePushButton = PM_PushButton(self, text="Replace")

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

        self.phraseNotFoundLabel = QLabel(self)
        self.phraseNotFoundLabel.setText("Sequence 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.
        widgetList = [('PM_ToolButton', self.loadSequenceButton, 0),
                      ('PM_ToolButton', self.saveSequenceButton, 1),
                      ('QLabel', "     Sequence direction:", 2),
                      ('PM_ComboBox', self.baseDirectionChoiceComboBox, 3),
                      ('QLabel', "     Find:", 4),
                      ('PM_LineEdit', self.findLineEdit, 5),
                      ('PM_ToolButton', self.findOptionsToolButton, 6),
                      ('PM_ToolButton', self.findPreviousToolButton, 7),
                      ('PM_ToolButton', self.findNextToolButton, 8),
                      ('QLabel', "     Replace:", 9),
                      ('PM_TextEdit', self.replaceLineEdit, 10),
                      ('PM_PushButton', self.replacePushButton, 11),
                      ('PM_Label', self.warningSign, 12),
                      ('PM_Label', self.phraseNotFoundLabel, 13),
                      ('QSpacerItem', 5, 5, 14)]

        widgetRow = PM_WidgetRow(self,
                                 title='',
                                 widgetList=widgetList,
                                 label="",
                                 spanWidth=True)
        return

    def _loadTextEditWidget(self):
        """
        Load the SequenceTexteditWidgets.         
        """
        self.sequenceTextEdit = \
            PM_TextEdit( self,
                         label = " Sequence: ",
                         spanWidth = False,
                         permit_enter_keystroke = False)
        self.sequenceTextEdit.setCursorWidth(2)
        self.sequenceTextEdit.setWordWrapMode(QTextOption.WrapAnywhere)
        self.sequenceTextEdit.setFixedHeight(20)

        #The StrandSequence 'Mate' it is a read only etxtedit that shows
        #the complementary strand sequence.
        self.sequenceTextEdit_mate = \
            PM_TextEdit(self,
                        label = "",
                        spanWidth = False,
                        permit_enter_keystroke = False
                        )
        palette = getPalette(None, QPalette.Base,
                             sequenceEditStrandMateBaseColor)
        self.sequenceTextEdit_mate.setPalette(palette)
        self.sequenceTextEdit_mate.setFixedHeight(20)
        self.sequenceTextEdit_mate.setReadOnly(True)
        self.sequenceTextEdit_mate.setWordWrapMode(QTextOption.WrapAnywhere)

        #Important to make sure that the horizontal and vertical scrollbars
        #for these text edits are never displayed.
        for textEdit in (self.sequenceTextEdit, self.sequenceTextEdit_mate):
            textEdit.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
            textEdit.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        return

    def _getFindLineEditStyleSheet(self):
        """
        Return the style sheet for the findLineEdit. This sets the following 
        properties only:
         - background-color

        This style is set whenever the searchStrig can't be found (sets
        a light red color background to the lineedit when this happens)   

        @return: The line edit style sheet.
        @rtype:  str

        """
        styleSheet = "QLineEdit {"\
                   "background-color: rgb(255, 102, 102)"\
                   "}"
        #Not used:
        #  background-color: rgb(217, 255, 216)\

        return styleSheet

    def _setFindOptionsToolButtonMenu(self):
        """
        Sets the menu for the findOptionstoolbutton that appears a small 
        menu button next to the findLineEdit.
        """
        self.findOptionsMenu = QMenu(self.findOptionsToolButton)

        self.caseSensitiveFindAction = QAction(self.findOptionsToolButton)
        self.caseSensitiveFindAction.setText('Match Case')
        self.caseSensitiveFindAction.setCheckable(True)
        self.caseSensitiveFindAction.setChecked(False)

        self.findOptionsMenu.addAction(self.caseSensitiveFindAction)
        self.findOptionsMenu.addSeparator()

        self.findOptionsToolButton.setMenu(self.findOptionsMenu)
        return

    def _addToolTipText(self):
        """
            What's Tool Tip text for widgets in this Property Manager.  
            """
        from ne1_ui.ToolTipText_for_PropertyManagers import ToolTip_DnaSequenceEditor
        ToolTip_DnaSequenceEditor(self)
        return

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

            """
        from ne1_ui.WhatsThisText_for_PropertyManagers import whatsThis_DnaSequenceEditor
        whatsThis_DnaSequenceEditor(self)
        return
class Ui_ProteinSequenceEditor(PM_DockWidget):
    """
    The Ui_DnaSequenceEditor class defines UI elements for the Sequence Editor
    object. The sequence editor is usually visible while in DNA edit mode.
    It is a DockWidget that is doced at the bottom of the MainWindow
    """
    _title         =  "Sequence Editor"
    _groupBoxCount = 0
    _lastGroupBox = None

    def __init__(self, win):
        """
        Constructor for the Ui_DnaSequenceEditor 
        @param win: The parentWidget (MainWindow) for the sequence editor 
        """
        
        self.win = win
        # Should parentWidget for a docwidget always be win? 
        #Not necessary but most likely it will be the case.        
        parentWidget = win 
        
        _superclass.__init__(self, parentWidget, title = self._title)
        
        #A flag used to restore the state of the Reports dock widget 
        #(which can be accessed through View  >  Reports) see self.show() and
        #self.closeEvent() for more details. 
        self._reportsDockWidget_closed_in_show_method = False
        self.setFixedHeight(90)

    def show(self):
        """
        Shows the sequence editor. While doing this, it also closes the reports
        dock widget (if visible) the state of the reports dockwidget will be
        restored when the sequence editor is closed. 
        @see:self.closeEvent()
        """
        self._reportsDockWidget_closed_in_show_method = False
        
        if self.win.viewFullScreenAction.isChecked() or \
           self.win.viewSemiFullScreenAction.isChecked():
            pass
        else:
            if self.win.reportsDockWidget.isVisible():
                self.win.reportsDockWidget.close()
                self._reportsDockWidget_closed_in_show_method = True

        _superclass.show(self)  
        
    def closeEvent(self, event):
        """
        Overrides close event. Makes sure that the visible state of the reports
        widgetis restored when the sequence editor is closed. 
        @see: self.show()
        """
        _superclass.closeEvent(self, event)
       
        if self.win.viewFullScreenAction.isChecked() or \
           self.win.viewSemiFullScreenAction.isChecked():
            pass
        else:
            if self._reportsDockWidget_closed_in_show_method:
                self.win.viewReportsAction.setChecked(True) 
                self._reportsDockWidget_closed_in_show_method = False

    def _loadWidgets(self):
        """
        Overrides PM.PM_DockWidget._loadWidgets. Loads the widget in this
        dockwidget.
        """
        self._loadMenuWidgets()
        self._loadTextEditWidget()


    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.loadSequenceButton = PM_ToolButton(
            self,
            iconPath = "ui/actions/Properties Manager/Open.png")  

        self.saveSequenceButton = PM_ToolButton(
            self, 
            iconPath = "ui/actions/Properties Manager/Save_Strand_Sequence.png") 

        self.loadSequenceButton.setAutoRaise(True)
        self.saveSequenceButton.setAutoRaise(True)

        
        #Find and replace widgets --
        self.findLineEdit = \
            PM_LineEdit( self, 
                         label        = "",
                         spanWidth    = False)
        self.findLineEdit.setMaximumWidth(60)


        self.replaceLineEdit = \
            PM_LineEdit( self, 
                         label        = "",
                         spanWidth    = False)
        self.replaceLineEdit.setMaximumWidth(60)

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

        self.findOptionsToolButton.setPopupMode(QToolButton.MenuButtonPopup)

        self._setFindOptionsToolButtonMenu()

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

        self.findPreviousToolButton = PM_ToolButton(
            self,
            iconPath = "ui/actions/Properties Manager/Find_Previous.png")
        self.findPreviousToolButton.setAutoRaise(True)

        self.replacePushButton = PM_PushButton(self, text = "Replace")

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

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

        

        #Widgets to include in the widget row. 
        widgetList = [('PM_ToolButton', self.loadSequenceButton, 0),
                      ('PM_ToolButton', self.saveSequenceButton, 1),
                      ('QLabel', "     Find:", 4),
                      ('PM_LineEdit', self.findLineEdit, 5),
                      ('PM_ToolButton', self.findOptionsToolButton, 6),
                      ('PM_ToolButton', self.findPreviousToolButton, 7),
                      ('PM_ToolButton', self.findNextToolButton, 8), 
                      ('QLabel', "     Replace:", 9),
                      ('PM_TextEdit', self.replaceLineEdit, 10), 
                      ('PM_PushButton', self.replacePushButton, 11),
                      ('PM_Label', self.warningSign, 12),
                      ('PM_Label', self.phraseNotFoundLabel, 13),
                      ('QSpacerItem', 5, 5, 14) ]

        widgetRow = PM_WidgetRow(self,
                                 title     = '',
                                 widgetList = widgetList,
                                 label = "",
                                 spanWidth = True )
        
        

    def _loadTextEditWidget(self):
        """
        Load the SequenceTexteditWidgets.         
        """        
        self.aaRulerTextEdit = \
            PM_TextEdit( self, 
                         label = "", 
                         spanWidth = False,
                         permit_enter_keystroke = False) 
        
        palette = getPalette(None, 
                             QPalette.Base, 
                             pmGrpBoxColor)
        self.aaRulerTextEdit.setPalette(palette)     
        self.aaRulerTextEdit.setWordWrapMode( QTextOption.WrapAnywhere )
        self.aaRulerTextEdit.setFixedHeight(20)
        self.aaRulerTextEdit.setReadOnly(True)
        
        self.sequenceTextEdit = \
            PM_TextEdit( self, 
                         label = " Sequence: ", 
                         spanWidth = False,
                         permit_enter_keystroke = False) 
        
        
        self.sequenceTextEdit.setCursorWidth(2)
        self.sequenceTextEdit.setWordWrapMode( QTextOption.WrapAnywhere )
        self.sequenceTextEdit.setFixedHeight(20)
        
        self.secStrucTextEdit = \
            PM_TextEdit( self, 
                         label = " Secondary structure: ", 
                         spanWidth = False,
                         permit_enter_keystroke = False) 
        
        palette = getPalette(None, 
                             QPalette.Base, 
                             sequenceEditStrandMateBaseColor)
        self.secStrucTextEdit.setPalette(palette)     
        self.secStrucTextEdit.setWordWrapMode( QTextOption.WrapAnywhere )
        self.secStrucTextEdit.setFixedHeight(20)
        self.secStrucTextEdit.setReadOnly(True)

        #Important to make sure that the horizontal and vertical scrollbars 
        #for these text edits are never displayed. 
        
        self.sequenceTextEdit.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.sequenceTextEdit.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.secStrucTextEdit.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.secStrucTextEdit.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.aaRulerTextEdit.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.aaRulerTextEdit.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)

    def _getFindLineEditStyleSheet(self):
        """
        Return the style sheet for the findLineEdit. This sets the following 
        properties only:
         - background-color

        This style is set whenever the searchStrig can't be found (sets
        a light red color background to the lineedit when this happens)   

        @return: The line edit style sheet.
        @rtype:  str

        """
        styleSheet = \
                   "QLineEdit {\
                   background-color: rgb(255, 102, 102)\
                   }"
        #Not used:
        #  background-color: rgb(217, 255, 216)\       

        return styleSheet

    def _setFindOptionsToolButtonMenu(self):
        """
        Sets the menu for the findOptionstoolbutton that appears a small 
        menu button next to the findLineEdit.
        """
        self.findOptionsMenu = QMenu(self.findOptionsToolButton)

        self.caseSensitiveFindAction = QAction(self.findOptionsToolButton)
        self.caseSensitiveFindAction.setText('Match Case')
        self.caseSensitiveFindAction.setCheckable(True)
        self.caseSensitiveFindAction.setChecked(False)

        self.findOptionsMenu.addAction(self.caseSensitiveFindAction)
        self.findOptionsMenu.addSeparator()

        self.findOptionsToolButton.setMenu(self.findOptionsMenu)

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

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

            """
        pass
Example #24
0
    def __init__(self, parentWidget, title="Message"):
        """
        PM_MessageGroupBox constructor.

        @param parentWidget: the PM_Dialog containing this message groupbox.
        @type  parentWidget: PM_Dialog

        @param title: The title on the collapse button
        @type  title: str
        """

        PM_GroupBox.__init__(self, parentWidget, title)

        self.vBoxLayout.setMargin(0)
        self.vBoxLayout.setSpacing(0)

        self.gridLayout.setMargin(0)
        self.gridLayout.setSpacing(0)

        self.MessageTextEdit = PM_TextEdit(
            self,
            label='',
            spanWidth=True,
            addToParent=False,
            ##cursorPosition = 'beginning'
        )
        # We pass addToParent = False to suppress the usual call by
        # PM_TextEdit.__init__ of self.addPmWidget(new textedit widget),
        # since we need to add it to self in a different way (below).
        # [bruce 071103 refactored this from what used to be a special case
        #  in PM_TextEdit.__init__ based on self being an instance of
        #  PM_MessageGroupBox.]

        # Needed for Intel MacOS. Otherwise, the horizontal scrollbar
        # is displayed in the MessageGroupBox. Mark 2007-05-24.
        # Shouldn't be needed with _setHeight() in PM_TextEdit.

        #Note 2008-06-17: We now permit a vertical scrollbar in message groupbox
        #--Ninad

        self.MessageTextEdit.setHorizontalScrollBarPolicy(
            Qt.ScrollBarAlwaysOff)

        # Add self.MessageTextEdit to self's vBoxLayout.
        self.vBoxLayout.addWidget(self.MessageTextEdit)
        # We should be calling the PM's getMessageTextEditPalette() method,
        # but that will take some extra work which I will do soon. Mark 2007-06-21
        self.MessageTextEdit.setPalette(
            getPalette(None, QPalette.Base, pmMessageBoxColor))
        self.MessageTextEdit.setReadOnly(True)
        #@self.MessageTextEdit.labelWidget = None # Never has one. Mark 2007-05-31
        self._widgetList.append(self.MessageTextEdit)
        self._rowCount += 1

        # wrapWrapMode seems to be set to QTextOption.WrapAnywhere on MacOS,
        # so let's force it here. Mark 2007-05-22.
        self.MessageTextEdit.setWordWrapMode(QTextOption.WordWrap)

        parentWidget.MessageTextEdit = self.MessageTextEdit

        # These two policies very important. Mark 2007-05-22
        self.setSizePolicy(
            QSizePolicy(QSizePolicy.Policy(QSizePolicy.Preferred),
                        QSizePolicy.Policy(QSizePolicy.Fixed)))

        self.MessageTextEdit.setSizePolicy(
            QSizePolicy(QSizePolicy.Policy(QSizePolicy.Preferred),
                        QSizePolicy.Policy(QSizePolicy.Fixed)))

        self.setWhatsThis("""<b>Messages</b>
                          <p>This prompts the user for a requisite operation and/or displays 
helpful messages to the user.</p>""")

        # Hide until insertHtmlMessage() loads a message.
        self.hide()
Example #25
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
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
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