def _loadSelectedAtomPosGroupBox(self, inPmGroupBox): """ Load the selected Atoms position groupbox It is a sub-gropbox of L{self.selectionOptionsGroupBox) @param inPmGroupBox: 'The Selected Atom Position Groupbox' @type inPmGroupBox: L{PM_GroupBox} """ self.selectedAtomLineEdit = PM_LineEdit(inPmGroupBox, label="Selected Atom:", text="", setAsDefault=False, spanWidth=False) self.selectedAtomLineEdit.setReadOnly(True) self.selectedAtomLineEdit.setEnabled(False) self.coordinateSpinboxes = PM_CoordinateSpinBoxes(inPmGroupBox) # User input to specify x-coordinate self.xCoordOfSelectedAtom = self.coordinateSpinboxes.xSpinBox # User input to specify y-coordinate self.yCoordOfSelectedAtom = self.coordinateSpinboxes.ySpinBox # User input to specify z-coordinate self.zCoordOfSelectedAtom = self.coordinateSpinboxes.zSpinBox
def _loadGroupBox1(self, pmGroupBox): """ Load widgets in group box. """ self.structure1LineEdit = PM_LineEdit(pmGroupBox, label="First structure:", setAsDefault=False) self.structure1LineEdit.setEnabled(False) self.structure2LineEdit = PM_LineEdit(pmGroupBox, label="Second structure:", setAsDefault=False) self.structure2LineEdit.setEnabled(False) self.thresholdDoubleSpinBox = PM_DoubleSpinBox( pmGroupBox, label="Threshold:", value=self.threshold, setAsDefault=True, minimum=0.0, maximum=360.0, decimals=1, singleStep=30.0, suffix=" deg", spanWidth=False, ) self.comparePushButton = PM_PushButton(pmGroupBox, text="Compare", setAsDefault=True) self.hidePushButton = PM_PushButton(pmGroupBox, text="Hide differences", setAsDefault=True) return
def _loadGroupBox1(self, pmGroupBox): """ Load widgets in group box. """ includeStrandsChoices = ["All strands in model", "Selected strands only"] self.includeStrandsComboBox = \ PM_ComboBox( pmGroupBox, label = "Include strands:", choices = includeStrandsChoices, setAsDefault = True) self.numberOfBasesLineEdit = \ PM_LineEdit( pmGroupBox, label = "Total nucleotides:", text = str(self.getNumberOfBases())) self.numberOfBasesLineEdit.setEnabled(False) self.numberOfXBasesLineEdit = \ PM_LineEdit( pmGroupBox, label = "Unassigned:", text = str(self.getNumberOfBases(unassignedOnly = True))) self.numberOfXBasesLineEdit.setEnabled(False) self.viewDnaOrderFileButton = \ PM_PushButton( pmGroupBox, label = "", text = "View DNA Order File...", spanWidth = True) return
def loadLineEditGroupBox(self, inPmGroupBox): """ Load PM_LineEdit test widgets in group box. """ self.lineEdit1 = \ PM_LineEdit( inPmGroupBox, label = "Name:", text = "RotaryMotor-1", setAsDefault = True, spanWidth = False) self.lineEdit2 = \ PM_LineEdit( inPmGroupBox, label = ":Name", labelColumn = 1, text = "RotaryMotor-1", setAsDefault = True, spanWidth = False) self.lineEdit3 = \ PM_LineEdit( inPmGroupBox, label = "LineEdit (spanWidth = True):", text = "RotaryMotor-1", setAsDefault = False, spanWidth = True)
def _loadGroupBox1(self, pmGroupBox): """ Load widgets in group box. """ includeStrandsChoices = [ "All strands in model", "Selected strands only" ] self.includeStrandsComboBox = \ PM_ComboBox( pmGroupBox, label = "Include strands:", choices = includeStrandsChoices, setAsDefault = True) self.numberOfBasesLineEdit = \ PM_LineEdit( pmGroupBox, label = "Total nucleotides:", text = str(self.getNumberOfBases())) self.numberOfBasesLineEdit.setEnabled(False) self.numberOfXBasesLineEdit = \ PM_LineEdit( pmGroupBox, label = "Unassigned:", text = str(self.getNumberOfBases(unassignedOnly = True))) self.numberOfXBasesLineEdit.setEnabled(False) self.viewDnaOrderFileButton = \ PM_PushButton( pmGroupBox, label = "", text = "View DNA Order File...", spanWidth = True) 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 _loadGroupBox2(self, pmGroupBox): """ Load widgets in group box 4. """ self.conformationComboBox = \ PM_ComboBox( pmGroupBox, label = "Conformation:", choices = ["B-DNA"], setAsDefault = True) dnaModelChoices = ['PAM3', 'PAM5'] self.dnaModelComboBox = \ PM_ComboBox( pmGroupBox, label = "Model:", choices = dnaModelChoices, setAsDefault = True) self.basesPerTurnDoubleSpinBox = \ PM_DoubleSpinBox( pmGroupBox, label = "Bases per turn:", value = env.prefs[bdnaBasesPerTurn_prefs_key], setAsDefault = True, minimum = 8.0, maximum = 20.0, decimals = 2, singleStep = 0.1 ) self.duplexRiseDoubleSpinBox = \ PM_DoubleSpinBox( pmGroupBox, label = "Rise:", value = env.prefs[bdnaRise_prefs_key], setAsDefault = True, minimum = 2.0, maximum = 4.0, decimals = 3, singleStep = 0.01 ) # Strand Length (i.e. the number of bases) self.numberOfBasePairsSpinBox = \ PM_SpinBox( pmGroupBox, label = "Base pairs:", value = self._numberOfBases, setAsDefault = False, minimum = 0, maximum = 10000 ) self.numberOfBasePairsSpinBox.setDisabled(True) # Duplex Length self.duplexLengthLineEdit = \ PM_LineEdit( pmGroupBox, label = "Duplex length: ", text = "0.0 Angstroms", setAsDefault = False) self.duplexLengthLineEdit.setDisabled(True)
def _loadGroupBox1(self, pmGroupBox): """ Load widgets in group box. """ self.nameLineEdit = PM_LineEdit(pmGroupBox, label="Name:") self.lengthLineEdit = PM_LineEdit(pmGroupBox, label="Length:") self.lengthLineEdit.setEnabled(False) self.currentResidueComboBox = PM_ComboBox(pmGroupBox, label="Current residue:", setAsDefault=False) BUTTON_LIST = [ ("QToolButton", 1, "Previous residue", "ui/actions/Properties Manager/Previous.png", "", "Previous residue", 0), ("QToolButton", 2, "Next residue", "ui/actions/Properties Manager/Next.png", "", "Next residue", 1) ] self.prevNextButtonRow = \ PM_ToolButtonRow( pmGroupBox, title = "", buttonList = BUTTON_LIST, label = 'Previous / Next:', isAutoRaise = True, isCheckable = False ) self.prevButton = self.prevNextButtonRow.getButtonById(1) self.nextButton = self.prevNextButtonRow.getButtonById(2) self.recenterViewCheckBox = \ PM_CheckBox( pmGroupBox, text = "Center view on current residue", setAsDefault = True, state = Qt.Unchecked, widgetColumn = 0, spanWidth = True) self.lockEditedCheckBox = \ PM_CheckBox( pmGroupBox, text = "Lock edited rotamers", setAsDefault = True, state = Qt.Checked, widgetColumn = 0, spanWidth = True) self.showAllResiduesCheckBox = \ PM_CheckBox( pmGroupBox, text = "Show all residues", setAsDefault = False, state = Qt.Unchecked, widgetColumn = 0, spanWidth = True) return
def _loadSelectionOptionsGroupBox(self, inPmGroupBox): """ Load widgets in the Selection Options group box. @param inPmGroupBox: The Selection Options box in the PM @type inPmGroupBox: L{PM_GroupBox} """ self.selectionFilterCheckBox = \ PM_CheckBox( inPmGroupBox, text = "Enable atom selection filter", widgetColumn = 0, state = Qt.Unchecked ) self.selectionFilterCheckBox.setDefaultValue(False) self.filterlistLE = PM_LineEdit(inPmGroupBox, label="", text="", setAsDefault=False, spanWidth=True) self.filterlistLE.setReadOnly(True) if self.selectionFilterCheckBox.isChecked(): self.filterlistLE.setEnabled(True) else: self.filterlistLE.setEnabled(False) self.showSelectedAtomInfoCheckBox = \ PM_CheckBox( inPmGroupBox, text = "Show Selected Atom Info", widgetColumn = 0, state = Qt.Unchecked) self.selectedAtomPosGroupBox = \ PM_GroupBox( inPmGroupBox, title = "") self._loadSelectedAtomPosGroupBox(self.selectedAtomPosGroupBox) self.toggle_selectedAtomPosGroupBox(show=0) self.enable_or_disable_selectedAtomPosGroupBox(bool_enable=False) self.reshapeSelectionCheckBox = \ PM_CheckBox( inPmGroupBox, text = 'Dragging reshapes selection', widgetColumn = 0, state = Qt.Unchecked ) connect_checkbox_with_boolean_pref(self.reshapeSelectionCheckBox, reshapeAtomsSelection_prefs_key) env.prefs[reshapeAtomsSelection_prefs_key] = False self.waterCheckBox = \ PM_CheckBox( inPmGroupBox, text = "Z depth filter (water surface)", widgetColumn = 0, state = Qt.Unchecked )
def _loadLayerPropertiesGroupBox(self, inPmGroupBox): """ Load widgets in the Layer Properties group box. @param inPmGroupBox: The Layer Properties groupbox in the PM @type inPmGroupBox: L{PM_GroupBox} """ self.currentLayerComboBox = \ PM_ComboBox( inPmGroupBox, index = 0, spanWidth = True ) self.addLayerButton = PM_PushButton(inPmGroupBox) self.addLayerButton.setIcon( geticon('ui/actions/Properties Manager/addlayer.png')) self.addLayerButton.setFixedSize(QSize(26, 26)) self.addLayerButton.setIconSize(QSize(22, 22)) # A widget list to create a widget row. # Format: # - Widget type, # - widget object, # - column firstRowWidgetList = [('PM_ComboBox', self.currentLayerComboBox, 1), ('PM_PushButton', self.addLayerButton, 2)] widgetRow = PM_WidgetRow( inPmGroupBox, title='', widgetList=firstRowWidgetList, label="Layer:", labelColumn=0, ) self.layerCellsSpinBox = \ PM_SpinBox( inPmGroupBox, label = "Lattice cells:", labelColumn = 0, value = 2, minimum = 1, maximum = 25 ) self.layerThicknessLineEdit = PM_LineEdit(inPmGroupBox, label="Thickness:", text="", setAsDefault=False, spanWidth=False) #self.layerThicknessLineEdit.setReadOnly(True) self.layerThicknessLineEdit.setDisabled(True) tooltip = "Thickness of layer in Angstroms" self.layerThicknessLineEdit.setToolTip(tooltip)
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 _loadGroupBox1(self, pmGroupBox): """ Load widgets in group box 4. """ self.nameLineEdit = PM_LineEdit(pmGroupBox, label="Segment name:", text="", setAsDefault=False) # Strand Length (i.e. the number of bases) self.numberOfBasePairsSpinBox = \ PM_SpinBox( pmGroupBox, label = "Base pairs:", 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.basesPerTurnDoubleSpinBox.setDisabled(True) self.duplexRiseDoubleSpinBox = \ PM_DoubleSpinBox( pmGroupBox, label = "Rise:", value = self.duplexRise, setAsDefault = True, minimum = 2.0, maximum = 4.0, decimals = 3, singleStep = 0.01 ) self.duplexRiseDoubleSpinBox.setDisabled(True) # Duplex Length self.duplexLengthLineEdit = \ PM_LineEdit( pmGroupBox, label = "Duplex length: ", text = "0.0 Angstroms", setAsDefault = False) self.duplexLengthLineEdit.setDisabled(True)
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 _loadSelectedAtomPosGroupBox(self, inPmGroupBox): """ Load the selected Atoms position groupbox It is a sub-gropbox of L{self.selectionOptionsGroupBox) @param inPmGroupBox: 'The Selected Atom Position Groupbox' @type inPmGroupBox: L{PM_GroupBox} """ self.selectedAtomLineEdit = PM_LineEdit( inPmGroupBox, label = "Selected Atom:", text = "", setAsDefault = False, spanWidth = False ) self.selectedAtomLineEdit.setReadOnly(True) self.selectedAtomLineEdit.setEnabled(False) self.coordinateSpinboxes = PM_CoordinateSpinBoxes(inPmGroupBox) # User input to specify x-coordinate self.xCoordOfSelectedAtom = self.coordinateSpinboxes.xSpinBox # User input to specify y-coordinate self.yCoordOfSelectedAtom = self.coordinateSpinboxes.ySpinBox # User input to specify z-coordinate self.zCoordOfSelectedAtom = self.coordinateSpinboxes.zSpinBox
def _loadSelectionOptionsGroupBox(self, inPmGroupBox): """ Load widgets in the Selection Options group box. @param inPmGroupBox: The Selection Options box in the PM @type inPmGroupBox: L{PM_GroupBox} """ self.selectionFilterCheckBox = \ PM_CheckBox( inPmGroupBox, text = "Enable atom selection filter", widgetColumn = 0, state = Qt.Unchecked ) self.selectionFilterCheckBox.setDefaultValue(False) self.filterlistLE = PM_LineEdit( inPmGroupBox, label = "", text = "", setAsDefault = False, spanWidth = True ) self.filterlistLE.setReadOnly(True) if self.selectionFilterCheckBox.isChecked(): self.filterlistLE.setEnabled(True) else: self.filterlistLE.setEnabled(False) self.showSelectedAtomInfoCheckBox = \ PM_CheckBox( inPmGroupBox, text = "Show Selected Atom Info", widgetColumn = 0, state = Qt.Unchecked) self.selectedAtomPosGroupBox = \ PM_GroupBox( inPmGroupBox, title = "") self._loadSelectedAtomPosGroupBox(self.selectedAtomPosGroupBox) self.toggle_selectedAtomPosGroupBox(show = 0) self.enable_or_disable_selectedAtomPosGroupBox( bool_enable = False) self.reshapeSelectionCheckBox = \ PM_CheckBox( inPmGroupBox, text = 'Dragging reshapes selection', widgetColumn = 0, state = Qt.Unchecked ) connect_checkbox_with_boolean_pref( self.reshapeSelectionCheckBox, reshapeAtomsSelection_prefs_key ) env.prefs[reshapeAtomsSelection_prefs_key] = False self.waterCheckBox = \ PM_CheckBox( inPmGroupBox, text = "Z depth filter (water surface)", widgetColumn = 0, state = Qt.Unchecked )
def _loadGroupBox1(self, pmGroupBox): """ Load widgets in group box 4. """ self.nameLineEdit = PM_LineEdit(pmGroupBox, label="Name:", text="", setAsDefault=False) # Nanotube Length self.ntLengthLineEdit = \ PM_LineEdit( pmGroupBox, label = "Length: ", text = "0.0 Angstroms", setAsDefault = False) self.ntLengthLineEdit.setDisabled(True) # Nanotube Radius self.ntDiameterLineEdit = \ PM_LineEdit( pmGroupBox, label = "Nanotube Diameter: ", setAsDefault = False) self.ntDiameterLineEdit.setDisabled(True) # Nanotube chirality. These are disabled (read-only) for now. --Mark self.chiralityNSpinBox = \ PM_SpinBox( pmGroupBox, label = "Chirality (n) :", minimum = 2, maximum = 100, setAsDefault = True ) self.chiralityNSpinBox.setDisabled(True) self.chiralityMSpinBox = \ PM_SpinBox( pmGroupBox, label = "Chirality (m) :", minimum = 0, maximum = 100, setAsDefault = True ) self.chiralityMSpinBox.setDisabled(True)
def _loadGroupBox1(self, pmGroupBox): """ Load widgets in group box 4. """ self.nameLineEdit = PM_LineEdit( pmGroupBox, label = "Name:", text = "", setAsDefault = False) # Nanotube Length self.ntLengthLineEdit = \ PM_LineEdit( pmGroupBox, label = "Length: ", text = "0.0 Angstroms", setAsDefault = False) self.ntLengthLineEdit.setDisabled(True) # Nanotube Radius self.ntDiameterLineEdit = \ PM_LineEdit( pmGroupBox, label = "Nanotube Diameter: ", setAsDefault = False) self.ntDiameterLineEdit.setDisabled(True) # Nanotube chirality. These are disabled (read-only) for now. --Mark self.chiralityNSpinBox = \ PM_SpinBox( pmGroupBox, label = "Chirality (n) :", minimum = 2, maximum = 100, setAsDefault = True ) self.chiralityNSpinBox.setDisabled(True) self.chiralityMSpinBox = \ PM_SpinBox( pmGroupBox, label = "Chirality (m) :", minimum = 0, maximum = 100, setAsDefault = True ) self.chiralityMSpinBox.setDisabled(True)
def _loadLayerPropertiesGroupBox(self, inPmGroupBox): """ Load widgets in the Layer Properties group box. @param inPmGroupBox: The Layer Properties groupbox in the PM @type inPmGroupBox: L{PM_GroupBox} """ self.currentLayerComboBox = \ PM_ComboBox( inPmGroupBox, index = 0, spanWidth = True ) self.addLayerButton = PM_PushButton(inPmGroupBox) self.addLayerButton.setIcon( geticon('ui/actions/Properties Manager/addlayer.png')) self.addLayerButton.setFixedSize(QSize(26, 26)) self.addLayerButton.setIconSize(QSize(22, 22)) # A widget list to create a widget row. # Format: # - Widget type, # - widget object, # - column firstRowWidgetList = [('PM_ComboBox', self.currentLayerComboBox, 1), ('PM_PushButton', self.addLayerButton, 2) ] widgetRow = PM_WidgetRow(inPmGroupBox, title = '', widgetList = firstRowWidgetList, label = "Layer:", labelColumn = 0, ) self.layerCellsSpinBox = \ PM_SpinBox( inPmGroupBox, label = "Lattice cells:", labelColumn = 0, value = 2, minimum = 1, maximum = 25 ) self.layerThicknessLineEdit = PM_LineEdit(inPmGroupBox, label = "Thickness:", text = "", setAsDefault = False, spanWidth = False ) #self.layerThicknessLineEdit.setReadOnly(True) self.layerThicknessLineEdit.setDisabled(True) tooltip = "Thickness of layer in Angstroms" self.layerThicknessLineEdit.setToolTip(tooltip)
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 _loadGroupBox1(self, pmGroupBox): """ Load widgets in group box. """ self.structure1LineEdit = \ PM_LineEdit( pmGroupBox, label = "First structure:", setAsDefault = False) self.structure1LineEdit.setEnabled(False) self.structure2LineEdit = \ PM_LineEdit( pmGroupBox, label = "Second structure:", setAsDefault = False) self.structure2LineEdit.setEnabled(False) self.thresholdDoubleSpinBox = \ PM_DoubleSpinBox( pmGroupBox, label = "Threshold:", value = self.threshold, setAsDefault = True, minimum = 0.0, maximum = 360.0, decimals = 1, singleStep = 30.0, suffix = " deg", spanWidth = False) self.comparePushButton = \ PM_PushButton( pmGroupBox, text = "Compare", setAsDefault = True) self.hidePushButton = \ PM_PushButton( pmGroupBox, text = "Hide differences", setAsDefault = True) return
def _loadGroupBox2(self, groupbox): """ Load widgets into group box 2. """ self.someLineEdit = \ PM_LineEdit( groupbox, label = "Text:", text = "initial text (pm)", setAsDefault = True, spanWidth = False ) ### TODO: self.someLineEdit.connectWithState( ... some text state ...) # and then connect the TextState text to the same state # (or just use that state? no, it needs an address outside that complicated expr) return
def _loadGroupBox1(self, pmGroupBox): """ Load widgets in group box 4. """ self.nameLineEdit = PM_LineEdit( pmGroupBox, label = "Segment name:", text = "", setAsDefault = False) # Strand Length (i.e. the number of bases) self.numberOfBasePairsSpinBox = \ PM_SpinBox( pmGroupBox, label = "Base pairs:", 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.basesPerTurnDoubleSpinBox.setDisabled(True) self.duplexRiseDoubleSpinBox = \ PM_DoubleSpinBox( pmGroupBox, label = "Rise:", value = self.duplexRise, setAsDefault = True, minimum = 2.0, maximum = 4.0, decimals = 3, singleStep = 0.01 ) self.duplexRiseDoubleSpinBox.setDisabled(True) # Duplex Length self.duplexLengthLineEdit = \ PM_LineEdit( pmGroupBox, label = "Duplex length: ", text = "0.0 Angstroms", setAsDefault = False) self.duplexLengthLineEdit.setDisabled(True)
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)
def _loadFreeDragRotateGroupBox(self, inPmGroupBox): """ Load widgets in the Free Drag Rotate group box, which is present within the Rotate groupbox. @param inPmGroupBox: The Free Drag Rotate group box in the Rotate group box. @type inPmGroupBox: L{PM_GroupBox} """ # Button list to create a toolbutton row. # Format: # - buttonId, # - buttonText , # - iconPath # - tooltip # - shortcut # - column BUTTON_LIST = [ ( "QToolButton", 1, "ROTATEDEFAULT", "ui/actions/Properties Manager/Rotate_Free.png", "", "F", 0 ), ( "QToolButton", 2, "ROTATEX", "ui/actions/Properties Manager/RotateX.png", "", "X", 1 ), ( "QToolButton", 3, "ROTATEY", "ui/actions/Properties Manager/RotateY.png", "", "Y", 2 ), ( "QToolButton", 4, "ROTATEZ", "ui/actions/Properties Manager/RotateZ.png", "", "Z", 3 ), ( "QToolButton", 5, "ROT_TRANS_ALONG_AXIS", "ui/actions/Properties Manager/translate+rotate-A.png", "", \ "A", 4 ) ] self.freeDragRotateButtonGroup = \ PM_ToolButtonRow( inPmGroupBox, title = "", buttonList = BUTTON_LIST, spanWidth = True, checkedId = 1, setAsDefault = True, ) self.rotateFreeButton = self.freeDragRotateButtonGroup.getButtonById(1) self.rotateXButton = self.freeDragRotateButtonGroup.getButtonById(2) self.rotateYButton = self.freeDragRotateButtonGroup.getButtonById(3) self.rotateZButton = self.freeDragRotateButtonGroup.getButtonById(4) self.rotAlongAxisButton = \ self.freeDragRotateButtonGroup.getButtonById(5) inPmGroupBox.setStyleSheet( self.freeDragRotateButtonGroup._getStyleSheet()) X_ROW_LABELS = [("QLabel", "Delta Theta X:", 0), ("QLabel", "", 1), ("QLabel", "0.00", 2), ("QLabel", "Degrees", 3)] Y_ROW_LABELS = [("QLabel", "Delta Theta Y:", 0), ("QLabel", "", 1), ("QLabel", "0.00", 2), ("QLabel", "Degrees", 3)] Z_ROW_LABELS = [("QLabel", "Delta Theta Z:", 0), ("QLabel", "", 1), ("QLabel", "0.00", 2), ("QLabel", "Degrees", 3)] self.rotateXLabelRow = PM_LabelRow(inPmGroupBox, title="", labelList=X_ROW_LABELS) self.deltaThetaX_lbl = self.rotateXLabelRow.labels[2] self.rotateYLabelRow = PM_LabelRow(inPmGroupBox, title="", labelList=Y_ROW_LABELS) self.deltaThetaY_lbl = self.rotateYLabelRow.labels[2] self.rotateZLabelRow = PM_LabelRow(inPmGroupBox, title="", labelList=Z_ROW_LABELS) self.deltaThetaZ_lbl = self.rotateZLabelRow.labels[2] self.rotateAboutPointButton = PM_ToolButton( inPmGroupBox, text = "Rotate selection about a point", iconPath = "ui/actions/Properties Manager"\ "/Rotate_Components.png", spanWidth = True ) self.rotateAboutPointButton.setCheckable(True) self.rotateAboutPointButton.setAutoRaise(True) self.rotateAboutPointButton.setToolButtonStyle( Qt.ToolButtonTextBesideIcon) self.rotateStartCoordLineEdit = PM_LineEdit( inPmGroupBox, label = "ui/actions/Properties Manager"\ "/Move_Start_Point.png", text = "Define 3 points", setAsDefault = False, ) self.rotateStartCoordLineEdit.setReadOnly(True) self.rotateStartCoordLineEdit.setEnabled(False)
def _loadGroupBox1(self, pmGroupBox): """ Load widgets in group box. """ self.nameLineEdit = PM_LineEdit( pmGroupBox, label = "Name:") self.lengthLineEdit = PM_LineEdit( pmGroupBox, label = "Length:") self.lengthLineEdit.setEnabled(False) self.currentResidueComboBox = PM_ComboBox( pmGroupBox, label = "Current residue:", setAsDefault = False) BUTTON_LIST = [ ("QToolButton", 1, "Previous residue", "ui/actions/Properties Manager/Previous.png", "", "Previous residue", 0 ), ( "QToolButton", 2, "Next residue", "ui/actions/Properties Manager/Next.png", "", "Next residue", 1 ) ] self.prevNextButtonRow = \ PM_ToolButtonRow( pmGroupBox, title = "", buttonList = BUTTON_LIST, label = 'Previous / Next:', isAutoRaise = True, isCheckable = False ) self.prevButton = self.prevNextButtonRow.getButtonById(1) self.nextButton = self.prevNextButtonRow.getButtonById(2) self.recenterViewCheckBox = \ PM_CheckBox( pmGroupBox, text = "Center view on current residue", setAsDefault = True, state = Qt.Unchecked, widgetColumn = 0, spanWidth = True) self.lockEditedCheckBox = \ PM_CheckBox( pmGroupBox, text = "Lock edited rotamers", setAsDefault = True, state = Qt.Checked, widgetColumn = 0, spanWidth = True) self.showAllResiduesCheckBox = \ PM_CheckBox( pmGroupBox, text = "Show all residues", setAsDefault = False, state = Qt.Unchecked, widgetColumn = 0, spanWidth = True) return
class Ui_DnaSequenceEditor(PM_DockWidget): """ The Ui_DnaSequenceEditor class defines UI elements for the Sequence Editor object. The sequence editor is usually visible while in while editing a DnaStrand. It is a DockWidget that is docked at the bottom of the MainWindow. """ _title = "Sequence Editor" _groupBoxCount = 0 _lastGroupBox = None def __init__(self, win): """ Constructor for the Ui_DnaSequenceEditor @param win: The parentWidget (MainWindow) for the sequence editor """ self.win = win # Should parentWidget for a docwidget always be win? #Not necessary but most likely it will be the case. parentWidget = win _superclass.__init__(self, parentWidget, title=self._title) #A flag used to restore the state of the Reports dock widget #(which can be accessed through View > Reports) see self.show() and #self.closeEvent() for more details. self._reportsDockWidget_closed_in_show_method = False self.setFixedHeight(90) return def show(self): """ Shows the sequence editor. While doing this, it also closes the reports dock widget (if visible) the state of the reports dockwidget will be restored when the sequence editor is closed. @see:self.closeEvent() """ self._reportsDockWidget_closed_in_show_method = False #hide the history widget first #(It will be shown back during self.close) #The history widget is hidden or shown only when both # 'View > Full Screen' and View > Semi Full Screen actions # are *unchecked* #Thus show or close methods won't do anything to history widget # if either of the above mentioned actions is checked. if self.win.viewFullScreenAction.isChecked() or \ self.win.viewSemiFullScreenAction.isChecked(): pass else: if self.win.reportsDockWidget.isVisible(): self.win.reportsDockWidget.close() self._reportsDockWidget_closed_in_show_method = True _superclass.show(self) return def closeEvent(self, event): """ Overrides close event. Makes sure that the visible state of the reports widgetis restored when the sequence editor is closed. @see: self.show() """ _superclass.closeEvent(self, event) if self.win.viewFullScreenAction.isChecked() or \ self.win.viewSemiFullScreenAction.isChecked(): pass else: if self._reportsDockWidget_closed_in_show_method: self.win.viewReportsAction.setChecked(True) self._reportsDockWidget_closed_in_show_method = False return def _loadWidgets(self): """ Overrides PM.PM_DockWidget._loadWidgets. Loads the widget in this dockwidget. """ self._loadMenuWidgets() self._loadTextEditWidget() return def _loadMenuWidgets(self): """ Load the various menu widgets (e.g. Open, save sequence options, Find and replace widgets etc. """ #Note: Find and replace widgets might be moved to their own class. self.loadSequenceButton = PM_ToolButton( self, iconPath="ui/actions/Properties Manager/Open.png") self.saveSequenceButton = PM_ToolButton( self, iconPath="ui/actions/Properties Manager/Save_Strand_Sequence.png") self.loadSequenceButton.setAutoRaise(True) self.saveSequenceButton.setAutoRaise(True) # Only supporting 5' to 3' direction until bug 2956 is fixed. # Mark 2008-12-19 editDirectionChoices = ["5' to 3'"] # , "3' to 5'"] self.baseDirectionChoiceComboBox = \ PM_ComboBox( self, choices = editDirectionChoices, index = 0, spanWidth = False ) #Find and replace widgets -- self.findLineEdit = \ PM_LineEdit( self, label = "", spanWidth = False) self.findLineEdit.setMaximumWidth(60) self.replaceLineEdit = \ PM_LineEdit( self, label = "", spanWidth = False) self.replaceLineEdit.setMaximumWidth(60) self.findOptionsToolButton = PM_ToolButton(self) self.findOptionsToolButton.setMaximumWidth(12) self.findOptionsToolButton.setAutoRaise(True) self.findOptionsToolButton.setPopupMode(QToolButton.MenuButtonPopup) self._setFindOptionsToolButtonMenu() self.findNextToolButton = PM_ToolButton( self, iconPath="ui/actions/Properties Manager/Find_Next.png") self.findNextToolButton.setAutoRaise(True) self.findPreviousToolButton = PM_ToolButton( self, iconPath="ui/actions/Properties Manager/Find_Previous.png") self.findPreviousToolButton.setAutoRaise(True) self.replacePushButton = PM_PushButton(self, text="Replace") self.warningSign = QLabel(self) self.warningSign.setPixmap( getpixmap('ui/actions/Properties Manager/Warning.png')) self.warningSign.hide() self.phraseNotFoundLabel = QLabel(self) self.phraseNotFoundLabel.setText("Sequence Not Found") self.phraseNotFoundLabel.hide() # NOTE: Following needs cleanup in the PM_WidgetRow/ PM_WidgetGrid # but this explanation is sufficient until thats done -- # When the widget type starts with the word 'PM_' , the # PM_WidgetRow treats it as a well defined widget and thus doesn't try # to create a QWidget object (or its subclasses) # This is the reason why qLabels such as self.warningSign and # self.phraseNotFoundLabel are defined as PM_Labels and not 'QLabels' # If they were defined as 'QLabel'(s) then PM_WidgetRow would have # recreated the label. Since we want to show/hide the above mentioned # labels (and if they were recreated as mentioned above), # we would have needed to define those something like this: # self.phraseNotFoundLabel = widgetRow._widgetList[-2] #Cleanup in PM_widgetGrid could be to check if the widget starts with #'Q' instead of 'PM_' #Widgets to include in the widget row. widgetList = [('PM_ToolButton', self.loadSequenceButton, 0), ('PM_ToolButton', self.saveSequenceButton, 1), ('QLabel', " Sequence direction:", 2), ('PM_ComboBox', self.baseDirectionChoiceComboBox, 3), ('QLabel', " Find:", 4), ('PM_LineEdit', self.findLineEdit, 5), ('PM_ToolButton', self.findOptionsToolButton, 6), ('PM_ToolButton', self.findPreviousToolButton, 7), ('PM_ToolButton', self.findNextToolButton, 8), ('QLabel', " Replace:", 9), ('PM_TextEdit', self.replaceLineEdit, 10), ('PM_PushButton', self.replacePushButton, 11), ('PM_Label', self.warningSign, 12), ('PM_Label', self.phraseNotFoundLabel, 13), ('QSpacerItem', 5, 5, 14)] widgetRow = PM_WidgetRow(self, title='', widgetList=widgetList, label="", spanWidth=True) return def _loadTextEditWidget(self): """ Load the SequenceTexteditWidgets. """ self.sequenceTextEdit = \ PM_TextEdit( self, label = " Sequence: ", spanWidth = False, permit_enter_keystroke = False) self.sequenceTextEdit.setCursorWidth(2) self.sequenceTextEdit.setWordWrapMode(QTextOption.WrapAnywhere) self.sequenceTextEdit.setFixedHeight(20) #The StrandSequence 'Mate' it is a read only etxtedit that shows #the complementary strand sequence. self.sequenceTextEdit_mate = \ PM_TextEdit(self, label = "", spanWidth = False, permit_enter_keystroke = False ) palette = getPalette(None, QPalette.Base, sequenceEditStrandMateBaseColor) self.sequenceTextEdit_mate.setPalette(palette) self.sequenceTextEdit_mate.setFixedHeight(20) self.sequenceTextEdit_mate.setReadOnly(True) self.sequenceTextEdit_mate.setWordWrapMode(QTextOption.WrapAnywhere) #Important to make sure that the horizontal and vertical scrollbars #for these text edits are never displayed. for textEdit in (self.sequenceTextEdit, self.sequenceTextEdit_mate): textEdit.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) textEdit.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) return def _getFindLineEditStyleSheet(self): """ Return the style sheet for the findLineEdit. This sets the following properties only: - background-color This style is set whenever the searchStrig can't be found (sets a light red color background to the lineedit when this happens) @return: The line edit style sheet. @rtype: str """ styleSheet = "QLineEdit {"\ "background-color: rgb(255, 102, 102)"\ "}" #Not used: # background-color: rgb(217, 255, 216)\ return styleSheet def _setFindOptionsToolButtonMenu(self): """ Sets the menu for the findOptionstoolbutton that appears a small menu button next to the findLineEdit. """ self.findOptionsMenu = QMenu(self.findOptionsToolButton) self.caseSensitiveFindAction = QAction(self.findOptionsToolButton) self.caseSensitiveFindAction.setText('Match Case') self.caseSensitiveFindAction.setCheckable(True) self.caseSensitiveFindAction.setChecked(False) self.findOptionsMenu.addAction(self.caseSensitiveFindAction) self.findOptionsMenu.addSeparator() self.findOptionsToolButton.setMenu(self.findOptionsMenu) return def _addToolTipText(self): """ What's Tool Tip text for widgets in this Property Manager. """ from ne1_ui.ToolTipText_for_PropertyManagers import ToolTip_DnaSequenceEditor ToolTip_DnaSequenceEditor(self) return def _addWhatsThisText(self): """ What's This text for widgets in this Property Manager. """ from ne1_ui.WhatsThisText_for_PropertyManagers import whatsThis_DnaSequenceEditor whatsThis_DnaSequenceEditor(self) return
class EditProtein_PropertyManager(Command_PropertyManager): """ The ProteinDisplayStyle_PropertyManager class provides a Property Manager for the B{Edit Protein} command on the Build Protein command toolbar. The selected peptide/protein is displayed in the protein reduced display style. The user can select individual rotamers and edit their chi angles. This is useful for certain types of protein design protocols using a 3rd party program like Rosetta. @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 = "Protein Properties" pmName = title iconPath = "ui/actions/Command Toolbar/BuildProtein/EditProtein.png" current_protein = None # The currently selected peptide. previous_protein = None # The last peptide selected. current_aa = None # The current amino acid. def __init__( self, command ): """ Constructor for the property manager. """ self.currentWorkingDirectory = env.prefs[workingDirectory_prefs_key] _superclass.__init__(self, command) self.sequenceEditor = self.win.createProteinSequenceEditorIfNeeded() self.showTopRowButtons( PM_DONE_BUTTON | \ PM_WHATS_THIS_BUTTON) return def connect_or_disconnect_signals(self, isConnect = True): if isConnect: change_connect = self.win.connect else: change_connect = self.win.disconnect change_connect(self.nameLineEdit, SIGNAL("editingFinished()"), self._nameChanged) change_connect(self.currentResidueComboBox, SIGNAL("activated(int)"), self.setCurrentAminoAcid) change_connect(self.prevButton, SIGNAL("clicked()"), self._expandPreviousRotamer) change_connect(self.nextButton, SIGNAL("clicked()"), self._expandNextRotamer) change_connect(self.recenterViewCheckBox, SIGNAL("toggled(bool)"), self._centerViewToggled) change_connect(self.showAllResiduesCheckBox, SIGNAL("toggled(bool)"), self._showAllResidues) # Rotamer control widgets. change_connect(self.chi1Dial, SIGNAL("valueChanged(int)"), self._rotateChi1) change_connect(self.chi2Dial, SIGNAL("valueChanged(int)"), self._rotateChi2) change_connect(self.chi3Dial, SIGNAL("valueChanged(int)"), self._rotateChi3) # Chi4 dial is hidden. change_connect(self.chi4Dial, SIGNAL("valueChanged(double)"), self._rotateChi4) return #== def _nameChanged(self): """ Slot for "Name" field. @TODO: Include a validator for the name field. """ if not self.current_protein: return _name = str(self.nameLineEdit.text()) if not _name: # Minimal test. Need to implement a validator. if self.current_protein: self.nameLineEdit.setText(self.current_protein.name) return self.current_protein.name = _name msg = "Editing structure <b>%s</b>." % _name self.updateMessage(msg) return def update_name_field(self): """ Update the name field showing the name of the currently selected protein. clear the combobox list. """ if not self.current_protein: self.nameLineEdit.setText("") else: self.nameLineEdit.setText(self.current_protein.name) return def update_length_field(self): """ Update the name field showing the name of the currently selected protein. clear the combobox list. """ if not self.current_protein: self.lengthLineEdit.setText("") else: length_str = "%d residues" % self.current_protein.protein.count_amino_acids() self.lengthLineEdit.setText(length_str) return def update_residue_combobox(self): """ Update the residue combobox with the amino acid sequence of the currently selected protein. If there is no currently selected protein, clear the combobox list. """ self.currentResidueComboBox.clear() if not self.current_protein: return aa_list = self.current_protein.protein.get_amino_acid_id_list() for j in range(len(aa_list)): aa_id, residue_id = aa_list[j].strip().split(":") self.currentResidueComboBox.addItem(residue_id) pass self.setCurrentAminoAcid() return def close(self): """ Closes the Property Manager. Overrides EditCommand_PM.close() """ self.sequenceEditor.hide() env.history.statusbar_msg("") if self.current_protein: self.current_protein.setDisplayStyle(self.previous_protein_display_style) self.previous_protein = None # Update name in case the it was changed by the user. self.current_protein.name = str(self.nameLineEdit.text()) _superclass.close(self) return def show(self): """ Show the PM. Extends superclass method. @note: _update_UI_do_updates() gets called immediately after this and updates PM widgets with their correct values/settings. """ _superclass.show(self) env.history.statusbar_msg("") return def _addGroupBoxes( self ): """ Add the Property Manager group boxes. """ self._pmGroupBox1 = PM_GroupBox( self, title = "Parameters") self._loadGroupBox1( self._pmGroupBox1 ) self._pmGroupBox2 = PM_GroupBox( self, title = "Rotamer Controls") self._loadGroupBox2( self._pmGroupBox2 ) return def _loadGroupBox1(self, pmGroupBox): """ Load widgets in group box. """ self.nameLineEdit = PM_LineEdit( pmGroupBox, label = "Name:") self.lengthLineEdit = PM_LineEdit( pmGroupBox, label = "Length:") self.lengthLineEdit.setEnabled(False) self.currentResidueComboBox = PM_ComboBox( pmGroupBox, label = "Current residue:", setAsDefault = False) BUTTON_LIST = [ ("QToolButton", 1, "Previous residue", "ui/actions/Properties Manager/Previous.png", "", "Previous residue", 0 ), ( "QToolButton", 2, "Next residue", "ui/actions/Properties Manager/Next.png", "", "Next residue", 1 ) ] self.prevNextButtonRow = \ PM_ToolButtonRow( pmGroupBox, title = "", buttonList = BUTTON_LIST, label = 'Previous / Next:', isAutoRaise = True, isCheckable = False ) self.prevButton = self.prevNextButtonRow.getButtonById(1) self.nextButton = self.prevNextButtonRow.getButtonById(2) self.recenterViewCheckBox = \ PM_CheckBox( pmGroupBox, text = "Center view on current residue", setAsDefault = True, state = Qt.Unchecked, widgetColumn = 0, spanWidth = True) self.lockEditedCheckBox = \ PM_CheckBox( pmGroupBox, text = "Lock edited rotamers", setAsDefault = True, state = Qt.Checked, widgetColumn = 0, spanWidth = True) self.showAllResiduesCheckBox = \ PM_CheckBox( pmGroupBox, text = "Show all residues", setAsDefault = False, state = Qt.Unchecked, widgetColumn = 0, spanWidth = True) return def _loadGroupBox2(self, pmGroupBox): """ Load widgets in group box. """ self.discreteStepsCheckBox = \ PM_CheckBox( pmGroupBox, text = "Use discrete steps", setAsDefault = True, state = Qt.Unchecked) self.chi1Dial = \ PM_Dial( pmGroupBox, label = "Chi1:", value = 0.000, setAsDefault = True, minimum = -180.0, maximum = 180.0, wrapping = True, suffix = "deg", spanWidth = False) self.chi1Dial.setEnabled(False) self.chi2Dial = \ PM_Dial( pmGroupBox, label = "Chi2:", value = 0.000, setAsDefault = True, minimum = -180.0, maximum = 180.0, suffix = "deg", spanWidth = False) self.chi2Dial.setEnabled(False) self.chi3Dial = \ PM_Dial( pmGroupBox, label = "Chi3:", value = 0.000, setAsDefault = True, minimum = -180.0, maximum = 180.0, suffix = "deg", spanWidth = False) self.chi3Dial.setEnabled(False) self.chi4Dial = \ PM_Dial( pmGroupBox, label = "Chi4:", value = 0.000, setAsDefault = True, minimum = -180.0, maximum = 180.0, suffix = "deg", spanWidth = False) self.chi4Dial.setEnabled(False) self.chi4Dial.hide() return def _addWhatsThisText( self ): pass def _addToolTipText(self): pass def _expandNextRotamer(self): """ Displays the next rotamer in the chain. @attention: this only works when the GDS is a reduced display style. """ if not self.current_protein: return self.current_protein.protein.traverse_forward() self.setCurrentAminoAcid() return def _expandPreviousRotamer(self): """ Displays the previous rotamer in the chain. @attention: this only works when the GDS is a reduced display style. """ if not self.current_protein: return self.current_protein.protein.traverse_backward() self.setCurrentAminoAcid() return def _centerViewToggled(self, checked): """ Slot for "Center view on current residue" checkbox. """ if checked: self.display_and_recenter() return def _showAllResidues(self, show): """ Slot for "Show all residues" checkbox. """ if not self.current_protein: return print "Show =",show if show: self._expandAllRotamers() else: self._collapseAllRotamers() return def _collapseAllRotamers(self): """ Hides all the rotamers (except the current rotamer). """ self.display_and_recenter() return def _expandAllRotamers(self): """ Displays all the rotamers. """ if not self.current_protein: return self.current_protein.protein.expand_all_rotamers() self.win.glpane.gl_update() return def display_and_recenter(self): """ Recenter the view on the current amino acid selected in the residue combobox (or the sequence editor). All rotamers except the current rotamer are collapsed (hidden). """ if not self.current_protein: return # Uncheck the "Show all residues" checkbox since they are being collapsed. # Disconnect signals so that showAllResiduesCheckBox won't general a signal. self.connect_or_disconnect_signals(isConnect = False) self.showAllResiduesCheckBox.setChecked(False) self.connect_or_disconnect_signals(isConnect = True) self.current_protein.protein.collapse_all_rotamers() # Display the current amino acid and center it in the view if the # "Center view on current residue" is checked. if self.current_aa: self.current_protein.protein.expand_rotamer(self.current_aa) self._update_chi_angles(self.current_aa) if self.recenterViewCheckBox.isChecked(): ca_atom = self.current_aa.get_c_alpha_atom() if ca_atom: self.win.glpane.pov = -ca_atom.posn() self.win.glpane.gl_update() return def _update_chi_angles(self, aa): """ """ angle = aa.get_chi_angle(0) if angle: self.chi1Dial.setEnabled(True) self.chi1Dial.setValue(angle) else: self.chi1Dial.setEnabled(False) self.chi1Dial.setValue(0.0) angle = aa.get_chi_angle(1) if angle: self.chi2Dial.setEnabled(True) self.chi2Dial.setValue(angle) else: self.chi2Dial.setEnabled(False) self.chi2Dial.setValue(0.0) angle = aa.get_chi_angle(2) if angle: self.chi3Dial.setEnabled(True) self.chi3Dial.setValue(angle) else: self.chi3Dial.setEnabled(False) self.chi3Dial.setValue(0.0) angle = aa.get_chi_angle(3) if angle: self.chi4Dial.setEnabled(True) self.chi4Dial.setValue(angle) else: self.chi4Dial.setEnabled(False) self.chi4Dial.setValue(0.0) return def setCurrentAminoAcid(self, aa_index = -1): """ Set the current amino acid to I{aa_index} and update the "Current residue" combobox and the sequence editor. @param aa_index: the amino acid index. If negative, update the PM and sequence editor based on the current aa_index. @type aa_index: int @note: This is the slot for the "Current residue" combobox. """ if not self.current_protein: return if aa_index < 0: aa_index = self.current_protein.protein.get_current_amino_acid_index() if 0: # Debugging statement print"setCurrentAminoAcid(): aa_index=", aa_index self.currentResidueComboBox.setCurrentIndex(aa_index) self.current_protein.protein.set_current_amino_acid_index(aa_index) self.current_aa = self.current_protein.protein.get_current_amino_acid() self.display_and_recenter() self.sequenceEditor.setCursorPosition(aa_index) return def _rotateChiAngle(self, chi, angle): """ Rotate around chi1 angle. """ if not self.current_protein: return if self.current_aa: self.current_protein.protein.expand_rotamer(self.current_aa) self.current_aa.set_chi_angle(chi, angle) self.win.glpane.gl_update() return def _rotateChi1(self, angle): """ Slot for Chi1 dial. """ self._rotateChiAngle(0, angle) self.chi1Dial.updateValueLabel() return def _rotateChi2(self, angle): """ Slot for Chi2 dial. """ self._rotateChiAngle(1, angle) self.chi2Dial.updateValueLabel() return def _rotateChi3(self, angle): """ Slot for Chi3 dial. """ self._rotateChiAngle(2, angle) self.chi3Dial.updateValueLabel() return def _rotateChi4(self, angle): """ Slot for Chi4 dial. @note: this dial is currently hidden and unused. """ self._rotateChiAngle(3, angle) return def _update_UI_do_updates(self): """ Overrides superclass method. @see: Command_PropertyManager._update_UI_do_updates() """ self.current_protein = self.win.assy.getSelectedProteinChunk() if self.current_protein is self.previous_protein: if 0: print "Edit Protein: _update_UI_do_updates() - DO NOTHING." return # It is common that the user will unselect the current protein. # If so, set current_protein to previous_protein so that it # (the previously selected protein) remains the current protein # in the PM and sequence editor. if not self.current_protein: self.current_protein = self.previous_protein return # Update all PM widgets that need to be since something has changed. if 0: print "Edit Protein: _update_UI_do_updates() - UPDATING THE PMGR." self.update_name_field() self.update_length_field() self.sequenceEditor.updateSequence(proteinChunk = self.current_protein) self.update_residue_combobox() # NOTE: Changing the display style of the protein chunks can take some # time. We should put up the wait (hourglass) cursor and restore # before returning. if self.previous_protein: self.previous_protein.setDisplayStyle(self.previous_protein_display_style) self.previous_protein = self.current_protein if self.current_protein: self.previous_protein_display_style = self.current_protein.getDisplayStyle() self.current_protein.setDisplayStyle(diPROTEIN) if self.current_protein: msg = "Editing structure <b>%s</b>." % self.current_protein.name else: msg = "Select a single structure to edit." self.updateMessage(msg) return
def _loadGroupBox2(self, pmGroupBox): """ Load widgets in group box 2. """ _ntTypeChoices = ['Carbon', 'Boron Nitride'] self.ntTypeComboBox = \ PM_ComboBox( pmGroupBox, label = "Type:", choices = _ntTypeChoices, setAsDefault = True) self.ntRiseDoubleSpinBox = \ PM_DoubleSpinBox( pmGroupBox, label = "Rise:", value = self.nanotube.getRise(), setAsDefault = True, minimum = 2.0, maximum = 4.0, decimals = 3, singleStep = 0.01 ) self.ntRiseDoubleSpinBox.hide() # Nanotube Length self.ntLengthLineEdit = \ PM_LineEdit( pmGroupBox, label = "Nanotube Length: ", text = "0.0 Angstroms", setAsDefault = False) self.ntLengthLineEdit.setDisabled(True) self.ntLengthLineEdit.hide() # Nanotube diameter self.ntDiameterLineEdit = \ PM_LineEdit( pmGroupBox, label = "Diameter: ", setAsDefault = False) self.ntDiameterLineEdit.setDisabled(True) self.updateNanotubeDiameter() self.chiralityNSpinBox = \ PM_SpinBox( pmGroupBox, label = "Chirality (n):", value = self.nanotube.getChiralityN(), minimum = 2, maximum = 100, setAsDefault = True ) self.chiralityMSpinBox = \ PM_SpinBox( pmGroupBox, label = "Chirality (m):", value = self.nanotube.getChiralityM(), minimum = 0, maximum = 100, setAsDefault = True ) # How about having user prefs for CNT and BNNT bond lengths? # I'm guessing that if the user wants to set these values, they will # do it once and would like those bond length values persist forever. # Need to discuss with others to determine if this spinbox comes out. # --Mark 2008-03-29 self.bondLengthDoubleSpinBox = \ PM_DoubleSpinBox( pmGroupBox, label = "Bond length:", value = self.nanotube.getBondLength(), setAsDefault = True, minimum = 1.0, maximum = 3.0, singleStep = 0.1, decimals = 3, suffix = " Angstroms" ) #self.bondLengthDoubleSpinBox.hide() endingChoices = ["Hydrogen", "None"] # Removed:, "Nitrogen"] self.endingsComboBox= \ PM_ComboBox( pmGroupBox, label = "Endings:", choices = endingChoices, index = 0, setAsDefault = True, spanWidth = False )
class InsertNanotube_PropertyManager( DnaOrCnt_PropertyManager): """ The InsertNanotube_PropertyManager class provides a Property Manager for the B{Build > Nanotube > CNT} 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 = "Insert Nanotube" pmName = title iconPath = "ui/actions/Tools/Build Structures/InsertNanotube.png" def __init__( self, win, editCommand ): """ Constructor for the Nanotube property manager. """ self.endPoint1 = None self.endPoint2 = None self.nanotube = Nanotube() # A 5x5 CNT. _superclass.__init__( self, win, editCommand) self.showTopRowButtons( PM_DONE_BUTTON | \ PM_CANCEL_BUTTON | \ PM_WHATS_THIS_BUTTON) 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: change_connect = self.win.connect else: change_connect = self.win.disconnect change_connect( self.ntTypeComboBox, SIGNAL("currentIndexChanged(const QString&)"), self._ntTypeComboBoxChanged ) change_connect(self.chiralityNSpinBox, SIGNAL("valueChanged(int)"), self._chiralityFixup) change_connect(self.chiralityMSpinBox, SIGNAL("valueChanged(int)"), self._chiralityFixup) change_connect(self.endingsComboBox, SIGNAL("currentIndexChanged(const QString&)"), self._endingsComboBoxChanged ) # This spin box is currently hidden. change_connect(self.bondLengthDoubleSpinBox, SIGNAL("valueChanged(double)"), self._bondLengthChanged) change_connect(self.showCursorTextCheckBox, SIGNAL('stateChanged(int)'), self._update_state_of_cursorTextGroupBox) def ok_btn_clicked(self): """ Slot for the OK button """ if self.editCommand: self.editCommand.preview_or_finalize_structure(previewing = False) ##env.history.message(self.editCommand.logMessage) self.win.toolsDone() def cancel_btn_clicked(self): """ Slot for the Cancel button. """ if self.editCommand: self.editCommand.cancelStructure() self.win.toolsCancel() def _update_widgets_in_PM_before_show(self): """ Update various widgets in this Property manager. Overrides MotorPropertyManager._update_widgets_in_PM_before_show. The various widgets , (e.g. spinboxes) will get values from the structure for which this propMgr is constructed for (self.editcCntroller.struct) @see: MotorPropertyManager._update_widgets_in_PM_before_show @see: self.show where it is called. """ pass def getFlyoutActionList(self): """ Returns custom actionlist that will be used in a specific mode or editing a feature etc Example: while in movie mode, the _createFlyoutToolBar method calls this. """ #'allActionsList' returns all actions in the flyout toolbar #including the subcontrolArea actions allActionsList = [] #Action List for subcontrol Area buttons. #In this mode there is really no subcontrol area. #We will treat subcontrol area same as 'command area' #(subcontrol area buttons will have an empty list as their command area #list). We will set the Comamnd Area palette background color to the #subcontrol area. subControlAreaActionList =[] self.exitEditCommandAction.setChecked(True) subControlAreaActionList.append(self.exitEditCommandAction) separator = QAction(self.w) separator.setSeparator(True) subControlAreaActionList.append(separator) allActionsList.extend(subControlAreaActionList) #Empty actionlist for the 'Command Area' commandActionLists = [] #Append empty 'lists' in 'commandActionLists equal to the #number of actions in subControlArea for i in range(len(subControlAreaActionList)): lst = [] commandActionLists.append(lst) params = (subControlAreaActionList, commandActionLists, allActionsList) return params def _addGroupBoxes( self ): """ Add the Insert Nanotube Property Manager group boxes. """ self._pmGroupBox1 = PM_GroupBox( self, title = "Endpoints" ) self._loadGroupBox1( self._pmGroupBox1 ) self._pmGroupBox1.hide() self._pmGroupBox2 = PM_GroupBox( self, title = "Parameters" ) self._loadGroupBox2( self._pmGroupBox2 ) self._displayOptionsGroupBox = PM_GroupBox( self, title = "Display Options" ) self._loadDisplayOptionsGroupBox( self._displayOptionsGroupBox ) self._pmGroupBox3 = PM_GroupBox( self, title = "Nanotube Distortion" ) self._loadGroupBox3( self._pmGroupBox3 ) self._pmGroupBox3.hide() #@ Temporary. self._pmGroupBox4 = PM_GroupBox( self, title = "Multi-Walled CNTs" ) self._loadGroupBox4( self._pmGroupBox4 ) self._pmGroupBox4.hide() #@ Temporary. self._pmGroupBox5 = PM_GroupBox( self, title = "Advanced Options" ) self._loadGroupBox5( self._pmGroupBox5 ) self._pmGroupBox5.hide() #@ Temporary. def _loadGroupBox1(self, pmGroupBox): """ Load widgets in group box 1. """ #Following toolbutton facilitates entering a temporary NanotubeLineMode #to create a CNT using endpoints of the specified line. self.specifyCntLineButton = PM_ToolButton( pmGroupBox, text = "Specify Endpoints", iconPath = "ui/actions/Properties Manager/Pencil.png", spanWidth = True ) self.specifyCntLineButton.setCheckable(True) self.specifyCntLineButton.setAutoRaise(True) self.specifyCntLineButton.setToolButtonStyle( Qt.ToolButtonTextBesideIcon) #EndPoint1 and endPoint2 coordinates. These widgets are hidden # as of 2007- 12 - 05 self._endPoint1SpinBoxes = PM_CoordinateSpinBoxes(pmGroupBox, label = "End Point 1") self.x1SpinBox = self._endPoint1SpinBoxes.xSpinBox self.y1SpinBox = self._endPoint1SpinBoxes.ySpinBox self.z1SpinBox = self._endPoint1SpinBoxes.zSpinBox self._endPoint2SpinBoxes = PM_CoordinateSpinBoxes(pmGroupBox, label = "End Point 2") self.x2SpinBox = self._endPoint2SpinBoxes.xSpinBox self.y2SpinBox = self._endPoint2SpinBoxes.ySpinBox self.z2SpinBox = self._endPoint2SpinBoxes.zSpinBox self._endPoint1SpinBoxes.hide() self._endPoint2SpinBoxes.hide() def _loadGroupBox2(self, pmGroupBox): """ Load widgets in group box 2. """ _ntTypeChoices = ['Carbon', 'Boron Nitride'] self.ntTypeComboBox = \ PM_ComboBox( pmGroupBox, label = "Type:", choices = _ntTypeChoices, setAsDefault = True) self.ntRiseDoubleSpinBox = \ PM_DoubleSpinBox( pmGroupBox, label = "Rise:", value = self.nanotube.getRise(), setAsDefault = True, minimum = 2.0, maximum = 4.0, decimals = 3, singleStep = 0.01 ) self.ntRiseDoubleSpinBox.hide() # Nanotube Length self.ntLengthLineEdit = \ PM_LineEdit( pmGroupBox, label = "Nanotube Length: ", text = "0.0 Angstroms", setAsDefault = False) self.ntLengthLineEdit.setDisabled(True) self.ntLengthLineEdit.hide() # Nanotube diameter self.ntDiameterLineEdit = \ PM_LineEdit( pmGroupBox, label = "Diameter: ", setAsDefault = False) self.ntDiameterLineEdit.setDisabled(True) self.updateNanotubeDiameter() self.chiralityNSpinBox = \ PM_SpinBox( pmGroupBox, label = "Chirality (n):", value = self.nanotube.getChiralityN(), minimum = 2, maximum = 100, setAsDefault = True ) self.chiralityMSpinBox = \ PM_SpinBox( pmGroupBox, label = "Chirality (m):", value = self.nanotube.getChiralityM(), minimum = 0, maximum = 100, setAsDefault = True ) # How about having user prefs for CNT and BNNT bond lengths? # I'm guessing that if the user wants to set these values, they will # do it once and would like those bond length values persist forever. # Need to discuss with others to determine if this spinbox comes out. # --Mark 2008-03-29 self.bondLengthDoubleSpinBox = \ PM_DoubleSpinBox( pmGroupBox, label = "Bond length:", value = self.nanotube.getBondLength(), setAsDefault = True, minimum = 1.0, maximum = 3.0, singleStep = 0.1, decimals = 3, suffix = " Angstroms" ) #self.bondLengthDoubleSpinBox.hide() endingChoices = ["Hydrogen", "None"] # Removed:, "Nitrogen"] self.endingsComboBox= \ PM_ComboBox( pmGroupBox, label = "Endings:", choices = endingChoices, index = 0, setAsDefault = True, spanWidth = False ) def _loadGroupBox3(self, inPmGroupBox): """ Load widgets in group box 3. """ self.zDistortionDoubleSpinBox = \ PM_DoubleSpinBox( inPmGroupBox, label = "Z-distortion:", value = 0.0, setAsDefault = True, minimum = 0.0, maximum = 10.0, singleStep = 0.1, decimals = 3, suffix = " Angstroms" ) self.xyDistortionDoubleSpinBox = \ PM_DoubleSpinBox( inPmGroupBox, label = "XY-distortion:", value = 0.0, setAsDefault = True, minimum = 0.0, maximum = 2.0, singleStep = 0.1, decimals = 3, suffix = " Angstroms" ) self.twistSpinBox = \ PM_SpinBox( inPmGroupBox, label = "Twist:", value = 0, setAsDefault = True, minimum = 0, maximum = 100, # What should maximum be? suffix = " deg/A" ) self.bendSpinBox = \ PM_SpinBox( inPmGroupBox, label = "Bend:", value = 0, setAsDefault = True, minimum = 0, maximum = 360, suffix = " deg" ) def _loadGroupBox4(self, inPmGroupBox): """ Load widgets in group box 4. """ # "Number of Nanotubes" SpinBox self.mwntCountSpinBox = \ PM_SpinBox( inPmGroupBox, label = "Number:", value = 1, setAsDefault = True, minimum = 1, maximum = 10, suffix = " nanotubes" ) self.mwntCountSpinBox.setSpecialValueText("SWNT") # "Spacing" lineedit. self.mwntSpacingDoubleSpinBox = \ PM_DoubleSpinBox( inPmGroupBox, label = "Spacing:", value = 2.46, setAsDefault = True, minimum = 1.0, maximum = 10.0, singleStep = 0.1, decimals = 3, suffix = " Angstroms" ) def _loadGroupBox5(self, pmGroupBox): """ Load widgets in group box 5. """ self._rubberbandLineGroupBox = PM_GroupBox( pmGroupBox, title = 'Rubber band Line:') ntLineChoices = ['Ladder'] self.ntRubberBandLineDisplayComboBox = \ PM_ComboBox( self._rubberbandLineGroupBox , label = " Display as:", choices = ntLineChoices, setAsDefault = True) self.lineSnapCheckBox = \ PM_CheckBox(self._rubberbandLineGroupBox , text = 'Enable line snap' , widgetColumn = 1, state = Qt.Checked ) 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 , insertNanotubeEditCommand_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) ("Nanotube length", insertNanotubeEditCommand_cursorTextCheckBox_length_prefs_key ), ("Angle", insertNanotubeEditCommand_cursorTextCheckBox_angle_prefs_key ) ] return params def _addToolTipText(self): """ Tool Tip text for widgets in the Insert Nanotube Property Manager. """ pass def _setEndPoints(self): """ Set the two endpoints of the nanotube using the values from the X, Y, Z coordinate spinboxes in the property manager. @note: The group box containing the 2 sets of XYZ spin boxes are currently hidden. """ # First endpoint (origin) of nanotube x1 = self.x1SpinBox.value() y1 = self.y1SpinBox.value() z1 = self.z1SpinBox.value() # Second endpoint (direction vector/axis) of nanotube. x2 = self.x2SpinBox.value() y2 = self.y2SpinBox.value() z2 = self.z2SpinBox.value() if not self.endPoint1: self.endPoint1 = V(x1, y1, z1) if not self.endPoint2: self.endPoint2 = V(x2, y2, z2) self.nanotube.setEndPoints(self.endPoint1, self.endPoint2) # Need arg "recompute=True", which will recompute the second # endpoint (endPoint2) using the nanotube rise. def getParameters(self): """ Return the parameters from this property manager to be used to create the nanotube. @return: A nanotube instance with its attrs set to the current parameters in the property manager. @rtype: L{Nanotube} @see: L{InsertNanotube_EditCommand._gatherParameters} where this is used """ self._setEndPoints() return (self.nanotube) def _ntTypeComboBoxChanged( self, type ): """ Slot for the Type combobox. It is called whenever the Type choice is changed. @param inIndex: The new index. @type inIndex: int """ self.nanotube.setType(str(type)) print "Bond Length =", self.nanotube.getBondLength() self.bondLengthDoubleSpinBox.setValue(self.nanotube.getBondLength()) #self.bondLengthDoubleSpinBox.setValue(ntBondLengths[inIndex]) def _bondLengthChanged(self, bondLength): """ Slot for the B{Bond Length} spinbox. """ self.nanotube.setBondLength(bondLength) self.updateNanotubeDiameter() return def _chiralityFixup(self, spinBoxValueJunk = None): """ Slot for several validators for different parameters. This gets called whenever the user changes the n, m chirality values. @param spinBoxValueJunk: This is the Spinbox value from the valueChanged signal. It is not used. We just want to know that the spinbox value has changed. @type spinBoxValueJunk: double or None """ _n, _m = self.nanotube.setChirality(self.chiralityNSpinBox.value(), self.chiralityMSpinBox.value()) #self.n, self.m = self.nanotube.getChirality() self.connect_or_disconnect_signals(isConnect = False) self.chiralityNSpinBox.setValue(_n) self.chiralityMSpinBox.setValue(_m) self.connect_or_disconnect_signals(isConnect = True) self.updateNanotubeDiameter() def updateNanotubeDiameter(self): """ Update the nanotube Diameter lineEdit widget. """ diameterText = "%-7.4f Angstroms" % (self.nanotube.getDiameter()) self.ntDiameterLineEdit.setText(diameterText) # ntRiseDoubleSpinBox is currently hidden. self.ntRiseDoubleSpinBox.setValue(self.nanotube.getRise()) def _endingsComboBoxChanged(self, endings): """ Slot for the B{Ending} combobox. @param endings: The option's text. @type endings: string """ self.nanotube.setEndings(str(endings)) return def _addWhatsThisText(self): """ What's This text for widgets in this Property Manager. """ whatsThis_InsertNanotube_PropertyManager(self) return
class Ui_BuildAtomsPropertyManager(Command_PropertyManager): """ The Ui_BuildAtomsPropertyManager class defines UI elements for the Property Manager of the B{Build Atoms mode}. @ivar title: The title that appears in the property manager header. @type title: str @ivar pmName: The name of this property manager. This is used to set the name of the PM_Dialog object via setObjectName(). @type name: str @ivar iconPath: The relative path to the PNG file that contains a 22 x 22 icon image that appears in the PM header. @type iconPath: str """ # The title that appears in the Property Manager header title = "Build Atoms" # The name of this Property Manager. This will be set to # the name of the PM_Dialog object via setObjectName(). pmName = title # The relative path to the PNG file that appears in the header iconPath = "ui/actions/Tools/Build Structures/BuildAtoms.png" def __init__(self, command): """ Constructor for the B{Build Atoms} property manager class that defines its UI. @param command: The parent mode where this Property Manager is used @type command: L{depositMode} """ self.previewGroupBox = None self.regularElementChooser = None self.PAM5Chooser = None self.PAM3Chooser = None self.elementChooser = None self.advancedOptionsGroupBox = None self.bondToolsGroupBox = None self.selectionFilterCheckBox = None self.filterlistLE = None self.selectedAtomInfoLabel = None #Initialize the following to None. (subclasses may not define this) #Make sure you initialize it before adding groupboxes! self.selectedAtomPosGroupBox = None self.showSelectedAtomInfoCheckBox = None _superclass.__init__(self, command) self.showTopRowButtons(PM_DONE_BUTTON | PM_WHATS_THIS_BUTTON) msg = '' self.MessageGroupBox.insertHtmlMessage(msg, setAsDefault=False) def _addGroupBoxes(self): """ Add various group boxes to the Build Atoms Property manager. """ self._addPreviewGroupBox() self._addAtomChooserGroupBox() self._addBondToolsGroupBox() #@@@TODO HIDE the bonds tool groupbox initially as the #by default, the atoms tool is active when BuildAtoms command is #finist invoked. self.bondToolsGroupBox.hide() self._addSelectionOptionsGroupBox() self._addAdvancedOptionsGroupBox() def _addPreviewGroupBox(self): """ Adde the preview groupbox that shows the element selected in the element chooser. """ self.previewGroupBox = PM_PreviewGroupBox(self, glpane=self.o) def _addAtomChooserGroupBox(self): """ Add the Atom Chooser groupbox. This groupbox displays one of the following three groupboxes depending on the choice selected in the combobox: a) Periodic Table Elements L{self.regularElementChooser} b) PAM5 Atoms L{self.PAM5Chooser} c) PAM3 Atoms L{self.PAM3Chooser} @see: L{self.__updateAtomChooserGroupBoxes} """ self.atomChooserGroupBox = \ PM_GroupBox(self, title = "Atom Chooser") self._loadAtomChooserGroupBox(self.atomChooserGroupBox) self._updateAtomChooserGroupBoxes(currentIndex=0) def _addElementChooserGroupBox(self, inPmGroupBox): """ Add the 'Element Chooser' groupbox. (present within the Atom Chooser Groupbox) """ if not self.previewGroupBox: return elementViewer = self.previewGroupBox.elementViewer self.regularElementChooser = \ PM_ElementChooser( inPmGroupBox, parentPropMgr = self, elementViewer = elementViewer) def _add_PAM5_AtomChooserGroupBox(self, inPmGroupBox): """ Add the 'PAM5 Atom Chooser' groupbox (present within the Atom Chooser Groupbox) """ if not self.previewGroupBox: return elementViewer = self.previewGroupBox.elementViewer self.PAM5Chooser = \ PM_PAM5_AtomChooser( inPmGroupBox, parentPropMgr = self, elementViewer = elementViewer) def _add_PAM3_AtomChooserGroupBox(self, inPmGroupBox): """ Add the 'PAM3 Atom Chooser' groupbox (present within the Atom Chooser Groupbox) """ if not self.previewGroupBox: return elementViewer = self.previewGroupBox.elementViewer self.PAM3Chooser = \ PM_PAM3_AtomChooser( inPmGroupBox, parentPropMgr = self, elementViewer = elementViewer) def _hideAllAtomChooserGroupBoxes(self): """ Hides all Atom Chooser group boxes. """ if self.regularElementChooser: self.regularElementChooser.hide() if self.PAM5Chooser: self.PAM5Chooser.hide() if self.PAM3Chooser: self.PAM3Chooser.hide() def _addBondToolsGroupBox(self): """ Add the 'Bond Tools' groupbox. """ self.bondToolsGroupBox = \ PM_GroupBox( self, title = "Bond Tools") self._loadBondToolsGroupBox(self.bondToolsGroupBox) def _addSelectionOptionsGroupBox(self): """ Add 'Selection Options' groupbox """ self.selectionOptionsGroupBox = \ PM_GroupBox( self, title = "Selection Options" ) self._loadSelectionOptionsGroupBox(self.selectionOptionsGroupBox) def _loadAtomChooserGroupBox(self, inPmGroupBox): """ Load the widgets inside the Atom Chooser groupbox. @param inPmGroupBox: The Atom Chooser box in the PM @type inPmGroupBox: L{PM_GroupBox} """ atomChooserChoices = [ "Periodic Table Elements", "PAM5 Atoms", "PAM3 Atoms" ] self.atomChooserComboBox = \ PM_ComboBox( inPmGroupBox, label = '', choices = atomChooserChoices, index = 0, setAsDefault = False, spanWidth = True ) #Following fixes bug 2550 self.atomChooserComboBox.setFocusPolicy(Qt.NoFocus) self._addElementChooserGroupBox(inPmGroupBox) self._add_PAM5_AtomChooserGroupBox(inPmGroupBox) self._add_PAM3_AtomChooserGroupBox(inPmGroupBox) def _loadSelectionOptionsGroupBox(self, inPmGroupBox): """ Load widgets in the Selection Options group box. @param inPmGroupBox: The Selection Options box in the PM @type inPmGroupBox: L{PM_GroupBox} """ self.selectionFilterCheckBox = \ PM_CheckBox( inPmGroupBox, text = "Enable atom selection filter", widgetColumn = 0, state = Qt.Unchecked ) self.selectionFilterCheckBox.setDefaultValue(False) self.filterlistLE = PM_LineEdit(inPmGroupBox, label="", text="", setAsDefault=False, spanWidth=True) self.filterlistLE.setReadOnly(True) if self.selectionFilterCheckBox.isChecked(): self.filterlistLE.setEnabled(True) else: self.filterlistLE.setEnabled(False) self.showSelectedAtomInfoCheckBox = \ PM_CheckBox( inPmGroupBox, text = "Show Selected Atom Info", widgetColumn = 0, state = Qt.Unchecked) self.selectedAtomPosGroupBox = \ PM_GroupBox( inPmGroupBox, title = "") self._loadSelectedAtomPosGroupBox(self.selectedAtomPosGroupBox) self.toggle_selectedAtomPosGroupBox(show=0) self.enable_or_disable_selectedAtomPosGroupBox(bool_enable=False) self.reshapeSelectionCheckBox = \ PM_CheckBox( inPmGroupBox, text = 'Dragging reshapes selection', widgetColumn = 0, state = Qt.Unchecked ) connect_checkbox_with_boolean_pref(self.reshapeSelectionCheckBox, reshapeAtomsSelection_prefs_key) env.prefs[reshapeAtomsSelection_prefs_key] = False self.waterCheckBox = \ PM_CheckBox( inPmGroupBox, text = "Z depth filter (water surface)", widgetColumn = 0, state = Qt.Unchecked ) def _loadSelectedAtomPosGroupBox(self, inPmGroupBox): """ Load the selected Atoms position groupbox It is a sub-gropbox of L{self.selectionOptionsGroupBox) @param inPmGroupBox: 'The Selected Atom Position Groupbox' @type inPmGroupBox: L{PM_GroupBox} """ self.selectedAtomLineEdit = PM_LineEdit(inPmGroupBox, label="Selected Atom:", text="", setAsDefault=False, spanWidth=False) self.selectedAtomLineEdit.setReadOnly(True) self.selectedAtomLineEdit.setEnabled(False) self.coordinateSpinboxes = PM_CoordinateSpinBoxes(inPmGroupBox) # User input to specify x-coordinate self.xCoordOfSelectedAtom = self.coordinateSpinboxes.xSpinBox # User input to specify y-coordinate self.yCoordOfSelectedAtom = self.coordinateSpinboxes.ySpinBox # User input to specify z-coordinate self.zCoordOfSelectedAtom = self.coordinateSpinboxes.zSpinBox def _addAdvancedOptionsGroupBox(self): """ Add 'Advanced Options' groupbox """ self.advancedOptionsGroupBox = \ PM_GroupBox( self, title = "Advanced Options" ) self._loadAdvancedOptionsGroupBox(self.advancedOptionsGroupBox) def _loadAdvancedOptionsGroupBox(self, inPmGroupBox): """ Load widgets in the Advanced Options group box. @param inPmGroupBox: The Advanced Options box in the PM @type inPmGroupBox: L{PM_GroupBox} """ self.autoBondCheckBox = \ PM_CheckBox( inPmGroupBox, text = 'Auto bond', widgetColumn = 0, state = Qt.Checked ) self.highlightingCheckBox = \ PM_CheckBox( inPmGroupBox, text = "Hover highlighting", widgetColumn = 0, state = Qt.Checked ) def _loadBondToolsGroupBox(self, inPmGroupBox): """ Load widgets in the Bond Tools group box. @param inPmGroupBox: The Bond Tools box in the PM @type inPmGroupBox: L{PM_GroupBox} """ # Button list to create a toolbutton row. # Format: # - buttonId, # - buttonText , # - iconPath # - tooltip # - shortcut # - column BOND_TOOL_BUTTONS = \ [ ( "QToolButton", 0, "SINGLE", "", "", None, 0), ( "QToolButton", 1, "DOUBLE", "", "", None, 1), ( "QToolButton", 2, "TRIPLE", "", "", None, 2), ( "QToolButton", 3, "AROMATIC", "", "", None, 3), ( "QToolButton", 4, "GRAPHITIC", "", "", None, 4), ( "QToolButton", 5, "CUTBONDS", "", "", None, 5) ] self.bondToolButtonRow = \ PM_ToolButtonRow( inPmGroupBox, title = "", buttonList = BOND_TOOL_BUTTONS, checkedId = None, setAsDefault = True ) def _addWhatsThisText(self): """ "What's This" text for widgets in this Property Manager. """ from ne1_ui.WhatsThisText_for_PropertyManagers import whatsThis_BuildAtomsPropertyManager whatsThis_BuildAtomsPropertyManager(self) def _addToolTipText(self): """ Tool Tip text for widgets in this Property Manager. """ from ne1_ui.ToolTipText_for_PropertyManagers import ToolTip_BuildAtomsPropertyManager ToolTip_BuildAtomsPropertyManager(self) def toggle_selectedAtomPosGroupBox(self, show=0): """ Show or hide L{self.selectedAtomPosGroupBox} depending on the state of the checkbox (L{self.showSelectedAtomInfoCheckBox}) @param show: Flag that shows or hides the groupbox (can have values 0 or 1 @type show: int """ if show: self.selectedAtomPosGroupBox.show() else: self.selectedAtomPosGroupBox.hide() def enable_or_disable_selectedAtomPosGroupBox(self, bool_enable=False): """ Enable or disable Selected AtomPosGroupBox present within 'selection options' and also the checkbox that shows or hide this groupbox. These two widgets are enabled when only a single atom is selected from the 3D workspace. @param bool_enable: Flag that enables or disables widgets @type bool_enable: boolean """ if self.showSelectedAtomInfoCheckBox: self.showSelectedAtomInfoCheckBox.setEnabled(bool_enable) if self.selectedAtomPosGroupBox: self.selectedAtomPosGroupBox.setEnabled(bool_enable) def _updateAtomChooserGroupBoxes(self, currentIndex): """ Updates the Atom Chooser Groupbox. It displays one of the following three groupboxes depending on the choice selected in the combobox: a) Periodic Table Elements L{self.regularElementChooser} b) PAM5 Atoms L{self.PAM5Chooser} c) PAM3 Atoms L{self.PAM3Chooser} It also sets self.elementChooser to the current active Atom chooser and updates the display accordingly in the Preview groupbox. """ self._hideAllAtomChooserGroupBoxes() if currentIndex is 0: self.elementChooser = self.regularElementChooser self.regularElementChooser.show() if currentIndex is 1: self.elementChooser = self.PAM5Chooser self.PAM5Chooser.show() if currentIndex is 2: self.elementChooser = self.PAM3Chooser self.PAM3Chooser.show() if self.elementChooser: self.elementChooser.updateElementViewer() self.updateMessage() def updateMessage(self): """ Update the Message groupbox with informative message. Subclasses should override this. """ pass
class Ui_BuildCrystal_PropertyManager(Command_PropertyManager): """ The Ui_BuildCrystal_PropertyManager class defines UI elements for the Property Manager of the B{Crystal mode}. @ivar title: The title that appears in the property manager header. @type title: str @ivar pmName: The name of this property manager. This is used to set the name of the PM_Dialog object via setObjectName(). @type name: str @ivar iconPath: The relative path to the PNG file that contains a 22 x 22 icon image that appears in the PM header. @type iconPath: str """ # <title> - the title that appears in the property manager header. title = "Build Crystal" # <iconPath> - full path to PNG file that appears in the header. # The name of this Property Manager. This will be set to # the name of the PM_Dialog object via setObjectName(). pmName = title iconPath = "ui/actions/Tools/Build Structures/Build Crystal.png" def __init__(self, command): """ Constructor for the B{Crystal} property manager class that defines its UI. @param command: The parent mode where this Property Manager is used @type command: L{BuildCrystal_Command} """ _superclass.__init__(self, command) self.showTopRowButtons( PM_DONE_BUTTON | \ PM_CANCEL_BUTTON | \ PM_WHATS_THIS_BUTTON) def _addGroupBoxes(self): """ Add various group boxes to the Property manager. """ self._addCrystalSpecsGroupbox() self._addLayerPropertiesGroupBox() self._addDisplayOptionsGroupBox() self._addAdvancedOptionsGroupBox() def _addCrystalSpecsGroupbox(self): """ Add 'Crystal groupbox' to the PM """ self.crystalSpecsGroupBox = \ PM_GroupBox(self, title = "Crystal Specifications") self._loadCrystalSpecsGroupBox(self.crystalSpecsGroupBox) def _addLayerPropertiesGroupBox(self): """ Add 'Layer Properties' groupbox to the PM """ self.layerPropertiesGroupBox = \ PM_GroupBox(self, title = "Layer Properties") self._loadLayerPropertiesGroupBox(self.layerPropertiesGroupBox) def _addAdvancedOptionsGroupBox(self): """ Add 'Advanced Options' groupbox """ self.advancedOptionsGroupBox = \ PM_GroupBox( self, title = "Advanced Options" ) self._loadAdvancedOptionsGroupBox(self.advancedOptionsGroupBox) def _addDisplayOptionsGroupBox(self): """ Add 'Display Options' groupbox """ self.displayOptionsGroupBox = PM_GroupBox(self, title = 'Display Options') self._loadDisplayOptionsGroupBox(self.displayOptionsGroupBox) def _loadCrystalSpecsGroupBox(self, inPmGroupBox): """ Load widgets in the Crystal Specifications group box. @param inPmGroupBox: The Crystal Specifications groupbox in the PM @type inPmGroupBox: L{PM_GroupBox} """ latticeChoices = ["Diamond", "Lonsdaleite"] self.latticeCBox = \ PM_ComboBox( inPmGroupBox, label = 'Lattice:', labelColumn = 0, choices = latticeChoices, index = 0, setAsDefault = True, spanWidth = False ) # Button list to create a toolbutton row. # Format: # - buttonType, # - buttonId, # - buttonText , # - iconPath # - tooltip # - shortcut # - column BUTTON_LIST = [ ( "QToolButton", 0, "Surface 100", "ui/actions/Properties Manager/Surface100.png", "Surface 100", "", 0), ( "QToolButton", 1, "Surface 110", "ui/actions/Properties Manager/Surface110.png", "Surface 110", "", 1), ( "QToolButton", 2, "Surface 111", "ui/actions/Properties Manager/Surface111.png", "Surface 110", "", 2) ] self.gridOrientationButtonRow = \ PM_ToolButtonRow(inPmGroupBox, title = "", label = "Orientation:", buttonList = BUTTON_LIST, checkedId = 0, setAsDefault = True, spanWidth = False ) self.orientButtonGroup = self.gridOrientationButtonRow.buttonGroup self.surface100_btn = self.gridOrientationButtonRow.getButtonById(0) self.surface110_btn = self.gridOrientationButtonRow.getButtonById(1) self.surface111_btn = self.gridOrientationButtonRow.getButtonById(2) self.rotateGridByAngleSpinBox = \ PM_SpinBox( inPmGroupBox, label = "Rotate by: ", labelColumn = 0, value = 45, minimum = 0, maximum = 360, singleStep = 5, suffix = " degrees") GRID_ANGLE_BUTTONS = [ ("QToolButton", 0, "Anticlockwise", "ui/actions/Properties Manager/rotate_minus.png", "", "+", 0 ), ( "QToolButton", 1, "Clockwise", "ui/actions/Properties Manager/rotate_plus.png", "", "-", 1 ) ] self.gridRotateButtonRow = \ PM_ToolButtonRow( inPmGroupBox, title = "", buttonList = GRID_ANGLE_BUTTONS, label = 'Rotate grid:', isAutoRaise = False, isCheckable = False ) self.rotGridAntiClockwiseButton = \ self.gridRotateButtonRow.getButtonById(0) self.rotGridClockwiseButton = \ self.gridRotateButtonRow.getButtonById(1) def _loadLayerPropertiesGroupBox(self, inPmGroupBox): """ Load widgets in the Layer Properties group box. @param inPmGroupBox: The Layer Properties groupbox in the PM @type inPmGroupBox: L{PM_GroupBox} """ self.currentLayerComboBox = \ PM_ComboBox( inPmGroupBox, index = 0, spanWidth = True ) self.addLayerButton = PM_PushButton(inPmGroupBox) self.addLayerButton.setIcon( geticon('ui/actions/Properties Manager/addlayer.png')) self.addLayerButton.setFixedSize(QSize(26, 26)) self.addLayerButton.setIconSize(QSize(22, 22)) # A widget list to create a widget row. # Format: # - Widget type, # - widget object, # - column firstRowWidgetList = [('PM_ComboBox', self.currentLayerComboBox, 1), ('PM_PushButton', self.addLayerButton, 2) ] widgetRow = PM_WidgetRow(inPmGroupBox, title = '', widgetList = firstRowWidgetList, label = "Layer:", labelColumn = 0, ) self.layerCellsSpinBox = \ PM_SpinBox( inPmGroupBox, label = "Lattice cells:", labelColumn = 0, value = 2, minimum = 1, maximum = 25 ) self.layerThicknessLineEdit = PM_LineEdit(inPmGroupBox, label = "Thickness:", text = "", setAsDefault = False, spanWidth = False ) #self.layerThicknessLineEdit.setReadOnly(True) self.layerThicknessLineEdit.setDisabled(True) tooltip = "Thickness of layer in Angstroms" self.layerThicknessLineEdit.setToolTip(tooltip) def _loadAdvancedOptionsGroupBox(self, inPmGroupBox): """ Load widgets in the Advanced Options group box. @param inPmGroupBox: The Advanced Options box in the PM @type inPmGroupBox: L{PM_GroupBox} """ self.snapGridCheckBox = \ PM_CheckBox(inPmGroupBox, text = "Snap to grid", state = Qt.Checked ) tooltip = "Snap selection point to a nearest cell grid point." self.snapGridCheckBox.setToolTip(tooltip) self.freeViewCheckBox = \ PM_CheckBox(inPmGroupBox, text = "Enable free view", state = Qt.Unchecked ) def _loadDisplayOptionsGroupBox(self, inPmGroupBox): """ Load widgets in the Display Options groupbox. @param inPmGroupBox: The Display Options groupbox @type inPmGroupBox: L{PM_GroupBox} """ displayChoices = ['Tubes', 'Spheres'] self.dispModeComboBox = \ PM_ComboBox( inPmGroupBox, label = 'Display style:', choices = displayChoices, index = 0, setAsDefault = False, spanWidth = False ) self.gridLineCheckBox = PM_CheckBox(inPmGroupBox, text = "Show grid lines", widgetColumn = 0, state = Qt.Checked) self.fullModelCheckBox = PM_CheckBox(inPmGroupBox, text = "Show model", widgetColumn = 0, state = Qt.Unchecked) def _addWhatsThisText(self): """ What's This text for widgets in this Property Manager. @note: Many PM widgets are still missing their "What's This" text. """ from ne1_ui.WhatsThisText_for_PropertyManagers import whatsThis_CookiePropertyManager whatsThis_CookiePropertyManager(self) def _addToolTipText(self): """ What's Tool Tip text for widgets in this Property Manager. """ from ne1_ui.ToolTipText_for_PropertyManagers import ToolTip_CookiePropertyManager ToolTip_CookiePropertyManager(self)
class DnaSegment_PropertyManager(DnaOrCnt_PropertyManager): """ The DnaSegmenta_PropertyManager class provides a Property Manager for the DnaSegment_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 = "DnaSegment Properties" iconPath = "ui/actions/Tools/Build Structures/DNA.png" def __init__(self, command): """ Constructor for the Build DNA property manager. """ self.endPoint1 = V(0, 0, 0) self.endPoint2 = V(0, 0, 0) self._numberOfBases = 0 self._conformation = 'B-DNA' self.duplexRise = 3.18 self.basesPerTurn = 10 self.dnaModel = 'PAM3' _superclass.__init__(self, command) self.showTopRowButtons( PM_DONE_BUTTON | \ PM_CANCEL_BUTTON | \ PM_PREVIEW_BUTTON | \ PM_WHATS_THIS_BUTTON) msg = "Use resize handles to resize the segment. Drag any axis or sugar"\ " atom for translation or rotation about axis respectively. Dragging"\ " any bond will freely move the whole segment." self.updateMessage(msg) 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: change_connect = self.win.connect else: change_connect = self.win.disconnect _superclass.connect_or_disconnect_signals(self, isConnect) change_connect(self.numberOfBasePairsSpinBox, SIGNAL("valueChanged(int)"), self.numberOfBasesChanged) change_connect(self.basesPerTurnDoubleSpinBox, SIGNAL("valueChanged(double)"), self.basesPerTurnChanged) change_connect(self.duplexRiseDoubleSpinBox, SIGNAL("valueChanged(double)"), self.duplexRiseChanged) change_connect(self.showCursorTextCheckBox, SIGNAL('stateChanged(int)'), self._update_state_of_cursorTextGroupBox) def _update_UI_do_updates(self): """ @see: Command_PropertyManager._update_UI_do_updates() @see: DnaSegment_EditCommand.command_update_UI() @see: DnaSegment_EditCommand.hasResizableStructure() @see: self._current_model_changed_params() """ currentParams = self._current_model_changed_params() #Optimization. Return from the model_changed method if the #params are the same. if same_vals(currentParams, self._previous_model_changed_params): return isStructResizable, why_not = currentParams #update the self._previous_model_changed_params with this new param set. self._previous_model_changed_params = currentParams if not isStructResizable: #disable all widgets if self._pmGroupBox1.isEnabled(): self._pmGroupBox1.setEnabled(False) msg = redmsg("DnaSegment is not resizable. Reason: %s" % (why_not)) self.updateMessage(msg) else: if not self._pmGroupBox1.isEnabled(): self._pmGroupBox1.setEnabled(True) msg = "Use resize handles to resize the segment. Drag any axis or sugar"\ " atom for translation or rotation about axis respectively. Dragging"\ " any bond will freely move the whole segment." self.updateMessage(msg) def _current_model_changed_params(self): """ Returns a tuple containing the parameters that will be compared against the previously stored parameters. This provides a quick test to determine whether to do more things in self.model_changed() @see: self.model_changed() which calls this @see: self._previous_model_changed_params attr. """ params = None if self.command: isStructResizable, why_not = self.command.hasResizableStructure() params = (isStructResizable, why_not) return params def show(self): """ Show this property manager. Overrides EditCommand_PM.show() This method also retrives the name information from the command's structure for its name line edit field. @see: DnaSegment_EditCommand.getStructureName() @see: self.close() """ _superclass.show(self) if self.command is not None: name = self.command.getStructureName() if name is not None: self.nameLineEdit.setText(name) 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) _superclass.close(self) 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? """ numberOfBasePairs, \ dnaForm, \ dnaModel,\ basesPerTurn, \ duplexRise, \ endPoint1, \ endPoint2 , \ color = params if numberOfBasePairs is not None: self.numberOfBasePairsSpinBox.setValue(numberOfBasePairs) 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 endPoint1 is not None: self.endPoint1 = endPoint1 if endPoint2 is not None: self.endPoint2 = endPoint2 if color is not None: self._colorChooser.setColor(color) def getParameters(self): """ """ #See bug 2802 for details about the parameter #'number_of_basePairs_from_struct'. Basically it is used to check #if the structure got modified (e.g. because of undo) #The numberOfBases parameter obtained from the propMgr is given as a #separate parameter for the reasons mentioned in bug 2802 #-- Ninad 2008-04-12 number_of_basePairs_from_struct = None if self.command.hasValidStructure(): number_of_basePairs_from_struct = self.command.struct.getNumberOfBasePairs( ) numberOfBases = self.numberOfBasePairsSpinBox.value() dnaForm = self._conformation dnaModel = self.dnaModel basesPerTurn = self.basesPerTurn duplexRise = self.duplexRise color = self._colorChooser.getColor() return (number_of_basePairs_from_struct, numberOfBases, dnaForm, dnaModel, basesPerTurn, duplexRise, self.endPoint1, self.endPoint2, color) def numberOfBasesChanged(self, numberOfBases): """ Slot for the B{Number of Bases} spinbox. """ duplexRise = self.duplexRiseDoubleSpinBox.value() # Update the Duplex Length lineEdit widget. text = str(getDuplexLength(self._conformation, numberOfBases, duplexRise = duplexRise)) \ + " Angstroms" self.duplexLengthLineEdit.setText(text) return def basesPerTurnChanged(self, basesPerTurn): """ Slot for the B{Bases per turn} spinbox. """ self.basesPerTurn = basesPerTurn def duplexRiseChanged(self, rise): """ Slot for the B{Rise} spinbox. """ self.duplexRise = rise 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="Segment name:", text="", setAsDefault=False) # Strand Length (i.e. the number of bases) self.numberOfBasePairsSpinBox = \ PM_SpinBox( pmGroupBox, label = "Base pairs:", 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.basesPerTurnDoubleSpinBox.setDisabled(True) self.duplexRiseDoubleSpinBox = \ PM_DoubleSpinBox( pmGroupBox, label = "Rise:", value = self.duplexRise, setAsDefault = True, minimum = 2.0, maximum = 4.0, decimals = 3, singleStep = 0.01 ) self.duplexRiseDoubleSpinBox.setDisabled(True) # Duplex Length self.duplexLengthLineEdit = \ PM_LineEdit( pmGroupBox, label = "Duplex length: ", text = "0.0 Angstroms", setAsDefault = False) self.duplexLengthLineEdit.setDisabled(True) 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, dnaSegmentEditCommand_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 base pairs", dnaSegmentEditCommand_cursorTextCheckBox_numberOfBasePairs_prefs_key), ("Duplex length", dnaSegmentEditCommand_cursorTextCheckBox_length_prefs_key), ("Number of basepairs to be changed", dnaSegmentEditCommand_cursorTextCheckBox_changedBasePairs_prefs_key) ] return params def _addWhatsThisText(self): """ Add what's this text. """ pass def _addToolTipText(self): """ Add Tooltip text """ pass
def _loadMenuWidgets(self): """ Load the various menu widgets (e.g. Open, save sequence options, Find and replace widgets etc. """ #Note: Find and replace widgets might be moved to their own class. self.loadSequenceButton = PM_ToolButton( self, iconPath = "ui/actions/Properties Manager/Open.png") self.saveSequenceButton = PM_ToolButton( self, iconPath = "ui/actions/Properties Manager/Save_Strand_Sequence.png") self.loadSequenceButton.setAutoRaise(True) self.saveSequenceButton.setAutoRaise(True) #Find and replace widgets -- self.findLineEdit = \ PM_LineEdit( self, label = "", spanWidth = False) self.findLineEdit.setMaximumWidth(60) self.replaceLineEdit = \ PM_LineEdit( self, label = "", spanWidth = False) self.replaceLineEdit.setMaximumWidth(60) self.findOptionsToolButton = PM_ToolButton(self) self.findOptionsToolButton.setMaximumWidth(12) self.findOptionsToolButton.setAutoRaise(True) self.findOptionsToolButton.setPopupMode(QToolButton.MenuButtonPopup) self._setFindOptionsToolButtonMenu() self.findNextToolButton = PM_ToolButton( self, iconPath = "ui/actions/Properties Manager/Find_Next.png") self.findNextToolButton.setAutoRaise(True) self.findPreviousToolButton = PM_ToolButton( self, iconPath = "ui/actions/Properties Manager/Find_Previous.png") self.findPreviousToolButton.setAutoRaise(True) self.replacePushButton = PM_PushButton(self, text = "Replace") self.warningSign = QLabel(self) self.warningSign.setPixmap( getpixmap('ui/actions/Properties Manager/Warning.png')) self.warningSign.hide() self.phraseNotFoundLabel = QLabel(self) self.phraseNotFoundLabel.setText("Sequence Not Found") self.phraseNotFoundLabel.hide() #Widgets to include in the widget row. widgetList = [('PM_ToolButton', self.loadSequenceButton, 0), ('PM_ToolButton', self.saveSequenceButton, 1), ('QLabel', " Find:", 4), ('PM_LineEdit', self.findLineEdit, 5), ('PM_ToolButton', self.findOptionsToolButton, 6), ('PM_ToolButton', self.findPreviousToolButton, 7), ('PM_ToolButton', self.findNextToolButton, 8), ('QLabel', " Replace:", 9), ('PM_TextEdit', self.replaceLineEdit, 10), ('PM_PushButton', self.replacePushButton, 11), ('PM_Label', self.warningSign, 12), ('PM_Label', self.phraseNotFoundLabel, 13), ('QSpacerItem', 5, 5, 14) ] widgetRow = PM_WidgetRow(self, title = '', widgetList = widgetList, label = "", spanWidth = True )
def _loadMenuWidgets(self): """ Load the various menu widgets (e.g. Open, save sequence options, Find and replace widgets etc. """ self.loadSequenceButton = PM_ToolButton( self, iconPath="ui/actions/Properties Manager/Open.png") self.saveSequenceButton = PM_ToolButton( self, iconPath="ui/actions/Properties Manager/Save_Strand_Sequence.png") self.loadSequenceButton.setAutoRaise(True) self.saveSequenceButton.setAutoRaise(True) # Hide load and save buttons until they are implemented. -Mark 2008-12-20. self.loadSequenceButton.hide() self.saveSequenceButton.hide() #Find and replace widgets -- self.findLineEdit = \ PM_LineEdit( self, label = "", spanWidth = False) self.findLineEdit.setMaximumWidth(60) self.replaceLineEdit = \ PM_LineEdit( self, label = " Replace:", spanWidth = False) self.replaceLineEdit.setMaximumWidth(60) self.findOptionsToolButton = PM_ToolButton(self) self.findOptionsToolButton.setMaximumWidth(12) self.findOptionsToolButton.setAutoRaise(True) self.findOptionsToolButton.setPopupMode(QToolButton.MenuButtonPopup) self._setFindOptionsToolButtonMenu() self.findNextToolButton = PM_ToolButton( self, iconPath="ui/actions/Properties Manager/Find_Next.png") self.findNextToolButton.setAutoRaise(True) self.findPreviousToolButton = PM_ToolButton( self, iconPath="ui/actions/Properties Manager/Find_Previous.png") self.findPreviousToolButton.setAutoRaise(True) self.replacePushButton = PM_PushButton(self, text="Replace") # Hide Replace widgets until we add support for transmuting residues. # Mark 2008-12-19 #self.replaceLabel.hide() self.replacePushButton.hide() self.replaceLineEdit.hide() self.warningSign = QLabel(self) self.warningSign.setPixmap( getpixmap('ui/actions/Properties Manager/Warning.png')) self.warningSign.hide() self.phraseNotFoundLabel = QLabel(self) self.phraseNotFoundLabel.setText("Sequence Not Found") self.phraseNotFoundLabel.hide() #Widgets to include in the widget row. widgetList = [ ('PM_ToolButton', self.loadSequenceButton, 0), ('PM_ToolButton', self.saveSequenceButton, 1), ('QLabel', " Find:", 4), ('PM_LineEdit', self.findLineEdit, 5), ('PM_ToolButton', self.findOptionsToolButton, 6), ('PM_ToolButton', self.findPreviousToolButton, 7), ('PM_ToolButton', self.findNextToolButton, 8), #('PM_Label', self.replaceLabel, 9), ('PM_TextEdit', self.replaceLineEdit, 9), ('PM_PushButton', self.replacePushButton, 10), ('PM_Label', self.warningSign, 11), ('PM_Label', self.phraseNotFoundLabel, 12), ('QSpacerItem', 5, 5, 13) ] widgetRow = PM_WidgetRow(self, title='', widgetList=widgetList, label="", spanWidth=True) 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
class InsertDna_PropertyManager(DnaOrCnt_PropertyManager): """ The InsertDna_PropertyManager class provides a Property Manager for the B{Insert 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 = "Insert DNA" pmName = title iconPath = "ui/actions/Command Toolbar/BuildDna/InsertDna.png" def __init__(self, command): """ Constructor for the DNA Duplex property manager. """ self.endPoint1 = None self.endPoint2 = None self._conformation = "B-DNA" self._numberOfBases = 0 self._basesPerTurn = getDuplexBasesPerTurn(self._conformation) self._duplexRise = getDuplexRise(self._conformation) self._duplexLength = getDuplexLength(self._conformation, self._numberOfBases) _superclass.__init__(self, command) self.showTopRowButtons( PM_DONE_BUTTON | \ PM_CANCEL_BUTTON | \ PM_WHATS_THIS_BUTTON) 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: change_connect = self.win.connect else: change_connect = self.win.disconnect change_connect(self._placementOptions.buttonGroup, SIGNAL("buttonClicked(int)"), self.activateSpecifyReferencePlaneTool) change_connect(self.conformationComboBox, SIGNAL("currentIndexChanged(int)"), self.conformationComboBoxChanged) change_connect(self.numberOfBasePairsSpinBox, SIGNAL("valueChanged(int)"), self.numberOfBasesChanged) change_connect(self.basesPerTurnDoubleSpinBox, SIGNAL("valueChanged(double)"), self.basesPerTurnChanged) change_connect(self.duplexRiseDoubleSpinBox, SIGNAL("valueChanged(double)"), self.duplexRiseChanged) change_connect(self.showCursorTextCheckBox, SIGNAL('stateChanged(int)'), self._update_state_of_cursorTextGroupBox) self.duplexRiseDoubleSpinBox.connectWithState( Preferences_StateRef_double(bdnaRise_prefs_key, env.prefs[bdnaRise_prefs_key])) self.basesPerTurnDoubleSpinBox.connectWithState( Preferences_StateRef_double(bdnaBasesPerTurn_prefs_key, env.prefs[bdnaBasesPerTurn_prefs_key])) def show(self): _superclass.show(self) self.updateMessage("Specify the DNA parameters below, then click "\ "two endpoints in the graphics area to insert a DNA duplex.") def _addGroupBoxes(self): """ Add the DNA Property Manager group boxes. """ self._pmReferencePlaneGroupBox = PM_GroupBox(self, title="Placement Options") self._loadReferencePlaneGroupBox(self._pmReferencePlaneGroupBox) self._pmGroupBox1 = PM_GroupBox(self, title="Endpoints") self._loadGroupBox1(self._pmGroupBox1) self._pmGroupBox1.hide() self._pmGroupBox2 = PM_GroupBox(self, title="Parameters") self._loadGroupBox2(self._pmGroupBox2) self._displayOptionsGroupBox = PM_GroupBox(self, title="Display Options") self._loadDisplayOptionsGroupBox(self._displayOptionsGroupBox) def _loadGroupBox1(self, pmGroupBox): """ Load widgets in group box 3. """ #Folllowing toolbutton facilitates entering a temporary DnaLineMode #to create a DNA using endpoints of the specified line. self.specifyDnaLineButton = PM_ToolButton( pmGroupBox, text="Specify Endpoints", iconPath="ui/actions/Properties Manager/Pencil.png", spanWidth=True) self.specifyDnaLineButton.setCheckable(True) self.specifyDnaLineButton.setAutoRaise(True) self.specifyDnaLineButton.setToolButtonStyle( Qt.ToolButtonTextBesideIcon) #EndPoint1 and endPoint2 coordinates. These widgets are hidden # as of 2007- 12 - 05 self._endPoint1SpinBoxes = PM_CoordinateSpinBoxes(pmGroupBox, label="End Point 1") self.x1SpinBox = self._endPoint1SpinBoxes.xSpinBox self.y1SpinBox = self._endPoint1SpinBoxes.ySpinBox self.z1SpinBox = self._endPoint1SpinBoxes.zSpinBox self._endPoint2SpinBoxes = PM_CoordinateSpinBoxes(pmGroupBox, label="End Point 2") self.x2SpinBox = self._endPoint2SpinBoxes.xSpinBox self.y2SpinBox = self._endPoint2SpinBoxes.ySpinBox self.z2SpinBox = self._endPoint2SpinBoxes.zSpinBox self._endPoint1SpinBoxes.hide() self._endPoint2SpinBoxes.hide() def _loadGroupBox2(self, pmGroupBox): """ Load widgets in group box 4. """ self.conformationComboBox = \ PM_ComboBox( pmGroupBox, label = "Conformation:", choices = ["B-DNA"], setAsDefault = True) dnaModelChoices = ['PAM3', 'PAM5'] self.dnaModelComboBox = \ PM_ComboBox( pmGroupBox, label = "Model:", choices = dnaModelChoices, setAsDefault = True) self.basesPerTurnDoubleSpinBox = \ PM_DoubleSpinBox( pmGroupBox, label = "Bases per turn:", value = env.prefs[bdnaBasesPerTurn_prefs_key], setAsDefault = True, minimum = 8.0, maximum = 20.0, decimals = 2, singleStep = 0.1 ) self.duplexRiseDoubleSpinBox = \ PM_DoubleSpinBox( pmGroupBox, label = "Rise:", value = env.prefs[bdnaRise_prefs_key], setAsDefault = True, minimum = 2.0, maximum = 4.0, decimals = 3, singleStep = 0.01 ) # Strand Length (i.e. the number of bases) self.numberOfBasePairsSpinBox = \ PM_SpinBox( pmGroupBox, label = "Base pairs:", value = self._numberOfBases, setAsDefault = False, minimum = 0, maximum = 10000 ) self.numberOfBasePairsSpinBox.setDisabled(True) # Duplex Length self.duplexLengthLineEdit = \ PM_LineEdit( pmGroupBox, label = "Duplex length: ", text = "0.0 Angstroms", setAsDefault = False) self.duplexLengthLineEdit.setDisabled(True) def _loadDisplayOptionsGroupBox(self, pmGroupBox): """ Load widgets in the Display Options GroupBox @see: DnaOrCnt_PropertyManager. _loadDisplayOptionsGroupBox """ #Call the superclass method that loads the cursor text checkboxes. #Note, as of 2008-05-19, the superclass, DnaOrCnt_PropertyManager #only loads the cursor text groupboxes. Subclasses like this can #call custom methods like self._loadCursorTextCheckBoxes etc if they #don't need all groupboxes that the superclass loads. _superclass._loadDisplayOptionsGroupBox(self, pmGroupBox) self._rubberbandLineGroupBox = PM_GroupBox(pmGroupBox, title='Rubber band line:') dnaLineChoices = ['Ribbons', 'Ladder'] self.dnaRubberBandLineDisplayComboBox = \ PM_ComboBox( self._rubberbandLineGroupBox , label = " Display as:", choices = dnaLineChoices, setAsDefault = True) self.lineSnapCheckBox = \ PM_CheckBox(self._rubberbandLineGroupBox , text = 'Enable line snap' , widgetColumn = 1, state = Qt.Checked ) 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, dnaDuplexEditCommand_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 base pairs", dnaDuplexEditCommand_cursorTextCheckBox_numberOfBasePairs_prefs_key), ("Number of turns", dnaDuplexEditCommand_cursorTextCheckBox_numberOfTurns_prefs_key), ("Duplex length", dnaDuplexEditCommand_cursorTextCheckBox_length_prefs_key), ("Angle", dnaDuplexEditCommand_cursorTextCheckBox_angle_prefs_key) ] return params def _addToolTipText(self): """ Tool Tip text for widgets in the DNA Property Manager. """ pass def conformationComboBoxChanged(self, inIndex): """ Slot for the Conformation combobox. It is called whenever the Conformation choice is changed. @param inIndex: The new index. @type inIndex: int """ conformation = self.conformationComboBox.currentText() if conformation == "B-DNA": self.basesPerTurnDoubleSpinBox.setValue("10.0") elif conformation == "Z-DNA": self.basesPerTurnDoubleSpinBox.setValue("12.0") else: msg = redmsg("conformationComboBoxChanged(): \ Error - unknown DNA conformation. Index = " + inIndex) env.history.message(msg) self.duplexLengthSpinBox.setSingleStep(getDuplexRise(conformation)) def numberOfBasesChanged(self, numberOfBases): """ Slot for the B{Number of Bases} spinbox. """ # Update the Duplex Length lineEdit widget. text = str(getDuplexLength(self._conformation, numberOfBases, self._duplexRise)) \ + " Angstroms" self.duplexLengthLineEdit.setText(text) return def basesPerTurnChanged(self, basesPerTurn): """ Slot for the B{Bases per turn} spinbox. """ self.command.basesPerTurn = basesPerTurn self._basesPerTurn = basesPerTurn return def duplexRiseChanged(self, rise): """ Slot for the B{Rise} spinbox. """ self.command.duplexRise = rise self._duplexRise = rise return def getParameters(self): """ Return the parameters from this property manager to be used to create the DNA duplex. @return: A tuple containing the parameters @rtype: tuple @see: L{InsertDna_EditCommand._gatherParameters} where this is used """ numberOfBases = self.numberOfBasePairsSpinBox.value() dnaForm = str(self.conformationComboBox.currentText()) basesPerTurn = self.basesPerTurnDoubleSpinBox.value() duplexRise = self.duplexRiseDoubleSpinBox.value() dnaModel = str(self.dnaModelComboBox.currentText()) # First endpoint (origin) of DNA duplex x1 = self.x1SpinBox.value() y1 = self.y1SpinBox.value() z1 = self.z1SpinBox.value() # Second endpoint (direction vector/axis) of DNA duplex. x2 = self.x2SpinBox.value() y2 = self.y2SpinBox.value() z2 = self.z2SpinBox.value() if not self.endPoint1: self.endPoint1 = V(x1, y1, z1) if not self.endPoint2: self.endPoint2 = V(x2, y2, z2) return (numberOfBases, dnaForm, dnaModel, basesPerTurn, duplexRise, self.endPoint1, self.endPoint2) def _addWhatsThisText(self): """ What's This text for widgets in this Property Manager. """ whatsThis_InsertDna_PropertyManager(self)
class Ui_ProteinSequenceEditor(PM_DockWidget): """ The Ui_DnaSequenceEditor class defines UI elements for the Sequence Editor object. The sequence editor is usually visible while in DNA edit mode. It is a DockWidget that is doced at the bottom of the MainWindow """ _title = "Sequence Editor" _groupBoxCount = 0 _lastGroupBox = None def __init__(self, win): """ Constructor for the Ui_DnaSequenceEditor @param win: The parentWidget (MainWindow) for the sequence editor """ self.win = win # Should parentWidget for a docwidget always be win? #Not necessary but most likely it will be the case. parentWidget = win _superclass.__init__(self, parentWidget, title = self._title) #A flag used to restore the state of the Reports dock widget #(which can be accessed through View > Reports) see self.show() and #self.closeEvent() for more details. self._reportsDockWidget_closed_in_show_method = False self.setFixedHeight(90) def show(self): """ Shows the sequence editor. While doing this, it also closes the reports dock widget (if visible) the state of the reports dockwidget will be restored when the sequence editor is closed. @see:self.closeEvent() """ self._reportsDockWidget_closed_in_show_method = False if self.win.viewFullScreenAction.isChecked() or \ self.win.viewSemiFullScreenAction.isChecked(): pass else: if self.win.reportsDockWidget.isVisible(): self.win.reportsDockWidget.close() self._reportsDockWidget_closed_in_show_method = True _superclass.show(self) def closeEvent(self, event): """ Overrides close event. Makes sure that the visible state of the reports widgetis restored when the sequence editor is closed. @see: self.show() """ _superclass.closeEvent(self, event) if self.win.viewFullScreenAction.isChecked() or \ self.win.viewSemiFullScreenAction.isChecked(): pass else: if self._reportsDockWidget_closed_in_show_method: self.win.viewReportsAction.setChecked(True) self._reportsDockWidget_closed_in_show_method = False def _loadWidgets(self): """ Overrides PM.PM_DockWidget._loadWidgets. Loads the widget in this dockwidget. """ self._loadMenuWidgets() self._loadTextEditWidget() def _loadMenuWidgets(self): """ Load the various menu widgets (e.g. Open, save sequence options, Find and replace widgets etc. """ #Note: Find and replace widgets might be moved to their own class. self.loadSequenceButton = PM_ToolButton( self, iconPath = "ui/actions/Properties Manager/Open.png") self.saveSequenceButton = PM_ToolButton( self, iconPath = "ui/actions/Properties Manager/Save_Strand_Sequence.png") self.loadSequenceButton.setAutoRaise(True) self.saveSequenceButton.setAutoRaise(True) #Find and replace widgets -- self.findLineEdit = \ PM_LineEdit( self, label = "", spanWidth = False) self.findLineEdit.setMaximumWidth(60) self.replaceLineEdit = \ PM_LineEdit( self, label = "", spanWidth = False) self.replaceLineEdit.setMaximumWidth(60) self.findOptionsToolButton = PM_ToolButton(self) self.findOptionsToolButton.setMaximumWidth(12) self.findOptionsToolButton.setAutoRaise(True) self.findOptionsToolButton.setPopupMode(QToolButton.MenuButtonPopup) self._setFindOptionsToolButtonMenu() self.findNextToolButton = PM_ToolButton( self, iconPath = "ui/actions/Properties Manager/Find_Next.png") self.findNextToolButton.setAutoRaise(True) self.findPreviousToolButton = PM_ToolButton( self, iconPath = "ui/actions/Properties Manager/Find_Previous.png") self.findPreviousToolButton.setAutoRaise(True) self.replacePushButton = PM_PushButton(self, text = "Replace") self.warningSign = QLabel(self) self.warningSign.setPixmap( getpixmap('ui/actions/Properties Manager/Warning.png')) self.warningSign.hide() self.phraseNotFoundLabel = QLabel(self) self.phraseNotFoundLabel.setText("Sequence Not Found") self.phraseNotFoundLabel.hide() #Widgets to include in the widget row. widgetList = [('PM_ToolButton', self.loadSequenceButton, 0), ('PM_ToolButton', self.saveSequenceButton, 1), ('QLabel', " Find:", 4), ('PM_LineEdit', self.findLineEdit, 5), ('PM_ToolButton', self.findOptionsToolButton, 6), ('PM_ToolButton', self.findPreviousToolButton, 7), ('PM_ToolButton', self.findNextToolButton, 8), ('QLabel', " Replace:", 9), ('PM_TextEdit', self.replaceLineEdit, 10), ('PM_PushButton', self.replacePushButton, 11), ('PM_Label', self.warningSign, 12), ('PM_Label', self.phraseNotFoundLabel, 13), ('QSpacerItem', 5, 5, 14) ] widgetRow = PM_WidgetRow(self, title = '', widgetList = widgetList, label = "", spanWidth = True ) def _loadTextEditWidget(self): """ Load the SequenceTexteditWidgets. """ self.aaRulerTextEdit = \ PM_TextEdit( self, label = "", spanWidth = False, permit_enter_keystroke = False) palette = getPalette(None, QPalette.Base, pmGrpBoxColor) self.aaRulerTextEdit.setPalette(palette) self.aaRulerTextEdit.setWordWrapMode( QTextOption.WrapAnywhere ) self.aaRulerTextEdit.setFixedHeight(20) self.aaRulerTextEdit.setReadOnly(True) self.sequenceTextEdit = \ PM_TextEdit( self, label = " Sequence: ", spanWidth = False, permit_enter_keystroke = False) self.sequenceTextEdit.setCursorWidth(2) self.sequenceTextEdit.setWordWrapMode( QTextOption.WrapAnywhere ) self.sequenceTextEdit.setFixedHeight(20) self.secStrucTextEdit = \ PM_TextEdit( self, label = " Secondary structure: ", spanWidth = False, permit_enter_keystroke = False) palette = getPalette(None, QPalette.Base, sequenceEditStrandMateBaseColor) self.secStrucTextEdit.setPalette(palette) self.secStrucTextEdit.setWordWrapMode( QTextOption.WrapAnywhere ) self.secStrucTextEdit.setFixedHeight(20) self.secStrucTextEdit.setReadOnly(True) #Important to make sure that the horizontal and vertical scrollbars #for these text edits are never displayed. self.sequenceTextEdit.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.sequenceTextEdit.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.secStrucTextEdit.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.secStrucTextEdit.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.aaRulerTextEdit.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.aaRulerTextEdit.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) def _getFindLineEditStyleSheet(self): """ Return the style sheet for the findLineEdit. This sets the following properties only: - background-color This style is set whenever the searchStrig can't be found (sets a light red color background to the lineedit when this happens) @return: The line edit style sheet. @rtype: str """ styleSheet = \ "QLineEdit {\ background-color: rgb(255, 102, 102)\ }" #Not used: # background-color: rgb(217, 255, 216)\ return styleSheet def _setFindOptionsToolButtonMenu(self): """ Sets the menu for the findOptionstoolbutton that appears a small menu button next to the findLineEdit. """ self.findOptionsMenu = QMenu(self.findOptionsToolButton) self.caseSensitiveFindAction = QAction(self.findOptionsToolButton) self.caseSensitiveFindAction.setText('Match Case') self.caseSensitiveFindAction.setCheckable(True) self.caseSensitiveFindAction.setChecked(False) self.findOptionsMenu.addAction(self.caseSensitiveFindAction) self.findOptionsMenu.addSeparator() self.findOptionsToolButton.setMenu(self.findOptionsMenu) def _addToolTipText(self): """ What's Tool Tip text for widgets in this Property Manager. """ pass def _addWhatsThisText(self): """ What's This text for widgets in this Property Manager. """ pass
class DnaDuplexPropertyManager( DnaOrCnt_PropertyManager ): """ The DnaDuplexPropertyManager class provides a Property Manager for the B{Build > DNA > Duplex} 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 = "Insert DNA" pmName = title iconPath = "ui/actions/Tools/Build Structures/InsertDsDna.png" def __init__( self, win, editCommand ): """ Constructor for the DNA Duplex property manager. """ self.endPoint1 = None self.endPoint2 = None self._conformation = "B-DNA" self._numberOfBases = 0 self._basesPerTurn = getDuplexBasesPerTurn(self._conformation) self._duplexRise = getDuplexRise(self._conformation) self._duplexLength = getDuplexLength(self._conformation, self._numberOfBases) _superclass.__init__( self, win, editCommand) self.showTopRowButtons( PM_DONE_BUTTON | \ PM_CANCEL_BUTTON | \ PM_WHATS_THIS_BUTTON) 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: change_connect = self.win.connect else: change_connect = self.win.disconnect change_connect(self._placementOptions.buttonGroup, SIGNAL("buttonClicked(int)"), self.activateSpecifyReferencePlaneTool) change_connect( self.conformationComboBox, SIGNAL("currentIndexChanged(int)"), self.conformationComboBoxChanged ) change_connect( self.numberOfBasePairsSpinBox, SIGNAL("valueChanged(int)"), self.numberOfBasesChanged ) change_connect( self.basesPerTurnDoubleSpinBox, SIGNAL("valueChanged(double)"), self.basesPerTurnChanged ) change_connect( self.duplexRiseDoubleSpinBox, SIGNAL("valueChanged(double)"), self.duplexRiseChanged ) change_connect(self.showCursorTextCheckBox, SIGNAL('stateChanged(int)'), self._update_state_of_cursorTextGroupBox) self.duplexRiseDoubleSpinBox.connectWithState( Preferences_StateRef_double( bdnaRise_prefs_key, env.prefs[bdnaRise_prefs_key] ) ) self.basesPerTurnDoubleSpinBox.connectWithState( Preferences_StateRef_double( bdnaBasesPerTurn_prefs_key, env.prefs[bdnaBasesPerTurn_prefs_key] ) ) def ok_btn_clicked(self): """ Slot for the OK button """ if self.editCommand: self.editCommand.preview_or_finalize_structure(previewing = False) ##env.history.message(self.editCommand.logMessage) self.win.toolsDone() def cancel_btn_clicked(self): """ Slot for the Cancel button. """ if self.editCommand: self.editCommand.cancelStructure() self.win.toolsCancel() def _update_widgets_in_PM_before_show(self): """ Update various widgets in this Property manager. Overrides superclass method @see: MotorPropertyManager._update_widgets_in_PM_before_show @see: self.show where it is called. """ pass def getFlyoutActionList(self): """ returns custom actionlist that will be used in a specific mode or editing a feature etc Example: while in movie mode, the _createFlyoutToolBar method calls this """ #'allActionsList' returns all actions in the flyout toolbar #including the subcontrolArea actions allActionsList = [] #Action List for subcontrol Area buttons. #In this mode there is really no subcontrol area. #We will treat subcontrol area same as 'command area' #(subcontrol area buttons will have an empty list as their command area #list). We will set the Comamnd Area palette background color to the #subcontrol area. subControlAreaActionList =[] self.exitEditCommandAction.setChecked(True) subControlAreaActionList.append(self.exitEditCommandAction) separator = QAction(self.w) separator.setSeparator(True) subControlAreaActionList.append(separator) allActionsList.extend(subControlAreaActionList) #Empty actionlist for the 'Command Area' commandActionLists = [] #Append empty 'lists' in 'commandActionLists equal to the #number of actions in subControlArea for i in range(len(subControlAreaActionList)): lst = [] commandActionLists.append(lst) params = (subControlAreaActionList, commandActionLists, allActionsList) return params def _addGroupBoxes( self ): """ Add the DNA Property Manager group boxes. """ self._pmReferencePlaneGroupBox = PM_GroupBox( self, title = "Placement Options" ) self._loadReferencePlaneGroupBox( self._pmReferencePlaneGroupBox ) self._pmGroupBox1 = PM_GroupBox( self, title = "Endpoints" ) self._loadGroupBox1( self._pmGroupBox1 ) self._pmGroupBox1.hide() self._pmGroupBox2 = PM_GroupBox( self, title = "Parameters" ) self._loadGroupBox2( self._pmGroupBox2 ) self._displayOptionsGroupBox = PM_GroupBox( self, title = "Display Options" ) self._loadDisplayOptionsGroupBox( self._displayOptionsGroupBox ) def _loadGroupBox1(self, pmGroupBox): """ Load widgets in group box 3. """ #Folllowing toolbutton facilitates entering a temporary DnaLineMode #to create a DNA using endpoints of the specified line. self.specifyDnaLineButton = PM_ToolButton( pmGroupBox, text = "Specify Endpoints", iconPath = "ui/actions/Properties Manager/Pencil.png", spanWidth = True ) self.specifyDnaLineButton.setCheckable(True) self.specifyDnaLineButton.setAutoRaise(True) self.specifyDnaLineButton.setToolButtonStyle( Qt.ToolButtonTextBesideIcon) #EndPoint1 and endPoint2 coordinates. These widgets are hidden # as of 2007- 12 - 05 self._endPoint1SpinBoxes = PM_CoordinateSpinBoxes(pmGroupBox, label = "End Point 1") self.x1SpinBox = self._endPoint1SpinBoxes.xSpinBox self.y1SpinBox = self._endPoint1SpinBoxes.ySpinBox self.z1SpinBox = self._endPoint1SpinBoxes.zSpinBox self._endPoint2SpinBoxes = PM_CoordinateSpinBoxes(pmGroupBox, label = "End Point 2") self.x2SpinBox = self._endPoint2SpinBoxes.xSpinBox self.y2SpinBox = self._endPoint2SpinBoxes.ySpinBox self.z2SpinBox = self._endPoint2SpinBoxes.zSpinBox self._endPoint1SpinBoxes.hide() self._endPoint2SpinBoxes.hide() def _loadGroupBox2(self, pmGroupBox): """ Load widgets in group box 4. """ self.conformationComboBox = \ PM_ComboBox( pmGroupBox, label = "Conformation:", choices = ["B-DNA"], setAsDefault = True) dnaModelChoices = ['PAM3', 'PAM5'] self.dnaModelComboBox = \ PM_ComboBox( pmGroupBox, label = "Model:", choices = dnaModelChoices, setAsDefault = True) self.basesPerTurnDoubleSpinBox = \ PM_DoubleSpinBox( pmGroupBox, label = "Bases per turn:", value = env.prefs[bdnaBasesPerTurn_prefs_key], setAsDefault = True, minimum = 8.0, maximum = 20.0, decimals = 2, singleStep = 0.1 ) self.duplexRiseDoubleSpinBox = \ PM_DoubleSpinBox( pmGroupBox, label = "Rise:", value = env.prefs[bdnaRise_prefs_key], setAsDefault = True, minimum = 2.0, maximum = 4.0, decimals = 3, singleStep = 0.01 ) # Strand Length (i.e. the number of bases) self.numberOfBasePairsSpinBox = \ PM_SpinBox( pmGroupBox, label = "Base pairs:", value = self._numberOfBases, setAsDefault = False, minimum = 0, maximum = 10000 ) self.numberOfBasePairsSpinBox.setDisabled(True) # Duplex Length self.duplexLengthLineEdit = \ PM_LineEdit( pmGroupBox, label = "Duplex length: ", text = "0.0 Angstroms", setAsDefault = False) self.duplexLengthLineEdit.setDisabled(True) def _loadDisplayOptionsGroupBox(self, pmGroupBox): """ Load widgets in the Display Options GroupBox @see: DnaOrCnt_PropertyManager. _loadDisplayOptionsGroupBox """ #Call the superclass method that loads the cursor text checkboxes. #Note, as of 2008-05-19, the superclass, DnaOrCnt_PropertyManager #only loads the cursor text groupboxes. Subclasses like this can #call custom methods like self._loadCursorTextCheckBoxes etc if they #don't need all groupboxes that the superclass loads. _superclass._loadDisplayOptionsGroupBox(self, pmGroupBox) self._rubberbandLineGroupBox = PM_GroupBox( pmGroupBox, title = 'Rubber band line:') dnaLineChoices = ['Ribbons', 'Ladder'] self.dnaRubberBandLineDisplayComboBox = \ PM_ComboBox( self._rubberbandLineGroupBox , label = " Display as:", choices = dnaLineChoices, setAsDefault = True) self.lineSnapCheckBox = \ PM_CheckBox(self._rubberbandLineGroupBox , text = 'Enable line snap' , widgetColumn = 1, state = Qt.Checked ) 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 , dnaDuplexEditCommand_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 base pairs", dnaDuplexEditCommand_cursorTextCheckBox_numberOfBasePairs_prefs_key), ("Number of turns", dnaDuplexEditCommand_cursorTextCheckBox_numberOfTurns_prefs_key), ("Duplex length", dnaDuplexEditCommand_cursorTextCheckBox_length_prefs_key), ("Angle", dnaDuplexEditCommand_cursorTextCheckBox_angle_prefs_key) ] return params def _addToolTipText(self): """ Tool Tip text for widgets in the DNA Property Manager. """ pass def conformationComboBoxChanged( self, inIndex ): """ Slot for the Conformation combobox. It is called whenever the Conformation choice is changed. @param inIndex: The new index. @type inIndex: int """ conformation = self.conformationComboBox.currentText() if conformation == "B-DNA": self.basesPerTurnDoubleSpinBox.setValue("10.0") elif conformation == "Z-DNA": self.basesPerTurnDoubleSpinBox.setValue("12.0") else: msg = redmsg("conformationComboBoxChanged(): \ Error - unknown DNA conformation. Index = "+ inIndex) env.history.message(msg) self.duplexLengthSpinBox.setSingleStep(getDuplexRise(conformation)) def numberOfBasesChanged( self, numberOfBases ): """ Slot for the B{Number of Bases} spinbox. """ # Update the Duplex Length lineEdit widget. text = str(getDuplexLength(self._conformation, numberOfBases, self._duplexRise)) \ + " Angstroms" self.duplexLengthLineEdit.setText(text) return def basesPerTurnChanged( self, basesPerTurn ): """ Slot for the B{Bases per turn} spinbox. """ self.editCommand.basesPerTurn = basesPerTurn self._basesPerTurn = basesPerTurn return def duplexRiseChanged( self, rise ): """ Slot for the B{Rise} spinbox. """ self.editCommand.duplexRise = rise self._duplexRise = rise return def getParameters(self): """ Return the parameters from this property manager to be used to create the DNA duplex. @return: A tuple containing the parameters @rtype: tuple @see: L{DnaDuplex_EditCommand._gatherParameters} where this is used """ numberOfBases = self.numberOfBasePairsSpinBox.value() dnaForm = str(self.conformationComboBox.currentText()) basesPerTurn = self.basesPerTurnDoubleSpinBox.value() duplexRise = self.duplexRiseDoubleSpinBox.value() dnaModel = str(self.dnaModelComboBox.currentText()) # First endpoint (origin) of DNA duplex x1 = self.x1SpinBox.value() y1 = self.y1SpinBox.value() z1 = self.z1SpinBox.value() # Second endpoint (direction vector/axis) of DNA duplex. x2 = self.x2SpinBox.value() y2 = self.y2SpinBox.value() z2 = self.z2SpinBox.value() if not self.endPoint1: self.endPoint1 = V(x1, y1, z1) if not self.endPoint2: self.endPoint2 = V(x2, y2, z2) return (numberOfBases, dnaForm, dnaModel, basesPerTurn, duplexRise, self.endPoint1, self.endPoint2) def _addWhatsThisText(self): """ What's This text for widgets in this Property Manager. """ whatsThis_DnaDuplexPropertyManager(self)
class OrderDna_PropertyManager( PM_Dialog, DebugMenuMixin ): """ The OrderDna_PropertyManager class provides a Property Manager for the B{Order Dna} command on the flyout toolbar in the Build > Dna mode. @ivar title: The title that appears in the property manager header. @type title: str @ivar pmName: The name of this property manager. This is used to set the name of the PM_Dialog object via setObjectName(). @type name: str @ivar iconPath: The relative path to the PNG file that contains a 22 x 22 icon image that appears in the PM header. @type iconPath: str """ title = "Order Dna" pmName = title iconPath = "ui/actions/Command Toolbar/Order_DNA.png" def __init__( self, parentCommand ): """ Constructor for the property manager. """ self.parentMode = parentCommand self.w = self.parentMode.w self.win = self.parentMode.w self.pw = self.parentMode.pw self.o = self.win.glpane self.assy = self.win.assy PM_Dialog.__init__(self, self.pmName, self.iconPath, self.title) DebugMenuMixin._init1( self ) self.showTopRowButtons( PM_DONE_BUTTON | \ PM_WHATS_THIS_BUTTON) self.update_includeStrands() # Updates the message box. """ if self.getNumberOfBases(): msg = "Click on <b>View DNA Order File...</b> to preview a "\ "DNA order for all DNA strands in the current model." else: msg = "<font color=red>There is no DNA in the current model." self.updateMessage(msg) """ 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: change_connect = self.win.connect else: change_connect = self.win.disconnect change_connect( self.viewDnaOrderFileButton, SIGNAL("clicked()"), self.viewDnaOrderFile) change_connect( self.includeStrandsComboBox, SIGNAL("activated(int)"), self.update_includeStrands ) def ok_btn_clicked(self): """ Slot for the OK button """ self.win.toolsDone() def show(self): """ Shows the Property Manager. Overrides PM_Dialog.show. """ PM_Dialog.show(self) self.connect_or_disconnect_signals(isConnect = True) def close(self): """ Closes the Property Manager. Overrides PM_Dialog.close. """ self.connect_or_disconnect_signals(False) PM_Dialog.close(self) def _addGroupBoxes( self ): """ Add the Property Manager group boxes. """ self._pmGroupBox1 = PM_GroupBox( self, title = "Options" ) self._loadGroupBox1( self._pmGroupBox1 ) def _loadGroupBox1(self, pmGroupBox): """ Load widgets in group box. """ includeStrandsChoices = ["All strands in model", "Selected strands only"] self.includeStrandsComboBox = \ PM_ComboBox( pmGroupBox, label = "Include strands:", choices = includeStrandsChoices, setAsDefault = True) self.numberOfBasesLineEdit = \ PM_LineEdit( pmGroupBox, label = "Number of bases:", text = str(self.getNumberOfBases())) self.numberOfBasesLineEdit.setEnabled(False) self.viewDnaOrderFileButton = \ PM_PushButton( pmGroupBox, label = "", text = "View DNA Order File...", spanWidth = True) 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 # Ask Bruce where this should live (i.e. class Part?) --Mark def getAllDnaStrands(self, selectedOnly = False): """ Returns a list of all the DNA strands in the current part, or only the selected strands if I{selectedOnly} is True. @param selectedOnly: If True, return only the selected DNA strands. @type selectedOnly: bool """ dnaStrandList = [] def func(node): if isinstance(node, DnaStrand): if selectedOnly: if node.picked: dnaStrandList.append(node) else: dnaStrandList.append(node) self.win.assy.part.topnode.apply2all(func) return dnaStrandList def getNumberOfBases(self, selectedOnly = False): """ Returns the number of bases count for all the DNA strands in the current part, or only the selected strand if I{selectedOnly} is True. @param selectedOnly: If True, return only the selected DNA strands. @type selectedOnly: bool """ dnaSequenceString = '' selectedOnly = self.includeStrandsComboBox.currentIndex() strandList = self.getAllDnaStrands(selectedOnly) for strand in strandList: strandSequenceString = str(strand.getStrandSequence()) dnaSequenceString += strandSequenceString return len(dnaSequenceString) def getDnaSequence(self, format = 'CSV'): """ Return the complete Dna sequence information string (i.e. all strand sequences) in the specified format. @return: The Dna sequence string @rtype: string """ if format == 'CSV': #comma separated values. separator = ',' dnaSequenceString = '' selectedOnly = self.includeStrandsComboBox.currentIndex() strandList = self.getAllDnaStrands(selectedOnly) for strand in strandList: dnaSequenceString = dnaSequenceString + strand.name + separator strandSequenceString = str(strand.getStrandSequence()) if strandSequenceString: strandSequenceString = strandSequenceString.upper() dnaSequenceString = dnaSequenceString + strandSequenceString dnaSequenceString = dnaSequenceString + "\n" return dnaSequenceString def viewDnaOrderFile(self, openFileInEditor = True): """ Opens a text editor and loads a temporary text file containing all the DNA strand names and their sequences in the current DNA object. It will look something like this: Strand1,ATCAGCTACGCATCGCT Strand2,TAGTCGATGCGTAGCGA ... Strandn, ... The user can then save the file to a permanent location using the text editor the file is loaded (and displayed) in. @see: Ui_DnaFlyout.orderDnaCommand @see: writeDnaOrderFile() @TODO: assy.getAllDnaObjects(). """ dnaSequence = self.getDnaSequence(format = 'CSV') if dnaSequence: tmpdir = find_or_make_Nanorex_subdir('temp') fileBaseName = 'DnaOrder' temporaryFile = os.path.join(tmpdir, "%s.csv" % fileBaseName) writeDnaOrderFile(temporaryFile, self.assy, dnaSequence) if openFileInEditor: open_file_in_editor(temporaryFile) def update_includeStrands(self, ignoreVal = 0): """ Slot method for "Include (strands)" combobox. """ idx = self.includeStrandsComboBox.currentIndex() includeType = ["model", "selection"] _numberOfBases = self.getNumberOfBases() self.numberOfBasesLineEdit.setText(str(_numberOfBases)) if _numberOfBases > 0: self.viewDnaOrderFileButton.setEnabled(True) msg = "Click on <b>View DNA Order File...</b> to preview a " \ "DNA order for all DNA strands in the current %s." \ % includeType[idx] else: self.viewDnaOrderFileButton.setEnabled(False) msg = "<font color=red>" \ "There are no DNA strands in the current %s." \ % includeType[idx] self.updateMessage(msg)
class EditNanotube_PropertyManager( DnaOrCnt_PropertyManager ): """ The NanotubeSegmenta_PropertyManager class provides a Property Manager for the EditNanotube_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 = "Nanotube Properties" pmName = title iconPath = "ui/actions/Command Toolbar/BuildNanotube/EditNanotube.png" def __init__( self, command ): """ Constructor for the Cnt Segment Properties 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 # Initialized here. Their values will be set in # _update_widgets_in_PM_before_show() self.endPoint1 = V(0, 0, 0) self.endPoint2 = V(0, 0, 0) _superclass.__init__( self, command) self.showTopRowButtons( PM_DONE_BUTTON | \ PM_CANCEL_BUTTON | \ PM_WHATS_THIS_BUTTON) 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: change_connect = self.win.connect else: change_connect = self.win.disconnect change_connect(self.nameLineEdit, SIGNAL("editingFinished()"), self._nameChanged) change_connect(self.showCursorTextCheckBox, SIGNAL('stateChanged(int)'), self._update_state_of_cursorTextGroupBox) return def show(self): """ Show this property manager. Overrides EditCommand_PM.show() This method also retrives the name information from the command's structure for its name line edit field. @see: EditNanotube_EditCommand.getStructureName() @see: self.close() """ _superclass.show(self) #if self.command is not None: #name = self.command.getStructureName() #if name is not None: #self.nameLineEdit.setText(name) 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: EditNanotube_EditCommand.setStructureName """ if self.command is not None: name = str(self.nameLineEdit.text()) self.command.setStructureName(name) _superclass.close(self) 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 , editNanotubeEditCommand_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) ("Nanotube length", editNanotubeEditCommand_cursorTextCheckBox_length_prefs_key) ] return params def setParameters(self, params): """ This is called when entering "Nanotube Segment Properties (i.e. "Edit properties...") to retrieve and set parameters of the nanotube segment that might be modified during this command and are needed to regenerate the nanotube segment. @param params: The parameters of the nanotube segment. These parameters are retreived via L{NanotubeSegment.getProps()}, called from L{EditNanotube_EditCommand.editStructure()}. Parameters: - n, m (chirality) - type (i.e. carbon or boron nitride) - endings (none, hydrogen, nitrogen) - endpoints (endPoint1, endPoint2) @type params: list (n, m), type, endings, (endPoint1, endPoint2) @note: Any widgets in the property manager that display these parameters should be updated here. @see: L{NanotubeSegment.getProps()} 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? """ (self.n, self.m), self.type, self.endings,\ (self.endPoint1, self.endPoint2) = params # This is needed to update the endpoints since the Nanotube segment # may have been moved (i.e. translated or rotated). In that case, # the endpoints are not updated, so we recompute them here. nanotubeChunk = self.command.struct.members[0] self.endPoint1, self.endPoint2, radius = \ self.command.struct.nanotube.computeEndPointsFromChunk(nanotubeChunk) if 0: print "\n--------------" print "setParameters():" print "Struct=", self.command.struct print "N, M:", self.n, self.m print "type:", self.type print "endings:", self.endings print "pt1, pt2:", self.endPoint1, self.endPoint2 def getParameters(self): """ Get the parameters that the edit command will use to determine if any have changed. If any have, then the nanotube will be modified. """ if 0: print "\n--------------" print "getParameters():" print "Struct=", self.command.struct print "N, M:", self.n, self.m print "type:", self.type print "endings:", self.endings print "pt1, pt2:", self.endPoint1, self.endPoint2 return (self.n, self.m, self.type, self.endings, self.endPoint1, self.endPoint2) def _update_widgets_in_PM_before_show(self): """ This is called only when user is editing an existing structure. Its different than self.update_widgets_in_pm_before_show. (that method is called just before showing the property manager) @see: EditNanotube_EditCommand.editStructure() """ if self.command and self.command.hasValidStructure(): self.nanotube = self.command.struct.nanotube self.n, self.m = self.nanotube.getChirality() self.type = self.nanotube.getType() self.endings = self.nanotube.getEndings() self.endPoint1, self.endPoint2 = self.nanotube.getEndPoints() pass # Note that _update_widgets_in_PM_before_show() is called in # self.show, before you connect the signals. So, for the # 'first show' we will need to manually set the value of any # widgets that need updated. But later, when a different # NanotubeSegment is clicked, (while still in # EditNanotube_EditCommand, the propMgr will already be connected # so any calls in that case is redundant. self.updateNameField() self.updateLength() self.updateNanotubeDiameter() self.updateChirality() return def _update_UI_do_updates(self): """ Overrides superclass method. @see: Command_PropertyManager._update_UI_do_updates() """ self._update_widgets_in_PM_before_show() if self.command.struct: msg = "Editing structure <b>%s</b>." % \ self.command.getStructureName() else: msg = "Select a nanotube to edit." self.updateMessage(msg) return def _addGroupBoxes( self ): """ Add the 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 = "Name:", text = "", setAsDefault = False) # Nanotube Length self.ntLengthLineEdit = \ PM_LineEdit( pmGroupBox, label = "Length: ", text = "0.0 Angstroms", setAsDefault = False) self.ntLengthLineEdit.setDisabled(True) # Nanotube Radius self.ntDiameterLineEdit = \ PM_LineEdit( pmGroupBox, label = "Nanotube Diameter: ", setAsDefault = False) self.ntDiameterLineEdit.setDisabled(True) # Nanotube chirality. These are disabled (read-only) for now. --Mark self.chiralityNSpinBox = \ PM_SpinBox( pmGroupBox, label = "Chirality (n) :", minimum = 2, maximum = 100, setAsDefault = True ) self.chiralityNSpinBox.setDisabled(True) self.chiralityMSpinBox = \ PM_SpinBox( pmGroupBox, label = "Chirality (m) :", minimum = 0, maximum = 100, setAsDefault = True ) self.chiralityMSpinBox.setDisabled(True) def _addWhatsThisText(self): """ Add what's this text. """ pass def _addToolTipText(self): """ Add Tooltip text """ pass def _nameChanged(self): """ Slot for "Name" field. @TODO: Include a validator for the name field. """ _name = str(self.nameLineEdit.text()) if not _name: # Minimal test. Need to implement a validator. self.updateNameField() return self.command.setStructureName(_name) msg = "Editing structure <b>%s</b>." % _name self.updateMessage(msg) return def updateNameField(self): """ Update the name field showing the name of the currently selected protein. clear the combobox list. """ if self.command.hasValidStructure(): self.nameLineEdit.setEnabled(True) self.nameLineEdit.setText(self.command.getStructureName()) else: self.nameLineEdit.setDisabled(True) self.nameLineEdit.setText("") return def updateLength( self ): """ Update the nanotube Length lineEdit widget. """ if self.command.hasValidStructure(): _nanotubeLength = vlen(self.endPoint1 - self.endPoint2) _lengthText = "%-7.4f Angstroms" % (_nanotubeLength) else: _lengthText = "" self.ntLengthLineEdit.setText(_lengthText) return def updateNanotubeDiameter(self): """ Update the nanotube Diameter lineEdit widget. """ if self.command.hasValidStructure(): _diameterText = "%-7.4f Angstroms" % (self.nanotube.getDiameter()) else: _diameterText = "" self.ntDiameterLineEdit.setText(_diameterText) return def updateChirality( self ): """ Update the nanotube chirality spinboxes (read-only). """ if self.command.hasValidStructure(): n, m = self.nanotube.getChirality() else: n = 0 m = 0 self.chiralityNSpinBox.setValue(n) self.chiralityMSpinBox.setValue(m) return pass # End of EditNanotube_PropertyManager class
class Ui_BuildAtomsPropertyManager(Command_PropertyManager): """ The Ui_BuildAtomsPropertyManager class defines UI elements for the Property Manager of the B{Build Atoms mode}. @ivar title: The title that appears in the property manager header. @type title: str @ivar pmName: The name of this property manager. This is used to set the name of the PM_Dialog object via setObjectName(). @type name: str @ivar iconPath: The relative path to the PNG file that contains a 22 x 22 icon image that appears in the PM header. @type iconPath: str """ # The title that appears in the Property Manager header title = "Build Atoms" # The name of this Property Manager. This will be set to # the name of the PM_Dialog object via setObjectName(). pmName = title # The relative path to the PNG file that appears in the header iconPath = "ui/actions/Tools/Build Structures/BuildAtoms.png" def __init__(self, command): """ Constructor for the B{Build Atoms} property manager class that defines its UI. @param command: The parent mode where this Property Manager is used @type command: L{depositMode} """ self.previewGroupBox = None self.regularElementChooser = None self.PAM5Chooser = None self.PAM3Chooser = None self.elementChooser = None self.advancedOptionsGroupBox = None self.bondToolsGroupBox = None self.selectionFilterCheckBox = None self.filterlistLE = None self.selectedAtomInfoLabel = None #Initialize the following to None. (subclasses may not define this) #Make sure you initialize it before adding groupboxes! self.selectedAtomPosGroupBox = None self.showSelectedAtomInfoCheckBox = None _superclass.__init__(self, command) self.showTopRowButtons(PM_DONE_BUTTON | PM_WHATS_THIS_BUTTON) msg = '' self.MessageGroupBox.insertHtmlMessage(msg, setAsDefault=False) def _addGroupBoxes(self): """ Add various group boxes to the Build Atoms Property manager. """ self._addPreviewGroupBox() self._addAtomChooserGroupBox() self._addBondToolsGroupBox() #@@@TODO HIDE the bonds tool groupbox initially as the #by default, the atoms tool is active when BuildAtoms command is #finist invoked. self.bondToolsGroupBox.hide() self._addSelectionOptionsGroupBox() self._addAdvancedOptionsGroupBox() def _addPreviewGroupBox(self): """ Adde the preview groupbox that shows the element selected in the element chooser. """ self.previewGroupBox = PM_PreviewGroupBox( self, glpane = self.o ) def _addAtomChooserGroupBox(self): """ Add the Atom Chooser groupbox. This groupbox displays one of the following three groupboxes depending on the choice selected in the combobox: a) Periodic Table Elements L{self.regularElementChooser} b) PAM5 Atoms L{self.PAM5Chooser} c) PAM3 Atoms L{self.PAM3Chooser} @see: L{self.__updateAtomChooserGroupBoxes} """ self.atomChooserGroupBox = \ PM_GroupBox(self, title = "Atom Chooser") self._loadAtomChooserGroupBox(self.atomChooserGroupBox) self._updateAtomChooserGroupBoxes(currentIndex = 0) def _addElementChooserGroupBox(self, inPmGroupBox): """ Add the 'Element Chooser' groupbox. (present within the Atom Chooser Groupbox) """ if not self.previewGroupBox: return elementViewer = self.previewGroupBox.elementViewer self.regularElementChooser = \ PM_ElementChooser( inPmGroupBox, parentPropMgr = self, elementViewer = elementViewer) def _add_PAM5_AtomChooserGroupBox(self, inPmGroupBox): """ Add the 'PAM5 Atom Chooser' groupbox (present within the Atom Chooser Groupbox) """ if not self.previewGroupBox: return elementViewer = self.previewGroupBox.elementViewer self.PAM5Chooser = \ PM_PAM5_AtomChooser( inPmGroupBox, parentPropMgr = self, elementViewer = elementViewer) def _add_PAM3_AtomChooserGroupBox(self, inPmGroupBox): """ Add the 'PAM3 Atom Chooser' groupbox (present within the Atom Chooser Groupbox) """ if not self.previewGroupBox: return elementViewer = self.previewGroupBox.elementViewer self.PAM3Chooser = \ PM_PAM3_AtomChooser( inPmGroupBox, parentPropMgr = self, elementViewer = elementViewer) def _hideAllAtomChooserGroupBoxes(self): """ Hides all Atom Chooser group boxes. """ if self.regularElementChooser: self.regularElementChooser.hide() if self.PAM5Chooser: self.PAM5Chooser.hide() if self.PAM3Chooser: self.PAM3Chooser.hide() def _addBondToolsGroupBox(self): """ Add the 'Bond Tools' groupbox. """ self.bondToolsGroupBox = \ PM_GroupBox( self, title = "Bond Tools") self._loadBondToolsGroupBox(self.bondToolsGroupBox) def _addSelectionOptionsGroupBox(self): """ Add 'Selection Options' groupbox """ self.selectionOptionsGroupBox = \ PM_GroupBox( self, title = "Selection Options" ) self._loadSelectionOptionsGroupBox(self.selectionOptionsGroupBox) def _loadAtomChooserGroupBox(self, inPmGroupBox): """ Load the widgets inside the Atom Chooser groupbox. @param inPmGroupBox: The Atom Chooser box in the PM @type inPmGroupBox: L{PM_GroupBox} """ atomChooserChoices = [ "Periodic Table Elements", "PAM5 Atoms", "PAM3 Atoms" ] self.atomChooserComboBox = \ PM_ComboBox( inPmGroupBox, label = '', choices = atomChooserChoices, index = 0, setAsDefault = False, spanWidth = True ) #Following fixes bug 2550 self.atomChooserComboBox.setFocusPolicy(Qt.NoFocus) self._addElementChooserGroupBox(inPmGroupBox) self._add_PAM5_AtomChooserGroupBox(inPmGroupBox) self._add_PAM3_AtomChooserGroupBox(inPmGroupBox) def _loadSelectionOptionsGroupBox(self, inPmGroupBox): """ Load widgets in the Selection Options group box. @param inPmGroupBox: The Selection Options box in the PM @type inPmGroupBox: L{PM_GroupBox} """ self.selectionFilterCheckBox = \ PM_CheckBox( inPmGroupBox, text = "Enable atom selection filter", widgetColumn = 0, state = Qt.Unchecked ) self.selectionFilterCheckBox.setDefaultValue(False) self.filterlistLE = PM_LineEdit( inPmGroupBox, label = "", text = "", setAsDefault = False, spanWidth = True ) self.filterlistLE.setReadOnly(True) if self.selectionFilterCheckBox.isChecked(): self.filterlistLE.setEnabled(True) else: self.filterlistLE.setEnabled(False) self.showSelectedAtomInfoCheckBox = \ PM_CheckBox( inPmGroupBox, text = "Show Selected Atom Info", widgetColumn = 0, state = Qt.Unchecked) self.selectedAtomPosGroupBox = \ PM_GroupBox( inPmGroupBox, title = "") self._loadSelectedAtomPosGroupBox(self.selectedAtomPosGroupBox) self.toggle_selectedAtomPosGroupBox(show = 0) self.enable_or_disable_selectedAtomPosGroupBox( bool_enable = False) self.reshapeSelectionCheckBox = \ PM_CheckBox( inPmGroupBox, text = 'Dragging reshapes selection', widgetColumn = 0, state = Qt.Unchecked ) connect_checkbox_with_boolean_pref( self.reshapeSelectionCheckBox, reshapeAtomsSelection_prefs_key ) env.prefs[reshapeAtomsSelection_prefs_key] = False self.waterCheckBox = \ PM_CheckBox( inPmGroupBox, text = "Z depth filter (water surface)", widgetColumn = 0, state = Qt.Unchecked ) def _loadSelectedAtomPosGroupBox(self, inPmGroupBox): """ Load the selected Atoms position groupbox It is a sub-gropbox of L{self.selectionOptionsGroupBox) @param inPmGroupBox: 'The Selected Atom Position Groupbox' @type inPmGroupBox: L{PM_GroupBox} """ self.selectedAtomLineEdit = PM_LineEdit( inPmGroupBox, label = "Selected Atom:", text = "", setAsDefault = False, spanWidth = False ) self.selectedAtomLineEdit.setReadOnly(True) self.selectedAtomLineEdit.setEnabled(False) self.coordinateSpinboxes = PM_CoordinateSpinBoxes(inPmGroupBox) # User input to specify x-coordinate self.xCoordOfSelectedAtom = self.coordinateSpinboxes.xSpinBox # User input to specify y-coordinate self.yCoordOfSelectedAtom = self.coordinateSpinboxes.ySpinBox # User input to specify z-coordinate self.zCoordOfSelectedAtom = self.coordinateSpinboxes.zSpinBox def _addAdvancedOptionsGroupBox(self): """ Add 'Advanced Options' groupbox """ self.advancedOptionsGroupBox = \ PM_GroupBox( self, title = "Advanced Options" ) self._loadAdvancedOptionsGroupBox(self.advancedOptionsGroupBox) def _loadAdvancedOptionsGroupBox(self, inPmGroupBox): """ Load widgets in the Advanced Options group box. @param inPmGroupBox: The Advanced Options box in the PM @type inPmGroupBox: L{PM_GroupBox} """ self.autoBondCheckBox = \ PM_CheckBox( inPmGroupBox, text = 'Auto bond', widgetColumn = 0, state = Qt.Checked ) self.highlightingCheckBox = \ PM_CheckBox( inPmGroupBox, text = "Hover highlighting", widgetColumn = 0, state = Qt.Checked ) def _loadBondToolsGroupBox(self, inPmGroupBox): """ Load widgets in the Bond Tools group box. @param inPmGroupBox: The Bond Tools box in the PM @type inPmGroupBox: L{PM_GroupBox} """ # Button list to create a toolbutton row. # Format: # - buttonId, # - buttonText , # - iconPath # - tooltip # - shortcut # - column BOND_TOOL_BUTTONS = \ [ ( "QToolButton", 0, "SINGLE", "", "", None, 0), ( "QToolButton", 1, "DOUBLE", "", "", None, 1), ( "QToolButton", 2, "TRIPLE", "", "", None, 2), ( "QToolButton", 3, "AROMATIC", "", "", None, 3), ( "QToolButton", 4, "GRAPHITIC", "", "", None, 4), ( "QToolButton", 5, "CUTBONDS", "", "", None, 5) ] self.bondToolButtonRow = \ PM_ToolButtonRow( inPmGroupBox, title = "", buttonList = BOND_TOOL_BUTTONS, checkedId = None, setAsDefault = True ) def _addWhatsThisText(self): """ "What's This" text for widgets in this Property Manager. """ from ne1_ui.WhatsThisText_for_PropertyManagers import whatsThis_BuildAtomsPropertyManager whatsThis_BuildAtomsPropertyManager(self) def _addToolTipText(self): """ Tool Tip text for widgets in this Property Manager. """ from ne1_ui.ToolTipText_for_PropertyManagers import ToolTip_BuildAtomsPropertyManager ToolTip_BuildAtomsPropertyManager(self) def toggle_selectedAtomPosGroupBox(self, show = 0): """ Show or hide L{self.selectedAtomPosGroupBox} depending on the state of the checkbox (L{self.showSelectedAtomInfoCheckBox}) @param show: Flag that shows or hides the groupbox (can have values 0 or 1 @type show: int """ if show: self.selectedAtomPosGroupBox.show() else: self.selectedAtomPosGroupBox.hide() def enable_or_disable_selectedAtomPosGroupBox(self, bool_enable = False): """ Enable or disable Selected AtomPosGroupBox present within 'selection options' and also the checkbox that shows or hide this groupbox. These two widgets are enabled when only a single atom is selected from the 3D workspace. @param bool_enable: Flag that enables or disables widgets @type bool_enable: boolean """ if self.showSelectedAtomInfoCheckBox: self.showSelectedAtomInfoCheckBox.setEnabled(bool_enable) if self.selectedAtomPosGroupBox: self.selectedAtomPosGroupBox.setEnabled(bool_enable) def _updateAtomChooserGroupBoxes(self, currentIndex): """ Updates the Atom Chooser Groupbox. It displays one of the following three groupboxes depending on the choice selected in the combobox: a) Periodic Table Elements L{self.regularElementChooser} b) PAM5 Atoms L{self.PAM5Chooser} c) PAM3 Atoms L{self.PAM3Chooser} It also sets self.elementChooser to the current active Atom chooser and updates the display accordingly in the Preview groupbox. """ self._hideAllAtomChooserGroupBoxes() if currentIndex is 0: self.elementChooser = self.regularElementChooser self.regularElementChooser.show() if currentIndex is 1: self.elementChooser = self.PAM5Chooser self.PAM5Chooser.show() if currentIndex is 2: self.elementChooser = self.PAM3Chooser self.PAM3Chooser.show() if self.elementChooser: self.elementChooser.updateElementViewer() self.updateMessage() def updateMessage(self): """ Update the Message groupbox with informative message. Subclasses should override this. """ pass
def _loadFreeDragTranslateGroupBox(self, inPmGroupBox): """ Load widgets in the Free Drag Translate group box, which is present within the Translate groupbox. @param inPmGroupBox: The Free Drag Translate group box in the Translate group box. @type inPmGroupBox: L{PM_GroupBox} """ # Button list to create a toolbutton row. # Format: # - buttonId, # - buttonText , # - iconPath # - tooltip # - shortcut # - column BUTTON_LIST = [ ( "QToolButton", 1, "MOVEDEFAULT", "ui/actions/Properties Manager/Move_Free.png", "", "F", 0), ( "QToolButton", 2, "TRANSX", "ui/actions/Properties Manager/TranslateX.png", "", "X", 1), ( "QToolButton", 3, "TRANSY", "ui/actions/Properties Manager/TranslateY.png", "", "Y", 2), ( "QToolButton", 4, "TRANSZ", "ui/actions/Properties Manager/TranslateZ.png", "", "Z", 3), ( "QToolButton", 5, "ROT_TRANS_ALONG_AXIS", "ui/actions/Properties Manager/translate+rotate-A.png", "", \ "A", 4) ] self.freeDragTranslateButtonGroup = \ PM_ToolButtonRow( inPmGroupBox, title = "", buttonList = BUTTON_LIST, checkedId = 1, setAsDefault = True, ) self.transFreeButton =self.freeDragTranslateButtonGroup.getButtonById(1) self.transXButton = self.freeDragTranslateButtonGroup.getButtonById(2) self.transYButton = self.freeDragTranslateButtonGroup.getButtonById(3) self.transZButton = self.freeDragTranslateButtonGroup.getButtonById(4) self.transAlongAxisButton = \ self.freeDragTranslateButtonGroup.getButtonById(5) self.moveFromToButton = PM_ToolButton( inPmGroupBox, text = "Translate from/to", iconPath = "ui/actions/Properties Manager"\ "/Translate_Components.png", spanWidth = True ) self.moveFromToButton.setCheckable(True) self.moveFromToButton.setAutoRaise(True) self.moveFromToButton.setToolButtonStyle( Qt.ToolButtonTextBesideIcon) self.startCoordLineEdit = PM_LineEdit( inPmGroupBox, label = "ui/actions/Properties Manager"\ "/Move_Start_Point.png", text = "Define 'from' and 'to' points", setAsDefault = False, ) self.startCoordLineEdit.setReadOnly(True) self.startCoordLineEdit.setEnabled(False)
class DnaSegment_PropertyManager( DnaOrCnt_PropertyManager): """ The DnaSegmenta_PropertyManager class provides a Property Manager for the DnaSegment_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 = "DnaSegment Properties" pmName = title iconPath = "ui/actions/Tools/Build Structures/DNA.png" def __init__( self, win, editCommand ): """ Constructor for the Build DNA property manager. """ #For model changed signal #@see: self.model_changed() and self._current_model_changed_params #for example use self._previous_model_changed_params = None #see self.connect_or_disconnect_signals for comment about this flag self.isAlreadyConnected = False self.isAlreadyDisconnected = False self.endPoint1 = V(0, 0, 0) self.endPoint2 = V(0, 0, 0) 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_CANCEL_BUTTON | \ PM_PREVIEW_BUTTON | \ PM_WHATS_THIS_BUTTON) msg = "Use resize handles to resize the segment. Drag any axis or sugar"\ " atom for translation or rotation about axis respectively. Dragging"\ " any bond will freely move the whole segment." self.updateMessage(msg) 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: change_connect = self.win.connect else: change_connect = self.win.disconnect _superclass.connect_or_disconnect_signals(self, isConnect) change_connect( self.numberOfBasePairsSpinBox, SIGNAL("valueChanged(int)"), self.numberOfBasesChanged ) change_connect( self.basesPerTurnDoubleSpinBox, SIGNAL("valueChanged(double)"), self.basesPerTurnChanged ) change_connect( self.duplexRiseDoubleSpinBox, SIGNAL("valueChanged(double)"), self.duplexRiseChanged ) change_connect(self.showCursorTextCheckBox, SIGNAL('stateChanged(int)'), self._update_state_of_cursorTextGroupBox) def model_changed(self): """ @see: DnaSegment_EditCommand.model_changed() @see: DnaSegment_EditCommand.hasResizableStructure() @see: self._current_model_changed_params() """ currentParams = self._current_model_changed_params() #Optimization. Return from the model_changed method if the #params are the same. if same_vals(currentParams, self._previous_model_changed_params): return isStructResizable, why_not = currentParams #update the self._previous_model_changed_params with this new param set. self._previous_model_changed_params = currentParams if not isStructResizable: #disable all widgets if self._pmGroupBox1.isEnabled(): self._pmGroupBox1.setEnabled(False) msg = redmsg("DnaSegment is not resizable. Reason: %s"%(why_not)) self.updateMessage(msg) else: if not self._pmGroupBox1.isEnabled(): self._pmGroupBox1.setEnabled(True) msg = "Use resize handles to resize the segment. Drag any axis or sugar"\ " atom for translation or rotation about axis respectively. Dragging"\ " any bond will freely move the whole segment." self.updateMessage(msg) def _current_model_changed_params(self): """ Returns a tuple containing the parameters that will be compared against the previously stored parameters. This provides a quick test to determine whether to do more things in self.model_changed() @see: self.model_changed() which calls this @see: self._previous_model_changed_params attr. """ params = None if self.editCommand: isStructResizable, why_not = self.editCommand.hasResizableStructure() params = (isStructResizable, why_not) return params def show(self): """ Show this property manager. Overrides EditCommand_PM.show() This method also retrives the name information from the editCommand's structure for its name line edit field. @see: DnaSegment_EditCommand.getStructureName() @see: self.close() """ _superclass.show(self) 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) _superclass.close(self) 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? """ numberOfBasePairs, \ dnaForm, \ dnaModel,\ basesPerTurn, \ duplexRise, \ endPoint1, \ endPoint2 , \ color = params if numberOfBasePairs is not None: self.numberOfBasePairsSpinBox.setValue(numberOfBasePairs) 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 endPoint1 is not None: self.endPoint1 = endPoint1 if endPoint2 is not None: self.endPoint2 = endPoint2 if color is not None: self._colorChooser.setColor(color) def getParameters(self): """ """ #See bug 2802 for details about the parameter #'number_of_basePairs_from_struct'. Basically it is used to check #if the structure got modified (e.g. because of undo) #The numberOfBases parameter obtained from the propMgr is given as a #separate parameter for the reasons mentioned in bug 2802 #-- Ninad 2008-04-12 number_of_basePairs_from_struct = None if self.editCommand.hasValidStructure(): number_of_basePairs_from_struct = self.editCommand.struct.getNumberOfBasePairs() numberOfBases = self.numberOfBasePairsSpinBox.value() dnaForm = self._conformation dnaModel = self.dnaModel basesPerTurn = self.basesPerTurn duplexRise = self.duplexRise color = self._colorChooser.getColor() return ( number_of_basePairs_from_struct, numberOfBases, dnaForm, dnaModel, basesPerTurn, duplexRise, self.endPoint1, self.endPoint2, color ) def numberOfBasesChanged( self, numberOfBases ): """ Slot for the B{Number of Bases" spinbox. """ duplexRise = self.duplexRiseDoubleSpinBox.value() # Update the Duplex Length lineEdit widget. text = str(getDuplexLength(self._conformation, numberOfBases, duplexRise = duplexRise)) \ + " Angstroms" self.duplexLengthLineEdit.setText(text) return def basesPerTurnChanged( self, basesPerTurn ): """ Slot for the B{Bases per turn} spinbox. """ self.basesPerTurn = basesPerTurn def duplexRiseChanged( self, rise ): """ Slot for the B{Rise} spinbox. """ self.duplexRise = rise 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 = "Segment name:", text = "", setAsDefault = False) # Strand Length (i.e. the number of bases) self.numberOfBasePairsSpinBox = \ PM_SpinBox( pmGroupBox, label = "Base pairs:", 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 ) # Duplex Length self.duplexLengthLineEdit = \ PM_LineEdit( pmGroupBox, label = "Duplex length: ", text = "0.0 Angstroms", setAsDefault = False) self.duplexLengthLineEdit.setDisabled(True) 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 , dnaSegmentEditCommand_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 base pairs", dnaSegmentEditCommand_cursorTextCheckBox_numberOfBasePairs_prefs_key), ("Duplex length", dnaSegmentEditCommand_cursorTextCheckBox_length_prefs_key), ("Number of basepairs to be changed", dnaSegmentEditCommand_cursorTextCheckBox_changedBasePairs_prefs_key) ] return params def _addWhatsThisText(self): """ Add what's this text. """ pass def _addToolTipText(self): """ Add Tooltip text """ pass
def _loadFreeDragRotateGroupBox(self, inPmGroupBox): """ Load widgets in the Free Drag Rotate group box, which is present within the Rotate groupbox. @param inPmGroupBox: The Free Drag Rotate group box in the Rotate group box. @type inPmGroupBox: L{PM_GroupBox} """ # Button list to create a toolbutton row. # Format: # - buttonId, # - buttonText , # - iconPath # - tooltip # - shortcut # - column BUTTON_LIST = [ ( "QToolButton", 1, "ROTATEDEFAULT", "ui/actions/Properties Manager/Rotate_Free.png", "", "F", 0 ), ( "QToolButton", 2, "ROTATEX", "ui/actions/Properties Manager/RotateX.png", "", "X", 1 ), ( "QToolButton", 3, "ROTATEY", "ui/actions/Properties Manager/RotateY.png", "", "Y", 2 ), ( "QToolButton", 4, "ROTATEZ", "ui/actions/Properties Manager/RotateZ.png", "", "Z", 3 ), ( "QToolButton", 5, "ROT_TRANS_ALONG_AXIS", "ui/actions/Properties Manager/translate+rotate-A.png", "", \ "A", 4 ) ] self.freeDragRotateButtonGroup = \ PM_ToolButtonRow( inPmGroupBox, title = "", buttonList = BUTTON_LIST, spanWidth = True, checkedId = 1, setAsDefault = True, ) self.rotateFreeButton = self.freeDragRotateButtonGroup.getButtonById(1) self.rotateXButton = self.freeDragRotateButtonGroup.getButtonById(2) self.rotateYButton = self.freeDragRotateButtonGroup.getButtonById(3) self.rotateZButton = self.freeDragRotateButtonGroup.getButtonById(4) self.rotAlongAxisButton = \ self.freeDragRotateButtonGroup.getButtonById(5) inPmGroupBox.setStyleSheet( self.freeDragRotateButtonGroup._getStyleSheet()) X_ROW_LABELS = [("QLabel", "Delta Theta X:", 0), ("QLabel", "", 1), ("QLabel", "0.00", 2), ("QLabel", "Degrees", 3)] Y_ROW_LABELS = [("QLabel", "Delta Theta Y:", 0), ("QLabel", "", 1), ("QLabel", "0.00", 2), ("QLabel", "Degrees", 3)] Z_ROW_LABELS = [("QLabel", "Delta Theta Z:", 0), ("QLabel", "", 1), ("QLabel", "0.00", 2), ("QLabel", "Degrees", 3)] self.rotateXLabelRow = PM_LabelRow( inPmGroupBox, title = "", labelList = X_ROW_LABELS ) self.deltaThetaX_lbl = self.rotateXLabelRow.labels[2] self.rotateYLabelRow = PM_LabelRow( inPmGroupBox, title = "", labelList = Y_ROW_LABELS ) self.deltaThetaY_lbl = self.rotateYLabelRow.labels[2] self.rotateZLabelRow = PM_LabelRow( inPmGroupBox, title = "", labelList = Z_ROW_LABELS ) self.deltaThetaZ_lbl = self.rotateZLabelRow.labels[2] self.rotateAboutPointButton = PM_ToolButton( inPmGroupBox, text = "Rotate selection about a point", iconPath = "ui/actions/Properties Manager"\ "/Rotate_Components.png", spanWidth = True ) self.rotateAboutPointButton.setCheckable(True) self.rotateAboutPointButton.setAutoRaise(True) self.rotateAboutPointButton.setToolButtonStyle( Qt.ToolButtonTextBesideIcon) self.rotateStartCoordLineEdit = PM_LineEdit( inPmGroupBox, label = "ui/actions/Properties Manager"\ "/Move_Start_Point.png", text = "Define 3 points", setAsDefault = False, ) self.rotateStartCoordLineEdit.setReadOnly(True) self.rotateStartCoordLineEdit.setEnabled(False)
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 Ui_MovePropertyManager(Command_PropertyManager): # The title that appears in the Property Manager header title = "Move" # The name of this Property Manager. This will be set to # the name of the PM_Dialog object via setObjectName(). pmName = title # The relative path to the PNG file that appears in the header iconPath = "ui/actions/Properties Manager/Translate_Components.png" # The title(s) that appear in the property manager header. # (these are changed depending on the active group box) translateTitle = "Translate" rotateTitle = "Rotate" # The full path to PNG file(s) that appears in the header. translateIconPath = "ui/actions/Properties Manager/Translate_Components.png" rotateIconPath = "ui/actions/Properties Manager/Rotate_Components.png" def __init__(self, command): _superclass.__init__(self, command) self.showTopRowButtons(PM_DONE_BUTTON | PM_WHATS_THIS_BUTTON) def _addGroupBoxes(self): """ Add groupboxes to the Property Manager dialog. """ self.translateGroupBox = PM_GroupBox( self, title = "Translate", connectTitleButton = False) self.translateGroupBox.titleButton.setShortcut('T') self._loadTranslateGroupBox(self.translateGroupBox) self.rotateGroupBox = PM_GroupBox( self, title = "Rotate", connectTitleButton = False) self.rotateGroupBox.titleButton.setShortcut('R') self._loadRotateGroupBox(self.rotateGroupBox) self.translateGroupBox.collapse() self.rotateGroupBox.collapse() # == Begin Translate Group Box ===================== def _loadTranslateGroupBox(self, inPmGroupBox): """ Load widgets in the Translate group box. @param inPmGroupBox: The Translate group box in the PM @type inPmGroupBox: L{PM_GroupBox} """ translateChoices = [ "Free Drag", "By Delta XYZ", "To XYZ Position" ] self.translateComboBox = \ PM_ComboBox( inPmGroupBox, label = '', choices = translateChoices, index = 0, setAsDefault = False, spanWidth = True ) self.freeDragTranslateGroupBox = PM_GroupBox( inPmGroupBox ) self._loadFreeDragTranslateGroupBox(self.freeDragTranslateGroupBox) self.byDeltaGroupBox = PM_GroupBox( inPmGroupBox ) self._loadByDeltaGroupBox(self.byDeltaGroupBox) self.toPositionGroupBox = PM_GroupBox( inPmGroupBox ) self._loadToPositionGroupBox(self.toPositionGroupBox) self.updateTranslateGroupBoxes(0) def _loadFreeDragTranslateGroupBox(self, inPmGroupBox): """ Load widgets in the Free Drag Translate group box, which is present within the Translate groupbox. @param inPmGroupBox: The Free Drag Translate group box in the Translate group box. @type inPmGroupBox: L{PM_GroupBox} """ # Button list to create a toolbutton row. # Format: # - buttonId, # - buttonText , # - iconPath # - tooltip # - shortcut # - column BUTTON_LIST = [ ( "QToolButton", 1, "MOVEDEFAULT", "ui/actions/Properties Manager/Move_Free.png", "", "F", 0), ( "QToolButton", 2, "TRANSX", "ui/actions/Properties Manager/TranslateX.png", "", "X", 1), ( "QToolButton", 3, "TRANSY", "ui/actions/Properties Manager/TranslateY.png", "", "Y", 2), ( "QToolButton", 4, "TRANSZ", "ui/actions/Properties Manager/TranslateZ.png", "", "Z", 3), ( "QToolButton", 5, "ROT_TRANS_ALONG_AXIS", "ui/actions/Properties Manager/translate+rotate-A.png", "", \ "A", 4) ] self.freeDragTranslateButtonGroup = \ PM_ToolButtonRow( inPmGroupBox, title = "", buttonList = BUTTON_LIST, checkedId = 1, setAsDefault = True, ) self.transFreeButton =self.freeDragTranslateButtonGroup.getButtonById(1) self.transXButton = self.freeDragTranslateButtonGroup.getButtonById(2) self.transYButton = self.freeDragTranslateButtonGroup.getButtonById(3) self.transZButton = self.freeDragTranslateButtonGroup.getButtonById(4) self.transAlongAxisButton = \ self.freeDragTranslateButtonGroup.getButtonById(5) self.moveFromToButton = PM_ToolButton( inPmGroupBox, text = "Translate from/to", iconPath = "ui/actions/Properties Manager"\ "/Translate_Components.png", spanWidth = True ) self.moveFromToButton.setCheckable(True) self.moveFromToButton.setAutoRaise(True) self.moveFromToButton.setToolButtonStyle( Qt.ToolButtonTextBesideIcon) self.startCoordLineEdit = PM_LineEdit( inPmGroupBox, label = "ui/actions/Properties Manager"\ "/Move_Start_Point.png", text = "Define 'from' and 'to' points", setAsDefault = False, ) self.startCoordLineEdit.setReadOnly(True) self.startCoordLineEdit.setEnabled(False) def _loadByDeltaGroupBox(self, inPmGroupBox): """ Load widgets in the translate By Delta group box, which is present within the Translate groupbox. @param inPmGroupBox: The Translate By Delta group box in the translate group box. @type inPmGroupBox: L{PM_GroupBox} """ self.moveDeltaXSpinBox = \ PM_DoubleSpinBox( inPmGroupBox, label = "ui/actions/Properties Manager/Delta_X.png", value = 0.0, setAsDefault = True, minimum = -100.0, maximum = 100.0, singleStep = 1.0, decimals = 3, suffix = ' Angstroms', spanWidth = False ) self.moveDeltaYSpinBox = \ PM_DoubleSpinBox( inPmGroupBox, label = "ui/actions/Properties Manager/Delta_Y.png", value = 0.0, setAsDefault = True, minimum = -100.0, maximum = 100.0, singleStep = 1.0, decimals = 3, suffix = ' Angstroms', spanWidth = False ) self.moveDeltaZSpinBox = \ PM_DoubleSpinBox( inPmGroupBox, label = "ui/actions/Properties Manager/Delta_Z.png", value = 0.0, setAsDefault = True, minimum = -100.0, maximum = 100.0, singleStep = 1.0, decimals = 3, suffix = ' Angstroms', spanWidth = False ) DELTA_BUTTONS = [ ("QToolButton",1, "Delta Plus", "ui/actions/Properties Manager/Move_Delta_Plus.png", "", "+", 0 ), ( "QToolButton", 2, "Delta Minus", "ui/actions/Properties Manager/Move_Delta_Minus.png", "", "-", 1 ) ] self.translateDeltaButtonRow = \ PM_ToolButtonRow( inPmGroupBox, title = "", buttonList = DELTA_BUTTONS, label = 'Translate:', isAutoRaise = True, isCheckable = False ) self.transDeltaPlusButton = \ self.translateDeltaButtonRow.getButtonById(1) self.transDeltaMinusButton = \ self.translateDeltaButtonRow.getButtonById(2) def _loadToPositionGroupBox(self, inPmGroupBox): """ Load widgets in the Translate To a given Position group box, which is present within the Translate groupbox. @param inPmGroupBox: Translate To Position group box in the Translate group box. @type inPmGroupBox: L{PM_GroupBox} """ self.toPositionspinboxes = PM_CoordinateSpinBoxes(inPmGroupBox) self.moveXSpinBox = self.toPositionspinboxes.xSpinBox self.moveYSpinBox = self.toPositionspinboxes.ySpinBox self.moveZSpinBox = self.toPositionspinboxes.zSpinBox self.moveAbsoluteButton = \ PM_PushButton( inPmGroupBox, label = "", text = "Move Selection", spanWidth = True ) # == Begin Rotate Group Box ===================== def _loadRotateGroupBox(self, inPmGroupBox): """ Load widgets in the Rotate group box, @param inPmGroupBox: The Rotate GroupBox in the PM @type inPmGroupBox: L{PM_GroupBox} """ rotateChoices = [ "Free Drag", "By Specified Angle"] self.rotateComboBox = \ PM_ComboBox( inPmGroupBox, label = '', choices = rotateChoices, index = 0, setAsDefault = False, spanWidth = True ) self.rotateAsUnitCB = \ PM_CheckBox( inPmGroupBox, text = 'Rotate as a unit' , widgetColumn = 0, state = Qt.Checked ) self.freeDragRotateGroupBox = PM_GroupBox( inPmGroupBox ) self._loadFreeDragRotateGroupBox(self.freeDragRotateGroupBox) self.bySpecifiedAngleGroupBox = PM_GroupBox( inPmGroupBox ) self._loadBySpecifiedAngleGroupBox(self.bySpecifiedAngleGroupBox) self.updateRotateGroupBoxes(0) def _loadFreeDragRotateGroupBox(self, inPmGroupBox): """ Load widgets in the Free Drag Rotate group box, which is present within the Rotate groupbox. @param inPmGroupBox: The Free Drag Rotate group box in the Rotate group box. @type inPmGroupBox: L{PM_GroupBox} """ # Button list to create a toolbutton row. # Format: # - buttonId, # - buttonText , # - iconPath # - tooltip # - shortcut # - column BUTTON_LIST = [ ( "QToolButton", 1, "ROTATEDEFAULT", "ui/actions/Properties Manager/Rotate_Free.png", "", "F", 0 ), ( "QToolButton", 2, "ROTATEX", "ui/actions/Properties Manager/RotateX.png", "", "X", 1 ), ( "QToolButton", 3, "ROTATEY", "ui/actions/Properties Manager/RotateY.png", "", "Y", 2 ), ( "QToolButton", 4, "ROTATEZ", "ui/actions/Properties Manager/RotateZ.png", "", "Z", 3 ), ( "QToolButton", 5, "ROT_TRANS_ALONG_AXIS", "ui/actions/Properties Manager/translate+rotate-A.png", "", \ "A", 4 ) ] self.freeDragRotateButtonGroup = \ PM_ToolButtonRow( inPmGroupBox, title = "", buttonList = BUTTON_LIST, spanWidth = True, checkedId = 1, setAsDefault = True, ) self.rotateFreeButton = self.freeDragRotateButtonGroup.getButtonById(1) self.rotateXButton = self.freeDragRotateButtonGroup.getButtonById(2) self.rotateYButton = self.freeDragRotateButtonGroup.getButtonById(3) self.rotateZButton = self.freeDragRotateButtonGroup.getButtonById(4) self.rotAlongAxisButton = \ self.freeDragRotateButtonGroup.getButtonById(5) inPmGroupBox.setStyleSheet( self.freeDragRotateButtonGroup._getStyleSheet()) X_ROW_LABELS = [("QLabel", "Delta Theta X:", 0), ("QLabel", "", 1), ("QLabel", "0.00", 2), ("QLabel", "Degrees", 3)] Y_ROW_LABELS = [("QLabel", "Delta Theta Y:", 0), ("QLabel", "", 1), ("QLabel", "0.00", 2), ("QLabel", "Degrees", 3)] Z_ROW_LABELS = [("QLabel", "Delta Theta Z:", 0), ("QLabel", "", 1), ("QLabel", "0.00", 2), ("QLabel", "Degrees", 3)] self.rotateXLabelRow = PM_LabelRow( inPmGroupBox, title = "", labelList = X_ROW_LABELS ) self.deltaThetaX_lbl = self.rotateXLabelRow.labels[2] self.rotateYLabelRow = PM_LabelRow( inPmGroupBox, title = "", labelList = Y_ROW_LABELS ) self.deltaThetaY_lbl = self.rotateYLabelRow.labels[2] self.rotateZLabelRow = PM_LabelRow( inPmGroupBox, title = "", labelList = Z_ROW_LABELS ) self.deltaThetaZ_lbl = self.rotateZLabelRow.labels[2] self.rotateAboutPointButton = PM_ToolButton( inPmGroupBox, text = "Rotate selection about a point", iconPath = "ui/actions/Properties Manager"\ "/Rotate_Components.png", spanWidth = True ) self.rotateAboutPointButton.setCheckable(True) self.rotateAboutPointButton.setAutoRaise(True) self.rotateAboutPointButton.setToolButtonStyle( Qt.ToolButtonTextBesideIcon) self.rotateStartCoordLineEdit = PM_LineEdit( inPmGroupBox, label = "ui/actions/Properties Manager"\ "/Move_Start_Point.png", text = "Define 3 points", setAsDefault = False, ) self.rotateStartCoordLineEdit.setReadOnly(True) self.rotateStartCoordLineEdit.setEnabled(False) def _loadBySpecifiedAngleGroupBox(self, inPmGroupBox): """ Load widgets in the Rotate By Specified Angle group box, which is present within the Rotate groupbox. @param inPmGroupBox: Rotate By Specified Angle group box in the Rotate group box. @type inPmGroupBox: L{PM_GroupBox} """ # Button list to create a toolbutton row. # Format: # - buttonId, # - buttonText , # - iconPath # - tooltip # - shortcut # - column BUTTON_LIST = [ ( "QToolButton", 1, "ROTATEX", "ui/actions/Properties Manager/RotateX.png", "Rotate about X axis", "X", 0 ), ( "QToolButton", 2, "ROTATEY", "ui/actions/Properties Manager/RotateY.png", "Rotate about Y axis", "Y", 1 ), ( "QToolButton", 3, "ROTATEZ", "ui/actions/Properties Manager/RotateZ.png", "Rotate about Z axis","Z", 2 ), ] self.rotateAroundAxisButtonRow = \ PM_ToolButtonRow( inPmGroupBox, title = "", buttonList = BUTTON_LIST, alignment = 'Right', label = 'Rotate Around:' ) self.rotXaxisButton = \ self.rotateAroundAxisButtonRow.getButtonById(1) self.rotYaxisButton = \ self.rotateAroundAxisButtonRow.getButtonById(2) self.rotZaxisButton = \ self.rotateAroundAxisButtonRow.getButtonById(3) self.rotateThetaSpinBox = \ PM_DoubleSpinBox(inPmGroupBox, label = "Rotate By:", value = 0.0, setAsDefault = True, minimum = 0, maximum = 360.0, singleStep = 1.0, decimals = 2, suffix = ' Degrees') THETA_BUTTONS = [ ( "QToolButton", 1, "Theta Plus", "ui/actions/Properties Manager/Move_Theta_Plus.png", "", "+", 0 ), ( "QToolButton", 2, "Theta Minus", "ui/actions/Properties Manager/Move_Theta_Minus.png", "", "-", 1 ) ] self.rotateThetaButtonRow = \ PM_ToolButtonRow( inPmGroupBox, title = "", buttonList = THETA_BUTTONS, label = 'Direction:', isAutoRaise = True, isCheckable = False ) self.rotateThetaPlusButton = self.rotateThetaButtonRow.getButtonById(1) self.rotateThetaMinusButton = self.rotateThetaButtonRow.getButtonById(2) # == End Rotate Group Box ===================== # == Slots for Translate group box def _hideAllTranslateGroupBoxes(self): """ Hides all Translate group boxes. """ self.toPositionGroupBox.hide() self.byDeltaGroupBox.hide() self.freeDragTranslateGroupBox.hide() def updateTranslateGroupBoxes(self, id): """ Update the translate group boxes displayed based on the translate option selected. @param id: Integer value corresponding to the combobox item in the Translate group box. @type id: int """ self._hideAllTranslateGroupBoxes() if id is 0: self.freeDragTranslateGroupBox.show() if id is 1: self.byDeltaGroupBox.show() if id is 2: self.toPositionGroupBox.show() self.updateMessage() def changeMoveOption(self, button): """ Subclasses should reimplement this method. @param button: QToolButton that decides the type of translate operation to be set. @type button: QToolButton L{http://doc.trolltech.com/4.2/qtoolbutton.html} @see: B{MovePropertyManager.changeMoveOption} which overrides this method """ pass # == Slots for Rotate group box def updateRotateGroupBoxes(self, id): """ Update the translate group boxes displayed based on the translate option selected. @param id: Integer value corresponding to the combobox item in the Rotate group box. @type id: int """ if id is 0: self.bySpecifiedAngleGroupBox.hide() self.freeDragRotateGroupBox.show() if id is 1: self.freeDragRotateGroupBox.hide() self.bySpecifiedAngleGroupBox.show() self.updateMessage() def changeRotateOption(self, button): """ Subclasses should reimplement this method. @param button: QToolButton that decides the type of rotate operation to be set. @type button: QToolButton L{http://doc.trolltech.com/4.2/qtoolbutton.html} @see: B{MovePropertyManage.changeRotateOption} which overrides this method """ pass def _addWhatsThisText(self): """ What's This text for some of the widgets in this Property Manager. """ from ne1_ui.WhatsThisText_for_PropertyManagers import whatsThis_MovePropertyManager whatsThis_MovePropertyManager(self) def _addToolTipText(self): """ Tool Tip text for widgets in this Property Manager. """ from ne1_ui.ToolTipText_for_PropertyManagers import ToolTip_MovePropertyManager ToolTip_MovePropertyManager(self)
class InsertNanotube_PropertyManager(DnaOrCnt_PropertyManager): """ The InsertNanotube_PropertyManager class provides a Property Manager for the B{Build > Nanotube > CNT} 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 = "Insert Nanotube" pmName = title iconPath = "ui/actions/Tools/Build Structures/InsertNanotube.png" def __init__(self, win, editCommand): """ Constructor for the Nanotube property manager. """ self.endPoint1 = None self.endPoint2 = None self.nanotube = Nanotube() # A 5x5 CNT. _superclass.__init__(self, win, editCommand) self.showTopRowButtons( PM_DONE_BUTTON | \ PM_CANCEL_BUTTON | \ PM_WHATS_THIS_BUTTON) 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: change_connect = self.win.connect else: change_connect = self.win.disconnect change_connect(self.ntTypeComboBox, SIGNAL("currentIndexChanged(const QString&)"), self._ntTypeComboBoxChanged) change_connect(self.chiralityNSpinBox, SIGNAL("valueChanged(int)"), self._chiralityFixup) change_connect(self.chiralityMSpinBox, SIGNAL("valueChanged(int)"), self._chiralityFixup) change_connect(self.endingsComboBox, SIGNAL("currentIndexChanged(const QString&)"), self._endingsComboBoxChanged) # This spin box is currently hidden. change_connect(self.bondLengthDoubleSpinBox, SIGNAL("valueChanged(double)"), self._bondLengthChanged) change_connect(self.showCursorTextCheckBox, SIGNAL('stateChanged(int)'), self._update_state_of_cursorTextGroupBox) def ok_btn_clicked(self): """ Slot for the OK button """ if self.editCommand: self.editCommand.preview_or_finalize_structure(previewing=False) ##env.history.message(self.editCommand.logMessage) self.win.toolsDone() def cancel_btn_clicked(self): """ Slot for the Cancel button. """ if self.editCommand: self.editCommand.cancelStructure() self.win.toolsCancel() def _update_widgets_in_PM_before_show(self): """ Update various widgets in this Property manager. Overrides MotorPropertyManager._update_widgets_in_PM_before_show. The various widgets , (e.g. spinboxes) will get values from the structure for which this propMgr is constructed for (self.editcCntroller.struct) @see: MotorPropertyManager._update_widgets_in_PM_before_show @see: self.show where it is called. """ pass def getFlyoutActionList(self): """ Returns custom actionlist that will be used in a specific mode or editing a feature etc Example: while in movie mode, the _createFlyoutToolBar method calls this. """ #'allActionsList' returns all actions in the flyout toolbar #including the subcontrolArea actions allActionsList = [] #Action List for subcontrol Area buttons. #In this mode there is really no subcontrol area. #We will treat subcontrol area same as 'command area' #(subcontrol area buttons will have an empty list as their command area #list). We will set the Comamnd Area palette background color to the #subcontrol area. subControlAreaActionList = [] self.exitEditCommandAction.setChecked(True) subControlAreaActionList.append(self.exitEditCommandAction) separator = QAction(self.w) separator.setSeparator(True) subControlAreaActionList.append(separator) allActionsList.extend(subControlAreaActionList) #Empty actionlist for the 'Command Area' commandActionLists = [] #Append empty 'lists' in 'commandActionLists equal to the #number of actions in subControlArea for i in range(len(subControlAreaActionList)): lst = [] commandActionLists.append(lst) params = (subControlAreaActionList, commandActionLists, allActionsList) return params def _addGroupBoxes(self): """ Add the Insert Nanotube Property Manager group boxes. """ self._pmGroupBox1 = PM_GroupBox(self, title="Endpoints") self._loadGroupBox1(self._pmGroupBox1) self._pmGroupBox1.hide() self._pmGroupBox2 = PM_GroupBox(self, title="Parameters") self._loadGroupBox2(self._pmGroupBox2) self._displayOptionsGroupBox = PM_GroupBox(self, title="Display Options") self._loadDisplayOptionsGroupBox(self._displayOptionsGroupBox) self._pmGroupBox3 = PM_GroupBox(self, title="Nanotube Distortion") self._loadGroupBox3(self._pmGroupBox3) self._pmGroupBox3.hide() #@ Temporary. self._pmGroupBox4 = PM_GroupBox(self, title="Multi-Walled CNTs") self._loadGroupBox4(self._pmGroupBox4) self._pmGroupBox4.hide() #@ Temporary. self._pmGroupBox5 = PM_GroupBox(self, title="Advanced Options") self._loadGroupBox5(self._pmGroupBox5) self._pmGroupBox5.hide() #@ Temporary. def _loadGroupBox1(self, pmGroupBox): """ Load widgets in group box 1. """ #Following toolbutton facilitates entering a temporary NanotubeLineMode #to create a CNT using endpoints of the specified line. self.specifyCntLineButton = PM_ToolButton( pmGroupBox, text="Specify Endpoints", iconPath="ui/actions/Properties Manager/Pencil.png", spanWidth=True) self.specifyCntLineButton.setCheckable(True) self.specifyCntLineButton.setAutoRaise(True) self.specifyCntLineButton.setToolButtonStyle( Qt.ToolButtonTextBesideIcon) #EndPoint1 and endPoint2 coordinates. These widgets are hidden # as of 2007- 12 - 05 self._endPoint1SpinBoxes = PM_CoordinateSpinBoxes(pmGroupBox, label="End Point 1") self.x1SpinBox = self._endPoint1SpinBoxes.xSpinBox self.y1SpinBox = self._endPoint1SpinBoxes.ySpinBox self.z1SpinBox = self._endPoint1SpinBoxes.zSpinBox self._endPoint2SpinBoxes = PM_CoordinateSpinBoxes(pmGroupBox, label="End Point 2") self.x2SpinBox = self._endPoint2SpinBoxes.xSpinBox self.y2SpinBox = self._endPoint2SpinBoxes.ySpinBox self.z2SpinBox = self._endPoint2SpinBoxes.zSpinBox self._endPoint1SpinBoxes.hide() self._endPoint2SpinBoxes.hide() def _loadGroupBox2(self, pmGroupBox): """ Load widgets in group box 2. """ _ntTypeChoices = ['Carbon', 'Boron Nitride'] self.ntTypeComboBox = \ PM_ComboBox( pmGroupBox, label = "Type:", choices = _ntTypeChoices, setAsDefault = True) self.ntRiseDoubleSpinBox = \ PM_DoubleSpinBox( pmGroupBox, label = "Rise:", value = self.nanotube.getRise(), setAsDefault = True, minimum = 2.0, maximum = 4.0, decimals = 3, singleStep = 0.01 ) self.ntRiseDoubleSpinBox.hide() # Nanotube Length self.ntLengthLineEdit = \ PM_LineEdit( pmGroupBox, label = "Nanotube Length: ", text = "0.0 Angstroms", setAsDefault = False) self.ntLengthLineEdit.setDisabled(True) self.ntLengthLineEdit.hide() # Nanotube diameter self.ntDiameterLineEdit = \ PM_LineEdit( pmGroupBox, label = "Diameter: ", setAsDefault = False) self.ntDiameterLineEdit.setDisabled(True) self.updateNanotubeDiameter() self.chiralityNSpinBox = \ PM_SpinBox( pmGroupBox, label = "Chirality (n):", value = self.nanotube.getChiralityN(), minimum = 2, maximum = 100, setAsDefault = True ) self.chiralityMSpinBox = \ PM_SpinBox( pmGroupBox, label = "Chirality (m):", value = self.nanotube.getChiralityM(), minimum = 0, maximum = 100, setAsDefault = True ) # How about having user prefs for CNT and BNNT bond lengths? # I'm guessing that if the user wants to set these values, they will # do it once and would like those bond length values persist forever. # Need to discuss with others to determine if this spinbox comes out. # --Mark 2008-03-29 self.bondLengthDoubleSpinBox = \ PM_DoubleSpinBox( pmGroupBox, label = "Bond length:", value = self.nanotube.getBondLength(), setAsDefault = True, minimum = 1.0, maximum = 3.0, singleStep = 0.1, decimals = 3, suffix = " Angstroms" ) #self.bondLengthDoubleSpinBox.hide() endingChoices = ["Hydrogen", "None"] # Removed:, "Nitrogen"] self.endingsComboBox= \ PM_ComboBox( pmGroupBox, label = "Endings:", choices = endingChoices, index = 0, setAsDefault = True, spanWidth = False ) def _loadGroupBox3(self, inPmGroupBox): """ Load widgets in group box 3. """ self.zDistortionDoubleSpinBox = \ PM_DoubleSpinBox( inPmGroupBox, label = "Z-distortion:", value = 0.0, setAsDefault = True, minimum = 0.0, maximum = 10.0, singleStep = 0.1, decimals = 3, suffix = " Angstroms" ) self.xyDistortionDoubleSpinBox = \ PM_DoubleSpinBox( inPmGroupBox, label = "XY-distortion:", value = 0.0, setAsDefault = True, minimum = 0.0, maximum = 2.0, singleStep = 0.1, decimals = 3, suffix = " Angstroms" ) self.twistSpinBox = \ PM_SpinBox( inPmGroupBox, label = "Twist:", value = 0, setAsDefault = True, minimum = 0, maximum = 100, # What should maximum be? suffix = " deg/A" ) self.bendSpinBox = \ PM_SpinBox( inPmGroupBox, label = "Bend:", value = 0, setAsDefault = True, minimum = 0, maximum = 360, suffix = " deg" ) def _loadGroupBox4(self, inPmGroupBox): """ Load widgets in group box 4. """ # "Number of Nanotubes" SpinBox self.mwntCountSpinBox = \ PM_SpinBox( inPmGroupBox, label = "Number:", value = 1, setAsDefault = True, minimum = 1, maximum = 10, suffix = " nanotubes" ) self.mwntCountSpinBox.setSpecialValueText("SWNT") # "Spacing" lineedit. self.mwntSpacingDoubleSpinBox = \ PM_DoubleSpinBox( inPmGroupBox, label = "Spacing:", value = 2.46, setAsDefault = True, minimum = 1.0, maximum = 10.0, singleStep = 0.1, decimals = 3, suffix = " Angstroms" ) def _loadGroupBox5(self, pmGroupBox): """ Load widgets in group box 5. """ self._rubberbandLineGroupBox = PM_GroupBox(pmGroupBox, title='Rubber band Line:') ntLineChoices = ['Ladder'] self.ntRubberBandLineDisplayComboBox = \ PM_ComboBox( self._rubberbandLineGroupBox , label = " Display as:", choices = ntLineChoices, setAsDefault = True) self.lineSnapCheckBox = \ PM_CheckBox(self._rubberbandLineGroupBox , text = 'Enable line snap' , widgetColumn = 1, state = Qt.Checked ) 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, insertNanotubeEditCommand_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) ("Nanotube length", insertNanotubeEditCommand_cursorTextCheckBox_length_prefs_key ), ("Angle", insertNanotubeEditCommand_cursorTextCheckBox_angle_prefs_key ) ] return params def _addToolTipText(self): """ Tool Tip text for widgets in the Insert Nanotube Property Manager. """ pass def _setEndPoints(self): """ Set the two endpoints of the nanotube using the values from the X, Y, Z coordinate spinboxes in the property manager. @note: The group box containing the 2 sets of XYZ spin boxes are currently hidden. """ # First endpoint (origin) of nanotube x1 = self.x1SpinBox.value() y1 = self.y1SpinBox.value() z1 = self.z1SpinBox.value() # Second endpoint (direction vector/axis) of nanotube. x2 = self.x2SpinBox.value() y2 = self.y2SpinBox.value() z2 = self.z2SpinBox.value() if not self.endPoint1: self.endPoint1 = V(x1, y1, z1) if not self.endPoint2: self.endPoint2 = V(x2, y2, z2) self.nanotube.setEndPoints(self.endPoint1, self.endPoint2) # Need arg "recompute=True", which will recompute the second # endpoint (endPoint2) using the nanotube rise. def getParameters(self): """ Return the parameters from this property manager to be used to create the nanotube. @return: A nanotube instance with its attrs set to the current parameters in the property manager. @rtype: L{Nanotube} @see: L{InsertNanotube_EditCommand._gatherParameters} where this is used """ self._setEndPoints() return (self.nanotube) def _ntTypeComboBoxChanged(self, type): """ Slot for the Type combobox. It is called whenever the Type choice is changed. @param inIndex: The new index. @type inIndex: int """ self.nanotube.setType(str(type)) print "Bond Length =", self.nanotube.getBondLength() self.bondLengthDoubleSpinBox.setValue(self.nanotube.getBondLength()) #self.bondLengthDoubleSpinBox.setValue(ntBondLengths[inIndex]) def _bondLengthChanged(self, bondLength): """ Slot for the B{Bond Length} spinbox. """ self.nanotube.setBondLength(bondLength) self.updateNanotubeDiameter() return def _chiralityFixup(self, spinBoxValueJunk=None): """ Slot for several validators for different parameters. This gets called whenever the user changes the n, m chirality values. @param spinBoxValueJunk: This is the Spinbox value from the valueChanged signal. It is not used. We just want to know that the spinbox value has changed. @type spinBoxValueJunk: double or None """ _n, _m = self.nanotube.setChirality(self.chiralityNSpinBox.value(), self.chiralityMSpinBox.value()) #self.n, self.m = self.nanotube.getChirality() self.connect_or_disconnect_signals(isConnect=False) self.chiralityNSpinBox.setValue(_n) self.chiralityMSpinBox.setValue(_m) self.connect_or_disconnect_signals(isConnect=True) self.updateNanotubeDiameter() def updateNanotubeDiameter(self): """ Update the nanotube Diameter lineEdit widget. """ diameterText = "%-7.4f Angstroms" % (self.nanotube.getDiameter()) self.ntDiameterLineEdit.setText(diameterText) # ntRiseDoubleSpinBox is currently hidden. self.ntRiseDoubleSpinBox.setValue(self.nanotube.getRise()) def _endingsComboBoxChanged(self, endings): """ Slot for the B{Ending} combobox. @param endings: The option's text. @type endings: string """ self.nanotube.setEndings(str(endings)) return def _addWhatsThisText(self): """ What's This text for widgets in this Property Manager. """ whatsThis_InsertNanotube_PropertyManager(self) return
def _loadMenuWidgets(self): """ Load the various menu widgets (e.g. Open, save sequence options, Find and replace widgets etc. """ self.loadSequenceButton = PM_ToolButton( self, iconPath = "ui/actions/Properties Manager/Open.png") self.saveSequenceButton = PM_ToolButton( self, iconPath = "ui/actions/Properties Manager/Save_Strand_Sequence.png") self.loadSequenceButton.setAutoRaise(True) self.saveSequenceButton.setAutoRaise(True) # Hide load and save buttons until they are implemented. -Mark 2008-12-20. self.loadSequenceButton.hide() self.saveSequenceButton.hide() #Find and replace widgets -- self.findLineEdit = \ PM_LineEdit( self, label = "", spanWidth = False) self.findLineEdit.setMaximumWidth(60) self.replaceLineEdit = \ PM_LineEdit( self, label = " Replace:", spanWidth = False) self.replaceLineEdit.setMaximumWidth(60) self.findOptionsToolButton = PM_ToolButton(self) self.findOptionsToolButton.setMaximumWidth(12) self.findOptionsToolButton.setAutoRaise(True) self.findOptionsToolButton.setPopupMode(QToolButton.MenuButtonPopup) self._setFindOptionsToolButtonMenu() self.findNextToolButton = PM_ToolButton( self, iconPath = "ui/actions/Properties Manager/Find_Next.png") self.findNextToolButton.setAutoRaise(True) self.findPreviousToolButton = PM_ToolButton( self, iconPath = "ui/actions/Properties Manager/Find_Previous.png") self.findPreviousToolButton.setAutoRaise(True) self.replacePushButton = PM_PushButton(self, text = "Replace") # Hide Replace widgets until we add support for transmuting residues. # Mark 2008-12-19 #self.replaceLabel.hide() self.replacePushButton.hide() self.replaceLineEdit.hide() self.warningSign = QLabel(self) self.warningSign.setPixmap( getpixmap('ui/actions/Properties Manager/Warning.png')) self.warningSign.hide() self.phraseNotFoundLabel = QLabel(self) self.phraseNotFoundLabel.setText("Sequence Not Found") self.phraseNotFoundLabel.hide() #Widgets to include in the widget row. widgetList = [('PM_ToolButton', self.loadSequenceButton, 0), ('PM_ToolButton', self.saveSequenceButton, 1), ('QLabel', " Find:", 4), ('PM_LineEdit', self.findLineEdit, 5), ('PM_ToolButton', self.findOptionsToolButton, 6), ('PM_ToolButton', self.findPreviousToolButton, 7), ('PM_ToolButton', self.findNextToolButton, 8), #('PM_Label', self.replaceLabel, 9), ('PM_TextEdit', self.replaceLineEdit, 9), ('PM_PushButton', self.replacePushButton, 10), ('PM_Label', self.warningSign, 11), ('PM_Label', self.phraseNotFoundLabel, 12), ('QSpacerItem', 5, 5, 13) ] widgetRow = PM_WidgetRow(self, title = '', widgetList = widgetList, label = "", spanWidth = True ) return
def _loadMenuWidgets(self): """ Load the various menu widgets (e.g. Open, save sequence options, Find and replace widgets etc. """ #Note: Find and replace widgets might be moved to their own class. self.loadSequenceButton = PM_ToolButton( self, iconPath="ui/actions/Properties Manager/Open.png") self.saveSequenceButton = PM_ToolButton( self, iconPath="ui/actions/Properties Manager/Save_Strand_Sequence.png") self.loadSequenceButton.setAutoRaise(True) self.saveSequenceButton.setAutoRaise(True) # Only supporting 5' to 3' direction until bug 2956 is fixed. # Mark 2008-12-19 editDirectionChoices = ["5' to 3'"] # , "3' to 5'"] self.baseDirectionChoiceComboBox = \ PM_ComboBox( self, choices = editDirectionChoices, index = 0, spanWidth = False ) #Find and replace widgets -- self.findLineEdit = \ PM_LineEdit( self, label = "", spanWidth = False) self.findLineEdit.setMaximumWidth(60) self.replaceLineEdit = \ PM_LineEdit( self, label = "", spanWidth = False) self.replaceLineEdit.setMaximumWidth(60) self.findOptionsToolButton = PM_ToolButton(self) self.findOptionsToolButton.setMaximumWidth(12) self.findOptionsToolButton.setAutoRaise(True) self.findOptionsToolButton.setPopupMode(QToolButton.MenuButtonPopup) self._setFindOptionsToolButtonMenu() self.findNextToolButton = PM_ToolButton( self, iconPath="ui/actions/Properties Manager/Find_Next.png") self.findNextToolButton.setAutoRaise(True) self.findPreviousToolButton = PM_ToolButton( self, iconPath="ui/actions/Properties Manager/Find_Previous.png") self.findPreviousToolButton.setAutoRaise(True) self.replacePushButton = PM_PushButton(self, text="Replace") self.warningSign = QLabel(self) self.warningSign.setPixmap( getpixmap('ui/actions/Properties Manager/Warning.png')) self.warningSign.hide() self.phraseNotFoundLabel = QLabel(self) self.phraseNotFoundLabel.setText("Sequence Not Found") self.phraseNotFoundLabel.hide() # NOTE: Following needs cleanup in the PM_WidgetRow/ PM_WidgetGrid # but this explanation is sufficient until thats done -- # When the widget type starts with the word 'PM_' , the # PM_WidgetRow treats it as a well defined widget and thus doesn't try # to create a QWidget object (or its subclasses) # This is the reason why qLabels such as self.warningSign and # self.phraseNotFoundLabel are defined as PM_Labels and not 'QLabels' # If they were defined as 'QLabel'(s) then PM_WidgetRow would have # recreated the label. Since we want to show/hide the above mentioned # labels (and if they were recreated as mentioned above), # we would have needed to define those something like this: # self.phraseNotFoundLabel = widgetRow._widgetList[-2] #Cleanup in PM_widgetGrid could be to check if the widget starts with #'Q' instead of 'PM_' #Widgets to include in the widget row. widgetList = [('PM_ToolButton', self.loadSequenceButton, 0), ('PM_ToolButton', self.saveSequenceButton, 1), ('QLabel', " Sequence direction:", 2), ('PM_ComboBox', self.baseDirectionChoiceComboBox, 3), ('QLabel', " Find:", 4), ('PM_LineEdit', self.findLineEdit, 5), ('PM_ToolButton', self.findOptionsToolButton, 6), ('PM_ToolButton', self.findPreviousToolButton, 7), ('PM_ToolButton', self.findNextToolButton, 8), ('QLabel', " Replace:", 9), ('PM_TextEdit', self.replaceLineEdit, 10), ('PM_PushButton', self.replacePushButton, 11), ('PM_Label', self.warningSign, 12), ('PM_Label', self.phraseNotFoundLabel, 13), ('QSpacerItem', 5, 5, 14)] widgetRow = PM_WidgetRow(self, title='', widgetList=widgetList, label="", spanWidth=True) return
class Ui_CookiePropertyManager(PM_Dialog): """ The Ui_CookiePropertyManager class defines UI elements for the Property Manager of the B{Crystal mode}. @ivar title: The title that appears in the property manager header. @type title: str @ivar pmName: The name of this property manager. This is used to set the name of the PM_Dialog object via setObjectName(). @type name: str @ivar iconPath: The relative path to the PNG file that contains a 22 x 22 icon image that appears in the PM header. @type iconPath: str """ # <title> - the title that appears in the property manager header. title = "Build Crystal" # <iconPath> - full path to PNG file that appears in the header. # The name of this Property Manager. This will be set to # the name of the PM_Dialog object via setObjectName(). pmName = title iconPath = "ui/actions/Tools/Build Structures/Build Crystal.png" def __init__(self, parentMode): """ Constructor for the B{Crystal} property manager class that defines its UI. @param parentMode: The parent mode where this Property Manager is used @type parentMode: L{cookieMode} """ self.parentMode = parentMode self.w = self.parentMode.w self.win = self.parentMode.w self.pw = self.parentMode.pw self.o = self.parentMode.o PM_Dialog.__init__(self, self.pmName, self.iconPath, self.title) self.showTopRowButtons( PM_DONE_BUTTON | \ PM_CANCEL_BUTTON | \ PM_WHATS_THIS_BUTTON) msg = '' self.MessageGroupBox.insertHtmlMessage(msg, setAsDefault=False) def _addGroupBoxes(self): """ Add various group boxes to the Property manager. """ self._addCrystalSpecsGroupbox() self._addLayerPropertiesGroupBox() self._addDisplayOptionsGroupBox() self._addAdvancedOptionsGroupBox() def _addCrystalSpecsGroupbox(self): """ Add 'Crystal groupbox' to the PM """ self.crystalSpecsGroupBox = \ PM_GroupBox(self, title = "Crystal Specifications") self._loadCrystalSpecsGroupBox(self.crystalSpecsGroupBox) def _addLayerPropertiesGroupBox(self): """ Add 'Layer Properties' groupbox to the PM """ self.layerPropertiesGroupBox = \ PM_GroupBox(self, title = "Layer Properties") self._loadLayerPropertiesGroupBox(self.layerPropertiesGroupBox) def _addAdvancedOptionsGroupBox(self): """ Add 'Advanced Options' groupbox """ self.advancedOptionsGroupBox = \ PM_GroupBox( self, title = "Advanced Options" ) self._loadAdvancedOptionsGroupBox(self.advancedOptionsGroupBox) def _addDisplayOptionsGroupBox(self): """ Add 'Display Options' groupbox """ self.displayOptionsGroupBox = PM_GroupBox(self, title='Display Options') self._loadDisplayOptionsGroupBox(self.displayOptionsGroupBox) def _loadCrystalSpecsGroupBox(self, inPmGroupBox): """ Load widgets in the Crystal Specifications group box. @param inPmGroupBox: The Crystal Specifications groupbox in the PM @type inPmGroupBox: L{PM_GroupBox} """ latticeChoices = ["Diamond", "Lonsdaleite"] self.latticeCBox = \ PM_ComboBox( inPmGroupBox, label = 'Lattice:', labelColumn = 0, choices = latticeChoices, index = 0, setAsDefault = True, spanWidth = False ) # Button list to create a toolbutton row. # Format: # - buttonType, # - buttonId, # - buttonText , # - iconPath # - tooltip # - shortcut # - column BUTTON_LIST = [("QToolButton", 0, "Surface 100", "ui/actions/Properties Manager/Surface100.png", "Surface 100", "", 0), ("QToolButton", 1, "Surface 110", "ui/actions/Properties Manager/Surface110.png", "Surface 110", "", 1), ("QToolButton", 2, "Surface 111", "ui/actions/Properties Manager/Surface111.png", "Surface 110", "", 2)] self.gridOrientationButtonRow = \ PM_ToolButtonRow(inPmGroupBox, title = "", label = "Orientation:", buttonList = BUTTON_LIST, checkedId = 0, setAsDefault = True, spanWidth = False ) self.orientButtonGroup = self.gridOrientationButtonRow.buttonGroup self.surface100_btn = self.gridOrientationButtonRow.getButtonById(0) self.surface110_btn = self.gridOrientationButtonRow.getButtonById(1) self.surface111_btn = self.gridOrientationButtonRow.getButtonById(2) self.rotateGridByAngleSpinBox = \ PM_SpinBox( inPmGroupBox, label = "Rotate by: ", labelColumn = 0, value = 45, minimum = 0, maximum = 360, singleStep = 5, suffix = " degrees") GRID_ANGLE_BUTTONS = [ ("QToolButton", 0, "Anticlockwise", "ui/actions/Properties Manager/rotate_minus.png", "", "+", 0), ("QToolButton", 1, "Clockwise", "ui/actions/Properties Manager/rotate_plus.png", "", "-", 1) ] self.gridRotateButtonRow = \ PM_ToolButtonRow( inPmGroupBox, title = "", buttonList = GRID_ANGLE_BUTTONS, label = 'Rotate grid:', isAutoRaise = False, isCheckable = False ) self.rotGridAntiClockwiseButton = \ self.gridRotateButtonRow.getButtonById(0) self.rotGridClockwiseButton = \ self.gridRotateButtonRow.getButtonById(1) def _loadLayerPropertiesGroupBox(self, inPmGroupBox): """ Load widgets in the Layer Properties group box. @param inPmGroupBox: The Layer Properties groupbox in the PM @type inPmGroupBox: L{PM_GroupBox} """ self.currentLayerComboBox = \ PM_ComboBox( inPmGroupBox, index = 0, spanWidth = True ) self.addLayerButton = PM_PushButton(inPmGroupBox) self.addLayerButton.setIcon( geticon('ui/actions/Properties Manager/addlayer.png')) self.addLayerButton.setFixedSize(QSize(26, 26)) self.addLayerButton.setIconSize(QSize(22, 22)) # A widget list to create a widget row. # Format: # - Widget type, # - widget object, # - column firstRowWidgetList = [('PM_ComboBox', self.currentLayerComboBox, 1), ('PM_PushButton', self.addLayerButton, 2)] widgetRow = PM_WidgetRow( inPmGroupBox, title='', widgetList=firstRowWidgetList, label="Layer:", labelColumn=0, ) self.layerCellsSpinBox = \ PM_SpinBox( inPmGroupBox, label = "Lattice cells:", labelColumn = 0, value = 2, minimum = 1, maximum = 25 ) self.layerThicknessLineEdit = PM_LineEdit(inPmGroupBox, label="Thickness:", text="", setAsDefault=False, spanWidth=False) #self.layerThicknessLineEdit.setReadOnly(True) self.layerThicknessLineEdit.setDisabled(True) tooltip = "Thickness of layer in Angstroms" self.layerThicknessLineEdit.setToolTip(tooltip) def _loadAdvancedOptionsGroupBox(self, inPmGroupBox): """ Load widgets in the Advanced Options group box. @param inPmGroupBox: The Advanced Options box in the PM @type inPmGroupBox: L{PM_GroupBox} """ self.snapGridCheckBox = \ PM_CheckBox(inPmGroupBox, text = "Snap to grid", state = Qt.Checked ) tooltip = "Snap selection point to a nearest cell grid point." self.snapGridCheckBox.setToolTip(tooltip) self.freeViewCheckBox = \ PM_CheckBox(inPmGroupBox, text = "Enable free view", state = Qt.Unchecked ) def _loadDisplayOptionsGroupBox(self, inPmGroupBox): """ Load widgets in the Display Options groupbox. @param inPmGroupBox: The Display Options groupbox @type inPmGroupBox: L{PM_GroupBox} """ displayChoices = ['Tubes', 'Spheres'] self.dispModeComboBox = \ PM_ComboBox( inPmGroupBox, label = 'Display style:', choices = displayChoices, index = 0, setAsDefault = False, spanWidth = False ) self.gridLineCheckBox = PM_CheckBox(inPmGroupBox, text="Show grid lines", widgetColumn=0, state=Qt.Checked) self.fullModelCheckBox = PM_CheckBox(inPmGroupBox, text="Show model", widgetColumn=0, state=Qt.Unchecked) def _addWhatsThisText(self): """ What's This text for widgets in this Property Manager. @note: Many PM widgets are still missing their "What's This" text. """ from ne1_ui.WhatsThisText_for_PropertyManagers import whatsThis_CookiePropertyManager whatsThis_CookiePropertyManager(self) def _addToolTipText(self): """ What's Tool Tip text for widgets in this Property Manager. """ from ne1_ui.ToolTipText_for_PropertyManagers import ToolTip_CookiePropertyManager ToolTip_CookiePropertyManager(self)
def _loadFreeDragTranslateGroupBox(self, inPmGroupBox): """ Load widgets in the Free Drag Translate group box, which is present within the Translate groupbox. @param inPmGroupBox: The Free Drag Translate group box in the Translate group box. @type inPmGroupBox: L{PM_GroupBox} """ # Button list to create a toolbutton row. # Format: # - buttonId, # - buttonText , # - iconPath # - tooltip # - shortcut # - column BUTTON_LIST = [ ( "QToolButton", 1, "MOVEDEFAULT", "ui/actions/Properties Manager/Move_Free.png", "", "F", 0), ( "QToolButton", 2, "TRANSX", "ui/actions/Properties Manager/TranslateX.png", "", "X", 1), ( "QToolButton", 3, "TRANSY", "ui/actions/Properties Manager/TranslateY.png", "", "Y", 2), ( "QToolButton", 4, "TRANSZ", "ui/actions/Properties Manager/TranslateZ.png", "", "Z", 3), ( "QToolButton", 5, "ROT_TRANS_ALONG_AXIS", "ui/actions/Properties Manager/translate+rotate-A.png", "", \ "A", 4) ] self.freeDragTranslateButtonGroup = \ PM_ToolButtonRow( inPmGroupBox, title = "", buttonList = BUTTON_LIST, checkedId = 1, setAsDefault = True, ) self.transFreeButton = self.freeDragTranslateButtonGroup.getButtonById( 1) self.transXButton = self.freeDragTranslateButtonGroup.getButtonById(2) self.transYButton = self.freeDragTranslateButtonGroup.getButtonById(3) self.transZButton = self.freeDragTranslateButtonGroup.getButtonById(4) self.transAlongAxisButton = \ self.freeDragTranslateButtonGroup.getButtonById(5) self.moveFromToButton = PM_ToolButton( inPmGroupBox, text = "Translate from/to", iconPath = "ui/actions/Properties Manager"\ "/Translate_Components.png", spanWidth = True ) self.moveFromToButton.setCheckable(True) self.moveFromToButton.setAutoRaise(True) self.moveFromToButton.setToolButtonStyle(Qt.ToolButtonTextBesideIcon) self.startCoordLineEdit = PM_LineEdit( inPmGroupBox, label = "ui/actions/Properties Manager"\ "/Move_Start_Point.png", text = "Define 'from' and 'to' points", setAsDefault = False, ) self.startCoordLineEdit.setReadOnly(True) self.startCoordLineEdit.setEnabled(False)
def _loadMenuWidgets(self): """ Load the various menu widgets (e.g. Open, save sequence options, Find and replace widgets etc. """ #Note: Find and replace widgets might be moved to their own class. self.loadSequenceButton = PM_ToolButton( self, iconPath = "ui/actions/Properties Manager/Open.png") self.saveSequenceButton = PM_ToolButton( self, iconPath = "ui/actions/Properties Manager/Save_Strand_Sequence.png") self.loadSequenceButton.setAutoRaise(True) self.saveSequenceButton.setAutoRaise(True) editDirectionChoices = ["5' to 3'", "3' to 5'"] self.baseDirectionChoiceComboBox = \ PM_ComboBox( self, choices = editDirectionChoices, index = 0, spanWidth = False ) #Find and replace widgets -- self.findLineEdit = \ PM_LineEdit( self, label = "", spanWidth = False) self.findLineEdit.setMaximumWidth(60) self.replaceLineEdit = \ PM_LineEdit( self, label = "", spanWidth = False) self.replaceLineEdit.setMaximumWidth(60) self.findOptionsToolButton = PM_ToolButton(self) self.findOptionsToolButton.setMaximumWidth(12) self.findOptionsToolButton.setAutoRaise(True) self.findOptionsToolButton.setPopupMode(QToolButton.MenuButtonPopup) self._setFindOptionsToolButtonMenu() self.findNextToolButton = PM_ToolButton( self, iconPath = "ui/actions/Properties Manager/Find_Next.png") self.findNextToolButton.setAutoRaise(True) self.findPreviousToolButton = PM_ToolButton( self, iconPath = "ui/actions/Properties Manager/Find_Previous.png") self.findPreviousToolButton.setAutoRaise(True) self.replacePushButton = PM_PushButton(self, text = "Replace") self.warningSign = QLabel(self) self.warningSign.setPixmap( getpixmap('ui/actions/Properties Manager/Warning.png')) self.warningSign.hide() self.phraseNotFoundLabel = QLabel(self) self.phraseNotFoundLabel.setText("Sequence Not Found") self.phraseNotFoundLabel.hide() # NOTE: Following needs cleanup in the PM_WidgetRow/ PM_WidgetGrid # but this explanation is sufficient until thats done -- # When the widget type starts with the word 'PM_' , the # PM_WidgetRow treats it as a well defined widget and thus doesn't try # to create a QWidget object (or its subclasses) # This is the reason why qLabels such as self.warningSign and # self.phraseNotFoundLabel are defined as PM_Labels and not 'QLabels' # If they were defined as 'QLabel'(s) then PM_WidgetRow would have # recreated the label. Since we want to show/hide the above mentioned # labels (and if they were recreated as mentioned above), # we would have needed to define those something like this: # self.phraseNotFoundLabel = widgetRow._widgetList[-2] #Cleanup in PM_widgetGrid could be to check if the widget starts with #'Q' instead of 'PM_' #Widgets to include in the widget row. widgetList = [('PM_ToolButton', self.loadSequenceButton, 0), ('PM_ToolButton', self.saveSequenceButton, 1), ('QLabel', " Sequence direction:", 2), ('PM_ComboBox', self.baseDirectionChoiceComboBox , 3), ('QLabel', " Find:", 4), ('PM_LineEdit', self.findLineEdit, 5), ('PM_ToolButton', self.findOptionsToolButton, 6), ('PM_ToolButton', self.findPreviousToolButton, 7), ('PM_ToolButton', self.findNextToolButton, 8), ('QLabel', " Replace:", 9), ('PM_TextEdit', self.replaceLineEdit, 10), ('PM_PushButton', self.replacePushButton, 11), ('PM_Label', self.warningSign, 12), ('PM_Label', self.phraseNotFoundLabel, 13), ('QSpacerItem', 5, 5, 14) ] widgetRow = PM_WidgetRow(self, title = '', widgetList = widgetList, label = "", spanWidth = True )
class Ui_MovePropertyManager(Command_PropertyManager): # The title that appears in the Property Manager header title = "Move" # The name of this Property Manager. This will be set to # the name of the PM_Dialog object via setObjectName(). pmName = title # The relative path to the PNG file that appears in the header iconPath = "ui/actions/Properties Manager/Translate_Components.png" # The title(s) that appear in the property manager header. # (these are changed depending on the active group box) translateTitle = "Translate" rotateTitle = "Rotate" # The full path to PNG file(s) that appears in the header. translateIconPath = "ui/actions/Properties Manager/Translate_Components.png" rotateIconPath = "ui/actions/Properties Manager/Rotate_Components.png" def __init__(self, command): _superclass.__init__(self, command) self.showTopRowButtons(PM_DONE_BUTTON | PM_WHATS_THIS_BUTTON) def _addGroupBoxes(self): """ Add groupboxes to the Property Manager dialog. """ self.translateGroupBox = PM_GroupBox(self, title="Translate", connectTitleButton=False) self.translateGroupBox.titleButton.setShortcut('T') self._loadTranslateGroupBox(self.translateGroupBox) self.rotateGroupBox = PM_GroupBox(self, title="Rotate", connectTitleButton=False) self.rotateGroupBox.titleButton.setShortcut('R') self._loadRotateGroupBox(self.rotateGroupBox) self.translateGroupBox.collapse() self.rotateGroupBox.collapse() # == Begin Translate Group Box ===================== def _loadTranslateGroupBox(self, inPmGroupBox): """ Load widgets in the Translate group box. @param inPmGroupBox: The Translate group box in the PM @type inPmGroupBox: L{PM_GroupBox} """ translateChoices = ["Free Drag", "By Delta XYZ", "To XYZ Position"] self.translateComboBox = \ PM_ComboBox( inPmGroupBox, label = '', choices = translateChoices, index = 0, setAsDefault = False, spanWidth = True ) self.freeDragTranslateGroupBox = PM_GroupBox(inPmGroupBox) self._loadFreeDragTranslateGroupBox(self.freeDragTranslateGroupBox) self.byDeltaGroupBox = PM_GroupBox(inPmGroupBox) self._loadByDeltaGroupBox(self.byDeltaGroupBox) self.toPositionGroupBox = PM_GroupBox(inPmGroupBox) self._loadToPositionGroupBox(self.toPositionGroupBox) self.updateTranslateGroupBoxes(0) def _loadFreeDragTranslateGroupBox(self, inPmGroupBox): """ Load widgets in the Free Drag Translate group box, which is present within the Translate groupbox. @param inPmGroupBox: The Free Drag Translate group box in the Translate group box. @type inPmGroupBox: L{PM_GroupBox} """ # Button list to create a toolbutton row. # Format: # - buttonId, # - buttonText , # - iconPath # - tooltip # - shortcut # - column BUTTON_LIST = [ ( "QToolButton", 1, "MOVEDEFAULT", "ui/actions/Properties Manager/Move_Free.png", "", "F", 0), ( "QToolButton", 2, "TRANSX", "ui/actions/Properties Manager/TranslateX.png", "", "X", 1), ( "QToolButton", 3, "TRANSY", "ui/actions/Properties Manager/TranslateY.png", "", "Y", 2), ( "QToolButton", 4, "TRANSZ", "ui/actions/Properties Manager/TranslateZ.png", "", "Z", 3), ( "QToolButton", 5, "ROT_TRANS_ALONG_AXIS", "ui/actions/Properties Manager/translate+rotate-A.png", "", \ "A", 4) ] self.freeDragTranslateButtonGroup = \ PM_ToolButtonRow( inPmGroupBox, title = "", buttonList = BUTTON_LIST, checkedId = 1, setAsDefault = True, ) self.transFreeButton = self.freeDragTranslateButtonGroup.getButtonById( 1) self.transXButton = self.freeDragTranslateButtonGroup.getButtonById(2) self.transYButton = self.freeDragTranslateButtonGroup.getButtonById(3) self.transZButton = self.freeDragTranslateButtonGroup.getButtonById(4) self.transAlongAxisButton = \ self.freeDragTranslateButtonGroup.getButtonById(5) self.moveFromToButton = PM_ToolButton( inPmGroupBox, text = "Translate from/to", iconPath = "ui/actions/Properties Manager"\ "/Translate_Components.png", spanWidth = True ) self.moveFromToButton.setCheckable(True) self.moveFromToButton.setAutoRaise(True) self.moveFromToButton.setToolButtonStyle(Qt.ToolButtonTextBesideIcon) self.startCoordLineEdit = PM_LineEdit( inPmGroupBox, label = "ui/actions/Properties Manager"\ "/Move_Start_Point.png", text = "Define 'from' and 'to' points", setAsDefault = False, ) self.startCoordLineEdit.setReadOnly(True) self.startCoordLineEdit.setEnabled(False) def _loadByDeltaGroupBox(self, inPmGroupBox): """ Load widgets in the translate By Delta group box, which is present within the Translate groupbox. @param inPmGroupBox: The Translate By Delta group box in the translate group box. @type inPmGroupBox: L{PM_GroupBox} """ self.moveDeltaXSpinBox = \ PM_DoubleSpinBox( inPmGroupBox, label = "ui/actions/Properties Manager/Delta_X.png", value = 0.0, setAsDefault = True, minimum = -100.0, maximum = 100.0, singleStep = 1.0, decimals = 3, suffix = ' Angstroms', spanWidth = False ) self.moveDeltaYSpinBox = \ PM_DoubleSpinBox( inPmGroupBox, label = "ui/actions/Properties Manager/Delta_Y.png", value = 0.0, setAsDefault = True, minimum = -100.0, maximum = 100.0, singleStep = 1.0, decimals = 3, suffix = ' Angstroms', spanWidth = False ) self.moveDeltaZSpinBox = \ PM_DoubleSpinBox( inPmGroupBox, label = "ui/actions/Properties Manager/Delta_Z.png", value = 0.0, setAsDefault = True, minimum = -100.0, maximum = 100.0, singleStep = 1.0, decimals = 3, suffix = ' Angstroms', spanWidth = False ) DELTA_BUTTONS = [ ("QToolButton", 1, "Delta Plus", "ui/actions/Properties Manager/Move_Delta_Plus.png", "", "+", 0), ("QToolButton", 2, "Delta Minus", "ui/actions/Properties Manager/Move_Delta_Minus.png", "", "-", 1) ] self.translateDeltaButtonRow = \ PM_ToolButtonRow( inPmGroupBox, title = "", buttonList = DELTA_BUTTONS, label = 'Translate:', isAutoRaise = True, isCheckable = False ) self.transDeltaPlusButton = \ self.translateDeltaButtonRow.getButtonById(1) self.transDeltaMinusButton = \ self.translateDeltaButtonRow.getButtonById(2) def _loadToPositionGroupBox(self, inPmGroupBox): """ Load widgets in the Translate To a given Position group box, which is present within the Translate groupbox. @param inPmGroupBox: Translate To Position group box in the Translate group box. @type inPmGroupBox: L{PM_GroupBox} """ self.toPositionspinboxes = PM_CoordinateSpinBoxes(inPmGroupBox) self.moveXSpinBox = self.toPositionspinboxes.xSpinBox self.moveYSpinBox = self.toPositionspinboxes.ySpinBox self.moveZSpinBox = self.toPositionspinboxes.zSpinBox self.moveAbsoluteButton = \ PM_PushButton( inPmGroupBox, label = "", text = "Move Selection", spanWidth = True ) # == Begin Rotate Group Box ===================== def _loadRotateGroupBox(self, inPmGroupBox): """ Load widgets in the Rotate group box, @param inPmGroupBox: The Rotate GroupBox in the PM @type inPmGroupBox: L{PM_GroupBox} """ rotateChoices = ["Free Drag", "By Specified Angle"] self.rotateComboBox = \ PM_ComboBox( inPmGroupBox, label = '', choices = rotateChoices, index = 0, setAsDefault = False, spanWidth = True ) self.rotateAsUnitCB = \ PM_CheckBox( inPmGroupBox, text = 'Rotate as a unit' , widgetColumn = 0, state = Qt.Checked ) self.freeDragRotateGroupBox = PM_GroupBox(inPmGroupBox) self._loadFreeDragRotateGroupBox(self.freeDragRotateGroupBox) self.bySpecifiedAngleGroupBox = PM_GroupBox(inPmGroupBox) self._loadBySpecifiedAngleGroupBox(self.bySpecifiedAngleGroupBox) self.updateRotateGroupBoxes(0) def _loadFreeDragRotateGroupBox(self, inPmGroupBox): """ Load widgets in the Free Drag Rotate group box, which is present within the Rotate groupbox. @param inPmGroupBox: The Free Drag Rotate group box in the Rotate group box. @type inPmGroupBox: L{PM_GroupBox} """ # Button list to create a toolbutton row. # Format: # - buttonId, # - buttonText , # - iconPath # - tooltip # - shortcut # - column BUTTON_LIST = [ ( "QToolButton", 1, "ROTATEDEFAULT", "ui/actions/Properties Manager/Rotate_Free.png", "", "F", 0 ), ( "QToolButton", 2, "ROTATEX", "ui/actions/Properties Manager/RotateX.png", "", "X", 1 ), ( "QToolButton", 3, "ROTATEY", "ui/actions/Properties Manager/RotateY.png", "", "Y", 2 ), ( "QToolButton", 4, "ROTATEZ", "ui/actions/Properties Manager/RotateZ.png", "", "Z", 3 ), ( "QToolButton", 5, "ROT_TRANS_ALONG_AXIS", "ui/actions/Properties Manager/translate+rotate-A.png", "", \ "A", 4 ) ] self.freeDragRotateButtonGroup = \ PM_ToolButtonRow( inPmGroupBox, title = "", buttonList = BUTTON_LIST, spanWidth = True, checkedId = 1, setAsDefault = True, ) self.rotateFreeButton = self.freeDragRotateButtonGroup.getButtonById(1) self.rotateXButton = self.freeDragRotateButtonGroup.getButtonById(2) self.rotateYButton = self.freeDragRotateButtonGroup.getButtonById(3) self.rotateZButton = self.freeDragRotateButtonGroup.getButtonById(4) self.rotAlongAxisButton = \ self.freeDragRotateButtonGroup.getButtonById(5) inPmGroupBox.setStyleSheet( self.freeDragRotateButtonGroup._getStyleSheet()) X_ROW_LABELS = [("QLabel", "Delta Theta X:", 0), ("QLabel", "", 1), ("QLabel", "0.00", 2), ("QLabel", "Degrees", 3)] Y_ROW_LABELS = [("QLabel", "Delta Theta Y:", 0), ("QLabel", "", 1), ("QLabel", "0.00", 2), ("QLabel", "Degrees", 3)] Z_ROW_LABELS = [("QLabel", "Delta Theta Z:", 0), ("QLabel", "", 1), ("QLabel", "0.00", 2), ("QLabel", "Degrees", 3)] self.rotateXLabelRow = PM_LabelRow(inPmGroupBox, title="", labelList=X_ROW_LABELS) self.deltaThetaX_lbl = self.rotateXLabelRow.labels[2] self.rotateYLabelRow = PM_LabelRow(inPmGroupBox, title="", labelList=Y_ROW_LABELS) self.deltaThetaY_lbl = self.rotateYLabelRow.labels[2] self.rotateZLabelRow = PM_LabelRow(inPmGroupBox, title="", labelList=Z_ROW_LABELS) self.deltaThetaZ_lbl = self.rotateZLabelRow.labels[2] self.rotateAboutPointButton = PM_ToolButton( inPmGroupBox, text = "Rotate selection about a point", iconPath = "ui/actions/Properties Manager"\ "/Rotate_Components.png", spanWidth = True ) self.rotateAboutPointButton.setCheckable(True) self.rotateAboutPointButton.setAutoRaise(True) self.rotateAboutPointButton.setToolButtonStyle( Qt.ToolButtonTextBesideIcon) self.rotateStartCoordLineEdit = PM_LineEdit( inPmGroupBox, label = "ui/actions/Properties Manager"\ "/Move_Start_Point.png", text = "Define 3 points", setAsDefault = False, ) self.rotateStartCoordLineEdit.setReadOnly(True) self.rotateStartCoordLineEdit.setEnabled(False) def _loadBySpecifiedAngleGroupBox(self, inPmGroupBox): """ Load widgets in the Rotate By Specified Angle group box, which is present within the Rotate groupbox. @param inPmGroupBox: Rotate By Specified Angle group box in the Rotate group box. @type inPmGroupBox: L{PM_GroupBox} """ # Button list to create a toolbutton row. # Format: # - buttonId, # - buttonText , # - iconPath # - tooltip # - shortcut # - column BUTTON_LIST = [ ("QToolButton", 1, "ROTATEX", "ui/actions/Properties Manager/RotateX.png", "Rotate about X axis", "X", 0), ("QToolButton", 2, "ROTATEY", "ui/actions/Properties Manager/RotateY.png", "Rotate about Y axis", "Y", 1), ("QToolButton", 3, "ROTATEZ", "ui/actions/Properties Manager/RotateZ.png", "Rotate about Z axis", "Z", 2), ] self.rotateAroundAxisButtonRow = \ PM_ToolButtonRow( inPmGroupBox, title = "", buttonList = BUTTON_LIST, alignment = 'Right', label = 'Rotate Around:' ) self.rotXaxisButton = \ self.rotateAroundAxisButtonRow.getButtonById(1) self.rotYaxisButton = \ self.rotateAroundAxisButtonRow.getButtonById(2) self.rotZaxisButton = \ self.rotateAroundAxisButtonRow.getButtonById(3) self.rotateThetaSpinBox = \ PM_DoubleSpinBox(inPmGroupBox, label = "Rotate By:", value = 0.0, setAsDefault = True, minimum = 0, maximum = 360.0, singleStep = 1.0, decimals = 2, suffix = ' Degrees') THETA_BUTTONS = [ ("QToolButton", 1, "Theta Plus", "ui/actions/Properties Manager/Move_Theta_Plus.png", "", "+", 0), ("QToolButton", 2, "Theta Minus", "ui/actions/Properties Manager/Move_Theta_Minus.png", "", "-", 1) ] self.rotateThetaButtonRow = \ PM_ToolButtonRow( inPmGroupBox, title = "", buttonList = THETA_BUTTONS, label = 'Direction:', isAutoRaise = True, isCheckable = False ) self.rotateThetaPlusButton = self.rotateThetaButtonRow.getButtonById(1) self.rotateThetaMinusButton = self.rotateThetaButtonRow.getButtonById( 2) # == End Rotate Group Box ===================== # == Slots for Translate group box def _hideAllTranslateGroupBoxes(self): """ Hides all Translate group boxes. """ self.toPositionGroupBox.hide() self.byDeltaGroupBox.hide() self.freeDragTranslateGroupBox.hide() def updateTranslateGroupBoxes(self, id): """ Update the translate group boxes displayed based on the translate option selected. @param id: Integer value corresponding to the combobox item in the Translate group box. @type id: int """ self._hideAllTranslateGroupBoxes() if id is 0: self.freeDragTranslateGroupBox.show() if id is 1: self.byDeltaGroupBox.show() if id is 2: self.toPositionGroupBox.show() self.updateMessage() def changeMoveOption(self, button): """ Subclasses should reimplement this method. @param button: QToolButton that decides the type of translate operation to be set. @type button: QToolButton L{http://doc.trolltech.com/4.2/qtoolbutton.html} @see: B{MovePropertyManager.changeMoveOption} which overrides this method """ pass # == Slots for Rotate group box def updateRotateGroupBoxes(self, id): """ Update the translate group boxes displayed based on the translate option selected. @param id: Integer value corresponding to the combobox item in the Rotate group box. @type id: int """ if id is 0: self.bySpecifiedAngleGroupBox.hide() self.freeDragRotateGroupBox.show() if id is 1: self.freeDragRotateGroupBox.hide() self.bySpecifiedAngleGroupBox.show() self.updateMessage() def changeRotateOption(self, button): """ Subclasses should reimplement this method. @param button: QToolButton that decides the type of rotate operation to be set. @type button: QToolButton L{http://doc.trolltech.com/4.2/qtoolbutton.html} @see: B{MovePropertyManage.changeRotateOption} which overrides this method """ pass def _addWhatsThisText(self): """ What's This text for some of the widgets in this Property Manager. """ from ne1_ui.WhatsThisText_for_PropertyManagers import whatsThis_MovePropertyManager whatsThis_MovePropertyManager(self) def _addToolTipText(self): """ Tool Tip text for widgets in this Property Manager. """ from ne1_ui.ToolTipText_for_PropertyManagers import ToolTip_MovePropertyManager ToolTip_MovePropertyManager(self)
class Ui_DnaSequenceEditor(PM_DockWidget): """ The Ui_DnaSequenceEditor class defines UI elements for the Sequence Editor object. The sequence editor is usually visible while in DNA edit mode. It is a DockWidget that is doced at the bottom of the MainWindow """ _title = "Sequence Editor" _groupBoxCount = 0 _lastGroupBox = None def __init__(self, win): """ Constructor for the Ui_DnaSequenceEditor @param win: The parentWidget (MainWindow) for the sequence editor """ self.win = win # Should parentWidget for a docwidget always be win? #Not necessary but most likely it will be the case. parentWidget = win _superclass.__init__(self, parentWidget, title = self._title) #A flag used to restore the state of the Reports dock widget #(which can be accessed through View > Reports) see self.show() and #self.closeEvent() for more details. self._reportsDockWidget_closed_in_show_method = False self.setFixedHeight(90) def show(self): """ Shows the sequence editor. While doing this, it also closes the reports dock widget (if visible) the state of the reports dockwidget will be restored when the sequence editor is closed. @see:self.closeEvent() """ self._reportsDockWidget_closed_in_show_method = False #hide the history widget first #(It will be shown back during self.close) #The history widget is hidden or shown only when both # 'View > Full Screen' and View > Semi Full Screen actions # are *unchecked* #Thus show or close methods won't do anything to history widget # if either of the above mentioned actions is checked. if self.win.viewFullScreenAction.isChecked() or \ self.win.viewSemiFullScreenAction.isChecked(): pass else: if self.win.reportsDockWidget.isVisible(): self.win.reportsDockWidget.close() self._reportsDockWidget_closed_in_show_method = True _superclass.show(self) def closeEvent(self, event): """ Overrides close event. Makes sure that the visible state of the reports widgetis restored when the sequence editor is closed. @see: self.show() """ _superclass.closeEvent(self, event) if self.win.viewFullScreenAction.isChecked() or \ self.win.viewSemiFullScreenAction.isChecked(): pass else: if self._reportsDockWidget_closed_in_show_method: self.win.viewReportsAction.setChecked(True) self._reportsDockWidget_closed_in_show_method = False def _loadWidgets(self): """ Overrides PM.PM_DockWidget._loadWidgets. Loads the widget in this dockwidget. """ self._loadMenuWidgets() self._loadTextEditWidget() def _loadMenuWidgets(self): """ Load the various menu widgets (e.g. Open, save sequence options, Find and replace widgets etc. """ #Note: Find and replace widgets might be moved to their own class. self.loadSequenceButton = PM_ToolButton( self, iconPath = "ui/actions/Properties Manager/Open.png") self.saveSequenceButton = PM_ToolButton( self, iconPath = "ui/actions/Properties Manager/Save_Strand_Sequence.png") self.loadSequenceButton.setAutoRaise(True) self.saveSequenceButton.setAutoRaise(True) editDirectionChoices = ["5' to 3'", "3' to 5'"] self.baseDirectionChoiceComboBox = \ PM_ComboBox( self, choices = editDirectionChoices, index = 0, spanWidth = False ) #Find and replace widgets -- self.findLineEdit = \ PM_LineEdit( self, label = "", spanWidth = False) self.findLineEdit.setMaximumWidth(60) self.replaceLineEdit = \ PM_LineEdit( self, label = "", spanWidth = False) self.replaceLineEdit.setMaximumWidth(60) self.findOptionsToolButton = PM_ToolButton(self) self.findOptionsToolButton.setMaximumWidth(12) self.findOptionsToolButton.setAutoRaise(True) self.findOptionsToolButton.setPopupMode(QToolButton.MenuButtonPopup) self._setFindOptionsToolButtonMenu() self.findNextToolButton = PM_ToolButton( self, iconPath = "ui/actions/Properties Manager/Find_Next.png") self.findNextToolButton.setAutoRaise(True) self.findPreviousToolButton = PM_ToolButton( self, iconPath = "ui/actions/Properties Manager/Find_Previous.png") self.findPreviousToolButton.setAutoRaise(True) self.replacePushButton = PM_PushButton(self, text = "Replace") self.warningSign = QLabel(self) self.warningSign.setPixmap( getpixmap('ui/actions/Properties Manager/Warning.png')) self.warningSign.hide() self.phraseNotFoundLabel = QLabel(self) self.phraseNotFoundLabel.setText("Sequence Not Found") self.phraseNotFoundLabel.hide() # NOTE: Following needs cleanup in the PM_WidgetRow/ PM_WidgetGrid # but this explanation is sufficient until thats done -- # When the widget type starts with the word 'PM_' , the # PM_WidgetRow treats it as a well defined widget and thus doesn't try # to create a QWidget object (or its subclasses) # This is the reason why qLabels such as self.warningSign and # self.phraseNotFoundLabel are defined as PM_Labels and not 'QLabels' # If they were defined as 'QLabel'(s) then PM_WidgetRow would have # recreated the label. Since we want to show/hide the above mentioned # labels (and if they were recreated as mentioned above), # we would have needed to define those something like this: # self.phraseNotFoundLabel = widgetRow._widgetList[-2] #Cleanup in PM_widgetGrid could be to check if the widget starts with #'Q' instead of 'PM_' #Widgets to include in the widget row. widgetList = [('PM_ToolButton', self.loadSequenceButton, 0), ('PM_ToolButton', self.saveSequenceButton, 1), ('QLabel', " Sequence direction:", 2), ('PM_ComboBox', self.baseDirectionChoiceComboBox , 3), ('QLabel', " Find:", 4), ('PM_LineEdit', self.findLineEdit, 5), ('PM_ToolButton', self.findOptionsToolButton, 6), ('PM_ToolButton', self.findPreviousToolButton, 7), ('PM_ToolButton', self.findNextToolButton, 8), ('QLabel', " Replace:", 9), ('PM_TextEdit', self.replaceLineEdit, 10), ('PM_PushButton', self.replacePushButton, 11), ('PM_Label', self.warningSign, 12), ('PM_Label', self.phraseNotFoundLabel, 13), ('QSpacerItem', 5, 5, 14) ] widgetRow = PM_WidgetRow(self, title = '', widgetList = widgetList, label = "", spanWidth = True ) def _loadTextEditWidget(self): """ Load the SequenceTexteditWidgets. """ self.sequenceTextEdit = \ PM_TextEdit( self, label = " Sequence: ", spanWidth = False, permit_enter_keystroke = False) self.sequenceTextEdit.setCursorWidth(2) self.sequenceTextEdit.setWordWrapMode( QTextOption.WrapAnywhere ) self.sequenceTextEdit.setFixedHeight(20) #The StrandSequence 'Mate' it is a read only etxtedit that shows #the complementary strand sequence. self.sequenceTextEdit_mate = \ PM_TextEdit(self, label = "", spanWidth = False, permit_enter_keystroke = False ) palette = getPalette(None, QPalette.Base, sequenceEditStrandMateBaseColor) self.sequenceTextEdit_mate.setPalette(palette) self.sequenceTextEdit_mate.setFixedHeight(20) self.sequenceTextEdit_mate.setReadOnly(True) self.sequenceTextEdit_mate.setWordWrapMode(QTextOption.WrapAnywhere) #Important to make sure that the horizontal and vertical scrollbars #for these text edits are never displayed. for textEdit in (self.sequenceTextEdit, self.sequenceTextEdit_mate): textEdit.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) textEdit.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) def _getFindLineEditStyleSheet(self): """ Return the style sheet for the findLineEdit. This sets the following properties only: - background-color This style is set whenever the searchStrig can't be found (sets a light red color background to the lineedit when this happens) @return: The line edit style sheet. @rtype: str """ styleSheet = \ "QLineEdit {\ background-color: rgb(255, 102, 102)\ }" #Not used: # background-color: rgb(217, 255, 216)\ return styleSheet def _setFindOptionsToolButtonMenu(self): """ Sets the menu for the findOptionstoolbutton that appears a small menu button next to the findLineEdit. """ self.findOptionsMenu = QMenu(self.findOptionsToolButton) self.caseSensitiveFindAction = QAction(self.findOptionsToolButton) self.caseSensitiveFindAction.setText('Match Case') self.caseSensitiveFindAction.setCheckable(True) self.caseSensitiveFindAction.setChecked(False) self.findOptionsMenu.addAction(self.caseSensitiveFindAction) self.findOptionsMenu.addSeparator() self.findOptionsToolButton.setMenu(self.findOptionsMenu) def _addToolTipText(self): """ What's Tool Tip text for widgets in this Property Manager. """ from ne1_ui.ToolTipText_for_PropertyManagers import ToolTip_SequenceEditor ToolTip_SequenceEditor(self) def _addWhatsThisText(self): """ What's This text for widgets in this Property Manager. """ from ne1_ui.WhatsThisText_for_PropertyManagers import whatsThis_SequenceEditor whatsThis_SequenceEditor(self)
class OrderDna_PropertyManager(Command_PropertyManager): """ The OrderDna_PropertyManager class provides a Property Manager for the B{Order Dna} command on the flyout toolbar in the Build > Dna mode. @ivar title: The title that appears in the property manager header. @type title: str @ivar pmName: The name of this property manager. This is used to set the name of the PM_Dialog object via setObjectName(). @type name: str @ivar iconPath: The relative path to the PNG file that contains a 22 x 22 icon image that appears in the PM header. @type iconPath: str """ title = "Order DNA" pmName = title iconPath = "ui/actions/Command Toolbar/BuildDna/OrderDna.png" def __init__(self, command): """ Constructor for the property manager. """ _superclass.__init__(self, command) self.assy = self.win.assy self.showTopRowButtons( PM_DONE_BUTTON | \ PM_WHATS_THIS_BUTTON) self.update_includeStrands() # Updates the message box. 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: change_connect = self.win.connect else: change_connect = self.win.disconnect change_connect(self.viewDnaOrderFileButton, SIGNAL("clicked()"), self.viewDnaOrderFile) change_connect(self.includeStrandsComboBox, SIGNAL("activated(int)"), self.update_includeStrands) return def _addGroupBoxes(self): """ Add the Property Manager group boxes. """ self._pmGroupBox1 = PM_GroupBox(self, title="Options") self._loadGroupBox1(self._pmGroupBox1) def _loadGroupBox1(self, pmGroupBox): """ Load widgets in group box. """ includeStrandsChoices = [ "All strands in model", "Selected strands only" ] self.includeStrandsComboBox = \ PM_ComboBox( pmGroupBox, label = "Include strands:", choices = includeStrandsChoices, setAsDefault = True) self.numberOfBasesLineEdit = \ PM_LineEdit( pmGroupBox, label = "Total nucleotides:", text = str(self.getNumberOfBases())) self.numberOfBasesLineEdit.setEnabled(False) self.numberOfXBasesLineEdit = \ PM_LineEdit( pmGroupBox, label = "Unassigned:", text = str(self.getNumberOfBases(unassignedOnly = True))) self.numberOfXBasesLineEdit.setEnabled(False) self.viewDnaOrderFileButton = \ PM_PushButton( pmGroupBox, label = "", text = "View DNA Order File...", spanWidth = True) return def _addWhatsThisText(self): """ What's This text for widgets in this Property Manager. """ whatsThis_OrderDna_PropertyManager(self) return def _addToolTipText(self): """ Tool Tip text for widgets in the DNA Property Manager. """ pass # Ask Bruce where this should live (i.e. class Part?) --Mark def getAllDnaStrands(self, selectedOnly=False): """ Returns a list of all the DNA strands in the current part, or only the selected strands if I{selectedOnly} is True. @param selectedOnly: If True, return only the selected DNA strands. @type selectedOnly: bool """ dnaStrandList = [] def func(node): if isinstance(node, DnaStrand): if selectedOnly: if node.picked: dnaStrandList.append(node) else: dnaStrandList.append(node) self.win.assy.part.topnode.apply2all(func) return dnaStrandList def getNumberOfBases(self, selectedOnly=False, unassignedOnly=False): """ Returns the number of bases count for all the DNA strands in the current part, or only the selected strand if I{selectedOnly} is True. @param selectedOnly: If True, return only the number of bases in the selected DNA strands. @type selectedOnly: bool @param unassignedOnly: If True, return only the number of unassigned bases (i.e. base letters = X). @type unassignedOnly: bool """ dnaSequenceString = '' selectedOnly = self.includeStrandsComboBox.currentIndex() strandList = self.getAllDnaStrands(selectedOnly) for strand in strandList: strandSequenceString = str(strand.getStrandSequence()) dnaSequenceString += strandSequenceString if unassignedOnly: return dnaSequenceString.count("X") return len(dnaSequenceString) def _update_UI_do_updates(self): """ Overrides superclass method. """ self.update_includeStrands() return def getDnaSequence(self, format='CSV'): """ Return the complete Dna sequence information string (i.e. all strand sequences) in the specified format. @return: The Dna sequence string @rtype: string """ if format == 'CSV': #comma separated values. separator = ',' dnaSequenceString = '' selectedOnly = self.includeStrandsComboBox.currentIndex() strandList = self.getAllDnaStrands(selectedOnly) for strand in strandList: dnaSequenceString = dnaSequenceString + strand.name + separator strandSequenceString = str(strand.getStrandSequence()) if strandSequenceString: strandSequenceString = strandSequenceString.upper() strandLength = str(len(strandSequenceString)) + separator dnaSequenceString = dnaSequenceString + strandLength + strandSequenceString dnaSequenceString = dnaSequenceString + "\n" return dnaSequenceString def viewDnaOrderFile(self, openFileInEditor=True): """ Writes a DNA Order file in comma-separated values (CSV) format and opens it in a text editor. The user must save the file to a permanent location using the text editor. @see: Ui_DnaFlyout.orderDnaCommand @see: writeDnaOrderFile() @TODO: assy.getAllDnaObjects(). """ dnaSequence = self.getDnaSequence(format='CSV') if dnaSequence: tmpdir = find_or_make_Nanorex_subdir('temp') fileBaseName = 'DnaOrder' temporaryFile = os.path.join(tmpdir, "%s.csv" % fileBaseName) writeDnaOrderFile(temporaryFile, self.assy, self.getNumberOfBases(), self.getNumberOfBases(unassignedOnly=True), dnaSequence) if openFileInEditor: open_file_in_editor(temporaryFile) return def update_includeStrands(self, ignoreVal=0): """ Slot method for "Include (strands)" combobox. """ idx = self.includeStrandsComboBox.currentIndex() includeType = ["model", "selection"] _numberOfBases = self.getNumberOfBases() self.numberOfBasesLineEdit.setText(str(_numberOfBases) + " bases") _numberOfXBases = self.getNumberOfBases(unassignedOnly=True) self.numberOfXBasesLineEdit.setText(str(_numberOfXBases) + " bases") # Make the background color red if there are any unassigned bases. if _numberOfXBases: self.numberOfXBasesLineEdit.setStyleSheet(\ "QLineEdit {"\ "background-color: rgb(255, 0, 0)"\ "}") else: self.numberOfXBasesLineEdit.setStyleSheet(\ "QLineEdit {"\ "background-color: rgb(255, 255, 255)"\ "}") if _numberOfBases > 0: self.viewDnaOrderFileButton.setEnabled(True) msg = "Click on <b>View DNA Order File...</b> to preview a " \ "DNA order for all DNA strands in the current %s." \ % includeType[idx] else: self.viewDnaOrderFileButton.setEnabled(False) msg = "<font color=red>" \ "There are no DNA strands in the current %s." \ % includeType[idx] self.updateMessage(msg) return
class CompareProteins_PropertyManager(Command_PropertyManager): """ The CompareProteins_PropertyManager class provides a Property Manager for the B{Compare Proteins} command on the Build Protein flyout toolbar. @ivar title: The title that appears in the property manager header. @type title: str @ivar pmName: The name of this property manager. This is used to set the name of the PM_Dialog object via setObjectName(). @type name: str @ivar iconPath: The relative path to the PNG file that contains a 22 x 22 icon image that appears in the PM header. @type iconPath: str @ivar proteinChunk1: The first currently selected protein to be compared. @type proteinChunk1: protein chunk @ivar proteinChunk2: The second currently selected protein to be compared. @type proteinChunk2: protein chunk """ title = "Compare Proteins" pmName = title iconPath = "ui/actions/Command Toolbar/BuildProtein/Compare.png" proteinChunk1 = None proteinChunk2 = None def __init__(self, command): """ Constructor for the property manager. """ self.threshold = 10.0 _superclass.__init__(self, command) self.showTopRowButtons(PM_DONE_BUTTON | PM_WHATS_THIS_BUTTON) return def connect_or_disconnect_signals(self, isConnect=True): if isConnect: change_connect = self.win.connect else: change_connect = self.win.disconnect change_connect(self.comparePushButton, SIGNAL("clicked()"), self._compareProteins) change_connect(self.thresholdDoubleSpinBox, SIGNAL("valueChanged(double)"), self._thresholdChanged) change_connect(self.hidePushButton, SIGNAL("clicked()"), self._hideDifferences) return def close(self): """ Closes the Property Manager. Overrides EditCommand_PM.close() """ env.history.statusbar_msg("") self._resetAminoAcids() _superclass.close(self) # Restore the original global display style. self.o.setGlobalDisplayStyle(self.originalDisplayStyle) return def show(self): """ Show the PM. Extends superclass method. @note: _update_UI_do_updates() gets called immediately after this and updates PM widgets with their correct values/settings. """ _superclass.show(self) env.history.statusbar_msg("") # Force the Global Display Style to "Protein" since this is the only way # to see comparisons. The global display style will be restored when leaving # this command (via self.close()). self.originalDisplayStyle = self.o.displayMode self.o.setGlobalDisplayStyle(diPROTEIN) return def _addGroupBoxes(self): """ Add the Property Manager group boxes. """ self._pmGroupBox1 = PM_GroupBox(self, title="Compare") self._loadGroupBox1(self._pmGroupBox1) return def _addWhatsThisText(self): """ What's This text for widgets in this Property Manager. """ pass def _addToolTipText(self): """ Tool Tip text for widgets in this Property Manager. """ pass def _loadGroupBox1(self, pmGroupBox): """ Load widgets in group box. """ self.structure1LineEdit = PM_LineEdit(pmGroupBox, label="First structure:", setAsDefault=False) self.structure1LineEdit.setEnabled(False) self.structure2LineEdit = PM_LineEdit(pmGroupBox, label="Second structure:", setAsDefault=False) self.structure2LineEdit.setEnabled(False) self.thresholdDoubleSpinBox = PM_DoubleSpinBox( pmGroupBox, label="Threshold:", value=self.threshold, setAsDefault=True, minimum=0.0, maximum=360.0, decimals=1, singleStep=30.0, suffix=" deg", spanWidth=False, ) self.comparePushButton = PM_PushButton(pmGroupBox, text="Compare", setAsDefault=True) self.hidePushButton = PM_PushButton(pmGroupBox, text="Hide differences", setAsDefault=True) return def _compareProteins(self): """ Slot for Compare button. Compares two selected proteins of the same length. Amino acids that differ greater than the "threshold" value are displayed in two colors (red for the first protein and yellow for the second protein) and are only visible when the two proteins are displayed in the reduced display style. """ from utilities.constants import red, orange, green, cyan if not self.proteinChunk1 or not self.proteinChunk2: return protein_1 = self.proteinChunk1.protein protein_2 = self.proteinChunk2.protein if protein_1 and protein_2: aa_list_1 = protein_1.get_amino_acids() aa_list_2 = protein_2.get_amino_acids() protein_1.collapse_all_rotamers() protein_2.collapse_all_rotamers() if len(aa_list_1) == len(aa_list_2): for aa1, aa2 in zip(aa_list_1, aa_list_2): aa1.color = None aa2.color = None # aa1.collapse() # aa2.collapse() if aa1.get_one_letter_code() != aa2.get_one_letter_code(): aa1.set_color(red) aa1.expand() aa2.set_color(yellow) aa2.expand() else: max = 0.0 for chi in range(0, 3): angle1 = aa1.get_chi_angle(chi) angle2 = aa2.get_chi_angle(chi) if angle1 and angle2: if angle1 < 0.0: angle1 += 360.0 if angle2 < 0.0: angle2 += 360.0 diff = abs(angle1 - angle2) if diff > max: max = diff if max >= self.threshold: # This be a parameter. aa1.set_color(green) aa1.expand() aa2.set_color(cyan) aa2.expand() self.win.glpane.gl_update() else: msg = "The lengths of compared proteins are not equal." self.updateMessage(msg) env.history.redmsg(msg) return def _hideDifferences(self): """ Slot for the "Hide differences" button. Hides amino acids that differ greater than the "threshold" value. @warning: Untested. Code looks suspicious. """ if not self.proteinChunk1 or not self.proteinChunk2: return protein_1 = self.proteinChunk1.protein protein_2 = self.proteinChunk2.protein if protein_1 and protein_2: aa_list_1 = protein_1.get_amino_acids() aa_list_2 = protein_2.get_amino_acids() if len(aa_list_1) == len(aa_list_2): protein_1.collapse_all_rotamers() # @@@ protein_2.collapse_all_rotamers() # @@@ for aa1, aa2 in zip(aa_list_1, aa_list_2): aa1.color = None aa2.color = None aa1.collapse() aa2.collapse() self.win.glpane.gl_update() return def _thresholdChanged(self, value): """ Slot for Threshold spinbox. """ self.threshold = value self._compareProteins() return def _resetAminoAcids(self): """ Resets the color and collapse all amino acids of all proteins. """ proteinChunkList = getAllProteinChunksInPart(self.win.assy) for proteinChunk in proteinChunkList: proteinChunk.protein.collapse_all_rotamers() aa_list = proteinChunk.protein.get_amino_acids() for aa in aa_list: aa.color = None aa.collapse() self.win.glpane.gl_update() return def _update_UI_do_updates(self): """ Overrides superclass method. @see: Command_PropertyManager._update_UI_do_updates() """ self.proteinChunk1 = None self.proteinChunk2 = None self.comparePushButton.setEnabled(False) self.hidePushButton.setEnabled(False) selectedProteinList = self.win.assy.getSelectedProteinChunks() if len(selectedProteinList) == 0: self.structure1LineEdit.setText("") self.structure2LineEdit.setText("") msg = ( "Select two structures of the same length in the graphics area, " "then click the <b>Compare</b> button to compare them." ) elif len(selectedProteinList) == 1: self.proteinChunk1 = selectedProteinList[0] aa1_count = " (%d)" % self.proteinChunk1.protein.count_amino_acids() self.structure1LineEdit.setText(self.proteinChunk1.name + aa1_count) self.structure2LineEdit.setText("") msg = ( "Select one more structure in the graphics area that is the same " "length as <b>" + self.proteinChunk1.name + "</b>. " "Then click the <b>Compare</b> button to compare them." ) elif len(selectedProteinList) == 2: self.proteinChunk1 = selectedProteinList[0] aa1_count = " (%d)" % self.proteinChunk1.protein.count_amino_acids() self.structure1LineEdit.setText(self.proteinChunk1.name + aa1_count) self.proteinChunk2 = selectedProteinList[1] aa2_count = " (%d)" % self.proteinChunk2.protein.count_amino_acids() self.structure2LineEdit.setText(self.proteinChunk2.name + aa2_count) if aa1_count == aa2_count: self.comparePushButton.setEnabled(True) self.hidePushButton.setEnabled(True) msg = "Click the <b>Compare</b> button to compare the two selected structures." else: msg = "<b>%s</b> and <b>%s</b> are not the same length." % ( self.proteinChunk1.name, self.proteinChunk2.name, ) msg = redmsg(msg) else: self.structure1LineEdit.setText("") self.structure2LineEdit.setText("") msg = redmsg("Too many proteins selected.") self.updateMessage(msg) env.history.redmsg(msg) return