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
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
示例#4
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