# -*- coding: utf-8 -*- """ $Id$ Copyright 2010 Lars Kruse This file is part of PyCAM. PyCAM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. PyCAM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with PyCAM. If not, see . """ import pycam.Utils.log # Tkinter is used for "EmergencyDialog" below - but we will try to import it # carefully. #import Tkinter import sys import os log = pycam.Utils.log.get_logger() DEPENDENCY_DESCRIPTION = { "gtk": ("Python bindings for GTK+", "Install the package 'python-gtk2'", "see http://www.bonifazi.eu/appunti/pygtk_windows_installer.exe"), "opengl": ("Python bindings for OpenGL", "Install the package 'python-opengl'", "see http://www.bonifazi.eu/appunti/pygtk_windows_installer.exe"), "gtkgl": ("GTK extension for OpenGL", "Install the package 'python-gtkglext1'", "see http://www.bonifazi.eu/appunti/pygtk_windows_installer.exe"), "gl": ("OpenGL support of graphic driver", "Your current graphic driver does not support OpenGL. Please consult " \ + "'glxgears' to locate this problem."), } REQUIREMENTS_LINK = "http://sf.net/apps/mediawiki/pycam/?title=Requirements" # Usually the windows registry "HKEY_LOCAL_MACHINE/SOFTWARE/Gtk+/Path" contains # something like: C:\Programs\Common files\GTK # Afterwards we need to append "\bin" to get the library subdirectory. WINDOWS_GTK_REGISTRY_PATH = r"SOFTWARE\Gtk+" WINDOWS_GTK_REGISTRY_KEY = "Path" WINDOWS_GTK_LIB_SUBDIR = "bin" def import_gtk_carefully(): """ especially for windows: try to locate required libraries manually, if the import of GTK fails """ try: import _winreg in_windows = True except ImportError: in_windows = False if not in_windows: # We are not in windows - thus we just try to import gtk without # the need for any more manual preparations. import gtk else: # We try to retrive the GTK library directory from the registry before # trying any import. Otherwise the user will always see a warning # dialog regarding the missing libglib-2.0-0.dll file. This Windows # warning dialog can't be suppressed - thus we should try to avoid it. try: reg_path = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, WINDOWS_GTK_REGISTRY_PATH) gtk_dll_path = os.path.join(_winreg.QueryValueEx(reg_path, WINDOWS_GTK_REGISTRY_KEY)[0], WINDOWS_GTK_LIB_SUBDIR) _winreg.CloseKey(reg_path) except NameError: # GTK is probably not installed - the next import will fail pass except OSError: # "WindowsError" - this happens with pyinstaller binaries pass else: # add the new path to the PATH environment variable if "PATH" in os.environ: if not gtk_dll_path in os.environ["PATH"].split(os.pathsep): # append the guessed path to the library search path os.environ["PATH"] += "%s%s" % (os.pathsep, gtk_dll_path) else: os.environ["PATH"] = gtk_dll_path # everything should be prepared - now we try to import it again import gtk def requirements_details_gtk(): result = {} try: import_gtk_carefully() result["gtk"] = True except ImportError, err_msg: log.error("Failed to import GTK: %s" % str(err_msg)) result["gtk"] = False return result def recommends_details_gtk(): result = {} try: import gtk.gtkgl result["gtkgl"] = True result["gl"] = True except ImportError, err_msg: log.warn("Failed to import OpenGL for GTK (ImportError): %s" % \ str(err_msg)) result["gtkgl"] = False except RuntimeError, err_msg: log.warn("Failed to import OpenGL for GTK (RuntimeError): %s" % \ str(err_msg)) result["gl"] = False try: import OpenGL result["opengl"] = True except ImportError, err_msg: log.warn("Failed to import OpenGL: %s" % str(err_msg)) result["opengl"] = False def check_dependencies(details): """you can feed this function with the output of '(requirements|recommends)_details_*'. The result is True if all dependencies are met. """ failed = [key for (key, state) in details.items() if not state] return len(failed) == 0 def get_dependency_report(details, prefix=""): result = [] DESC_COL = 0 if sys.platform.startswith("win"): ADVICE_COL = 2 else: ADVICE_COL = 1 for key, state in details.items(): text = "%s%s: " % (prefix, DEPENDENCY_DESCRIPTION[key][DESC_COL]) if state: text += "OK" else: text += "MISSING (%s)" % DEPENDENCY_DESCRIPTION[key][ADVICE_COL] result.append(text) return os.linesep.join(result) def set_parent_controls_sensitivity(widget, new_state): """ go through all widgets above the given one and change their "sensitivity" state. This effects everything besides the single given widget, its direct line of ancestors and all attached labels (e.g for notebook tabs). Useful for disabling the screen while an action is going on. """ child = widget parent = widget.get_parent() def disable_if_different(obj, (parent, active)): if hasattr(parent, "get_tab_label") and \ (obj is parent.get_tab_label(active)): # skip the label of the current tab (in a notebook) return if not obj is active: obj.set_sensitive(new_state) while parent: # Use "forall" instead of "foreach" - this also catches all tab # labels. parent.forall(disable_if_different, (parent, child)) child = parent parent = parent.get_parent() class EmergencyDialog(object): """ This graphical message window requires no external dependencies. The Tk interface package is part of the main python distribution. Use this class for displaying dependency errors (especially on Windows). """ def __init__(self, title, message): try: import Tkinter except ImportError: # tk is not installed log.warn("Failed to show error dialog due to a missing Tkinter " \ + "Python package.") return try: root = Tkinter.Tk() except Tkinter.TclError, err_msg: log.info(("Failed to create error dialog window (%s). Probably " \ + "you are running PyCAM from a terminal.") % err_msg) return root.title(title) root.bind("", self.finish) root.bind("", self.finish) root.minsize(300, 100) self.root = root frame = Tkinter.Frame(root) frame.pack() # add text output as label message = Tkinter.Message(root, text=message) # we need some space for the dependency report message["width"] = 800 message.pack() # add the "close" button close = Tkinter.Button(root, text="Close") close["command"] = self.finish close.pack(side=Tkinter.BOTTOM) root.mainloop() def finish(self, *args): self.root.quit()