예제 #1
0
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
예제 #2
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 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)
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
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
예제 #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