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