install pywin32-220
This commit is contained in:
parent
15d9012f5a
commit
93f7d415a0
581 changed files with 100203 additions and 0 deletions
BIN
Lib/site-packages/pythonwin/Pythonwin.exe
Normal file
BIN
Lib/site-packages/pythonwin/Pythonwin.exe
Normal file
Binary file not shown.
BIN
Lib/site-packages/pythonwin/dde.pyd
Normal file
BIN
Lib/site-packages/pythonwin/dde.pyd
Normal file
Binary file not shown.
30
Lib/site-packages/pythonwin/license.txt
Normal file
30
Lib/site-packages/pythonwin/license.txt
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
Unless stated in the specfic source file, this work is
|
||||
Copyright (c) 1994-2008, Mark Hammond
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
|
||||
Neither name of Mark Hammond nor the name of contributors may be used
|
||||
to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
BIN
Lib/site-packages/pythonwin/mfc140u.dll
Normal file
BIN
Lib/site-packages/pythonwin/mfc140u.dll
Normal file
Binary file not shown.
BIN
Lib/site-packages/pythonwin/mfcm140u.dll
Normal file
BIN
Lib/site-packages/pythonwin/mfcm140u.dll
Normal file
Binary file not shown.
221
Lib/site-packages/pythonwin/pywin/Demos/app/basictimerapp.py
Normal file
221
Lib/site-packages/pythonwin/pywin/Demos/app/basictimerapp.py
Normal file
|
|
@ -0,0 +1,221 @@
|
|||
# basictimerapp - a really simple timer application.
|
||||
# This should be run using the command line:
|
||||
# pythonwin /app demos\basictimerapp.py
|
||||
import win32ui
|
||||
import win32api
|
||||
import win32con
|
||||
import sys
|
||||
from pywin.framework import app, cmdline, dlgappcore, cmdline
|
||||
import timer
|
||||
import time
|
||||
import string
|
||||
|
||||
class TimerAppDialog(dlgappcore.AppDialog):
|
||||
softspace=1
|
||||
def __init__(self, appName = ""):
|
||||
dlgappcore.AppDialog.__init__(self, win32ui.IDD_GENERAL_STATUS)
|
||||
self.timerAppName = appName
|
||||
self.argOff = 0
|
||||
if len(self.timerAppName)==0:
|
||||
if len(sys.argv)>1 and sys.argv[1][0]!='/':
|
||||
self.timerAppName = sys.argv[1]
|
||||
self.argOff = 1
|
||||
|
||||
def PreDoModal(self):
|
||||
# sys.stderr = sys.stdout
|
||||
pass
|
||||
|
||||
def ProcessArgs(self, args):
|
||||
for arg in args:
|
||||
if arg=="/now":
|
||||
self.OnOK()
|
||||
|
||||
def OnInitDialog(self):
|
||||
win32ui.SetProfileFileName('pytimer.ini')
|
||||
self.title = win32ui.GetProfileVal(self.timerAppName, "Title", "Remote System Timer")
|
||||
self.buildTimer = win32ui.GetProfileVal(self.timerAppName, "Timer", "EachMinuteIntervaler()")
|
||||
self.doWork = win32ui.GetProfileVal(self.timerAppName, "Work", "DoDemoWork()")
|
||||
# replace "\n" with real \n.
|
||||
self.doWork = self.doWork.replace('\\n','\n')
|
||||
dlgappcore.AppDialog.OnInitDialog(self)
|
||||
|
||||
self.SetWindowText(self.title)
|
||||
self.prompt1 = self.GetDlgItem(win32ui.IDC_PROMPT1)
|
||||
self.prompt2 = self.GetDlgItem(win32ui.IDC_PROMPT2)
|
||||
self.prompt3 = self.GetDlgItem(win32ui.IDC_PROMPT3)
|
||||
self.butOK = self.GetDlgItem(win32con.IDOK)
|
||||
self.butCancel = self.GetDlgItem(win32con.IDCANCEL)
|
||||
self.prompt1.SetWindowText("Python Timer App")
|
||||
self.prompt2.SetWindowText("")
|
||||
self.prompt3.SetWindowText("")
|
||||
self.butOK.SetWindowText("Do it now")
|
||||
self.butCancel.SetWindowText("Close")
|
||||
|
||||
self.timerManager = TimerManager(self)
|
||||
self.ProcessArgs(sys.argv[self.argOff:])
|
||||
self.timerManager.go()
|
||||
return 1
|
||||
|
||||
def OnDestroy(self,msg):
|
||||
dlgappcore.AppDialog.OnDestroy(self, msg)
|
||||
self.timerManager.stop()
|
||||
def OnOK(self):
|
||||
# stop the timer, then restart after setting special boolean
|
||||
self.timerManager.stop()
|
||||
self.timerManager.bConnectNow = 1
|
||||
self.timerManager.go()
|
||||
return
|
||||
# def OnCancel(self): default behaviour - cancel == close.
|
||||
# return
|
||||
|
||||
class TimerManager:
|
||||
def __init__(self, dlg):
|
||||
self.dlg = dlg
|
||||
self.timerId = None
|
||||
self.intervaler = eval(self.dlg.buildTimer)
|
||||
self.bConnectNow = 0
|
||||
self.bHaveSetPrompt1 = 0
|
||||
def CaptureOutput(self):
|
||||
self.oldOut = sys.stdout
|
||||
self.oldErr = sys.stderr
|
||||
sys.stdout = sys.stderr = self
|
||||
self.bHaveSetPrompt1 = 0
|
||||
def ReleaseOutput(self):
|
||||
sys.stdout = self.oldOut
|
||||
sys.stderr = self.oldErr
|
||||
def write(self, str):
|
||||
s = str.strip()
|
||||
if len(s):
|
||||
if self.bHaveSetPrompt1:
|
||||
dest = self.dlg.prompt3
|
||||
else:
|
||||
dest = self.dlg.prompt1
|
||||
self.bHaveSetPrompt1 = 1
|
||||
dest.SetWindowText(s)
|
||||
def go(self):
|
||||
self.OnTimer(None,None)
|
||||
def stop(self):
|
||||
if self.timerId: timer.kill_timer (self.timerId)
|
||||
self.timerId = None
|
||||
|
||||
def OnTimer(self, id, timeVal):
|
||||
if id: timer.kill_timer (id)
|
||||
if self.intervaler.IsTime() or self.bConnectNow :
|
||||
# do the work.
|
||||
try:
|
||||
self.dlg.SetWindowText(self.dlg.title + " - Working...")
|
||||
self.dlg.butOK.EnableWindow(0)
|
||||
self.dlg.butCancel.EnableWindow(0)
|
||||
self.CaptureOutput()
|
||||
try:
|
||||
exec(self.dlg.doWork)
|
||||
print("The last operation completed successfully.")
|
||||
except:
|
||||
t, v, tb = sys.exc_info()
|
||||
str = "Failed: %s: %s" % (t, repr(v))
|
||||
print(str)
|
||||
self.oldErr.write(str)
|
||||
tb = None # Prevent cycle
|
||||
finally:
|
||||
self.ReleaseOutput()
|
||||
self.dlg.butOK.EnableWindow()
|
||||
self.dlg.butCancel.EnableWindow()
|
||||
self.dlg.SetWindowText(self.dlg.title)
|
||||
else:
|
||||
now = time.time()
|
||||
nextTime = self.intervaler.GetNextTime()
|
||||
if nextTime:
|
||||
timeDiffSeconds = nextTime - now
|
||||
timeDiffMinutes = int(timeDiffSeconds / 60)
|
||||
timeDiffSeconds = timeDiffSeconds % 60
|
||||
timeDiffHours = int(timeDiffMinutes / 60)
|
||||
timeDiffMinutes = timeDiffMinutes % 60
|
||||
self.dlg.prompt1.SetWindowText("Next connection due in %02d:%02d:%02d" % (timeDiffHours,timeDiffMinutes,timeDiffSeconds))
|
||||
self.timerId = timer.set_timer (self.intervaler.GetWakeupInterval(), self.OnTimer)
|
||||
self.bConnectNow = 0
|
||||
|
||||
class TimerIntervaler:
|
||||
def __init__(self):
|
||||
self.nextTime = None
|
||||
self.wakeUpInterval = 2000
|
||||
def GetWakeupInterval(self):
|
||||
return self.wakeUpInterval
|
||||
def GetNextTime(self):
|
||||
return self.nextTime
|
||||
def IsTime(self):
|
||||
now = time.time()
|
||||
if self.nextTime is None:
|
||||
self.nextTime = self.SetFirstTime(now)
|
||||
ret = 0
|
||||
if now >= self.nextTime:
|
||||
ret = 1
|
||||
self.nextTime = self.SetNextTime(self.nextTime, now)
|
||||
# do the work.
|
||||
return ret
|
||||
|
||||
class EachAnyIntervaler(TimerIntervaler):
|
||||
def __init__(self, timeAt, timePos, timeAdd, wakeUpInterval = None):
|
||||
TimerIntervaler.__init__(self)
|
||||
self.timeAt = timeAt
|
||||
self.timePos = timePos
|
||||
self.timeAdd = timeAdd
|
||||
if wakeUpInterval:
|
||||
self.wakeUpInterval = wakeUpInterval
|
||||
def SetFirstTime(self, now):
|
||||
timeTup = time.localtime(now)
|
||||
lst = []
|
||||
for item in timeTup:
|
||||
lst.append(item)
|
||||
bAdd = timeTup[self.timePos] > self.timeAt
|
||||
lst[self.timePos] = self.timeAt
|
||||
for pos in range(self.timePos+1, 6):
|
||||
lst[pos]=0
|
||||
ret = time.mktime(tuple(lst))
|
||||
if (bAdd):
|
||||
ret = ret + self.timeAdd
|
||||
return ret;
|
||||
|
||||
def SetNextTime(self, lastTime, now):
|
||||
return lastTime + self.timeAdd
|
||||
|
||||
class EachMinuteIntervaler(EachAnyIntervaler):
|
||||
def __init__(self, at=0):
|
||||
EachAnyIntervaler.__init__(self, at, 5, 60, 2000)
|
||||
|
||||
class EachHourIntervaler(EachAnyIntervaler):
|
||||
def __init__(self, at=0):
|
||||
EachAnyIntervaler.__init__(self, at, 4, 3600, 10000)
|
||||
|
||||
class EachDayIntervaler(EachAnyIntervaler):
|
||||
def __init__(self,at=0):
|
||||
EachAnyIntervaler.__init__(self, at, 3, 86400, 10000)
|
||||
|
||||
class TimerDialogApp(dlgappcore.DialogApp):
|
||||
def CreateDialog(self):
|
||||
return TimerAppDialog()
|
||||
|
||||
def DoDemoWork():
|
||||
print("Doing the work...")
|
||||
print("About to connect")
|
||||
win32api.MessageBeep(win32con.MB_ICONASTERISK)
|
||||
win32api.Sleep(2000)
|
||||
print("Doing something else...")
|
||||
win32api.MessageBeep(win32con.MB_ICONEXCLAMATION)
|
||||
win32api.Sleep(2000)
|
||||
print("More work.")
|
||||
win32api.MessageBeep(win32con.MB_ICONHAND)
|
||||
win32api.Sleep(2000)
|
||||
print("The last bit.")
|
||||
win32api.MessageBeep(win32con.MB_OK)
|
||||
win32api.Sleep(2000)
|
||||
|
||||
app = TimerDialogApp()
|
||||
|
||||
def t():
|
||||
t = TimerAppDialog("Test Dialog")
|
||||
t.DoModal()
|
||||
return t
|
||||
|
||||
if __name__=='__main__':
|
||||
import demoutils
|
||||
demoutils.NeedApp()
|
||||
194
Lib/site-packages/pythonwin/pywin/Demos/app/customprint.py
Normal file
194
Lib/site-packages/pythonwin/pywin/Demos/app/customprint.py
Normal file
|
|
@ -0,0 +1,194 @@
|
|||
# A demo of an Application object that has some custom print functionality.
|
||||
|
||||
# If you desire, you can also run this from inside Pythonwin, in which
|
||||
# case it will do the demo inside the Pythonwin environment.
|
||||
|
||||
# This sample was contributed by Roger Burnham.
|
||||
|
||||
from pywin.mfc import docview, dialog, afxres
|
||||
from pywin.framework import app
|
||||
|
||||
import win32con
|
||||
import win32ui
|
||||
import win32api
|
||||
|
||||
PRINTDLGORD = 1538
|
||||
IDC_PRINT_MAG_EDIT = 1010
|
||||
|
||||
|
||||
class PrintDemoTemplate(docview.DocTemplate):
|
||||
def _SetupSharedMenu_(self):
|
||||
pass
|
||||
|
||||
class PrintDemoView(docview.ScrollView):
|
||||
|
||||
def OnInitialUpdate(self):
|
||||
ret = self._obj_.OnInitialUpdate()
|
||||
self.colors = {'Black' : (0x00<<0) + (0x00<<8) + (0x00<<16),
|
||||
'Red' : (0xff<<0) + (0x00<<8) + (0x00<<16),
|
||||
'Green' : (0x00<<0) + (0xff<<8) + (0x00<<16),
|
||||
'Blue' : (0x00<<0) + (0x00<<8) + (0xff<<16),
|
||||
'Cyan' : (0x00<<0) + (0xff<<8) + (0xff<<16),
|
||||
'Magenta': (0xff<<0) + (0x00<<8) + (0xff<<16),
|
||||
'Yellow' : (0xff<<0) + (0xff<<8) + (0x00<<16),
|
||||
}
|
||||
self.pens = {}
|
||||
for name, color in self.colors.items():
|
||||
self.pens[name] = win32ui.CreatePen(win32con.PS_SOLID,
|
||||
5, color)
|
||||
self.pen = None
|
||||
self.size = (128,128)
|
||||
self.SetScaleToFitSize(self.size)
|
||||
self.HookCommand(self.OnFilePrint, afxres.ID_FILE_PRINT)
|
||||
self.HookCommand(self.OnFilePrintPreview,
|
||||
win32ui.ID_FILE_PRINT_PREVIEW)
|
||||
return ret
|
||||
|
||||
def OnDraw(self, dc):
|
||||
oldPen = None
|
||||
x,y = self.size
|
||||
delta = 2
|
||||
colors = list(self.colors.keys())
|
||||
colors.sort()
|
||||
colors = colors*2
|
||||
for color in colors:
|
||||
if oldPen is None:
|
||||
oldPen = dc.SelectObject(self.pens[color])
|
||||
else:
|
||||
dc.SelectObject(self.pens[color])
|
||||
dc.MoveTo(( delta, delta))
|
||||
dc.LineTo((x-delta, delta))
|
||||
dc.LineTo((x-delta, y-delta))
|
||||
dc.LineTo(( delta, y-delta))
|
||||
dc.LineTo(( delta, delta))
|
||||
delta = delta + 4
|
||||
if x-delta <= 0 or y-delta <= 0:
|
||||
break
|
||||
dc.SelectObject(oldPen)
|
||||
|
||||
def OnPrepareDC (self, dc, pInfo):
|
||||
if dc.IsPrinting():
|
||||
mag = self.prtDlg['mag']
|
||||
dc.SetMapMode(win32con.MM_ANISOTROPIC);
|
||||
dc.SetWindowOrg((0, 0))
|
||||
dc.SetWindowExt((1, 1))
|
||||
dc.SetViewportOrg((0, 0))
|
||||
dc.SetViewportExt((mag, mag))
|
||||
|
||||
def OnPreparePrinting(self, pInfo):
|
||||
flags = (win32ui.PD_USEDEVMODECOPIES|
|
||||
win32ui.PD_PAGENUMS|
|
||||
win32ui.PD_NOPAGENUMS|
|
||||
win32ui.PD_NOSELECTION)
|
||||
self.prtDlg = ImagePrintDialog(pInfo, PRINTDLGORD, flags)
|
||||
pInfo.SetPrintDialog(self.prtDlg)
|
||||
pInfo.SetMinPage(1)
|
||||
pInfo.SetMaxPage(1)
|
||||
pInfo.SetFromPage(1)
|
||||
pInfo.SetToPage(1)
|
||||
ret = self.DoPreparePrinting(pInfo)
|
||||
return ret
|
||||
|
||||
def OnBeginPrinting(self, dc, pInfo):
|
||||
return self._obj_.OnBeginPrinting(dc, pInfo)
|
||||
|
||||
def OnEndPrinting(self, dc, pInfo):
|
||||
del self.prtDlg
|
||||
return self._obj_.OnEndPrinting(dc, pInfo)
|
||||
|
||||
def OnFilePrintPreview(self, *arg):
|
||||
self._obj_.OnFilePrintPreview()
|
||||
|
||||
def OnFilePrint(self, *arg):
|
||||
self._obj_.OnFilePrint()
|
||||
|
||||
def OnPrint(self, dc, pInfo):
|
||||
doc = self.GetDocument()
|
||||
metrics = dc.GetTextMetrics()
|
||||
cxChar = metrics['tmAveCharWidth']
|
||||
cyChar = metrics['tmHeight']
|
||||
left, top, right, bottom = pInfo.GetDraw()
|
||||
dc.TextOut(0, 2*cyChar, doc.GetTitle())
|
||||
top = top + (7*cyChar)/2
|
||||
dc.MoveTo(left, top)
|
||||
dc.LineTo(right, top)
|
||||
top = top + cyChar
|
||||
# this seems to have not effect...
|
||||
# get what I want with the dc.SetWindowOrg calls
|
||||
pInfo.SetDraw((left, top, right, bottom))
|
||||
dc.SetWindowOrg((0, -top))
|
||||
|
||||
self.OnDraw(dc)
|
||||
dc.SetTextAlign(win32con.TA_LEFT|win32con.TA_BOTTOM)
|
||||
|
||||
rect = self.GetWindowRect()
|
||||
rect = self.ScreenToClient(rect)
|
||||
height = (rect[3]-rect[1])
|
||||
dc.SetWindowOrg((0, -(top+height+cyChar)))
|
||||
dc.MoveTo(left, 0)
|
||||
dc.LineTo(right, 0)
|
||||
|
||||
x = 0
|
||||
y = (3*cyChar)/2
|
||||
|
||||
dc.TextOut(x, y, doc.GetTitle())
|
||||
y = y + cyChar
|
||||
|
||||
|
||||
class PrintDemoApp(app.CApp):
|
||||
def __init__(self):
|
||||
app.CApp.__init__(self)
|
||||
|
||||
def InitInstance(self):
|
||||
template = PrintDemoTemplate(None, None,
|
||||
None, PrintDemoView)
|
||||
self.AddDocTemplate(template)
|
||||
self._obj_.InitMDIInstance()
|
||||
self.LoadMainFrame()
|
||||
doc = template.OpenDocumentFile(None)
|
||||
doc.SetTitle('Custom Print Document')
|
||||
|
||||
|
||||
class ImagePrintDialog(dialog.PrintDialog):
|
||||
|
||||
sectionPos = 'Image Print Demo'
|
||||
|
||||
def __init__(self, pInfo, dlgID, flags=win32ui.PD_USEDEVMODECOPIES):
|
||||
dialog.PrintDialog.__init__(self, pInfo, dlgID, flags=flags)
|
||||
mag = win32ui.GetProfileVal(self.sectionPos,
|
||||
'Document Magnification',
|
||||
0)
|
||||
if mag <= 0:
|
||||
mag = 2
|
||||
win32ui.WriteProfileVal(self.sectionPos,
|
||||
'Document Magnification',
|
||||
mag)
|
||||
|
||||
self['mag'] = mag
|
||||
|
||||
def OnInitDialog(self):
|
||||
self.magCtl = self.GetDlgItem(IDC_PRINT_MAG_EDIT)
|
||||
self.magCtl.SetWindowText(repr(self['mag']))
|
||||
return dialog.PrintDialog.OnInitDialog(self)
|
||||
def OnOK(self):
|
||||
dialog.PrintDialog.OnOK(self)
|
||||
strMag = self.magCtl.GetWindowText()
|
||||
try:
|
||||
self['mag'] = int(strMag)
|
||||
except:
|
||||
pass
|
||||
win32ui.WriteProfileVal(self.sectionPos,
|
||||
'Document Magnification',
|
||||
self['mag'])
|
||||
|
||||
|
||||
if __name__=='__main__':
|
||||
# Running under Pythonwin
|
||||
def test():
|
||||
template = PrintDemoTemplate(None, None,
|
||||
None, PrintDemoView)
|
||||
template.OpenDocumentFile(None)
|
||||
test()
|
||||
else:
|
||||
app = PrintDemoApp()
|
||||
|
||||
52
Lib/site-packages/pythonwin/pywin/Demos/app/demoutils.py
Normal file
52
Lib/site-packages/pythonwin/pywin/Demos/app/demoutils.py
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
# Utilities for the demos
|
||||
|
||||
import sys, win32api, win32con, win32ui
|
||||
|
||||
NotScriptMsg = """\
|
||||
This demo program is not designed to be run as a Script, but is
|
||||
probably used by some other test program. Please try another demo.
|
||||
"""
|
||||
|
||||
NeedGUIMsg = """\
|
||||
This demo program can only be run from inside of Pythonwin
|
||||
|
||||
You must start Pythonwin, and select 'Run' from the toolbar or File menu
|
||||
"""
|
||||
|
||||
|
||||
NeedAppMsg = """\
|
||||
This demo program is a 'Pythonwin Application'.
|
||||
|
||||
It is more demo code than an example of Pythonwin's capabilities.
|
||||
|
||||
To run it, you must execute the command:
|
||||
pythonwin.exe /app "%s"
|
||||
|
||||
Would you like to execute it now?
|
||||
"""
|
||||
|
||||
def NotAScript():
|
||||
import win32ui
|
||||
win32ui.MessageBox(NotScriptMsg, "Demos")
|
||||
|
||||
def NeedGoodGUI():
|
||||
from pywin.framework.app import HaveGoodGUI
|
||||
rc = HaveGoodGUI()
|
||||
if not rc:
|
||||
win32ui.MessageBox(NeedGUIMsg, "Demos")
|
||||
return rc
|
||||
|
||||
def NeedApp():
|
||||
import win32ui
|
||||
rc = win32ui.MessageBox(NeedAppMsg % sys.argv[0], "Demos", win32con.MB_YESNO)
|
||||
if rc==win32con.IDYES:
|
||||
try:
|
||||
parent = win32ui.GetMainFrame().GetSafeHwnd()
|
||||
win32api.ShellExecute(parent, None, 'pythonwin.exe', '/app "%s"' % sys.argv[0], None, 1)
|
||||
except win32api.error as details:
|
||||
win32ui.MessageBox("Error executing command - %s" % (details), "Demos")
|
||||
|
||||
|
||||
if __name__=='__main__':
|
||||
import demoutils
|
||||
demoutils.NotAScript()
|
||||
46
Lib/site-packages/pythonwin/pywin/Demos/app/dlgappdemo.py
Normal file
46
Lib/site-packages/pythonwin/pywin/Demos/app/dlgappdemo.py
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
# dlgappdemo - a demo of a dialog application.
|
||||
# This is a demonstration of both a custom "application" module,
|
||||
# and a Python program in a dialog box.
|
||||
#
|
||||
# NOTE: You CAN NOT import this module from either PythonWin or Python.
|
||||
# This module must be specified on the commandline to PythonWin only.
|
||||
# eg, PythonWin /app dlgappdemo.py
|
||||
|
||||
from pywin.framework import dlgappcore, app
|
||||
import win32ui
|
||||
import sys
|
||||
|
||||
class TestDialogApp(dlgappcore.DialogApp):
|
||||
def CreateDialog(self):
|
||||
return TestAppDialog()
|
||||
|
||||
|
||||
class TestAppDialog(dlgappcore.AppDialog):
|
||||
def __init__(self):
|
||||
self.edit = None
|
||||
dlgappcore.AppDialog.__init__(self, win32ui.IDD_LARGE_EDIT)
|
||||
def OnInitDialog(self):
|
||||
self.SetWindowText('Test dialog application')
|
||||
self.edit = self.GetDlgItem(win32ui.IDC_EDIT1)
|
||||
print("Hello from Python")
|
||||
print("args are:", end=' ')
|
||||
for arg in sys.argv:
|
||||
print(arg)
|
||||
return 1
|
||||
|
||||
def PreDoModal(self):
|
||||
sys.stdout = sys.stderr = self
|
||||
|
||||
def write(self, str):
|
||||
if self.edit:
|
||||
self.edit.SetSel(-2)
|
||||
# translate \n to \n\r
|
||||
self.edit.ReplaceSel(str.replace('\n','\r\n'))
|
||||
else:
|
||||
win32ui.OutputDebug("dlgapp - no edit control! >>\n%s\n<<\n" % str )
|
||||
|
||||
app.AppBuilder = TestDialogApp
|
||||
|
||||
if __name__=='__main__':
|
||||
import demoutils
|
||||
demoutils.NeedApp()
|
||||
62
Lib/site-packages/pythonwin/pywin/Demos/app/dojobapp.py
Normal file
62
Lib/site-packages/pythonwin/pywin/Demos/app/dojobapp.py
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
# dojobapp - do a job, show the result in a dialog, and exit.
|
||||
#
|
||||
# Very simple - faily minimal dialog based app.
|
||||
#
|
||||
# This should be run using the command line:
|
||||
# pythonwin /app demos\dojobapp.py
|
||||
|
||||
import win32ui
|
||||
import win32api
|
||||
import win32con
|
||||
import sys
|
||||
from pywin.framework import app, dlgappcore
|
||||
import string
|
||||
|
||||
class DoJobAppDialog(dlgappcore.AppDialog):
|
||||
softspace=1
|
||||
def __init__(self, appName = ""):
|
||||
self.appName = appName
|
||||
dlgappcore.AppDialog.__init__(self, win32ui.IDD_GENERAL_STATUS)
|
||||
|
||||
def PreDoModal(self):
|
||||
pass
|
||||
|
||||
def ProcessArgs(self, args):
|
||||
pass
|
||||
|
||||
def OnInitDialog(self):
|
||||
self.SetWindowText(self.appName)
|
||||
butCancel = self.GetDlgItem(win32con.IDCANCEL)
|
||||
butCancel.ShowWindow(win32con.SW_HIDE)
|
||||
p1 = self.GetDlgItem(win32ui.IDC_PROMPT1)
|
||||
p2 = self.GetDlgItem(win32ui.IDC_PROMPT2)
|
||||
|
||||
# Do something here!
|
||||
|
||||
p1.SetWindowText("Hello there")
|
||||
p2.SetWindowText("from the demo")
|
||||
def OnDestroy(self,msg):
|
||||
pass
|
||||
# def OnOK(self):
|
||||
# pass
|
||||
# def OnCancel(self): default behaviour - cancel == close.
|
||||
# return
|
||||
|
||||
class DoJobDialogApp(dlgappcore.DialogApp):
|
||||
def CreateDialog(self):
|
||||
return DoJobAppDialog("Do Something")
|
||||
|
||||
class CopyToDialogApp(DoJobDialogApp):
|
||||
def __init__(self):
|
||||
DoJobDialogApp.__init__(self)
|
||||
|
||||
app.AppBuilder = DoJobDialogApp
|
||||
|
||||
def t():
|
||||
t = DoJobAppDialog("Copy To")
|
||||
t.DoModal()
|
||||
return t
|
||||
|
||||
if __name__=='__main__':
|
||||
import demoutils
|
||||
demoutils.NeedApp()
|
||||
45
Lib/site-packages/pythonwin/pywin/Demos/app/helloapp.py
Normal file
45
Lib/site-packages/pythonwin/pywin/Demos/app/helloapp.py
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
##
|
||||
## helloapp.py
|
||||
##
|
||||
##
|
||||
## A nice, small 'hello world' Pythonwin application.
|
||||
## NOT an MDI application - just a single, normal, top-level window.
|
||||
##
|
||||
## MUST be run with the command line "pythonwin.exe /app helloapp.py"
|
||||
## (or if you are really keen, rename "pythonwin.exe" to something else, then
|
||||
## using MSVC or similar, edit the string section in the .EXE to name this file)
|
||||
##
|
||||
## Originally by Willy Heineman <wheineman@uconect.net>
|
||||
|
||||
|
||||
import win32con
|
||||
import win32ui
|
||||
from pywin.mfc import window, dialog, afxres
|
||||
from pywin.mfc.thread import WinApp
|
||||
|
||||
# The main frame.
|
||||
# Does almost nothing at all - doesnt even create a child window!
|
||||
class HelloWindow(window.Wnd):
|
||||
def __init__(self):
|
||||
# The window.Wnd ctor creates a Window object, and places it in
|
||||
# self._obj_. Note the window object exists, but the window itself
|
||||
# does not!
|
||||
window.Wnd.__init__(self, win32ui.CreateWnd())
|
||||
|
||||
# Now we ask the window object to create the window itself.
|
||||
self._obj_.CreateWindowEx(win32con.WS_EX_CLIENTEDGE, \
|
||||
win32ui.RegisterWndClass(0, 0, win32con.COLOR_WINDOW + 1), \
|
||||
'Hello World!', win32con.WS_OVERLAPPEDWINDOW, \
|
||||
(100, 100, 400, 300), None, 0, None)
|
||||
|
||||
# The application object itself.
|
||||
class HelloApp(WinApp):
|
||||
|
||||
def InitInstance(self):
|
||||
self.frame = HelloWindow()
|
||||
self.frame.ShowWindow(win32con.SW_SHOWNORMAL)
|
||||
# We need to tell MFC what our main frame is.
|
||||
self.SetMainFrame(self.frame)
|
||||
|
||||
# Now create the application object itself!
|
||||
app = HelloApp()
|
||||
108
Lib/site-packages/pythonwin/pywin/Demos/cmdserver.py
Normal file
108
Lib/site-packages/pythonwin/pywin/Demos/cmdserver.py
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
# cmdserver.py
|
||||
|
||||
# Demo code that is not Pythonwin related, but too good to throw away...
|
||||
|
||||
import win32api
|
||||
import sys
|
||||
from pywin.framework import winout
|
||||
|
||||
import _thread, sys
|
||||
|
||||
import traceback
|
||||
|
||||
class ThreadWriter:
|
||||
"Assign an instance to sys.stdout for per-thread printing objects - Courtesy Guido!"
|
||||
def __init__(self):
|
||||
"Constructor -- initialize the table of writers"
|
||||
self.writers = {}
|
||||
self.origStdOut = None
|
||||
def register(self, writer):
|
||||
"Register the writer for the current thread"
|
||||
self.writers[_thread.get_ident()] = writer
|
||||
if self.origStdOut is None:
|
||||
self.origStdOut = sys.stdout
|
||||
sys.stdout = self
|
||||
|
||||
def unregister(self):
|
||||
"Remove the writer for the current thread, if any"
|
||||
try:
|
||||
del self.writers[_thread.get_ident()]
|
||||
except KeyError:
|
||||
pass
|
||||
if len(self.writers)==0:
|
||||
sys.stdout = self.origStdOut
|
||||
self.origStdOut = None
|
||||
|
||||
def getwriter(self):
|
||||
"Return the current thread's writer, default sys.stdout"
|
||||
try:
|
||||
return self.writers[_thread.get_ident()]
|
||||
except KeyError:
|
||||
return self.origStdOut
|
||||
|
||||
def write(self, str):
|
||||
"Write to the current thread's writer, default sys.stdout"
|
||||
self.getwriter().write(str)
|
||||
|
||||
def Test():
|
||||
num=1
|
||||
while num<1000:
|
||||
print('Hello there no ' + str(num))
|
||||
win32api.Sleep(50)
|
||||
num = num + 1
|
||||
|
||||
class flags:
|
||||
SERVER_BEST = 0
|
||||
SERVER_IMMEDIATE = 1
|
||||
SERVER_THREAD = 2
|
||||
SERVER_PROCESS = 3
|
||||
|
||||
def StartServer( cmd, title=None, bCloseOnEnd=0, serverFlags = flags.SERVER_BEST ):
|
||||
out = winout.WindowOutput( title, None, winout.flags.WQ_IDLE )
|
||||
if not title:
|
||||
title=cmd
|
||||
out.Create(title)
|
||||
# ServerThread((out, cmd, title, bCloseOnEnd))
|
||||
# out = sys.stdout
|
||||
_thread.start_new_thread( ServerThread, (out, cmd, title, bCloseOnEnd) )
|
||||
|
||||
def ServerThread(myout, cmd, title, bCloseOnEnd):
|
||||
try:
|
||||
writer.register(myout)
|
||||
print('Executing "%s"\n' % cmd)
|
||||
bOK = 1
|
||||
try:
|
||||
import __main__
|
||||
exec (cmd+'\n', __main__.__dict__)
|
||||
except:
|
||||
bOK = 0
|
||||
if bOK:
|
||||
print("Command terminated without errors.")
|
||||
else:
|
||||
t, v, tb = sys.exc_info()
|
||||
print(t, ': ', v)
|
||||
traceback.print_tb(tb)
|
||||
tb = None # prevent a cycle
|
||||
print("Command terminated with an unhandled exception")
|
||||
writer.unregister()
|
||||
if bOK and bCloseOnEnd:
|
||||
myout.frame.DestroyWindow()
|
||||
|
||||
# Unhandled exception of any kind in a thread kills the gui!
|
||||
except:
|
||||
t, v, tb = sys.exc_info()
|
||||
print(t, ': ', v)
|
||||
traceback.print_tb(tb)
|
||||
tb = None
|
||||
print("Thread failed")
|
||||
|
||||
# assist for reloading (when debugging) - use only 1 tracer object,
|
||||
# else a large chain of tracer objects will exist.
|
||||
#try:
|
||||
# writer
|
||||
#except NameError:
|
||||
# writer=ThreadWriter()
|
||||
if __name__=='__main__':
|
||||
import demoutils
|
||||
demoutils.NotAScript()
|
||||
|
||||
98
Lib/site-packages/pythonwin/pywin/Demos/createwin.py
Normal file
98
Lib/site-packages/pythonwin/pywin/Demos/createwin.py
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
#
|
||||
# Window creation example
|
||||
#
|
||||
# This example creates a minimal "control" that just fills in its
|
||||
# window with red. To make your own control, subclass Control and
|
||||
# write your own OnPaint() method. See PyCWnd.HookMessage for what
|
||||
# the parameters to OnPaint are.
|
||||
#
|
||||
|
||||
from pywin.mfc import dialog, window
|
||||
import win32ui
|
||||
import win32con
|
||||
import win32api
|
||||
|
||||
class Control(window.Wnd):
|
||||
"""Generic control class"""
|
||||
def __init__ (self):
|
||||
window.Wnd.__init__(self, win32ui.CreateWnd ())
|
||||
|
||||
def OnPaint (self):
|
||||
dc, paintStruct = self.BeginPaint()
|
||||
self.DoPaint(dc)
|
||||
self.EndPaint(paintStruct)
|
||||
|
||||
def DoPaint (self, dc): # Override this!
|
||||
pass
|
||||
|
||||
class RedBox (Control):
|
||||
def DoPaint (self, dc):
|
||||
dc.FillSolidRect (self.GetClientRect(), win32api.RGB(255,0,0))
|
||||
|
||||
|
||||
class RedBoxWithPie (RedBox):
|
||||
def DoPaint (self, dc):
|
||||
RedBox.DoPaint(self, dc)
|
||||
r = self.GetClientRect()
|
||||
dc.Pie(r[0], r[1], r[2], r[3], 0,0,r[2], r[3]//2)
|
||||
|
||||
def MakeDlgTemplate():
|
||||
style = (win32con.DS_MODALFRAME |
|
||||
win32con.WS_POPUP |
|
||||
win32con.WS_VISIBLE |
|
||||
win32con.WS_CAPTION |
|
||||
win32con.WS_SYSMENU |
|
||||
win32con.DS_SETFONT)
|
||||
cs = (win32con.WS_CHILD |
|
||||
win32con.WS_VISIBLE)
|
||||
|
||||
w = 64
|
||||
h = 64
|
||||
|
||||
dlg = [["Red box",
|
||||
(0, 0, w, h),
|
||||
style,
|
||||
None,
|
||||
(8, "MS Sans Serif")],
|
||||
]
|
||||
|
||||
s = win32con.WS_TABSTOP | cs
|
||||
|
||||
dlg.append([128,
|
||||
"Cancel",
|
||||
win32con.IDCANCEL,
|
||||
(7, h - 18, 50, 14), s | win32con.BS_PUSHBUTTON])
|
||||
|
||||
return dlg
|
||||
|
||||
class TestDialog(dialog.Dialog):
|
||||
def OnInitDialog(self):
|
||||
rc = dialog.Dialog.OnInitDialog(self)
|
||||
self.redbox = RedBox ()
|
||||
self.redbox.CreateWindow (None, "RedBox",
|
||||
win32con.WS_CHILD |
|
||||
win32con.WS_VISIBLE,
|
||||
(5, 5, 90, 68),
|
||||
self, 1003)
|
||||
return rc
|
||||
|
||||
class TestPieDialog(dialog.Dialog):
|
||||
def OnInitDialog(self):
|
||||
rc = dialog.Dialog.OnInitDialog(self)
|
||||
self.control = RedBoxWithPie()
|
||||
self.control.CreateWindow (None, "RedBox with Pie",
|
||||
win32con.WS_CHILD |
|
||||
win32con.WS_VISIBLE,
|
||||
(5, 5, 90, 68),
|
||||
self, 1003)
|
||||
|
||||
def demo(modal=0):
|
||||
d = TestPieDialog (MakeDlgTemplate())
|
||||
if modal:
|
||||
d.DoModal()
|
||||
else:
|
||||
d.CreateWindow()
|
||||
|
||||
if __name__=='__main__':
|
||||
demo(1)
|
||||
|
||||
54
Lib/site-packages/pythonwin/pywin/Demos/demoutils.py
Normal file
54
Lib/site-packages/pythonwin/pywin/Demos/demoutils.py
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
# Utilities for the demos
|
||||
|
||||
import sys, win32api, win32con, win32ui
|
||||
|
||||
NotScriptMsg = """\
|
||||
This demo program is not designed to be run as a Script, but is
|
||||
probably used by some other test program. Please try another demo.
|
||||
"""
|
||||
|
||||
NeedGUIMsg = """\
|
||||
This demo program can only be run from inside of Pythonwin
|
||||
|
||||
You must start Pythonwin, and select 'Run' from the toolbar or File menu
|
||||
"""
|
||||
|
||||
|
||||
NeedAppMsg = """\
|
||||
This demo program is a 'Pythonwin Application'.
|
||||
|
||||
It is more demo code than an example of Pythonwin's capabilities.
|
||||
|
||||
To run it, you must execute the command:
|
||||
pythonwin.exe /app "%s"
|
||||
|
||||
Would you like to execute it now?
|
||||
"""
|
||||
|
||||
def NotAScript():
|
||||
import win32ui
|
||||
win32ui.MessageBox(NotScriptMsg, "Demos")
|
||||
|
||||
def NeedGoodGUI():
|
||||
from pywin.framework.app import HaveGoodGUI
|
||||
rc = HaveGoodGUI()
|
||||
if not rc:
|
||||
win32ui.MessageBox(NeedGUIMsg, "Demos")
|
||||
return rc
|
||||
|
||||
def NeedApp():
|
||||
import win32ui
|
||||
rc = win32ui.MessageBox(NeedAppMsg % sys.argv[0], "Demos", win32con.MB_YESNO)
|
||||
if rc==win32con.IDYES:
|
||||
try:
|
||||
parent = win32ui.GetMainFrame().GetSafeHwnd()
|
||||
win32api.ShellExecute(parent, None, 'pythonwin.exe', '/app "%s"' % sys.argv[0], None, 1)
|
||||
except win32api.error as details:
|
||||
win32ui.MessageBox("Error executing command - %s" % (details), "Demos")
|
||||
|
||||
|
||||
from pywin.framework.app import HaveGoodGUI
|
||||
|
||||
if __name__=='__main__':
|
||||
import demoutils
|
||||
demoutils.NotAScript()
|
||||
69
Lib/site-packages/pythonwin/pywin/Demos/dibdemo.py
Normal file
69
Lib/site-packages/pythonwin/pywin/Demos/dibdemo.py
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
# A demo which creates a view and a frame which displays a PPM format bitmap
|
||||
#
|
||||
# This hasnnt been run in a while, as I dont have many of that format around!
|
||||
import win32ui
|
||||
import win32con
|
||||
import win32api
|
||||
import string
|
||||
|
||||
class DIBView:
|
||||
def __init__(self, doc, dib):
|
||||
self.dib = dib
|
||||
self.view = win32ui.CreateView(doc)
|
||||
self.width = self.height = 0
|
||||
# set up message handlers
|
||||
# self.view.OnPrepareDC = self.OnPrepareDC
|
||||
self.view.HookMessage (self.OnSize, win32con.WM_SIZE)
|
||||
|
||||
def OnSize (self, params):
|
||||
lParam = params[3]
|
||||
self.width = win32api.LOWORD(lParam)
|
||||
self.height = win32api.HIWORD(lParam)
|
||||
|
||||
def OnDraw (self, ob, dc):
|
||||
# set sizes used for "non strecth" mode.
|
||||
self.view.SetScrollSizes(win32con.MM_TEXT, self.dib.GetSize())
|
||||
dibSize = self.dib.GetSize()
|
||||
dibRect = (0,0,dibSize[0], dibSize[1])
|
||||
# stretch BMP.
|
||||
#self.dib.Paint(dc, (0,0,self.width, self.height),dibRect)
|
||||
# non stretch.
|
||||
self.dib.Paint(dc)
|
||||
|
||||
class DIBDemo:
|
||||
def __init__(self, filename, * bPBM):
|
||||
# init data members
|
||||
f = open(filename, 'rb')
|
||||
dib=win32ui.CreateDIBitmap()
|
||||
if len(bPBM)>0:
|
||||
magic=f.readline()
|
||||
if magic != "P6\n":
|
||||
print("The file is not a PBM format file")
|
||||
raise ValueError("Failed - The file is not a PBM format file")
|
||||
# check magic?
|
||||
rowcollist=f.readline().split()
|
||||
cols=int(rowcollist[0])
|
||||
rows=int(rowcollist[1])
|
||||
f.readline() # whats this one?
|
||||
dib.LoadPBMData(f,(cols,rows))
|
||||
else:
|
||||
dib.LoadWindowsFormatFile(f)
|
||||
f.close()
|
||||
# create doc/view
|
||||
self.doc = win32ui.CreateDoc()
|
||||
self.dibView = DIBView( self.doc, dib )
|
||||
self.frame = win32ui.CreateMDIFrame()
|
||||
self.frame.LoadFrame() # this will force OnCreateClient
|
||||
self.doc.SetTitle ('DIB Demo')
|
||||
self.frame.ShowWindow()
|
||||
|
||||
# display the sucka
|
||||
self.frame.ActivateFrame()
|
||||
|
||||
def OnCreateClient( self, createparams, context ):
|
||||
self.dibView.view.CreateWindow(self.frame)
|
||||
return 1
|
||||
|
||||
if __name__=='__main__':
|
||||
import demoutils
|
||||
demoutils.NotAScript()
|
||||
137
Lib/site-packages/pythonwin/pywin/Demos/dlgtest.py
Normal file
137
Lib/site-packages/pythonwin/pywin/Demos/dlgtest.py
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
# A Demo of Pythonwin's Dialog and Property Page support.
|
||||
|
||||
###################
|
||||
#
|
||||
# First demo - use the built-in to Pythonwin "Tab Stop" dialog, but
|
||||
# customise it heavily.
|
||||
#
|
||||
# ID's for the tabstop dialog - out test.
|
||||
#
|
||||
from win32ui import IDD_SET_TABSTOPS
|
||||
from win32ui import IDC_EDIT_TABS
|
||||
from win32ui import IDC_PROMPT_TABS
|
||||
from win32con import IDOK
|
||||
from win32con import IDCANCEL
|
||||
|
||||
import win32ui
|
||||
import win32con
|
||||
|
||||
from pywin.mfc import dialog
|
||||
|
||||
class TestDialog(dialog.Dialog):
|
||||
def __init__(self, modal=1):
|
||||
dialog.Dialog.__init__(self, IDD_SET_TABSTOPS)
|
||||
self.counter=0
|
||||
if modal:
|
||||
self.DoModal()
|
||||
else:
|
||||
self.CreateWindow()
|
||||
|
||||
def OnInitDialog(self):
|
||||
# Set the caption of the dialog itself.
|
||||
self.SetWindowText("Used to be Tab Stops!")
|
||||
# Get a child control, remember it, and change its text.
|
||||
self.edit=self.GetDlgItem(IDC_EDIT_TABS) # the text box.
|
||||
self.edit.SetWindowText("Test")
|
||||
# Hook a Windows message for the dialog.
|
||||
self.edit.HookMessage(self.KillFocus, win32con.WM_KILLFOCUS)
|
||||
# Get the prompt control, and change its next.
|
||||
prompt=self.GetDlgItem(IDC_PROMPT_TABS) # the prompt box.
|
||||
prompt.SetWindowText("Prompt")
|
||||
# And the same for the button..
|
||||
cancel=self.GetDlgItem(IDCANCEL) # the cancel button
|
||||
cancel.SetWindowText("&Kill me")
|
||||
|
||||
# And just for demonstration purposes, we hook the notify message for the dialog.
|
||||
# This allows us to be notified when the Edit Control text changes.
|
||||
self.HookCommand(self.OnNotify, IDC_EDIT_TABS)
|
||||
|
||||
def OnNotify(self, controlid, code):
|
||||
if code==win32con.EN_CHANGE:
|
||||
print("Edit text changed!")
|
||||
return 1 # I handled this, so no need to call defaults!
|
||||
|
||||
# kill focus for the edit box.
|
||||
# Simply increment the value in the text box.
|
||||
def KillFocus(self,msg):
|
||||
self.counter=self.counter+1
|
||||
if self.edit != None:
|
||||
self.edit.SetWindowText(str(self.counter))
|
||||
|
||||
# Called when the dialog box is terminating...
|
||||
def OnDestroy(self,msg):
|
||||
del self.edit
|
||||
del self.counter
|
||||
|
||||
# A very simply Property Sheet.
|
||||
# We only make a new class for demonstration purposes.
|
||||
class TestSheet(dialog.PropertySheet):
|
||||
def __init__(self, title):
|
||||
dialog.PropertySheet.__init__(self, title)
|
||||
self.HookMessage(self.OnActivate, win32con.WM_ACTIVATE)
|
||||
def OnActivate(self, msg):
|
||||
pass
|
||||
|
||||
# A very simply Property Page, which will be "owned" by the above
|
||||
# Property Sheet.
|
||||
# We create a new class, just so we can hook a control notification.
|
||||
class TestPage(dialog.PropertyPage):
|
||||
def OnInitDialog(self):
|
||||
# We use the HookNotify function to allow Python to respond to
|
||||
# Windows WM_NOTIFY messages.
|
||||
# In this case, we are interested in BN_CLICKED messages.
|
||||
self.HookNotify(self.OnNotify, win32con.BN_CLICKED)
|
||||
def OnNotify(self, std, extra):
|
||||
print("OnNotify", std, extra)
|
||||
|
||||
# Some code that actually uses these objects.
|
||||
def demo(modal = 0):
|
||||
TestDialog(modal)
|
||||
|
||||
# property sheet/page demo
|
||||
ps=win32ui.CreatePropertySheet('Property Sheet/Page Demo')
|
||||
# Create a completely standard PropertyPage.
|
||||
page1=win32ui.CreatePropertyPage(win32ui.IDD_PROPDEMO1)
|
||||
# Create our custom property page.
|
||||
page2=TestPage(win32ui.IDD_PROPDEMO2)
|
||||
ps.AddPage(page1)
|
||||
ps.AddPage(page2)
|
||||
if modal:
|
||||
ps.DoModal()
|
||||
else:
|
||||
style = win32con.WS_SYSMENU|win32con.WS_POPUP|win32con.WS_CAPTION|win32con.DS_MODALFRAME|win32con.WS_VISIBLE
|
||||
styleex = win32con.WS_EX_DLGMODALFRAME | win32con.WS_EX_PALETTEWINDOW
|
||||
ps.CreateWindow(win32ui.GetMainFrame(), style, styleex)
|
||||
|
||||
|
||||
def test(modal=1):
|
||||
|
||||
# dlg=dialog.Dialog(1010)
|
||||
# dlg.CreateWindow()
|
||||
# dlg.EndDialog(0)
|
||||
# del dlg
|
||||
# return
|
||||
# property sheet/page demo
|
||||
ps=TestSheet('Property Sheet/Page Demo')
|
||||
page1=win32ui.CreatePropertyPage(win32ui.IDD_PROPDEMO1)
|
||||
page2=win32ui.CreatePropertyPage(win32ui.IDD_PROPDEMO2)
|
||||
ps.AddPage(page1)
|
||||
ps.AddPage(page2)
|
||||
del page1
|
||||
del page2
|
||||
if modal:
|
||||
ps.DoModal()
|
||||
else:
|
||||
ps.CreateWindow(win32ui.GetMainFrame())
|
||||
return ps
|
||||
|
||||
def d():
|
||||
dlg = win32ui.CreateDialog(win32ui.IDD_DEBUGGER)
|
||||
dlg.datalist.append((win32ui.IDC_DBG_RADIOSTACK, "radio"))
|
||||
print("data list is ", dlg.datalist)
|
||||
dlg.data['radio']=1
|
||||
dlg.DoModal()
|
||||
print(dlg.data['radio'])
|
||||
|
||||
if __name__=='__main__':
|
||||
demo(1)
|
||||
73
Lib/site-packages/pythonwin/pywin/Demos/dyndlg.py
Normal file
73
Lib/site-packages/pythonwin/pywin/Demos/dyndlg.py
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
# dyndlg.py
|
||||
# contributed by Curt Hagenlocher <chi@earthlink.net>
|
||||
|
||||
# Dialog Template params:
|
||||
# Parameter 0 - Window caption
|
||||
# Parameter 1 - Bounds (rect tuple)
|
||||
# Parameter 2 - Window style
|
||||
# Parameter 3 - Extended style
|
||||
# Parameter 4 - Font tuple
|
||||
# Parameter 5 - Menu name
|
||||
# Parameter 6 - Window class
|
||||
# Dialog item params:
|
||||
# Parameter 0 - Window class
|
||||
# Parameter 1 - Text
|
||||
# Parameter 2 - ID
|
||||
# Parameter 3 - Bounds
|
||||
# Parameter 4 - Style
|
||||
# Parameter 5 - Extended style
|
||||
# Parameter 6 - Extra data
|
||||
|
||||
|
||||
import win32ui
|
||||
import win32con
|
||||
from pywin.mfc import dialog, window
|
||||
|
||||
def MakeDlgTemplate():
|
||||
style = win32con.DS_MODALFRAME | win32con.WS_POPUP | win32con.WS_VISIBLE | win32con.WS_CAPTION | win32con.WS_SYSMENU | win32con.DS_SETFONT
|
||||
cs = win32con.WS_CHILD | win32con.WS_VISIBLE
|
||||
dlg = [ ["Select Warehouse", (0, 0, 177, 93), style, None, (8, "MS Sans Serif")], ]
|
||||
dlg.append([130, "Current Warehouse:", -1, (7, 7, 69, 9), cs | win32con.SS_LEFT])
|
||||
dlg.append([130, "ASTORIA", 128, (16, 17, 99, 7), cs | win32con.SS_LEFT])
|
||||
dlg.append([130, "New &Warehouse:", -1, (7, 29, 69, 9), cs | win32con.SS_LEFT])
|
||||
s = win32con.WS_TABSTOP | cs
|
||||
# dlg.append([131, None, 130, (5, 40, 110, 48),
|
||||
# s | win32con.LBS_NOTIFY | win32con.LBS_SORT | win32con.LBS_NOINTEGRALHEIGHT | win32con.WS_VSCROLL | win32con.WS_BORDER])
|
||||
dlg.append(["{8E27C92B-1264-101C-8A2F-040224009C02}", None, 131, (5, 40, 110, 48),win32con.WS_TABSTOP])
|
||||
|
||||
dlg.append([128, "OK", win32con.IDOK, (124, 5, 50, 14), s | win32con.BS_DEFPUSHBUTTON])
|
||||
s = win32con.BS_PUSHBUTTON | s
|
||||
dlg.append([128, "Cancel", win32con.IDCANCEL, (124, 22, 50, 14), s])
|
||||
dlg.append([128, "&Help", 100, (124, 74, 50, 14), s])
|
||||
|
||||
return dlg
|
||||
|
||||
def test1():
|
||||
win32ui.CreateDialogIndirect( MakeDlgTemplate() ).DoModal()
|
||||
|
||||
def test2():
|
||||
dialog.Dialog( MakeDlgTemplate() ).DoModal()
|
||||
|
||||
def test3():
|
||||
dlg = win32ui.LoadDialogResource(win32ui.IDD_SET_TABSTOPS)
|
||||
dlg[0][0] = 'New Dialog Title'
|
||||
dlg[0][1] = (80, 20, 161, 60)
|
||||
dlg[1][1] = '&Confusion:'
|
||||
cs = win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.WS_TABSTOP | win32con.BS_PUSHBUTTON
|
||||
dlg.append([128, "&Help", 100, (111, 41, 40, 14), cs])
|
||||
dialog.Dialog( dlg ).DoModal()
|
||||
|
||||
def test4():
|
||||
page1=dialog.PropertyPage(win32ui.LoadDialogResource(win32ui.IDD_PROPDEMO1))
|
||||
page2=dialog.PropertyPage(win32ui.LoadDialogResource(win32ui.IDD_PROPDEMO2))
|
||||
ps=dialog.PropertySheet('Property Sheet/Page Demo', None, [page1, page2])
|
||||
ps.DoModal()
|
||||
|
||||
def testall():
|
||||
test1()
|
||||
test2()
|
||||
test3()
|
||||
test4()
|
||||
|
||||
if __name__=='__main__':
|
||||
testall()
|
||||
79
Lib/site-packages/pythonwin/pywin/Demos/fontdemo.py
Normal file
79
Lib/site-packages/pythonwin/pywin/Demos/fontdemo.py
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
# Demo of Generic document windows, DC, and Font usage
|
||||
# by Dave Brennan (brennan@hal.com)
|
||||
|
||||
# usage examples:
|
||||
|
||||
# >>> from fontdemo import *
|
||||
# >>> d = FontDemo('Hello, Python')
|
||||
# >>> f1 = { 'name':'Arial', 'height':36, 'weight':win32con.FW_BOLD}
|
||||
# >>> d.SetFont(f1)
|
||||
# >>> f2 = {'name':'Courier New', 'height':24, 'italic':1}
|
||||
# >>> d.SetFont (f2)
|
||||
|
||||
import win32ui
|
||||
import win32con
|
||||
import win32api
|
||||
|
||||
from pywin.mfc import docview
|
||||
|
||||
|
||||
# font is a dictionary in which the following elements matter:
|
||||
# (the best matching font to supplied parameters is returned)
|
||||
# name string name of the font as known by Windows
|
||||
# size point size of font in logical units
|
||||
# weight weight of font (win32con.FW_NORMAL, win32con.FW_BOLD)
|
||||
# italic boolean; true if set to anything but None
|
||||
# underline boolean; true if set to anything but None
|
||||
|
||||
class FontView(docview.ScrollView):
|
||||
def __init__(self, doc, text = 'Python Rules!', font_spec = {'name':'Arial', 'height':42}):
|
||||
docview.ScrollView.__init__(self, doc)
|
||||
self.font = win32ui.CreateFont (font_spec)
|
||||
self.text = text
|
||||
self.width = self.height = 0
|
||||
# set up message handlers
|
||||
self.HookMessage (self.OnSize, win32con.WM_SIZE)
|
||||
def OnAttachedObjectDeath(self):
|
||||
docview.ScrollView.OnAttachedObjectDeath(self)
|
||||
del self.font
|
||||
|
||||
def SetFont (self, new_font):
|
||||
# Change font on the fly
|
||||
self.font = win32ui.CreateFont (new_font)
|
||||
# redraw the entire client window
|
||||
selfInvalidateRect (None)
|
||||
def OnSize (self, params):
|
||||
lParam = params[3]
|
||||
self.width = win32api.LOWORD(lParam)
|
||||
self.height = win32api.HIWORD(lParam)
|
||||
|
||||
def OnPrepareDC (self, dc, printinfo):
|
||||
# Set up the DC for forthcoming OnDraw call
|
||||
self.SetScrollSizes(win32con.MM_TEXT, (100,100))
|
||||
dc.SetTextColor (win32api.RGB(0,0,255))
|
||||
dc.SetBkColor (win32api.GetSysColor (win32con.COLOR_WINDOW))
|
||||
dc.SelectObject (self.font)
|
||||
dc.SetTextAlign (win32con.TA_CENTER | win32con.TA_BASELINE)
|
||||
|
||||
def OnDraw (self, dc):
|
||||
if (self.width == 0 and self.height == 0):
|
||||
left, top, right, bottom = self.GetClientRect()
|
||||
self.width = right - left
|
||||
self.height = bottom - top
|
||||
x, y = self.width // 2, self.height // 2
|
||||
dc.TextOut (x, y, self.text)
|
||||
|
||||
def FontDemo():
|
||||
# create doc/view
|
||||
template = docview.DocTemplate(win32ui.IDR_PYTHONTYPE, None, None, FontView)
|
||||
doc=template.OpenDocumentFile(None)
|
||||
doc.SetTitle ('Font Demo')
|
||||
# print "template is ", template, "obj is", template._obj_
|
||||
template.close()
|
||||
# print "closed"
|
||||
# del template
|
||||
|
||||
if __name__=='__main__':
|
||||
import demoutils
|
||||
if demoutils.NeedGoodGUI():
|
||||
FontDemo()
|
||||
68
Lib/site-packages/pythonwin/pywin/Demos/guidemo.py
Normal file
68
Lib/site-packages/pythonwin/pywin/Demos/guidemo.py
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
# GUI Demo - just a worker script to invoke all the other demo/test scripts.
|
||||
import win32ui
|
||||
import __main__
|
||||
import sys
|
||||
import regutil
|
||||
import win32api
|
||||
|
||||
demos = [ \
|
||||
# ('Font', 'import fontdemo;fontdemo.FontDemo()'),
|
||||
('Open GL Demo', 'import openGLDemo;openGLDemo.test()'),
|
||||
('Threaded GUI', 'import threadedgui;threadedgui.ThreadedDemo()'),
|
||||
('Tree View Demo', 'import hiertest;hiertest.demoboth()'),
|
||||
('3-Way Splitter Window', 'import splittst;splittst.demo()'),
|
||||
('Custom Toolbars and Tooltips', 'import toolbar;toolbar.test()'),
|
||||
('Progress Bar', 'import progressbar;progressbar.demo()'),
|
||||
('Slider Control', 'import sliderdemo;sliderdemo.demo()'),
|
||||
('Dynamic window creation', 'import createwin;createwin.demo()'),
|
||||
('Various Dialog demos', 'import dlgtest;dlgtest.demo()'),
|
||||
('OCX Control Demo', 'from ocx import ocxtest;ocxtest.demo()'),
|
||||
('OCX Serial Port Demo', 'from ocx import ocxserialtest; ocxserialtest.test()'),
|
||||
('IE4 Control Demo', 'from ocx import webbrowser; webbrowser.Demo("http://www.python.org")'),
|
||||
]
|
||||
|
||||
def demo():
|
||||
try:
|
||||
# seeif I can locate the demo files.
|
||||
import fontdemo
|
||||
except ImportError:
|
||||
# else put the demos direectory on the path (if not already)
|
||||
try:
|
||||
instPath = regutil.GetRegistryDefaultValue(regutil.BuildDefaultPythonKey() + "\\InstallPath")
|
||||
except win32api.error:
|
||||
print("The InstallPath can not be located, and the Demos directory is not on the path")
|
||||
instPath="."
|
||||
|
||||
demosDir = win32ui.FullPath(instPath + "\\Demos")
|
||||
for path in sys.path:
|
||||
if win32ui.FullPath(path)==demosDir:
|
||||
break
|
||||
else:
|
||||
sys.path.append(demosDir)
|
||||
import fontdemo
|
||||
|
||||
import sys
|
||||
if "/go" in sys.argv:
|
||||
for name, cmd in demos:
|
||||
try:
|
||||
exec(cmd)
|
||||
except:
|
||||
print("Demo of %s failed - %s:%s" % (cmd,sys.exc_info()[0], sys.exc_info()[1]))
|
||||
return
|
||||
# Otherwise allow the user to select the demo to run
|
||||
|
||||
import pywin.dialogs.list
|
||||
while 1:
|
||||
rc = pywin.dialogs.list.SelectFromLists( "Select a Demo", demos, ['Demo Title'] )
|
||||
if rc is None:
|
||||
break
|
||||
title, cmd = demos[rc]
|
||||
try:
|
||||
exec(cmd)
|
||||
except:
|
||||
print("Demo of %s failed - %s:%s" % (title,sys.exc_info()[0], sys.exc_info()[1]))
|
||||
|
||||
if __name__==__main__.__name__:
|
||||
import demoutils
|
||||
if demoutils.NeedGoodGUI():
|
||||
demo()
|
||||
104
Lib/site-packages/pythonwin/pywin/Demos/hiertest.py
Normal file
104
Lib/site-packages/pythonwin/pywin/Demos/hiertest.py
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
import win32ui
|
||||
import os
|
||||
import commctrl
|
||||
|
||||
from pywin.tools import hierlist
|
||||
from pywin.mfc import docview, window
|
||||
|
||||
# directory listbox
|
||||
# This has obvious limitations - doesnt track subdirs, etc. Demonstrates
|
||||
# simple use of Python code for querying the tree as needed.
|
||||
# Only use strings, and lists of strings (from curdir())
|
||||
class DirHierList(hierlist.HierList):
|
||||
def __init__(self, root, listBoxID = win32ui.IDC_LIST1):
|
||||
hierlist.HierList.__init__(self, root, win32ui.IDB_HIERFOLDERS, listBoxID)
|
||||
def GetText(self, item):
|
||||
return os.path.basename(item)
|
||||
def GetSubList(self, item):
|
||||
if os.path.isdir(item):
|
||||
ret = [os.path.join(item, fname) for fname in os.listdir(item)]
|
||||
else:
|
||||
ret = None
|
||||
return ret
|
||||
# if the item is a dir, it is expandable.
|
||||
def IsExpandable(self, item):
|
||||
return os.path.isdir(item)
|
||||
def GetSelectedBitmapColumn(self, item):
|
||||
return self.GetBitmapColumn(item)+6 # Use different color for selection
|
||||
|
||||
class TestDocument(docview.Document):
|
||||
def __init__(self, template):
|
||||
docview.Document.__init__(self, template)
|
||||
self.hierlist = hierlist.HierListWithItems(HLIFileDir("\\"), win32ui.IDB_HIERFOLDERS, win32ui.AFX_IDW_PANE_FIRST)
|
||||
|
||||
class HierListView(docview.TreeView):
|
||||
def OnInitialUpdate(self):
|
||||
rc = self._obj_.OnInitialUpdate()
|
||||
self.hierList = self.GetDocument().hierlist
|
||||
self.hierList.HierInit(self.GetParent())
|
||||
self.hierList.SetStyle(commctrl.TVS_HASLINES | commctrl.TVS_LINESATROOT | commctrl.TVS_HASBUTTONS)
|
||||
return rc
|
||||
|
||||
class HierListFrame(window.MDIChildWnd):
|
||||
pass
|
||||
|
||||
def GetTestRoot():
|
||||
tree1 = ('Tree 1',[('Item 1','Item 1 data'),'Item 2',3])
|
||||
tree2 = ('Tree 2',[('Item 2.1','Item 2 data'),'Item 2.2',2.3])
|
||||
return ('Root',[tree1,tree2,'Item 3'])
|
||||
|
||||
def demoboth():
|
||||
template = docview.DocTemplate(win32ui.IDR_PYTHONTYPE, TestDocument, HierListFrame, HierListView)
|
||||
template.OpenDocumentFile(None).SetTitle("Hierlist demo")
|
||||
|
||||
demomodeless()
|
||||
|
||||
def demomodeless():
|
||||
testList2=DirHierList("\\")
|
||||
dlg=hierlist.HierDialog('hier list test',testList2)
|
||||
dlg.CreateWindow()
|
||||
|
||||
def demodlg ():
|
||||
testList2=DirHierList("\\")
|
||||
dlg=hierlist.HierDialog('hier list test',testList2)
|
||||
dlg.DoModal()
|
||||
|
||||
def demo():
|
||||
template = docview.DocTemplate(win32ui.IDR_PYTHONTYPE, TestDocument, HierListFrame, HierListView)
|
||||
template.OpenDocumentFile(None).SetTitle("Hierlist demo")
|
||||
|
||||
#
|
||||
# Demo/Test for HierList items.
|
||||
#
|
||||
# Easy to make a better directory program.
|
||||
#
|
||||
class HLIFileDir(hierlist.HierListItem):
|
||||
def __init__( self, filename ):
|
||||
self.filename = filename
|
||||
hierlist.HierListItem.__init__(self)
|
||||
def GetText(self):
|
||||
try:
|
||||
return "%-20s %d bytes" % (os.path.basename(self.filename), os.stat(self.filename)[6])
|
||||
except os.error as details:
|
||||
return "%-20s - %s" % (self.filename, details[1])
|
||||
|
||||
def IsExpandable(self):
|
||||
return os.path.isdir(self.filename)
|
||||
def GetSubList(self):
|
||||
ret = []
|
||||
for newname in os.listdir(self.filename):
|
||||
if newname not in ['.', '..']:
|
||||
ret.append( HLIFileDir( os.path.join(self.filename,newname ) ) )
|
||||
return ret
|
||||
|
||||
|
||||
def demohli():
|
||||
template = docview.DocTemplate(win32ui.IDR_PYTHONTYPE, TestDocument, hierlist.HierListFrame, hierlist.HierListView)
|
||||
template.OpenDocumentFile(None).SetTitle("Hierlist demo")
|
||||
|
||||
if __name__=='__main__':
|
||||
import demoutils
|
||||
if demoutils.HaveGoodGUI():
|
||||
demoboth()
|
||||
else:
|
||||
demodlg()
|
||||
12
Lib/site-packages/pythonwin/pywin/Demos/menutest.py
Normal file
12
Lib/site-packages/pythonwin/pywin/Demos/menutest.py
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
# Run this as a python script, to gray "close" off the edit window system menu.
|
||||
from pywin.framework import interact
|
||||
import win32con
|
||||
|
||||
if __name__=='__main__':
|
||||
import demoutils
|
||||
if demoutils.NeedGoodGUI():
|
||||
win=interact.edit.currentView.GetParent()
|
||||
menu=win.GetSystemMenu()
|
||||
id=menu.GetMenuItemID(6)
|
||||
menu.EnableMenuItem(id,win32con.MF_BYCOMMAND|win32con.MF_GRAYED)
|
||||
print("The interactive window's 'Close' menu item is now disabled.")
|
||||
49
Lib/site-packages/pythonwin/pywin/Demos/objdoc.py
Normal file
49
Lib/site-packages/pythonwin/pywin/Demos/objdoc.py
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
# This is a sample file, and shows the basic framework for using an "Object" based
|
||||
# document, rather than a "filename" based document.
|
||||
# This is referenced by the Pythonwin .html documentation.
|
||||
|
||||
# In the example below, the OpenObject() method is used instead of OpenDocumentFile,
|
||||
# and all the core MFC document open functionality is retained.
|
||||
|
||||
import win32ui
|
||||
from pywin.mfc import docview
|
||||
|
||||
class object_template (docview.DocTemplate):
|
||||
def __init__(self):
|
||||
docview.DocTemplate.__init__(self, None, None, None, object_view)
|
||||
def OpenObject(self, object): # Use this instead of OpenDocumentFile.
|
||||
# Look for existing open document
|
||||
for doc in self.GetDocumentList():
|
||||
print("document is ", doc)
|
||||
if doc.object is object:
|
||||
doc.GetFirstView().ActivateFrame()
|
||||
return doc
|
||||
# not found - new one.
|
||||
doc = object_document(self, object)
|
||||
frame = self.CreateNewFrame(doc)
|
||||
doc.OnNewDocument()
|
||||
doc.SetTitle(str(object))
|
||||
self.InitialUpdateFrame(frame, doc)
|
||||
return doc
|
||||
|
||||
class object_document (docview.Document):
|
||||
def __init__(self, template, object):
|
||||
docview.Document.__init__(self, template)
|
||||
self.object = object
|
||||
def OnOpenDocument (self, name):
|
||||
raise RuntimeError("Should not be called if template strings set up correctly")
|
||||
return 0
|
||||
|
||||
class object_view (docview.EditView):
|
||||
def OnInitialUpdate (self):
|
||||
self.ReplaceSel("Object is %s" % repr(self.GetDocument().object))
|
||||
|
||||
def demo ():
|
||||
t = object_template()
|
||||
d = t.OpenObject(win32ui)
|
||||
return (t, d)
|
||||
|
||||
if __name__=='__main__':
|
||||
import demoutils
|
||||
if demoutils.NeedGoodGUI():
|
||||
demo()
|
||||
0
Lib/site-packages/pythonwin/pywin/Demos/ocx/__init__.py
Normal file
0
Lib/site-packages/pythonwin/pywin/Demos/ocx/__init__.py
Normal file
54
Lib/site-packages/pythonwin/pywin/Demos/ocx/demoutils.py
Normal file
54
Lib/site-packages/pythonwin/pywin/Demos/ocx/demoutils.py
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
# Utilities for the demos
|
||||
|
||||
import sys, win32api, win32con, win32ui
|
||||
|
||||
NotScriptMsg = """\
|
||||
This demo program is not designed to be run as a Script, but is
|
||||
probably used by some other test program. Please try another demo.
|
||||
"""
|
||||
|
||||
NeedGUIMsg = """\
|
||||
This demo program can only be run from inside of Pythonwin
|
||||
|
||||
You must start Pythonwin, and select 'Run' from the toolbar or File menu
|
||||
"""
|
||||
|
||||
|
||||
NeedAppMsg = """\
|
||||
This demo program is a 'Pythonwin Application'.
|
||||
|
||||
It is more demo code than an example of Pythonwin's capabilities.
|
||||
|
||||
To run it, you must execute the command:
|
||||
pythonwin.exe /app "%s"
|
||||
|
||||
Would you like to execute it now?
|
||||
"""
|
||||
|
||||
def NotAScript():
|
||||
import win32ui
|
||||
win32ui.MessageBox(NotScriptMsg, "Demos")
|
||||
|
||||
def NeedGoodGUI():
|
||||
from pywin.framework.app import HaveGoodGUI
|
||||
rc = HaveGoodGUI()
|
||||
if not rc:
|
||||
win32ui.MessageBox(NeedGUIMsg, "Demos")
|
||||
return rc
|
||||
|
||||
def NeedApp():
|
||||
import win32ui
|
||||
rc = win32ui.MessageBox(NeedAppMsg % sys.argv[0], "Demos", win32con.MB_YESNO)
|
||||
if rc==win32con.IDYES:
|
||||
try:
|
||||
parent = win32ui.GetMainFrame().GetSafeHwnd()
|
||||
win32api.ShellExecute(parent, None, 'pythonwin.exe', '/app "%s"' % sys.argv[0], None, 1)
|
||||
except win32api.error as details:
|
||||
win32ui.MessageBox("Error executing command - %s" % (details), "Demos")
|
||||
|
||||
|
||||
from pywin.framework.app import HaveGoodGUI
|
||||
|
||||
if __name__=='__main__':
|
||||
import demoutils
|
||||
demoutils.NotAScript()
|
||||
84
Lib/site-packages/pythonwin/pywin/Demos/ocx/flash.py
Normal file
84
Lib/site-packages/pythonwin/pywin/Demos/ocx/flash.py
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
# By Bradley Schatz
|
||||
# simple flash/python application demonstrating bidirectional
|
||||
# communicaion between flash and python. Click the sphere to see
|
||||
# behavior. Uses Bounce.swf from FlashBounce.zip, available from
|
||||
# http://pages.cpsc.ucalgary.ca/~saul/vb_examples/tutorial12/
|
||||
|
||||
# Update to the path of the .swf file (note it could be a true URL)
|
||||
flash_url = "c:\\bounce.swf"
|
||||
|
||||
import win32ui, win32con, win32api, regutil
|
||||
from pywin.mfc import window, activex
|
||||
from win32com.client import gencache
|
||||
import sys
|
||||
|
||||
FlashModule = gencache.EnsureModule("{D27CDB6B-AE6D-11CF-96B8-444553540000}", 0, 1, 0)
|
||||
|
||||
if FlashModule is None:
|
||||
raise ImportError("Flash does not appear to be installed.")
|
||||
|
||||
class MyFlashComponent(activex.Control, FlashModule.ShockwaveFlash):
|
||||
def __init__(self):
|
||||
activex.Control.__init__(self)
|
||||
FlashModule.ShockwaveFlash.__init__(self)
|
||||
self.x = 50
|
||||
self.y = 50
|
||||
self.angle = 30
|
||||
self.started = 0
|
||||
|
||||
def OnFSCommand(self, command, args):
|
||||
print("FSCommend" , command, args)
|
||||
self.x = self.x + 20
|
||||
self.y = self.y + 20
|
||||
self.angle = self.angle + 20
|
||||
if self.x > 200 or self.y > 200:
|
||||
self.x = 0
|
||||
self.y = 0
|
||||
if self.angle > 360:
|
||||
self.angle = 0
|
||||
self.SetVariable("xVal", self.x)
|
||||
self.SetVariable("yVal", self.y)
|
||||
self.SetVariable("angle", self.angle)
|
||||
self.TPlay("_root.mikeBall")
|
||||
|
||||
def OnProgress(self, percentDone):
|
||||
print("PercentDone", percentDone)
|
||||
def OnReadyStateChange(self, newState):
|
||||
# 0=Loading, 1=Uninitialized, 2=Loaded, 3=Interactive, 4=Complete
|
||||
print("State", newState)
|
||||
|
||||
|
||||
class BrowserFrame(window.MDIChildWnd):
|
||||
def __init__(self, url = None):
|
||||
if url is None:
|
||||
self.url = regutil.GetRegisteredHelpFile("Main Python Documentation")
|
||||
else:
|
||||
self.url = url
|
||||
pass # Dont call base class doc/view version...
|
||||
def Create(self, title, rect = None, parent = None):
|
||||
style = win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.WS_OVERLAPPEDWINDOW
|
||||
self._obj_ = win32ui.CreateMDIChild()
|
||||
self._obj_.AttachObject(self)
|
||||
self._obj_.CreateWindow(None, title, style, rect, parent)
|
||||
rect = self.GetClientRect()
|
||||
rect = (0,0,rect[2]-rect[0], rect[3]-rect[1])
|
||||
self.ocx = MyFlashComponent()
|
||||
self.ocx.CreateControl("Flash Player", win32con.WS_VISIBLE | win32con.WS_CHILD, rect, self, 1000)
|
||||
self.ocx.LoadMovie(0,flash_url)
|
||||
self.ocx.Play()
|
||||
self.HookMessage (self.OnSize, win32con.WM_SIZE)
|
||||
|
||||
def OnSize (self, params):
|
||||
rect = self.GetClientRect()
|
||||
rect = (0,0,rect[2]-rect[0], rect[3]-rect[1])
|
||||
self.ocx.SetWindowPos(0, rect, 0)
|
||||
|
||||
def Demo():
|
||||
url = None
|
||||
if len(sys.argv)>1:
|
||||
url = win32api.GetFullPathName(sys.argv[1])
|
||||
f = BrowserFrame(url)
|
||||
f.Create("Flash Player")
|
||||
|
||||
if __name__=='__main__':
|
||||
Demo()
|
||||
127
Lib/site-packages/pythonwin/pywin/Demos/ocx/msoffice.py
Normal file
127
Lib/site-packages/pythonwin/pywin/Demos/ocx/msoffice.py
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
# This demo uses some of the Microsoft Office components.
|
||||
#
|
||||
# It was taken from an MSDN article showing how to embed excel.
|
||||
# It is not comlpete yet, but it _does_ show an Excel spreadsheet in a frame!
|
||||
#
|
||||
|
||||
import win32ui, win32uiole, win32con, regutil
|
||||
from pywin.mfc import window, activex, object, docview
|
||||
from win32com.client import gencache
|
||||
|
||||
#WordModule = gencache.EnsureModule('{00020905-0000-0000-C000-000000000046}', 1033, 8, 0)
|
||||
#if WordModule is None:
|
||||
# raise ImportError, "Microsoft Word version 8 does not appear to be installed."
|
||||
|
||||
|
||||
class OleClientItem(object.CmdTarget):
|
||||
def __init__(self, doc):
|
||||
object.CmdTarget.__init__(self, win32uiole.CreateOleClientItem(doc))
|
||||
|
||||
def OnGetItemPosition(self):
|
||||
# For now return a hard-coded rect.
|
||||
return (10, 10, 210, 210)
|
||||
|
||||
def OnActivate(self):
|
||||
# Allow only one inplace activate item per frame
|
||||
view = self.GetActiveView()
|
||||
item = self.GetDocument().GetInPlaceActiveItem(view)
|
||||
if item is not None and item._obj_ != self._obj_:
|
||||
item.Close()
|
||||
self._obj_.OnActivate()
|
||||
|
||||
def OnChange(self, oleNotification, dwParam):
|
||||
self._obj_.OnChange(oleNotification, dwParam)
|
||||
self.GetDocument().UpdateAllViews(None)
|
||||
|
||||
def OnChangeItemPosition(self, rect):
|
||||
# During in-place activation CEmbed_ExcelCntrItem::OnChangeItemPosition
|
||||
# is called by the server to change the position of the in-place
|
||||
# window. Usually, this is a result of the data in the server
|
||||
# document changing such that the extent has changed or as a result
|
||||
# of in-place resizing.
|
||||
#
|
||||
# The default here is to call the base class, which will call
|
||||
# COleClientItem::SetItemRects to move the item
|
||||
# to the new position.
|
||||
if not self._obj_.OnChangeItemPosition(self, rect):
|
||||
return 0
|
||||
|
||||
# TODO: update any cache you may have of the item's rectangle/extent
|
||||
return 1
|
||||
|
||||
class OleDocument(object.CmdTarget):
|
||||
def __init__(self, template):
|
||||
object.CmdTarget.__init__(self, win32uiole.CreateOleDocument(template))
|
||||
self.EnableCompoundFile()
|
||||
|
||||
class ExcelView(docview.ScrollView):
|
||||
def OnInitialUpdate(self):
|
||||
self.HookMessage(self.OnSetFocus, win32con.WM_SETFOCUS)
|
||||
self.HookMessage (self.OnSize, win32con.WM_SIZE)
|
||||
|
||||
self.SetScrollSizes(win32con.MM_TEXT, (100, 100))
|
||||
rc = self._obj_.OnInitialUpdate()
|
||||
self.EmbedExcel()
|
||||
return rc
|
||||
|
||||
def EmbedExcel(self):
|
||||
doc = self.GetDocument()
|
||||
self.clientItem = OleClientItem(doc)
|
||||
self.clientItem.CreateNewItem("Excel.Sheet")
|
||||
self.clientItem.DoVerb(-1, self)
|
||||
doc.UpdateAllViews(None)
|
||||
|
||||
def OnDraw(self, dc):
|
||||
doc = self.GetDocument()
|
||||
pos = doc.GetStartPosition()
|
||||
clientItem, pos = doc.GetNextItem(pos)
|
||||
clientItem.Draw(dc, (10, 10, 210, 210) )
|
||||
|
||||
# Special handling of OnSetFocus and OnSize are required for a container
|
||||
# when an object is being edited in-place.
|
||||
def OnSetFocus(self, msg):
|
||||
item = self.GetDocument().GetInPlaceActiveItem(self)
|
||||
if item is not None and item.GetItemState()==win32uiole.COleClientItem_activeUIState:
|
||||
wnd = item.GetInPlaceWindow()
|
||||
if wnd is not None:
|
||||
wnd.SetFocus()
|
||||
return 0 # Dont get the base version called.
|
||||
return 1 # Call the base version.
|
||||
|
||||
def OnSize (self, params):
|
||||
item = self.GetDocument().GetInPlaceActiveItem(self)
|
||||
if item is not None:
|
||||
item.SetItemRects()
|
||||
return 1 # do call the base!
|
||||
|
||||
class OleTemplate(docview.DocTemplate):
|
||||
def __init__(self, resourceId=None, MakeDocument=None, MakeFrame=None, MakeView=None):
|
||||
if MakeDocument is None: MakeDocument = OleDocument
|
||||
if MakeView is None: MakeView = ExcelView
|
||||
docview.DocTemplate.__init__(self, resourceId, MakeDocument, MakeFrame, MakeView)
|
||||
|
||||
class WordFrame(window.MDIChildWnd):
|
||||
def __init__(self, doc = None):
|
||||
self._obj_ = win32ui.CreateMDIChild()
|
||||
self._obj_.AttachObject(self)
|
||||
# Dont call base class doc/view version...
|
||||
def Create(self, title, rect = None, parent = None):
|
||||
style = win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.WS_OVERLAPPEDWINDOW
|
||||
self._obj_.CreateWindow(None, title, style, rect, parent)
|
||||
|
||||
rect = self.GetClientRect()
|
||||
rect = (0,0,rect[2]-rect[0], rect[3]-rect[1])
|
||||
self.ocx = MyWordControl()
|
||||
self.ocx.CreateControl("Microsoft Word", win32con.WS_VISIBLE | win32con.WS_CHILD, rect, self, 20000)
|
||||
|
||||
def Demo():
|
||||
import sys, win32api
|
||||
docName = None
|
||||
if len(sys.argv)>1:
|
||||
docName = win32api.GetFullPathName(sys.argv[1])
|
||||
OleTemplate().OpenDocumentFile(None)
|
||||
# f = WordFrame(docName)
|
||||
# f.Create("Microsoft Office")
|
||||
|
||||
if __name__=='__main__':
|
||||
Demo()
|
||||
101
Lib/site-packages/pythonwin/pywin/Demos/ocx/ocxserialtest.py
Normal file
101
Lib/site-packages/pythonwin/pywin/Demos/ocx/ocxserialtest.py
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
# ocxserialtest.py
|
||||
#
|
||||
# Sample that uses the mscomm OCX to talk to a serial
|
||||
# device.
|
||||
|
||||
# Very simple - queries a modem for ATI responses
|
||||
|
||||
import win32ui, win32uiole
|
||||
import win32con
|
||||
from pywin.mfc import dialog, activex
|
||||
from win32com.client import gencache
|
||||
import pythoncom
|
||||
|
||||
SERIAL_SETTINGS = '19200,n,8,1'
|
||||
SERIAL_PORT = 2
|
||||
|
||||
win32ui.DoWaitCursor(1)
|
||||
serialModule = gencache.EnsureModule("{648A5603-2C6E-101B-82B6-000000000014}", 0, 1, 1)
|
||||
win32ui.DoWaitCursor(0)
|
||||
if serialModule is None:
|
||||
raise ImportError("MS COMM Control does not appear to be installed on the PC")
|
||||
|
||||
|
||||
def MakeDlgTemplate():
|
||||
style = win32con.DS_MODALFRAME | win32con.WS_POPUP \
|
||||
| win32con.WS_VISIBLE | win32con.WS_CAPTION \
|
||||
| win32con.WS_SYSMENU | win32con.DS_SETFONT
|
||||
cs = win32con.WS_CHILD | win32con.WS_VISIBLE
|
||||
dlg = [ ["Very Basic Terminal",
|
||||
(0, 0, 350, 180), style, None, (8, "MS Sans Serif")], ]
|
||||
s = win32con.WS_TABSTOP | cs
|
||||
dlg.append(["RICHEDIT", None, 132, (5, 5, 340, 170),s | win32con.ES_WANTRETURN | win32con.ES_MULTILINE | win32con.ES_AUTOVSCROLL | win32con.WS_VSCROLL])
|
||||
return dlg
|
||||
|
||||
|
||||
####################################
|
||||
#
|
||||
# Serial Control
|
||||
#
|
||||
class MySerialControl(activex.Control, serialModule.MSComm):
|
||||
def __init__(self, parent):
|
||||
activex.Control.__init__(self)
|
||||
serialModule.MSComm.__init__(self)
|
||||
self.parent = parent
|
||||
def OnComm(self):
|
||||
self.parent.OnComm()
|
||||
|
||||
class TestSerDialog(dialog.Dialog):
|
||||
def __init__(self, *args):
|
||||
dialog.Dialog.__init__(*(self,)+args)
|
||||
self.olectl = None
|
||||
def OnComm(self):
|
||||
event = self.olectl.CommEvent
|
||||
if event == serialModule.OnCommConstants.comEvReceive:
|
||||
self.editwindow.ReplaceSel(self.olectl.Input)
|
||||
|
||||
def OnKey(self, key):
|
||||
if self.olectl:
|
||||
self.olectl.Output = chr(key)
|
||||
|
||||
def OnInitDialog(self):
|
||||
rc = dialog.Dialog.OnInitDialog(self)
|
||||
self.editwindow = self.GetDlgItem(132)
|
||||
self.editwindow.HookAllKeyStrokes(self.OnKey)
|
||||
|
||||
self.olectl = MySerialControl(self)
|
||||
try:
|
||||
self.olectl.CreateControl("OCX",
|
||||
win32con.WS_TABSTOP | win32con.WS_VISIBLE,
|
||||
(7,43,500,300), self._obj_, 131)
|
||||
except win32ui.error:
|
||||
self.MessageBox("The Serial Control could not be created")
|
||||
self.olectl = None
|
||||
self.EndDialog(win32con.IDCANCEL)
|
||||
if self.olectl:
|
||||
self.olectl.Settings = SERIAL_SETTINGS
|
||||
self.olectl.CommPort = SERIAL_PORT
|
||||
self.olectl.RThreshold = 1
|
||||
try:
|
||||
self.olectl.PortOpen = 1
|
||||
except pythoncom.com_error as details:
|
||||
print("Could not open the specified serial port - %s" % (details.excepinfo[2]))
|
||||
self.EndDialog(win32con.IDCANCEL)
|
||||
return rc
|
||||
|
||||
def OnDestroy(self, msg):
|
||||
if self.olectl:
|
||||
try:
|
||||
self.olectl.PortOpen = 0
|
||||
except pythoncom.com_error as details:
|
||||
print("Error closing port - %s" % (details.excepinfo[2]))
|
||||
return dialog.Dialog.OnDestroy(self, msg)
|
||||
|
||||
def test():
|
||||
d = TestSerDialog(MakeDlgTemplate() )
|
||||
d.DoModal()
|
||||
|
||||
if __name__ == "__main__":
|
||||
import demoutils
|
||||
if demoutils.NeedGoodGUI():
|
||||
test()
|
||||
186
Lib/site-packages/pythonwin/pywin/Demos/ocx/ocxtest.py
Normal file
186
Lib/site-packages/pythonwin/pywin/Demos/ocx/ocxtest.py
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
# OCX Tester for Pythonwin
|
||||
#
|
||||
# This file _is_ ready to run. All that is required is that the OCXs being tested
|
||||
# are installed on your machine.
|
||||
#
|
||||
# The .py files behind the OCXs will be automatically generated and imported.
|
||||
|
||||
from pywin.mfc import dialog, window, activex
|
||||
import win32ui, win32uiole
|
||||
import win32con
|
||||
import os, sys, win32api, glob
|
||||
from win32com.client import gencache
|
||||
|
||||
|
||||
def MakeDlgTemplate():
|
||||
style = win32con.DS_MODALFRAME | win32con.WS_POPUP | win32con.WS_VISIBLE | win32con.WS_CAPTION | win32con.WS_SYSMENU | win32con.DS_SETFONT
|
||||
cs = win32con.WS_CHILD | win32con.WS_VISIBLE
|
||||
dlg = [ ["OCX Demos", (0, 0, 350, 350), style, None, (8, "MS Sans Serif")], ]
|
||||
s = win32con.WS_TABSTOP | cs
|
||||
# dlg.append([131, None, 130, (5, 40, 110, 48),
|
||||
# s | win32con.LBS_NOTIFY | win32con.LBS_SORT | win32con.LBS_NOINTEGRALHEIGHT | win32con.WS_VSCROLL | win32con.WS_BORDER])
|
||||
# dlg.append(["{8E27C92B-1264-101C-8A2F-040224009C02}", None, 131, (5, 40, 110, 48),win32con.WS_TABSTOP])
|
||||
|
||||
dlg.append([128, "About", win32con.IDOK, (124, 5, 50, 14), s | win32con.BS_DEFPUSHBUTTON])
|
||||
s = win32con.BS_PUSHBUTTON | s
|
||||
dlg.append([128, "Close", win32con.IDCANCEL, (124, 22, 50, 14), s])
|
||||
|
||||
return dlg
|
||||
|
||||
####################################
|
||||
#
|
||||
# Calendar test code
|
||||
#
|
||||
|
||||
def GetTestCalendarClass():
|
||||
global calendarParentModule
|
||||
win32ui.DoWaitCursor(1)
|
||||
calendarParentModule = gencache.EnsureModule("{8E27C92E-1264-101C-8A2F-040224009C02}", 0, 7, 0)
|
||||
win32ui.DoWaitCursor(0)
|
||||
if calendarParentModule is None:
|
||||
return None
|
||||
|
||||
class TestCalDialog(dialog.Dialog):
|
||||
def OnInitDialog(self):
|
||||
|
||||
class MyCal(activex.Control, calendarParentModule.Calendar):
|
||||
def OnAfterUpdate(self):
|
||||
print("OnAfterUpdate")
|
||||
def OnClick(self):
|
||||
print("OnClick")
|
||||
def OnDblClick(self):
|
||||
print("OnDblClick")
|
||||
def OnKeyDown(self, KeyCode, Shift):
|
||||
print("OnKeyDown", KeyCode, Shift)
|
||||
def OnKeyPress(self, KeyAscii):
|
||||
print("OnKeyPress", KeyAscii)
|
||||
def OnKeyUp(self, KeyCode, Shift):
|
||||
print("OnKeyUp", KeyCode, Shift)
|
||||
def OnBeforeUpdate(self, Cancel):
|
||||
print("OnBeforeUpdate", Cancel)
|
||||
def OnNewMonth(self):
|
||||
print("OnNewMonth")
|
||||
def OnNewYear(self):
|
||||
print("OnNewYear")
|
||||
|
||||
rc = dialog.Dialog.OnInitDialog(self)
|
||||
self.olectl = MyCal()
|
||||
try:
|
||||
self.olectl.CreateControl("OCX", win32con.WS_TABSTOP | win32con.WS_VISIBLE, (7,43,500,300), self._obj_, 131)
|
||||
except win32ui.error:
|
||||
self.MessageBox("The Calendar Control could not be created")
|
||||
self.olectl = None
|
||||
self.EndDialog(win32con.IDCANCEL)
|
||||
|
||||
return rc
|
||||
def OnOK(self):
|
||||
self.olectl.AboutBox()
|
||||
|
||||
return TestCalDialog
|
||||
|
||||
|
||||
####################################
|
||||
#
|
||||
# Video Control
|
||||
#
|
||||
def GetTestVideoModule():
|
||||
global videoControlModule, videoControlFileName
|
||||
win32ui.DoWaitCursor(1)
|
||||
videoControlModule = gencache.EnsureModule("{05589FA0-C356-11CE-BF01-00AA0055595A}", 0, 2, 0)
|
||||
win32ui.DoWaitCursor(0)
|
||||
if videoControlModule is None:
|
||||
return None
|
||||
fnames = glob.glob(os.path.join(win32api.GetWindowsDirectory(), "*.avi"))
|
||||
if not fnames:
|
||||
print("No AVI files available in system directory")
|
||||
return None
|
||||
videoControlFileName = fnames[0]
|
||||
return videoControlModule
|
||||
|
||||
def GetTestVideoDialogClass():
|
||||
if GetTestVideoModule() is None:
|
||||
return None
|
||||
class TestVideoDialog(dialog.Dialog):
|
||||
def OnInitDialog(self):
|
||||
rc = dialog.Dialog.OnInitDialog(self)
|
||||
try:
|
||||
self.olectl = activex.MakeControlInstance(videoControlModule.ActiveMovie)
|
||||
self.olectl.CreateControl("", win32con.WS_TABSTOP | win32con.WS_VISIBLE, (7,43,500,300), self._obj_, 131)
|
||||
except win32ui.error:
|
||||
self.MessageBox("The Video Control could not be created")
|
||||
self.olectl = None
|
||||
self.EndDialog(win32con.IDCANCEL)
|
||||
return
|
||||
|
||||
self.olectl.FileName = videoControlFileName
|
||||
# self.olectl.Run()
|
||||
return rc
|
||||
def OnOK(self):
|
||||
self.olectl.AboutBox()
|
||||
return TestVideoDialog
|
||||
|
||||
###############
|
||||
#
|
||||
# An OCX in an MDI Frame
|
||||
#
|
||||
class OCXFrame(window.MDIChildWnd):
|
||||
def __init__(self):
|
||||
pass # Dont call base class doc/view version...
|
||||
def Create(self, controlClass, title, rect = None, parent = None):
|
||||
style = win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.WS_OVERLAPPEDWINDOW
|
||||
self._obj_ = win32ui.CreateMDIChild()
|
||||
self._obj_.AttachObject(self)
|
||||
self._obj_.CreateWindow(None, title, style, rect, parent)
|
||||
|
||||
rect = self.GetClientRect()
|
||||
rect = (0,0,rect[2]-rect[0], rect[3]-rect[1])
|
||||
self.ocx = controlClass()
|
||||
self.ocx.CreateControl("", win32con.WS_VISIBLE | win32con.WS_CHILD, rect, self, 1000)
|
||||
|
||||
def MDITest():
|
||||
calendarParentModule = gencache.EnsureModule("{8E27C92E-1264-101C-8A2F-040224009C02}", 0, 7, 0)
|
||||
class MyCal(activex.Control, calendarParentModule.Calendar):
|
||||
def OnAfterUpdate(self):
|
||||
print("OnAfterUpdate")
|
||||
def OnClick(self):
|
||||
print("OnClick")
|
||||
|
||||
f = OCXFrame()
|
||||
f.Create(MyCal, "Calendar Test")
|
||||
|
||||
|
||||
def test1():
|
||||
klass = GetTestCalendarClass()
|
||||
if klass is None:
|
||||
print("Can not test the MSAccess Calendar control - it does not appear to be installed")
|
||||
return
|
||||
|
||||
d = klass(MakeDlgTemplate() )
|
||||
d.DoModal()
|
||||
|
||||
def test2():
|
||||
klass = GetTestVideoDialogClass()
|
||||
if klass is None:
|
||||
print("Can not test the Video OCX - it does not appear to be installed,")
|
||||
print("or no AVI files can be found.")
|
||||
return
|
||||
d = klass(MakeDlgTemplate() )
|
||||
d.DoModal()
|
||||
d = None
|
||||
|
||||
def test3():
|
||||
d = TestCOMMDialog(MakeDlgTemplate() )
|
||||
d.DoModal()
|
||||
d = None
|
||||
|
||||
def testall():
|
||||
test1()
|
||||
test2()
|
||||
|
||||
def demo():
|
||||
testall()
|
||||
|
||||
if __name__=='__main__':
|
||||
import demoutils
|
||||
if demoutils.NeedGoodGUI():
|
||||
testall()
|
||||
55
Lib/site-packages/pythonwin/pywin/Demos/ocx/webbrowser.py
Normal file
55
Lib/site-packages/pythonwin/pywin/Demos/ocx/webbrowser.py
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
# This demo uses the IE4 Web Browser control.
|
||||
|
||||
# It catches an "OnNavigate" event, and updates the frame title.
|
||||
# (event stuff by Neil Hodgson)
|
||||
|
||||
import win32ui, win32con, win32api, regutil
|
||||
from pywin.mfc import window, activex
|
||||
from win32com.client import gencache
|
||||
import sys
|
||||
|
||||
WebBrowserModule = gencache.EnsureModule("{EAB22AC0-30C1-11CF-A7EB-0000C05BAE0B}", 0, 1, 1)
|
||||
if WebBrowserModule is None:
|
||||
raise ImportError("IE4 does not appear to be installed.")
|
||||
|
||||
class MyWebBrowser(activex.Control, WebBrowserModule.WebBrowser):
|
||||
def OnBeforeNavigate2(self, pDisp, URL, Flags, TargetFrameName, PostData, Headers, Cancel):
|
||||
self.GetParent().OnNavigate(URL)
|
||||
#print "BeforeNavigate2", pDisp, URL, Flags, TargetFrameName, PostData, Headers, Cancel
|
||||
|
||||
class BrowserFrame(window.MDIChildWnd):
|
||||
def __init__(self, url = None):
|
||||
if url is None:
|
||||
self.url = regutil.GetRegisteredHelpFile("Main Python Documentation")
|
||||
if self.url is None:
|
||||
self.url = "http://www.python.org"
|
||||
else:
|
||||
self.url = url
|
||||
pass # Dont call base class doc/view version...
|
||||
def Create(self, title, rect = None, parent = None):
|
||||
style = win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.WS_OVERLAPPEDWINDOW
|
||||
self._obj_ = win32ui.CreateMDIChild()
|
||||
self._obj_.AttachObject(self)
|
||||
self._obj_.CreateWindow(None, title, style, rect, parent)
|
||||
rect = self.GetClientRect()
|
||||
rect = (0,0,rect[2]-rect[0], rect[3]-rect[1])
|
||||
self.ocx = MyWebBrowser()
|
||||
self.ocx.CreateControl("Web Browser", win32con.WS_VISIBLE | win32con.WS_CHILD, rect, self, 1000)
|
||||
self.ocx.Navigate(self.url)
|
||||
self.HookMessage (self.OnSize, win32con.WM_SIZE)
|
||||
def OnSize (self, params):
|
||||
rect = self.GetClientRect()
|
||||
rect = (0,0,rect[2]-rect[0], rect[3]-rect[1])
|
||||
self.ocx.SetWindowPos(0, rect, 0)
|
||||
def OnNavigate(self, url):
|
||||
title = "Web Browser - %s" % (url,)
|
||||
self.SetWindowText(title)
|
||||
|
||||
def Demo(url=None):
|
||||
if url is None and len(sys.argv)>1:
|
||||
url = win32api.GetFullPathName(sys.argv[1])
|
||||
f = BrowserFrame(url)
|
||||
f.Create("Web Browser")
|
||||
|
||||
if __name__=='__main__':
|
||||
Demo()
|
||||
358
Lib/site-packages/pythonwin/pywin/Demos/openGLDemo.py
Normal file
358
Lib/site-packages/pythonwin/pywin/Demos/openGLDemo.py
Normal file
|
|
@ -0,0 +1,358 @@
|
|||
# Ported from the win32 and MFC OpenGL Samples.
|
||||
|
||||
from pywin.mfc import docview
|
||||
import sys
|
||||
try:
|
||||
from OpenGL.GL import *
|
||||
from OpenGL.GLU import *
|
||||
except ImportError:
|
||||
print("The OpenGL extensions do not appear to be installed.")
|
||||
print("This Pythonwin demo can not run")
|
||||
sys.exit(1)
|
||||
|
||||
import win32con
|
||||
import win32ui
|
||||
import win32api
|
||||
import timer
|
||||
|
||||
PFD_TYPE_RGBA = 0
|
||||
PFD_TYPE_COLORINDEX = 1
|
||||
PFD_MAIN_PLANE = 0
|
||||
PFD_OVERLAY_PLANE = 1
|
||||
PFD_UNDERLAY_PLANE = (-1)
|
||||
PFD_DOUBLEBUFFER = 0x00000001
|
||||
PFD_STEREO = 0x00000002
|
||||
PFD_DRAW_TO_WINDOW = 0x00000004
|
||||
PFD_DRAW_TO_BITMAP = 0x00000008
|
||||
PFD_SUPPORT_GDI = 0x00000010
|
||||
PFD_SUPPORT_OPENGL = 0x00000020
|
||||
PFD_GENERIC_FORMAT = 0x00000040
|
||||
PFD_NEED_PALETTE = 0x00000080
|
||||
PFD_NEED_SYSTEM_PALETTE = 0x00000100
|
||||
PFD_SWAP_EXCHANGE = 0x00000200
|
||||
PFD_SWAP_COPY = 0x00000400
|
||||
PFD_SWAP_LAYER_BUFFERS = 0x00000800
|
||||
PFD_GENERIC_ACCELERATED = 0x00001000
|
||||
PFD_DEPTH_DONTCARE = 0x20000000
|
||||
PFD_DOUBLEBUFFER_DONTCARE = 0x40000000
|
||||
PFD_STEREO_DONTCARE = 0x80000000
|
||||
|
||||
|
||||
#threeto8 = [0, 0o111>>1, 0o222>>1, 0o333>>1, 0o444>>1, 0o555>>1, 0o666>>1, 0o377]
|
||||
threeto8 = [0, 73>>1, 146>>1, 219>>1, 292>>1, 365>>1, 438>>1, 255]
|
||||
twoto8 = [0, 0x55, 0xaa, 0xff]
|
||||
oneto8 = [0, 255]
|
||||
|
||||
def ComponentFromIndex(i, nbits, shift):
|
||||
# val = (unsigned char) (i >> shift);
|
||||
val = (i >> shift) & 0xF;
|
||||
if nbits==1:
|
||||
val = val & 0x1
|
||||
return oneto8[val]
|
||||
elif nbits==2:
|
||||
val = val & 0x3
|
||||
return twoto8[val]
|
||||
elif nbits==3:
|
||||
val = val & 0x7
|
||||
return threeto8[val]
|
||||
else:
|
||||
return 0;
|
||||
|
||||
OpenGLViewParent=docview.ScrollView
|
||||
class OpenGLView(OpenGLViewParent):
|
||||
def PreCreateWindow(self, cc):
|
||||
self.HookMessage (self.OnSize, win32con.WM_SIZE)
|
||||
# An OpenGL window must be created with the following flags and must not
|
||||
# include CS_PARENTDC for the class style. Refer to SetPixelFormat
|
||||
# documentation in the "Comments" section for further information.
|
||||
style = cc[5]
|
||||
style = style | win32con.WS_CLIPSIBLINGS | win32con.WS_CLIPCHILDREN
|
||||
cc = cc[0], cc[1], cc[2], cc[3], cc[4], style, cc[6], cc[7], cc[8]
|
||||
cc = self._obj_.PreCreateWindow(cc)
|
||||
return cc
|
||||
|
||||
def OnSize (self, params):
|
||||
lParam = params[3]
|
||||
cx = win32api.LOWORD(lParam)
|
||||
cy = win32api.HIWORD(lParam)
|
||||
glViewport(0, 0, cx, cy)
|
||||
|
||||
if self.oldrect[2] > cx or self.oldrect[3] > cy:
|
||||
self.RedrawWindow()
|
||||
|
||||
self.OnSizeChange(cx, cy)
|
||||
|
||||
self.oldrect = self.oldrect[0], self.oldrect[1], cx, cy
|
||||
|
||||
def OnInitialUpdate(self):
|
||||
self.SetScaleToFitSize((100,100)) # or SetScrollSizes() - A Pythonwin requirement
|
||||
return self._obj_.OnInitialUpdate()
|
||||
# return rc
|
||||
|
||||
def OnCreate(self, cs):
|
||||
self.oldrect = self.GetClientRect()
|
||||
self._InitContexts()
|
||||
self.Init()
|
||||
|
||||
def OnDestroy(self, msg):
|
||||
self.Term()
|
||||
self._DestroyContexts()
|
||||
return OpenGLViewParent.OnDestroy(self, msg)
|
||||
|
||||
|
||||
def OnDraw(self, dc):
|
||||
self.DrawScene()
|
||||
|
||||
def OnEraseBkgnd(self, dc):
|
||||
return 1
|
||||
|
||||
# The OpenGL helpers
|
||||
def _SetupPixelFormat(self):
|
||||
dc = self.dc.GetSafeHdc()
|
||||
pfd = CreatePIXELFORMATDESCRIPTOR()
|
||||
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER
|
||||
pfd.iPixelType = PFD_TYPE_RGBA
|
||||
pfd.cColorBits = 24
|
||||
pfd.cDepthBits = 32
|
||||
pfd.iLayerType = PFD_MAIN_PLANE
|
||||
pixelformat = ChoosePixelFormat(dc, pfd)
|
||||
SetPixelFormat(dc, pixelformat, pfd)
|
||||
self._CreateRGBPalette()
|
||||
|
||||
def _CreateRGBPalette(self):
|
||||
dc = self.dc.GetSafeHdc()
|
||||
n = GetPixelFormat(dc)
|
||||
pfd = DescribePixelFormat(dc, n)
|
||||
if pfd.dwFlags & PFD_NEED_PALETTE:
|
||||
n = 1 << pfd.cColorBits
|
||||
pal = []
|
||||
for i in range(n):
|
||||
this = ComponentFromIndex(i, pfd.cRedBits, pfd.cRedShift), \
|
||||
ComponentFromIndex(i, pfd.cGreenBits, pfd.cGreenShift), \
|
||||
ComponentFromIndex(i, pfd.cBlueBits, pfd.cBlueShift), \
|
||||
0
|
||||
pal.append(this)
|
||||
hpal = win32ui.CreatePalette(pal)
|
||||
self.dc.SelectPalette(hpal, 0)
|
||||
self.dc.RealizePalette()
|
||||
|
||||
def _InitContexts(self):
|
||||
self.dc = self.GetDC()
|
||||
self._SetupPixelFormat()
|
||||
hrc = wglCreateContext(self.dc.GetSafeHdc())
|
||||
wglMakeCurrent(self.dc.GetSafeHdc(), hrc)
|
||||
|
||||
def _DestroyContexts(self):
|
||||
hrc = wglGetCurrentContext()
|
||||
wglMakeCurrent(0, 0)
|
||||
if hrc: wglDeleteContext(hrc)
|
||||
|
||||
# The methods to support OpenGL
|
||||
def DrawScene(self):
|
||||
assert 0, "You must override this method"
|
||||
|
||||
def Init(self):
|
||||
assert 0, "You must override this method"
|
||||
|
||||
def OnSizeChange(self, cx, cy):
|
||||
pass
|
||||
|
||||
def Term(self):
|
||||
pass
|
||||
|
||||
|
||||
class TestView(OpenGLView):
|
||||
|
||||
def OnSizeChange(self, right, bottom):
|
||||
glClearColor( 0.0, 0.0, 0.0, 1.0 );
|
||||
glClearDepth( 1.0 );
|
||||
glEnable(GL_DEPTH_TEST)
|
||||
|
||||
glMatrixMode( GL_PROJECTION )
|
||||
if bottom:
|
||||
aspect = right / bottom
|
||||
else:
|
||||
aspect = 0 # When window created!
|
||||
glLoadIdentity()
|
||||
gluPerspective( 45.0, aspect, 3.0, 7.0 )
|
||||
glMatrixMode( GL_MODELVIEW )
|
||||
|
||||
near_plane = 3.0;
|
||||
far_plane = 7.0;
|
||||
maxObjectSize = 3.0;
|
||||
self.radius = near_plane + maxObjectSize/2.0;
|
||||
|
||||
|
||||
def Init(self):
|
||||
pass
|
||||
|
||||
def DrawScene(self):
|
||||
glClearColor(0.0, 0.0, 0.0, 1.0)
|
||||
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT )
|
||||
|
||||
glPushMatrix()
|
||||
glTranslatef(0.0, 0.0, -self.radius);
|
||||
|
||||
self._DrawCone()
|
||||
|
||||
self._DrawPyramid()
|
||||
|
||||
glPopMatrix()
|
||||
glFinish()
|
||||
|
||||
SwapBuffers( wglGetCurrentDC() )
|
||||
|
||||
def _DrawCone(self):
|
||||
glColor3f(0.0, 1.0, 0.0)
|
||||
|
||||
glPushMatrix()
|
||||
glTranslatef(-1.0, 0.0, 0.0);
|
||||
quadObj = gluNewQuadric();
|
||||
gluQuadricDrawStyle(quadObj, GLU_FILL);
|
||||
gluQuadricNormals(quadObj, GLU_SMOOTH);
|
||||
gluCylinder(quadObj, 1.0, 0.0, 1.0, 20, 10);
|
||||
# gluDeleteQuadric(quadObj);
|
||||
glPopMatrix();
|
||||
|
||||
def _DrawPyramid(self):
|
||||
glPushMatrix()
|
||||
glTranslatef(1.0, 0.0, 0.0)
|
||||
glBegin(GL_TRIANGLE_FAN)
|
||||
glColor3f(1.0, 0.0, 0.0)
|
||||
glVertex3f(0.0, 1.0, 0.0)
|
||||
glColor3f(0.0, 1.0, 0.0)
|
||||
glVertex3f(-1.0, 0.0, 0.0)
|
||||
glColor3f(0.0, 0.0, 1.0)
|
||||
glVertex3f(0.0, 0.0, 1.0)
|
||||
glColor3f(0.0, 1.0, 0.0)
|
||||
glVertex3f(1.0, 0.0, 0.0)
|
||||
glEnd()
|
||||
glPopMatrix()
|
||||
|
||||
class CubeView(OpenGLView):
|
||||
def OnSizeChange(self, right, bottom):
|
||||
glClearColor( 0.0, 0.0, 0.0, 1.0 );
|
||||
glClearDepth( 1.0 );
|
||||
glEnable(GL_DEPTH_TEST)
|
||||
|
||||
glMatrixMode( GL_PROJECTION )
|
||||
if bottom:
|
||||
aspect = right / bottom
|
||||
else:
|
||||
aspect = 0 # When window created!
|
||||
glLoadIdentity()
|
||||
gluPerspective( 45.0, aspect, 3.0, 7.0 )
|
||||
glMatrixMode( GL_MODELVIEW )
|
||||
|
||||
near_plane = 3.0;
|
||||
far_plane = 7.0;
|
||||
maxObjectSize = 3.0;
|
||||
self.radius = near_plane + maxObjectSize/2.0;
|
||||
|
||||
def Init(self):
|
||||
self.busy = 0
|
||||
self.wAngleY = 10.0
|
||||
self.wAngleX = 1.0
|
||||
self.wAngleZ = 5.0
|
||||
self.timerid = timer.set_timer (150, self.OnTimer)
|
||||
|
||||
def OnTimer(self, id, timeVal):
|
||||
self.DrawScene()
|
||||
|
||||
def Term(self):
|
||||
timer.kill_timer(self.timerid)
|
||||
|
||||
def DrawScene(self):
|
||||
if self.busy: return
|
||||
self.busy = 1
|
||||
|
||||
glClearColor(0.0, 0.0, 0.0, 1.0);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
glPushMatrix();
|
||||
|
||||
glTranslatef(0.0, 0.0, -self.radius);
|
||||
glRotatef(self.wAngleX, 1.0, 0.0, 0.0);
|
||||
glRotatef(self.wAngleY, 0.0, 1.0, 0.0);
|
||||
glRotatef(self.wAngleZ, 0.0, 0.0, 1.0);
|
||||
|
||||
self.wAngleX = self.wAngleX + 1.0
|
||||
self.wAngleY = self.wAngleY + 10.0
|
||||
self.wAngleZ = self.wAngleZ + 5.0;
|
||||
|
||||
|
||||
glBegin(GL_QUAD_STRIP);
|
||||
glColor3f(1.0, 0.0, 1.0);
|
||||
glVertex3f(-0.5, 0.5, 0.5);
|
||||
|
||||
glColor3f(1.0, 0.0, 0.0);
|
||||
glVertex3f(-0.5, -0.5, 0.5);
|
||||
|
||||
glColor3f(1.0, 1.0, 1.0);
|
||||
glVertex3f(0.5, 0.5, 0.5);
|
||||
|
||||
glColor3f(1.0, 1.0, 0.0);
|
||||
glVertex3f(0.5, -0.5, 0.5);
|
||||
|
||||
glColor3f(0.0, 1.0, 1.0);
|
||||
glVertex3f(0.5, 0.5, -0.5);
|
||||
|
||||
glColor3f(0.0, 1.0, 0.0);
|
||||
glVertex3f(0.5, -0.5, -0.5);
|
||||
|
||||
glColor3f(0.0, 0.0, 1.0);
|
||||
glVertex3f(-0.5, 0.5, -0.5);
|
||||
|
||||
glColor3f(0.0, 0.0, 0.0);
|
||||
glVertex3f(-0.5, -0.5, -0.5);
|
||||
|
||||
glColor3f(1.0, 0.0, 1.0);
|
||||
glVertex3f(-0.5, 0.5, 0.5);
|
||||
|
||||
glColor3f(1.0, 0.0, 0.0);
|
||||
glVertex3f(-0.5, -0.5, 0.5);
|
||||
|
||||
glEnd();
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
glColor3f(1.0, 0.0, 1.0);
|
||||
glVertex3f(-0.5, 0.5, 0.5);
|
||||
|
||||
glColor3f(1.0, 1.0, 1.0);
|
||||
glVertex3f(0.5, 0.5, 0.5);
|
||||
|
||||
glColor3f(0.0, 1.0, 1.0);
|
||||
glVertex3f(0.5, 0.5, -0.5);
|
||||
|
||||
glColor3f(0.0, 0.0, 1.0);
|
||||
glVertex3f(-0.5, 0.5, -0.5);
|
||||
glEnd();
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
glColor3f(1.0, 0.0, 0.0);
|
||||
glVertex3f(-0.5, -0.5, 0.5);
|
||||
|
||||
glColor3f(1.0, 1.0, 0.0);
|
||||
glVertex3f(0.5, -0.5, 0.5);
|
||||
|
||||
glColor3f(0.0, 1.0, 0.0);
|
||||
glVertex3f(0.5, -0.5, -0.5);
|
||||
|
||||
glColor3f(0.0, 0.0, 0.0);
|
||||
glVertex3f(-0.5, -0.5, -0.5);
|
||||
glEnd();
|
||||
|
||||
glPopMatrix();
|
||||
|
||||
glFinish();
|
||||
SwapBuffers(wglGetCurrentDC());
|
||||
|
||||
self.busy = 0
|
||||
|
||||
def test():
|
||||
template = docview.DocTemplate(None, None, None, CubeView )
|
||||
# template = docview.DocTemplate(None, None, None, TestView )
|
||||
template.OpenDocumentFile(None)
|
||||
|
||||
if __name__=='__main__':
|
||||
test()
|
||||
88
Lib/site-packages/pythonwin/pywin/Demos/progressbar.py
Normal file
88
Lib/site-packages/pythonwin/pywin/Demos/progressbar.py
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
#
|
||||
# Progress bar control example
|
||||
#
|
||||
# PyCProgressCtrl encapsulates the MFC CProgressCtrl class. To use it,
|
||||
# you:
|
||||
#
|
||||
# - Create the control with win32ui.CreateProgressCtrl()
|
||||
# - Create the control window with PyCProgressCtrl.CreateWindow()
|
||||
# - Initialize the range if you want it to be other than (0, 100) using
|
||||
# PyCProgressCtrl.SetRange()
|
||||
# - Either:
|
||||
# - Set the step size with PyCProgressCtrl.SetStep(), and
|
||||
# - Increment using PyCProgressCtrl.StepIt()
|
||||
# or:
|
||||
# - Set the amount completed using PyCProgressCtrl.SetPos()
|
||||
#
|
||||
# Example and progress bar code courtesy of KDL Technologies, Ltd., Hong Kong SAR, China.
|
||||
#
|
||||
|
||||
from pywin.mfc import dialog
|
||||
import win32ui
|
||||
import win32con
|
||||
|
||||
def MakeDlgTemplate():
|
||||
style = (win32con.DS_MODALFRAME |
|
||||
win32con.WS_POPUP |
|
||||
win32con.WS_VISIBLE |
|
||||
win32con.WS_CAPTION |
|
||||
win32con.WS_SYSMENU |
|
||||
win32con.DS_SETFONT)
|
||||
cs = (win32con.WS_CHILD |
|
||||
win32con.WS_VISIBLE)
|
||||
|
||||
w = 215
|
||||
h = 36
|
||||
|
||||
dlg = [["Progress bar control example",
|
||||
(0, 0, w, h),
|
||||
style,
|
||||
None,
|
||||
(8, "MS Sans Serif")],
|
||||
]
|
||||
|
||||
s = win32con.WS_TABSTOP | cs
|
||||
|
||||
dlg.append([128,
|
||||
"Tick",
|
||||
win32con.IDOK,
|
||||
(10, h - 18, 50, 14), s | win32con.BS_DEFPUSHBUTTON])
|
||||
|
||||
dlg.append([128,
|
||||
"Cancel",
|
||||
win32con.IDCANCEL,
|
||||
(w - 60, h - 18, 50, 14), s | win32con.BS_PUSHBUTTON])
|
||||
|
||||
return dlg
|
||||
|
||||
class TestDialog(dialog.Dialog):
|
||||
def OnInitDialog(self):
|
||||
rc = dialog.Dialog.OnInitDialog(self)
|
||||
self.pbar = win32ui.CreateProgressCtrl()
|
||||
self.pbar.CreateWindow (win32con.WS_CHILD |
|
||||
win32con.WS_VISIBLE,
|
||||
(10, 10, 310, 24),
|
||||
self, 1001)
|
||||
# self.pbar.SetStep (5)
|
||||
self.progress = 0
|
||||
self.pincr = 5
|
||||
return rc
|
||||
|
||||
def OnOK(self):
|
||||
# NB: StepIt wraps at the end if you increment past the upper limit!
|
||||
# self.pbar.StepIt()
|
||||
self.progress = self.progress + self.pincr
|
||||
if self.progress > 100:
|
||||
self.progress = 100
|
||||
if self.progress <= 100:
|
||||
self.pbar.SetPos(self.progress)
|
||||
|
||||
def demo(modal = 0):
|
||||
d = TestDialog (MakeDlgTemplate())
|
||||
if modal:
|
||||
d.DoModal()
|
||||
else:
|
||||
d.CreateWindow ()
|
||||
|
||||
if __name__=='__main__':
|
||||
demo(1)
|
||||
54
Lib/site-packages/pythonwin/pywin/Demos/sliderdemo.py
Normal file
54
Lib/site-packages/pythonwin/pywin/Demos/sliderdemo.py
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
# sliderdemo.py
|
||||
# Demo of the slider control courtesy of Mike Fletcher.
|
||||
|
||||
import win32con, win32ui
|
||||
from pywin.mfc import dialog
|
||||
|
||||
class MyDialog(dialog.Dialog):
|
||||
'''
|
||||
Example using simple controls
|
||||
'''
|
||||
_dialogstyle = (win32con.WS_MINIMIZEBOX | win32con.WS_DLGFRAME |
|
||||
win32con.DS_MODALFRAME | win32con.WS_POPUP | win32con.WS_VISIBLE |
|
||||
win32con.WS_CAPTION | win32con.WS_SYSMENU | win32con.DS_SETFONT )
|
||||
_buttonstyle = (win32con.BS_PUSHBUTTON | win32con.WS_TABSTOP |
|
||||
win32con.WS_CHILD | win32con.WS_VISIBLE)
|
||||
### The static template, contains all "normal" dialog items
|
||||
DIALOGTEMPLATE = [
|
||||
# the dialog itself is the first element in the template
|
||||
["Example slider", (0, 0, 50, 43), _dialogstyle, None, (8, "MS SansSerif")],
|
||||
# rest of elements are the controls within the dialog
|
||||
# standard "Close" button
|
||||
[128, "Close", win32con.IDCANCEL, (0, 30, 50, 13), _buttonstyle], ]
|
||||
### ID of the control to be created during dialog initialisation
|
||||
IDC_SLIDER = 9500
|
||||
def __init__(self ):
|
||||
dialog.Dialog.__init__(self, self.DIALOGTEMPLATE)
|
||||
def OnInitDialog(self):
|
||||
rc = dialog.Dialog.OnInitDialog(self)
|
||||
# now initialise your controls that you want to create
|
||||
# programmatically, including those which are OLE controls
|
||||
# those created directly by win32ui.Create*
|
||||
# and your "custom controls" which are subclasses/whatever
|
||||
win32ui.EnableControlContainer()
|
||||
self.slider = win32ui.CreateSliderCtrl( )
|
||||
self.slider.CreateWindow( win32con.WS_TABSTOP | win32con.WS_VISIBLE,
|
||||
(0,0,100,30),
|
||||
self._obj_,
|
||||
self.IDC_SLIDER)
|
||||
self.HookMessage(self.OnSliderMove, win32con.WM_HSCROLL)
|
||||
return rc
|
||||
|
||||
def OnSliderMove(self, params):
|
||||
print("Slider moved")
|
||||
|
||||
def OnCancel(self):
|
||||
print("The slider control is at position", self.slider.GetPos())
|
||||
self._obj_.OnCancel()
|
||||
###
|
||||
def demo():
|
||||
dia = MyDialog()
|
||||
dia.DoModal()
|
||||
|
||||
if __name__ == "__main__":
|
||||
demo()
|
||||
72
Lib/site-packages/pythonwin/pywin/Demos/splittst.py
Normal file
72
Lib/site-packages/pythonwin/pywin/Demos/splittst.py
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
import win32ui
|
||||
import win32con
|
||||
import fontdemo
|
||||
from pywin.mfc import window, docview
|
||||
import commctrl
|
||||
|
||||
# derive from CMDIChild. This does much work for us.
|
||||
|
||||
class SplitterFrame(window.MDIChildWnd):
|
||||
def __init__(self):
|
||||
# call base CreateFrame
|
||||
self.images = None
|
||||
window.MDIChildWnd.__init__(self)
|
||||
|
||||
def OnCreateClient(self, cp, context):
|
||||
splitter = win32ui.CreateSplitter()
|
||||
doc = context.doc
|
||||
frame_rect = self.GetWindowRect()
|
||||
size = ((frame_rect[2] - frame_rect[0]),
|
||||
(frame_rect[3] - frame_rect[1])//2)
|
||||
sub_size = (size[0]//2, size[1])
|
||||
splitter.CreateStatic (self, 2, 1)
|
||||
self.v1 = win32ui.CreateEditView(doc)
|
||||
self.v2 = fontdemo.FontView(doc)
|
||||
# CListControl view
|
||||
self.v3 = win32ui.CreateListView(doc)
|
||||
sub_splitter = win32ui.CreateSplitter()
|
||||
# pass "splitter" so each view knows how to get to the others
|
||||
sub_splitter.CreateStatic (splitter, 1, 2)
|
||||
sub_splitter.CreateView(self.v1, 0, 0, (sub_size))
|
||||
sub_splitter.CreateView(self.v2, 0, 1, (0,0)) # size ignored.
|
||||
splitter.SetRowInfo(0, size[1] ,0)
|
||||
splitter.CreateView (self.v3, 1, 0, (0,0)) # size ignored.
|
||||
# Setup items in the imagelist
|
||||
self.images = win32ui.CreateImageList(32,32,1,5,5)
|
||||
self.images.Add(win32ui.GetApp().LoadIcon(win32ui.IDR_MAINFRAME))
|
||||
self.images.Add(win32ui.GetApp().LoadIcon(win32ui.IDR_PYTHONCONTYPE))
|
||||
self.images.Add(win32ui.GetApp().LoadIcon(win32ui.IDR_TEXTTYPE))
|
||||
self.v3.SetImageList(self.images, commctrl.LVSIL_NORMAL)
|
||||
self.v3.InsertItem(0, "Icon 1", 0)
|
||||
self.v3.InsertItem(0, "Icon 2", 1)
|
||||
self.v3.InsertItem(0, "Icon 3", 2)
|
||||
# self.v3.Arrange(commctrl.LVA_DEFAULT) Hmmm - win95 aligns left always???
|
||||
return 1
|
||||
def OnDestroy(self, msg):
|
||||
window.MDIChildWnd.OnDestroy(self, msg)
|
||||
if self.images:
|
||||
self.images.DeleteImageList()
|
||||
self.images = None
|
||||
|
||||
def InitialUpdateFrame(self, doc, makeVisible):
|
||||
self.v1.ReplaceSel("Hello from Edit Window 1")
|
||||
self.v1.SetModifiedFlag(0)
|
||||
|
||||
class SampleTemplate(docview.DocTemplate):
|
||||
def __init__(self):
|
||||
docview.DocTemplate.__init__(self, win32ui.IDR_PYTHONTYPE, None, SplitterFrame, None)
|
||||
def InitialUpdateFrame(self, frame, doc, makeVisible):
|
||||
# print "frame is ", frame, frame._obj_
|
||||
# print "doc is ", doc, doc._obj_
|
||||
self._obj_.InitialUpdateFrame(frame, doc, makeVisible) # call default handler.
|
||||
frame.InitialUpdateFrame(doc, makeVisible)
|
||||
|
||||
def demo():
|
||||
template = SampleTemplate()
|
||||
doc=template.OpenDocumentFile(None)
|
||||
doc.SetTitle("Splitter Demo")
|
||||
|
||||
if __name__=='__main__':
|
||||
import demoutils
|
||||
if demoutils.NeedGoodGUI():
|
||||
demo()
|
||||
174
Lib/site-packages/pythonwin/pywin/Demos/threadedgui.py
Normal file
174
Lib/site-packages/pythonwin/pywin/Demos/threadedgui.py
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
# Demo of using just windows, without documents and views.
|
||||
|
||||
# Also demo of a GUI thread, pretty much direct from the MFC C++ sample MTMDI.
|
||||
|
||||
import win32ui
|
||||
import win32con
|
||||
import win32api
|
||||
import timer
|
||||
|
||||
from pywin.mfc import window, docview, thread
|
||||
from pywin.mfc.thread import WinThread
|
||||
|
||||
|
||||
WM_USER_PREPARE_TO_CLOSE = win32con.WM_USER + 32
|
||||
|
||||
# font is a dictionary in which the following elements matter:
|
||||
# (the best matching font to supplied parameters is returned)
|
||||
# name string name of the font as known by Windows
|
||||
# size point size of font in logical units
|
||||
# weight weight of font (win32con.FW_NORMAL, win32con.FW_BOLD)
|
||||
# italic boolean; true if set to anything but None
|
||||
# underline boolean; true if set to anything but None
|
||||
|
||||
# This window is a child window of a frame. It is not the frame window itself.
|
||||
class FontWindow(window.Wnd):
|
||||
def __init__(self, text = 'Python Rules!'):
|
||||
window.Wnd.__init__(self)
|
||||
self.text = text
|
||||
self.index = 0
|
||||
self.incr = 1
|
||||
self.width = self.height = 0
|
||||
self.ChangeAttributes()
|
||||
# set up message handlers
|
||||
|
||||
def Create(self, title, style, rect, parent):
|
||||
classStyle = win32con.CS_HREDRAW | win32con.CS_VREDRAW
|
||||
className = win32ui.RegisterWndClass(classStyle, 0, win32con.COLOR_WINDOW+1, 0)
|
||||
self._obj_ = win32ui.CreateWnd()
|
||||
self._obj_.AttachObject(self)
|
||||
self._obj_.CreateWindow(className, title, style, rect, parent, win32ui.AFX_IDW_PANE_FIRST)
|
||||
self.HookMessage (self.OnSize, win32con.WM_SIZE)
|
||||
self.HookMessage (self.OnPrepareToClose, WM_USER_PREPARE_TO_CLOSE)
|
||||
self.HookMessage (self.OnDestroy, win32con.WM_DESTROY)
|
||||
self.timerid = timer.set_timer (100, self.OnTimer)
|
||||
self.InvalidateRect()
|
||||
|
||||
def OnDestroy (self, msg):
|
||||
timer.kill_timer(self.timerid)
|
||||
|
||||
def OnTimer(self, id, timeVal):
|
||||
self.index = self.index + self.incr
|
||||
if self.index > len(self.text):
|
||||
self.incr = -1
|
||||
self.index = len(self.text)
|
||||
elif self.index < 0:
|
||||
self.incr = 1
|
||||
self.index = 0
|
||||
self.InvalidateRect()
|
||||
|
||||
def OnPaint (self):
|
||||
# print "Paint message from thread", win32api.GetCurrentThreadId()
|
||||
dc, paintStruct = self.BeginPaint()
|
||||
self.OnPrepareDC(dc, None)
|
||||
|
||||
if (self.width == 0 and self.height == 0):
|
||||
left, top, right, bottom = self.GetClientRect()
|
||||
self.width = right - left
|
||||
self.height = bottom - top
|
||||
x, y = self.width // 2, self.height // 2
|
||||
dc.TextOut (x, y, self.text[:self.index])
|
||||
self.EndPaint(paintStruct)
|
||||
|
||||
def ChangeAttributes(self):
|
||||
font_spec = {'name':'Arial', 'height':42}
|
||||
self.font = win32ui.CreateFont (font_spec)
|
||||
|
||||
def OnPrepareToClose(self, params):
|
||||
self.DestroyWindow()
|
||||
|
||||
def OnSize (self, params):
|
||||
lParam = params[3]
|
||||
self.width = win32api.LOWORD(lParam)
|
||||
self.height = win32api.HIWORD(lParam)
|
||||
|
||||
def OnPrepareDC (self, dc, printinfo):
|
||||
# Set up the DC for forthcoming OnDraw call
|
||||
dc.SetTextColor (win32api.RGB(0,0,255))
|
||||
dc.SetBkColor (win32api.GetSysColor (win32con.COLOR_WINDOW))
|
||||
dc.SelectObject (self.font)
|
||||
dc.SetTextAlign (win32con.TA_CENTER | win32con.TA_BASELINE)
|
||||
|
||||
class FontFrame(window.MDIChildWnd):
|
||||
def __init__(self):
|
||||
pass # Dont call base class doc/view version...
|
||||
def Create(self, title, rect = None, parent = None):
|
||||
style = win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.WS_OVERLAPPEDWINDOW
|
||||
self._obj_ = win32ui.CreateMDIChild()
|
||||
self._obj_.AttachObject(self)
|
||||
|
||||
self._obj_.CreateWindow(None, title, style, rect, parent)
|
||||
rect = self.GetClientRect()
|
||||
rect = (0,0,rect[2]-rect[0], rect[3]-rect[1])
|
||||
self.child = FontWindow("Not threaded")
|
||||
self.child.Create("FontDemo", win32con.WS_CHILD | win32con.WS_VISIBLE, rect, self)
|
||||
|
||||
|
||||
class TestThread(WinThread):
|
||||
def __init__(self, parentWindow):
|
||||
self.parentWindow = parentWindow
|
||||
self.child = None
|
||||
WinThread.__init__(self)
|
||||
def InitInstance(self):
|
||||
rect = self.parentWindow.GetClientRect()
|
||||
rect = (0,0,rect[2]-rect[0], rect[3]-rect[1])
|
||||
|
||||
self.child = FontWindow()
|
||||
self.child.Create("FontDemo", win32con.WS_CHILD | win32con.WS_VISIBLE, rect, self.parentWindow)
|
||||
self.SetMainFrame(self.child)
|
||||
return WinThread.InitInstance(self)
|
||||
|
||||
def ExitInstance(self):
|
||||
return 0
|
||||
|
||||
class ThreadedFontFrame(window.MDIChildWnd):
|
||||
def __init__(self):
|
||||
pass # Dont call base class doc/view version...
|
||||
self.thread = None
|
||||
def Create(self, title, rect = None, parent = None):
|
||||
style = win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.WS_OVERLAPPEDWINDOW
|
||||
self._obj_ = win32ui.CreateMDIChild()
|
||||
self._obj_.CreateWindow(None, title, style, rect, parent)
|
||||
self._obj_.HookMessage(self.OnDestroy, win32con.WM_DESTROY)
|
||||
self._obj_.HookMessage (self.OnSize, win32con.WM_SIZE)
|
||||
|
||||
self.thread = TestThread(self)
|
||||
self.thread.CreateThread()
|
||||
|
||||
def OnSize(self, msg):
|
||||
pass
|
||||
|
||||
def OnDestroy(self, msg):
|
||||
win32ui.OutputDebugString("OnDestroy\n")
|
||||
if self.thread and self.thread.child:
|
||||
child = self.thread.child
|
||||
child.SendMessage(WM_USER_PREPARE_TO_CLOSE, 0, 0)
|
||||
win32ui.OutputDebugString("Destroyed\n")
|
||||
|
||||
|
||||
def Demo():
|
||||
f = FontFrame()
|
||||
f.Create("Font Demo")
|
||||
|
||||
def ThreadedDemo():
|
||||
rect = win32ui.GetMainFrame().GetMDIClient().GetClientRect()
|
||||
rect = rect[0], int(rect[3]*3/4), int(rect[2]/4), rect[3]
|
||||
incr = rect[2]
|
||||
for i in range(4):
|
||||
if i==0:
|
||||
f = FontFrame()
|
||||
title = "Not threaded"
|
||||
else:
|
||||
f = ThreadedFontFrame()
|
||||
title = "Threaded GUI Demo"
|
||||
f.Create(title, rect)
|
||||
rect = rect[0] + incr, rect[1], rect[2]+incr, rect[3]
|
||||
# Givem a chance to start
|
||||
win32api.Sleep(100)
|
||||
win32ui.PumpWaitingMessages()
|
||||
|
||||
if __name__=='__main__':
|
||||
import demoutils
|
||||
if demoutils.NeedGoodGUI():
|
||||
ThreadedDemo()
|
||||
# Demo()
|
||||
93
Lib/site-packages/pythonwin/pywin/Demos/toolbar.py
Normal file
93
Lib/site-packages/pythonwin/pywin/Demos/toolbar.py
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
# Demo of ToolBars
|
||||
|
||||
# Shows the toolbar control.
|
||||
# Demos how to make custom tooltips, etc.
|
||||
|
||||
import win32ui
|
||||
import win32con
|
||||
import win32api
|
||||
from pywin.mfc import docview, window, afxres
|
||||
import commctrl
|
||||
|
||||
class GenericFrame(window.MDIChildWnd):
|
||||
def OnCreateClient(self, cp, context):
|
||||
# handlers for toolbar buttons
|
||||
self.HookCommand (self.OnPrevious, 401)
|
||||
self.HookCommand (self.OnNext, 402)
|
||||
# Its not necessary for us to hook both of these - the
|
||||
# common controls should fall-back all by themselves.
|
||||
# Indeed, given we hook TTN_NEEDTEXTW, commctrl.TTN_NEEDTEXTA
|
||||
# will not be called.
|
||||
self.HookNotify(self.GetTTText, commctrl.TTN_NEEDTEXT)
|
||||
self.HookNotify(self.GetTTText, commctrl.TTN_NEEDTEXTW)
|
||||
|
||||
# parent = win32ui.GetMainFrame()
|
||||
parent = self
|
||||
style = win32con.WS_CHILD | win32con.WS_VISIBLE | \
|
||||
afxres.CBRS_SIZE_DYNAMIC | afxres.CBRS_TOP | afxres.CBRS_TOOLTIPS | afxres.CBRS_FLYBY
|
||||
|
||||
buttons = (win32ui.ID_APP_ABOUT,win32ui.ID_VIEW_INTERACTIVE)
|
||||
bitmap = win32ui.IDB_BROWSER_HIER
|
||||
tbid = 0xE840
|
||||
self.toolbar = tb = win32ui.CreateToolBar (parent, style, tbid)
|
||||
tb.LoadBitmap(bitmap)
|
||||
tb.SetButtons(buttons)
|
||||
|
||||
tb.EnableDocking(afxres.CBRS_ALIGN_ANY)
|
||||
tb.SetWindowText("Test")
|
||||
parent.EnableDocking(afxres.CBRS_ALIGN_ANY)
|
||||
parent.DockControlBar(tb)
|
||||
parent.LoadBarState("ToolbarTest")
|
||||
window.MDIChildWnd.OnCreateClient(self, cp, context)
|
||||
return 1
|
||||
|
||||
def OnDestroy(self, msg):
|
||||
self.SaveBarState("ToolbarTest")
|
||||
|
||||
def GetTTText(self, std, extra):
|
||||
(hwndFrom, idFrom, code) = std
|
||||
text, hinst, flags = extra
|
||||
if flags & commctrl.TTF_IDISHWND:
|
||||
return # Not handled
|
||||
if (idFrom==win32ui.ID_APP_ABOUT):
|
||||
# our 'extra' return value needs to be the following
|
||||
# entries from a NMTTDISPINFO[W] struct:
|
||||
# (szText, hinst, uFlags). None means 'don't change
|
||||
# the value'
|
||||
return 0, ("It works!", None, None)
|
||||
return None # not handled.
|
||||
|
||||
def GetMessageString(self, id):
|
||||
if id==win32ui.ID_APP_ABOUT:
|
||||
return "Dialog Test\nTest"
|
||||
else:
|
||||
return self._obj_.GetMessageString(id)
|
||||
|
||||
def OnSize (self, params):
|
||||
print('OnSize called with ', params)
|
||||
|
||||
def OnNext (self, id, cmd):
|
||||
print('OnNext called')
|
||||
|
||||
def OnPrevious (self, id, cmd):
|
||||
print('OnPrevious called')
|
||||
|
||||
msg = """\
|
||||
This toolbar was dynamically created.\r
|
||||
\r
|
||||
The first item's tooltips is provided by Python code.\r
|
||||
\r
|
||||
(Dont close the window with the toolbar in a floating state - it may not re-appear!)\r
|
||||
"""
|
||||
|
||||
def test():
|
||||
template = docview.DocTemplate( win32ui.IDR_PYTHONTYPE, None, GenericFrame, docview.EditView)
|
||||
doc = template.OpenDocumentFile(None)
|
||||
doc.SetTitle("Toolbar Test")
|
||||
view = doc.GetFirstView()
|
||||
view.SetWindowText(msg)
|
||||
|
||||
if __name__=='__main__':
|
||||
import demoutils
|
||||
if demoutils.NeedGoodGUI():
|
||||
test()
|
||||
29
Lib/site-packages/pythonwin/pywin/IDLE.cfg
Normal file
29
Lib/site-packages/pythonwin/pywin/IDLE.cfg
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
[General]
|
||||
# We base this configuration on the default config.
|
||||
# You can list "Based On" as many times as you like
|
||||
Based On = default
|
||||
|
||||
[Keys]
|
||||
# Only list keys different to default.
|
||||
# Note you may wish to rebind some of the default
|
||||
# Pythonwin keys to "Beep" or "DoNothing"
|
||||
|
||||
Alt+L = LocateSelectedFile
|
||||
Ctrl+Q = AppExit
|
||||
|
||||
# Other non-default Pythonwin keys
|
||||
Alt+A = EditSelectAll
|
||||
Alt+M = LocateModule
|
||||
|
||||
# Movement
|
||||
Ctrl+D = GotoEndOfFile
|
||||
|
||||
# Tabs and other indent features
|
||||
Alt+T = <<toggle-tabs>>
|
||||
Ctrl+[ = <<indent-region>>
|
||||
Ctrl+] = <<dedent-region>>
|
||||
|
||||
[Keys:Interactive]
|
||||
Alt+P = <<history-previous>>
|
||||
Alt+N = <<history-next>>
|
||||
|
||||
10
Lib/site-packages/pythonwin/pywin/__init__.py
Normal file
10
Lib/site-packages/pythonwin/pywin/__init__.py
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
# is_platform_unicode is an old variable that was never correctly used and
|
||||
# is no longer referenced in pywin32. It is staying for a few releases incase
|
||||
# others are looking at it, but it will go away soon!
|
||||
is_platform_unicode = 0
|
||||
|
||||
# Ditto default_platform_encoding - not referenced and will die.
|
||||
default_platform_encoding = "mbcs"
|
||||
|
||||
# This one *is* real and used - but in practice can't be changed.
|
||||
default_scintilla_encoding = "utf-8" # Scintilla _only_ supports this ATM
|
||||
113
Lib/site-packages/pythonwin/pywin/debugger/__init__.py
Normal file
113
Lib/site-packages/pythonwin/pywin/debugger/__init__.py
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
import sys
|
||||
|
||||
# Some cruft to deal with the Pythonwin GUI booting up from a non GUI app.
|
||||
def _MakeDebuggerGUI():
|
||||
app.InitInstance()
|
||||
|
||||
isInprocApp = -1
|
||||
def _CheckNeedGUI():
|
||||
global isInprocApp
|
||||
if isInprocApp==-1:
|
||||
import win32ui
|
||||
isInprocApp = win32ui.GetApp().IsInproc()
|
||||
if isInprocApp:
|
||||
# MAY Need it - may already have one
|
||||
need = "pywin.debugger.dbgpyapp" not in sys.modules
|
||||
else:
|
||||
need = 0
|
||||
if need:
|
||||
import pywin.framework.app
|
||||
from . import dbgpyapp
|
||||
pywin.framework.app.CreateDefaultGUI(dbgpyapp.DebuggerPythonApp)
|
||||
|
||||
else:
|
||||
# Check we have the appropriate editor
|
||||
# No longer necessary!
|
||||
pass
|
||||
return need
|
||||
|
||||
# Inject some methods in the top level name-space.
|
||||
currentDebugger = None # Wipe out any old one on reload.
|
||||
|
||||
def _GetCurrentDebugger():
|
||||
global currentDebugger
|
||||
if currentDebugger is None:
|
||||
_CheckNeedGUI()
|
||||
from . import debugger
|
||||
currentDebugger = debugger.Debugger()
|
||||
return currentDebugger
|
||||
|
||||
def GetDebugger():
|
||||
# An error here is not nice - as we are probably trying to
|
||||
# break into the debugger on a Python error, any
|
||||
# error raised by this is usually silent, and causes
|
||||
# big problems later!
|
||||
try:
|
||||
rc = _GetCurrentDebugger()
|
||||
rc.GUICheckInit()
|
||||
return rc
|
||||
except:
|
||||
print("Could not create the debugger!")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return None
|
||||
|
||||
def close():
|
||||
if currentDebugger is not None:
|
||||
currentDebugger.close()
|
||||
|
||||
def run(cmd,globals=None, locals=None, start_stepping = 1):
|
||||
_GetCurrentDebugger().run(cmd, globals,locals, start_stepping)
|
||||
|
||||
def runeval(expression, globals=None, locals=None):
|
||||
return _GetCurrentDebugger().runeval(expression, globals, locals)
|
||||
|
||||
def runcall(*args):
|
||||
return _GetCurrentDebugger().runcall(*args)
|
||||
|
||||
def set_trace():
|
||||
import sys
|
||||
d = _GetCurrentDebugger()
|
||||
|
||||
if d.frameShutdown: return # App closing
|
||||
|
||||
if d.stopframe != d.botframe:
|
||||
# If im not "running"
|
||||
return
|
||||
|
||||
sys.settrace(None) # May be hooked
|
||||
d.reset()
|
||||
d.set_trace()
|
||||
|
||||
# "brk" is an alias for "set_trace" ("break" is a reserved word :-(
|
||||
brk = set_trace
|
||||
|
||||
# Post-Mortem interface
|
||||
|
||||
def post_mortem(t=None):
|
||||
if t is None:
|
||||
t = sys.exc_info()[2] # Will be valid if we are called from an except handler.
|
||||
if t is None:
|
||||
try:
|
||||
t = sys.last_traceback
|
||||
except AttributeError:
|
||||
print("No traceback can be found from which to perform post-mortem debugging!")
|
||||
print("No debugging can continue")
|
||||
return
|
||||
p = _GetCurrentDebugger()
|
||||
if p.frameShutdown: return # App closing
|
||||
# No idea why I need to settrace to None - it should have been reset by now?
|
||||
sys.settrace(None)
|
||||
p.reset()
|
||||
while t.tb_next != None: t = t.tb_next
|
||||
p.bAtPostMortem = 1
|
||||
p.prep_run(None)
|
||||
try:
|
||||
p.interaction(t.tb_frame, t)
|
||||
finally:
|
||||
t = None
|
||||
p.bAtPostMortem = 0
|
||||
p.done_run()
|
||||
|
||||
def pm(t=None):
|
||||
post_mortem(t)
|
||||
31
Lib/site-packages/pythonwin/pywin/debugger/configui.py
Normal file
31
Lib/site-packages/pythonwin/pywin/debugger/configui.py
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
from . import dbgcon
|
||||
from pywin.mfc import dialog
|
||||
import win32ui
|
||||
|
||||
class DebuggerOptionsPropPage(dialog.PropertyPage):
|
||||
def __init__(self):
|
||||
dialog.PropertyPage.__init__(self, win32ui.IDD_PP_DEBUGGER)
|
||||
|
||||
def OnInitDialog(self):
|
||||
options = self.options = dbgcon.LoadDebuggerOptions()
|
||||
self.AddDDX(win32ui.IDC_CHECK1, dbgcon.OPT_HIDE)
|
||||
self[dbgcon.OPT_STOP_EXCEPTIONS] = options[dbgcon.OPT_STOP_EXCEPTIONS]
|
||||
self.AddDDX(win32ui.IDC_CHECK2, dbgcon.OPT_STOP_EXCEPTIONS)
|
||||
self[dbgcon.OPT_HIDE] = options[dbgcon.OPT_HIDE]
|
||||
return dialog.PropertyPage.OnInitDialog(self)
|
||||
|
||||
def OnOK(self):
|
||||
self.UpdateData()
|
||||
dirty = 0
|
||||
for key, val in list(self.items()):
|
||||
if key in self.options:
|
||||
if self.options[key] != val:
|
||||
self.options[key] = val
|
||||
dirty = 1
|
||||
if dirty:
|
||||
dbgcon.SaveDebuggerOptions(self.options)
|
||||
# If there is a debugger open, then set its options.
|
||||
import pywin.debugger
|
||||
if pywin.debugger.currentDebugger is not None:
|
||||
pywin.debugger.currentDebugger.options = self.options
|
||||
return 1
|
||||
28
Lib/site-packages/pythonwin/pywin/debugger/dbgcon.py
Normal file
28
Lib/site-packages/pythonwin/pywin/debugger/dbgcon.py
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
# General constants for the debugger
|
||||
|
||||
DBGSTATE_NOT_DEBUGGING = 0
|
||||
DBGSTATE_RUNNING = 1
|
||||
DBGSTATE_BREAK = 2
|
||||
DBGSTATE_QUITTING = 3 # Attempting to back out of the debug session.
|
||||
|
||||
LINESTATE_CURRENT = 0x1 # This line is where we are stopped
|
||||
LINESTATE_BREAKPOINT = 0x2 # This line is a breakpoint
|
||||
LINESTATE_CALLSTACK = 0x4 # This line is in the callstack.
|
||||
|
||||
OPT_HIDE = 'hide'
|
||||
OPT_STOP_EXCEPTIONS = 'stopatexceptions'
|
||||
|
||||
import win32api, win32ui
|
||||
|
||||
def DoGetOption(optsDict, optName, default):
|
||||
optsDict[optName] = win32ui.GetProfileVal("Debugger Options", optName, default)
|
||||
|
||||
def LoadDebuggerOptions():
|
||||
opts = {}
|
||||
DoGetOption(opts, OPT_HIDE, 0)
|
||||
DoGetOption(opts, OPT_STOP_EXCEPTIONS, 1)
|
||||
return opts
|
||||
|
||||
def SaveDebuggerOptions(opts):
|
||||
for key, val in opts.items():
|
||||
win32ui.WriteProfileVal("Debugger Options", key, val)
|
||||
47
Lib/site-packages/pythonwin/pywin/debugger/dbgpyapp.py
Normal file
47
Lib/site-packages/pythonwin/pywin/debugger/dbgpyapp.py
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
# dbgpyapp.py - Debugger Python application class
|
||||
#
|
||||
import win32con
|
||||
import win32ui
|
||||
import sys
|
||||
import string
|
||||
import os
|
||||
from pywin.framework import intpyapp
|
||||
|
||||
version = '0.3.0'
|
||||
|
||||
class DebuggerPythonApp(intpyapp.InteractivePythonApp):
|
||||
def LoadMainFrame(self):
|
||||
" Create the main applications frame "
|
||||
self.frame = self.CreateMainFrame()
|
||||
self.SetMainFrame(self.frame)
|
||||
self.frame.LoadFrame(win32ui.IDR_DEBUGGER, win32con.WS_OVERLAPPEDWINDOW)
|
||||
self.frame.DragAcceptFiles() # we can accept these.
|
||||
self.frame.ShowWindow(win32con.SW_HIDE);
|
||||
self.frame.UpdateWindow();
|
||||
|
||||
# but we do rehook, hooking the new code objects.
|
||||
self.HookCommands()
|
||||
|
||||
def InitInstance(self):
|
||||
# Use a registry path of "Python\Pythonwin Debugger
|
||||
win32ui.SetAppName(win32ui.LoadString(win32ui.IDR_DEBUGGER))
|
||||
win32ui.SetRegistryKey("Python %s" % (sys.winver,))
|
||||
# We _need_ the Scintilla color editor.
|
||||
# (and we _always_ get it now :-)
|
||||
|
||||
numMRU = win32ui.GetProfileVal("Settings","Recent File List Size", 10)
|
||||
win32ui.LoadStdProfileSettings(numMRU)
|
||||
|
||||
self.LoadMainFrame()
|
||||
|
||||
# Display the interactive window if the user wants it.
|
||||
from pywin.framework import interact
|
||||
interact.CreateInteractiveWindowUserPreference()
|
||||
|
||||
# Load the modules we use internally.
|
||||
self.LoadSystemModules()
|
||||
# Load additional module the user may want.
|
||||
self.LoadUserModules()
|
||||
|
||||
# win32ui.CreateDebuggerThread()
|
||||
win32ui.EnableControlContainer()
|
||||
985
Lib/site-packages/pythonwin/pywin/debugger/debugger.py
Normal file
985
Lib/site-packages/pythonwin/pywin/debugger/debugger.py
Normal file
|
|
@ -0,0 +1,985 @@
|
|||
# debugger.py
|
||||
|
||||
# A debugger for Pythonwin. Built from pdb.
|
||||
|
||||
# Mark Hammond (MHammond@skippinet.com.au) - Dec 94.
|
||||
|
||||
# usage:
|
||||
# >>> import pywin.debugger
|
||||
# >>> pywin.debugger.GetDebugger().run("command")
|
||||
|
||||
import pdb
|
||||
import bdb
|
||||
import sys
|
||||
import string
|
||||
import os
|
||||
import types
|
||||
|
||||
import win32ui
|
||||
import win32api
|
||||
import win32con
|
||||
import pywin.docking.DockingBar
|
||||
from pywin.mfc import dialog, object, afxres, window
|
||||
from pywin.framework import app, interact, editor, scriptutils
|
||||
from pywin.framework.editor.color.coloreditor import MARKER_CURRENT, MARKER_BREAKPOINT
|
||||
from pywin.tools import browser, hierlist
|
||||
import commctrl
|
||||
import traceback
|
||||
|
||||
#import win32traceutil
|
||||
if win32ui.UNICODE:
|
||||
LVN_ENDLABELEDIT = commctrl.LVN_ENDLABELEDITW
|
||||
else:
|
||||
LVN_ENDLABELEDIT = commctrl.LVN_ENDLABELEDITA
|
||||
|
||||
from .dbgcon import *
|
||||
|
||||
error = "pywin.debugger.error"
|
||||
|
||||
def SetInteractiveContext(globs, locs):
|
||||
if interact.edit is not None and interact.edit.currentView is not None:
|
||||
interact.edit.currentView.SetContext(globs, locs)
|
||||
|
||||
def _LineStateToMarker(ls):
|
||||
if ls==LINESTATE_CURRENT:
|
||||
return MARKER_CURRENT
|
||||
# elif ls == LINESTATE_CALLSTACK:
|
||||
# return MARKER_CALLSTACK
|
||||
return MARKER_BREAKPOINT
|
||||
|
||||
class HierListItem(browser.HLIPythonObject):
|
||||
pass
|
||||
|
||||
class HierFrameItem(HierListItem):
|
||||
def __init__(self, frame, debugger):
|
||||
HierListItem.__init__(self, frame, repr(frame))
|
||||
self.debugger = debugger
|
||||
def GetText(self):
|
||||
name = self.myobject.f_code.co_name
|
||||
if not name or name == '?' :
|
||||
# See if locals has a '__name__' (ie, a module)
|
||||
if '__name__' in self.myobject.f_locals:
|
||||
name = str(self.myobject.f_locals['__name__']) + " module"
|
||||
else:
|
||||
name = '<Debugger Context>'
|
||||
|
||||
return "%s (%s:%d)" % (name, os.path.split(self.myobject.f_code.co_filename)[1], self.myobject.f_lineno)
|
||||
def GetBitmapColumn(self):
|
||||
if self.debugger.curframe is self.myobject:
|
||||
return 7
|
||||
else:
|
||||
return 8
|
||||
def GetSubList(self):
|
||||
ret = []
|
||||
ret.append(HierFrameDict(self.myobject.f_locals, "Locals", 2))
|
||||
ret.append(HierFrameDict(self.myobject.f_globals, "Globals", 1))
|
||||
return ret
|
||||
def IsExpandable(self):
|
||||
return 1
|
||||
def TakeDefaultAction(self):
|
||||
# Set the default frame to be this frame.
|
||||
self.debugger.set_cur_frame(self.myobject)
|
||||
return 1
|
||||
|
||||
class HierFrameDict(browser.HLIDict):
|
||||
def __init__(self, dict, name, bitmapColumn):
|
||||
self.bitmapColumn=bitmapColumn
|
||||
browser.HLIDict.__init__(self, dict, name)
|
||||
def GetBitmapColumn(self):
|
||||
return self.bitmapColumn
|
||||
|
||||
class NoStackAvailableItem(HierListItem):
|
||||
def __init__(self, why):
|
||||
HierListItem.__init__(self, None, why)
|
||||
def IsExpandable(self):
|
||||
return 0
|
||||
def GetText(self):
|
||||
return self.name
|
||||
def GetBitmapColumn(self):
|
||||
return 8
|
||||
|
||||
class HierStackRoot(HierListItem):
|
||||
def __init__( self, debugger ):
|
||||
HierListItem.__init__(self, debugger, None)
|
||||
self.last_stack = []
|
||||
## def __del__(self):
|
||||
## print "HierStackRoot dieing"
|
||||
def GetSubList(self):
|
||||
debugger = self.myobject
|
||||
# print self.debugger.stack, self.debugger.curframe
|
||||
ret = []
|
||||
if debugger.debuggerState==DBGSTATE_BREAK:
|
||||
stackUse=debugger.stack[:]
|
||||
stackUse.reverse()
|
||||
self.last_stack = []
|
||||
for frame, lineno in stackUse:
|
||||
self.last_stack.append( (frame, lineno) )
|
||||
if frame is debugger.userbotframe: # Dont bother showing frames below our bottom frame.
|
||||
break
|
||||
for frame, lineno in self.last_stack:
|
||||
ret.append( HierFrameItem( frame, debugger ) )
|
||||
## elif debugger.debuggerState==DBGSTATE_NOT_DEBUGGING:
|
||||
## ret.append(NoStackAvailableItem('<nothing is being debugged>'))
|
||||
## else:
|
||||
## ret.append(NoStackAvailableItem('<stack not available while running>'))
|
||||
return ret
|
||||
def GetText(self):
|
||||
return 'root item'
|
||||
def IsExpandable(self):
|
||||
return 1
|
||||
|
||||
class HierListDebugger(hierlist.HierListWithItems):
|
||||
""" Hier List of stack frames, breakpoints, whatever """
|
||||
def __init__(self):
|
||||
hierlist.HierListWithItems.__init__(self, None, win32ui.IDB_DEBUGGER_HIER, None, win32api.RGB(255,0,0))
|
||||
def Setup(self, debugger):
|
||||
root = HierStackRoot(debugger)
|
||||
self.AcceptRoot(root)
|
||||
# def Refresh(self):
|
||||
# self.Setup()
|
||||
|
||||
class DebuggerWindow(window.Wnd):
|
||||
def __init__(self, ob):
|
||||
window.Wnd.__init__(self, ob)
|
||||
self.debugger = None
|
||||
|
||||
def Init(self, debugger):
|
||||
self.debugger = debugger
|
||||
|
||||
def GetDefRect(self):
|
||||
defRect = app.LoadWindowSize("Debugger Windows\\" + self.title)
|
||||
if defRect[2]-defRect[0]==0:
|
||||
defRect = 0, 0, 150, 150
|
||||
return defRect
|
||||
|
||||
def OnDestroy(self, msg):
|
||||
newSize = self.GetWindowPlacement()[4]
|
||||
pywin.framework.app.SaveWindowSize("Debugger Windows\\" + self.title, newSize)
|
||||
return window.Wnd.OnDestroy(self, msg)
|
||||
|
||||
def OnKeyDown(self, msg):
|
||||
key = msg[2]
|
||||
if key in [13, 27, 32]: return 1
|
||||
if key in [46,8]: # delete/BS key
|
||||
self.DeleteSelected()
|
||||
return 0
|
||||
view = scriptutils.GetActiveView()
|
||||
try:
|
||||
firer = view.bindings.fire_key_event
|
||||
except AttributeError:
|
||||
firer = None
|
||||
if firer is not None:
|
||||
return firer(msg)
|
||||
else:
|
||||
return 1
|
||||
|
||||
def DeleteSelected(self):
|
||||
win32api.MessageBeep()
|
||||
|
||||
def EditSelected(self):
|
||||
win32api.MessageBeep()
|
||||
|
||||
class DebuggerStackWindow(DebuggerWindow):
|
||||
title = "Stack"
|
||||
def __init__(self):
|
||||
DebuggerWindow.__init__(self, win32ui.CreateTreeCtrl())
|
||||
self.list = HierListDebugger()
|
||||
self.listOK = 0
|
||||
def SaveState(self):
|
||||
self.list.DeleteAllItems()
|
||||
self.listOK = 0
|
||||
win32ui.WriteProfileVal("Debugger Windows\\" + self.title, "Visible", self.IsWindowVisible())
|
||||
def CreateWindow(self, parent):
|
||||
style = win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.WS_BORDER | commctrl.TVS_HASLINES | commctrl.TVS_LINESATROOT | commctrl.TVS_HASBUTTONS
|
||||
self._obj_.CreateWindow(style, self.GetDefRect(), parent, win32ui.IDC_LIST1)
|
||||
self.HookMessage(self.OnKeyDown, win32con.WM_KEYDOWN)
|
||||
self.HookMessage(self.OnKeyDown, win32con.WM_SYSKEYDOWN)
|
||||
self.list.HierInit (parent, self)
|
||||
self.listOK = 0 # delayed setup
|
||||
#self.list.Setup()
|
||||
|
||||
def RespondDebuggerState(self, state):
|
||||
assert self.debugger is not None, "Init not called"
|
||||
if not self.listOK:
|
||||
self.listOK = 1
|
||||
self.list.Setup(self.debugger)
|
||||
else:
|
||||
self.list.Refresh()
|
||||
|
||||
def RespondDebuggerData(self):
|
||||
try:
|
||||
handle = self.GetChildItem(0)
|
||||
except win32ui.error:
|
||||
return # No items
|
||||
while 1:
|
||||
item = self.list.ItemFromHandle(handle)
|
||||
col = self.list.GetBitmapColumn(item)
|
||||
selCol = self.list.GetSelectedBitmapColumn(item)
|
||||
if selCol is None: selCol = col
|
||||
if self.list.GetItemImage(handle)!= (col, selCol):
|
||||
self.list.SetItemImage(handle, col, selCol)
|
||||
try:
|
||||
handle = self.GetNextSiblingItem(handle)
|
||||
except win32ui.error:
|
||||
break
|
||||
|
||||
class DebuggerListViewWindow(DebuggerWindow):
|
||||
def __init__(self):
|
||||
DebuggerWindow.__init__(self, win32ui.CreateListCtrl())
|
||||
def CreateWindow(self, parent):
|
||||
list = self
|
||||
style = win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.WS_BORDER | commctrl.LVS_EDITLABELS | commctrl.LVS_REPORT
|
||||
self._obj_.CreateWindow(style, self.GetDefRect(), parent, win32ui.IDC_LIST1)
|
||||
self.HookMessage(self.OnKeyDown, win32con.WM_KEYDOWN)
|
||||
self.HookMessage(self.OnKeyDown, win32con.WM_SYSKEYDOWN)
|
||||
list = self
|
||||
title, width = self.columns[0]
|
||||
itemDetails = (commctrl.LVCFMT_LEFT, width, title, 0)
|
||||
list.InsertColumn(0, itemDetails)
|
||||
col = 1
|
||||
for title, width in self.columns[1:]:
|
||||
col = col + 1
|
||||
itemDetails = (commctrl.LVCFMT_LEFT, width, title, 0)
|
||||
list.InsertColumn(col, itemDetails)
|
||||
parent.HookNotify(self.OnListEndLabelEdit, LVN_ENDLABELEDIT)
|
||||
parent.HookNotify(self.OnItemRightClick, commctrl.NM_RCLICK)
|
||||
parent.HookNotify(self.OnItemDoubleClick, commctrl.NM_DBLCLK)
|
||||
|
||||
def RespondDebuggerData(self):
|
||||
pass
|
||||
|
||||
def RespondDebuggerState(self, state):
|
||||
pass
|
||||
|
||||
def EditSelected(self):
|
||||
try:
|
||||
sel = self.GetNextItem(-1, commctrl.LVNI_SELECTED)
|
||||
except win32ui.error:
|
||||
return
|
||||
self.EditLabel(sel)
|
||||
|
||||
def OnKeyDown(self, msg):
|
||||
key = msg[2]
|
||||
# If someone starts typing, they probably are trying to edit the text!
|
||||
if chr(key) in string.ascii_uppercase:
|
||||
self.EditSelected()
|
||||
return 0
|
||||
return DebuggerWindow.OnKeyDown(self, msg)
|
||||
|
||||
def OnItemDoubleClick(self, notify_data, extra):
|
||||
self.EditSelected()
|
||||
|
||||
def OnItemRightClick(self, notify_data, extra):
|
||||
# First select the item we right-clicked on.
|
||||
pt = self.ScreenToClient(win32api.GetCursorPos())
|
||||
flags, hItem, subitem = self.HitTest(pt)
|
||||
if hItem==-1 or commctrl.TVHT_ONITEM & flags==0:
|
||||
return None
|
||||
self.SetItemState(hItem, commctrl.LVIS_SELECTED, commctrl.LVIS_SELECTED)
|
||||
|
||||
menu = win32ui.CreatePopupMenu()
|
||||
menu.AppendMenu(win32con.MF_STRING|win32con.MF_ENABLED,1000, "Edit item")
|
||||
menu.AppendMenu(win32con.MF_STRING|win32con.MF_ENABLED,1001, "Delete item")
|
||||
dockbar = self.GetParent()
|
||||
if dockbar.IsFloating():
|
||||
hook_parent = win32ui.GetMainFrame()
|
||||
else:
|
||||
hook_parent = self.GetParentFrame()
|
||||
hook_parent.HookCommand(self.OnEditItem, 1000)
|
||||
hook_parent.HookCommand(self.OnDeleteItem, 1001)
|
||||
menu.TrackPopupMenu(win32api.GetCursorPos()) # track at mouse position.
|
||||
return None
|
||||
|
||||
def OnDeleteItem(self,command, code):
|
||||
self.DeleteSelected()
|
||||
def OnEditItem(self, command, code):
|
||||
self.EditSelected()
|
||||
|
||||
class DebuggerBreakpointsWindow(DebuggerListViewWindow):
|
||||
title = "Breakpoints"
|
||||
columns = [ ("Condition", 70), ("Location", 1024)]
|
||||
|
||||
def SaveState(self):
|
||||
items = []
|
||||
for i in range(self.GetItemCount()):
|
||||
items.append(self.GetItemText(i,0))
|
||||
items.append(self.GetItemText(i,1))
|
||||
win32ui.WriteProfileVal("Debugger Windows\\" + self.title, "BreakpointList", "\t".join(items))
|
||||
win32ui.WriteProfileVal("Debugger Windows\\" + self.title, "Visible", self.IsWindowVisible())
|
||||
return 1
|
||||
|
||||
def OnListEndLabelEdit(self, std, extra):
|
||||
item = extra[0]
|
||||
text = item[4]
|
||||
if text is None: return
|
||||
|
||||
item_id = self.GetItem(item[0])[6]
|
||||
|
||||
from bdb import Breakpoint
|
||||
for bplist in Breakpoint.bplist.values():
|
||||
for bp in bplist:
|
||||
if id(bp)==item_id:
|
||||
if text.strip().lower()=="none":
|
||||
text = None
|
||||
bp.cond = text
|
||||
break
|
||||
self.RespondDebuggerData()
|
||||
|
||||
def DeleteSelected(self):
|
||||
try:
|
||||
num = self.GetNextItem(-1, commctrl.LVNI_SELECTED)
|
||||
item_id = self.GetItem(num)[6]
|
||||
from bdb import Breakpoint
|
||||
for bplist in list(Breakpoint.bplist.values()):
|
||||
for bp in bplist:
|
||||
if id(bp)==item_id:
|
||||
self.debugger.clear_break(bp.file, bp.line)
|
||||
break
|
||||
except win32ui.error:
|
||||
win32api.MessageBeep()
|
||||
self.RespondDebuggerData()
|
||||
|
||||
def RespondDebuggerData(self):
|
||||
l = self
|
||||
l.DeleteAllItems()
|
||||
index = -1
|
||||
from bdb import Breakpoint
|
||||
for bplist in Breakpoint.bplist.values():
|
||||
for bp in bplist:
|
||||
baseName = os.path.split(bp.file)[1]
|
||||
cond = bp.cond
|
||||
item = index+1, 0, 0, 0, str(cond), 0, id(bp)
|
||||
index = l.InsertItem(item)
|
||||
l.SetItemText(index, 1, "%s: %s" % (baseName, bp.line))
|
||||
|
||||
class DebuggerWatchWindow(DebuggerListViewWindow):
|
||||
title = "Watch"
|
||||
columns = [ ("Expression", 70), ("Value", 1024)]
|
||||
|
||||
def CreateWindow(self, parent):
|
||||
DebuggerListViewWindow.CreateWindow(self, parent)
|
||||
items = win32ui.GetProfileVal("Debugger Windows\\" + self.title, "Items", "").split("\t")
|
||||
index = -1
|
||||
for item in items:
|
||||
if item:
|
||||
index = self.InsertItem(index+1, item)
|
||||
self.InsertItem(index+1, "<New Item>")
|
||||
|
||||
def SaveState(self):
|
||||
items = []
|
||||
for i in range(self.GetItemCount()-1):
|
||||
items.append(self.GetItemText(i,0))
|
||||
win32ui.WriteProfileVal("Debugger Windows\\" + self.title, "Items", "\t".join(items))
|
||||
win32ui.WriteProfileVal("Debugger Windows\\" + self.title, "Visible", self.IsWindowVisible())
|
||||
return 1
|
||||
|
||||
def OnListEndLabelEdit(self, std, extra):
|
||||
item = extra[0]
|
||||
itemno = item[0]
|
||||
text = item[4]
|
||||
if text is None: return
|
||||
self.SetItemText(itemno, 0, text)
|
||||
if itemno == self.GetItemCount()-1:
|
||||
self.InsertItem(itemno+1, "<New Item>")
|
||||
self.RespondDebuggerState(self.debugger.debuggerState)
|
||||
|
||||
def DeleteSelected(self):
|
||||
try:
|
||||
num = self.GetNextItem(-1, commctrl.LVNI_SELECTED)
|
||||
if num < self.GetItemCount()-1: # We cant delete the last
|
||||
self.DeleteItem(num)
|
||||
except win32ui.error:
|
||||
win32api.MessageBeep()
|
||||
|
||||
def RespondDebuggerState(self, state):
|
||||
globs = locs = None
|
||||
if state==DBGSTATE_BREAK:
|
||||
if self.debugger.curframe:
|
||||
globs = self.debugger.curframe.f_globals
|
||||
locs = self.debugger.curframe.f_locals
|
||||
elif state==DBGSTATE_NOT_DEBUGGING:
|
||||
import __main__
|
||||
globs = locs = __main__.__dict__
|
||||
for i in range(self.GetItemCount()-1):
|
||||
text = self.GetItemText(i, 0)
|
||||
if globs is None:
|
||||
val = ""
|
||||
else:
|
||||
try:
|
||||
val = repr( eval( text, globs, locs) )
|
||||
except SyntaxError:
|
||||
val = "Syntax Error"
|
||||
except:
|
||||
t, v, tb = sys.exc_info()
|
||||
val = traceback.format_exception_only(t, v)[0].strip()
|
||||
tb = None # prevent a cycle.
|
||||
self.SetItemText(i, 1, val)
|
||||
|
||||
def CreateDebuggerDialog(parent, klass):
|
||||
control = klass()
|
||||
control.CreateWindow(parent)
|
||||
return control
|
||||
|
||||
DebuggerDialogInfos = (
|
||||
(0xe810, DebuggerStackWindow, None),
|
||||
(0xe811, DebuggerBreakpointsWindow, (10, 10)),
|
||||
(0xe812, DebuggerWatchWindow, None),
|
||||
)
|
||||
|
||||
# Prepare all the "control bars" for this package.
|
||||
# If control bars are not all loaded when the toolbar-state functions are
|
||||
# called, things go horribly wrong.
|
||||
def PrepareControlBars(frame):
|
||||
style = win32con.WS_CHILD | afxres.CBRS_SIZE_DYNAMIC | afxres.CBRS_TOP | afxres.CBRS_TOOLTIPS | afxres.CBRS_FLYBY
|
||||
tbd = win32ui.CreateToolBar (frame, style, win32ui.ID_VIEW_TOOLBAR_DBG)
|
||||
tbd.ModifyStyle(0, commctrl.TBSTYLE_FLAT)
|
||||
tbd.LoadToolBar(win32ui.IDR_DEBUGGER)
|
||||
tbd.EnableDocking(afxres.CBRS_ALIGN_ANY)
|
||||
tbd.SetWindowText("Debugger")
|
||||
frame.DockControlBar(tbd)
|
||||
|
||||
# and the other windows.
|
||||
for id, klass, float in DebuggerDialogInfos:
|
||||
try:
|
||||
frame.GetControlBar(id)
|
||||
exists=1
|
||||
except win32ui.error:
|
||||
exists=0
|
||||
if exists: continue
|
||||
bar = pywin.docking.DockingBar.DockingBar()
|
||||
style=win32con.WS_CHILD | afxres.CBRS_LEFT # don't create visible.
|
||||
bar.CreateWindow(frame, CreateDebuggerDialog, klass.title, id, style, childCreatorArgs=(klass,))
|
||||
bar.SetBarStyle( bar.GetBarStyle()|afxres.CBRS_TOOLTIPS|afxres.CBRS_FLYBY|afxres.CBRS_SIZE_DYNAMIC)
|
||||
bar.EnableDocking(afxres.CBRS_ALIGN_ANY)
|
||||
if float is None:
|
||||
frame.DockControlBar(bar)
|
||||
else:
|
||||
frame.FloatControlBar(bar, float, afxres.CBRS_ALIGN_ANY)
|
||||
|
||||
## frame.ShowControlBar(bar, 0, 1)
|
||||
|
||||
|
||||
SKIP_NONE=0
|
||||
SKIP_STEP=1
|
||||
SKIP_RUN=2
|
||||
|
||||
debugger_parent=pdb.Pdb
|
||||
class Debugger(debugger_parent):
|
||||
def __init__(self):
|
||||
self.inited = 0
|
||||
self.skipBotFrame = SKIP_NONE
|
||||
self.userbotframe = None
|
||||
self.frameShutdown = 0
|
||||
self.pumping = 0
|
||||
self.debuggerState = DBGSTATE_NOT_DEBUGGING # Assume so, anyway.
|
||||
self.shownLineCurrent = None # The last filename I highlighted.
|
||||
self.shownLineCallstack = None # The last filename I highlighted.
|
||||
self.last_cmd_debugged = ""
|
||||
self.abortClosed = 0
|
||||
self.isInitialBreakpoint = 0
|
||||
debugger_parent.__init__(self)
|
||||
|
||||
# See if any break-points have been set in the editor
|
||||
for doc in editor.editorTemplate.GetDocumentList():
|
||||
lineNo = -1
|
||||
while 1:
|
||||
lineNo = doc.MarkerGetNext(lineNo+1, MARKER_BREAKPOINT)
|
||||
if lineNo <= 0: break
|
||||
self.set_break(doc.GetPathName(), lineNo)
|
||||
|
||||
self.reset()
|
||||
self.inForcedGUI = win32ui.GetApp().IsInproc()
|
||||
self.options = LoadDebuggerOptions()
|
||||
self.bAtException = self.bAtPostMortem = 0
|
||||
|
||||
def __del__(self):
|
||||
self.close()
|
||||
def close(self, frameShutdown = 0):
|
||||
# abortClose indicates if we have total shutdown
|
||||
# (ie, main window is dieing)
|
||||
if self.pumping:
|
||||
# Can stop pump here, as it only posts a message, and
|
||||
# returns immediately.
|
||||
if not self.StopDebuggerPump(): # User cancelled close.
|
||||
return 0
|
||||
# NOTE - from this point on the close can not be
|
||||
# stopped - the WM_QUIT message is already in the queue.
|
||||
self.frameShutdown = frameShutdown
|
||||
if not self.inited: return 1
|
||||
self.inited = 0
|
||||
|
||||
SetInteractiveContext(None, None)
|
||||
|
||||
frame = win32ui.GetMainFrame()
|
||||
# Hide the debuger toolbars (as they wont normally form part of the main toolbar state.
|
||||
for id, klass, float in DebuggerDialogInfos:
|
||||
try:
|
||||
tb = frame.GetControlBar(id)
|
||||
if tb.dialog is not None: # We may never have actually been shown.
|
||||
tb.dialog.SaveState()
|
||||
frame.ShowControlBar(tb, 0, 1)
|
||||
except win32ui.error:
|
||||
pass
|
||||
|
||||
self._UnshowCurrentLine()
|
||||
self.set_quit()
|
||||
return 1
|
||||
|
||||
def StopDebuggerPump(self):
|
||||
assert self.pumping, "Can't stop the debugger pump if Im not pumping!"
|
||||
# After stopping a pump, I may never return.
|
||||
if self.GUIAboutToFinishInteract():
|
||||
self.pumping = 0
|
||||
win32ui.StopDebuggerPump() # Posts a message, so we do return.
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def get_option(self, option):
|
||||
"""Public interface into debugger options
|
||||
"""
|
||||
try:
|
||||
return self.options[option]
|
||||
except KeyError:
|
||||
raise error("Option %s is not a valid option" % option)
|
||||
|
||||
def prep_run(self, cmd):
|
||||
pass
|
||||
def done_run(self, cmd=None):
|
||||
self.RespondDebuggerState(DBGSTATE_NOT_DEBUGGING)
|
||||
self.close()
|
||||
def canonic(self, fname):
|
||||
return os.path.abspath(fname).lower()
|
||||
def reset(self):
|
||||
debugger_parent.reset(self)
|
||||
self.userbotframe = None
|
||||
self.UpdateAllLineStates()
|
||||
self._UnshowCurrentLine()
|
||||
|
||||
|
||||
def setup(self, f, t):
|
||||
debugger_parent.setup(self, f, t)
|
||||
self.bAtException = t is not None
|
||||
|
||||
def set_break(self, filename, lineno, temporary=0, cond = None):
|
||||
filename = self.canonic(filename)
|
||||
self.SetLineState(filename, lineno, LINESTATE_BREAKPOINT)
|
||||
return debugger_parent.set_break(self, filename, lineno, temporary, cond)
|
||||
|
||||
def clear_break(self, filename, lineno):
|
||||
filename = self.canonic(filename)
|
||||
self.ResetLineState(filename, lineno, LINESTATE_BREAKPOINT)
|
||||
return debugger_parent.clear_break(self, filename, lineno)
|
||||
|
||||
def cmdloop(self):
|
||||
if self.frameShutdown: return # App in the process of closing - never break in!
|
||||
self.GUIAboutToBreak()
|
||||
|
||||
def print_stack_entry(self, frame):
|
||||
# We dont want a stack printed - our GUI is better :-)
|
||||
pass
|
||||
|
||||
def user_return(self, frame, return_value):
|
||||
# Same as parent, just no "print"
|
||||
# This function is called when a return trap is set here
|
||||
frame.f_locals['__return__'] = return_value
|
||||
self.interaction(frame, None)
|
||||
|
||||
def user_call(self, frame, args):
|
||||
# base class has an annoying 'print' that adds no value to us...
|
||||
if self.stop_here(frame):
|
||||
self.interaction(frame, None)
|
||||
|
||||
def user_exception(self, frame, exc_info):
|
||||
# This function is called if an exception occurs,
|
||||
# but only if we are to stop at or just below this level
|
||||
(exc_type, exc_value, exc_traceback) = exc_info
|
||||
if self.get_option(OPT_STOP_EXCEPTIONS):
|
||||
frame.f_locals['__exception__'] = exc_type, exc_value
|
||||
print("Unhandled exception while debugging...")
|
||||
# on both py2k and py3k, we may be called with exc_value
|
||||
# being the args to the exception, or it may already be
|
||||
# instantiated (IOW, PyErr_Normalize() hasn't been
|
||||
# called on the args). In py2k this is fine, but in
|
||||
# py3k, traceback.print_exception fails. So on py3k
|
||||
# we instantiate an exception instance to print.
|
||||
if sys.version_info > (3,) and not isinstance(exc_value, BaseException):
|
||||
# they are args - may be a single item or already a tuple
|
||||
if not isinstance(exc_value, tuple):
|
||||
exc_value = (exc_value,)
|
||||
exc_value = exc_type(*exc_value)
|
||||
|
||||
traceback.print_exception(exc_type, exc_value, exc_traceback)
|
||||
self.interaction(frame, exc_traceback)
|
||||
|
||||
def user_line(self, frame):
|
||||
if frame.f_lineno==0: return
|
||||
debugger_parent.user_line(self, frame)
|
||||
|
||||
def stop_here(self, frame):
|
||||
if self.isInitialBreakpoint:
|
||||
self.isInitialBreakpoint = 0
|
||||
self.set_continue()
|
||||
return 0
|
||||
if frame is self.botframe and self.skipBotFrame == SKIP_RUN:
|
||||
self.set_continue()
|
||||
return 0
|
||||
if frame is self.botframe and self.skipBotFrame == SKIP_STEP:
|
||||
self.set_step()
|
||||
return 0
|
||||
return debugger_parent.stop_here(self, frame)
|
||||
|
||||
def run(self, cmd,globals=None, locals=None, start_stepping = 1):
|
||||
if not isinstance(cmd, (str, types.CodeType)):
|
||||
raise TypeError("Only strings can be run")
|
||||
self.last_cmd_debugged = cmd
|
||||
if start_stepping:
|
||||
self.isInitialBreakpoint = 0
|
||||
else:
|
||||
self.isInitialBreakpoint = 1
|
||||
try:
|
||||
if globals is None:
|
||||
import __main__
|
||||
globals = __main__.__dict__
|
||||
if locals is None:
|
||||
locals = globals
|
||||
self.reset()
|
||||
self.prep_run(cmd)
|
||||
sys.settrace(self.trace_dispatch)
|
||||
if type(cmd) != types.CodeType:
|
||||
cmd = cmd+'\n'
|
||||
try:
|
||||
try:
|
||||
if start_stepping: self.skipBotFrame = SKIP_STEP
|
||||
else: self.skipBotFrame = SKIP_RUN
|
||||
exec(cmd, globals, locals)
|
||||
except bdb.BdbQuit:
|
||||
pass
|
||||
finally:
|
||||
self.skipBotFrame = SKIP_NONE
|
||||
self.quitting = 1
|
||||
sys.settrace(None)
|
||||
|
||||
finally:
|
||||
self.done_run(cmd)
|
||||
|
||||
def runeval(self, expr, globals=None, locals=None):
|
||||
self.prep_run(expr)
|
||||
try:
|
||||
debugger_parent.runeval(self, expr, globals, locals)
|
||||
finally:
|
||||
self.done_run(expr)
|
||||
|
||||
def runexec(self, what, globs=None, locs=None):
|
||||
self.reset()
|
||||
sys.settrace(self.trace_dispatch)
|
||||
try:
|
||||
try:
|
||||
exec(what, globs, locs)
|
||||
except bdb.BdbQuit:
|
||||
pass
|
||||
finally:
|
||||
self.quitting = 1
|
||||
sys.settrace(None)
|
||||
|
||||
def do_set_step(self):
|
||||
if self.GUIAboutToRun():
|
||||
self.set_step()
|
||||
|
||||
def do_set_next(self):
|
||||
if self.GUIAboutToRun():
|
||||
self.set_next(self.curframe)
|
||||
|
||||
def do_set_return(self):
|
||||
if self.GUIAboutToRun():
|
||||
self.set_return(self.curframe)
|
||||
|
||||
def do_set_continue(self):
|
||||
if self.GUIAboutToRun():
|
||||
self.set_continue()
|
||||
|
||||
def set_quit(self):
|
||||
ok = 1
|
||||
if self.pumping:
|
||||
ok = self.StopDebuggerPump()
|
||||
if ok:
|
||||
debugger_parent.set_quit(self)
|
||||
|
||||
def _dump_frame_(self, frame,name=None):
|
||||
if name is None: name = ""
|
||||
if frame:
|
||||
if frame.f_code and frame.f_code.co_filename:
|
||||
fname = os.path.split(frame.f_code.co_filename)[1]
|
||||
else:
|
||||
fname = "??"
|
||||
print(repr(name), fname, frame.f_lineno, frame)
|
||||
else:
|
||||
print(repr(name), "None")
|
||||
|
||||
def set_trace(self):
|
||||
# Start debugging from _2_ levels up!
|
||||
try:
|
||||
1 + ''
|
||||
except:
|
||||
frame = sys.exc_info()[2].tb_frame.f_back.f_back
|
||||
self.reset()
|
||||
self.userbotframe = None
|
||||
while frame:
|
||||
# scriptutils.py creates a local variable with name
|
||||
# '_debugger_stop_frame_', and we dont go past it
|
||||
# (everything above this is Pythonwin framework code)
|
||||
if "_debugger_stop_frame_" in frame.f_locals:
|
||||
self.userbotframe = frame
|
||||
break
|
||||
|
||||
frame.f_trace = self.trace_dispatch
|
||||
self.botframe = frame
|
||||
frame = frame.f_back
|
||||
self.set_step()
|
||||
sys.settrace(self.trace_dispatch)
|
||||
|
||||
def set_cur_frame(self, frame):
|
||||
# Sets the "current" frame - ie, the frame with focus. This is the
|
||||
# frame on which "step out" etc actions are taken.
|
||||
# This may or may not be the top of the stack.
|
||||
assert frame is not None, "You must pass a valid frame"
|
||||
self.curframe = frame
|
||||
for f, index in self.stack:
|
||||
if f is frame:
|
||||
self.curindex = index
|
||||
break
|
||||
else:
|
||||
assert 0, "Can't find the frame in the stack."
|
||||
SetInteractiveContext(frame.f_globals, frame.f_locals)
|
||||
self.GUIRespondDebuggerData()
|
||||
self.ShowCurrentLine()
|
||||
|
||||
def IsBreak(self):
|
||||
return self.debuggerState == DBGSTATE_BREAK
|
||||
|
||||
def IsDebugging(self):
|
||||
return self.debuggerState != DBGSTATE_NOT_DEBUGGING
|
||||
|
||||
def RespondDebuggerState(self, state):
|
||||
if state == self.debuggerState: return
|
||||
if state==DBGSTATE_NOT_DEBUGGING: # Debugger exists, but not doing anything
|
||||
title = ""
|
||||
elif state==DBGSTATE_RUNNING: # Code is running under the debugger.
|
||||
title = " - running"
|
||||
elif state==DBGSTATE_BREAK: # We are at a breakpoint or stepping or whatever.
|
||||
if self.bAtException:
|
||||
if self.bAtPostMortem:
|
||||
title = " - post mortem exception"
|
||||
else:
|
||||
title = " - exception"
|
||||
else:
|
||||
title = " - break"
|
||||
else:
|
||||
raise error("Invalid debugger state passed!")
|
||||
win32ui.GetMainFrame().SetWindowText(win32ui.LoadString(win32ui.IDR_MAINFRAME) + title)
|
||||
if self.debuggerState == DBGSTATE_QUITTING and state != DBGSTATE_NOT_DEBUGGING:
|
||||
print("Ignoring state change cos Im trying to stop!", state)
|
||||
return
|
||||
self.debuggerState = state
|
||||
try:
|
||||
frame = win32ui.GetMainFrame()
|
||||
except win32ui.error:
|
||||
frame = None
|
||||
if frame is not None:
|
||||
for id, klass, float in DebuggerDialogInfos:
|
||||
cb = win32ui.GetMainFrame().GetControlBar(id).dialog
|
||||
cb.RespondDebuggerState(state)
|
||||
# Tell each open editor window about the state transition
|
||||
for doc in editor.editorTemplate.GetDocumentList():
|
||||
doc.OnDebuggerStateChange(state)
|
||||
self.ShowCurrentLine()
|
||||
|
||||
#
|
||||
# GUI debugger interface.
|
||||
#
|
||||
def GUICheckInit(self):
|
||||
if self.inited: return
|
||||
self.inited = 1
|
||||
frame = win32ui.GetMainFrame()
|
||||
|
||||
# Ensure the debugger windows are attached to the debugger.
|
||||
for id, klass, float in DebuggerDialogInfos:
|
||||
w = frame.GetControlBar(id)
|
||||
w.dialog.Init(self)
|
||||
# Show toolbar if it was visible during last debug session
|
||||
# This would be better done using a CDockState, but that class is not wrapped yet
|
||||
if win32ui.GetProfileVal("Debugger Windows\\" + w.dialog.title, "Visible", 0):
|
||||
frame.ShowControlBar(w, 1, 1)
|
||||
|
||||
# ALWAYS show debugging toolbar, regardless of saved state
|
||||
tb = frame.GetControlBar(win32ui.ID_VIEW_TOOLBAR_DBG)
|
||||
frame.ShowControlBar(tb, 1, 1)
|
||||
self.GUIRespondDebuggerData()
|
||||
|
||||
# frame.RecalcLayout()
|
||||
|
||||
def GetDebuggerBar(self, barName):
|
||||
frame = win32ui.GetMainFrame()
|
||||
for id, klass, float in DebuggerDialogInfos:
|
||||
if klass.title == barName:
|
||||
return frame.GetControlBar(id)
|
||||
assert 0, "Can't find a bar of that name!"
|
||||
|
||||
def GUIRespondDebuggerData(self):
|
||||
if not self.inited: # GUI not inited - no toolbars etc.
|
||||
return
|
||||
|
||||
for id, klass, float in DebuggerDialogInfos:
|
||||
cb = win32ui.GetMainFrame().GetControlBar(id).dialog
|
||||
cb.RespondDebuggerData()
|
||||
|
||||
def GUIAboutToRun(self):
|
||||
if not self.StopDebuggerPump():
|
||||
return 0
|
||||
self._UnshowCurrentLine()
|
||||
self.RespondDebuggerState(DBGSTATE_RUNNING)
|
||||
SetInteractiveContext(None, None)
|
||||
return 1
|
||||
|
||||
def GUIAboutToBreak(self):
|
||||
"Called as the GUI debugger is about to get context, and take control of the running program."
|
||||
self.GUICheckInit()
|
||||
self.RespondDebuggerState(DBGSTATE_BREAK)
|
||||
self.GUIAboutToInteract()
|
||||
if self.pumping:
|
||||
print("!!! Already pumping - outa here")
|
||||
return
|
||||
self.pumping = 1
|
||||
win32ui.StartDebuggerPump() # NOTE - This will NOT return until the user is finished interacting
|
||||
assert not self.pumping, "Should not be pumping once the pump has finished"
|
||||
if self.frameShutdown: # User shut down app while debugging
|
||||
win32ui.GetMainFrame().PostMessage(win32con.WM_CLOSE)
|
||||
|
||||
def GUIAboutToInteract(self):
|
||||
"Called as the GUI is about to perform any interaction with the user"
|
||||
frame = win32ui.GetMainFrame()
|
||||
# Remember the enabled state of our main frame
|
||||
# may be disabled primarily if a modal dialog is displayed.
|
||||
# Only get at enabled via GetWindowLong.
|
||||
self.bFrameEnabled = frame.IsWindowEnabled()
|
||||
self.oldForeground = None
|
||||
fw = win32ui.GetForegroundWindow()
|
||||
if fw is not frame:
|
||||
self.oldForeground = fw
|
||||
# fw.EnableWindow(0) Leave enabled for now?
|
||||
self.oldFrameEnableState = frame.IsWindowEnabled()
|
||||
frame.EnableWindow(1)
|
||||
if self.inForcedGUI and not frame.IsWindowVisible():
|
||||
frame.ShowWindow(win32con.SW_SHOW)
|
||||
frame.UpdateWindow()
|
||||
if self.curframe:
|
||||
SetInteractiveContext(self.curframe.f_globals, self.curframe.f_locals)
|
||||
else:
|
||||
SetInteractiveContext(None, None)
|
||||
self.GUIRespondDebuggerData()
|
||||
|
||||
def GUIAboutToFinishInteract(self):
|
||||
"""Called as the GUI is about to finish any interaction with the user
|
||||
Returns non zero if we are allowed to stop interacting"""
|
||||
if self.oldForeground is not None:
|
||||
try:
|
||||
win32ui.GetMainFrame().EnableWindow(self.oldFrameEnableState)
|
||||
self.oldForeground.EnableWindow(1)
|
||||
except win32ui.error:
|
||||
# old window may be dead.
|
||||
pass
|
||||
# self.oldForeground.SetForegroundWindow() - fails??
|
||||
if not self.inForcedGUI:
|
||||
return 1 # Never a problem, and nothing else to do.
|
||||
# If we are running a forced GUI, we may never get an opportunity
|
||||
# to interact again. Therefore we perform a "SaveAll", to makesure that
|
||||
# any documents are saved before leaving.
|
||||
for template in win32ui.GetApp().GetDocTemplateList():
|
||||
for doc in template.GetDocumentList():
|
||||
if not doc.SaveModified():
|
||||
return 0
|
||||
# All documents saved - now hide the app and debugger.
|
||||
if self.get_option(OPT_HIDE):
|
||||
frame = win32ui.GetMainFrame()
|
||||
frame.ShowWindow(win32con.SW_HIDE)
|
||||
return 1
|
||||
|
||||
#
|
||||
# Pythonwin interface - all stuff to do with showing source files,
|
||||
# changing line states etc.
|
||||
#
|
||||
def ShowLineState(self, fileName, lineNo, lineState):
|
||||
# Set the state of a line, open if not already
|
||||
self.ShowLineNo(fileName, lineNo)
|
||||
self.SetLineState(fileName, lineNo, lineState)
|
||||
|
||||
def SetLineState(self, fileName, lineNo, lineState):
|
||||
# Set the state of a line if the document is open.
|
||||
doc = editor.editorTemplate.FindOpenDocument(fileName)
|
||||
if doc is not None:
|
||||
marker = _LineStateToMarker(lineState)
|
||||
if not doc.MarkerCheck(lineNo, marker):
|
||||
doc.MarkerAdd(lineNo, marker)
|
||||
|
||||
def ResetLineState(self, fileName, lineNo, lineState):
|
||||
# Set the state of a line if the document is open.
|
||||
doc = editor.editorTemplate.FindOpenDocument(fileName)
|
||||
if doc is not None:
|
||||
marker = _LineStateToMarker(lineState)
|
||||
doc.MarkerDelete(lineNo, marker)
|
||||
|
||||
def UpdateDocumentLineStates(self, doc):
|
||||
# Show all lines in their special status color. If the doc is open
|
||||
# all line states are reset.
|
||||
doc.MarkerDeleteAll( MARKER_BREAKPOINT )
|
||||
doc.MarkerDeleteAll( MARKER_CURRENT )
|
||||
fname = self.canonic(doc.GetPathName())
|
||||
# Now loop over all break-points
|
||||
for line in self.breaks.get(fname, []):
|
||||
doc.MarkerAdd(line, MARKER_BREAKPOINT)
|
||||
# And the current line if in this document.
|
||||
if self.shownLineCurrent and fname == self.shownLineCurrent[0]:
|
||||
lineNo = self.shownLineCurrent[1]
|
||||
if not doc.MarkerCheck(lineNo, MARKER_CURRENT):
|
||||
doc.MarkerAdd(lineNo, MARKER_CURRENT)
|
||||
# if self.shownLineCallstack and fname == self.shownLineCallstack[0]:
|
||||
# doc.MarkerAdd(self.shownLineCallstack[1], MARKER_CURRENT)
|
||||
|
||||
def UpdateAllLineStates(self):
|
||||
for doc in editor.editorTemplate.GetDocumentList():
|
||||
self.UpdateDocumentLineStates(doc)
|
||||
|
||||
def ShowCurrentLine(self):
|
||||
# Show the current line. Only ever 1 current line - undoes last current
|
||||
# The "Current Line" is self.curframe.
|
||||
# The "Callstack Line" is the top of the stack.
|
||||
# If current == callstack, only show as current.
|
||||
self._UnshowCurrentLine() # un-highlight the old one.
|
||||
if self.curframe:
|
||||
fileName = self.canonic(self.curframe.f_code.co_filename)
|
||||
lineNo = self.curframe.f_lineno
|
||||
self.shownLineCurrent = fileName, lineNo
|
||||
self.ShowLineState(fileName, lineNo, LINESTATE_CURRENT)
|
||||
|
||||
def _UnshowCurrentLine(self):
|
||||
"Unshow the current line, and forget it"
|
||||
if self.shownLineCurrent is not None:
|
||||
fname, lineno = self.shownLineCurrent
|
||||
self.ResetLineState(fname, lineno, LINESTATE_CURRENT)
|
||||
self.shownLineCurrent = None
|
||||
|
||||
def ShowLineNo( self, filename, lineno ):
|
||||
wasOpen = editor.editorTemplate.FindOpenDocument(filename) is not None
|
||||
if os.path.isfile(filename) and scriptutils.JumpToDocument(filename, lineno):
|
||||
if not wasOpen:
|
||||
doc = editor.editorTemplate.FindOpenDocument(filename)
|
||||
if doc is not None:
|
||||
self.UpdateDocumentLineStates(doc)
|
||||
return 1
|
||||
return 0
|
||||
return 1
|
||||
else:
|
||||
# Can't find the source file - linecache may have it?
|
||||
import linecache
|
||||
line = linecache.getline(filename, lineno)
|
||||
print("%s(%d): %s" % (os.path.basename(filename), lineno, line[:-1].expandtabs(4)))
|
||||
return 0
|
||||
48
Lib/site-packages/pythonwin/pywin/debugger/fail.py
Normal file
48
Lib/site-packages/pythonwin/pywin/debugger/fail.py
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
# NOTE NOTE - This module is designed to fail!
|
||||
#
|
||||
# The ONLY purpose for this script is testing/demoing the
|
||||
# Pythonwin debugger package.
|
||||
|
||||
# It does nothing useful, and it even doesnt do that!
|
||||
|
||||
import pywin.debugger, sys, time
|
||||
import traceback
|
||||
|
||||
def a():
|
||||
a=1
|
||||
try:
|
||||
b()
|
||||
except:
|
||||
# Break into the debugger with the exception information.
|
||||
pywin.debugger.post_mortem(sys.exc_info()[2])
|
||||
a=1
|
||||
a=2
|
||||
a=3
|
||||
a=4
|
||||
pass
|
||||
|
||||
def b():
|
||||
b=1
|
||||
pywin.debugger.set_trace()
|
||||
# After importing or running this module, you are likely to be
|
||||
# sitting at the next line. This is because we explicitely
|
||||
# broke into the debugger using the "set_trace() function
|
||||
# "pywin.debugger.brk()" is a shorter alias for this.
|
||||
c()
|
||||
pass
|
||||
|
||||
def c():
|
||||
c=1
|
||||
d()
|
||||
|
||||
def d():
|
||||
d=1
|
||||
e(d)
|
||||
raise ValueError("Hi")
|
||||
|
||||
def e(arg):
|
||||
e=1
|
||||
time.sleep(1)
|
||||
return e
|
||||
|
||||
a()
|
||||
215
Lib/site-packages/pythonwin/pywin/default.cfg
Normal file
215
Lib/site-packages/pythonwin/pywin/default.cfg
Normal file
|
|
@ -0,0 +1,215 @@
|
|||
# The default keyboard etc configuration file for Pythonwin.
|
||||
#
|
||||
# The format of this file is very similar to a Windows INI file.
|
||||
# Sections are identified with [Section] lines, but comments
|
||||
# use the standatd Python # character. Depending on the section,
|
||||
# lines may not be in the standard "key=value" format.
|
||||
|
||||
# NOTE: You should not need to modify this file.
|
||||
# Simply create a new .CFG file, and add an entry:
|
||||
# [General]
|
||||
# BasedOn = Default
|
||||
#
|
||||
# and add your customisations. Then select your new configuration
|
||||
# from the Pythonwin View/Options/Editor dialog.
|
||||
# This way you get to add your own customisations,
|
||||
# but still take advantage of changes to the default
|
||||
# configuration in new releases.
|
||||
|
||||
# See IDLE.cfg for an example extension configuration.
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
[IDLE Extensions]
|
||||
|
||||
# The list of IDLE extensions to load. The extensions
|
||||
# AutoIndent, AutoFormat and possibly others are
|
||||
# "built-in", so do not need specifying.
|
||||
|
||||
FormatParagraph
|
||||
CallTips
|
||||
|
||||
|
||||
[Keys]
|
||||
|
||||
# The list of _default_ key definitions.
|
||||
# See [Keys:Interactive] and [Keys:Editor] below for further defs.
|
||||
|
||||
#Events of the format <<event-name>>
|
||||
# are events defined in IDLE extensions.
|
||||
|
||||
Alt+Q = <<format-paragraph>>
|
||||
|
||||
Ctrl+W = ViewWhitespace
|
||||
Ctrl+Shift+8 = ViewWhitespace # The MSVC default key def.
|
||||
|
||||
Ctrl+Shift+F = ViewFixedFont
|
||||
|
||||
# Auto-complete, call-tips, etc.
|
||||
Alt+/ = <<expand-word>>
|
||||
Ctrl+Space = <<expand-word>>
|
||||
( = <<paren-open>>
|
||||
) = <<paren-close>>
|
||||
Up = <<check-calltip-cancel>>
|
||||
Down = <<check-calltip-cancel>>
|
||||
Left = <<check-calltip-cancel>>
|
||||
Right = <<check-calltip-cancel>>
|
||||
. = KeyDot
|
||||
|
||||
# Debugger - These are the MSVC default keys, for want of a better choice.
|
||||
F9 = DbgBreakpointToggle
|
||||
F5 = DbgGo
|
||||
Shift+F5 = DbgClose
|
||||
F11 = DbgStep
|
||||
F10 = DbgStepOver
|
||||
Shift+F11 = DbgStepOut
|
||||
|
||||
Ctrl+F3 = AutoFindNext
|
||||
|
||||
|
||||
[Keys:Editor]
|
||||
# Key bindings specific to the editor
|
||||
F2 = GotoNextBookmark
|
||||
Ctrl+F2 = ToggleBookmark
|
||||
Ctrl+G = GotoLine
|
||||
|
||||
Alt+I = ShowInteractiveWindow
|
||||
Alt-B = AddBanner # A sample Event defined in this file.
|
||||
|
||||
# Block operations
|
||||
Alt+3 = <<comment-region>>
|
||||
Shift+Alt+3 = <<uncomment-region>>
|
||||
Alt+4 = <<uncomment-region>> # IDLE default.
|
||||
Alt+5 = <<tabify-region>>
|
||||
Alt+6 = <<untabify-region>>
|
||||
|
||||
# Tabs and other indent features
|
||||
Back = <<smart-backspace>>
|
||||
Ctrl+T = <<toggle-tabs>>
|
||||
Alt+U = <<change-indentwidth>>
|
||||
Enter = EnterKey
|
||||
Tab = TabKey
|
||||
Shift-Tab = <<dedent-region>>
|
||||
|
||||
# Folding
|
||||
Add = FoldExpand
|
||||
Alt+Add = FoldExpandAll
|
||||
Shift+Add = FoldExpandSecondLevel
|
||||
Subtract = FoldCollapse
|
||||
Alt+Subtract = FoldCollapseAll
|
||||
Shift+Subtract = FoldCollapseSecondLevel
|
||||
Multiply = FoldTopLevel
|
||||
|
||||
[Keys:Interactive]
|
||||
# Key bindings specific to the interactive window.
|
||||
# History for the interactive window
|
||||
Ctrl+Up = <<history-previous>>
|
||||
Ctrl+Down = <<history-next>>
|
||||
Enter = ProcessEnter
|
||||
Ctrl+Enter = ProcessEnter
|
||||
Shift+Enter = ProcessEnter
|
||||
Esc = ProcessEsc
|
||||
Alt+I = WindowBack # Toggle back to previous window.
|
||||
Home = InteractiveHome # A sample Event defined in this file.
|
||||
Shift+Home = InteractiveHomeExtend # A sample Event defined in this file.
|
||||
|
||||
# When docked, the Ctrl+Tab and Shift+Ctrl+Tab keys dont work as expected.
|
||||
Ctrl+Tab = MDINext
|
||||
Ctrl+Shift+Tab = MDIPrev
|
||||
|
||||
[Extensions]
|
||||
# Python event handlers specific to this config file.
|
||||
# All functions not starting with an "_" are assumed
|
||||
# to be events, and take 2 params:
|
||||
# * editor_window is the same object passed to IDLE
|
||||
# extensions. editor_window.text is a text widget
|
||||
# that conforms to the Tk text widget interface.
|
||||
# * event is the event being fired. Will always be None
|
||||
# in the current implementation.
|
||||
|
||||
# Simply by defining these functions, they are available as
|
||||
# events.
|
||||
# Note that we bind keystrokes to these events in the various
|
||||
# [Keys] sections.
|
||||
|
||||
# Add a simple file/class/function simple banner
|
||||
def AddBanner(editor_window, event):
|
||||
|
||||
text = editor_window.text
|
||||
big_line = "#" * 70
|
||||
banner = "%s\n## \n## \n## \n%s\n" % (big_line, big_line)
|
||||
|
||||
# Insert at the start of the current line.
|
||||
pos = text.index("insert linestart")
|
||||
|
||||
text.undo_block_start() # Allow action to be undone as a single unit.
|
||||
text.insert(pos, banner)
|
||||
text.undo_block_stop()
|
||||
|
||||
# Now set the insert point to the middle of the banner.
|
||||
line, col = [int(s) for s in pos.split(".")]
|
||||
text.mark_set("insert", "%d.1 lineend" % (line+2, ) )
|
||||
|
||||
|
||||
# Here is a sample event bound to the "Home" key in the
|
||||
# interactive window
|
||||
def InteractiveHome(editor_window, event):
|
||||
return _DoInteractiveHome(editor_window.text, 0)
|
||||
|
||||
def InteractiveHomeExtend(editor_window, event):
|
||||
return _DoInteractiveHome(editor_window.text, 1)
|
||||
|
||||
def _DoInteractiveHome(text, extend):
|
||||
import sys
|
||||
# If Scintilla has an autocomplete window open, then let Scintilla handle it.
|
||||
if text.edit.SCIAutoCActive():
|
||||
return 1
|
||||
of_interest = "insert linestart + %d c" % len(sys.ps1)
|
||||
if not text.compare("insert", "==", of_interest) and \
|
||||
text.get("insert linestart", of_interest) in [sys.ps1, sys.ps2]: # Not sys.ps? line
|
||||
end = of_interest
|
||||
else:
|
||||
end = "insert linestart"
|
||||
|
||||
if extend: start = "insert"
|
||||
else: start = end
|
||||
text.tag_add("sel", start, end)
|
||||
|
||||
# From Niki Spahie
|
||||
def AutoFindNext(editor_window, event):
|
||||
"find selected text or word under cursor"
|
||||
|
||||
from pywin.scintilla import find
|
||||
from pywin.scintilla import scintillacon
|
||||
|
||||
try:
|
||||
sci = editor_window.edit
|
||||
word = sci.GetSelText()
|
||||
if word:
|
||||
find.lastSearch.findText = word
|
||||
find.lastSearch.sel = sci.GetSel()
|
||||
else:
|
||||
pos = sci.SendScintilla( scintillacon.SCI_GETCURRENTPOS )
|
||||
start = sci.SendScintilla( scintillacon.SCI_WORDSTARTPOSITION, pos, 1 )
|
||||
end = sci.SendScintilla( scintillacon.SCI_WORDENDPOSITION, pos, 1 )
|
||||
word = sci.GetTextRange( start, end )
|
||||
if word:
|
||||
find.lastSearch.findText = word
|
||||
find.lastSearch.sel = (start,end)
|
||||
except Exception:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
find.FindNext()
|
||||
|
||||
|
||||
# A couple of generic events.
|
||||
def Beep(editor_window, event):
|
||||
editor_window.text.beep()
|
||||
|
||||
def DoNothing(editor_window, event):
|
||||
pass
|
||||
|
||||
def ContinueEvent(editor_window, event):
|
||||
# Almost an "unbind" - allows Pythonwin/MFC to handle the keystroke
|
||||
return 1
|
||||
|
||||
0
Lib/site-packages/pythonwin/pywin/dialogs/__init__.py
Normal file
0
Lib/site-packages/pythonwin/pywin/dialogs/__init__.py
Normal file
116
Lib/site-packages/pythonwin/pywin/dialogs/ideoptions.py
Normal file
116
Lib/site-packages/pythonwin/pywin/dialogs/ideoptions.py
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
# The property page to define generic IDE options for Pythonwin
|
||||
|
||||
from pywin.mfc import dialog
|
||||
from pywin.framework import interact
|
||||
import win32ui
|
||||
import win32con
|
||||
|
||||
buttonControlMap = {
|
||||
win32ui.IDC_BUTTON1: win32ui.IDC_EDIT1,
|
||||
win32ui.IDC_BUTTON2: win32ui.IDC_EDIT2,
|
||||
win32ui.IDC_BUTTON3: win32ui.IDC_EDIT3,
|
||||
}
|
||||
|
||||
class OptionsPropPage(dialog.PropertyPage):
|
||||
def __init__(self):
|
||||
dialog.PropertyPage.__init__(self, win32ui.IDD_PP_IDE)
|
||||
self.AddDDX(win32ui.IDC_CHECK1, "bShowAtStartup")
|
||||
self.AddDDX(win32ui.IDC_CHECK2, "bDocking")
|
||||
self.AddDDX(win32ui.IDC_EDIT4, 'MRUSize', "i")
|
||||
|
||||
def OnInitDialog(self):
|
||||
|
||||
edit = self.GetDlgItem(win32ui.IDC_EDIT1)
|
||||
format = eval(win32ui.GetProfileVal(interact.sectionProfile, interact.STYLE_INTERACTIVE_PROMPT, str(interact.formatInput)))
|
||||
edit.SetDefaultCharFormat(format)
|
||||
edit.SetWindowText("Input Text")
|
||||
|
||||
edit = self.GetDlgItem(win32ui.IDC_EDIT2)
|
||||
format = eval(win32ui.GetProfileVal(interact.sectionProfile, interact.STYLE_INTERACTIVE_OUTPUT, str(interact.formatOutput)))
|
||||
edit.SetDefaultCharFormat(format)
|
||||
edit.SetWindowText("Output Text")
|
||||
|
||||
edit = self.GetDlgItem(win32ui.IDC_EDIT3)
|
||||
format = eval(win32ui.GetProfileVal(interact.sectionProfile, interact.STYLE_INTERACTIVE_ERROR, str(interact.formatOutputError)))
|
||||
edit.SetDefaultCharFormat(format)
|
||||
edit.SetWindowText("Error Text")
|
||||
|
||||
self['bShowAtStartup'] = interact.LoadPreference("Show at startup", 1)
|
||||
self['bDocking'] = interact.LoadPreference("Docking", 0)
|
||||
self['MRUSize'] = win32ui.GetProfileVal("Settings","Recent File List Size", 10)
|
||||
|
||||
# Hook the button clicks.
|
||||
self.HookCommand(self.HandleCharFormatChange, win32ui.IDC_BUTTON1)
|
||||
self.HookCommand(self.HandleCharFormatChange, win32ui.IDC_BUTTON2)
|
||||
self.HookCommand(self.HandleCharFormatChange, win32ui.IDC_BUTTON3)
|
||||
|
||||
# Ensure the spin control remains in range.
|
||||
spinner = self.GetDlgItem(win32ui.IDC_SPIN1)
|
||||
spinner.SetRange(1, 16)
|
||||
|
||||
return dialog.PropertyPage.OnInitDialog(self)
|
||||
|
||||
# Called to save away the new format tuple for the specified item.
|
||||
def HandleCharFormatChange(self, id, code):
|
||||
if code == win32con.BN_CLICKED:
|
||||
editId = buttonControlMap.get(id)
|
||||
assert editId is not None, "Format button has no associated edit control"
|
||||
editControl = self.GetDlgItem(editId)
|
||||
existingFormat = editControl.GetDefaultCharFormat()
|
||||
flags = win32con.CF_SCREENFONTS
|
||||
d=win32ui.CreateFontDialog(existingFormat, flags, None, self)
|
||||
if d.DoModal()==win32con.IDOK:
|
||||
cf = d.GetCharFormat()
|
||||
editControl.SetDefaultCharFormat(cf)
|
||||
self.SetModified(1)
|
||||
return 0 # We handled this fully!
|
||||
|
||||
def OnOK(self):
|
||||
# Handle the edit controls - get all the fonts, put them back into interact, then
|
||||
# get interact to save its stuff!
|
||||
controlAttrs = [
|
||||
(win32ui.IDC_EDIT1, interact.STYLE_INTERACTIVE_PROMPT),
|
||||
(win32ui.IDC_EDIT2, interact.STYLE_INTERACTIVE_OUTPUT),
|
||||
(win32ui.IDC_EDIT3, interact.STYLE_INTERACTIVE_ERROR)]
|
||||
for id, key in controlAttrs:
|
||||
control = self.GetDlgItem(id)
|
||||
fmt = control.GetDefaultCharFormat()
|
||||
win32ui.WriteProfileVal(interact.sectionProfile, key, str(fmt))
|
||||
|
||||
# Save the other interactive window options.
|
||||
interact.SavePreference("Show at startup", self['bShowAtStartup'])
|
||||
interact.SavePreference("Docking", self['bDocking'])
|
||||
|
||||
# And the other options.
|
||||
win32ui.WriteProfileVal("Settings","Recent File List Size", self['MRUSize'])
|
||||
|
||||
return 1
|
||||
def ChangeFormat(self, fmtAttribute, fmt):
|
||||
dlg = win32ui.CreateFontDialog(fmt)
|
||||
if dlg.DoModal() != win32con.IDOK: return None
|
||||
return dlg.GetCharFormat()
|
||||
|
||||
def OnFormatTitle(self, command, code):
|
||||
fmt = self.GetFormat(interact.formatTitle)
|
||||
if fmt:
|
||||
formatTitle = fmt
|
||||
SaveFontPreferences()
|
||||
|
||||
def OnFormatInput(self, command, code):
|
||||
global formatInput
|
||||
fmt = self.GetFormat(formatInput)
|
||||
if fmt:
|
||||
formatInput = fmt
|
||||
SaveFontPreferences()
|
||||
def OnFormatOutput(self, command, code):
|
||||
global formatOutput
|
||||
fmt = self.GetFormat(formatOutput)
|
||||
if fmt:
|
||||
formatOutput = fmt
|
||||
SaveFontPreferences()
|
||||
def OnFormatError(self, command, code):
|
||||
global formatOutputError
|
||||
fmt = self.GetFormat(formatOutputError)
|
||||
if fmt:
|
||||
formatOutputError = fmt
|
||||
SaveFontPreferences()
|
||||
122
Lib/site-packages/pythonwin/pywin/dialogs/list.py
Normal file
122
Lib/site-packages/pythonwin/pywin/dialogs/list.py
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
from pywin.mfc import dialog
|
||||
import win32ui, win32con, commctrl, win32api
|
||||
|
||||
class ListDialog (dialog.Dialog):
|
||||
|
||||
def __init__ (self, title, list):
|
||||
dialog.Dialog.__init__ (self, self._maketemplate(title))
|
||||
self.HookMessage (self.on_size, win32con.WM_SIZE)
|
||||
self.HookNotify(self.OnListItemChange, commctrl.LVN_ITEMCHANGED)
|
||||
self.HookCommand(self.OnListClick, win32ui.IDC_LIST1)
|
||||
self.items = list
|
||||
|
||||
def _maketemplate(self, title):
|
||||
style = win32con.WS_DLGFRAME | win32con.WS_SYSMENU | win32con.WS_VISIBLE
|
||||
ls = (
|
||||
win32con.WS_CHILD |
|
||||
win32con.WS_VISIBLE |
|
||||
commctrl.LVS_ALIGNLEFT |
|
||||
commctrl.LVS_REPORT
|
||||
)
|
||||
bs = (
|
||||
win32con.WS_CHILD |
|
||||
win32con.WS_VISIBLE
|
||||
)
|
||||
return [ [title, (0, 0, 200, 200), style, None, (8, "MS Sans Serif")],
|
||||
["SysListView32", None, win32ui.IDC_LIST1, (0, 0, 200, 200), ls],
|
||||
[128, "OK", win32con.IDOK, (10, 0, 50, 14), bs | win32con.BS_DEFPUSHBUTTON],
|
||||
[128, "Cancel",win32con.IDCANCEL,(0, 0, 50, 14), bs],
|
||||
]
|
||||
|
||||
def FillList(self):
|
||||
size = self.GetWindowRect()
|
||||
width = size[2] - size[0] - (10)
|
||||
itemDetails = (commctrl.LVCFMT_LEFT, width, "Item", 0)
|
||||
self.itemsControl.InsertColumn(0, itemDetails)
|
||||
index = 0
|
||||
for item in self.items:
|
||||
index = self.itemsControl.InsertItem(index+1, str(item), 0)
|
||||
|
||||
def OnListClick(self, id, code):
|
||||
if code==commctrl.NM_DBLCLK:
|
||||
self.EndDialog(win32con.IDOK)
|
||||
return 1
|
||||
|
||||
def OnListItemChange(self,std, extra):
|
||||
(hwndFrom, idFrom, code), (itemNotify, sub, newState, oldState, change, point, lparam) = std, extra
|
||||
oldSel = (oldState & commctrl.LVIS_SELECTED)!=0
|
||||
newSel = (newState & commctrl.LVIS_SELECTED)!=0
|
||||
if oldSel != newSel:
|
||||
try:
|
||||
self.selecteditem = itemNotify
|
||||
self.butOK.EnableWindow(1)
|
||||
except win32ui.error:
|
||||
self.selecteditem = None
|
||||
|
||||
|
||||
def OnInitDialog (self):
|
||||
rc = dialog.Dialog.OnInitDialog (self)
|
||||
self.itemsControl = self.GetDlgItem(win32ui.IDC_LIST1)
|
||||
self.butOK = self.GetDlgItem(win32con.IDOK)
|
||||
self.butCancel = self.GetDlgItem(win32con.IDCANCEL)
|
||||
|
||||
self.FillList()
|
||||
|
||||
size = self.GetWindowRect()
|
||||
self.LayoutControls(size[2]-size[0], size[3]-size[1])
|
||||
self.butOK.EnableWindow(0) # wait for first selection
|
||||
return rc
|
||||
|
||||
def LayoutControls(self, w, h):
|
||||
self.itemsControl.MoveWindow((0,0,w,h-30))
|
||||
self.butCancel.MoveWindow((10, h-24, 60, h-4))
|
||||
self.butOK.MoveWindow((w-60, h-24, w-10, h-4))
|
||||
|
||||
def on_size (self, params):
|
||||
lparam = params[3]
|
||||
w = win32api.LOWORD(lparam)
|
||||
h = win32api.HIWORD(lparam)
|
||||
self.LayoutControls(w, h)
|
||||
|
||||
class ListsDialog(ListDialog):
|
||||
def __init__(self, title, list, colHeadings = ['Item']):
|
||||
ListDialog.__init__(self, title, list)
|
||||
self.colHeadings = colHeadings
|
||||
|
||||
def FillList(self):
|
||||
index = 0
|
||||
size = self.GetWindowRect()
|
||||
width = size[2] - size[0] - (10) - win32api.GetSystemMetrics(win32con.SM_CXVSCROLL)
|
||||
numCols = len(self.colHeadings)
|
||||
|
||||
for col in self.colHeadings:
|
||||
itemDetails = (commctrl.LVCFMT_LEFT, width/numCols, col, 0)
|
||||
self.itemsControl.InsertColumn(index, itemDetails)
|
||||
index = index + 1
|
||||
index = 0
|
||||
for items in self.items:
|
||||
index = self.itemsControl.InsertItem(index+1, str(items[0]), 0)
|
||||
for itemno in range(1,numCols):
|
||||
item = items[itemno]
|
||||
self.itemsControl.SetItemText(index, itemno, str(item))
|
||||
|
||||
def SelectFromList (title, lst):
|
||||
dlg = ListDialog(title, lst)
|
||||
if dlg.DoModal()==win32con.IDOK:
|
||||
return dlg.selecteditem
|
||||
else:
|
||||
return None
|
||||
|
||||
def SelectFromLists (title, lists, headings):
|
||||
dlg = ListsDialog(title, lists, headings)
|
||||
if dlg.DoModal()==win32con.IDOK:
|
||||
return dlg.selecteditem
|
||||
else:
|
||||
return None
|
||||
|
||||
def test():
|
||||
# print SelectFromList('Single list', [1,2,3])
|
||||
print(SelectFromLists('Multi-List', [ ('1',1, 'a'), ('2',2, 'b'), ('3',3, 'c' )], ['Col 1', 'Col 2']))
|
||||
|
||||
if __name__=='__main__':
|
||||
test()
|
||||
121
Lib/site-packages/pythonwin/pywin/dialogs/login.py
Normal file
121
Lib/site-packages/pythonwin/pywin/dialogs/login.py
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
'''login -- PythonWin user ID and password dialog box
|
||||
|
||||
(Adapted from originally distributed with Mark Hammond's PythonWin -
|
||||
this now replaces it!)
|
||||
|
||||
login.GetLogin() displays a modal "OK/Cancel" dialog box with input
|
||||
fields for a user ID and password. The password field input is masked
|
||||
with *'s. GetLogin takes two optional parameters, a window title, and a
|
||||
default user ID. If these parameters are omitted, the title defaults to
|
||||
"Login", and the user ID is left blank. GetLogin returns a (userid, password)
|
||||
tuple. GetLogin can be called from scripts running on the console - i.e. you
|
||||
don't need to write a full-blown GUI app to use it.
|
||||
|
||||
login.GetPassword() is similar, except there is no username field.
|
||||
|
||||
Example:
|
||||
import pywin.dialogs.login
|
||||
title = "FTP Login"
|
||||
def_user = "fred"
|
||||
userid, password = pywin.dialogs.login.GetLogin(title, def_user)
|
||||
|
||||
Jim Eggleston, 28 August 1996
|
||||
Merged with dlgpass and moved to pywin.dialogs by Mark Hammond Jan 1998.
|
||||
'''
|
||||
|
||||
import win32ui
|
||||
import win32api
|
||||
import win32con
|
||||
from pywin.mfc import dialog
|
||||
|
||||
def MakeLoginDlgTemplate(title):
|
||||
style = win32con.DS_MODALFRAME | win32con.WS_POPUP | win32con.WS_VISIBLE | win32con.WS_CAPTION | win32con.WS_SYSMENU | win32con.DS_SETFONT
|
||||
cs = win32con.WS_CHILD | win32con.WS_VISIBLE
|
||||
|
||||
# Window frame and title
|
||||
dlg = [ [title, (0, 0, 184, 40), style, None, (8, "MS Sans Serif")], ]
|
||||
|
||||
# ID label and text box
|
||||
dlg.append([130, "User ID:", -1, (7, 9, 69, 9), cs | win32con.SS_LEFT])
|
||||
s = cs | win32con.WS_TABSTOP | win32con.WS_BORDER
|
||||
dlg.append(['EDIT', None, win32ui.IDC_EDIT1, (50, 7, 60, 12), s])
|
||||
|
||||
# Password label and text box
|
||||
dlg.append([130, "Password:", -1, (7, 22, 69, 9), cs | win32con.SS_LEFT])
|
||||
s = cs | win32con.WS_TABSTOP | win32con.WS_BORDER
|
||||
dlg.append(['EDIT', None, win32ui.IDC_EDIT2, (50, 20, 60, 12), s | win32con.ES_PASSWORD])
|
||||
|
||||
# OK/Cancel Buttons
|
||||
s = cs | win32con.WS_TABSTOP
|
||||
dlg.append([128, "OK", win32con.IDOK, (124, 5, 50, 14), s | win32con.BS_DEFPUSHBUTTON])
|
||||
s = win32con.BS_PUSHBUTTON | s
|
||||
dlg.append([128, "Cancel", win32con.IDCANCEL, (124, 20, 50, 14), s])
|
||||
return dlg
|
||||
|
||||
def MakePasswordDlgTemplate(title):
|
||||
style = win32con.DS_MODALFRAME | win32con.WS_POPUP | win32con.WS_VISIBLE | win32con.WS_CAPTION | win32con.WS_SYSMENU | win32con.DS_SETFONT
|
||||
cs = win32con.WS_CHILD | win32con.WS_VISIBLE
|
||||
# Window frame and title
|
||||
dlg = [ [title, (0, 0, 177, 45), style, None, (8, "MS Sans Serif")], ]
|
||||
|
||||
# Password label and text box
|
||||
dlg.append([130, "Password:", -1, (7, 7, 69, 9), cs | win32con.SS_LEFT])
|
||||
s = cs | win32con.WS_TABSTOP | win32con.WS_BORDER
|
||||
dlg.append(['EDIT', None, win32ui.IDC_EDIT1, (50, 7, 60, 12), s | win32con.ES_PASSWORD])
|
||||
|
||||
# OK/Cancel Buttons
|
||||
s = cs | win32con.WS_TABSTOP | win32con.BS_PUSHBUTTON
|
||||
dlg.append([128, "OK", win32con.IDOK, (124, 5, 50, 14), s | win32con.BS_DEFPUSHBUTTON])
|
||||
dlg.append([128, "Cancel", win32con.IDCANCEL, (124, 22, 50, 14), s])
|
||||
return dlg
|
||||
|
||||
class LoginDlg(dialog.Dialog):
|
||||
Cancel = 0
|
||||
def __init__(self, title):
|
||||
dialog.Dialog.__init__(self, MakeLoginDlgTemplate(title) )
|
||||
self.AddDDX(win32ui.IDC_EDIT1,'userid')
|
||||
self.AddDDX(win32ui.IDC_EDIT2,'password')
|
||||
|
||||
def GetLogin(title='Login', userid='', password=''):
|
||||
d = LoginDlg(title)
|
||||
d['userid'] = userid
|
||||
d['password'] = password
|
||||
if d.DoModal() != win32con.IDOK:
|
||||
return (None, None)
|
||||
else:
|
||||
return (d['userid'], d['password'])
|
||||
|
||||
class PasswordDlg(dialog.Dialog):
|
||||
def __init__(self, title):
|
||||
dialog.Dialog.__init__(self, MakePasswordDlgTemplate(title) )
|
||||
self.AddDDX(win32ui.IDC_EDIT1,'password')
|
||||
|
||||
def GetPassword(title='Password', password=''):
|
||||
d = PasswordDlg(title)
|
||||
d['password'] = password
|
||||
if d.DoModal()!=win32con.IDOK:
|
||||
return None
|
||||
return d['password']
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
title = 'Login'
|
||||
def_user = ''
|
||||
if len(sys.argv) > 1:
|
||||
title = sys.argv[1]
|
||||
if len(sys.argv) > 2:
|
||||
def_userid = sys.argv[2]
|
||||
userid, password = GetLogin(title, def_user)
|
||||
if userid == password == None:
|
||||
print("User pressed Cancel")
|
||||
else:
|
||||
print("User ID: ", userid)
|
||||
print("Password:", password)
|
||||
newpassword = GetPassword("Reenter just for fun", password)
|
||||
if newpassword is None:
|
||||
print("User cancelled")
|
||||
else:
|
||||
what = ""
|
||||
if newpassword != password:
|
||||
what = "not "
|
||||
print("The passwords did %smatch" % (what))
|
||||
227
Lib/site-packages/pythonwin/pywin/dialogs/status.py
Normal file
227
Lib/site-packages/pythonwin/pywin/dialogs/status.py
Normal file
|
|
@ -0,0 +1,227 @@
|
|||
# No cancel button.
|
||||
|
||||
from pywin.mfc import dialog
|
||||
from pywin.mfc.thread import WinThread
|
||||
import threading
|
||||
import win32ui
|
||||
import win32con
|
||||
import win32api
|
||||
import time
|
||||
|
||||
def MakeProgressDlgTemplate(caption, staticText = ""):
|
||||
style = (win32con.DS_MODALFRAME |
|
||||
win32con.WS_POPUP |
|
||||
win32con.WS_VISIBLE |
|
||||
win32con.WS_CAPTION |
|
||||
win32con.WS_SYSMENU |
|
||||
win32con.DS_SETFONT)
|
||||
cs = (win32con.WS_CHILD |
|
||||
win32con.WS_VISIBLE)
|
||||
|
||||
w = 215
|
||||
h = 36 # With button
|
||||
h = 40
|
||||
|
||||
dlg = [[caption,
|
||||
(0, 0, w, h),
|
||||
style,
|
||||
None,
|
||||
(8, "MS Sans Serif")],
|
||||
]
|
||||
|
||||
s = win32con.WS_TABSTOP | cs
|
||||
|
||||
dlg.append([130, staticText, 1000, (7, 7, w-7, h-32), cs | win32con.SS_LEFT])
|
||||
|
||||
# dlg.append([128,
|
||||
# "Cancel",
|
||||
# win32con.IDCANCEL,
|
||||
# (w - 60, h - 18, 50, 14), s | win32con.BS_PUSHBUTTON])
|
||||
|
||||
return dlg
|
||||
|
||||
class CStatusProgressDialog(dialog.Dialog):
|
||||
def __init__(self, title, msg = "", maxticks = 100, tickincr = 1):
|
||||
self.initMsg = msg
|
||||
templ = MakeProgressDlgTemplate(title, msg)
|
||||
dialog.Dialog.__init__(self, templ)
|
||||
self.maxticks = maxticks
|
||||
self.tickincr = tickincr
|
||||
self.pbar = None
|
||||
|
||||
def OnInitDialog(self):
|
||||
rc = dialog.Dialog.OnInitDialog(self)
|
||||
self.static = self.GetDlgItem(1000)
|
||||
self.pbar = win32ui.CreateProgressCtrl()
|
||||
self.pbar.CreateWindow (win32con.WS_CHILD |
|
||||
win32con.WS_VISIBLE,
|
||||
(10, 30, 310, 44),
|
||||
self, 1001)
|
||||
self.pbar.SetRange(0, self.maxticks)
|
||||
self.pbar.SetStep(self.tickincr)
|
||||
self.progress = 0
|
||||
self.pincr = 5
|
||||
return rc
|
||||
|
||||
def Close(self):
|
||||
self.EndDialog(0)
|
||||
|
||||
def SetMaxTicks(self, maxticks):
|
||||
if self.pbar is not None:
|
||||
self.pbar.SetRange(0, maxticks)
|
||||
|
||||
def Tick(self):
|
||||
if self.pbar is not None:
|
||||
self.pbar.StepIt()
|
||||
|
||||
def SetTitle(self, text):
|
||||
self.SetWindowText(text)
|
||||
|
||||
def SetText(self, text):
|
||||
self.SetDlgItemText(1000, text)
|
||||
|
||||
def Set(self, pos, max = None):
|
||||
if self.pbar is not None:
|
||||
self.pbar.SetPos(pos)
|
||||
if max is not None:
|
||||
self.pbar.SetRange(0, max)
|
||||
|
||||
# a progress dialog created in a new thread - especially suitable for
|
||||
# console apps with no message loop.
|
||||
MYWM_SETTITLE = win32con.WM_USER+10
|
||||
MYWM_SETMSG = win32con.WM_USER+11
|
||||
MYWM_TICK = win32con.WM_USER+12
|
||||
MYWM_SETMAXTICKS = win32con.WM_USER+13
|
||||
MYWM_SET = win32con.WM_USER+14
|
||||
|
||||
class CThreadedStatusProcessDialog(CStatusProgressDialog):
|
||||
def __init__(self, title, msg = "", maxticks = 100, tickincr = 1):
|
||||
self.title = title
|
||||
self.msg = msg
|
||||
self.threadid = win32api.GetCurrentThreadId()
|
||||
CStatusProgressDialog.__init__(self, title, msg, maxticks, tickincr)
|
||||
|
||||
def OnInitDialog(self):
|
||||
rc = CStatusProgressDialog.OnInitDialog(self)
|
||||
self.HookMessage(self.OnTitle, MYWM_SETTITLE)
|
||||
self.HookMessage(self.OnMsg, MYWM_SETMSG)
|
||||
self.HookMessage(self.OnTick, MYWM_TICK)
|
||||
self.HookMessage(self.OnMaxTicks, MYWM_SETMAXTICKS)
|
||||
self.HookMessage(self.OnSet, MYWM_SET)
|
||||
return rc
|
||||
|
||||
def _Send(self, msg):
|
||||
try:
|
||||
self.PostMessage(msg)
|
||||
except win32ui.error:
|
||||
# the user closed the window - but this does not cancel the
|
||||
# process - so just ignore it.
|
||||
pass
|
||||
|
||||
def OnTitle(self, msg):
|
||||
CStatusProgressDialog.SetTitle(self, self.title)
|
||||
|
||||
def OnMsg(self, msg):
|
||||
CStatusProgressDialog.SetText(self, self.msg)
|
||||
|
||||
def OnTick(self, msg):
|
||||
CStatusProgressDialog.Tick(self)
|
||||
|
||||
def OnMaxTicks(self, msg):
|
||||
CStatusProgressDialog.SetMaxTicks(self, self.maxticks)
|
||||
|
||||
def OnSet(self, msg):
|
||||
CStatusProgressDialog.Set(self, self.pos, self.max)
|
||||
|
||||
def Close(self):
|
||||
assert self.threadid, "No thread!"
|
||||
win32api.PostThreadMessage(self.threadid, win32con.WM_QUIT, 0, 0)
|
||||
|
||||
def SetMaxTicks(self, maxticks):
|
||||
self.maxticks = maxticks
|
||||
self._Send(MYWM_SETMAXTICKS)
|
||||
def SetTitle(self, title):
|
||||
self.title = title
|
||||
self._Send(MYWM_SETTITLE)
|
||||
def SetText(self, text):
|
||||
self.msg = text
|
||||
self._Send(MYWM_SETMSG)
|
||||
def Tick(self):
|
||||
self._Send(MYWM_TICK)
|
||||
def Set(self, pos, max = None):
|
||||
self.pos = pos
|
||||
self.max = max
|
||||
self._Send(MYWM_SET)
|
||||
|
||||
class ProgressThread(WinThread):
|
||||
def __init__(self, title, msg = "", maxticks = 100, tickincr = 1):
|
||||
self.title = title
|
||||
self.msg = msg
|
||||
self.maxticks = maxticks
|
||||
self.tickincr = tickincr
|
||||
self.dialog = None
|
||||
WinThread.__init__(self)
|
||||
self.createdEvent = threading.Event()
|
||||
|
||||
def InitInstance(self):
|
||||
self.dialog = CThreadedStatusProcessDialog( self.title, self.msg, self.maxticks, self.tickincr)
|
||||
self.dialog.CreateWindow()
|
||||
try:
|
||||
self.dialog.SetForegroundWindow()
|
||||
except win32ui.error:
|
||||
pass
|
||||
self.createdEvent.set()
|
||||
return WinThread.InitInstance(self)
|
||||
|
||||
def ExitInstance(self):
|
||||
return 0
|
||||
|
||||
|
||||
def StatusProgressDialog(title, msg = "", maxticks = 100, parent = None):
|
||||
d = CStatusProgressDialog (title, msg, maxticks)
|
||||
d.CreateWindow (parent)
|
||||
return d
|
||||
|
||||
def ThreadedStatusProgressDialog(title, msg = "", maxticks = 100):
|
||||
t = ProgressThread(title, msg, maxticks)
|
||||
t.CreateThread()
|
||||
# Need to run a basic "PumpWaitingMessages" loop just incase we are
|
||||
# running inside Pythonwin.
|
||||
# Basic timeout incase things go terribly wrong. Ideally we should use
|
||||
# win32event.MsgWaitForMultipleObjects(), but we use a threading module
|
||||
# event - so use a dumb strategy
|
||||
end_time = time.time() + 10
|
||||
while time.time() < end_time:
|
||||
if t.createdEvent.isSet():
|
||||
break
|
||||
win32ui.PumpWaitingMessages()
|
||||
time.sleep(0.1)
|
||||
return t.dialog
|
||||
|
||||
def demo():
|
||||
d = StatusProgressDialog("A Demo", "Doing something...")
|
||||
import win32api
|
||||
for i in range(100):
|
||||
if i == 50:
|
||||
d.SetText("Getting there...")
|
||||
if i==90:
|
||||
d.SetText("Nearly done...")
|
||||
win32api.Sleep(20)
|
||||
d.Tick()
|
||||
d.Close()
|
||||
|
||||
def thread_demo():
|
||||
d = ThreadedStatusProgressDialog("A threaded demo", "Doing something")
|
||||
import win32api
|
||||
for i in range(100):
|
||||
if i == 50:
|
||||
d.SetText("Getting there...")
|
||||
if i==90:
|
||||
d.SetText("Nearly done...")
|
||||
win32api.Sleep(20)
|
||||
d.Tick()
|
||||
d.Close()
|
||||
|
||||
if __name__=='__main__':
|
||||
thread_demo()
|
||||
#demo()
|
||||
541
Lib/site-packages/pythonwin/pywin/docking/DockingBar.py
Normal file
541
Lib/site-packages/pythonwin/pywin/docking/DockingBar.py
Normal file
|
|
@ -0,0 +1,541 @@
|
|||
# DockingBar.py
|
||||
|
||||
# Ported directly (comments and all) from the samples at www.codeguru.com
|
||||
|
||||
# WARNING: Use at your own risk, as this interface is highly likely to change.
|
||||
# Currently we support only one child per DockingBar. Later we need to add
|
||||
# support for multiple children.
|
||||
|
||||
import win32api, win32con, win32ui
|
||||
from pywin.mfc import afxres, window
|
||||
import struct
|
||||
|
||||
clrBtnHilight = win32api.GetSysColor(win32con.COLOR_BTNHILIGHT)
|
||||
clrBtnShadow = win32api.GetSysColor(win32con.COLOR_BTNSHADOW)
|
||||
|
||||
def CenterPoint(rect):
|
||||
width = rect[2]-rect[0]
|
||||
height = rect[3]-rect[1]
|
||||
return rect[0] + width//2, rect[1] + height//2
|
||||
|
||||
def OffsetRect(rect, point):
|
||||
(x, y) = point
|
||||
return rect[0]+x, rect[1]+y, rect[2]+x, rect[3]+y
|
||||
|
||||
def DeflateRect(rect, point):
|
||||
(x, y) = point
|
||||
return rect[0]+x, rect[1]+y, rect[2]-x, rect[3]-y
|
||||
|
||||
def PtInRect(rect, pt):
|
||||
return rect[0] <= pt[0] < rect[2] and rect[1] <= pt[1] < rect[3]
|
||||
|
||||
class DockingBar(window.Wnd):
|
||||
def __init__(self, obj=None):
|
||||
if obj is None:
|
||||
obj = win32ui.CreateControlBar()
|
||||
window.Wnd.__init__(self, obj)
|
||||
self.dialog = None
|
||||
self.nDockBarID = 0
|
||||
self.sizeMin = 32, 32
|
||||
self.sizeHorz = 200, 200
|
||||
self.sizeVert = 200, 200
|
||||
self.sizeFloat = 200, 200
|
||||
self.bTracking = 0
|
||||
self.bInRecalcNC = 0
|
||||
self.cxEdge = 6
|
||||
self.cxBorder = 3
|
||||
self.cxGripper = 20
|
||||
self.brushBkgd = win32ui.CreateBrush()
|
||||
self.brushBkgd.CreateSolidBrush(win32api.GetSysColor(win32con.COLOR_BTNFACE))
|
||||
|
||||
# Support for diagonal resizing
|
||||
self.cyBorder = 3
|
||||
self.cCaptionSize = win32api.GetSystemMetrics(win32con.SM_CYSMCAPTION)
|
||||
self.cMinWidth = win32api.GetSystemMetrics(win32con.SM_CXMIN)
|
||||
self.cMinHeight = win32api.GetSystemMetrics(win32con.SM_CYMIN)
|
||||
self.rectUndock = (0,0,0,0)
|
||||
|
||||
def OnUpdateCmdUI(self, target, bDisableIfNoHndler):
|
||||
return self.UpdateDialogControls(target, bDisableIfNoHndler)
|
||||
|
||||
def CreateWindow(self, parent, childCreator, title, id, style=win32con.WS_CHILD | win32con.WS_VISIBLE | afxres.CBRS_LEFT, childCreatorArgs=()):
|
||||
assert not ((style & afxres.CBRS_SIZE_FIXED) and (style & afxres.CBRS_SIZE_DYNAMIC)), "Invalid style"
|
||||
self.rectClose = self.rectBorder = self.rectGripper = self.rectTracker = 0,0,0,0
|
||||
|
||||
# save the style
|
||||
self._obj_.dwStyle = style & afxres.CBRS_ALL
|
||||
|
||||
cursor = win32api.LoadCursor(0, win32con.IDC_ARROW)
|
||||
wndClass = win32ui.RegisterWndClass(win32con.CS_DBLCLKS, cursor, self.brushBkgd.GetSafeHandle(), 0)
|
||||
|
||||
self._obj_.CreateWindow(wndClass, title, style, (0,0,0,0), parent, id)
|
||||
|
||||
# Create the child dialog
|
||||
self.dialog = childCreator(*(self,) + childCreatorArgs)
|
||||
|
||||
# use the dialog dimensions as default base dimensions
|
||||
assert self.dialog.IsWindow(), "The childCreator function %s did not create a window!" % childCreator
|
||||
rect = self.dialog.GetWindowRect()
|
||||
self.sizeHorz = self.sizeVert = self.sizeFloat = rect[2]-rect[0], rect[3]-rect[1]
|
||||
|
||||
self.sizeHorz = self.sizeHorz[0], self.sizeHorz[1] + self.cxEdge + self.cxBorder
|
||||
self.sizeVert = self.sizeVert[0] + self.cxEdge + self.cxBorder, self.sizeVert[1]
|
||||
self.HookMessages()
|
||||
|
||||
def CalcFixedLayout(self, bStretch, bHorz):
|
||||
rectTop = self.dockSite.GetControlBar(afxres.AFX_IDW_DOCKBAR_TOP).GetWindowRect()
|
||||
rectLeft = self.dockSite.GetControlBar(afxres.AFX_IDW_DOCKBAR_LEFT).GetWindowRect()
|
||||
if bStretch:
|
||||
nHorzDockBarWidth = 32767
|
||||
nVertDockBarHeight = 32767
|
||||
else:
|
||||
nHorzDockBarWidth = rectTop[2]-rectTop[0] + 4
|
||||
nVertDockBarHeight = rectLeft[3]-rectLeft[1] + 4
|
||||
|
||||
if self.IsFloating():
|
||||
return self.sizeFloat
|
||||
if bHorz:
|
||||
return nHorzDockBarWidth, self.sizeHorz[1]
|
||||
return self.sizeVert[0], nVertDockBarHeight
|
||||
|
||||
def CalcDynamicLayout(self, length, mode):
|
||||
# Support for diagonal sizing.
|
||||
if self.IsFloating():
|
||||
self.GetParent().GetParent().ModifyStyle(win32ui.MFS_4THICKFRAME, 0)
|
||||
if mode & (win32ui.LM_HORZDOCK | win32ui.LM_VERTDOCK):
|
||||
flags = win32con.SWP_NOSIZE | win32con.SWP_NOMOVE | win32con.SWP_NOZORDER |\
|
||||
win32con.SWP_NOACTIVATE | win32con.SWP_FRAMECHANGED
|
||||
self.SetWindowPos(0, (0, 0, 0, 0,), flags)
|
||||
self.dockSite.RecalcLayout()
|
||||
return self._obj_.CalcDynamicLayout(length, mode)
|
||||
|
||||
if mode & win32ui.LM_MRUWIDTH:
|
||||
return self.sizeFloat
|
||||
if mode & win32ui.LM_COMMIT:
|
||||
self.sizeFloat = length, self.sizeFloat[1]
|
||||
return self.sizeFloat
|
||||
# More diagonal sizing.
|
||||
if self.IsFloating():
|
||||
dc = self.dockContext
|
||||
pt = win32api.GetCursorPos()
|
||||
windowRect = self.GetParent().GetParent().GetWindowRect()
|
||||
|
||||
hittest = dc.nHitTest
|
||||
if hittest==win32con.HTTOPLEFT:
|
||||
cx = max(windowRect[2] - pt[0], self.cMinWidth) - self.cxBorder
|
||||
cy = max(windowRect[3] - self.cCaptionSize - pt[1],self.cMinHeight) - 1
|
||||
self.sizeFloat = cx, cy
|
||||
|
||||
top = min(pt[1], windowRect[3] - self.cCaptionSize - self.cMinHeight) - self.cyBorder
|
||||
left = min(pt[0], windowRect[2] - self.cMinWidth) - 1
|
||||
dc.rectFrameDragHorz = left, top, dc.rectFrameDragHorz[2], dc.rectFrameDragHorz[3]
|
||||
return self.sizeFloat
|
||||
if hittest==win32con.HTTOPRIGHT:
|
||||
cx = max(pt[0] - windowRect[0], self.cMinWidth)
|
||||
cy = max(windowRect[3] - self.cCaptionSize - pt[1], self.cMinHeight) - 1
|
||||
self.sizeFloat = cx, cy
|
||||
|
||||
top = min(pt[1], windowRect[3] - self.cCaptionSize - self.cMinHeight) - self.cyBorder
|
||||
dc.rectFrameDragHorz = dc.rectFrameDragHorz[0], top, dc.rectFrameDragHorz[2], dc.rectFrameDragHorz[3]
|
||||
return self.sizeFloat
|
||||
|
||||
if hittest==win32con.HTBOTTOMLEFT:
|
||||
cx = max(windowRect[2] - pt[0], self.cMinWidth) - self.cxBorder
|
||||
cy = max(pt[1] - windowRect[1] - self.cCaptionSize, self.cMinHeight)
|
||||
self.sizeFloat = cx, cy
|
||||
|
||||
left = min(pt[0], windowRect[2] -self.cMinWidth) - 1
|
||||
dc.rectFrameDragHorz = left, dc.rectFrameDragHorz[1], dc.rectFrameDragHorz[2], dc.rectFrameDragHorz[3]
|
||||
return self.sizeFloat
|
||||
|
||||
if hittest==win32con.HTBOTTOMRIGHT:
|
||||
cx = max(pt[0] - windowRect[0], self.cMinWidth)
|
||||
cy = max(pt[1] - windowRect[1] - self.cCaptionSize, self.cMinHeight)
|
||||
self.sizeFloat = cx, cy
|
||||
return self.sizeFloat
|
||||
|
||||
if mode & win32ui.LM_LENGTHY:
|
||||
self.sizeFloat = self.sizeFloat[0], max(self.sizeMin[1], length)
|
||||
return self.sizeFloat
|
||||
else:
|
||||
return max(self.sizeMin[0], length), self.sizeFloat[1]
|
||||
|
||||
def OnWindowPosChanged(self, msg):
|
||||
if self.GetSafeHwnd()==0 or self.dialog is None:
|
||||
return 0
|
||||
lparam = msg[3]
|
||||
""" LPARAM used with WM_WINDOWPOSCHANGED:
|
||||
typedef struct {
|
||||
HWND hwnd;
|
||||
HWND hwndInsertAfter;
|
||||
int x;
|
||||
int y;
|
||||
int cx;
|
||||
int cy;
|
||||
UINT flags;} WINDOWPOS;
|
||||
"""
|
||||
format = "PPiiiii"
|
||||
bytes = win32ui.GetBytes( lparam, struct.calcsize(format) )
|
||||
hwnd, hwndAfter, x, y, cx, cy, flags = struct.unpack(format, bytes)
|
||||
|
||||
if self.bInRecalcNC:
|
||||
rc = self.GetClientRect()
|
||||
self.dialog.MoveWindow(rc)
|
||||
return 0
|
||||
# Find on which side are we docked
|
||||
nDockBarID = self.GetParent().GetDlgCtrlID()
|
||||
# Return if dropped at same location
|
||||
# no docking side change and no size change
|
||||
if (nDockBarID == self.nDockBarID) and \
|
||||
(flags & win32con.SWP_NOSIZE) and \
|
||||
((self._obj_.dwStyle & afxres.CBRS_BORDER_ANY) != afxres.CBRS_BORDER_ANY):
|
||||
return
|
||||
self.nDockBarID = nDockBarID
|
||||
|
||||
# Force recalc the non-client area
|
||||
self.bInRecalcNC = 1
|
||||
try:
|
||||
swpflags = win32con.SWP_NOSIZE | win32con.SWP_NOMOVE | win32con.SWP_NOZORDER | win32con.SWP_FRAMECHANGED
|
||||
self.SetWindowPos(0, (0,0,0,0), swpflags)
|
||||
finally:
|
||||
self.bInRecalcNC = 0
|
||||
return 0
|
||||
|
||||
# This is a virtual and not a message hook.
|
||||
def OnSetCursor(self, window, nHitTest, wMouseMsg):
|
||||
if nHitTest != win32con.HTSIZE or self.bTracking:
|
||||
return self._obj_.OnSetCursor(window, nHitTest, wMouseMsg)
|
||||
|
||||
if self.IsHorz():
|
||||
win32api.SetCursor(win32api.LoadCursor(0, win32con.IDC_SIZENS))
|
||||
else:
|
||||
win32api.SetCursor(win32api.LoadCursor(0, win32con.IDC_SIZEWE))
|
||||
return 1
|
||||
|
||||
# Mouse Handling
|
||||
def OnLButtonUp(self, msg):
|
||||
if not self.bTracking:
|
||||
return 1 # pass it on.
|
||||
self.StopTracking(1)
|
||||
return 0 # Dont pass on
|
||||
|
||||
def OnLButtonDown(self, msg):
|
||||
# UINT nFlags, CPoint point)
|
||||
# only start dragging if clicked in "void" space
|
||||
if self.dockBar is not None:
|
||||
# start the drag
|
||||
pt = msg[5]
|
||||
pt = self.ClientToScreen(pt)
|
||||
self.dockContext.StartDrag(pt)
|
||||
return 0
|
||||
return 1
|
||||
|
||||
def OnNcLButtonDown(self, msg):
|
||||
if self.bTracking: return 0
|
||||
nHitTest = wparam = msg[2]
|
||||
pt = msg[5]
|
||||
|
||||
if nHitTest==win32con.HTSYSMENU and not self.IsFloating():
|
||||
self.GetDockingFrame().ShowControlBar(self, 0, 0)
|
||||
elif nHitTest == win32con.HTMINBUTTON and not self.IsFloating():
|
||||
self.dockContext.ToggleDocking()
|
||||
elif nHitTest == win32con.HTCAPTION and not self.IsFloating() and self.dockBar is not None:
|
||||
self.dockContext.StartDrag(pt)
|
||||
elif nHitTest == win32con.HTSIZE and not self.IsFloating():
|
||||
self.StartTracking()
|
||||
else:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def OnLButtonDblClk(self, msg):
|
||||
# only toggle docking if clicked in "void" space
|
||||
if self.dockBar is not None:
|
||||
# toggle docking
|
||||
self.dockContext.ToggleDocking()
|
||||
return 0
|
||||
return 1
|
||||
|
||||
def OnNcLButtonDblClk(self, msg):
|
||||
nHitTest = wparam = msg[2]
|
||||
# UINT nHitTest, CPoint point)
|
||||
if self.dockBar is not None and nHitTest == win32con.HTCAPTION:
|
||||
# toggle docking
|
||||
self.dockContext.ToggleDocking()
|
||||
return 0
|
||||
return 1
|
||||
|
||||
def OnMouseMove(self, msg):
|
||||
flags = wparam = msg[2]
|
||||
lparam = msg[3]
|
||||
if self.IsFloating() or not self.bTracking:
|
||||
return 1
|
||||
|
||||
# Convert unsigned 16 bit to signed 32 bit.
|
||||
x=win32api.LOWORD(lparam)
|
||||
if x & 32768: x = x | -65536
|
||||
y = win32api.HIWORD(lparam)
|
||||
if y & 32768: y = y | -65536
|
||||
pt = x, y
|
||||
cpt = CenterPoint(self.rectTracker)
|
||||
pt = self.ClientToWnd(pt)
|
||||
if self.IsHorz():
|
||||
if cpt[1] != pt[1]:
|
||||
self.OnInvertTracker(self.rectTracker)
|
||||
self.rectTracker = OffsetRect(self.rectTracker, (0, pt[1] - cpt[1]))
|
||||
self.OnInvertTracker(self.rectTracker)
|
||||
else:
|
||||
if cpt[0] != pt[0]:
|
||||
self.OnInvertTracker(self.rectTracker)
|
||||
self.rectTracker = OffsetRect(self.rectTracker, (pt[0]-cpt[0], 0))
|
||||
self.OnInvertTracker(self.rectTracker)
|
||||
|
||||
return 0 # Dont pass it on.
|
||||
|
||||
# def OnBarStyleChange(self, old, new):
|
||||
|
||||
def OnNcCalcSize(self, bCalcValid, size_info):
|
||||
(rc0, rc1, rc2, pos) = size_info
|
||||
self.rectBorder = self.GetWindowRect()
|
||||
self.rectBorder = OffsetRect( self.rectBorder, (-self.rectBorder[0], -self.rectBorder[1]) )
|
||||
|
||||
dwBorderStyle = self._obj_.dwStyle | afxres.CBRS_BORDER_ANY
|
||||
|
||||
if self.nDockBarID==afxres.AFX_IDW_DOCKBAR_TOP:
|
||||
dwBorderStyle = dwBorderStyle & ~afxres.CBRS_BORDER_BOTTOM;
|
||||
rc0.left = rc0.left + self.cxGripper
|
||||
rc0.bottom = rc0.bottom-self.cxEdge
|
||||
rc0.top = rc0.top + self.cxBorder
|
||||
rc0.right = rc0.right - self.cxBorder
|
||||
self.rectBorder = self.rectBorder[0], self.rectBorder[3]-self.cxEdge, self.rectBorder[2], self.rectBorder[3]
|
||||
elif self.nDockBarID==afxres.AFX_IDW_DOCKBAR_BOTTOM:
|
||||
dwBorderStyle = dwBorderStyle & ~afxres.CBRS_BORDER_TOP
|
||||
rc0.left = rc0.left + self.cxGripper
|
||||
rc0.top = rc0.top + self.cxEdge
|
||||
rc0.bottom = rc0.bottom - self.cxBorder
|
||||
rc0.right = rc0.right - self.cxBorder
|
||||
self.rectBorder = self.rectBorder[0], self.rectBorder[1], self.rectBorder[2], self.rectBorder[1]+self.cxEdge
|
||||
elif self.nDockBarID==afxres.AFX_IDW_DOCKBAR_LEFT:
|
||||
dwBorderStyle = dwBorderStyle & ~afxres.CBRS_BORDER_RIGHT
|
||||
rc0.right = rc0.right - self.cxEdge
|
||||
rc0.left = rc0.left + self.cxBorder
|
||||
rc0.bottom = rc0.bottom - self.cxBorder
|
||||
rc0.top = rc0.top + self.cxGripper
|
||||
self.rectBorder = self.rectBorder[2] - self.cxEdge, self.rectBorder[1], self.rectBorder[2], self.rectBorder[3]
|
||||
elif self.nDockBarID==afxres.AFX_IDW_DOCKBAR_RIGHT:
|
||||
dwBorderStyle = dwBorderStyle & ~afxres.CBRS_BORDER_LEFT
|
||||
rc0.left = rc0.left + self.cxEdge
|
||||
rc0.right = rc0.right - self.cxBorder
|
||||
rc0.bottom = rc0.bottom - self.cxBorder
|
||||
rc0.top = rc0.top + self.cxGripper
|
||||
self.rectBorder = self.rectBorder[0], self.rectBorder[1], self.rectBorder[0]+self.cxEdge, self.rectBorder[3]
|
||||
else:
|
||||
self.rectBorder = 0,0,0,0
|
||||
|
||||
self.SetBarStyle(dwBorderStyle)
|
||||
return 0
|
||||
|
||||
def OnNcPaint(self, msg):
|
||||
self.EraseNonClient()
|
||||
dc = self.GetWindowDC()
|
||||
ctl = win32api.GetSysColor(win32con.COLOR_BTNHIGHLIGHT)
|
||||
cbr = win32api.GetSysColor(win32con.COLOR_BTNSHADOW)
|
||||
dc.Draw3dRect(self.rectBorder, ctl, cbr)
|
||||
|
||||
self.DrawGripper(dc)
|
||||
|
||||
rect = self.GetClientRect()
|
||||
self.InvalidateRect( rect, 1)
|
||||
return 0
|
||||
|
||||
def OnNcHitTest(self, pt): # A virtual, not a hooked message.
|
||||
if self.IsFloating():
|
||||
return 1
|
||||
|
||||
ptOrig = pt
|
||||
rect = self.GetWindowRect()
|
||||
pt = pt[0] - rect[0], pt[1] - rect[1]
|
||||
|
||||
if PtInRect(self.rectClose, pt):
|
||||
return win32con.HTSYSMENU
|
||||
elif PtInRect(self.rectUndock, pt):
|
||||
return win32con.HTMINBUTTON
|
||||
elif PtInRect(self.rectGripper, pt):
|
||||
return win32con.HTCAPTION
|
||||
elif PtInRect(self.rectBorder, pt):
|
||||
return win32con.HTSIZE
|
||||
else:
|
||||
return self._obj_.OnNcHitTest(ptOrig)
|
||||
|
||||
def StartTracking(self):
|
||||
self.SetCapture()
|
||||
|
||||
# make sure no updates are pending
|
||||
self.RedrawWindow(None, None, win32con.RDW_ALLCHILDREN | win32con.RDW_UPDATENOW)
|
||||
self.dockSite.LockWindowUpdate()
|
||||
|
||||
self.ptOld = CenterPoint(self.rectBorder)
|
||||
self.bTracking = 1
|
||||
|
||||
self.rectTracker = self.rectBorder;
|
||||
if not self.IsHorz():
|
||||
l, t, r, b = self.rectTracker
|
||||
b = b - 4
|
||||
self.rectTracker = l, t, r, b
|
||||
|
||||
self.OnInvertTracker(self.rectTracker);
|
||||
|
||||
def OnCaptureChanged(self, msg):
|
||||
hwnd = lparam = msg[3]
|
||||
if self.bTracking and hwnd != self.GetSafeHwnd():
|
||||
self.StopTracking(0) # cancel tracking
|
||||
return 1
|
||||
|
||||
def StopTracking(self, bAccept):
|
||||
self.OnInvertTracker(self.rectTracker)
|
||||
self.dockSite.UnlockWindowUpdate()
|
||||
self.bTracking = 0
|
||||
self.ReleaseCapture()
|
||||
if not bAccept: return
|
||||
|
||||
rcc = self.dockSite.GetWindowRect()
|
||||
if self.IsHorz():
|
||||
newsize = self.sizeHorz[1]
|
||||
maxsize = newsize + (rcc[3]-rcc[1])
|
||||
minsize = self.sizeMin[1]
|
||||
else:
|
||||
newsize = self.sizeVert[0]
|
||||
maxsize = newsize + (rcc[2]-rcc[0])
|
||||
minsize = self.sizeMin[0]
|
||||
|
||||
pt = CenterPoint(self.rectTracker)
|
||||
if self.nDockBarID== afxres.AFX_IDW_DOCKBAR_TOP:
|
||||
newsize = newsize + (pt[1] - self.ptOld[1])
|
||||
elif self.nDockBarID== afxres.AFX_IDW_DOCKBAR_BOTTOM:
|
||||
newsize = newsize + (- pt[1] + self.ptOld[1])
|
||||
elif self.nDockBarID== afxres.AFX_IDW_DOCKBAR_LEFT:
|
||||
newsize = newsize + (pt[0] - self.ptOld[0])
|
||||
elif self.nDockBarID== afxres.AFX_IDW_DOCKBAR_RIGHT:
|
||||
newsize = newsize + (- pt[0] + self.ptOld[0])
|
||||
newsize = max(minsize, min(maxsize, newsize))
|
||||
if self.IsHorz():
|
||||
self.sizeHorz = self.sizeHorz[0], newsize
|
||||
else:
|
||||
self.sizeVert = newsize, self.sizeVert[1]
|
||||
self.dockSite.RecalcLayout()
|
||||
return 0
|
||||
|
||||
def OnInvertTracker(self, rect):
|
||||
assert rect[2]-rect[0]>0 and rect[3]-rect[1]>0, "rect is empty"
|
||||
assert self.bTracking
|
||||
rcc = self.GetWindowRect()
|
||||
rcf = self.dockSite.GetWindowRect()
|
||||
|
||||
rect = OffsetRect(rect, (rcc[0] - rcf[0], rcc[1] - rcf[1]))
|
||||
rect = DeflateRect(rect, (1, 1));
|
||||
|
||||
flags = win32con.DCX_WINDOW|win32con.DCX_CACHE|win32con.DCX_LOCKWINDOWUPDATE
|
||||
dc = self.dockSite.GetDCEx(None, flags)
|
||||
try:
|
||||
brush = win32ui.GetHalftoneBrush()
|
||||
oldBrush = dc.SelectObject(brush)
|
||||
|
||||
dc.PatBlt((rect[0], rect[1]), (rect[2]-rect[0], rect[3]-rect[1]), win32con.PATINVERT)
|
||||
dc.SelectObject(oldBrush)
|
||||
finally:
|
||||
self.dockSite.ReleaseDC(dc)
|
||||
|
||||
def IsHorz(self):
|
||||
return self.nDockBarID == afxres.AFX_IDW_DOCKBAR_TOP or \
|
||||
self.nDockBarID == afxres.AFX_IDW_DOCKBAR_BOTTOM
|
||||
|
||||
def ClientToWnd(self, pt):
|
||||
x, y=pt
|
||||
if self.nDockBarID == afxres.AFX_IDW_DOCKBAR_BOTTOM:
|
||||
y = y + self.cxEdge
|
||||
elif self.nDockBarID == afxres.AFX_IDW_DOCKBAR_RIGHT:
|
||||
x = x + self.cxEdge
|
||||
return x,y
|
||||
|
||||
def DrawGripper(self, dc):
|
||||
# no gripper if floating
|
||||
if self._obj_.dwStyle & afxres.CBRS_FLOATING:
|
||||
return
|
||||
|
||||
# -==HACK==-
|
||||
# in order to calculate the client area properly after docking,
|
||||
# the client area must be recalculated twice (I have no idea why)
|
||||
self.dockSite.RecalcLayout()
|
||||
# -==END HACK==-
|
||||
|
||||
gripper = self.GetWindowRect()
|
||||
gripper = self.ScreenToClient( gripper )
|
||||
gripper = OffsetRect( gripper, (-gripper[0], -gripper[1]) )
|
||||
gl, gt, gr, gb = gripper
|
||||
|
||||
if self._obj_.dwStyle & afxres.CBRS_ORIENT_HORZ:
|
||||
# gripper at left
|
||||
self.rectGripper = gl, gt + 40, gl+20, gb
|
||||
# draw close box
|
||||
self.rectClose = gl+7, gt + 10, gl+19, gt+22
|
||||
dc.DrawFrameControl(self.rectClose, win32con.DFC_CAPTION, win32con.DFCS_CAPTIONCLOSE)
|
||||
# draw docking toggle box
|
||||
self.rectUndock = OffsetRect(self.rectClose, (0,13))
|
||||
dc.DrawFrameControl(self.rectUndock, win32con.DFC_CAPTION, win32con.DFCS_CAPTIONMAX);
|
||||
|
||||
gt = gt + 38
|
||||
gb = gb - 10
|
||||
gl = gl + 10
|
||||
gr = gl + 3
|
||||
gripper = gl, gt, gr, gb
|
||||
dc.Draw3dRect( gripper, clrBtnHilight, clrBtnShadow )
|
||||
dc.Draw3dRect( OffsetRect(gripper, (4,0)), clrBtnHilight, clrBtnShadow )
|
||||
else:
|
||||
# gripper at top
|
||||
self.rectGripper = gl, gt, gr-40, gt+20
|
||||
# draw close box
|
||||
self.rectClose = gr-21, gt+7, gr-10, gt+18
|
||||
dc.DrawFrameControl(self.rectClose, win32con.DFC_CAPTION, win32con.DFCS_CAPTIONCLOSE)
|
||||
# draw docking toggle box
|
||||
self.rectUndock = OffsetRect( self.rectClose, (-13,0) )
|
||||
dc.DrawFrameControl(self.rectUndock, win32con.DFC_CAPTION, win32con.DFCS_CAPTIONMAX)
|
||||
gr = gr - 38;
|
||||
gl = gl + 10
|
||||
gt = gt + 10
|
||||
gb = gt + 3
|
||||
|
||||
gripper = gl, gt, gr, gb
|
||||
dc.Draw3dRect( gripper, clrBtnHilight, clrBtnShadow )
|
||||
dc.Draw3dRect( OffsetRect(gripper, (0,4) ), clrBtnHilight, clrBtnShadow )
|
||||
|
||||
def HookMessages(self):
|
||||
self.HookMessage(self.OnLButtonUp, win32con.WM_LBUTTONUP)
|
||||
self.HookMessage(self.OnLButtonDown, win32con.WM_LBUTTONDOWN)
|
||||
self.HookMessage(self.OnLButtonDblClk, win32con.WM_LBUTTONDBLCLK)
|
||||
self.HookMessage(self.OnNcLButtonDown, win32con.WM_NCLBUTTONDOWN)
|
||||
self.HookMessage(self.OnNcLButtonDblClk, win32con.WM_NCLBUTTONDBLCLK)
|
||||
self.HookMessage(self.OnMouseMove, win32con.WM_MOUSEMOVE)
|
||||
self.HookMessage(self.OnNcPaint, win32con.WM_NCPAINT)
|
||||
self.HookMessage(self.OnCaptureChanged, win32con.WM_CAPTURECHANGED)
|
||||
self.HookMessage(self.OnWindowPosChanged, win32con.WM_WINDOWPOSCHANGED)
|
||||
# self.HookMessage(self.OnSize, win32con.WM_SIZE)
|
||||
|
||||
def EditCreator(parent):
|
||||
d = win32ui.CreateEdit()
|
||||
es = win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.WS_BORDER | win32con.ES_MULTILINE | win32con.ES_WANTRETURN
|
||||
d.CreateWindow( es, (0,0,150,150), parent, 1000)
|
||||
return d
|
||||
|
||||
def test():
|
||||
import pywin.mfc.dialog
|
||||
global bar
|
||||
bar = DockingBar()
|
||||
creator = EditCreator
|
||||
bar.CreateWindow(win32ui.GetMainFrame(), creator, "Coolbar Demo",0xfffff)
|
||||
# win32ui.GetMainFrame().ShowControlBar(bar, 1, 0)
|
||||
bar.SetBarStyle( bar.GetBarStyle()|afxres.CBRS_TOOLTIPS|afxres.CBRS_FLYBY|afxres.CBRS_SIZE_DYNAMIC)
|
||||
bar.EnableDocking(afxres.CBRS_ALIGN_ANY)
|
||||
win32ui.GetMainFrame().DockControlBar(bar, afxres.AFX_IDW_DOCKBAR_BOTTOM)
|
||||
|
||||
|
||||
if __name__=='__main__':
|
||||
test()
|
||||
0
Lib/site-packages/pythonwin/pywin/docking/__init__.py
Normal file
0
Lib/site-packages/pythonwin/pywin/docking/__init__.py
Normal file
0
Lib/site-packages/pythonwin/pywin/framework/__init__.py
Normal file
0
Lib/site-packages/pythonwin/pywin/framework/__init__.py
Normal file
408
Lib/site-packages/pythonwin/pywin/framework/app.py
Normal file
408
Lib/site-packages/pythonwin/pywin/framework/app.py
Normal file
|
|
@ -0,0 +1,408 @@
|
|||
# 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", "http://starship.python.net/crew/mhammond/win32", 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
|
||||
143
Lib/site-packages/pythonwin/pywin/framework/bitmap.py
Normal file
143
Lib/site-packages/pythonwin/pywin/framework/bitmap.py
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
import win32ui
|
||||
import win32con
|
||||
import win32api
|
||||
import string
|
||||
import os
|
||||
from . import app
|
||||
import sys
|
||||
|
||||
from pywin.mfc import docview, window
|
||||
|
||||
bStretch = 1
|
||||
|
||||
class BitmapDocument(docview.Document):
|
||||
"A bitmap document. Holds the bitmap data itself."
|
||||
def __init__(self, template):
|
||||
docview.Document.__init__(self, template)
|
||||
self.bitmap=None
|
||||
def OnNewDocument(self):
|
||||
# I can not create new bitmaps.
|
||||
win32ui.MessageBox("Bitmaps can not be created.")
|
||||
def OnOpenDocument(self, filename):
|
||||
self.bitmap=win32ui.CreateBitmap()
|
||||
# init data members
|
||||
f = open(filename, 'rb')
|
||||
try:
|
||||
try:
|
||||
self.bitmap.LoadBitmapFile(f)
|
||||
except IOError:
|
||||
win32ui.MessageBox("Could not load the bitmap from %s" % filename)
|
||||
return 0
|
||||
finally:
|
||||
f.close()
|
||||
self.size = self.bitmap.GetSize()
|
||||
return 1
|
||||
def DeleteContents(self):
|
||||
self.bitmap=None
|
||||
|
||||
class BitmapView(docview.ScrollView):
|
||||
"A view of a bitmap. Obtains data from document."
|
||||
def __init__(self, doc):
|
||||
docview.ScrollView.__init__(self, doc)
|
||||
self.width = self.height = 0
|
||||
# set up message handlers
|
||||
self.HookMessage (self.OnSize, win32con.WM_SIZE)
|
||||
|
||||
def OnInitialUpdate(self):
|
||||
doc = self.GetDocument()
|
||||
if doc.bitmap:
|
||||
bitmapSize = doc.bitmap.GetSize()
|
||||
self.SetScrollSizes(win32con.MM_TEXT, bitmapSize)
|
||||
|
||||
def OnSize (self, params):
|
||||
lParam = params[3]
|
||||
self.width = win32api.LOWORD(lParam)
|
||||
self.height = win32api.HIWORD(lParam)
|
||||
|
||||
def OnDraw (self, dc):
|
||||
# set sizes used for "non stretch" mode.
|
||||
doc = self.GetDocument()
|
||||
if doc.bitmap is None: return
|
||||
bitmapSize = doc.bitmap.GetSize()
|
||||
if bStretch:
|
||||
# stretch BMP.
|
||||
viewRect = (0,0,self.width, self.height)
|
||||
bitmapRect = (0,0,bitmapSize[0], bitmapSize[1])
|
||||
doc.bitmap.Paint(dc, viewRect, bitmapRect)
|
||||
else:
|
||||
# non stretch.
|
||||
doc.bitmap.Paint(dc)
|
||||
|
||||
class BitmapFrame(window.MDIChildWnd):
|
||||
def OnCreateClient( self, createparams, context ):
|
||||
borderX = win32api.GetSystemMetrics(win32con.SM_CXFRAME)
|
||||
borderY = win32api.GetSystemMetrics(win32con.SM_CYFRAME)
|
||||
titleY = win32api.GetSystemMetrics(win32con.SM_CYCAPTION) # includes border
|
||||
# try and maintain default window pos, else adjust if cant fit
|
||||
# get the main client window dimensions.
|
||||
mdiClient = win32ui.GetMainFrame().GetWindow(win32con.GW_CHILD)
|
||||
clientWindowRect=mdiClient.ScreenToClient(mdiClient.GetWindowRect())
|
||||
clientWindowSize=(clientWindowRect[2]-clientWindowRect[0],clientWindowRect[3]-clientWindowRect[1])
|
||||
left, top, right, bottom=mdiClient.ScreenToClient(self.GetWindowRect())
|
||||
# width, height=context.doc.size[0], context.doc.size[1]
|
||||
# width = width+borderX*2
|
||||
# height= height+titleY+borderY*2-1
|
||||
# if (left+width)>clientWindowSize[0]:
|
||||
# left = clientWindowSize[0] - width
|
||||
# if left<0:
|
||||
# left = 0
|
||||
# width = clientWindowSize[0]
|
||||
# if (top+height)>clientWindowSize[1]:
|
||||
# top = clientWindowSize[1] - height
|
||||
# if top<0:
|
||||
# top = 0
|
||||
# height = clientWindowSize[1]
|
||||
# self.frame.MoveWindow((left, top, left+width, top+height),0)
|
||||
window.MDIChildWnd.OnCreateClient(self, createparams, context)
|
||||
return 1
|
||||
|
||||
|
||||
class BitmapTemplate(docview.DocTemplate):
|
||||
def __init__(self):
|
||||
docview.DocTemplate.__init__(self, win32ui.IDR_PYTHONTYPE, BitmapDocument, BitmapFrame, BitmapView)
|
||||
def MatchDocType(self, fileName, fileType):
|
||||
doc = self.FindOpenDocument(fileName)
|
||||
if doc: return doc
|
||||
ext = os.path.splitext(fileName)[1].lower()
|
||||
if ext =='.bmp': # removed due to PIL! or ext=='.ppm':
|
||||
return win32ui.CDocTemplate_Confidence_yesAttemptNative
|
||||
return win32ui.CDocTemplate_Confidence_maybeAttemptForeign
|
||||
# return win32ui.CDocTemplate_Confidence_noAttempt
|
||||
|
||||
# For debugging purposes, when this module may be reloaded many times.
|
||||
try:
|
||||
win32ui.GetApp().RemoveDocTemplate(bitmapTemplate)
|
||||
except NameError:
|
||||
pass
|
||||
|
||||
bitmapTemplate = BitmapTemplate()
|
||||
bitmapTemplate.SetDocStrings('\nBitmap\nBitmap\nBitmap (*.bmp)\n.bmp\nPythonBitmapFileType\nPython Bitmap File')
|
||||
win32ui.GetApp().AddDocTemplate(bitmapTemplate)
|
||||
|
||||
# This works, but just didnt make it through the code reorg.
|
||||
#class PPMBitmap(Bitmap):
|
||||
# def LoadBitmapFile(self, file ):
|
||||
# magic=file.readline()
|
||||
# if magic <> "P6\n":
|
||||
# raise TypeError, "The file is not a PPM format file"
|
||||
# rowcollist=string.split(file.readline())
|
||||
# cols=string.atoi(rowcollist[0])
|
||||
# rows=string.atoi(rowcollist[1])
|
||||
# file.readline() # whats this one?
|
||||
# self.bitmap.LoadPPMFile(file,(cols,rows))
|
||||
|
||||
|
||||
def t():
|
||||
bitmapTemplate.OpenDocumentFile('d:\\winnt\\arcade.bmp')
|
||||
#OpenBMPFile( 'd:\\winnt\\arcade.bmp')
|
||||
|
||||
def demo():
|
||||
import glob
|
||||
winDir=win32api.GetWindowsDirectory()
|
||||
for fileName in glob.glob1(winDir, '*.bmp')[:2]:
|
||||
bitmapTemplate.OpenDocumentFile(os.path.join(winDir, fileName))
|
||||
49
Lib/site-packages/pythonwin/pywin/framework/cmdline.py
Normal file
49
Lib/site-packages/pythonwin/pywin/framework/cmdline.py
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
# cmdline - command line utilities.
|
||||
import sys
|
||||
import win32ui
|
||||
import string
|
||||
|
||||
def ParseArgs( str ):
|
||||
import string
|
||||
ret=[]
|
||||
pos = 0
|
||||
length=len(str)
|
||||
while pos<length:
|
||||
try:
|
||||
while str[pos] in string.whitespace: pos = pos+1
|
||||
except IndexError:
|
||||
break
|
||||
if pos>=length:
|
||||
break
|
||||
if str[pos]=='"':
|
||||
pos=pos+1
|
||||
try:
|
||||
endPos = str.index('"', pos)-1
|
||||
nextPos = endPos+2
|
||||
except ValueError:
|
||||
endPos=length
|
||||
nextPos=endPos+1
|
||||
else:
|
||||
endPos = pos
|
||||
while endPos<length and not str[endPos] in string.whitespace: endPos = endPos+1
|
||||
nextPos=endPos+1
|
||||
ret.append(str[pos:endPos+1].strip())
|
||||
pos = nextPos
|
||||
return ret
|
||||
|
||||
def FixArgFileName(fileName):
|
||||
"""Convert a filename on the commandline to something useful.
|
||||
Given an automatic filename on the commandline, turn it a python module name,
|
||||
with the path added to sys.path. """
|
||||
import os
|
||||
path, fname = os.path.split(fileName)
|
||||
if len(path)==0:
|
||||
path = os.curdir
|
||||
path=os.path.abspath(path)
|
||||
# must check that the command line arg's path is in sys.path
|
||||
for syspath in sys.path:
|
||||
if os.path.abspath(syspath)==path:
|
||||
break
|
||||
else:
|
||||
sys.path.append(path)
|
||||
return os.path.splitext(fname)[0]
|
||||
170
Lib/site-packages/pythonwin/pywin/framework/dbgcommands.py
Normal file
170
Lib/site-packages/pythonwin/pywin/framework/dbgcommands.py
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
# Command Handlers for the debugger.
|
||||
|
||||
# Not in the debugger package, as I always want these interfaces to be
|
||||
# available, even if the debugger has not yet been (or can not be)
|
||||
# imported
|
||||
import win32ui, win32con
|
||||
from . import scriptutils
|
||||
import warnings
|
||||
from pywin.scintilla.control import CScintillaEditInterface
|
||||
|
||||
IdToBarNames = {
|
||||
win32ui.IDC_DBG_STACK : ("Stack",0),
|
||||
win32ui.IDC_DBG_BREAKPOINTS : ("Breakpoints",0),
|
||||
win32ui.IDC_DBG_WATCH : ("Watch",1),
|
||||
}
|
||||
|
||||
class DebuggerCommandHandler:
|
||||
def HookCommands(self):
|
||||
commands = ( (self.OnStep, None, win32ui.IDC_DBG_STEP),
|
||||
(self.OnStepOut, self.OnUpdateOnlyBreak, win32ui.IDC_DBG_STEPOUT),
|
||||
(self.OnStepOver, None, win32ui.IDC_DBG_STEPOVER),
|
||||
(self.OnGo, None, win32ui.IDC_DBG_GO),
|
||||
(self.OnClose, self.OnUpdateClose, win32ui.IDC_DBG_CLOSE),
|
||||
(self.OnAdd, self.OnUpdateAddBreakpoints, win32ui.IDC_DBG_ADD),
|
||||
(self.OnClearAll, self.OnUpdateClearAllBreakpoints, win32ui.IDC_DBG_CLEAR),
|
||||
# (self.OnDebuggerToolbar, self.OnUpdateDebuggerToolbar, win32ui.ID_DEBUGGER_TOOLBAR),
|
||||
)
|
||||
|
||||
frame = win32ui.GetMainFrame()
|
||||
|
||||
for methHandler, methUpdate, id in commands:
|
||||
frame.HookCommand(methHandler, id);
|
||||
if not methUpdate is None:
|
||||
frame.HookCommandUpdate(methUpdate, id)
|
||||
|
||||
for id in list(IdToBarNames.keys()):
|
||||
frame.HookCommand( self.OnDebuggerBar, id)
|
||||
frame.HookCommandUpdate(self.OnUpdateDebuggerBar, id)
|
||||
|
||||
def OnDebuggerToolbar(self, id, code):
|
||||
if code==0:
|
||||
return not win32ui.GetMainFrame().OnBarCheck(id)
|
||||
|
||||
def OnUpdateDebuggerToolbar(self, cmdui):
|
||||
win32ui.GetMainFrame().OnUpdateControlBarMenu(cmdui)
|
||||
cmdui.Enable(1)
|
||||
|
||||
def _GetDebugger(self):
|
||||
try:
|
||||
import pywin.debugger
|
||||
return pywin.debugger.currentDebugger
|
||||
except ImportError:
|
||||
return None
|
||||
|
||||
def _DoOrStart(self, doMethod, startFlag):
|
||||
d=self._GetDebugger()
|
||||
if d is not None and d.IsDebugging():
|
||||
method = getattr(d, doMethod)
|
||||
method()
|
||||
else:
|
||||
scriptutils.RunScript(defName=None, defArgs=None, bShowDialog = 0, debuggingType=startFlag)
|
||||
|
||||
def OnStep(self, msg, code):
|
||||
self._DoOrStart("do_set_step", scriptutils.RS_DEBUGGER_STEP)
|
||||
|
||||
def OnStepOver(self, msg, code):
|
||||
self._DoOrStart("do_set_next", scriptutils.RS_DEBUGGER_STEP)
|
||||
|
||||
def OnStepOut(self, msg, code):
|
||||
d=self._GetDebugger()
|
||||
if d is not None and d.IsDebugging():
|
||||
d.do_set_return()
|
||||
|
||||
def OnGo(self, msg, code):
|
||||
self._DoOrStart("do_set_continue", scriptutils.RS_DEBUGGER_GO)
|
||||
|
||||
def OnClose(self, msg, code):
|
||||
d=self._GetDebugger()
|
||||
if d is not None:
|
||||
if d.IsDebugging():
|
||||
d.set_quit()
|
||||
else:
|
||||
d.close()
|
||||
|
||||
def OnUpdateClose(self, cmdui):
|
||||
d=self._GetDebugger()
|
||||
if d is not None and d.inited:
|
||||
cmdui.Enable(1)
|
||||
else:
|
||||
cmdui.Enable(0)
|
||||
|
||||
def OnAdd(self, msg, code):
|
||||
doc, view = scriptutils.GetActiveEditorDocument()
|
||||
if doc is None:
|
||||
## Don't do a messagebox, as this could be triggered from the app's
|
||||
## idle loop whenever the debug toolbar is visible, giving a never-ending
|
||||
## series of dialogs. This can happen when the OnUpdate handler
|
||||
## for the toolbar button IDC_DBG_ADD fails, since MFC falls back to
|
||||
## sending a normal command if the UI update command fails.
|
||||
## win32ui.MessageBox('There is no active window - no breakpoint can be added')
|
||||
warnings.warn('There is no active window - no breakpoint can be added')
|
||||
return None
|
||||
pathName = doc.GetPathName()
|
||||
lineNo = view.LineFromChar(view.GetSel()[0])+1
|
||||
# If I have a debugger, then tell it, otherwise just add a marker
|
||||
d=self._GetDebugger()
|
||||
if d is None:
|
||||
import pywin.framework.editor.color.coloreditor
|
||||
doc.MarkerToggle(lineNo, pywin.framework.editor.color.coloreditor.MARKER_BREAKPOINT)
|
||||
else:
|
||||
if d.get_break(pathName, lineNo):
|
||||
win32ui.SetStatusText('Clearing breakpoint',1)
|
||||
rc = d.clear_break(pathName, lineNo)
|
||||
else:
|
||||
win32ui.SetStatusText('Setting breakpoint',1)
|
||||
rc = d.set_break(pathName, lineNo)
|
||||
if rc:
|
||||
win32ui.MessageBox(rc)
|
||||
d.GUIRespondDebuggerData()
|
||||
|
||||
def OnClearAll(self, msg, code):
|
||||
win32ui.SetStatusText('Clearing all breakpoints')
|
||||
d=self._GetDebugger()
|
||||
if d is None:
|
||||
import pywin.framework.editor
|
||||
import pywin.framework.editor.color.coloreditor
|
||||
for doc in pywin.framework.editor.editorTemplate.GetDocumentList():
|
||||
doc.MarkerDeleteAll(pywin.framework.editor.color.coloreditor.MARKER_BREAKPOINT)
|
||||
else:
|
||||
d.clear_all_breaks()
|
||||
d.UpdateAllLineStates()
|
||||
d.GUIRespondDebuggerData()
|
||||
|
||||
def OnUpdateOnlyBreak(self, cmdui):
|
||||
d=self._GetDebugger()
|
||||
ok = d is not None and d.IsBreak()
|
||||
cmdui.Enable(ok)
|
||||
|
||||
def OnUpdateAddBreakpoints(self, cmdui):
|
||||
doc, view = scriptutils.GetActiveEditorDocument()
|
||||
if doc is None or not isinstance(view, CScintillaEditInterface):
|
||||
enabled = 0
|
||||
else:
|
||||
enabled = 1
|
||||
lineNo = view.LineFromChar(view.GetSel()[0])+1
|
||||
import pywin.framework.editor.color.coloreditor
|
||||
cmdui.SetCheck(doc.MarkerAtLine(lineNo, pywin.framework.editor.color.coloreditor.MARKER_BREAKPOINT) != 0)
|
||||
cmdui.Enable(enabled)
|
||||
|
||||
def OnUpdateClearAllBreakpoints(self, cmdui):
|
||||
d=self._GetDebugger()
|
||||
cmdui.Enable(d is None or len(d.breaks)!=0)
|
||||
|
||||
def OnUpdateDebuggerBar(self, cmdui):
|
||||
name, always = IdToBarNames.get(cmdui.m_nID)
|
||||
enabled = always
|
||||
d=self._GetDebugger()
|
||||
if d is not None and d.IsDebugging() and name is not None:
|
||||
enabled = 1
|
||||
bar = d.GetDebuggerBar(name)
|
||||
cmdui.SetCheck(bar.IsWindowVisible())
|
||||
cmdui.Enable(enabled)
|
||||
|
||||
def OnDebuggerBar(self, id, code):
|
||||
name = IdToBarNames.get(id)[0]
|
||||
d=self._GetDebugger()
|
||||
if d is not None and name is not None:
|
||||
bar = d.GetDebuggerBar(name)
|
||||
newState = not bar.IsWindowVisible()
|
||||
win32ui.GetMainFrame().ShowControlBar(bar, newState, 1)
|
||||
69
Lib/site-packages/pythonwin/pywin/framework/dlgappcore.py
Normal file
69
Lib/site-packages/pythonwin/pywin/framework/dlgappcore.py
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
# dlgappcore.
|
||||
#
|
||||
# base classes for dialog based apps.
|
||||
|
||||
from . import app
|
||||
import win32ui
|
||||
import win32con
|
||||
import win32api
|
||||
import sys
|
||||
from pywin.mfc import dialog
|
||||
|
||||
error = "Dialog Application Error"
|
||||
|
||||
class AppDialog(dialog.Dialog):
|
||||
"The dialog box for the application"
|
||||
def __init__(self, id, dll=None):
|
||||
self.iconId = win32ui.IDR_MAINFRAME
|
||||
dialog.Dialog.__init__(self, id, dll)
|
||||
|
||||
def OnInitDialog(self):
|
||||
return dialog.Dialog.OnInitDialog(self)
|
||||
|
||||
# Provide support for a dlg app using an icon
|
||||
def OnPaint(self):
|
||||
if not self.IsIconic(): return self._obj_.OnPaint()
|
||||
self.DefWindowProc(win32con.WM_ICONERASEBKGND, dc.GetHandleOutput(), 0)
|
||||
left, top, right, bottom = self.GetClientRect()
|
||||
left = (right - win32api.GetSystemMetrics(win32con.SM_CXICON)) >> 1
|
||||
top = (bottom - win32api.GetSystemMetrics(win32con.SM_CYICON)) >> 1
|
||||
hIcon = win32ui.GetApp().LoadIcon(self.iconId)
|
||||
self.GetDC().DrawIcon((left, top), hIcon)
|
||||
|
||||
# Only needed to provide a minimized icon (and this seems
|
||||
# less important under win95/NT4
|
||||
def OnEraseBkgnd(self, dc):
|
||||
if self.IsIconic():
|
||||
return 1
|
||||
else:
|
||||
return self._obj_.OnEraseBkgnd(dc)
|
||||
def OnQueryDragIcon(self):
|
||||
return win32ui.GetApp().LoadIcon(self.iconId)
|
||||
|
||||
def PreDoModal(self):
|
||||
pass
|
||||
|
||||
|
||||
class DialogApp(app.CApp):
|
||||
"An application class, for an app with main dialog box"
|
||||
def InitInstance(self):
|
||||
# win32ui.SetProfileFileName('dlgapp.ini')
|
||||
win32ui.LoadStdProfileSettings()
|
||||
win32ui.EnableControlContainer()
|
||||
win32ui.Enable3dControls()
|
||||
self.dlg = self.frame = self.CreateDialog()
|
||||
|
||||
if self.frame is None:
|
||||
raise error("No dialog was created by CreateDialog()")
|
||||
return
|
||||
|
||||
self._obj_.InitDlgInstance(self.dlg)
|
||||
self.PreDoModal()
|
||||
self.dlg.PreDoModal()
|
||||
self.dlg.DoModal()
|
||||
|
||||
def CreateDialog(self):
|
||||
pass
|
||||
def PreDoModal(self):
|
||||
pass
|
||||
|
||||
|
|
@ -0,0 +1,200 @@
|
|||
# ModuleBrowser.py - A view that provides a module browser for an editor document.
|
||||
import pywin.mfc.docview
|
||||
import win32ui
|
||||
import win32con
|
||||
import commctrl
|
||||
import win32api
|
||||
from pywin.tools import hierlist, browser
|
||||
import pywin.framework.scriptutils
|
||||
import afxres
|
||||
|
||||
import pyclbr
|
||||
|
||||
class HierListCLBRModule(hierlist.HierListItem):
|
||||
def __init__(self, modName, clbrdata):
|
||||
self.modName = modName
|
||||
self.clbrdata = clbrdata
|
||||
def GetText(self):
|
||||
return self.modName
|
||||
def GetSubList(self):
|
||||
ret = []
|
||||
for item in self.clbrdata.values():
|
||||
if item.__class__ != pyclbr.Class: # ie, it is a pyclbr Function instance (only introduced post 1.5.2)
|
||||
ret.append(HierListCLBRFunction( item ) )
|
||||
else:
|
||||
ret.append(HierListCLBRClass( item) )
|
||||
ret.sort()
|
||||
return ret
|
||||
def IsExpandable(self):
|
||||
return 1
|
||||
|
||||
class HierListCLBRItem(hierlist.HierListItem):
|
||||
def __init__(self, name, file, lineno, suffix = ""):
|
||||
self.name = str(name)
|
||||
self.file = file
|
||||
self.lineno = lineno
|
||||
self.suffix = suffix
|
||||
def __lt__(self, other):
|
||||
return self.name < other.name
|
||||
def __eq__(self, other):
|
||||
return self.name == other.name
|
||||
def GetText(self):
|
||||
return self.name + self.suffix
|
||||
def TakeDefaultAction(self):
|
||||
if self.file:
|
||||
pywin.framework.scriptutils.JumpToDocument(self.file, self.lineno, bScrollToTop = 1)
|
||||
else:
|
||||
win32ui.SetStatusText("Can not locate the source code for this object.")
|
||||
def PerformItemSelected(self):
|
||||
if self.file is None:
|
||||
msg = "%s - source can not be located." % (self.name, )
|
||||
else:
|
||||
msg = "%s defined at line %d of %s" % (self.name, self.lineno, self.file)
|
||||
win32ui.SetStatusText(msg)
|
||||
|
||||
class HierListCLBRClass(HierListCLBRItem):
|
||||
def __init__(self, clbrclass, suffix = ""):
|
||||
try:
|
||||
name = clbrclass.name
|
||||
file = clbrclass.file
|
||||
lineno = clbrclass.lineno
|
||||
self.super = clbrclass.super
|
||||
self.methods = clbrclass.methods
|
||||
except AttributeError:
|
||||
name = clbrclass
|
||||
file = lineno = None
|
||||
self.super = []; self.methods = {}
|
||||
HierListCLBRItem.__init__(self, name, file, lineno, suffix)
|
||||
def GetSubList(self):
|
||||
r1 = []
|
||||
for c in self.super:
|
||||
r1.append(HierListCLBRClass(c, " (Parent class)"))
|
||||
r1.sort()
|
||||
r2=[]
|
||||
for meth, lineno in self.methods.items():
|
||||
r2.append(HierListCLBRMethod(meth, self.file, lineno))
|
||||
r2.sort()
|
||||
return r1+r2
|
||||
def IsExpandable(self):
|
||||
return len(self.methods) + len(self.super)
|
||||
def GetBitmapColumn(self):
|
||||
return 21
|
||||
|
||||
class HierListCLBRFunction(HierListCLBRItem):
|
||||
def __init__(self, clbrfunc, suffix = ""):
|
||||
name = clbrfunc.name
|
||||
file = clbrfunc.file
|
||||
lineno = clbrfunc.lineno
|
||||
HierListCLBRItem.__init__(self, name, file, lineno, suffix)
|
||||
def GetBitmapColumn(self):
|
||||
return 22
|
||||
|
||||
class HierListCLBRMethod(HierListCLBRItem):
|
||||
def GetBitmapColumn(self):
|
||||
return 22
|
||||
|
||||
class HierListCLBRErrorItem(hierlist.HierListItem):
|
||||
def __init__(self, text):
|
||||
self.text = text
|
||||
def GetText(self):
|
||||
return self.text
|
||||
def GetSubList(self):
|
||||
return [HierListCLBRErrorItem(self.text)]
|
||||
def IsExpandable(self):
|
||||
return 0
|
||||
|
||||
class HierListCLBRErrorRoot(HierListCLBRErrorItem):
|
||||
def IsExpandable(self):
|
||||
return 1
|
||||
|
||||
class BrowserView(pywin.mfc.docview.TreeView):
|
||||
def OnInitialUpdate(self):
|
||||
self.list = None
|
||||
rc = self._obj_.OnInitialUpdate()
|
||||
self.HookMessage(self.OnSize, win32con.WM_SIZE)
|
||||
self.bDirty = 0
|
||||
self.destroying = 0
|
||||
return rc
|
||||
|
||||
def DestroyBrowser(self):
|
||||
self.DestroyList()
|
||||
|
||||
def OnActivateView(self, activate, av, dv):
|
||||
# print "AV", self.bDirty, activate
|
||||
if activate:
|
||||
self.CheckRefreshList()
|
||||
return self._obj_.OnActivateView(activate, av, dv)
|
||||
|
||||
def _MakeRoot(self):
|
||||
path = self.GetDocument().GetPathName()
|
||||
if not path:
|
||||
return HierListCLBRErrorRoot("Error: Can not browse a file until it is saved")
|
||||
else:
|
||||
mod, path = pywin.framework.scriptutils.GetPackageModuleName(path)
|
||||
if self.bDirty:
|
||||
what = "Refreshing"
|
||||
# Hack for pyclbr being too smart
|
||||
try:
|
||||
del pyclbr._modules[mod]
|
||||
except (KeyError, AttributeError):
|
||||
pass
|
||||
else:
|
||||
what = "Building"
|
||||
win32ui.SetStatusText("%s class list - please wait..." % (what,), 1)
|
||||
win32ui.DoWaitCursor(1)
|
||||
try:
|
||||
reader = pyclbr.readmodule_ex # new version post 1.5.2
|
||||
except AttributeError:
|
||||
reader = pyclbr.readmodule
|
||||
try:
|
||||
data = reader(mod, [path])
|
||||
if data:
|
||||
return HierListCLBRModule(mod, data)
|
||||
else:
|
||||
return HierListCLBRErrorRoot("No Python classes in module.")
|
||||
|
||||
finally:
|
||||
win32ui.DoWaitCursor(0)
|
||||
win32ui.SetStatusText(win32ui.LoadString(afxres.AFX_IDS_IDLEMESSAGE))
|
||||
|
||||
def DestroyList(self):
|
||||
self.destroying = 1
|
||||
list = getattr(self, "list", None) # If the document was not successfully opened, we may not have a list.
|
||||
self.list = None
|
||||
if list is not None:
|
||||
list.HierTerm()
|
||||
self.destroying = 0
|
||||
|
||||
def CheckMadeList(self):
|
||||
if self.list is not None or self.destroying: return
|
||||
self.rootitem = root = self._MakeRoot()
|
||||
self.list = list = hierlist.HierListWithItems( root, win32ui.IDB_BROWSER_HIER)
|
||||
list.HierInit(self.GetParentFrame(), self)
|
||||
list.SetStyle(commctrl.TVS_HASLINES | commctrl.TVS_LINESATROOT | commctrl.TVS_HASBUTTONS)
|
||||
|
||||
def CheckRefreshList(self):
|
||||
if self.bDirty:
|
||||
if self.list is None:
|
||||
self.CheckMadeList()
|
||||
else:
|
||||
new_root = self._MakeRoot()
|
||||
if self.rootitem.__class__==new_root.__class__==HierListCLBRModule:
|
||||
self.rootitem.modName = new_root.modName
|
||||
self.rootitem.clbrdata = new_root.clbrdata
|
||||
self.list.Refresh()
|
||||
else:
|
||||
self.list.AcceptRoot(self._MakeRoot())
|
||||
self.bDirty = 0
|
||||
|
||||
def OnSize(self, params):
|
||||
lparam = params[3]
|
||||
w = win32api.LOWORD(lparam)
|
||||
h = win32api.HIWORD(lparam)
|
||||
if w != 0:
|
||||
self.CheckMadeList()
|
||||
elif w == 0:
|
||||
self.DestroyList()
|
||||
return 1
|
||||
|
||||
def _UpdateUIForState(self):
|
||||
self.bDirty = 1
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
# __init__ for the Pythonwin editor package.
|
||||
#
|
||||
# We used to support optional editors - eg, color or non-color.
|
||||
#
|
||||
# This really isnt necessary with Scintilla, and scintilla
|
||||
# is getting so deeply embedded that it was too much work.
|
||||
|
||||
import win32ui, sys, win32con
|
||||
|
||||
defaultCharacterFormat = (-402653169, 0, 200, 0, 0, 0, 49, 'Courier New')
|
||||
|
||||
##def GetDefaultEditorModuleName():
|
||||
## import pywin
|
||||
## # If someone has set pywin.editormodulename, then this is what we use
|
||||
## try:
|
||||
## prefModule = pywin.editormodulename
|
||||
## except AttributeError:
|
||||
## prefModule = win32ui.GetProfileVal("Editor","Module", "")
|
||||
## return prefModule
|
||||
##
|
||||
##def WriteDefaultEditorModule(module):
|
||||
## try:
|
||||
## module = module.__name__
|
||||
## except:
|
||||
## pass
|
||||
## win32ui.WriteProfileVal("Editor", "Module", module)
|
||||
|
||||
def LoadDefaultEditor():
|
||||
pass
|
||||
## prefModule = GetDefaultEditorModuleName()
|
||||
## restorePrefModule = None
|
||||
## mod = None
|
||||
## if prefModule:
|
||||
## try:
|
||||
## mod = __import__(prefModule)
|
||||
## except 'xx':
|
||||
## msg = "Importing your preferred editor ('%s') failed.\n\nError %s: %s\n\nAn attempt will be made to load the default editor.\n\nWould you like this editor disabled in the future?" % (prefModule, sys.exc_info()[0], sys.exc_info()[1])
|
||||
## rc = win32ui.MessageBox(msg, "Error importing editor", win32con.MB_YESNO)
|
||||
## if rc == win32con.IDNO:
|
||||
## restorePrefModule = prefModule
|
||||
## WriteDefaultEditorModule("")
|
||||
## del rc
|
||||
##
|
||||
## try:
|
||||
## # Try and load the default one - dont catch errors here.
|
||||
## if mod is None:
|
||||
## prefModule = "pywin.framework.editor.color.coloreditor"
|
||||
## mod = __import__(prefModule)
|
||||
##
|
||||
## # Get at the real module.
|
||||
## mod = sys.modules[prefModule]
|
||||
##
|
||||
## # Do a "from mod import *"
|
||||
## globals().update(mod.__dict__)
|
||||
##
|
||||
## finally:
|
||||
## # Restore the users default editor if it failed and they requested not to disable it.
|
||||
## if restorePrefModule:
|
||||
## WriteDefaultEditorModule(restorePrefModule)
|
||||
|
||||
def GetEditorOption(option, defaultValue, min=None, max = None):
|
||||
rc = win32ui.GetProfileVal("Editor", option, defaultValue)
|
||||
if min is not None and rc < min: rc = defaultValue
|
||||
if max is not None and rc > max: rc = defaultValue
|
||||
return rc
|
||||
|
||||
def SetEditorOption(option, newValue):
|
||||
win32ui.WriteProfileVal("Editor", option, newValue)
|
||||
|
||||
def DeleteEditorOption(option):
|
||||
try:
|
||||
win32ui.WriteProfileVal("Editor", option, None)
|
||||
except win32ui.error:
|
||||
pass
|
||||
|
||||
# Load and save font tuples
|
||||
def GetEditorFontOption(option, default = None):
|
||||
if default is None: default = defaultCharacterFormat
|
||||
fmt = GetEditorOption( option, "" )
|
||||
if fmt == "": return default
|
||||
try:
|
||||
return eval(fmt)
|
||||
except:
|
||||
print("WARNING: Invalid font setting in registry - setting ignored")
|
||||
return default
|
||||
|
||||
def SetEditorFontOption(option, newValue):
|
||||
SetEditorOption(option, str(newValue))
|
||||
|
||||
from pywin.framework.editor.color.coloreditor import editorTemplate
|
||||
|
|
@ -0,0 +1,525 @@
|
|||
# Color Editor originally by Neil Hodgson, but restructured by mh to integrate
|
||||
# even tighter into Pythonwin.
|
||||
import win32ui
|
||||
import win32con
|
||||
import win32api
|
||||
import sys
|
||||
|
||||
import pywin.scintilla.keycodes
|
||||
from pywin.scintilla import bindings
|
||||
|
||||
from pywin.framework.editor import GetEditorOption, SetEditorOption, GetEditorFontOption, SetEditorFontOption, defaultCharacterFormat
|
||||
#from pywin.framework.editor import EditorPropertyPage
|
||||
|
||||
MSG_CHECK_EXTERNAL_FILE = win32con.WM_USER+1999 ## WARNING: Duplicated in document.py and editor.py
|
||||
|
||||
# Define a few common markers
|
||||
MARKER_BOOKMARK = 0
|
||||
MARKER_BREAKPOINT = 1
|
||||
MARKER_CURRENT = 2
|
||||
|
||||
from pywin.debugger import dbgcon
|
||||
from pywin.scintilla.document import CScintillaDocument
|
||||
from pywin.framework.editor.document import EditorDocumentBase
|
||||
from pywin.scintilla import scintillacon # For the marker definitions
|
||||
import pywin.scintilla.view
|
||||
|
||||
class SyntEditDocument(EditorDocumentBase):
|
||||
"A SyntEdit document. "
|
||||
def OnDebuggerStateChange(self, state):
|
||||
self._ApplyOptionalToViews("OnDebuggerStateChange", state)
|
||||
def HookViewNotifications(self, view):
|
||||
EditorDocumentBase.HookViewNotifications(self, view)
|
||||
view.SCISetUndoCollection(1)
|
||||
def FinalizeViewCreation(self, view):
|
||||
EditorDocumentBase.FinalizeViewCreation(self, view)
|
||||
if view==self.GetFirstView():
|
||||
self.GetDocTemplate().CheckIDLEMenus(view.idle)
|
||||
|
||||
SyntEditViewParent=pywin.scintilla.view.CScintillaView
|
||||
class SyntEditView(SyntEditViewParent):
|
||||
"A view of a SyntEdit. Obtains data from document."
|
||||
def __init__(self, doc):
|
||||
SyntEditViewParent.__init__(self, doc)
|
||||
self.bCheckingFile = 0
|
||||
|
||||
def OnInitialUpdate(self):
|
||||
SyntEditViewParent.OnInitialUpdate(self)
|
||||
|
||||
self.HookMessage(self.OnRClick,win32con.WM_RBUTTONDOWN)
|
||||
|
||||
for id in [win32ui.ID_VIEW_FOLD_COLLAPSE, win32ui.ID_VIEW_FOLD_COLLAPSE_ALL,
|
||||
win32ui.ID_VIEW_FOLD_EXPAND, win32ui.ID_VIEW_FOLD_EXPAND_ALL]:
|
||||
|
||||
self.HookCommand(self.OnCmdViewFold, id)
|
||||
self.HookCommandUpdate(self.OnUpdateViewFold, id)
|
||||
self.HookCommand(self.OnCmdViewFoldTopLevel, win32ui.ID_VIEW_FOLD_TOPLEVEL)
|
||||
|
||||
# Define the markers
|
||||
# self.SCIMarkerDeleteAll()
|
||||
self.SCIMarkerDefineAll(MARKER_BOOKMARK, scintillacon.SC_MARK_ROUNDRECT, win32api.RGB(0x0, 0x0, 0x0), win32api.RGB(0, 0xff, 0xff))
|
||||
|
||||
self.SCIMarkerDefine(MARKER_CURRENT, scintillacon.SC_MARK_ARROW)
|
||||
self.SCIMarkerSetBack(MARKER_CURRENT, win32api.RGB(0xff, 0xff, 0x00))
|
||||
|
||||
# Define the folding markers
|
||||
if 1: #traditional markers
|
||||
self.SCIMarkerDefineAll(scintillacon.SC_MARKNUM_FOLDEROPEN, scintillacon.SC_MARK_MINUS, win32api.RGB(0xff, 0xff, 0xff), win32api.RGB(0, 0, 0))
|
||||
self.SCIMarkerDefineAll(scintillacon.SC_MARKNUM_FOLDER, scintillacon.SC_MARK_PLUS, win32api.RGB(0xff, 0xff, 0xff), win32api.RGB(0, 0, 0))
|
||||
self.SCIMarkerDefineAll(scintillacon.SC_MARKNUM_FOLDERSUB, scintillacon.SC_MARK_EMPTY, win32api.RGB(0xff, 0xff, 0xff), win32api.RGB(0, 0, 0))
|
||||
self.SCIMarkerDefineAll(scintillacon.SC_MARKNUM_FOLDERTAIL, scintillacon.SC_MARK_EMPTY, win32api.RGB(0xff, 0xff, 0xff), win32api.RGB(0, 0, 0))
|
||||
self.SCIMarkerDefineAll(scintillacon.SC_MARKNUM_FOLDEREND, scintillacon.SC_MARK_EMPTY, win32api.RGB(0xff, 0xff, 0xff), win32api.RGB(0, 0, 0))
|
||||
self.SCIMarkerDefineAll(scintillacon.SC_MARKNUM_FOLDEROPENMID, scintillacon.SC_MARK_EMPTY, win32api.RGB(0xff, 0xff, 0xff), win32api.RGB(0, 0, 0))
|
||||
self.SCIMarkerDefineAll(scintillacon.SC_MARKNUM_FOLDERMIDTAIL, scintillacon.SC_MARK_EMPTY, win32api.RGB(0xff, 0xff, 0xff), win32api.RGB(0, 0, 0))
|
||||
else: # curved markers
|
||||
self.SCIMarkerDefineAll(scintillacon.SC_MARKNUM_FOLDEROPEN, scintillacon.SC_MARK_CIRCLEMINUS, win32api.RGB(0xff, 0xff, 0xff), win32api.RGB(0, 0, 0))
|
||||
self.SCIMarkerDefineAll(scintillacon.SC_MARKNUM_FOLDER, scintillacon.SC_MARK_CIRCLEPLUS, win32api.RGB(0xff, 0xff, 0xff), win32api.RGB(0, 0, 0))
|
||||
self.SCIMarkerDefineAll(scintillacon.SC_MARKNUM_FOLDERSUB, scintillacon.SC_MARK_VLINE, win32api.RGB(0xff, 0xff, 0xff), win32api.RGB(0, 0, 0))
|
||||
self.SCIMarkerDefineAll(scintillacon.SC_MARKNUM_FOLDERTAIL, scintillacon.SC_MARK_LCORNERCURVE, win32api.RGB(0xff, 0xff, 0xff), win32api.RGB(0, 0, 0))
|
||||
self.SCIMarkerDefineAll(scintillacon.SC_MARKNUM_FOLDEREND, scintillacon.SC_MARK_CIRCLEPLUSCONNECTED, win32api.RGB(0xff, 0xff, 0xff), win32api.RGB(0, 0, 0))
|
||||
self.SCIMarkerDefineAll(scintillacon.SC_MARKNUM_FOLDEROPENMID, scintillacon.SC_MARK_CIRCLEMINUSCONNECTED, win32api.RGB(0xff, 0xff, 0xff), win32api.RGB(0, 0, 0))
|
||||
self.SCIMarkerDefineAll(scintillacon.SC_MARKNUM_FOLDERMIDTAIL, scintillacon.SC_MARK_TCORNERCURVE, win32api.RGB(0xff, 0xff, 0xff), win32api.RGB(0, 0, 0))
|
||||
|
||||
self.SCIMarkerDefine(MARKER_BREAKPOINT, scintillacon.SC_MARK_CIRCLE)
|
||||
# Marker background depends on debugger state
|
||||
self.SCIMarkerSetFore(MARKER_BREAKPOINT, win32api.RGB(0x0, 0, 0))
|
||||
# Get the current debugger state.
|
||||
try:
|
||||
import pywin.debugger
|
||||
if pywin.debugger.currentDebugger is None:
|
||||
state = dbgcon.DBGSTATE_NOT_DEBUGGING
|
||||
else:
|
||||
state = pywin.debugger.currentDebugger.debuggerState
|
||||
except ImportError:
|
||||
state = dbgcon.DBGSTATE_NOT_DEBUGGING
|
||||
self.OnDebuggerStateChange(state)
|
||||
|
||||
def _GetSubConfigNames(self):
|
||||
return ["editor"] # Allow [Keys:Editor] sections to be specific to us
|
||||
|
||||
def DoConfigChange(self):
|
||||
SyntEditViewParent.DoConfigChange(self)
|
||||
tabSize = GetEditorOption("Tab Size", 4, 2)
|
||||
indentSize = GetEditorOption("Indent Size", 4, 2)
|
||||
bUseTabs = GetEditorOption("Use Tabs", 0)
|
||||
bSmartTabs = GetEditorOption("Smart Tabs", 1)
|
||||
ext = self.idle.IDLEExtension("AutoIndent") # Required extension.
|
||||
|
||||
self.SCISetViewWS( GetEditorOption("View Whitespace", 0) )
|
||||
self.SCISetViewEOL( GetEditorOption("View EOL", 0) )
|
||||
self.SCISetIndentationGuides( GetEditorOption("View Indentation Guides", 0) )
|
||||
|
||||
if GetEditorOption("Right Edge Enabled", 0):
|
||||
mode = scintillacon.EDGE_BACKGROUND
|
||||
else:
|
||||
mode = scintillacon.EDGE_NONE
|
||||
self.SCISetEdgeMode(mode)
|
||||
self.SCISetEdgeColumn( GetEditorOption("Right Edge Column", 75) )
|
||||
self.SCISetEdgeColor( GetEditorOption("Right Edge Color", win32api.RGB(0xef, 0xef, 0xef)))
|
||||
|
||||
width = GetEditorOption("Marker Margin Width", 16)
|
||||
self.SCISetMarginWidthN(1, width)
|
||||
width = GetEditorOption("Fold Margin Width", 12)
|
||||
self.SCISetMarginWidthN(2, width)
|
||||
width = GetEditorOption("Line Number Margin Width", 0)
|
||||
self.SCISetMarginWidthN(0, width)
|
||||
self.bFolding = GetEditorOption("Enable Folding", 1)
|
||||
fold_flags = 0
|
||||
self.SendScintilla(scintillacon.SCI_SETMODEVENTMASK, scintillacon.SC_MOD_CHANGEFOLD);
|
||||
if self.bFolding:
|
||||
if GetEditorOption("Fold Lines", 1):
|
||||
fold_flags = 16
|
||||
|
||||
self.SCISetProperty("fold", self.bFolding)
|
||||
self.SCISetFoldFlags(fold_flags)
|
||||
|
||||
tt_color = GetEditorOption("Tab Timmy Color", win32api.RGB(0xff, 0, 0))
|
||||
self.SendScintilla(scintillacon.SCI_INDICSETFORE, 1, tt_color)
|
||||
|
||||
tt_use = GetEditorOption("Use Tab Timmy", 1)
|
||||
if tt_use:
|
||||
self.SCISetProperty("tab.timmy.whinge.level", "1")
|
||||
|
||||
# Auto-indent has very complicated behaviour. In a nutshell, the only
|
||||
# way to get sensible behaviour from it is to ensure tabwidth != indentsize.
|
||||
# Further, usetabs will only ever go from 1->0, never 0->1.
|
||||
# This is _not_ the behaviour Pythonwin wants:
|
||||
# * Tab width is arbitary, so should have no impact on smarts.
|
||||
# * bUseTabs setting should reflect how new files are created, and
|
||||
# if Smart Tabs disabled, existing files are edited
|
||||
# * If "Smart Tabs" is enabled, bUseTabs should have no bearing
|
||||
# for existing files (unless of course no context can be determined)
|
||||
#
|
||||
# So for smart tabs we configure the widget with completely dummy
|
||||
# values (ensuring tabwidth != indentwidth), ask it to guess, then
|
||||
# look at the values it has guessed, and re-configure
|
||||
if bSmartTabs:
|
||||
ext.config(usetabs=1, tabwidth=5, indentwidth=4)
|
||||
ext.set_indentation_params(1)
|
||||
if ext.indentwidth==5:
|
||||
# Either 5 literal spaces, or a single tab character. Assume a tab
|
||||
usetabs = 1
|
||||
indentwidth = tabSize
|
||||
else:
|
||||
# Either Indented with spaces, and indent size has been guessed or
|
||||
# an empty file (or no context found - tough!)
|
||||
if self.GetTextLength()==0: # emtpy
|
||||
usetabs = bUseTabs
|
||||
indentwidth = indentSize
|
||||
else: # guessed.
|
||||
indentwidth = ext.indentwidth
|
||||
usetabs = 0
|
||||
# Tab size can never be guessed - set at user preference.
|
||||
ext.config(usetabs=usetabs, indentwidth=indentwidth, tabwidth=tabSize)
|
||||
else:
|
||||
# Dont want smart-tabs - just set the options!
|
||||
ext.config(usetabs=bUseTabs, tabwidth=tabSize, indentwidth=indentSize)
|
||||
self.SCISetIndent(indentSize)
|
||||
self.SCISetTabWidth(tabSize)
|
||||
|
||||
def OnDebuggerStateChange(self, state):
|
||||
if state == dbgcon.DBGSTATE_NOT_DEBUGGING:
|
||||
# Indicate breakpoints arent really usable.
|
||||
# Not quite white - useful when no marker margin, so set as background color.
|
||||
self.SCIMarkerSetBack(MARKER_BREAKPOINT, win32api.RGB(0xef, 0xef, 0xef))
|
||||
else:
|
||||
# A light-red, so still readable when no marker margin.
|
||||
self.SCIMarkerSetBack(MARKER_BREAKPOINT, win32api.RGB(0xff, 0x80, 0x80))
|
||||
|
||||
def HookDocumentHandlers(self):
|
||||
SyntEditViewParent.HookDocumentHandlers(self)
|
||||
self.HookMessage(self.OnCheckExternalDocumentUpdated,MSG_CHECK_EXTERNAL_FILE)
|
||||
|
||||
def HookHandlers(self):
|
||||
SyntEditViewParent.HookHandlers(self)
|
||||
self.HookMessage(self.OnSetFocus, win32con.WM_SETFOCUS)
|
||||
|
||||
def _PrepareUserStateChange(self):
|
||||
return self.GetSel(), self.GetFirstVisibleLine()
|
||||
def _EndUserStateChange(self, info):
|
||||
scrollOff = info[1] - self.GetFirstVisibleLine()
|
||||
if scrollOff:
|
||||
self.LineScroll(scrollOff)
|
||||
# Make sure we dont reset the cursor beyond the buffer.
|
||||
max = self.GetTextLength()
|
||||
newPos = min(info[0][0], max), min(info[0][1], max)
|
||||
self.SetSel(newPos)
|
||||
|
||||
#######################################
|
||||
# The Windows Message or Notify handlers.
|
||||
#######################################
|
||||
def OnMarginClick(self, std, extra):
|
||||
notify = self.SCIUnpackNotifyMessage(extra)
|
||||
if notify.margin==2: # Our fold margin
|
||||
line_click = self.LineFromChar(notify.position)
|
||||
# max_line = self.GetLineCount()
|
||||
if self.SCIGetFoldLevel(line_click) & scintillacon.SC_FOLDLEVELHEADERFLAG:
|
||||
# If a fold point.
|
||||
self.SCIToggleFold(line_click)
|
||||
return 1
|
||||
|
||||
def OnSetFocus(self,msg):
|
||||
# Even though we use file change notifications, we should be very sure about it here.
|
||||
self.OnCheckExternalDocumentUpdated(msg)
|
||||
return 1
|
||||
|
||||
def OnCheckExternalDocumentUpdated(self, msg):
|
||||
if self.bCheckingFile: return
|
||||
self.bCheckingFile = 1
|
||||
self.GetDocument().CheckExternalDocumentUpdated()
|
||||
self.bCheckingFile = 0
|
||||
|
||||
def OnRClick(self,params):
|
||||
menu = win32ui.CreatePopupMenu()
|
||||
self.AppendMenu(menu, "&Locate module", "LocateModule")
|
||||
self.AppendMenu(menu, flags=win32con.MF_SEPARATOR)
|
||||
self.AppendMenu(menu, "&Undo", "EditUndo")
|
||||
self.AppendMenu(menu, '&Redo', 'EditRedo')
|
||||
self.AppendMenu(menu, flags=win32con.MF_SEPARATOR)
|
||||
self.AppendMenu(menu, 'Cu&t', 'EditCut')
|
||||
self.AppendMenu(menu, '&Copy', 'EditCopy')
|
||||
self.AppendMenu(menu, '&Paste', 'EditPaste')
|
||||
self.AppendMenu(menu, flags=win32con.MF_SEPARATOR)
|
||||
self.AppendMenu(menu, '&Select all', 'EditSelectAll')
|
||||
self.AppendMenu(menu, 'View &Whitespace', 'ViewWhitespace', checked=self.SCIGetViewWS())
|
||||
self.AppendMenu(menu, "&Fixed Font", "ViewFixedFont", checked = self._GetColorizer().bUseFixed)
|
||||
self.AppendMenu(menu, flags=win32con.MF_SEPARATOR)
|
||||
self.AppendMenu(menu, "&Goto line...", "GotoLine")
|
||||
|
||||
submenu = win32ui.CreatePopupMenu()
|
||||
newitems = self.idle.GetMenuItems("edit")
|
||||
for text, event in newitems:
|
||||
self.AppendMenu(submenu, text, event)
|
||||
|
||||
flags=win32con.MF_STRING|win32con.MF_ENABLED|win32con.MF_POPUP
|
||||
menu.AppendMenu(flags, submenu.GetHandle(), "&Source code")
|
||||
|
||||
flags = win32con.TPM_LEFTALIGN|win32con.TPM_LEFTBUTTON|win32con.TPM_RIGHTBUTTON
|
||||
menu.TrackPopupMenu(params[5], flags, self)
|
||||
return 0
|
||||
def OnCmdViewFold(self, cid, code): # Handle the menu command
|
||||
if cid == win32ui.ID_VIEW_FOLD_EXPAND_ALL:
|
||||
self.FoldExpandAllEvent(None)
|
||||
elif cid == win32ui.ID_VIEW_FOLD_EXPAND:
|
||||
self.FoldExpandEvent(None)
|
||||
elif cid == win32ui.ID_VIEW_FOLD_COLLAPSE_ALL:
|
||||
self.FoldCollapseAllEvent(None)
|
||||
elif cid == win32ui.ID_VIEW_FOLD_COLLAPSE:
|
||||
self.FoldCollapseEvent(None)
|
||||
else:
|
||||
print("Unknown collapse/expand ID")
|
||||
def OnUpdateViewFold(self, cmdui): # Update the tick on the UI.
|
||||
if not self.bFolding:
|
||||
cmdui.Enable(0)
|
||||
return
|
||||
id = cmdui.m_nID
|
||||
if id in [win32ui.ID_VIEW_FOLD_EXPAND_ALL, win32ui.ID_VIEW_FOLD_COLLAPSE_ALL]:
|
||||
cmdui.Enable()
|
||||
else:
|
||||
enable = 0
|
||||
lineno = self.LineFromChar(self.GetSel()[0])
|
||||
foldable = self.SCIGetFoldLevel(lineno) & scintillacon.SC_FOLDLEVELHEADERFLAG
|
||||
is_expanded = self.SCIGetFoldExpanded(lineno)
|
||||
if id == win32ui.ID_VIEW_FOLD_EXPAND:
|
||||
if foldable and not is_expanded:
|
||||
enable = 1
|
||||
elif id == win32ui.ID_VIEW_FOLD_COLLAPSE:
|
||||
if foldable and is_expanded:
|
||||
enable = 1
|
||||
cmdui.Enable(enable)
|
||||
|
||||
def OnCmdViewFoldTopLevel(self, cid, code): # Handle the menu command
|
||||
self.FoldTopLevelEvent(None)
|
||||
|
||||
#######################################
|
||||
# The Events
|
||||
#######################################
|
||||
def ToggleBookmarkEvent(self, event, pos = -1):
|
||||
"""Toggle a bookmark at the specified or current position
|
||||
"""
|
||||
if pos==-1:
|
||||
pos, end = self.GetSel()
|
||||
startLine = self.LineFromChar(pos)
|
||||
self.GetDocument().MarkerToggle(startLine+1, MARKER_BOOKMARK)
|
||||
return 0
|
||||
|
||||
def GotoNextBookmarkEvent(self, event, fromPos=-1):
|
||||
""" Move to the next bookmark
|
||||
"""
|
||||
if fromPos==-1:
|
||||
fromPos, end = self.GetSel()
|
||||
startLine = self.LineFromChar(fromPos)+1 # Zero based line to start
|
||||
nextLine = self.GetDocument().MarkerGetNext(startLine+1, MARKER_BOOKMARK)-1
|
||||
if nextLine<0:
|
||||
nextLine = self.GetDocument().MarkerGetNext(0, MARKER_BOOKMARK)-1
|
||||
if nextLine <0 or nextLine == startLine-1:
|
||||
win32api.MessageBeep()
|
||||
else:
|
||||
self.SCIEnsureVisible(nextLine)
|
||||
self.SCIGotoLine(nextLine)
|
||||
return 0
|
||||
|
||||
def TabKeyEvent(self, event):
|
||||
"""Insert an indent. If no selection, a single indent, otherwise a block indent
|
||||
"""
|
||||
# Handle auto-complete first.
|
||||
if self.SCIAutoCActive():
|
||||
self.SCIAutoCComplete()
|
||||
return 0
|
||||
# Call the IDLE event.
|
||||
return self.bindings.fire("<<smart-indent>>", event)
|
||||
|
||||
def EnterKeyEvent(self, event):
|
||||
"""Handle the enter key with special handling for auto-complete
|
||||
"""
|
||||
# Handle auto-complete first.
|
||||
if self.SCIAutoCActive():
|
||||
self.SCIAutoCComplete()
|
||||
self.SCIAutoCCancel()
|
||||
# Call the IDLE event.
|
||||
return self.bindings.fire("<<newline-and-indent>>", event)
|
||||
|
||||
def ShowInteractiveWindowEvent(self, event):
|
||||
import pywin.framework.interact
|
||||
pywin.framework.interact.ShowInteractiveWindow()
|
||||
|
||||
def FoldTopLevelEvent(self, event = None):
|
||||
if not self.bFolding:
|
||||
return 1
|
||||
|
||||
win32ui.DoWaitCursor(1)
|
||||
try:
|
||||
self.Colorize()
|
||||
maxLine = self.GetLineCount()
|
||||
# Find the first line, and check out its state.
|
||||
for lineSeek in range(maxLine):
|
||||
if self.SCIGetFoldLevel(lineSeek) & scintillacon.SC_FOLDLEVELHEADERFLAG:
|
||||
expanding = not self.SCIGetFoldExpanded(lineSeek)
|
||||
break
|
||||
else:
|
||||
# no folds here!
|
||||
return
|
||||
for lineSeek in range(lineSeek, maxLine):
|
||||
level = self.SCIGetFoldLevel(lineSeek)
|
||||
level_no = level & scintillacon.SC_FOLDLEVELNUMBERMASK - scintillacon.SC_FOLDLEVELBASE
|
||||
is_header = level & scintillacon.SC_FOLDLEVELHEADERFLAG
|
||||
# print lineSeek, level_no, is_header
|
||||
if level_no == 0 and is_header:
|
||||
if (expanding and not self.SCIGetFoldExpanded(lineSeek)) or \
|
||||
(not expanding and self.SCIGetFoldExpanded(lineSeek)):
|
||||
self.SCIToggleFold(lineSeek)
|
||||
finally:
|
||||
win32ui.DoWaitCursor(-1)
|
||||
|
||||
def FoldExpandSecondLevelEvent(self, event):
|
||||
if not self.bFolding:
|
||||
return 1
|
||||
win32ui.DoWaitCursor(1)
|
||||
## I think this is needed since Scintilla may not have
|
||||
## already formatted parts of file outside visible window.
|
||||
self.Colorize()
|
||||
levels=[scintillacon.SC_FOLDLEVELBASE]
|
||||
## Scintilla's level number is based on amount of whitespace indentation
|
||||
for lineno in range(self.GetLineCount()):
|
||||
level = self.SCIGetFoldLevel(lineno)
|
||||
if not level & scintillacon.SC_FOLDLEVELHEADERFLAG:
|
||||
continue
|
||||
curr_level = level & scintillacon.SC_FOLDLEVELNUMBERMASK
|
||||
if curr_level > levels[-1]:
|
||||
levels.append(curr_level)
|
||||
try:
|
||||
level_ind=levels.index(curr_level)
|
||||
except ValueError:
|
||||
## probably syntax error in source file, bail
|
||||
break
|
||||
levels=levels[:level_ind+1]
|
||||
if level_ind == 1 and not self.SCIGetFoldExpanded(lineno):
|
||||
self.SCIToggleFold(lineno)
|
||||
win32ui.DoWaitCursor(-1)
|
||||
|
||||
def FoldCollapseSecondLevelEvent(self, event):
|
||||
if not self.bFolding:
|
||||
return 1
|
||||
win32ui.DoWaitCursor(1)
|
||||
## I think this is needed since Scintilla may not have
|
||||
## already formatted parts of file outside visible window.
|
||||
self.Colorize()
|
||||
levels=[scintillacon.SC_FOLDLEVELBASE]
|
||||
## Scintilla's level number is based on amount of whitespace indentation
|
||||
for lineno in range(self.GetLineCount()):
|
||||
level = self.SCIGetFoldLevel(lineno)
|
||||
if not level & scintillacon.SC_FOLDLEVELHEADERFLAG:
|
||||
continue
|
||||
curr_level = level & scintillacon.SC_FOLDLEVELNUMBERMASK
|
||||
if curr_level > levels[-1]:
|
||||
levels.append(curr_level)
|
||||
try:
|
||||
level_ind=levels.index(curr_level)
|
||||
except ValueError:
|
||||
## probably syntax error in source file, bail
|
||||
break
|
||||
levels=levels[:level_ind+1]
|
||||
if level_ind == 1 and self.SCIGetFoldExpanded(lineno):
|
||||
self.SCIToggleFold(lineno)
|
||||
win32ui.DoWaitCursor(-1)
|
||||
|
||||
def FoldExpandEvent(self, event):
|
||||
if not self.bFolding:
|
||||
return 1
|
||||
win32ui.DoWaitCursor(1)
|
||||
lineno = self.LineFromChar(self.GetSel()[0])
|
||||
if self.SCIGetFoldLevel(lineno) & scintillacon.SC_FOLDLEVELHEADERFLAG and \
|
||||
not self.SCIGetFoldExpanded(lineno):
|
||||
self.SCIToggleFold(lineno)
|
||||
win32ui.DoWaitCursor(-1)
|
||||
|
||||
def FoldExpandAllEvent(self, event):
|
||||
if not self.bFolding:
|
||||
return 1
|
||||
win32ui.DoWaitCursor(1)
|
||||
for lineno in range(0, self.GetLineCount()):
|
||||
if self.SCIGetFoldLevel(lineno) & scintillacon.SC_FOLDLEVELHEADERFLAG and \
|
||||
not self.SCIGetFoldExpanded(lineno):
|
||||
self.SCIToggleFold(lineno)
|
||||
win32ui.DoWaitCursor(-1)
|
||||
|
||||
def FoldCollapseEvent(self, event):
|
||||
if not self.bFolding:
|
||||
return 1
|
||||
win32ui.DoWaitCursor(1)
|
||||
lineno = self.LineFromChar(self.GetSel()[0])
|
||||
if self.SCIGetFoldLevel(lineno) & scintillacon.SC_FOLDLEVELHEADERFLAG and \
|
||||
self.SCIGetFoldExpanded(lineno):
|
||||
self.SCIToggleFold(lineno)
|
||||
win32ui.DoWaitCursor(-1)
|
||||
|
||||
def FoldCollapseAllEvent(self, event):
|
||||
if not self.bFolding:
|
||||
return 1
|
||||
win32ui.DoWaitCursor(1)
|
||||
self.Colorize()
|
||||
for lineno in range(0, self.GetLineCount()):
|
||||
if self.SCIGetFoldLevel(lineno) & scintillacon.SC_FOLDLEVELHEADERFLAG and \
|
||||
self.SCIGetFoldExpanded(lineno):
|
||||
self.SCIToggleFold(lineno)
|
||||
win32ui.DoWaitCursor(-1)
|
||||
|
||||
|
||||
from pywin.framework.editor.frame import EditorFrame
|
||||
class SplitterFrame(EditorFrame):
|
||||
def OnCreate(self, cs):
|
||||
self.HookCommand(self.OnWindowSplit, win32ui.ID_WINDOW_SPLIT)
|
||||
return 1
|
||||
def OnWindowSplit(self, id, code):
|
||||
self.GetDlgItem(win32ui.AFX_IDW_PANE_FIRST).DoKeyboardSplit()
|
||||
return 1
|
||||
|
||||
from pywin.framework.editor.template import EditorTemplateBase
|
||||
class SyntEditTemplate(EditorTemplateBase):
|
||||
def __init__(self, res=win32ui.IDR_TEXTTYPE, makeDoc=None, makeFrame=None, makeView=None):
|
||||
if makeDoc is None: makeDoc = SyntEditDocument
|
||||
if makeView is None: makeView = SyntEditView
|
||||
if makeFrame is None: makeFrame = SplitterFrame
|
||||
self.bSetMenus = 0
|
||||
EditorTemplateBase.__init__(self, res, makeDoc, makeFrame, makeView)
|
||||
|
||||
def CheckIDLEMenus(self, idle):
|
||||
if self.bSetMenus: return
|
||||
self.bSetMenus = 1
|
||||
|
||||
submenu = win32ui.CreatePopupMenu()
|
||||
newitems = idle.GetMenuItems("edit")
|
||||
flags=win32con.MF_STRING|win32con.MF_ENABLED
|
||||
for text, event in newitems:
|
||||
id = bindings.event_to_commands.get(event)
|
||||
if id is not None:
|
||||
keyname = pywin.scintilla.view.configManager.get_key_binding( event, ["editor"] )
|
||||
if keyname is not None:
|
||||
text = text + "\t" + keyname
|
||||
submenu.AppendMenu(flags, id, text)
|
||||
|
||||
mainMenu = self.GetSharedMenu()
|
||||
editMenu = mainMenu.GetSubMenu(1)
|
||||
editMenu.AppendMenu(win32con.MF_SEPARATOR, 0, "")
|
||||
editMenu.AppendMenu(win32con.MF_STRING | win32con.MF_POPUP | win32con.MF_ENABLED, submenu.GetHandle(), "&Source Code")
|
||||
|
||||
def _CreateDocTemplate(self, resourceId):
|
||||
return win32ui.CreateDocTemplate(resourceId)
|
||||
|
||||
def CreateWin32uiDocument(self):
|
||||
return self.DoCreateDoc()
|
||||
|
||||
def GetPythonPropertyPages(self):
|
||||
"""Returns a list of property pages
|
||||
"""
|
||||
from pywin.scintilla import configui
|
||||
return EditorTemplateBase.GetPythonPropertyPages(self) + [configui.ScintillaFormatPropertyPage()]
|
||||
|
||||
# For debugging purposes, when this module may be reloaded many times.
|
||||
try:
|
||||
win32ui.GetApp().RemoveDocTemplate(editorTemplate)
|
||||
except NameError:
|
||||
pass
|
||||
|
||||
editorTemplate = SyntEditTemplate()
|
||||
win32ui.GetApp().AddDocTemplate(editorTemplate)
|
||||
257
Lib/site-packages/pythonwin/pywin/framework/editor/configui.py
Normal file
257
Lib/site-packages/pythonwin/pywin/framework/editor/configui.py
Normal file
|
|
@ -0,0 +1,257 @@
|
|||
from pywin.mfc import dialog
|
||||
from . import document
|
||||
import win32ui
|
||||
import win32con
|
||||
import win32api
|
||||
|
||||
from pywin.framework.editor import GetEditorOption, SetEditorOption, DeleteEditorOption, GetEditorFontOption, SetEditorFontOption, defaultCharacterFormat, editorTemplate
|
||||
import pywin.scintilla.config
|
||||
|
||||
# The standard 16 color VGA palette should always be possible
|
||||
paletteVGA = ( ("Black",0,0,0), ("Navy",0,0,128), ("Green",0,128,0), ("Cyan",0,128,128),
|
||||
("Maroon",128,0,0), ("Purple",128,0,128), ("Olive",128,128,0), ("Gray",128,128,128),
|
||||
("Silver",192,192,192), ("Blue",0,0,255), ("Lime",0,255,0), ("Aqua",0,255,255),
|
||||
("Red",255,0,0), ("Fuchsia",255,0,255), ("Yellow",255,255,0), ("White",255,255,255) )
|
||||
|
||||
######################################################
|
||||
#
|
||||
# Property Page for editor options
|
||||
#
|
||||
class EditorPropertyPage(dialog.PropertyPage):
|
||||
def __init__(self):
|
||||
dialog.PropertyPage.__init__(self, win32ui.IDD_PP_EDITOR)
|
||||
self.autooptions = []
|
||||
self._AddEditorOption(win32ui.IDC_AUTO_RELOAD, "i", "Auto Reload", 1)
|
||||
self._AddEditorOption(win32ui.IDC_COMBO1, "i", "Backup Type", document.BAK_DOT_BAK_BAK_DIR)
|
||||
self._AddEditorOption(win32ui.IDC_AUTOCOMPLETE, "i", "Autocomplete Attributes", 1)
|
||||
self._AddEditorOption(win32ui.IDC_CALLTIPS, "i", "Show Call Tips", 1)
|
||||
self._AddEditorOption(win32ui.IDC_MARGIN_LINENUMBER, "i", "Line Number Margin Width", 0)
|
||||
self._AddEditorOption(win32ui.IDC_RADIO1, "i", "MarkersInMargin", None)
|
||||
self._AddEditorOption(win32ui.IDC_MARGIN_MARKER, "i", "Marker Margin Width", None)
|
||||
self["Marker Margin Width"] = GetEditorOption("Marker Margin Width", 16)
|
||||
|
||||
# Folding
|
||||
self._AddEditorOption(win32ui.IDC_MARGIN_FOLD, "i", "Fold Margin Width", 12)
|
||||
self._AddEditorOption(win32ui.IDC_FOLD_ENABLE, "i", "Enable Folding", 1)
|
||||
self._AddEditorOption(win32ui.IDC_FOLD_ON_OPEN, "i", "Fold On Open", 0)
|
||||
self._AddEditorOption(win32ui.IDC_FOLD_SHOW_LINES, "i", "Fold Lines", 1)
|
||||
|
||||
# Right edge.
|
||||
self._AddEditorOption(win32ui.IDC_RIGHTEDGE_ENABLE, "i", "Right Edge Enabled", 0)
|
||||
self._AddEditorOption(win32ui.IDC_RIGHTEDGE_COLUMN, "i", "Right Edge Column", 75)
|
||||
|
||||
# Source control, etc
|
||||
self.AddDDX(win32ui.IDC_VSS_INTEGRATE, "bVSS")
|
||||
self.AddDDX(win32ui.IDC_KEYBOARD_CONFIG, "Configs", "l")
|
||||
self["Configs"] = pywin.scintilla.config.find_config_files()
|
||||
|
||||
|
||||
|
||||
def _AddEditorOption(self, idd, typ, optionName, defaultVal):
|
||||
self.AddDDX(idd, optionName, typ)
|
||||
# some options are "derived" - ie, can be implied from others
|
||||
# (eg, "view markers in background" is implied from "markerMarginWidth==0"
|
||||
# So we don't actually store these values, but they do still get DDX support.
|
||||
if defaultVal is not None:
|
||||
self[optionName] = GetEditorOption(optionName, defaultVal)
|
||||
self.autooptions.append((optionName, defaultVal))
|
||||
|
||||
def OnInitDialog(self):
|
||||
for name, val in self.autooptions:
|
||||
self[name] = GetEditorOption(name, val)
|
||||
|
||||
# Note that these MUST be in the same order as the BAK constants.
|
||||
cbo = self.GetDlgItem(win32ui.IDC_COMBO1)
|
||||
cbo.AddString("None")
|
||||
cbo.AddString(".BAK File")
|
||||
cbo.AddString("TEMP dir")
|
||||
cbo.AddString("Own dir")
|
||||
|
||||
# Source Safe
|
||||
bVSS = GetEditorOption("Source Control Module", "") == "pywin.framework.editor.vss"
|
||||
self['bVSS'] = bVSS
|
||||
|
||||
edit = self.GetDlgItem(win32ui.IDC_RIGHTEDGE_SAMPLE)
|
||||
edit.SetWindowText("Sample Color")
|
||||
|
||||
rc = dialog.PropertyPage.OnInitDialog(self)
|
||||
|
||||
try:
|
||||
self.GetDlgItem(win32ui.IDC_KEYBOARD_CONFIG).SelectString(-1, GetEditorOption("Keyboard Config", "default"))
|
||||
except win32ui.error:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
pass
|
||||
|
||||
self.HookCommand(self.OnButSimple, win32ui.IDC_FOLD_ENABLE)
|
||||
self.HookCommand(self.OnButSimple, win32ui.IDC_RADIO1)
|
||||
self.HookCommand(self.OnButSimple, win32ui.IDC_RADIO2)
|
||||
self.HookCommand(self.OnButSimple, win32ui.IDC_RIGHTEDGE_ENABLE)
|
||||
self.HookCommand(self.OnButEdgeColor, win32ui.IDC_RIGHTEDGE_DEFINE)
|
||||
|
||||
butMarginEnabled = self['Marker Margin Width'] > 0
|
||||
self.GetDlgItem(win32ui.IDC_RADIO1).SetCheck(butMarginEnabled)
|
||||
self.GetDlgItem(win32ui.IDC_RADIO2).SetCheck(not butMarginEnabled)
|
||||
|
||||
self.edgeColor = self.initialEdgeColor = GetEditorOption("Right Edge Color", win32api.RGB(0xef, 0xef, 0xef))
|
||||
for spinner_id in (win32ui.IDC_SPIN1, win32ui.IDC_SPIN2, win32ui.IDC_SPIN3):
|
||||
spinner=self.GetDlgItem(spinner_id)
|
||||
spinner.SetRange(0,100)
|
||||
self.UpdateUIForState()
|
||||
|
||||
return rc
|
||||
|
||||
def OnButSimple(self, id, code):
|
||||
if code == win32con.BN_CLICKED:
|
||||
self.UpdateUIForState()
|
||||
|
||||
def OnButEdgeColor(self, id, code):
|
||||
if code == win32con.BN_CLICKED:
|
||||
d = win32ui.CreateColorDialog(self.edgeColor, 0, self)
|
||||
# Ensure the current color is a custom color (as it may not be in the swatch)
|
||||
# plus some other nice gray scales.
|
||||
ccs = [self.edgeColor]
|
||||
for c in range(0xef, 0x4f, -0x10):
|
||||
ccs.append(win32api.RGB(c,c,c))
|
||||
d.SetCustomColors( ccs )
|
||||
if d.DoModal() == win32con.IDOK:
|
||||
self.edgeColor = d.GetColor()
|
||||
self.UpdateUIForState()
|
||||
|
||||
def UpdateUIForState(self):
|
||||
folding = self.GetDlgItem(win32ui.IDC_FOLD_ENABLE).GetCheck()
|
||||
self.GetDlgItem(win32ui.IDC_FOLD_ON_OPEN).EnableWindow(folding)
|
||||
self.GetDlgItem(win32ui.IDC_FOLD_SHOW_LINES).EnableWindow(folding)
|
||||
|
||||
widthEnabled = self.GetDlgItem(win32ui.IDC_RADIO1).GetCheck()
|
||||
self.GetDlgItem(win32ui.IDC_MARGIN_MARKER).EnableWindow(widthEnabled)
|
||||
self.UpdateData() # Ensure self[] is up to date with the control data.
|
||||
if widthEnabled and self["Marker Margin Width"] == 0:
|
||||
self["Marker Margin Width"] = 16
|
||||
self.UpdateData(0) # Ensure control up to date with self[]
|
||||
|
||||
# Right edge
|
||||
edgeEnabled = self.GetDlgItem(win32ui.IDC_RIGHTEDGE_ENABLE).GetCheck()
|
||||
self.GetDlgItem(win32ui.IDC_RIGHTEDGE_COLUMN).EnableWindow(edgeEnabled)
|
||||
self.GetDlgItem(win32ui.IDC_RIGHTEDGE_SAMPLE).EnableWindow(edgeEnabled)
|
||||
self.GetDlgItem(win32ui.IDC_RIGHTEDGE_DEFINE).EnableWindow(edgeEnabled)
|
||||
|
||||
edit = self.GetDlgItem(win32ui.IDC_RIGHTEDGE_SAMPLE)
|
||||
edit.SetBackgroundColor(0, self.edgeColor)
|
||||
|
||||
def OnOK(self):
|
||||
for name, defVal in self.autooptions:
|
||||
SetEditorOption(name, self[name])
|
||||
# Margin width gets handled differently.
|
||||
if self['MarkersInMargin'] == 0:
|
||||
SetEditorOption("Marker Margin Width", self["Marker Margin Width"])
|
||||
else:
|
||||
SetEditorOption("Marker Margin Width", 0)
|
||||
if self.edgeColor != self.initialEdgeColor:
|
||||
SetEditorOption("Right Edge Color", self.edgeColor)
|
||||
if self['bVSS']:
|
||||
SetEditorOption("Source Control Module", "pywin.framework.editor.vss")
|
||||
else:
|
||||
if GetEditorOption("Source Control Module", "")=='pywin.framework.editor.vss':
|
||||
SetEditorOption("Source Control Module", "")
|
||||
# Keyboard config
|
||||
configname = self.GetDlgItem(win32ui.IDC_KEYBOARD_CONFIG).GetWindowText()
|
||||
if configname:
|
||||
if configname == "default":
|
||||
DeleteEditorOption("Keyboard Config")
|
||||
else:
|
||||
SetEditorOption("Keyboard Config", configname)
|
||||
|
||||
import pywin.scintilla.view
|
||||
pywin.scintilla.view.LoadConfiguration()
|
||||
|
||||
# Now tell all views we have changed.
|
||||
## for doc in editorTemplate.GetDocumentList():
|
||||
## for view in doc.GetAllViews():
|
||||
## try:
|
||||
## fn = view.OnConfigChange
|
||||
## except AttributeError:
|
||||
## continue
|
||||
## fn()
|
||||
return 1
|
||||
|
||||
class EditorWhitespacePropertyPage(dialog.PropertyPage):
|
||||
def __init__(self):
|
||||
dialog.PropertyPage.__init__(self, win32ui.IDD_PP_TABS)
|
||||
self.autooptions = []
|
||||
self._AddEditorOption(win32ui.IDC_TAB_SIZE, "i", "Tab Size", 4)
|
||||
self._AddEditorOption(win32ui.IDC_INDENT_SIZE, "i", "Indent Size", 4)
|
||||
self._AddEditorOption(win32ui.IDC_USE_SMART_TABS, "i", "Smart Tabs", 1)
|
||||
self._AddEditorOption(win32ui.IDC_VIEW_WHITESPACE, "i", "View Whitespace", 0)
|
||||
self._AddEditorOption(win32ui.IDC_VIEW_EOL, "i", "View EOL", 0)
|
||||
self._AddEditorOption(win32ui.IDC_VIEW_INDENTATIONGUIDES, "i", "View Indentation Guides", 0)
|
||||
|
||||
def _AddEditorOption(self, idd, typ, optionName, defaultVal):
|
||||
self.AddDDX(idd, optionName, typ)
|
||||
self[optionName] = GetEditorOption(optionName, defaultVal)
|
||||
self.autooptions.append((optionName, defaultVal))
|
||||
|
||||
def OnInitDialog(self):
|
||||
for name, val in self.autooptions:
|
||||
self[name] = GetEditorOption(name, val)
|
||||
|
||||
rc = dialog.PropertyPage.OnInitDialog(self)
|
||||
|
||||
idc = win32ui.IDC_TABTIMMY_NONE
|
||||
if GetEditorOption("Use Tab Timmy", 1):
|
||||
idc = win32ui.IDC_TABTIMMY_IND
|
||||
self.GetDlgItem(idc).SetCheck(1)
|
||||
|
||||
idc = win32ui.IDC_RADIO1
|
||||
if GetEditorOption("Use Tabs", 0):
|
||||
idc = win32ui.IDC_USE_TABS
|
||||
self.GetDlgItem(idc).SetCheck(1)
|
||||
|
||||
tt_color = GetEditorOption("Tab Timmy Color", win32api.RGB(0xff, 0, 0))
|
||||
self.cbo = self.GetDlgItem(win32ui.IDC_COMBO1)
|
||||
for c in paletteVGA:
|
||||
self.cbo.AddString(c[0])
|
||||
sel = 0
|
||||
for c in paletteVGA:
|
||||
if tt_color == win32api.RGB(c[1], c[2], c[3]):
|
||||
break
|
||||
sel = sel + 1
|
||||
else:
|
||||
sel = -1
|
||||
self.cbo.SetCurSel(sel)
|
||||
self.HookCommand(self.OnButSimple, win32ui.IDC_TABTIMMY_NONE)
|
||||
self.HookCommand(self.OnButSimple, win32ui.IDC_TABTIMMY_IND)
|
||||
self.HookCommand(self.OnButSimple, win32ui.IDC_TABTIMMY_BG)
|
||||
# Set ranges for the spinners.
|
||||
for spinner_id in [win32ui.IDC_SPIN1, win32ui.IDC_SPIN2]:
|
||||
spinner = self.GetDlgItem(spinner_id)
|
||||
spinner.SetRange(1, 16)
|
||||
return rc
|
||||
|
||||
def OnButSimple(self, id, code):
|
||||
if code == win32con.BN_CLICKED:
|
||||
self.UpdateUIForState()
|
||||
|
||||
def UpdateUIForState(self):
|
||||
timmy = self.GetDlgItem(win32ui.IDC_TABTIMMY_NONE).GetCheck()
|
||||
self.GetDlgItem(win32ui.IDC_COMBO1).EnableWindow(not timmy)
|
||||
|
||||
def OnOK(self):
|
||||
for name, defVal in self.autooptions:
|
||||
SetEditorOption(name, self[name])
|
||||
|
||||
SetEditorOption("Use Tabs", self.GetDlgItem(win32ui.IDC_USE_TABS).GetCheck())
|
||||
|
||||
SetEditorOption("Use Tab Timmy", self.GetDlgItem(win32ui.IDC_TABTIMMY_IND).GetCheck())
|
||||
c = paletteVGA[self.cbo.GetCurSel()]
|
||||
SetEditorOption("Tab Timmy Color", win32api.RGB(c[1], c[2], c[3]))
|
||||
|
||||
return 1
|
||||
|
||||
def testpp():
|
||||
ps = dialog.PropertySheet("Editor Options")
|
||||
ps.AddPage(EditorWhitespacePropertyPage())
|
||||
ps.DoModal()
|
||||
|
||||
if __name__=='__main__':
|
||||
testpp()
|
||||
332
Lib/site-packages/pythonwin/pywin/framework/editor/document.py
Normal file
332
Lib/site-packages/pythonwin/pywin/framework/editor/document.py
Normal file
|
|
@ -0,0 +1,332 @@
|
|||
# We no longer support the old, non-colour editor!
|
||||
|
||||
from pywin.mfc import docview, object
|
||||
from pywin.framework.editor import GetEditorOption
|
||||
import win32ui
|
||||
import os
|
||||
import win32con
|
||||
import string
|
||||
import traceback
|
||||
import win32api
|
||||
import shutil
|
||||
|
||||
BAK_NONE=0
|
||||
BAK_DOT_BAK=1
|
||||
BAK_DOT_BAK_TEMP_DIR=2
|
||||
BAK_DOT_BAK_BAK_DIR=3
|
||||
|
||||
MSG_CHECK_EXTERNAL_FILE = win32con.WM_USER+1999 ## WARNING: Duplicated in editor.py and coloreditor.py
|
||||
|
||||
import pywin.scintilla.document
|
||||
ParentEditorDocument=pywin.scintilla.document.CScintillaDocument
|
||||
class EditorDocumentBase(ParentEditorDocument):
|
||||
def __init__(self, template):
|
||||
self.bAutoReload = GetEditorOption("Auto Reload", 1)
|
||||
self.bDeclinedReload = 0 # Has the user declined to reload.
|
||||
self.fileStat = None
|
||||
self.bReportedFileNotFound = 0
|
||||
|
||||
# what sort of bak file should I create.
|
||||
# default to write to %temp%/bak/filename.ext
|
||||
self.bakFileType=GetEditorOption("Backup Type", BAK_DOT_BAK_BAK_DIR)
|
||||
|
||||
self.watcherThread = FileWatchingThread(self)
|
||||
self.watcherThread.CreateThread()
|
||||
# Should I try and use VSS integration?
|
||||
self.scModuleName=GetEditorOption("Source Control Module", "")
|
||||
self.scModule = None # Loaded when first used.
|
||||
ParentEditorDocument.__init__(self, template, template.CreateWin32uiDocument())
|
||||
|
||||
def OnCloseDocument(self ):
|
||||
self.watcherThread.SignalStop()
|
||||
return self._obj_.OnCloseDocument()
|
||||
|
||||
# def OnOpenDocument(self, name):
|
||||
# rc = ParentEditorDocument.OnOpenDocument(self, name)
|
||||
# self.GetFirstView()._SetLoadedText(self.text)
|
||||
# self._DocumentStateChanged()
|
||||
# return rc
|
||||
|
||||
def OnSaveDocument( self, fileName ):
|
||||
win32ui.SetStatusText("Saving file...",1)
|
||||
# rename to bak if required.
|
||||
dir, basename = os.path.split(fileName)
|
||||
if self.bakFileType==BAK_DOT_BAK:
|
||||
bakFileName=dir+'\\'+os.path.splitext(basename)[0]+'.bak'
|
||||
elif self.bakFileType==BAK_DOT_BAK_TEMP_DIR:
|
||||
bakFileName=win32api.GetTempPath()+'\\'+os.path.splitext(basename)[0]+'.bak'
|
||||
elif self.bakFileType==BAK_DOT_BAK_BAK_DIR:
|
||||
tempPath=os.path.join(win32api.GetTempPath(),'bak')
|
||||
try:
|
||||
os.mkdir(tempPath,0)
|
||||
except os.error:
|
||||
pass
|
||||
bakFileName=os.path.join(tempPath,basename)
|
||||
try:
|
||||
os.unlink(bakFileName) # raise NameError if no bakups wanted.
|
||||
except (os.error, NameError):
|
||||
pass
|
||||
try:
|
||||
# Do a copy as it might be on different volumes,
|
||||
# and the file may be a hard-link, causing the link
|
||||
# to follow the backup.
|
||||
shutil.copy2(fileName, bakFileName)
|
||||
except (os.error, NameError, IOError):
|
||||
pass
|
||||
try:
|
||||
self.SaveFile(fileName)
|
||||
except IOError as details:
|
||||
win32ui.MessageBox("Error - could not save file\r\n\r\n%s"%details)
|
||||
return 0
|
||||
except (UnicodeEncodeError, LookupError) as details:
|
||||
rc = win32ui.MessageBox("Encoding failed: \r\n%s"%details +
|
||||
'\r\nPlease add desired source encoding as first line of file, eg \r\n' +
|
||||
'# -*- coding: mbcs -*-\r\n\r\n' +
|
||||
'If you continue, the file will be saved as binary and will\r\n' +
|
||||
'not be valid in the declared encoding.\r\n\r\n' +
|
||||
'Save the file as binary with an invalid encoding?',
|
||||
"File save failed",
|
||||
win32con.MB_YESNO | win32con.MB_DEFBUTTON2)
|
||||
if rc==win32con.IDYES:
|
||||
try:
|
||||
self.SaveFile(fileName, encoding="latin-1")
|
||||
except IOError as details:
|
||||
win32ui.MessageBox("Error - could not save file\r\n\r\n%s"%details)
|
||||
return 0
|
||||
else:
|
||||
return 0
|
||||
self.SetModifiedFlag(0) # No longer dirty
|
||||
self.bDeclinedReload = 0 # They probably want to know if it changes again!
|
||||
win32ui.AddToRecentFileList(fileName)
|
||||
self.SetPathName(fileName)
|
||||
win32ui.SetStatusText("Ready")
|
||||
self._DocumentStateChanged()
|
||||
return 1
|
||||
|
||||
def FinalizeViewCreation(self, view):
|
||||
ParentEditorDocument.FinalizeViewCreation(self, view)
|
||||
if view == self.GetFirstView():
|
||||
self._DocumentStateChanged()
|
||||
if view.bFolding and GetEditorOption("Fold On Open", 0):
|
||||
view.FoldTopLevelEvent()
|
||||
|
||||
def HookViewNotifications(self, view):
|
||||
ParentEditorDocument.HookViewNotifications(self, view)
|
||||
|
||||
# Support for reloading the document from disk - presumably after some
|
||||
# external application has modified it (or possibly source control has
|
||||
# checked it out.
|
||||
def ReloadDocument(self):
|
||||
"""Reloads the document from disk. Assumes the file has
|
||||
been saved and user has been asked if necessary - it just does it!
|
||||
"""
|
||||
win32ui.SetStatusText("Reloading document. Please wait...", 1)
|
||||
self.SetModifiedFlag(0)
|
||||
# Loop over all views, saving their state, then reload the document
|
||||
views = self.GetAllViews()
|
||||
states = []
|
||||
for view in views:
|
||||
try:
|
||||
info = view._PrepareUserStateChange()
|
||||
except AttributeError: # Not our editor view?
|
||||
info = None
|
||||
states.append(info)
|
||||
self.OnOpenDocument(self.GetPathName())
|
||||
for view, info in zip(views, states):
|
||||
if info is not None:
|
||||
view._EndUserStateChange(info)
|
||||
self._DocumentStateChanged()
|
||||
win32ui.SetStatusText("Document reloaded.")
|
||||
|
||||
# Reloading the file
|
||||
def CheckExternalDocumentUpdated(self):
|
||||
if self.bDeclinedReload or not self.GetPathName():
|
||||
return
|
||||
try:
|
||||
newstat = os.stat(self.GetPathName())
|
||||
except os.error as exc:
|
||||
if not self.bReportedFileNotFound:
|
||||
print("The file '%s' is open for editing, but\nchecking it for changes caused the error: %s" % (self.GetPathName(), exc.strerror))
|
||||
self.bReportedFileNotFound = 1
|
||||
return
|
||||
if self.bReportedFileNotFound:
|
||||
print("The file '%s' has re-appeared - continuing to watch for changes..." % (self.GetPathName(),))
|
||||
self.bReportedFileNotFound = 0 # Once found again we want to start complaining.
|
||||
changed = (self.fileStat is None) or \
|
||||
self.fileStat[0] != newstat[0] or \
|
||||
self.fileStat[6] != newstat[6] or \
|
||||
self.fileStat[8] != newstat[8] or \
|
||||
self.fileStat[9] != newstat[9]
|
||||
if changed:
|
||||
question = None
|
||||
if self.IsModified():
|
||||
question = "%s\r\n\r\nThis file has been modified outside of the source editor.\r\nDo you want to reload it and LOSE THE CHANGES in the source editor?" % self.GetPathName()
|
||||
mbStyle = win32con.MB_YESNO | win32con.MB_DEFBUTTON2 # Default to "No"
|
||||
else:
|
||||
if not self.bAutoReload:
|
||||
question = "%s\r\n\r\nThis file has been modified outside of the source editor.\r\nDo you want to reload it?" % self.GetPathName()
|
||||
mbStyle = win32con.MB_YESNO # Default to "Yes"
|
||||
if question:
|
||||
rc = win32ui.MessageBox(question, None, mbStyle)
|
||||
if rc!=win32con.IDYES:
|
||||
self.bDeclinedReload = 1
|
||||
return
|
||||
self.ReloadDocument()
|
||||
|
||||
def _DocumentStateChanged(self):
|
||||
"""Called whenever the documents state (on disk etc) has been changed
|
||||
by the editor (eg, as the result of a save operation)
|
||||
"""
|
||||
if self.GetPathName():
|
||||
try:
|
||||
self.fileStat = os.stat(self.GetPathName())
|
||||
except os.error:
|
||||
self.fileStat = None
|
||||
else:
|
||||
self.fileStat = None
|
||||
self.watcherThread._DocumentStateChanged()
|
||||
self._UpdateUIForState()
|
||||
self._ApplyOptionalToViews("_UpdateUIForState")
|
||||
self._ApplyOptionalToViews("SetReadOnly", self._IsReadOnly())
|
||||
self._ApplyOptionalToViews("SCISetSavePoint")
|
||||
# Allow the debugger to reset us too.
|
||||
import pywin.debugger
|
||||
if pywin.debugger.currentDebugger is not None:
|
||||
pywin.debugger.currentDebugger.UpdateDocumentLineStates(self)
|
||||
|
||||
# Read-only document support - make it obvious to the user
|
||||
# that the file is read-only.
|
||||
def _IsReadOnly(self):
|
||||
return self.fileStat is not None and (self.fileStat[0] & 128)==0
|
||||
|
||||
def _UpdateUIForState(self):
|
||||
"""Change the title to reflect the state of the document -
|
||||
eg ReadOnly, Dirty, etc
|
||||
"""
|
||||
filename = self.GetPathName()
|
||||
if not filename: return # New file - nothing to do
|
||||
try:
|
||||
# This seems necessary so the internal state of the window becomes
|
||||
# "visible". without it, it is still shown, but certain functions
|
||||
# (such as updating the title) dont immediately work?
|
||||
self.GetFirstView().ShowWindow(win32con.SW_SHOW)
|
||||
title = win32ui.GetFileTitle(filename)
|
||||
except win32ui.error:
|
||||
title = filename
|
||||
if self._IsReadOnly():
|
||||
title = title + " (read-only)"
|
||||
self.SetTitle(title)
|
||||
|
||||
def MakeDocumentWritable(self):
|
||||
pretend_ss = 0 # Set to 1 to test this without source safe :-)
|
||||
if not self.scModuleName and not pretend_ss: # No Source Control support.
|
||||
win32ui.SetStatusText("Document is read-only, and no source-control system is configured")
|
||||
win32api.MessageBeep()
|
||||
return 0
|
||||
|
||||
# We have source control support - check if the user wants to use it.
|
||||
msg = "Would you like to check this file out?"
|
||||
defButton = win32con.MB_YESNO
|
||||
if self.IsModified():
|
||||
msg = msg + "\r\n\r\nALL CHANGES IN THE EDITOR WILL BE LOST"
|
||||
defButton = win32con.MB_YESNO
|
||||
if win32ui.MessageBox(msg, None, defButton)!=win32con.IDYES:
|
||||
return 0
|
||||
|
||||
if pretend_ss:
|
||||
print("We are only pretending to check it out!")
|
||||
win32api.SetFileAttributes(self.GetPathName(), win32con.FILE_ATTRIBUTE_NORMAL)
|
||||
self.ReloadDocument()
|
||||
return 1
|
||||
|
||||
# Now call on the module to do it.
|
||||
if self.scModule is None:
|
||||
try:
|
||||
self.scModule = __import__(self.scModuleName)
|
||||
for part in self.scModuleName.split('.')[1:]:
|
||||
self.scModule = getattr(self.scModule, part)
|
||||
except:
|
||||
traceback.print_exc()
|
||||
print("Error loading source control module.")
|
||||
return 0
|
||||
|
||||
if self.scModule.CheckoutFile(self.GetPathName()):
|
||||
self.ReloadDocument()
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def CheckMakeDocumentWritable(self):
|
||||
if self._IsReadOnly():
|
||||
return self.MakeDocumentWritable()
|
||||
return 1
|
||||
|
||||
def SaveModified(self):
|
||||
# Called as the document is closed. If we are about
|
||||
# to prompt for a save, bring the document to the foreground.
|
||||
if self.IsModified():
|
||||
frame = self.GetFirstView().GetParentFrame()
|
||||
try:
|
||||
frame.MDIActivate()
|
||||
frame.AutoRestore()
|
||||
except:
|
||||
print("Could not bring document to foreground")
|
||||
return self._obj_.SaveModified()
|
||||
|
||||
# NOTE - I DONT use the standard threading module,
|
||||
# as this waits for all threads to terminate at shutdown.
|
||||
# When using the debugger, it is possible shutdown will
|
||||
# occur without Pythonwin getting a complete shutdown,
|
||||
# so we deadlock at the end - threading is waiting for
|
||||
import pywin.mfc.thread
|
||||
import win32event
|
||||
class FileWatchingThread(pywin.mfc.thread.WinThread):
|
||||
def __init__(self, doc):
|
||||
self.doc = doc
|
||||
self.adminEvent = win32event.CreateEvent(None, 0, 0, None)
|
||||
self.stopEvent = win32event.CreateEvent(None, 0, 0, None)
|
||||
self.watchEvent = None
|
||||
pywin.mfc.thread.WinThread.__init__(self)
|
||||
|
||||
def _DocumentStateChanged(self):
|
||||
win32event.SetEvent(self.adminEvent)
|
||||
|
||||
def RefreshEvent(self):
|
||||
self.hwnd = self.doc.GetFirstView().GetSafeHwnd()
|
||||
if self.watchEvent is not None:
|
||||
win32api.FindCloseChangeNotification(self.watchEvent)
|
||||
self.watchEvent = None
|
||||
path = self.doc.GetPathName()
|
||||
if path: path = os.path.dirname(path)
|
||||
if path:
|
||||
filter = win32con.FILE_NOTIFY_CHANGE_FILE_NAME | \
|
||||
win32con.FILE_NOTIFY_CHANGE_ATTRIBUTES | \
|
||||
win32con.FILE_NOTIFY_CHANGE_LAST_WRITE
|
||||
try:
|
||||
self.watchEvent = win32api.FindFirstChangeNotification(path, 0, filter)
|
||||
except win32api.error as exc:
|
||||
print("Can not watch file", path, "for changes -", exc.strerror)
|
||||
def SignalStop(self):
|
||||
win32event.SetEvent(self.stopEvent)
|
||||
def Run(self):
|
||||
while 1:
|
||||
handles = [self.stopEvent, self.adminEvent]
|
||||
if self.watchEvent is not None:
|
||||
handles.append(self.watchEvent)
|
||||
rc = win32event.WaitForMultipleObjects(handles, 0, win32event.INFINITE)
|
||||
if rc == win32event.WAIT_OBJECT_0:
|
||||
break
|
||||
elif rc == win32event.WAIT_OBJECT_0+1:
|
||||
self.RefreshEvent()
|
||||
else:
|
||||
win32api.PostMessage(self.hwnd, MSG_CHECK_EXTERNAL_FILE, 0, 0)
|
||||
try:
|
||||
# If the directory has been removed underneath us, we get this error.
|
||||
win32api.FindNextChangeNotification(self.watchEvent)
|
||||
except win32api.error as exc:
|
||||
print("Can not watch file", self.doc.GetPathName(), "for changes -", exc.strerror)
|
||||
break
|
||||
|
||||
# close a circular reference
|
||||
self.doc = None
|
||||
if self.watchEvent:
|
||||
win32api.FindCloseChangeNotification(self.watchEvent)
|
||||
465
Lib/site-packages/pythonwin/pywin/framework/editor/editor.py
Normal file
465
Lib/site-packages/pythonwin/pywin/framework/editor/editor.py
Normal file
|
|
@ -0,0 +1,465 @@
|
|||
#####################################################################
|
||||
#
|
||||
# editor.py
|
||||
#
|
||||
# A general purpose text editor, built on top of the win32ui edit
|
||||
# type, which is built on an MFC CEditView
|
||||
#
|
||||
#
|
||||
# We now support reloading of externally modified documented
|
||||
# (eg, presumably by some other process, such as source control or
|
||||
# another editor.
|
||||
# We also suport auto-loading of externally modified files.
|
||||
# - if the current document has not been modified in this
|
||||
# editor, but has been modified on disk, then the file
|
||||
# can be automatically reloaded.
|
||||
#
|
||||
# Note that it will _always_ prompt you if the file in the editor has been modified.
|
||||
|
||||
|
||||
import win32ui
|
||||
import win32api
|
||||
import win32con
|
||||
import regex
|
||||
import re
|
||||
import string
|
||||
import sys, os
|
||||
import traceback
|
||||
from pywin.mfc import docview, dialog, afxres
|
||||
|
||||
from pywin.framework.editor import GetEditorOption, SetEditorOption, GetEditorFontOption, SetEditorFontOption, defaultCharacterFormat
|
||||
|
||||
patImport=regex.symcomp('import \(<name>.*\)')
|
||||
patIndent=regex.compile('^\\([ \t]*[~ \t]\\)')
|
||||
|
||||
ID_LOCATE_FILE = 0xe200
|
||||
ID_GOTO_LINE = 0xe2001
|
||||
MSG_CHECK_EXTERNAL_FILE = win32con.WM_USER+1999 ## WARNING: Duplicated in document.py and coloreditor.py
|
||||
|
||||
# Key Codes that modify the bufffer when Ctrl or Alt are NOT pressed.
|
||||
MODIFYING_VK_KEYS = [win32con.VK_BACK, win32con.VK_TAB, win32con.VK_RETURN, win32con.VK_SPACE, win32con.VK_DELETE]
|
||||
for k in range(48, 91):
|
||||
MODIFYING_VK_KEYS.append(k)
|
||||
|
||||
# Key Codes that modify the bufffer when Ctrl is pressed.
|
||||
MODIFYING_VK_KEYS_CTRL = [win32con.VK_BACK, win32con.VK_RETURN, win32con.VK_SPACE, win32con.VK_DELETE]
|
||||
|
||||
# Key Codes that modify the bufffer when Alt is pressed.
|
||||
MODIFYING_VK_KEYS_ALT = [win32con.VK_BACK, win32con.VK_RETURN, win32con.VK_SPACE, win32con.VK_DELETE]
|
||||
|
||||
|
||||
# The editor itself starts here.
|
||||
# Using the MFC Document/View model, we have an EditorDocument, which is responsible for
|
||||
# managing the contents of the file, and a view which is responsible for rendering it.
|
||||
#
|
||||
# Due to a limitation in the Windows edit controls, we are limited to one view
|
||||
# per document, although nothing in this code assumes this (I hope!)
|
||||
|
||||
isRichText=1 # We are using the Rich Text control. This has not been tested with value "0" for quite some time!
|
||||
|
||||
#ParentEditorDocument=docview.Document
|
||||
from .document import EditorDocumentBase
|
||||
ParentEditorDocument=EditorDocumentBase
|
||||
class EditorDocument(ParentEditorDocument):
|
||||
#
|
||||
# File loading and saving operations
|
||||
#
|
||||
def OnOpenDocument(self, filename):
|
||||
#
|
||||
# handle Unix and PC text file format.
|
||||
#
|
||||
|
||||
# Get the "long name" of the file name, as it may have been translated
|
||||
# to short names by the shell.
|
||||
self.SetPathName(filename) # Must set this early!
|
||||
# Now do the work!
|
||||
self.BeginWaitCursor()
|
||||
win32ui.SetStatusText("Loading file...",1)
|
||||
try:
|
||||
f = open(filename,"rb")
|
||||
except IOError:
|
||||
win32ui.MessageBox(filename + '\nCan not find this file\nPlease verify that the correct path and file name are given')
|
||||
self.EndWaitCursor()
|
||||
return 0
|
||||
raw=f.read()
|
||||
f.close()
|
||||
contents = self.TranslateLoadedData(raw)
|
||||
rc = 0
|
||||
if win32ui.IsWin32s() and len(contents)>62000: # give or take a few bytes
|
||||
win32ui.MessageBox("This file is too big for Python on Windows 3.1\r\nPlease use another editor to view this file.")
|
||||
else:
|
||||
try:
|
||||
self.GetFirstView().SetWindowText(contents)
|
||||
rc = 1
|
||||
except TypeError: # Null byte in file.
|
||||
win32ui.MessageBox("This file contains NULL bytes, and can not be edited")
|
||||
rc = 0
|
||||
|
||||
self.EndWaitCursor()
|
||||
self.SetModifiedFlag(0) # No longer dirty
|
||||
self._DocumentStateChanged()
|
||||
return rc
|
||||
|
||||
def TranslateLoadedData(self, data):
|
||||
"""Given raw data read from a file, massage it suitable for the edit window"""
|
||||
# if a CR in the first 250 chars, then perform the expensive translate
|
||||
if data[:250].find('\r')==-1:
|
||||
win32ui.SetStatusText("Translating from Unix file format - please wait...",1)
|
||||
return re.sub('\r*\n','\r\n',data)
|
||||
else:
|
||||
return data
|
||||
|
||||
def SaveFile(self, fileName, encoding=None):
|
||||
if isRichText:
|
||||
view = self.GetFirstView()
|
||||
view.SaveTextFile(fileName, encoding=encoding)
|
||||
else: # Old style edit view window.
|
||||
self.GetFirstView().SaveFile(fileName)
|
||||
try:
|
||||
# Make sure line cache has updated info about me!
|
||||
import linecache
|
||||
linecache.checkcache()
|
||||
except:
|
||||
pass
|
||||
|
||||
#
|
||||
# Color state stuff
|
||||
#
|
||||
def SetAllLineColors(self, color = None):
|
||||
for view in self.GetAllViews():
|
||||
view.SetAllLineColors(color)
|
||||
|
||||
def SetLineColor(self, lineNo, color):
|
||||
"Color a line of all views"
|
||||
for view in self.GetAllViews():
|
||||
view.SetLineColor(lineNo, color)
|
||||
|
||||
|
||||
# def StreamTextOut(self, data): ### This seems unreliable???
|
||||
# self.saveFileHandle.write(data)
|
||||
# return 1 # keep em coming!
|
||||
|
||||
#ParentEditorView=docview.EditView
|
||||
ParentEditorView=docview.RichEditView
|
||||
class EditorView(ParentEditorView):
|
||||
def __init__(self, doc):
|
||||
ParentEditorView.__init__(self, doc)
|
||||
if isRichText:
|
||||
self.SetWordWrap(win32ui.CRichEditView_WrapNone)
|
||||
|
||||
self.addToMRU = 1
|
||||
self.HookHandlers()
|
||||
self.bCheckingFile = 0
|
||||
|
||||
self.defCharFormat = GetEditorFontOption("Default Font", defaultCharacterFormat)
|
||||
|
||||
# Smart tabs override everything else if context can be worked out.
|
||||
self.bSmartTabs = GetEditorOption("Smart Tabs", 1)
|
||||
|
||||
self.tabSize = GetEditorOption("Tab Size", 8)
|
||||
self.indentSize = GetEditorOption("Indent Size", 8)
|
||||
# If next indent is at a tab position, and useTabs is set, a tab will be inserted.
|
||||
self.bUseTabs = GetEditorOption("Use Tabs", 1)
|
||||
|
||||
def OnInitialUpdate(self):
|
||||
rc = self._obj_.OnInitialUpdate()
|
||||
self.SetDefaultCharFormat(self.defCharFormat)
|
||||
return rc
|
||||
|
||||
def CutCurLine(self):
|
||||
curLine = self._obj_.LineFromChar()
|
||||
nextLine = curLine+1
|
||||
start = self._obj_.LineIndex(curLine)
|
||||
end = self._obj_.LineIndex(nextLine)
|
||||
if end==0: # must be last line.
|
||||
end = start + self.end.GetLineLength(curLine)
|
||||
self._obj_.SetSel(start,end)
|
||||
self._obj_.Cut()
|
||||
def _PrepareUserStateChange(self):
|
||||
"Return selection, lineindex, etc info, so it can be restored"
|
||||
self.SetRedraw(0)
|
||||
return self.GetModify(), self.GetSel(), self.GetFirstVisibleLine()
|
||||
def _EndUserStateChange(self, info):
|
||||
scrollOff = info[2] - self.GetFirstVisibleLine()
|
||||
if scrollOff:
|
||||
self.LineScroll(scrollOff)
|
||||
self.SetSel(info[1])
|
||||
self.SetModify(info[0])
|
||||
self.SetRedraw(1)
|
||||
self.InvalidateRect()
|
||||
self.UpdateWindow()
|
||||
|
||||
def _UpdateUIForState(self):
|
||||
self.SetReadOnly(self.GetDocument()._IsReadOnly())
|
||||
|
||||
def SetAllLineColors(self, color = None):
|
||||
if isRichText:
|
||||
info = self._PrepareUserStateChange()
|
||||
try:
|
||||
if color is None: color = self.defCharFormat[4]
|
||||
self.SetSel(0,-1)
|
||||
self.SetSelectionCharFormat((win32con.CFM_COLOR, 0,0,0,color))
|
||||
finally:
|
||||
self._EndUserStateChange(info)
|
||||
|
||||
def SetLineColor(self, lineNo, color):
|
||||
"lineNo is the 1 based line number to set. If color is None, default color is used."
|
||||
if isRichText:
|
||||
info = self._PrepareUserStateChange()
|
||||
try:
|
||||
if color is None: color = self.defCharFormat[4]
|
||||
lineNo = lineNo-1
|
||||
startIndex = self.LineIndex(lineNo)
|
||||
if startIndex!=-1:
|
||||
self.SetSel(startIndex, self.LineIndex(lineNo+1))
|
||||
self.SetSelectionCharFormat((win32con.CFM_COLOR, 0,0,0,color))
|
||||
finally:
|
||||
self._EndUserStateChange(info)
|
||||
|
||||
def Indent(self):
|
||||
"""Insert an indent to move the cursor to the next tab position.
|
||||
|
||||
Honors the tab size and 'use tabs' settings. Assumes the cursor is already at the
|
||||
position to be indented, and the selection is a single character (ie, not a block)
|
||||
"""
|
||||
start, end = self._obj_.GetSel()
|
||||
startLine = self._obj_.LineFromChar(start)
|
||||
line = self._obj_.GetLine(startLine)
|
||||
realCol = start - self._obj_.LineIndex(startLine)
|
||||
# Calulate the next tab stop.
|
||||
# Expand existing tabs.
|
||||
curCol = 0
|
||||
for ch in line[:realCol]:
|
||||
if ch=='\t':
|
||||
curCol = ((curCol / self.tabSize) + 1) * self.tabSize
|
||||
else:
|
||||
curCol = curCol + 1
|
||||
nextColumn = ((curCol / self.indentSize) + 1) * self.indentSize
|
||||
# print "curCol is", curCol, "nextColumn is", nextColumn
|
||||
ins = None
|
||||
if self.bSmartTabs:
|
||||
# Look for some context.
|
||||
if realCol==0: # Start of the line - see if the line above can tell us
|
||||
lookLine = startLine-1
|
||||
while lookLine >= 0:
|
||||
check = self._obj_.GetLine(lookLine)[0:1]
|
||||
if check in ['\t', ' ']:
|
||||
ins = check
|
||||
break
|
||||
lookLine = lookLine - 1
|
||||
else: # See if the previous char can tell us
|
||||
check = line[realCol-1]
|
||||
if check in ['\t', ' ']:
|
||||
ins = check
|
||||
|
||||
# Either smart tabs off, or not smart enough!
|
||||
# Use the "old style" settings.
|
||||
if ins is None:
|
||||
if self.bUseTabs and nextColumn % self.tabSize==0:
|
||||
ins = '\t'
|
||||
else:
|
||||
ins = ' '
|
||||
|
||||
if ins == ' ':
|
||||
# Calc the number of spaces to take us to the next stop
|
||||
ins = ins * (nextColumn - curCol)
|
||||
|
||||
self._obj_.ReplaceSel(ins)
|
||||
|
||||
|
||||
def BlockDent(self, isIndent, startLine, endLine):
|
||||
" Indent/Undent all lines specified "
|
||||
if not self.GetDocument().CheckMakeDocumentWritable(): return 0
|
||||
tabSize=self.tabSize # hard-code for now!
|
||||
info = self._PrepareUserStateChange()
|
||||
try:
|
||||
for lineNo in range(startLine, endLine):
|
||||
pos=self._obj_.LineIndex(lineNo)
|
||||
self._obj_.SetSel(pos, pos)
|
||||
if isIndent:
|
||||
self.Indent()
|
||||
else:
|
||||
line = self._obj_.GetLine(lineNo)
|
||||
try:
|
||||
noToDel = 0
|
||||
if line[0]=='\t':
|
||||
noToDel = 1
|
||||
elif line[0]==' ':
|
||||
for noToDel in range(0,tabSize):
|
||||
if line[noToDel]!=' ':
|
||||
break
|
||||
else:
|
||||
noToDel=tabSize
|
||||
if noToDel:
|
||||
self._obj_.SetSel(pos, pos+noToDel)
|
||||
self._obj_.Clear()
|
||||
except IndexError:
|
||||
pass
|
||||
finally:
|
||||
self._EndUserStateChange(info)
|
||||
self.GetDocument().SetModifiedFlag(1) # Now dirty
|
||||
self._obj_.SetSel(self.LineIndex(startLine), self.LineIndex(endLine))
|
||||
|
||||
def GotoLine(self, lineNo = None):
|
||||
try:
|
||||
if lineNo is None:
|
||||
lineNo = int(input("Enter Line Number"))
|
||||
except (ValueError, KeyboardInterrupt):
|
||||
return 0
|
||||
self.GetLineCount() # Seems to be needed when file first opened???
|
||||
charNo = self.LineIndex(lineNo-1)
|
||||
self.SetSel(charNo)
|
||||
|
||||
def HookHandlers(self): # children can override, but should still call me!
|
||||
# self.HookAllKeyStrokes(self.OnKey)
|
||||
self.HookMessage(self.OnCheckExternalDocumentUpdated,MSG_CHECK_EXTERNAL_FILE)
|
||||
self.HookMessage(self.OnRClick,win32con.WM_RBUTTONDOWN)
|
||||
self.HookMessage(self.OnSetFocus, win32con.WM_SETFOCUS)
|
||||
self.HookMessage(self.OnKeyDown, win32con.WM_KEYDOWN)
|
||||
self.HookKeyStroke(self.OnKeyCtrlY, 25) # ^Y
|
||||
self.HookKeyStroke(self.OnKeyCtrlG, 7) # ^G
|
||||
self.HookKeyStroke(self.OnKeyTab, 9) # TAB
|
||||
self.HookKeyStroke(self.OnKeyEnter, 13) # Enter
|
||||
self.HookCommand(self.OnCmdLocateFile, ID_LOCATE_FILE)
|
||||
self.HookCommand(self.OnCmdGotoLine, ID_GOTO_LINE)
|
||||
self.HookCommand(self.OnEditPaste, afxres.ID_EDIT_PASTE)
|
||||
self.HookCommand(self.OnEditCut, afxres.ID_EDIT_CUT)
|
||||
|
||||
# Hook Handlers
|
||||
def OnSetFocus(self,msg):
|
||||
# Even though we use file change notifications, we should be very sure about it here.
|
||||
self.OnCheckExternalDocumentUpdated(msg)
|
||||
|
||||
def OnRClick(self,params):
|
||||
menu = win32ui.CreatePopupMenu()
|
||||
|
||||
# look for a module name
|
||||
line=self._obj_.GetLine().strip()
|
||||
flags=win32con.MF_STRING|win32con.MF_ENABLED
|
||||
if patImport.match(line)==len(line):
|
||||
menu.AppendMenu(flags, ID_LOCATE_FILE, "&Locate %s.py"%patImport.group('name'))
|
||||
menu.AppendMenu(win32con.MF_SEPARATOR);
|
||||
menu.AppendMenu(flags, win32ui.ID_EDIT_UNDO, '&Undo')
|
||||
menu.AppendMenu(win32con.MF_SEPARATOR);
|
||||
menu.AppendMenu(flags, win32ui.ID_EDIT_CUT, 'Cu&t')
|
||||
menu.AppendMenu(flags, win32ui.ID_EDIT_COPY, '&Copy')
|
||||
menu.AppendMenu(flags, win32ui.ID_EDIT_PASTE, '&Paste')
|
||||
menu.AppendMenu(flags, win32con.MF_SEPARATOR);
|
||||
menu.AppendMenu(flags, win32ui.ID_EDIT_SELECT_ALL, '&Select all')
|
||||
menu.AppendMenu(flags, win32con.MF_SEPARATOR);
|
||||
menu.AppendMenu(flags, ID_GOTO_LINE, '&Goto line...')
|
||||
menu.TrackPopupMenu(params[5])
|
||||
return 0
|
||||
|
||||
def OnCmdGotoLine(self, cmd, code):
|
||||
self.GotoLine()
|
||||
return 0
|
||||
|
||||
def OnCmdLocateFile(self, cmd, code):
|
||||
modName = patImport.group('name')
|
||||
if not modName:
|
||||
return 0
|
||||
import pywin.framework.scriptutils
|
||||
fileName = pywin.framework.scriptutils.LocatePythonFile(modName)
|
||||
if fileName is None:
|
||||
win32ui.SetStatusText("Can't locate module %s" % modName)
|
||||
else:
|
||||
win32ui.GetApp().OpenDocumentFile(fileName)
|
||||
return 0
|
||||
|
||||
# Key handlers
|
||||
def OnKeyEnter(self, key):
|
||||
if not self.GetDocument().CheckMakeDocumentWritable(): return 0
|
||||
curLine = self._obj_.GetLine()
|
||||
self._obj_.ReplaceSel('\r\n') # insert the newline
|
||||
# If the current line indicates the next should be indented,
|
||||
# then copy the current indentation to this line.
|
||||
res = patIndent.match(curLine,0)
|
||||
if res>0 and curLine.strip():
|
||||
curIndent = patIndent.group(1)
|
||||
self._obj_.ReplaceSel(curIndent)
|
||||
return 0 # dont pass on
|
||||
|
||||
def OnKeyCtrlY(self, key):
|
||||
if not self.GetDocument().CheckMakeDocumentWritable(): return 0
|
||||
self.CutCurLine()
|
||||
return 0 # dont let him have it!
|
||||
def OnKeyCtrlG(self, key):
|
||||
self.GotoLine()
|
||||
return 0 # dont let him have it!
|
||||
def OnKeyTab(self, key):
|
||||
if not self.GetDocument().CheckMakeDocumentWritable(): return 0
|
||||
start, end = self._obj_.GetSel()
|
||||
if start==end: # normal TAB key
|
||||
self.Indent()
|
||||
return 0 # we handled this.
|
||||
|
||||
# Otherwise it is a block indent/dedent.
|
||||
if start>end:
|
||||
start, end = end, start # swap them.
|
||||
startLine = self._obj_.LineFromChar(start)
|
||||
endLine = self._obj_.LineFromChar(end)
|
||||
|
||||
self.BlockDent(win32api.GetKeyState(win32con.VK_SHIFT)>=0, startLine, endLine)
|
||||
return 0
|
||||
|
||||
|
||||
def OnEditPaste(self, id, code):
|
||||
# Return 1 if we can make the file editable.(or it already is!)
|
||||
return self.GetDocument().CheckMakeDocumentWritable()
|
||||
|
||||
def OnEditCut(self, id, code):
|
||||
# Return 1 if we can make the file editable.(or it already is!)
|
||||
return self.GetDocument().CheckMakeDocumentWritable()
|
||||
|
||||
def OnKeyDown(self, msg):
|
||||
key = msg[2]
|
||||
if win32api.GetKeyState(win32con.VK_CONTROL) & 0x8000:
|
||||
modList = MODIFYING_VK_KEYS_CTRL
|
||||
elif win32api.GetKeyState(win32con.VK_MENU) & 0x8000:
|
||||
modList = MODIFYING_VK_KEYS_ALT
|
||||
else:
|
||||
modList = MODIFYING_VK_KEYS
|
||||
|
||||
if key in modList:
|
||||
# Return 1 if we can make the file editable.(or it already is!)
|
||||
return self.GetDocument().CheckMakeDocumentWritable()
|
||||
return 1 # Pass it on OK
|
||||
|
||||
# def OnKey(self, key):
|
||||
# return self.GetDocument().CheckMakeDocumentWritable()
|
||||
|
||||
def OnCheckExternalDocumentUpdated(self, msg):
|
||||
if self._obj_ is None or self.bCheckingFile: return
|
||||
self.bCheckingFile = 1
|
||||
self.GetDocument().CheckExternalDocumentUpdated()
|
||||
self.bCheckingFile = 0
|
||||
|
||||
from .template import EditorTemplateBase
|
||||
class EditorTemplate(EditorTemplateBase):
|
||||
def __init__(self, res=win32ui.IDR_TEXTTYPE, makeDoc=None, makeFrame=None, makeView=None):
|
||||
if makeDoc is None: makeDoc = EditorDocument
|
||||
if makeView is None: makeView = EditorView
|
||||
EditorTemplateBase.__init__(self, res, makeDoc, makeFrame, makeView)
|
||||
|
||||
def _CreateDocTemplate(self, resourceId):
|
||||
return win32ui.CreateRichEditDocTemplate(resourceId)
|
||||
|
||||
def CreateWin32uiDocument(self):
|
||||
return self.DoCreateRichEditDoc()
|
||||
|
||||
def Create(fileName = None, title=None, template = None):
|
||||
return editorTemplate.OpenDocumentFile(fileName)
|
||||
|
||||
from pywin.framework.editor import GetDefaultEditorModuleName
|
||||
prefModule = GetDefaultEditorModuleName()
|
||||
# Initialize only if this is the "default" editor.
|
||||
if __name__==prefModule:
|
||||
# For debugging purposes, when this module may be reloaded many times.
|
||||
try:
|
||||
win32ui.GetApp().RemoveDocTemplate(editorTemplate)
|
||||
except (NameError, win32ui.error):
|
||||
pass
|
||||
|
||||
editorTemplate = EditorTemplate()
|
||||
win32ui.GetApp().AddDocTemplate(editorTemplate)
|
||||
76
Lib/site-packages/pythonwin/pywin/framework/editor/frame.py
Normal file
76
Lib/site-packages/pythonwin/pywin/framework/editor/frame.py
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
# frame.py - The MDI frame window for an editor.
|
||||
import pywin.framework.window
|
||||
import win32ui
|
||||
import win32con
|
||||
import afxres
|
||||
|
||||
from . import ModuleBrowser
|
||||
|
||||
class EditorFrame(pywin.framework.window.MDIChildWnd):
|
||||
def OnCreateClient(self, cp, context):
|
||||
|
||||
# Create the default view as specified by the template (ie, the editor view)
|
||||
view = context.template.MakeView(context.doc)
|
||||
# Create the browser view.
|
||||
browserView = ModuleBrowser.BrowserView(context.doc)
|
||||
view2 = context.template.MakeView(context.doc)
|
||||
|
||||
splitter = win32ui.CreateSplitter()
|
||||
style = win32con.WS_CHILD | win32con.WS_VISIBLE
|
||||
splitter.CreateStatic (self, 1, 2, style, win32ui.AFX_IDW_PANE_FIRST)
|
||||
sub_splitter = self.sub_splitter = win32ui.CreateSplitter()
|
||||
sub_splitter.CreateStatic (splitter, 2, 1, style, win32ui.AFX_IDW_PANE_FIRST+1)
|
||||
|
||||
# Note we must add the default view first, so that doc.GetFirstView() returns the editor view.
|
||||
sub_splitter.CreateView(view, 1, 0, (0,0))
|
||||
splitter.CreateView (browserView, 0, 0, (0,0))
|
||||
sub_splitter.CreateView(view2,0, 0, (0,0))
|
||||
|
||||
## print "First view is", context.doc.GetFirstView()
|
||||
## print "Views are", view, view2, browserView
|
||||
## print "Parents are", view.GetParent(), view2.GetParent(), browserView.GetParent()
|
||||
## print "Splitter is", splitter
|
||||
## print "sub splitter is", sub_splitter
|
||||
## Old
|
||||
## splitter.CreateStatic (self, 1, 2)
|
||||
## splitter.CreateView(view, 0, 1, (0,0)) # size ignored.
|
||||
## splitter.CreateView (browserView, 0, 0, (0, 0))
|
||||
|
||||
# Restrict the size of the browser splitter (and we can avoid filling
|
||||
# it until it is shown)
|
||||
splitter.SetColumnInfo(0, 10, 20)
|
||||
# And the active view is our default view (so it gets initial focus)
|
||||
self.SetActiveView(view)
|
||||
|
||||
def GetEditorView(self):
|
||||
# In a multi-view (eg, splitter) environment, get
|
||||
# an editor (ie, scintilla) view
|
||||
# Look for the splitter opened the most!
|
||||
if self.sub_splitter is None:
|
||||
return self.GetDlgItem(win32ui.AFX_IDW_PANE_FIRST)
|
||||
v1 = self.sub_splitter.GetPane(0,0)
|
||||
v2 = self.sub_splitter.GetPane(1,0)
|
||||
r1 = v1.GetWindowRect()
|
||||
r2 = v2.GetWindowRect()
|
||||
if r1[3]-r1[1] > r2[3]-r2[1]:
|
||||
return v1
|
||||
return v2
|
||||
|
||||
def GetBrowserView(self):
|
||||
# XXX - should fix this :-)
|
||||
return self.GetActiveDocument().GetAllViews()[1]
|
||||
|
||||
def OnClose(self):
|
||||
doc=self.GetActiveDocument()
|
||||
if not doc.SaveModified():
|
||||
## Cancel button selected from Save dialog, do not actually close
|
||||
## print 'close cancelled'
|
||||
return 0
|
||||
## So the 'Save' dialog doesn't come up twice
|
||||
doc._obj_.SetModifiedFlag(False)
|
||||
|
||||
# Must force the module browser to close itself here (OnDestroy for the view itself is too late!)
|
||||
self.sub_splitter = None # ensure no circles!
|
||||
self.GetBrowserView().DestroyBrowser()
|
||||
return self._obj_.OnClose()
|
||||
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
import string
|
||||
import win32ui
|
||||
import win32api
|
||||
from pywin.mfc import docview
|
||||
import pywin.framework.window
|
||||
import os
|
||||
from . import frame
|
||||
|
||||
ParentEditorTemplate=docview.DocTemplate
|
||||
class EditorTemplateBase(ParentEditorTemplate):
|
||||
def __init__(self, res=win32ui.IDR_TEXTTYPE, makeDoc=None, makeFrame=None, makeView=None):
|
||||
if makeFrame is None: makeFrame = frame.EditorFrame
|
||||
ParentEditorTemplate.__init__(self, res, makeDoc, makeFrame, makeView)
|
||||
|
||||
def _CreateDocTemplate(self, resourceId):
|
||||
assert 0, "You must override this"
|
||||
def CreateWin32uiDocument(self):
|
||||
assert 0, "You must override this"
|
||||
def GetFileExtensions(self):
|
||||
return ".txt", ".py"
|
||||
def MatchDocType(self, fileName, fileType):
|
||||
doc = self.FindOpenDocument(fileName)
|
||||
if doc: return doc
|
||||
ext = os.path.splitext(fileName)[1].lower()
|
||||
if ext in self.GetFileExtensions():
|
||||
return win32ui.CDocTemplate_Confidence_yesAttemptNative
|
||||
return win32ui.CDocTemplate_Confidence_maybeAttemptForeign
|
||||
|
||||
def InitialUpdateFrame(self, frame, doc, makeVisible=1):
|
||||
self._obj_.InitialUpdateFrame(frame, doc, makeVisible) # call default handler.
|
||||
doc._UpdateUIForState()
|
||||
|
||||
def GetPythonPropertyPages(self):
|
||||
"""Returns a list of property pages
|
||||
"""
|
||||
from . import configui
|
||||
return [configui.EditorPropertyPage(), configui.EditorWhitespacePropertyPage()]
|
||||
|
||||
def OpenDocumentFile(self, filename, bMakeVisible = 1):
|
||||
if filename is not None:
|
||||
try:
|
||||
path = os.path.split(filename)[0]
|
||||
# print "The editor is translating", `filename`,"to",
|
||||
filename = win32api.FindFiles(filename)[0][8]
|
||||
filename = os.path.join(path, filename)
|
||||
# print `filename`
|
||||
except (win32api.error, IndexError) as details:
|
||||
pass
|
||||
# print "Couldnt get the full filename!", details
|
||||
return self._obj_.OpenDocumentFile(filename, bMakeVisible)
|
||||
93
Lib/site-packages/pythonwin/pywin/framework/editor/vss.py
Normal file
93
Lib/site-packages/pythonwin/pywin/framework/editor/vss.py
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
# vss.py -- Source Control using Microsoft VSS.
|
||||
|
||||
# Provides routines for checking files out of VSS.
|
||||
#
|
||||
# Uses an INI file very similar to how VB integrates with VSS - even
|
||||
# as far as using the same name.
|
||||
|
||||
# The file must be named "Mssccprj.scc", and be in the format of
|
||||
# an INI file. This file may be in a parent directory, in which
|
||||
# case the project name will be built from what is specified in the
|
||||
# ini file, plus the path from the INI file to the file itself.
|
||||
#
|
||||
# The INI file should have a [Python] section, and a
|
||||
# Project=Project Name
|
||||
# and optionally
|
||||
# Database=??
|
||||
|
||||
|
||||
import win32ui, win32api, win32con, os, string, sys
|
||||
|
||||
import traceback
|
||||
|
||||
g_iniName = "Mssccprj.scc" # Use the same INI name as VB!
|
||||
|
||||
g_sourceSafe = None
|
||||
|
||||
def FindVssProjectInfo(fullfname):
|
||||
"""Looks up the file system for an INI file describing the project.
|
||||
|
||||
Looking up the tree is for ni style packages.
|
||||
|
||||
Returns (projectName, pathToFileName) where pathToFileName contains
|
||||
the path from the ini file to the actual file.
|
||||
"""
|
||||
path, fnameonly = os.path.split(fullfname)
|
||||
origPath = path
|
||||
project = ""
|
||||
retPaths = [fnameonly]
|
||||
while not project:
|
||||
iniName = os.path.join(path, g_iniName)
|
||||
database = win32api.GetProfileVal("Python","Database", "", iniName)
|
||||
project = win32api.GetProfileVal("Python","Project", "", iniName)
|
||||
if project:
|
||||
break;
|
||||
# No valid INI file in this directory - look up a level.
|
||||
path, addpath = os.path.split(path)
|
||||
if not addpath: # Root?
|
||||
break
|
||||
retPaths.insert(0, addpath)
|
||||
if not project:
|
||||
win32ui.MessageBox("%s\r\n\r\nThis directory is not configured for Python/VSS" % origPath)
|
||||
return
|
||||
return project, "/".join(retPaths), database
|
||||
|
||||
|
||||
def CheckoutFile(fileName):
|
||||
global g_sourceSafe
|
||||
import pythoncom
|
||||
ok = 0
|
||||
# Assumes the fileName has a complete path,
|
||||
# and that the INI file can be found in that path
|
||||
# (or a parent path if a ni style package)
|
||||
try:
|
||||
import win32com.client, win32com.client.gencache
|
||||
mod = win32com.client.gencache.EnsureModule('{783CD4E0-9D54-11CF-B8EE-00608CC9A71F}', 0, 5, 0)
|
||||
if mod is None:
|
||||
win32ui.MessageBox("VSS does not appear to be installed. The TypeInfo can not be created")
|
||||
return ok
|
||||
|
||||
rc = FindVssProjectInfo(fileName)
|
||||
if rc is None:
|
||||
return
|
||||
project, vssFname, database = rc
|
||||
if g_sourceSafe is None:
|
||||
g_sourceSafe=win32com.client.Dispatch("SourceSafe")
|
||||
# SS seems a bit wierd. It defaults the arguments as empty strings, but
|
||||
# then complains when they are used - so we pass "Missing"
|
||||
if not database:
|
||||
database = pythoncom.Missing
|
||||
g_sourceSafe.Open(database, pythoncom.Missing, pythoncom.Missing)
|
||||
item = g_sourceSafe.VSSItem("$/%s/%s" % (project, vssFname))
|
||||
item.Checkout(None, fileName)
|
||||
ok = 1
|
||||
except pythoncom.com_error as exc:
|
||||
win32ui.MessageBox(exc.strerror, "Error checking out file")
|
||||
except:
|
||||
typ, val, tb = sys.exc_info()
|
||||
traceback.print_exc()
|
||||
win32ui.MessageBox("%s - %s" % (str(typ), str(val)),"Error checking out file")
|
||||
tb = None # Cleanup a cycle
|
||||
return ok
|
||||
|
||||
|
||||
151
Lib/site-packages/pythonwin/pywin/framework/help.py
Normal file
151
Lib/site-packages/pythonwin/pywin/framework/help.py
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
# help.py - help utilities for PythonWin.
|
||||
import win32api
|
||||
import win32con
|
||||
import win32ui
|
||||
import string
|
||||
import sys
|
||||
import regutil
|
||||
import string, os
|
||||
|
||||
htmlhelp_handle = None
|
||||
|
||||
html_help_command_translators = {
|
||||
win32con.HELP_CONTENTS : 1, # HH_DISPLAY_TOC
|
||||
win32con.HELP_CONTEXT : 15, # HH_HELP_CONTEXT
|
||||
win32con.HELP_FINDER : 1, # HH_DISPLAY_TOC
|
||||
}
|
||||
|
||||
def FinalizeHelp():
|
||||
global htmlhelp_handle
|
||||
if htmlhelp_handle is not None:
|
||||
import win32help
|
||||
try:
|
||||
#frame = win32ui.GetMainFrame().GetSafeHwnd()
|
||||
frame = 0
|
||||
win32help.HtmlHelp(frame, None, win32help.HH_UNINITIALIZE, htmlhelp_handle)
|
||||
except win32help.error:
|
||||
print("Failed to finalize htmlhelp!")
|
||||
htmlhelp_handle = None
|
||||
|
||||
def OpenHelpFile(fileName, helpCmd = None, helpArg = None):
|
||||
"Open a help file, given a full path"
|
||||
# default help arg.
|
||||
win32ui.DoWaitCursor(1)
|
||||
try:
|
||||
if helpCmd is None: helpCmd = win32con.HELP_CONTENTS
|
||||
ext = os.path.splitext(fileName)[1].lower()
|
||||
if ext == ".hlp":
|
||||
win32api.WinHelp( win32ui.GetMainFrame().GetSafeHwnd(), fileName, helpCmd, helpArg)
|
||||
# XXX - using the htmlhelp API wreaks havoc with keyboard shortcuts
|
||||
# so we disable it, forcing ShellExecute, which works fine (but
|
||||
# doesn't close the help file when Pythonwin is closed.
|
||||
# Tom Heller also points out http://www.microsoft.com/mind/0499/faq/faq0499.asp,
|
||||
# which may or may not be related.
|
||||
elif 0 and ext == ".chm":
|
||||
import win32help
|
||||
global htmlhelp_handle
|
||||
helpCmd = html_help_command_translators.get(helpCmd, helpCmd)
|
||||
#frame = win32ui.GetMainFrame().GetSafeHwnd()
|
||||
frame = 0 # Dont want it overlapping ours!
|
||||
if htmlhelp_handle is None:
|
||||
htmlhelp_hwnd, htmlhelp_handle = win32help.HtmlHelp(frame, None, win32help.HH_INITIALIZE)
|
||||
win32help.HtmlHelp(frame, fileName, helpCmd, helpArg)
|
||||
else:
|
||||
# Hope that the extension is registered, and we know what to do!
|
||||
win32api.ShellExecute(0, "open", fileName, None, "", win32con.SW_SHOW)
|
||||
return fileName
|
||||
finally:
|
||||
win32ui.DoWaitCursor(-1)
|
||||
|
||||
def ListAllHelpFiles():
|
||||
ret = []
|
||||
ret = _ListAllHelpFilesInRoot(win32con.HKEY_LOCAL_MACHINE)
|
||||
# Ensure we don't get dups.
|
||||
for item in _ListAllHelpFilesInRoot(win32con.HKEY_CURRENT_USER):
|
||||
if item not in ret:
|
||||
ret.append(item)
|
||||
return ret
|
||||
|
||||
def _ListAllHelpFilesInRoot(root):
|
||||
"""Returns a list of (helpDesc, helpFname) for all registered help files
|
||||
"""
|
||||
import regutil
|
||||
retList = []
|
||||
try:
|
||||
key = win32api.RegOpenKey(root, regutil.BuildDefaultPythonKey() + "\\Help", 0, win32con.KEY_READ)
|
||||
except win32api.error as exc:
|
||||
import winerror
|
||||
if exc.winerror!=winerror.ERROR_FILE_NOT_FOUND:
|
||||
raise
|
||||
return retList
|
||||
try:
|
||||
keyNo = 0
|
||||
while 1:
|
||||
try:
|
||||
helpDesc = win32api.RegEnumKey(key, keyNo)
|
||||
helpFile = win32api.RegQueryValue(key, helpDesc)
|
||||
retList.append((helpDesc, helpFile))
|
||||
keyNo = keyNo + 1
|
||||
except win32api.error as exc:
|
||||
import winerror
|
||||
if exc.winerror!=winerror.ERROR_NO_MORE_ITEMS:
|
||||
raise
|
||||
break
|
||||
finally:
|
||||
win32api.RegCloseKey(key)
|
||||
return retList
|
||||
|
||||
def SelectAndRunHelpFile():
|
||||
from pywin.dialogs import list
|
||||
helpFiles = ListAllHelpFiles()
|
||||
if len(helpFiles)==1:
|
||||
# only 1 help file registered - probably ours - no point asking
|
||||
index = 0
|
||||
else:
|
||||
index = list.SelectFromLists("Select Help file", helpFiles, ["Title"])
|
||||
if index is not None:
|
||||
OpenHelpFile(helpFiles[index][1])
|
||||
|
||||
|
||||
helpIDMap = None
|
||||
|
||||
def SetHelpMenuOtherHelp(mainMenu):
|
||||
"""Modifies the main Help Menu to handle all registered help files.
|
||||
mainMenu -- The main menu to modify - usually from docTemplate.GetSharedMenu()
|
||||
"""
|
||||
|
||||
# Load all help files from the registry.
|
||||
global helpIDMap
|
||||
if helpIDMap is None:
|
||||
helpIDMap = {}
|
||||
cmdID = win32ui.ID_HELP_OTHER
|
||||
excludeList = ['Main Python Documentation', 'Pythonwin Reference']
|
||||
firstList = ListAllHelpFiles()
|
||||
# We actually want to not only exclude these entries, but
|
||||
# their help file names (as many entries may share the same name)
|
||||
excludeFnames = []
|
||||
for desc, fname in firstList:
|
||||
if desc in excludeList:
|
||||
excludeFnames.append(fname)
|
||||
|
||||
helpDescs = []
|
||||
for desc, fname in firstList:
|
||||
if fname not in excludeFnames:
|
||||
helpIDMap[cmdID] = (desc, fname)
|
||||
win32ui.GetMainFrame().HookCommand(HandleHelpOtherCommand, cmdID)
|
||||
cmdID = cmdID + 1
|
||||
|
||||
helpMenu = mainMenu.GetSubMenu(mainMenu.GetMenuItemCount()-1) # Help menu always last.
|
||||
otherHelpMenuPos = 2 # cant search for ID, as sub-menu has no ID.
|
||||
otherMenu = helpMenu.GetSubMenu(otherHelpMenuPos)
|
||||
while otherMenu.GetMenuItemCount():
|
||||
otherMenu.DeleteMenu(0, win32con.MF_BYPOSITION)
|
||||
|
||||
if helpIDMap:
|
||||
for id, (desc, fname) in helpIDMap.items():
|
||||
otherMenu.AppendMenu(win32con.MF_ENABLED|win32con.MF_STRING,id, desc)
|
||||
else:
|
||||
helpMenu.EnableMenuItem(otherHelpMenuPos, win32con.MF_BYPOSITION | win32con.MF_GRAYED)
|
||||
|
||||
def HandleHelpOtherCommand(cmd, code):
|
||||
OpenHelpFile(helpIDMap[cmd][1])
|
||||
870
Lib/site-packages/pythonwin/pywin/framework/interact.py
Normal file
870
Lib/site-packages/pythonwin/pywin/framework/interact.py
Normal file
|
|
@ -0,0 +1,870 @@
|
|||
|
||||
##################################################################
|
||||
##
|
||||
## Interactive Shell Window
|
||||
##
|
||||
|
||||
import sys, os
|
||||
import code
|
||||
import string
|
||||
|
||||
import win32ui
|
||||
import win32api
|
||||
import win32clipboard
|
||||
import win32con
|
||||
import traceback
|
||||
import afxres
|
||||
import array
|
||||
import __main__
|
||||
|
||||
import pywin.scintilla.formatter
|
||||
import pywin.scintilla.control
|
||||
import pywin.scintilla.IDLEenvironment
|
||||
import pywin.framework.app
|
||||
|
||||
## sequential after ID_GOTO_LINE defined in editor.py
|
||||
ID_EDIT_COPY_CODE = 0xe2002
|
||||
ID_EDIT_EXEC_CLIPBOARD = 0x2003
|
||||
|
||||
trace=pywin.scintilla.formatter.trace
|
||||
|
||||
from . import winout
|
||||
|
||||
import re
|
||||
# from IDLE.
|
||||
_is_block_opener = re.compile(r":\s*(#.*)?$").search
|
||||
_is_block_closer = re.compile(r"""
|
||||
\s*
|
||||
( return
|
||||
| break
|
||||
| continue
|
||||
| raise
|
||||
| pass
|
||||
)
|
||||
\b
|
||||
""", re.VERBOSE).match
|
||||
|
||||
tracebackHeader = "Traceback (".encode("ascii")
|
||||
|
||||
sectionProfile = "Interactive Window"
|
||||
valueFormatTitle = "FormatTitle"
|
||||
valueFormatInput = "FormatInput"
|
||||
valueFormatOutput = "FormatOutput"
|
||||
valueFormatOutputError = "FormatOutputError"
|
||||
|
||||
# These are defaults only. Values are read from the registry.
|
||||
formatTitle = (-536870897, 0, 220, 0, 16711680, 184, 34, 'Arial')
|
||||
formatInput = (-402653169, 0, 200, 0, 0, 0, 49, 'Courier New')
|
||||
formatOutput = (-402653169, 0, 200, 0, 8421376, 0, 49, 'Courier New')
|
||||
formatOutputError = (-402653169, 0, 200, 0, 255, 0, 49, 'Courier New')
|
||||
|
||||
try:
|
||||
sys.ps1
|
||||
except AttributeError:
|
||||
sys.ps1 = '>>> '
|
||||
sys.ps2 = '... '
|
||||
|
||||
def LoadPreference(preference, default = ""):
|
||||
return win32ui.GetProfileVal(sectionProfile, preference, default)
|
||||
|
||||
def SavePreference( prefName, prefValue ):
|
||||
win32ui.WriteProfileVal( sectionProfile, prefName, prefValue )
|
||||
|
||||
def GetPromptPrefix(line):
|
||||
ps1=sys.ps1
|
||||
if line[:len(ps1)]==ps1: return ps1
|
||||
ps2=sys.ps2
|
||||
if line[:len(ps2)]==ps2: return ps2
|
||||
|
||||
#############################################################
|
||||
#
|
||||
# Colorizer related code.
|
||||
#
|
||||
#############################################################
|
||||
STYLE_INTERACTIVE_EOL = "Interactive EOL"
|
||||
STYLE_INTERACTIVE_OUTPUT = "Interactive Output"
|
||||
STYLE_INTERACTIVE_PROMPT = "Interactive Prompt"
|
||||
STYLE_INTERACTIVE_BANNER = "Interactive Banner"
|
||||
STYLE_INTERACTIVE_ERROR = "Interactive Error"
|
||||
STYLE_INTERACTIVE_ERROR_FINALLINE = "Interactive Error (final line)"
|
||||
|
||||
INTERACTIVE_STYLES = [STYLE_INTERACTIVE_EOL, STYLE_INTERACTIVE_OUTPUT, STYLE_INTERACTIVE_PROMPT, STYLE_INTERACTIVE_BANNER, STYLE_INTERACTIVE_ERROR, STYLE_INTERACTIVE_ERROR_FINALLINE]
|
||||
|
||||
FormatterParent = pywin.scintilla.formatter.PythonSourceFormatter
|
||||
class InteractiveFormatter(FormatterParent):
|
||||
def __init__(self, scintilla):
|
||||
FormatterParent.__init__(self, scintilla)
|
||||
self.bannerDisplayed = False
|
||||
|
||||
def SetStyles(self):
|
||||
FormatterParent.SetStyles(self)
|
||||
Style = pywin.scintilla.formatter.Style
|
||||
self.RegisterStyle( Style(STYLE_INTERACTIVE_EOL, STYLE_INTERACTIVE_PROMPT ) )
|
||||
self.RegisterStyle( Style(STYLE_INTERACTIVE_PROMPT, formatInput ) )
|
||||
self.RegisterStyle( Style(STYLE_INTERACTIVE_OUTPUT, formatOutput) )
|
||||
self.RegisterStyle( Style(STYLE_INTERACTIVE_BANNER, formatTitle ) )
|
||||
self.RegisterStyle( Style(STYLE_INTERACTIVE_ERROR, formatOutputError ) )
|
||||
self.RegisterStyle( Style(STYLE_INTERACTIVE_ERROR_FINALLINE, STYLE_INTERACTIVE_ERROR ) )
|
||||
|
||||
def LoadPreference(self, name, default):
|
||||
rc = win32ui.GetProfileVal("Format", name, default)
|
||||
if rc==default:
|
||||
rc = win32ui.GetProfileVal(sectionProfile, name, default)
|
||||
return rc
|
||||
|
||||
def ColorizeInteractiveCode(self, cdoc, styleStart, stylePyStart):
|
||||
lengthDoc = len(cdoc)
|
||||
if lengthDoc == 0: return
|
||||
state = styleStart
|
||||
# As per comments in Colorize(), we work with the raw utf8
|
||||
# bytes. To avoid too muych py3k pain, we treat each utf8 byte
|
||||
# as a latin-1 unicode character - we only use it to compare
|
||||
# against ascii chars anyway...
|
||||
chNext = cdoc[0:1].decode('latin-1')
|
||||
startSeg = 0
|
||||
i = 0
|
||||
lastState=state # debug only
|
||||
while i < lengthDoc:
|
||||
ch = chNext
|
||||
chNext = cdoc[i+1:i+2].decode('latin-1')
|
||||
|
||||
# trace("ch=%r, i=%d, next=%r, state=%s" % (ch, i, chNext, state))
|
||||
if state == STYLE_INTERACTIVE_EOL:
|
||||
if ch not in '\r\n':
|
||||
self.ColorSeg(startSeg, i-1, state)
|
||||
startSeg = i
|
||||
if ch in [sys.ps1[0], sys.ps2[0]]:
|
||||
state = STYLE_INTERACTIVE_PROMPT
|
||||
elif cdoc[i:i+len(tracebackHeader)]==tracebackHeader:
|
||||
state = STYLE_INTERACTIVE_ERROR
|
||||
else:
|
||||
state = STYLE_INTERACTIVE_OUTPUT
|
||||
elif state == STYLE_INTERACTIVE_PROMPT:
|
||||
if ch not in sys.ps1 + sys.ps2 + " ":
|
||||
self.ColorSeg(startSeg, i-1, state)
|
||||
startSeg = i
|
||||
if ch in '\r\n':
|
||||
state = STYLE_INTERACTIVE_EOL
|
||||
else:
|
||||
state = stylePyStart # Start coloring Python code.
|
||||
elif state in [STYLE_INTERACTIVE_OUTPUT]:
|
||||
if ch in '\r\n':
|
||||
self.ColorSeg(startSeg, i-1, state)
|
||||
startSeg = i
|
||||
state = STYLE_INTERACTIVE_EOL
|
||||
elif state == STYLE_INTERACTIVE_ERROR:
|
||||
if ch in '\r\n' and chNext and chNext not in string.whitespace:
|
||||
# Everything including me
|
||||
self.ColorSeg(startSeg, i, state)
|
||||
startSeg = i+1
|
||||
state = STYLE_INTERACTIVE_ERROR_FINALLINE
|
||||
elif i == 0 and ch not in string.whitespace:
|
||||
# If we are coloring from the start of a line,
|
||||
# we need this better check for the last line
|
||||
# Color up to not including me
|
||||
self.ColorSeg(startSeg, i-1, state)
|
||||
startSeg = i
|
||||
state = STYLE_INTERACTIVE_ERROR_FINALLINE
|
||||
elif state == STYLE_INTERACTIVE_ERROR_FINALLINE:
|
||||
if ch in '\r\n':
|
||||
self.ColorSeg(startSeg, i-1, state)
|
||||
startSeg = i
|
||||
state = STYLE_INTERACTIVE_EOL
|
||||
elif state == STYLE_INTERACTIVE_BANNER:
|
||||
if ch in '\r\n' and (chNext=='' or chNext in ">["):
|
||||
# Everything including me
|
||||
self.ColorSeg(startSeg, i-1, state)
|
||||
startSeg = i
|
||||
state = STYLE_INTERACTIVE_EOL
|
||||
else:
|
||||
# It is a PythonColorizer state - seek past the end of the line
|
||||
# and ask the Python colorizer to color that.
|
||||
end = startSeg
|
||||
while end < lengthDoc and cdoc[end] not in '\r\n'.encode('ascii'):
|
||||
end = end + 1
|
||||
self.ColorizePythonCode( cdoc[:end], startSeg, state)
|
||||
stylePyStart = self.GetStringStyle(end-1)
|
||||
if stylePyStart is None:
|
||||
stylePyStart = pywin.scintilla.formatter.STYLE_DEFAULT
|
||||
else:
|
||||
stylePyStart = stylePyStart.name
|
||||
startSeg =end
|
||||
i = end - 1 # ready for increment.
|
||||
chNext = cdoc[end:end+1].decode('latin-1')
|
||||
state = STYLE_INTERACTIVE_EOL
|
||||
if lastState != state:
|
||||
lastState = state
|
||||
i = i + 1
|
||||
# and the rest
|
||||
if startSeg<i:
|
||||
self.ColorSeg(startSeg, i-1, state)
|
||||
|
||||
def Colorize(self, start=0, end=-1):
|
||||
# scintilla's formatting is all done in terms of utf, so
|
||||
# we work with utf8 bytes instead of unicode. This magically
|
||||
# works as any extended chars found in the utf8 don't change
|
||||
# the semantics.
|
||||
stringVal = self.scintilla.GetTextRange(start, end, decode=False)
|
||||
styleStart = None
|
||||
stylePyStart = None
|
||||
if start > 1:
|
||||
# Likely we are being asked to color from the start of the line.
|
||||
# We find the last formatted character on the previous line.
|
||||
# If TQString, we continue it. Otherwise, we reset.
|
||||
look = start -1
|
||||
while look and self.scintilla.SCIGetCharAt(look) in '\n\r':
|
||||
look = look - 1
|
||||
if look and look < start-1: # Did we find a char before the \n\r sets?
|
||||
strstyle = self.GetStringStyle(look)
|
||||
quote_char = None
|
||||
if strstyle is not None:
|
||||
if strstyle.name == pywin.scintilla.formatter.STYLE_TQSSTRING:
|
||||
quote_char = "'"
|
||||
elif strstyle.name == pywin.scintilla.formatter.STYLE_TQDSTRING:
|
||||
quote_char = '"'
|
||||
if quote_char is not None:
|
||||
# It is a TQS. If the TQS is not terminated, we
|
||||
# carry the style through.
|
||||
if look > 2:
|
||||
look_str = self.scintilla.SCIGetCharAt(look-2) + self.scintilla.SCIGetCharAt(look-1) + self.scintilla.SCIGetCharAt(look)
|
||||
if look_str != quote_char * 3:
|
||||
stylePyStart = strstyle.name
|
||||
if stylePyStart is None: stylePyStart = pywin.scintilla.formatter.STYLE_DEFAULT
|
||||
|
||||
if start > 0:
|
||||
stylenum = self.scintilla.SCIGetStyleAt(start - 1)
|
||||
styleStart = self.GetStyleByNum(stylenum).name
|
||||
elif self.bannerDisplayed:
|
||||
styleStart = STYLE_INTERACTIVE_EOL
|
||||
else:
|
||||
styleStart = STYLE_INTERACTIVE_BANNER
|
||||
self.bannerDisplayed = True
|
||||
self.scintilla.SCIStartStyling(start, 31)
|
||||
self.style_buffer = array.array("b", (0,)*len(stringVal))
|
||||
self.ColorizeInteractiveCode(stringVal, styleStart, stylePyStart)
|
||||
self.scintilla.SCISetStylingEx(self.style_buffer)
|
||||
self.style_buffer = None
|
||||
|
||||
###############################################################
|
||||
#
|
||||
# This class handles the Python interactive interpreter.
|
||||
#
|
||||
# It uses a basic EditWindow, and does all the magic.
|
||||
# This is triggered by the enter key hander attached by the
|
||||
# start-up code. It determines if a command is to be executed
|
||||
# or continued (ie, emit "... ") by snooping around the current
|
||||
# line, looking for the prompts
|
||||
#
|
||||
class PythonwinInteractiveInterpreter(code.InteractiveInterpreter):
|
||||
def __init__(self, locals = None, globals = None):
|
||||
if locals is None: locals = __main__.__dict__
|
||||
if globals is None: globals = locals
|
||||
self.globals = globals
|
||||
code.InteractiveInterpreter.__init__(self, locals)
|
||||
def showsyntaxerror(self, filename=None):
|
||||
sys.stderr.write(tracebackHeader.decode('ascii')) # So the color syntaxer recognises it.
|
||||
code.InteractiveInterpreter.showsyntaxerror(self, filename)
|
||||
def runcode(self, code):
|
||||
try:
|
||||
exec(code, self.globals, self.locals)
|
||||
except SystemExit:
|
||||
raise
|
||||
except:
|
||||
self.showtraceback()
|
||||
|
||||
class InteractiveCore:
|
||||
def __init__(self, banner = None):
|
||||
self.banner = banner
|
||||
# LoadFontPreferences()
|
||||
def Init(self):
|
||||
self.oldStdOut = self.oldStdErr = None
|
||||
|
||||
# self.SetWordWrap(win32ui.CRichEditView_WrapNone)
|
||||
self.interp = PythonwinInteractiveInterpreter()
|
||||
|
||||
self.OutputGrab() # Release at cleanup.
|
||||
|
||||
if self.GetTextLength()==0:
|
||||
if self.banner is None:
|
||||
suffix = ""
|
||||
if win32ui.debug: suffix = ", debug build"
|
||||
sys.stderr.write("PythonWin %s on %s%s.\n" % (sys.version, sys.platform, suffix) )
|
||||
sys.stderr.write("Portions %s - see 'Help/About PythonWin' for further copyright information.\n" % (win32ui.copyright,) )
|
||||
else:
|
||||
sys.stderr.write(banner)
|
||||
rcfile = os.environ.get('PYTHONSTARTUP')
|
||||
if rcfile:
|
||||
import __main__
|
||||
try:
|
||||
execfile(rcfile, __main__.__dict__, __main__.__dict__)
|
||||
except:
|
||||
sys.stderr.write(">>> \nError executing PYTHONSTARTUP script %r\n" % (rcfile))
|
||||
traceback.print_exc(file=sys.stderr)
|
||||
self.AppendToPrompt([])
|
||||
|
||||
def SetContext(self, globals, locals, name = "Dbg"):
|
||||
oldPrompt = sys.ps1
|
||||
if globals is None:
|
||||
# Reset
|
||||
sys.ps1 = ">>> "
|
||||
sys.ps2 = "... "
|
||||
locals = globals = __main__.__dict__
|
||||
else:
|
||||
sys.ps1 = "[%s]>>> " % name
|
||||
sys.ps2 = "[%s]... " % name
|
||||
self.interp.locals = locals
|
||||
self.interp.globals = globals
|
||||
self.AppendToPrompt([], oldPrompt)
|
||||
|
||||
def GetContext(self):
|
||||
return self.interp.globals, self.interp.locals
|
||||
|
||||
def DoGetLine(self, line=-1):
|
||||
if line==-1: line = self.LineFromChar()
|
||||
line = self.GetLine(line)
|
||||
while line and line[-1] in ['\r', '\n']:
|
||||
line = line[:-1]
|
||||
return line
|
||||
def AppendToPrompt(self,bufLines, oldPrompt = None):
|
||||
" Take a command and stick it at the end of the buffer (with python prompts inserted if required)."
|
||||
self.flush()
|
||||
lastLineNo = self.GetLineCount()-1
|
||||
line = self.DoGetLine(lastLineNo)
|
||||
if oldPrompt and line==oldPrompt:
|
||||
self.SetSel(self.GetTextLength()-len(oldPrompt), self.GetTextLength())
|
||||
self.ReplaceSel(sys.ps1)
|
||||
elif (line!=str(sys.ps1)):
|
||||
if len(line)!=0: self.write('\n')
|
||||
self.write(sys.ps1)
|
||||
self.flush()
|
||||
self.idle.text.mark_set("iomark", "end-1c")
|
||||
if not bufLines:
|
||||
return
|
||||
terms = (["\n" + sys.ps2] * (len(bufLines)-1)) + ['']
|
||||
for bufLine, term in zip(bufLines, terms):
|
||||
if bufLine.strip():
|
||||
self.write( bufLine + term )
|
||||
self.flush()
|
||||
|
||||
def EnsureNoPrompt(self):
|
||||
# Get ready to write some text NOT at a Python prompt.
|
||||
self.flush()
|
||||
lastLineNo = self.GetLineCount()-1
|
||||
line = self.DoGetLine(lastLineNo)
|
||||
if not line or line in [sys.ps1, sys.ps2]:
|
||||
self.SetSel(self.GetTextLength()-len(line), self.GetTextLength())
|
||||
self.ReplaceSel('')
|
||||
else:
|
||||
# Just add a new line.
|
||||
self.write('\n')
|
||||
|
||||
def _GetSubConfigNames(self):
|
||||
return ["interactive"] # Allow [Keys:Interactive] sections to be specific
|
||||
|
||||
def HookHandlers(self):
|
||||
# Hook menu command (executed when a menu item with that ID is selected from a menu/toolbar
|
||||
self.HookCommand(self.OnSelectBlock, win32ui.ID_EDIT_SELECT_BLOCK)
|
||||
self.HookCommand(self.OnEditCopyCode, ID_EDIT_COPY_CODE)
|
||||
self.HookCommand(self.OnEditExecClipboard, ID_EDIT_EXEC_CLIPBOARD)
|
||||
mod = pywin.scintilla.IDLEenvironment.GetIDLEModule("IdleHistory")
|
||||
if mod is not None:
|
||||
self.history = mod.History(self.idle.text, "\n" + sys.ps2)
|
||||
else:
|
||||
self.history = None
|
||||
# hack for now for event handling.
|
||||
|
||||
# GetBlockBoundary takes a line number, and will return the
|
||||
# start and and line numbers of the block, and a flag indicating if the
|
||||
# block is a Python code block.
|
||||
# If the line specified has a Python prompt, then the lines are parsed
|
||||
# backwards and forwards, and the flag is true.
|
||||
# If the line does not start with a prompt, the block is searched forward
|
||||
# and backward until a prompt _is_ found, and all lines in between without
|
||||
# prompts are returned, and the flag is false.
|
||||
def GetBlockBoundary( self, lineNo ):
|
||||
line = self.DoGetLine(lineNo)
|
||||
maxLineNo = self.GetLineCount()-1
|
||||
prefix = GetPromptPrefix(line)
|
||||
if prefix is None: # Non code block
|
||||
flag = 0
|
||||
startLineNo = lineNo
|
||||
while startLineNo>0:
|
||||
if GetPromptPrefix(self.DoGetLine(startLineNo-1)) is not None:
|
||||
break # there _is_ a prompt
|
||||
startLineNo = startLineNo-1
|
||||
endLineNo = lineNo
|
||||
while endLineNo<maxLineNo:
|
||||
if GetPromptPrefix(self.DoGetLine(endLineNo+1)) is not None:
|
||||
break # there _is_ a prompt
|
||||
endLineNo = endLineNo+1
|
||||
else: # Code block
|
||||
flag = 1
|
||||
startLineNo = lineNo
|
||||
while startLineNo>0 and prefix!=str(sys.ps1):
|
||||
prefix = GetPromptPrefix(self.DoGetLine(startLineNo-1))
|
||||
if prefix is None:
|
||||
break; # there is no prompt.
|
||||
startLineNo = startLineNo - 1
|
||||
endLineNo = lineNo
|
||||
while endLineNo<maxLineNo:
|
||||
prefix = GetPromptPrefix(self.DoGetLine(endLineNo+1))
|
||||
if prefix is None:
|
||||
break # there is no prompt
|
||||
if prefix==str(sys.ps1):
|
||||
break # this is another command
|
||||
endLineNo = endLineNo+1
|
||||
# continue until end of buffer, or no prompt
|
||||
return (startLineNo, endLineNo, flag)
|
||||
|
||||
def ExtractCommand( self, lines ):
|
||||
start, end = lines
|
||||
retList = []
|
||||
while end >= start:
|
||||
thisLine = self.DoGetLine(end)
|
||||
promptLen = len(GetPromptPrefix(thisLine))
|
||||
retList = [thisLine[promptLen:]] + retList
|
||||
end = end-1
|
||||
return retList
|
||||
|
||||
def OutputGrab(self):
|
||||
# import win32traceutil; return
|
||||
self.oldStdOut = sys.stdout
|
||||
self.oldStdErr = sys.stderr
|
||||
sys.stdout=self
|
||||
sys.stderr=self
|
||||
self.flush()
|
||||
|
||||
def OutputRelease(self):
|
||||
# a command may have overwritten these - only restore if not.
|
||||
if self.oldStdOut is not None:
|
||||
if sys.stdout == self:
|
||||
sys.stdout=self.oldStdOut
|
||||
if self.oldStdErr is not None:
|
||||
if sys.stderr == self:
|
||||
sys.stderr=self.oldStdErr
|
||||
self.oldStdOut = None
|
||||
self.oldStdErr = None
|
||||
self.flush()
|
||||
|
||||
###################################
|
||||
#
|
||||
# Message/Command/Key Hooks.
|
||||
#
|
||||
# Enter key handler
|
||||
#
|
||||
def ProcessEnterEvent(self, event ):
|
||||
#If autocompletion has been triggered, complete and do not process event
|
||||
if self.SCIAutoCActive():
|
||||
self.SCIAutoCComplete()
|
||||
self.SCICancel()
|
||||
return
|
||||
|
||||
self.SCICancel()
|
||||
# First, check for an error message
|
||||
haveGrabbedOutput = 0
|
||||
if self.HandleSpecialLine(): return 0
|
||||
|
||||
lineNo = self.LineFromChar()
|
||||
start, end, isCode = self.GetBlockBoundary(lineNo)
|
||||
# If we are not in a code block just go to the prompt (or create a new one)
|
||||
if not isCode:
|
||||
self.AppendToPrompt([])
|
||||
win32ui.SetStatusText(win32ui.LoadString(afxres.AFX_IDS_IDLEMESSAGE))
|
||||
return
|
||||
|
||||
lines = self.ExtractCommand((start,end))
|
||||
|
||||
# If we are in a code-block, but it isnt at the end of the buffer
|
||||
# then copy it to the end ready for editing and subsequent execution
|
||||
if end!=self.GetLineCount()-1:
|
||||
win32ui.SetStatusText('Press ENTER to execute command')
|
||||
self.AppendToPrompt(lines)
|
||||
self.SetSel(-2)
|
||||
return
|
||||
|
||||
# If SHIFT held down, we want new code here and now!
|
||||
bNeedIndent = win32api.GetKeyState(win32con.VK_SHIFT)<0 or win32api.GetKeyState(win32con.VK_CONTROL)<0
|
||||
if bNeedIndent:
|
||||
self.ReplaceSel("\n")
|
||||
else:
|
||||
self.SetSel(-2)
|
||||
self.ReplaceSel("\n")
|
||||
source = '\n'.join(lines)
|
||||
while source and source[-1] in '\t ':
|
||||
source = source[:-1]
|
||||
self.OutputGrab() # grab the output for the command exec.
|
||||
try:
|
||||
if self.interp.runsource(source, "<interactive input>"): # Need more input!
|
||||
bNeedIndent = 1
|
||||
else:
|
||||
# If the last line isnt empty, append a newline
|
||||
if self.history is not None:
|
||||
self.history.history_store(source)
|
||||
self.AppendToPrompt([])
|
||||
win32ui.SetStatusText(win32ui.LoadString(afxres.AFX_IDS_IDLEMESSAGE))
|
||||
# win32ui.SetStatusText('Successfully executed statement')
|
||||
finally:
|
||||
self.OutputRelease()
|
||||
if bNeedIndent:
|
||||
win32ui.SetStatusText('Ready to continue the command')
|
||||
# Now attempt correct indentation (should use IDLE?)
|
||||
curLine = self.DoGetLine(lineNo)[len(sys.ps2):]
|
||||
pos = 0
|
||||
indent=''
|
||||
while len(curLine)>pos and curLine[pos] in string.whitespace:
|
||||
indent = indent + curLine[pos]
|
||||
pos = pos + 1
|
||||
if _is_block_opener(curLine):
|
||||
indent = indent + '\t'
|
||||
elif _is_block_closer(curLine):
|
||||
indent = indent[:-1]
|
||||
# use ReplaceSel to ensure it goes at the cursor rather than end of buffer.
|
||||
self.ReplaceSel(sys.ps2+indent)
|
||||
return 0
|
||||
|
||||
# ESC key handler
|
||||
def ProcessEscEvent(self, event):
|
||||
# Implement a cancel.
|
||||
if self.SCIAutoCActive() or self.SCICallTipActive():
|
||||
self.SCICancel()
|
||||
else:
|
||||
win32ui.SetStatusText('Cancelled.')
|
||||
self.AppendToPrompt(('',))
|
||||
return 0
|
||||
|
||||
def OnSelectBlock(self,command, code):
|
||||
lineNo = self.LineFromChar()
|
||||
start, end, isCode = self.GetBlockBoundary(lineNo)
|
||||
startIndex = self.LineIndex(start)
|
||||
endIndex = self.LineIndex(end+1)-2 # skip \r + \n
|
||||
if endIndex<0: # must be beyond end of buffer
|
||||
endIndex = -2 # self.Length()
|
||||
self.SetSel(startIndex,endIndex)
|
||||
|
||||
def OnEditCopyCode(self, command, code):
|
||||
""" Sanitizes code from interactive window, removing prompts and output,
|
||||
and inserts it in the clipboard."""
|
||||
code=self.GetSelText()
|
||||
lines=code.splitlines()
|
||||
out_lines=[]
|
||||
for line in lines:
|
||||
if line.startswith(sys.ps1):
|
||||
line=line[len(sys.ps1):]
|
||||
out_lines.append(line)
|
||||
elif line.startswith(sys.ps2):
|
||||
line=line[len(sys.ps2):]
|
||||
out_lines.append(line)
|
||||
out_code=os.linesep.join(out_lines)
|
||||
win32clipboard.OpenClipboard()
|
||||
try:
|
||||
win32clipboard.SetClipboardData(win32clipboard.CF_UNICODETEXT, str(out_code))
|
||||
finally:
|
||||
win32clipboard.CloseClipboard()
|
||||
|
||||
def OnEditExecClipboard(self, command, code):
|
||||
""" Executes python code directly from the clipboard."""
|
||||
win32clipboard.OpenClipboard()
|
||||
try:
|
||||
code=win32clipboard.GetClipboardData(win32clipboard.CF_UNICODETEXT)
|
||||
finally:
|
||||
win32clipboard.CloseClipboard()
|
||||
|
||||
code=code.replace('\r\n','\n')+'\n'
|
||||
try:
|
||||
o=compile(code, '<clipboard>', 'exec')
|
||||
exec(o, __main__.__dict__)
|
||||
except:
|
||||
traceback.print_exc()
|
||||
|
||||
def GetRightMenuItems(self):
|
||||
# Just override parents
|
||||
ret = []
|
||||
flags = 0
|
||||
ret.append((flags, win32ui.ID_EDIT_UNDO, '&Undo'))
|
||||
ret.append(win32con.MF_SEPARATOR)
|
||||
ret.append((flags, win32ui.ID_EDIT_CUT, 'Cu&t'))
|
||||
ret.append((flags, win32ui.ID_EDIT_COPY, '&Copy'))
|
||||
|
||||
start, end=self.GetSel()
|
||||
if start!=end:
|
||||
ret.append((flags, ID_EDIT_COPY_CODE, 'Copy code without prompts'))
|
||||
if win32clipboard.IsClipboardFormatAvailable(win32clipboard.CF_UNICODETEXT):
|
||||
ret.append((flags, ID_EDIT_EXEC_CLIPBOARD, 'Execute python code from clipboard'))
|
||||
|
||||
ret.append((flags, win32ui.ID_EDIT_PASTE, '&Paste'))
|
||||
ret.append(win32con.MF_SEPARATOR)
|
||||
ret.append((flags, win32ui.ID_EDIT_SELECT_ALL, '&Select all'))
|
||||
ret.append((flags, win32ui.ID_EDIT_SELECT_BLOCK, 'Select &block'))
|
||||
ret.append((flags, win32ui.ID_VIEW_WHITESPACE, "View &Whitespace"))
|
||||
return ret
|
||||
|
||||
def MDINextEvent(self, event):
|
||||
win32ui.GetMainFrame().MDINext(0)
|
||||
def MDIPrevEvent(self, event):
|
||||
win32ui.GetMainFrame().MDINext(0)
|
||||
|
||||
def WindowBackEvent(self, event):
|
||||
parent = self.GetParentFrame()
|
||||
if parent == win32ui.GetMainFrame():
|
||||
# It is docked.
|
||||
try:
|
||||
wnd, isactive = parent.MDIGetActive()
|
||||
wnd.SetFocus()
|
||||
except win32ui.error:
|
||||
# No MDI window active!
|
||||
pass
|
||||
else:
|
||||
# Normal Window
|
||||
try:
|
||||
lastActive = self.GetParentFrame().lastActive
|
||||
# If the window is invalid, reset it.
|
||||
if lastActive is not None and (lastActive._obj_ is None or lastActive.GetSafeHwnd()==0):
|
||||
lastActive = self.GetParentFrame().lastActive = None
|
||||
win32ui.SetStatusText("The last active Window has been closed.")
|
||||
except AttributeError:
|
||||
print("Can't find the last active window!")
|
||||
lastActive = None
|
||||
if lastActive is not None:
|
||||
lastActive.MDIActivate()
|
||||
|
||||
class InteractiveView(InteractiveCore, winout.WindowOutputView):
|
||||
def __init__(self, doc):
|
||||
InteractiveCore.__init__(self)
|
||||
winout.WindowOutputView.__init__(self, doc)
|
||||
self.encoding = pywin.default_scintilla_encoding
|
||||
|
||||
def _MakeColorizer(self):
|
||||
return InteractiveFormatter(self)
|
||||
def OnInitialUpdate(self):
|
||||
winout.WindowOutputView.OnInitialUpdate(self)
|
||||
self.SetWordWrap()
|
||||
self.Init()
|
||||
def HookHandlers(self):
|
||||
winout.WindowOutputView.HookHandlers(self)
|
||||
InteractiveCore.HookHandlers(self)
|
||||
|
||||
class CInteractivePython(winout.WindowOutput):
|
||||
def __init__(self, makeDoc = None, makeFrame = None):
|
||||
self.IsFinalDestroy = 0
|
||||
winout.WindowOutput.__init__(self, sectionProfile, sectionProfile, \
|
||||
winout.flags.WQ_LINE, 1, None, makeDoc, makeFrame, InteractiveView )
|
||||
self.Create()
|
||||
|
||||
def OnViewDestroy(self, view):
|
||||
if self.IsFinalDestroy:
|
||||
view.OutputRelease()
|
||||
winout.WindowOutput.OnViewDestroy(self, view)
|
||||
|
||||
def Close(self):
|
||||
self.IsFinalDestroy = 1
|
||||
winout.WindowOutput.Close(self)
|
||||
|
||||
class InteractiveFrame(winout.WindowOutputFrame):
|
||||
def __init__(self):
|
||||
self.lastActive = None
|
||||
winout.WindowOutputFrame.__init__(self)
|
||||
|
||||
def OnMDIActivate(self, bActive, wndActive, wndDeactive):
|
||||
if bActive:
|
||||
self.lastActive = wndDeactive
|
||||
|
||||
######################################################################
|
||||
##
|
||||
## Dockable Window Support
|
||||
##
|
||||
######################################################################
|
||||
ID_DOCKED_INTERACTIVE_CONTROLBAR = 0xe802
|
||||
|
||||
DockedInteractiveViewParent = InteractiveView
|
||||
class DockedInteractiveView(DockedInteractiveViewParent):
|
||||
def HookHandlers(self):
|
||||
DockedInteractiveViewParent.HookHandlers(self)
|
||||
self.HookMessage(self.OnSetFocus, win32con.WM_SETFOCUS)
|
||||
self.HookMessage(self.OnKillFocus, win32con.WM_KILLFOCUS)
|
||||
def OnSetFocus(self, msg):
|
||||
self.GetParentFrame().SetActiveView(self)
|
||||
return 1
|
||||
def OnKillFocus(self, msg):
|
||||
# If we are losing focus to another in this app, reset the main frame's active view.
|
||||
hwnd = wparam = msg[2]
|
||||
try:
|
||||
wnd = win32ui.CreateWindowFromHandle(hwnd)
|
||||
reset = wnd.GetTopLevelFrame()==self.GetTopLevelFrame()
|
||||
except win32ui.error:
|
||||
reset = 0 # Not my window
|
||||
if reset: self.GetParentFrame().SetActiveView(None)
|
||||
return 1
|
||||
def OnDestroy(self, msg):
|
||||
newSize = self.GetWindowPlacement()[4]
|
||||
pywin.framework.app.SaveWindowSize("Interactive Window", newSize, "docked")
|
||||
try:
|
||||
if self.GetParentFrame().GetActiveView==self:
|
||||
self.GetParentFrame().SetActiveView(None)
|
||||
except win32ui.error:
|
||||
pass
|
||||
try:
|
||||
if win32ui.GetMainFrame().GetActiveView()==self:
|
||||
win32ui.GetMainFrame().SetActiveView(None)
|
||||
except win32ui.error:
|
||||
pass
|
||||
return DockedInteractiveViewParent.OnDestroy(self, msg)
|
||||
|
||||
class CDockedInteractivePython(CInteractivePython):
|
||||
def __init__(self, dockbar):
|
||||
self.bFirstCreated = 0
|
||||
self.dockbar = dockbar
|
||||
CInteractivePython.__init__(self)
|
||||
def NeedRecreateWindow(self):
|
||||
if self.bCreating:
|
||||
return 0
|
||||
try:
|
||||
frame = win32ui.GetMainFrame()
|
||||
if frame.closing:
|
||||
return 0 # Dieing!
|
||||
except (win32ui.error, AttributeError):
|
||||
return 0 # The app is dieing!
|
||||
try:
|
||||
cb = frame.GetControlBar(ID_DOCKED_INTERACTIVE_CONTROLBAR)
|
||||
return not cb.IsWindowVisible()
|
||||
except win32ui.error:
|
||||
return 1 # Control bar does not exist!
|
||||
def RecreateWindow(self):
|
||||
try:
|
||||
dockbar = win32ui.GetMainFrame().GetControlBar(ID_DOCKED_INTERACTIVE_CONTROLBAR)
|
||||
win32ui.GetMainFrame().ShowControlBar(dockbar, 1, 1)
|
||||
except win32ui.error:
|
||||
CreateDockedInteractiveWindow()
|
||||
|
||||
def Create(self):
|
||||
self.bCreating = 1
|
||||
doc = InteractiveDocument(None, self.DoCreateDoc())
|
||||
view = DockedInteractiveView(doc)
|
||||
defRect = pywin.framework.app.LoadWindowSize("Interactive Window", "docked")
|
||||
if defRect[2]-defRect[0]==0:
|
||||
defRect = 0, 0, 500, 200
|
||||
style = win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.WS_BORDER
|
||||
id = 1050 # win32ui.AFX_IDW_PANE_FIRST
|
||||
view.CreateWindow(self.dockbar, id, style, defRect)
|
||||
view.OnInitialUpdate()
|
||||
self.bFirstCreated = 1
|
||||
|
||||
self.currentView = doc.GetFirstView()
|
||||
self.bCreating = 0
|
||||
if self.title: doc.SetTitle(self.title)
|
||||
|
||||
# The factory we pass to the dockable window support.
|
||||
def InteractiveViewCreator(parent):
|
||||
global edit
|
||||
edit = CDockedInteractivePython(parent)
|
||||
return edit.currentView
|
||||
|
||||
def CreateDockedInteractiveWindow():
|
||||
# Later, the DockingBar should be capable of hosting multiple
|
||||
# children.
|
||||
from pywin.docking.DockingBar import DockingBar
|
||||
bar = DockingBar()
|
||||
creator = InteractiveViewCreator
|
||||
bar.CreateWindow(win32ui.GetMainFrame(), creator, "Interactive Window", ID_DOCKED_INTERACTIVE_CONTROLBAR)
|
||||
bar.SetBarStyle( bar.GetBarStyle()|afxres.CBRS_TOOLTIPS|afxres.CBRS_FLYBY|afxres.CBRS_SIZE_DYNAMIC)
|
||||
bar.EnableDocking(afxres.CBRS_ALIGN_ANY)
|
||||
win32ui.GetMainFrame().DockControlBar(bar, afxres.AFX_IDW_DOCKBAR_BOTTOM)
|
||||
|
||||
######################################################################
|
||||
#
|
||||
# The public interface to this module.
|
||||
#
|
||||
######################################################################
|
||||
# No extra functionality now, but maybe later, so
|
||||
# publicize these names.
|
||||
InteractiveDocument = winout.WindowOutputDocument
|
||||
|
||||
# We remember our one and only interactive window in the "edit" variable.
|
||||
edit = None
|
||||
|
||||
def CreateInteractiveWindowUserPreference(makeDoc = None, makeFrame = None):
|
||||
"""Create some sort of interactive window if the user's preference say we should.
|
||||
"""
|
||||
bCreate = LoadPreference("Show at startup", 1)
|
||||
if bCreate:
|
||||
CreateInteractiveWindow(makeDoc, makeFrame)
|
||||
|
||||
def CreateInteractiveWindow(makeDoc = None, makeFrame = None):
|
||||
"""Create a standard or docked interactive window unconditionally
|
||||
"""
|
||||
assert edit is None, "Creating second interactive window!"
|
||||
bDocking = LoadPreference("Docking", 0)
|
||||
if bDocking:
|
||||
CreateDockedInteractiveWindow()
|
||||
else:
|
||||
CreateMDIInteractiveWindow(makeDoc, makeFrame)
|
||||
assert edit is not None, "Created interactive window, but did not set the global!"
|
||||
edit.currentView.SetFocus()
|
||||
|
||||
def CreateMDIInteractiveWindow(makeDoc = None, makeFrame = None):
|
||||
"""Create a standard (non-docked) interactive window unconditionally
|
||||
"""
|
||||
global edit
|
||||
if makeDoc is None: makeDoc = InteractiveDocument
|
||||
if makeFrame is None: makeFrame = InteractiveFrame
|
||||
edit = CInteractivePython(makeDoc=makeDoc,makeFrame=makeFrame)
|
||||
|
||||
def DestroyInteractiveWindow():
|
||||
""" Destroy the interactive window.
|
||||
This is different to Closing the window,
|
||||
which may automatically re-appear. Once destroyed, it can never be recreated,
|
||||
and a complete new instance must be created (which the various other helper
|
||||
functions will then do after making this call
|
||||
"""
|
||||
global edit
|
||||
if edit is not None and edit.currentView is not None:
|
||||
if edit.currentView.GetParentFrame() == win32ui.GetMainFrame():
|
||||
# It is docked - do nothing now (this is only called at shutdown!)
|
||||
pass
|
||||
else:
|
||||
# It is a standard window - call Close on the container.
|
||||
edit.Close()
|
||||
edit = None
|
||||
|
||||
def CloseInteractiveWindow():
|
||||
"""Close the interactive window, allowing it to be re-created on demand.
|
||||
"""
|
||||
global edit
|
||||
if edit is not None and edit.currentView is not None:
|
||||
if edit.currentView.GetParentFrame() == win32ui.GetMainFrame():
|
||||
# It is docked, just hide the dock bar.
|
||||
frame = win32ui.GetMainFrame()
|
||||
cb = frame.GetControlBar(ID_DOCKED_INTERACTIVE_CONTROLBAR)
|
||||
frame.ShowControlBar(cb, 0, 1)
|
||||
else:
|
||||
# It is a standard window - destroy the frame/view, allowing the object itself to remain.
|
||||
edit.currentView.GetParentFrame().DestroyWindow()
|
||||
|
||||
def ToggleInteractiveWindow():
|
||||
"""If the interactive window is visible, hide it, otherwise show it.
|
||||
"""
|
||||
if edit is None:
|
||||
CreateInteractiveWindow()
|
||||
else:
|
||||
if edit.NeedRecreateWindow():
|
||||
edit.RecreateWindow()
|
||||
else:
|
||||
# Close it, allowing a reopen.
|
||||
CloseInteractiveWindow()
|
||||
|
||||
def ShowInteractiveWindow():
|
||||
"""Shows (or creates if necessary) an interactive window"""
|
||||
if edit is None:
|
||||
CreateInteractiveWindow()
|
||||
else:
|
||||
if edit.NeedRecreateWindow():
|
||||
edit.RecreateWindow()
|
||||
else:
|
||||
parent = edit.currentView.GetParentFrame()
|
||||
if parent == win32ui.GetMainFrame(): # It is docked.
|
||||
edit.currentView.SetFocus()
|
||||
else: # It is a "normal" window
|
||||
edit.currentView.GetParentFrame().AutoRestore()
|
||||
win32ui.GetMainFrame().MDIActivate(edit.currentView.GetParentFrame())
|
||||
|
||||
def IsInteractiveWindowVisible():
|
||||
return edit is not None and not edit.NeedRecreateWindow()
|
||||
447
Lib/site-packages/pythonwin/pywin/framework/intpyapp.py
Normal file
447
Lib/site-packages/pythonwin/pywin/framework/intpyapp.py
Normal file
|
|
@ -0,0 +1,447 @@
|
|||
# intpyapp.py - Interactive Python application class
|
||||
#
|
||||
import win32con
|
||||
import win32api
|
||||
import win32ui
|
||||
import __main__
|
||||
import sys
|
||||
import string
|
||||
from . import app
|
||||
import traceback
|
||||
from pywin.mfc import window, afxres, dialog
|
||||
import commctrl
|
||||
from . import dbgcommands
|
||||
|
||||
lastLocateFileName = ".py" # used in the "File/Locate" dialog...
|
||||
|
||||
# todo - _SetupSharedMenu should be moved to a framework class.
|
||||
def _SetupSharedMenu_(self):
|
||||
sharedMenu = self.GetSharedMenu()
|
||||
from pywin.framework import toolmenu
|
||||
toolmenu.SetToolsMenu(sharedMenu)
|
||||
from pywin.framework import help
|
||||
help.SetHelpMenuOtherHelp(sharedMenu)
|
||||
from pywin.mfc import docview
|
||||
docview.DocTemplate._SetupSharedMenu_=_SetupSharedMenu_
|
||||
|
||||
class MainFrame(app.MainFrame):
|
||||
def OnCreate(self, createStruct):
|
||||
self.closing = 0
|
||||
if app.MainFrame.OnCreate(self, createStruct)==-1:
|
||||
return -1
|
||||
style = win32con.WS_CHILD | afxres.CBRS_SIZE_DYNAMIC | afxres.CBRS_TOP | afxres.CBRS_TOOLTIPS | afxres.CBRS_FLYBY
|
||||
|
||||
self.EnableDocking(afxres.CBRS_ALIGN_ANY)
|
||||
|
||||
tb = win32ui.CreateToolBar (self, style | win32con.WS_VISIBLE)
|
||||
tb.ModifyStyle(0, commctrl.TBSTYLE_FLAT)
|
||||
tb.LoadToolBar(win32ui.IDR_MAINFRAME)
|
||||
tb.EnableDocking(afxres.CBRS_ALIGN_ANY)
|
||||
tb.SetWindowText("Standard")
|
||||
self.DockControlBar(tb)
|
||||
# Any other packages which use toolbars
|
||||
from pywin.debugger.debugger import PrepareControlBars
|
||||
PrepareControlBars(self)
|
||||
# Note "interact" also uses dockable windows, but they already happen
|
||||
|
||||
# And a "Tools" menu on the main frame.
|
||||
menu = self.GetMenu()
|
||||
from . import toolmenu
|
||||
toolmenu.SetToolsMenu(menu, 2)
|
||||
# And fix the "Help" menu on the main frame
|
||||
from pywin.framework import help
|
||||
help.SetHelpMenuOtherHelp(menu)
|
||||
|
||||
def OnClose(self):
|
||||
try:
|
||||
import pywin.debugger
|
||||
if pywin.debugger.currentDebugger is not None and pywin.debugger.currentDebugger.pumping:
|
||||
try:
|
||||
pywin.debugger.currentDebugger.close(1)
|
||||
except:
|
||||
traceback.print_exc()
|
||||
return
|
||||
except win32ui.error:
|
||||
pass
|
||||
self.closing = 1
|
||||
self.SaveBarState("ToolbarDefault")
|
||||
self.SetActiveView(None) # Otherwise MFC's OnClose may _not_ prompt for save.
|
||||
|
||||
from pywin.framework import help
|
||||
help.FinalizeHelp()
|
||||
|
||||
self.DestroyControlBar(afxres.AFX_IDW_TOOLBAR)
|
||||
self.DestroyControlBar(win32ui.ID_VIEW_TOOLBAR_DBG)
|
||||
|
||||
return self._obj_.OnClose()
|
||||
|
||||
def DestroyControlBar(self, id):
|
||||
try:
|
||||
bar = self.GetControlBar(id)
|
||||
except win32ui.error:
|
||||
return
|
||||
bar.DestroyWindow()
|
||||
|
||||
def OnCommand(self, wparam, lparam):
|
||||
# By default, the current MDI child frame will process WM_COMMAND
|
||||
# messages before any docked control bars - even if the control bar
|
||||
# has focus. This is a problem for the interactive window when docked.
|
||||
# Therefore, we detect the situation of a view having the main frame
|
||||
# as its parent, and assume it must be a docked view (which it will in an MDI app)
|
||||
try:
|
||||
v = self.GetActiveView() # Raise an exception if none - good - then we want default handling
|
||||
# Main frame _does_ have a current view (ie, a docking view) - see if it wants it.
|
||||
if v.OnCommand(wparam, lparam):
|
||||
return 1
|
||||
except (win32ui.error, AttributeError):
|
||||
pass
|
||||
return self._obj_.OnCommand(wparam, lparam)
|
||||
|
||||
class InteractivePythonApp(app.CApp):
|
||||
# This works if necessary - just we dont need to override the Run method.
|
||||
# def Run(self):
|
||||
# return self._obj_.Run()
|
||||
|
||||
def HookCommands(self):
|
||||
app.CApp.HookCommands(self)
|
||||
dbgcommands.DebuggerCommandHandler().HookCommands()
|
||||
self.HookCommand(self.OnViewBrowse,win32ui.ID_VIEW_BROWSE)
|
||||
self.HookCommand(self.OnFileImport,win32ui.ID_FILE_IMPORT)
|
||||
self.HookCommand(self.OnFileCheck,win32ui.ID_FILE_CHECK)
|
||||
self.HookCommandUpdate(self.OnUpdateFileCheck, win32ui.ID_FILE_CHECK)
|
||||
self.HookCommand(self.OnFileRun,win32ui.ID_FILE_RUN)
|
||||
self.HookCommand(self.OnFileLocate,win32ui.ID_FILE_LOCATE)
|
||||
self.HookCommand(self.OnInteractiveWindow, win32ui.ID_VIEW_INTERACTIVE)
|
||||
self.HookCommandUpdate(self.OnUpdateInteractiveWindow, win32ui.ID_VIEW_INTERACTIVE)
|
||||
self.HookCommand(self.OnViewOptions, win32ui.ID_VIEW_OPTIONS)
|
||||
self.HookCommand(self.OnHelpIndex, afxres.ID_HELP_INDEX)
|
||||
self.HookCommand(self.OnFileSaveAll, win32ui.ID_FILE_SAVE_ALL)
|
||||
self.HookCommand(self.OnViewToolbarDbg, win32ui.ID_VIEW_TOOLBAR_DBG)
|
||||
self.HookCommandUpdate(self.OnUpdateViewToolbarDbg, win32ui.ID_VIEW_TOOLBAR_DBG)
|
||||
|
||||
def CreateMainFrame(self):
|
||||
return MainFrame()
|
||||
|
||||
def MakeExistingDDEConnection(self):
|
||||
# Use DDE to connect to an existing instance
|
||||
# Return None if no existing instance
|
||||
try:
|
||||
from . import intpydde
|
||||
except ImportError:
|
||||
# No dde support!
|
||||
return None
|
||||
conv = intpydde.CreateConversation(self.ddeServer)
|
||||
try:
|
||||
conv.ConnectTo("Pythonwin", "System")
|
||||
return conv
|
||||
except intpydde.error:
|
||||
return None
|
||||
|
||||
def InitDDE(self):
|
||||
# Do all the magic DDE handling.
|
||||
# Returns TRUE if we have pumped the arguments to our
|
||||
# remote DDE app, and we should terminate.
|
||||
try:
|
||||
from . import intpydde
|
||||
except ImportError:
|
||||
self.ddeServer = None
|
||||
intpydde = None
|
||||
if intpydde is not None:
|
||||
self.ddeServer = intpydde.DDEServer(self)
|
||||
self.ddeServer.Create("Pythonwin", intpydde.CBF_FAIL_SELFCONNECTIONS )
|
||||
try:
|
||||
# If there is an existing instance, pump the arguments to it.
|
||||
connection = self.MakeExistingDDEConnection()
|
||||
if connection is not None:
|
||||
if self.ProcessArgs(sys.argv, connection) is None:
|
||||
return 1
|
||||
except:
|
||||
# It is too early to 'print' an exception - we
|
||||
# don't have stdout setup yet!
|
||||
win32ui.DisplayTraceback(sys.exc_info(), " - error in DDE conversation with Pythonwin")
|
||||
|
||||
def InitInstance(self):
|
||||
# Allow "/nodde" and "/new" to optimize this!
|
||||
if "/nodde" not in sys.argv and "/new" not in sys.argv:
|
||||
if self.InitDDE():
|
||||
return 1 # A remote DDE client is doing it for us!
|
||||
else:
|
||||
self.ddeServer = None
|
||||
|
||||
win32ui.SetRegistryKey("Python %s" % (sys.winver,)) # MFC automatically puts the main frame caption on!
|
||||
app.CApp.InitInstance(self)
|
||||
|
||||
# Create the taskbar icon
|
||||
win32ui.CreateDebuggerThread()
|
||||
|
||||
# Allow Pythonwin to host OCX controls.
|
||||
win32ui.EnableControlContainer()
|
||||
|
||||
# Display the interactive window if the user wants it.
|
||||
from . import interact
|
||||
interact.CreateInteractiveWindowUserPreference()
|
||||
|
||||
# Load the modules we use internally.
|
||||
self.LoadSystemModules()
|
||||
|
||||
# Load additional module the user may want.
|
||||
self.LoadUserModules()
|
||||
|
||||
# Load the ToolBar state near the end of the init process, as
|
||||
# there may be Toolbar IDs created by the user or other modules.
|
||||
# By now all these modules should be loaded, so all the toolbar IDs loaded.
|
||||
try:
|
||||
self.frame.LoadBarState("ToolbarDefault")
|
||||
except win32ui.error:
|
||||
# MFC sucks. It does essentially "GetDlgItem(x)->Something", so if the
|
||||
# toolbar with ID x does not exist, MFC crashes! Pythonwin has a trap for this
|
||||
# but I need to investigate more how to prevent it (AFAIK, ensuring all the
|
||||
# toolbars are created by now _should_ stop it!)
|
||||
pass
|
||||
|
||||
# Finally process the command line arguments.
|
||||
self.ProcessArgs(sys.argv)
|
||||
|
||||
def ExitInstance(self):
|
||||
win32ui.DestroyDebuggerThread()
|
||||
try:
|
||||
from . import interact
|
||||
interact.DestroyInteractiveWindow()
|
||||
except:
|
||||
pass
|
||||
if self.ddeServer is not None:
|
||||
self.ddeServer.Shutdown()
|
||||
self.ddeServer = None
|
||||
return app.CApp.ExitInstance(self)
|
||||
|
||||
def Activate(self):
|
||||
# Bring to the foreground. Mainly used when another app starts up, it asks
|
||||
# this one to activate itself, then it terminates.
|
||||
frame = win32ui.GetMainFrame()
|
||||
frame.SetForegroundWindow()
|
||||
if frame.GetWindowPlacement()[1]==win32con.SW_SHOWMINIMIZED:
|
||||
frame.ShowWindow(win32con.SW_RESTORE)
|
||||
|
||||
def ProcessArgs(self, args, dde = None):
|
||||
# If we are going to talk to a remote app via DDE, then
|
||||
# activate it!
|
||||
if dde is not None: dde.Exec("self.Activate()")
|
||||
if len(args) and args[0] in ['/nodde','/new']: del args[0] # already handled.
|
||||
if len(args)<1 or not args[0]: # argv[0]=='' when started without args, just like Python.exe!
|
||||
return
|
||||
try:
|
||||
if args[0] and args[0][0]!='/':
|
||||
argStart = 0
|
||||
argType = win32ui.GetProfileVal("Python","Default Arg Type","/edit").lower()
|
||||
else:
|
||||
argStart = 1
|
||||
argType = args[0]
|
||||
if argStart >= len(args):
|
||||
raise TypeError("The command line requires an additional arg.")
|
||||
if argType=="/edit":
|
||||
# Load up the default application.
|
||||
if dde:
|
||||
fname = win32api.GetFullPathName(args[argStart])
|
||||
dde.Exec("win32ui.GetApp().OpenDocumentFile(%s)" % (repr(fname)))
|
||||
else:
|
||||
win32ui.GetApp().OpenDocumentFile(args[argStart])
|
||||
elif argType=="/rundlg":
|
||||
if dde:
|
||||
dde.Exec("from pywin.framework import scriptutils;scriptutils.RunScript('%s', '%s', 1)" % (args[argStart], ' '.join(args[argStart+1:])))
|
||||
else:
|
||||
from . import scriptutils
|
||||
scriptutils.RunScript(args[argStart], ' '.join(args[argStart+1:]))
|
||||
elif argType=="/run":
|
||||
if dde:
|
||||
dde.Exec("from pywin.framework import scriptutils;scriptutils.RunScript('%s', '%s', 0)" % (args[argStart], ' '.join(args[argStart+1:])))
|
||||
else:
|
||||
from . import scriptutils
|
||||
scriptutils.RunScript(args[argStart], ' '.join(args[argStart+1:]), 0)
|
||||
elif argType=="/app":
|
||||
raise RuntimeError("/app only supported for new instances of Pythonwin.exe")
|
||||
elif argType=='/dde': # Send arbitary command
|
||||
if dde is not None:
|
||||
dde.Exec(args[argStart])
|
||||
else:
|
||||
win32ui.MessageBox("The /dde command can only be used\r\nwhen Pythonwin is already running")
|
||||
else:
|
||||
raise TypeError("Command line arguments not recognised")
|
||||
except:
|
||||
# too early for print anything.
|
||||
win32ui.DisplayTraceback(sys.exc_info(), " - error processing command line args")
|
||||
|
||||
|
||||
def LoadSystemModules(self):
|
||||
self.DoLoadModules("pywin.framework.editor,pywin.framework.stdin")
|
||||
|
||||
def LoadUserModules(self, moduleNames = None):
|
||||
# Load the users modules.
|
||||
if moduleNames is None:
|
||||
default = "pywin.framework.sgrepmdi,pywin.framework.mdi_pychecker"
|
||||
moduleNames=win32ui.GetProfileVal('Python','Startup Modules',default)
|
||||
self.DoLoadModules(moduleNames)
|
||||
|
||||
def DoLoadModules(self, moduleNames): # ", sep string of module names.
|
||||
if not moduleNames: return
|
||||
modules = moduleNames.split(",")
|
||||
for module in modules:
|
||||
try:
|
||||
__import__(module)
|
||||
except: # Catch em all, else the app itself dies! 'ImportError:
|
||||
traceback.print_exc()
|
||||
msg = 'Startup import of user module "%s" failed' % module
|
||||
print(msg)
|
||||
win32ui.MessageBox(msg)
|
||||
|
||||
#
|
||||
# DDE Callback
|
||||
#
|
||||
def OnDDECommand(self, command):
|
||||
try:
|
||||
exec(command + "\n")
|
||||
except:
|
||||
print("ERROR executing DDE command: ", command)
|
||||
traceback.print_exc()
|
||||
raise
|
||||
|
||||
#
|
||||
# General handlers
|
||||
#
|
||||
def OnViewBrowse( self, id, code ):
|
||||
" Called when ViewBrowse message is received "
|
||||
from pywin.mfc import dialog
|
||||
from pywin.tools import browser
|
||||
obName = dialog.GetSimpleInput('Object', '__builtins__', 'Browse Python Object')
|
||||
if obName is None:
|
||||
return
|
||||
try:
|
||||
browser.Browse(eval(obName, __main__.__dict__, __main__.__dict__))
|
||||
except NameError:
|
||||
win32ui.MessageBox('This is no object with this name')
|
||||
except AttributeError:
|
||||
win32ui.MessageBox('The object has no attribute of that name')
|
||||
except:
|
||||
traceback.print_exc()
|
||||
win32ui.MessageBox('This object can not be browsed')
|
||||
|
||||
def OnFileImport( self, id, code ):
|
||||
" Called when a FileImport message is received. Import the current or specified file"
|
||||
from . import scriptutils
|
||||
scriptutils.ImportFile()
|
||||
|
||||
def OnFileCheck( self, id, code ):
|
||||
" Called when a FileCheck message is received. Check the current file."
|
||||
from . import scriptutils
|
||||
scriptutils.CheckFile()
|
||||
|
||||
def OnUpdateFileCheck(self, cmdui):
|
||||
from . import scriptutils
|
||||
cmdui.Enable( scriptutils.GetActiveFileName(0) is not None )
|
||||
|
||||
def OnFileRun( self, id, code ):
|
||||
" Called when a FileRun message is received. "
|
||||
from . import scriptutils
|
||||
showDlg = win32api.GetKeyState(win32con.VK_SHIFT) >= 0
|
||||
scriptutils.RunScript(None, None, showDlg)
|
||||
|
||||
def OnFileLocate( self, id, code ):
|
||||
from pywin.mfc import dialog
|
||||
from . import scriptutils
|
||||
import os
|
||||
global lastLocateFileName # save the new version away for next time...
|
||||
|
||||
name = dialog.GetSimpleInput('File name', lastLocateFileName, 'Locate Python File')
|
||||
if name is None: # Cancelled.
|
||||
return
|
||||
lastLocateFileName = name
|
||||
# if ".py" supplied, rip it off!
|
||||
# should also check for .pys and .pyw
|
||||
if lastLocateFileName[-3:].lower()=='.py':
|
||||
lastLocateFileName = lastLocateFileName[:-3]
|
||||
lastLocateFileName = lastLocateFileName.replace(".","\\")
|
||||
newName = scriptutils.LocatePythonFile(lastLocateFileName)
|
||||
if newName is None:
|
||||
win32ui.MessageBox("The file '%s' can not be located" % lastLocateFileName)
|
||||
else:
|
||||
win32ui.GetApp().OpenDocumentFile(newName)
|
||||
|
||||
# Display all the "options" proprety pages we can find
|
||||
def OnViewOptions(self, id, code):
|
||||
win32ui.InitRichEdit()
|
||||
sheet = dialog.PropertySheet("Pythonwin Options")
|
||||
# Add property pages we know about that need manual work.
|
||||
from pywin.dialogs import ideoptions
|
||||
sheet.AddPage( ideoptions.OptionsPropPage() )
|
||||
|
||||
from . import toolmenu
|
||||
sheet.AddPage( toolmenu.ToolMenuPropPage() )
|
||||
|
||||
# Get other dynamic pages from templates.
|
||||
pages = []
|
||||
for template in self.GetDocTemplateList():
|
||||
try:
|
||||
# Dont actually call the function with the exception handler.
|
||||
getter = template.GetPythonPropertyPages
|
||||
except AttributeError:
|
||||
# Template does not provide property pages!
|
||||
continue
|
||||
pages = pages + getter()
|
||||
|
||||
# Debugger template goes at the end
|
||||
try:
|
||||
from pywin.debugger import configui
|
||||
except ImportError:
|
||||
configui = None
|
||||
if configui is not None: pages.append(configui.DebuggerOptionsPropPage())
|
||||
# Now simply add the pages, and display the dialog.
|
||||
for page in pages:
|
||||
sheet.AddPage(page)
|
||||
|
||||
if sheet.DoModal()==win32con.IDOK:
|
||||
win32ui.SetStatusText("Applying configuration changes...", 1)
|
||||
win32ui.DoWaitCursor(1)
|
||||
# Tell every Window in our app that win.ini has changed!
|
||||
win32ui.GetMainFrame().SendMessageToDescendants(win32con.WM_WININICHANGE, 0, 0)
|
||||
win32ui.DoWaitCursor(0)
|
||||
|
||||
def OnInteractiveWindow(self, id, code):
|
||||
# toggle the existing state.
|
||||
from . import interact
|
||||
interact.ToggleInteractiveWindow()
|
||||
|
||||
def OnUpdateInteractiveWindow(self, cmdui):
|
||||
try:
|
||||
interact=sys.modules['pywin.framework.interact']
|
||||
state = interact.IsInteractiveWindowVisible()
|
||||
except KeyError: # Interactive module hasnt ever been imported.
|
||||
state = 0
|
||||
cmdui.Enable()
|
||||
cmdui.SetCheck(state)
|
||||
|
||||
def OnFileSaveAll(self, id, code):
|
||||
# Only attempt to save editor documents.
|
||||
from pywin.framework.editor import editorTemplate
|
||||
num = 0
|
||||
for doc in editorTemplate.GetDocumentList():
|
||||
if doc.IsModified() and doc.GetPathName():
|
||||
num = num = 1
|
||||
doc.OnSaveDocument(doc.GetPathName())
|
||||
win32ui.SetStatusText("%d documents saved" % num, 1)
|
||||
|
||||
def OnViewToolbarDbg(self, id, code):
|
||||
if code==0:
|
||||
return not win32ui.GetMainFrame().OnBarCheck(id)
|
||||
|
||||
def OnUpdateViewToolbarDbg(self, cmdui):
|
||||
win32ui.GetMainFrame().OnUpdateControlBarMenu(cmdui)
|
||||
cmdui.Enable(1)
|
||||
|
||||
def OnHelpIndex( self, id, code ):
|
||||
from . import help
|
||||
help.SelectAndRunHelpFile()
|
||||
|
||||
# As per the comments in app.py, this use is depreciated.
|
||||
# app.AppBuilder = InteractivePythonApp
|
||||
|
||||
# Now all we do is create the application
|
||||
thisApp = InteractivePythonApp()
|
||||
56
Lib/site-packages/pythonwin/pywin/framework/intpydde.py
Normal file
56
Lib/site-packages/pythonwin/pywin/framework/intpydde.py
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
# DDE support for Pythonwin
|
||||
#
|
||||
# Seems to work fine (in the context that IE4 seems to have broken
|
||||
# DDE on _all_ NT4 machines I have tried, but only when a "Command Prompt" window
|
||||
# is open. Strange, but true. If you have problems with this, close all Command Prompts!
|
||||
|
||||
|
||||
import win32ui
|
||||
import win32api, win32con
|
||||
from pywin.mfc import object
|
||||
from dde import *
|
||||
import sys, traceback
|
||||
|
||||
class DDESystemTopic(object.Object):
|
||||
def __init__(self, app):
|
||||
self.app = app
|
||||
object.Object.__init__(self, CreateServerSystemTopic())
|
||||
def Exec(self, data):
|
||||
try:
|
||||
# print "Executing", cmd
|
||||
self.app.OnDDECommand(data)
|
||||
except:
|
||||
t,v,tb = sys.exc_info()
|
||||
# The DDE Execution failed.
|
||||
print("Error executing DDE command.")
|
||||
traceback.print_exception(t,v,tb)
|
||||
return 0
|
||||
|
||||
class DDEServer(object.Object):
|
||||
def __init__(self, app):
|
||||
self.app = app
|
||||
object.Object.__init__(self, CreateServer())
|
||||
self.topic = self.item = None
|
||||
|
||||
def CreateSystemTopic(self):
|
||||
return DDESystemTopic(self.app)
|
||||
|
||||
def Shutdown(self):
|
||||
self._obj_.Shutdown()
|
||||
self._obj_.Destroy()
|
||||
if self.topic is not None:
|
||||
self.topic.Destroy()
|
||||
self.topic = None
|
||||
if self.item is not None:
|
||||
self.item.Destroy()
|
||||
self.item = None
|
||||
|
||||
def OnCreate(self):
|
||||
return 1
|
||||
|
||||
def Status(self, msg):
|
||||
try:
|
||||
win32ui.SetStatusText(msg)
|
||||
except win32ui.error:
|
||||
pass
|
||||
|
||||
629
Lib/site-packages/pythonwin/pywin/framework/mdi_pychecker.py
Normal file
629
Lib/site-packages/pythonwin/pywin/framework/mdi_pychecker.py
Normal file
|
|
@ -0,0 +1,629 @@
|
|||
######################################################################
|
||||
##
|
||||
## The Pychecker MDI Plug-In UserModule for Pythonwin
|
||||
##
|
||||
## contributed by Robert Kiendl
|
||||
##
|
||||
## Style is similar to (and inherited) from the SGrepMDI UserModule
|
||||
##
|
||||
## Usage:
|
||||
##
|
||||
## Start Pychecker on current file: Menu/File/New../Pychecker.
|
||||
## Use it: Jump to Pychecker warning source lines by double-click.
|
||||
## Auto-add "#$pycheck_no" / "#$pycheck_no=specific-re-pattern" tags
|
||||
## to source lines by context/right-mouse-click on warning lines.
|
||||
##
|
||||
## It requires pychecker installed and the pychecker.bat to be on
|
||||
## the PATH. Example pychecker.bat:
|
||||
##
|
||||
## REM pychecker.bat
|
||||
## C:\bin\python.exe C:\PYTHON23\Lib\site-packages\pychecker\checker.py %1 %2 %3 %4 %5 %6 %7 %8 %9
|
||||
##
|
||||
## Adding it as default module in PythonWin:
|
||||
##
|
||||
## +++ ./intpyapp.py 2006-10-02 17:59:32.974161600 +0200
|
||||
## @@ -272,7 +282,7 @@
|
||||
## def LoadUserModules(self, moduleNames = None):
|
||||
## # Load the users modules.
|
||||
## if moduleNames is None:
|
||||
## - default = "sgrepmdi"
|
||||
## + default = "sgrepmdi,mdi_pychecker"
|
||||
## moduleNames=win32ui.GetProfileVal('Python','Startup Modules',default)
|
||||
## self.DoLoadModules(moduleNames)
|
||||
##
|
||||
######################################################################
|
||||
|
||||
import win32ui
|
||||
import win32api
|
||||
from pywin.mfc import docview, dialog, window
|
||||
import win32con
|
||||
import sys, string, re, glob, os, stat, time
|
||||
from . import scriptutils
|
||||
|
||||
def getsubdirs(d):
|
||||
dlist = []
|
||||
flist = glob.glob(d+'\\*')
|
||||
for f in flist:
|
||||
if os.path.isdir(f):
|
||||
dlist.append(f)
|
||||
dlist = dlist + getsubdirs(f)
|
||||
return dlist
|
||||
|
||||
class dirpath:
|
||||
def __init__(self, str, recurse=0):
|
||||
dp = str.split(';')
|
||||
dirs = {}
|
||||
for d in dp:
|
||||
if os.path.isdir(d):
|
||||
d = d.lower()
|
||||
if d not in dirs:
|
||||
dirs[d] = None
|
||||
if recurse:
|
||||
subdirs = getsubdirs(d)
|
||||
for sd in subdirs:
|
||||
sd = sd.lower()
|
||||
if sd not in dirs:
|
||||
dirs[sd] = None
|
||||
elif os.path.isfile(d):
|
||||
pass
|
||||
else:
|
||||
x = None
|
||||
if d in os.environ:
|
||||
x = dirpath(os.environ[d])
|
||||
elif d[:5] == 'HKEY_':
|
||||
keystr = d.split('\\')
|
||||
try:
|
||||
root = eval('win32con.'+keystr[0])
|
||||
except:
|
||||
win32ui.MessageBox("Can't interpret registry key name '%s'" % keystr[0])
|
||||
try:
|
||||
subkey = '\\'.join(keystr[1:])
|
||||
val = win32api.RegQueryValue(root, subkey)
|
||||
if val:
|
||||
x = dirpath(val)
|
||||
else:
|
||||
win32ui.MessageBox("Registry path '%s' did not return a path entry" % d)
|
||||
except:
|
||||
win32ui.MessageBox("Can't interpret registry key value: %s" % keystr[1:])
|
||||
else:
|
||||
win32ui.MessageBox("Directory '%s' not found" % d)
|
||||
if x:
|
||||
for xd in x:
|
||||
if xd not in dirs:
|
||||
dirs[xd] = None
|
||||
if recurse:
|
||||
subdirs = getsubdirs(xd)
|
||||
for sd in subdirs:
|
||||
sd = sd.lower()
|
||||
if sd not in dirs:
|
||||
dirs[sd] = None
|
||||
self.dirs = []
|
||||
for d in dirs.keys():
|
||||
self.dirs.append(d)
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self.dirs[key]
|
||||
def __len__(self):
|
||||
return len(self.dirs)
|
||||
def __setitem__(self, key, value):
|
||||
self.dirs[key] = value
|
||||
def __delitem__(self, key):
|
||||
del self.dirs[key]
|
||||
def __getslice__(self, lo, hi):
|
||||
return self.dirs[lo:hi]
|
||||
def __setslice__(self, lo, hi, seq):
|
||||
self.dirs[lo:hi] = seq
|
||||
def __delslice__(self, lo, hi):
|
||||
del self.dirs[lo:hi]
|
||||
def __add__(self, other):
|
||||
if type(other) == type(self) or type(other) == type([]):
|
||||
return self.dirs + other.dirs
|
||||
def __radd__(self, other):
|
||||
if type(other) == type(self) or type(other) == type([]):
|
||||
return other.dirs + self.dirs
|
||||
|
||||
# Group(1) is the filename, group(2) is the lineno.
|
||||
#regexGrepResult=regex.compile("^\\([a-zA-Z]:.*\\)(\\([0-9]+\\))")
|
||||
#regexGrep=re.compile(r"^([a-zA-Z]:[^(]*)\((\d+)\)")
|
||||
regexGrep=re.compile(r"^(..[^\(:]+)?[\(:](\d+)[\):]:?\s*(.*)")
|
||||
|
||||
#these are the atom numbers defined by Windows for basic dialog controls
|
||||
|
||||
BUTTON = 0x80
|
||||
EDIT = 0x81
|
||||
STATIC = 0x82
|
||||
LISTBOX = 0x83
|
||||
SCROLLBAR = 0x84
|
||||
COMBOBOX = 0x85
|
||||
|
||||
class TheTemplate(docview.RichEditDocTemplate):
|
||||
def __init__(self):
|
||||
docview.RichEditDocTemplate.__init__(self, win32ui.IDR_TEXTTYPE, TheDocument, TheFrame, TheView)
|
||||
self.SetDocStrings("\nPychecker\nPychecker\nPychecker params (*.pychecker)\n.pychecker\n\n\n")
|
||||
win32ui.GetApp().AddDocTemplate(self)
|
||||
self.docparams = None
|
||||
|
||||
def MatchDocType(self, fileName, fileType):
|
||||
doc = self.FindOpenDocument(fileName)
|
||||
if doc: return doc
|
||||
ext = os.path.splitext(fileName)[1].lower()
|
||||
if ext =='.pychecker':
|
||||
return win32ui.CDocTemplate_Confidence_yesAttemptNative
|
||||
return win32ui.CDocTemplate_Confidence_noAttempt
|
||||
|
||||
def setParams(self, params):
|
||||
self.docparams = params
|
||||
|
||||
def readParams(self):
|
||||
tmp = self.docparams
|
||||
self.docparams = None
|
||||
return tmp
|
||||
|
||||
class TheFrame(window.MDIChildWnd):
|
||||
# The template and doc params will one day be removed.
|
||||
def __init__(self, wnd = None):
|
||||
window.MDIChildWnd.__init__(self, wnd)
|
||||
|
||||
class TheDocument(docview.RichEditDoc):
|
||||
def __init__(self, template):
|
||||
docview.RichEditDoc.__init__(self, template)
|
||||
self.dirpattern = ''
|
||||
self.filpattern = ''
|
||||
self.greppattern = ''
|
||||
self.casesensitive = 1
|
||||
self.recurse = 1
|
||||
self.verbose = 0
|
||||
|
||||
def OnOpenDocument(self, fnm):
|
||||
#this bizarre stuff with params is so right clicking in a result window
|
||||
#and starting a new grep can communicate the default parameters to the
|
||||
#new grep.
|
||||
try:
|
||||
params = open(fnm,'r').read()
|
||||
except:
|
||||
params = None
|
||||
self.setInitParams(params)
|
||||
return self.OnNewDocument()
|
||||
|
||||
def OnCloseDocument(self):
|
||||
try:
|
||||
win32ui.GetApp().DeleteIdleHandler(self.idleHandler)
|
||||
except:
|
||||
pass
|
||||
return self._obj_.OnCloseDocument()
|
||||
|
||||
def saveInitParams(self):
|
||||
# Only save the flags, not the text boxes.
|
||||
paramstr = "\t\t\t%d\t%d" % (self.casesensitive, self.recurse)
|
||||
win32ui.WriteProfileVal("Pychecker", "Params", paramstr)
|
||||
|
||||
def setInitParams(self, paramstr):
|
||||
if paramstr is None:
|
||||
paramstr = win32ui.GetProfileVal("Pychecker", "Params", '\t\t\t1\t0\t0')
|
||||
params = paramstr.split('\t')
|
||||
if len(params) < 3:
|
||||
params = params + ['']*(3-len(params))
|
||||
if len(params) < 6:
|
||||
params = params + [0]*(6-len(params))
|
||||
self.dirpattern = params[0]
|
||||
self.filpattern = params[1]
|
||||
self.greppattern = params[2] or '-#1000 --only'
|
||||
self.casesensitive = int(params[3])
|
||||
self.recurse = int(params[4])
|
||||
self.verbose = int(params[5])
|
||||
# setup some reasonable defaults.
|
||||
if not self.dirpattern:
|
||||
try:
|
||||
editor=win32ui.GetMainFrame().MDIGetActive()[0].GetEditorView()
|
||||
self.dirpattern=os.path.abspath(os.path.dirname(editor.GetDocument().GetPathName()))
|
||||
except (AttributeError,win32ui.error):
|
||||
self.dirpattern = os.getcwd()
|
||||
if not self.filpattern:
|
||||
try:
|
||||
editor=win32ui.GetMainFrame().MDIGetActive()[0].GetEditorView()
|
||||
self.filpattern=editor.GetDocument().GetPathName()
|
||||
except AttributeError:
|
||||
self.filpattern = "*.py"
|
||||
|
||||
def OnNewDocument(self):
|
||||
if self.dirpattern == '':
|
||||
self.setInitParams(greptemplate.readParams())
|
||||
d = TheDialog(self.dirpattern, self.filpattern, self.greppattern, self.casesensitive, self.recurse, self.verbose)
|
||||
if d.DoModal() == win32con.IDOK:
|
||||
self.dirpattern = d['dirpattern']
|
||||
self.filpattern = d['filpattern']
|
||||
self.greppattern = d['greppattern']
|
||||
#self.casesensitive = d['casesensitive']
|
||||
#self.recurse = d['recursive']
|
||||
#self.verbose = d['verbose']
|
||||
self.doSearch()
|
||||
self.saveInitParams()
|
||||
return 1
|
||||
return 0 # cancelled - return zero to stop frame creation.
|
||||
|
||||
def doSearch(self):
|
||||
self.dp = dirpath(self.dirpattern, self.recurse)
|
||||
self.SetTitle("Pychecker Run '%s' (options: %s)" % (self.filpattern, self.greppattern))
|
||||
#self.text = []
|
||||
self.GetFirstView().Append('#Pychecker Run in '+self.dirpattern+' %s\n'%time.asctime())
|
||||
if self.verbose:
|
||||
self.GetFirstView().Append('# ='+repr(self.dp.dirs)+'\n')
|
||||
self.GetFirstView().Append('# Files '+self.filpattern+'\n')
|
||||
self.GetFirstView().Append('# Options '+self.greppattern+'\n')
|
||||
self.fplist = self.filpattern.split(';')
|
||||
self.GetFirstView().Append('# Running... ( double click on result lines in order to jump to the source code ) \n')
|
||||
win32ui.SetStatusText("Pychecker running. Please wait...", 0)
|
||||
self.dpndx = self.fpndx = 0
|
||||
self.fndx = -1
|
||||
if not self.dp:
|
||||
self.GetFirstView().Append("# ERROR: '%s' does not resolve to any search locations" % self.dirpattern)
|
||||
self.SetModifiedFlag(0)
|
||||
else:
|
||||
##self.flist = glob.glob(self.dp[0]+'\\'+self.fplist[0])
|
||||
import operator
|
||||
self.flist = reduce(operator.add, list(map(glob.glob,self.fplist)) )
|
||||
#import pywin.debugger;pywin.debugger.set_trace()
|
||||
self.startPycheckerRun()
|
||||
def idleHandler(self,handler,count):
|
||||
import time
|
||||
time.sleep(0.001)
|
||||
if self.result!=None:
|
||||
win32ui.GetApp().DeleteIdleHandler(self.idleHandler)
|
||||
return 0
|
||||
return 1 #more
|
||||
def startPycheckerRun(self):
|
||||
self.result=None
|
||||
old=win32api.SetCursor(win32api.LoadCursor(0, win32con.IDC_APPSTARTING))
|
||||
win32ui.GetApp().AddIdleHandler(self.idleHandler)
|
||||
import _thread
|
||||
_thread.start_new(self.threadPycheckerRun,())
|
||||
##win32api.SetCursor(old)
|
||||
def threadPycheckerRun(self):
|
||||
result=''
|
||||
rc=-1
|
||||
try:
|
||||
options = self.greppattern
|
||||
files= ' '.join(self.flist)
|
||||
# Recently MarkH has failed to run pychecker without it having
|
||||
# been explicitly installed - so we assume it is and locate it
|
||||
# from its default location.
|
||||
# Step1 - get python.exe
|
||||
py = os.path.join(sys.prefix, 'python.exe')
|
||||
if not os.path.isfile(py):
|
||||
if "64 bit" in sys.version:
|
||||
py = os.path.join(sys.prefix, 'PCBuild', 'amd64', 'python.exe')
|
||||
else:
|
||||
py = os.path.join(sys.prefix, 'PCBuild', 'python.exe')
|
||||
try:
|
||||
py = win32api.GetShortPathName(py)
|
||||
except win32api.error:
|
||||
py = ""
|
||||
# Find checker.py
|
||||
from distutils.sysconfig import get_python_lib
|
||||
pychecker = os.path.join(get_python_lib(), 'pychecker', 'checker.py')
|
||||
if not os.path.isfile(py):
|
||||
result = "Can't find python.exe!\n"
|
||||
elif not os.path.isfile(pychecker):
|
||||
result = "Can't find checker.py - please install pychecker " \
|
||||
"(or run 'setup.py install' if you have the source version)\n"
|
||||
else:
|
||||
cmd='%s "%s" %s %s 2>&1' % (py, pychecker, options,files)
|
||||
##fin,fout,ferr=os.popen3(cmd)
|
||||
##result=ferr.read()+fout.read()
|
||||
result=os.popen(cmd).read()
|
||||
##rc=f.close()
|
||||
self.GetFirstView().Append(result)
|
||||
finally:
|
||||
self.result=result
|
||||
print('== Pychecker run finished ==')
|
||||
self.GetFirstView().Append('\n'+'== Pychecker run finished ==')
|
||||
self.SetModifiedFlag(0)
|
||||
def _inactive_idleHandler(self, handler, count):
|
||||
self.fndx = self.fndx + 1
|
||||
if self.fndx < len(self.flist):
|
||||
f = self.flist[self.fndx]
|
||||
if self.verbose:
|
||||
self.GetFirstView().Append('# ..'+f+'\n')
|
||||
win32ui.SetStatusText("Searching "+f, 0)
|
||||
lines = open(f, 'r').readlines()
|
||||
for i in range(len(lines)):
|
||||
line = lines[i]
|
||||
if self.pat.search(line) != None:
|
||||
self.GetFirstView().Append(f+'('+repr(i+1) + ') '+line)
|
||||
else:
|
||||
self.fndx = -1
|
||||
self.fpndx = self.fpndx + 1
|
||||
if self.fpndx < len(self.fplist):
|
||||
self.flist = glob.glob(self.dp[self.dpndx] + '\\' + self.fplist[self.fpndx])
|
||||
else:
|
||||
self.fpndx = 0
|
||||
self.dpndx = self.dpndx + 1
|
||||
if self.dpndx < len(self.dp):
|
||||
self.flist = glob.glob(self.dp[self.dpndx] + '\\' + self.fplist[self.fpndx])
|
||||
else:
|
||||
win32ui.SetStatusText("Search complete.", 0)
|
||||
self.SetModifiedFlag(0) # default to not modified.
|
||||
try:
|
||||
win32ui.GetApp().DeleteIdleHandler(self.idleHandler)
|
||||
except:
|
||||
pass
|
||||
return 0
|
||||
return 1
|
||||
|
||||
def GetParams(self):
|
||||
return self.dirpattern+'\t'+self.filpattern+'\t'+self.greppattern+'\t'+repr(self.casesensitive)+'\t'+repr(self.recurse)+'\t'+repr(self.verbose)
|
||||
|
||||
def OnSaveDocument(self, filename):
|
||||
# print 'OnSaveDocument() filename=',filename
|
||||
savefile = open(filename,"wb")
|
||||
txt = self.GetParams()+'\n'
|
||||
# print 'writing',txt
|
||||
savefile.write(txt)
|
||||
savefile.close()
|
||||
self.SetModifiedFlag(0)
|
||||
return 1
|
||||
|
||||
ID_OPEN_FILE = 0xe500
|
||||
ID_PYCHECKER = 0xe501
|
||||
ID_SAVERESULTS = 0x502
|
||||
ID_TRYAGAIN = 0x503
|
||||
ID_ADDCOMMENT = 0x504
|
||||
ID_ADDPYCHECKNO2 = 0x505
|
||||
|
||||
class TheView(docview.RichEditView):
|
||||
def __init__(self, doc):
|
||||
docview.RichEditView.__init__(self, doc)
|
||||
self.SetWordWrap(win32ui.CRichEditView_WrapNone)
|
||||
self.HookHandlers()
|
||||
|
||||
def OnInitialUpdate(self):
|
||||
rc = self._obj_.OnInitialUpdate()
|
||||
format = (-402653169, 0, 200, 0, 0, 0, 49, 'Courier New')
|
||||
self.SetDefaultCharFormat(format)
|
||||
return rc
|
||||
|
||||
def HookHandlers(self):
|
||||
self.HookMessage(self.OnRClick, win32con.WM_RBUTTONDOWN)
|
||||
self.HookCommand(self.OnCmdOpenFile, ID_OPEN_FILE)
|
||||
self.HookCommand(self.OnCmdThe, ID_PYCHECKER)
|
||||
self.HookCommand(self.OnCmdSave, ID_SAVERESULTS)
|
||||
self.HookCommand(self.OnTryAgain, ID_TRYAGAIN)
|
||||
self.HookCommand(self.OnAddComment, ID_ADDCOMMENT)
|
||||
self.HookCommand(self.OnAddComment, ID_ADDPYCHECKNO2)
|
||||
self.HookMessage(self.OnLDblClick,win32con.WM_LBUTTONDBLCLK)
|
||||
|
||||
def OnLDblClick(self,params):
|
||||
line = self.GetLine()
|
||||
regexGrepResult = regexGrep.match(line)
|
||||
if regexGrepResult:
|
||||
fname = regexGrepResult.group(1)
|
||||
line = int(regexGrepResult.group(2))
|
||||
scriptutils.JumpToDocument(fname, line)
|
||||
return 0 # dont pass on
|
||||
return 1 # pass it on by default.
|
||||
|
||||
def OnRClick(self, params):
|
||||
menu = win32ui.CreatePopupMenu()
|
||||
flags=win32con.MF_STRING|win32con.MF_ENABLED
|
||||
lineno = self._obj_.LineFromChar(-1) #selection or current line
|
||||
line = self._obj_.GetLine(lineno)
|
||||
regexGrepResult = regexGrep.match(line)
|
||||
charstart, charend = self._obj_.GetSel()
|
||||
if regexGrepResult:
|
||||
self.fnm = regexGrepResult.group(1)
|
||||
self.lnnum = int(regexGrepResult.group(2))
|
||||
menu.AppendMenu(flags, ID_OPEN_FILE, "&Open "+self.fnm)
|
||||
menu.AppendMenu(flags, ID_ADDCOMMENT, "&Add to source: Comment Tag/#$pycheck_no ..")
|
||||
menu.AppendMenu(flags, ID_ADDPYCHECKNO2, "&Add to source: Specific #$pycheck_no=%(errtext)s ..")
|
||||
menu.AppendMenu(win32con.MF_SEPARATOR)
|
||||
menu.AppendMenu(flags, ID_TRYAGAIN, "&Try Again")
|
||||
menu.AppendMenu(flags, win32ui.ID_EDIT_CUT, 'Cu&t')
|
||||
menu.AppendMenu(flags, win32ui.ID_EDIT_COPY, '&Copy')
|
||||
menu.AppendMenu(flags, win32ui.ID_EDIT_PASTE, '&Paste')
|
||||
menu.AppendMenu(flags, win32con.MF_SEPARATOR);
|
||||
menu.AppendMenu(flags, win32ui.ID_EDIT_SELECT_ALL, '&Select all')
|
||||
menu.AppendMenu(flags, win32con.MF_SEPARATOR);
|
||||
menu.AppendMenu(flags, ID_SAVERESULTS, 'Sa&ve results')
|
||||
menu.TrackPopupMenu(params[5])
|
||||
return 0
|
||||
|
||||
def OnAddComment(self, cmd, code):
|
||||
addspecific= cmd==ID_ADDPYCHECKNO2
|
||||
_=list(self.GetSel())
|
||||
_.sort()
|
||||
start,end=_
|
||||
line_start, line_end = self.LineFromChar(start), self.LineFromChar(end)
|
||||
first=1
|
||||
for i in range(line_start,line_end+1):
|
||||
line = self.GetLine(i)
|
||||
m = regexGrep.match(line)
|
||||
if m:
|
||||
if first:
|
||||
first=0
|
||||
cmnt=dialog.GetSimpleInput( "Add to %s lines" % (line_end-line_start+1),
|
||||
addspecific and " #$pycheck_no=%(errtext)s" or " #$pycheck_no" )
|
||||
if not cmnt:
|
||||
return 0
|
||||
##import pywin.debugger;pywin.debugger.set_trace()
|
||||
fname = m.group(1)
|
||||
line = int(m.group(2))
|
||||
view = scriptutils.JumpToDocument(fname,line)
|
||||
pos=view.LineIndex(line)-1
|
||||
if view.GetTextRange(pos-1,pos) in ('\r','\n'):
|
||||
pos -= 1
|
||||
view.SetSel(pos, pos)
|
||||
errtext=m.group(3)
|
||||
if start!=end and line_start==line_end:
|
||||
errtext=self.GetSelText()
|
||||
errtext=repr(re.escape(errtext).replace('\ ',' '))
|
||||
view.ReplaceSel( addspecific and cmnt % locals()
|
||||
or cmnt )
|
||||
return 0
|
||||
|
||||
|
||||
def OnCmdOpenFile(self, cmd, code):
|
||||
doc = win32ui.GetApp().OpenDocumentFile(self.fnm)
|
||||
if doc:
|
||||
vw = doc.GetFirstView()
|
||||
#hope you have an editor that implements GotoLine()!
|
||||
try:
|
||||
vw.GotoLine(int(self.lnnum))
|
||||
except:
|
||||
pass
|
||||
return 0
|
||||
|
||||
def OnCmdThe(self, cmd, code):
|
||||
curparamsstr = self.GetDocument().GetParams()
|
||||
params = curparamsstr.split('\t')
|
||||
params[2] = self.sel
|
||||
greptemplate.setParams('\t'.join(params))
|
||||
greptemplate.OpenDocumentFile()
|
||||
return 0
|
||||
|
||||
def OnTryAgain(self, cmd, code):
|
||||
greptemplate.setParams(self.GetDocument().GetParams())
|
||||
greptemplate.OpenDocumentFile()
|
||||
return 0
|
||||
|
||||
def OnCmdSave(self, cmd, code):
|
||||
flags = win32con.OFN_OVERWRITEPROMPT
|
||||
dlg = win32ui.CreateFileDialog(0, None, None, flags, "Text Files (*.txt)|*.txt||", self)
|
||||
dlg.SetOFNTitle("Save Results As")
|
||||
if dlg.DoModal() == win32con.IDOK:
|
||||
pn = dlg.GetPathName()
|
||||
self._obj_.SaveFile(pn)
|
||||
return 0
|
||||
|
||||
def Append(self, strng):
|
||||
numlines = self.GetLineCount()
|
||||
endpos = self.LineIndex(numlines-1) + len(self.GetLine(numlines-1))
|
||||
self.SetSel(endpos, endpos)
|
||||
self.ReplaceSel(strng)
|
||||
|
||||
|
||||
class TheDialog(dialog.Dialog):
|
||||
def __init__(self, dp, fp, gp, cs, r, v):
|
||||
style = win32con.DS_MODALFRAME | win32con.WS_POPUP | win32con.WS_VISIBLE | win32con.WS_CAPTION | win32con.WS_SYSMENU | win32con.DS_SETFONT
|
||||
CS = win32con.WS_CHILD | win32con.WS_VISIBLE
|
||||
tmp = [ ["Pychecker Run", (0, 0, 210, 90), style, None, (8, "MS Sans Serif")], ]
|
||||
tmp.append([STATIC, "Files:", -1, (7, 7, 50, 9), CS ])
|
||||
tmp.append([EDIT, gp, 103, (52, 7, 144, 11), CS | win32con.WS_TABSTOP | win32con.ES_AUTOHSCROLL | win32con.WS_BORDER])
|
||||
tmp.append([STATIC, "Directories:", -1, (7, 20, 50, 9), CS ])
|
||||
tmp.append([EDIT, dp, 102, (52, 20, 128, 11), CS | win32con.WS_TABSTOP | win32con.ES_AUTOHSCROLL | win32con.WS_BORDER])
|
||||
tmp.append([BUTTON, '...', 110, (182,20, 16, 11), CS | win32con.BS_PUSHBUTTON | win32con.WS_TABSTOP])
|
||||
tmp.append([STATIC, "Options:", -1, (7, 33, 50, 9), CS ])
|
||||
tmp.append([EDIT, fp, 101, (52, 33, 128, 11), CS | win32con.WS_TABSTOP | win32con.ES_AUTOHSCROLL | win32con.WS_BORDER ])
|
||||
tmp.append([BUTTON, '...', 111, (182,33, 16, 11), CS | win32con.BS_PUSHBUTTON | win32con.WS_TABSTOP])
|
||||
#tmp.append([BUTTON,'Case sensitive', 104, (7, 45, 72, 9), CS | win32con.BS_AUTOCHECKBOX | win32con.BS_LEFTTEXT| win32con.WS_TABSTOP])
|
||||
#tmp.append([BUTTON,'Subdirectories', 105, (7, 56, 72, 9), CS | win32con.BS_AUTOCHECKBOX | win32con.BS_LEFTTEXT| win32con.WS_TABSTOP])
|
||||
#tmp.append([BUTTON,'Verbose', 106, (7, 67, 72, 9), CS | win32con.BS_AUTOCHECKBOX | win32con.BS_LEFTTEXT| win32con.WS_TABSTOP])
|
||||
tmp.append([BUTTON,'OK', win32con.IDOK, (166,53, 32, 12), CS | win32con.BS_DEFPUSHBUTTON| win32con.WS_TABSTOP])
|
||||
tmp.append([BUTTON,'Cancel', win32con.IDCANCEL, (166,67, 32, 12), CS | win32con.BS_PUSHBUTTON| win32con.WS_TABSTOP])
|
||||
dialog.Dialog.__init__(self, tmp)
|
||||
self.AddDDX(101,'greppattern')
|
||||
self.AddDDX(102,'dirpattern')
|
||||
self.AddDDX(103,'filpattern')
|
||||
#self.AddDDX(104,'casesensitive')
|
||||
#self.AddDDX(105,'recursive')
|
||||
#self.AddDDX(106,'verbose')
|
||||
self._obj_.data['greppattern'] = gp
|
||||
self._obj_.data['dirpattern'] = dp
|
||||
self._obj_.data['filpattern'] = fp
|
||||
#self._obj_.data['casesensitive'] = cs
|
||||
#self._obj_.data['recursive'] = r
|
||||
#self._obj_.data['verbose'] = v
|
||||
self.HookCommand(self.OnMoreDirectories, 110)
|
||||
self.HookCommand(self.OnMoreFiles, 111)
|
||||
|
||||
def OnMoreDirectories(self, cmd, code):
|
||||
self.getMore('Pychecker\\Directories', 'dirpattern')
|
||||
|
||||
def OnMoreFiles(self, cmd, code):
|
||||
self.getMore('Pychecker\\File Types', 'filpattern')
|
||||
|
||||
def getMore(self, section, key):
|
||||
self.UpdateData(1)
|
||||
#get the items out of the ini file
|
||||
ini = win32ui.GetProfileFileName()
|
||||
secitems = win32api.GetProfileSection(section, ini)
|
||||
items = []
|
||||
for secitem in secitems:
|
||||
items.append(secitem.split('=')[1])
|
||||
dlg = TheParamsDialog(items)
|
||||
if dlg.DoModal() == win32con.IDOK:
|
||||
itemstr = ';'.join(dlg.getItems())
|
||||
self._obj_.data[key] = itemstr
|
||||
#update the ini file with dlg.getNew()
|
||||
i = 0
|
||||
newitems = dlg.getNew()
|
||||
if newitems:
|
||||
items = items + newitems
|
||||
for item in items:
|
||||
win32api.WriteProfileVal(section, repr(i), item, ini)
|
||||
i = i + 1
|
||||
self.UpdateData(0)
|
||||
|
||||
def OnOK(self):
|
||||
self.UpdateData(1)
|
||||
for id, name in [(101,'greppattern'), (102,'dirpattern'), (103,'filpattern')]:
|
||||
if not self[name]:
|
||||
self.GetDlgItem(id).SetFocus()
|
||||
win32api.MessageBeep()
|
||||
win32ui.SetStatusText("Please enter a value")
|
||||
return
|
||||
self._obj_.OnOK()
|
||||
|
||||
class TheParamsDialog(dialog.Dialog):
|
||||
def __init__(self, items):
|
||||
self.items = items
|
||||
self.newitems = []
|
||||
style = win32con.DS_MODALFRAME | win32con.WS_POPUP | win32con.WS_VISIBLE | win32con.WS_CAPTION | win32con.WS_SYSMENU | win32con.DS_SETFONT
|
||||
CS = win32con.WS_CHILD | win32con.WS_VISIBLE
|
||||
tmp = [ ["Pychecker Parameters", (0, 0, 205, 100), style, None, (8, "MS Sans Serif")], ]
|
||||
tmp.append([LISTBOX, '', 107, (7, 7, 150, 72), CS | win32con.LBS_MULTIPLESEL| win32con.LBS_STANDARD | win32con.LBS_HASSTRINGS | win32con.WS_TABSTOP | win32con.LBS_NOTIFY])
|
||||
tmp.append([BUTTON,'OK', win32con.IDOK, (167, 7, 32, 12), CS | win32con.BS_DEFPUSHBUTTON| win32con.WS_TABSTOP])
|
||||
tmp.append([BUTTON,'Cancel', win32con.IDCANCEL, (167,23, 32, 12), CS | win32con.BS_PUSHBUTTON| win32con.WS_TABSTOP])
|
||||
tmp.append([STATIC,'New:', -1, (2, 83, 15, 12), CS])
|
||||
tmp.append([EDIT, '', 108, (18, 83, 139, 12), CS | win32con.WS_TABSTOP | win32con.ES_AUTOHSCROLL | win32con.WS_BORDER])
|
||||
tmp.append([BUTTON,'Add', 109, (167,83, 32, 12), CS | win32con.BS_PUSHBUTTON| win32con.WS_TABSTOP])
|
||||
dialog.Dialog.__init__(self, tmp)
|
||||
self.HookCommand(self.OnAddItem, 109)
|
||||
self.HookCommand(self.OnListDoubleClick, 107)
|
||||
|
||||
def OnInitDialog(self):
|
||||
lb = self.GetDlgItem(107)
|
||||
for item in self.items:
|
||||
lb.AddString(item)
|
||||
return self._obj_.OnInitDialog()
|
||||
|
||||
def OnAddItem(self, cmd, code):
|
||||
eb = self.GetDlgItem(108)
|
||||
item = eb.GetLine(0)
|
||||
self.newitems.append(item)
|
||||
lb = self.GetDlgItem(107)
|
||||
i = lb.AddString(item)
|
||||
lb.SetSel(i, 1)
|
||||
return 1
|
||||
|
||||
def OnListDoubleClick(self, cmd, code):
|
||||
if code == win32con.LBN_DBLCLK:
|
||||
self.OnOK()
|
||||
return 1
|
||||
|
||||
def OnOK(self):
|
||||
lb = self.GetDlgItem(107)
|
||||
self.selections = lb.GetSelTextItems()
|
||||
self._obj_.OnOK()
|
||||
|
||||
def getItems(self):
|
||||
return self.selections
|
||||
|
||||
def getNew(self):
|
||||
return self.newitems
|
||||
|
||||
try:
|
||||
win32ui.GetApp().RemoveDocTemplate(greptemplate)
|
||||
except NameError:
|
||||
pass
|
||||
|
||||
greptemplate = TheTemplate()
|
||||
623
Lib/site-packages/pythonwin/pywin/framework/scriptutils.py
Normal file
623
Lib/site-packages/pythonwin/pywin/framework/scriptutils.py
Normal file
|
|
@ -0,0 +1,623 @@
|
|||
"""
|
||||
Various utilities for running/importing a script
|
||||
"""
|
||||
import sys
|
||||
import win32ui
|
||||
import win32api
|
||||
import win32con
|
||||
import __main__
|
||||
from pywin.mfc import dialog
|
||||
from pywin.mfc.docview import TreeView
|
||||
import os
|
||||
import string
|
||||
import traceback
|
||||
import linecache
|
||||
import bdb
|
||||
|
||||
from .cmdline import ParseArgs
|
||||
|
||||
RS_DEBUGGER_NONE=0 # Dont run under the debugger.
|
||||
RS_DEBUGGER_STEP=1 # Start stepping under the debugger
|
||||
RS_DEBUGGER_GO=2 # Just run under the debugger, stopping only at break-points.
|
||||
RS_DEBUGGER_PM=3 # Dont run under debugger, but do post-mortem analysis on exception.
|
||||
|
||||
debugging_options = """No debugging
|
||||
Step-through in the debugger
|
||||
Run in the debugger
|
||||
Post-Mortem of unhandled exceptions""".split("\n")
|
||||
|
||||
byte_cr = "\r".encode("ascii")
|
||||
byte_lf = "\n".encode("ascii")
|
||||
byte_crlf = "\r\n".encode("ascii")
|
||||
|
||||
# A dialog box for the "Run Script" command.
|
||||
class DlgRunScript(dialog.Dialog):
|
||||
"A class for the 'run script' dialog"
|
||||
def __init__(self, bHaveDebugger):
|
||||
dialog.Dialog.__init__(self, win32ui.IDD_RUN_SCRIPT )
|
||||
self.AddDDX(win32ui.IDC_EDIT1, "script")
|
||||
self.AddDDX(win32ui.IDC_EDIT2, "args")
|
||||
self.AddDDX(win32ui.IDC_COMBO1, "debuggingType", "i")
|
||||
self.HookCommand(self.OnBrowse, win32ui.IDC_BUTTON2)
|
||||
self.bHaveDebugger = bHaveDebugger
|
||||
def OnInitDialog(self):
|
||||
rc = dialog.Dialog.OnInitDialog(self)
|
||||
cbo = self.GetDlgItem(win32ui.IDC_COMBO1)
|
||||
for o in debugging_options:
|
||||
cbo.AddString(o)
|
||||
cbo.SetCurSel(self['debuggingType'])
|
||||
if not self.bHaveDebugger:
|
||||
cbo.EnableWindow(0)
|
||||
|
||||
def OnBrowse(self, id, cmd):
|
||||
openFlags = win32con.OFN_OVERWRITEPROMPT|win32con.OFN_FILEMUSTEXIST
|
||||
dlg = win32ui.CreateFileDialog(1,None,None,openFlags, "Python Scripts (*.py)|*.py||", self)
|
||||
dlg.SetOFNTitle("Run Script")
|
||||
if dlg.DoModal()!=win32con.IDOK:
|
||||
return 0
|
||||
self['script'] = dlg.GetPathName()
|
||||
self.UpdateData(0)
|
||||
return 0
|
||||
|
||||
def GetDebugger():
|
||||
"""Get the default Python debugger. Returns the debugger, or None.
|
||||
|
||||
It is assumed the debugger has a standard "pdb" defined interface.
|
||||
Currently always returns the 'pywin.debugger' debugger, or None
|
||||
(pdb is _not_ returned as it is not effective in this GUI environment)
|
||||
"""
|
||||
try:
|
||||
import pywin.debugger
|
||||
return pywin.debugger
|
||||
except ImportError:
|
||||
return None
|
||||
|
||||
def IsOnPythonPath(path):
|
||||
"Given a path only, see if it is on the Pythonpath. Assumes path is a full path spec."
|
||||
# must check that the command line arg's path is in sys.path
|
||||
for syspath in sys.path:
|
||||
try:
|
||||
# Python 1.5 and later allows an empty sys.path entry.
|
||||
if syspath and win32ui.FullPath(syspath)==path:
|
||||
return 1
|
||||
except win32ui.error as details:
|
||||
print("Warning: The sys.path entry '%s' is invalid\n%s" % (syspath, details))
|
||||
return 0
|
||||
|
||||
def GetPackageModuleName(fileName):
|
||||
"""Given a filename, return (module name, new path).
|
||||
eg - given "c:\a\b\c\my.py", return ("b.c.my",None) if "c:\a" is on sys.path.
|
||||
If no package found, will return ("my", "c:\a\b\c")
|
||||
"""
|
||||
path, fname = os.path.split(fileName)
|
||||
path=origPath=win32ui.FullPath(path)
|
||||
fname = os.path.splitext(fname)[0]
|
||||
modBits = []
|
||||
newPathReturn = None
|
||||
if not IsOnPythonPath(path):
|
||||
# Module not directly on the search path - see if under a package.
|
||||
while len(path)>3: # ie 'C:\'
|
||||
path, modBit = os.path.split(path)
|
||||
modBits.append(modBit)
|
||||
# If on path, _and_ existing package of that name loaded.
|
||||
if IsOnPythonPath(path) and modBit in sys.modules and \
|
||||
(os.path.exists(os.path.join(path, modBit, '__init__.py')) or \
|
||||
os.path.exists(os.path.join(path, modBit, '__init__.pyc')) or \
|
||||
os.path.exists(os.path.join(path, modBit, '__init__.pyo')) \
|
||||
):
|
||||
modBits.reverse()
|
||||
return ".".join(modBits) + "." + fname, newPathReturn
|
||||
# Not found - look a level higher
|
||||
else:
|
||||
newPathReturn = origPath
|
||||
|
||||
return fname, newPathReturn
|
||||
|
||||
def GetActiveView():
|
||||
"""Gets the edit control (eg, EditView) with the focus, or None
|
||||
"""
|
||||
try:
|
||||
childFrame, bIsMaximised = win32ui.GetMainFrame().MDIGetActive()
|
||||
return childFrame.GetActiveView()
|
||||
except win32ui.error:
|
||||
return None
|
||||
|
||||
def GetActiveEditControl():
|
||||
view = GetActiveView()
|
||||
if view is None: return None
|
||||
if hasattr(view, "SCIAddText"): # Is it a scintilla control?
|
||||
return view
|
||||
try:
|
||||
return view.GetRichEditCtrl()
|
||||
except AttributeError:
|
||||
pass
|
||||
try:
|
||||
return view.GetEditCtrl()
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
def GetActiveEditorDocument():
|
||||
"""Returns the active editor document and view, or (None,None) if no
|
||||
active document or its not an editor document.
|
||||
"""
|
||||
view = GetActiveView()
|
||||
if view is None or isinstance(view, TreeView):
|
||||
return (None, None)
|
||||
doc = view.GetDocument()
|
||||
if hasattr(doc, "MarkerAdd"): # Is it an Editor document?
|
||||
return doc, view
|
||||
return (None, None)
|
||||
|
||||
def GetActiveFileName(bAutoSave = 1):
|
||||
"""Gets the file name for the active frame, saving it if necessary.
|
||||
|
||||
Returns None if it cant be found, or raises KeyboardInterrupt.
|
||||
"""
|
||||
pathName = None
|
||||
active = GetActiveView()
|
||||
if active is None:
|
||||
return None
|
||||
try:
|
||||
doc = active.GetDocument()
|
||||
pathName = doc.GetPathName()
|
||||
|
||||
if bAutoSave and \
|
||||
(len(pathName)>0 or \
|
||||
doc.GetTitle()[:8]=="Untitled" or \
|
||||
doc.GetTitle()[:6]=="Script"): # if not a special purpose window
|
||||
if doc.IsModified():
|
||||
try:
|
||||
doc.OnSaveDocument(pathName)
|
||||
pathName = doc.GetPathName()
|
||||
|
||||
# clear the linecache buffer
|
||||
linecache.clearcache()
|
||||
|
||||
except win32ui.error:
|
||||
raise KeyboardInterrupt
|
||||
|
||||
except (win32ui.error, AttributeError):
|
||||
pass
|
||||
if not pathName:
|
||||
return None
|
||||
return pathName
|
||||
|
||||
lastScript = ''
|
||||
lastArgs = ''
|
||||
lastDebuggingType = RS_DEBUGGER_NONE
|
||||
|
||||
def RunScript(defName=None, defArgs=None, bShowDialog = 1, debuggingType=None):
|
||||
global lastScript, lastArgs, lastDebuggingType
|
||||
_debugger_stop_frame_ = 1 # Magic variable so the debugger will hide me!
|
||||
|
||||
# Get the debugger - may be None!
|
||||
debugger = GetDebugger()
|
||||
|
||||
if defName is None:
|
||||
try:
|
||||
pathName = GetActiveFileName()
|
||||
except KeyboardInterrupt:
|
||||
return # User cancelled save.
|
||||
else:
|
||||
pathName = defName
|
||||
if not pathName:
|
||||
pathName = lastScript
|
||||
if defArgs is None:
|
||||
args = ''
|
||||
if pathName==lastScript:
|
||||
args = lastArgs
|
||||
else:
|
||||
args = defArgs
|
||||
if debuggingType is None: debuggingType = lastDebuggingType
|
||||
|
||||
if not pathName or bShowDialog:
|
||||
dlg = DlgRunScript(debugger is not None)
|
||||
dlg['script'] = pathName
|
||||
dlg['args'] = args
|
||||
dlg['debuggingType'] = debuggingType
|
||||
if dlg.DoModal() != win32con.IDOK:
|
||||
return
|
||||
script=dlg['script']
|
||||
args=dlg['args']
|
||||
debuggingType = dlg['debuggingType']
|
||||
if not script: return
|
||||
if debuggingType == RS_DEBUGGER_GO and debugger is not None:
|
||||
# This may surprise users - they select "Run under debugger", but
|
||||
# it appears not to! Only warn when they pick from the dialog!
|
||||
# First - ensure the debugger is activated to pickup any break-points
|
||||
# set in the editor.
|
||||
try:
|
||||
# Create the debugger, but _dont_ init the debugger GUI.
|
||||
rd = debugger._GetCurrentDebugger()
|
||||
except AttributeError:
|
||||
rd = None
|
||||
if rd is not None and len(rd.breaks)==0:
|
||||
msg = "There are no active break-points.\r\n\r\nSelecting this debug option without any\r\nbreak-points is unlikely to have the desired effect\r\nas the debugger is unlikely to be invoked..\r\n\r\nWould you like to step-through in the debugger instead?"
|
||||
rc = win32ui.MessageBox(msg, win32ui.LoadString(win32ui.IDR_DEBUGGER), win32con.MB_YESNOCANCEL | win32con.MB_ICONINFORMATION)
|
||||
if rc == win32con.IDCANCEL:
|
||||
return
|
||||
if rc == win32con.IDYES:
|
||||
debuggingType = RS_DEBUGGER_STEP
|
||||
|
||||
lastDebuggingType = debuggingType
|
||||
lastScript = script
|
||||
lastArgs = args
|
||||
else:
|
||||
script = pathName
|
||||
|
||||
# try and open the script.
|
||||
if len(os.path.splitext(script)[1])==0: # check if no extension supplied, and give one.
|
||||
script = script + '.py'
|
||||
# If no path specified, try and locate the file
|
||||
path, fnameonly = os.path.split(script)
|
||||
if len(path)==0:
|
||||
try:
|
||||
os.stat(fnameonly) # See if it is OK as is...
|
||||
script = fnameonly
|
||||
except os.error:
|
||||
fullScript = LocatePythonFile(script)
|
||||
if fullScript is None:
|
||||
win32ui.MessageBox("The file '%s' can not be located" % script )
|
||||
return
|
||||
script = fullScript
|
||||
else:
|
||||
path = win32ui.FullPath(path)
|
||||
if not IsOnPythonPath(path): sys.path.append(path)
|
||||
|
||||
# py3k fun: If we use text mode to open the file, we get \r\n
|
||||
# translated so Python allows the syntax (good!), but we get back
|
||||
# text already decoded from the default encoding (bad!) and Python
|
||||
# ignores any encoding decls (bad!). If we use binary mode we get
|
||||
# the raw bytes and Python looks at the encoding (good!) but \r\n
|
||||
# chars stay in place so Python throws a syntax error (bad!).
|
||||
# So: so the binary thing and manually normalize \r\n.
|
||||
try:
|
||||
f = open(script, 'rb')
|
||||
except IOError as exc:
|
||||
win32ui.MessageBox("The file could not be opened - %s (%d)" % (exc.strerror, exc.errno))
|
||||
return
|
||||
|
||||
# Get the source-code - as above, normalize \r\n
|
||||
code = f.read().replace(byte_crlf, byte_lf).replace(byte_cr, byte_lf) + byte_lf
|
||||
|
||||
# Remember and hack sys.argv for the script.
|
||||
oldArgv = sys.argv
|
||||
sys.argv = ParseArgs(args)
|
||||
sys.argv.insert(0, script)
|
||||
# sys.path[0] is the path of the script
|
||||
oldPath0 = sys.path[0]
|
||||
newPath0 = os.path.split(script)[0]
|
||||
if not oldPath0: # if sys.path[0] is empty
|
||||
sys.path[0] = newPath0
|
||||
insertedPath0 = 0
|
||||
else:
|
||||
sys.path.insert(0, newPath0)
|
||||
insertedPath0 = 1
|
||||
bWorked = 0
|
||||
win32ui.DoWaitCursor(1)
|
||||
base = os.path.split(script)[1]
|
||||
# Allow windows to repaint before starting.
|
||||
win32ui.PumpWaitingMessages()
|
||||
win32ui.SetStatusText('Running script %s...' % base,1 )
|
||||
exitCode = 0
|
||||
from pywin.framework import interact
|
||||
# Check the debugger flags
|
||||
if debugger is None and (debuggingType != RS_DEBUGGER_NONE):
|
||||
win32ui.MessageBox("No debugger is installed. Debugging options have been ignored!")
|
||||
debuggingType = RS_DEBUGGER_NONE
|
||||
|
||||
# Get a code object - ignore the debugger for this, as it is probably a syntax error
|
||||
# at this point
|
||||
try:
|
||||
codeObject = compile(code, script, "exec")
|
||||
except:
|
||||
# Almost certainly a syntax error!
|
||||
_HandlePythonFailure("run script", script)
|
||||
# No code object which to run/debug.
|
||||
return
|
||||
__main__.__file__=script
|
||||
try:
|
||||
if debuggingType == RS_DEBUGGER_STEP:
|
||||
debugger.run(codeObject, __main__.__dict__, start_stepping=1)
|
||||
elif debuggingType == RS_DEBUGGER_GO:
|
||||
debugger.run(codeObject, __main__.__dict__, start_stepping=0)
|
||||
else:
|
||||
# Post mortem or no debugging
|
||||
exec(codeObject, __main__.__dict__)
|
||||
bWorked = 1
|
||||
except bdb.BdbQuit:
|
||||
# Dont print tracebacks when the debugger quit, but do print a message.
|
||||
print("Debugging session cancelled.")
|
||||
exitCode = 1
|
||||
bWorked = 1
|
||||
except SystemExit as code:
|
||||
exitCode = code
|
||||
bWorked = 1
|
||||
except KeyboardInterrupt:
|
||||
# Consider this successful, as we dont want the debugger.
|
||||
# (but we do want a traceback!)
|
||||
if interact.edit and interact.edit.currentView:
|
||||
interact.edit.currentView.EnsureNoPrompt()
|
||||
traceback.print_exc()
|
||||
if interact.edit and interact.edit.currentView:
|
||||
interact.edit.currentView.AppendToPrompt([])
|
||||
bWorked = 1
|
||||
except:
|
||||
if interact.edit and interact.edit.currentView:
|
||||
interact.edit.currentView.EnsureNoPrompt()
|
||||
traceback.print_exc()
|
||||
if interact.edit and interact.edit.currentView:
|
||||
interact.edit.currentView.AppendToPrompt([])
|
||||
if debuggingType == RS_DEBUGGER_PM:
|
||||
debugger.pm()
|
||||
del __main__.__file__
|
||||
sys.argv = oldArgv
|
||||
if insertedPath0:
|
||||
del sys.path[0]
|
||||
else:
|
||||
sys.path[0] = oldPath0
|
||||
f.close()
|
||||
if bWorked:
|
||||
win32ui.SetStatusText("Script '%s' returned exit code %s" %(script, exitCode))
|
||||
else:
|
||||
win32ui.SetStatusText('Exception raised while running script %s' % base)
|
||||
try:
|
||||
sys.stdout.flush()
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
win32ui.DoWaitCursor(0)
|
||||
|
||||
def ImportFile():
|
||||
""" This code looks for the current window, and determines if it can be imported. If not,
|
||||
it will prompt for a file name, and allow it to be imported. """
|
||||
try:
|
||||
pathName = GetActiveFileName()
|
||||
except KeyboardInterrupt:
|
||||
pathName = None
|
||||
|
||||
if pathName is not None:
|
||||
if os.path.splitext(pathName)[1].lower() not in ('.py','.pyw','.pyx'):
|
||||
pathName = None
|
||||
|
||||
if pathName is None:
|
||||
openFlags = win32con.OFN_OVERWRITEPROMPT|win32con.OFN_FILEMUSTEXIST
|
||||
dlg = win32ui.CreateFileDialog(1,None,None,openFlags, "Python Scripts (*.py;*.pyw)|*.py;*.pyw;*.pyx||")
|
||||
dlg.SetOFNTitle("Import Script")
|
||||
if dlg.DoModal()!=win32con.IDOK:
|
||||
return 0
|
||||
|
||||
pathName = dlg.GetPathName()
|
||||
|
||||
# If already imported, dont look for package
|
||||
path, modName = os.path.split(pathName)
|
||||
modName, modExt = os.path.splitext(modName)
|
||||
newPath = None
|
||||
# note that some packages (*cough* email *cough*) use "lazy importers"
|
||||
# meaning sys.modules can change as a side-effect of looking at
|
||||
# module.__file__ - so we must take a copy (ie, items() in py2k,
|
||||
# list(items()) in py3k)
|
||||
for key, mod in list(sys.modules.items()):
|
||||
if hasattr(mod, '__file__'):
|
||||
fname = mod.__file__
|
||||
base, ext = os.path.splitext(fname)
|
||||
if ext.lower() in ['.pyo', '.pyc']:
|
||||
ext = '.py'
|
||||
fname = base + ext
|
||||
if win32ui.ComparePath(fname, pathName):
|
||||
modName = key
|
||||
break
|
||||
else: # for not broken
|
||||
modName, newPath = GetPackageModuleName(pathName)
|
||||
if newPath: sys.path.append(newPath)
|
||||
|
||||
if modName in sys.modules:
|
||||
bNeedReload = 1
|
||||
what = "reload"
|
||||
else:
|
||||
what = "import"
|
||||
bNeedReload = 0
|
||||
|
||||
win32ui.SetStatusText(what.capitalize()+'ing module...',1)
|
||||
win32ui.DoWaitCursor(1)
|
||||
# win32ui.GetMainFrame().BeginWaitCursor()
|
||||
|
||||
try:
|
||||
# always do an import, as it is cheap if it's already loaded. This ensures
|
||||
# it is in our name space.
|
||||
codeObj = compile('import '+modName,'<auto import>','exec')
|
||||
except SyntaxError:
|
||||
win32ui.SetStatusText('Invalid filename for import: "' +modName+'"')
|
||||
return
|
||||
try:
|
||||
exec(codeObj, __main__.__dict__)
|
||||
mod = sys.modules.get(modName)
|
||||
if bNeedReload:
|
||||
try:
|
||||
## The interpreter sees this import as a local assignment, so Python 2.x throws
|
||||
## UnboundLocalError: local variable 'reload' referenced before assignment
|
||||
## when you try to use reload after this fails
|
||||
from imp import reload as my_reload # py3k
|
||||
except ImportError:
|
||||
my_reload = reload # reload a builtin in py2k
|
||||
mod = my_reload(sys.modules[modName])
|
||||
win32ui.SetStatusText('Successfully ' + what + "ed module '"+modName+"': %s" % getattr(mod,'__file__',"<unkown file>"))
|
||||
except:
|
||||
_HandlePythonFailure(what)
|
||||
win32ui.DoWaitCursor(0)
|
||||
|
||||
def CheckFile():
|
||||
""" This code looks for the current window, and gets Python to check it
|
||||
without actually executing any code (ie, by compiling only)
|
||||
"""
|
||||
try:
|
||||
pathName = GetActiveFileName()
|
||||
except KeyboardInterrupt:
|
||||
return
|
||||
|
||||
what = "check"
|
||||
win32ui.SetStatusText(what.capitalize()+'ing module...',1)
|
||||
win32ui.DoWaitCursor(1)
|
||||
try:
|
||||
f = open(pathName)
|
||||
except IOError as details:
|
||||
print("Cant open file '%s' - %s" % (pathName, details))
|
||||
return
|
||||
try:
|
||||
code = f.read() + "\n"
|
||||
finally:
|
||||
f.close()
|
||||
try:
|
||||
codeObj = compile(code, pathName,'exec')
|
||||
if RunTabNanny(pathName):
|
||||
win32ui.SetStatusText("Python and the TabNanny successfully checked the file '"+os.path.basename(pathName)+"'")
|
||||
except SyntaxError:
|
||||
_HandlePythonFailure(what, pathName)
|
||||
except:
|
||||
traceback.print_exc()
|
||||
_HandlePythonFailure(what)
|
||||
win32ui.DoWaitCursor(0)
|
||||
|
||||
def RunTabNanny(filename):
|
||||
import io as io
|
||||
tabnanny = FindTabNanny()
|
||||
if tabnanny is None:
|
||||
win32ui.MessageBox("The TabNanny is not around, so the children can run amok!" )
|
||||
return
|
||||
|
||||
# Capture the tab-nanny output
|
||||
newout = io.StringIO()
|
||||
old_out = sys.stderr, sys.stdout
|
||||
sys.stderr = sys.stdout = newout
|
||||
try:
|
||||
tabnanny.check(filename)
|
||||
finally:
|
||||
# Restore output
|
||||
sys.stderr, sys.stdout = old_out
|
||||
data = newout.getvalue()
|
||||
if data:
|
||||
try:
|
||||
lineno = data.split()[1]
|
||||
lineno = int(lineno)
|
||||
_JumpToPosition(filename, lineno)
|
||||
try: # Try and display whitespace
|
||||
GetActiveEditControl().SCISetViewWS(1)
|
||||
except:
|
||||
pass
|
||||
win32ui.SetStatusText("The TabNanny found trouble at line %d" % lineno)
|
||||
except (IndexError, TypeError, ValueError):
|
||||
print("The tab nanny complained, but I cant see where!")
|
||||
print(data)
|
||||
return 0
|
||||
return 1
|
||||
|
||||
def _JumpToPosition(fileName, lineno, col = 1):
|
||||
JumpToDocument(fileName, lineno, col)
|
||||
|
||||
def JumpToDocument(fileName, lineno=0, col = 1, nChars = 0, bScrollToTop = 0):
|
||||
# Jump to the position in a file.
|
||||
# If lineno is <= 0, dont move the position - just open/restore.
|
||||
# if nChars > 0, select that many characters.
|
||||
# if bScrollToTop, the specified line will be moved to the top of the window
|
||||
# (eg, bScrollToTop should be false when jumping to an error line to retain the
|
||||
# context, but true when jumping to a method defn, where we want the full body.
|
||||
# Return the view which is editing the file, or None on error.
|
||||
doc = win32ui.GetApp().OpenDocumentFile(fileName)
|
||||
if doc is None: return None
|
||||
frame = doc.GetFirstView().GetParentFrame()
|
||||
try:
|
||||
view = frame.GetEditorView()
|
||||
if frame.GetActiveView() != view:
|
||||
frame.SetActiveView(view)
|
||||
frame.AutoRestore()
|
||||
except AttributeError: # Not an editor frame??
|
||||
view = doc.GetFirstView()
|
||||
if lineno > 0:
|
||||
charNo = view.LineIndex(lineno-1)
|
||||
start = charNo + col - 1
|
||||
size = view.GetTextLength()
|
||||
try:
|
||||
view.EnsureCharsVisible(charNo)
|
||||
except AttributeError:
|
||||
print("Doesnt appear to be one of our views?")
|
||||
view.SetSel(min(start, size), min(start + nChars, size))
|
||||
if bScrollToTop:
|
||||
curTop = view.GetFirstVisibleLine()
|
||||
nScroll = (lineno-1) - curTop
|
||||
view.LineScroll(nScroll, 0)
|
||||
view.SetFocus()
|
||||
return view
|
||||
|
||||
def _HandlePythonFailure(what, syntaxErrorPathName = None):
|
||||
typ, details, tb = sys.exc_info()
|
||||
if isinstance(details, SyntaxError):
|
||||
try:
|
||||
msg, (fileName, line, col, text) = details
|
||||
if (not fileName or fileName =="<string>") and syntaxErrorPathName:
|
||||
fileName = syntaxErrorPathName
|
||||
_JumpToPosition(fileName, line, col)
|
||||
except (TypeError, ValueError):
|
||||
msg = str(details)
|
||||
win32ui.SetStatusText('Failed to ' + what + ' - syntax error - %s' % msg)
|
||||
else:
|
||||
traceback.print_exc()
|
||||
win32ui.SetStatusText('Failed to ' + what + ' - ' + str(details) )
|
||||
tb = None # Clean up a cycle.
|
||||
|
||||
# Find the Python TabNanny in either the standard library or the Python Tools/Scripts directory.
|
||||
def FindTabNanny():
|
||||
try:
|
||||
return __import__("tabnanny")
|
||||
except ImportError:
|
||||
pass
|
||||
# OK - not in the standard library - go looking.
|
||||
filename = "tabnanny.py"
|
||||
try:
|
||||
path = win32api.RegQueryValue(win32con.HKEY_LOCAL_MACHINE, "SOFTWARE\\Python\\PythonCore\\%s\\InstallPath" % (sys.winver))
|
||||
except win32api.error:
|
||||
print("WARNING - The Python registry does not have an 'InstallPath' setting")
|
||||
print(" The file '%s' can not be located" % (filename))
|
||||
return None
|
||||
fname = os.path.join(path, "Tools\\Scripts\\%s" % filename)
|
||||
try:
|
||||
os.stat(fname)
|
||||
except os.error:
|
||||
print("WARNING - The file '%s' can not be located in path '%s'" % (filename, path))
|
||||
return None
|
||||
|
||||
tabnannyhome, tabnannybase = os.path.split(fname)
|
||||
tabnannybase = os.path.splitext(tabnannybase)[0]
|
||||
# Put tab nanny at the top of the path.
|
||||
sys.path.insert(0, tabnannyhome)
|
||||
try:
|
||||
return __import__(tabnannybase)
|
||||
finally:
|
||||
# remove the tab-nanny from the path
|
||||
del sys.path[0]
|
||||
|
||||
def LocatePythonFile( fileName, bBrowseIfDir = 1 ):
|
||||
" Given a file name, return a fully qualified file name, or None "
|
||||
# first look for the exact file as specified
|
||||
if not os.path.isfile(fileName):
|
||||
# Go looking!
|
||||
baseName = fileName
|
||||
for path in sys.path:
|
||||
fileName = os.path.abspath(os.path.join(path, baseName))
|
||||
if os.path.isdir(fileName):
|
||||
if bBrowseIfDir:
|
||||
d=win32ui.CreateFileDialog(1, "*.py", None, 0, "Python Files (*.py)|*.py|All files|*.*")
|
||||
d.SetOFNInitialDir(fileName)
|
||||
rc=d.DoModal()
|
||||
if rc==win32con.IDOK:
|
||||
fileName = d.GetPathName()
|
||||
break
|
||||
else:
|
||||
return None
|
||||
else:
|
||||
fileName = fileName + ".py"
|
||||
if os.path.isfile(fileName):
|
||||
break # Found it!
|
||||
|
||||
else: # for not broken out of
|
||||
return None
|
||||
return win32ui.FullPath(fileName)
|
||||
530
Lib/site-packages/pythonwin/pywin/framework/sgrepmdi.py
Normal file
530
Lib/site-packages/pythonwin/pywin/framework/sgrepmdi.py
Normal file
|
|
@ -0,0 +1,530 @@
|
|||
#SGrepMDI is by Gordon McMillan (gmcm@hypernet.com)
|
||||
#It does basically what Find In Files does in MSVC with a couple enhancements.
|
||||
# - It saves any directories in the app's ini file (if you want to get rid
|
||||
# of them you'll have to edit the file)
|
||||
# - "Directories" can be directories,
|
||||
# - semicolon separated lists of "directories",
|
||||
# - environment variables that evaluate to "directories",
|
||||
# - registry path names that evaluate to "directories",
|
||||
# - all of which is recursive, so you can mix them all up.
|
||||
# - It is MDI, so you can 'nest' greps and return to earlier ones,
|
||||
# (ie, have multiple results open at the same time)
|
||||
# - Like FIF, double clicking a line opens an editor and takes you to the line.
|
||||
# - You can highlight text, right click and start a new grep with the selected
|
||||
# text as search pattern and same directories etc as before.
|
||||
# - You can save grep parameters (so you don't lose your hardearned pattern)
|
||||
# from File|Save
|
||||
# - You can save grep results by right clicking in the result window.
|
||||
# Hats off to Mark Hammond for providing an environment where I could cobble
|
||||
# something like this together in a couple evenings!
|
||||
|
||||
import win32ui
|
||||
import win32api
|
||||
from pywin.mfc import docview, dialog, window
|
||||
import win32con
|
||||
import string
|
||||
import re
|
||||
import glob
|
||||
import os
|
||||
import stat
|
||||
import glob
|
||||
from . import scriptutils
|
||||
|
||||
def getsubdirs(d):
|
||||
dlist = []
|
||||
flist = glob.glob(d+'\\*')
|
||||
for f in flist:
|
||||
if os.path.isdir(f):
|
||||
dlist.append(f)
|
||||
dlist = dlist + getsubdirs(f)
|
||||
return dlist
|
||||
|
||||
class dirpath:
|
||||
def __init__(self, str, recurse=0):
|
||||
dp = str.split(';')
|
||||
dirs = {}
|
||||
for d in dp:
|
||||
if os.path.isdir(d):
|
||||
d = d.lower()
|
||||
if d not in dirs:
|
||||
dirs[d] = None
|
||||
if recurse:
|
||||
subdirs = getsubdirs(d)
|
||||
for sd in subdirs:
|
||||
sd = sd.lower()
|
||||
if sd not in dirs:
|
||||
dirs[sd] = None
|
||||
elif os.path.isfile(d):
|
||||
pass
|
||||
else:
|
||||
x = None
|
||||
if d in os.environ:
|
||||
x = dirpath(os.environ[d])
|
||||
elif d[:5] == 'HKEY_':
|
||||
keystr = d.split('\\')
|
||||
try:
|
||||
root = eval('win32con.'+keystr[0])
|
||||
except:
|
||||
win32ui.MessageBox("Can't interpret registry key name '%s'" % keystr[0])
|
||||
try:
|
||||
subkey = '\\'.join(keystr[1:])
|
||||
val = win32api.RegQueryValue(root, subkey)
|
||||
if val:
|
||||
x = dirpath(val)
|
||||
else:
|
||||
win32ui.MessageBox("Registry path '%s' did not return a path entry" % d)
|
||||
except:
|
||||
win32ui.MessageBox("Can't interpret registry key value: %s" % keystr[1:])
|
||||
else:
|
||||
win32ui.MessageBox("Directory '%s' not found" % d)
|
||||
if x:
|
||||
for xd in x:
|
||||
if xd not in dirs:
|
||||
dirs[xd] = None
|
||||
if recurse:
|
||||
subdirs = getsubdirs(xd)
|
||||
for sd in subdirs:
|
||||
sd = sd.lower()
|
||||
if sd not in dirs:
|
||||
dirs[sd] = None
|
||||
self.dirs = []
|
||||
for d in list(dirs.keys()):
|
||||
self.dirs.append(d)
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self.dirs[key]
|
||||
def __len__(self):
|
||||
return len(self.dirs)
|
||||
def __setitem__(self, key, value):
|
||||
self.dirs[key] = value
|
||||
def __delitem__(self, key):
|
||||
del self.dirs[key]
|
||||
def __getslice__(self, lo, hi):
|
||||
return self.dirs[lo:hi]
|
||||
def __setslice__(self, lo, hi, seq):
|
||||
self.dirs[lo:hi] = seq
|
||||
def __delslice__(self, lo, hi):
|
||||
del self.dirs[lo:hi]
|
||||
def __add__(self, other):
|
||||
if type(other) == type(self) or type(other) == type([]):
|
||||
return self.dirs + other.dirs
|
||||
def __radd__(self, other):
|
||||
if type(other) == type(self) or type(other) == type([]):
|
||||
return other.dirs + self.dirs
|
||||
|
||||
# Group(1) is the filename, group(2) is the lineno.
|
||||
#regexGrepResult=regex.compile("^\\([a-zA-Z]:.*\\)(\\([0-9]+\\))")
|
||||
|
||||
regexGrep=re.compile(r"^([a-zA-Z]:[^(]*)\(([0-9]+)\)")
|
||||
|
||||
#these are the atom numbers defined by Windows for basic dialog controls
|
||||
|
||||
BUTTON = 0x80
|
||||
EDIT = 0x81
|
||||
STATIC = 0x82
|
||||
LISTBOX = 0x83
|
||||
SCROLLBAR = 0x84
|
||||
COMBOBOX = 0x85
|
||||
|
||||
class GrepTemplate(docview.RichEditDocTemplate):
|
||||
def __init__(self):
|
||||
docview.RichEditDocTemplate.__init__(self, win32ui.IDR_TEXTTYPE, GrepDocument, GrepFrame, GrepView)
|
||||
self.SetDocStrings("\nGrep\nGrep\nGrep params (*.grep)\n.grep\n\n\n")
|
||||
win32ui.GetApp().AddDocTemplate(self)
|
||||
self.docparams = None
|
||||
|
||||
def MatchDocType(self, fileName, fileType):
|
||||
doc = self.FindOpenDocument(fileName)
|
||||
if doc: return doc
|
||||
ext = os.path.splitext(fileName)[1].lower()
|
||||
if ext =='.grep':
|
||||
return win32ui.CDocTemplate_Confidence_yesAttemptNative
|
||||
return win32ui.CDocTemplate_Confidence_noAttempt
|
||||
|
||||
def setParams(self, params):
|
||||
self.docparams = params
|
||||
|
||||
def readParams(self):
|
||||
tmp = self.docparams
|
||||
self.docparams = None
|
||||
return tmp
|
||||
|
||||
class GrepFrame(window.MDIChildWnd):
|
||||
# The template and doc params will one day be removed.
|
||||
def __init__(self, wnd = None):
|
||||
window.MDIChildWnd.__init__(self, wnd)
|
||||
|
||||
class GrepDocument(docview.RichEditDoc):
|
||||
def __init__(self, template):
|
||||
docview.RichEditDoc.__init__(self, template)
|
||||
self.dirpattern = ''
|
||||
self.filpattern = ''
|
||||
self.greppattern = ''
|
||||
self.casesensitive = 1
|
||||
self.recurse = 1
|
||||
self.verbose = 0
|
||||
|
||||
def OnOpenDocument(self, fnm):
|
||||
#this bizarre stuff with params is so right clicking in a result window
|
||||
#and starting a new grep can communicate the default parameters to the
|
||||
#new grep.
|
||||
try:
|
||||
params = open(fnm,'r').read()
|
||||
except:
|
||||
params = None
|
||||
self.setInitParams(params)
|
||||
return self.OnNewDocument()
|
||||
|
||||
def OnCloseDocument(self):
|
||||
try:
|
||||
win32ui.GetApp().DeleteIdleHandler(self.SearchFile)
|
||||
except:
|
||||
pass
|
||||
return self._obj_.OnCloseDocument()
|
||||
|
||||
def saveInitParams(self):
|
||||
# Only save the flags, not the text boxes.
|
||||
paramstr = "\t%s\t\t%d\t%d" % (self.filpattern, self.casesensitive, self.recurse)
|
||||
win32ui.WriteProfileVal("Grep", "Params", paramstr)
|
||||
|
||||
def setInitParams(self, paramstr):
|
||||
if paramstr is None:
|
||||
paramstr = win32ui.GetProfileVal("Grep", "Params", '\t\t\t1\t0\t0')
|
||||
params = paramstr.split('\t')
|
||||
if len(params) < 3:
|
||||
params = params + ['']*(3-len(params))
|
||||
if len(params) < 6:
|
||||
params = params + [0]*(6-len(params))
|
||||
self.dirpattern = params[0]
|
||||
self.filpattern = params[1]
|
||||
self.greppattern = params[2]
|
||||
self.casesensitive = int(params[3])
|
||||
self.recurse = int(params[4])
|
||||
self.verbose = int(params[5])
|
||||
# setup some reasonable defaults.
|
||||
if not self.dirpattern:
|
||||
try:
|
||||
editor=win32ui.GetMainFrame().MDIGetActive()[0].GetEditorView()
|
||||
self.dirpattern=os.path.abspath(os.path.dirname(editor.GetDocument().GetPathName()))
|
||||
except (AttributeError, win32ui.error):
|
||||
self.dirpattern = os.getcwd()
|
||||
if not self.filpattern:
|
||||
self.filpattern = "*.py"
|
||||
|
||||
def OnNewDocument(self):
|
||||
if self.dirpattern == '':
|
||||
self.setInitParams(greptemplate.readParams())
|
||||
d = GrepDialog(self.dirpattern, self.filpattern, self.greppattern, self.casesensitive, self.recurse, self.verbose)
|
||||
if d.DoModal() == win32con.IDOK:
|
||||
self.dirpattern = d['dirpattern']
|
||||
self.filpattern = d['filpattern']
|
||||
self.greppattern = d['greppattern']
|
||||
self.casesensitive = d['casesensitive']
|
||||
self.recurse = d['recursive']
|
||||
self.verbose = d['verbose']
|
||||
self.doSearch()
|
||||
self.saveInitParams()
|
||||
return 1
|
||||
return 0 # cancelled - return zero to stop frame creation.
|
||||
|
||||
def doSearch(self):
|
||||
self.dp = dirpath(self.dirpattern, self.recurse)
|
||||
self.SetTitle("Grep for %s in %s" % (self.greppattern, self.filpattern))
|
||||
#self.text = []
|
||||
self.GetFirstView().Append('#Search '+self.dirpattern+'\n')
|
||||
if self.verbose:
|
||||
self.GetFirstView().Append('# ='+repr(self.dp.dirs)+'\n')
|
||||
self.GetFirstView().Append('# Files '+self.filpattern+'\n')
|
||||
self.GetFirstView().Append('# For '+self.greppattern+'\n')
|
||||
self.fplist = self.filpattern.split(';')
|
||||
if self.casesensitive:
|
||||
self.pat = re.compile(self.greppattern)
|
||||
else:
|
||||
self.pat = re.compile(self.greppattern, re.IGNORECASE)
|
||||
win32ui.SetStatusText("Searching. Please wait...", 0)
|
||||
self.dpndx = self.fpndx = 0
|
||||
self.fndx = -1
|
||||
if not self.dp:
|
||||
self.GetFirstView().Append("# ERROR: '%s' does not resolve to any search locations" % self.dirpattern)
|
||||
self.SetModifiedFlag(0)
|
||||
else:
|
||||
self.flist = glob.glob(self.dp[0]+'\\'+self.fplist[0])
|
||||
win32ui.GetApp().AddIdleHandler(self.SearchFile)
|
||||
|
||||
def SearchFile(self, handler, count):
|
||||
self.fndx = self.fndx + 1
|
||||
if self.fndx < len(self.flist):
|
||||
f = self.flist[self.fndx]
|
||||
if self.verbose:
|
||||
self.GetFirstView().Append('# ..'+f+'\n')
|
||||
# Directories may match the file type pattern, and files may be removed
|
||||
# while grep is running
|
||||
if os.path.isfile(f):
|
||||
win32ui.SetStatusText("Searching "+f, 0)
|
||||
lines = open(f, 'r').readlines()
|
||||
for i in range(len(lines)):
|
||||
line = lines[i]
|
||||
if self.pat.search(line) != None:
|
||||
self.GetFirstView().Append(f+'('+repr(i+1) + ') '+line)
|
||||
else:
|
||||
self.fndx = -1
|
||||
self.fpndx = self.fpndx + 1
|
||||
if self.fpndx < len(self.fplist):
|
||||
self.flist = glob.glob(self.dp[self.dpndx] + '\\' + self.fplist[self.fpndx])
|
||||
else:
|
||||
self.fpndx = 0
|
||||
self.dpndx = self.dpndx + 1
|
||||
if self.dpndx < len(self.dp):
|
||||
self.flist = glob.glob(self.dp[self.dpndx] + '\\' + self.fplist[self.fpndx])
|
||||
else:
|
||||
win32ui.SetStatusText("Search complete.", 0)
|
||||
self.SetModifiedFlag(0) # default to not modified.
|
||||
try:
|
||||
win32ui.GetApp().DeleteIdleHandler(self.SearchFile)
|
||||
except:
|
||||
pass
|
||||
return 0
|
||||
return 1
|
||||
|
||||
def GetParams(self):
|
||||
return self.dirpattern+'\t'+self.filpattern+'\t'+self.greppattern+'\t'+repr(self.casesensitive)+'\t'+repr(self.recurse)+'\t'+repr(self.verbose)
|
||||
|
||||
def OnSaveDocument(self, filename):
|
||||
# print 'OnSaveDocument() filename=',filename
|
||||
savefile = open(filename,"wb")
|
||||
txt = self.GetParams()+'\n'
|
||||
# print 'writing',txt
|
||||
savefile.write(txt)
|
||||
savefile.close()
|
||||
self.SetModifiedFlag(0)
|
||||
return 1
|
||||
|
||||
ID_OPEN_FILE = 0xe400
|
||||
ID_GREP = 0xe401
|
||||
ID_SAVERESULTS = 0x402
|
||||
ID_TRYAGAIN = 0x403
|
||||
|
||||
class GrepView(docview.RichEditView):
|
||||
def __init__(self, doc):
|
||||
docview.RichEditView.__init__(self, doc)
|
||||
self.SetWordWrap(win32ui.CRichEditView_WrapNone)
|
||||
self.HookHandlers()
|
||||
|
||||
def OnInitialUpdate(self):
|
||||
rc = self._obj_.OnInitialUpdate()
|
||||
format = (-402653169, 0, 200, 0, 0, 0, 49, 'Courier New')
|
||||
self.SetDefaultCharFormat(format)
|
||||
return rc
|
||||
|
||||
def HookHandlers(self):
|
||||
self.HookMessage(self.OnRClick, win32con.WM_RBUTTONDOWN)
|
||||
self.HookCommand(self.OnCmdOpenFile, ID_OPEN_FILE)
|
||||
self.HookCommand(self.OnCmdGrep, ID_GREP)
|
||||
self.HookCommand(self.OnCmdSave, ID_SAVERESULTS)
|
||||
self.HookCommand(self.OnTryAgain, ID_TRYAGAIN)
|
||||
self.HookMessage(self.OnLDblClick,win32con.WM_LBUTTONDBLCLK)
|
||||
|
||||
def OnLDblClick(self,params):
|
||||
line = self.GetLine()
|
||||
regexGrepResult = regexGrep.match(line)
|
||||
if regexGrepResult:
|
||||
fname = regexGrepResult.group(1)
|
||||
line = int(regexGrepResult.group(2))
|
||||
scriptutils.JumpToDocument(fname, line)
|
||||
return 0 # dont pass on
|
||||
return 1 # pass it on by default.
|
||||
|
||||
def OnRClick(self, params):
|
||||
menu = win32ui.CreatePopupMenu()
|
||||
flags=win32con.MF_STRING|win32con.MF_ENABLED
|
||||
lineno = self._obj_.LineFromChar(-1) #selection or current line
|
||||
line = self._obj_.GetLine(lineno)
|
||||
regexGrepResult = regexGrep.match(line)
|
||||
if regexGrepResult:
|
||||
self.fnm = regexGrepResult.group(1)
|
||||
self.lnnum = int(regexGrepResult.group(2))
|
||||
menu.AppendMenu(flags, ID_OPEN_FILE, "&Open "+self.fnm)
|
||||
menu.AppendMenu(win32con.MF_SEPARATOR)
|
||||
menu.AppendMenu(flags, ID_TRYAGAIN, "&Try Again")
|
||||
charstart, charend = self._obj_.GetSel()
|
||||
if charstart != charend:
|
||||
linestart = self._obj_.LineIndex(lineno)
|
||||
self.sel = line[charstart-linestart:charend-linestart]
|
||||
menu.AppendMenu(flags, ID_GREP, "&Grep for "+self.sel)
|
||||
menu.AppendMenu(win32con.MF_SEPARATOR)
|
||||
menu.AppendMenu(flags, win32ui.ID_EDIT_CUT, 'Cu&t')
|
||||
menu.AppendMenu(flags, win32ui.ID_EDIT_COPY, '&Copy')
|
||||
menu.AppendMenu(flags, win32ui.ID_EDIT_PASTE, '&Paste')
|
||||
menu.AppendMenu(flags, win32con.MF_SEPARATOR);
|
||||
menu.AppendMenu(flags, win32ui.ID_EDIT_SELECT_ALL, '&Select all')
|
||||
menu.AppendMenu(flags, win32con.MF_SEPARATOR);
|
||||
menu.AppendMenu(flags, ID_SAVERESULTS, 'Sa&ve results')
|
||||
menu.TrackPopupMenu(params[5])
|
||||
return 0
|
||||
|
||||
def OnCmdOpenFile(self, cmd, code):
|
||||
doc = win32ui.GetApp().OpenDocumentFile(self.fnm)
|
||||
if doc:
|
||||
vw = doc.GetFirstView()
|
||||
#hope you have an editor that implements GotoLine()!
|
||||
try:
|
||||
vw.GotoLine(int(self.lnnum))
|
||||
except:
|
||||
pass
|
||||
return 0
|
||||
|
||||
def OnCmdGrep(self, cmd, code):
|
||||
curparamsstr = self.GetDocument().GetParams()
|
||||
params = curparamsstr.split('\t')
|
||||
params[2] = self.sel
|
||||
greptemplate.setParams('\t'.join(params))
|
||||
greptemplate.OpenDocumentFile()
|
||||
return 0
|
||||
|
||||
def OnTryAgain(self, cmd, code):
|
||||
greptemplate.setParams(self.GetDocument().GetParams())
|
||||
greptemplate.OpenDocumentFile()
|
||||
return 0
|
||||
|
||||
def OnCmdSave(self, cmd, code):
|
||||
flags = win32con.OFN_OVERWRITEPROMPT
|
||||
dlg = win32ui.CreateFileDialog(0, None, None, flags, "Text Files (*.txt)|*.txt||", self)
|
||||
dlg.SetOFNTitle("Save Results As")
|
||||
if dlg.DoModal() == win32con.IDOK:
|
||||
pn = dlg.GetPathName()
|
||||
self._obj_.SaveTextFile(pn)
|
||||
return 0
|
||||
|
||||
def Append(self, strng):
|
||||
numlines = self.GetLineCount()
|
||||
endpos = self.LineIndex(numlines-1) + len(self.GetLine(numlines-1))
|
||||
self.SetSel(endpos, endpos)
|
||||
self.ReplaceSel(strng)
|
||||
|
||||
|
||||
class GrepDialog(dialog.Dialog):
|
||||
def __init__(self, dp, fp, gp, cs, r, v):
|
||||
style = win32con.DS_MODALFRAME | win32con.WS_POPUP | win32con.WS_VISIBLE | win32con.WS_CAPTION | win32con.WS_SYSMENU | win32con.DS_SETFONT
|
||||
CS = win32con.WS_CHILD | win32con.WS_VISIBLE
|
||||
tmp = [ ["Grep", (0, 0, 210, 90), style, None, (8, "MS Sans Serif")], ]
|
||||
tmp.append([STATIC, "Grep For:", -1, (7, 7, 50, 9), CS ])
|
||||
tmp.append([EDIT, gp, 101, (52, 7, 144, 11), CS | win32con.WS_TABSTOP | win32con.ES_AUTOHSCROLL | win32con.WS_BORDER])
|
||||
tmp.append([STATIC, "Directories:", -1, (7, 20, 50, 9), CS ])
|
||||
tmp.append([EDIT, dp, 102, (52, 20, 128, 11), CS | win32con.WS_TABSTOP | win32con.ES_AUTOHSCROLL | win32con.WS_BORDER])
|
||||
tmp.append([BUTTON, '...', 110, (182,20, 16, 11), CS | win32con.BS_PUSHBUTTON | win32con.WS_TABSTOP])
|
||||
tmp.append([STATIC, "File types:", -1, (7, 33, 50, 9), CS ])
|
||||
tmp.append([EDIT, fp, 103, (52, 33, 128, 11), CS | win32con.WS_TABSTOP | win32con.ES_AUTOHSCROLL | win32con.WS_BORDER ])
|
||||
tmp.append([BUTTON, '...', 111, (182,33, 16, 11), CS | win32con.BS_PUSHBUTTON | win32con.WS_TABSTOP])
|
||||
tmp.append([BUTTON,'Case sensitive', 104, (7, 45, 72, 9), CS | win32con.BS_AUTOCHECKBOX | win32con.BS_LEFTTEXT| win32con.WS_TABSTOP])
|
||||
tmp.append([BUTTON,'Subdirectories', 105, (7, 56, 72, 9), CS | win32con.BS_AUTOCHECKBOX | win32con.BS_LEFTTEXT| win32con.WS_TABSTOP])
|
||||
tmp.append([BUTTON,'Verbose', 106, (7, 67, 72, 9), CS | win32con.BS_AUTOCHECKBOX | win32con.BS_LEFTTEXT| win32con.WS_TABSTOP])
|
||||
tmp.append([BUTTON,'OK', win32con.IDOK, (166,53, 32, 12), CS | win32con.BS_DEFPUSHBUTTON| win32con.WS_TABSTOP])
|
||||
tmp.append([BUTTON,'Cancel', win32con.IDCANCEL, (166,67, 32, 12), CS | win32con.BS_PUSHBUTTON| win32con.WS_TABSTOP])
|
||||
dialog.Dialog.__init__(self, tmp)
|
||||
self.AddDDX(101,'greppattern')
|
||||
self.AddDDX(102,'dirpattern')
|
||||
self.AddDDX(103,'filpattern')
|
||||
self.AddDDX(104,'casesensitive')
|
||||
self.AddDDX(105,'recursive')
|
||||
self.AddDDX(106,'verbose')
|
||||
self._obj_.data['greppattern'] = gp
|
||||
self._obj_.data['dirpattern'] = dp
|
||||
self._obj_.data['filpattern'] = fp
|
||||
self._obj_.data['casesensitive'] = cs
|
||||
self._obj_.data['recursive'] = r
|
||||
self._obj_.data['verbose'] = v
|
||||
self.HookCommand(self.OnMoreDirectories, 110)
|
||||
self.HookCommand(self.OnMoreFiles, 111)
|
||||
|
||||
def OnMoreDirectories(self, cmd, code):
|
||||
self.getMore('Grep\\Directories', 'dirpattern')
|
||||
|
||||
def OnMoreFiles(self, cmd, code):
|
||||
self.getMore('Grep\\File Types', 'filpattern')
|
||||
|
||||
def getMore(self, section, key):
|
||||
self.UpdateData(1)
|
||||
#get the items out of the ini file
|
||||
ini = win32ui.GetProfileFileName()
|
||||
secitems = win32api.GetProfileSection(section, ini)
|
||||
items = []
|
||||
for secitem in secitems:
|
||||
items.append(secitem.split('=')[1])
|
||||
dlg = GrepParamsDialog(items)
|
||||
if dlg.DoModal() == win32con.IDOK:
|
||||
itemstr = ';'.join(dlg.getItems())
|
||||
self._obj_.data[key] = itemstr
|
||||
#update the ini file with dlg.getNew()
|
||||
i = 0
|
||||
newitems = dlg.getNew()
|
||||
if newitems:
|
||||
items = items + newitems
|
||||
for item in items:
|
||||
win32api.WriteProfileVal(section, repr(i), item, ini)
|
||||
i = i + 1
|
||||
self.UpdateData(0)
|
||||
|
||||
def OnOK(self):
|
||||
self.UpdateData(1)
|
||||
for id, name in [(101,'greppattern'), (102,'dirpattern'), (103,'filpattern')]:
|
||||
if not self[name]:
|
||||
self.GetDlgItem(id).SetFocus()
|
||||
win32api.MessageBeep()
|
||||
win32ui.SetStatusText("Please enter a value")
|
||||
return
|
||||
self._obj_.OnOK()
|
||||
|
||||
class GrepParamsDialog(dialog.Dialog):
|
||||
def __init__(self, items):
|
||||
self.items = items
|
||||
self.newitems = []
|
||||
style = win32con.DS_MODALFRAME | win32con.WS_POPUP | win32con.WS_VISIBLE | win32con.WS_CAPTION | win32con.WS_SYSMENU | win32con.DS_SETFONT
|
||||
CS = win32con.WS_CHILD | win32con.WS_VISIBLE
|
||||
tmp = [ ["Grep Parameters", (0, 0, 205, 100), style, None, (8, "MS Sans Serif")], ]
|
||||
tmp.append([LISTBOX, '', 107, (7, 7, 150, 72), CS | win32con.LBS_MULTIPLESEL| win32con.LBS_STANDARD | win32con.LBS_HASSTRINGS | win32con.WS_TABSTOP | win32con.LBS_NOTIFY])
|
||||
tmp.append([BUTTON,'OK', win32con.IDOK, (167, 7, 32, 12), CS | win32con.BS_DEFPUSHBUTTON| win32con.WS_TABSTOP])
|
||||
tmp.append([BUTTON,'Cancel', win32con.IDCANCEL, (167,23, 32, 12), CS | win32con.BS_PUSHBUTTON| win32con.WS_TABSTOP])
|
||||
tmp.append([STATIC,'New:', -1, (2, 83, 15, 12), CS])
|
||||
tmp.append([EDIT, '', 108, (18, 83, 139, 12), CS | win32con.WS_TABSTOP | win32con.ES_AUTOHSCROLL | win32con.WS_BORDER])
|
||||
tmp.append([BUTTON,'Add', 109, (167,83, 32, 12), CS | win32con.BS_PUSHBUTTON| win32con.WS_TABSTOP])
|
||||
dialog.Dialog.__init__(self, tmp)
|
||||
self.HookCommand(self.OnAddItem, 109)
|
||||
self.HookCommand(self.OnListDoubleClick, 107)
|
||||
|
||||
def OnInitDialog(self):
|
||||
lb = self.GetDlgItem(107)
|
||||
for item in self.items:
|
||||
lb.AddString(item)
|
||||
return self._obj_.OnInitDialog()
|
||||
|
||||
def OnAddItem(self, cmd, code):
|
||||
eb = self.GetDlgItem(108)
|
||||
item = eb.GetLine(0)
|
||||
self.newitems.append(item)
|
||||
lb = self.GetDlgItem(107)
|
||||
i = lb.AddString(item)
|
||||
lb.SetSel(i, 1)
|
||||
return 1
|
||||
|
||||
def OnListDoubleClick(self, cmd, code):
|
||||
if code == win32con.LBN_DBLCLK:
|
||||
self.OnOK()
|
||||
return 1
|
||||
|
||||
def OnOK(self):
|
||||
lb = self.GetDlgItem(107)
|
||||
self.selections = lb.GetSelTextItems()
|
||||
self._obj_.OnOK()
|
||||
|
||||
def getItems(self):
|
||||
return self.selections
|
||||
|
||||
def getNew(self):
|
||||
return self.newitems
|
||||
|
||||
try:
|
||||
win32ui.GetApp().RemoveDocTemplate(greptemplate)
|
||||
except NameError:
|
||||
pass
|
||||
|
||||
greptemplate = GrepTemplate()
|
||||
62
Lib/site-packages/pythonwin/pywin/framework/startup.py
Normal file
62
Lib/site-packages/pythonwin/pywin/framework/startup.py
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
# startup.py
|
||||
#
|
||||
"The main application startup code for PythonWin."
|
||||
|
||||
#
|
||||
# This does the basic command line handling.
|
||||
|
||||
# Keep this as short as possible, cos error output is only redirected if
|
||||
# this runs OK. Errors in imported modules are much better - the messages go somewhere (not any more :-)
|
||||
|
||||
import sys
|
||||
import win32ui
|
||||
|
||||
# You may wish to redirect error output somewhere useful if you have startup errors.
|
||||
# eg, 'import win32traceutil' will do this for you.
|
||||
# import win32traceutil # Just uncomment this line to see error output!
|
||||
|
||||
# An old class I used to use - generally only useful if Pythonwin is running under MSVC
|
||||
#class DebugOutput:
|
||||
# softspace=1
|
||||
# def write(self,message):
|
||||
# win32ui.OutputDebug(message)
|
||||
#sys.stderr=sys.stdout=DebugOutput()
|
||||
|
||||
# To fix a problem with Pythonwin when started from the Pythonwin directory,
|
||||
# we update the pywin path to ensure it is absolute.
|
||||
# If it is indeed relative, it will be relative to our current directory.
|
||||
# If its already absolute, then this will have no affect.
|
||||
import pywin, pywin.framework
|
||||
pywin.__path__[0] = win32ui.FullPath(pywin.__path__[0])
|
||||
pywin.framework.__path__[0] = win32ui.FullPath(pywin.framework.__path__[0])
|
||||
|
||||
# make a few wierd sys values. This is so later we can clobber sys.argv to trick
|
||||
# scripts when running under a GUI environment.
|
||||
|
||||
moduleName = "pywin.framework.intpyapp"
|
||||
sys.appargvoffset = 0
|
||||
sys.appargv = sys.argv[:]
|
||||
# Must check for /app param here.
|
||||
if len(sys.argv)>=2 and sys.argv[0].lower()=='/app':
|
||||
from . import cmdline
|
||||
moduleName = cmdline.FixArgFileName(sys.argv[1])
|
||||
sys.appargvoffset = 2
|
||||
newargv=sys.argv[sys.appargvoffset:]
|
||||
# newargv.insert(0, sys.argv[0])
|
||||
sys.argv = newargv
|
||||
|
||||
# Import the application module.
|
||||
__import__(moduleName)
|
||||
|
||||
try:
|
||||
win32ui.GetApp()._obj_
|
||||
# This worked - an app already exists - do nothing more
|
||||
except (AttributeError, win32ui.error):
|
||||
# This means either no app object exists at all, or the one
|
||||
# that does exist does not have a Python class (ie, was created
|
||||
# by the host .EXE). In this case, we do the "old style" init...
|
||||
from . import app
|
||||
if app.AppBuilder is None:
|
||||
raise TypeError("No application object has been registered")
|
||||
|
||||
app.App = app.AppBuilder()
|
||||
173
Lib/site-packages/pythonwin/pywin/framework/stdin.py
Normal file
173
Lib/site-packages/pythonwin/pywin/framework/stdin.py
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
# Copyright (c) 2000 David Abrahams. Permission to copy, use, modify, sell
|
||||
# and distribute this software is granted provided this copyright
|
||||
# notice appears in all copies. This software is provided "as is" without
|
||||
# express or implied warranty, and with no claim as to its suitability for
|
||||
# any purpose.
|
||||
"""Provides a class Stdin which can be used to emulate the regular old
|
||||
sys.stdin for the PythonWin interactive window. Right now it just pops
|
||||
up a raw_input() dialog. With luck, someone will integrate it into the
|
||||
actual PythonWin interactive window someday.
|
||||
|
||||
WARNING: Importing this file automatically replaces sys.stdin with an
|
||||
instance of Stdin (below). This is useful because you can just open
|
||||
Stdin.py in PythonWin and hit the import button to get it set up right
|
||||
if you don't feel like changing PythonWin's source. To put things back
|
||||
the way they were, simply use this magic incantation:
|
||||
import sys
|
||||
sys.stdin = sys.stdin.real_file
|
||||
"""
|
||||
import sys
|
||||
|
||||
try:
|
||||
get_input_line = raw_input # py2x
|
||||
except NameError:
|
||||
get_input_line = input # py3k
|
||||
|
||||
class Stdin:
|
||||
def __init__(self):
|
||||
self.real_file = sys.stdin # NOTE: Likely to be None in py3k
|
||||
self.buffer = ""
|
||||
self.closed = False
|
||||
|
||||
def __getattr__(self, name):
|
||||
"""Forward most functions to the real sys.stdin for absolute realism.
|
||||
"""
|
||||
if self.real_file is None:
|
||||
raise AttributeError(name)
|
||||
return getattr(self.real_file, name)
|
||||
|
||||
def isatty(self):
|
||||
"""Return 1 if the file is connected to a tty(-like) device, else 0.
|
||||
"""
|
||||
return 1
|
||||
|
||||
def read(self, size = -1):
|
||||
"""Read at most size bytes from the file (less if the read
|
||||
hits EOF or no more data is immediately available on a pipe,
|
||||
tty or similar device). If the size argument is negative or
|
||||
omitted, read all data until EOF is reached. The bytes are
|
||||
returned as a string object. An empty string is returned when
|
||||
EOF is encountered immediately. (For certain files, like ttys,
|
||||
it makes sense to continue reading after an EOF is hit.)"""
|
||||
result_size = self.__get_lines(size)
|
||||
return self.__extract_from_buffer(result_size)
|
||||
|
||||
def readline(self, size = -1):
|
||||
"""Read one entire line from the file. A trailing newline
|
||||
character is kept in the string2.6 (but may be absent when a file ends
|
||||
with an incomplete line). If the size argument is present and
|
||||
non-negative, it is a maximum byte count (including the trailing
|
||||
newline) and an incomplete line may be returned. An empty string is
|
||||
returned when EOF is hit immediately. Note: unlike stdio's fgets(),
|
||||
the returned string contains null characters ('\0') if they occurred
|
||||
in the input.
|
||||
"""
|
||||
maximum_result_size = self.__get_lines(size, lambda buffer: '\n' in buffer)
|
||||
|
||||
if '\n' in self.buffer[:maximum_result_size]:
|
||||
result_size = self.buffer.find('\n', 0, maximum_result_size) + 1
|
||||
assert(result_size > 0)
|
||||
else:
|
||||
result_size = maximum_result_size
|
||||
|
||||
return self.__extract_from_buffer(result_size)
|
||||
|
||||
def __extract_from_buffer(self, character_count):
|
||||
"""Remove the first character_count characters from the internal buffer and
|
||||
return them.
|
||||
"""
|
||||
result = self.buffer[:character_count]
|
||||
self.buffer = self.buffer[character_count:]
|
||||
return result
|
||||
|
||||
def __get_lines(self, desired_size, done_reading = lambda buffer: False):
|
||||
"""Keep adding lines to our internal buffer until done_reading(self.buffer)
|
||||
is true or EOF has been reached or we have desired_size bytes in the buffer.
|
||||
If desired_size < 0, we are never satisfied until we reach EOF. If done_reading
|
||||
is not supplied, it is not consulted.
|
||||
|
||||
If desired_size < 0, returns the length of the internal buffer. Otherwise,
|
||||
returns desired_size.
|
||||
"""
|
||||
while not done_reading(self.buffer) and (desired_size < 0
|
||||
or len(self.buffer) < desired_size):
|
||||
try:
|
||||
self.__get_line()
|
||||
except (EOFError, KeyboardInterrupt): # deal with cancellation of get_input_line dialog
|
||||
desired_size = len(self.buffer) # Be satisfied!
|
||||
|
||||
if desired_size < 0:
|
||||
return len(self.buffer)
|
||||
else:
|
||||
return desired_size
|
||||
|
||||
def __get_line(self):
|
||||
"""Grab one line from get_input_line() and append it to the buffer.
|
||||
"""
|
||||
line = get_input_line()
|
||||
print('>>>',line) # echo input to console
|
||||
self.buffer = self.buffer + line + '\n'
|
||||
|
||||
def readlines(self, *sizehint):
|
||||
"""Read until EOF using readline() and return a list containing the lines
|
||||
thus read. If the optional sizehint argument is present, instead of
|
||||
reading up to EOF, whole lines totalling approximately sizehint bytes
|
||||
(possibly after rounding up to an internal buffer size) are read.
|
||||
"""
|
||||
result = []
|
||||
total_read = 0
|
||||
while sizehint == () or total_read < sizehint[0]:
|
||||
line = self.readline()
|
||||
if line == '':
|
||||
break
|
||||
total_read = total_read + len(line)
|
||||
result.append(line)
|
||||
return result
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_input = r"""this is some test
|
||||
input that I am hoping
|
||||
~
|
||||
will be very instructive
|
||||
and when I am done
|
||||
I will have tested everything.
|
||||
Twelve and twenty blackbirds
|
||||
baked in a pie. Patty cake
|
||||
patty cake so am I.
|
||||
~
|
||||
Thirty-five niggling idiots!
|
||||
Sell you soul to the devil, baby
|
||||
"""
|
||||
|
||||
def fake_raw_input(prompt=None):
|
||||
"""Replacement for raw_input() which pulls lines out of global test_input.
|
||||
For testing only!
|
||||
"""
|
||||
global test_input
|
||||
if '\n' not in test_input:
|
||||
end_of_line_pos = len(test_input)
|
||||
else:
|
||||
end_of_line_pos = test_input.find('\n')
|
||||
result = test_input[:end_of_line_pos]
|
||||
test_input = test_input[end_of_line_pos + 1:]
|
||||
if len(result) == 0 or result[0] == '~':
|
||||
raise EOFError()
|
||||
return result
|
||||
|
||||
get_input_line = fake_raw_input
|
||||
|
||||
# Some completely inadequate tests, just to make sure the code's not totally broken
|
||||
try:
|
||||
x = Stdin()
|
||||
print(x.read())
|
||||
print(x.readline())
|
||||
print(x.read(12))
|
||||
print(x.readline(47))
|
||||
print(x.readline(3))
|
||||
print(x.readlines())
|
||||
finally:
|
||||
get_input_line = raw_input
|
||||
else:
|
||||
import sys
|
||||
sys.stdin = Stdin()
|
||||
|
||||
256
Lib/site-packages/pythonwin/pywin/framework/toolmenu.py
Normal file
256
Lib/site-packages/pythonwin/pywin/framework/toolmenu.py
Normal file
|
|
@ -0,0 +1,256 @@
|
|||
# toolmenu.py
|
||||
|
||||
import win32ui
|
||||
import win32con
|
||||
import win32api
|
||||
from . import app
|
||||
import sys
|
||||
import string
|
||||
|
||||
tools = {}
|
||||
idPos = 100
|
||||
|
||||
# The default items should no tools menu exist in the INI file.
|
||||
defaultToolMenuItems = [
|
||||
('Browser', 'win32ui.GetApp().OnViewBrowse(0,0)'),
|
||||
('Browse PythonPath', 'from pywin.tools import browseProjects;browseProjects.Browse()'),
|
||||
('Edit Python Path', 'from pywin.tools import regedit;regedit.EditRegistry()'),
|
||||
('COM Makepy utility', 'from win32com.client import makepy;makepy.main()'),
|
||||
('COM Browser', 'from win32com.client import combrowse;combrowse.main()'),
|
||||
('Trace Collector Debugging tool', 'from pywin.tools import TraceCollector;TraceCollector.MakeOutputWindow()'),
|
||||
]
|
||||
|
||||
def LoadToolMenuItems():
|
||||
# Load from the registry.
|
||||
items = []
|
||||
lookNo = 1
|
||||
while 1:
|
||||
menu = win32ui.GetProfileVal("Tools Menu\\%s" % lookNo, "", "")
|
||||
if menu=="":
|
||||
break
|
||||
cmd = win32ui.GetProfileVal("Tools Menu\\%s" % lookNo, "Command", "")
|
||||
items.append((menu, cmd))
|
||||
lookNo = lookNo + 1
|
||||
|
||||
if len(items)==0:
|
||||
items = defaultToolMenuItems
|
||||
return items
|
||||
|
||||
def WriteToolMenuItems( items ):
|
||||
# Items is a list of (menu, command)
|
||||
# Delete the entire registry tree.
|
||||
try:
|
||||
mainKey = win32ui.GetAppRegistryKey()
|
||||
toolKey = win32api.RegOpenKey(mainKey, "Tools Menu")
|
||||
except win32ui.error:
|
||||
toolKey = None
|
||||
if toolKey is not None:
|
||||
while 1:
|
||||
try:
|
||||
subkey = win32api.RegEnumKey(toolKey, 0)
|
||||
except win32api.error:
|
||||
break
|
||||
win32api.RegDeleteKey(toolKey, subkey)
|
||||
# Keys are now removed - write the new ones.
|
||||
# But first check if we have the defaults - and if so, dont write anything!
|
||||
if items==defaultToolMenuItems:
|
||||
return
|
||||
itemNo = 1
|
||||
for menu, cmd in items:
|
||||
win32ui.WriteProfileVal("Tools Menu\\%s" % itemNo, "", menu)
|
||||
win32ui.WriteProfileVal("Tools Menu\\%s" % itemNo, "Command", cmd)
|
||||
itemNo = itemNo + 1
|
||||
|
||||
def SetToolsMenu(menu, menuPos = None):
|
||||
global tools
|
||||
global idPos
|
||||
|
||||
# todo - check the menu does not already exist.
|
||||
# Create the new menu
|
||||
toolsMenu = win32ui.CreatePopupMenu()
|
||||
|
||||
# Load from the ini file.
|
||||
items = LoadToolMenuItems()
|
||||
for menuString, cmd in items:
|
||||
tools[idPos] = (menuString, cmd, menuString)
|
||||
toolsMenu.AppendMenu(win32con.MF_ENABLED|win32con.MF_STRING,idPos, menuString)
|
||||
win32ui.GetMainFrame().HookCommand(HandleToolCommand, idPos)
|
||||
idPos=idPos+1
|
||||
|
||||
# Find the correct spot to insert the new tools menu.
|
||||
if menuPos is None:
|
||||
menuPos = menu.GetMenuItemCount()-2
|
||||
if menuPos<0: menuPos=0
|
||||
|
||||
menu.InsertMenu(menuPos, win32con.MF_BYPOSITION|win32con.MF_ENABLED|win32con.MF_STRING|win32con.MF_POPUP, toolsMenu.GetHandle(), '&Tools')
|
||||
|
||||
def HandleToolCommand(cmd, code):
|
||||
import traceback
|
||||
import re
|
||||
global tools
|
||||
(menuString, pyCmd, desc) = tools[cmd]
|
||||
win32ui.SetStatusText("Executing tool %s" % desc, 1)
|
||||
pyCmd = re.sub('\\\\n','\n', pyCmd)
|
||||
win32ui.DoWaitCursor(1)
|
||||
oldFlag = None
|
||||
try:
|
||||
oldFlag = sys.stdout.template.writeQueueing
|
||||
sys.stdout.template.writeQueueing = 0
|
||||
except (NameError, AttributeError):
|
||||
pass
|
||||
|
||||
try:
|
||||
exec("%s\n" % pyCmd)
|
||||
worked=1
|
||||
except SystemExit:
|
||||
# The program raised a SystemExit - ignore it.
|
||||
worked = 1
|
||||
except:
|
||||
print("Failed to execute command:\n%s" % pyCmd)
|
||||
traceback.print_exc()
|
||||
worked=0
|
||||
if oldFlag is not None:
|
||||
sys.stdout.template.writeQueueing = oldFlag
|
||||
win32ui.DoWaitCursor(0)
|
||||
if worked:
|
||||
text = "Completed successfully."
|
||||
else:
|
||||
text = "Error executing %s." % desc
|
||||
win32ui.SetStatusText(text, 1)
|
||||
|
||||
# The property page for maintaing the items on the Tools menu.
|
||||
import commctrl
|
||||
from pywin.mfc import dialog
|
||||
|
||||
if win32ui.UNICODE:
|
||||
LVN_ENDLABELEDIT = commctrl.LVN_ENDLABELEDITW
|
||||
else:
|
||||
LVN_ENDLABELEDIT = commctrl.LVN_ENDLABELEDITA
|
||||
|
||||
class ToolMenuPropPage(dialog.PropertyPage):
|
||||
def __init__(self):
|
||||
self.bImChangingEditControls = 0 # Am I programatically changing the controls?
|
||||
dialog.PropertyPage.__init__(self, win32ui.IDD_PP_TOOLMENU)
|
||||
|
||||
def OnInitDialog(self):
|
||||
self.editMenuCommand = self.GetDlgItem(win32ui.IDC_EDIT2)
|
||||
self.butNew = self.GetDlgItem(win32ui.IDC_BUTTON3)
|
||||
|
||||
# Now hook the change notification messages for the edit controls.
|
||||
self.HookCommand(self.OnCommandEditControls, win32ui.IDC_EDIT1)
|
||||
self.HookCommand(self.OnCommandEditControls, win32ui.IDC_EDIT2)
|
||||
|
||||
self.HookNotify(self.OnNotifyListControl, commctrl.LVN_ITEMCHANGED)
|
||||
self.HookNotify(self.OnNotifyListControlEndLabelEdit, commctrl.LVN_ENDLABELEDIT)
|
||||
|
||||
# Hook the button clicks.
|
||||
self.HookCommand(self.OnButtonNew, win32ui.IDC_BUTTON3) # New Item
|
||||
self.HookCommand(self.OnButtonDelete, win32ui.IDC_BUTTON4) # Delete item
|
||||
self.HookCommand(self.OnButtonMove, win32ui.IDC_BUTTON1) # Move up
|
||||
self.HookCommand(self.OnButtonMove, win32ui.IDC_BUTTON2) # Move down
|
||||
|
||||
# Setup the columns in the list control
|
||||
lc = self.GetDlgItem(win32ui.IDC_LIST1)
|
||||
rect = lc.GetWindowRect()
|
||||
cx = rect[2] - rect[0]
|
||||
colSize = cx/2 - win32api.GetSystemMetrics(win32con.SM_CXBORDER) - 1
|
||||
|
||||
item = commctrl.LVCFMT_LEFT, colSize, "Menu Text"
|
||||
lc.InsertColumn(0, item)
|
||||
|
||||
item = commctrl.LVCFMT_LEFT, colSize, "Python Command"
|
||||
lc.InsertColumn(1, item)
|
||||
|
||||
# Insert the existing tools menu
|
||||
itemNo = 0
|
||||
for desc, cmd in LoadToolMenuItems():
|
||||
lc.InsertItem(itemNo, desc)
|
||||
lc.SetItemText(itemNo, 1, cmd)
|
||||
itemNo = itemNo + 1
|
||||
|
||||
self.listControl = lc
|
||||
return dialog.PropertyPage.OnInitDialog(self)
|
||||
|
||||
def OnOK(self):
|
||||
# Write the menu back to the registry.
|
||||
items = []
|
||||
itemLook = 0
|
||||
while 1:
|
||||
try:
|
||||
text = self.listControl.GetItemText(itemLook, 0);
|
||||
if not text:
|
||||
break
|
||||
items.append( (text, self.listControl.GetItemText(itemLook, 1)) )
|
||||
except win32ui.error:
|
||||
# no more items!
|
||||
break
|
||||
itemLook = itemLook + 1
|
||||
WriteToolMenuItems( items )
|
||||
return self._obj_.OnOK()
|
||||
|
||||
def OnCommandEditControls(self, id, cmd):
|
||||
# print "OnEditControls", id, cmd
|
||||
if cmd==win32con.EN_CHANGE and not self.bImChangingEditControls:
|
||||
itemNo = self.listControl.GetNextItem(-1, commctrl.LVNI_SELECTED)
|
||||
newText = self.editMenuCommand.GetWindowText()
|
||||
self.listControl.SetItemText(itemNo, 1, newText)
|
||||
|
||||
return 0
|
||||
|
||||
def OnNotifyListControlEndLabelEdit(self, id, cmd):
|
||||
newText = self.listControl.GetEditControl().GetWindowText()
|
||||
itemNo = self.listControl.GetNextItem(-1, commctrl.LVNI_SELECTED)
|
||||
self.listControl.SetItemText(itemNo, 0, newText)
|
||||
|
||||
def OnNotifyListControl(self, id, cmd):
|
||||
# print id, cmd
|
||||
try:
|
||||
itemNo = self.listControl.GetNextItem(-1, commctrl.LVNI_SELECTED)
|
||||
except win32ui.error: # No selection!
|
||||
return
|
||||
|
||||
self.bImChangingEditControls = 1
|
||||
try:
|
||||
item = self.listControl.GetItem(itemNo, 1)
|
||||
self.editMenuCommand.SetWindowText(item[4])
|
||||
finally:
|
||||
self.bImChangingEditControls = 0
|
||||
|
||||
return 0 # we have handled this!
|
||||
|
||||
def OnButtonNew(self, id, cmd):
|
||||
if cmd==win32con.BN_CLICKED:
|
||||
newIndex = self.listControl.GetItemCount()
|
||||
self.listControl.InsertItem(newIndex, "Click to edit the text")
|
||||
self.listControl.EnsureVisible(newIndex, 0)
|
||||
|
||||
def OnButtonMove(self, id, cmd):
|
||||
if cmd==win32con.BN_CLICKED:
|
||||
try:
|
||||
itemNo = self.listControl.GetNextItem(-1, commctrl.LVNI_SELECTED)
|
||||
except win32ui.error:
|
||||
return
|
||||
menu = self.listControl.GetItemText(itemNo, 0)
|
||||
cmd = self.listControl.GetItemText(itemNo, 1)
|
||||
if id == win32ui.IDC_BUTTON1:
|
||||
# Move up
|
||||
if itemNo > 0:
|
||||
self.listControl.DeleteItem(itemNo)
|
||||
# reinsert it.
|
||||
self.listControl.InsertItem(itemNo-1, menu)
|
||||
self.listControl.SetItemText(itemNo-1, 1, cmd)
|
||||
else:
|
||||
# Move down.
|
||||
if itemNo < self.listControl.GetItemCount()-1:
|
||||
self.listControl.DeleteItem(itemNo)
|
||||
# reinsert it.
|
||||
self.listControl.InsertItem(itemNo+1, menu)
|
||||
self.listControl.SetItemText(itemNo+1, 1, cmd)
|
||||
|
||||
def OnButtonDelete(self, id, cmd):
|
||||
if cmd==win32con.BN_CLICKED:
|
||||
try:
|
||||
itemNo = self.listControl.GetNextItem(-1, commctrl.LVNI_SELECTED)
|
||||
except win32ui.error: # No selection!
|
||||
return
|
||||
self.listControl.DeleteItem(itemNo)
|
||||
13
Lib/site-packages/pythonwin/pywin/framework/window.py
Normal file
13
Lib/site-packages/pythonwin/pywin/framework/window.py
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
# Framework Window classes.
|
||||
|
||||
# Most Pythonwin windows should use these classes rather than
|
||||
# the raw MFC ones if they want Pythonwin specific functionality.
|
||||
import pywin.mfc.window
|
||||
import win32con
|
||||
|
||||
class MDIChildWnd(pywin.mfc.window.MDIChildWnd):
|
||||
def AutoRestore(self):
|
||||
"If the window is minimised or maximised, restore it."
|
||||
p = self.GetWindowPlacement()
|
||||
if p[1]==win32con.SW_MINIMIZE or p[1]==win32con.SW_SHOWMINIMIZED:
|
||||
self.SetWindowPlacement(p[0], win32con.SW_RESTORE, p[2], p[3], p[4])
|
||||
518
Lib/site-packages/pythonwin/pywin/framework/winout.py
Normal file
518
Lib/site-packages/pythonwin/pywin/framework/winout.py
Normal file
|
|
@ -0,0 +1,518 @@
|
|||
# winout.py
|
||||
#
|
||||
# generic "output window"
|
||||
#
|
||||
# This Window will detect itself closing, and recreate next time output is
|
||||
# written to it.
|
||||
|
||||
# This has the option of writing output at idle time (by hooking the
|
||||
# idle message, and queueing output) or writing as each
|
||||
# write is executed.
|
||||
# Updating the window directly gives a jerky appearance as many writes
|
||||
# take place between commands, and the windows scrolls, and updates etc
|
||||
# Updating at idle-time may defer all output of a long process, giving the
|
||||
# appearence nothing is happening.
|
||||
# There is a compromise "line" mode, which will output whenever
|
||||
# a complete line is available.
|
||||
|
||||
# behaviour depends on self.writeQueueing
|
||||
|
||||
# This module is thread safe - output can originate from any thread. If any thread
|
||||
# other than the main thread attempts to print, it is always queued until next idle time
|
||||
|
||||
import sys, string, re
|
||||
from pywin.mfc import docview
|
||||
from pywin.framework import app, window
|
||||
import win32ui, win32api, win32con
|
||||
import queue
|
||||
|
||||
debug = lambda msg: None
|
||||
|
||||
##debug=win32ui.OutputDebugString
|
||||
##import win32trace;win32trace.InitWrite() # for debugging - delete me!
|
||||
##debug = win32trace.write
|
||||
|
||||
class flags:
|
||||
# queueing of output.
|
||||
WQ_NONE = 0
|
||||
WQ_LINE = 1
|
||||
WQ_IDLE = 2
|
||||
|
||||
#WindowOutputDocumentParent=docview.RichEditDoc
|
||||
#WindowOutputDocumentParent=docview.Document
|
||||
import pywin.scintilla.document
|
||||
from pywin.scintilla import scintillacon
|
||||
from pywin import default_scintilla_encoding
|
||||
|
||||
WindowOutputDocumentParent=pywin.scintilla.document.CScintillaDocument
|
||||
class WindowOutputDocument(WindowOutputDocumentParent):
|
||||
def SaveModified(self):
|
||||
return 1 # say it is OK to destroy my document
|
||||
|
||||
def OnSaveDocument( self, fileName ):
|
||||
win32ui.SetStatusText("Saving file...",1)
|
||||
try:
|
||||
self.SaveFile(fileName)
|
||||
except IOError as details:
|
||||
win32ui.MessageBox("Error - could not save file\r\n\r\n%s"%details)
|
||||
return 0
|
||||
win32ui.SetStatusText("Ready")
|
||||
return 1
|
||||
|
||||
class WindowOutputFrame(window.MDIChildWnd):
|
||||
def __init__(self, wnd = None):
|
||||
window.MDIChildWnd.__init__(self, wnd)
|
||||
self.HookMessage(self.OnSizeMove, win32con.WM_SIZE)
|
||||
self.HookMessage(self.OnSizeMove, win32con.WM_MOVE)
|
||||
|
||||
def LoadFrame( self, idResource, style, wndParent, context ):
|
||||
self.template = context.template
|
||||
return self._obj_.LoadFrame(idResource, style, wndParent, context)
|
||||
|
||||
def PreCreateWindow(self, cc):
|
||||
cc = self._obj_.PreCreateWindow(cc)
|
||||
if self.template.defSize and self.template.defSize[0] != self.template.defSize[1]:
|
||||
rect = app.RectToCreateStructRect(self.template.defSize)
|
||||
cc = cc[0], cc[1], cc[2], cc[3], rect, cc[5], cc[6], cc[7], cc[8]
|
||||
return cc
|
||||
def OnSizeMove(self, msg):
|
||||
# so recreate maintains position.
|
||||
# Need to map coordinates from the
|
||||
# frame windows first child.
|
||||
mdiClient = self.GetParent()
|
||||
self.template.defSize = mdiClient.ScreenToClient(self.GetWindowRect())
|
||||
def OnDestroy(self, message):
|
||||
self.template.OnFrameDestroy(self)
|
||||
return 1
|
||||
|
||||
class WindowOutputViewImpl:
|
||||
def __init__(self):
|
||||
self.patErrorMessage=re.compile('\W*File "(.*)", line ([0-9]+)')
|
||||
self.template = self.GetDocument().GetDocTemplate()
|
||||
|
||||
def HookHandlers(self):
|
||||
# Hook for the right-click menu.
|
||||
self.HookMessage(self.OnRClick,win32con.WM_RBUTTONDOWN)
|
||||
|
||||
def OnDestroy(self, msg):
|
||||
self.template.OnViewDestroy(self)
|
||||
|
||||
def OnInitialUpdate(self):
|
||||
self.RestoreKillBuffer()
|
||||
self.SetSel(-2) # end of buffer
|
||||
|
||||
def GetRightMenuItems(self):
|
||||
ret = []
|
||||
flags=win32con.MF_STRING|win32con.MF_ENABLED
|
||||
ret.append((flags, win32ui.ID_EDIT_COPY, '&Copy'))
|
||||
ret.append((flags, win32ui.ID_EDIT_SELECT_ALL, '&Select all'))
|
||||
return ret
|
||||
|
||||
#
|
||||
# Windows command handlers, virtuals, etc.
|
||||
#
|
||||
def OnRClick(self,params):
|
||||
paramsList = self.GetRightMenuItems()
|
||||
menu = win32ui.CreatePopupMenu()
|
||||
for appendParams in paramsList:
|
||||
if type(appendParams)!=type(()):
|
||||
appendParams = (appendParams,)
|
||||
menu.AppendMenu(*appendParams)
|
||||
menu.TrackPopupMenu(params[5]) # track at mouse position.
|
||||
return 0
|
||||
|
||||
# as this is often used as an output window, exeptions will often
|
||||
# be printed. Therefore, we support this functionality at this level.
|
||||
# Returns TRUE if the current line is an error message line, and will
|
||||
# jump to it. FALSE if no error (and no action taken)
|
||||
def HandleSpecialLine(self):
|
||||
from . import scriptutils
|
||||
line = self.GetLine()
|
||||
if line[:11]=="com_error: ":
|
||||
# An OLE Exception - pull apart the exception
|
||||
# and try and locate a help file.
|
||||
try:
|
||||
import win32api, win32con
|
||||
det = eval(line[line.find(":")+1:].strip())
|
||||
win32ui.SetStatusText("Opening help file on OLE error...");
|
||||
from . import help
|
||||
help.OpenHelpFile(det[2][3],win32con.HELP_CONTEXT, det[2][4])
|
||||
return 1
|
||||
except win32api.error as details:
|
||||
win32ui.SetStatusText("The help file could not be opened - %s" % details.strerror)
|
||||
return 1
|
||||
except:
|
||||
win32ui.SetStatusText("Line is a COM error, but no WinHelp details can be parsed");
|
||||
# Look for a Python traceback.
|
||||
matchResult = self.patErrorMessage.match(line)
|
||||
if matchResult is None:
|
||||
# No match - try the previous line
|
||||
lineNo = self.LineFromChar()
|
||||
if lineNo > 0:
|
||||
line = self.GetLine(lineNo-1)
|
||||
matchResult = self.patErrorMessage.match(line)
|
||||
if matchResult is not None:
|
||||
# we have an error line.
|
||||
fileName = matchResult.group(1)
|
||||
if fileName[0]=="<":
|
||||
win32ui.SetStatusText("Can not load this file")
|
||||
return 1 # still was an error message.
|
||||
else:
|
||||
lineNoString = matchResult.group(2)
|
||||
# Attempt to locate the file (in case it is a relative spec)
|
||||
fileNameSpec = fileName
|
||||
fileName = scriptutils.LocatePythonFile(fileName)
|
||||
if fileName is None:
|
||||
# Dont force update, so it replaces the idle prompt.
|
||||
win32ui.SetStatusText("Cant locate the file '%s'" % (fileNameSpec), 0)
|
||||
return 1
|
||||
|
||||
win32ui.SetStatusText("Jumping to line "+lineNoString+" of file "+fileName,1)
|
||||
if not scriptutils.JumpToDocument(fileName, int(lineNoString)):
|
||||
win32ui.SetStatusText("Could not open %s" % fileName)
|
||||
return 1 # still was an error message.
|
||||
return 1
|
||||
return 0 # not an error line
|
||||
def write(self, msg):
|
||||
return self.template.write(msg)
|
||||
def writelines(self, lines):
|
||||
for line in lines:
|
||||
self.write(line)
|
||||
def flush(self):
|
||||
self.template.flush()
|
||||
|
||||
class WindowOutputViewRTF(docview.RichEditView, WindowOutputViewImpl):
|
||||
def __init__(self, doc):
|
||||
docview.RichEditView.__init__(self, doc)
|
||||
WindowOutputViewImpl.__init__(self)
|
||||
|
||||
def OnInitialUpdate(self):
|
||||
WindowOutputViewImpl.OnInitialUpdate(self)
|
||||
return docview.RichEditView.OnInitialUpdate(self)
|
||||
|
||||
def OnDestroy(self, msg):
|
||||
WindowOutputViewImpl.OnDestroy(self, msg)
|
||||
docview.RichEditView.OnDestroy(self, msg)
|
||||
|
||||
def HookHandlers(self):
|
||||
WindowOutputViewImpl.HookHandlers(self)
|
||||
# Hook for finding and locating error messages
|
||||
self.HookMessage(self.OnLDoubleClick,win32con.WM_LBUTTONDBLCLK)
|
||||
# docview.RichEditView.HookHandlers(self)
|
||||
|
||||
def OnLDoubleClick(self,params):
|
||||
if self.HandleSpecialLine():
|
||||
return 0 # dont pass on
|
||||
return 1 # pass it on by default.
|
||||
|
||||
def RestoreKillBuffer(self):
|
||||
if len(self.template.killBuffer):
|
||||
self.StreamIn(win32con.SF_RTF, self._StreamRTFIn)
|
||||
self.template.killBuffer = []
|
||||
|
||||
def SaveKillBuffer(self):
|
||||
self.StreamOut(win32con.SF_RTFNOOBJS, self._StreamRTFOut)
|
||||
|
||||
def _StreamRTFOut(self, data):
|
||||
self.template.killBuffer.append(data)
|
||||
return 1 # keep em coming!
|
||||
|
||||
def _StreamRTFIn(self, bytes):
|
||||
try:
|
||||
item = self.template.killBuffer[0]
|
||||
self.template.killBuffer.remove(item)
|
||||
if bytes < len(item):
|
||||
print("Warning - output buffer not big enough!")
|
||||
return item
|
||||
except IndexError:
|
||||
return None
|
||||
def dowrite(self, str):
|
||||
self.SetSel(-2)
|
||||
self.ReplaceSel(str)
|
||||
|
||||
import pywin.scintilla.view
|
||||
class WindowOutputViewScintilla(pywin.scintilla.view.CScintillaView, WindowOutputViewImpl):
|
||||
def __init__(self, doc):
|
||||
pywin.scintilla.view.CScintillaView.__init__(self, doc)
|
||||
WindowOutputViewImpl.__init__(self)
|
||||
|
||||
def OnInitialUpdate(self):
|
||||
pywin.scintilla.view.CScintillaView.OnInitialUpdate(self)
|
||||
self.SCISetMarginWidth(3)
|
||||
WindowOutputViewImpl.OnInitialUpdate(self)
|
||||
|
||||
def OnDestroy(self, msg):
|
||||
WindowOutputViewImpl.OnDestroy(self, msg)
|
||||
pywin.scintilla.view.CScintillaView.OnDestroy(self, msg)
|
||||
|
||||
def HookHandlers(self):
|
||||
WindowOutputViewImpl.HookHandlers(self)
|
||||
pywin.scintilla.view.CScintillaView.HookHandlers(self)
|
||||
self.GetParent().HookNotify(self.OnScintillaDoubleClick, scintillacon.SCN_DOUBLECLICK)
|
||||
## self.HookMessage(self.OnLDoubleClick,win32con.WM_LBUTTONDBLCLK)
|
||||
|
||||
def OnScintillaDoubleClick(self, std, extra):
|
||||
self.HandleSpecialLine()
|
||||
|
||||
## def OnLDoubleClick(self,params):
|
||||
## return 0 # never dont pass on
|
||||
|
||||
def RestoreKillBuffer(self):
|
||||
assert len(self.template.killBuffer) in [0,1], "Unexpected killbuffer contents"
|
||||
if self.template.killBuffer:
|
||||
self.SCIAddText(self.template.killBuffer[0])
|
||||
self.template.killBuffer = []
|
||||
def SaveKillBuffer(self):
|
||||
self.template.killBuffer = [self.GetTextRange(0,-1)]
|
||||
def dowrite(self, str):
|
||||
end = self.GetTextLength()
|
||||
atEnd = end==self.GetSel()[0]
|
||||
self.SCIInsertText(str, end)
|
||||
if atEnd:
|
||||
self.SetSel(self.GetTextLength())
|
||||
|
||||
def SetWordWrap(self, bWrapOn = 1):
|
||||
if bWrapOn:
|
||||
wrap_mode = scintillacon.SC_WRAP_WORD
|
||||
else:
|
||||
wrap_mode = scintillacon.SC_WRAP_NONE
|
||||
self.SCISetWrapMode(wrap_mode)
|
||||
|
||||
def _MakeColorizer(self):
|
||||
return None # No colorizer for me!
|
||||
|
||||
WindowOutputView = WindowOutputViewScintilla
|
||||
# The WindowOutput class is actually an MFC template. This is a conventient way of
|
||||
# making sure that my state can exist beyond the life of the windows themselves.
|
||||
# This is primarily to support the functionality of a WindowOutput window automatically
|
||||
# being recreated if necessary when written to.
|
||||
class WindowOutput(docview.DocTemplate):
|
||||
""" Looks like a general Output Window - text can be written by the 'write' method.
|
||||
Will auto-create itself on first write, and also on next write after being closed """
|
||||
softspace=1
|
||||
def __init__(self, title=None, defSize=None, queueing = flags.WQ_LINE, \
|
||||
bAutoRestore = 1, style=None,
|
||||
makeDoc = None, makeFrame = None, makeView = None):
|
||||
""" init the output window -
|
||||
Params
|
||||
title=None -- What is the title of the window
|
||||
defSize=None -- What is the default size for the window - if this
|
||||
is a string, the size will be loaded from the ini file.
|
||||
queueing = flags.WQ_LINE -- When should output be written
|
||||
bAutoRestore=1 -- Should a minimized window be restored.
|
||||
style -- Style for Window, or None for default.
|
||||
makeDoc, makeFrame, makeView -- Classes for frame, view and window respectively.
|
||||
"""
|
||||
if makeDoc is None: makeDoc = WindowOutputDocument
|
||||
if makeFrame is None: makeFrame = WindowOutputFrame
|
||||
if makeView is None: makeView = WindowOutputViewScintilla
|
||||
docview.DocTemplate.__init__(self, win32ui.IDR_PYTHONTYPE, \
|
||||
makeDoc, makeFrame, makeView)
|
||||
self.SetDocStrings("\nOutput\n\nText Documents (*.txt)\n.txt\n\n\n")
|
||||
win32ui.GetApp().AddDocTemplate(self)
|
||||
self.writeQueueing = queueing
|
||||
self.errorCantRecreate = 0
|
||||
self.killBuffer=[]
|
||||
self.style = style
|
||||
self.bAutoRestore = bAutoRestore
|
||||
self.title = title
|
||||
self.bCreating = 0
|
||||
self.interruptCount = 0
|
||||
if type(defSize)==type(''): # is a string - maintain size pos from ini file.
|
||||
self.iniSizeSection = defSize
|
||||
self.defSize = app.LoadWindowSize(defSize)
|
||||
self.loadedSize = self.defSize
|
||||
else:
|
||||
self.iniSizeSection = None
|
||||
self.defSize=defSize
|
||||
self.currentView = None
|
||||
self.outputQueue = queue.Queue(-1)
|
||||
self.mainThreadId = win32api.GetCurrentThreadId()
|
||||
self.idleHandlerSet = 0
|
||||
self.SetIdleHandler()
|
||||
|
||||
def __del__(self):
|
||||
self.Close()
|
||||
|
||||
def Create(self, title=None, style = None):
|
||||
self.bCreating = 1
|
||||
if title: self.title = title
|
||||
if style: self.style = style
|
||||
doc=self.OpenDocumentFile()
|
||||
if doc is None: return
|
||||
self.currentView = doc.GetFirstView()
|
||||
self.bCreating = 0
|
||||
if self.title: doc.SetTitle(self.title)
|
||||
|
||||
def Close(self):
|
||||
self.RemoveIdleHandler()
|
||||
try:
|
||||
parent = self.currentView.GetParent()
|
||||
except (AttributeError, win32ui.error): # Already closed
|
||||
return
|
||||
parent.DestroyWindow()
|
||||
|
||||
def SetTitle(self, title):
|
||||
self.title = title
|
||||
if self.currentView: self.currentView.GetDocument().SetTitle(self.title)
|
||||
|
||||
def OnViewDestroy(self, view):
|
||||
self.currentView.SaveKillBuffer()
|
||||
self.currentView = None
|
||||
|
||||
def OnFrameDestroy(self, frame):
|
||||
if self.iniSizeSection:
|
||||
# use GetWindowPlacement(), as it works even when min'd or max'd
|
||||
newSize = frame.GetWindowPlacement()[4]
|
||||
if self.loadedSize!=newSize:
|
||||
app.SaveWindowSize(self.iniSizeSection, newSize)
|
||||
|
||||
def SetIdleHandler(self):
|
||||
if not self.idleHandlerSet:
|
||||
debug("Idle handler set\n")
|
||||
win32ui.GetApp().AddIdleHandler(self.QueueIdleHandler)
|
||||
self.idleHandlerSet = 1
|
||||
|
||||
def RemoveIdleHandler(self):
|
||||
if self.idleHandlerSet:
|
||||
debug("Idle handler reset\n")
|
||||
if (win32ui.GetApp().DeleteIdleHandler(self.QueueIdleHandler)==0):
|
||||
debug('Error deleting idle handler\n')
|
||||
self.idleHandlerSet = 0
|
||||
|
||||
def RecreateWindow(self):
|
||||
if self.errorCantRecreate:
|
||||
debug("Error = not trying again")
|
||||
return 0
|
||||
try:
|
||||
# This will fail if app shutting down
|
||||
win32ui.GetMainFrame().GetSafeHwnd()
|
||||
self.Create()
|
||||
return 1
|
||||
except (win32ui.error, AttributeError):
|
||||
self.errorCantRecreate = 1
|
||||
debug("Winout can not recreate the Window!\n")
|
||||
return 0
|
||||
|
||||
# this handles the idle message, and does the printing.
|
||||
def QueueIdleHandler(self,handler,count):
|
||||
try:
|
||||
bEmpty = self.QueueFlush(20)
|
||||
# If the queue is empty, then we are back to idle and restart interrupt logic.
|
||||
if bEmpty: self.interruptCount = 0
|
||||
except KeyboardInterrupt:
|
||||
# First interrupt since idle we just pass on.
|
||||
# later ones we dump the queue and give up.
|
||||
self.interruptCount = self.interruptCount + 1
|
||||
if self.interruptCount > 1:
|
||||
# Drop the queue quickly as the user is already annoyed :-)
|
||||
self.outputQueue = queue.Queue(-1)
|
||||
print("Interrupted.")
|
||||
bEmpty = 1
|
||||
else:
|
||||
raise # re-raise the error so the users exception filters up.
|
||||
return not bEmpty # More to do if not empty.
|
||||
|
||||
# Returns true if the Window needs to be recreated.
|
||||
def NeedRecreateWindow(self):
|
||||
try:
|
||||
if self.currentView is not None and self.currentView.IsWindow():
|
||||
return 0
|
||||
except (win32ui.error, AttributeError): # Attribute error if the win32ui object has died.
|
||||
pass
|
||||
return 1
|
||||
|
||||
# Returns true if the Window is OK (either cos it was, or because it was recreated
|
||||
def CheckRecreateWindow(self):
|
||||
if self.bCreating: return 1
|
||||
if not self.NeedRecreateWindow():
|
||||
return 1
|
||||
if self.bAutoRestore:
|
||||
if self.RecreateWindow():
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def QueueFlush(self, max = None):
|
||||
# Returns true if the queue is empty after the flush
|
||||
# debug("Queueflush - %d, %d\n" % (max, self.outputQueue.qsize()))
|
||||
if self.bCreating: return 1
|
||||
items = []
|
||||
rc = 0
|
||||
while max is None or max > 0:
|
||||
try:
|
||||
item = self.outputQueue.get_nowait()
|
||||
items.append(item)
|
||||
except queue.Empty:
|
||||
rc = 1
|
||||
break
|
||||
if max is not None:
|
||||
max = max - 1
|
||||
if len(items) != 0:
|
||||
if not self.CheckRecreateWindow():
|
||||
debug(":Recreate failed!\n")
|
||||
return 1 # In trouble - so say we have nothing to do.
|
||||
win32ui.PumpWaitingMessages() # Pump paint messages
|
||||
self.currentView.dowrite(''.join(items))
|
||||
return rc
|
||||
|
||||
def HandleOutput(self,message):
|
||||
# debug("QueueOutput on thread %d, flags %d with '%s'...\n" % (win32api.GetCurrentThreadId(), self.writeQueueing, message ))
|
||||
self.outputQueue.put(message)
|
||||
if win32api.GetCurrentThreadId() != self.mainThreadId:
|
||||
pass
|
||||
# debug("not my thread - ignoring queue options!\n")
|
||||
elif self.writeQueueing==flags.WQ_LINE:
|
||||
pos = message.rfind('\n')
|
||||
if pos>=0:
|
||||
# debug("Line queueing - forcing flush\n")
|
||||
self.QueueFlush()
|
||||
return
|
||||
elif self.writeQueueing==flags.WQ_NONE:
|
||||
# debug("WQ_NONE - flushing!\n")
|
||||
self.QueueFlush()
|
||||
return
|
||||
# Let our idle handler get it - wake it up
|
||||
try:
|
||||
win32ui.GetMainFrame().PostMessage(win32con.WM_USER) # Kick main thread off.
|
||||
except win32ui.error:
|
||||
# This can happen as the app is shutting down, so we send it to the C++ debugger
|
||||
win32api.OutputDebugString(message)
|
||||
|
||||
# delegate certain fns to my view.
|
||||
def writelines(self, lines):
|
||||
for line in lines:
|
||||
self.write(line)
|
||||
|
||||
def write(self,message):
|
||||
self.HandleOutput(message)
|
||||
|
||||
def flush(self):
|
||||
self.QueueFlush()
|
||||
|
||||
def HandleSpecialLine(self):
|
||||
self.currentView.HandleSpecialLine()
|
||||
|
||||
def RTFWindowOutput(*args, **kw):
|
||||
kw['makeView'] = WindowOutputViewRTF
|
||||
return WindowOutput(*args, **kw)
|
||||
|
||||
|
||||
def thread_test(o):
|
||||
for i in range(5):
|
||||
o.write("Hi from thread %d\n" % (win32api.GetCurrentThreadId()))
|
||||
win32api.Sleep(100)
|
||||
|
||||
def test():
|
||||
w = WindowOutput(queueing=flags.WQ_IDLE)
|
||||
w.write("First bit of text\n")
|
||||
import _thread
|
||||
for i in range(5):
|
||||
w.write("Hello from the main thread\n")
|
||||
_thread.start_new(thread_test, (w,))
|
||||
for i in range(2):
|
||||
w.write("Hello from the main thread\n")
|
||||
win32api.Sleep(50)
|
||||
return w
|
||||
|
||||
if __name__=='__main__':
|
||||
test()
|
||||
92
Lib/site-packages/pythonwin/pywin/idle/AutoExpand.py
Normal file
92
Lib/site-packages/pythonwin/pywin/idle/AutoExpand.py
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
import string
|
||||
import re
|
||||
|
||||
###$ event <<expand-word>>
|
||||
###$ win <Alt-slash>
|
||||
###$ unix <Alt-slash>
|
||||
|
||||
class AutoExpand:
|
||||
|
||||
keydefs = {
|
||||
'<<expand-word>>': ['<Alt-slash>'],
|
||||
}
|
||||
|
||||
unix_keydefs = {
|
||||
'<<expand-word>>': ['<Meta-slash>'],
|
||||
}
|
||||
|
||||
menudefs = [
|
||||
('edit', [
|
||||
('E_xpand word', '<<expand-word>>'),
|
||||
]),
|
||||
]
|
||||
|
||||
wordchars = string.ascii_letters + string.digits + "_"
|
||||
|
||||
def __init__(self, editwin):
|
||||
self.text = editwin.text
|
||||
self.text.wordlist = None # XXX what is this?
|
||||
self.state = None
|
||||
|
||||
def expand_word_event(self, event):
|
||||
curinsert = self.text.index("insert")
|
||||
curline = self.text.get("insert linestart", "insert lineend")
|
||||
if not self.state:
|
||||
words = self.getwords()
|
||||
index = 0
|
||||
else:
|
||||
words, index, insert, line = self.state
|
||||
if insert != curinsert or line != curline:
|
||||
words = self.getwords()
|
||||
index = 0
|
||||
if not words:
|
||||
self.text.bell()
|
||||
return "break"
|
||||
word = self.getprevword()
|
||||
self.text.delete("insert - %d chars" % len(word), "insert")
|
||||
newword = words[index]
|
||||
index = (index + 1) % len(words)
|
||||
if index == 0:
|
||||
self.text.bell() # Warn we cycled around
|
||||
self.text.insert("insert", newword)
|
||||
curinsert = self.text.index("insert")
|
||||
curline = self.text.get("insert linestart", "insert lineend")
|
||||
self.state = words, index, curinsert, curline
|
||||
return "break"
|
||||
|
||||
def getwords(self):
|
||||
word = self.getprevword()
|
||||
if not word:
|
||||
return []
|
||||
before = self.text.get("1.0", "insert wordstart")
|
||||
wbefore = re.findall(r"\b" + word + r"\w+\b", before)
|
||||
del before
|
||||
after = self.text.get("insert wordend", "end")
|
||||
wafter = re.findall(r"\b" + word + r"\w+\b", after)
|
||||
del after
|
||||
if not wbefore and not wafter:
|
||||
return []
|
||||
words = []
|
||||
dict = {}
|
||||
# search backwards through words before
|
||||
wbefore.reverse()
|
||||
for w in wbefore:
|
||||
if dict.get(w):
|
||||
continue
|
||||
words.append(w)
|
||||
dict[w] = w
|
||||
# search onwards through words after
|
||||
for w in wafter:
|
||||
if dict.get(w):
|
||||
continue
|
||||
words.append(w)
|
||||
dict[w] = w
|
||||
words.append(word)
|
||||
return words
|
||||
|
||||
def getprevword(self):
|
||||
line = self.text.get("insert linestart", "insert")
|
||||
i = len(line)
|
||||
while i > 0 and line[i-1] in self.wordchars:
|
||||
i = i-1
|
||||
return line[i:]
|
||||
529
Lib/site-packages/pythonwin/pywin/idle/AutoIndent.py
Normal file
529
Lib/site-packages/pythonwin/pywin/idle/AutoIndent.py
Normal file
|
|
@ -0,0 +1,529 @@
|
|||
import sys
|
||||
import string, tokenize
|
||||
from . import PyParse
|
||||
from pywin import default_scintilla_encoding
|
||||
|
||||
if sys.version_info < (3,):
|
||||
# in py2k, tokenize() takes a 'token eater' callback, while
|
||||
# generate_tokens is a generator that works with str objects.
|
||||
token_generator = tokenize.generate_tokens
|
||||
else:
|
||||
# in py3k tokenize() is the generator working with 'byte' objects, and
|
||||
# token_generator is the 'undocumented b/w compat' function that
|
||||
# theoretically works with str objects - but actually seems to fail)
|
||||
token_generator = tokenize.tokenize
|
||||
|
||||
class AutoIndent:
|
||||
|
||||
menudefs = [
|
||||
('edit', [
|
||||
None,
|
||||
('_Indent region', '<<indent-region>>'),
|
||||
('_Dedent region', '<<dedent-region>>'),
|
||||
('Comment _out region', '<<comment-region>>'),
|
||||
('U_ncomment region', '<<uncomment-region>>'),
|
||||
('Tabify region', '<<tabify-region>>'),
|
||||
('Untabify region', '<<untabify-region>>'),
|
||||
('Toggle tabs', '<<toggle-tabs>>'),
|
||||
('New indent width', '<<change-indentwidth>>'),
|
||||
]),
|
||||
]
|
||||
|
||||
keydefs = {
|
||||
'<<smart-backspace>>': ['<Key-BackSpace>'],
|
||||
'<<newline-and-indent>>': ['<Key-Return>', '<KP_Enter>'],
|
||||
'<<smart-indent>>': ['<Key-Tab>']
|
||||
}
|
||||
|
||||
windows_keydefs = {
|
||||
'<<indent-region>>': ['<Control-bracketright>'],
|
||||
'<<dedent-region>>': ['<Control-bracketleft>'],
|
||||
'<<comment-region>>': ['<Alt-Key-3>'],
|
||||
'<<uncomment-region>>': ['<Alt-Key-4>'],
|
||||
'<<tabify-region>>': ['<Alt-Key-5>'],
|
||||
'<<untabify-region>>': ['<Alt-Key-6>'],
|
||||
'<<toggle-tabs>>': ['<Alt-Key-t>'],
|
||||
'<<change-indentwidth>>': ['<Alt-Key-u>'],
|
||||
}
|
||||
|
||||
unix_keydefs = {
|
||||
'<<indent-region>>': ['<Alt-bracketright>',
|
||||
'<Meta-bracketright>',
|
||||
'<Control-bracketright>'],
|
||||
'<<dedent-region>>': ['<Alt-bracketleft>',
|
||||
'<Meta-bracketleft>',
|
||||
'<Control-bracketleft>'],
|
||||
'<<comment-region>>': ['<Alt-Key-3>', '<Meta-Key-3>'],
|
||||
'<<uncomment-region>>': ['<Alt-Key-4>', '<Meta-Key-4>'],
|
||||
'<<tabify-region>>': ['<Alt-Key-5>', '<Meta-Key-5>'],
|
||||
'<<untabify-region>>': ['<Alt-Key-6>', '<Meta-Key-6>'],
|
||||
'<<toggle-tabs>>': ['<Alt-Key-t>'],
|
||||
'<<change-indentwidth>>': ['<Alt-Key-u>'],
|
||||
}
|
||||
|
||||
# usetabs true -> literal tab characters are used by indent and
|
||||
# dedent cmds, possibly mixed with spaces if
|
||||
# indentwidth is not a multiple of tabwidth
|
||||
# false -> tab characters are converted to spaces by indent
|
||||
# and dedent cmds, and ditto TAB keystrokes
|
||||
# indentwidth is the number of characters per logical indent level.
|
||||
# tabwidth is the display width of a literal tab character.
|
||||
# CAUTION: telling Tk to use anything other than its default
|
||||
# tab setting causes it to use an entirely different tabbing algorithm,
|
||||
# treating tab stops as fixed distances from the left margin.
|
||||
# Nobody expects this, so for now tabwidth should never be changed.
|
||||
usetabs = 1
|
||||
indentwidth = 4
|
||||
tabwidth = 8 # for IDLE use, must remain 8 until Tk is fixed
|
||||
|
||||
# If context_use_ps1 is true, parsing searches back for a ps1 line;
|
||||
# else searches for a popular (if, def, ...) Python stmt.
|
||||
context_use_ps1 = 0
|
||||
|
||||
# When searching backwards for a reliable place to begin parsing,
|
||||
# first start num_context_lines[0] lines back, then
|
||||
# num_context_lines[1] lines back if that didn't work, and so on.
|
||||
# The last value should be huge (larger than the # of lines in a
|
||||
# conceivable file).
|
||||
# Making the initial values larger slows things down more often.
|
||||
num_context_lines = 50, 500, 5000000
|
||||
|
||||
def __init__(self, editwin):
|
||||
self.editwin = editwin
|
||||
self.text = editwin.text
|
||||
|
||||
def config(self, **options):
|
||||
for key, value in options.items():
|
||||
if key == 'usetabs':
|
||||
self.usetabs = value
|
||||
elif key == 'indentwidth':
|
||||
self.indentwidth = value
|
||||
elif key == 'tabwidth':
|
||||
self.tabwidth = value
|
||||
elif key == 'context_use_ps1':
|
||||
self.context_use_ps1 = value
|
||||
else:
|
||||
raise KeyError("bad option name: %s" % repr(key))
|
||||
|
||||
# If ispythonsource and guess are true, guess a good value for
|
||||
# indentwidth based on file content (if possible), and if
|
||||
# indentwidth != tabwidth set usetabs false.
|
||||
# In any case, adjust the Text widget's view of what a tab
|
||||
# character means.
|
||||
|
||||
def set_indentation_params(self, ispythonsource, guess=1):
|
||||
if guess and ispythonsource:
|
||||
i = self.guess_indent()
|
||||
if 2 <= i <= 8:
|
||||
self.indentwidth = i
|
||||
if self.indentwidth != self.tabwidth:
|
||||
self.usetabs = 0
|
||||
|
||||
self.editwin.set_tabwidth(self.tabwidth)
|
||||
|
||||
def smart_backspace_event(self, event):
|
||||
text = self.text
|
||||
first, last = self.editwin.get_selection_indices()
|
||||
if first and last:
|
||||
text.delete(first, last)
|
||||
text.mark_set("insert", first)
|
||||
return "break"
|
||||
# Delete whitespace left, until hitting a real char or closest
|
||||
# preceding virtual tab stop.
|
||||
chars = text.get("insert linestart", "insert")
|
||||
if chars == '':
|
||||
if text.compare("insert", ">", "1.0"):
|
||||
# easy: delete preceding newline
|
||||
text.delete("insert-1c")
|
||||
else:
|
||||
text.bell() # at start of buffer
|
||||
return "break"
|
||||
if chars[-1] not in " \t":
|
||||
# easy: delete preceding real char
|
||||
text.delete("insert-1c")
|
||||
return "break"
|
||||
# Ick. It may require *inserting* spaces if we back up over a
|
||||
# tab character! This is written to be clear, not fast.
|
||||
have = len(chars.expandtabs(self.tabwidth))
|
||||
assert have > 0
|
||||
want = int((have - 1) / self.indentwidth) * self.indentwidth
|
||||
ncharsdeleted = 0
|
||||
while 1:
|
||||
chars = chars[:-1]
|
||||
ncharsdeleted = ncharsdeleted + 1
|
||||
have = len(chars.expandtabs(self.tabwidth))
|
||||
if have <= want or chars[-1] not in " \t":
|
||||
break
|
||||
text.undo_block_start()
|
||||
text.delete("insert-%dc" % ncharsdeleted, "insert")
|
||||
if have < want:
|
||||
text.insert("insert", ' ' * (want - have))
|
||||
text.undo_block_stop()
|
||||
return "break"
|
||||
|
||||
def smart_indent_event(self, event):
|
||||
# if intraline selection:
|
||||
# delete it
|
||||
# elif multiline selection:
|
||||
# do indent-region & return
|
||||
# indent one level
|
||||
text = self.text
|
||||
first, last = self.editwin.get_selection_indices()
|
||||
text.undo_block_start()
|
||||
try:
|
||||
if first and last:
|
||||
if index2line(first) != index2line(last):
|
||||
return self.indent_region_event(event)
|
||||
text.delete(first, last)
|
||||
text.mark_set("insert", first)
|
||||
prefix = text.get("insert linestart", "insert")
|
||||
raw, effective = classifyws(prefix, self.tabwidth)
|
||||
if raw == len(prefix):
|
||||
# only whitespace to the left
|
||||
self.reindent_to(effective + self.indentwidth)
|
||||
else:
|
||||
if self.usetabs:
|
||||
pad = '\t'
|
||||
else:
|
||||
effective = len(prefix.expandtabs(self.tabwidth))
|
||||
n = self.indentwidth
|
||||
pad = ' ' * (n - effective % n)
|
||||
text.insert("insert", pad)
|
||||
text.see("insert")
|
||||
return "break"
|
||||
finally:
|
||||
text.undo_block_stop()
|
||||
|
||||
def newline_and_indent_event(self, event):
|
||||
text = self.text
|
||||
first, last = self.editwin.get_selection_indices()
|
||||
text.undo_block_start()
|
||||
try:
|
||||
if first and last:
|
||||
text.delete(first, last)
|
||||
text.mark_set("insert", first)
|
||||
line = text.get("insert linestart", "insert")
|
||||
i, n = 0, len(line)
|
||||
while i < n and line[i] in " \t":
|
||||
i = i+1
|
||||
if i == n:
|
||||
# the cursor is in or at leading indentation; just inject
|
||||
# an empty line at the start and strip space from current line
|
||||
text.delete("insert - %d chars" % i, "insert")
|
||||
text.insert("insert linestart", '\n')
|
||||
return "break"
|
||||
indent = line[:i]
|
||||
# strip whitespace before insert point
|
||||
i = 0
|
||||
while line and line[-1] in " \t":
|
||||
line = line[:-1]
|
||||
i = i+1
|
||||
if i:
|
||||
text.delete("insert - %d chars" % i, "insert")
|
||||
# strip whitespace after insert point
|
||||
while text.get("insert") in " \t":
|
||||
text.delete("insert")
|
||||
# start new line
|
||||
text.insert("insert", '\n')
|
||||
|
||||
# adjust indentation for continuations and block
|
||||
# open/close first need to find the last stmt
|
||||
lno = index2line(text.index('insert'))
|
||||
y = PyParse.Parser(self.indentwidth, self.tabwidth)
|
||||
for context in self.num_context_lines:
|
||||
startat = max(lno - context, 1)
|
||||
startatindex = repr(startat) + ".0"
|
||||
rawtext = text.get(startatindex, "insert")
|
||||
y.set_str(rawtext)
|
||||
bod = y.find_good_parse_start(
|
||||
self.context_use_ps1,
|
||||
self._build_char_in_string_func(startatindex))
|
||||
if bod is not None or startat == 1:
|
||||
break
|
||||
y.set_lo(bod or 0)
|
||||
c = y.get_continuation_type()
|
||||
if c != PyParse.C_NONE:
|
||||
# The current stmt hasn't ended yet.
|
||||
if c == PyParse.C_STRING:
|
||||
# inside a string; just mimic the current indent
|
||||
text.insert("insert", indent)
|
||||
elif c == PyParse.C_BRACKET:
|
||||
# line up with the first (if any) element of the
|
||||
# last open bracket structure; else indent one
|
||||
# level beyond the indent of the line with the
|
||||
# last open bracket
|
||||
self.reindent_to(y.compute_bracket_indent())
|
||||
elif c == PyParse.C_BACKSLASH:
|
||||
# if more than one line in this stmt already, just
|
||||
# mimic the current indent; else if initial line
|
||||
# has a start on an assignment stmt, indent to
|
||||
# beyond leftmost =; else to beyond first chunk of
|
||||
# non-whitespace on initial line
|
||||
if y.get_num_lines_in_stmt() > 1:
|
||||
text.insert("insert", indent)
|
||||
else:
|
||||
self.reindent_to(y.compute_backslash_indent())
|
||||
else:
|
||||
assert 0, "bogus continuation type " + repr(c)
|
||||
return "break"
|
||||
|
||||
# This line starts a brand new stmt; indent relative to
|
||||
# indentation of initial line of closest preceding
|
||||
# interesting stmt.
|
||||
indent = y.get_base_indent_string()
|
||||
text.insert("insert", indent)
|
||||
if y.is_block_opener():
|
||||
self.smart_indent_event(event)
|
||||
elif indent and y.is_block_closer():
|
||||
self.smart_backspace_event(event)
|
||||
return "break"
|
||||
finally:
|
||||
text.see("insert")
|
||||
text.undo_block_stop()
|
||||
|
||||
auto_indent = newline_and_indent_event
|
||||
|
||||
# Our editwin provides a is_char_in_string function that works
|
||||
# with a Tk text index, but PyParse only knows about offsets into
|
||||
# a string. This builds a function for PyParse that accepts an
|
||||
# offset.
|
||||
|
||||
def _build_char_in_string_func(self, startindex):
|
||||
def inner(offset, _startindex=startindex,
|
||||
_icis=self.editwin.is_char_in_string):
|
||||
return _icis(_startindex + "+%dc" % offset)
|
||||
return inner
|
||||
|
||||
def indent_region_event(self, event):
|
||||
head, tail, chars, lines = self.get_region()
|
||||
for pos in range(len(lines)):
|
||||
line = lines[pos]
|
||||
if line:
|
||||
raw, effective = classifyws(line, self.tabwidth)
|
||||
effective = effective + self.indentwidth
|
||||
lines[pos] = self._make_blanks(effective) + line[raw:]
|
||||
self.set_region(head, tail, chars, lines)
|
||||
return "break"
|
||||
|
||||
def dedent_region_event(self, event):
|
||||
head, tail, chars, lines = self.get_region()
|
||||
for pos in range(len(lines)):
|
||||
line = lines[pos]
|
||||
if line:
|
||||
raw, effective = classifyws(line, self.tabwidth)
|
||||
effective = max(effective - self.indentwidth, 0)
|
||||
lines[pos] = self._make_blanks(effective) + line[raw:]
|
||||
self.set_region(head, tail, chars, lines)
|
||||
return "break"
|
||||
|
||||
def comment_region_event(self, event):
|
||||
head, tail, chars, lines = self.get_region()
|
||||
for pos in range(len(lines) - 1):
|
||||
line = lines[pos]
|
||||
lines[pos] = '##' + line
|
||||
self.set_region(head, tail, chars, lines)
|
||||
|
||||
def uncomment_region_event(self, event):
|
||||
head, tail, chars, lines = self.get_region()
|
||||
for pos in range(len(lines)):
|
||||
line = lines[pos]
|
||||
if not line:
|
||||
continue
|
||||
if line[:2] == '##':
|
||||
line = line[2:]
|
||||
elif line[:1] == '#':
|
||||
line = line[1:]
|
||||
lines[pos] = line
|
||||
self.set_region(head, tail, chars, lines)
|
||||
|
||||
def tabify_region_event(self, event):
|
||||
head, tail, chars, lines = self.get_region()
|
||||
tabwidth = self._asktabwidth()
|
||||
for pos in range(len(lines)):
|
||||
line = lines[pos]
|
||||
if line:
|
||||
raw, effective = classifyws(line, tabwidth)
|
||||
ntabs, nspaces = divmod(effective, tabwidth)
|
||||
lines[pos] = '\t' * ntabs + ' ' * nspaces + line[raw:]
|
||||
self.set_region(head, tail, chars, lines)
|
||||
|
||||
def untabify_region_event(self, event):
|
||||
head, tail, chars, lines = self.get_region()
|
||||
tabwidth = self._asktabwidth()
|
||||
for pos in range(len(lines)):
|
||||
lines[pos] = lines[pos].expandtabs(tabwidth)
|
||||
self.set_region(head, tail, chars, lines)
|
||||
|
||||
def toggle_tabs_event(self, event):
|
||||
if self.editwin.askyesno(
|
||||
"Toggle tabs",
|
||||
"Turn tabs " + ("on", "off")[self.usetabs] + "?",
|
||||
parent=self.text):
|
||||
self.usetabs = not self.usetabs
|
||||
return "break"
|
||||
|
||||
# XXX this isn't bound to anything -- see class tabwidth comments
|
||||
def change_tabwidth_event(self, event):
|
||||
new = self._asktabwidth()
|
||||
if new != self.tabwidth:
|
||||
self.tabwidth = new
|
||||
self.set_indentation_params(0, guess=0)
|
||||
return "break"
|
||||
|
||||
def change_indentwidth_event(self, event):
|
||||
new = self.editwin.askinteger(
|
||||
"Indent width",
|
||||
"New indent width (1-16)",
|
||||
parent=self.text,
|
||||
initialvalue=self.indentwidth,
|
||||
minvalue=1,
|
||||
maxvalue=16)
|
||||
if new and new != self.indentwidth:
|
||||
self.indentwidth = new
|
||||
return "break"
|
||||
|
||||
def get_region(self):
|
||||
text = self.text
|
||||
first, last = self.editwin.get_selection_indices()
|
||||
if first and last:
|
||||
head = text.index(first + " linestart")
|
||||
tail = text.index(last + "-1c lineend +1c")
|
||||
else:
|
||||
head = text.index("insert linestart")
|
||||
tail = text.index("insert lineend +1c")
|
||||
chars = text.get(head, tail)
|
||||
lines = chars.split("\n")
|
||||
return head, tail, chars, lines
|
||||
|
||||
def set_region(self, head, tail, chars, lines):
|
||||
text = self.text
|
||||
newchars = "\n".join(lines)
|
||||
if newchars == chars:
|
||||
text.bell()
|
||||
return
|
||||
text.tag_remove("sel", "1.0", "end")
|
||||
text.mark_set("insert", head)
|
||||
text.undo_block_start()
|
||||
text.delete(head, tail)
|
||||
text.insert(head, newchars)
|
||||
text.undo_block_stop()
|
||||
text.tag_add("sel", head, "insert")
|
||||
|
||||
# Make string that displays as n leading blanks.
|
||||
|
||||
def _make_blanks(self, n):
|
||||
if self.usetabs:
|
||||
ntabs, nspaces = divmod(n, self.tabwidth)
|
||||
return '\t' * ntabs + ' ' * nspaces
|
||||
else:
|
||||
return ' ' * n
|
||||
|
||||
# Delete from beginning of line to insert point, then reinsert
|
||||
# column logical (meaning use tabs if appropriate) spaces.
|
||||
|
||||
def reindent_to(self, column):
|
||||
text = self.text
|
||||
text.undo_block_start()
|
||||
if text.compare("insert linestart", "!=", "insert"):
|
||||
text.delete("insert linestart", "insert")
|
||||
if column:
|
||||
text.insert("insert", self._make_blanks(column))
|
||||
text.undo_block_stop()
|
||||
|
||||
def _asktabwidth(self):
|
||||
return self.editwin.askinteger(
|
||||
"Tab width",
|
||||
"Spaces per tab?",
|
||||
parent=self.text,
|
||||
initialvalue=self.tabwidth,
|
||||
minvalue=1,
|
||||
maxvalue=16) or self.tabwidth
|
||||
|
||||
# Guess indentwidth from text content.
|
||||
# Return guessed indentwidth. This should not be believed unless
|
||||
# it's in a reasonable range (e.g., it will be 0 if no indented
|
||||
# blocks are found).
|
||||
|
||||
def guess_indent(self):
|
||||
opener, indented = IndentSearcher(self.text, self.tabwidth).run()
|
||||
if opener and indented:
|
||||
raw, indentsmall = classifyws(opener, self.tabwidth)
|
||||
raw, indentlarge = classifyws(indented, self.tabwidth)
|
||||
else:
|
||||
indentsmall = indentlarge = 0
|
||||
return indentlarge - indentsmall
|
||||
|
||||
# "line.col" -> line, as an int
|
||||
def index2line(index):
|
||||
return int(float(index))
|
||||
|
||||
# Look at the leading whitespace in s.
|
||||
# Return pair (# of leading ws characters,
|
||||
# effective # of leading blanks after expanding
|
||||
# tabs to width tabwidth)
|
||||
|
||||
def classifyws(s, tabwidth):
|
||||
raw = effective = 0
|
||||
for ch in s:
|
||||
if ch == ' ':
|
||||
raw = raw + 1
|
||||
effective = effective + 1
|
||||
elif ch == '\t':
|
||||
raw = raw + 1
|
||||
effective = (effective // tabwidth + 1) * tabwidth
|
||||
else:
|
||||
break
|
||||
return raw, effective
|
||||
|
||||
class IndentSearcher:
|
||||
|
||||
# .run() chews over the Text widget, looking for a block opener
|
||||
# and the stmt following it. Returns a pair,
|
||||
# (line containing block opener, line containing stmt)
|
||||
# Either or both may be None.
|
||||
|
||||
def __init__(self, text, tabwidth):
|
||||
self.text = text
|
||||
self.tabwidth = tabwidth
|
||||
self.i = self.finished = 0
|
||||
self.blkopenline = self.indentedline = None
|
||||
|
||||
def readline(self):
|
||||
if self.finished:
|
||||
val = ""
|
||||
else:
|
||||
i = self.i = self.i + 1
|
||||
mark = repr(i) + ".0"
|
||||
if self.text.compare(mark, ">=", "end"):
|
||||
val = ""
|
||||
else:
|
||||
val = self.text.get(mark, mark + " lineend+1c")
|
||||
# hrm - not sure this is correct in py3k - the source code may have
|
||||
# an encoding declared, but the data will *always* be in
|
||||
# default_scintilla_encoding - so if anyone looks at the encoding decl
|
||||
# in the source they will be wrong. I think. Maybe. Or something...
|
||||
return val.encode(default_scintilla_encoding)
|
||||
|
||||
def run(self):
|
||||
OPENERS=('class', 'def', 'for', 'if', 'try', 'while')
|
||||
INDENT=tokenize.INDENT
|
||||
NAME=tokenize.NAME
|
||||
|
||||
save_tabsize = tokenize.tabsize
|
||||
tokenize.tabsize = self.tabwidth
|
||||
try:
|
||||
try:
|
||||
for (typ, token, start, end, line) in token_generator(self.readline):
|
||||
if typ == NAME and token in OPENERS:
|
||||
self.blkopenline = line
|
||||
elif typ == INDENT and self.blkopenline:
|
||||
self.indentedline = line
|
||||
break
|
||||
|
||||
except (tokenize.TokenError, IndentationError):
|
||||
# since we cut off the tokenizer early, we can trigger
|
||||
# spurious errors
|
||||
pass
|
||||
finally:
|
||||
tokenize.tabsize = save_tabsize
|
||||
return self.blkopenline, self.indentedline
|
||||
188
Lib/site-packages/pythonwin/pywin/idle/CallTips.py
Normal file
188
Lib/site-packages/pythonwin/pywin/idle/CallTips.py
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
# CallTips.py - An IDLE extension that provides "Call Tips" - ie, a floating window that
|
||||
# displays parameter information as you open parens.
|
||||
|
||||
import string
|
||||
import sys
|
||||
import inspect
|
||||
import traceback
|
||||
|
||||
class CallTips:
|
||||
|
||||
menudefs = [
|
||||
]
|
||||
|
||||
keydefs = {
|
||||
'<<paren-open>>': ['<Key-parenleft>'],
|
||||
'<<paren-close>>': ['<Key-parenright>'],
|
||||
'<<check-calltip-cancel>>': ['<KeyRelease>'],
|
||||
'<<calltip-cancel>>': ['<ButtonPress>', '<Key-Escape>'],
|
||||
}
|
||||
|
||||
windows_keydefs = {
|
||||
}
|
||||
|
||||
unix_keydefs = {
|
||||
}
|
||||
|
||||
def __init__(self, editwin):
|
||||
self.editwin = editwin
|
||||
self.text = editwin.text
|
||||
self.calltip = None
|
||||
if hasattr(self.text, "make_calltip_window"):
|
||||
self._make_calltip_window = self.text.make_calltip_window
|
||||
else:
|
||||
self._make_calltip_window = self._make_tk_calltip_window
|
||||
|
||||
def close(self):
|
||||
self._make_calltip_window = None
|
||||
|
||||
# Makes a Tk based calltip window. Used by IDLE, but not Pythonwin.
|
||||
# See __init__ above for how this is used.
|
||||
def _make_tk_calltip_window(self):
|
||||
import CallTipWindow
|
||||
return CallTipWindow.CallTip(self.text)
|
||||
|
||||
def _remove_calltip_window(self):
|
||||
if self.calltip:
|
||||
self.calltip.hidetip()
|
||||
self.calltip = None
|
||||
|
||||
def paren_open_event(self, event):
|
||||
self._remove_calltip_window()
|
||||
arg_text = get_arg_text(self.get_object_at_cursor())
|
||||
if arg_text:
|
||||
self.calltip_start = self.text.index("insert")
|
||||
self.calltip = self._make_calltip_window()
|
||||
self.calltip.showtip(arg_text)
|
||||
return "" #so the event is handled normally.
|
||||
|
||||
def paren_close_event(self, event):
|
||||
# Now just hides, but later we should check if other
|
||||
# paren'd expressions remain open.
|
||||
self._remove_calltip_window()
|
||||
return "" #so the event is handled normally.
|
||||
|
||||
def check_calltip_cancel_event(self, event):
|
||||
if self.calltip:
|
||||
# If we have moved before the start of the calltip,
|
||||
# or off the calltip line, then cancel the tip.
|
||||
# (Later need to be smarter about multi-line, etc)
|
||||
if self.text.compare("insert", "<=", self.calltip_start) or \
|
||||
self.text.compare("insert", ">", self.calltip_start + " lineend"):
|
||||
self._remove_calltip_window()
|
||||
return "" #so the event is handled normally.
|
||||
|
||||
def calltip_cancel_event(self, event):
|
||||
self._remove_calltip_window()
|
||||
return "" #so the event is handled normally.
|
||||
|
||||
def get_object_at_cursor(self,
|
||||
wordchars="._" + string.ascii_uppercase + string.ascii_lowercase + string.digits):
|
||||
# XXX - This needs to be moved to a better place
|
||||
# so the "." attribute lookup code can also use it.
|
||||
text = self.text
|
||||
chars = text.get("insert linestart", "insert")
|
||||
i = len(chars)
|
||||
while i and chars[i-1] in wordchars:
|
||||
i = i-1
|
||||
word = chars[i:]
|
||||
if word:
|
||||
# How is this for a hack!
|
||||
import sys, __main__
|
||||
namespace = sys.modules.copy()
|
||||
namespace.update(__main__.__dict__)
|
||||
try:
|
||||
return eval(word, namespace)
|
||||
except:
|
||||
pass
|
||||
return None # Can't find an object.
|
||||
|
||||
def _find_constructor(class_ob):
|
||||
# Given a class object, return a function object used for the
|
||||
# constructor (ie, __init__() ) or None if we can't find one.
|
||||
try:
|
||||
if sys.version_info < (3,):
|
||||
return class_ob.__init__.im_func
|
||||
else:
|
||||
return class_ob.__init__.__func__
|
||||
except AttributeError:
|
||||
for base in class_ob.__bases__:
|
||||
rc = _find_constructor(base)
|
||||
if rc is not None: return rc
|
||||
return None
|
||||
|
||||
def get_arg_text(ob):
|
||||
# Get a string describing the arguments for the given object.
|
||||
argText = ""
|
||||
if ob is not None:
|
||||
argOffset = 0
|
||||
if inspect.isclass(ob):
|
||||
# Look for the highest __init__ in the class chain.
|
||||
fob = _find_constructor(ob)
|
||||
if fob is None:
|
||||
fob = lambda: None
|
||||
else:
|
||||
fob = ob
|
||||
if inspect.isfunction(fob) or inspect.ismethod(fob):
|
||||
try:
|
||||
# py3k has a 'getfullargspec' which can handle py3k specific things.
|
||||
arg_getter = getattr(inspect, "getfullargspec", inspect.getargspec)
|
||||
argText = inspect.formatargspec(*arg_getter(fob))
|
||||
except:
|
||||
print("Failed to format the args")
|
||||
traceback.print_exc()
|
||||
# See if we can use the docstring
|
||||
if hasattr(ob, "__doc__"):
|
||||
doc=ob.__doc__
|
||||
try:
|
||||
doc = doc.strip()
|
||||
pos = doc.find("\n")
|
||||
except AttributeError:
|
||||
## New style classes may have __doc__ slot without actually
|
||||
## having a string assigned to it
|
||||
pass
|
||||
else:
|
||||
if pos<0 or pos>70: pos=70
|
||||
if argText: argText = argText + "\n"
|
||||
argText = argText + doc[:pos]
|
||||
|
||||
return argText
|
||||
|
||||
#################################################
|
||||
#
|
||||
# Test code
|
||||
#
|
||||
if __name__=='__main__':
|
||||
|
||||
def t1(): "()"
|
||||
def t2(a, b=None): "(a, b=None)"
|
||||
def t3(a, *args): "(a, *args)"
|
||||
def t4(*args): "(*args)"
|
||||
def t5(a, *args): "(a, *args)"
|
||||
def t6(a, b=None, *args, **kw): "(a, b=None, *args, **kw)"
|
||||
|
||||
class TC:
|
||||
"(self, a=None, *b)"
|
||||
def __init__(self, a=None, *b): "(self, a=None, *b)"
|
||||
def t1(self): "(self)"
|
||||
def t2(self, a, b=None): "(self, a, b=None)"
|
||||
def t3(self, a, *args): "(self, a, *args)"
|
||||
def t4(self, *args): "(self, *args)"
|
||||
def t5(self, a, *args): "(self, a, *args)"
|
||||
def t6(self, a, b=None, *args, **kw): "(self, a, b=None, *args, **kw)"
|
||||
|
||||
def test( tests ):
|
||||
failed=[]
|
||||
for t in tests:
|
||||
expected = t.__doc__ + "\n" + t.__doc__
|
||||
if get_arg_text(t) != expected:
|
||||
failed.append(t)
|
||||
print("%s - expected %s, but got %s" % (t, repr(expected), repr(get_arg_text(t))))
|
||||
print("%d of %d tests failed" % (len(failed), len(tests)))
|
||||
|
||||
tc = TC()
|
||||
tests = t1, t2, t3, t4, t5, t6, \
|
||||
TC, tc.t1, tc.t2, tc.t3, tc.t4, tc.t5, tc.t6
|
||||
|
||||
test(tests)
|
||||
|
||||
155
Lib/site-packages/pythonwin/pywin/idle/FormatParagraph.py
Normal file
155
Lib/site-packages/pythonwin/pywin/idle/FormatParagraph.py
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
# Extension to format a paragraph
|
||||
|
||||
# Does basic, standard text formatting, and also understands Python
|
||||
# comment blocks. Thus, for editing Python source code, this
|
||||
# extension is really only suitable for reformatting these comment
|
||||
# blocks or triple-quoted strings.
|
||||
|
||||
# Known problems with comment reformatting:
|
||||
# * If there is a selection marked, and the first line of the
|
||||
# selection is not complete, the block will probably not be detected
|
||||
# as comments, and will have the normal "text formatting" rules
|
||||
# applied.
|
||||
# * If a comment block has leading whitespace that mixes tabs and
|
||||
# spaces, they will not be considered part of the same block.
|
||||
# * Fancy comments, like this bulleted list, arent handled :-)
|
||||
|
||||
import string
|
||||
import re
|
||||
|
||||
class FormatParagraph:
|
||||
|
||||
menudefs = [
|
||||
('edit', [
|
||||
('Format Paragraph', '<<format-paragraph>>'),
|
||||
])
|
||||
]
|
||||
|
||||
keydefs = {
|
||||
'<<format-paragraph>>': ['<Alt-q>'],
|
||||
}
|
||||
|
||||
unix_keydefs = {
|
||||
'<<format-paragraph>>': ['<Meta-q>'],
|
||||
}
|
||||
|
||||
def __init__(self, editwin):
|
||||
self.editwin = editwin
|
||||
|
||||
def close(self):
|
||||
self.editwin = None
|
||||
|
||||
def format_paragraph_event(self, event):
|
||||
text = self.editwin.text
|
||||
first, last = self.editwin.get_selection_indices()
|
||||
if first and last:
|
||||
data = text.get(first, last)
|
||||
comment_header = ''
|
||||
else:
|
||||
first, last, comment_header, data = \
|
||||
find_paragraph(text, text.index("insert"))
|
||||
if comment_header:
|
||||
# Reformat the comment lines - convert to text sans header.
|
||||
lines = data.split("\n")
|
||||
lines = map(lambda st, l=len(comment_header): st[l:], lines)
|
||||
data = "\n".join(lines)
|
||||
# Reformat to 70 chars or a 20 char width, whichever is greater.
|
||||
format_width = max(70-len(comment_header), 20)
|
||||
newdata = reformat_paragraph(data, format_width)
|
||||
# re-split and re-insert the comment header.
|
||||
newdata = newdata.split("\n")
|
||||
# If the block ends in a \n, we dont want the comment
|
||||
# prefix inserted after it. (Im not sure it makes sense to
|
||||
# reformat a comment block that isnt made of complete
|
||||
# lines, but whatever!) Can't think of a clean soltution,
|
||||
# so we hack away
|
||||
block_suffix = ""
|
||||
if not newdata[-1]:
|
||||
block_suffix = "\n"
|
||||
newdata = newdata[:-1]
|
||||
builder = lambda item, prefix=comment_header: prefix+item
|
||||
newdata = '\n'.join([builder(d) for d in newdata]) + block_suffix
|
||||
else:
|
||||
# Just a normal text format
|
||||
newdata = reformat_paragraph(data)
|
||||
text.tag_remove("sel", "1.0", "end")
|
||||
if newdata != data:
|
||||
text.mark_set("insert", first)
|
||||
text.undo_block_start()
|
||||
text.delete(first, last)
|
||||
text.insert(first, newdata)
|
||||
text.undo_block_stop()
|
||||
else:
|
||||
text.mark_set("insert", last)
|
||||
text.see("insert")
|
||||
|
||||
def find_paragraph(text, mark):
|
||||
lineno, col = list(map(int, mark.split(".")))
|
||||
line = text.get("%d.0" % lineno, "%d.0 lineend" % lineno)
|
||||
while text.compare("%d.0" % lineno, "<", "end") and is_all_white(line):
|
||||
lineno = lineno + 1
|
||||
line = text.get("%d.0" % lineno, "%d.0 lineend" % lineno)
|
||||
first_lineno = lineno
|
||||
comment_header = get_comment_header(line)
|
||||
comment_header_len = len(comment_header)
|
||||
while get_comment_header(line)==comment_header and \
|
||||
not is_all_white(line[comment_header_len:]):
|
||||
lineno = lineno + 1
|
||||
line = text.get("%d.0" % lineno, "%d.0 lineend" % lineno)
|
||||
last = "%d.0" % lineno
|
||||
# Search back to beginning of paragraph
|
||||
lineno = first_lineno - 1
|
||||
line = text.get("%d.0" % lineno, "%d.0 lineend" % lineno)
|
||||
while lineno > 0 and \
|
||||
get_comment_header(line)==comment_header and \
|
||||
not is_all_white(line[comment_header_len:]):
|
||||
lineno = lineno - 1
|
||||
line = text.get("%d.0" % lineno, "%d.0 lineend" % lineno)
|
||||
first = "%d.0" % (lineno+1)
|
||||
return first, last, comment_header, text.get(first, last)
|
||||
|
||||
def reformat_paragraph(data, limit=70):
|
||||
lines = data.split("\n")
|
||||
i = 0
|
||||
n = len(lines)
|
||||
while i < n and is_all_white(lines[i]):
|
||||
i = i+1
|
||||
if i >= n:
|
||||
return data
|
||||
indent1 = get_indent(lines[i])
|
||||
if i+1 < n and not is_all_white(lines[i+1]):
|
||||
indent2 = get_indent(lines[i+1])
|
||||
else:
|
||||
indent2 = indent1
|
||||
new = lines[:i]
|
||||
partial = indent1
|
||||
while i < n and not is_all_white(lines[i]):
|
||||
# XXX Should take double space after period (etc.) into account
|
||||
words = re.split("(\s+)", lines[i])
|
||||
for j in range(0, len(words), 2):
|
||||
word = words[j]
|
||||
if not word:
|
||||
continue # Can happen when line ends in whitespace
|
||||
if len((partial + word).expandtabs()) > limit and \
|
||||
partial != indent1:
|
||||
new.append(partial.rstrip())
|
||||
partial = indent2
|
||||
partial = partial + word + " "
|
||||
if j+1 < len(words) and words[j+1] != " ":
|
||||
partial = partial + " "
|
||||
i = i+1
|
||||
new.append(partial.rstrip())
|
||||
# XXX Should reformat remaining paragraphs as well
|
||||
new.extend(lines[i:])
|
||||
return "\n".join(new)
|
||||
|
||||
def is_all_white(line):
|
||||
return re.match(r"^\s*$", line) is not None
|
||||
|
||||
def get_indent(line):
|
||||
return re.match(r"^(\s*)", line).group()
|
||||
|
||||
def get_comment_header(line):
|
||||
m = re.match(r"^(\s*#*)", line)
|
||||
if m is None: return ""
|
||||
return m.group(1)
|
||||
89
Lib/site-packages/pythonwin/pywin/idle/IdleHistory.py
Normal file
89
Lib/site-packages/pythonwin/pywin/idle/IdleHistory.py
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
import string
|
||||
|
||||
class History:
|
||||
|
||||
def __init__(self, text, output_sep = "\n"):
|
||||
self.text = text
|
||||
self.history = []
|
||||
self.history_prefix = None
|
||||
self.history_pointer = None
|
||||
self.output_sep = output_sep
|
||||
text.bind("<<history-previous>>", self.history_prev)
|
||||
text.bind("<<history-next>>", self.history_next)
|
||||
|
||||
def history_next(self, event):
|
||||
self.history_do(0)
|
||||
return "break"
|
||||
|
||||
def history_prev(self, event):
|
||||
self.history_do(1)
|
||||
return "break"
|
||||
|
||||
def _get_source(self, start, end):
|
||||
# Get source code from start index to end index. Lines in the
|
||||
# text control may be separated by sys.ps2 .
|
||||
lines = self.text.get(start, end).split(self.output_sep)
|
||||
return "\n".join(lines)
|
||||
|
||||
def _put_source(self, where, source):
|
||||
output = self.output_sep.join(source.split("\n"))
|
||||
self.text.insert(where, output)
|
||||
|
||||
def history_do(self, reverse):
|
||||
nhist = len(self.history)
|
||||
pointer = self.history_pointer
|
||||
prefix = self.history_prefix
|
||||
if pointer is not None and prefix is not None:
|
||||
if self.text.compare("insert", "!=", "end-1c") or \
|
||||
self._get_source("iomark", "end-1c") != self.history[pointer]:
|
||||
pointer = prefix = None
|
||||
if pointer is None or prefix is None:
|
||||
prefix = self._get_source("iomark", "end-1c")
|
||||
if reverse:
|
||||
pointer = nhist
|
||||
else:
|
||||
pointer = -1
|
||||
nprefix = len(prefix)
|
||||
while 1:
|
||||
if reverse:
|
||||
pointer = pointer - 1
|
||||
else:
|
||||
pointer = pointer + 1
|
||||
if pointer < 0 or pointer >= nhist:
|
||||
self.text.bell()
|
||||
if self._get_source("iomark", "end-1c") != prefix:
|
||||
self.text.delete("iomark", "end-1c")
|
||||
self._put_source("iomark", prefix)
|
||||
pointer = prefix = None
|
||||
break
|
||||
item = self.history[pointer]
|
||||
if item[:nprefix] == prefix and len(item) > nprefix:
|
||||
self.text.delete("iomark", "end-1c")
|
||||
self._put_source("iomark", item)
|
||||
break
|
||||
self.text.mark_set("insert", "end-1c")
|
||||
self.text.see("insert")
|
||||
self.text.tag_remove("sel", "1.0", "end")
|
||||
self.history_pointer = pointer
|
||||
self.history_prefix = prefix
|
||||
|
||||
def history_store(self, source):
|
||||
source = source.strip()
|
||||
if len(source) > 2:
|
||||
# avoid duplicates
|
||||
try:
|
||||
self.history.remove(source)
|
||||
except ValueError:
|
||||
pass
|
||||
self.history.append(source)
|
||||
self.history_pointer = None
|
||||
self.history_prefix = None
|
||||
|
||||
def recall(self, s):
|
||||
s = s.strip()
|
||||
self.text.tag_remove("sel", "1.0", "end")
|
||||
self.text.delete("iomark", "end-1c")
|
||||
self.text.mark_set("insert", "end-1c")
|
||||
self.text.insert("insert", s)
|
||||
self.text.see("insert")
|
||||
|
||||
568
Lib/site-packages/pythonwin/pywin/idle/PyParse.py
Normal file
568
Lib/site-packages/pythonwin/pywin/idle/PyParse.py
Normal file
|
|
@ -0,0 +1,568 @@
|
|||
import string
|
||||
import re
|
||||
import sys
|
||||
|
||||
# Reason last stmt is continued (or C_NONE if it's not).
|
||||
C_NONE, C_BACKSLASH, C_STRING, C_BRACKET = list(range(4))
|
||||
|
||||
if 0: # for throwaway debugging output
|
||||
def dump(*stuff):
|
||||
sys.__stdout__.write(" ".join(map(str, stuff)) + "\n")
|
||||
|
||||
# Find what looks like the start of a popular stmt.
|
||||
|
||||
_synchre = re.compile(r"""
|
||||
^
|
||||
[ \t]*
|
||||
(?: if
|
||||
| for
|
||||
| while
|
||||
| else
|
||||
| def
|
||||
| return
|
||||
| assert
|
||||
| break
|
||||
| class
|
||||
| continue
|
||||
| elif
|
||||
| try
|
||||
| except
|
||||
| raise
|
||||
| import
|
||||
)
|
||||
\b
|
||||
""", re.VERBOSE | re.MULTILINE).search
|
||||
|
||||
# Match blank line or non-indenting comment line.
|
||||
|
||||
_junkre = re.compile(r"""
|
||||
[ \t]*
|
||||
(?: \# \S .* )?
|
||||
\n
|
||||
""", re.VERBOSE).match
|
||||
|
||||
# Match any flavor of string; the terminating quote is optional
|
||||
# so that we're robust in the face of incomplete program text.
|
||||
|
||||
_match_stringre = re.compile(r"""
|
||||
\""" [^"\\]* (?:
|
||||
(?: \\. | "(?!"") )
|
||||
[^"\\]*
|
||||
)*
|
||||
(?: \""" )?
|
||||
|
||||
| " [^"\\\n]* (?: \\. [^"\\\n]* )* "?
|
||||
|
||||
| ''' [^'\\]* (?:
|
||||
(?: \\. | '(?!'') )
|
||||
[^'\\]*
|
||||
)*
|
||||
(?: ''' )?
|
||||
|
||||
| ' [^'\\\n]* (?: \\. [^'\\\n]* )* '?
|
||||
""", re.VERBOSE | re.DOTALL).match
|
||||
|
||||
# Match a line that starts with something interesting;
|
||||
# used to find the first item of a bracket structure.
|
||||
|
||||
_itemre = re.compile(r"""
|
||||
[ \t]*
|
||||
[^\s#\\] # if we match, m.end()-1 is the interesting char
|
||||
""", re.VERBOSE).match
|
||||
|
||||
# Match start of stmts that should be followed by a dedent.
|
||||
|
||||
_closere = re.compile(r"""
|
||||
\s*
|
||||
(?: return
|
||||
| break
|
||||
| continue
|
||||
| raise
|
||||
| pass
|
||||
)
|
||||
\b
|
||||
""", re.VERBOSE).match
|
||||
|
||||
# Chew up non-special chars as quickly as possible. If match is
|
||||
# successful, m.end() less 1 is the index of the last boring char
|
||||
# matched. If match is unsuccessful, the string starts with an
|
||||
# interesting char.
|
||||
|
||||
_chew_ordinaryre = re.compile(r"""
|
||||
[^[\](){}#'"\\]+
|
||||
""", re.VERBOSE).match
|
||||
|
||||
# Build translation table to map uninteresting chars to "x", open
|
||||
# brackets to "(", and close brackets to ")".
|
||||
|
||||
_tran = ['x'] * 256
|
||||
for ch in "({[":
|
||||
_tran[ord(ch)] = '('
|
||||
for ch in ")}]":
|
||||
_tran[ord(ch)] = ')'
|
||||
for ch in "\"'\\\n#":
|
||||
_tran[ord(ch)] = ch
|
||||
# We are called with unicode strings, and str.translate is one of the few
|
||||
# py2k functions which can't 'do the right thing' - so take care to ensure
|
||||
# _tran is full of unicode...
|
||||
_tran = ''.join(_tran)
|
||||
del ch
|
||||
|
||||
class Parser:
|
||||
|
||||
def __init__(self, indentwidth, tabwidth):
|
||||
self.indentwidth = indentwidth
|
||||
self.tabwidth = tabwidth
|
||||
|
||||
def set_str(self, str):
|
||||
assert len(str) == 0 or str[-1] == '\n', "Oops - have str %r" % (str,)
|
||||
self.str = str
|
||||
self.study_level = 0
|
||||
|
||||
# Return index of a good place to begin parsing, as close to the
|
||||
# end of the string as possible. This will be the start of some
|
||||
# popular stmt like "if" or "def". Return None if none found:
|
||||
# the caller should pass more prior context then, if possible, or
|
||||
# if not (the entire program text up until the point of interest
|
||||
# has already been tried) pass 0 to set_lo.
|
||||
#
|
||||
# This will be reliable iff given a reliable is_char_in_string
|
||||
# function, meaning that when it says "no", it's absolutely
|
||||
# guaranteed that the char is not in a string.
|
||||
#
|
||||
# Ack, hack: in the shell window this kills us, because there's
|
||||
# no way to tell the differences between output, >>> etc and
|
||||
# user input. Indeed, IDLE's first output line makes the rest
|
||||
# look like it's in an unclosed paren!:
|
||||
# Python 1.5.2 (#0, Apr 13 1999, ...
|
||||
|
||||
def find_good_parse_start(self, use_ps1, is_char_in_string=None):
|
||||
str, pos = self.str, None
|
||||
if use_ps1:
|
||||
# shell window
|
||||
ps1 = '\n' + sys.ps1
|
||||
i = str.rfind(ps1)
|
||||
if i >= 0:
|
||||
pos = i + len(ps1)
|
||||
# make it look like there's a newline instead
|
||||
# of ps1 at the start -- hacking here once avoids
|
||||
# repeated hackery later
|
||||
self.str = str[:pos-1] + '\n' + str[pos:]
|
||||
return pos
|
||||
|
||||
# File window -- real work.
|
||||
if not is_char_in_string:
|
||||
# no clue -- make the caller pass everything
|
||||
return None
|
||||
|
||||
# Peek back from the end for a good place to start,
|
||||
# but don't try too often; pos will be left None, or
|
||||
# bumped to a legitimate synch point.
|
||||
limit = len(str)
|
||||
for tries in range(5):
|
||||
i = str.rfind(":\n", 0, limit)
|
||||
if i < 0:
|
||||
break
|
||||
i = str.rfind('\n', 0, i) + 1 # start of colon line
|
||||
m = _synchre(str, i, limit)
|
||||
if m and not is_char_in_string(m.start()):
|
||||
pos = m.start()
|
||||
break
|
||||
limit = i
|
||||
if pos is None:
|
||||
# Nothing looks like a block-opener, or stuff does
|
||||
# but is_char_in_string keeps returning true; most likely
|
||||
# we're in or near a giant string, the colorizer hasn't
|
||||
# caught up enough to be helpful, or there simply *aren't*
|
||||
# any interesting stmts. In any of these cases we're
|
||||
# going to have to parse the whole thing to be sure, so
|
||||
# give it one last try from the start, but stop wasting
|
||||
# time here regardless of the outcome.
|
||||
m = _synchre(str)
|
||||
if m and not is_char_in_string(m.start()):
|
||||
pos = m.start()
|
||||
return pos
|
||||
|
||||
# Peeking back worked; look forward until _synchre no longer
|
||||
# matches.
|
||||
i = pos + 1
|
||||
while 1:
|
||||
m = _synchre(str, i)
|
||||
if m:
|
||||
s, i = m.span()
|
||||
if not is_char_in_string(s):
|
||||
pos = s
|
||||
else:
|
||||
break
|
||||
return pos
|
||||
|
||||
# Throw away the start of the string. Intended to be called with
|
||||
# find_good_parse_start's result.
|
||||
|
||||
def set_lo(self, lo):
|
||||
assert lo == 0 or self.str[lo-1] == '\n'
|
||||
if lo > 0:
|
||||
self.str = self.str[lo:]
|
||||
|
||||
# As quickly as humanly possible <wink>, find the line numbers (0-
|
||||
# based) of the non-continuation lines.
|
||||
# Creates self.{goodlines, continuation}.
|
||||
|
||||
def _study1(self):
|
||||
if self.study_level >= 1:
|
||||
return
|
||||
self.study_level = 1
|
||||
|
||||
# Map all uninteresting characters to "x", all open brackets
|
||||
# to "(", all close brackets to ")", then collapse runs of
|
||||
# uninteresting characters. This can cut the number of chars
|
||||
# by a factor of 10-40, and so greatly speed the following loop.
|
||||
str = self.str
|
||||
str = str.translate(_tran)
|
||||
str = str.replace('xxxxxxxx', 'x')
|
||||
str = str.replace('xxxx', 'x')
|
||||
str = str.replace('xx', 'x')
|
||||
str = str.replace('xx', 'x')
|
||||
str = str.replace('\nx', '\n')
|
||||
# note that replacing x\n with \n would be incorrect, because
|
||||
# x may be preceded by a backslash
|
||||
|
||||
# March over the squashed version of the program, accumulating
|
||||
# the line numbers of non-continued stmts, and determining
|
||||
# whether & why the last stmt is a continuation.
|
||||
continuation = C_NONE
|
||||
level = lno = 0 # level is nesting level; lno is line number
|
||||
self.goodlines = goodlines = [0]
|
||||
push_good = goodlines.append
|
||||
i, n = 0, len(str)
|
||||
while i < n:
|
||||
ch = str[i]
|
||||
i = i+1
|
||||
|
||||
# cases are checked in decreasing order of frequency
|
||||
if ch == 'x':
|
||||
continue
|
||||
|
||||
if ch == '\n':
|
||||
lno = lno + 1
|
||||
if level == 0:
|
||||
push_good(lno)
|
||||
# else we're in an unclosed bracket structure
|
||||
continue
|
||||
|
||||
if ch == '(':
|
||||
level = level + 1
|
||||
continue
|
||||
|
||||
if ch == ')':
|
||||
if level:
|
||||
level = level - 1
|
||||
# else the program is invalid, but we can't complain
|
||||
continue
|
||||
|
||||
if ch == '"' or ch == "'":
|
||||
# consume the string
|
||||
quote = ch
|
||||
if str[i-1:i+2] == quote * 3:
|
||||
quote = quote * 3
|
||||
w = len(quote) - 1
|
||||
i = i+w
|
||||
while i < n:
|
||||
ch = str[i]
|
||||
i = i+1
|
||||
|
||||
if ch == 'x':
|
||||
continue
|
||||
|
||||
if str[i-1:i+w] == quote:
|
||||
i = i+w
|
||||
break
|
||||
|
||||
if ch == '\n':
|
||||
lno = lno + 1
|
||||
if w == 0:
|
||||
# unterminated single-quoted string
|
||||
if level == 0:
|
||||
push_good(lno)
|
||||
break
|
||||
continue
|
||||
|
||||
if ch == '\\':
|
||||
assert i < n
|
||||
if str[i] == '\n':
|
||||
lno = lno + 1
|
||||
i = i+1
|
||||
continue
|
||||
|
||||
# else comment char or paren inside string
|
||||
|
||||
else:
|
||||
# didn't break out of the loop, so we're still
|
||||
# inside a string
|
||||
continuation = C_STRING
|
||||
continue # with outer loop
|
||||
|
||||
if ch == '#':
|
||||
# consume the comment
|
||||
i = str.find('\n', i)
|
||||
assert i >= 0
|
||||
continue
|
||||
|
||||
assert ch == '\\'
|
||||
assert i < n
|
||||
if str[i] == '\n':
|
||||
lno = lno + 1
|
||||
if i+1 == n:
|
||||
continuation = C_BACKSLASH
|
||||
i = i+1
|
||||
|
||||
# The last stmt may be continued for all 3 reasons.
|
||||
# String continuation takes precedence over bracket
|
||||
# continuation, which beats backslash continuation.
|
||||
if continuation != C_STRING and level > 0:
|
||||
continuation = C_BRACKET
|
||||
self.continuation = continuation
|
||||
|
||||
# Push the final line number as a sentinel value, regardless of
|
||||
# whether it's continued.
|
||||
assert (continuation == C_NONE) == (goodlines[-1] == lno)
|
||||
if goodlines[-1] != lno:
|
||||
push_good(lno)
|
||||
|
||||
def get_continuation_type(self):
|
||||
self._study1()
|
||||
return self.continuation
|
||||
|
||||
# study1 was sufficient to determine the continuation status,
|
||||
# but doing more requires looking at every character. study2
|
||||
# does this for the last interesting statement in the block.
|
||||
# Creates:
|
||||
# self.stmt_start, stmt_end
|
||||
# slice indices of last interesting stmt
|
||||
# self.lastch
|
||||
# last non-whitespace character before optional trailing
|
||||
# comment
|
||||
# self.lastopenbracketpos
|
||||
# if continuation is C_BRACKET, index of last open bracket
|
||||
|
||||
def _study2(self):
|
||||
_ws=string.whitespace
|
||||
if self.study_level >= 2:
|
||||
return
|
||||
self._study1()
|
||||
self.study_level = 2
|
||||
|
||||
# Set p and q to slice indices of last interesting stmt.
|
||||
str, goodlines = self.str, self.goodlines
|
||||
i = len(goodlines) - 1
|
||||
p = len(str) # index of newest line
|
||||
while i:
|
||||
assert p
|
||||
# p is the index of the stmt at line number goodlines[i].
|
||||
# Move p back to the stmt at line number goodlines[i-1].
|
||||
q = p
|
||||
for nothing in range(goodlines[i-1], goodlines[i]):
|
||||
# tricky: sets p to 0 if no preceding newline
|
||||
p = str.rfind('\n', 0, p-1) + 1
|
||||
# The stmt str[p:q] isn't a continuation, but may be blank
|
||||
# or a non-indenting comment line.
|
||||
if _junkre(str, p):
|
||||
i = i-1
|
||||
else:
|
||||
break
|
||||
if i == 0:
|
||||
# nothing but junk!
|
||||
assert p == 0
|
||||
q = p
|
||||
self.stmt_start, self.stmt_end = p, q
|
||||
|
||||
# Analyze this stmt, to find the last open bracket (if any)
|
||||
# and last interesting character (if any).
|
||||
lastch = ""
|
||||
stack = [] # stack of open bracket indices
|
||||
push_stack = stack.append
|
||||
while p < q:
|
||||
# suck up all except ()[]{}'"#\\
|
||||
m = _chew_ordinaryre(str, p, q)
|
||||
if m:
|
||||
# we skipped at least one boring char
|
||||
newp = m.end()
|
||||
# back up over totally boring whitespace
|
||||
i = newp - 1 # index of last boring char
|
||||
while i >= p and str[i] in " \t\n":
|
||||
i = i-1
|
||||
if i >= p:
|
||||
lastch = str[i]
|
||||
p = newp
|
||||
if p >= q:
|
||||
break
|
||||
|
||||
ch = str[p]
|
||||
|
||||
if ch in "([{":
|
||||
push_stack(p)
|
||||
lastch = ch
|
||||
p = p+1
|
||||
continue
|
||||
|
||||
if ch in ")]}":
|
||||
if stack:
|
||||
del stack[-1]
|
||||
lastch = ch
|
||||
p = p+1
|
||||
continue
|
||||
|
||||
if ch == '"' or ch == "'":
|
||||
# consume string
|
||||
# Note that study1 did this with a Python loop, but
|
||||
# we use a regexp here; the reason is speed in both
|
||||
# cases; the string may be huge, but study1 pre-squashed
|
||||
# strings to a couple of characters per line. study1
|
||||
# also needed to keep track of newlines, and we don't
|
||||
# have to.
|
||||
lastch = ch
|
||||
p = _match_stringre(str, p, q).end()
|
||||
continue
|
||||
|
||||
if ch == '#':
|
||||
# consume comment and trailing newline
|
||||
p = str.find('\n', p, q) + 1
|
||||
assert p > 0
|
||||
continue
|
||||
|
||||
assert ch == '\\'
|
||||
p = p+1 # beyond backslash
|
||||
assert p < q
|
||||
if str[p] != '\n':
|
||||
# the program is invalid, but can't complain
|
||||
lastch = ch + str[p]
|
||||
p = p+1 # beyond escaped char
|
||||
|
||||
# end while p < q:
|
||||
|
||||
self.lastch = lastch
|
||||
if stack:
|
||||
self.lastopenbracketpos = stack[-1]
|
||||
|
||||
# Assuming continuation is C_BRACKET, return the number
|
||||
# of spaces the next line should be indented.
|
||||
|
||||
def compute_bracket_indent(self):
|
||||
self._study2()
|
||||
assert self.continuation == C_BRACKET
|
||||
j = self.lastopenbracketpos
|
||||
str = self.str
|
||||
n = len(str)
|
||||
origi = i = str.rfind('\n', 0, j) + 1
|
||||
j = j+1 # one beyond open bracket
|
||||
# find first list item; set i to start of its line
|
||||
while j < n:
|
||||
m = _itemre(str, j)
|
||||
if m:
|
||||
j = m.end() - 1 # index of first interesting char
|
||||
extra = 0
|
||||
break
|
||||
else:
|
||||
# this line is junk; advance to next line
|
||||
i = j = str.find('\n', j) + 1
|
||||
else:
|
||||
# nothing interesting follows the bracket;
|
||||
# reproduce the bracket line's indentation + a level
|
||||
j = i = origi
|
||||
while str[j] in " \t":
|
||||
j = j+1
|
||||
extra = self.indentwidth
|
||||
return len(str[i:j].expandtabs(self.tabwidth)) + extra
|
||||
|
||||
# Return number of physical lines in last stmt (whether or not
|
||||
# it's an interesting stmt! this is intended to be called when
|
||||
# continuation is C_BACKSLASH).
|
||||
|
||||
def get_num_lines_in_stmt(self):
|
||||
self._study1()
|
||||
goodlines = self.goodlines
|
||||
return goodlines[-1] - goodlines[-2]
|
||||
|
||||
# Assuming continuation is C_BACKSLASH, return the number of spaces
|
||||
# the next line should be indented. Also assuming the new line is
|
||||
# the first one following the initial line of the stmt.
|
||||
|
||||
def compute_backslash_indent(self):
|
||||
self._study2()
|
||||
assert self.continuation == C_BACKSLASH
|
||||
str = self.str
|
||||
i = self.stmt_start
|
||||
while str[i] in " \t":
|
||||
i = i+1
|
||||
startpos = i
|
||||
|
||||
# See whether the initial line starts an assignment stmt; i.e.,
|
||||
# look for an = operator
|
||||
endpos = str.find('\n', startpos) + 1
|
||||
found = level = 0
|
||||
while i < endpos:
|
||||
ch = str[i]
|
||||
if ch in "([{":
|
||||
level = level + 1
|
||||
i = i+1
|
||||
elif ch in ")]}":
|
||||
if level:
|
||||
level = level - 1
|
||||
i = i+1
|
||||
elif ch == '"' or ch == "'":
|
||||
i = _match_stringre(str, i, endpos).end()
|
||||
elif ch == '#':
|
||||
break
|
||||
elif level == 0 and ch == '=' and \
|
||||
(i == 0 or str[i-1] not in "=<>!") and \
|
||||
str[i+1] != '=':
|
||||
found = 1
|
||||
break
|
||||
else:
|
||||
i = i+1
|
||||
|
||||
if found:
|
||||
# found a legit =, but it may be the last interesting
|
||||
# thing on the line
|
||||
i = i+1 # move beyond the =
|
||||
found = re.match(r"\s*\\", str[i:endpos]) is None
|
||||
|
||||
if not found:
|
||||
# oh well ... settle for moving beyond the first chunk
|
||||
# of non-whitespace chars
|
||||
i = startpos
|
||||
while str[i] not in " \t\n":
|
||||
i = i+1
|
||||
|
||||
return len(str[self.stmt_start : i].expandtabs(self.tabwidth)) + 1
|
||||
|
||||
# Return the leading whitespace on the initial line of the last
|
||||
# interesting stmt.
|
||||
|
||||
def get_base_indent_string(self):
|
||||
self._study2()
|
||||
i, n = self.stmt_start, self.stmt_end
|
||||
j = i
|
||||
str = self.str
|
||||
while j < n and str[j] in " \t":
|
||||
j = j + 1
|
||||
return str[i:j]
|
||||
|
||||
# Did the last interesting stmt open a block?
|
||||
|
||||
def is_block_opener(self):
|
||||
self._study2()
|
||||
return self.lastch == ':'
|
||||
|
||||
# Did the last interesting stmt close a block?
|
||||
|
||||
def is_block_closer(self):
|
||||
self._study2()
|
||||
return _closere(self.str, self.stmt_start) is not None
|
||||
|
||||
# index of last open bracket ({[, or None if none
|
||||
lastopenbracketpos = None
|
||||
|
||||
def get_last_open_bracket_pos(self):
|
||||
self._study2()
|
||||
return self.lastopenbracketpos
|
||||
1
Lib/site-packages/pythonwin/pywin/idle/__init__.py
Normal file
1
Lib/site-packages/pythonwin/pywin/idle/__init__.py
Normal file
|
|
@ -0,0 +1 @@
|
|||
# This file denotes the directory as a Python package.
|
||||
0
Lib/site-packages/pythonwin/pywin/mfc/__init__.py
Normal file
0
Lib/site-packages/pythonwin/pywin/mfc/__init__.py
Normal file
75
Lib/site-packages/pythonwin/pywin/mfc/activex.py
Normal file
75
Lib/site-packages/pythonwin/pywin/mfc/activex.py
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
"""Support for ActiveX control hosting in Pythonwin.
|
||||
"""
|
||||
import win32ui, win32uiole
|
||||
from . import window
|
||||
# XXX - we are still "classic style" classes in py2x, so we need can't yet
|
||||
# use 'type()' everywhere - revisit soon, as py2x will move to new-style too...
|
||||
try:
|
||||
from types import ClassType as new_type
|
||||
except ImportError:
|
||||
new_type = type # py3k
|
||||
|
||||
class Control(window.Wnd):
|
||||
"""An ActiveX control base class. A new class must be derived from both
|
||||
this class and the Events class. See the demos for more details.
|
||||
"""
|
||||
def __init__(self):
|
||||
self.__dict__["_dispobj_"] = None
|
||||
window.Wnd.__init__(self)
|
||||
|
||||
def _GetControlCLSID( self ):
|
||||
return self.CLSID
|
||||
def _GetDispatchClass(self):
|
||||
return self.default_interface
|
||||
def _GetEventMap(self):
|
||||
return self.default_source._dispid_to_func_
|
||||
|
||||
def CreateControl(self, windowTitle, style, rect, parent, id, lic_string=None):
|
||||
clsid = str(self._GetControlCLSID())
|
||||
self.__dict__["_obj_"] = win32ui.CreateControl(clsid, windowTitle, style, rect, parent, id, None, False, lic_string)
|
||||
klass = self._GetDispatchClass()
|
||||
dispobj = klass(win32uiole.GetIDispatchForWindow(self._obj_))
|
||||
self.HookOleEvents()
|
||||
self.__dict__["_dispobj_"] = dispobj
|
||||
|
||||
def HookOleEvents(self):
|
||||
dict = self._GetEventMap()
|
||||
for dispid, methodName in dict.items():
|
||||
if hasattr(self, methodName):
|
||||
self._obj_.HookOleEvent( getattr(self, methodName), dispid )
|
||||
|
||||
def __getattr__(self, attr):
|
||||
# Delegate attributes to the windows and the Dispatch object for this class
|
||||
try:
|
||||
return window.Wnd.__getattr__(self, attr)
|
||||
except AttributeError:
|
||||
pass
|
||||
return getattr(self._dispobj_, attr)
|
||||
def __setattr__(self, attr, value):
|
||||
if hasattr(self.__dict__, attr):
|
||||
self.__dict__[attr] = value
|
||||
return
|
||||
try:
|
||||
if self._dispobj_:
|
||||
self._dispobj_.__setattr__(attr, value)
|
||||
return
|
||||
except AttributeError:
|
||||
pass
|
||||
self.__dict__[attr] = value
|
||||
|
||||
def MakeControlClass( controlClass, name = None ):
|
||||
"""Given a CoClass in a generated .py file, this function will return a Class
|
||||
object which can be used as an OCX control.
|
||||
|
||||
This function is used when you do not want to handle any events from the OCX
|
||||
control. If you need events, then you should derive a class from both the
|
||||
activex.Control class and the CoClass
|
||||
"""
|
||||
if name is None:
|
||||
name = controlClass.__name__
|
||||
return new_type("OCX" + name, (Control, controlClass), {})
|
||||
|
||||
def MakeControlInstance( controlClass, name = None ):
|
||||
"""As for MakeControlClass(), but returns an instance of the class.
|
||||
"""
|
||||
return MakeControlClass(controlClass, name)()
|
||||
497
Lib/site-packages/pythonwin/pywin/mfc/afxres.py
Normal file
497
Lib/site-packages/pythonwin/pywin/mfc/afxres.py
Normal file
|
|
@ -0,0 +1,497 @@
|
|||
# Generated by h2py from stdin
|
||||
TCS_MULTILINE = 0x0200
|
||||
CBRS_ALIGN_LEFT = 0x1000
|
||||
CBRS_ALIGN_TOP = 0x2000
|
||||
CBRS_ALIGN_RIGHT = 0x4000
|
||||
CBRS_ALIGN_BOTTOM = 0x8000
|
||||
CBRS_ALIGN_ANY = 0xF000
|
||||
CBRS_BORDER_LEFT = 0x0100
|
||||
CBRS_BORDER_TOP = 0x0200
|
||||
CBRS_BORDER_RIGHT = 0x0400
|
||||
CBRS_BORDER_BOTTOM = 0x0800
|
||||
CBRS_BORDER_ANY = 0x0F00
|
||||
CBRS_TOOLTIPS = 0x0010
|
||||
CBRS_FLYBY = 0x0020
|
||||
CBRS_FLOAT_MULTI = 0x0040
|
||||
CBRS_BORDER_3D = 0x0080
|
||||
CBRS_HIDE_INPLACE = 0x0008
|
||||
CBRS_SIZE_DYNAMIC = 0x0004
|
||||
CBRS_SIZE_FIXED = 0x0002
|
||||
CBRS_FLOATING = 0x0001
|
||||
CBRS_GRIPPER = 0x00400000
|
||||
CBRS_ORIENT_HORZ = (CBRS_ALIGN_TOP|CBRS_ALIGN_BOTTOM)
|
||||
CBRS_ORIENT_VERT = (CBRS_ALIGN_LEFT|CBRS_ALIGN_RIGHT)
|
||||
CBRS_ORIENT_ANY = (CBRS_ORIENT_HORZ|CBRS_ORIENT_VERT)
|
||||
CBRS_ALL = 0xFFFF
|
||||
CBRS_NOALIGN = 0x00000000
|
||||
CBRS_LEFT = (CBRS_ALIGN_LEFT|CBRS_BORDER_RIGHT)
|
||||
CBRS_TOP = (CBRS_ALIGN_TOP|CBRS_BORDER_BOTTOM)
|
||||
CBRS_RIGHT = (CBRS_ALIGN_RIGHT|CBRS_BORDER_LEFT)
|
||||
CBRS_BOTTOM = (CBRS_ALIGN_BOTTOM|CBRS_BORDER_TOP)
|
||||
SBPS_NORMAL = 0x0000
|
||||
SBPS_NOBORDERS = 0x0100
|
||||
SBPS_POPOUT = 0x0200
|
||||
SBPS_OWNERDRAW = 0x1000
|
||||
SBPS_DISABLED = 0x04000000
|
||||
SBPS_STRETCH = 0x08000000
|
||||
ID_INDICATOR_EXT = 0xE700
|
||||
ID_INDICATOR_CAPS = 0xE701
|
||||
ID_INDICATOR_NUM = 0xE702
|
||||
ID_INDICATOR_SCRL = 0xE703
|
||||
ID_INDICATOR_OVR = 0xE704
|
||||
ID_INDICATOR_REC = 0xE705
|
||||
ID_INDICATOR_KANA = 0xE706
|
||||
ID_SEPARATOR = 0
|
||||
AFX_IDW_CONTROLBAR_FIRST = 0xE800
|
||||
AFX_IDW_CONTROLBAR_LAST = 0xE8FF
|
||||
AFX_IDW_TOOLBAR = 0xE800
|
||||
AFX_IDW_STATUS_BAR = 0xE801
|
||||
AFX_IDW_PREVIEW_BAR = 0xE802
|
||||
AFX_IDW_RESIZE_BAR = 0xE803
|
||||
AFX_IDW_DOCKBAR_TOP = 0xE81B
|
||||
AFX_IDW_DOCKBAR_LEFT = 0xE81C
|
||||
AFX_IDW_DOCKBAR_RIGHT = 0xE81D
|
||||
AFX_IDW_DOCKBAR_BOTTOM = 0xE81E
|
||||
AFX_IDW_DOCKBAR_FLOAT = 0xE81F
|
||||
def AFX_CONTROLBAR_MASK(nIDC): return (1 << (nIDC - AFX_IDW_CONTROLBAR_FIRST))
|
||||
|
||||
AFX_IDW_PANE_FIRST = 0xE900
|
||||
AFX_IDW_PANE_LAST = 0xE9ff
|
||||
AFX_IDW_HSCROLL_FIRST = 0xEA00
|
||||
AFX_IDW_VSCROLL_FIRST = 0xEA10
|
||||
AFX_IDW_SIZE_BOX = 0xEA20
|
||||
AFX_IDW_PANE_SAVE = 0xEA21
|
||||
AFX_IDS_APP_TITLE = 0xE000
|
||||
AFX_IDS_IDLEMESSAGE = 0xE001
|
||||
AFX_IDS_HELPMODEMESSAGE = 0xE002
|
||||
AFX_IDS_APP_TITLE_EMBEDDING = 0xE003
|
||||
AFX_IDS_COMPANY_NAME = 0xE004
|
||||
AFX_IDS_OBJ_TITLE_INPLACE = 0xE005
|
||||
ID_FILE_NEW = 0xE100
|
||||
ID_FILE_OPEN = 0xE101
|
||||
ID_FILE_CLOSE = 0xE102
|
||||
ID_FILE_SAVE = 0xE103
|
||||
ID_FILE_SAVE_AS = 0xE104
|
||||
ID_FILE_PAGE_SETUP = 0xE105
|
||||
ID_FILE_PRINT_SETUP = 0xE106
|
||||
ID_FILE_PRINT = 0xE107
|
||||
ID_FILE_PRINT_DIRECT = 0xE108
|
||||
ID_FILE_PRINT_PREVIEW = 0xE109
|
||||
ID_FILE_UPDATE = 0xE10A
|
||||
ID_FILE_SAVE_COPY_AS = 0xE10B
|
||||
ID_FILE_SEND_MAIL = 0xE10C
|
||||
ID_FILE_MRU_FIRST = 0xE110
|
||||
ID_FILE_MRU_FILE1 = 0xE110
|
||||
ID_FILE_MRU_FILE2 = 0xE111
|
||||
ID_FILE_MRU_FILE3 = 0xE112
|
||||
ID_FILE_MRU_FILE4 = 0xE113
|
||||
ID_FILE_MRU_FILE5 = 0xE114
|
||||
ID_FILE_MRU_FILE6 = 0xE115
|
||||
ID_FILE_MRU_FILE7 = 0xE116
|
||||
ID_FILE_MRU_FILE8 = 0xE117
|
||||
ID_FILE_MRU_FILE9 = 0xE118
|
||||
ID_FILE_MRU_FILE10 = 0xE119
|
||||
ID_FILE_MRU_FILE11 = 0xE11A
|
||||
ID_FILE_MRU_FILE12 = 0xE11B
|
||||
ID_FILE_MRU_FILE13 = 0xE11C
|
||||
ID_FILE_MRU_FILE14 = 0xE11D
|
||||
ID_FILE_MRU_FILE15 = 0xE11E
|
||||
ID_FILE_MRU_FILE16 = 0xE11F
|
||||
ID_FILE_MRU_LAST = 0xE11F
|
||||
ID_EDIT_CLEAR = 0xE120
|
||||
ID_EDIT_CLEAR_ALL = 0xE121
|
||||
ID_EDIT_COPY = 0xE122
|
||||
ID_EDIT_CUT = 0xE123
|
||||
ID_EDIT_FIND = 0xE124
|
||||
ID_EDIT_PASTE = 0xE125
|
||||
ID_EDIT_PASTE_LINK = 0xE126
|
||||
ID_EDIT_PASTE_SPECIAL = 0xE127
|
||||
ID_EDIT_REPEAT = 0xE128
|
||||
ID_EDIT_REPLACE = 0xE129
|
||||
ID_EDIT_SELECT_ALL = 0xE12A
|
||||
ID_EDIT_UNDO = 0xE12B
|
||||
ID_EDIT_REDO = 0xE12C
|
||||
ID_WINDOW_NEW = 0xE130
|
||||
ID_WINDOW_ARRANGE = 0xE131
|
||||
ID_WINDOW_CASCADE = 0xE132
|
||||
ID_WINDOW_TILE_HORZ = 0xE133
|
||||
ID_WINDOW_TILE_VERT = 0xE134
|
||||
ID_WINDOW_SPLIT = 0xE135
|
||||
AFX_IDM_WINDOW_FIRST = 0xE130
|
||||
AFX_IDM_WINDOW_LAST = 0xE13F
|
||||
AFX_IDM_FIRST_MDICHILD = 0xFF00
|
||||
ID_APP_ABOUT = 0xE140
|
||||
ID_APP_EXIT = 0xE141
|
||||
ID_HELP_INDEX = 0xE142
|
||||
ID_HELP_FINDER = 0xE143
|
||||
ID_HELP_USING = 0xE144
|
||||
ID_CONTEXT_HELP = 0xE145
|
||||
ID_HELP = 0xE146
|
||||
ID_DEFAULT_HELP = 0xE147
|
||||
ID_NEXT_PANE = 0xE150
|
||||
ID_PREV_PANE = 0xE151
|
||||
ID_FORMAT_FONT = 0xE160
|
||||
ID_OLE_INSERT_NEW = 0xE200
|
||||
ID_OLE_EDIT_LINKS = 0xE201
|
||||
ID_OLE_EDIT_CONVERT = 0xE202
|
||||
ID_OLE_EDIT_CHANGE_ICON = 0xE203
|
||||
ID_OLE_EDIT_PROPERTIES = 0xE204
|
||||
ID_OLE_VERB_FIRST = 0xE210
|
||||
ID_OLE_VERB_LAST = 0xE21F
|
||||
AFX_ID_PREVIEW_CLOSE = 0xE300
|
||||
AFX_ID_PREVIEW_NUMPAGE = 0xE301
|
||||
AFX_ID_PREVIEW_NEXT = 0xE302
|
||||
AFX_ID_PREVIEW_PREV = 0xE303
|
||||
AFX_ID_PREVIEW_PRINT = 0xE304
|
||||
AFX_ID_PREVIEW_ZOOMIN = 0xE305
|
||||
AFX_ID_PREVIEW_ZOOMOUT = 0xE306
|
||||
ID_VIEW_TOOLBAR = 0xE800
|
||||
ID_VIEW_STATUS_BAR = 0xE801
|
||||
ID_RECORD_FIRST = 0xE900
|
||||
ID_RECORD_LAST = 0xE901
|
||||
ID_RECORD_NEXT = 0xE902
|
||||
ID_RECORD_PREV = 0xE903
|
||||
IDC_STATIC = (-1)
|
||||
AFX_IDS_SCFIRST = 0xEF00
|
||||
AFX_IDS_SCSIZE = 0xEF00
|
||||
AFX_IDS_SCMOVE = 0xEF01
|
||||
AFX_IDS_SCMINIMIZE = 0xEF02
|
||||
AFX_IDS_SCMAXIMIZE = 0xEF03
|
||||
AFX_IDS_SCNEXTWINDOW = 0xEF04
|
||||
AFX_IDS_SCPREVWINDOW = 0xEF05
|
||||
AFX_IDS_SCCLOSE = 0xEF06
|
||||
AFX_IDS_SCRESTORE = 0xEF12
|
||||
AFX_IDS_SCTASKLIST = 0xEF13
|
||||
AFX_IDS_MDICHILD = 0xEF1F
|
||||
AFX_IDS_DESKACCESSORY = 0xEFDA
|
||||
AFX_IDS_OPENFILE = 0xF000
|
||||
AFX_IDS_SAVEFILE = 0xF001
|
||||
AFX_IDS_ALLFILTER = 0xF002
|
||||
AFX_IDS_UNTITLED = 0xF003
|
||||
AFX_IDS_SAVEFILECOPY = 0xF004
|
||||
AFX_IDS_PREVIEW_CLOSE = 0xF005
|
||||
AFX_IDS_UNNAMED_FILE = 0xF006
|
||||
AFX_IDS_ABOUT = 0xF010
|
||||
AFX_IDS_HIDE = 0xF011
|
||||
AFX_IDP_NO_ERROR_AVAILABLE = 0xF020
|
||||
AFX_IDS_NOT_SUPPORTED_EXCEPTION = 0xF021
|
||||
AFX_IDS_RESOURCE_EXCEPTION = 0xF022
|
||||
AFX_IDS_MEMORY_EXCEPTION = 0xF023
|
||||
AFX_IDS_USER_EXCEPTION = 0xF024
|
||||
AFX_IDS_PRINTONPORT = 0xF040
|
||||
AFX_IDS_ONEPAGE = 0xF041
|
||||
AFX_IDS_TWOPAGE = 0xF042
|
||||
AFX_IDS_PRINTPAGENUM = 0xF043
|
||||
AFX_IDS_PREVIEWPAGEDESC = 0xF044
|
||||
AFX_IDS_PRINTDEFAULTEXT = 0xF045
|
||||
AFX_IDS_PRINTDEFAULT = 0xF046
|
||||
AFX_IDS_PRINTFILTER = 0xF047
|
||||
AFX_IDS_PRINTCAPTION = 0xF048
|
||||
AFX_IDS_PRINTTOFILE = 0xF049
|
||||
AFX_IDS_OBJECT_MENUITEM = 0xF080
|
||||
AFX_IDS_EDIT_VERB = 0xF081
|
||||
AFX_IDS_ACTIVATE_VERB = 0xF082
|
||||
AFX_IDS_CHANGE_LINK = 0xF083
|
||||
AFX_IDS_AUTO = 0xF084
|
||||
AFX_IDS_MANUAL = 0xF085
|
||||
AFX_IDS_FROZEN = 0xF086
|
||||
AFX_IDS_ALL_FILES = 0xF087
|
||||
AFX_IDS_SAVE_MENU = 0xF088
|
||||
AFX_IDS_UPDATE_MENU = 0xF089
|
||||
AFX_IDS_SAVE_AS_MENU = 0xF08A
|
||||
AFX_IDS_SAVE_COPY_AS_MENU = 0xF08B
|
||||
AFX_IDS_EXIT_MENU = 0xF08C
|
||||
AFX_IDS_UPDATING_ITEMS = 0xF08D
|
||||
AFX_IDS_METAFILE_FORMAT = 0xF08E
|
||||
AFX_IDS_DIB_FORMAT = 0xF08F
|
||||
AFX_IDS_BITMAP_FORMAT = 0xF090
|
||||
AFX_IDS_LINKSOURCE_FORMAT = 0xF091
|
||||
AFX_IDS_EMBED_FORMAT = 0xF092
|
||||
AFX_IDS_PASTELINKEDTYPE = 0xF094
|
||||
AFX_IDS_UNKNOWNTYPE = 0xF095
|
||||
AFX_IDS_RTF_FORMAT = 0xF096
|
||||
AFX_IDS_TEXT_FORMAT = 0xF097
|
||||
AFX_IDS_INVALID_CURRENCY = 0xF098
|
||||
AFX_IDS_INVALID_DATETIME = 0xF099
|
||||
AFX_IDS_INVALID_DATETIMESPAN = 0xF09A
|
||||
AFX_IDP_INVALID_FILENAME = 0xF100
|
||||
AFX_IDP_FAILED_TO_OPEN_DOC = 0xF101
|
||||
AFX_IDP_FAILED_TO_SAVE_DOC = 0xF102
|
||||
AFX_IDP_ASK_TO_SAVE = 0xF103
|
||||
AFX_IDP_FAILED_TO_CREATE_DOC = 0xF104
|
||||
AFX_IDP_FILE_TOO_LARGE = 0xF105
|
||||
AFX_IDP_FAILED_TO_START_PRINT = 0xF106
|
||||
AFX_IDP_FAILED_TO_LAUNCH_HELP = 0xF107
|
||||
AFX_IDP_INTERNAL_FAILURE = 0xF108
|
||||
AFX_IDP_COMMAND_FAILURE = 0xF109
|
||||
AFX_IDP_FAILED_MEMORY_ALLOC = 0xF10A
|
||||
AFX_IDP_PARSE_INT = 0xF110
|
||||
AFX_IDP_PARSE_REAL = 0xF111
|
||||
AFX_IDP_PARSE_INT_RANGE = 0xF112
|
||||
AFX_IDP_PARSE_REAL_RANGE = 0xF113
|
||||
AFX_IDP_PARSE_STRING_SIZE = 0xF114
|
||||
AFX_IDP_PARSE_RADIO_BUTTON = 0xF115
|
||||
AFX_IDP_PARSE_BYTE = 0xF116
|
||||
AFX_IDP_PARSE_UINT = 0xF117
|
||||
AFX_IDP_PARSE_DATETIME = 0xF118
|
||||
AFX_IDP_PARSE_CURRENCY = 0xF119
|
||||
AFX_IDP_FAILED_INVALID_FORMAT = 0xF120
|
||||
AFX_IDP_FAILED_INVALID_PATH = 0xF121
|
||||
AFX_IDP_FAILED_DISK_FULL = 0xF122
|
||||
AFX_IDP_FAILED_ACCESS_READ = 0xF123
|
||||
AFX_IDP_FAILED_ACCESS_WRITE = 0xF124
|
||||
AFX_IDP_FAILED_IO_ERROR_READ = 0xF125
|
||||
AFX_IDP_FAILED_IO_ERROR_WRITE = 0xF126
|
||||
AFX_IDP_STATIC_OBJECT = 0xF180
|
||||
AFX_IDP_FAILED_TO_CONNECT = 0xF181
|
||||
AFX_IDP_SERVER_BUSY = 0xF182
|
||||
AFX_IDP_BAD_VERB = 0xF183
|
||||
AFX_IDP_FAILED_TO_NOTIFY = 0xF185
|
||||
AFX_IDP_FAILED_TO_LAUNCH = 0xF186
|
||||
AFX_IDP_ASK_TO_UPDATE = 0xF187
|
||||
AFX_IDP_FAILED_TO_UPDATE = 0xF188
|
||||
AFX_IDP_FAILED_TO_REGISTER = 0xF189
|
||||
AFX_IDP_FAILED_TO_AUTO_REGISTER = 0xF18A
|
||||
AFX_IDP_FAILED_TO_CONVERT = 0xF18B
|
||||
AFX_IDP_GET_NOT_SUPPORTED = 0xF18C
|
||||
AFX_IDP_SET_NOT_SUPPORTED = 0xF18D
|
||||
AFX_IDP_ASK_TO_DISCARD = 0xF18E
|
||||
AFX_IDP_FAILED_TO_CREATE = 0xF18F
|
||||
AFX_IDP_FAILED_MAPI_LOAD = 0xF190
|
||||
AFX_IDP_INVALID_MAPI_DLL = 0xF191
|
||||
AFX_IDP_FAILED_MAPI_SEND = 0xF192
|
||||
AFX_IDP_FILE_NONE = 0xF1A0
|
||||
AFX_IDP_FILE_GENERIC = 0xF1A1
|
||||
AFX_IDP_FILE_NOT_FOUND = 0xF1A2
|
||||
AFX_IDP_FILE_BAD_PATH = 0xF1A3
|
||||
AFX_IDP_FILE_TOO_MANY_OPEN = 0xF1A4
|
||||
AFX_IDP_FILE_ACCESS_DENIED = 0xF1A5
|
||||
AFX_IDP_FILE_INVALID_FILE = 0xF1A6
|
||||
AFX_IDP_FILE_REMOVE_CURRENT = 0xF1A7
|
||||
AFX_IDP_FILE_DIR_FULL = 0xF1A8
|
||||
AFX_IDP_FILE_BAD_SEEK = 0xF1A9
|
||||
AFX_IDP_FILE_HARD_IO = 0xF1AA
|
||||
AFX_IDP_FILE_SHARING = 0xF1AB
|
||||
AFX_IDP_FILE_LOCKING = 0xF1AC
|
||||
AFX_IDP_FILE_DISKFULL = 0xF1AD
|
||||
AFX_IDP_FILE_EOF = 0xF1AE
|
||||
AFX_IDP_ARCH_NONE = 0xF1B0
|
||||
AFX_IDP_ARCH_GENERIC = 0xF1B1
|
||||
AFX_IDP_ARCH_READONLY = 0xF1B2
|
||||
AFX_IDP_ARCH_ENDOFFILE = 0xF1B3
|
||||
AFX_IDP_ARCH_WRITEONLY = 0xF1B4
|
||||
AFX_IDP_ARCH_BADINDEX = 0xF1B5
|
||||
AFX_IDP_ARCH_BADCLASS = 0xF1B6
|
||||
AFX_IDP_ARCH_BADSCHEMA = 0xF1B7
|
||||
AFX_IDS_OCC_SCALEUNITS_PIXELS = 0xF1C0
|
||||
AFX_IDS_STATUS_FONT = 0xF230
|
||||
AFX_IDS_TOOLTIP_FONT = 0xF231
|
||||
AFX_IDS_UNICODE_FONT = 0xF232
|
||||
AFX_IDS_MINI_FONT = 0xF233
|
||||
AFX_IDP_SQL_FIRST = 0xF280
|
||||
AFX_IDP_SQL_CONNECT_FAIL = 0xF281
|
||||
AFX_IDP_SQL_RECORDSET_FORWARD_ONLY = 0xF282
|
||||
AFX_IDP_SQL_EMPTY_COLUMN_LIST = 0xF283
|
||||
AFX_IDP_SQL_FIELD_SCHEMA_MISMATCH = 0xF284
|
||||
AFX_IDP_SQL_ILLEGAL_MODE = 0xF285
|
||||
AFX_IDP_SQL_MULTIPLE_ROWS_AFFECTED = 0xF286
|
||||
AFX_IDP_SQL_NO_CURRENT_RECORD = 0xF287
|
||||
AFX_IDP_SQL_NO_ROWS_AFFECTED = 0xF288
|
||||
AFX_IDP_SQL_RECORDSET_READONLY = 0xF289
|
||||
AFX_IDP_SQL_SQL_NO_TOTAL = 0xF28A
|
||||
AFX_IDP_SQL_ODBC_LOAD_FAILED = 0xF28B
|
||||
AFX_IDP_SQL_DYNASET_NOT_SUPPORTED = 0xF28C
|
||||
AFX_IDP_SQL_SNAPSHOT_NOT_SUPPORTED = 0xF28D
|
||||
AFX_IDP_SQL_API_CONFORMANCE = 0xF28E
|
||||
AFX_IDP_SQL_SQL_CONFORMANCE = 0xF28F
|
||||
AFX_IDP_SQL_NO_DATA_FOUND = 0xF290
|
||||
AFX_IDP_SQL_ROW_UPDATE_NOT_SUPPORTED = 0xF291
|
||||
AFX_IDP_SQL_ODBC_V2_REQUIRED = 0xF292
|
||||
AFX_IDP_SQL_NO_POSITIONED_UPDATES = 0xF293
|
||||
AFX_IDP_SQL_LOCK_MODE_NOT_SUPPORTED = 0xF294
|
||||
AFX_IDP_SQL_DATA_TRUNCATED = 0xF295
|
||||
AFX_IDP_SQL_ROW_FETCH = 0xF296
|
||||
AFX_IDP_SQL_INCORRECT_ODBC = 0xF297
|
||||
AFX_IDP_SQL_UPDATE_DELETE_FAILED = 0xF298
|
||||
AFX_IDP_SQL_DYNAMIC_CURSOR_NOT_SUPPORTED = 0xF299
|
||||
AFX_IDP_DAO_FIRST = 0xF2A0
|
||||
AFX_IDP_DAO_ENGINE_INITIALIZATION = 0xF2A0
|
||||
AFX_IDP_DAO_DFX_BIND = 0xF2A1
|
||||
AFX_IDP_DAO_OBJECT_NOT_OPEN = 0xF2A2
|
||||
AFX_IDP_DAO_ROWTOOSHORT = 0xF2A3
|
||||
AFX_IDP_DAO_BADBINDINFO = 0xF2A4
|
||||
AFX_IDP_DAO_COLUMNUNAVAILABLE = 0xF2A5
|
||||
AFX_IDC_LISTBOX = 100
|
||||
AFX_IDC_CHANGE = 101
|
||||
AFX_IDC_PRINT_DOCNAME = 201
|
||||
AFX_IDC_PRINT_PRINTERNAME = 202
|
||||
AFX_IDC_PRINT_PORTNAME = 203
|
||||
AFX_IDC_PRINT_PAGENUM = 204
|
||||
ID_APPLY_NOW = 0x3021
|
||||
ID_WIZBACK = 0x3023
|
||||
ID_WIZNEXT = 0x3024
|
||||
ID_WIZFINISH = 0x3025
|
||||
AFX_IDC_TAB_CONTROL = 0x3020
|
||||
AFX_IDD_FILEOPEN = 28676
|
||||
AFX_IDD_FILESAVE = 28677
|
||||
AFX_IDD_FONT = 28678
|
||||
AFX_IDD_COLOR = 28679
|
||||
AFX_IDD_PRINT = 28680
|
||||
AFX_IDD_PRINTSETUP = 28681
|
||||
AFX_IDD_FIND = 28682
|
||||
AFX_IDD_REPLACE = 28683
|
||||
AFX_IDD_NEWTYPEDLG = 30721
|
||||
AFX_IDD_PRINTDLG = 30722
|
||||
AFX_IDD_PREVIEW_TOOLBAR = 30723
|
||||
AFX_IDD_PREVIEW_SHORTTOOLBAR = 30731
|
||||
AFX_IDD_INSERTOBJECT = 30724
|
||||
AFX_IDD_CHANGEICON = 30725
|
||||
AFX_IDD_CONVERT = 30726
|
||||
AFX_IDD_PASTESPECIAL = 30727
|
||||
AFX_IDD_EDITLINKS = 30728
|
||||
AFX_IDD_FILEBROWSE = 30729
|
||||
AFX_IDD_BUSY = 30730
|
||||
AFX_IDD_OBJECTPROPERTIES = 30732
|
||||
AFX_IDD_CHANGESOURCE = 30733
|
||||
AFX_IDC_CONTEXTHELP = 30977
|
||||
AFX_IDC_MAGNIFY = 30978
|
||||
AFX_IDC_SMALLARROWS = 30979
|
||||
AFX_IDC_HSPLITBAR = 30980
|
||||
AFX_IDC_VSPLITBAR = 30981
|
||||
AFX_IDC_NODROPCRSR = 30982
|
||||
AFX_IDC_TRACKNWSE = 30983
|
||||
AFX_IDC_TRACKNESW = 30984
|
||||
AFX_IDC_TRACKNS = 30985
|
||||
AFX_IDC_TRACKWE = 30986
|
||||
AFX_IDC_TRACK4WAY = 30987
|
||||
AFX_IDC_MOVE4WAY = 30988
|
||||
AFX_IDB_MINIFRAME_MENU = 30994
|
||||
AFX_IDB_CHECKLISTBOX_NT = 30995
|
||||
AFX_IDB_CHECKLISTBOX_95 = 30996
|
||||
AFX_IDR_PREVIEW_ACCEL = 30997
|
||||
AFX_IDI_STD_MDIFRAME = 31233
|
||||
AFX_IDI_STD_FRAME = 31234
|
||||
AFX_IDC_FONTPROP = 1000
|
||||
AFX_IDC_FONTNAMES = 1001
|
||||
AFX_IDC_FONTSTYLES = 1002
|
||||
AFX_IDC_FONTSIZES = 1003
|
||||
AFX_IDC_STRIKEOUT = 1004
|
||||
AFX_IDC_UNDERLINE = 1005
|
||||
AFX_IDC_SAMPLEBOX = 1006
|
||||
AFX_IDC_COLOR_BLACK = 1100
|
||||
AFX_IDC_COLOR_WHITE = 1101
|
||||
AFX_IDC_COLOR_RED = 1102
|
||||
AFX_IDC_COLOR_GREEN = 1103
|
||||
AFX_IDC_COLOR_BLUE = 1104
|
||||
AFX_IDC_COLOR_YELLOW = 1105
|
||||
AFX_IDC_COLOR_MAGENTA = 1106
|
||||
AFX_IDC_COLOR_CYAN = 1107
|
||||
AFX_IDC_COLOR_GRAY = 1108
|
||||
AFX_IDC_COLOR_LIGHTGRAY = 1109
|
||||
AFX_IDC_COLOR_DARKRED = 1110
|
||||
AFX_IDC_COLOR_DARKGREEN = 1111
|
||||
AFX_IDC_COLOR_DARKBLUE = 1112
|
||||
AFX_IDC_COLOR_LIGHTBROWN = 1113
|
||||
AFX_IDC_COLOR_DARKMAGENTA = 1114
|
||||
AFX_IDC_COLOR_DARKCYAN = 1115
|
||||
AFX_IDC_COLORPROP = 1116
|
||||
AFX_IDC_SYSTEMCOLORS = 1117
|
||||
AFX_IDC_PROPNAME = 1201
|
||||
AFX_IDC_PICTURE = 1202
|
||||
AFX_IDC_BROWSE = 1203
|
||||
AFX_IDC_CLEAR = 1204
|
||||
AFX_IDD_PROPPAGE_COLOR = 32257
|
||||
AFX_IDD_PROPPAGE_FONT = 32258
|
||||
AFX_IDD_PROPPAGE_PICTURE = 32259
|
||||
AFX_IDB_TRUETYPE = 32384
|
||||
AFX_IDS_PROPPAGE_UNKNOWN = 0xFE01
|
||||
AFX_IDS_COLOR_DESKTOP = 0xFE04
|
||||
AFX_IDS_COLOR_APPWORKSPACE = 0xFE05
|
||||
AFX_IDS_COLOR_WNDBACKGND = 0xFE06
|
||||
AFX_IDS_COLOR_WNDTEXT = 0xFE07
|
||||
AFX_IDS_COLOR_MENUBAR = 0xFE08
|
||||
AFX_IDS_COLOR_MENUTEXT = 0xFE09
|
||||
AFX_IDS_COLOR_ACTIVEBAR = 0xFE0A
|
||||
AFX_IDS_COLOR_INACTIVEBAR = 0xFE0B
|
||||
AFX_IDS_COLOR_ACTIVETEXT = 0xFE0C
|
||||
AFX_IDS_COLOR_INACTIVETEXT = 0xFE0D
|
||||
AFX_IDS_COLOR_ACTIVEBORDER = 0xFE0E
|
||||
AFX_IDS_COLOR_INACTIVEBORDER = 0xFE0F
|
||||
AFX_IDS_COLOR_WNDFRAME = 0xFE10
|
||||
AFX_IDS_COLOR_SCROLLBARS = 0xFE11
|
||||
AFX_IDS_COLOR_BTNFACE = 0xFE12
|
||||
AFX_IDS_COLOR_BTNSHADOW = 0xFE13
|
||||
AFX_IDS_COLOR_BTNTEXT = 0xFE14
|
||||
AFX_IDS_COLOR_BTNHIGHLIGHT = 0xFE15
|
||||
AFX_IDS_COLOR_DISABLEDTEXT = 0xFE16
|
||||
AFX_IDS_COLOR_HIGHLIGHT = 0xFE17
|
||||
AFX_IDS_COLOR_HIGHLIGHTTEXT = 0xFE18
|
||||
AFX_IDS_REGULAR = 0xFE19
|
||||
AFX_IDS_BOLD = 0xFE1A
|
||||
AFX_IDS_ITALIC = 0xFE1B
|
||||
AFX_IDS_BOLDITALIC = 0xFE1C
|
||||
AFX_IDS_SAMPLETEXT = 0xFE1D
|
||||
AFX_IDS_DISPLAYSTRING_FONT = 0xFE1E
|
||||
AFX_IDS_DISPLAYSTRING_COLOR = 0xFE1F
|
||||
AFX_IDS_DISPLAYSTRING_PICTURE = 0xFE20
|
||||
AFX_IDS_PICTUREFILTER = 0xFE21
|
||||
AFX_IDS_PICTYPE_UNKNOWN = 0xFE22
|
||||
AFX_IDS_PICTYPE_NONE = 0xFE23
|
||||
AFX_IDS_PICTYPE_BITMAP = 0xFE24
|
||||
AFX_IDS_PICTYPE_METAFILE = 0xFE25
|
||||
AFX_IDS_PICTYPE_ICON = 0xFE26
|
||||
AFX_IDS_COLOR_PPG = 0xFE28
|
||||
AFX_IDS_COLOR_PPG_CAPTION = 0xFE29
|
||||
AFX_IDS_FONT_PPG = 0xFE2A
|
||||
AFX_IDS_FONT_PPG_CAPTION = 0xFE2B
|
||||
AFX_IDS_PICTURE_PPG = 0xFE2C
|
||||
AFX_IDS_PICTURE_PPG_CAPTION = 0xFE2D
|
||||
AFX_IDS_PICTUREBROWSETITLE = 0xFE30
|
||||
AFX_IDS_BORDERSTYLE_0 = 0xFE31
|
||||
AFX_IDS_BORDERSTYLE_1 = 0xFE32
|
||||
AFX_IDS_VERB_EDIT = 0xFE40
|
||||
AFX_IDS_VERB_PROPERTIES = 0xFE41
|
||||
AFX_IDP_PICTURECANTOPEN = 0xFE83
|
||||
AFX_IDP_PICTURECANTLOAD = 0xFE84
|
||||
AFX_IDP_PICTURETOOLARGE = 0xFE85
|
||||
AFX_IDP_PICTUREREADFAILED = 0xFE86
|
||||
AFX_IDP_E_ILLEGALFUNCTIONCALL = 0xFEA0
|
||||
AFX_IDP_E_OVERFLOW = 0xFEA1
|
||||
AFX_IDP_E_OUTOFMEMORY = 0xFEA2
|
||||
AFX_IDP_E_DIVISIONBYZERO = 0xFEA3
|
||||
AFX_IDP_E_OUTOFSTRINGSPACE = 0xFEA4
|
||||
AFX_IDP_E_OUTOFSTACKSPACE = 0xFEA5
|
||||
AFX_IDP_E_BADFILENAMEORNUMBER = 0xFEA6
|
||||
AFX_IDP_E_FILENOTFOUND = 0xFEA7
|
||||
AFX_IDP_E_BADFILEMODE = 0xFEA8
|
||||
AFX_IDP_E_FILEALREADYOPEN = 0xFEA9
|
||||
AFX_IDP_E_DEVICEIOERROR = 0xFEAA
|
||||
AFX_IDP_E_FILEALREADYEXISTS = 0xFEAB
|
||||
AFX_IDP_E_BADRECORDLENGTH = 0xFEAC
|
||||
AFX_IDP_E_DISKFULL = 0xFEAD
|
||||
AFX_IDP_E_BADRECORDNUMBER = 0xFEAE
|
||||
AFX_IDP_E_BADFILENAME = 0xFEAF
|
||||
AFX_IDP_E_TOOMANYFILES = 0xFEB0
|
||||
AFX_IDP_E_DEVICEUNAVAILABLE = 0xFEB1
|
||||
AFX_IDP_E_PERMISSIONDENIED = 0xFEB2
|
||||
AFX_IDP_E_DISKNOTREADY = 0xFEB3
|
||||
AFX_IDP_E_PATHFILEACCESSERROR = 0xFEB4
|
||||
AFX_IDP_E_PATHNOTFOUND = 0xFEB5
|
||||
AFX_IDP_E_INVALIDPATTERNSTRING = 0xFEB6
|
||||
AFX_IDP_E_INVALIDUSEOFNULL = 0xFEB7
|
||||
AFX_IDP_E_INVALIDFILEFORMAT = 0xFEB8
|
||||
AFX_IDP_E_INVALIDPROPERTYVALUE = 0xFEB9
|
||||
AFX_IDP_E_INVALIDPROPERTYARRAYINDEX = 0xFEBA
|
||||
AFX_IDP_E_SETNOTSUPPORTEDATRUNTIME = 0xFEBB
|
||||
AFX_IDP_E_SETNOTSUPPORTED = 0xFEBC
|
||||
AFX_IDP_E_NEEDPROPERTYARRAYINDEX = 0xFEBD
|
||||
AFX_IDP_E_SETNOTPERMITTED = 0xFEBE
|
||||
AFX_IDP_E_GETNOTSUPPORTEDATRUNTIME = 0xFEBF
|
||||
AFX_IDP_E_GETNOTSUPPORTED = 0xFEC0
|
||||
AFX_IDP_E_PROPERTYNOTFOUND = 0xFEC1
|
||||
AFX_IDP_E_INVALIDCLIPBOARDFORMAT = 0xFEC2
|
||||
AFX_IDP_E_INVALIDPICTURE = 0xFEC3
|
||||
AFX_IDP_E_PRINTERERROR = 0xFEC4
|
||||
AFX_IDP_E_CANTSAVEFILETOTEMP = 0xFEC5
|
||||
AFX_IDP_E_SEARCHTEXTNOTFOUND = 0xFEC6
|
||||
AFX_IDP_E_REPLACEMENTSTOOLONG = 0xFEC7
|
||||
241
Lib/site-packages/pythonwin/pywin/mfc/dialog.py
Normal file
241
Lib/site-packages/pythonwin/pywin/mfc/dialog.py
Normal file
|
|
@ -0,0 +1,241 @@
|
|||
""" \
|
||||
Base class for Dialogs. Also contains a few useful utility functions
|
||||
"""
|
||||
# dialog.py
|
||||
# Python class for Dialog Boxes in PythonWin.
|
||||
|
||||
import win32ui
|
||||
import win32con
|
||||
# sob - 2to3 doesn't see this as a relative import :(
|
||||
from pywin.mfc import window
|
||||
|
||||
def dllFromDll(dllid):
|
||||
" given a 'dll' (maybe a dll, filename, etc), return a DLL object "
|
||||
if dllid==None:
|
||||
return None
|
||||
elif type('')==type(dllid):
|
||||
return win32ui.LoadLibrary(dllid)
|
||||
else:
|
||||
try:
|
||||
dllid.GetFileName()
|
||||
except AttributeError:
|
||||
raise TypeError("DLL parameter must be None, a filename or a dll object")
|
||||
return dllid
|
||||
|
||||
class Dialog(window.Wnd):
|
||||
" Base class for a dialog"
|
||||
def __init__( self, id, dllid=None ):
|
||||
""" id is the resource ID, or a template
|
||||
dllid may be None, a dll object, or a string with a dll name """
|
||||
# must take a reference to the DLL until InitDialog.
|
||||
self.dll=dllFromDll(dllid)
|
||||
if type(id)==type([]): # a template
|
||||
dlg=win32ui.CreateDialogIndirect(id)
|
||||
else:
|
||||
dlg=win32ui.CreateDialog(id, self.dll)
|
||||
window.Wnd.__init__(self, dlg)
|
||||
self.HookCommands()
|
||||
self.bHaveInit = None
|
||||
|
||||
def HookCommands(self):
|
||||
pass
|
||||
|
||||
def OnAttachedObjectDeath(self):
|
||||
self.data = self._obj_.data
|
||||
window.Wnd.OnAttachedObjectDeath(self)
|
||||
|
||||
# provide virtuals.
|
||||
def OnOK(self):
|
||||
self._obj_.OnOK()
|
||||
def OnCancel(self):
|
||||
self._obj_.OnCancel()
|
||||
def OnInitDialog(self):
|
||||
self.bHaveInit = 1
|
||||
if self._obj_.data:
|
||||
self._obj_.UpdateData(0)
|
||||
return 1 # I did NOT set focus to a child window.
|
||||
def OnDestroy(self,msg):
|
||||
self.dll = None # theoretically not needed if object destructs normally.
|
||||
# DDX support
|
||||
def AddDDX( self, *args ):
|
||||
self._obj_.datalist.append(args)
|
||||
# Make a dialog object look like a dictionary for the DDX support
|
||||
def __bool__(self):
|
||||
return True
|
||||
def __len__(self): return len(self.data)
|
||||
def __getitem__(self, key): return self.data[key]
|
||||
def __setitem__(self, key, item): self._obj_.data[key] = item# self.UpdateData(0)
|
||||
def keys(self): return list(self.data.keys())
|
||||
def items(self): return list(self.data.items())
|
||||
def values(self): return list(self.data.values())
|
||||
# XXX - needs py3k work!
|
||||
def has_key(self, key): return key in self.data
|
||||
|
||||
class PrintDialog(Dialog):
|
||||
" Base class for a print dialog"
|
||||
def __init__(self, pInfo, dlgID,
|
||||
printSetupOnly = 0,
|
||||
flags=(win32ui.PD_ALLPAGES|
|
||||
win32ui.PD_USEDEVMODECOPIES|
|
||||
win32ui.PD_NOPAGENUMS|
|
||||
win32ui.PD_HIDEPRINTTOFILE|
|
||||
win32ui.PD_NOSELECTION),
|
||||
parent=None,
|
||||
dllid=None):
|
||||
self.dll=dllFromDll(dllid)
|
||||
if type(dlgID)==type([]): # a template
|
||||
raise TypeError("dlgID parameter must be an integer resource ID")
|
||||
dlg=win32ui.CreatePrintDialog(dlgID, printSetupOnly,
|
||||
flags, parent,
|
||||
self.dll)
|
||||
window.Wnd.__init__(self, dlg)
|
||||
self.HookCommands()
|
||||
self.bHaveInit = None
|
||||
self.pInfo = pInfo
|
||||
# init values (if PrintSetup is called, values still available)
|
||||
flags = pInfo.GetFlags()
|
||||
self['toFile'] = (flags&win32ui.PD_PRINTTOFILE != 0)
|
||||
self['direct'] = pInfo.GetDirect()
|
||||
self['preview'] = pInfo.GetPreview()
|
||||
self['continuePrinting'] = pInfo.GetContinuePrinting()
|
||||
self['curPage'] = pInfo.GetCurPage()
|
||||
self['numPreviewPages'] = pInfo.GetNumPreviewPages()
|
||||
self['userData'] = pInfo.GetUserData()
|
||||
self['draw'] = pInfo.GetDraw()
|
||||
self['pageDesc'] = pInfo.GetPageDesc()
|
||||
self['minPage'] = pInfo.GetMinPage()
|
||||
self['maxPage'] = pInfo.GetMaxPage()
|
||||
self['offsetPage'] = pInfo.GetOffsetPage()
|
||||
self['fromPage'] = pInfo.GetFromPage()
|
||||
self['toPage'] = pInfo.GetToPage()
|
||||
# these values updated after OnOK
|
||||
self['copies'] = 0
|
||||
self['deviceName'] = ''
|
||||
self['driverName'] = ''
|
||||
self['printAll'] = 0
|
||||
self['printCollate'] = 0
|
||||
self['printRange'] = 0
|
||||
self['printSelection'] = 0
|
||||
|
||||
def OnInitDialog(self):
|
||||
self.pInfo.CreatePrinterDC() # This also sets the hDC of the pInfo structure.
|
||||
return self._obj_.OnInitDialog()
|
||||
|
||||
def OnCancel(self):
|
||||
del self.pInfo
|
||||
def OnOK(self):
|
||||
'''DoModal has finished. Can now access the users choices'''
|
||||
self._obj_.OnOK()
|
||||
pInfo = self.pInfo
|
||||
# user values
|
||||
flags = pInfo.GetFlags()
|
||||
self['toFile'] = (flags&win32ui.PD_PRINTTOFILE != 0)
|
||||
self['direct'] = pInfo.GetDirect()
|
||||
self['preview'] = pInfo.GetPreview()
|
||||
self['continuePrinting'] = pInfo.GetContinuePrinting()
|
||||
self['curPage'] = pInfo.GetCurPage()
|
||||
self['numPreviewPages'] = pInfo.GetNumPreviewPages()
|
||||
self['userData'] = pInfo.GetUserData()
|
||||
self['draw'] = pInfo.GetDraw()
|
||||
self['pageDesc'] = pInfo.GetPageDesc()
|
||||
self['minPage'] = pInfo.GetMinPage()
|
||||
self['maxPage'] = pInfo.GetMaxPage()
|
||||
self['offsetPage'] = pInfo.GetOffsetPage()
|
||||
self['fromPage'] = pInfo.GetFromPage()
|
||||
self['toPage'] = pInfo.GetToPage()
|
||||
self['copies'] = pInfo.GetCopies()
|
||||
self['deviceName'] = pInfo.GetDeviceName()
|
||||
self['driverName'] = pInfo.GetDriverName()
|
||||
self['printAll'] = pInfo.PrintAll()
|
||||
self['printCollate'] = pInfo.PrintCollate()
|
||||
self['printRange'] = pInfo.PrintRange()
|
||||
self['printSelection'] = pInfo.PrintSelection()
|
||||
del self.pInfo
|
||||
|
||||
class PropertyPage(Dialog):
|
||||
" Base class for a Property Page"
|
||||
def __init__( self, id, dllid=None, caption=0 ):
|
||||
""" id is the resource ID
|
||||
dllid may be None, a dll object, or a string with a dll name """
|
||||
|
||||
self.dll = dllFromDll(dllid)
|
||||
if self.dll:
|
||||
oldRes = win32ui.SetResource(self.dll)
|
||||
if type(id)==type([]):
|
||||
dlg=win32ui.CreatePropertyPageIndirect(id)
|
||||
else:
|
||||
dlg=win32ui.CreatePropertyPage(id, caption)
|
||||
if self.dll:
|
||||
win32ui.SetResource(oldRes)
|
||||
# dont call dialog init!
|
||||
window.Wnd.__init__(self, dlg)
|
||||
self.HookCommands()
|
||||
|
||||
class PropertySheet(window.Wnd):
|
||||
def __init__(self, caption, dll=None, pageList=None ):# parent=None, style,etc):
|
||||
" Initialize a property sheet. pageList is a list of ID's "
|
||||
# must take a reference to the DLL until InitDialog.
|
||||
self.dll=dllFromDll(dll)
|
||||
self.sheet = win32ui.CreatePropertySheet(caption)
|
||||
window.Wnd.__init__(self, self.sheet)
|
||||
if not pageList is None:
|
||||
self.AddPage(pageList)
|
||||
|
||||
def OnInitDialog(self):
|
||||
return self._obj_.OnInitDialog()
|
||||
|
||||
def DoModal(self):
|
||||
if self.dll:
|
||||
oldRes = win32ui.SetResource(self.dll)
|
||||
rc = self.sheet.DoModal()
|
||||
if self.dll:
|
||||
win32ui.SetResource(oldRes)
|
||||
return rc
|
||||
|
||||
def AddPage(self, pages):
|
||||
if self.dll:
|
||||
oldRes = win32ui.SetResource(self.dll)
|
||||
try: # try list style access
|
||||
pages[0]
|
||||
isSeq = 1
|
||||
except (TypeError,KeyError):
|
||||
isSeq = 0
|
||||
if isSeq:
|
||||
for page in pages:
|
||||
self.DoAddSinglePage(page)
|
||||
else:
|
||||
self.DoAddSinglePage(pages)
|
||||
if self.dll:
|
||||
win32ui.SetResource(oldRes)
|
||||
|
||||
def DoAddSinglePage(self, page):
|
||||
"Page may be page, or int ID. Assumes DLL setup "
|
||||
if type(page)==type(0):
|
||||
self.sheet.AddPage(win32ui.CreatePropertyPage(page))
|
||||
else:
|
||||
self.sheet.AddPage(page)
|
||||
|
||||
# define some app utility functions.
|
||||
def GetSimpleInput(prompt, defValue='', title=None ):
|
||||
""" displays a dialog, and returns a string, or None if cancelled.
|
||||
args prompt, defValue='', title=main frames title """
|
||||
# uses a simple dialog to return a string object.
|
||||
if title is None: title=win32ui.GetMainFrame().GetWindowText()
|
||||
# 2to3 insists on converting 'Dialog.__init__' to 'tkinter.dialog...'
|
||||
DlgBaseClass = Dialog
|
||||
class DlgSimpleInput(DlgBaseClass):
|
||||
def __init__(self, prompt, defValue, title ):
|
||||
self.title=title
|
||||
DlgBaseClass.__init__(self, win32ui.IDD_SIMPLE_INPUT)
|
||||
self.AddDDX(win32ui.IDC_EDIT1,'result')
|
||||
self.AddDDX(win32ui.IDC_PROMPT1, 'prompt')
|
||||
self._obj_.data['result']=defValue
|
||||
self._obj_.data['prompt']=prompt
|
||||
def OnInitDialog(self):
|
||||
self.SetWindowText(self.title)
|
||||
return DlgBaseClass.OnInitDialog(self)
|
||||
|
||||
dlg=DlgSimpleInput( prompt, defValue, title)
|
||||
if dlg.DoModal() != win32con.IDOK:
|
||||
return None
|
||||
return dlg['result']
|
||||
116
Lib/site-packages/pythonwin/pywin/mfc/docview.py
Normal file
116
Lib/site-packages/pythonwin/pywin/mfc/docview.py
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
# document and view classes for MFC.
|
||||
import win32ui
|
||||
import win32con
|
||||
from . import object
|
||||
from . import window
|
||||
|
||||
class View(window.Wnd):
|
||||
def __init__(self, initobj):
|
||||
window.Wnd.__init__(self, initobj)
|
||||
def OnInitialUpdate(self):
|
||||
pass
|
||||
|
||||
# Simple control based views.
|
||||
class CtrlView(View):
|
||||
def __init__(self, doc, wndclass, style=0):
|
||||
View.__init__(self, win32ui.CreateCtrlView(doc, wndclass, style))
|
||||
|
||||
class EditView(CtrlView):
|
||||
def __init__(self, doc):
|
||||
View.__init__(self, win32ui.CreateEditView(doc))
|
||||
|
||||
class RichEditView(CtrlView):
|
||||
def __init__(self, doc):
|
||||
View.__init__(self, win32ui.CreateRichEditView(doc))
|
||||
|
||||
class ListView(CtrlView):
|
||||
def __init__(self, doc):
|
||||
View.__init__(self, win32ui.CreateListView(doc))
|
||||
|
||||
class TreeView(CtrlView):
|
||||
def __init__(self, doc):
|
||||
View.__init__(self, win32ui.CreateTreeView(doc))
|
||||
|
||||
# Other more advanced views.
|
||||
class ScrollView(View):
|
||||
def __init__(self, doc):
|
||||
View.__init__(self, win32ui.CreateView(doc))
|
||||
|
||||
class FormView(View):
|
||||
def __init__(self, doc, id):
|
||||
View.__init__(self, win32ui.CreateFormView(doc, id))
|
||||
|
||||
class Document(object.CmdTarget):
|
||||
def __init__(self, template, docobj=None):
|
||||
if docobj is None:
|
||||
docobj = template.DoCreateDoc()
|
||||
object.CmdTarget.__init__(self, docobj)
|
||||
|
||||
class RichEditDoc(object.CmdTarget):
|
||||
def __init__(self, template):
|
||||
object.CmdTarget.__init__(self, template.DoCreateRichEditDoc())
|
||||
|
||||
class CreateContext:
|
||||
"A transient base class used as a CreateContext"
|
||||
def __init__(self, template, doc = None):
|
||||
self.template = template
|
||||
self.doc = doc
|
||||
def __del__(self):
|
||||
self.close()
|
||||
def close(self):
|
||||
self.doc = None
|
||||
self.template = None
|
||||
|
||||
class DocTemplate(object.CmdTarget):
|
||||
def __init__(self, resourceId=None, MakeDocument=None, MakeFrame=None, MakeView=None):
|
||||
if resourceId is None: resourceId = win32ui.IDR_PYTHONTYPE
|
||||
object.CmdTarget.__init__(self, self._CreateDocTemplate(resourceId))
|
||||
self.MakeDocument=MakeDocument
|
||||
self.MakeFrame=MakeFrame
|
||||
self.MakeView=MakeView
|
||||
self._SetupSharedMenu_()
|
||||
def _SetupSharedMenu_(self):
|
||||
pass # to be overridden by each "app"
|
||||
def _CreateDocTemplate(self, resourceId):
|
||||
return win32ui.CreateDocTemplate(resourceId)
|
||||
def __del__(self):
|
||||
object.CmdTarget.__del__(self)
|
||||
def CreateCreateContext(self, doc=None):
|
||||
return CreateContext(self, doc)
|
||||
def CreateNewFrame(self, doc):
|
||||
makeFrame = self.MakeFrame
|
||||
if makeFrame is None: makeFrame = window.MDIChildWnd
|
||||
wnd = makeFrame()
|
||||
context = self.CreateCreateContext(doc)
|
||||
wnd.LoadFrame(self.GetResourceID(), -1, None, context) # triggers OnCreateClient...
|
||||
return wnd
|
||||
def CreateNewDocument(self):
|
||||
makeDocument = self.MakeDocument
|
||||
if makeDocument is None:
|
||||
makeDocument = Document
|
||||
return makeDocument(self)
|
||||
def CreateView(self, frame, context):
|
||||
makeView = self.MakeView
|
||||
if makeView is None: makeView = EditView
|
||||
view = makeView(context.doc)
|
||||
view.CreateWindow(frame)
|
||||
|
||||
class RichEditDocTemplate(DocTemplate):
|
||||
def __init__(self, resourceId=None, MakeDocument=None, MakeFrame=None, MakeView=None):
|
||||
if MakeView is None: MakeView = RichEditView
|
||||
if MakeDocument is None: MakeDocument = RichEditDoc
|
||||
DocTemplate.__init__(self, resourceId, MakeDocument, MakeFrame, MakeView)
|
||||
|
||||
def _CreateDocTemplate(self, resourceId):
|
||||
return win32ui.CreateRichEditDocTemplate(resourceId)
|
||||
|
||||
def t():
|
||||
class FormTemplate(DocTemplate):
|
||||
def CreateView(self, frame, context):
|
||||
makeView = self.MakeView
|
||||
# view = FormView(context.doc, win32ui.IDD_PROPDEMO1)
|
||||
view = ListView(context.doc)
|
||||
view.CreateWindow(frame)
|
||||
|
||||
t=FormTemplate()
|
||||
return t.OpenDocumentFile(None)
|
||||
55
Lib/site-packages/pythonwin/pywin/mfc/object.py
Normal file
55
Lib/site-packages/pythonwin/pywin/mfc/object.py
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
# MFC base classes.
|
||||
import sys
|
||||
import win32ui
|
||||
|
||||
class Object:
|
||||
def __init__(self, initObj = None):
|
||||
self.__dict__['_obj_'] = initObj
|
||||
# self._obj_ = initObj
|
||||
if initObj is not None: initObj.AttachObject(self)
|
||||
def __del__(self):
|
||||
self.close()
|
||||
def __getattr__(self, attr): # Make this object look like the underlying win32ui one.
|
||||
# During cleanup __dict__ is not available, causing recursive death.
|
||||
if not attr.startswith('__'):
|
||||
try:
|
||||
o = self.__dict__['_obj_']
|
||||
if o is not None:
|
||||
return getattr(o, attr)
|
||||
# Only raise this error for non "internal" names -
|
||||
# Python may be calling __len__, __nonzero__, etc, so
|
||||
# we dont want this exception
|
||||
if attr[0]!= '_' and attr[-1] != '_':
|
||||
raise win32ui.error("The MFC object has died.")
|
||||
except KeyError:
|
||||
# No _obj_ at all - dont report MFC object died when there isnt one!
|
||||
pass
|
||||
raise AttributeError(attr)
|
||||
|
||||
def OnAttachedObjectDeath(self):
|
||||
# print "object", self.__class__.__name__, "dieing"
|
||||
self._obj_ = None
|
||||
def close(self):
|
||||
if '_obj_' in self.__dict__:
|
||||
if self._obj_ is not None:
|
||||
self._obj_.AttachObject(None)
|
||||
self._obj_ = None
|
||||
|
||||
class CmdTarget(Object):
|
||||
def __init__(self, initObj):
|
||||
Object.__init__(self, initObj)
|
||||
def HookNotifyRange(self, handler, firstID, lastID):
|
||||
oldhandlers = []
|
||||
for i in range(firstID, lastID + 1):
|
||||
oldhandlers.append(self.HookNotify(handler, i))
|
||||
return oldhandlers
|
||||
def HookCommandRange(self, handler, firstID, lastID):
|
||||
oldhandlers = []
|
||||
for i in range(firstID, lastID + 1):
|
||||
oldhandlers.append(self.HookCommand(handler, i))
|
||||
return oldhandlers
|
||||
def HookCommandUpdateRange(self, handler, firstID, lastID):
|
||||
oldhandlers = []
|
||||
for i in range(firstID, lastID + 1):
|
||||
oldhandlers.append(self.HookCommandUpdate(handler, i))
|
||||
return oldhandlers
|
||||
22
Lib/site-packages/pythonwin/pywin/mfc/thread.py
Normal file
22
Lib/site-packages/pythonwin/pywin/mfc/thread.py
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
# Thread and application objects
|
||||
|
||||
from . import object
|
||||
import win32ui
|
||||
|
||||
class WinThread(object.CmdTarget):
|
||||
def __init__(self, initObj = None):
|
||||
if initObj is None:
|
||||
initObj = win32ui.CreateThread()
|
||||
object.CmdTarget.__init__(self, initObj)
|
||||
|
||||
def InitInstance(self):
|
||||
pass # Default None/0 return indicates success for InitInstance()
|
||||
def ExitInstance(self):
|
||||
pass
|
||||
|
||||
|
||||
class WinApp(WinThread):
|
||||
def __init__(self, initApp = None):
|
||||
if initApp is None:
|
||||
initApp = win32ui.GetApp()
|
||||
WinThread.__init__(self, initApp)
|
||||
41
Lib/site-packages/pythonwin/pywin/mfc/window.py
Normal file
41
Lib/site-packages/pythonwin/pywin/mfc/window.py
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
# The MFCish window classes.
|
||||
from . import object
|
||||
import win32ui
|
||||
import win32con
|
||||
|
||||
class Wnd(object.CmdTarget):
|
||||
def __init__(self, initobj=None):
|
||||
object.CmdTarget.__init__(self, initobj)
|
||||
if self._obj_: self._obj_.HookMessage(self.OnDestroy, win32con.WM_DESTROY)
|
||||
def OnDestroy(self, msg):
|
||||
pass
|
||||
|
||||
# NOTE NOTE - This facility is currently disabled in Pythonwin!!!!!
|
||||
# Note - to process all messages for your window, add the following method
|
||||
# to a derived class. This code provides default message handling (ie, is
|
||||
# identical, except presumably in speed, as if the method did not exist at
|
||||
# all, so presumably will be modified to test for specific messages to be
|
||||
# useful!
|
||||
# def WindowProc(self, msg, wParam, lParam):
|
||||
# rc, lResult = self._obj_.OnWndMsg(msg, wParam, lParam)
|
||||
# if not rc: lResult = self._obj_.DefWindowProc(msg, wParam, lParam)
|
||||
# return lResult
|
||||
|
||||
class FrameWnd(Wnd):
|
||||
def __init__(self, wnd):
|
||||
Wnd.__init__(self, wnd)
|
||||
|
||||
class MDIChildWnd(FrameWnd):
|
||||
def __init__(self, wnd = None):
|
||||
if wnd is None:
|
||||
wnd=win32ui.CreateMDIChild()
|
||||
FrameWnd.__init__(self, wnd)
|
||||
def OnCreateClient(self, cp, context):
|
||||
if context is not None and context.template is not None:
|
||||
context.template.CreateView(self, context)
|
||||
|
||||
class MDIFrameWnd(FrameWnd):
|
||||
def __init__(self, wnd = None):
|
||||
if wnd is None:
|
||||
wnd=win32ui.CreateMDIFrame()
|
||||
FrameWnd.__init__(self, wnd)
|
||||
528
Lib/site-packages/pythonwin/pywin/scintilla/IDLEenvironment.py
Normal file
528
Lib/site-packages/pythonwin/pywin/scintilla/IDLEenvironment.py
Normal file
|
|
@ -0,0 +1,528 @@
|
|||
# Code that allows Pythonwin to pretend it is IDLE
|
||||
# (at least as far as most IDLE extensions are concerned)
|
||||
|
||||
import string
|
||||
import win32api
|
||||
import win32ui
|
||||
import win32con
|
||||
import sys
|
||||
|
||||
from pywin.mfc.dialog import GetSimpleInput
|
||||
from pywin import default_scintilla_encoding
|
||||
|
||||
wordchars = string.ascii_uppercase + string.ascii_lowercase + string.digits
|
||||
|
||||
class TextError(Exception): # When a TclError would normally be raised.
|
||||
pass
|
||||
|
||||
|
||||
class EmptyRange(Exception): # Internally raised.
|
||||
pass
|
||||
|
||||
def GetIDLEModule(module):
|
||||
try:
|
||||
# First get it from Pythonwin it is exists.
|
||||
modname = "pywin.idle." + module
|
||||
__import__(modname)
|
||||
except ImportError as details:
|
||||
msg = "The IDLE extension '%s' can not be located.\r\n\r\n" \
|
||||
"Please correct the installation and restart the" \
|
||||
" application.\r\n\r\n%s" % (module, details)
|
||||
win32ui.MessageBox(msg)
|
||||
return None
|
||||
mod=sys.modules[modname]
|
||||
mod.TclError = TextError # A hack that can go soon!
|
||||
return mod
|
||||
|
||||
# A class that is injected into the IDLE auto-indent extension.
|
||||
# It allows for decent performance when opening a new file,
|
||||
# as auto-indent uses the tokenizer module to determine indents.
|
||||
# The default AutoIndent readline method works OK, but it goes through
|
||||
# this layer of Tk index indirection for every single line. For large files
|
||||
# without indents (and even small files with indents :-) it was pretty slow!
|
||||
def fast_readline(self):
|
||||
if self.finished:
|
||||
val = ""
|
||||
else:
|
||||
if "_scint_lines" not in self.__dict__:
|
||||
# XXX - note - assumes this is only called once the file is loaded!
|
||||
self._scint_lines = self.text.edit.GetTextRange().split("\n")
|
||||
sl = self._scint_lines
|
||||
i = self.i = self.i + 1
|
||||
if i >= len(sl):
|
||||
val = ""
|
||||
else:
|
||||
val = sl[i]+"\n"
|
||||
return val.encode(default_scintilla_encoding)
|
||||
|
||||
try:
|
||||
GetIDLEModule("AutoIndent").IndentSearcher.readline = fast_readline
|
||||
except AttributeError: # GetIDLEModule may return None
|
||||
pass
|
||||
|
||||
# A class that attempts to emulate an IDLE editor window.
|
||||
# Construct with a Pythonwin view.
|
||||
class IDLEEditorWindow:
|
||||
def __init__(self, edit):
|
||||
self.edit = edit
|
||||
self.text = TkText(edit)
|
||||
self.extensions = {}
|
||||
self.extension_menus = {}
|
||||
|
||||
def close(self):
|
||||
self.edit = self.text = None
|
||||
self.extension_menus = None
|
||||
try:
|
||||
for ext in self.extensions.values():
|
||||
closer = getattr(ext, "close", None)
|
||||
if closer is not None:
|
||||
closer()
|
||||
finally:
|
||||
self.extensions = {}
|
||||
|
||||
def IDLEExtension(self, extension):
|
||||
ext = self.extensions.get(extension)
|
||||
if ext is not None: return ext
|
||||
mod = GetIDLEModule(extension)
|
||||
if mod is None: return None
|
||||
klass = getattr(mod, extension)
|
||||
ext = self.extensions[extension] = klass(self)
|
||||
# Find and bind all the events defined in the extension.
|
||||
events = [item for item in dir(klass) if item[-6:]=="_event"]
|
||||
for event in events:
|
||||
name = "<<%s>>" % (event[:-6].replace("_", "-"), )
|
||||
self.edit.bindings.bind(name, getattr(ext, event))
|
||||
return ext
|
||||
|
||||
def GetMenuItems(self, menu_name):
|
||||
# Get all menu items for the menu name (eg, "edit")
|
||||
bindings = self.edit.bindings
|
||||
ret = []
|
||||
for ext in self.extensions.values():
|
||||
menudefs = getattr(ext, "menudefs", [])
|
||||
for name, items in menudefs:
|
||||
if name == menu_name:
|
||||
for text, event in [item for item in items if item is not None]:
|
||||
text = text.replace("&", "&&")
|
||||
text = text.replace("_", "&")
|
||||
ret.append((text, event))
|
||||
return ret
|
||||
|
||||
######################################################################
|
||||
# The IDLE "Virtual UI" methods that are exposed to the IDLE extensions.
|
||||
#
|
||||
def askinteger(self, caption, prompt, parent=None, initialvalue=0, minvalue=None, maxvalue=None):
|
||||
while 1:
|
||||
rc = GetSimpleInput(prompt, str(initialvalue), caption)
|
||||
if rc is None: return 0 # Correct "cancel" semantics?
|
||||
err = None
|
||||
try:
|
||||
rc = int(rc)
|
||||
except ValueError:
|
||||
err = "Please enter an integer"
|
||||
if not err and minvalue is not None and rc < minvalue:
|
||||
err = "Please enter an integer greater then or equal to %s" % (minvalue,)
|
||||
if not err and maxvalue is not None and rc > maxvalue:
|
||||
err = "Please enter an integer less then or equal to %s" % (maxvalue,)
|
||||
if err:
|
||||
win32ui.MessageBox(err, caption, win32con.MB_OK)
|
||||
continue
|
||||
return rc
|
||||
def askyesno(self, caption, prompt, parent=None):
|
||||
return win32ui.MessageBox(prompt, caption, win32con.MB_YESNO)==win32con.IDYES
|
||||
|
||||
######################################################################
|
||||
# The IDLE "Virtual Text Widget" methods that are exposed to the IDLE extensions.
|
||||
#
|
||||
|
||||
# Is character at text_index in a Python string? Return 0 for
|
||||
# "guaranteed no", true for anything else.
|
||||
def is_char_in_string(self, text_index):
|
||||
# A helper for the code analyser - we need internal knowledge of
|
||||
# the colorizer to get this information
|
||||
# This assumes the colorizer has got to this point!
|
||||
text_index = self.text._getoffset(text_index)
|
||||
c = self.text.edit._GetColorizer()
|
||||
if c and c.GetStringStyle(text_index) is None:
|
||||
return 0
|
||||
return 1
|
||||
|
||||
# If a selection is defined in the text widget, return
|
||||
# (start, end) as Tkinter text indices, otherwise return
|
||||
# (None, None)
|
||||
def get_selection_indices(self):
|
||||
try:
|
||||
first = self.text.index("sel.first")
|
||||
last = self.text.index("sel.last")
|
||||
return first, last
|
||||
except TextError:
|
||||
return None, None
|
||||
|
||||
def set_tabwidth(self, width ):
|
||||
self.edit.SCISetTabWidth(width)
|
||||
|
||||
def get_tabwidth(self):
|
||||
return self.edit.GetTabWidth()
|
||||
|
||||
# A class providing the generic "Call Tips" interface
|
||||
class CallTips:
|
||||
def __init__(self, edit):
|
||||
self.edit = edit
|
||||
def showtip(self, tip_text):
|
||||
self.edit.SCICallTipShow(tip_text)
|
||||
def hidetip(self):
|
||||
self.edit.SCICallTipCancel()
|
||||
|
||||
########################################
|
||||
#
|
||||
# Helpers for the TkText emulation.
|
||||
def TkOffsetToIndex(offset, edit):
|
||||
lineoff = 0
|
||||
# May be 1 > actual end if we pretended there was a trailing '\n'
|
||||
offset = min(offset, edit.GetTextLength())
|
||||
line = edit.LineFromChar(offset)
|
||||
lineIndex = edit.LineIndex(line)
|
||||
return "%d.%d" % (line+1, offset-lineIndex)
|
||||
|
||||
def _NextTok(str, pos):
|
||||
# Returns (token, endPos)
|
||||
end = len(str)
|
||||
if pos>=end: return None, 0
|
||||
while pos < end and str[pos] in string.whitespace:
|
||||
pos = pos + 1
|
||||
# Special case for +-
|
||||
if str[pos] in '+-':
|
||||
return str[pos],pos+1
|
||||
# Digits also a special case.
|
||||
endPos = pos
|
||||
while endPos < end and str[endPos] in string.digits+".":
|
||||
endPos = endPos + 1
|
||||
if pos!=endPos: return str[pos:endPos], endPos
|
||||
endPos = pos
|
||||
while endPos < end and str[endPos] not in string.whitespace + string.digits + "+-":
|
||||
endPos = endPos + 1
|
||||
if pos!=endPos: return str[pos:endPos], endPos
|
||||
return None, 0
|
||||
|
||||
def TkIndexToOffset(bm, edit, marks):
|
||||
base, nextTokPos = _NextTok(bm, 0)
|
||||
if base is None: raise ValueError("Empty bookmark ID!")
|
||||
if base.find(".")>0:
|
||||
try:
|
||||
line, col = base.split(".", 2)
|
||||
if col=="first" or col=="last":
|
||||
# Tag name
|
||||
if line != "sel": raise ValueError("Tags arent here!")
|
||||
sel = edit.GetSel()
|
||||
if sel[0]==sel[1]:
|
||||
raise EmptyRange
|
||||
if col=="first":
|
||||
pos = sel[0]
|
||||
else:
|
||||
pos = sel[1]
|
||||
else:
|
||||
# Lines are 1 based for tkinter
|
||||
line = int(line)-1
|
||||
if line > edit.GetLineCount():
|
||||
pos = edit.GetTextLength()+1
|
||||
else:
|
||||
pos = edit.LineIndex(line)
|
||||
if pos==-1: pos = edit.GetTextLength()
|
||||
pos = pos + int(col)
|
||||
except (ValueError, IndexError):
|
||||
raise ValueError("Unexpected literal in '%s'" % base)
|
||||
elif base == 'insert':
|
||||
pos = edit.GetSel()[0]
|
||||
elif base=='end':
|
||||
pos = edit.GetTextLength()
|
||||
# Pretend there is a trailing '\n' if necessary
|
||||
if pos and edit.SCIGetCharAt(pos-1) != "\n":
|
||||
pos = pos+1
|
||||
else:
|
||||
try:
|
||||
pos = marks[base]
|
||||
except KeyError:
|
||||
raise ValueError("Unsupported base offset or undefined mark '%s'" % base)
|
||||
|
||||
while 1:
|
||||
word, nextTokPos = _NextTok(bm, nextTokPos)
|
||||
if word is None: break
|
||||
if word in ['+','-']:
|
||||
num, nextTokPos = _NextTok(bm, nextTokPos)
|
||||
if num is None: raise ValueError("+/- operator needs 2 args")
|
||||
what, nextTokPos = _NextTok(bm, nextTokPos)
|
||||
if what is None: raise ValueError("+/- operator needs 2 args")
|
||||
if what[0] != "c": raise ValueError("+/- only supports chars")
|
||||
if word=='+':
|
||||
pos = pos + int(num)
|
||||
else:
|
||||
pos = pos - int(num)
|
||||
elif word=='wordstart':
|
||||
while pos > 0 and edit.SCIGetCharAt(pos-1) in wordchars:
|
||||
pos = pos - 1
|
||||
elif word=='wordend':
|
||||
end = edit.GetTextLength()
|
||||
while pos < end and edit.SCIGetCharAt(pos) in wordchars:
|
||||
pos = pos + 1
|
||||
elif word=='linestart':
|
||||
while pos > 0 and edit.SCIGetCharAt(pos-1) not in '\n\r':
|
||||
pos = pos - 1
|
||||
elif word=='lineend':
|
||||
end = edit.GetTextLength()
|
||||
while pos < end and edit.SCIGetCharAt(pos) not in '\n\r':
|
||||
pos = pos + 1
|
||||
else:
|
||||
raise ValueError("Unsupported relative offset '%s'" % word)
|
||||
return max(pos, 0) # Tkinter is tollerant of -ve indexes - we aren't
|
||||
|
||||
# A class that resembles an IDLE (ie, a Tk) text widget.
|
||||
# Construct with an edit object (eg, an editor view)
|
||||
class TkText:
|
||||
def __init__(self, edit):
|
||||
self.calltips = None
|
||||
self.edit = edit
|
||||
self.marks = {}
|
||||
## def __getattr__(self, attr):
|
||||
## if attr=="tk": return self # So text.tk.call works.
|
||||
## if attr=="master": return None # ditto!
|
||||
## raise AttributeError, attr
|
||||
## def __getitem__(self, item):
|
||||
## if item=="tabs":
|
||||
## size = self.edit.GetTabWidth()
|
||||
## if size==8: return "" # Tk default
|
||||
## return size # correct semantics?
|
||||
## elif item=="font": # Used for measurements we dont need to do!
|
||||
## return "Dont know the font"
|
||||
## raise IndexError, "Invalid index '%s'" % item
|
||||
def make_calltip_window(self):
|
||||
if self.calltips is None:
|
||||
self.calltips = CallTips(self.edit)
|
||||
return self.calltips
|
||||
def _getoffset(self, index):
|
||||
return TkIndexToOffset(index, self.edit, self.marks)
|
||||
def _getindex(self, off):
|
||||
return TkOffsetToIndex(off, self.edit)
|
||||
def _fix_indexes(self, start, end):
|
||||
# first some magic to handle skipping over utf8 extended chars.
|
||||
while start > 0 and ord(self.edit.SCIGetCharAt(start)) & 0xC0 == 0x80:
|
||||
start -= 1
|
||||
while end < self.edit.GetTextLength() and ord(self.edit.SCIGetCharAt(end)) & 0xC0 == 0x80:
|
||||
end += 1
|
||||
# now handling fixing \r\n->\n disparities...
|
||||
if start>0 and self.edit.SCIGetCharAt(start)=='\n' and self.edit.SCIGetCharAt(start-1)=='\r':
|
||||
start = start - 1
|
||||
if end < self.edit.GetTextLength() and self.edit.SCIGetCharAt(end-1)=='\r' and self.edit.SCIGetCharAt(end)=='\n':
|
||||
end = end + 1
|
||||
return start, end
|
||||
## def get_tab_width(self):
|
||||
## return self.edit.GetTabWidth()
|
||||
## def call(self, *rest):
|
||||
## # Crap to support Tk measurement hacks for tab widths
|
||||
## if rest[0] != "font" or rest[1] != "measure":
|
||||
## raise ValueError, "Unsupport call type"
|
||||
## return len(rest[5])
|
||||
## def configure(self, **kw):
|
||||
## for name, val in kw.items():
|
||||
## if name=="tabs":
|
||||
## self.edit.SCISetTabWidth(int(val))
|
||||
## else:
|
||||
## raise ValueError, "Unsupported configuration item %s" % kw
|
||||
def bind(self, binding, handler):
|
||||
self.edit.bindings.bind(binding, handler)
|
||||
def get(self, start, end = None):
|
||||
try:
|
||||
start = self._getoffset(start)
|
||||
if end is None:
|
||||
end = start+1
|
||||
else:
|
||||
end = self._getoffset(end)
|
||||
except EmptyRange:
|
||||
return ""
|
||||
# Simple semantic checks to conform to the Tk text interface
|
||||
if end <= start: return ""
|
||||
max = self.edit.GetTextLength()
|
||||
checkEnd = 0
|
||||
if end > max:
|
||||
end = max
|
||||
checkEnd = 1
|
||||
start, end = self._fix_indexes(start, end)
|
||||
ret = self.edit.GetTextRange(start, end)
|
||||
# pretend a trailing '\n' exists if necessary.
|
||||
if checkEnd and (not ret or ret[-1] != '\n'): ret = ret + '\n'
|
||||
return ret.replace("\r", "")
|
||||
def index(self, spec):
|
||||
try:
|
||||
return self._getindex(self._getoffset(spec))
|
||||
except EmptyRange:
|
||||
return ""
|
||||
def insert(self, pos, text):
|
||||
try:
|
||||
pos = self._getoffset(pos)
|
||||
except EmptyRange:
|
||||
raise TextError("Empty range")
|
||||
self.edit.SetSel((pos, pos))
|
||||
# IDLE only deals with "\n" - we will be nicer
|
||||
|
||||
bits = text.split('\n')
|
||||
self.edit.SCIAddText(bits[0])
|
||||
for bit in bits[1:]:
|
||||
self.edit.SCINewline()
|
||||
self.edit.SCIAddText(bit)
|
||||
|
||||
def delete(self, start, end=None):
|
||||
try:
|
||||
start = self._getoffset(start)
|
||||
if end is not None: end = self._getoffset(end)
|
||||
except EmptyRange:
|
||||
raise TextError("Empty range")
|
||||
# If end is specified and == start, then we must delete nothing.
|
||||
if start==end: return
|
||||
# If end is not specified, delete one char
|
||||
if end is None:
|
||||
end = start+1
|
||||
else:
|
||||
# Tk says not to delete in this case, but our control would.
|
||||
if end<start: return
|
||||
if start==self.edit.GetTextLength(): return # Nothing to delete.
|
||||
old = self.edit.GetSel()[0] # Lose a selection
|
||||
# Hack for partial '\r\n' and UTF-8 char removal
|
||||
start, end = self._fix_indexes(start, end)
|
||||
self.edit.SetSel((start, end))
|
||||
self.edit.Clear()
|
||||
if old>=start and old<end:
|
||||
old=start
|
||||
elif old>=end:
|
||||
old = old - (end-start)
|
||||
self.edit.SetSel(old)
|
||||
|
||||
def bell(self):
|
||||
win32api.MessageBeep()
|
||||
|
||||
def see(self, pos):
|
||||
# Most commands we use in Scintilla actually force the selection
|
||||
# to be seen, making this unnecessary.
|
||||
pass
|
||||
|
||||
def mark_set(self, name, pos):
|
||||
try:
|
||||
pos = self._getoffset(pos)
|
||||
except EmptyRange:
|
||||
raise TextError("Empty range '%s'" % pos)
|
||||
if name == "insert":
|
||||
self.edit.SetSel( pos )
|
||||
else:
|
||||
self.marks[name]=pos
|
||||
|
||||
def tag_add(self, name, start, end):
|
||||
if name != "sel": raise ValueError("Only sel tag is supported")
|
||||
try:
|
||||
start = self._getoffset(start)
|
||||
end = self._getoffset(end)
|
||||
except EmptyRange:
|
||||
raise TextError("Empty range")
|
||||
self.edit.SetSel( start, end )
|
||||
|
||||
def tag_remove(self, name, start, end):
|
||||
if name !="sel" or start != "1.0" or end != "end":
|
||||
raise ValueError("Cant remove this tag")
|
||||
# Turn the sel into a cursor
|
||||
self.edit.SetSel(self.edit.GetSel()[0])
|
||||
|
||||
def compare(self, i1, op, i2):
|
||||
try:
|
||||
i1=self._getoffset(i1)
|
||||
except EmptyRange:
|
||||
i1 = ""
|
||||
try:
|
||||
i2=self._getoffset(i2)
|
||||
except EmptyRange:
|
||||
i2 = ""
|
||||
return eval("%d%s%d" % (i1,op,i2))
|
||||
|
||||
def undo_block_start(self):
|
||||
self.edit.SCIBeginUndoAction()
|
||||
|
||||
def undo_block_stop(self):
|
||||
self.edit.SCIEndUndoAction()
|
||||
|
||||
######################################################################
|
||||
#
|
||||
# Test related code.
|
||||
#
|
||||
######################################################################
|
||||
def TestCheck(index, edit, expected=None):
|
||||
rc = TkIndexToOffset(index, edit, {})
|
||||
if rc != expected:
|
||||
print("ERROR: Index", index,", expected", expected, "but got", rc)
|
||||
|
||||
def TestGet(fr, to, t, expected):
|
||||
got = t.get(fr, to)
|
||||
if got != expected:
|
||||
print("ERROR: get(%s, %s) expected %s, but got %s" % (repr(fr), repr(to), repr(expected), repr(got)))
|
||||
|
||||
def test():
|
||||
import pywin.framework.editor
|
||||
d=pywin.framework.editor.editorTemplate.OpenDocumentFile(None)
|
||||
e=d.GetFirstView()
|
||||
t = TkText(e)
|
||||
e.SCIAddText("hi there how\nare you today\r\nI hope you are well")
|
||||
e.SetSel((4,4))
|
||||
|
||||
skip = """
|
||||
TestCheck("insert", e, 4)
|
||||
TestCheck("insert wordstart", e, 3)
|
||||
TestCheck("insert wordend", e, 8)
|
||||
TestCheck("insert linestart", e, 0)
|
||||
TestCheck("insert lineend", e, 12)
|
||||
TestCheck("insert + 4 chars", e, 8)
|
||||
TestCheck("insert +4c", e, 8)
|
||||
TestCheck("insert - 2 chars", e, 2)
|
||||
TestCheck("insert -2c", e, 2)
|
||||
TestCheck("insert-2c", e, 2)
|
||||
TestCheck("insert-2 c", e, 2)
|
||||
TestCheck("insert- 2c", e, 2)
|
||||
TestCheck("1.1", e, 1)
|
||||
TestCheck("1.0", e, 0)
|
||||
TestCheck("2.0", e, 13)
|
||||
try:
|
||||
TestCheck("sel.first", e, 0)
|
||||
print "*** sel.first worked with an empty selection"
|
||||
except TextError:
|
||||
pass
|
||||
e.SetSel((4,5))
|
||||
TestCheck("sel.first- 2c", e, 2)
|
||||
TestCheck("sel.last- 2c", e, 3)
|
||||
"""
|
||||
# Check EOL semantics
|
||||
e.SetSel((4,4))
|
||||
TestGet("insert lineend", "insert lineend +1c", t, "\n")
|
||||
e.SetSel((20, 20))
|
||||
TestGet("insert lineend", "insert lineend +1c", t, "\n")
|
||||
e.SetSel((35, 35))
|
||||
TestGet("insert lineend", "insert lineend +1c", t, "\n")
|
||||
|
||||
class IDLEWrapper:
|
||||
def __init__(self, control):
|
||||
self.text = control
|
||||
|
||||
def IDLETest(extension):
|
||||
import sys, os
|
||||
modname = "pywin.idle." + extension
|
||||
__import__(modname)
|
||||
mod=sys.modules[modname]
|
||||
mod.TclError = TextError
|
||||
klass = getattr(mod, extension)
|
||||
|
||||
# Create a new Scintilla Window.
|
||||
import pywin.framework.editor
|
||||
d=pywin.framework.editor.editorTemplate.OpenDocumentFile(None)
|
||||
v=d.GetFirstView()
|
||||
fname=os.path.splitext(__file__)[0] + ".py"
|
||||
v.SCIAddText(open(fname).read())
|
||||
d.SetModifiedFlag(0)
|
||||
r=klass( IDLEWrapper( TkText(v) ) )
|
||||
return r
|
||||
|
||||
if __name__=='__main__':
|
||||
test()
|
||||
|
||||
1
Lib/site-packages/pythonwin/pywin/scintilla/__init__.py
Normal file
1
Lib/site-packages/pythonwin/pywin/scintilla/__init__.py
Normal file
|
|
@ -0,0 +1 @@
|
|||
# package init.
|
||||
172
Lib/site-packages/pythonwin/pywin/scintilla/bindings.py
Normal file
172
Lib/site-packages/pythonwin/pywin/scintilla/bindings.py
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
from . import IDLEenvironment
|
||||
import string
|
||||
import win32ui
|
||||
import win32api
|
||||
import win32con
|
||||
from . import keycodes
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
HANDLER_ARGS_GUESS=0
|
||||
HANDLER_ARGS_NATIVE=1
|
||||
HANDLER_ARGS_IDLE=2
|
||||
HANDLER_ARGS_EXTENSION=3
|
||||
|
||||
next_id = 5000
|
||||
|
||||
event_to_commands = {}# dict of integer IDs to event names.
|
||||
command_to_events = {}# dict of event names to int IDs
|
||||
|
||||
def assign_command_id(event, id = 0):
|
||||
global next_id
|
||||
if id == 0:
|
||||
id = event_to_commands.get(event, 0)
|
||||
if id == 0:
|
||||
id = next_id
|
||||
next_id = next_id + 1
|
||||
# Only map the ones we allocated - specified ones are assumed to have a handler
|
||||
command_to_events[id] = event
|
||||
event_to_commands[event] = id
|
||||
return id
|
||||
|
||||
class SendCommandHandler:
|
||||
def __init__(self, cmd):
|
||||
self.cmd = cmd
|
||||
def __call__(self, *args):
|
||||
win32ui.GetMainFrame().SendMessage(win32con.WM_COMMAND, self.cmd)
|
||||
|
||||
class Binding:
|
||||
def __init__(self, handler, handler_args_type):
|
||||
self.handler = handler
|
||||
self.handler_args_type = handler_args_type
|
||||
|
||||
class BindingsManager:
|
||||
def __init__(self, parent_view):
|
||||
self.parent_view = parent_view
|
||||
self.bindings = {} # dict of Binding instances.
|
||||
self.keymap = {}
|
||||
|
||||
def prepare_configure(self):
|
||||
self.keymap = {}
|
||||
|
||||
def complete_configure(self):
|
||||
for id in command_to_events.keys():
|
||||
self.parent_view.HookCommand(self._OnCommand, id)
|
||||
|
||||
def close(self):
|
||||
self.parent_view = self.bindings = self.keymap = None
|
||||
|
||||
def report_error(self, problem):
|
||||
try:
|
||||
win32ui.SetStatusText(problem, 1)
|
||||
except win32ui.error:
|
||||
# No status bar!
|
||||
print(problem)
|
||||
|
||||
def update_keymap(self, keymap):
|
||||
self.keymap.update(keymap)
|
||||
|
||||
def bind(self, event, handler, handler_args_type = HANDLER_ARGS_GUESS, cid = 0):
|
||||
if handler is None:
|
||||
handler = SendCommandHandler(cid)
|
||||
self.bindings[event] = self._new_binding(handler, handler_args_type)
|
||||
self.bind_command(event, cid)
|
||||
|
||||
def bind_command(self, event, id = 0):
|
||||
"Binds an event to a Windows control/command ID"
|
||||
id = assign_command_id(event, id)
|
||||
return id
|
||||
|
||||
def get_command_id(self, event):
|
||||
id = event_to_commands.get(event)
|
||||
if id is None:
|
||||
# See if we even have an event of that name!?
|
||||
if event not in self.bindings:
|
||||
return None
|
||||
id = self.bind_command(event)
|
||||
return id
|
||||
|
||||
def _OnCommand(self, id, code):
|
||||
event = command_to_events.get(id)
|
||||
if event is None:
|
||||
self.report_error("No event associated with event ID %d" % id)
|
||||
return 1
|
||||
return self.fire(event)
|
||||
|
||||
def _new_binding(self, event, handler_args_type):
|
||||
return Binding(event, handler_args_type)
|
||||
|
||||
def _get_IDLE_handler(self, ext, handler):
|
||||
try:
|
||||
instance = self.parent_view.idle.IDLEExtension(ext)
|
||||
name = handler.replace("-", "_") + "_event"
|
||||
return getattr(instance, name)
|
||||
except (ImportError, AttributeError):
|
||||
msg = "Can not find event '%s' in IDLE extension '%s'" % (handler, ext)
|
||||
self.report_error(msg)
|
||||
return None
|
||||
|
||||
def fire(self, event, event_param = None):
|
||||
# Fire the specified event. Result is native Pythonwin result
|
||||
# (ie, 1==pass one, 0 or None==handled)
|
||||
|
||||
# First look up the event directly - if there, we are set.
|
||||
binding = self.bindings.get(event)
|
||||
if binding is None:
|
||||
# If possible, find it!
|
||||
# A native method name
|
||||
handler = getattr(self.parent_view, event + "Event", None)
|
||||
if handler is None:
|
||||
# Can't decide if I should report an error??
|
||||
self.report_error("The event name '%s' can not be found." % event)
|
||||
# Either way, just let the default handlers grab it.
|
||||
return 1
|
||||
binding = self._new_binding(handler, HANDLER_ARGS_NATIVE)
|
||||
# Cache it.
|
||||
self.bindings[event] = binding
|
||||
|
||||
handler_args_type = binding.handler_args_type
|
||||
# Now actually fire it.
|
||||
if handler_args_type==HANDLER_ARGS_GUESS:
|
||||
# Can't be native, as natives are never added with "guess".
|
||||
# Must be extension or IDLE.
|
||||
if event[0]=="<":
|
||||
handler_args_type = HANDLER_ARGS_IDLE
|
||||
else:
|
||||
handler_args_type = HANDLER_ARGS_EXTENSION
|
||||
try:
|
||||
if handler_args_type==HANDLER_ARGS_EXTENSION:
|
||||
args = self.parent_view.idle, event_param
|
||||
else:
|
||||
args = (event_param,)
|
||||
rc = binding.handler(*args)
|
||||
if handler_args_type==HANDLER_ARGS_IDLE:
|
||||
# Convert to our return code.
|
||||
if rc in [None, "break"]:
|
||||
rc = 0
|
||||
else:
|
||||
rc = 1
|
||||
except:
|
||||
message = "Firing event '%s' failed." % event
|
||||
print(message)
|
||||
traceback.print_exc()
|
||||
self.report_error(message)
|
||||
rc = 1 # Let any default handlers have a go!
|
||||
return rc
|
||||
|
||||
def fire_key_event(self, msg):
|
||||
key = msg[2]
|
||||
keyState = 0
|
||||
if win32api.GetKeyState(win32con.VK_CONTROL) & 0x8000:
|
||||
keyState = keyState | win32con.RIGHT_CTRL_PRESSED | win32con.LEFT_CTRL_PRESSED
|
||||
if win32api.GetKeyState(win32con.VK_SHIFT) & 0x8000:
|
||||
keyState = keyState | win32con.SHIFT_PRESSED
|
||||
if win32api.GetKeyState(win32con.VK_MENU) & 0x8000:
|
||||
keyState = keyState | win32con.LEFT_ALT_PRESSED | win32con.RIGHT_ALT_PRESSED
|
||||
keyinfo = key, keyState
|
||||
# Special hacks for the dead-char key on non-US keyboards.
|
||||
# (XXX - which do not work :-(
|
||||
event = self.keymap.get( keyinfo )
|
||||
if event is None:
|
||||
return 1
|
||||
return self.fire(event, None)
|
||||
322
Lib/site-packages/pythonwin/pywin/scintilla/config.py
Normal file
322
Lib/site-packages/pythonwin/pywin/scintilla/config.py
Normal file
|
|
@ -0,0 +1,322 @@
|
|||
# config.py - deals with loading configuration information.
|
||||
|
||||
# Loads config data from a .cfg file. Also caches the compiled
|
||||
# data back into a .cfc file.
|
||||
|
||||
# If you are wondering how to avoid needing .cfg files (eg,
|
||||
# if you are freezing Pythonwin etc) I suggest you create a
|
||||
# .py file, and put the config info in a docstring. Then
|
||||
# pass a CStringIO file (rather than a filename) to the
|
||||
# config manager.
|
||||
import sys
|
||||
import string
|
||||
from . import keycodes
|
||||
import marshal
|
||||
import stat
|
||||
import os
|
||||
import types
|
||||
import traceback
|
||||
import pywin
|
||||
import glob
|
||||
import imp
|
||||
|
||||
import win32api
|
||||
|
||||
debugging = 0
|
||||
if debugging:
|
||||
import win32traceutil # Some trace statements fire before the interactive window is open.
|
||||
def trace(*args):
|
||||
sys.stderr.write(" ".join(map(str, args)) + "\n")
|
||||
else:
|
||||
trace = lambda *args: None
|
||||
|
||||
compiled_config_version = 3
|
||||
|
||||
def split_line(line, lineno):
|
||||
comment_pos = line.find("#")
|
||||
if comment_pos>=0: line = line[:comment_pos]
|
||||
sep_pos = line.rfind("=")
|
||||
if sep_pos == -1:
|
||||
if line.strip():
|
||||
print("Warning: Line %d: %s is an invalid entry" % (lineno, repr(line)))
|
||||
return None, None
|
||||
return "", ""
|
||||
return line[:sep_pos].strip(), line[sep_pos+1:].strip()
|
||||
|
||||
def get_section_header(line):
|
||||
# Returns the section if the line is a section header, else None
|
||||
if line[0] == "[":
|
||||
end = line.find("]")
|
||||
if end==-1: end=len(line)
|
||||
rc = line[1:end].lower()
|
||||
try:
|
||||
i = rc.index(":")
|
||||
return rc[:i], rc[i+1:]
|
||||
except ValueError:
|
||||
return rc, ""
|
||||
return None, None
|
||||
|
||||
def find_config_file(f):
|
||||
return os.path.join(pywin.__path__[0], f + ".cfg")
|
||||
|
||||
def find_config_files():
|
||||
return [os.path.split(x)[1]
|
||||
for x in [os.path.splitext(x)[0] for x in glob.glob(os.path.join(pywin.__path__[0], "*.cfg"))]
|
||||
]
|
||||
|
||||
class ConfigManager:
|
||||
def __init__(self, f):
|
||||
self.filename = "unknown"
|
||||
self.last_error = None
|
||||
self.key_to_events = {}
|
||||
if hasattr(f, "readline"):
|
||||
fp = f
|
||||
self.filename = "<config string>"
|
||||
compiled_name = None
|
||||
else:
|
||||
try:
|
||||
f = find_config_file(f)
|
||||
src_stat = os.stat(f)
|
||||
except os.error:
|
||||
self.report_error("Config file '%s' not found" % f)
|
||||
return
|
||||
self.filename = f
|
||||
self.basename = os.path.basename(f)
|
||||
trace("Loading configuration", self.basename)
|
||||
compiled_name = os.path.splitext(f)[0] + ".cfc"
|
||||
try:
|
||||
cf = open(compiled_name, "rb")
|
||||
try:
|
||||
ver = marshal.load(cf)
|
||||
ok = compiled_config_version == ver
|
||||
if ok:
|
||||
kblayoutname = marshal.load(cf)
|
||||
magic = marshal.load(cf)
|
||||
size = marshal.load(cf)
|
||||
mtime = marshal.load(cf)
|
||||
if magic == imp.get_magic() and \
|
||||
win32api.GetKeyboardLayoutName() == kblayoutname and \
|
||||
src_stat[stat.ST_MTIME] == mtime and \
|
||||
src_stat[stat.ST_SIZE] == size:
|
||||
self.cache = marshal.load(cf)
|
||||
trace("Configuration loaded cached", compiled_name)
|
||||
return # We are ready to roll!
|
||||
finally:
|
||||
cf.close()
|
||||
except (os.error, IOError, EOFError):
|
||||
pass
|
||||
fp = open(f)
|
||||
self.cache = {}
|
||||
lineno = 1
|
||||
line = fp.readline()
|
||||
while line:
|
||||
# Skip to the next section (maybe already there!)
|
||||
section, subsection = get_section_header(line)
|
||||
while line and section is None:
|
||||
line = fp.readline()
|
||||
if not line: break
|
||||
lineno = lineno + 1
|
||||
section, subsection = get_section_header(line)
|
||||
if not line: break
|
||||
|
||||
if section=="keys":
|
||||
line, lineno = self._load_keys(subsection, fp, lineno)
|
||||
elif section == "extensions":
|
||||
line, lineno = self._load_extensions(subsection, fp, lineno)
|
||||
elif section == "idle extensions":
|
||||
line, lineno = self._load_idle_extensions(subsection, fp, lineno)
|
||||
elif section == "general":
|
||||
line, lineno = self._load_general(subsection, fp, lineno)
|
||||
else:
|
||||
self.report_error("Unrecognised section header '%s:%s'" % (section,subsection))
|
||||
line = fp.readline()
|
||||
lineno = lineno + 1
|
||||
# Check critical data.
|
||||
if not self.cache.get("keys"):
|
||||
self.report_error("No keyboard definitions were loaded")
|
||||
if not self.last_error and compiled_name:
|
||||
try:
|
||||
cf = open(compiled_name, "wb")
|
||||
marshal.dump(compiled_config_version, cf)
|
||||
marshal.dump(win32api.GetKeyboardLayoutName(), cf)
|
||||
marshal.dump(imp.get_magic(), cf)
|
||||
marshal.dump(src_stat[stat.ST_SIZE], cf)
|
||||
marshal.dump(src_stat[stat.ST_MTIME], cf)
|
||||
marshal.dump(self.cache, cf)
|
||||
cf.close()
|
||||
except (IOError, EOFError):
|
||||
pass # Ignore errors - may be read only.
|
||||
|
||||
def configure(self, editor, subsections = None):
|
||||
# Execute the extension code, and find any events.
|
||||
# First, we "recursively" connect any we are based on.
|
||||
if subsections is None: subsections = []
|
||||
subsections = [''] + subsections
|
||||
general = self.get_data("general")
|
||||
if general:
|
||||
parents = general.get("based on", [])
|
||||
for parent in parents:
|
||||
trace("Configuration based on", parent, "- loading.")
|
||||
parent = self.__class__(parent)
|
||||
parent.configure(editor, subsections)
|
||||
if parent.last_error:
|
||||
self.report_error(parent.last_error)
|
||||
|
||||
bindings = editor.bindings
|
||||
codeob = self.get_data("extension code")
|
||||
if codeob is not None:
|
||||
ns = {}
|
||||
try:
|
||||
exec(codeob, ns)
|
||||
except:
|
||||
traceback.print_exc()
|
||||
self.report_error("Executing extension code failed")
|
||||
ns = None
|
||||
if ns:
|
||||
num = 0
|
||||
for name, func in list(ns.items()):
|
||||
if type(func)==types.FunctionType and name[:1] != '_':
|
||||
bindings.bind(name, func)
|
||||
num = num + 1
|
||||
trace("Configuration Extension code loaded", num, "events")
|
||||
# Load the idle extensions
|
||||
for subsection in subsections:
|
||||
for ext in self.get_data("idle extensions", {}).get(subsection, []):
|
||||
try:
|
||||
editor.idle.IDLEExtension(ext)
|
||||
trace("Loaded IDLE extension", ext)
|
||||
except:
|
||||
self.report_error("Can not load the IDLE extension '%s'" % ext)
|
||||
|
||||
# Now bind up the key-map (remembering a reverse map
|
||||
subsection_keymap = self.get_data("keys")
|
||||
num_bound = 0
|
||||
for subsection in subsections:
|
||||
keymap = subsection_keymap.get(subsection, {})
|
||||
bindings.update_keymap(keymap)
|
||||
num_bound = num_bound + len(keymap)
|
||||
trace("Configuration bound", num_bound, "keys")
|
||||
|
||||
def get_key_binding(self, event, subsections = None):
|
||||
if subsections is None: subsections = []
|
||||
subsections = [''] + subsections
|
||||
|
||||
subsection_keymap = self.get_data("keys")
|
||||
for subsection in subsections:
|
||||
map = self.key_to_events.get(subsection)
|
||||
if map is None: # Build it
|
||||
map = {}
|
||||
keymap = subsection_keymap.get(subsection, {})
|
||||
for key_info, map_event in list(keymap.items()):
|
||||
map[map_event] = key_info
|
||||
self.key_to_events[subsection] = map
|
||||
|
||||
info = map.get(event)
|
||||
if info is not None:
|
||||
return keycodes.make_key_name( info[0], info[1] )
|
||||
return None
|
||||
|
||||
def report_error(self, msg):
|
||||
self.last_error = msg
|
||||
print("Error in %s: %s" % (self.filename, msg))
|
||||
def report_warning(self, msg):
|
||||
print("Warning in %s: %s" % (self.filename, msg))
|
||||
|
||||
def _readline(self, fp, lineno, bStripComments = 1):
|
||||
line = fp.readline()
|
||||
lineno = lineno + 1
|
||||
if line:
|
||||
bBreak = get_section_header(line)[0] is not None # A new section is starting
|
||||
if bStripComments and not bBreak:
|
||||
pos = line.find("#")
|
||||
if pos>=0: line=line[:pos]+"\n"
|
||||
else:
|
||||
bBreak=1
|
||||
return line, lineno, bBreak
|
||||
|
||||
def get_data(self, name, default=None):
|
||||
return self.cache.get(name, default)
|
||||
|
||||
def _save_data(self, name, data):
|
||||
self.cache[name] = data
|
||||
return data
|
||||
|
||||
def _load_general(self, sub_section, fp, lineno):
|
||||
map = {}
|
||||
while 1:
|
||||
line, lineno, bBreak = self._readline(fp, lineno)
|
||||
if bBreak: break
|
||||
|
||||
key, val = split_line(line, lineno)
|
||||
if not key: continue
|
||||
key = key.lower()
|
||||
l = map.get(key, [])
|
||||
l.append(val)
|
||||
map[key]=l
|
||||
self._save_data("general", map)
|
||||
return line, lineno
|
||||
|
||||
def _load_keys(self, sub_section, fp, lineno):
|
||||
# Builds a nested dictionary of
|
||||
# (scancode, flags) = event_name
|
||||
main_map = self.get_data("keys", {})
|
||||
map = main_map.get(sub_section, {})
|
||||
while 1:
|
||||
line, lineno, bBreak = self._readline(fp, lineno)
|
||||
if bBreak: break
|
||||
|
||||
key, event = split_line(line, lineno)
|
||||
if not event: continue
|
||||
sc, flag = keycodes.parse_key_name(key)
|
||||
if sc is None:
|
||||
self.report_warning("Line %d: Invalid key name '%s'" % (lineno, key))
|
||||
else:
|
||||
map[sc, flag] = event
|
||||
main_map[sub_section] = map
|
||||
self._save_data("keys", main_map)
|
||||
return line, lineno
|
||||
|
||||
def _load_extensions(self, sub_section, fp, lineno):
|
||||
start_lineno = lineno
|
||||
lines = []
|
||||
while 1:
|
||||
line, lineno, bBreak = self._readline(fp, lineno, 0)
|
||||
if bBreak: break
|
||||
lines.append(line)
|
||||
try:
|
||||
c = compile(
|
||||
"\n" * start_lineno + # produces correct tracebacks
|
||||
"".join(lines), self.filename, "exec")
|
||||
self._save_data("extension code", c)
|
||||
except SyntaxError as details:
|
||||
errlineno = details.lineno + start_lineno
|
||||
# Should handle syntax errors better here, and offset the lineno.
|
||||
self.report_error("Compiling extension code failed:\r\nFile: %s\r\nLine %d\r\n%s" \
|
||||
% (details.filename, errlineno, details.msg))
|
||||
return line, lineno
|
||||
|
||||
def _load_idle_extensions(self, sub_section, fp, lineno):
|
||||
extension_map = self.get_data("idle extensions")
|
||||
if extension_map is None: extension_map = {}
|
||||
extensions = []
|
||||
while 1:
|
||||
line, lineno, bBreak = self._readline(fp, lineno)
|
||||
if bBreak: break
|
||||
line = line.strip()
|
||||
if line:
|
||||
extensions.append(line)
|
||||
extension_map[sub_section] = extensions
|
||||
self._save_data("idle extensions", extension_map)
|
||||
return line, lineno
|
||||
|
||||
def test():
|
||||
import time
|
||||
start = time.clock()
|
||||
f="default"
|
||||
cm = ConfigManager(f)
|
||||
map = cm.get_data("keys")
|
||||
took = time.clock()-start
|
||||
print("Loaded %s items in %.4f secs" % (len(map), took))
|
||||
|
||||
if __name__=='__main__':
|
||||
test()
|
||||
266
Lib/site-packages/pythonwin/pywin/scintilla/configui.py
Normal file
266
Lib/site-packages/pythonwin/pywin/scintilla/configui.py
Normal file
|
|
@ -0,0 +1,266 @@
|
|||
from pywin.mfc import dialog
|
||||
import win32api
|
||||
import win32con
|
||||
import win32ui
|
||||
import copy
|
||||
import string
|
||||
from . import scintillacon
|
||||
|
||||
# Used to indicate that style should use default color
|
||||
from win32con import CLR_INVALID
|
||||
|
||||
######################################################
|
||||
# Property Page for syntax formatting options
|
||||
|
||||
# The standard 16 color VGA palette should always be possible
|
||||
paletteVGA = (
|
||||
("Black", win32api.RGB(0,0,0)),
|
||||
("Navy", win32api.RGB(0,0,128)),
|
||||
("Green", win32api.RGB(0,128,0)),
|
||||
("Cyan", win32api.RGB(0,128,128)),
|
||||
("Maroon", win32api.RGB(128,0,0)),
|
||||
("Purple", win32api.RGB(128,0,128)),
|
||||
("Olive", win32api.RGB(128,128,0)),
|
||||
("Gray", win32api.RGB(128,128,128)),
|
||||
("Silver", win32api.RGB(192,192,192)),
|
||||
("Blue", win32api.RGB(0,0,255)),
|
||||
("Lime", win32api.RGB(0,255,0)),
|
||||
("Aqua", win32api.RGB(0,255,255)),
|
||||
("Red", win32api.RGB(255,0,0)),
|
||||
("Fuchsia", win32api.RGB(255,0,255)),
|
||||
("Yellow", win32api.RGB(255,255,0)),
|
||||
("White", win32api.RGB(255,255,255)),
|
||||
# and a few others will generally be possible.
|
||||
("DarkGrey", win32api.RGB(64,64,64)),
|
||||
("PurpleBlue", win32api.RGB(64,64,192)),
|
||||
("DarkGreen", win32api.RGB(0,96,0)),
|
||||
("DarkOlive", win32api.RGB(128,128,64)),
|
||||
("MediumBlue", win32api.RGB(0,0,192)),
|
||||
("DarkNavy", win32api.RGB(0,0,96)),
|
||||
("Magenta", win32api.RGB(96,0,96)),
|
||||
("OffWhite", win32api.RGB(255,255,220)),
|
||||
("LightPurple", win32api.RGB(220,220,255)),
|
||||
("<Default>", win32con.CLR_INVALID)
|
||||
)
|
||||
|
||||
class ScintillaFormatPropertyPage(dialog.PropertyPage):
|
||||
def __init__(self, scintillaClass = None, caption = 0):
|
||||
self.scintillaClass = scintillaClass
|
||||
dialog.PropertyPage.__init__(self, win32ui.IDD_PP_FORMAT, caption=caption)
|
||||
|
||||
def OnInitDialog(self):
|
||||
try:
|
||||
if self.scintillaClass is None:
|
||||
from . import control
|
||||
sc = control.CScintillaEdit
|
||||
else:
|
||||
sc = self.scintillaClass
|
||||
|
||||
self.scintilla = sc()
|
||||
style = win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.ES_MULTILINE
|
||||
# Convert the rect size
|
||||
rect = self.MapDialogRect( (5, 5, 120, 75))
|
||||
self.scintilla.CreateWindow(style, rect, self, 111)
|
||||
self.HookNotify(self.OnBraceMatch, scintillacon.SCN_CHECKBRACE)
|
||||
self.scintilla.HookKeyStroke(self.OnEsc, 27)
|
||||
self.scintilla.SCISetViewWS(1)
|
||||
self.pos_bstart = self.pos_bend = self.pos_bbad = 0
|
||||
|
||||
colorizer = self.scintilla._GetColorizer()
|
||||
text = colorizer.GetSampleText()
|
||||
items = text.split('|', 2)
|
||||
pos = len(items[0])
|
||||
self.scintilla.SCIAddText(''.join(items))
|
||||
self.scintilla.SetSel(pos, pos)
|
||||
self.scintilla.ApplyFormattingStyles()
|
||||
self.styles = self.scintilla._GetColorizer().styles
|
||||
|
||||
self.cbo = self.GetDlgItem(win32ui.IDC_COMBO1)
|
||||
for c in paletteVGA:
|
||||
self.cbo.AddString(c[0])
|
||||
|
||||
self.cboBoldItalic = self.GetDlgItem(win32ui.IDC_COMBO2)
|
||||
for item in ["Bold Italic", "Bold", "Italic", "Regular"]:
|
||||
self.cboBoldItalic.InsertString(0, item)
|
||||
|
||||
self.butIsDefault = self.GetDlgItem(win32ui.IDC_CHECK1)
|
||||
self.butIsDefaultBackground = self.GetDlgItem(win32ui.IDC_CHECK2)
|
||||
self.listbox = self.GetDlgItem(win32ui.IDC_LIST1)
|
||||
self.HookCommand(self.OnListCommand, win32ui.IDC_LIST1)
|
||||
names = list(self.styles.keys())
|
||||
names.sort()
|
||||
for name in names:
|
||||
if self.styles[name].aliased is None:
|
||||
self.listbox.AddString(name)
|
||||
self.listbox.SetCurSel(0)
|
||||
|
||||
idc = win32ui.IDC_RADIO1
|
||||
if not self.scintilla._GetColorizer().bUseFixed: idc = win32ui.IDC_RADIO2
|
||||
self.GetDlgItem(idc).SetCheck(1)
|
||||
self.UpdateUIForStyle(self.styles[names[0]])
|
||||
|
||||
self.scintilla.HookFormatter(self)
|
||||
self.HookCommand(self.OnButDefaultFixedFont, win32ui.IDC_BUTTON1)
|
||||
self.HookCommand(self.OnButDefaultPropFont, win32ui.IDC_BUTTON2)
|
||||
self.HookCommand(self.OnButThisFont, win32ui.IDC_BUTTON3)
|
||||
self.HookCommand(self.OnButUseDefaultFont, win32ui.IDC_CHECK1)
|
||||
self.HookCommand(self.OnButThisBackground, win32ui.IDC_BUTTON4)
|
||||
self.HookCommand(self.OnButUseDefaultBackground, win32ui.IDC_CHECK2)
|
||||
self.HookCommand(self.OnStyleUIChanged, win32ui.IDC_COMBO1)
|
||||
self.HookCommand(self.OnStyleUIChanged, win32ui.IDC_COMBO2)
|
||||
self.HookCommand(self.OnButFixedOrDefault, win32ui.IDC_RADIO1)
|
||||
self.HookCommand(self.OnButFixedOrDefault, win32ui.IDC_RADIO2)
|
||||
except:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def OnEsc(self, ch):
|
||||
self.GetParent().EndDialog(win32con.IDCANCEL)
|
||||
|
||||
def OnBraceMatch(self, std, extra):
|
||||
import pywin.scintilla.view
|
||||
pywin.scintilla.view.DoBraceMatch(self.scintilla)
|
||||
|
||||
def GetSelectedStyle(self):
|
||||
return self.styles[self.listbox.GetText(self.listbox.GetCurSel())]
|
||||
|
||||
def _DoButDefaultFont(self, extra_flags, attr):
|
||||
baseFormat = getattr(self.scintilla._GetColorizer(), attr)
|
||||
flags = extra_flags | win32con.CF_SCREENFONTS | win32con.CF_EFFECTS | win32con.CF_FORCEFONTEXIST
|
||||
d=win32ui.CreateFontDialog(baseFormat, flags, None, self)
|
||||
if d.DoModal()==win32con.IDOK:
|
||||
setattr(self.scintilla._GetColorizer(), attr, d.GetCharFormat())
|
||||
self.OnStyleUIChanged(0, win32con.BN_CLICKED)
|
||||
|
||||
def OnButDefaultFixedFont(self, id, code):
|
||||
if code==win32con.BN_CLICKED:
|
||||
self._DoButDefaultFont(win32con.CF_FIXEDPITCHONLY, "baseFormatFixed")
|
||||
return 1
|
||||
|
||||
def OnButDefaultPropFont(self, id, code):
|
||||
if code==win32con.BN_CLICKED:
|
||||
self._DoButDefaultFont(win32con.CF_SCALABLEONLY, "baseFormatProp")
|
||||
return 1
|
||||
|
||||
def OnButFixedOrDefault(self, id, code):
|
||||
if code==win32con.BN_CLICKED:
|
||||
bUseFixed = id == win32ui.IDC_RADIO1
|
||||
self.GetDlgItem(win32ui.IDC_RADIO1).GetCheck() != 0
|
||||
self.scintilla._GetColorizer().bUseFixed = bUseFixed
|
||||
self.scintilla.ApplyFormattingStyles(0)
|
||||
return 1
|
||||
|
||||
def OnButThisFont(self, id, code):
|
||||
if code==win32con.BN_CLICKED:
|
||||
flags = win32con.CF_SCREENFONTS | win32con.CF_EFFECTS | win32con.CF_FORCEFONTEXIST
|
||||
style = self.GetSelectedStyle()
|
||||
# If the selected style is based on the default, we need to apply
|
||||
# the default to it.
|
||||
def_format = self.scintilla._GetColorizer().GetDefaultFormat()
|
||||
format = style.GetCompleteFormat(def_format)
|
||||
d=win32ui.CreateFontDialog(format, flags, None, self)
|
||||
if d.DoModal()==win32con.IDOK:
|
||||
style.format = d.GetCharFormat()
|
||||
self.scintilla.ApplyFormattingStyles(0)
|
||||
return 1
|
||||
|
||||
def OnButUseDefaultFont(self, id, code):
|
||||
if code == win32con.BN_CLICKED:
|
||||
isDef = self.butIsDefault.GetCheck()
|
||||
self.GetDlgItem(win32ui.IDC_BUTTON3).EnableWindow(not isDef)
|
||||
if isDef: # Being reset to the default font.
|
||||
style = self.GetSelectedStyle()
|
||||
style.ForceAgainstDefault()
|
||||
self.UpdateUIForStyle(style)
|
||||
self.scintilla.ApplyFormattingStyles(0)
|
||||
else:
|
||||
# User wants to override default -
|
||||
# do nothing!
|
||||
pass
|
||||
|
||||
def OnButThisBackground(self, id, code):
|
||||
if code==win32con.BN_CLICKED:
|
||||
style = self.GetSelectedStyle()
|
||||
bg = win32api.RGB(0xff, 0xff, 0xff)
|
||||
if style.background != CLR_INVALID:
|
||||
bg = style.background
|
||||
d=win32ui.CreateColorDialog(bg, 0, self)
|
||||
if d.DoModal()==win32con.IDOK:
|
||||
style.background = d.GetColor()
|
||||
self.scintilla.ApplyFormattingStyles(0)
|
||||
return 1
|
||||
|
||||
def OnButUseDefaultBackground(self, id, code):
|
||||
if code == win32con.BN_CLICKED:
|
||||
isDef = self.butIsDefaultBackground.GetCheck()
|
||||
self.GetDlgItem(win32ui.IDC_BUTTON4).EnableWindow(not isDef)
|
||||
if isDef: # Being reset to the default color
|
||||
style = self.GetSelectedStyle()
|
||||
style.background = style.default_background
|
||||
self.UpdateUIForStyle(style)
|
||||
self.scintilla.ApplyFormattingStyles(0)
|
||||
else:
|
||||
# User wants to override default -
|
||||
# do nothing!
|
||||
pass
|
||||
|
||||
|
||||
def OnListCommand(self, id, code):
|
||||
if code==win32con.LBN_SELCHANGE:
|
||||
style = self.GetSelectedStyle()
|
||||
self.UpdateUIForStyle(style)
|
||||
return 1
|
||||
|
||||
def UpdateUIForStyle(self, style ):
|
||||
format = style.format
|
||||
sel = 0
|
||||
for c in paletteVGA:
|
||||
if format[4] == c[1]:
|
||||
# print "Style", style.name, "is", c[0]
|
||||
break
|
||||
sel = sel + 1
|
||||
else:
|
||||
sel = -1
|
||||
self.cbo.SetCurSel(sel)
|
||||
self.butIsDefault.SetCheck(style.IsBasedOnDefault())
|
||||
self.GetDlgItem(win32ui.IDC_BUTTON3).EnableWindow(not style.IsBasedOnDefault())
|
||||
|
||||
self.butIsDefaultBackground.SetCheck(style.background == style.default_background)
|
||||
self.GetDlgItem(win32ui.IDC_BUTTON4).EnableWindow(style.background != style.default_background)
|
||||
|
||||
bold = format[1] & win32con.CFE_BOLD != 0; italic = format[1] & win32con.CFE_ITALIC != 0
|
||||
self.cboBoldItalic.SetCurSel( bold*2 + italic )
|
||||
|
||||
def OnStyleUIChanged(self, id, code):
|
||||
if code in [win32con.BN_CLICKED, win32con.CBN_SELCHANGE]:
|
||||
style = self.GetSelectedStyle()
|
||||
self.ApplyUIFormatToStyle(style)
|
||||
self.scintilla.ApplyFormattingStyles(0)
|
||||
return 0
|
||||
return 1
|
||||
|
||||
def ApplyUIFormatToStyle(self, style):
|
||||
format = style.format
|
||||
color = paletteVGA[self.cbo.GetCurSel()]
|
||||
effect = 0
|
||||
sel = self.cboBoldItalic.GetCurSel()
|
||||
if sel==0:
|
||||
effect = 0
|
||||
elif sel==1:
|
||||
effect = win32con.CFE_ITALIC
|
||||
elif sel==2:
|
||||
effect = win32con.CFE_BOLD
|
||||
else:
|
||||
effect = win32con.CFE_BOLD | win32con.CFE_ITALIC
|
||||
maskFlags=format[0]|win32con.CFM_COLOR|win32con.CFM_BOLD|win32con.CFM_ITALIC
|
||||
style.format = (maskFlags, effect, style.format[2], style.format[3], color[1]) + style.format[5:]
|
||||
|
||||
def OnOK(self):
|
||||
self.scintilla._GetColorizer().SavePreferences()
|
||||
return 1
|
||||
|
||||
def test():
|
||||
page = ColorEditorPropertyPage()
|
||||
sheet = pywin.mfc.dialog.PropertySheet("Test")
|
||||
sheet.AddPage(page)
|
||||
sheet.CreateWindow()
|
||||
434
Lib/site-packages/pythonwin/pywin/scintilla/control.py
Normal file
434
Lib/site-packages/pythonwin/pywin/scintilla/control.py
Normal file
|
|
@ -0,0 +1,434 @@
|
|||
# An Python interface to the Scintilla control.
|
||||
#
|
||||
# Exposes Python classes that allow you to use Scintilla as
|
||||
# a "standard" MFC edit control (eg, control.GetTextLength(), control.GetSel()
|
||||
# plus many Scintilla specific features (eg control.SCIAddStyledText())
|
||||
|
||||
from pywin.mfc import window
|
||||
from pywin import default_scintilla_encoding
|
||||
import win32con
|
||||
import win32ui
|
||||
import win32api
|
||||
import array
|
||||
import struct
|
||||
import string
|
||||
import os
|
||||
from . import scintillacon
|
||||
|
||||
# Load Scintilla.dll to get access to the control.
|
||||
# We expect to find this in the same directory as win32ui.pyd
|
||||
dllid = None
|
||||
if win32ui.debug: # If running _d version of Pythonwin...
|
||||
try:
|
||||
dllid = win32api.LoadLibrary(os.path.join(os.path.split(win32ui.__file__)[0], "Scintilla_d.DLL"))
|
||||
except win32api.error: # Not there - we dont _need_ a debug ver, so ignore this error.
|
||||
pass
|
||||
if dllid is None:
|
||||
try:
|
||||
dllid = win32api.LoadLibrary(os.path.join(os.path.split(win32ui.__file__)[0], "Scintilla.DLL"))
|
||||
except win32api.error:
|
||||
pass
|
||||
if dllid is None:
|
||||
# Still not there - lets see if Windows can find it by searching?
|
||||
dllid = win32api.LoadLibrary("Scintilla.DLL")
|
||||
|
||||
# null_byte is str in py2k, bytes on py3k
|
||||
null_byte = "\0".encode('ascii')
|
||||
|
||||
## These are from Richedit.h - need to add to win32con or commctrl
|
||||
EM_GETTEXTRANGE = 1099
|
||||
EM_EXLINEFROMCHAR = 1078
|
||||
EM_FINDTEXTEX = 1103
|
||||
EM_GETSELTEXT = 1086
|
||||
EM_EXSETSEL = win32con.WM_USER + 55
|
||||
|
||||
class ScintillaNotification:
|
||||
def __init__(self, **args):
|
||||
self.__dict__.update(args)
|
||||
|
||||
class ScintillaControlInterface:
|
||||
def SCIUnpackNotifyMessage(self, msg):
|
||||
format = "iiiiPiiiPPiiii"
|
||||
bytes = win32ui.GetBytes( msg, struct.calcsize(format) )
|
||||
position, ch, modifiers, modificationType, text_ptr, \
|
||||
length, linesAdded, msg, wParam, lParam, line, \
|
||||
foldLevelNow, foldLevelPrev, margin \
|
||||
= struct.unpack(format, bytes)
|
||||
return ScintillaNotification(position=position,ch=ch,
|
||||
modifiers=modifiers, modificationType=modificationType,
|
||||
text_ptr = text_ptr, length=length, linesAdded=linesAdded,
|
||||
msg = msg, wParam = wParam, lParam = lParam,
|
||||
line = line, foldLevelNow = foldLevelNow, foldLevelPrev = foldLevelPrev,
|
||||
margin = margin)
|
||||
|
||||
def SCIAddText(self, text):
|
||||
self.SendMessage(scintillacon.SCI_ADDTEXT, text.encode(default_scintilla_encoding))
|
||||
def SCIAddStyledText(self, text, style = None):
|
||||
# If style is None, text is assumed to be a "native" Scintilla buffer.
|
||||
# If style is specified, text is a normal string, and the style is
|
||||
# assumed to apply to the entire string.
|
||||
if style is not None:
|
||||
text = list(map(lambda char, style=style: char+chr(style), text))
|
||||
text = ''.join(text)
|
||||
self.SendMessage(scintillacon.SCI_ADDSTYLEDTEXT, text.encode(default_scintilla_encoding))
|
||||
def SCIInsertText(self, text, pos=-1):
|
||||
# SCIInsertText allows unicode or bytes - but if they are bytes,
|
||||
# the caller must ensure it is encoded correctly.
|
||||
if isinstance(text, str):
|
||||
text = text.encode(default_scintilla_encoding)
|
||||
self.SendScintilla(scintillacon.SCI_INSERTTEXT, pos, text + null_byte)
|
||||
def SCISetSavePoint(self):
|
||||
self.SendScintilla(scintillacon.SCI_SETSAVEPOINT)
|
||||
def SCISetUndoCollection(self, collectFlag):
|
||||
self.SendScintilla(scintillacon.SCI_SETUNDOCOLLECTION, collectFlag)
|
||||
def SCIBeginUndoAction(self):
|
||||
self.SendScintilla(scintillacon.SCI_BEGINUNDOACTION)
|
||||
def SCIEndUndoAction(self):
|
||||
self.SendScintilla(scintillacon.SCI_ENDUNDOACTION)
|
||||
|
||||
def SCIGetCurrentPos(self):
|
||||
return self.SendScintilla(scintillacon.SCI_GETCURRENTPOS)
|
||||
def SCIGetCharAt(self, pos):
|
||||
# Must ensure char is unsigned!
|
||||
return chr(self.SendScintilla(scintillacon.SCI_GETCHARAT, pos) & 0xFF)
|
||||
def SCIGotoLine(self, line):
|
||||
self.SendScintilla(scintillacon.SCI_GOTOLINE, line)
|
||||
def SCIBraceMatch(self, pos, maxReStyle):
|
||||
return self.SendScintilla(scintillacon.SCI_BRACEMATCH, pos, maxReStyle)
|
||||
def SCIBraceHighlight(self, pos, posOpposite):
|
||||
return self.SendScintilla(scintillacon.SCI_BRACEHIGHLIGHT, pos, posOpposite)
|
||||
def SCIBraceBadHighlight(self, pos):
|
||||
return self.SendScintilla(scintillacon.SCI_BRACEBADLIGHT, pos)
|
||||
|
||||
####################################
|
||||
# Styling
|
||||
# def SCIColourise(self, start=0, end=-1):
|
||||
# NOTE - dependent on of we use builtin lexer, so handled below.
|
||||
def SCIGetEndStyled(self):
|
||||
return self.SendScintilla(scintillacon.SCI_GETENDSTYLED)
|
||||
def SCIStyleSetFore(self, num, v):
|
||||
return self.SendScintilla(scintillacon.SCI_STYLESETFORE, num, v)
|
||||
def SCIStyleSetBack(self, num, v):
|
||||
return self.SendScintilla(scintillacon.SCI_STYLESETBACK, num, v)
|
||||
def SCIStyleSetEOLFilled(self, num, v):
|
||||
return self.SendScintilla(scintillacon.SCI_STYLESETEOLFILLED, num, v)
|
||||
def SCIStyleSetFont(self, num, name, characterset=0):
|
||||
buff = (name + "\0").encode(default_scintilla_encoding)
|
||||
self.SendScintilla(scintillacon.SCI_STYLESETFONT, num, buff)
|
||||
self.SendScintilla(scintillacon.SCI_STYLESETCHARACTERSET, num, characterset)
|
||||
def SCIStyleSetBold(self, num, bBold):
|
||||
self.SendScintilla(scintillacon.SCI_STYLESETBOLD, num, bBold)
|
||||
def SCIStyleSetItalic(self, num, bItalic):
|
||||
self.SendScintilla(scintillacon.SCI_STYLESETITALIC, num, bItalic)
|
||||
def SCIStyleSetSize(self, num, size):
|
||||
self.SendScintilla(scintillacon.SCI_STYLESETSIZE, num, size)
|
||||
def SCIGetViewWS(self):
|
||||
return self.SendScintilla(scintillacon.SCI_GETVIEWWS)
|
||||
def SCISetViewWS(self, val):
|
||||
self.SendScintilla(scintillacon.SCI_SETVIEWWS, not (val==0))
|
||||
self.InvalidateRect()
|
||||
def SCISetIndentationGuides(self, val):
|
||||
self.SendScintilla(scintillacon.SCI_SETINDENTATIONGUIDES, val)
|
||||
def SCIGetIndentationGuides(self):
|
||||
return self.SendScintilla(scintillacon.SCI_GETINDENTATIONGUIDES)
|
||||
def SCISetIndent(self, val):
|
||||
self.SendScintilla(scintillacon.SCI_SETINDENT, val)
|
||||
def SCIGetIndent(self, val):
|
||||
return self.SendScintilla(scintillacon.SCI_GETINDENT)
|
||||
|
||||
def SCIGetViewEOL(self):
|
||||
return self.SendScintilla(scintillacon.SCI_GETVIEWEOL)
|
||||
def SCISetViewEOL(self, val):
|
||||
self.SendScintilla(scintillacon.SCI_SETVIEWEOL, not(val==0))
|
||||
self.InvalidateRect()
|
||||
def SCISetTabWidth(self, width):
|
||||
self.SendScintilla(scintillacon.SCI_SETTABWIDTH, width, 0)
|
||||
def SCIStartStyling(self, pos, mask):
|
||||
self.SendScintilla(scintillacon.SCI_STARTSTYLING, pos, mask)
|
||||
def SCISetStyling(self, pos, attr):
|
||||
self.SendScintilla(scintillacon.SCI_SETSTYLING, pos, attr)
|
||||
def SCISetStylingEx(self, ray): # ray is an array.
|
||||
address, length = ray.buffer_info()
|
||||
self.SendScintilla(scintillacon.SCI_SETSTYLINGEX, length, address)
|
||||
def SCIGetStyleAt(self, pos):
|
||||
return self.SendScintilla(scintillacon.SCI_GETSTYLEAT, pos)
|
||||
def SCISetMarginWidth(self, width):
|
||||
self.SendScintilla(scintillacon.SCI_SETMARGINWIDTHN, 1, width)
|
||||
def SCISetMarginWidthN(self, n, width):
|
||||
self.SendScintilla(scintillacon.SCI_SETMARGINWIDTHN, n, width)
|
||||
def SCISetFoldFlags(self, flags):
|
||||
self.SendScintilla(scintillacon.SCI_SETFOLDFLAGS, flags)
|
||||
# Markers
|
||||
def SCIMarkerDefineAll(self, markerNum, markerType, fore, back):
|
||||
self.SCIMarkerDefine(markerNum, markerType)
|
||||
self.SCIMarkerSetFore(markerNum, fore)
|
||||
self.SCIMarkerSetBack(markerNum, back)
|
||||
def SCIMarkerDefine(self, markerNum, markerType):
|
||||
self.SendScintilla(scintillacon.SCI_MARKERDEFINE, markerNum, markerType)
|
||||
def SCIMarkerSetFore(self, markerNum, fore):
|
||||
self.SendScintilla(scintillacon.SCI_MARKERSETFORE, markerNum, fore)
|
||||
def SCIMarkerSetBack(self, markerNum, back):
|
||||
self.SendScintilla(scintillacon.SCI_MARKERSETBACK, markerNum, back)
|
||||
def SCIMarkerAdd(self, lineNo, markerNum):
|
||||
self.SendScintilla(scintillacon.SCI_MARKERADD, lineNo, markerNum)
|
||||
def SCIMarkerDelete(self, lineNo, markerNum):
|
||||
self.SendScintilla(scintillacon.SCI_MARKERDELETE, lineNo, markerNum)
|
||||
def SCIMarkerDeleteAll(self, markerNum=-1):
|
||||
self.SendScintilla(scintillacon.SCI_MARKERDELETEALL, markerNum)
|
||||
def SCIMarkerGet(self, lineNo):
|
||||
return self.SendScintilla(scintillacon.SCI_MARKERGET, lineNo)
|
||||
def SCIMarkerNext(self, lineNo, markerNum):
|
||||
return self.SendScintilla(scintillacon.SCI_MARKERNEXT, lineNo, markerNum)
|
||||
def SCICancel(self):
|
||||
self.SendScintilla(scintillacon.SCI_CANCEL)
|
||||
# AutoComplete
|
||||
def SCIAutoCShow(self, text):
|
||||
if type(text) in [type([]), type(())]:
|
||||
text = ' '.join(text)
|
||||
buff = (text + "\0").encode(default_scintilla_encoding)
|
||||
return self.SendScintilla(scintillacon.SCI_AUTOCSHOW, 0, buff)
|
||||
def SCIAutoCCancel(self):
|
||||
self.SendScintilla(scintillacon.SCI_AUTOCCANCEL)
|
||||
def SCIAutoCActive(self):
|
||||
return self.SendScintilla(scintillacon.SCI_AUTOCACTIVE)
|
||||
def SCIAutoCComplete(self):
|
||||
return self.SendScintilla(scintillacon.SCI_AUTOCCOMPLETE)
|
||||
def SCIAutoCStops(self, stops):
|
||||
buff = (stops + "\0").encode(default_scintilla_encoding)
|
||||
self.SendScintilla(scintillacon.SCI_AUTOCSTOPS, 0, buff)
|
||||
def SCIAutoCSetAutoHide(self, hide):
|
||||
self.SendScintilla(scintillacon.SCI_AUTOCSETAUTOHIDE, hide)
|
||||
def SCIAutoCSetFillups(self, fillups):
|
||||
self.SendScintilla(scintillacon.SCI_AUTOCSETFILLUPS, fillups)
|
||||
# Call tips
|
||||
def SCICallTipShow(self, text, pos=-1):
|
||||
if pos==-1: pos = self.GetSel()[0]
|
||||
buff = (text + "\0").encode(default_scintilla_encoding)
|
||||
self.SendScintilla(scintillacon.SCI_CALLTIPSHOW, pos, buff)
|
||||
def SCICallTipCancel(self):
|
||||
self.SendScintilla(scintillacon.SCI_CALLTIPCANCEL)
|
||||
def SCICallTipActive(self):
|
||||
return self.SendScintilla(scintillacon.SCI_CALLTIPACTIVE)
|
||||
def SCICallTipPosStart(self):
|
||||
return self.SendScintilla(scintillacon.SCI_CALLTIPPOSSTART)
|
||||
def SCINewline(self):
|
||||
self.SendScintilla(scintillacon.SCI_NEWLINE)
|
||||
# Lexer etc
|
||||
def SCISetKeywords(self, keywords, kw_list_no = 0):
|
||||
buff = (keywords+"\0").encode(default_scintilla_encoding)
|
||||
self.SendScintilla(scintillacon.SCI_SETKEYWORDS, kw_list_no, buff)
|
||||
def SCISetProperty(self, name, value):
|
||||
name_buff = array.array('b', (name + '\0').encode(default_scintilla_encoding))
|
||||
val_buff = array.array("b", (str(value)+'\0').encode(default_scintilla_encoding))
|
||||
address_name_buffer = name_buff.buffer_info()[0]
|
||||
address_val_buffer = val_buff.buffer_info()[0]
|
||||
self.SendScintilla(scintillacon.SCI_SETPROPERTY, address_name_buffer, address_val_buffer)
|
||||
def SCISetStyleBits(self, nbits):
|
||||
self.SendScintilla(scintillacon.SCI_SETSTYLEBITS, nbits)
|
||||
# Folding
|
||||
def SCIGetFoldLevel(self, lineno):
|
||||
return self.SendScintilla(scintillacon.SCI_GETFOLDLEVEL, lineno)
|
||||
def SCIToggleFold(self, lineno):
|
||||
return self.SendScintilla(scintillacon.SCI_TOGGLEFOLD, lineno)
|
||||
def SCIEnsureVisible(self, lineno):
|
||||
self.SendScintilla(scintillacon.SCI_ENSUREVISIBLE, lineno)
|
||||
def SCIGetFoldExpanded(self, lineno):
|
||||
return self.SendScintilla(scintillacon.SCI_GETFOLDEXPANDED, lineno)
|
||||
# right edge
|
||||
def SCISetEdgeColumn(self, edge):
|
||||
self.SendScintilla(scintillacon.SCI_SETEDGECOLUMN, edge)
|
||||
def SCIGetEdgeColumn(self):
|
||||
return self.SendScintilla(scintillacon.SCI_GETEDGECOLUMN)
|
||||
def SCISetEdgeMode(self, mode):
|
||||
self.SendScintilla(scintillacon.SCI_SETEDGEMODE, mode)
|
||||
def SCIGetEdgeMode(self):
|
||||
return self.SendScintilla(scintillacon.SCI_GETEDGEMODE)
|
||||
def SCISetEdgeColor(self, color):
|
||||
self.SendScintilla(scintillacon.SCI_SETEDGECOLOUR, color)
|
||||
def SCIGetEdgeColor(self):
|
||||
return self.SendScintilla(scintillacon.SCI_GETEDGECOLOR)
|
||||
# Multi-doc
|
||||
def SCIGetDocPointer(self):
|
||||
return self.SendScintilla(scintillacon.SCI_GETDOCPOINTER)
|
||||
def SCISetDocPointer(self, p):
|
||||
return self.SendScintilla(scintillacon.SCI_SETDOCPOINTER, 0, p)
|
||||
def SCISetWrapMode(self, mode):
|
||||
return self.SendScintilla(scintillacon.SCI_SETWRAPMODE, mode)
|
||||
def SCIGetWrapMode(self):
|
||||
return self.SendScintilla(scintillacon.SCI_GETWRAPMODE)
|
||||
|
||||
class CScintillaEditInterface(ScintillaControlInterface):
|
||||
def close(self):
|
||||
self.colorizer = None
|
||||
def Clear(self):
|
||||
self.SendScintilla(win32con.WM_CLEAR)
|
||||
def Clear(self):
|
||||
self.SendScintilla(win32con.WM_CLEAR)
|
||||
def FindText(self, flags, range, findText):
|
||||
""" LPARAM for EM_FINDTEXTEX:
|
||||
typedef struct _findtextex {
|
||||
CHARRANGE chrg;
|
||||
LPCTSTR lpstrText;
|
||||
CHARRANGE chrgText;} FINDTEXTEX;
|
||||
typedef struct _charrange {
|
||||
LONG cpMin;
|
||||
LONG cpMax;} CHARRANGE;
|
||||
"""
|
||||
findtextex_fmt='llPll'
|
||||
## Scintilla does not handle unicode in EM_FINDTEXT msg (FINDTEXTEX struct)
|
||||
txt_buff = (findText+'\0').encode(default_scintilla_encoding)
|
||||
txt_array = array.array('b', txt_buff)
|
||||
ft_buff = struct.pack(findtextex_fmt, range[0], range[1], txt_array.buffer_info()[0], 0, 0)
|
||||
ft_array = array.array('b', ft_buff)
|
||||
rc = self.SendScintilla(EM_FINDTEXTEX, flags, ft_array.buffer_info()[0])
|
||||
ftUnpacked = struct.unpack(findtextex_fmt, ft_array)
|
||||
return rc, (ftUnpacked[3], ftUnpacked[4])
|
||||
|
||||
def GetSel(self):
|
||||
currentPos = self.SendScintilla(scintillacon.SCI_GETCURRENTPOS)
|
||||
anchorPos = self.SendScintilla(scintillacon.SCI_GETANCHOR)
|
||||
if currentPos < anchorPos:
|
||||
return (currentPos, anchorPos)
|
||||
else:
|
||||
return (anchorPos, currentPos)
|
||||
return currentPos;
|
||||
|
||||
def GetSelText(self):
|
||||
start, end = self.GetSel()
|
||||
txtBuf = array.array('b', null_byte * (end-start+1))
|
||||
addressTxtBuf = txtBuf.buffer_info()[0]
|
||||
# EM_GETSELTEXT is documented as returning the number of chars
|
||||
# not including the NULL, but scintilla includes the NULL. A
|
||||
# quick glance at the scintilla impl doesn't make this
|
||||
# obvious - the NULL is included in the 'selection' object
|
||||
# and reflected in the length of that 'selection' object.
|
||||
# I expect that is a bug in scintilla and may be fixed by now,
|
||||
# but we just blindly assume that the last char is \0 and
|
||||
# strip it.
|
||||
self.SendScintilla(EM_GETSELTEXT, 0, addressTxtBuf)
|
||||
return txtBuf.tostring()[:-1].decode(default_scintilla_encoding)
|
||||
|
||||
def SetSel(self, start=0, end=None):
|
||||
if type(start)==type(()):
|
||||
assert end is None, "If you pass a point in the first param, the second must be None"
|
||||
start, end = start
|
||||
elif end is None:
|
||||
end = start
|
||||
if start < 0: start = self.GetTextLength()
|
||||
if end < 0: end = self.GetTextLength()
|
||||
assert start <= self.GetTextLength(), "The start postion is invalid (%d/%d)" % (start, self.GetTextLength())
|
||||
assert end <= self.GetTextLength(), "The end postion is invalid (%d/%d)" % (end, self.GetTextLength())
|
||||
cr = struct.pack('ll', start, end)
|
||||
crBuff = array.array('b', cr)
|
||||
addressCrBuff = crBuff.buffer_info()[0]
|
||||
rc = self.SendScintilla(EM_EXSETSEL, 0, addressCrBuff)
|
||||
|
||||
def GetLineCount(self):
|
||||
return self.SendScintilla(win32con.EM_GETLINECOUNT)
|
||||
|
||||
def LineFromChar(self, charPos=-1):
|
||||
if charPos==-1: charPos = self.GetSel()[0]
|
||||
assert charPos >= 0 and charPos <= self.GetTextLength(), "The charPos postion (%s) is invalid (max=%s)" % (charPos, self.GetTextLength())
|
||||
#return self.SendScintilla(EM_EXLINEFROMCHAR, charPos)
|
||||
# EM_EXLINEFROMCHAR puts charPos in lParam, not wParam
|
||||
return self.SendScintilla(EM_EXLINEFROMCHAR, 0, charPos)
|
||||
|
||||
def LineIndex(self, line):
|
||||
return self.SendScintilla(win32con.EM_LINEINDEX, line)
|
||||
|
||||
def ScrollCaret(self):
|
||||
return self.SendScintilla(win32con.EM_SCROLLCARET)
|
||||
|
||||
def GetCurLineNumber(self):
|
||||
return self.LineFromChar(self.SCIGetCurrentPos())
|
||||
|
||||
def GetTextLength(self):
|
||||
return self.SendScintilla(scintillacon.SCI_GETTEXTLENGTH)
|
||||
|
||||
def GetTextRange(self, start = 0, end = -1, decode = True):
|
||||
if end == -1: end = self.SendScintilla(scintillacon.SCI_GETTEXTLENGTH)
|
||||
assert end>=start, "Negative index requested (%d/%d)" % (start, end)
|
||||
assert start >= 0 and start <= self.GetTextLength(), "The start postion is invalid"
|
||||
assert end >= 0 and end <= self.GetTextLength(), "The end postion is invalid"
|
||||
initer = null_byte * (end - start + 1)
|
||||
buff = array.array('b', initer)
|
||||
addressBuffer = buff.buffer_info()[0]
|
||||
tr = struct.pack('llP', start, end, addressBuffer)
|
||||
trBuff = array.array('b', tr)
|
||||
addressTrBuff = trBuff.buffer_info()[0]
|
||||
num_bytes = self.SendScintilla(EM_GETTEXTRANGE, 0, addressTrBuff)
|
||||
ret = buff.tostring()[:num_bytes]
|
||||
if decode:
|
||||
ret = ret.decode(default_scintilla_encoding)
|
||||
return ret
|
||||
|
||||
def ReplaceSel(self, str):
|
||||
buff = (str + "\0").encode(default_scintilla_encoding)
|
||||
self.SendScintilla(scintillacon.SCI_REPLACESEL, 0, buff)
|
||||
|
||||
def GetLine(self, line=-1):
|
||||
if line == -1: line = self.GetCurLineNumber()
|
||||
start = self.LineIndex(line)
|
||||
end = self.LineIndex(line+1)
|
||||
return self.GetTextRange(start, end)
|
||||
|
||||
def SetReadOnly(self, flag = 1):
|
||||
return self.SendScintilla(win32con.EM_SETREADONLY, flag)
|
||||
|
||||
def LineScroll(self, lines, cols=0):
|
||||
return self.SendScintilla(win32con.EM_LINESCROLL, cols, lines)
|
||||
|
||||
def GetFirstVisibleLine(self):
|
||||
return self.SendScintilla(win32con.EM_GETFIRSTVISIBLELINE)
|
||||
|
||||
def SetWordWrap(self, mode):
|
||||
if mode != win32ui.CRichEditView_WrapNone:
|
||||
raise ValueError("We dont support word-wrap (I dont think :-)")
|
||||
|
||||
class CScintillaColorEditInterface(CScintillaEditInterface):
|
||||
################################
|
||||
# Plug-in colorizer support
|
||||
def _GetColorizer(self):
|
||||
if not hasattr(self, "colorizer"):
|
||||
self.colorizer = self._MakeColorizer()
|
||||
return self.colorizer
|
||||
def _MakeColorizer(self):
|
||||
# Give parent a chance to hook.
|
||||
parent_func = getattr(self.GetParentFrame(), "_MakeColorizer", None)
|
||||
if parent_func is not None:
|
||||
return parent_func()
|
||||
from . import formatter
|
||||
## return formatter.PythonSourceFormatter(self)
|
||||
return formatter.BuiltinPythonSourceFormatter(self)
|
||||
|
||||
def Colorize(self, start=0, end=-1):
|
||||
c = self._GetColorizer()
|
||||
if c is not None: c.Colorize(start, end)
|
||||
|
||||
def ApplyFormattingStyles(self, bReload=1):
|
||||
c = self._GetColorizer()
|
||||
if c is not None: c.ApplyFormattingStyles(bReload)
|
||||
|
||||
# The Parent window will normally hook
|
||||
def HookFormatter(self, parent = None):
|
||||
c = self._GetColorizer()
|
||||
if c is not None: # No need if we have no color!
|
||||
c.HookFormatter(parent)
|
||||
|
||||
class CScintillaEdit(window.Wnd, CScintillaColorEditInterface):
|
||||
def __init__(self, wnd=None):
|
||||
if wnd is None:
|
||||
wnd = win32ui.CreateWnd()
|
||||
window.Wnd.__init__(self, wnd)
|
||||
def SendScintilla(self, msg, w=0, l=0):
|
||||
return self.SendMessage(msg, w, l)
|
||||
def CreateWindow(self, style, rect, parent, id):
|
||||
self._obj_.CreateWindow(
|
||||
"Scintilla",
|
||||
"Scintilla",
|
||||
style,
|
||||
rect,
|
||||
parent,
|
||||
id,
|
||||
None)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue