class InsertNanotube_PropertyManager(DnaOrCnt_PropertyManager): """ The InsertNanotube_PropertyManager class provides a Property Manager for the B{Build > Nanotube > CNT} command. @ivar title: The title that appears in the property manager header. @type title: str @ivar pmName: The name of this property manager. This is used to set the name of the PM_Dialog object via setObjectName(). @type name: str @ivar iconPath: The relative path to the PNG file that contains a 22 x 22 icon image that appears in the PM header. @type iconPath: str """ title = "Insert Nanotube" pmName = title iconPath = "ui/actions/Tools/Build Structures/InsertNanotube.png" def __init__(self, win, editCommand): """ Constructor for the Nanotube property manager. """ self.endPoint1 = None self.endPoint2 = None self.nanotube = Nanotube() # A 5x5 CNT. _superclass.__init__(self, win, editCommand) self.showTopRowButtons( PM_DONE_BUTTON | \ PM_CANCEL_BUTTON | \ PM_WHATS_THIS_BUTTON) def connect_or_disconnect_signals(self, isConnect): """ Connect or disconnect widget signals sent to their slot methods. This can be overridden in subclasses. By default it does nothing. @param isConnect: If True the widget will send the signals to the slot method. @type isConnect: boolean """ if isConnect: change_connect = self.win.connect else: change_connect = self.win.disconnect change_connect(self.ntTypeComboBox, SIGNAL("currentIndexChanged(const QString&)"), self._ntTypeComboBoxChanged) change_connect(self.chiralityNSpinBox, SIGNAL("valueChanged(int)"), self._chiralityFixup) change_connect(self.chiralityMSpinBox, SIGNAL("valueChanged(int)"), self._chiralityFixup) change_connect(self.endingsComboBox, SIGNAL("currentIndexChanged(const QString&)"), self._endingsComboBoxChanged) # This spin box is currently hidden. change_connect(self.bondLengthDoubleSpinBox, SIGNAL("valueChanged(double)"), self._bondLengthChanged) change_connect(self.showCursorTextCheckBox, SIGNAL('stateChanged(int)'), self._update_state_of_cursorTextGroupBox) def ok_btn_clicked(self): """ Slot for the OK button """ if self.editCommand: self.editCommand.preview_or_finalize_structure(previewing=False) ##env.history.message(self.editCommand.logMessage) self.win.toolsDone() def cancel_btn_clicked(self): """ Slot for the Cancel button. """ if self.editCommand: self.editCommand.cancelStructure() self.win.toolsCancel() def _update_widgets_in_PM_before_show(self): """ Update various widgets in this Property manager. Overrides MotorPropertyManager._update_widgets_in_PM_before_show. The various widgets , (e.g. spinboxes) will get values from the structure for which this propMgr is constructed for (self.editcCntroller.struct) @see: MotorPropertyManager._update_widgets_in_PM_before_show @see: self.show where it is called. """ pass def getFlyoutActionList(self): """ Returns custom actionlist that will be used in a specific mode or editing a feature etc Example: while in movie mode, the _createFlyoutToolBar method calls this. """ #'allActionsList' returns all actions in the flyout toolbar #including the subcontrolArea actions allActionsList = [] #Action List for subcontrol Area buttons. #In this mode there is really no subcontrol area. #We will treat subcontrol area same as 'command area' #(subcontrol area buttons will have an empty list as their command area #list). We will set the Comamnd Area palette background color to the #subcontrol area. subControlAreaActionList = [] self.exitEditCommandAction.setChecked(True) subControlAreaActionList.append(self.exitEditCommandAction) separator = QAction(self.w) separator.setSeparator(True) subControlAreaActionList.append(separator) allActionsList.extend(subControlAreaActionList) #Empty actionlist for the 'Command Area' commandActionLists = [] #Append empty 'lists' in 'commandActionLists equal to the #number of actions in subControlArea for i in range(len(subControlAreaActionList)): lst = [] commandActionLists.append(lst) params = (subControlAreaActionList, commandActionLists, allActionsList) return params def _addGroupBoxes(self): """ Add the Insert Nanotube Property Manager group boxes. """ self._pmGroupBox1 = PM_GroupBox(self, title="Endpoints") self._loadGroupBox1(self._pmGroupBox1) self._pmGroupBox1.hide() self._pmGroupBox2 = PM_GroupBox(self, title="Parameters") self._loadGroupBox2(self._pmGroupBox2) self._displayOptionsGroupBox = PM_GroupBox(self, title="Display Options") self._loadDisplayOptionsGroupBox(self._displayOptionsGroupBox) self._pmGroupBox3 = PM_GroupBox(self, title="Nanotube Distortion") self._loadGroupBox3(self._pmGroupBox3) self._pmGroupBox3.hide() #@ Temporary. self._pmGroupBox4 = PM_GroupBox(self, title="Multi-Walled CNTs") self._loadGroupBox4(self._pmGroupBox4) self._pmGroupBox4.hide() #@ Temporary. self._pmGroupBox5 = PM_GroupBox(self, title="Advanced Options") self._loadGroupBox5(self._pmGroupBox5) self._pmGroupBox5.hide() #@ Temporary. def _loadGroupBox1(self, pmGroupBox): """ Load widgets in group box 1. """ #Following toolbutton facilitates entering a temporary NanotubeLineMode #to create a CNT using endpoints of the specified line. self.specifyCntLineButton = PM_ToolButton( pmGroupBox, text="Specify Endpoints", iconPath="ui/actions/Properties Manager/Pencil.png", spanWidth=True) self.specifyCntLineButton.setCheckable(True) self.specifyCntLineButton.setAutoRaise(True) self.specifyCntLineButton.setToolButtonStyle( Qt.ToolButtonTextBesideIcon) #EndPoint1 and endPoint2 coordinates. These widgets are hidden # as of 2007- 12 - 05 self._endPoint1SpinBoxes = PM_CoordinateSpinBoxes(pmGroupBox, label="End Point 1") self.x1SpinBox = self._endPoint1SpinBoxes.xSpinBox self.y1SpinBox = self._endPoint1SpinBoxes.ySpinBox self.z1SpinBox = self._endPoint1SpinBoxes.zSpinBox self._endPoint2SpinBoxes = PM_CoordinateSpinBoxes(pmGroupBox, label="End Point 2") self.x2SpinBox = self._endPoint2SpinBoxes.xSpinBox self.y2SpinBox = self._endPoint2SpinBoxes.ySpinBox self.z2SpinBox = self._endPoint2SpinBoxes.zSpinBox self._endPoint1SpinBoxes.hide() self._endPoint2SpinBoxes.hide() def _loadGroupBox2(self, pmGroupBox): """ Load widgets in group box 2. """ _ntTypeChoices = ['Carbon', 'Boron Nitride'] self.ntTypeComboBox = \ PM_ComboBox( pmGroupBox, label = "Type:", choices = _ntTypeChoices, setAsDefault = True) self.ntRiseDoubleSpinBox = \ PM_DoubleSpinBox( pmGroupBox, label = "Rise:", value = self.nanotube.getRise(), setAsDefault = True, minimum = 2.0, maximum = 4.0, decimals = 3, singleStep = 0.01 ) self.ntRiseDoubleSpinBox.hide() # Nanotube Length self.ntLengthLineEdit = \ PM_LineEdit( pmGroupBox, label = "Nanotube Length: ", text = "0.0 Angstroms", setAsDefault = False) self.ntLengthLineEdit.setDisabled(True) self.ntLengthLineEdit.hide() # Nanotube diameter self.ntDiameterLineEdit = \ PM_LineEdit( pmGroupBox, label = "Diameter: ", setAsDefault = False) self.ntDiameterLineEdit.setDisabled(True) self.updateNanotubeDiameter() self.chiralityNSpinBox = \ PM_SpinBox( pmGroupBox, label = "Chirality (n):", value = self.nanotube.getChiralityN(), minimum = 2, maximum = 100, setAsDefault = True ) self.chiralityMSpinBox = \ PM_SpinBox( pmGroupBox, label = "Chirality (m):", value = self.nanotube.getChiralityM(), minimum = 0, maximum = 100, setAsDefault = True ) # How about having user prefs for CNT and BNNT bond lengths? # I'm guessing that if the user wants to set these values, they will # do it once and would like those bond length values persist forever. # Need to discuss with others to determine if this spinbox comes out. # --Mark 2008-03-29 self.bondLengthDoubleSpinBox = \ PM_DoubleSpinBox( pmGroupBox, label = "Bond length:", value = self.nanotube.getBondLength(), setAsDefault = True, minimum = 1.0, maximum = 3.0, singleStep = 0.1, decimals = 3, suffix = " Angstroms" ) #self.bondLengthDoubleSpinBox.hide() endingChoices = ["Hydrogen", "None"] # Removed:, "Nitrogen"] self.endingsComboBox= \ PM_ComboBox( pmGroupBox, label = "Endings:", choices = endingChoices, index = 0, setAsDefault = True, spanWidth = False ) def _loadGroupBox3(self, inPmGroupBox): """ Load widgets in group box 3. """ self.zDistortionDoubleSpinBox = \ PM_DoubleSpinBox( inPmGroupBox, label = "Z-distortion:", value = 0.0, setAsDefault = True, minimum = 0.0, maximum = 10.0, singleStep = 0.1, decimals = 3, suffix = " Angstroms" ) self.xyDistortionDoubleSpinBox = \ PM_DoubleSpinBox( inPmGroupBox, label = "XY-distortion:", value = 0.0, setAsDefault = True, minimum = 0.0, maximum = 2.0, singleStep = 0.1, decimals = 3, suffix = " Angstroms" ) self.twistSpinBox = \ PM_SpinBox( inPmGroupBox, label = "Twist:", value = 0, setAsDefault = True, minimum = 0, maximum = 100, # What should maximum be? suffix = " deg/A" ) self.bendSpinBox = \ PM_SpinBox( inPmGroupBox, label = "Bend:", value = 0, setAsDefault = True, minimum = 0, maximum = 360, suffix = " deg" ) def _loadGroupBox4(self, inPmGroupBox): """ Load widgets in group box 4. """ # "Number of Nanotubes" SpinBox self.mwntCountSpinBox = \ PM_SpinBox( inPmGroupBox, label = "Number:", value = 1, setAsDefault = True, minimum = 1, maximum = 10, suffix = " nanotubes" ) self.mwntCountSpinBox.setSpecialValueText("SWNT") # "Spacing" lineedit. self.mwntSpacingDoubleSpinBox = \ PM_DoubleSpinBox( inPmGroupBox, label = "Spacing:", value = 2.46, setAsDefault = True, minimum = 1.0, maximum = 10.0, singleStep = 0.1, decimals = 3, suffix = " Angstroms" ) def _loadGroupBox5(self, pmGroupBox): """ Load widgets in group box 5. """ self._rubberbandLineGroupBox = PM_GroupBox(pmGroupBox, title='Rubber band Line:') ntLineChoices = ['Ladder'] self.ntRubberBandLineDisplayComboBox = \ PM_ComboBox( self._rubberbandLineGroupBox , label = " Display as:", choices = ntLineChoices, setAsDefault = True) self.lineSnapCheckBox = \ PM_CheckBox(self._rubberbandLineGroupBox , text = 'Enable line snap' , widgetColumn = 1, state = Qt.Checked ) def _connect_showCursorTextCheckBox(self): """ Connect the show cursor text checkbox with user prefs_key. Overrides DnaOrCnt_PropertyManager._connect_showCursorTextCheckBox """ connect_checkbox_with_boolean_pref( self.showCursorTextCheckBox, insertNanotubeEditCommand_showCursorTextCheckBox_prefs_key) def _params_for_creating_cursorTextCheckBoxes(self): """ Returns params needed to create various cursor text checkboxes connected to prefs_keys that allow custom cursor texts. @return: A list containing tuples in the following format: ('checkBoxTextString' , preference_key). PM_PrefsCheckBoxes uses this data to create checkboxes with the the given names and connects them to the provided preference keys. (Note that PM_PrefsCheckBoxes puts thes within a GroupBox) @rtype: list @see: PM_PrefsCheckBoxes @see: self._loadDisplayOptionsGroupBox where this list is used. @see: Superclass method which is overridden here -- DnaOrCnt_PropertyManager._params_for_creating_cursorTextCheckBoxes() """ params = \ [ #Format: (" checkbox text", prefs_key) ("Nanotube length", insertNanotubeEditCommand_cursorTextCheckBox_length_prefs_key ), ("Angle", insertNanotubeEditCommand_cursorTextCheckBox_angle_prefs_key ) ] return params def _addToolTipText(self): """ Tool Tip text for widgets in the Insert Nanotube Property Manager. """ pass def _setEndPoints(self): """ Set the two endpoints of the nanotube using the values from the X, Y, Z coordinate spinboxes in the property manager. @note: The group box containing the 2 sets of XYZ spin boxes are currently hidden. """ # First endpoint (origin) of nanotube x1 = self.x1SpinBox.value() y1 = self.y1SpinBox.value() z1 = self.z1SpinBox.value() # Second endpoint (direction vector/axis) of nanotube. x2 = self.x2SpinBox.value() y2 = self.y2SpinBox.value() z2 = self.z2SpinBox.value() if not self.endPoint1: self.endPoint1 = V(x1, y1, z1) if not self.endPoint2: self.endPoint2 = V(x2, y2, z2) self.nanotube.setEndPoints(self.endPoint1, self.endPoint2) # Need arg "recompute=True", which will recompute the second # endpoint (endPoint2) using the nanotube rise. def getParameters(self): """ Return the parameters from this property manager to be used to create the nanotube. @return: A nanotube instance with its attrs set to the current parameters in the property manager. @rtype: L{Nanotube} @see: L{InsertNanotube_EditCommand._gatherParameters} where this is used """ self._setEndPoints() return (self.nanotube) def _ntTypeComboBoxChanged(self, type): """ Slot for the Type combobox. It is called whenever the Type choice is changed. @param inIndex: The new index. @type inIndex: int """ self.nanotube.setType(str(type)) print "Bond Length =", self.nanotube.getBondLength() self.bondLengthDoubleSpinBox.setValue(self.nanotube.getBondLength()) #self.bondLengthDoubleSpinBox.setValue(ntBondLengths[inIndex]) def _bondLengthChanged(self, bondLength): """ Slot for the B{Bond Length} spinbox. """ self.nanotube.setBondLength(bondLength) self.updateNanotubeDiameter() return def _chiralityFixup(self, spinBoxValueJunk=None): """ Slot for several validators for different parameters. This gets called whenever the user changes the n, m chirality values. @param spinBoxValueJunk: This is the Spinbox value from the valueChanged signal. It is not used. We just want to know that the spinbox value has changed. @type spinBoxValueJunk: double or None """ _n, _m = self.nanotube.setChirality(self.chiralityNSpinBox.value(), self.chiralityMSpinBox.value()) #self.n, self.m = self.nanotube.getChirality() self.connect_or_disconnect_signals(isConnect=False) self.chiralityNSpinBox.setValue(_n) self.chiralityMSpinBox.setValue(_m) self.connect_or_disconnect_signals(isConnect=True) self.updateNanotubeDiameter() def updateNanotubeDiameter(self): """ Update the nanotube Diameter lineEdit widget. """ diameterText = "%-7.4f Angstroms" % (self.nanotube.getDiameter()) self.ntDiameterLineEdit.setText(diameterText) # ntRiseDoubleSpinBox is currently hidden. self.ntRiseDoubleSpinBox.setValue(self.nanotube.getRise()) def _endingsComboBoxChanged(self, endings): """ Slot for the B{Ending} combobox. @param endings: The option's text. @type endings: string """ self.nanotube.setEndings(str(endings)) return def _addWhatsThisText(self): """ What's This text for widgets in this Property Manager. """ whatsThis_InsertNanotube_PropertyManager(self) return
class Ui_CookiePropertyManager(PM_Dialog): """ The Ui_CookiePropertyManager class defines UI elements for the Property Manager of the B{Crystal mode}. @ivar title: The title that appears in the property manager header. @type title: str @ivar pmName: The name of this property manager. This is used to set the name of the PM_Dialog object via setObjectName(). @type name: str @ivar iconPath: The relative path to the PNG file that contains a 22 x 22 icon image that appears in the PM header. @type iconPath: str """ # <title> - the title that appears in the property manager header. title = "Build Crystal" # <iconPath> - full path to PNG file that appears in the header. # The name of this Property Manager. This will be set to # the name of the PM_Dialog object via setObjectName(). pmName = title iconPath = "ui/actions/Tools/Build Structures/Build Crystal.png" def __init__(self, parentMode): """ Constructor for the B{Crystal} property manager class that defines its UI. @param parentMode: The parent mode where this Property Manager is used @type parentMode: L{cookieMode} """ self.parentMode = parentMode self.w = self.parentMode.w self.win = self.parentMode.w self.pw = self.parentMode.pw self.o = self.parentMode.o PM_Dialog.__init__(self, self.pmName, self.iconPath, self.title) self.showTopRowButtons( PM_DONE_BUTTON | \ PM_CANCEL_BUTTON | \ PM_WHATS_THIS_BUTTON) msg = '' self.MessageGroupBox.insertHtmlMessage(msg, setAsDefault=False) def _addGroupBoxes(self): """ Add various group boxes to the Property manager. """ self._addCrystalSpecsGroupbox() self._addLayerPropertiesGroupBox() self._addDisplayOptionsGroupBox() self._addAdvancedOptionsGroupBox() def _addCrystalSpecsGroupbox(self): """ Add 'Crystal groupbox' to the PM """ self.crystalSpecsGroupBox = \ PM_GroupBox(self, title = "Crystal Specifications") self._loadCrystalSpecsGroupBox(self.crystalSpecsGroupBox) def _addLayerPropertiesGroupBox(self): """ Add 'Layer Properties' groupbox to the PM """ self.layerPropertiesGroupBox = \ PM_GroupBox(self, title = "Layer Properties") self._loadLayerPropertiesGroupBox(self.layerPropertiesGroupBox) def _addAdvancedOptionsGroupBox(self): """ Add 'Advanced Options' groupbox """ self.advancedOptionsGroupBox = \ PM_GroupBox( self, title = "Advanced Options" ) self._loadAdvancedOptionsGroupBox(self.advancedOptionsGroupBox) def _addDisplayOptionsGroupBox(self): """ Add 'Display Options' groupbox """ self.displayOptionsGroupBox = PM_GroupBox(self, title='Display Options') self._loadDisplayOptionsGroupBox(self.displayOptionsGroupBox) def _loadCrystalSpecsGroupBox(self, inPmGroupBox): """ Load widgets in the Crystal Specifications group box. @param inPmGroupBox: The Crystal Specifications groupbox in the PM @type inPmGroupBox: L{PM_GroupBox} """ latticeChoices = ["Diamond", "Lonsdaleite"] self.latticeCBox = \ PM_ComboBox( inPmGroupBox, label = 'Lattice:', labelColumn = 0, choices = latticeChoices, index = 0, setAsDefault = True, spanWidth = False ) # Button list to create a toolbutton row. # Format: # - buttonType, # - buttonId, # - buttonText , # - iconPath # - tooltip # - shortcut # - column BUTTON_LIST = [("QToolButton", 0, "Surface 100", "ui/actions/Properties Manager/Surface100.png", "Surface 100", "", 0), ("QToolButton", 1, "Surface 110", "ui/actions/Properties Manager/Surface110.png", "Surface 110", "", 1), ("QToolButton", 2, "Surface 111", "ui/actions/Properties Manager/Surface111.png", "Surface 110", "", 2)] self.gridOrientationButtonRow = \ PM_ToolButtonRow(inPmGroupBox, title = "", label = "Orientation:", buttonList = BUTTON_LIST, checkedId = 0, setAsDefault = True, spanWidth = False ) self.orientButtonGroup = self.gridOrientationButtonRow.buttonGroup self.surface100_btn = self.gridOrientationButtonRow.getButtonById(0) self.surface110_btn = self.gridOrientationButtonRow.getButtonById(1) self.surface111_btn = self.gridOrientationButtonRow.getButtonById(2) self.rotateGridByAngleSpinBox = \ PM_SpinBox( inPmGroupBox, label = "Rotate by: ", labelColumn = 0, value = 45, minimum = 0, maximum = 360, singleStep = 5, suffix = " degrees") GRID_ANGLE_BUTTONS = [ ("QToolButton", 0, "Anticlockwise", "ui/actions/Properties Manager/rotate_minus.png", "", "+", 0), ("QToolButton", 1, "Clockwise", "ui/actions/Properties Manager/rotate_plus.png", "", "-", 1) ] self.gridRotateButtonRow = \ PM_ToolButtonRow( inPmGroupBox, title = "", buttonList = GRID_ANGLE_BUTTONS, label = 'Rotate grid:', isAutoRaise = False, isCheckable = False ) self.rotGridAntiClockwiseButton = \ self.gridRotateButtonRow.getButtonById(0) self.rotGridClockwiseButton = \ self.gridRotateButtonRow.getButtonById(1) def _loadLayerPropertiesGroupBox(self, inPmGroupBox): """ Load widgets in the Layer Properties group box. @param inPmGroupBox: The Layer Properties groupbox in the PM @type inPmGroupBox: L{PM_GroupBox} """ self.currentLayerComboBox = \ PM_ComboBox( inPmGroupBox, index = 0, spanWidth = True ) self.addLayerButton = PM_PushButton(inPmGroupBox) self.addLayerButton.setIcon( geticon('ui/actions/Properties Manager/addlayer.png')) self.addLayerButton.setFixedSize(QSize(26, 26)) self.addLayerButton.setIconSize(QSize(22, 22)) # A widget list to create a widget row. # Format: # - Widget type, # - widget object, # - column firstRowWidgetList = [('PM_ComboBox', self.currentLayerComboBox, 1), ('PM_PushButton', self.addLayerButton, 2)] widgetRow = PM_WidgetRow( inPmGroupBox, title='', widgetList=firstRowWidgetList, label="Layer:", labelColumn=0, ) self.layerCellsSpinBox = \ PM_SpinBox( inPmGroupBox, label = "Lattice cells:", labelColumn = 0, value = 2, minimum = 1, maximum = 25 ) self.layerThicknessLineEdit = PM_LineEdit(inPmGroupBox, label="Thickness:", text="", setAsDefault=False, spanWidth=False) #self.layerThicknessLineEdit.setReadOnly(True) self.layerThicknessLineEdit.setDisabled(True) tooltip = "Thickness of layer in Angstroms" self.layerThicknessLineEdit.setToolTip(tooltip) def _loadAdvancedOptionsGroupBox(self, inPmGroupBox): """ Load widgets in the Advanced Options group box. @param inPmGroupBox: The Advanced Options box in the PM @type inPmGroupBox: L{PM_GroupBox} """ self.snapGridCheckBox = \ PM_CheckBox(inPmGroupBox, text = "Snap to grid", state = Qt.Checked ) tooltip = "Snap selection point to a nearest cell grid point." self.snapGridCheckBox.setToolTip(tooltip) self.freeViewCheckBox = \ PM_CheckBox(inPmGroupBox, text = "Enable free view", state = Qt.Unchecked ) def _loadDisplayOptionsGroupBox(self, inPmGroupBox): """ Load widgets in the Display Options groupbox. @param inPmGroupBox: The Display Options groupbox @type inPmGroupBox: L{PM_GroupBox} """ displayChoices = ['Tubes', 'Spheres'] self.dispModeComboBox = \ PM_ComboBox( inPmGroupBox, label = 'Display style:', choices = displayChoices, index = 0, setAsDefault = False, spanWidth = False ) self.gridLineCheckBox = PM_CheckBox(inPmGroupBox, text="Show grid lines", widgetColumn=0, state=Qt.Checked) self.fullModelCheckBox = PM_CheckBox(inPmGroupBox, text="Show model", widgetColumn=0, state=Qt.Unchecked) def _addWhatsThisText(self): """ What's This text for widgets in this Property Manager. @note: Many PM widgets are still missing their "What's This" text. """ from ne1_ui.WhatsThisText_for_PropertyManagers import whatsThis_CookiePropertyManager whatsThis_CookiePropertyManager(self) def _addToolTipText(self): """ What's Tool Tip text for widgets in this Property Manager. """ from ne1_ui.ToolTipText_for_PropertyManagers import ToolTip_CookiePropertyManager ToolTip_CookiePropertyManager(self)
class DnaSegment_PropertyManager( DnaOrCnt_PropertyManager): """ The DnaSegmenta_PropertyManager class provides a Property Manager for the DnaSegment_EditCommand. @ivar title: The title that appears in the property manager header. @type title: str @ivar pmName: The name of this property manager. This is used to set the name of the PM_Dialog object via setObjectName(). @type name: str @ivar iconPath: The relative path to the PNG file that contains a 22 x 22 icon image that appears in the PM header. @type iconPath: str """ title = "DnaSegment Properties" pmName = title iconPath = "ui/actions/Tools/Build Structures/DNA.png" def __init__( self, win, editCommand ): """ Constructor for the Build DNA property manager. """ #For model changed signal #@see: self.model_changed() and self._current_model_changed_params #for example use self._previous_model_changed_params = None #see self.connect_or_disconnect_signals for comment about this flag self.isAlreadyConnected = False self.isAlreadyDisconnected = False self.endPoint1 = V(0, 0, 0) self.endPoint2 = V(0, 0, 0) self._numberOfBases = 0 self._conformation = 'B-DNA' self.duplexRise = 3.18 self.basesPerTurn = 10 self.dnaModel = 'PAM3' _superclass.__init__( self, win, editCommand) self.showTopRowButtons( PM_DONE_BUTTON | \ PM_CANCEL_BUTTON | \ PM_PREVIEW_BUTTON | \ PM_WHATS_THIS_BUTTON) msg = "Use resize handles to resize the segment. Drag any axis or sugar"\ " atom for translation or rotation about axis respectively. Dragging"\ " any bond will freely move the whole segment." self.updateMessage(msg) def connect_or_disconnect_signals(self, isConnect): """ Connect or disconnect widget signals sent to their slot methods. This can be overridden in subclasses. By default it does nothing. @param isConnect: If True the widget will send the signals to the slot method. @type isConnect: boolean """ if isConnect: change_connect = self.win.connect else: change_connect = self.win.disconnect _superclass.connect_or_disconnect_signals(self, isConnect) change_connect( self.numberOfBasePairsSpinBox, SIGNAL("valueChanged(int)"), self.numberOfBasesChanged ) change_connect( self.basesPerTurnDoubleSpinBox, SIGNAL("valueChanged(double)"), self.basesPerTurnChanged ) change_connect( self.duplexRiseDoubleSpinBox, SIGNAL("valueChanged(double)"), self.duplexRiseChanged ) change_connect(self.showCursorTextCheckBox, SIGNAL('stateChanged(int)'), self._update_state_of_cursorTextGroupBox) def model_changed(self): """ @see: DnaSegment_EditCommand.model_changed() @see: DnaSegment_EditCommand.hasResizableStructure() @see: self._current_model_changed_params() """ currentParams = self._current_model_changed_params() #Optimization. Return from the model_changed method if the #params are the same. if same_vals(currentParams, self._previous_model_changed_params): return isStructResizable, why_not = currentParams #update the self._previous_model_changed_params with this new param set. self._previous_model_changed_params = currentParams if not isStructResizable: #disable all widgets if self._pmGroupBox1.isEnabled(): self._pmGroupBox1.setEnabled(False) msg = redmsg("DnaSegment is not resizable. Reason: %s"%(why_not)) self.updateMessage(msg) else: if not self._pmGroupBox1.isEnabled(): self._pmGroupBox1.setEnabled(True) msg = "Use resize handles to resize the segment. Drag any axis or sugar"\ " atom for translation or rotation about axis respectively. Dragging"\ " any bond will freely move the whole segment." self.updateMessage(msg) def _current_model_changed_params(self): """ Returns a tuple containing the parameters that will be compared against the previously stored parameters. This provides a quick test to determine whether to do more things in self.model_changed() @see: self.model_changed() which calls this @see: self._previous_model_changed_params attr. """ params = None if self.editCommand: isStructResizable, why_not = self.editCommand.hasResizableStructure() params = (isStructResizable, why_not) return params def show(self): """ Show this property manager. Overrides EditCommand_PM.show() This method also retrives the name information from the editCommand's structure for its name line edit field. @see: DnaSegment_EditCommand.getStructureName() @see: self.close() """ _superclass.show(self) if self.editCommand is not None: name = self.editCommand.getStructureName() if name is not None: self.nameLineEdit.setText(name) def close(self): """ Close this property manager. Also sets the name of the self.editCommand's structure to the one displayed in the line edit field. @see self.show() @see: DnaSegment_EditCommand.setStructureName """ if self.editCommand is not None: name = str(self.nameLineEdit.text()) self.editCommand.setStructureName(name) _superclass.close(self) def setParameters(self, params): """ This is usually called when you are editing an existing structure. Some property manager ui elements then display the information obtained from the object being edited. TODO: - Make this a EditCommand_PM API method? - See also the routines GraphicsMode.setParams or object.setProps ..better to name them all in one style? """ numberOfBasePairs, \ dnaForm, \ dnaModel,\ basesPerTurn, \ duplexRise, \ endPoint1, \ endPoint2 , \ color = params if numberOfBasePairs is not None: self.numberOfBasePairsSpinBox.setValue(numberOfBasePairs) if dnaForm is not None: self._conformation = dnaForm if dnaModel is not None: self.dnaModel = dnaModel if duplexRise is not None: self.duplexRiseDoubleSpinBox.setValue(duplexRise) if basesPerTurn is not None: self.basesPerTurnDoubleSpinBox.setValue(basesPerTurn) if endPoint1 is not None: self.endPoint1 = endPoint1 if endPoint2 is not None: self.endPoint2 = endPoint2 if color is not None: self._colorChooser.setColor(color) def getParameters(self): """ """ #See bug 2802 for details about the parameter #'number_of_basePairs_from_struct'. Basically it is used to check #if the structure got modified (e.g. because of undo) #The numberOfBases parameter obtained from the propMgr is given as a #separate parameter for the reasons mentioned in bug 2802 #-- Ninad 2008-04-12 number_of_basePairs_from_struct = None if self.editCommand.hasValidStructure(): number_of_basePairs_from_struct = self.editCommand.struct.getNumberOfBasePairs() numberOfBases = self.numberOfBasePairsSpinBox.value() dnaForm = self._conformation dnaModel = self.dnaModel basesPerTurn = self.basesPerTurn duplexRise = self.duplexRise color = self._colorChooser.getColor() return ( number_of_basePairs_from_struct, numberOfBases, dnaForm, dnaModel, basesPerTurn, duplexRise, self.endPoint1, self.endPoint2, color ) def numberOfBasesChanged( self, numberOfBases ): """ Slot for the B{Number of Bases" spinbox. """ duplexRise = self.duplexRiseDoubleSpinBox.value() # Update the Duplex Length lineEdit widget. text = str(getDuplexLength(self._conformation, numberOfBases, duplexRise = duplexRise)) \ + " Angstroms" self.duplexLengthLineEdit.setText(text) return def basesPerTurnChanged( self, basesPerTurn ): """ Slot for the B{Bases per turn} spinbox. """ self.basesPerTurn = basesPerTurn def duplexRiseChanged( self, rise ): """ Slot for the B{Rise} spinbox. """ self.duplexRise = rise def _addGroupBoxes( self ): """ Add the DNA Property Manager group boxes. """ self._pmGroupBox1 = PM_GroupBox( self, title = "Parameters" ) self._loadGroupBox1( self._pmGroupBox1 ) self._displayOptionsGroupBox = PM_GroupBox( self, title = "Display Options" ) self._loadDisplayOptionsGroupBox( self._displayOptionsGroupBox ) def _loadGroupBox1(self, pmGroupBox): """ Load widgets in group box 4. """ self.nameLineEdit = PM_LineEdit( pmGroupBox, label = "Segment name:", text = "", setAsDefault = False) # Strand Length (i.e. the number of bases) self.numberOfBasePairsSpinBox = \ PM_SpinBox( pmGroupBox, label = "Base pairs:", value = self._numberOfBases, setAsDefault = False, minimum = 2, maximum = 10000 ) self.basesPerTurnDoubleSpinBox = \ PM_DoubleSpinBox( pmGroupBox, label = "Bases per turn:", value = self.basesPerTurn, setAsDefault = True, minimum = 8.0, maximum = 20.0, decimals = 2, singleStep = 0.1 ) self.duplexRiseDoubleSpinBox = \ PM_DoubleSpinBox( pmGroupBox, label = "Rise:", value = self.duplexRise, setAsDefault = True, minimum = 2.0, maximum = 4.0, decimals = 3, singleStep = 0.01 ) # Duplex Length self.duplexLengthLineEdit = \ PM_LineEdit( pmGroupBox, label = "Duplex length: ", text = "0.0 Angstroms", setAsDefault = False) self.duplexLengthLineEdit.setDisabled(True) def _loadDisplayOptionsGroupBox(self, pmGroupBox): """ Overrides superclass method. Also loads the color chooser widget. """ self._loadColorChooser(pmGroupBox) _superclass._loadDisplayOptionsGroupBox(self, pmGroupBox) def _connect_showCursorTextCheckBox(self): """ Connect the show cursor text checkbox with user prefs_key. Overrides DnaOrCnt_PropertyManager._connect_showCursorTextCheckBox """ connect_checkbox_with_boolean_pref( self.showCursorTextCheckBox , dnaSegmentEditCommand_showCursorTextCheckBox_prefs_key) def _params_for_creating_cursorTextCheckBoxes(self): """ Returns params needed to create various cursor text checkboxes connected to prefs_keys that allow custom cursor texts. @return: A list containing tuples in the following format: ('checkBoxTextString' , preference_key). PM_PrefsCheckBoxes uses this data to create checkboxes with the the given names and connects them to the provided preference keys. (Note that PM_PrefsCheckBoxes puts thes within a GroupBox) @rtype: list @see: PM_PrefsCheckBoxes @see: self._loadDisplayOptionsGroupBox where this list is used. @see: Superclass method which is overridden here -- DnaOrCnt_PropertyManager._params_for_creating_cursorTextCheckBoxes() """ params = \ [ #Format: (" checkbox text", prefs_key) ("Number of base pairs", dnaSegmentEditCommand_cursorTextCheckBox_numberOfBasePairs_prefs_key), ("Duplex length", dnaSegmentEditCommand_cursorTextCheckBox_length_prefs_key), ("Number of basepairs to be changed", dnaSegmentEditCommand_cursorTextCheckBox_changedBasePairs_prefs_key) ] return params def _addWhatsThisText(self): """ Add what's this text. """ pass def _addToolTipText(self): """ Add Tooltip text """ pass
class InsertDna_PropertyManager(DnaOrCnt_PropertyManager): """ The InsertDna_PropertyManager class provides a Property Manager for the B{Insert Dna} command. @ivar title: The title that appears in the property manager header. @type title: str @ivar pmName: The name of this property manager. This is used to set the name of the PM_Dialog object via setObjectName(). @type name: str @ivar iconPath: The relative path to the PNG file that contains a 22 x 22 icon image that appears in the PM header. @type iconPath: str """ title = "Insert DNA" pmName = title iconPath = "ui/actions/Command Toolbar/BuildDna/InsertDna.png" def __init__(self, command): """ Constructor for the DNA Duplex property manager. """ self.endPoint1 = None self.endPoint2 = None self._conformation = "B-DNA" self._numberOfBases = 0 self._basesPerTurn = getDuplexBasesPerTurn(self._conformation) self._duplexRise = getDuplexRise(self._conformation) self._duplexLength = getDuplexLength(self._conformation, self._numberOfBases) _superclass.__init__(self, command) self.showTopRowButtons( PM_DONE_BUTTON | \ PM_CANCEL_BUTTON | \ PM_WHATS_THIS_BUTTON) def connect_or_disconnect_signals(self, isConnect): """ Connect or disconnect widget signals sent to their slot methods. This can be overridden in subclasses. By default it does nothing. @param isConnect: If True the widget will send the signals to the slot method. @type isConnect: boolean """ if isConnect: change_connect = self.win.connect else: change_connect = self.win.disconnect change_connect(self._placementOptions.buttonGroup, SIGNAL("buttonClicked(int)"), self.activateSpecifyReferencePlaneTool) change_connect(self.conformationComboBox, SIGNAL("currentIndexChanged(int)"), self.conformationComboBoxChanged) change_connect(self.numberOfBasePairsSpinBox, SIGNAL("valueChanged(int)"), self.numberOfBasesChanged) change_connect(self.basesPerTurnDoubleSpinBox, SIGNAL("valueChanged(double)"), self.basesPerTurnChanged) change_connect(self.duplexRiseDoubleSpinBox, SIGNAL("valueChanged(double)"), self.duplexRiseChanged) change_connect(self.showCursorTextCheckBox, SIGNAL('stateChanged(int)'), self._update_state_of_cursorTextGroupBox) self.duplexRiseDoubleSpinBox.connectWithState( Preferences_StateRef_double(bdnaRise_prefs_key, env.prefs[bdnaRise_prefs_key])) self.basesPerTurnDoubleSpinBox.connectWithState( Preferences_StateRef_double(bdnaBasesPerTurn_prefs_key, env.prefs[bdnaBasesPerTurn_prefs_key])) def show(self): _superclass.show(self) self.updateMessage("Specify the DNA parameters below, then click "\ "two endpoints in the graphics area to insert a DNA duplex.") def _addGroupBoxes(self): """ Add the DNA Property Manager group boxes. """ self._pmReferencePlaneGroupBox = PM_GroupBox(self, title="Placement Options") self._loadReferencePlaneGroupBox(self._pmReferencePlaneGroupBox) self._pmGroupBox1 = PM_GroupBox(self, title="Endpoints") self._loadGroupBox1(self._pmGroupBox1) self._pmGroupBox1.hide() self._pmGroupBox2 = PM_GroupBox(self, title="Parameters") self._loadGroupBox2(self._pmGroupBox2) self._displayOptionsGroupBox = PM_GroupBox(self, title="Display Options") self._loadDisplayOptionsGroupBox(self._displayOptionsGroupBox) def _loadGroupBox1(self, pmGroupBox): """ Load widgets in group box 3. """ #Folllowing toolbutton facilitates entering a temporary DnaLineMode #to create a DNA using endpoints of the specified line. self.specifyDnaLineButton = PM_ToolButton( pmGroupBox, text="Specify Endpoints", iconPath="ui/actions/Properties Manager/Pencil.png", spanWidth=True) self.specifyDnaLineButton.setCheckable(True) self.specifyDnaLineButton.setAutoRaise(True) self.specifyDnaLineButton.setToolButtonStyle( Qt.ToolButtonTextBesideIcon) #EndPoint1 and endPoint2 coordinates. These widgets are hidden # as of 2007- 12 - 05 self._endPoint1SpinBoxes = PM_CoordinateSpinBoxes(pmGroupBox, label="End Point 1") self.x1SpinBox = self._endPoint1SpinBoxes.xSpinBox self.y1SpinBox = self._endPoint1SpinBoxes.ySpinBox self.z1SpinBox = self._endPoint1SpinBoxes.zSpinBox self._endPoint2SpinBoxes = PM_CoordinateSpinBoxes(pmGroupBox, label="End Point 2") self.x2SpinBox = self._endPoint2SpinBoxes.xSpinBox self.y2SpinBox = self._endPoint2SpinBoxes.ySpinBox self.z2SpinBox = self._endPoint2SpinBoxes.zSpinBox self._endPoint1SpinBoxes.hide() self._endPoint2SpinBoxes.hide() def _loadGroupBox2(self, pmGroupBox): """ Load widgets in group box 4. """ self.conformationComboBox = \ PM_ComboBox( pmGroupBox, label = "Conformation:", choices = ["B-DNA"], setAsDefault = True) dnaModelChoices = ['PAM3', 'PAM5'] self.dnaModelComboBox = \ PM_ComboBox( pmGroupBox, label = "Model:", choices = dnaModelChoices, setAsDefault = True) self.basesPerTurnDoubleSpinBox = \ PM_DoubleSpinBox( pmGroupBox, label = "Bases per turn:", value = env.prefs[bdnaBasesPerTurn_prefs_key], setAsDefault = True, minimum = 8.0, maximum = 20.0, decimals = 2, singleStep = 0.1 ) self.duplexRiseDoubleSpinBox = \ PM_DoubleSpinBox( pmGroupBox, label = "Rise:", value = env.prefs[bdnaRise_prefs_key], setAsDefault = True, minimum = 2.0, maximum = 4.0, decimals = 3, singleStep = 0.01 ) # Strand Length (i.e. the number of bases) self.numberOfBasePairsSpinBox = \ PM_SpinBox( pmGroupBox, label = "Base pairs:", value = self._numberOfBases, setAsDefault = False, minimum = 0, maximum = 10000 ) self.numberOfBasePairsSpinBox.setDisabled(True) # Duplex Length self.duplexLengthLineEdit = \ PM_LineEdit( pmGroupBox, label = "Duplex length: ", text = "0.0 Angstroms", setAsDefault = False) self.duplexLengthLineEdit.setDisabled(True) def _loadDisplayOptionsGroupBox(self, pmGroupBox): """ Load widgets in the Display Options GroupBox @see: DnaOrCnt_PropertyManager. _loadDisplayOptionsGroupBox """ #Call the superclass method that loads the cursor text checkboxes. #Note, as of 2008-05-19, the superclass, DnaOrCnt_PropertyManager #only loads the cursor text groupboxes. Subclasses like this can #call custom methods like self._loadCursorTextCheckBoxes etc if they #don't need all groupboxes that the superclass loads. _superclass._loadDisplayOptionsGroupBox(self, pmGroupBox) self._rubberbandLineGroupBox = PM_GroupBox(pmGroupBox, title='Rubber band line:') dnaLineChoices = ['Ribbons', 'Ladder'] self.dnaRubberBandLineDisplayComboBox = \ PM_ComboBox( self._rubberbandLineGroupBox , label = " Display as:", choices = dnaLineChoices, setAsDefault = True) self.lineSnapCheckBox = \ PM_CheckBox(self._rubberbandLineGroupBox , text = 'Enable line snap' , widgetColumn = 1, state = Qt.Checked ) def _connect_showCursorTextCheckBox(self): """ Connect the show cursor text checkbox with user prefs_key. Overrides DnaOrCnt_PropertyManager._connect_showCursorTextCheckBox """ connect_checkbox_with_boolean_pref( self.showCursorTextCheckBox, dnaDuplexEditCommand_showCursorTextCheckBox_prefs_key) def _params_for_creating_cursorTextCheckBoxes(self): """ Returns params needed to create various cursor text checkboxes connected to prefs_keys that allow custom cursor texts. @return: A list containing tuples in the following format: ('checkBoxTextString' , preference_key). PM_PrefsCheckBoxes uses this data to create checkboxes with the the given names and connects them to the provided preference keys. (Note that PM_PrefsCheckBoxes puts thes within a GroupBox) @rtype: list @see: PM_PrefsCheckBoxes @see: self._loadDisplayOptionsGroupBox where this list is used. @see: Superclass method which is overridden here -- DnaOrCnt_PropertyManager._params_for_creating_cursorTextCheckBoxes() """ params = \ [ #Format: (" checkbox text", prefs_key) ("Number of base pairs", dnaDuplexEditCommand_cursorTextCheckBox_numberOfBasePairs_prefs_key), ("Number of turns", dnaDuplexEditCommand_cursorTextCheckBox_numberOfTurns_prefs_key), ("Duplex length", dnaDuplexEditCommand_cursorTextCheckBox_length_prefs_key), ("Angle", dnaDuplexEditCommand_cursorTextCheckBox_angle_prefs_key) ] return params def _addToolTipText(self): """ Tool Tip text for widgets in the DNA Property Manager. """ pass def conformationComboBoxChanged(self, inIndex): """ Slot for the Conformation combobox. It is called whenever the Conformation choice is changed. @param inIndex: The new index. @type inIndex: int """ conformation = self.conformationComboBox.currentText() if conformation == "B-DNA": self.basesPerTurnDoubleSpinBox.setValue("10.0") elif conformation == "Z-DNA": self.basesPerTurnDoubleSpinBox.setValue("12.0") else: msg = redmsg("conformationComboBoxChanged(): \ Error - unknown DNA conformation. Index = " + inIndex) env.history.message(msg) self.duplexLengthSpinBox.setSingleStep(getDuplexRise(conformation)) def numberOfBasesChanged(self, numberOfBases): """ Slot for the B{Number of Bases} spinbox. """ # Update the Duplex Length lineEdit widget. text = str(getDuplexLength(self._conformation, numberOfBases, self._duplexRise)) \ + " Angstroms" self.duplexLengthLineEdit.setText(text) return def basesPerTurnChanged(self, basesPerTurn): """ Slot for the B{Bases per turn} spinbox. """ self.command.basesPerTurn = basesPerTurn self._basesPerTurn = basesPerTurn return def duplexRiseChanged(self, rise): """ Slot for the B{Rise} spinbox. """ self.command.duplexRise = rise self._duplexRise = rise return def getParameters(self): """ Return the parameters from this property manager to be used to create the DNA duplex. @return: A tuple containing the parameters @rtype: tuple @see: L{InsertDna_EditCommand._gatherParameters} where this is used """ numberOfBases = self.numberOfBasePairsSpinBox.value() dnaForm = str(self.conformationComboBox.currentText()) basesPerTurn = self.basesPerTurnDoubleSpinBox.value() duplexRise = self.duplexRiseDoubleSpinBox.value() dnaModel = str(self.dnaModelComboBox.currentText()) # First endpoint (origin) of DNA duplex x1 = self.x1SpinBox.value() y1 = self.y1SpinBox.value() z1 = self.z1SpinBox.value() # Second endpoint (direction vector/axis) of DNA duplex. x2 = self.x2SpinBox.value() y2 = self.y2SpinBox.value() z2 = self.z2SpinBox.value() if not self.endPoint1: self.endPoint1 = V(x1, y1, z1) if not self.endPoint2: self.endPoint2 = V(x2, y2, z2) return (numberOfBases, dnaForm, dnaModel, basesPerTurn, duplexRise, self.endPoint1, self.endPoint2) def _addWhatsThisText(self): """ What's This text for widgets in this Property Manager. """ whatsThis_InsertDna_PropertyManager(self)
class Ui_BuildCrystal_PropertyManager(Command_PropertyManager): """ The Ui_BuildCrystal_PropertyManager class defines UI elements for the Property Manager of the B{Crystal mode}. @ivar title: The title that appears in the property manager header. @type title: str @ivar pmName: The name of this property manager. This is used to set the name of the PM_Dialog object via setObjectName(). @type name: str @ivar iconPath: The relative path to the PNG file that contains a 22 x 22 icon image that appears in the PM header. @type iconPath: str """ # <title> - the title that appears in the property manager header. title = "Build Crystal" # <iconPath> - full path to PNG file that appears in the header. # The name of this Property Manager. This will be set to # the name of the PM_Dialog object via setObjectName(). pmName = title iconPath = "ui/actions/Tools/Build Structures/Build Crystal.png" def __init__(self, command): """ Constructor for the B{Crystal} property manager class that defines its UI. @param command: The parent mode where this Property Manager is used @type command: L{BuildCrystal_Command} """ _superclass.__init__(self, command) self.showTopRowButtons( PM_DONE_BUTTON | \ PM_CANCEL_BUTTON | \ PM_WHATS_THIS_BUTTON) def _addGroupBoxes(self): """ Add various group boxes to the Property manager. """ self._addCrystalSpecsGroupbox() self._addLayerPropertiesGroupBox() self._addDisplayOptionsGroupBox() self._addAdvancedOptionsGroupBox() def _addCrystalSpecsGroupbox(self): """ Add 'Crystal groupbox' to the PM """ self.crystalSpecsGroupBox = \ PM_GroupBox(self, title = "Crystal Specifications") self._loadCrystalSpecsGroupBox(self.crystalSpecsGroupBox) def _addLayerPropertiesGroupBox(self): """ Add 'Layer Properties' groupbox to the PM """ self.layerPropertiesGroupBox = \ PM_GroupBox(self, title = "Layer Properties") self._loadLayerPropertiesGroupBox(self.layerPropertiesGroupBox) def _addAdvancedOptionsGroupBox(self): """ Add 'Advanced Options' groupbox """ self.advancedOptionsGroupBox = \ PM_GroupBox( self, title = "Advanced Options" ) self._loadAdvancedOptionsGroupBox(self.advancedOptionsGroupBox) def _addDisplayOptionsGroupBox(self): """ Add 'Display Options' groupbox """ self.displayOptionsGroupBox = PM_GroupBox(self, title = 'Display Options') self._loadDisplayOptionsGroupBox(self.displayOptionsGroupBox) def _loadCrystalSpecsGroupBox(self, inPmGroupBox): """ Load widgets in the Crystal Specifications group box. @param inPmGroupBox: The Crystal Specifications groupbox in the PM @type inPmGroupBox: L{PM_GroupBox} """ latticeChoices = ["Diamond", "Lonsdaleite"] self.latticeCBox = \ PM_ComboBox( inPmGroupBox, label = 'Lattice:', labelColumn = 0, choices = latticeChoices, index = 0, setAsDefault = True, spanWidth = False ) # Button list to create a toolbutton row. # Format: # - buttonType, # - buttonId, # - buttonText , # - iconPath # - tooltip # - shortcut # - column BUTTON_LIST = [ ( "QToolButton", 0, "Surface 100", "ui/actions/Properties Manager/Surface100.png", "Surface 100", "", 0), ( "QToolButton", 1, "Surface 110", "ui/actions/Properties Manager/Surface110.png", "Surface 110", "", 1), ( "QToolButton", 2, "Surface 111", "ui/actions/Properties Manager/Surface111.png", "Surface 110", "", 2) ] self.gridOrientationButtonRow = \ PM_ToolButtonRow(inPmGroupBox, title = "", label = "Orientation:", buttonList = BUTTON_LIST, checkedId = 0, setAsDefault = True, spanWidth = False ) self.orientButtonGroup = self.gridOrientationButtonRow.buttonGroup self.surface100_btn = self.gridOrientationButtonRow.getButtonById(0) self.surface110_btn = self.gridOrientationButtonRow.getButtonById(1) self.surface111_btn = self.gridOrientationButtonRow.getButtonById(2) self.rotateGridByAngleSpinBox = \ PM_SpinBox( inPmGroupBox, label = "Rotate by: ", labelColumn = 0, value = 45, minimum = 0, maximum = 360, singleStep = 5, suffix = " degrees") GRID_ANGLE_BUTTONS = [ ("QToolButton", 0, "Anticlockwise", "ui/actions/Properties Manager/rotate_minus.png", "", "+", 0 ), ( "QToolButton", 1, "Clockwise", "ui/actions/Properties Manager/rotate_plus.png", "", "-", 1 ) ] self.gridRotateButtonRow = \ PM_ToolButtonRow( inPmGroupBox, title = "", buttonList = GRID_ANGLE_BUTTONS, label = 'Rotate grid:', isAutoRaise = False, isCheckable = False ) self.rotGridAntiClockwiseButton = \ self.gridRotateButtonRow.getButtonById(0) self.rotGridClockwiseButton = \ self.gridRotateButtonRow.getButtonById(1) def _loadLayerPropertiesGroupBox(self, inPmGroupBox): """ Load widgets in the Layer Properties group box. @param inPmGroupBox: The Layer Properties groupbox in the PM @type inPmGroupBox: L{PM_GroupBox} """ self.currentLayerComboBox = \ PM_ComboBox( inPmGroupBox, index = 0, spanWidth = True ) self.addLayerButton = PM_PushButton(inPmGroupBox) self.addLayerButton.setIcon( geticon('ui/actions/Properties Manager/addlayer.png')) self.addLayerButton.setFixedSize(QSize(26, 26)) self.addLayerButton.setIconSize(QSize(22, 22)) # A widget list to create a widget row. # Format: # - Widget type, # - widget object, # - column firstRowWidgetList = [('PM_ComboBox', self.currentLayerComboBox, 1), ('PM_PushButton', self.addLayerButton, 2) ] widgetRow = PM_WidgetRow(inPmGroupBox, title = '', widgetList = firstRowWidgetList, label = "Layer:", labelColumn = 0, ) self.layerCellsSpinBox = \ PM_SpinBox( inPmGroupBox, label = "Lattice cells:", labelColumn = 0, value = 2, minimum = 1, maximum = 25 ) self.layerThicknessLineEdit = PM_LineEdit(inPmGroupBox, label = "Thickness:", text = "", setAsDefault = False, spanWidth = False ) #self.layerThicknessLineEdit.setReadOnly(True) self.layerThicknessLineEdit.setDisabled(True) tooltip = "Thickness of layer in Angstroms" self.layerThicknessLineEdit.setToolTip(tooltip) def _loadAdvancedOptionsGroupBox(self, inPmGroupBox): """ Load widgets in the Advanced Options group box. @param inPmGroupBox: The Advanced Options box in the PM @type inPmGroupBox: L{PM_GroupBox} """ self.snapGridCheckBox = \ PM_CheckBox(inPmGroupBox, text = "Snap to grid", state = Qt.Checked ) tooltip = "Snap selection point to a nearest cell grid point." self.snapGridCheckBox.setToolTip(tooltip) self.freeViewCheckBox = \ PM_CheckBox(inPmGroupBox, text = "Enable free view", state = Qt.Unchecked ) def _loadDisplayOptionsGroupBox(self, inPmGroupBox): """ Load widgets in the Display Options groupbox. @param inPmGroupBox: The Display Options groupbox @type inPmGroupBox: L{PM_GroupBox} """ displayChoices = ['Tubes', 'Spheres'] self.dispModeComboBox = \ PM_ComboBox( inPmGroupBox, label = 'Display style:', choices = displayChoices, index = 0, setAsDefault = False, spanWidth = False ) self.gridLineCheckBox = PM_CheckBox(inPmGroupBox, text = "Show grid lines", widgetColumn = 0, state = Qt.Checked) self.fullModelCheckBox = PM_CheckBox(inPmGroupBox, text = "Show model", widgetColumn = 0, state = Qt.Unchecked) def _addWhatsThisText(self): """ What's This text for widgets in this Property Manager. @note: Many PM widgets are still missing their "What's This" text. """ from ne1_ui.WhatsThisText_for_PropertyManagers import whatsThis_CookiePropertyManager whatsThis_CookiePropertyManager(self) def _addToolTipText(self): """ What's Tool Tip text for widgets in this Property Manager. """ from ne1_ui.ToolTipText_for_PropertyManagers import ToolTip_CookiePropertyManager ToolTip_CookiePropertyManager(self)
class 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 DnaSegment_PropertyManager(DnaOrCnt_PropertyManager): """ The DnaSegmenta_PropertyManager class provides a Property Manager for the DnaSegment_EditCommand. @ivar title: The title that appears in the property manager header. @type title: str @ivar pmName: The name of this property manager. This is used to set the name of the PM_Dialog object via setObjectName(). @type name: str @ivar iconPath: The relative path to the PNG file that contains a 22 x 22 icon image that appears in the PM header. @type iconPath: str """ title = "DnaSegment Properties" iconPath = "ui/actions/Tools/Build Structures/DNA.png" def __init__(self, command): """ Constructor for the Build DNA property manager. """ self.endPoint1 = V(0, 0, 0) self.endPoint2 = V(0, 0, 0) self._numberOfBases = 0 self._conformation = 'B-DNA' self.duplexRise = 3.18 self.basesPerTurn = 10 self.dnaModel = 'PAM3' _superclass.__init__(self, command) self.showTopRowButtons( PM_DONE_BUTTON | \ PM_CANCEL_BUTTON | \ PM_PREVIEW_BUTTON | \ PM_WHATS_THIS_BUTTON) msg = "Use resize handles to resize the segment. Drag any axis or sugar"\ " atom for translation or rotation about axis respectively. Dragging"\ " any bond will freely move the whole segment." self.updateMessage(msg) def connect_or_disconnect_signals(self, isConnect): """ Connect or disconnect widget signals sent to their slot methods. This can be overridden in subclasses. By default it does nothing. @param isConnect: If True the widget will send the signals to the slot method. @type isConnect: boolean """ if isConnect: change_connect = self.win.connect else: change_connect = self.win.disconnect _superclass.connect_or_disconnect_signals(self, isConnect) change_connect(self.numberOfBasePairsSpinBox, SIGNAL("valueChanged(int)"), self.numberOfBasesChanged) change_connect(self.basesPerTurnDoubleSpinBox, SIGNAL("valueChanged(double)"), self.basesPerTurnChanged) change_connect(self.duplexRiseDoubleSpinBox, SIGNAL("valueChanged(double)"), self.duplexRiseChanged) change_connect(self.showCursorTextCheckBox, SIGNAL('stateChanged(int)'), self._update_state_of_cursorTextGroupBox) def _update_UI_do_updates(self): """ @see: Command_PropertyManager._update_UI_do_updates() @see: DnaSegment_EditCommand.command_update_UI() @see: DnaSegment_EditCommand.hasResizableStructure() @see: self._current_model_changed_params() """ currentParams = self._current_model_changed_params() #Optimization. Return from the model_changed method if the #params are the same. if same_vals(currentParams, self._previous_model_changed_params): return isStructResizable, why_not = currentParams #update the self._previous_model_changed_params with this new param set. self._previous_model_changed_params = currentParams if not isStructResizable: #disable all widgets if self._pmGroupBox1.isEnabled(): self._pmGroupBox1.setEnabled(False) msg = redmsg("DnaSegment is not resizable. Reason: %s" % (why_not)) self.updateMessage(msg) else: if not self._pmGroupBox1.isEnabled(): self._pmGroupBox1.setEnabled(True) msg = "Use resize handles to resize the segment. Drag any axis or sugar"\ " atom for translation or rotation about axis respectively. Dragging"\ " any bond will freely move the whole segment." self.updateMessage(msg) def _current_model_changed_params(self): """ Returns a tuple containing the parameters that will be compared against the previously stored parameters. This provides a quick test to determine whether to do more things in self.model_changed() @see: self.model_changed() which calls this @see: self._previous_model_changed_params attr. """ params = None if self.command: isStructResizable, why_not = self.command.hasResizableStructure() params = (isStructResizable, why_not) return params def show(self): """ Show this property manager. Overrides EditCommand_PM.show() This method also retrives the name information from the command's structure for its name line edit field. @see: DnaSegment_EditCommand.getStructureName() @see: self.close() """ _superclass.show(self) if self.command is not None: name = self.command.getStructureName() if name is not None: self.nameLineEdit.setText(name) def close(self): """ Close this property manager. Also sets the name of the self.command's structure to the one displayed in the line edit field. @see self.show() @see: DnaSegment_EditCommand.setStructureName """ if self.command is not None: name = str(self.nameLineEdit.text()) self.command.setStructureName(name) _superclass.close(self) def setParameters(self, params): """ This is usually called when you are editing an existing structure. Some property manager ui elements then display the information obtained from the object being edited. TODO: - Make this a EditCommand_PM API method? - See also the routines GraphicsMode.setParams or object.setProps ..better to name them all in one style? """ numberOfBasePairs, \ dnaForm, \ dnaModel,\ basesPerTurn, \ duplexRise, \ endPoint1, \ endPoint2 , \ color = params if numberOfBasePairs is not None: self.numberOfBasePairsSpinBox.setValue(numberOfBasePairs) if dnaForm is not None: self._conformation = dnaForm if dnaModel is not None: self.dnaModel = dnaModel if duplexRise is not None: self.duplexRiseDoubleSpinBox.setValue(duplexRise) if basesPerTurn is not None: self.basesPerTurnDoubleSpinBox.setValue(basesPerTurn) if endPoint1 is not None: self.endPoint1 = endPoint1 if endPoint2 is not None: self.endPoint2 = endPoint2 if color is not None: self._colorChooser.setColor(color) def getParameters(self): """ """ #See bug 2802 for details about the parameter #'number_of_basePairs_from_struct'. Basically it is used to check #if the structure got modified (e.g. because of undo) #The numberOfBases parameter obtained from the propMgr is given as a #separate parameter for the reasons mentioned in bug 2802 #-- Ninad 2008-04-12 number_of_basePairs_from_struct = None if self.command.hasValidStructure(): number_of_basePairs_from_struct = self.command.struct.getNumberOfBasePairs( ) numberOfBases = self.numberOfBasePairsSpinBox.value() dnaForm = self._conformation dnaModel = self.dnaModel basesPerTurn = self.basesPerTurn duplexRise = self.duplexRise color = self._colorChooser.getColor() return (number_of_basePairs_from_struct, numberOfBases, dnaForm, dnaModel, basesPerTurn, duplexRise, self.endPoint1, self.endPoint2, color) def numberOfBasesChanged(self, numberOfBases): """ Slot for the B{Number of Bases} spinbox. """ duplexRise = self.duplexRiseDoubleSpinBox.value() # Update the Duplex Length lineEdit widget. text = str(getDuplexLength(self._conformation, numberOfBases, duplexRise = duplexRise)) \ + " Angstroms" self.duplexLengthLineEdit.setText(text) return def basesPerTurnChanged(self, basesPerTurn): """ Slot for the B{Bases per turn} spinbox. """ self.basesPerTurn = basesPerTurn def duplexRiseChanged(self, rise): """ Slot for the B{Rise} spinbox. """ self.duplexRise = rise def _addGroupBoxes(self): """ Add the DNA Property Manager group boxes. """ self._pmGroupBox1 = PM_GroupBox(self, title="Parameters") self._loadGroupBox1(self._pmGroupBox1) self._displayOptionsGroupBox = PM_GroupBox(self, title="Display Options") self._loadDisplayOptionsGroupBox(self._displayOptionsGroupBox) def _loadGroupBox1(self, pmGroupBox): """ Load widgets in group box 4. """ self.nameLineEdit = PM_LineEdit(pmGroupBox, label="Segment name:", text="", setAsDefault=False) # Strand Length (i.e. the number of bases) self.numberOfBasePairsSpinBox = \ PM_SpinBox( pmGroupBox, label = "Base pairs:", value = self._numberOfBases, setAsDefault = False, minimum = 2, maximum = 10000 ) self.basesPerTurnDoubleSpinBox = \ PM_DoubleSpinBox( pmGroupBox, label = "Bases per turn:", value = self.basesPerTurn, setAsDefault = True, minimum = 8.0, maximum = 20.0, decimals = 2, singleStep = 0.1 ) self.basesPerTurnDoubleSpinBox.setDisabled(True) self.duplexRiseDoubleSpinBox = \ PM_DoubleSpinBox( pmGroupBox, label = "Rise:", value = self.duplexRise, setAsDefault = True, minimum = 2.0, maximum = 4.0, decimals = 3, singleStep = 0.01 ) self.duplexRiseDoubleSpinBox.setDisabled(True) # Duplex Length self.duplexLengthLineEdit = \ PM_LineEdit( pmGroupBox, label = "Duplex length: ", text = "0.0 Angstroms", setAsDefault = False) self.duplexLengthLineEdit.setDisabled(True) def _loadDisplayOptionsGroupBox(self, pmGroupBox): """ Overrides superclass method. Also loads the color chooser widget. """ self._loadColorChooser(pmGroupBox) _superclass._loadDisplayOptionsGroupBox(self, pmGroupBox) def _connect_showCursorTextCheckBox(self): """ Connect the show cursor text checkbox with user prefs_key. Overrides DnaOrCnt_PropertyManager._connect_showCursorTextCheckBox """ connect_checkbox_with_boolean_pref( self.showCursorTextCheckBox, dnaSegmentEditCommand_showCursorTextCheckBox_prefs_key) def _params_for_creating_cursorTextCheckBoxes(self): """ Returns params needed to create various cursor text checkboxes connected to prefs_keys that allow custom cursor texts. @return: A list containing tuples in the following format: ('checkBoxTextString' , preference_key). PM_PrefsCheckBoxes uses this data to create checkboxes with the the given names and connects them to the provided preference keys. (Note that PM_PrefsCheckBoxes puts thes within a GroupBox) @rtype: list @see: PM_PrefsCheckBoxes @see: self._loadDisplayOptionsGroupBox where this list is used. @see: Superclass method which is overridden here -- DnaOrCnt_PropertyManager._params_for_creating_cursorTextCheckBoxes() """ params = \ [ #Format: (" checkbox text", prefs_key) ("Number of base pairs", dnaSegmentEditCommand_cursorTextCheckBox_numberOfBasePairs_prefs_key), ("Duplex length", dnaSegmentEditCommand_cursorTextCheckBox_length_prefs_key), ("Number of basepairs to be changed", dnaSegmentEditCommand_cursorTextCheckBox_changedBasePairs_prefs_key) ] return params def _addWhatsThisText(self): """ Add what's this text. """ pass def _addToolTipText(self): """ Add Tooltip text """ pass
class InsertNanotube_PropertyManager( DnaOrCnt_PropertyManager): """ The InsertNanotube_PropertyManager class provides a Property Manager for the B{Build > Nanotube > CNT} command. @ivar title: The title that appears in the property manager header. @type title: str @ivar pmName: The name of this property manager. This is used to set the name of the PM_Dialog object via setObjectName(). @type name: str @ivar iconPath: The relative path to the PNG file that contains a 22 x 22 icon image that appears in the PM header. @type iconPath: str """ title = "Insert Nanotube" pmName = title iconPath = "ui/actions/Tools/Build Structures/InsertNanotube.png" def __init__( self, win, editCommand ): """ Constructor for the Nanotube property manager. """ self.endPoint1 = None self.endPoint2 = None self.nanotube = Nanotube() # A 5x5 CNT. _superclass.__init__( self, win, editCommand) self.showTopRowButtons( PM_DONE_BUTTON | \ PM_CANCEL_BUTTON | \ PM_WHATS_THIS_BUTTON) def connect_or_disconnect_signals(self, isConnect): """ Connect or disconnect widget signals sent to their slot methods. This can be overridden in subclasses. By default it does nothing. @param isConnect: If True the widget will send the signals to the slot method. @type isConnect: boolean """ if isConnect: change_connect = self.win.connect else: change_connect = self.win.disconnect change_connect( self.ntTypeComboBox, SIGNAL("currentIndexChanged(const QString&)"), self._ntTypeComboBoxChanged ) change_connect(self.chiralityNSpinBox, SIGNAL("valueChanged(int)"), self._chiralityFixup) change_connect(self.chiralityMSpinBox, SIGNAL("valueChanged(int)"), self._chiralityFixup) change_connect(self.endingsComboBox, SIGNAL("currentIndexChanged(const QString&)"), self._endingsComboBoxChanged ) # This spin box is currently hidden. change_connect(self.bondLengthDoubleSpinBox, SIGNAL("valueChanged(double)"), self._bondLengthChanged) change_connect(self.showCursorTextCheckBox, SIGNAL('stateChanged(int)'), self._update_state_of_cursorTextGroupBox) def ok_btn_clicked(self): """ Slot for the OK button """ if self.editCommand: self.editCommand.preview_or_finalize_structure(previewing = False) ##env.history.message(self.editCommand.logMessage) self.win.toolsDone() def cancel_btn_clicked(self): """ Slot for the Cancel button. """ if self.editCommand: self.editCommand.cancelStructure() self.win.toolsCancel() def _update_widgets_in_PM_before_show(self): """ Update various widgets in this Property manager. Overrides MotorPropertyManager._update_widgets_in_PM_before_show. The various widgets , (e.g. spinboxes) will get values from the structure for which this propMgr is constructed for (self.editcCntroller.struct) @see: MotorPropertyManager._update_widgets_in_PM_before_show @see: self.show where it is called. """ pass def getFlyoutActionList(self): """ Returns custom actionlist that will be used in a specific mode or editing a feature etc Example: while in movie mode, the _createFlyoutToolBar method calls this. """ #'allActionsList' returns all actions in the flyout toolbar #including the subcontrolArea actions allActionsList = [] #Action List for subcontrol Area buttons. #In this mode there is really no subcontrol area. #We will treat subcontrol area same as 'command area' #(subcontrol area buttons will have an empty list as their command area #list). We will set the Comamnd Area palette background color to the #subcontrol area. subControlAreaActionList =[] self.exitEditCommandAction.setChecked(True) subControlAreaActionList.append(self.exitEditCommandAction) separator = QAction(self.w) separator.setSeparator(True) subControlAreaActionList.append(separator) allActionsList.extend(subControlAreaActionList) #Empty actionlist for the 'Command Area' commandActionLists = [] #Append empty 'lists' in 'commandActionLists equal to the #number of actions in subControlArea for i in range(len(subControlAreaActionList)): lst = [] commandActionLists.append(lst) params = (subControlAreaActionList, commandActionLists, allActionsList) return params def _addGroupBoxes( self ): """ Add the Insert Nanotube Property Manager group boxes. """ self._pmGroupBox1 = PM_GroupBox( self, title = "Endpoints" ) self._loadGroupBox1( self._pmGroupBox1 ) self._pmGroupBox1.hide() self._pmGroupBox2 = PM_GroupBox( self, title = "Parameters" ) self._loadGroupBox2( self._pmGroupBox2 ) self._displayOptionsGroupBox = PM_GroupBox( self, title = "Display Options" ) self._loadDisplayOptionsGroupBox( self._displayOptionsGroupBox ) self._pmGroupBox3 = PM_GroupBox( self, title = "Nanotube Distortion" ) self._loadGroupBox3( self._pmGroupBox3 ) self._pmGroupBox3.hide() #@ Temporary. self._pmGroupBox4 = PM_GroupBox( self, title = "Multi-Walled CNTs" ) self._loadGroupBox4( self._pmGroupBox4 ) self._pmGroupBox4.hide() #@ Temporary. self._pmGroupBox5 = PM_GroupBox( self, title = "Advanced Options" ) self._loadGroupBox5( self._pmGroupBox5 ) self._pmGroupBox5.hide() #@ Temporary. def _loadGroupBox1(self, pmGroupBox): """ Load widgets in group box 1. """ #Following toolbutton facilitates entering a temporary NanotubeLineMode #to create a CNT using endpoints of the specified line. self.specifyCntLineButton = PM_ToolButton( pmGroupBox, text = "Specify Endpoints", iconPath = "ui/actions/Properties Manager/Pencil.png", spanWidth = True ) self.specifyCntLineButton.setCheckable(True) self.specifyCntLineButton.setAutoRaise(True) self.specifyCntLineButton.setToolButtonStyle( Qt.ToolButtonTextBesideIcon) #EndPoint1 and endPoint2 coordinates. These widgets are hidden # as of 2007- 12 - 05 self._endPoint1SpinBoxes = PM_CoordinateSpinBoxes(pmGroupBox, label = "End Point 1") self.x1SpinBox = self._endPoint1SpinBoxes.xSpinBox self.y1SpinBox = self._endPoint1SpinBoxes.ySpinBox self.z1SpinBox = self._endPoint1SpinBoxes.zSpinBox self._endPoint2SpinBoxes = PM_CoordinateSpinBoxes(pmGroupBox, label = "End Point 2") self.x2SpinBox = self._endPoint2SpinBoxes.xSpinBox self.y2SpinBox = self._endPoint2SpinBoxes.ySpinBox self.z2SpinBox = self._endPoint2SpinBoxes.zSpinBox self._endPoint1SpinBoxes.hide() self._endPoint2SpinBoxes.hide() def _loadGroupBox2(self, pmGroupBox): """ Load widgets in group box 2. """ _ntTypeChoices = ['Carbon', 'Boron Nitride'] self.ntTypeComboBox = \ PM_ComboBox( pmGroupBox, label = "Type:", choices = _ntTypeChoices, setAsDefault = True) self.ntRiseDoubleSpinBox = \ PM_DoubleSpinBox( pmGroupBox, label = "Rise:", value = self.nanotube.getRise(), setAsDefault = True, minimum = 2.0, maximum = 4.0, decimals = 3, singleStep = 0.01 ) self.ntRiseDoubleSpinBox.hide() # Nanotube Length self.ntLengthLineEdit = \ PM_LineEdit( pmGroupBox, label = "Nanotube Length: ", text = "0.0 Angstroms", setAsDefault = False) self.ntLengthLineEdit.setDisabled(True) self.ntLengthLineEdit.hide() # Nanotube diameter self.ntDiameterLineEdit = \ PM_LineEdit( pmGroupBox, label = "Diameter: ", setAsDefault = False) self.ntDiameterLineEdit.setDisabled(True) self.updateNanotubeDiameter() self.chiralityNSpinBox = \ PM_SpinBox( pmGroupBox, label = "Chirality (n):", value = self.nanotube.getChiralityN(), minimum = 2, maximum = 100, setAsDefault = True ) self.chiralityMSpinBox = \ PM_SpinBox( pmGroupBox, label = "Chirality (m):", value = self.nanotube.getChiralityM(), minimum = 0, maximum = 100, setAsDefault = True ) # How about having user prefs for CNT and BNNT bond lengths? # I'm guessing that if the user wants to set these values, they will # do it once and would like those bond length values persist forever. # Need to discuss with others to determine if this spinbox comes out. # --Mark 2008-03-29 self.bondLengthDoubleSpinBox = \ PM_DoubleSpinBox( pmGroupBox, label = "Bond length:", value = self.nanotube.getBondLength(), setAsDefault = True, minimum = 1.0, maximum = 3.0, singleStep = 0.1, decimals = 3, suffix = " Angstroms" ) #self.bondLengthDoubleSpinBox.hide() endingChoices = ["Hydrogen", "None"] # Removed:, "Nitrogen"] self.endingsComboBox= \ PM_ComboBox( pmGroupBox, label = "Endings:", choices = endingChoices, index = 0, setAsDefault = True, spanWidth = False ) def _loadGroupBox3(self, inPmGroupBox): """ Load widgets in group box 3. """ self.zDistortionDoubleSpinBox = \ PM_DoubleSpinBox( inPmGroupBox, label = "Z-distortion:", value = 0.0, setAsDefault = True, minimum = 0.0, maximum = 10.0, singleStep = 0.1, decimals = 3, suffix = " Angstroms" ) self.xyDistortionDoubleSpinBox = \ PM_DoubleSpinBox( inPmGroupBox, label = "XY-distortion:", value = 0.0, setAsDefault = True, minimum = 0.0, maximum = 2.0, singleStep = 0.1, decimals = 3, suffix = " Angstroms" ) self.twistSpinBox = \ PM_SpinBox( inPmGroupBox, label = "Twist:", value = 0, setAsDefault = True, minimum = 0, maximum = 100, # What should maximum be? suffix = " deg/A" ) self.bendSpinBox = \ PM_SpinBox( inPmGroupBox, label = "Bend:", value = 0, setAsDefault = True, minimum = 0, maximum = 360, suffix = " deg" ) def _loadGroupBox4(self, inPmGroupBox): """ Load widgets in group box 4. """ # "Number of Nanotubes" SpinBox self.mwntCountSpinBox = \ PM_SpinBox( inPmGroupBox, label = "Number:", value = 1, setAsDefault = True, minimum = 1, maximum = 10, suffix = " nanotubes" ) self.mwntCountSpinBox.setSpecialValueText("SWNT") # "Spacing" lineedit. self.mwntSpacingDoubleSpinBox = \ PM_DoubleSpinBox( inPmGroupBox, label = "Spacing:", value = 2.46, setAsDefault = True, minimum = 1.0, maximum = 10.0, singleStep = 0.1, decimals = 3, suffix = " Angstroms" ) def _loadGroupBox5(self, pmGroupBox): """ Load widgets in group box 5. """ self._rubberbandLineGroupBox = PM_GroupBox( pmGroupBox, title = 'Rubber band Line:') ntLineChoices = ['Ladder'] self.ntRubberBandLineDisplayComboBox = \ PM_ComboBox( self._rubberbandLineGroupBox , label = " Display as:", choices = ntLineChoices, setAsDefault = True) self.lineSnapCheckBox = \ PM_CheckBox(self._rubberbandLineGroupBox , text = 'Enable line snap' , widgetColumn = 1, state = Qt.Checked ) def _connect_showCursorTextCheckBox(self): """ Connect the show cursor text checkbox with user prefs_key. Overrides DnaOrCnt_PropertyManager._connect_showCursorTextCheckBox """ connect_checkbox_with_boolean_pref( self.showCursorTextCheckBox , insertNanotubeEditCommand_showCursorTextCheckBox_prefs_key ) def _params_for_creating_cursorTextCheckBoxes(self): """ Returns params needed to create various cursor text checkboxes connected to prefs_keys that allow custom cursor texts. @return: A list containing tuples in the following format: ('checkBoxTextString' , preference_key). PM_PrefsCheckBoxes uses this data to create checkboxes with the the given names and connects them to the provided preference keys. (Note that PM_PrefsCheckBoxes puts thes within a GroupBox) @rtype: list @see: PM_PrefsCheckBoxes @see: self._loadDisplayOptionsGroupBox where this list is used. @see: Superclass method which is overridden here -- DnaOrCnt_PropertyManager._params_for_creating_cursorTextCheckBoxes() """ params = \ [ #Format: (" checkbox text", prefs_key) ("Nanotube length", insertNanotubeEditCommand_cursorTextCheckBox_length_prefs_key ), ("Angle", insertNanotubeEditCommand_cursorTextCheckBox_angle_prefs_key ) ] return params def _addToolTipText(self): """ Tool Tip text for widgets in the Insert Nanotube Property Manager. """ pass def _setEndPoints(self): """ Set the two endpoints of the nanotube using the values from the X, Y, Z coordinate spinboxes in the property manager. @note: The group box containing the 2 sets of XYZ spin boxes are currently hidden. """ # First endpoint (origin) of nanotube x1 = self.x1SpinBox.value() y1 = self.y1SpinBox.value() z1 = self.z1SpinBox.value() # Second endpoint (direction vector/axis) of nanotube. x2 = self.x2SpinBox.value() y2 = self.y2SpinBox.value() z2 = self.z2SpinBox.value() if not self.endPoint1: self.endPoint1 = V(x1, y1, z1) if not self.endPoint2: self.endPoint2 = V(x2, y2, z2) self.nanotube.setEndPoints(self.endPoint1, self.endPoint2) # Need arg "recompute=True", which will recompute the second # endpoint (endPoint2) using the nanotube rise. def getParameters(self): """ Return the parameters from this property manager to be used to create the nanotube. @return: A nanotube instance with its attrs set to the current parameters in the property manager. @rtype: L{Nanotube} @see: L{InsertNanotube_EditCommand._gatherParameters} where this is used """ self._setEndPoints() return (self.nanotube) def _ntTypeComboBoxChanged( self, type ): """ Slot for the Type combobox. It is called whenever the Type choice is changed. @param inIndex: The new index. @type inIndex: int """ self.nanotube.setType(str(type)) print "Bond Length =", self.nanotube.getBondLength() self.bondLengthDoubleSpinBox.setValue(self.nanotube.getBondLength()) #self.bondLengthDoubleSpinBox.setValue(ntBondLengths[inIndex]) def _bondLengthChanged(self, bondLength): """ Slot for the B{Bond Length} spinbox. """ self.nanotube.setBondLength(bondLength) self.updateNanotubeDiameter() return def _chiralityFixup(self, spinBoxValueJunk = None): """ Slot for several validators for different parameters. This gets called whenever the user changes the n, m chirality values. @param spinBoxValueJunk: This is the Spinbox value from the valueChanged signal. It is not used. We just want to know that the spinbox value has changed. @type spinBoxValueJunk: double or None """ _n, _m = self.nanotube.setChirality(self.chiralityNSpinBox.value(), self.chiralityMSpinBox.value()) #self.n, self.m = self.nanotube.getChirality() self.connect_or_disconnect_signals(isConnect = False) self.chiralityNSpinBox.setValue(_n) self.chiralityMSpinBox.setValue(_m) self.connect_or_disconnect_signals(isConnect = True) self.updateNanotubeDiameter() def updateNanotubeDiameter(self): """ Update the nanotube Diameter lineEdit widget. """ diameterText = "%-7.4f Angstroms" % (self.nanotube.getDiameter()) self.ntDiameterLineEdit.setText(diameterText) # ntRiseDoubleSpinBox is currently hidden. self.ntRiseDoubleSpinBox.setValue(self.nanotube.getRise()) def _endingsComboBoxChanged(self, endings): """ Slot for the B{Ending} combobox. @param endings: The option's text. @type endings: string """ self.nanotube.setEndings(str(endings)) return def _addWhatsThisText(self): """ What's This text for widgets in this Property Manager. """ whatsThis_InsertNanotube_PropertyManager(self) return
class 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 DnaDuplexPropertyManager( DnaOrCnt_PropertyManager ): """ The DnaDuplexPropertyManager class provides a Property Manager for the B{Build > DNA > Duplex} command. @ivar title: The title that appears in the property manager header. @type title: str @ivar pmName: The name of this property manager. This is used to set the name of the PM_Dialog object via setObjectName(). @type name: str @ivar iconPath: The relative path to the PNG file that contains a 22 x 22 icon image that appears in the PM header. @type iconPath: str """ title = "Insert DNA" pmName = title iconPath = "ui/actions/Tools/Build Structures/InsertDsDna.png" def __init__( self, win, editCommand ): """ Constructor for the DNA Duplex property manager. """ self.endPoint1 = None self.endPoint2 = None self._conformation = "B-DNA" self._numberOfBases = 0 self._basesPerTurn = getDuplexBasesPerTurn(self._conformation) self._duplexRise = getDuplexRise(self._conformation) self._duplexLength = getDuplexLength(self._conformation, self._numberOfBases) _superclass.__init__( self, win, editCommand) self.showTopRowButtons( PM_DONE_BUTTON | \ PM_CANCEL_BUTTON | \ PM_WHATS_THIS_BUTTON) def connect_or_disconnect_signals(self, isConnect): """ Connect or disconnect widget signals sent to their slot methods. This can be overridden in subclasses. By default it does nothing. @param isConnect: If True the widget will send the signals to the slot method. @type isConnect: boolean """ if isConnect: change_connect = self.win.connect else: change_connect = self.win.disconnect change_connect(self._placementOptions.buttonGroup, SIGNAL("buttonClicked(int)"), self.activateSpecifyReferencePlaneTool) change_connect( self.conformationComboBox, SIGNAL("currentIndexChanged(int)"), self.conformationComboBoxChanged ) change_connect( self.numberOfBasePairsSpinBox, SIGNAL("valueChanged(int)"), self.numberOfBasesChanged ) change_connect( self.basesPerTurnDoubleSpinBox, SIGNAL("valueChanged(double)"), self.basesPerTurnChanged ) change_connect( self.duplexRiseDoubleSpinBox, SIGNAL("valueChanged(double)"), self.duplexRiseChanged ) change_connect(self.showCursorTextCheckBox, SIGNAL('stateChanged(int)'), self._update_state_of_cursorTextGroupBox) self.duplexRiseDoubleSpinBox.connectWithState( Preferences_StateRef_double( bdnaRise_prefs_key, env.prefs[bdnaRise_prefs_key] ) ) self.basesPerTurnDoubleSpinBox.connectWithState( Preferences_StateRef_double( bdnaBasesPerTurn_prefs_key, env.prefs[bdnaBasesPerTurn_prefs_key] ) ) def ok_btn_clicked(self): """ Slot for the OK button """ if self.editCommand: self.editCommand.preview_or_finalize_structure(previewing = False) ##env.history.message(self.editCommand.logMessage) self.win.toolsDone() def cancel_btn_clicked(self): """ Slot for the Cancel button. """ if self.editCommand: self.editCommand.cancelStructure() self.win.toolsCancel() def _update_widgets_in_PM_before_show(self): """ Update various widgets in this Property manager. Overrides superclass method @see: MotorPropertyManager._update_widgets_in_PM_before_show @see: self.show where it is called. """ pass def getFlyoutActionList(self): """ returns custom actionlist that will be used in a specific mode or editing a feature etc Example: while in movie mode, the _createFlyoutToolBar method calls this """ #'allActionsList' returns all actions in the flyout toolbar #including the subcontrolArea actions allActionsList = [] #Action List for subcontrol Area buttons. #In this mode there is really no subcontrol area. #We will treat subcontrol area same as 'command area' #(subcontrol area buttons will have an empty list as their command area #list). We will set the Comamnd Area palette background color to the #subcontrol area. subControlAreaActionList =[] self.exitEditCommandAction.setChecked(True) subControlAreaActionList.append(self.exitEditCommandAction) separator = QAction(self.w) separator.setSeparator(True) subControlAreaActionList.append(separator) allActionsList.extend(subControlAreaActionList) #Empty actionlist for the 'Command Area' commandActionLists = [] #Append empty 'lists' in 'commandActionLists equal to the #number of actions in subControlArea for i in range(len(subControlAreaActionList)): lst = [] commandActionLists.append(lst) params = (subControlAreaActionList, commandActionLists, allActionsList) return params def _addGroupBoxes( self ): """ Add the DNA Property Manager group boxes. """ self._pmReferencePlaneGroupBox = PM_GroupBox( self, title = "Placement Options" ) self._loadReferencePlaneGroupBox( self._pmReferencePlaneGroupBox ) self._pmGroupBox1 = PM_GroupBox( self, title = "Endpoints" ) self._loadGroupBox1( self._pmGroupBox1 ) self._pmGroupBox1.hide() self._pmGroupBox2 = PM_GroupBox( self, title = "Parameters" ) self._loadGroupBox2( self._pmGroupBox2 ) self._displayOptionsGroupBox = PM_GroupBox( self, title = "Display Options" ) self._loadDisplayOptionsGroupBox( self._displayOptionsGroupBox ) def _loadGroupBox1(self, pmGroupBox): """ Load widgets in group box 3. """ #Folllowing toolbutton facilitates entering a temporary DnaLineMode #to create a DNA using endpoints of the specified line. self.specifyDnaLineButton = PM_ToolButton( pmGroupBox, text = "Specify Endpoints", iconPath = "ui/actions/Properties Manager/Pencil.png", spanWidth = True ) self.specifyDnaLineButton.setCheckable(True) self.specifyDnaLineButton.setAutoRaise(True) self.specifyDnaLineButton.setToolButtonStyle( Qt.ToolButtonTextBesideIcon) #EndPoint1 and endPoint2 coordinates. These widgets are hidden # as of 2007- 12 - 05 self._endPoint1SpinBoxes = PM_CoordinateSpinBoxes(pmGroupBox, label = "End Point 1") self.x1SpinBox = self._endPoint1SpinBoxes.xSpinBox self.y1SpinBox = self._endPoint1SpinBoxes.ySpinBox self.z1SpinBox = self._endPoint1SpinBoxes.zSpinBox self._endPoint2SpinBoxes = PM_CoordinateSpinBoxes(pmGroupBox, label = "End Point 2") self.x2SpinBox = self._endPoint2SpinBoxes.xSpinBox self.y2SpinBox = self._endPoint2SpinBoxes.ySpinBox self.z2SpinBox = self._endPoint2SpinBoxes.zSpinBox self._endPoint1SpinBoxes.hide() self._endPoint2SpinBoxes.hide() def _loadGroupBox2(self, pmGroupBox): """ Load widgets in group box 4. """ self.conformationComboBox = \ PM_ComboBox( pmGroupBox, label = "Conformation:", choices = ["B-DNA"], setAsDefault = True) dnaModelChoices = ['PAM3', 'PAM5'] self.dnaModelComboBox = \ PM_ComboBox( pmGroupBox, label = "Model:", choices = dnaModelChoices, setAsDefault = True) self.basesPerTurnDoubleSpinBox = \ PM_DoubleSpinBox( pmGroupBox, label = "Bases per turn:", value = env.prefs[bdnaBasesPerTurn_prefs_key], setAsDefault = True, minimum = 8.0, maximum = 20.0, decimals = 2, singleStep = 0.1 ) self.duplexRiseDoubleSpinBox = \ PM_DoubleSpinBox( pmGroupBox, label = "Rise:", value = env.prefs[bdnaRise_prefs_key], setAsDefault = True, minimum = 2.0, maximum = 4.0, decimals = 3, singleStep = 0.01 ) # Strand Length (i.e. the number of bases) self.numberOfBasePairsSpinBox = \ PM_SpinBox( pmGroupBox, label = "Base pairs:", value = self._numberOfBases, setAsDefault = False, minimum = 0, maximum = 10000 ) self.numberOfBasePairsSpinBox.setDisabled(True) # Duplex Length self.duplexLengthLineEdit = \ PM_LineEdit( pmGroupBox, label = "Duplex length: ", text = "0.0 Angstroms", setAsDefault = False) self.duplexLengthLineEdit.setDisabled(True) def _loadDisplayOptionsGroupBox(self, pmGroupBox): """ Load widgets in the Display Options GroupBox @see: DnaOrCnt_PropertyManager. _loadDisplayOptionsGroupBox """ #Call the superclass method that loads the cursor text checkboxes. #Note, as of 2008-05-19, the superclass, DnaOrCnt_PropertyManager #only loads the cursor text groupboxes. Subclasses like this can #call custom methods like self._loadCursorTextCheckBoxes etc if they #don't need all groupboxes that the superclass loads. _superclass._loadDisplayOptionsGroupBox(self, pmGroupBox) self._rubberbandLineGroupBox = PM_GroupBox( pmGroupBox, title = 'Rubber band line:') dnaLineChoices = ['Ribbons', 'Ladder'] self.dnaRubberBandLineDisplayComboBox = \ PM_ComboBox( self._rubberbandLineGroupBox , label = " Display as:", choices = dnaLineChoices, setAsDefault = True) self.lineSnapCheckBox = \ PM_CheckBox(self._rubberbandLineGroupBox , text = 'Enable line snap' , widgetColumn = 1, state = Qt.Checked ) def _connect_showCursorTextCheckBox(self): """ Connect the show cursor text checkbox with user prefs_key. Overrides DnaOrCnt_PropertyManager._connect_showCursorTextCheckBox """ connect_checkbox_with_boolean_pref( self.showCursorTextCheckBox , dnaDuplexEditCommand_showCursorTextCheckBox_prefs_key) def _params_for_creating_cursorTextCheckBoxes(self): """ Returns params needed to create various cursor text checkboxes connected to prefs_keys that allow custom cursor texts. @return: A list containing tuples in the following format: ('checkBoxTextString' , preference_key). PM_PrefsCheckBoxes uses this data to create checkboxes with the the given names and connects them to the provided preference keys. (Note that PM_PrefsCheckBoxes puts thes within a GroupBox) @rtype: list @see: PM_PrefsCheckBoxes @see: self._loadDisplayOptionsGroupBox where this list is used. @see: Superclass method which is overridden here -- DnaOrCnt_PropertyManager._params_for_creating_cursorTextCheckBoxes() """ params = \ [ #Format: (" checkbox text", prefs_key) ("Number of base pairs", dnaDuplexEditCommand_cursorTextCheckBox_numberOfBasePairs_prefs_key), ("Number of turns", dnaDuplexEditCommand_cursorTextCheckBox_numberOfTurns_prefs_key), ("Duplex length", dnaDuplexEditCommand_cursorTextCheckBox_length_prefs_key), ("Angle", dnaDuplexEditCommand_cursorTextCheckBox_angle_prefs_key) ] return params def _addToolTipText(self): """ Tool Tip text for widgets in the DNA Property Manager. """ pass def conformationComboBoxChanged( self, inIndex ): """ Slot for the Conformation combobox. It is called whenever the Conformation choice is changed. @param inIndex: The new index. @type inIndex: int """ conformation = self.conformationComboBox.currentText() if conformation == "B-DNA": self.basesPerTurnDoubleSpinBox.setValue("10.0") elif conformation == "Z-DNA": self.basesPerTurnDoubleSpinBox.setValue("12.0") else: msg = redmsg("conformationComboBoxChanged(): \ Error - unknown DNA conformation. Index = "+ inIndex) env.history.message(msg) self.duplexLengthSpinBox.setSingleStep(getDuplexRise(conformation)) def numberOfBasesChanged( self, numberOfBases ): """ Slot for the B{Number of Bases} spinbox. """ # Update the Duplex Length lineEdit widget. text = str(getDuplexLength(self._conformation, numberOfBases, self._duplexRise)) \ + " Angstroms" self.duplexLengthLineEdit.setText(text) return def basesPerTurnChanged( self, basesPerTurn ): """ Slot for the B{Bases per turn} spinbox. """ self.editCommand.basesPerTurn = basesPerTurn self._basesPerTurn = basesPerTurn return def duplexRiseChanged( self, rise ): """ Slot for the B{Rise} spinbox. """ self.editCommand.duplexRise = rise self._duplexRise = rise return def getParameters(self): """ Return the parameters from this property manager to be used to create the DNA duplex. @return: A tuple containing the parameters @rtype: tuple @see: L{DnaDuplex_EditCommand._gatherParameters} where this is used """ numberOfBases = self.numberOfBasePairsSpinBox.value() dnaForm = str(self.conformationComboBox.currentText()) basesPerTurn = self.basesPerTurnDoubleSpinBox.value() duplexRise = self.duplexRiseDoubleSpinBox.value() dnaModel = str(self.dnaModelComboBox.currentText()) # First endpoint (origin) of DNA duplex x1 = self.x1SpinBox.value() y1 = self.y1SpinBox.value() z1 = self.z1SpinBox.value() # Second endpoint (direction vector/axis) of DNA duplex. x2 = self.x2SpinBox.value() y2 = self.y2SpinBox.value() z2 = self.z2SpinBox.value() if not self.endPoint1: self.endPoint1 = V(x1, y1, z1) if not self.endPoint2: self.endPoint2 = V(x2, y2, z2) return (numberOfBases, dnaForm, dnaModel, basesPerTurn, duplexRise, self.endPoint1, self.endPoint2) def _addWhatsThisText(self): """ What's This text for widgets in this Property Manager. """ whatsThis_DnaDuplexPropertyManager(self)