1#A* ------------------------------------------------------------------- 2#B* This file contains source code for the PyMOL computer program 3#C* copyright 1998-2000 by Warren Lyford Delano of DeLano Scientific. 4#D* ------------------------------------------------------------------- 5#E* It is unlawful to modify or remove this copyright notice. 6#F* ------------------------------------------------------------------- 7#G* Please see the accompanying LICENSE file for further information. 8#H* ------------------------------------------------------------------- 9#I* Additional authors of this source file include: 10#-* 11#-* NOTE: Based on code by John E. Grayson which was in turn 12#-* based on code written by Doug Hellmann. 13#Z* ------------------------------------------------------------------- 14 15from __future__ import print_function 16 17import sys 18import os 19from glob import glob 20import re 21import traceback 22import Pmw 23 24if sys.version_info[0] == 2: 25 import Queue 26 from Tkinter import * 27 from tkFileDialog import * 28 import tkMessageBox 29else: 30 import queue as Queue 31 from tkinter import * 32 from tkinter.filedialog import * 33 import tkinter.messagebox as tkMessageBox 34 35try: 36 # monkey patch Pmw's error message box 37 def _reporterror(func, args): 38 import pymol 39 40 exc_type, exc_value, exc_traceback = sys.exc_info() 41 msg = "Sorry this command was not successful at this time" 42 if issubclass(exc_type, (pymol.cmd.QuietException)): 43 tkMessageBox.showerror('Error', msg) 44 elif issubclass(exc_type, (pymol.CmdException)): 45 tkMessageBox.showerror(getattr(exc_value, 'label', 'Error'), str(exc_value.message).strip() or msg) 46 else: 47 _reporterror.orig(func, args) 48 49 PmwBase = sys.modules[Pmw.MegaWidget.__module__] 50 _reporterror.orig = PmwBase._reporterror 51 PmwBase._reporterror = _reporterror 52 53 del PmwBase 54except Exception as e: 55 print('monkey patching _reporterror failed:', e) 56 57class PMGApp(Pmw.MegaWidget): 58 59 def initOS(self): 60 # Initialize platform-specific options 61 if sys.platform == 'darwin': 62 self.initializeTk_mac() 63 elif sys.platform[:3] == 'win': 64 self.initializeTk_win32() 65 elif sys.platform[:5] == 'linux': 66 self.initializeTk_unix() 67 else: 68 self.initializeTk_unix() 69# self.root.tk.call('tk','scaling',1) 70 71 # try to get the windows properly aligned... 72 osFrame = { 'win32' : (4,60), 'irix' : (0,41), 73 'darwin': (0,51), 'cygwin' : (0,60), 74 'linux' : (0,31), 'linux2' : (0,31) } 75 76 self.frameXAdjust, self.frameYAdjust = osFrame.get(sys.platform, (0, 51)) 77 78 def initializeTk_win32(self): 79 pass 80 81 def initializeTk_mac(self): 82 pass 83 84 def initializeTk_unix(self): 85 pass 86 87 def getLoadableFileTypes(self): 88 return [("All Readable","*.pdb"), 89 ("All Readable","*.pdb1"), 90 ("All Readable","*.ccp4"), 91 ("All Readable","*.xplor"), 92 ("All Readable","*.mol"), 93 ("All Readable","*.mol2"), 94 ("All Readable","*.sdf"), 95 ("All Readable","*.xyz"), 96 ("All Readable","*.r3d"), 97 ("All Readable","*.cc1"), 98 ("All Readable","*.cc2"), 99 ("All Readable","*.ent"), 100 ("All Readable","*.dat"), 101 ("All Readable","*.out"), 102 ("All Readable","*.mmd"), 103 ("All Readable","*.mmod"), 104 ("All Readable","*.pse"), 105 ("All Readable","*.psw"), 106 ("All Readable","*.phi"), 107 ("All Readable","*.fld"), 108 ("All Readable","*.grd"), 109 ("All Readable","*.o"), 110 ("All Readable","*.omap"), 111 ("All Readable","*.brix"), 112 ("All Readable","*.dx"), 113 ("All Readable","*.pqr"), 114 ("All Readable","*.p5m"), 115 ("All Readable","*.p1m"), 116 ("All Readable","*.cube"), 117 ("All Readable","*.cif"), 118 ("All Readable","*.moe"), # proprietary format 119 ("All Readable","*.mae"), # proprietary format 120 ("All Readable","*.maegz"), # proprietary format 121 ("All Readable","*.cms"), # proprietary format 122 ("All Readable","*.idx"), # proprietary format 123 ("All Readable","*.fasta"), 124 ("All Readable","*.aln"), 125 ("All Readable","*.acnt"), 126 ("All Readable","*.mtz"), 127 ("All Readable","*.vis"), 128 ("All Readable","*.psf"), 129 ("All Readable","*.pdbml"), 130 ("All Readable","*.xml"), 131 ("All Readable","*.xml.gz"), 132 ("All Readable","*.pdbqt"), 133 ("All Readable","*.cml"), 134 ("All Readable","*.mmtf"), 135 ("PDB File","*.pdb"), 136 ("PDB1 File","*.pdb1"), 137 ("All Files","*.*"), 138 ("All Files","*"), 139 ("PDB File","*.ent"), 140 ("PyMOL Session","*.pse"), 141 ("PyMOL Show","*.psw"), 142 ("CCP4 Map","*.ccp4"), 143 ("XPLOR Map","*.xplor"), 144 ("MOL2/Multi-MOL2","*.mol2"), 145 ("Macromodel File","*.dat"), 146 ("Macromodel File","*.out"), 147 ("Macromodel File","*.mmd"), 148 ("Macromodel File","*.mmod"), 149# ("MTZ Reflection File","*.mtz"), 150 ("BRIX/O Map","*.o"), 151 ("BRIX/O Map","*.omap"), 152 ("BRIX/O Map","*.brix"), 153 ("CIF","*.cif"), 154 ("Gaussian Cube Map","*.cube"), 155 ("DX Map","*.dx"), 156 ("AVS (MEAD) Field","*.fld"), 157 ("MOL File","*.mol"), 158 ("MOE File","*.moe"), # proprietary format 159 ("MAE File","*.mae"), # proprietary format 160 ("MAE File","*.maegz"), # proprietary format 161 ("MAE File","*.cms"), # proprietary format 162 ("Desmond Trajectory","*.idx"), # proprietary format 163 ("VIS File","*.vis"), 164 ("ChemPy Model","*.pkl"), 165 ("Raster3D Scene","*.r3d"), 166 ("SDF File","*.sdf"), 167 ("ChemDraw3D File","*.cc1"), 168 ("ChemDraw3D File","*.cc2"), 169 ("XYZ File","*.xyz"), 170 ("Fasta File","*.fasta"), 171 ("CLUSTAL file","*.aln"), 172 ("ACNT Map","*.acnt"), 173 ("Protein Structure File","*.psf"), 174 ("PDBML","*.pdbml"), 175 ("PDBML","*.xml"), 176 ("PDBML","*.xml.gz"), 177 ("PDBQT","*.pdbqt"), 178 ("Chemical Markup Language","*.cml"), 179 ("MMTF","*.mmtf"), 180 ("MMTF","*.mmtf.gz"), 181 ] 182 183 def initializeTk_colors_common(self): 184 #self.root.option_add('*background', 'grey') #let system decide 185 self.root.option_add('*foreground', 'black') 186 self.root.option_add('*EntryField.Entry.background', 'white') 187 self.root.option_add('*Entry.background', 'white') 188 self.root.option_add('*MessageBar.Entry.background', 'gray85') 189 self.root.option_add('*Listbox*background', 'white') 190 self.root.option_add('*Listbox*selectBackground', 'dark slate blue') 191 self.root.option_add('*Listbox*selectForeground', 'white') 192 193 def quit_app(self): 194 self.pymol.cmd.log_close() 195 self.pymol.cmd.quit() # avoid logging this - it's inconvenient... 196 197 def flush_fifo_once(self): 198 # flush the external GUI fifo command queue 199 while not self.fifo.empty(): 200 try: 201 cmmd = self.fifo.get(0) 202 if isinstance(cmmd, str): 203 exec(cmmd) 204 else: 205 cmmd() 206 except: 207 traceback.print_exc() 208 209 def flush_fifo(self): 210 self.flush_fifo_once() 211 if self.allow_after: 212 self.root.after(20,self.flush_fifo) # 50X a second 213 214 def run(self,poll=0): 215 # this call to mainloop needs to be replaced with something revocable 216 self.flush_fifo_once() 217 keep_alive = 1 218 if poll: 219 import time 220 while keep_alive: 221 self.root.update() 222 time.sleep(0.05) 223 else: 224 self.root.mainloop() 225 226 self.quit_app() 227 228 def execute(self,cmmd): 229 self.fifo.put(cmmd) 230 231 def my_show(self,win,center=1): 232 if sys.platform!='linux2': 233 win.show() 234 else: # autocenter, deiconify, and run mainloop 235 # this is a workaround for a bug in the 236 # interaction between Tcl/Tk and common Linux 237 # window managers (namely KDE/Gnome) which causes 238 # an annoying 1-2 second delay in opening windows! 239 if center: 240 tw = win.winfo_reqwidth()+100 241 th = win.winfo_reqheight()+100 242 vw = win.winfo_vrootwidth() 243 vh = win.winfo_vrootheight() 244 x = max(0,(vw-tw)/2) 245 y = max(0,(vh-th)/2) 246 win.geometry(newGeometry="+%d+%d"%(x,y)) 247 win.deiconify() 248 249 def my_withdraw(self,win): 250 if sys.platform!='linux2': 251 win.withdraw() 252 else: 253 win.destroy() 254 255 def _initializePlugins(self): 256 from pymol.plugins import legacysupport 257 return legacysupport.initializePlugins(self) 258 259 def addSkinMenuItems(self,menuBar,menuName): 260 if not hasattr(self,'skinNameList'): 261 # find installed skins 262 skin_pattern = re.sub(r"[\/\\][^\/\\]*$","/skins/*/__init__.py*",__file__) 263 raw_list = glob(skin_pattern) 264 unique = {} 265 for a in raw_list: 266 key = re.sub(r"[\/\\]__init__\.py.*$","",a) 267 unique[re.sub(r".*[\/\\]","",key)] = 1 268 name_list = list(unique.keys()) 269 name_list.sort() 270 self.skinNameList = name_list 271 if hasattr(self,'skinNameList'): 272 for name in self.skinNameList: 273 caps_name = name.capitalize() 274 menuBar.addmenuitem(menuName, 'command', name, 275 label=caps_name, 276 command=lambda s=self,n=name:s.setSkin(n)) 277 278 279 def setSkin(self,skin,run=1): 280 if isinstance(skin,str): 281 inv = sys.modules.get("pymol.invocation",None) 282 if inv!=None: 283 module_path = inv.options.gui +".skins."+ skin 284 __import__(inv.options.gui +".skins."+ skin) 285 skin = sys.modules[module_path].__init__(self) 286 if skin != self.skin: 287 if self.skin != None: 288 self.skin.takedown() 289 self.skin = skin 290 291 if run: 292 self.runSkin() 293 294 def runSkin(self): 295 if self.skin != None: 296 self.skin.setup() 297 298 def __init__(self, pymol_instance, skin): 299 300 # prevent overloading 301 self.initializePlugins = self._initializePlugins 302 303 self.allow_after = 1 # easy switch for troubleshooting threads 304 305 self.pymol = pymol_instance 306 307 if self.pymol._ext_gui != None: 308 309 raise RuntimeError # only one PMGApp should ever be instantiated 310 311 else: 312 313 # create a FIFO so that PyMOL can send code to be executed by the GUI thread 314 315 self.fifo = Queue.Queue(0) 316 317 # create a pymol global so that PyMOL can find the external GUI 318 319 self.pymol._ext_gui = self 320 321 self.skin = None 322 323 # initialize Tcl/Tk 324 325 self.root = Tk() # creates the root window for the application 326 327 # color scheme 328 329 self.initializeTk_colors_common() 330 331 # operating-system dependencies 332 333 self.initOS() 334 335 # Python megawigit initialization 336 337 Pmw.initialise(self.root) 338 339 # Initialize the base class 340 341 Pmw.MegaWidget.__init__(self, parent=self.root) 342 343 # read the command line arguments regarding: 344 # - the size of the root window 345 # - the skin to use 346 347 inv = sys.modules.get("pymol.invocation",None) 348 if inv != None: 349 if skin == None: 350 skin = inv.options.skin 351 self.frameWidth = inv.options.win_x + 220 352 self.frameXPos = inv.options.win_px - self.frameXAdjust 353 self.frameHeight = inv.options.ext_y 354 self.frameYPos = inv.options.win_py - ( 355 self.frameHeight + self.frameYAdjust) 356 self.setSkin(skin,run=0) 357 358 # define the size of the root window 359 360 import platform 361 if sys.platform == 'darwin' and platform.mac_ver()[0] >= '10.9': 362 # let OS X Maverics place the window automatically, to avoid 363 # off-screen placement in multi-monitor setup 364 self.root.geometry('%dx%d' % (self.frameWidth, self.frameHeight)) 365 else: 366 self.root.geometry('%dx%d+%d+%d' % ( 367 self.frameWidth, self.frameHeight, self.frameXPos, self.frameYPos)) 368 369 # activate polling on the fifo 370 371 if self.allow_after: 372 self.root.after(1000,self.flush_fifo) 373 374 # and let 'er rip 375 376 self.runSkin() 377 378