Spaces:
Sleeping
Sleeping
| # App.py | |
| # Application stuff. | |
| # The application is responsible for managing the main frame window. | |
| # | |
| # We also grab the FileOpen command, to invoke our Python editor | |
| " The PythonWin application code. Manages most aspects of MDI, etc " | |
| import os | |
| import sys | |
| import traceback | |
| import regutil | |
| import win32api | |
| import win32con | |
| import win32ui | |
| from pywin.mfc import afxres, dialog, window | |
| from pywin.mfc.thread import WinApp | |
| from . import scriptutils | |
| ## NOTE: App and AppBuild should NOT be used - instead, you should contruct your | |
| ## APP class manually whenever you like (just ensure you leave these 2 params None!) | |
| ## Whoever wants the generic "Application" should get it via win32iu.GetApp() | |
| # These are "legacy" | |
| AppBuilder = None | |
| App = None # default - if used, must end up a CApp derived class. | |
| # Helpers that should one day be removed! | |
| def AddIdleHandler(handler): | |
| print( | |
| "app.AddIdleHandler is deprecated - please use win32ui.GetApp().AddIdleHandler() instead." | |
| ) | |
| return win32ui.GetApp().AddIdleHandler(handler) | |
| def DeleteIdleHandler(handler): | |
| print( | |
| "app.DeleteIdleHandler is deprecated - please use win32ui.GetApp().DeleteIdleHandler() instead." | |
| ) | |
| return win32ui.GetApp().DeleteIdleHandler(handler) | |
| # Helper for writing a Window position by name, and later loading it. | |
| def SaveWindowSize(section, rect, state=""): | |
| """Writes a rectangle to an INI file | |
| Args: section = section name in the applications INI file | |
| rect = a rectangle in a (cy, cx, y, x) tuple | |
| (same format as CREATESTRUCT position tuples).""" | |
| left, top, right, bottom = rect | |
| if state: | |
| state = state + " " | |
| win32ui.WriteProfileVal(section, state + "left", left) | |
| win32ui.WriteProfileVal(section, state + "top", top) | |
| win32ui.WriteProfileVal(section, state + "right", right) | |
| win32ui.WriteProfileVal(section, state + "bottom", bottom) | |
| def LoadWindowSize(section, state=""): | |
| """Loads a section from an INI file, and returns a rect in a tuple (see SaveWindowSize)""" | |
| if state: | |
| state = state + " " | |
| left = win32ui.GetProfileVal(section, state + "left", 0) | |
| top = win32ui.GetProfileVal(section, state + "top", 0) | |
| right = win32ui.GetProfileVal(section, state + "right", 0) | |
| bottom = win32ui.GetProfileVal(section, state + "bottom", 0) | |
| return (left, top, right, bottom) | |
| def RectToCreateStructRect(rect): | |
| return (rect[3] - rect[1], rect[2] - rect[0], rect[1], rect[0]) | |
| # Define FrameWindow and Application objects | |
| # | |
| # The Main Frame of the application. | |
| class MainFrame(window.MDIFrameWnd): | |
| sectionPos = "Main Window" | |
| statusBarIndicators = ( | |
| afxres.ID_SEPARATOR, # // status line indicator | |
| afxres.ID_INDICATOR_CAPS, | |
| afxres.ID_INDICATOR_NUM, | |
| afxres.ID_INDICATOR_SCRL, | |
| win32ui.ID_INDICATOR_LINENUM, | |
| win32ui.ID_INDICATOR_COLNUM, | |
| ) | |
| def OnCreate(self, cs): | |
| self._CreateStatusBar() | |
| return 0 | |
| def _CreateStatusBar(self): | |
| self.statusBar = win32ui.CreateStatusBar(self) | |
| self.statusBar.SetIndicators(self.statusBarIndicators) | |
| self.HookCommandUpdate(self.OnUpdatePosIndicator, win32ui.ID_INDICATOR_LINENUM) | |
| self.HookCommandUpdate(self.OnUpdatePosIndicator, win32ui.ID_INDICATOR_COLNUM) | |
| def OnUpdatePosIndicator(self, cmdui): | |
| editControl = scriptutils.GetActiveEditControl() | |
| value = " " * 5 | |
| if editControl is not None: | |
| try: | |
| startChar, endChar = editControl.GetSel() | |
| lineNo = editControl.LineFromChar(startChar) | |
| colNo = endChar - editControl.LineIndex(lineNo) | |
| if cmdui.m_nID == win32ui.ID_INDICATOR_LINENUM: | |
| value = "%0*d" % (5, lineNo + 1) | |
| else: | |
| value = "%0*d" % (3, colNo + 1) | |
| except win32ui.error: | |
| pass | |
| cmdui.SetText(value) | |
| cmdui.Enable() | |
| def PreCreateWindow(self, cc): | |
| cc = self._obj_.PreCreateWindow(cc) | |
| pos = LoadWindowSize(self.sectionPos) | |
| self.startRect = pos | |
| if pos[2] - pos[0]: | |
| rect = RectToCreateStructRect(pos) | |
| cc = cc[0], cc[1], cc[2], cc[3], rect, cc[5], cc[6], cc[7], cc[8] | |
| return cc | |
| def OnDestroy(self, msg): | |
| # use GetWindowPlacement(), as it works even when min'd or max'd | |
| rectNow = self.GetWindowPlacement()[4] | |
| if rectNow != self.startRect: | |
| SaveWindowSize(self.sectionPos, rectNow) | |
| return 0 | |
| class CApp(WinApp): | |
| "A class for the application" | |
| def __init__(self): | |
| self.oldCallbackCaller = None | |
| WinApp.__init__(self, win32ui.GetApp()) | |
| self.idleHandlers = [] | |
| def InitInstance(self): | |
| "Called to crank up the app" | |
| HookInput() | |
| numMRU = win32ui.GetProfileVal("Settings", "Recent File List Size", 10) | |
| win32ui.LoadStdProfileSettings(numMRU) | |
| # self._obj_.InitMDIInstance() | |
| if win32api.GetVersionEx()[0] < 4: | |
| win32ui.SetDialogBkColor() | |
| win32ui.Enable3dControls() | |
| # install a "callback caller" - a manager for the callbacks | |
| # self.oldCallbackCaller = win32ui.InstallCallbackCaller(self.CallbackManager) | |
| self.LoadMainFrame() | |
| self.SetApplicationPaths() | |
| def ExitInstance(self): | |
| "Called as the app dies - too late to prevent it here!" | |
| win32ui.OutputDebug("Application shutdown\n") | |
| # Restore the callback manager, if any. | |
| try: | |
| win32ui.InstallCallbackCaller(self.oldCallbackCaller) | |
| except AttributeError: | |
| pass | |
| if self.oldCallbackCaller: | |
| del self.oldCallbackCaller | |
| self.frame = None # clean Python references to the now destroyed window object. | |
| self.idleHandlers = [] | |
| # Attempt cleanup if not already done! | |
| if self._obj_: | |
| self._obj_.AttachObject(None) | |
| self._obj_ = None | |
| global App | |
| global AppBuilder | |
| App = None | |
| AppBuilder = None | |
| return 0 | |
| def HaveIdleHandler(self, handler): | |
| return handler in self.idleHandlers | |
| def AddIdleHandler(self, handler): | |
| self.idleHandlers.append(handler) | |
| def DeleteIdleHandler(self, handler): | |
| self.idleHandlers.remove(handler) | |
| def OnIdle(self, count): | |
| try: | |
| ret = 0 | |
| handlers = self.idleHandlers[:] # copy list, as may be modified during loop | |
| for handler in handlers: | |
| try: | |
| thisRet = handler(handler, count) | |
| except: | |
| print("Idle handler %s failed" % (repr(handler))) | |
| traceback.print_exc() | |
| print("Idle handler removed from list") | |
| try: | |
| self.DeleteIdleHandler(handler) | |
| except ValueError: # Item not in list. | |
| pass | |
| thisRet = 0 | |
| ret = ret or thisRet | |
| return ret | |
| except KeyboardInterrupt: | |
| pass | |
| def CreateMainFrame(self): | |
| return MainFrame() | |
| def LoadMainFrame(self): | |
| "Create the main applications frame" | |
| self.frame = self.CreateMainFrame() | |
| self.SetMainFrame(self.frame) | |
| self.frame.LoadFrame(win32ui.IDR_MAINFRAME, win32con.WS_OVERLAPPEDWINDOW) | |
| self.frame.DragAcceptFiles() # we can accept these. | |
| self.frame.ShowWindow(win32ui.GetInitialStateRequest()) | |
| self.frame.UpdateWindow() | |
| self.HookCommands() | |
| def OnHelp(self, id, code): | |
| try: | |
| if id == win32ui.ID_HELP_GUI_REF: | |
| helpFile = regutil.GetRegisteredHelpFile("Pythonwin Reference") | |
| helpCmd = win32con.HELP_CONTENTS | |
| else: | |
| helpFile = regutil.GetRegisteredHelpFile("Main Python Documentation") | |
| helpCmd = win32con.HELP_FINDER | |
| if helpFile is None: | |
| win32ui.MessageBox("The help file is not registered!") | |
| else: | |
| from . import help | |
| help.OpenHelpFile(helpFile, helpCmd) | |
| except: | |
| t, v, tb = sys.exc_info() | |
| win32ui.MessageBox( | |
| "Internal error in help file processing\r\n%s: %s" % (t, v) | |
| ) | |
| tb = None # Prevent a cycle | |
| def DoLoadModules(self, modules): | |
| # XXX - this should go, but the debugger uses it :-( | |
| # dont do much checking! | |
| for module in modules: | |
| __import__(module) | |
| def HookCommands(self): | |
| self.frame.HookMessage(self.OnDropFiles, win32con.WM_DROPFILES) | |
| self.HookCommand(self.HandleOnFileOpen, win32ui.ID_FILE_OPEN) | |
| self.HookCommand(self.HandleOnFileNew, win32ui.ID_FILE_NEW) | |
| self.HookCommand(self.OnFileMRU, win32ui.ID_FILE_MRU_FILE1) | |
| self.HookCommand(self.OnHelpAbout, win32ui.ID_APP_ABOUT) | |
| self.HookCommand(self.OnHelp, win32ui.ID_HELP_PYTHON) | |
| self.HookCommand(self.OnHelp, win32ui.ID_HELP_GUI_REF) | |
| # Hook for the right-click menu. | |
| self.frame.GetWindow(win32con.GW_CHILD).HookMessage( | |
| self.OnRClick, win32con.WM_RBUTTONDOWN | |
| ) | |
| def SetApplicationPaths(self): | |
| # Load the users/application paths | |
| new_path = [] | |
| apppath = win32ui.GetProfileVal("Python", "Application Path", "").split(";") | |
| for path in apppath: | |
| if len(path) > 0: | |
| new_path.append(win32ui.FullPath(path)) | |
| for extra_num in range(1, 11): | |
| apppath = win32ui.GetProfileVal( | |
| "Python", "Application Path %d" % extra_num, "" | |
| ).split(";") | |
| if len(apppath) == 0: | |
| break | |
| for path in apppath: | |
| if len(path) > 0: | |
| new_path.append(win32ui.FullPath(path)) | |
| sys.path = new_path + sys.path | |
| def OnRClick(self, params): | |
| "Handle right click message" | |
| # put up the entire FILE menu! | |
| menu = win32ui.LoadMenu(win32ui.IDR_TEXTTYPE).GetSubMenu(0) | |
| menu.TrackPopupMenu(params[5]) # track at mouse position. | |
| return 0 | |
| def OnDropFiles(self, msg): | |
| "Handle a file being dropped from file manager" | |
| hDropInfo = msg[2] | |
| self.frame.SetActiveWindow() # active us | |
| nFiles = win32api.DragQueryFile(hDropInfo) | |
| try: | |
| for iFile in range(0, nFiles): | |
| fileName = win32api.DragQueryFile(hDropInfo, iFile) | |
| win32ui.GetApp().OpenDocumentFile(fileName) | |
| finally: | |
| win32api.DragFinish(hDropInfo) | |
| return 0 | |
| # No longer used by Pythonwin, as the C++ code has this same basic functionality | |
| # but handles errors slightly better. | |
| # It all still works, tho, so if you need similar functionality, you can use it. | |
| # Therefore I havent deleted this code completely! | |
| # def CallbackManager( self, ob, args = () ): | |
| # """Manage win32 callbacks. Trap exceptions, report on them, then return 'All OK' | |
| # to the frame-work. """ | |
| # import traceback | |
| # try: | |
| # ret = apply(ob, args) | |
| # return ret | |
| # except: | |
| # # take copies of the exception values, else other (handled) exceptions may get | |
| # # copied over by the other fns called. | |
| # win32ui.SetStatusText('An exception occured in a windows command handler.') | |
| # t, v, tb = sys.exc_info() | |
| # traceback.print_exception(t, v, tb.tb_next) | |
| # try: | |
| # sys.stdout.flush() | |
| # except (NameError, AttributeError): | |
| # pass | |
| # Command handlers. | |
| def OnFileMRU(self, id, code): | |
| "Called when a File 1-n message is recieved" | |
| fileName = win32ui.GetRecentFileList()[id - win32ui.ID_FILE_MRU_FILE1] | |
| win32ui.GetApp().OpenDocumentFile(fileName) | |
| def HandleOnFileOpen(self, id, code): | |
| "Called when FileOpen message is received" | |
| win32ui.GetApp().OnFileOpen() | |
| def HandleOnFileNew(self, id, code): | |
| "Called when FileNew message is received" | |
| win32ui.GetApp().OnFileNew() | |
| def OnHelpAbout(self, id, code): | |
| "Called when HelpAbout message is received. Displays the About dialog." | |
| win32ui.InitRichEdit() | |
| dlg = AboutBox() | |
| dlg.DoModal() | |
| def _GetRegistryValue(key, val, default=None): | |
| # val is registry value - None for default val. | |
| try: | |
| hkey = win32api.RegOpenKey(win32con.HKEY_CURRENT_USER, key) | |
| return win32api.RegQueryValueEx(hkey, val)[0] | |
| except win32api.error: | |
| try: | |
| hkey = win32api.RegOpenKey(win32con.HKEY_LOCAL_MACHINE, key) | |
| return win32api.RegQueryValueEx(hkey, val)[0] | |
| except win32api.error: | |
| return default | |
| scintilla = "Scintilla is Copyright 1998-2008 Neil Hodgson (http://www.scintilla.org)" | |
| idle = "This program uses IDLE extensions by Guido van Rossum, Tim Peters and others." | |
| contributors = "Thanks to the following people for making significant contributions: Roger Upole, Sidnei da Silva, Sam Rushing, Curt Hagenlocher, Dave Brennan, Roger Burnham, Gordon McMillan, Neil Hodgson, Laramie Leavitt. (let me know if I have forgotten you!)" | |
| # The About Box | |
| class AboutBox(dialog.Dialog): | |
| def __init__(self, idd=win32ui.IDD_ABOUTBOX): | |
| dialog.Dialog.__init__(self, idd) | |
| def OnInitDialog(self): | |
| text = ( | |
| "Pythonwin - Python IDE and GUI Framework for Windows.\n\n%s\n\nPython is %s\n\n%s\n\n%s\n\n%s" | |
| % (win32ui.copyright, sys.copyright, scintilla, idle, contributors) | |
| ) | |
| self.SetDlgItemText(win32ui.IDC_EDIT1, text) | |
| # Get the build number - written by installers. | |
| # For distutils build, read pywin32.version.txt | |
| import sysconfig | |
| site_packages = sysconfig.get_paths()["platlib"] | |
| try: | |
| build_no = ( | |
| open(os.path.join(site_packages, "pywin32.version.txt")).read().strip() | |
| ) | |
| ver = "pywin32 build %s" % build_no | |
| except EnvironmentError: | |
| ver = None | |
| if ver is None: | |
| # See if we are Part of Active Python | |
| ver = _GetRegistryValue( | |
| "SOFTWARE\\ActiveState\\ActivePython", "CurrentVersion" | |
| ) | |
| if ver is not None: | |
| ver = "ActivePython build %s" % (ver,) | |
| if ver is None: | |
| ver = "" | |
| self.SetDlgItemText(win32ui.IDC_ABOUT_VERSION, ver) | |
| self.HookCommand(self.OnButHomePage, win32ui.IDC_BUTTON1) | |
| def OnButHomePage(self, id, code): | |
| if code == win32con.BN_CLICKED: | |
| win32api.ShellExecute( | |
| 0, "open", "https://github.com/mhammond/pywin32", None, "", 1 | |
| ) | |
| def Win32RawInput(prompt=None): | |
| "Provide raw_input() for gui apps" | |
| # flush stderr/out first. | |
| try: | |
| sys.stdout.flush() | |
| sys.stderr.flush() | |
| except: | |
| pass | |
| if prompt is None: | |
| prompt = "" | |
| ret = dialog.GetSimpleInput(prompt) | |
| if ret == None: | |
| raise KeyboardInterrupt("operation cancelled") | |
| return ret | |
| def Win32Input(prompt=None): | |
| "Provide input() for gui apps" | |
| return eval(input(prompt)) | |
| def HookInput(): | |
| try: | |
| raw_input | |
| # must be py2x... | |
| sys.modules["__builtin__"].raw_input = Win32RawInput | |
| sys.modules["__builtin__"].input = Win32Input | |
| except NameError: | |
| # must be py3k | |
| import code | |
| sys.modules["builtins"].input = Win32RawInput | |
| def HaveGoodGUI(): | |
| """Returns true if we currently have a good gui available.""" | |
| return "pywin.framework.startup" in sys.modules | |
| def CreateDefaultGUI(appClass=None): | |
| """Creates a default GUI environment""" | |
| if appClass is None: | |
| from . import intpyapp # Bring in the default app - could be param'd later. | |
| appClass = intpyapp.InteractivePythonApp | |
| # Create and init the app. | |
| appClass().InitInstance() | |
| def CheckCreateDefaultGUI(): | |
| """Checks and creates if necessary a default GUI environment.""" | |
| rc = HaveGoodGUI() | |
| if not rc: | |
| CreateDefaultGUI() | |
| return rc | |