|
#$Id: wxMainFrame.py 201 2014-04-29 00:31:07Z sarkiss $
"""MainFrame for PyRx: Virtual Screening with AutoDock
Uses VTK and wxPython GUI with wx.aui (Advanced User Interface)"""
import wx
import wx.aui
import pdb, sys, os, traceback, shutil
from utils import rcFolder
from enthought.preferences.api import get_default_preferences
class ProgressStop(Exception):
"""This exception is raised when cancel is pressed in the ProgressDialog"""
pass
from about import version
from hbonds import toggle_hbonds
from mayaviActions import AddMayaviMenus, ID_RUN
from icons import atomPNG, pythonPNG, PyRxIcon, selectionPNG, hbondPNG
ID_OPEN = wx.NewId()
ID_PREFERENCES = wx.NewId()
ID_PERSPECTIVE = wx.NewId()
ID_ABOUT = wx.NewId()
ID_UPDATE = wx.NewId()
ID_IMPORT = wx.NewId()
ID_EXPORT = wx.NewId()
ID_HBOND = wx.NewId()
#ID_SHELL = wx.NewId()
class MainFrame(wx.Frame):
"This is the main frame for the app"
def __init__(self, parent, id=-1,
size=(800, 500), style=wx.DEFAULT_FRAME_STYLE):
title = "PyRx - Virtual Screening Tool - Version "+version
wx.Frame.__init__(self, parent, id, title, (10,10), size, style)
flags = wx.aui.AUI_MGR_ALLOW_FLOATING|wx.aui.AUI_MGR_TRANSPARENT_HINT|wx.aui.AUI_MGR_HINT_FADE|\
wx.aui.AUI_MGR_TRANSPARENT_DRAG|wx.aui.AUI_MGR_NO_VENETIAN_BLINDS_FADE|wx.aui.AUI_MGR_ALLOW_ACTIVE_PANE
self._mgr = wx.aui.AuiManager(self, flags)
# create menu
self.menuBar = wx.MenuBar()
fileMenu = wx.Menu()
fileMenu.Append(ID_OPEN, "&Load Molecule")
AddMayaviMenus(fileMenu, self)
fileMenu.AppendSeparator()
fileMenu.Append(ID_IMPORT, "&Import...")
fileMenu.Append(ID_EXPORT, "&Export...")
fileMenu.AppendSeparator()
fileMenu.Append(wx.ID_EXIT, "&Exit")
self.fileMenu = fileMenu
self.menuBar.Append(fileMenu, "&File")
editMenu = wx.Menu()
editMenu.Append(ID_PREFERENCES, "&Preferences...")
self.menuBar.Append(editMenu, "&Edit")
viewMenu = wx.Menu()
self.navigatorMenu = viewMenu.Append(wx.ID_ANY, "Navigator", kind=wx.ITEM_CHECK)
self.navigatorMenu.Check()
#removed View -> Graphics/Documents from here since hiding was not working properly (on Linux)
self.shellMenu = viewMenu.Append(wx.ID_ANY, "Wizard/Shell", kind=wx.ITEM_CHECK)
self.shellMenu.Check()
viewMenu.AppendSeparator()
viewMenu.Append(ID_PERSPECTIVE, "&Reset Perspective")
self.menuBar.Append(viewMenu, "&View")
helpMenu = wx.Menu()
helpMenu.Append(ID_UPDATE, "&Check for Updates...")
helpMenu.AppendSeparator()
helpMenu.Append(ID_ABOUT, "&About...")
self.menuBar.Append(helpMenu, "&Help")
self.SetMenuBar(self.menuBar)
#bind Menu and Toolbar event
self.Bind(wx.EVT_MENU, self.OnFileOpenMenu, id=ID_OPEN)
self.Bind(wx.EVT_MENU, self.OnImport, id=ID_IMPORT)
self.Bind(wx.EVT_MENU, self.OnExport, id=ID_EXPORT)
self.Bind(wx.EVT_MENU, self.OnClose, id=wx.ID_EXIT)
self.Bind(wx.EVT_MENU, self.OnPreferences, id=ID_PREFERENCES)
self.Bind(wx.EVT_MENU, self.ResetPerspective, id=ID_PERSPECTIVE)
self.Bind(wx.EVT_MENU_RANGE, self.OnFileHistory, id=wx.ID_FILE1, id2=wx.ID_FILE9)
self.Bind(wx.EVT_MENU, self.ToggleNavigator, self.navigatorMenu)
self.Bind(wx.EVT_MENU, self.ToggleShell, self.shellMenu)
self.Bind(wx.EVT_CLOSE, self.OnClose)
# create statusbar
self.statusBar = self.CreateStatusBar(1, wx.ST_SIZEGRIP)
self.statusBar.SetStatusWidths([-1])
self.statusBar.SetStatusText("Welcome to " + title, 0)
self.progressDialog = None
self.progressTextSuffix = None
# create toolbar
self.toolBar = wx.ToolBar(self, -1, wx.DefaultPosition, wx.DefaultSize,
wx.TB_FLAT | wx.TB_NODIVIDER)
self.toolBar.AddLabelTool(ID_OPEN, "Open", atomPNG,
shortHelp="Load Molecule (MolKit)", longHelp="Reads Molecule supported by MolKit and displays it")
self.toolBar.AddLabelTool(ID_RUN, "Run", pythonPNG,
shortHelp="Run Python script", longHelp="Run Python script")
self.navigator = wx.aui.AuiNotebook(self,size=wx.Size(size[0]/2,size[1]),
style=wx.aui.AUI_NB_TOP |
wx.aui.AUI_NB_TAB_SPLIT |
wx.aui.AUI_NB_TAB_MOVE |
wx.aui.AUI_NB_SCROLL_BUTTONS |
wx.aui.AUI_NB_WINDOWLIST_BUTTON)
self.view = wx.aui.AuiNotebook(self,size=wx.Size(size[0],size[1]),
style=wx.aui.AUI_NB_TOP |
wx.aui.AUI_NB_TAB_SPLIT |
wx.aui.AUI_NB_TAB_MOVE |
#wx.aui.AUI_NB_WINDOWLIST_BUTTON|
wx.aui.AUI_NB_SCROLL_BUTTONS
#|wx.aui.AUI_NB_CLOSE_ON_ACTIVE_TAB
)
self.controls = wx.aui.AuiNotebook(self,size=wx.Size(size[0],size[1]/2),
style=wx.aui.AUI_NB_TOP |
wx.aui.AUI_NB_TAB_SPLIT |
wx.aui.AUI_NB_TAB_MOVE |
wx.aui.AUI_NB_SCROLL_BUTTONS)
messages = []
import preferences
self.preferences_manager = preferences.preferences_manager
from molNavigator import MolNavigator, ID_CLEAR
self.molNav = MolNavigator(self) #Navigator -> Molecules tab
from autodockNavigator import AutoDockNavigator
self.autodockNav = AutoDockNavigator(self) #Navigator -> AutoDock tab
from mayaviEngine import MayaviEngine
MayaviEngine(self) #Navigator -> Graphics tab
try:
from matplotlibCanvas import PlotNotebook
self.matplot = PlotNotebook(self)
except Exception, inst:
messages.append("Error importing matplotlibCanvas: " + str(inst))
from textView import DocumentsView
self.documentsView = DocumentsView(self) # View -> Documents
from vinaWizard import VinaWizard
self.vinaWiz = VinaWizard(self) #Vina controls
from autodockWizard import AutoDockWizard
self.autodockWiz = AutoDockWizard(self) #AutoDock controls
try:
import traitedBabel
self.openBabel = traitedBabel.ChemicalTable(self)
except Exception, inst:
messages.append("Error importing traitedBabel: " + str(inst))
from shellCtrl import ShellController
self.shellCtrl = ShellController(self) #Python Shell under controls
from database import TableList
self.dbView = TableList(self)
from logger import Logger
self.logger = Logger(self)
from vtkAdaptor import vtkAdaptor
self.pmv = vtkAdaptor()
if messages:
for msg in messages:
self.log.warning(msg)
self._mgr.AddPane(self.navigator, wx.aui.AuiPaneInfo().Name('Navigator').Caption('Navigator').CloseButton(False).MaximizeButton(True).MinimizeButton(True).Left())
self.graphicsPaneInfo = wx.aui.AuiPaneInfo().Name("Graphics").Caption('View').CaptionVisible(True).CloseButton(False).MaximizeButton(True).MinimizeButton(True).Center()
self._mgr.AddPane(self.view, self.graphicsPaneInfo)
self.shellPaneInfo = wx.aui.AuiPaneInfo().Name("Controls").Caption('Controls').CaptionVisible(True).CloseButton(False).MaximizeButton(True).MinimizeButton(True).Bottom()
self._mgr.SetDockSizeConstraint(1./3., 0.4)
self._mgr.AddPane(self.controls, self.shellPaneInfo)
from about import About
self.Bind(wx.EVT_MENU, About, id=ID_ABOUT)
from update import Update
self.Bind(wx.EVT_MENU, Update, id=ID_UPDATE)
self.toolBar.AddSeparator()
self.toolBar.AddCheckLabelTool(ID_HBOND, "Hydrogen Bonds", hbondPNG,
shortHelp="Toggle Hydrogen Bonds", longHelp="Hydrogen Bonds")
self.Bind(wx.EVT_TOOL, toggle_hbonds, id=ID_HBOND)
self.toolBar.AddCheckLabelTool(ID_CLEAR, "Selection Spheres", selectionPNG,
shortHelp="Toggle Selection Spheres", longHelp="Toggle Selection Spheres")
self.Bind(wx.EVT_TOOL, self.molNav.ToggleSelection, id=ID_CLEAR)
self.toolBar.Realize()
self._mgr.AddPane(self.toolBar, wx.aui.AuiPaneInfo().Name("toolbar").Caption("Toolbar").ToolbarPane().Top())
size1 = self.autodockWiz.book.GetPage(0).sizer.GetMinSize()
size2 = self.controls.GetSize()
if size2[1] < size1[1]:
size2[1] = size1[1]
self.controls.SetSize(size2)
self.perspectiveInfo = self._mgr.SavePerspective()
self.LoadPerspective()
self.__create_file_history()
self.SetIcon(PyRxIcon)
preferences.setGlobalPreferences()
# from PyRx import Plugins
# wx.CallAfter(Plugins.init, self)
def ToggleShell(self, event):
"Toggles shell if self.shellMenu.IsChecked"
pane = self._mgr.GetPane("Controls")
if self.shellMenu.IsChecked():
self._mgr.RestorePane(pane)
#restoring shell when navigator is hidden restores navigator too this just makes sure that menus are in sync.
if not self.navigatorMenu.IsChecked():
self.navigatorMenu.Check()
else:
self._mgr.ClosePane(pane)
self._mgr.Update()
def ToggleNavigator(self, event):
pane = self._mgr.GetPane("Navigator")
if self.navigatorMenu.IsChecked():
self._mgr.RestorePane(pane)
if not self.shellMenu.IsChecked():
self.shellMenu.Check()
else:
self._mgr.ClosePane(pane)
self._mgr.Update()
def shellMenuUnCheck(self, event):
"This is called on wx.aui.EVT_AUI_PANE_CLOSE"
pane = event.GetPane()
if pane.name == "shell":
self.shellMenu.Check(False)
else:
event.Skip()
def OnPreferences(self, event):
# Show the UI...
self.preferences_manager.configure_traits(kind='modal')
# Save the preferences...
get_default_preferences().flush()
def ResetPerspective(self, event):
self._mgr.LoadPerspective(self.perspectiveInfo, True)
def SavePerspective(self):
filePath = os.path.join(rcFolder, '.PyRx_Perspective'+version)
open(filePath,'w').write(self._mgr.SavePerspective())
def LoadPerspective(self):
filePath = os.path.join(rcFolder, '.PyRx_Perspective'+version)
if os.path.exists(filePath):
self._mgr.LoadPerspective(open(filePath).read(), True)
else:
self._mgr.Update()
def OnClose(self, event):
"Invoked when application closes"
try:
# deinitialize the frame manager
self.documentsView.OnCloseWindow(event)
if hasattr(event,'GetVeto') and event.GetVeto():
return
self.SavePerspective()
old_path = self.wxcfg.GetPath()
self.wxcfg.SetPath('/RecentFiles')
self.fileHistory.Save(self.wxcfg)
self.wxcfg.SetPath(old_path)
self._mgr.UnInit()
# delete the frame
self.Destroy()
except Exception, inst:
print inst
def OnFileOpenMenu(self, event):
"Invoked on File Open Menu"
last_fileOpen = self.wxcfg.Read("last_fileOpen")
dlg = wx.FileDialog(self, "Choose a file", last_fileOpen, "",
"All Supported Files (*.pdb,*.pdbq(st),*.cif,*.mol2,*.pqr,*.gro)|*.cif;*.mol2;*.pdb;*.pqr;*.pdbq;*.pdbqs;*.pdbqt;*.gro|"+
"PDB files (*.pdb)|*.pdb|"+
"AutoDock files (*.pdbq,*.pdbqs,*.pdbqt)|*.pdbq;*.pdbqs;*.pdbqt|"+
"MOL2 files (*.mol2)|*.mol2|"+
"mmCIF files (*.cif)|*.cif|MEAD files (*.pqr)|*.pqr|"+
"Gromacs files (*.gro)|*.gro|All Files (*)|*",
style=wx.OPEN | wx.MULTIPLE | wx.CHANGE_DIR)
returnMol = []
try:
if dlg.ShowModal() == wx.ID_OK:
fileNames = dlg.GetPaths()
maximum = len(fileNames)
if maximum > 1:
dlg = wx.ProgressDialog("Reading Input Files. Please Wait...",
"Reading Input Files. Please Wait...",
maximum = maximum,
parent=self,
style = wx.PD_CAN_ABORT | wx.PD_APP_MODAL | wx.PD_ELAPSED_TIME
| wx.PD_REMAINING_TIME
)
keepGoing = True
for index, molFile in enumerate(fileNames):
# name, ext = os.path.splitext(molFile)
# if ext.lower() == '.pdbqt': #move the file to ~/.mgltools/PyRx/Ligands
# dst = os.path.join(self.vsModel.ligandsFolder, os.path.split(molFile)[-1])
# shutil.copy(molFile, dst)
if maximum > 1:
if maximum > 100 and ext.lower() == '.pdbqt': #change this number if needed
continue
(keepGoing, skip) = dlg.Update(index, "Reading "+molFile)
if not keepGoing:
break
mol = self.molNav.TryOpenMolecule(molFile)
returnMol.append(mol)
#self.navigator.SetSelection(0) #selects Molecules tab off Navigator
if fileNames:
self.wxcfg.Write("last_fileOpen", os.path.split(fileNames[0])[0])
except:
sys.last_type, sys.last_value, sys.last_traceback = sys.exc_info()
traceback.print_exc(file=self.shell)
self.shell.prompt()
self.log.error("Error in : "+str(command)+"\n"+self.shell.GetText())
finally:
dlg.Destroy()
return returnMol
def OpenDocument(self, path):
frame.documentsView._docManager.CreateDocument(path, flags=wx.lib.docview.DOC_SILENT)
frame.view.SetSelection(frame.view.GetPageIndex(frame.documentsView))
def TryCommand(self, command, *args, **kw):
"""
This function used try/except to execute a command.
except writes "Error in executing command" message in sys.stderr if try fails.
"""
self.SetAllCursors(wx.StockCursor(wx.CURSOR_WAIT))
self.Refresh()
self.Update()
retObject = None
try:
retObject = command(*args, **kw)
except Exception, inst:
self.SetAllCursors(wx.NullCursor)
if inst.__class__ != ProgressStop:
sys.last_type, sys.last_value, sys.last_traceback = sys.exc_info()
traceback.print_exc(file=self.shell)
self.shell.prompt()
self.log.error("Error in : "+str(command)+"\n"+self.shell.GetText())
self.SetAllCursors(wx.NullCursor)
return retObject
def PrintMessage(self, txt):
"Prints txt message"
print txt
self.shell.prompt()
def ConfigureProgressBar(self, **kw):
"Configures and opens wx.ProgressDialog"
self.progressCount = 0
if not kw.has_key('max'): return
self.progressMax = kw['max']
if self.progressDialog:
self.progressDialog.Destroy()
if self.progressTextSuffix:
self.progressText = self.progressTextTemplate.replace('??', self.progressTextSuffix[self.progressTextPositions])
self.progressTextPositions += 1
self.progressDialog = wx.ProgressDialog("Progress dialog",
self.progressText.strip(),
maximum = self.progressMax,
parent=self,
style = wx.PD_CAN_ABORT
| wx.PD_APP_MODAL
| wx.PD_ELAPSED_TIME
| wx.PD_REMAINING_TIME
)
def UpdateProgressBar(self):
"Updates ProgressBar"
self.progressCount = self.progressCount + 1
if self.progressCount >= self.progressMax-1:
if self.progressDialog:
self.progressDialog.Destroy()
self.progressDialog = None
else:
(keepGoing, skip) = self.progressDialog.Update(self.progressCount)
if not keepGoing:
self.progressDialog.Destroy()
raise ProgressStop()
def OnImport(self, event):
from importWizard import ImportWizard
wizard = ImportWizard(self)
wizard.Start()
def OnExport(self, event):
from exportWizard import ExportWizard
wizard = ExportWizard(self)
wizard.Start()
def OnFileHistory(self, evt):
# get the file based on the menu ID
fileNum = evt.GetId() - wx.ID_FILE1
path = self.fileHistory.GetHistoryFile(fileNum)
# add it back to the history so it will be moved up the list
self.fileHistory.AddFileToHistory(path)
retrunMol = self.molNav.TryOpenMolecule(path)
if not retrunMol:
self.fileHistory.RemoveFileFromHistory(0)
return retrunMol
def __create_file_history(self):
self.fileHistory = wx.FileHistory()
self.fileHistory.UseMenu(self.fileMenu)
self.wxcfg = wx.Config('PyRx')
old_path = self.wxcfg.GetPath()
self.wxcfg.SetPath('/RecentFiles')
self.fileHistory.Load(self.wxcfg)
self.wxcfg.SetPath(old_path)
def SetAllCursors(self, cursor):
SetAllCursors(self, cursor)
def SetAllCursors(parent, cursor):
"Sets the cursor for all Childrens. Note this function is needed because self.SetCursor is not working properly."
for child in parent.Children:
for grandChild in child.Children:
for grandGrandChild in grandChild.Children:
try: #to avoid GTKUpdateCursor(): NULL window returned by GTKGetWindow()
grandGrandChild.SetCursor(cursor)
except:
pass
grandChild.SetCursor(cursor)
child.SetCursor(cursor)
if __name__ == "__main__":
app = wx.App()
frame = MainFrame(None)
frame.Show()
app.MainLoop()
|