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 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 NanotubeSegment(Group): """ Model object which represents a Nanotube Segment inside a Nanotube Group. Internally, this is just a specialized Group containing a single chunk, itself containing all the atoms of a nanotube. """ # This should be a tuple of classifications that appear in # files_mmp._GROUP_CLASSIFICATIONS, most general first. # See comment in class Group for more info. [bruce 080115] _mmp_group_classifications = ('NanotubeSegment', ) nanotube = None _endPoint1 = None _endPoint2 = None # TODO: undo or copy code for those attrs, # and updating them when the underlying structure changes. # But maybe that won't be needed, if they are replaced # by computing them from the atom geometry as needed. # [bruce 080227 comment] autodelete_when_empty = True # (but only if current command permits that for this class -- # see comment near Group.autodelete_when_empty for more info, # and implems of Command.keep_empty_group) iconPath = "ui/modeltree/NanotubeSegment.png" hide_iconPath = "ui/modeltree/NanotubeSegment-hide.png" # This partially fixes bug 2914. Copying now works, but the following # "warning" is printed to stdout: # ****************** needs _copyOfObject: <cnt.model.Nanotube.Nanotube instance at 0x164FC030> # I'm guessing this means that we need to override abstract method # _copyOfObject() of DataMixin, but I'd like to discuss this with Bruce first. # I also have confirmed that there is still a bug when editing the # copied nanotube (it will automatically move from the clipboard # to the part after it is resized). # Mark 2008-07-09. copyable_attrs = Group.copyable_attrs + ('nanotube', ) def __init__(self, name, assy, dad, members=(), editCommand=None): Group.__init__(self, name, assy, dad, members=members, editCommand=editCommand) ###BUG: not all callers pass an editCommand. It would be better # to figure out on demand which editCommand would be appropriate. # [bruce 080227 comment] return def writemmp_other_info_opengroup(self, mapping): #bruce 080507 refactoring """ """ #bruce 080507 refactoring (split this out of Group.writemmp) # (I think the following condition is always true, but I didn't # prove this just now, so I left in the test for now.) encoded_classifications = self._encoded_classifications() if encoded_classifications == "NanotubeSegment": # This is a nanotube segment, so write the parameters into an info # record so we can read and restore them in the next session. # --Mark 2008-04-12 assert self.nanotube mapping.write("info opengroup nanotube-parameters = %d, %d, %s, %s\n" \ % (self.nanotube.getChiralityN(), self.nanotube.getChiralityM(), self.nanotube.getType(), self.nanotube.getEndings())) pass return def readmmp_info_opengroup_setitem(self, key, val, interp): """ [extends superclass method] """ #bruce 080507 refactoring (split this out of the superclass method) if key == ['nanotube-parameters']: # val includes all the parameters, separated by commas. n, m, type, endings = val.split(",") self.n = int(n) self.m = int(m) self.type = type.lstrip() self.endings = endings.lstrip() # Create the nanotube. from cnt.model.Nanotube import Nanotube self.nanotube = Nanotube() # Returns a 5x5 CNT. self.nanotube.setChirality(self.n, self.m) self.nanotube.setType(self.type) self.nanotube.setEndings(self.endings) # The endpoints are recomputed every time it is edited. else: Group.readmmp_info_opengroup_setitem(self, key, val, interp) return def edit(self): """ Edit this NanotubeSegment. @see: NanotubeSegment_EditCommand """ commandSequencer = self.assy.w.commandSequencer if commandSequencer.currentCommand.commandName != "NANOTUBE_SEGMENT": commandSequencer.userEnterTemporaryCommand('NANOTUBE_SEGMENT') assert commandSequencer.currentCommand.commandName == 'NANOTUBE_SEGMENT' commandSequencer.currentCommand.editStructure(self) #Following methods are likely to be revised in a fully functional dna data # model. These methods are mainly created to get working many core UI # operations for Rattlesnake. -- Ninad 2008-02-01 def get_all_content_chunks(self): """ Return all the chunks contained within this NanotubeSegment. @note: there is only one chunk inside this group. """ all_content_chunk_list = [] for member in self.members: if isinstance(member, Chunk): all_content_chunk_list.append(member) return all_content_chunk_list def getAxisVector(self, atomAtVectorOrigin=None): """ Returns the unit axis vector of the segment (vector between two axis end points) """ endPoint1, endPoint2 = self.nanotube.getEndPoints() if endPoint1 is None or endPoint2 is None: return V(0, 0, 0) #@see: RotateAboutAPoint command. The following code is disabled #as it has bugs (not debugged but could be in #self.nanotube.getEndPoints). So, rotate about a point won't work for #rotating a nanotube. -- Ninad 2008-05-13 ##if atomAtVectorOrigin is not None: ###If atomAtVectorOrigin is specified, we will return a vector that ###starts at this atom and ends at endPoint1 or endPoint2 . ###Which endPoint to choose will be dicided by the distance between ###atomAtVectorOrigin and the respective endPoints. (will choose the ###frthest endPoint ##origin = atomAtVectorOrigin.posn() ##if vlen(endPoint2 - origin ) > vlen(endPoint1 - origin): ##return norm(endPoint2 - endPoint1) ##else: ##return norm(endPoint1 - endPoint2) return norm(endPoint2 - endPoint1) def setProps(self, props): """ Sets some properties. These will be used while editing the structure. (but if the structure is read from an mmp file, this won't work. As a fall back, it returns some constant values) @see: InsertNanotube_EditCommand.createStructure which calls this method. @see: self.getProps, NanotubeSegment_EditCommand.editStructure """ (_n, _m), _type, _endings, (_endPoint1, _endPoint2) = props from cnt.model.Nanotube import Nanotube self.nanotube = Nanotube() self.nanotube.setChirality(_n, _m) self.nanotube.setType(_type) self.nanotube.setEndings(_endings) self.nanotube.setEndPoints(_endPoint1, _endPoint2) def getProps(self): """ Returns nanotube parameters necessary for editing. @see: NanotubeSegment_EditCommand.editStructure where it is used. @see: NanotubeSegment_PropertyManager.getParameters @see: NanotubeSegmentEditCommand._createStructure """ # Recompute the endpoints in case this nanotube was read from # MMP file (which means this nanotube doesn't have endpoint # parameters yet). self.nanotube.computeEndPointsFromChunk(self.members[0]) return self.nanotube.getParameters() def getNanotubeGroup(self): """ Return the NanotubeGroup we are contained in, or None if we're not inside one. """ return self.parent_node_of_class(self.assy.NanotubeGroup) def isAncestorOf(self, obj): """ Checks whether the object <obj> is contained within the NanotubeSegment Example: If the object is an Atom, it checks whether the atom's chunk is a member of this NanotubeSegment (chunk.dad is self) It also considers all the logical contents of the NanotubeSegment to determine whether self is an ancestor. (returns True even for logical contents) @see: self.get_all_content_chunks() @see: NanotubeSegment_GraphicsMode.leftDrag """ # TODO: this needs cleanup (it looks like it's made of two alternative # implems, one after the other), and speedup. [bruce 080507 comment] c = None if isinstance(obj, Atom): c = obj.molecule elif isinstance(obj, Bond): chunk1 = obj.atom1.molecule chunk2 = obj.atom1.molecule if chunk1 is chunk2: c = chunk1 elif isinstance(obj, Chunk): c = obj if c is not None: if c in self.get_all_content_chunks(): return True #NOTE: Need to check if the isinstance checks are acceptable (apparently #don't add any import cycle) Also this method needs to be revised #after we completely switch to dna data model. if isinstance(obj, Atom): chunk = obj.molecule if chunk.dad is self: return True else: return False elif isinstance(obj, Bond): chunk1 = obj.atom1.molecule chunk2 = obj.atom1.molecule if (chunk1.dad is self) or (chunk2.dad is self): return True elif isinstance(obj, Chunk): if obj.dad is self: return True return False def node_icon(self, display_prefs): del display_prefs # unused if self.all_content_is_hidden(): return imagename_to_pixmap(self.hide_iconPath) else: return imagename_to_pixmap(self.iconPath) # ======================================================================= # These methods were copied from DnaStrandOrSegment and edited for # this class. def permit_addnode_inside(self): #bruce 080626 """ [overrides Group method] """ return False def permits_ungrouping(self): """ Should the user interface permit users to dissolve this Group using self.ungroup? [overridden from Group] """ return self._show_all_kids_for_debug() # normally False # note: modelTree should modify menu text for Ungroup to say "(unsupported)", # but this is broken as of before 080318 since it uses a self.is_block() test. def _show_all_kids_for_debug(self): #bruce 080207 in deprecated class Block 080318 classname_short = self.__class__.__name__.split('.')[-1] debug_pref_name = "Model Tree: show content of %s?" % classname_short # typical examples (for text searches to find them here): # Model Tree: show content of DnaStrand? # Model Tree: show content of DnaSegment? return debug_pref(debug_pref_name, Choice_boolean_False) def permit_as_member(self, node, pre_updaters=True, **opts): """ [friend method for enforce_permitted_members_in_groups and subroutines] Does self permit node as a direct member, when called from enforce_permitted_members_in_groups with the same options as we are passed? @rtype: boolean [overrides Group method] """ #bruce 080319 # someday, reject if superclass would reject -- so far, it never does del opts assy = self.assy res = isinstance(node, assy.Chunk) #@ NEEDS SOMETHING MORE. return res def _f_wants_to_be_killed(self, pre_updaters=True, **opts): # in DnaStrandOrSegment """ [friend method for enforce_permitted_members_in_groups and subroutines] Does self want to be killed due to members that got ejected by _f_move_nonpermitted_members (or due to completely invalid structure from before then, and no value in keeping self even temporarily)? @rtype: boolean [overrides Group method] """ #bruce 080319 del opts, pre_updaters return not self.members def MT_DND_can_drop_inside(self): #bruce 080317, revised 080318 """ Are ModelTree Drag and Drop operations permitted to drop nodes inside self? [overrides Node/Group method] """ return self._show_all_kids_for_debug() # normally False def openable(self): # overrides Node.openable() """ whether tree widgets should permit the user to open/close their view of this node """ # if we decide this depends on the tree widget or on somet for thing about it, # we'll have to pass in some args... don't do that unless/until we need to. #If there are no MT_kids (subnodes visible in MT under this group) then #don't make this node 'openable'. This makes sure that expand/ collapse #pixmap next to the node is not shown for this type of Group with 0 #MT_kids #Examples of such groups include empty groups, DnaStrand Groups, #DnaSegments etc -- Ninad 2008-03-15 return len(self.MT_kids()) != 0 def _raw_MT_kids(self, display_prefs={}): """ DnaStrand or DnaSegment groups (subclasses of this class) should not show any MT kids. @see: Group._raw__MT_kids() @see: Group.MT_kids() """ if self._show_all_kids_for_debug(): # normally False # bruce 080318 return self.members return () pass # end of class NanotubeSegment
class NanotubeSegment(Group): """ Model object which represents a Nanotube Segment inside a Nanotube Group. Internally, this is just a specialized Group containing a single chunk, itself containing all the atoms of a nanotube. """ # This should be a tuple of classifications that appear in # files_mmp._GROUP_CLASSIFICATIONS, most general first. # See comment in class Group for more info. [bruce 080115] _mmp_group_classifications = ('NanotubeSegment',) nanotube = None _endPoint1 = None _endPoint2 = None # TODO: undo or copy code for those attrs, # and updating them when the underlying structure changes. # But maybe that won't be needed, if they are replaced # by computing them from the atom geometry as needed. # [bruce 080227 comment] autodelete_when_empty = True # (but only if current command permits that for this class -- # see comment near Group.autodelete_when_empty for more info, # and implems of Command.keep_empty_group) iconPath = "ui/modeltree/NanotubeSegment.png" hide_iconPath = "ui/modeltree/NanotubeSegment-hide.png" # This partially fixes bug 2914. Copying now works, but the following # "warning" is printed to stdout: # ****************** needs _copyOfObject: <cnt.model.Nanotube.Nanotube instance at 0x164FC030> # I'm guessing this means that we need to override abstract method # _copyOfObject() of DataMixin, but I'd like to discuss this with Bruce first. # I also have confirmed that there is still a bug when editing the # copied nanotube (it will automatically move from the clipboard # to the part after it is resized). # Mark 2008-07-09. copyable_attrs = Group.copyable_attrs + ('nanotube',) def __init__(self, name, assy, dad, members = (), editCommand = None): Group.__init__(self, name, assy, dad, members = members, editCommand = editCommand) ###BUG: not all callers pass an editCommand. It would be better # to figure out on demand which editCommand would be appropriate. # [bruce 080227 comment] return def writemmp_other_info_opengroup(self, mapping): #bruce 080507 refactoring """ """ #bruce 080507 refactoring (split this out of Group.writemmp) # (I think the following condition is always true, but I didn't # prove this just now, so I left in the test for now.) encoded_classifications = self._encoded_classifications() if encoded_classifications == "NanotubeSegment": # This is a nanotube segment, so write the parameters into an info # record so we can read and restore them in the next session. # --Mark 2008-04-12 assert self.nanotube mapping.write("info opengroup nanotube-parameters = %d, %d, %s, %s\n" \ % (self.nanotube.getChiralityN(), self.nanotube.getChiralityM(), self.nanotube.getType(), self.nanotube.getEndings())) pass return def readmmp_info_opengroup_setitem( self, key, val, interp ): """ [extends superclass method] """ #bruce 080507 refactoring (split this out of the superclass method) if key == ['nanotube-parameters']: # val includes all the parameters, separated by commas. n, m, type, endings = val.split(",") self.n = int(n) self.m = int(m) self.type = type.lstrip() self.endings = endings.lstrip() # Create the nanotube. from cnt.model.Nanotube import Nanotube self.nanotube = Nanotube() # Returns a 5x5 CNT. self.nanotube.setChirality(self.n, self.m) self.nanotube.setType(self.type) self.nanotube.setEndings(self.endings) # The endpoints are recomputed every time it is edited. else: Group.readmmp_info_opengroup_setitem( self, key, val, interp) return def edit(self): """ Edit this NanotubeSegment. @see: NanotubeSegment_EditCommand """ commandSequencer = self.assy.w.commandSequencer if commandSequencer.currentCommand.commandName != "NANOTUBE_SEGMENT": commandSequencer.userEnterTemporaryCommand('NANOTUBE_SEGMENT') assert commandSequencer.currentCommand.commandName == 'NANOTUBE_SEGMENT' commandSequencer.currentCommand.editStructure(self) #Following methods are likely to be revised in a fully functional dna data # model. These methods are mainly created to get working many core UI # operations for Rattlesnake. -- Ninad 2008-02-01 def get_all_content_chunks(self): """ Return all the chunks contained within this NanotubeSegment. @note: there is only one chunk inside this group. """ all_content_chunk_list = [] for member in self.members: if isinstance(member, Chunk): all_content_chunk_list.append(member) return all_content_chunk_list def getAxisVector(self, atomAtVectorOrigin = None): """ Returns the unit axis vector of the segment (vector between two axis end points) """ endPoint1, endPoint2 = self.nanotube.getEndPoints() if endPoint1 is None or endPoint2 is None: return V(0, 0, 0) #@see: RotateAboutAPoint command. The following code is disabled #as it has bugs (not debugged but could be in #self.nanotube.getEndPoints). So, rotate about a point won't work for #rotating a nanotube. -- Ninad 2008-05-13 ##if atomAtVectorOrigin is not None: ###If atomAtVectorOrigin is specified, we will return a vector that ###starts at this atom and ends at endPoint1 or endPoint2 . ###Which endPoint to choose will be dicided by the distance between ###atomAtVectorOrigin and the respective endPoints. (will choose the ###frthest endPoint ##origin = atomAtVectorOrigin.posn() ##if vlen(endPoint2 - origin ) > vlen(endPoint1 - origin): ##return norm(endPoint2 - endPoint1) ##else: ##return norm(endPoint1 - endPoint2) return norm(endPoint2 - endPoint1) def setProps(self, props): """ Sets some properties. These will be used while editing the structure. (but if the structure is read from an mmp file, this won't work. As a fall back, it returns some constant values) @see: InsertNanotube_EditCommand.createStructure which calls this method. @see: self.getProps, NanotubeSegment_EditCommand.editStructure """ (_n, _m), _type, _endings, (_endPoint1, _endPoint2) = props from cnt.model.Nanotube import Nanotube self.nanotube = Nanotube() self.nanotube.setChirality(_n, _m) self.nanotube.setType(_type) self.nanotube.setEndings(_endings) self.nanotube.setEndPoints(_endPoint1, _endPoint2) def getProps(self): """ Returns nanotube parameters necessary for editing. @see: NanotubeSegment_EditCommand.editStructure where it is used. @see: NanotubeSegment_PropertyManager.getParameters @see: NanotubeSegmentEditCommand._createStructure """ # Recompute the endpoints in case this nanotube was read from # MMP file (which means this nanotube doesn't have endpoint # parameters yet). self.nanotube.computeEndPointsFromChunk(self.members[0]) return self.nanotube.getParameters() def getNanotubeGroup(self): """ Return the NanotubeGroup we are contained in, or None if we're not inside one. """ return self.parent_node_of_class( self.assy.NanotubeGroup) def isAncestorOf(self, obj): """ Checks whether the object <obj> is contained within the NanotubeSegment Example: If the object is an Atom, it checks whether the atom's chunk is a member of this NanotubeSegment (chunk.dad is self) It also considers all the logical contents of the NanotubeSegment to determine whether self is an ancestor. (returns True even for logical contents) @see: self.get_all_content_chunks() @see: NanotubeSegment_GraphicsMode.leftDrag """ # TODO: this needs cleanup (it looks like it's made of two alternative # implems, one after the other), and speedup. [bruce 080507 comment] c = None if isinstance(obj, Atom): c = obj.molecule elif isinstance(obj, Bond): chunk1 = obj.atom1.molecule chunk2 = obj.atom1.molecule if chunk1 is chunk2: c = chunk1 elif isinstance(obj, Chunk): c = obj if c is not None: if c in self.get_all_content_chunks(): return True #NOTE: Need to check if the isinstance checks are acceptable (apparently #don't add any import cycle) Also this method needs to be revised #after we completely switch to dna data model. if isinstance(obj, Atom): chunk = obj.molecule if chunk.dad is self: return True else: return False elif isinstance(obj, Bond): chunk1 = obj.atom1.molecule chunk2 = obj.atom1.molecule if (chunk1.dad is self) or (chunk2.dad is self): return True elif isinstance(obj, Chunk): if obj.dad is self: return True return False def node_icon(self, display_prefs): del display_prefs # unused if self.all_content_is_hidden(): return imagename_to_pixmap( self.hide_iconPath) else: return imagename_to_pixmap( self.iconPath) # ======================================================================= # These methods were copied from DnaStrandOrSegment and edited for # this class. def permit_addnode_inside(self): #bruce 080626 """ [overrides Group method] """ return False def permits_ungrouping(self): """ Should the user interface permit users to dissolve this Group using self.ungroup? [overridden from Group] """ return self._show_all_kids_for_debug() # normally False # note: modelTree should modify menu text for Ungroup to say "(unsupported)", # but this is broken as of before 080318 since it uses a self.is_block() test. def _show_all_kids_for_debug(self): #bruce 080207 in deprecated class Block 080318 classname_short = self.__class__.__name__.split('.')[-1] debug_pref_name = "Model Tree: show content of %s?" % classname_short # typical examples (for text searches to find them here): # Model Tree: show content of DnaStrand? # Model Tree: show content of DnaSegment? return debug_pref( debug_pref_name, Choice_boolean_False ) def permit_as_member(self, node, pre_updaters = True, **opts): """ [friend method for enforce_permitted_members_in_groups and subroutines] Does self permit node as a direct member, when called from enforce_permitted_members_in_groups with the same options as we are passed? @rtype: boolean [overrides Group method] """ #bruce 080319 # someday, reject if superclass would reject -- so far, it never does del opts assy = self.assy res = isinstance( node, assy.Chunk) #@ NEEDS SOMETHING MORE. return res def _f_wants_to_be_killed(self, pre_updaters = True, **opts): # in DnaStrandOrSegment """ [friend method for enforce_permitted_members_in_groups and subroutines] Does self want to be killed due to members that got ejected by _f_move_nonpermitted_members (or due to completely invalid structure from before then, and no value in keeping self even temporarily)? @rtype: boolean [overrides Group method] """ #bruce 080319 del opts, pre_updaters return not self.members def MT_DND_can_drop_inside(self): #bruce 080317, revised 080318 """ Are ModelTree Drag and Drop operations permitted to drop nodes inside self? [overrides Node/Group method] """ return self._show_all_kids_for_debug() # normally False def openable(self): # overrides Node.openable() """ whether tree widgets should permit the user to open/close their view of this node """ # if we decide this depends on the tree widget or on somet for thing about it, # we'll have to pass in some args... don't do that unless/until we need to. #If there are no MT_kids (subnodes visible in MT under this group) then #don't make this node 'openable'. This makes sure that expand/ collapse #pixmap next to the node is not shown for this type of Group with 0 #MT_kids #Examples of such groups include empty groups, DnaStrand Groups, #DnaSegments etc -- Ninad 2008-03-15 return len(self.MT_kids()) != 0 def _raw_MT_kids(self, display_prefs = {}): """ DnaStrand or DnaSegment groups (subclasses of this class) should not show any MT kids. @see: Group._raw__MT_kids() @see: Group.MT_kids() """ if self._show_all_kids_for_debug(): # normally False # bruce 080318 return self.members return () pass # end of class NanotubeSegment