123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408 |
- # 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 win32con
- import win32api
- import win32ui
- import sys
- import string
- import os
- from pywin.mfc import window, dialog, afxres
- from pywin.mfc.thread import WinApp
- import traceback
- import regutil
- 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 distutils.sysconfig
- site_packages = distutils.sysconfig.get_python_lib(plat_specific=1)
- 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
|