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("""Preview Window
This displays the active object. It can be inserted by double
clicking in the 3D graphics area.
Left click on a red bondpoint to make it a green hotspot
(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.
Mouse Commands Supported
Left - Select hotspot (clipboard and library parts only)
Middle - Rotate view
\
Wheel - Zoom in/out \
""")
self.MMKit_groupBox.setWhatsThis("""Molecular Modeling Kit
A tabular widget for selecting atom types or other structures to insert
into the model.
Atoms Tab - A select group of atom types options from the periodic
table of elements.
Clipboard Tab - the list of objects copied on the clipboard (using
the Copy command).
Library Tab - Accesses the NE1 Part Library. There are hundreds of
structures to choose from.
""")
self.transmuteBtn.setWhatsThis("""Transmute Atoms
When clicked, transmutes selected atoms to the current type displayed
in the Preview window.
""")
self.transmuteCB.setWhatsThis("""Force to keep bonds
When checked, all bonds remain in place when atoms are transmuted,
even if this will result in unrealistic (chemical) bonds.
""")
self.selectionFilter_groupBox.setWhatsThis("""Atoms Selection Filter
When activated, only atoms listed can be selected.
""")
self.advancedOptions_groupBox.setWhatsThis("""Advanced Options
Autobond - when checked, the atom being inserted or attached to another
atom will autobond to other bondpoints of other candidate atoms automatically.
Highlighting - Turns on/off hover highlighting.
Water- Adds a tranparent plane normal to the screen through 0,0,0. Anything
behind the water plane can not be selected.
""")
self.transmuteAtomsAction.setWhatsThis("""Transmute Atoms
When clicked, transmutes selected atoms to the current type displayed
in the Preview window.
""")
pass # end of class MMKit
# end