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
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)
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)