def constructModel(self, elm, pos, dispMode): """ This is to try to repeat what 'make_Atom_and_bondpoints()' method does, but hope to remove some stuff not needed here. The main purpose is to build the geometry model for element display. @param elm: An object of class Elem @param elm: L{Elem} @param dispMode: the display mode of the atom @type dispMode: int @return: the Chunk which contains the geometry model. @rtype: L{Chunk} """ assy = Assembly(None, run_updaters=False) assy.set_glpane(self) # sets .o and .glpane mol = Chunk(assy, 'dummy') atm = Atom(elm.symbol, pos, mol) atm.display = dispMode ## bruce 050510 comment: this is approximately how you should change the atom type (e.g. to sp2) for this new atom: if self.hybrid_type_name: atm.set_atomtype_but_dont_revise_singlets(self.hybrid_type_name) ## see also atm.element.atomtypes -> a list of available atomtype objects for that element ## (which can be passed to set_atomtype_but_dont_revise_singlets) atm.make_bondpoints_when_no_bonds() self.elementMode = True return mol
def partChanged(self, selectedItem): """ Method called when user changed the partlib browser tree. @param selectedItem: Item currently selected in the L{self.partLib} @type selectedItem: L{self.partLib.FileItem} @attention: This is called in the L{PM_TreeView.mouseReleaseEvent}. The 'selectionChanged' signal for self.partLib apparently was not emitted so that code has been removed. """ #Copying some old code from deprecated MMKit.py -- ninad 2007-09-06 item = selectedItem self.newModel = None if isinstance(item, self.partLib.FileItem): mmpFile = str(item.getFileObj()) if os.path.isfile(mmpFile): self.newModel = \ Assembly(self.w, os.path.normpath(mmpFile), run_updaters = True # desirable for PartLib [bruce 080403] ) self.newModel.set_glpane( self.elementViewer) # sets its .o and .glpane readmmp(self.newModel, mmpFile) self.newModel.update_parts( ) #k not sure if needed after readmmp self.newModel.checkparts() if self.newModel.shelf.members: for m in self.newModel.shelf.members[:]: m.kill() #k guess about a correct way to handle them self.newModel.update_parts() #k probably not needed self.newModel.checkparts() #k probably not needed self._updateElementViewer(self.newModel)
def constructModel(self, elm, pos, dispMode): """ This is to try to repeat what 'make_Atom_and_bondpoints()' method does, but hope to remove some stuff not needed here. The main purpose is to build the geometry model for element display. @param elm: An object of class Elem @param elm: L{Elem} @param dispMode: the display mode of the atom @type dispMode: int @return: the Chunk which contains the geometry model. @rtype: L{Chunk} """ assy = Assembly(None, run_updaters = False) assy.set_glpane(self) # sets .o and .glpane mol = Chunk(assy, 'dummy') atm = Atom(elm.symbol, pos, mol) atm.display = dispMode ## bruce 050510 comment: this is approximately how you should change the atom type (e.g. to sp2) for this new atom: if self.hybrid_type_name: atm.set_atomtype_but_dont_revise_singlets(self.hybrid_type_name) ## see also atm.element.atomtypes -> a list of available atomtype objects for that element ## (which can be passed to set_atomtype_but_dont_revise_singlets) atm.make_bondpoints_when_no_bonds() self.elementMode = True return mol
def partChanged(self, selectedItem): """ Method called when user changed the partlib browser tree. @param selectedItem: Item currently selected in the L{self.partLib} @type selectedItem: L{self.partLib.FileItem} @attention: This is called in the L{PM_TreeView.mouseReleaseEvent}. The 'selectionChanged' signal for self.partLib apparently was not emitted so that code has been removed. """ #Copying some old code from deprecated MMKit.py -- ninad 2007-09-06 item = selectedItem self.newModel = None if isinstance(item, self.partLib.FileItem): mmpFile = str(item.getFileObj()) if os.path.isfile(mmpFile): self.newModel = \ Assembly(self.w, os.path.normpath(mmpFile), run_updaters = True # desirable for PartLib [bruce 080403] ) self.newModel.set_glpane(self.elementViewer) # sets its .o and .glpane readmmp(self.newModel, mmpFile) self.newModel.update_parts() #k not sure if needed after readmmp self.newModel.checkparts() if self.newModel.shelf.members: for m in self.newModel.shelf.members[:]: m.kill() #k guess about a correct way to handle them self.newModel.update_parts() #k probably not needed self.newModel.checkparts() #k probably not needed self._updateElementViewer(self.newModel)
def _libPageView(self, isFile = False): item = self.dirView.selectedItem() if not isFile and not isinstance(item, self.FileItem): self.newModel = None self.elemGLPane.updateModel(self.newModel) return mmpfile = str(item.getFileObj()) if os.path.isfile(mmpfile): #self.newModel = Assembly(self.w, "Assembly 1") self.newModel = Assembly(self.w, os.path.normpath(mmpfile)) #ninad060924 to fix bug 1164 self.newModel.o = self.elemGLPane ## Make it looks "Assembly" used by glpane. readmmp(self.newModel, mmpfile) # What we did in Qt 3: ## #self.newModel = Assembly(self.w, "Assembly 1") ## self.newModel = Assembly(self.w, os.path.normpath(mmpfile)) #ninad060924 to fix bug 1164 ## self.newModel.o = self.elemGLPane ## Make it looks "Assembly" used by glpane. ## readmmp(self.newModel, mmpfile) ## # The following is absolute nonsense, and is part of what's breaking the fix of bug 2028, ## # so it needs to be revised, to give this assy a standard structure. ## # We'll have to find some other way to draw the hotspot singlet ## # (e.g. a reasonable, straightforward way). So we did -- MMKitView.always_draw_hotspot is True. ## # [bruce 060627] ## ## # Move all stuff under assembly.tree into assy.shelf. This is needed to draw hotspot singlet ## ## def addChild(child): ## ## self.newModel.shelf.addchild(child) ## ## ## ## # Remove existing clipboard items from the libary part before adopting childern from 'tree'. ## ## self.newModel.shelf.members = [] ## ## self.newModel.tree.apply2all(addChild) ## ## ## ## self.newModel.shelf.prior_part = None ## ## self.newModel.part = Part(self.newModel, self.newModel.shelf) ## if 1: #bruce 060627 self.newModel.update_parts() #k not sure if needed after readmmp) self.newModel.checkparts() if self.newModel.shelf.members: if debug_flags.atom_debug: print "debug warning: library part %r contains clipboard items" % mmpfile # we'll see if this is common # happens for e.g. nanokids/nanoKid-C39H42O2.mmp for m in self.newModel.shelf.members[:]: m.kill() #k guess about a correct way to handle them self.newModel.update_parts() #k probably not needed self.newModel.checkparts() #k probably not needed else: self.newModel = None self.elemGLPane.updateModel(self.newModel)
class PM_PartLib(PM_GroupBox): """ The PM_PartLib class provides a groupbox containing a partlib directory The selected part in this list is shown by its elementViewer (an instance of L{PM_PreviewGroupBox}) The part being previewed can then be deposited into the 3D workspace. """ def __init__(self, parentWidget, title = 'Part Library', win = None, elementViewer = None ): self.w = win self.elementViewer = elementViewer # piotr 080410 changed diTUBES to diTrueCPK self.elementViewer.setDisplay(diTrueCPK) self.partLib = None self.newModel = None PM_GroupBox.__init__(self, parentWidget, title) self._loadPartLibGroupBox() def connect_or_disconnect_signals(self, isConnect): """ Connect or disconnect widget signals sent to their slot methods. @param isConnect: If True the widget will send the signals to the slot method. @type isConnect: boolean """ ##if isConnect: ## change_connect = self.w.connect ##else: ## change_connect = self.w.disconnect #Following doesn't work for some reasons so this call is disabled. #Instead , see PM_TreeView.mouseReleaseEvent where self.partChanged is #called. ##change_connect(self.partLib, ## SIGNAL("selectionChanged(QItemSelection *,\ ## QItemSelection *)"), ## self.partChanged) pass def _loadPartLibGroupBox(self): """ """ self.partLib = PM_TreeView(self) self.gridLayout.addWidget(self.partLib) #Append to the widget list. This is important for expand -collapse #functions (of the groupbox) to work properly. self._widgetList.append(self.partLib) def _updateElementViewer(self, newModel = None): """ Update the view of L{self.elementViewer} @param newModel: The model correseponding to the item selected in L{self.clipboardListWidget}. @type newModel: L{molecule} or L{Group} """ if not self.elementViewer: return assert isinstance(self.elementViewer, MMKitView) self.elementViewer.resetView() if newModel: self.elementViewer.updateModel(newModel) def partChanged(self, selectedItem): """ Method called when user changed the partlib browser tree. @param selectedItem: Item currently selected in the L{self.partLib} @type selectedItem: L{self.partLib.FileItem} @attention: This is called in the L{PM_TreeView.mouseReleaseEvent}. The 'selectionChanged' signal for self.partLib apparently was not emitted so that code has been removed. """ #Copying some old code from deprecated MMKit.py -- ninad 2007-09-06 item = selectedItem self.newModel = None if isinstance(item, self.partLib.FileItem): mmpFile = str(item.getFileObj()) if os.path.isfile(mmpFile): self.newModel = \ Assembly(self.w, os.path.normpath(mmpFile), run_updaters = True # desirable for PartLib [bruce 080403] ) self.newModel.set_glpane(self.elementViewer) # sets its .o and .glpane readmmp(self.newModel, mmpFile) self.newModel.update_parts() #k not sure if needed after readmmp self.newModel.checkparts() if self.newModel.shelf.members: for m in self.newModel.shelf.members[:]: m.kill() #k guess about a correct way to handle them self.newModel.update_parts() #k probably not needed self.newModel.checkparts() #k probably not needed self._updateElementViewer(self.newModel)
class MMKit(QDialog, Ui_MMKitDialog, PropertyManagerMixin, SponsorableMixin): """ THIS CLASS HAS BEEN DEPRECATED. SEE NEW IMPLEMETATION IN-- Ui_BuildAtomsPropertyManager.py, BuildAtomsPropertyManager.py, Ui_PartLibPropertyManager.py, PartLibPropertyManager.py, Ui_PastePropertyManager.py PastePropertyManager.py Provide the MMKit PM for Build Atoms mode. """ # <title> - the title that appears in the property manager header. title = "Build Atoms" # <iconPath> - full path to PNG file that appears in the header. iconPath = "ui/actions/Tools/Build Structures/Build Atoms.png" bond_id2name =['sp3', 'sp2', 'sp', 'sp2(graphitic)'] sponsor_keyword = 'Build' def __init__(self, parentMode, win): QDialog.__init__(self, win, Qt.Dialog)# Qt.WStyle_Customize | Qt.WStyle_Tool | Qt.WStyle_Title | Qt.WStyle_NoBorder) self.w = win self.o = self.w.glpane #@NOTE: As of 20070717, MMKit supports only depositMode as its parent #(and perhaps subclasses of depositMode ..but such a class that also #uses MMKit is NIY so it is unconfirmed) -- ninad self.parentMode = parentMode self.setupUi(self) # setupUi() did not add the icon or title. We do that here. pmSetPropMgrIcon( self, self.iconPath ) pmSetPropMgrTitle( self, self.title ) #self.connect(self.hybrid_btngrp,SIGNAL("buttonClicked(int)"),self.set_hybrid_type) self.pw = None # pw = partwindow self.connect(self.mmkit_tab, SIGNAL("currentChanged(int)"), self.tabCurrentChanged) self.connect(self.chunkListBox, SIGNAL("currentItemChanged(QListWidgetItem*,QListWidgetItem*)"), self.chunkChanged) self.connect(self.browseButton, SIGNAL("clicked(bool)"), self.browseDirectories) self.connect(self.defaultPartLibButton, SIGNAL("clicked(bool)"), self.useDefaultPartLibDirectory) #self.connect(self.elementButtonGroup,SIGNAL("buttonClicked(int)"),self.setElementInfo) self.connect(self.thumbView_groupBoxButton, SIGNAL("clicked()"), self.toggle_thumbView_groupBox) self.connect(self.bondTool_groupBoxButton , SIGNAL("clicked()"), self.toggle_bondTool_groupBox) self.connect(self.MMKitGrpBox_TitleButton, SIGNAL("clicked()"), self.toggle_MMKit_groupBox) self.connect(self.filterCB, SIGNAL("stateChanged(int)"), self.toggle_selectionFilter_groupBox) self.connect(self.advancedOptions_groupBoxButton, SIGNAL("clicked()"), self.toggle_advancedOptions_groupBox) # Make the elements act like a big exclusive radio button. self.theElements = QtGui.QButtonGroup() self.theElements.setExclusive(True) self.theElements.addButton(self.toolButton1, 1) self.theElements.addButton(self.toolButton2, 2) self.theElements.addButton(self.toolButton6, 6) self.theElements.addButton(self.toolButton7, 7) self.theElements.addButton(self.toolButton8, 8) self.theElements.addButton(self.toolButton10, 10) self.theElements.addButton(self.toolButton9, 9) self.theElements.addButton(self.toolButton13,13) self.theElements.addButton(self.toolButton17,17) self.theElements.addButton(self.toolButton5, 5) self.theElements.addButton(self.toolButton10_2, 18) self.theElements.addButton(self.toolButton15, 15) self.theElements.addButton(self.toolButton16, 16) self.theElements.addButton(self.toolButton14, 14) self.theElements.addButton(self.toolButton33, 33) self.theElements.addButton(self.toolButton34, 34) self.theElements.addButton(self.toolButton35, 35) self.theElements.addButton(self.toolButton32, 32) self.theElements.addButton(self.toolButton36, 36) self.connect(self.theElements, SIGNAL("buttonPressed(int)"), self.update_dialog) self.theHybridizations = QtGui.QButtonGroup() self.theHybridizations.setExclusive(True) self.theHybridizations.addButton(self.sp3_btn, 0) self.theHybridizations.addButton(self.sp2_btn, 1) self.theHybridizations.addButton(self.sp_btn, 2) self.theHybridizations.addButton(self.graphitic_btn, 3) self.connect(self.theHybridizations, SIGNAL("buttonClicked(int)"), self.update_hybrid_btngrp) self.connect(self.filterCB, SIGNAL("toggled(bool)"),self.set_selection_filter) self.elemTable = PeriodicTable self.displayMode = diTUBES self.elm = None self.newModel = None ## used to save the selected lib part self.flayout = None # It looks like we now have correct fixes for bugs 1659 and bug 1824. If so, it would be safe to simply # hardware self.icon_tabs to True and simplify code accordingly. But we're not 100% certain, so by leaving # it as a debug pref, we can help any users who see those bugs come up again. # wware 060420 # # Update, bruce 070328: the False value of this debug_pref is known to fail in the Qt4 version (on Mac anyway), # due to AttributeError exceptions for setMargin and setTabLabel, # so I'm changing the prefs key for it in order to let Qt3 and Qt4 have independent debug_pref settings, # adding a warning in the menu text, and adding a try/except to help in debugging this if anyone ever wants to. # (If the bugs Will mentioned go away entirely, we can abandon support for the False value instead of fixing it, # as Will suggested.) from utilities.debug_prefs import debug_pref, Choice_boolean_True self.icon_tabs = debug_pref("use icons in MMKit tabs? (only True works in Qt4)", Choice_boolean_True, prefs_key = "A7/mmkit tab icons/Qt4") #e Changes to this only take effect in the next session. # Ideally we'd add a history message about that, when this is changed. # (It's not yet easy to do that in a supported way in debug_pref.) [bruce 060313] if not self.icon_tabs: # This code is known to fail in Qt4 Mac version, as explained above. [bruce 061222 and 070328] try: self.mmkit_tab.setMargin ( 0 ) except: print_compact_traceback("ignoring this Qt4-specific exception: ") #bruce 061222 pass self.mmkit_tab.setTabLabel (self.atomsPage, 'Atoms') self.mmkit_tab.setTabLabel (self.clipboardPage, 'Clipbd') self.mmkit_tab.setTabLabel (self.libraryPage, 'Lib') else: # Add icons to MMKit's tabs. mark 060223. atoms_ic = imagename_to_icon("actions/Properties Manager/MMKit.png") self.mmkit_tab.setTabIcon(self.mmkit_tab.indexOf(self.atomsPage), QIcon(atoms_ic)) self.update_clipboard_page_icon() # Loads proper icon for clibpoard tab. Mark 2007-06-01 library_ic = imagename_to_icon("actions/Properties Manager/library.png") self.mmkit_tab.setTabIcon(self.mmkit_tab.indexOf(self.libraryPage), QIcon(library_ic)) # Tab tooltips. mark 060326 self.mmkit_tab.setTabToolTip(self.mmkit_tab.indexOf(self.atomsPage), 'Atoms') self.mmkit_tab.setTabToolTip(self.mmkit_tab.indexOf(self.clipboardPage), 'Clipboard') self.mmkit_tab.setTabToolTip(self.mmkit_tab.indexOf(self.libraryPage), 'Part Library') self._setNewView('MMKitView') # Set current element in element button group. self.theElements.button(self.w.Element).setChecked(True) #self.connect(self., SIGNAL("), ) self.connect(self.w.hybridComboBox, SIGNAL("activated(int)"), self.hybridChangedOutside) self.connect(self.w.hybridComboBox, SIGNAL("activated(const QString&)"), self.change2AtomsPage) self.connect(self.w.elemChangeComboBox, SIGNAL("activated(const QString&)"), self.change2AtomsPage) self.connect(self.w.pasteComboBox, SIGNAL("activated(const QString&)"), self.change2ClipboardPage) #self.connect(self.w.depositAtomDashboard.pasteBtn, SIGNAL("pressed()"), self.change2ClipboardPage) self.connect(self.w.depositAtomDashboard.pasteBtn, SIGNAL("stateChanged(int)"), self.pasteBtnStateChanged) self.connect(self.w.depositAtomDashboard.depositBtn, SIGNAL("stateChanged(int)"), self.depositBtnStateChanged) self.connect(self.dirView, SIGNAL("selectionChanged(QItemSelection *, QItemSelection *)"), self.partChanged) self.add_whats_this_text() return # from __init__ # == #bruce 060412 added everything related to __needs_update_xxx, to fix bugs 1726, 1629 and mitigate bug 1677; # for more info see the comments where update_clipboard_items is called (in depositMode.py). __needs_update_clipboard_items = False # (there could be other flags like this for other kinds of updates we might need) def show_propMgr(self): """ Show the Build Property Manager. """ #@NOTE: The build property manager files are still refered as MMKit and #MMKitDialog. This will change in the near future. -- ninad 20070717 self.update_dialog(self.parentMode.w.Element) self.parentMode.set_selection_filter(False) # disable selection filter self.openPropertyManager(self) #Following is an old comment, was originally in depositMode.init_gui: #Do these before connecting signals or we'll get history msgs. #Part of fix for bug 1620. mark 060322 self.highlightingCB.setChecked(self.parentMode.hover_highlighting_enabled) self.waterCB.setChecked(self.parentMode.water_enabled) def update_dialog(self, elemNum): """Called when the current element has been changed. Update non user interactive controls display for current selected element: element label info and element graphics info """ elm = self.elemTable.getElement(elemNum) currentIndex = self.mmkit_tab.currentIndex() atomPageIndex = self.mmkit_tab.indexOf(self.atomsPage) ##if elm == self.elm and self.currentPageOpen(AtomsPage): return if elm == self.elm and (currentIndex == atomPageIndex) : return ## The following statements are redundant in some situations. self.theElements.button(elemNum).setChecked(True) self.w.Element = elemNum self.color = self.elemTable.getElemColor(elemNum) self.elm = self.elemTable.getElement(elemNum) self.update_hybrid_btngrp() self.elemGLPane.resetView() self.elemGLPane.refreshDisplay(self.elm, self.displayMode) #update the selection filter self.update_selection_filter_list() # Fix for bug 353, to allow the dialog to be updated with the correct page. For example, # when the user selects Paste from the Edit toolbar/menu, the MMKit should show # the Clipboard page and not the Atoms page. Mark 050808 if self.w.depositState == 'Clipboard': self.change2ClipboardPage() else: self.change2AtomsPage() self.tabCurrentChanged() self.updateBuildAtomsMessage() # Mark 2007-06-01 def updateBuildAtomsMessage(self): """Updates the message box with an informative message based on the current page and current selected atom type. """ msg = "" if self.MMKit_groupBox.isVisible(): pageIndex = self.mmkit_tab.currentIndex() page = None if pageIndex is 0: # atomsPage msg = "Double click in empty space to insert a single " + self.elm.name + " atom. " if not self.elm.symbol in noblegases: msg += "Click on an atom's <i>red bondpoint</i> to attach a " + self.elm.name + " atom to it." elif pageIndex is 1: # clipboardPage pastableItems = self.w.assy.shelf.get_pastable_chunks() if pastableItems: msg = "Double click in empty space to insert a copy of the selected clipboard item. \ Click on a <i>red bondpoint</i> to attach a copy of the selected clipboard item." else: msg = "There are no items on the clipboard." elif pageIndex is 2: # libraryPage msg = "Double click in empty space to insert a copy of the selected part in the library." else: # Bonds Tool is selected (MMKit groupbox is hidden). if self.parentMode.cutBondsAction.isChecked(): msg = "<b> Cut Bonds </b> tool is active. \ Click on bonds in order to delete them." self.MessageGroupBox.insertHtmlMessage(msg) return if not hasattr(self, 'bondclick_v6'): # Mark 2007-06-01 return if self.bondclick_v6: name = btype_from_v6(self.bondclick_v6) msg = "Click bonds or bondpoints to make them %s bonds." % name # name is 'single' etc # Post message. self.MessageGroupBox.insertHtmlMessage(msg) #== Atom Selection Filter helper methods def set_selection_filter(self, enabled): """Slot for Atom Selection Filter checkbox. Prints history message when selection filter is enabled/disabled and updates the cursor. """ if enabled != self.w.selection_filter_enabled: if enabled: env.history.message("Atom Selection Filter enabled.") else: env.history.message("Atom Selection Filter disabled.") self.w.selection_filter_enabled = enabled #print "update_selection_filter_list(): self.w.filtered_elements=", self.w.filtered_elements ##self.update_selection_filter_list_widget() self.update_selection_filter_list() self.filterlistLE.setEnabled(enabled) self.filterCB.setChecked(enabled) self.o.graphicsMode.update_cursor() def update_selection_filter_list(self): """Adds/removes the element selected in the MMKit to/from Atom Selection Filter based on what modifier key is pressed (if any). """ eltnum = self.w.Element if self.o.modkeys is None: self.w.filtered_elements = [] self.w.filtered_elements.append(PeriodicTable.getElement(eltnum)) if self.o.modkeys == 'Shift': if not PeriodicTable.getElement(eltnum) in self.w.filtered_elements[:]: self.w.filtered_elements.append(PeriodicTable.getElement(eltnum)) elif self.o.modkeys == 'Control': if PeriodicTable.getElement(eltnum) in self.w.filtered_elements[:]: self.w.filtered_elements.remove(PeriodicTable.getElement(eltnum)) self.update_selection_filter_list_widget() def update_selection_filter_list_widget(self): """Updates the list of elements displayed in the Atom Selection Filter List. """ filtered_syms='' for e in self.w.filtered_elements[:]: if filtered_syms: filtered_syms += ", " filtered_syms += e.symbol #self.w.depositAtomDashboard.filterlistLE.setText(filtered_syms) self.filterlistLE.setText(filtered_syms) def toggle_bondTool_groupBox(self): self.toggle_groupbox(self.bondTool_groupBoxButton, self.bondToolWidget) def toggle_thumbView_groupBox(self): self.toggle_groupbox(self.thumbView_groupBoxButton, self.elementFrame) def toggle_MMKit_groupBox(self): self.toggle_groupbox(self.MMKitGrpBox_TitleButton, self.mmkit_tab, self.transmuteBtn, self.transmuteCB) def toggle_selectionFilter_groupBox(self, state): """ Toggles the groupbox item display depending on checked state of the selection filter checkbox """ #Current state is 'off' or(Qt.Unchecked) if state is 0: styleSheet = self.getGroupBoxCheckBoxStyleSheet(bool_expand = False) self.filterCB.setStyleSheet(styleSheet) palette = self.getGroupBoxCheckBoxPalette() self.filterCB.setPalette(palette) #hide the following widgets when checkbox is unchecked -- self.selectionFilter_label.hide() self.filterlistLE.hide() else: styleSheet = self.getGroupBoxCheckBoxStyleSheet(bool_expand = True) self.filterCB.setStyleSheet(styleSheet) palette = self.getGroupBoxCheckBoxPalette() self.filterCB.setPalette(palette) #hide the following widgets when checkbox is unchecked -- self.selectionFilter_label.show() self.filterlistLE.show() def toggle_advancedOptions_groupBox(self): self.toggle_groupbox(self.advancedOptions_groupBoxButton, self.autobondCB, self.waterCB, self.highlightingCB) #bruce 070615 removed 'def toggle_groupbox', since our mixin superclass PropertyManagerMixin # provides an identical-enough version. def tabCurrentChanged(self): pageIndex = self.mmkit_tab.currentIndex() page = None if pageIndex is 0: page = self.atomsPage elif pageIndex is 1: page = self.clipboardPage elif pageIndex is 2: page = self.libraryPage self.setup_current_page(page) def update_clipboard_items(self): self.__needs_update_clipboard_items = True self.update() # this makes sure self.event will get called; it might be better to test the flag only in self.repaint, not sure return def event(self, event): #bruce 060412 debug code, but also checks all self.__needs_update_xxx flags (an essential bugfix) if debug_mmkit_events: print "debug: MMKit.event got %r, type %r" % (event, event.type()) # Qt doc for QEvent lists 'enum type' codes; the subclass is also printed by %r if self.__needs_update_clipboard_items: self.__really_update_clipboard_items() self.__needs_update_clipboard_items = False res = QDialog.event(self, event) if debug_mmkit_events: if res is not None: print "debug: MMKit.event returns %r" % (res,) # usually True, sometimes False # if we return None we get TypeError: invalid result type from MMKit.event() return res # == def pasteBtnStateChanged(self, state): """Slot method. Called when the state of the Paste button of deposit dashboard has been changed. """ if state == QButton.On: self.change2ClipboardPage() def depositBtnStateChanged(self, state): """Slot method. Called when the state of the Deposit button of deposit dashboard has been changed. """ if state == QButton.On: self.change2AtomsPage() def hybridChangedOutside(self, newId): """Slot method. Called when user changes element hybridization from the dashboard. This method achieves the same effect as user clicked one of the hybridization buttons.""" self.theElements.button(newId).setChecked(True) self.set_hybrid_type(newId) self.w.Element = newId ## fix bug 868 self.w.depositAtomDashboard.depositBtn.setChecked(True) def change2AtomsPage(self): """Slot method called when user changes element/hybrid combobox or presses Deposit button from Build mode dashboard. """ if self.mmkit_tab.currentIndex() != AtomsPage: self.mmkit_tab.setCurrentIndex(AtomsPage) # Generates signal def change2ClipboardPage(self): """Slot method called when user changes pastable item combobox or presses the Paste button from the Build mode dashboard. """ if self.mmkit_tab.currentIndex() != ClipboardPage: self.mmkit_tab.setCurrentIndex(ClipboardPage) # Generates signal?? def setElementInfo(self,value): """Slot method called when an element button is pressed in the element ButtonGroup. """ self.w.setElement(value) def update_hybrid_btngrp(self, buttonIndex = 0): """Update the buttons of the current element\'s hybridization types into hybrid_btngrp; select the specified one if provided""" elem = PeriodicTable.getElement(self.w.Element) # self.w.Element is atomic number atypes = elem.atomtypes if elem.name == 'Carbon': self.setup_C_hybrid_buttons() elif elem.name == 'Nitrogen': self.setup_N_hybrid_buttons() elif elem.name == 'Oxygen': self.setup_O_hybrid_buttons() elif elem.name == 'Sulfur': self.setup_S_hybrid_buttons() else: self.hide_hybrid_btngrp() self.elemGLPane.changeHybridType(None) return #if len(atypes) > 1: # Prequisite: w.hybridComboBox has been updated at this moment. b_name = self.bond_id2name[buttonIndex] self.elemGLPane.changeHybridType(b_name) self.elemGLPane.refreshDisplay(self.elm, self.displayMode) self.theHybridizations.button(buttonIndex).setChecked(True) self.set_hybrid_type(buttonIndex) # Added Atomic Hybrids label. Mark 2007-05-30 self.atomic_hybrids_label.setText("Atomic Hybrids for " + elem.name + " :") self.show_hybrid_btngrp() def show_hybrid_btngrp(self): # Mark 2007-06-20 """Show the hybrid button group and label above it. This is a companion method to hide_hybrid_btngrp(). It includes workarounds for Qt layout issues that crop up when hiding/showing the hybrid button groupbox using Qt's hide() and show() methods. See bug 2407 for more information. """ if 1: self.hybrid_btngrp.show() else: self.hybrid_btngrp.show() self.atomic_hybrids_label.show() def hide_hybrid_btngrp(self): # Mark 2007-06-20 """Hide the hybrid button group and label above it. This is a companion method to show_hybrid_btngrp(). It includes workarounds for Qt layout issues that crop up when hiding/showing the hybrid button groupbox using Qt's hide() and show() methods. See bug 2407 for more information. """ if 1: # This way of hiding confuses the layout manager, so I had # do create special spacers and set sizepolicies just to make # this work. self.hybrid_btngrp.hide() # I had to do this instead of use hide() since hide() # confuses the layout manager in special situations, like # that described in bug 2407. Mark 2007-06-20 self.atomic_hybrids_label.setText(" ") else: # Alternate way of hiding. Hide all contents and the QButtonGroupbox # border, but there is no way to hide the border. self.sp3_btn.hide() self.sp2_btn.hide() self.sp_btn.hide() self.graphitic_btn.hide() self.atomic_hybrids_label.hide() def setup_C_hybrid_buttons(self): """Displays the Carbon hybrid buttons. """ self.theElements.button(self.w.Element).setChecked(True) self.sp3_btn.setIcon(imagename_to_icon('modeltree/C_sp3.png')) self.sp3_btn.show() self.sp2_btn.setIcon(imagename_to_icon('modeltree/C_sp2.png')) self.sp2_btn.show() self.sp_btn.setIcon(imagename_to_icon('modeltree/C_sp.png')) self.sp_btn.show() self.graphitic_btn.hide() def setup_N_hybrid_buttons(self): """Displays the Nitrogen hybrid buttons. """ self.sp3_btn.setIcon(imagename_to_icon('modeltree/N_sp3.png')) self.sp3_btn.show() self.sp2_btn.setIcon(imagename_to_icon('modeltree/N_sp2.png')) self.sp2_btn.show() self.sp_btn.setIcon(imagename_to_icon('modeltree/N_sp.png')) self.sp_btn.show() self.graphitic_btn.setIcon(imagename_to_icon('modeltree/N_graphitic.png')) self.graphitic_btn.show() def setup_O_hybrid_buttons(self): """Displays the Oxygen hybrid buttons. """ self.sp3_btn.setIcon(imagename_to_icon('modeltree/O_sp3.png')) self.sp3_btn.show() self.sp2_btn.setIcon(imagename_to_icon('modeltree/O_sp2.png')) self.sp2_btn.show() self.sp_btn.hide() self.graphitic_btn.hide() def setup_S_hybrid_buttons(self): """Displays the Sulfur hybrid buttons. """ self.sp3_btn.setIcon(imagename_to_icon('modeltree/O_sp3.png')) # S and O are the same. self.sp3_btn.show() self.sp2_btn.setIcon(imagename_to_icon('modeltree/O_sp2.png')) self.sp2_btn.show() self.sp_btn.hide() self.graphitic_btn.hide() def set_hybrid_type(self, type_id): """Slot method. Called when any of the hybrid type buttons was clicked. """ self.w.hybridComboBox.setCurrentIndex( type_id ) b_name = self.bond_id2name[type_id] #This condition fixs bug 866, also saves time since no need to draw without MMKIt shown if self.isVisible(): self.elemGLPane.changeHybridType(b_name) self.elemGLPane.refreshDisplay(self.elm, self.displayMode) def setup_current_page(self, page): """Slot method that is called whenever a user clicks on the 'Atoms', 'Clipboard' or 'Library' tab to change to that page. """ #print "setup_current_page: page=", page if page == self.atomsPage: # Atoms page self.w.depositState = 'Atoms' self.w.update_depositState_buttons() self.elemGLPane.resetView() self.elemGLPane.refreshDisplay(self.elm, self.displayMode) self.browseButton.hide() self.defaultPartLibButton.hide() self.atomsPageSpacer.changeSize(0,5, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) elif page == self.clipboardPage: # Clipboard page self.w.depositState = 'Clipboard' self.w.update_depositState_buttons() self.elemGLPane.setDisplay(self.displayMode) self._clipboardPageView() self.browseButton.hide() self.defaultPartLibButton.hide() self.atomsPageSpacer.changeSize(0,5, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) elif page == self.libraryPage: # Library page if self.rootDir: self.elemGLPane.setDisplay(self.displayMode) self._libPageView() self.browseButton.show() self.defaultPartLibButton.show() self.atomsPageSpacer.changeSize(0,5, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Minimum) #Turn off both paste and deposit buttons, so when in library page and user choose 'set hotspot and copy' #it will change to paste page, also, when no chunk selected, a history message shows instead of depositing an atom. self.w.depositState = 'Library' self.w.update_depositState_buttons() else: print 'Error: MMKit page unknown: ', page self.elemGLPane.setFocus() self.updateBuildAtomsMessage() def chunkChanged(self, item, previous): """Slot method. Called when user changed the selected chunk. """ itemId = self.chunkListBox.row(item) if itemId != -1: newChunk = self.pastableItems[itemId] #self.w.pasteComboBox.setCurrentIndex(itemId) #buildModeObj = self.w.commandSequencer._commandTable['DEPOSIT'] #assert buildModeObj #buildModeObj.setPaste() ##Compared to the above way, I think this way is better. Modules are more uncoupled. self.w.pasteComboBox.setCurrentIndex(itemId) # Fixes bug 1754. mark 060325 self.elemGLPane.updateModel(newChunk) def __really_update_clipboard_items(self): #bruce 060412 renamed this from update_clipboard_items to __really_update_clipboard_items """Updates the items in the clipboard\'s listview, if the clipboard is currently shown. """ if self.currentPageOpen(ClipboardPage): #bruce 060313 added this condition to fix bugs 1631, 1669, and MMKit part of 1627 self._clipboardPageView() # includes self.update_clipboard_page_icon() else: self.update_clipboard_page_icon() # do this part of it, even if page not shown return def partChanged(self, item): """Slot method, called when user changed the partlib brower tree""" if isinstance(item, self.FileItem): self._libPageView(True) else: self.newModel = None self.elemGLPane.updateModel(self.newModel) def getPastablePart(self): """Public method. Retrieve pastable part and hotspot if current tab page is in libary, otherwise, return None. """ if self.currentPageOpen(LibraryPage): return self.newModel, self.elemGLPane.hotspotAtom return None, None def currentPageOpen(self, page_id): """Returns True if <page_id> is the current page open in the tab widget, where: 0 = Atoms page 1 = Clipboard page 2 = Library page """ pageIndex = self.mmkit_tab.currentIndex() if page_id == pageIndex: return True else: return False def _libPageView(self, isFile = False): item = self.dirView.selectedItem() if not isFile and not isinstance(item, self.FileItem): self.newModel = None self.elemGLPane.updateModel(self.newModel) return mmpfile = str(item.getFileObj()) if os.path.isfile(mmpfile): #self.newModel = Assembly(self.w, "Assembly 1") self.newModel = Assembly(self.w, os.path.normpath(mmpfile)) #ninad060924 to fix bug 1164 self.newModel.o = self.elemGLPane ## Make it looks "Assembly" used by glpane. readmmp(self.newModel, mmpfile) # What we did in Qt 3: ## #self.newModel = Assembly(self.w, "Assembly 1") ## self.newModel = Assembly(self.w, os.path.normpath(mmpfile)) #ninad060924 to fix bug 1164 ## self.newModel.o = self.elemGLPane ## Make it looks "Assembly" used by glpane. ## readmmp(self.newModel, mmpfile) ## # The following is absolute nonsense, and is part of what's breaking the fix of bug 2028, ## # so it needs to be revised, to give this assy a standard structure. ## # We'll have to find some other way to draw the hotspot singlet ## # (e.g. a reasonable, straightforward way). So we did -- MMKitView.always_draw_hotspot is True. ## # [bruce 060627] ## ## # Move all stuff under assembly.tree into assy.shelf. This is needed to draw hotspot singlet ## ## def addChild(child): ## ## self.newModel.shelf.addchild(child) ## ## ## ## # Remove existing clipboard items from the libary part before adopting childern from 'tree'. ## ## self.newModel.shelf.members = [] ## ## self.newModel.tree.apply2all(addChild) ## ## ## ## self.newModel.shelf.prior_part = None ## ## self.newModel.part = Part(self.newModel, self.newModel.shelf) ## if 1: #bruce 060627 self.newModel.update_parts() #k not sure if needed after readmmp) self.newModel.checkparts() if self.newModel.shelf.members: if debug_flags.atom_debug: print "debug warning: library part %r contains clipboard items" % mmpfile # we'll see if this is common # happens for e.g. nanokids/nanoKid-C39H42O2.mmp for m in self.newModel.shelf.members[:]: m.kill() #k guess about a correct way to handle them self.newModel.update_parts() #k probably not needed self.newModel.checkparts() #k probably not needed else: self.newModel = None self.elemGLPane.updateModel(self.newModel) def _clipboardPageView(self): """Updates the clipboard page. """ if not self.currentPageOpen(ClipboardPage): # (old code permitted this to be false below in 'if len(list):', # but failed to check for it in the 'else' clause, # thus causing bug 1627 [I think], now fixed in our caller) print "bug: _clipboardPageView called when not self.currentPageOpen(ClipboardPage)" #bruce 060313 return self.pastableItems = self.w.assy.shelf.get_pastable_chunks() self.chunkListBox.clear() for item in self.pastableItems: self.chunkListBox.addItem(item.name) newModel = None if len(self.pastableItems): i = self.w.pasteComboBox.currentIndex() if i < 0: i = self.w.pasteComboBox.count() - 1 # Make sure the clipboard page is open before calling selSelected(), because # setSelected() causes the clipboard page to be displayed when we don't want it to # be displayed (i.e. pressing Control+C to copy something to the clipboard). self.chunkListBox.setCurrentItem(self.chunkListBox.item(i)) # bruce 060313 question: why don't we now have to pass the selected chunk to # self.elemGLPane.updateModel? ###@@@ newModel = self.pastableItems[i] self.elemGLPane.updateModel(newModel) self.update_clipboard_page_icon() def update_clipboard_page_icon(self): """Updates the Clipboard page (tab) icon with a full or empty clipboard icon based on whether there is anything on the clipboard (pasteables). """ if not self.icon_tabs: # Work around for bug 1659. mark 060310 [revised by bruce 060313] return if self.w.assy.shelf.get_pastable_chunks(): clipboard_ic = imagename_to_icon("actions/Properties Manager/clipboard-full.png") else: clipboard_ic = imagename_to_icon("actions/Properties Manager/clipboard-empty.png") self.mmkit_tab.setTabIcon(self.mmkit_tab.indexOf(self.clipboardPage), QIcon(clipboard_ic)) class DirView(QTreeView): def __init__(self, mmkit, parent): QTreeView.__init__(self, parent) self.setEnabled(True) self.model = QtGui.QDirModel(['*.mmp', '*.MMP'], # name filters QDir.AllEntries|QDir.AllDirs|QDir.NoDotAndDotDot, # filters QDir.Name # sort order ) # explanation of filters (from Qt 4.2 doc for QDirModel): # - QDir.AllEntries = list files, dirs, drives, symlinks. # - QDir.AllDirs = include dirs regardless of other filters [guess: needed to ignore the name filters for dirs] # - QDir.NoDotAndDotDot = don't include '.' and '..' dirs # # about dirnames of "CVS": # The docs don't mention any way to filter the dirnames using a callback, # or any choices besides "filter them same as filenames" or "don't filter them". # So there is no documented way to filter out the "CVS" subdirectories like we did in Qt3 # (short of subclassing this and overriding some methods, # but the docs don't make it obvious how to do that correctly). # Fortunately, autoBuild.py removes them from the partlib copy in built releases. # # Other QDirModel methods we might want to use: # QDirModel.refresh, to update its state from the filesystem (but see the docs -- # they imply we might have to pass the model's root pathname to that method, # even if it hasn't changed, but they're not entirely clear on that). # # [bruce 070502 comments] self.path = None self.mmkit = mmkit self.setModel(self.model) self.setWindowTitle(self.tr("Dir View")) self.setItemsExpandable(True) self.setAlternatingRowColors(True) self.setColumnWidth(0, 200) for i in range(2,4): self.setColumnWidth(i, 4) self.show() #Ninad 070326 reimplementing mouseReleaseEvent and resizeEvent #for DirView Class (which is a subclass of QTreeView) #The old code reimplemented 'event' class which handles *all* events. #There was a bad bug which didn't send an event when the widget is resized # and then the seletcion is changed. In NE1Qt3 this wasn't a problem because #it only had one column. Now that we have multiple columns #(which are needed to show the horizontal scrollbar. # While using Library page only resize event or mouse release events #by the user should update the thumbview. #The Qt documentation also suggests reimplementing subevents instead of the main #event handler method (event()) def mouseReleaseEvent(self, evt): """ Reimplementation of mouseReleaseEvent method of QTreeView""" if self.selectedItem() is not None: self.mmkit._libPageView() return QTreeView.mouseReleaseEvent(self, evt) def resizeEvent(self, evt): """ Reimplementation of resizeEvent method of QTreeView""" if self.selectedItem() is not None: self.mmkit._libPageView() return QTreeView.resizeEvent(self, evt) #Following method (event() ) is not reimplemented anymore. Instead, the subevent handlers are #reimplemented (see above) -- ninad 070326 """ def event(self, evt): if evt.type() == evt.Timer: # This is the event we get when the library selection changes, so if there has # been a library selection, update the library page's GLPane. But this can also # happen without a selection; in that case don't erase the atom page's display. if self.selectedItem() is not None: self.mmkit._libPageView() return QTreeView.event(self, evt)""" def setRootPath(self, path): self.path = path self.setRootIndex(self.model.index(path)) def selectedItem(self): indexes = self.selectedIndexes() if not indexes: return None index = indexes[0] if not index.isValid(): return None return self.FileItem(str(self.model.filePath(index))) class FileItem: def __init__(self, path): self.path = path dummy, self.filename = os.path.split(path) def name(self): return self.filename def getFileObj(self): return self.path DirView.FileItem = FileItem def _setNewView(self, viewClassName): # Put the GL widget inside the frame if not self.flayout: self.flayout = QVBoxLayout(self.elementFrame) self.flayout.setMargin(1) self.flayout.setSpacing(1) else: if self.elemGLPane: self.flayout.removeChild(self.elemGLPane) self.elemGLPane = None if viewClassName == 'ChunkView': # We never come here! How odd. self.elemGLPane = ChunkView(self.elementFrame, "chunk glPane", self.w.glpane) elif viewClassName == 'MMKitView': self.elemGLPane = MMKitView(self.elementFrame, "MMKitView glPane", self.w.glpane) self.flayout.addWidget(self.elemGLPane,1) #ninad 070326. Note that self.DirView inherits QTreeView. #It has got nothing to do with the experimental class DirView in file Dirview.py self.dirView = self.DirView(self, self.libraryPage) self.dirView.setSortingEnabled(False) #bruce 070521 changed True to False -- fixes "reverse order" bug on my Mac ##self.dirView.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn) libraryPageLayout = QVBoxLayout(self.libraryPage) libraryPageLayout.setMargin(pmMMKitPageMargin) # Was 4. Mark 2007-05-30 libraryPageLayout.setSpacing(2) libraryPageLayout.addWidget(self.dirView) filePath = os.path.dirname(os.path.abspath(sys.argv[0])) libDir = os.path.normpath(filePath + '/../partlib') self.libPathKey = '/nanorex/nE-1/libraryPath' libDir = env.prefs.get(self.libPathKey, libDir) if os.path.isdir(libDir): self.rootDir = libDir self.dirView.setRootPath(libDir) else: self.rootDir = None from history.HistoryWidget import redmsg env.history.message(redmsg("The part library directory: %s doesn't exist." %libDir)) def browseDirectories(self): """Slot method for the browse button of library page. """ # Determine what directory to open. if self.w.assy.filename: odir = os.path.dirname(self.w.assy.filename) else: from utilities.prefs_constants import workingDirectory_prefs_key odir = env.prefs[workingDirectory_prefs_key] fdir = QFileDialog.getExistingDirectory(self, "Choose library directory", odir) libDir = str(fdir) if libDir and os.path.isdir(libDir): env.prefs[self.libPathKey] = libDir self.dirView.setRootPath(libDir) #Refresh GL-thumbView display self.newModel = None self.elemGLPane.updateModel(self.newModel) def useDefaultPartLibDirectory(self): """ Slot method that to reset the part lib directory path to default""" from history.HistoryWidget import redmsg #ninad070503 : A future enhancement would be a preference to have # a user defined 'default dir path' for the #part lib location. # set libDir to the standard partlib path filePath = os.path.dirname(os.path.abspath(sys.argv[0])) libDir = os.path.normpath(filePath + '/../partlib') if libDir and os.path.isdir(libDir): if self.dirView.path == libDir: msg1 = "Current directory path for the partlib is the default path." msg2 = " Current path not changed" env.history.message(redmsg(msg1 + msg2)) return env.prefs[self.libPathKey] = libDir self.dirView.setRootPath(libDir) #Refresh GL-thumbView display self.newModel = None self.elemGLPane.updateModel(self.newModel) else: msg1 = "The default patlib directory %s doesn't exist."%libDir msg2 = "Current path not changed" env.history.message(redmsg(msg1 + msg2)) def closeEvent(self, e): """This event handler receives all MMKit close events. In other words, when this dialog's close() slot gets called, this gets called with event 'e'. """ self.hide() # If the 'Library' page is open, change it to 'Atoms'. Mark 051212. if self.currentPageOpen(LibraryPage): self.setup_current_page(self.atomsPage) #bruce 070615 commented out the following since I think it's obsolete: # (evidence: no other mentions of 'polish' or 'move_to_best_location' in our code, # and MMKit is no longer a movable dialog) ## num_polish = 0 ## ## def polish(self): ## """This slot is called after a widget has been fully created and before it is shown the very first time. ## Polishing is useful for final initialization which depends on having an instantiated widget. ## This is something a constructor cannot guarantee since the initialization of the subclasses might not be finished. ## After this function, the widget has a proper font and palette and QApplication.polish() has been called. ## Remember to call QDialog's implementation when reimplementing this function. ## """ ## QDialog.polish(self) # call QDialog's polish() implementation ## self.num_polish += 1 ## #&print "num_polish =", self.num_polish ## if self.num_polish < 2: ## # polish() is called twice; not sure why. ## # Call move_to_best_location() only after the second polish signal since ## # get_location() can only get self.frameGeometry() after that. ## return ## self.move_to_best_location(True) def show(self): """MMKit\'s show slot. """ #QDialog.show(self) #&print "MMKit.move: setting mainwindow to active window" #Show it in Property Manager Tab ninad061207 if not self.pw or self: self.pw = self.w.activePartWindow() #@@@ ninad061206 self.pw.updatePropertyManagerTab(self) self.setSponsor() else: if not self.pw: self.pw = self.w.activePartWindow() self.pw.updatePropertyManagerTab(self) self.w.activateWindow() # Fixes bug 1503. mark 060216. # Required to give the keyboard input focus back to self (MainWindow). def add_whats_this_text(self): """What's This text for some of the widgets in the Build > Atoms Property Manager. Many are still missing. """ self.elementFrame.setWhatsThis("""<b>Preview Window</b> <p>This displays the active object. It can be inserted by double clicking in the 3D graphics area.</p> <p>Left click on a red bondpoint to make it a green <i>hotspot</i> (clipboard and library parts only). The hotspot indicates which bondpoint should be used to bond the current object when selecting a bondpoint in the model.</p> <p><u>Mouse Commands Supported</u><br> Left - Select hotspot (clipboard and library parts only)<br> Middle - Rotate view<br> \ Wheel - Zoom in/out \ </p>""") self.MMKit_groupBox.setWhatsThis("""<b>Molecular Modeling Kit</b> <p>A tabular widget for selecting atom types or other structures to insert into the model.</p> <p><b>Atoms Tab</b> - A select group of atom types options from the periodic table of elements.</p> <p><b>Clipboard Tab</b> - the list of objects copied on the clipboard (using the Copy command).</p> <p><b>Library Tab</b> - Accesses the NE1 Part Library. There are hundreds of structures to choose from.</p>""") self.transmuteBtn.setWhatsThis("""<b>Transmute Atoms</b> <p>When clicked, transmutes selected atoms to the current type displayed in the Preview window.</p>""") self.transmuteCB.setWhatsThis("""<b>Force to keep bonds</b> <p>When checked, all bonds remain in place when atoms are transmuted, even if this will result in unrealistic (chemical) bonds.</p>""") self.selectionFilter_groupBox.setWhatsThis("""<b>Atoms Selection Filter</b> <p>When activated, only atoms listed can be selected.</p>""") self.advancedOptions_groupBox.setWhatsThis("""<b>Advanced Options</b> <p><b>Autobond</b> - when checked, the atom being inserted or attached to another atom will autobond to other bondpoints of other candidate atoms automatically.</p> <p><b>Highlighting</b> - Turns on/off hover highlighting.</p> <p><b>Water</b>- Adds a tranparent plane normal to the screen through 0,0,0. Anything behind the water plane can not be selected.</p>""") self.transmuteAtomsAction.setWhatsThis("""<b>Transmute Atoms</b> <p>When clicked, transmutes selected atoms to the current type displayed in the Preview window.</p>""") pass # end of class MMKit
class PM_PartLib(PM_GroupBox): """ The PM_PartLib class provides a groupbox containing a partlib directory The selected part in this list is shown by its elementViewer (an instance of L{PM_PreviewGroupBox}) The part being previewed can then be deposited into the 3D workspace. """ def __init__(self, parentWidget, title='Part Library', win=None, elementViewer=None): self.w = win self.elementViewer = elementViewer # piotr 080410 changed diTUBES to diTrueCPK self.elementViewer.setDisplay(diTrueCPK) self.partLib = None self.newModel = None PM_GroupBox.__init__(self, parentWidget, title) self._loadPartLibGroupBox() def connect_or_disconnect_signals(self, isConnect): """ Connect or disconnect widget signals sent to their slot methods. @param isConnect: If True the widget will send the signals to the slot method. @type isConnect: boolean """ ##if isConnect: ## change_connect = self.w.connect ##else: ## change_connect = self.w.disconnect #Following doesn't work for some reasons so this call is disabled. #Instead , see PM_TreeView.mouseReleaseEvent where self.partChanged is #called. ##change_connect(self.partLib, ## SIGNAL("selectionChanged(QItemSelection *,\ ## QItemSelection *)"), ## self.partChanged) pass def _loadPartLibGroupBox(self): """ """ self.partLib = PM_TreeView(self) self.gridLayout.addWidget(self.partLib) #Append to the widget list. This is important for expand -collapse #functions (of the groupbox) to work properly. self._widgetList.append(self.partLib) def _updateElementViewer(self, newModel=None): """ Update the view of L{self.elementViewer} @param newModel: The model correseponding to the item selected in L{self.clipboardListWidget}. @type newModel: L{molecule} or L{Group} """ if not self.elementViewer: return assert isinstance(self.elementViewer, MMKitView) self.elementViewer.resetView() if newModel: self.elementViewer.updateModel(newModel) def partChanged(self, selectedItem): """ Method called when user changed the partlib browser tree. @param selectedItem: Item currently selected in the L{self.partLib} @type selectedItem: L{self.partLib.FileItem} @attention: This is called in the L{PM_TreeView.mouseReleaseEvent}. The 'selectionChanged' signal for self.partLib apparently was not emitted so that code has been removed. """ #Copying some old code from deprecated MMKit.py -- ninad 2007-09-06 item = selectedItem self.newModel = None if isinstance(item, self.partLib.FileItem): mmpFile = str(item.getFileObj()) if os.path.isfile(mmpFile): self.newModel = \ Assembly(self.w, os.path.normpath(mmpFile), run_updaters = True # desirable for PartLib [bruce 080403] ) self.newModel.set_glpane( self.elementViewer) # sets its .o and .glpane readmmp(self.newModel, mmpFile) self.newModel.update_parts( ) #k not sure if needed after readmmp self.newModel.checkparts() if self.newModel.shelf.members: for m in self.newModel.shelf.members[:]: m.kill() #k guess about a correct way to handle them self.newModel.update_parts() #k probably not needed self.newModel.checkparts() #k probably not needed self._updateElementViewer(self.newModel)