class BuildProtein_PropertyManager(EditCommand_PM):
    """
    The BuildDna_PropertyManager class provides a Property Manager
    for the B{Build > Protein } command.

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

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

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

    title         =  "Build Protein"
    pmName        =  title
    #change this icon path later
    iconPath      =  "ui/actions/Tools/Build Structures/Protein.png"

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

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

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

        EditCommand_PM.__init__( self, command)

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

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

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

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

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

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

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


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

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


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

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

        if isConnect and self.isAlreadyConnected:
            return

        if not isConnect and self.isAlreadyDisconnected:
            return

        self.isAlreadyConnected = isConnect
        self.isAlreadyDisconnected = not isConnect

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

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

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

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


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


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

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


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

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

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

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

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

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

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

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

    title         =  "DnaStrand Properties"
    iconPath      =  "ui/actions/Properties Manager/Strand.png"

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

        self.sequenceEditor = None

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

        _superclass.__init__( self, command)

        self.showTopRowButtons( PM_DONE_BUTTON | \
                                PM_WHATS_THIS_BUTTON)
        return

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

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

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

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

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

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

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

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

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

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

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


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

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

        return params


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

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

    def setParameters(self, params):
        """
        This is usually called when you are editing an existing structure.
        It also gets called when selecting a new strand (within this command).
        Some property manager ui elements then display the information
        obtained from the object being edited.
        TODO:
        - Make this a EditCommand_PM API method?
        - See also the routines GraphicsMode.setParams or object.setProps
        ..better to name them all in one style?
        """
        numberOfBases, \
            dnaForm, \
            dnaModel, \
            color, \
            name = params

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

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

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

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

    def connect_or_disconnect_signals(self, isConnect):
        """
        Connect or disconnect widget signals sent to their slot methods.
        This can be overridden in subclasses. By default it does nothing.
        @param isConnect: If True the widget will send the signals to the slot
                          method.
        @type  isConnect: boolean
        """
        #TODO: This is a temporary fix for a bug. When you invoke a temporary
        # mode Entering such a temporary mode keeps the signals of
        #PM from the previous mode connected (
        #but while exiting that temporary mode and reentering the
        #previous mode, it atucally reconnects the signal! This gives rise to
        #lots  of bugs. This needs more general fix in Temporary mode API.
        # -- Ninad 2008-01-09 (similar comment exists in MovePropertyManager.py

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

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

        self.isAlreadyConnected = isConnect
        self.isAlreadyDisconnected = not isConnect

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


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

        _superclass.connect_or_disconnect_signals(self, isConnect)


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

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

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

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

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

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

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

        _superclass.close(self)
        return

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

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

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

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

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

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

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

            return

        self.command.setStructureName(name)

        self._update_UI_do_updates() # Updates the message box.

        return
class DnaStrand_PropertyManager( DnaOrCnt_PropertyManager):
    """
    The DnaStrand_PropertyManager class provides a Property Manager 
    for the DnaStrand_EditCommand.

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

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

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

    title         =  "DnaStrand Properties"
    pmName        =  title
    iconPath      =  "ui/actions/Properties Manager/Strand.png"

    def __init__( self, win, editCommand ):
        """
        Constructor for the Build DNA property manager.
        """
        
        #For model changed signal
        self.previousSelectionParams = None
        
        #see self.connect_or_disconnect_signals for comment about this flag
        self.isAlreadyConnected = False
        self.isAlreadyDisconnected = False
        
        self.sequenceEditor = None      
        
        self._numberOfBases = 0 
        self._conformation = 'B-DNA'
        self.duplexRise = 3.18
        self.basesPerTurn = 10
        self.dnaModel = 'PAM3'
        
        
        _superclass.__init__( self, 
                                    win,
                                    editCommand)


        
        self.showTopRowButtons( PM_DONE_BUTTON | \
                                PM_WHATS_THIS_BUTTON)
        
        self._loadSequenceEditor()
        
        msg = "Use resize handles to resize the strand. Use sequence editor"\
                   "to assign a new sequence or the current one to a file."
        self.updateMessage(msg)
        
               
    
    def _addGroupBoxes( self ):
        """
        Add the DNA Property Manager group boxes.
        """        
                
        self._pmGroupBox1 = PM_GroupBox( self, title = "Parameters" )
        self._loadGroupBox1( self._pmGroupBox1 )
        self._displayOptionsGroupBox = PM_GroupBox( self, 
                                                    title = "Display Options" )
        self._loadDisplayOptionsGroupBox( self._displayOptionsGroupBox )
    
    def _loadGroupBox1(self, pmGroupBox):
        """
        Load widgets in group box 4.
        """
        
        self.nameLineEdit = PM_LineEdit( pmGroupBox,
                         label         =  "Strand name:",
                         text          =  "",
                         setAsDefault  =  False)
        
        self.numberOfBasesSpinBox = \
            PM_SpinBox( pmGroupBox, 
                        label         =  "Number of bases:", 
                        value         =  self._numberOfBases,
                        setAsDefault  =  False,
                        minimum       =  2,
                        maximum       =  10000 )
        
        self.basesPerTurnDoubleSpinBox  =  \
            PM_DoubleSpinBox( pmGroupBox,
                              label         =  "Bases per turn:",
                              value         =  self.basesPerTurn,
                              setAsDefault  =  True,
                              minimum       =  8.0,
                              maximum       =  20.0,
                              decimals      =  2,
                              singleStep    =  0.1 )
        
        self.duplexRiseDoubleSpinBox  =  \
            PM_DoubleSpinBox( pmGroupBox,
                              label         =  "Rise:",
                              value         =  self.duplexRise,
                              setAsDefault  =  True,
                              minimum       =  2.0,
                              maximum       =  4.0,
                              decimals      =  3,
                              singleStep    =  0.01 )
        
        self.disableStructHighlightingCheckbox = \
            PM_CheckBox( pmGroupBox,
                         text         = "Don't highlight while editing DNA",
                         widgetColumn  = 0,
                         state        = Qt.Unchecked,
                         setAsDefault = True,
                         spanWidth = True
                         )
        
        #As of 2008-03-31, the properties such as number of bases will be 
        #editable only by using the resize handles. post FNANO we will support 
        #the 
        self.numberOfBasesSpinBox.setEnabled(False)
        self.basesPerTurnDoubleSpinBox.setEnabled(False)
        self.duplexRiseDoubleSpinBox.setEnabled(False)
        
    
            
    def _loadSequenceEditor(self):
        """
        Temporary code  that shows the Sequence editor ..a doc widget docked
        at the bottom of the mainwindow. The implementation is going to change
        before 'rattleSnake' product release.
        As of 2007-11-20: This feature (sequence editor) is waiting 
        for the ongoing dna model work to complete.
        """
        self.sequenceEditor = self.win.createDnaSequenceEditorIfNeeded() 
        self.sequenceEditor.hide()
        
        
    def _loadDisplayOptionsGroupBox(self, pmGroupBox):
        """
        Overrides superclass method. 
        Also loads the color chooser widget. 
        """
        self._loadColorChooser(pmGroupBox)
        _superclass._loadDisplayOptionsGroupBox(self, pmGroupBox)
        
         
    def _connect_showCursorTextCheckBox(self):
        """
        Connect the show cursor text checkbox with user prefs_key.
        Overrides 
        DnaOrCnt_PropertyManager._connect_showCursorTextCheckBox
        """
        connect_checkbox_with_boolean_pref(
            self.showCursorTextCheckBox , 
            dnaStrandEditCommand_showCursorTextCheckBox_prefs_key)


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

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

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

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

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

    def _addWhatsThisText(self):
        """
        Add what's this text. 
        Abstract method.
        """
        pass
class DnaStrand_PropertyManager(DnaOrCnt_PropertyManager):
    """
    The DnaStrand_PropertyManager class provides a Property Manager
    for the DnaStrand_EditCommand.

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

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

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

    title = "DnaStrand Properties"
    iconPath = "ui/actions/Properties Manager/Strand.png"

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

        self.sequenceEditor = None

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

        _superclass.__init__(self, command)

        self.showTopRowButtons( PM_DONE_BUTTON | \
                                PM_WHATS_THIS_BUTTON)
        return

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

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

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

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

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

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

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

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

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

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

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

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

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

        return params

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

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

    def setParameters(self, params):
        """
        This is usually called when you are editing an existing structure.
        It also gets called when selecting a new strand (within this command).
        Some property manager ui elements then display the information
        obtained from the object being edited.
        TODO:
        - Make this a EditCommand_PM API method?
        - See also the routines GraphicsMode.setParams or object.setProps
        ..better to name them all in one style?
        """
        numberOfBases, \
            dnaForm, \
            dnaModel, \
            color, \
            name = params

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

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

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

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

    def connect_or_disconnect_signals(self, isConnect):
        """
        Connect or disconnect widget signals sent to their slot methods.
        This can be overridden in subclasses. By default it does nothing.
        @param isConnect: If True the widget will send the signals to the slot
                          method.
        @type  isConnect: boolean
        """
        #TODO: This is a temporary fix for a bug. When you invoke a temporary
        # mode Entering such a temporary mode keeps the signals of
        #PM from the previous mode connected (
        #but while exiting that temporary mode and reentering the
        #previous mode, it atucally reconnects the signal! This gives rise to
        #lots  of bugs. This needs more general fix in Temporary mode API.
        # -- Ninad 2008-01-09 (similar comment exists in MovePropertyManager.py

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

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

        self.isAlreadyConnected = isConnect
        self.isAlreadyDisconnected = not isConnect

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

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

        _superclass.connect_or_disconnect_signals(self, isConnect)

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

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

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

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

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

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

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

        _superclass.close(self)
        return

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

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

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

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

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

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

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

            return

        self.command.setStructureName(name)

        self._update_UI_do_updates()  # Updates the message box.

        return
示例#5
0
class DnaStrand_PropertyManager(DnaOrCnt_PropertyManager):
    """
    The DnaStrand_PropertyManager class provides a Property Manager 
    for the DnaStrand_EditCommand.

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

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

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

    title = "DnaStrand Properties"
    pmName = title
    iconPath = "ui/actions/Properties Manager/Strand.png"

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

        #For model changed signal
        self.previousSelectionParams = None

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

        self.sequenceEditor = None

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

        _superclass.__init__(self, win, editCommand)



        self.showTopRowButtons( PM_DONE_BUTTON | \
                                PM_WHATS_THIS_BUTTON)

        self._loadSequenceEditor()

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        return params

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

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

    def setParameters(self, params):
        """
        This is usually called when you are editing an existing structure. 
        Some property manager ui elements then display the information 
        obtained from the object being edited. 
        TODO:
        - Make this a EditCommand_PM API method? 
        - See also the routines GraphicsMode.setParams or object.setProps
        ..better to name them all in one style?  
        """
        #Set the duplex rise and bases per turn spinbox values.

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

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

    def connect_or_disconnect_signals(self, isConnect):
        """
        Connect or disconnect widget signals sent to their slot methods.
        This can be overridden in subclasses. By default it does nothing.
        @param isConnect: If True the widget will send the signals to the slot 
                          method. 
        @type  isConnect: boolean
        """
        #TODO: This is a temporary fix for a bug. When you invoke a temporary
        # mode Entering such a temporary mode keeps the signals of
        #PM from the previous mode connected (
        #but while exiting that temporary mode and reentering the
        #previous mode, it atucally reconnects the signal! This gives rise to
        #lots  of bugs. This needs more general fix in Temporary mode API.
        # -- Ninad 2008-01-09 (similar comment exists in MovePropertyManager.py

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

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

        self.isAlreadyConnected = isConnect
        self.isAlreadyDisconnected = not isConnect

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

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

        _superclass.connect_or_disconnect_signals(self, isConnect)

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

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

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

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

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

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

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

        _superclass.close(self)

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

            self.updateSequence()

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

        if not self.editCommand.hasValidStructure():
            return

        strand = self.editCommand.struct

        titleString = 'Sequence Editor for ' + strand.name

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

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

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

    def _addWhatsThisText(self):
        """
        Add what's this text. 
        Abstract method.
        """
        pass
class BuildProtein_PropertyManager( EditCommand_PM, DebugMenuMixin ):
    """
    The BuildDna_PropertyManager class provides a Property Manager 
    for the B{Build > DNA } command.

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

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

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

    title         =  "Build Protein"
    pmName        =  title
    #change this ico path later
    iconPath      =  "ui/actions/Tools/Build Structures/Peptide.png"

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


        DebugMenuMixin._init1( self )

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

    def _addGroupBoxes( self ):
        """
        Add the DNA Property Manager group boxes.
        """
        """
        Add the DNA Property Manager group boxes.
        """        
                
        self._pmGroupBox1 = PM_GroupBox( self, title = "Parameters" )
        self._loadGroupBox1( self._pmGroupBox1 )
        
        pass
    
    def _loadGroupBox1(self, pmGroupBox):
        """
        Load widgets in group box 4.
        """
        
        self.nameLineEdit = PM_LineEdit( pmGroupBox,
                         label         =  "Protein chunk name:",
                         text          =  "",
                         setAsDefault  =  False)
        
        #Urmi 20080713: May be useful to set the minimum value to not zero
        self.numberOfAASpinBox = \
            PM_SpinBox( pmGroupBox, 
                        label         =  "Number of amino acids:", 
                        value         =  0,
                        setAsDefault  =  False,
                        minimum       =  0,
                        maximum       =  10000 )
        self.numberOfAASpinBox.setEnabled(False)
示例#7
0
class BuildProtein_PropertyManager(EditCommand_PM):
    """
    The BuildDna_PropertyManager class provides a Property Manager 
    for the B{Build > Protein } command.

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

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

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

    title = "Build Protein"
    pmName = title
    #change this icon path later
    iconPath = "ui/actions/Tools/Build Structures/Protein.png"

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

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

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

        EditCommand_PM.__init__(self, command)

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

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

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

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

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

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

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

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

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

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

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

        if isConnect and self.isAlreadyConnected:
            return

        if not isConnect and self.isAlreadyDisconnected:
            return

        self.isAlreadyConnected = isConnect
        self.isAlreadyDisconnected = not isConnect

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

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

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

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

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

    def enable_or_disable_gui_actions(self, bool_enable=False):
        """
        Enable or disable some gui actions when this property manager is 
        opened or closed, depending on the bool_enable. 
        @param bool_enable: enables/disables some gui action
        @type bool_enable: bool
        
        """
        if hasattr(self.command, 'flyoutToolbar') and \
           self.command.flyoutToolbar:
            self.command.flyoutToolbar.exitProteinAction.setEnabled(
                not bool_enable)

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

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

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

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

        #Urmi 20080713: May be useful to set the minimum value to not zero
        #Now it does not matter, since its disabled. But zero as the minimum
        #value in a spinbox does not work otherwise.
        self.numberOfAASpinBox = \
            PM_SpinBox( pmGroupBox,
                        label         =  "Amino Acids:",
                        value         =  0,
                        setAsDefault  =  False,
                        minimum       =  0,
                        maximum       =  10000 )
        #for now we do not allow changing number of residues
        self.numberOfAASpinBox.setEnabled(False)
        self.editPropertiesPushButton = PM_PushButton(pmGroupBox,
                                                      text="Edit Sequence",
                                                      setAsDefault=True)
class BuildProtein_PropertyManager(EditCommand_PM, DebugMenuMixin):
    """
    The BuildDna_PropertyManager class provides a Property Manager 
    for the B{Build > DNA } command.

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

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

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

    title = "Build Protein"
    pmName = title
    #change this ico path later
    iconPath = "ui/actions/Tools/Build Structures/Peptide.png"

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

        #For model changed signal
        self.previousSelectionParams = None

        #Urmi 20080713: set the protein chunk name and its length
        #for the first available chunk and not the selected one, that's
        #not implemented as yet

        #self.showProteinParametersAndSequenceEditorForInit(win)

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

        EditCommand_PM.__init__(self, win, editCommand)

        DebugMenuMixin._init1(self)

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

    def show(self):
        self.showProteinParametersAndSequenceEditor(self.win)
        EditCommand_PM.show(self)

        return

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

    def showProteinParametersAndSequenceEditor(self, win):
        """
        Show/ Hide protein parameters and sequence editor based
        """
        part = win.assy.part
        from simulation.ROSETTA.rosetta_commandruns import checkIfProteinChunkInPart
        proteinExists, proteinChunk = checkIfProteinChunkInPart(part)
        if proteinExists:
            self._proteinChunkName = proteinChunk.protein.get_pdb_id(
            ) + proteinChunk.protein.get_chain_id()
            self._numberOfAA = len(proteinChunk.protein.get_sequence_string())
        else:
            self._proteinChunkName = ''
            self._numberOfAA = 0

        self.nameLineEdit.setText(self._proteinChunkName)
        self.numberOfAASpinBox.setValue(self._numberOfAA)
        if proteinExists:
            self.nameLineEdit.setEnabled(True)
        else:
            self.nameLineEdit.setEnabled(False)

        self.sequenceEditor = win.createProteinSequenceEditorIfNeeded()
        #get the sequence for this protein chunk
        if proteinExists:
            sequence = proteinChunk.protein.get_sequence_string()
            self.sequenceEditor.setSequence(sequence)
            secStructure = proteinChunk.protein.get_secondary_structure_string(
            )
            self.sequenceEditor.setSecondaryStructure(secStructure)
            self.sequenceEditor.setRuler(len(secStructure))
            self.sequenceEditor.show()
        else:
            self.sequenceEditor.hide()

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

        if isConnect and self.isAlreadyConnected:
            return

        if not isConnect and self.isAlreadyDisconnected:
            return

        self.isAlreadyConnected = isConnect
        self.isAlreadyDisconnected = not isConnect

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

    def enable_or_disable_gui_actions(self, bool_enable=False):
        """
        Enable or disable some gui actions when this property manager is 
        opened or closed, depending on the bool_enable. 
        
        """
        #TODO: This is bad. It would have been much better to enable/disable
        #gui actions using a API method in command/commandSequencer which gets
        #called when you enter another command exiting or suspending the
        #previous one. . At present. it doesn't exist (first needs cleanup in
        #command/command sequencer (Done and other methods._)-- Ninad 2008-01-09
        if hasattr(self.editCommand, 'flyoutToolbar') and \
           self.editCommand.flyoutToolbar:
            self.editCommand.flyoutToolbar.exitProteinAction.setEnabled(
                not bool_enable)

    def ok_btn_clicked(self):
        """
        Slot for the OK button
        """

        self.win.toolsDone()

    def cancel_btn_clicked(self):
        """
        Slot for the Cancel button.
        """

        self.win.toolsCancel()

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

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

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

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

        pass

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

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

        #Urmi 20080713: May be useful to set the minimum value to not zero
        self.numberOfAASpinBox = \
            PM_SpinBox( pmGroupBox,
                        label         =  "Number of amino acids:",
                        value         =  0,
                        setAsDefault  =  False,
                        minimum       =  0,
                        maximum       =  10000 )
        self.numberOfAASpinBox.setEnabled(False)