install pywin32-220
This commit is contained in:
parent
15d9012f5a
commit
93f7d415a0
581 changed files with 100203 additions and 0 deletions
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)
|
||||
|
||||
274
Lib/site-packages/pythonwin/pywin/scintilla/document.py
Normal file
274
Lib/site-packages/pythonwin/pywin/scintilla/document.py
Normal file
|
|
@ -0,0 +1,274 @@
|
|||
import win32ui
|
||||
from pywin.mfc import docview
|
||||
from pywin import default_scintilla_encoding
|
||||
from . import scintillacon
|
||||
import win32con
|
||||
import string
|
||||
import os
|
||||
import codecs
|
||||
import re
|
||||
|
||||
crlf_bytes = "\r\n".encode("ascii")
|
||||
lf_bytes = "\n".encode("ascii")
|
||||
|
||||
# re from pep263 - but we use it both on bytes and strings.
|
||||
re_encoding_bytes = re.compile("coding[:=]\s*([-\w.]+)".encode("ascii"))
|
||||
re_encoding_text = re.compile("coding[:=]\s*([-\w.]+)")
|
||||
|
||||
ParentScintillaDocument=docview.Document
|
||||
class CScintillaDocument(ParentScintillaDocument):
|
||||
"A SyntEdit document. "
|
||||
def __init__(self, *args):
|
||||
self.bom = None # the BOM, if any, read from the file.
|
||||
# the encoding we detected from the source. Might have
|
||||
# detected via the BOM or an encoding decl. Note that in
|
||||
# the latter case (ie, while self.bom is None), it can't be
|
||||
# trusted - the user may have edited the encoding decl between
|
||||
# open and save.
|
||||
self.source_encoding = None
|
||||
ParentScintillaDocument.__init__(self, *args)
|
||||
|
||||
def DeleteContents(self):
|
||||
pass
|
||||
|
||||
def OnOpenDocument(self, filename):
|
||||
# init data members
|
||||
#print "Opening", filename
|
||||
self.SetPathName(filename) # Must set this early!
|
||||
try:
|
||||
# load the text as binary we can get smart
|
||||
# about detecting any existing EOL conventions.
|
||||
f = open(filename, 'rb')
|
||||
try:
|
||||
self._LoadTextFromFile(f)
|
||||
finally:
|
||||
f.close()
|
||||
except IOError:
|
||||
rc = win32ui.MessageBox("Could not load the file from %s\n\nDo you want to create a new file?" % filename,
|
||||
"Pythonwin", win32con.MB_YESNO | win32con.MB_ICONWARNING)
|
||||
if rc == win32con.IDNO:
|
||||
return 0
|
||||
assert rc == win32con.IDYES, rc
|
||||
try:
|
||||
f = open(filename, 'wb+')
|
||||
try:
|
||||
self._LoadTextFromFile(f)
|
||||
finally:
|
||||
f.close()
|
||||
except IOError as e:
|
||||
rc = win32ui.MessageBox("Cannot create the file %s" % filename)
|
||||
return 1
|
||||
|
||||
def SaveFile(self, fileName, encoding=None):
|
||||
view = self.GetFirstView()
|
||||
ok = view.SaveTextFile(fileName, encoding=encoding)
|
||||
if ok:
|
||||
view.SCISetSavePoint()
|
||||
return ok
|
||||
|
||||
def ApplyFormattingStyles(self):
|
||||
self._ApplyOptionalToViews("ApplyFormattingStyles")
|
||||
|
||||
# #####################
|
||||
# File related functions
|
||||
# Helper to transfer text from the MFC document to the control.
|
||||
def _LoadTextFromFile(self, f):
|
||||
# detect EOL mode - we don't support \r only - so find the
|
||||
# first '\n' and guess based on the char before.
|
||||
l = f.readline()
|
||||
l2 = f.readline()
|
||||
# If line ends with \r\n or has no line ending, use CRLF.
|
||||
if l.endswith(crlf_bytes) or not l.endswith(lf_bytes):
|
||||
eol_mode = scintillacon.SC_EOL_CRLF
|
||||
else:
|
||||
eol_mode = scintillacon.SC_EOL_LF
|
||||
|
||||
# Detect the encoding - first look for a BOM, and if not found,
|
||||
# look for a pep263 encoding declaration.
|
||||
for bom, encoding in (
|
||||
(codecs.BOM_UTF8, "utf8"),
|
||||
(codecs.BOM_UTF16_LE, "utf_16_le"),
|
||||
(codecs.BOM_UTF16_BE, "utf_16_be"),
|
||||
):
|
||||
if l.startswith(bom):
|
||||
self.bom = bom
|
||||
self.source_encoding = encoding
|
||||
l = l[len(bom):] # remove it.
|
||||
break
|
||||
else:
|
||||
# no bom detected - look for pep263 encoding decl.
|
||||
for look in (l, l2):
|
||||
# Note we are looking at raw bytes here: so
|
||||
# both the re itself uses bytes and the result
|
||||
# is bytes - but we need the result as a string.
|
||||
match = re_encoding_bytes.search(look)
|
||||
if match is not None:
|
||||
self.source_encoding = match.group(1).decode("ascii")
|
||||
break
|
||||
|
||||
# reading by lines would be too slow? Maybe we can use the
|
||||
# incremental encoders? For now just stick with loading the
|
||||
# entire file in memory.
|
||||
text = l + l2 + f.read()
|
||||
|
||||
# Translate from source encoding to UTF-8 bytes for Scintilla
|
||||
source_encoding = self.source_encoding
|
||||
# If we don't know an encoding, just use latin-1 to treat
|
||||
# it as bytes...
|
||||
if source_encoding is None:
|
||||
source_encoding = 'latin1'
|
||||
# we could optimize this by avoiding utf8 to-ing and from-ing,
|
||||
# but then we would lose the ability to handle invalid utf8
|
||||
# (and even then, the use of encoding aliases makes this tricky)
|
||||
# To create an invalid utf8 file:
|
||||
# >>> open(filename, "wb").write(codecs.BOM_UTF8+"bad \xa9har\r\n")
|
||||
try:
|
||||
dec = text.decode(source_encoding)
|
||||
except UnicodeError:
|
||||
print("WARNING: Failed to decode bytes from '%s' encoding - treating as latin1" % source_encoding)
|
||||
dec = text.decode('latin1')
|
||||
except LookupError:
|
||||
print("WARNING: Invalid encoding '%s' specified - treating as latin1" % source_encoding)
|
||||
dec = text.decode('latin1')
|
||||
# and put it back as utf8 - this shouldn't fail.
|
||||
text = dec.encode(default_scintilla_encoding)
|
||||
|
||||
view = self.GetFirstView()
|
||||
if view.IsWindow():
|
||||
# Turn off undo collection while loading
|
||||
view.SendScintilla(scintillacon.SCI_SETUNDOCOLLECTION, 0, 0)
|
||||
# Make sure the control isnt read-only
|
||||
view.SetReadOnly(0)
|
||||
view.SendScintilla(scintillacon.SCI_CLEARALL)
|
||||
view.SendMessage(scintillacon.SCI_ADDTEXT, text)
|
||||
view.SendScintilla(scintillacon.SCI_SETUNDOCOLLECTION, 1, 0)
|
||||
view.SendScintilla(win32con.EM_EMPTYUNDOBUFFER, 0, 0)
|
||||
# set EOL mode
|
||||
view.SendScintilla(scintillacon.SCI_SETEOLMODE, eol_mode)
|
||||
|
||||
def _SaveTextToFile(self, view, filename, encoding=None):
|
||||
s = view.GetTextRange() # already decoded from scintilla's encoding
|
||||
source_encoding = encoding
|
||||
if source_encoding is None:
|
||||
if self.bom:
|
||||
source_encoding = self.source_encoding
|
||||
else:
|
||||
# no BOM - look for an encoding.
|
||||
bits = re.split("[\r\n]*", s, 3)
|
||||
for look in bits[:-1]:
|
||||
match = re_encoding_text.search(look)
|
||||
if match is not None:
|
||||
source_encoding = match.group(1)
|
||||
self.source_encoding = source_encoding
|
||||
break
|
||||
|
||||
if source_encoding is None:
|
||||
source_encoding = 'latin1'
|
||||
|
||||
## encode data before opening file so script is not lost if encoding fails
|
||||
file_contents = s.encode(source_encoding)
|
||||
# Open in binary mode as scintilla itself ensures the
|
||||
# line endings are already appropriate
|
||||
f = open(filename, 'wb')
|
||||
try:
|
||||
if self.bom:
|
||||
f.write(self.bom)
|
||||
f.write(file_contents)
|
||||
finally:
|
||||
f.close()
|
||||
self.SetModifiedFlag(0)
|
||||
|
||||
def FinalizeViewCreation(self, view):
|
||||
pass
|
||||
|
||||
def HookViewNotifications(self, view):
|
||||
parent = view.GetParentFrame()
|
||||
parent.HookNotify(ViewNotifyDelegate(self, "OnBraceMatch"), scintillacon.SCN_CHECKBRACE)
|
||||
parent.HookNotify(ViewNotifyDelegate(self, "OnMarginClick"), scintillacon.SCN_MARGINCLICK)
|
||||
parent.HookNotify(ViewNotifyDelegate(self, "OnNeedShown"), scintillacon.SCN_NEEDSHOWN)
|
||||
|
||||
parent.HookNotify(DocumentNotifyDelegate(self, "OnSavePointReached"), scintillacon.SCN_SAVEPOINTREACHED)
|
||||
parent.HookNotify(DocumentNotifyDelegate(self, "OnSavePointLeft"), scintillacon.SCN_SAVEPOINTLEFT)
|
||||
parent.HookNotify(DocumentNotifyDelegate(self, "OnModifyAttemptRO"), scintillacon.SCN_MODIFYATTEMPTRO)
|
||||
# Tell scintilla what characters should abort auto-complete.
|
||||
view.SCIAutoCStops(string.whitespace+"()[]:;+-/*=\\?'!#@$%^&,<>\"'|" )
|
||||
|
||||
if view != self.GetFirstView():
|
||||
view.SCISetDocPointer(self.GetFirstView().SCIGetDocPointer())
|
||||
|
||||
|
||||
def OnSavePointReached(self, std, extra):
|
||||
self.SetModifiedFlag(0)
|
||||
|
||||
def OnSavePointLeft(self, std, extra):
|
||||
self.SetModifiedFlag(1)
|
||||
|
||||
def OnModifyAttemptRO(self, std, extra):
|
||||
self.MakeDocumentWritable()
|
||||
|
||||
# All Marker functions are 1 based.
|
||||
def MarkerAdd( self, lineNo, marker ):
|
||||
self.GetEditorView().SCIMarkerAdd(lineNo-1, marker)
|
||||
|
||||
def MarkerCheck(self, lineNo, marker ):
|
||||
v = self.GetEditorView()
|
||||
lineNo = lineNo - 1 # Make 0 based
|
||||
markerState = v.SCIMarkerGet(lineNo)
|
||||
return markerState & (1<<marker) != 0
|
||||
|
||||
def MarkerToggle( self, lineNo, marker ):
|
||||
v = self.GetEditorView()
|
||||
if self.MarkerCheck(lineNo, marker):
|
||||
v.SCIMarkerDelete(lineNo-1, marker)
|
||||
else:
|
||||
v.SCIMarkerAdd(lineNo-1, marker)
|
||||
def MarkerDelete( self, lineNo, marker ):
|
||||
self.GetEditorView().SCIMarkerDelete(lineNo-1, marker)
|
||||
def MarkerDeleteAll( self, marker ):
|
||||
self.GetEditorView().SCIMarkerDeleteAll(marker)
|
||||
def MarkerGetNext(self, lineNo, marker):
|
||||
return self.GetEditorView().SCIMarkerNext( lineNo-1, 1 << marker )+1
|
||||
def MarkerAtLine(self, lineNo, marker):
|
||||
markerState = self.GetEditorView().SCIMarkerGet(lineNo-1)
|
||||
return markerState & (1<<marker)
|
||||
|
||||
# Helper for reflecting functions to views.
|
||||
def _ApplyToViews(self, funcName, *args):
|
||||
for view in self.GetAllViews():
|
||||
func = getattr(view, funcName)
|
||||
func(*args)
|
||||
def _ApplyOptionalToViews(self, funcName, *args):
|
||||
for view in self.GetAllViews():
|
||||
func = getattr(view, funcName, None)
|
||||
if func is not None:
|
||||
func(*args)
|
||||
def GetEditorView(self):
|
||||
# Find the first frame with a view,
|
||||
# then ask it to give the editor view
|
||||
# as it knows which one is "active"
|
||||
try:
|
||||
frame_gev = self.GetFirstView().GetParentFrame().GetEditorView
|
||||
except AttributeError:
|
||||
return self.GetFirstView()
|
||||
return frame_gev()
|
||||
|
||||
# Delegate to the correct view, based on the control that sent it.
|
||||
class ViewNotifyDelegate:
|
||||
def __init__(self, doc, name):
|
||||
self.doc = doc
|
||||
self.name = name
|
||||
def __call__(self, std, extra):
|
||||
(hwndFrom, idFrom, code) = std
|
||||
for v in self.doc.GetAllViews():
|
||||
if v.GetSafeHwnd() == hwndFrom:
|
||||
return getattr(v, self.name)(*(std, extra))
|
||||
|
||||
# Delegate to the document, but only from a single view (as each view sends it seperately)
|
||||
class DocumentNotifyDelegate:
|
||||
def __init__(self, doc, name):
|
||||
self.doc = doc
|
||||
self.delegate = getattr(doc, name)
|
||||
def __call__(self, std, extra):
|
||||
(hwndFrom, idFrom, code) = std
|
||||
if hwndFrom == self.doc.GetEditorView().GetSafeHwnd():
|
||||
self.delegate(*(std, extra))
|
||||
334
Lib/site-packages/pythonwin/pywin/scintilla/find.py
Normal file
334
Lib/site-packages/pythonwin/pywin/scintilla/find.py
Normal file
|
|
@ -0,0 +1,334 @@
|
|||
# find.py - Find and Replace
|
||||
import win32con, win32api
|
||||
import win32ui
|
||||
from pywin.mfc import dialog
|
||||
import afxres
|
||||
from pywin.framework import scriptutils
|
||||
|
||||
FOUND_NOTHING=0
|
||||
FOUND_NORMAL=1
|
||||
FOUND_LOOPED_BACK=2
|
||||
FOUND_NEXT_FILE=3
|
||||
|
||||
class SearchParams:
|
||||
def __init__(self, other=None):
|
||||
if other is None:
|
||||
self.__dict__['findText'] = ""
|
||||
self.__dict__['replaceText'] = ""
|
||||
self.__dict__['matchCase'] = 0
|
||||
self.__dict__['matchWords'] = 0
|
||||
self.__dict__['acrossFiles'] = 0
|
||||
self.__dict__['remember'] = 1
|
||||
self.__dict__['sel'] = (-1,-1)
|
||||
self.__dict__['keepDialogOpen']=0
|
||||
else:
|
||||
self.__dict__.update(other.__dict__)
|
||||
# Helper so we cant misspell attributes :-)
|
||||
def __setattr__(self, attr, val):
|
||||
if not hasattr(self, attr):
|
||||
raise AttributeError(attr)
|
||||
self.__dict__[attr]=val
|
||||
|
||||
curDialog = None
|
||||
lastSearch = defaultSearch = SearchParams()
|
||||
searchHistory = []
|
||||
|
||||
def ShowFindDialog():
|
||||
_ShowDialog(FindDialog)
|
||||
|
||||
def ShowReplaceDialog():
|
||||
_ShowDialog(ReplaceDialog)
|
||||
|
||||
def _ShowDialog(dlgClass):
|
||||
global curDialog
|
||||
if curDialog is not None:
|
||||
if curDialog.__class__ != dlgClass:
|
||||
curDialog.DestroyWindow()
|
||||
curDialog = None
|
||||
else:
|
||||
curDialog.SetFocus()
|
||||
if curDialog is None:
|
||||
curDialog = dlgClass()
|
||||
curDialog.CreateWindow()
|
||||
|
||||
def FindNext():
|
||||
params = SearchParams(lastSearch)
|
||||
params.sel = (-1,-1)
|
||||
if not params.findText:
|
||||
ShowFindDialog()
|
||||
else:
|
||||
return _FindIt(None, params)
|
||||
|
||||
def _GetControl(control=None):
|
||||
if control is None:
|
||||
control = scriptutils.GetActiveEditControl()
|
||||
return control
|
||||
|
||||
def _FindIt(control, searchParams):
|
||||
global lastSearch, defaultSearch
|
||||
control = _GetControl(control)
|
||||
if control is None: return FOUND_NOTHING
|
||||
|
||||
# Move to the next char, so we find the next one.
|
||||
flags = 0
|
||||
if searchParams.matchWords: flags = flags | win32con.FR_WHOLEWORD
|
||||
if searchParams.matchCase: flags = flags | win32con.FR_MATCHCASE
|
||||
if searchParams.sel == (-1,-1):
|
||||
sel = control.GetSel()
|
||||
# If the position is the same as we found last time,
|
||||
# then we assume it is a "FindNext"
|
||||
if sel==lastSearch.sel:
|
||||
sel = sel[0]+1, sel[0]+1
|
||||
else:
|
||||
sel = searchParams.sel
|
||||
|
||||
if sel[0]==sel[1]: sel=sel[0], control.GetTextLength()
|
||||
|
||||
rc = FOUND_NOTHING
|
||||
# (Old edit control will fail here!)
|
||||
posFind, foundSel = control.FindText(flags, sel, searchParams.findText)
|
||||
lastSearch = SearchParams(searchParams)
|
||||
if posFind >= 0:
|
||||
rc = FOUND_NORMAL
|
||||
lineno = control.LineFromChar(posFind)
|
||||
control.SCIEnsureVisible(lineno)
|
||||
control.SetSel(foundSel)
|
||||
control.SetFocus()
|
||||
win32ui.SetStatusText(win32ui.LoadString(afxres.AFX_IDS_IDLEMESSAGE))
|
||||
if rc == FOUND_NOTHING and lastSearch.acrossFiles:
|
||||
# Loop around all documents. First find this document.
|
||||
try:
|
||||
try:
|
||||
doc = control.GetDocument()
|
||||
except AttributeError:
|
||||
try:
|
||||
doc = control.GetParent().GetDocument()
|
||||
except AttributeError:
|
||||
print("Cant find a document for the control!")
|
||||
doc = None
|
||||
if doc is not None:
|
||||
template = doc.GetDocTemplate()
|
||||
alldocs = template.GetDocumentList()
|
||||
mypos = lookpos = alldocs.index(doc)
|
||||
while 1:
|
||||
lookpos = (lookpos+1) % len(alldocs)
|
||||
if lookpos == mypos:
|
||||
break
|
||||
view = alldocs[lookpos].GetFirstView()
|
||||
posFind, foundSel = view.FindText(flags, (0, view.GetTextLength()), searchParams.findText)
|
||||
if posFind >= 0:
|
||||
nChars = foundSel[1]-foundSel[0]
|
||||
lineNo = view.LineFromChar(posFind) # zero based.
|
||||
lineStart = view.LineIndex(lineNo)
|
||||
colNo = posFind - lineStart # zero based.
|
||||
scriptutils.JumpToDocument(alldocs[lookpos].GetPathName(), lineNo+1, colNo+1, nChars)
|
||||
rc = FOUND_NEXT_FILE
|
||||
break
|
||||
except win32ui.error:
|
||||
pass
|
||||
if rc == FOUND_NOTHING:
|
||||
# Loop around this control - attempt to find from the start of the control.
|
||||
posFind, foundSel = control.FindText(flags, (0, sel[0]-1), searchParams.findText)
|
||||
if posFind >= 0:
|
||||
control.SCIEnsureVisible(control.LineFromChar(foundSel[0]))
|
||||
control.SetSel(foundSel)
|
||||
control.SetFocus()
|
||||
win32ui.SetStatusText("Not found! Searching from the top of the file.")
|
||||
rc = FOUND_LOOPED_BACK
|
||||
else:
|
||||
lastSearch.sel=-1,-1
|
||||
win32ui.SetStatusText("Can not find '%s'" % searchParams.findText )
|
||||
|
||||
if rc != FOUND_NOTHING:
|
||||
lastSearch.sel = foundSel
|
||||
|
||||
if lastSearch.remember:
|
||||
defaultSearch = lastSearch
|
||||
|
||||
# track search history
|
||||
try:
|
||||
ix = searchHistory.index(searchParams.findText)
|
||||
except ValueError:
|
||||
if len(searchHistory) > 50:
|
||||
searchHistory[50:] = []
|
||||
else:
|
||||
del searchHistory[ix]
|
||||
searchHistory.insert(0, searchParams.findText)
|
||||
|
||||
return rc
|
||||
|
||||
def _ReplaceIt(control):
|
||||
control = _GetControl(control)
|
||||
statusText = "Can not find '%s'." % lastSearch.findText
|
||||
rc = FOUND_NOTHING
|
||||
if control is not None and lastSearch.sel != (-1,-1):
|
||||
control.ReplaceSel(lastSearch.replaceText)
|
||||
rc = FindNext()
|
||||
if rc !=FOUND_NOTHING:
|
||||
statusText = win32ui.LoadString(afxres.AFX_IDS_IDLEMESSAGE)
|
||||
win32ui.SetStatusText(statusText)
|
||||
return rc
|
||||
|
||||
class FindReplaceDialog(dialog.Dialog):
|
||||
def __init__(self):
|
||||
dialog.Dialog.__init__(self,self._GetDialogTemplate())
|
||||
self.HookCommand(self.OnFindNext, 109)
|
||||
|
||||
def OnInitDialog(self):
|
||||
self.editFindText = self.GetDlgItem(102)
|
||||
self.butMatchWords = self.GetDlgItem(105)
|
||||
self.butMatchCase = self.GetDlgItem(107)
|
||||
self.butKeepDialogOpen = self.GetDlgItem(115)
|
||||
self.butAcrossFiles = self.GetDlgItem(116)
|
||||
self.butRemember = self.GetDlgItem(117)
|
||||
|
||||
self.editFindText.SetWindowText(defaultSearch.findText)
|
||||
control = _GetControl()
|
||||
# _GetControl only gets normal MDI windows; if the interactive
|
||||
# window is docked and no document open, we get None.
|
||||
if control:
|
||||
# If we have a selection, default to that.
|
||||
sel = control.GetSelText()
|
||||
if (len(sel) != 0):
|
||||
self.editFindText.SetWindowText(sel)
|
||||
if (defaultSearch.remember):
|
||||
defaultSearch.findText = sel
|
||||
for hist in searchHistory:
|
||||
self.editFindText.AddString(hist)
|
||||
|
||||
if hasattr(self.editFindText, 'SetEditSel'):
|
||||
self.editFindText.SetEditSel(0, -2)
|
||||
else:
|
||||
self.editFindText.SetSel(0, -2)
|
||||
self.editFindText.SetFocus()
|
||||
self.butMatchWords.SetCheck(defaultSearch.matchWords)
|
||||
self.butMatchCase.SetCheck(defaultSearch.matchCase)
|
||||
self.butKeepDialogOpen.SetCheck(defaultSearch.keepDialogOpen)
|
||||
self.butAcrossFiles.SetCheck(defaultSearch.acrossFiles)
|
||||
self.butRemember.SetCheck(defaultSearch.remember)
|
||||
return dialog.Dialog.OnInitDialog(self)
|
||||
|
||||
def OnDestroy(self, msg):
|
||||
global curDialog
|
||||
curDialog = None
|
||||
return dialog.Dialog.OnDestroy(self, msg)
|
||||
|
||||
def DoFindNext(self):
|
||||
params = SearchParams()
|
||||
params.findText = self.editFindText.GetWindowText()
|
||||
params.matchCase = self.butMatchCase.GetCheck()
|
||||
params.matchWords = self.butMatchWords.GetCheck()
|
||||
params.acrossFiles = self.butAcrossFiles.GetCheck()
|
||||
params.remember = self.butRemember.GetCheck()
|
||||
return _FindIt(None, params)
|
||||
|
||||
def OnFindNext(self, id, code):
|
||||
if not self.editFindText.GetWindowText():
|
||||
win32api.MessageBeep()
|
||||
return
|
||||
if self.DoFindNext() != FOUND_NOTHING:
|
||||
if not self.butKeepDialogOpen.GetCheck():
|
||||
self.DestroyWindow()
|
||||
|
||||
class FindDialog(FindReplaceDialog):
|
||||
def _GetDialogTemplate(self):
|
||||
style = win32con.DS_MODALFRAME | win32con.WS_POPUP | win32con.WS_VISIBLE | win32con.WS_CAPTION | win32con.WS_SYSMENU | win32con.DS_SETFONT
|
||||
visible = win32con.WS_CHILD | win32con.WS_VISIBLE
|
||||
dt = [
|
||||
["Find", (0, 2, 240, 75), style, None, (8, "MS Sans Serif")],
|
||||
["Static", "Fi&nd What:", 101, (5, 8, 40, 10), visible],
|
||||
["ComboBox", "", 102, (50, 7, 120, 120), visible | win32con.WS_BORDER | win32con.WS_TABSTOP |
|
||||
win32con.WS_VSCROLL |win32con.CBS_DROPDOWN |win32con.CBS_AUTOHSCROLL],
|
||||
["Button", "Match &whole word only", 105, (5, 23, 100, 10), visible | win32con.BS_AUTOCHECKBOX | win32con.WS_TABSTOP],
|
||||
["Button", "Match &case", 107, (5, 33, 100, 10), visible | win32con.BS_AUTOCHECKBOX | win32con.WS_TABSTOP],
|
||||
["Button", "Keep &dialog open", 115, (5, 43, 100, 10), visible | win32con.BS_AUTOCHECKBOX | win32con.WS_TABSTOP],
|
||||
["Button", "Across &open files", 116, (5, 52, 100, 10), visible | win32con.BS_AUTOCHECKBOX | win32con.WS_TABSTOP],
|
||||
["Button", "&Remember as default search", 117, (5, 61, 150, 10), visible | win32con.BS_AUTOCHECKBOX | win32con.WS_TABSTOP],
|
||||
["Button", "&Find Next", 109, (185, 5, 50, 14), visible | win32con.BS_DEFPUSHBUTTON | win32con.WS_TABSTOP],
|
||||
["Button", "Cancel", win32con.IDCANCEL, (185, 23, 50, 14), visible | win32con.WS_TABSTOP],
|
||||
]
|
||||
return dt
|
||||
|
||||
class ReplaceDialog(FindReplaceDialog):
|
||||
def _GetDialogTemplate(self):
|
||||
style = win32con.DS_MODALFRAME | win32con.WS_POPUP | win32con.WS_VISIBLE | win32con.WS_CAPTION | win32con.WS_SYSMENU | win32con.DS_SETFONT
|
||||
visible = win32con.WS_CHILD | win32con.WS_VISIBLE
|
||||
dt = [
|
||||
["Replace", (0, 2, 240, 95), style, 0, (8, "MS Sans Serif")],
|
||||
["Static", "Fi&nd What:", 101, (5, 8, 40, 10), visible],
|
||||
["ComboBox", "", 102, (60, 7, 110, 120), visible | win32con.WS_BORDER | win32con.WS_TABSTOP |
|
||||
win32con.WS_VSCROLL |win32con.CBS_DROPDOWN |win32con.CBS_AUTOHSCROLL],
|
||||
["Static", "Re&place with:", 103, (5, 25, 50, 10), visible],
|
||||
["ComboBox", "", 104, (60, 24, 110, 120), visible | win32con.WS_BORDER | win32con.WS_TABSTOP |
|
||||
win32con.WS_VSCROLL |win32con.CBS_DROPDOWN |win32con.CBS_AUTOHSCROLL],
|
||||
["Button", "Match &whole word only", 105, (5, 42, 100, 10), visible | win32con.BS_AUTOCHECKBOX | win32con.WS_TABSTOP],
|
||||
["Button", "Match &case", 107, (5, 52, 100, 10), visible | win32con.BS_AUTOCHECKBOX | win32con.WS_TABSTOP],
|
||||
["Button", "Keep &dialog open", 115, (5, 62, 100, 10), visible | win32con.BS_AUTOCHECKBOX | win32con.WS_TABSTOP],
|
||||
["Button", "Across &open files", 116, (5, 72, 100, 10), visible | win32con.BS_AUTOCHECKBOX | win32con.WS_TABSTOP],
|
||||
["Button", "&Remember as default search", 117, (5, 81, 150, 10), visible | win32con.BS_AUTOCHECKBOX | win32con.WS_TABSTOP],
|
||||
["Button", "&Find Next", 109, (185, 5, 50, 14), visible | win32con.BS_DEFPUSHBUTTON | win32con.WS_TABSTOP],
|
||||
["Button", "&Replace", 110, (185, 23, 50, 14), visible | win32con.WS_TABSTOP],
|
||||
["Button", "Replace &All", 111, (185, 41, 50, 14), visible | win32con.WS_TABSTOP],
|
||||
["Button", "Cancel", win32con.IDCANCEL, (185, 59, 50, 14), visible | win32con.WS_TABSTOP],
|
||||
|
||||
|
||||
]
|
||||
return dt
|
||||
|
||||
def OnInitDialog(self):
|
||||
rc = FindReplaceDialog.OnInitDialog(self)
|
||||
self.HookCommand(self.OnReplace, 110)
|
||||
self.HookCommand(self.OnReplaceAll, 111)
|
||||
self.HookMessage(self.OnActivate, win32con.WM_ACTIVATE)
|
||||
self.editReplaceText = self.GetDlgItem(104)
|
||||
self.editReplaceText.SetWindowText(lastSearch.replaceText)
|
||||
if hasattr(self.editReplaceText, 'SetEditSel'):
|
||||
self.editReplaceText.SetEditSel(0, -2)
|
||||
else:
|
||||
self.editReplaceText.SetSel(0, -2)
|
||||
self.butReplace = self.GetDlgItem(110)
|
||||
self.butReplaceAll = self.GetDlgItem(111)
|
||||
self.CheckButtonStates()
|
||||
return rc
|
||||
|
||||
def CheckButtonStates(self):
|
||||
# We can do a "Replace" or "Replace All" if the current selection
|
||||
# is the same as the search text.
|
||||
ft = self.editFindText.GetWindowText()
|
||||
control = _GetControl()
|
||||
# bCanReplace = len(ft)>0 and control.GetSelText() == ft
|
||||
bCanReplace = control is not None and lastSearch.sel == control.GetSel()
|
||||
self.butReplace.EnableWindow(bCanReplace)
|
||||
# self.butReplaceAll.EnableWindow(bCanReplace)
|
||||
|
||||
def OnActivate(self, msg):
|
||||
wparam = msg[2]
|
||||
fActive = win32api.LOWORD(wparam)
|
||||
if fActive != win32con.WA_INACTIVE:
|
||||
self.CheckButtonStates()
|
||||
|
||||
def OnFindNext(self, id, code):
|
||||
self.DoFindNext()
|
||||
self.CheckButtonStates()
|
||||
|
||||
def OnReplace(self, id, code):
|
||||
lastSearch.replaceText = self.editReplaceText.GetWindowText()
|
||||
_ReplaceIt(None)
|
||||
|
||||
def OnReplaceAll(self, id, code):
|
||||
control = _GetControl(None)
|
||||
if control is not None:
|
||||
control.SetSel(0)
|
||||
num = 0
|
||||
if self.DoFindNext() == FOUND_NORMAL:
|
||||
num = 1
|
||||
lastSearch.replaceText = self.editReplaceText.GetWindowText()
|
||||
while _ReplaceIt(control) == FOUND_NORMAL:
|
||||
num = num + 1
|
||||
|
||||
win32ui.SetStatusText("Replaced %d occurrences" % num)
|
||||
if num > 0 and not self.butKeepDialogOpen.GetCheck():
|
||||
self.DestroyWindow()
|
||||
|
||||
if __name__=='__main__':
|
||||
ShowFindDialog()
|
||||
587
Lib/site-packages/pythonwin/pywin/scintilla/formatter.py
Normal file
587
Lib/site-packages/pythonwin/pywin/scintilla/formatter.py
Normal file
|
|
@ -0,0 +1,587 @@
|
|||
# Does Python source formatting for Scintilla controls.
|
||||
import win32ui
|
||||
import win32api
|
||||
import win32con
|
||||
import winerror
|
||||
import string
|
||||
import array
|
||||
from . import scintillacon
|
||||
|
||||
WM_KICKIDLE = 0x036A
|
||||
|
||||
# Used to indicate that style should use default color
|
||||
from win32con import CLR_INVALID
|
||||
|
||||
debugging = 0
|
||||
if debugging:
|
||||
# Output must go to another process else the result of
|
||||
# the printing itself will trigger again trigger a trace.
|
||||
import sys, win32traceutil, win32trace
|
||||
def trace(*args):
|
||||
win32trace.write(' '.join(map(str, args)) + "\n")
|
||||
else:
|
||||
trace = lambda *args: None
|
||||
|
||||
class Style:
|
||||
"""Represents a single format
|
||||
"""
|
||||
def __init__(self, name, format, background = CLR_INVALID):
|
||||
self.name = name # Name the format representes eg, "String", "Class"
|
||||
# Default background for each style is only used when there are no
|
||||
# saved settings (generally on first startup)
|
||||
self.background = self.default_background = background
|
||||
if type(format)==type(''):
|
||||
self.aliased = format
|
||||
self.format = None
|
||||
else:
|
||||
self.format = format
|
||||
self.aliased = None
|
||||
self.stylenum = None # Not yet registered.
|
||||
def IsBasedOnDefault(self):
|
||||
return len(self.format)==5
|
||||
# If the currently extended font defintion matches the
|
||||
# default format, restore the format to the "simple" format.
|
||||
def NormalizeAgainstDefault(self, defaultFormat):
|
||||
if self.IsBasedOnDefault():
|
||||
return 0 # No more to do, and not changed.
|
||||
bIsDefault = self.format[7] == defaultFormat[7] and \
|
||||
self.format[2] == defaultFormat[2]
|
||||
if bIsDefault:
|
||||
self.ForceAgainstDefault()
|
||||
return bIsDefault
|
||||
def ForceAgainstDefault(self):
|
||||
self.format = self.format[:5]
|
||||
def GetCompleteFormat(self, defaultFormat):
|
||||
# Get the complete style after applying any relevant defaults.
|
||||
if len(self.format)==5: # It is a default one
|
||||
fmt = self.format + defaultFormat[5:]
|
||||
else:
|
||||
fmt = self.format
|
||||
flags = win32con.CFM_BOLD | win32con.CFM_CHARSET | win32con.CFM_COLOR | win32con.CFM_FACE | win32con.CFM_ITALIC | win32con.CFM_SIZE
|
||||
return (flags,) + fmt[1:]
|
||||
|
||||
# The Formatter interface
|
||||
# used primarily when the actual formatting is done by Scintilla!
|
||||
class FormatterBase:
|
||||
def __init__(self, scintilla):
|
||||
self.scintilla = scintilla
|
||||
self.baseFormatFixed = (-402653169, 0, 200, 0, 0, 0, 49, 'Courier New')
|
||||
self.baseFormatProp = (-402653169, 0, 200, 0, 0, 0, 49, 'Arial')
|
||||
self.bUseFixed = 1
|
||||
self.styles = {} # Indexed by name
|
||||
self.styles_by_id = {} # Indexed by allocated ID.
|
||||
self.SetStyles()
|
||||
|
||||
def HookFormatter(self, parent = None):
|
||||
raise NotImplementedError()
|
||||
|
||||
# Used by the IDLE extensions to quickly determine if a character is a string.
|
||||
def GetStringStyle(self, pos):
|
||||
try:
|
||||
style = self.styles_by_id[self.scintilla.SCIGetStyleAt(pos)]
|
||||
except KeyError:
|
||||
# A style we dont know about - probably not even a .py file - can't be a string
|
||||
return None
|
||||
if style.name in self.string_style_names:
|
||||
return style
|
||||
return None
|
||||
|
||||
def RegisterStyle(self, style, stylenum):
|
||||
assert stylenum is not None, "We must have a style number"
|
||||
assert style.stylenum is None, "Style has already been registered"
|
||||
assert stylenum not in self.styles, "We are reusing a style number!"
|
||||
style.stylenum = stylenum
|
||||
self.styles[style.name] = style
|
||||
self.styles_by_id[stylenum] = style
|
||||
|
||||
def SetStyles(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
def GetSampleText(self):
|
||||
return "Sample Text for the Format Dialog"
|
||||
|
||||
def GetDefaultFormat(self):
|
||||
if self.bUseFixed:
|
||||
return self.baseFormatFixed
|
||||
return self.baseFormatProp
|
||||
|
||||
# Update the control with the new style format.
|
||||
def _ReformatStyle(self, style):
|
||||
## Selection (background only for now)
|
||||
## Passing False for WPARAM to SCI_SETSELBACK is documented as resetting to scintilla default,
|
||||
## but does not work - selection background is not visible at all.
|
||||
## Default value in SPECIAL_STYLES taken from scintilla source.
|
||||
if style.name == STYLE_SELECTION:
|
||||
clr = style.background
|
||||
self.scintilla.SendScintilla(scintillacon.SCI_SETSELBACK, True, clr)
|
||||
|
||||
## Can't change font for selection, but could set color
|
||||
## However, the font color dropbox has no option for default, and thus would
|
||||
## always override syntax coloring
|
||||
## clr = style.format[4]
|
||||
## self.scintilla.SendScintilla(scintillacon.SCI_SETSELFORE, clr != CLR_INVALID, clr)
|
||||
return
|
||||
|
||||
assert style.stylenum is not None, "Unregistered style."
|
||||
#print "Reformat style", style.name, style.stylenum
|
||||
scintilla=self.scintilla
|
||||
stylenum = style.stylenum
|
||||
# Now we have the style number, indirect for the actual style.
|
||||
if style.aliased is not None:
|
||||
style = self.styles[style.aliased]
|
||||
f=style.format
|
||||
if style.IsBasedOnDefault():
|
||||
baseFormat = self.GetDefaultFormat()
|
||||
else: baseFormat = f
|
||||
scintilla.SCIStyleSetFore(stylenum, f[4])
|
||||
scintilla.SCIStyleSetFont(stylenum, baseFormat[7], baseFormat[5])
|
||||
if f[1] & 1: scintilla.SCIStyleSetBold(stylenum, 1)
|
||||
else: scintilla.SCIStyleSetBold(stylenum, 0)
|
||||
if f[1] & 2: scintilla.SCIStyleSetItalic(stylenum, 1)
|
||||
else: scintilla.SCIStyleSetItalic(stylenum, 0)
|
||||
scintilla.SCIStyleSetSize(stylenum, int(baseFormat[2]/20))
|
||||
scintilla.SCIStyleSetEOLFilled(stylenum, 1) # Only needed for unclosed strings.
|
||||
|
||||
## Default style background to whitespace background if set,
|
||||
## otherwise use system window color
|
||||
bg = style.background
|
||||
if bg == CLR_INVALID:
|
||||
bg = self.styles[STYLE_DEFAULT].background
|
||||
if bg == CLR_INVALID:
|
||||
bg = win32api.GetSysColor(win32con.COLOR_WINDOW)
|
||||
scintilla.SCIStyleSetBack(stylenum, bg)
|
||||
|
||||
|
||||
|
||||
def GetStyleByNum(self, stylenum):
|
||||
return self.styles_by_id[stylenum]
|
||||
|
||||
def ApplyFormattingStyles(self, bReload=1):
|
||||
if bReload:
|
||||
self.LoadPreferences()
|
||||
baseFormat = self.GetDefaultFormat()
|
||||
defaultStyle = Style("default", baseFormat)
|
||||
defaultStyle.stylenum = scintillacon.STYLE_DEFAULT
|
||||
self._ReformatStyle(defaultStyle)
|
||||
for style in list(self.styles.values()):
|
||||
if style.aliased is None:
|
||||
style.NormalizeAgainstDefault(baseFormat)
|
||||
self._ReformatStyle(style)
|
||||
self.scintilla.InvalidateRect()
|
||||
|
||||
# Some functions for loading and saving preferences. By default
|
||||
# an INI file (well, MFC maps this to the registry) is used.
|
||||
def LoadPreferences(self):
|
||||
self.baseFormatFixed = eval(self.LoadPreference("Base Format Fixed", str(self.baseFormatFixed)))
|
||||
self.baseFormatProp = eval(self.LoadPreference("Base Format Proportional", str(self.baseFormatProp)))
|
||||
self.bUseFixed = int(self.LoadPreference("Use Fixed", 1))
|
||||
|
||||
for style in list(self.styles.values()):
|
||||
new = self.LoadPreference(style.name, str(style.format))
|
||||
try:
|
||||
style.format = eval(new)
|
||||
except:
|
||||
print("Error loading style data for", style.name)
|
||||
# Use "vanilla" background hardcoded in PYTHON_STYLES if no settings in registry
|
||||
style.background = int(self.LoadPreference(style.name + " background", style.default_background))
|
||||
|
||||
def LoadPreference(self, name, default):
|
||||
return win32ui.GetProfileVal("Format", name, default)
|
||||
|
||||
def SavePreferences(self):
|
||||
self.SavePreference("Base Format Fixed", str(self.baseFormatFixed))
|
||||
self.SavePreference("Base Format Proportional", str(self.baseFormatProp))
|
||||
self.SavePreference("Use Fixed", self.bUseFixed)
|
||||
for style in list(self.styles.values()):
|
||||
if style.aliased is None:
|
||||
self.SavePreference(style.name, str(style.format))
|
||||
bg_name = style.name + " background"
|
||||
self.SavePreference(bg_name, style.background)
|
||||
|
||||
def SavePreference(self, name, value):
|
||||
win32ui.WriteProfileVal("Format", name, value)
|
||||
|
||||
# An abstract formatter
|
||||
# For all formatters we actually implement here.
|
||||
# (as opposed to those formatters built in to Scintilla)
|
||||
class Formatter(FormatterBase):
|
||||
def __init__(self, scintilla):
|
||||
self.bCompleteWhileIdle = 0
|
||||
self.bHaveIdleHandler = 0 # Dont currently have an idle handle
|
||||
self.nextstylenum = 0
|
||||
FormatterBase.__init__(self, scintilla)
|
||||
|
||||
def HookFormatter(self, parent = None):
|
||||
if parent is None: parent = self.scintilla.GetParent() # was GetParentFrame()!?
|
||||
parent.HookNotify(self.OnStyleNeeded, scintillacon.SCN_STYLENEEDED)
|
||||
|
||||
def OnStyleNeeded(self, std, extra):
|
||||
notify = self.scintilla.SCIUnpackNotifyMessage(extra)
|
||||
endStyledChar = self.scintilla.SendScintilla(scintillacon.SCI_GETENDSTYLED)
|
||||
lineEndStyled = self.scintilla.LineFromChar(endStyledChar)
|
||||
endStyled = self.scintilla.LineIndex(lineEndStyled)
|
||||
#print "enPosPaint %d endStyledChar %d lineEndStyled %d endStyled %d" % (endPosPaint, endStyledChar, lineEndStyled, endStyled)
|
||||
self.Colorize(endStyled, notify.position)
|
||||
|
||||
def ColorSeg(self, start, end, styleName):
|
||||
end = end+1
|
||||
# assert end-start>=0, "Can't have negative styling"
|
||||
stylenum = self.styles[styleName].stylenum
|
||||
while start<end:
|
||||
self.style_buffer[start]=stylenum
|
||||
start = start+1
|
||||
#self.scintilla.SCISetStyling(end - start + 1, stylenum)
|
||||
|
||||
def RegisterStyle(self, style, stylenum = None):
|
||||
if stylenum is None:
|
||||
stylenum = self.nextstylenum
|
||||
self.nextstylenum = self.nextstylenum + 1
|
||||
FormatterBase.RegisterStyle(self, style, stylenum)
|
||||
|
||||
def ColorizeString(self, str, charStart, styleStart):
|
||||
raise RuntimeError("You must override this method")
|
||||
|
||||
def Colorize(self, start=0, end=-1):
|
||||
scintilla = self.scintilla
|
||||
# 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 = scintilla.GetTextRange(start, end, decode=False)
|
||||
if start > 0:
|
||||
stylenum = scintilla.SCIGetStyleAt(start - 1)
|
||||
styleStart = self.GetStyleByNum(stylenum).name
|
||||
else:
|
||||
styleStart = None
|
||||
# trace("Coloring", start, end, end-start, len(stringVal), styleStart, self.scintilla.SCIGetCharAt(start))
|
||||
scintilla.SCIStartStyling(start, 31)
|
||||
self.style_buffer = array.array("b", (0,)*len(stringVal))
|
||||
self.ColorizeString(stringVal, styleStart)
|
||||
scintilla.SCISetStylingEx(self.style_buffer)
|
||||
self.style_buffer = None
|
||||
# trace("After styling, end styled is", self.scintilla.SCIGetEndStyled())
|
||||
if self.bCompleteWhileIdle and not self.bHaveIdleHandler and end!=-1 and end < scintilla.GetTextLength():
|
||||
self.bHaveIdleHandler = 1
|
||||
win32ui.GetApp().AddIdleHandler(self.DoMoreColoring)
|
||||
# Kicking idle makes the app seem slower when initially repainting!
|
||||
# win32ui.GetMainFrame().PostMessage(WM_KICKIDLE, 0, 0)
|
||||
|
||||
def DoMoreColoring(self, handler, count):
|
||||
try:
|
||||
scintilla = self.scintilla
|
||||
endStyled = scintilla.SCIGetEndStyled()
|
||||
lineStartStyled = scintilla.LineFromChar(endStyled)
|
||||
start = scintilla.LineIndex(lineStartStyled)
|
||||
end = scintilla.LineIndex(lineStartStyled+1)
|
||||
textlen = scintilla.GetTextLength()
|
||||
if end < 0: end = textlen
|
||||
|
||||
finished = end >= textlen
|
||||
self.Colorize(start, end)
|
||||
except (win32ui.error, AttributeError):
|
||||
# Window may have closed before we finished - no big deal!
|
||||
finished = 1
|
||||
|
||||
if finished:
|
||||
self.bHaveIdleHandler = 0
|
||||
win32ui.GetApp().DeleteIdleHandler(handler)
|
||||
return not finished
|
||||
|
||||
# A Formatter that knows how to format Python source
|
||||
from keyword import iskeyword, kwlist
|
||||
|
||||
wordstarts = '_0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
|
||||
wordchars = '._0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
|
||||
operators = '%^&*()-+=|{}[]:;<>,/?!.~'
|
||||
|
||||
STYLE_DEFAULT = "Whitespace"
|
||||
STYLE_COMMENT = "Comment"
|
||||
STYLE_COMMENT_BLOCK = "Comment Blocks"
|
||||
STYLE_NUMBER = "Number"
|
||||
STYLE_STRING = "String"
|
||||
STYLE_SQSTRING = "SQ String"
|
||||
STYLE_TQSSTRING = "TQS String"
|
||||
STYLE_TQDSTRING = "TQD String"
|
||||
STYLE_KEYWORD = "Keyword"
|
||||
STYLE_CLASS = "Class"
|
||||
STYLE_METHOD = "Method"
|
||||
STYLE_OPERATOR = "Operator"
|
||||
STYLE_IDENTIFIER = "Identifier"
|
||||
STYLE_BRACE = "Brace/Paren - matching"
|
||||
STYLE_BRACEBAD = "Brace/Paren - unmatched"
|
||||
STYLE_STRINGEOL = "String with no terminator"
|
||||
STYLE_LINENUMBER = "Line numbers"
|
||||
STYLE_INDENTGUIDE = "Indent guide"
|
||||
STYLE_SELECTION = "Selection"
|
||||
|
||||
STRING_STYLES = [STYLE_STRING, STYLE_SQSTRING, STYLE_TQSSTRING, STYLE_TQDSTRING, STYLE_STRINGEOL]
|
||||
|
||||
# These styles can have any ID - they are not special to scintilla itself.
|
||||
# However, if we use the built-in lexer, then we must use its style numbers
|
||||
# so in that case, they _are_ special.
|
||||
# (name, format, background, scintilla id)
|
||||
PYTHON_STYLES = [
|
||||
(STYLE_DEFAULT, (0, 0, 200, 0, 0x808080), CLR_INVALID, scintillacon.SCE_P_DEFAULT ),
|
||||
(STYLE_COMMENT, (0, 2, 200, 0, 0x008000), CLR_INVALID, scintillacon.SCE_P_COMMENTLINE ),
|
||||
(STYLE_COMMENT_BLOCK,(0, 2, 200, 0, 0x808080), CLR_INVALID, scintillacon.SCE_P_COMMENTBLOCK ),
|
||||
(STYLE_NUMBER, (0, 0, 200, 0, 0x808000), CLR_INVALID, scintillacon.SCE_P_NUMBER ),
|
||||
(STYLE_STRING, (0, 0, 200, 0, 0x008080), CLR_INVALID, scintillacon.SCE_P_STRING ),
|
||||
(STYLE_SQSTRING, STYLE_STRING, CLR_INVALID, scintillacon.SCE_P_CHARACTER ),
|
||||
(STYLE_TQSSTRING, STYLE_STRING, CLR_INVALID, scintillacon.SCE_P_TRIPLE ),
|
||||
(STYLE_TQDSTRING, STYLE_STRING, CLR_INVALID, scintillacon.SCE_P_TRIPLEDOUBLE),
|
||||
(STYLE_STRINGEOL, (0, 0, 200, 0, 0x000000), 0x008080, scintillacon.SCE_P_STRINGEOL),
|
||||
(STYLE_KEYWORD, (0, 1, 200, 0, 0x800000), CLR_INVALID, scintillacon.SCE_P_WORD),
|
||||
(STYLE_CLASS, (0, 1, 200, 0, 0xFF0000), CLR_INVALID, scintillacon.SCE_P_CLASSNAME ),
|
||||
(STYLE_METHOD, (0, 1, 200, 0, 0x808000), CLR_INVALID, scintillacon.SCE_P_DEFNAME),
|
||||
(STYLE_OPERATOR, (0, 0, 200, 0, 0x000000), CLR_INVALID, scintillacon.SCE_P_OPERATOR),
|
||||
(STYLE_IDENTIFIER, (0, 0, 200, 0, 0x000000), CLR_INVALID, scintillacon.SCE_P_IDENTIFIER ),
|
||||
]
|
||||
|
||||
# These styles _always_ have this specific style number, regardless of
|
||||
# internal or external formatter.
|
||||
SPECIAL_STYLES = [
|
||||
(STYLE_BRACE, (0, 0, 200, 0, 0x000000), 0xffff80, scintillacon.STYLE_BRACELIGHT),
|
||||
(STYLE_BRACEBAD, (0, 0, 200, 0, 0x000000), 0x8ea5f2, scintillacon.STYLE_BRACEBAD),
|
||||
(STYLE_LINENUMBER, (0, 0, 200, 0, 0x000000), win32api.GetSysColor(win32con.COLOR_3DFACE), scintillacon.STYLE_LINENUMBER),
|
||||
(STYLE_INDENTGUIDE, (0, 0, 200, 0, 0x000000), CLR_INVALID, scintillacon.STYLE_INDENTGUIDE),
|
||||
## Not actually a style; requires special handling to send appropriate messages to scintilla
|
||||
(STYLE_SELECTION, (0, 0, 200, 0, CLR_INVALID), win32api.RGB(0xc0, 0xc0, 0xc0), 999999),
|
||||
]
|
||||
|
||||
PythonSampleCode = """\
|
||||
# Some Python
|
||||
class Sample(Super):
|
||||
def Fn(self):
|
||||
\tself.v = 1024
|
||||
dest = 'dest.html'
|
||||
x = func(a + 1)|)
|
||||
s = "I forget...
|
||||
## A large
|
||||
## comment block"""
|
||||
|
||||
class PythonSourceFormatter(Formatter):
|
||||
string_style_names = STRING_STYLES
|
||||
def GetSampleText(self):
|
||||
return PythonSampleCode
|
||||
|
||||
def LoadStyles(self):
|
||||
pass
|
||||
|
||||
def SetStyles(self):
|
||||
for name, format, bg, ignore in PYTHON_STYLES:
|
||||
self.RegisterStyle( Style(name, format, bg) )
|
||||
for name, format, bg, sc_id in SPECIAL_STYLES:
|
||||
self.RegisterStyle( Style(name, format, bg), sc_id )
|
||||
|
||||
def ClassifyWord(self, cdoc, start, end, prevWord):
|
||||
word = cdoc[start:end+1].decode('latin-1')
|
||||
attr = STYLE_IDENTIFIER
|
||||
if prevWord == "class":
|
||||
attr = STYLE_CLASS
|
||||
elif prevWord == "def":
|
||||
attr = STYLE_METHOD
|
||||
elif word[0] in string.digits:
|
||||
attr = STYLE_NUMBER
|
||||
elif iskeyword(word):
|
||||
attr = STYLE_KEYWORD
|
||||
self.ColorSeg(start, end, attr)
|
||||
return word
|
||||
|
||||
def ColorizeString(self, str, styleStart):
|
||||
if styleStart is None: styleStart = STYLE_DEFAULT
|
||||
return self.ColorizePythonCode(str, 0, styleStart)
|
||||
|
||||
def ColorizePythonCode(self, cdoc, charStart, styleStart):
|
||||
# Straight translation of C++, should do better
|
||||
lengthDoc = len(cdoc)
|
||||
if lengthDoc <= charStart: return
|
||||
prevWord = ""
|
||||
state = styleStart
|
||||
chPrev = chPrev2 = chPrev3 = ' '
|
||||
chNext2 = chNext = cdoc[charStart:charStart+1].decode('latin-1')
|
||||
startSeg = i = charStart
|
||||
while i < lengthDoc:
|
||||
ch = chNext
|
||||
chNext = ' '
|
||||
if i+1 < lengthDoc: chNext = cdoc[i+1:i+2].decode('latin-1')
|
||||
chNext2 = ' '
|
||||
if i+2 < lengthDoc: chNext2 = cdoc[i+2:i+3].decode('latin-1')
|
||||
if state == STYLE_DEFAULT:
|
||||
if ch in wordstarts:
|
||||
self.ColorSeg(startSeg, i - 1, STYLE_DEFAULT)
|
||||
state = STYLE_KEYWORD
|
||||
startSeg = i
|
||||
elif ch == '#':
|
||||
self.ColorSeg(startSeg, i - 1, STYLE_DEFAULT)
|
||||
if chNext == '#':
|
||||
state = STYLE_COMMENT_BLOCK
|
||||
else:
|
||||
state = STYLE_COMMENT
|
||||
startSeg = i
|
||||
elif ch == '\"':
|
||||
self.ColorSeg(startSeg, i - 1, STYLE_DEFAULT)
|
||||
startSeg = i
|
||||
state = STYLE_COMMENT
|
||||
if chNext == '\"' and chNext2 == '\"':
|
||||
i = i + 2
|
||||
state = STYLE_TQDSTRING
|
||||
ch = ' '
|
||||
chPrev = ' '
|
||||
chNext = ' '
|
||||
if i+1 < lengthDoc: chNext = cdoc[i+1]
|
||||
else:
|
||||
state = STYLE_STRING
|
||||
elif ch == '\'':
|
||||
self.ColorSeg(startSeg, i - 1, STYLE_DEFAULT)
|
||||
startSeg = i
|
||||
state = STYLE_COMMENT
|
||||
if chNext == '\'' and chNext2 == '\'':
|
||||
i = i + 2
|
||||
state = STYLE_TQSSTRING
|
||||
ch = ' '
|
||||
chPrev = ' '
|
||||
chNext = ' '
|
||||
if i+1 < lengthDoc: chNext = cdoc[i+1]
|
||||
else:
|
||||
state = STYLE_SQSTRING
|
||||
elif ch in operators:
|
||||
self.ColorSeg(startSeg, i - 1, STYLE_DEFAULT)
|
||||
self.ColorSeg(i, i, STYLE_OPERATOR)
|
||||
startSeg = i+1
|
||||
elif state == STYLE_KEYWORD:
|
||||
if ch not in wordchars:
|
||||
prevWord = self.ClassifyWord(cdoc, startSeg, i-1, prevWord)
|
||||
state = STYLE_DEFAULT
|
||||
startSeg = i
|
||||
if ch == '#':
|
||||
if chNext == '#':
|
||||
state = STYLE_COMMENT_BLOCK
|
||||
else:
|
||||
state = STYLE_COMMENT
|
||||
elif ch == '\"':
|
||||
if chNext == '\"' and chNext2 == '\"':
|
||||
i = i + 2
|
||||
state = STYLE_TQDSTRING
|
||||
ch = ' '
|
||||
chPrev = ' '
|
||||
chNext = ' '
|
||||
if i+1 < lengthDoc: chNext = cdoc[i+1]
|
||||
else:
|
||||
state = STYLE_STRING
|
||||
elif ch == '\'':
|
||||
if chNext == '\'' and chNext2 == '\'':
|
||||
i = i + 2
|
||||
state = STYLE_TQSSTRING
|
||||
ch = ' '
|
||||
chPrev = ' '
|
||||
chNext = ' '
|
||||
if i+1 < lengthDoc: chNext = cdoc[i+1]
|
||||
else:
|
||||
state = STYLE_SQSTRING
|
||||
elif ch in operators:
|
||||
self.ColorSeg(startSeg, i, STYLE_OPERATOR)
|
||||
startSeg = i+1
|
||||
elif state == STYLE_COMMENT or state == STYLE_COMMENT_BLOCK:
|
||||
if ch == '\r' or ch == '\n':
|
||||
self.ColorSeg(startSeg, i-1, state)
|
||||
state = STYLE_DEFAULT
|
||||
startSeg = i
|
||||
elif state == STYLE_STRING:
|
||||
if ch == '\\':
|
||||
if chNext == '\"' or chNext == '\'' or chNext == '\\':
|
||||
i = i + 1
|
||||
ch = chNext
|
||||
chNext = ' '
|
||||
if i+1 < lengthDoc: chNext = cdoc[i+1]
|
||||
elif ch == '\"':
|
||||
self.ColorSeg(startSeg, i, STYLE_STRING)
|
||||
state = STYLE_DEFAULT
|
||||
startSeg = i+1
|
||||
elif state == STYLE_SQSTRING:
|
||||
if ch == '\\':
|
||||
if chNext == '\"' or chNext == '\'' or chNext == '\\':
|
||||
i = i+1
|
||||
ch = chNext
|
||||
chNext = ' '
|
||||
if i+1 < lengthDoc: chNext = cdoc[i+1]
|
||||
elif ch == '\'':
|
||||
self.ColorSeg(startSeg, i, STYLE_SQSTRING)
|
||||
state = STYLE_DEFAULT
|
||||
startSeg = i+1
|
||||
elif state == STYLE_TQSSTRING:
|
||||
if ch == '\'' and chPrev == '\'' and chPrev2 == '\'' and chPrev3 != '\\':
|
||||
self.ColorSeg(startSeg, i, STYLE_TQSSTRING)
|
||||
state = STYLE_DEFAULT
|
||||
startSeg = i+1
|
||||
elif state == STYLE_TQDSTRING and ch == '\"' and chPrev == '\"' and chPrev2 == '\"' and chPrev3 != '\\':
|
||||
self.ColorSeg(startSeg, i, STYLE_TQDSTRING)
|
||||
state = STYLE_DEFAULT
|
||||
startSeg = i+1
|
||||
chPrev3 = chPrev2
|
||||
chPrev2 = chPrev
|
||||
chPrev = ch
|
||||
i = i + 1
|
||||
if startSeg < lengthDoc:
|
||||
if state == STYLE_KEYWORD:
|
||||
self.ClassifyWord(cdoc, startSeg, lengthDoc-1, prevWord)
|
||||
else:
|
||||
self.ColorSeg(startSeg, lengthDoc-1, state)
|
||||
|
||||
|
||||
# These taken from the SciTE properties file.
|
||||
source_formatter_extensions = [
|
||||
( ".py .pys .pyw".split(), scintillacon.SCLEX_PYTHON ),
|
||||
( ".html .htm .asp .shtml".split(), scintillacon.SCLEX_HTML ),
|
||||
( "c .cc .cpp .cxx .h .hh .hpp .hxx .idl .odl .php3 .phtml .inc .js".split(), scintillacon.SCLEX_CPP ),
|
||||
( ".vbs .frm .ctl .cls".split(), scintillacon.SCLEX_VB ),
|
||||
( ".pl .pm .cgi .pod".split(), scintillacon.SCLEX_PERL ),
|
||||
( ".sql .spec .body .sps .spb .sf .sp".split(), scintillacon.SCLEX_SQL ),
|
||||
( ".tex .sty".split(), scintillacon.SCLEX_LATEX ),
|
||||
( ".xml .xul".split(), scintillacon.SCLEX_XML ),
|
||||
( ".err".split(), scintillacon.SCLEX_ERRORLIST ),
|
||||
( ".mak".split(), scintillacon.SCLEX_MAKEFILE ),
|
||||
( ".bat .cmd".split(), scintillacon.SCLEX_BATCH ),
|
||||
]
|
||||
|
||||
class BuiltinSourceFormatter(FormatterBase):
|
||||
# A class that represents a formatter built-in to Scintilla
|
||||
def __init__(self, scintilla, ext):
|
||||
self.ext = ext
|
||||
FormatterBase.__init__(self, scintilla)
|
||||
|
||||
def Colorize(self, start=0, end=-1):
|
||||
self.scintilla.SendScintilla(scintillacon.SCI_COLOURISE, start, end)
|
||||
def RegisterStyle(self, style, stylenum = None):
|
||||
assert style.stylenum is None, "Style has already been registered"
|
||||
if stylenum is None:
|
||||
stylenum = self.nextstylenum
|
||||
self.nextstylenum = self.nextstylenum + 1
|
||||
assert self.styles.get(stylenum) is None, "We are reusing a style number!"
|
||||
style.stylenum = stylenum
|
||||
self.styles[style.name] = style
|
||||
self.styles_by_id[stylenum] = style
|
||||
|
||||
def HookFormatter(self, parent = None):
|
||||
sc = self.scintilla
|
||||
for exts, formatter in source_formatter_extensions:
|
||||
if self.ext in exts:
|
||||
formatter_use = formatter
|
||||
break
|
||||
else:
|
||||
formatter_use = scintillacon.SCLEX_PYTHON
|
||||
sc.SendScintilla(scintillacon.SCI_SETLEXER, formatter_use)
|
||||
keywords = ' '.join(kwlist)
|
||||
sc.SCISetKeywords(keywords)
|
||||
|
||||
class BuiltinPythonSourceFormatter(BuiltinSourceFormatter):
|
||||
sci_lexer_name = scintillacon.SCLEX_PYTHON
|
||||
string_style_names = STRING_STYLES
|
||||
def __init__(self, sc, ext = ".py"):
|
||||
BuiltinSourceFormatter.__init__(self, sc, ext)
|
||||
def SetStyles(self):
|
||||
for name, format, bg, sc_id in PYTHON_STYLES:
|
||||
self.RegisterStyle( Style(name, format, bg), sc_id )
|
||||
for name, format, bg, sc_id in SPECIAL_STYLES:
|
||||
self.RegisterStyle( Style(name, format, bg), sc_id )
|
||||
def GetSampleText(self):
|
||||
return PythonSampleCode
|
||||
177
Lib/site-packages/pythonwin/pywin/scintilla/keycodes.py
Normal file
177
Lib/site-packages/pythonwin/pywin/scintilla/keycodes.py
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
import string
|
||||
import win32con
|
||||
import win32api
|
||||
import win32ui
|
||||
|
||||
MAPVK_VK_TO_CHAR = 2
|
||||
|
||||
key_name_to_vk = {}
|
||||
key_code_to_name = {}
|
||||
|
||||
_better_names = {
|
||||
"escape": "esc",
|
||||
"return": "enter",
|
||||
"back": "pgup",
|
||||
"next": "pgdn",
|
||||
}
|
||||
|
||||
def _fillvkmap():
|
||||
# Pull the VK_names from win32con
|
||||
names = [entry for entry in win32con.__dict__ if entry.startswith("VK_")]
|
||||
for name in names:
|
||||
code = getattr(win32con, name)
|
||||
n = name[3:].lower()
|
||||
key_name_to_vk[n] = code
|
||||
if n in _better_names:
|
||||
n = _better_names[n]
|
||||
key_name_to_vk[n] = code
|
||||
key_code_to_name[code] = n
|
||||
|
||||
|
||||
_fillvkmap()
|
||||
|
||||
def get_vk(chardesc):
|
||||
if len(chardesc)==1:
|
||||
# it is a character.
|
||||
info = win32api.VkKeyScan(chardesc)
|
||||
if info==-1:
|
||||
return None, None
|
||||
vk = win32api.LOBYTE(info)
|
||||
state = win32api.HIBYTE(info)
|
||||
modifiers = 0
|
||||
if state & 0x1:
|
||||
modifiers |= win32con.SHIFT_PRESSED
|
||||
if state & 0x2:
|
||||
modifiers |= win32con.LEFT_CTRL_PRESSED | win32con.RIGHT_CTRL_PRESSED
|
||||
if state & 0x4:
|
||||
modifiers |= win32con.LEFT_ALT_PRESSED | win32con.RIGHT_ALT_PRESSED
|
||||
return vk, modifiers
|
||||
# must be a 'key name'
|
||||
return key_name_to_vk.get(chardesc.lower()), 0
|
||||
|
||||
modifiers = {
|
||||
"alt" : win32con.LEFT_ALT_PRESSED | win32con.RIGHT_ALT_PRESSED,
|
||||
"lalt" : win32con.LEFT_ALT_PRESSED,
|
||||
"ralt" : win32con.RIGHT_ALT_PRESSED,
|
||||
"ctrl" : win32con.LEFT_CTRL_PRESSED | win32con.RIGHT_CTRL_PRESSED,
|
||||
"ctl" : win32con.LEFT_CTRL_PRESSED | win32con.RIGHT_CTRL_PRESSED,
|
||||
"control" : win32con.LEFT_CTRL_PRESSED | win32con.RIGHT_CTRL_PRESSED,
|
||||
"lctrl" : win32con.LEFT_CTRL_PRESSED,
|
||||
"lctl" : win32con.LEFT_CTRL_PRESSED,
|
||||
"rctrl" : win32con.RIGHT_CTRL_PRESSED,
|
||||
"rctl" : win32con.RIGHT_CTRL_PRESSED,
|
||||
"shift" : win32con.SHIFT_PRESSED,
|
||||
"key" : 0, # ignore key tag.
|
||||
}
|
||||
|
||||
def parse_key_name(name):
|
||||
name = name + "-" # Add a sentinal
|
||||
start = pos = 0
|
||||
max = len(name)
|
||||
toks = []
|
||||
while pos<max:
|
||||
if name[pos] in "+-":
|
||||
tok = name[start:pos]
|
||||
# use the ascii lower() version of tok, so ascii chars require
|
||||
# an explicit shift modifier - ie 'Ctrl+G' should be treated as
|
||||
# 'ctrl+g' - 'ctrl+shift+g' would be needed if desired.
|
||||
# This is mainly to avoid changing all the old keystroke defs
|
||||
toks.append(tok.lower())
|
||||
pos += 1 # skip the sep
|
||||
start = pos
|
||||
pos += 1
|
||||
flags = 0
|
||||
# do the modifiers
|
||||
for tok in toks[:-1]:
|
||||
mod = modifiers.get(tok.lower())
|
||||
if mod is not None:
|
||||
flags |= mod
|
||||
# the key name
|
||||
vk, this_flags = get_vk(toks[-1])
|
||||
return vk, flags | this_flags
|
||||
|
||||
_checks = [
|
||||
[ # Shift
|
||||
("Shift", win32con.SHIFT_PRESSED),
|
||||
],
|
||||
[ # Ctrl key
|
||||
("Ctrl", win32con.LEFT_CTRL_PRESSED | win32con.RIGHT_CTRL_PRESSED),
|
||||
("LCtrl", win32con.LEFT_CTRL_PRESSED),
|
||||
("RCtrl", win32con.RIGHT_CTRL_PRESSED),
|
||||
],
|
||||
[ # Alt key
|
||||
("Alt", win32con.LEFT_ALT_PRESSED | win32con.RIGHT_ALT_PRESSED),
|
||||
("LAlt", win32con.LEFT_ALT_PRESSED),
|
||||
("RAlt", win32con.RIGHT_ALT_PRESSED),
|
||||
],
|
||||
]
|
||||
|
||||
def make_key_name(vk, flags):
|
||||
# Check alt keys.
|
||||
flags_done = 0
|
||||
parts = []
|
||||
for moddata in _checks:
|
||||
for name, checkflag in moddata:
|
||||
if flags & checkflag:
|
||||
parts.append(name)
|
||||
flags_done = flags_done & checkflag
|
||||
break
|
||||
if flags_done & flags:
|
||||
parts.append(hex( flags & ~flags_done ) )
|
||||
# Now the key name.
|
||||
if vk is None:
|
||||
parts.append("<Unknown scan code>")
|
||||
else:
|
||||
try:
|
||||
parts.append(key_code_to_name[vk])
|
||||
except KeyError:
|
||||
# Not in our virtual key map - ask Windows what character this
|
||||
# key corresponds to.
|
||||
scancode = win32api.MapVirtualKey(vk, MAPVK_VK_TO_CHAR)
|
||||
parts.append(chr(scancode))
|
||||
sep = "+"
|
||||
if sep in parts: sep = "-"
|
||||
return sep.join([p.capitalize() for p in parts])
|
||||
|
||||
def _psc(char):
|
||||
sc, mods = get_vk(char)
|
||||
print("Char %s -> %d -> %s" % (repr(char), sc, key_code_to_name.get(sc)))
|
||||
|
||||
def test1():
|
||||
for ch in """aA0/?[{}];:'"`~_-+=\\|,<.>/?""":
|
||||
_psc(ch)
|
||||
for code in ["Home", "End", "Left", "Right", "Up", "Down", "Menu", "Next"]:
|
||||
_psc(code)
|
||||
|
||||
def _pkn(n):
|
||||
vk, flags = parse_key_name(n)
|
||||
print("%s -> %s,%s -> %s" % (n, vk, flags, make_key_name(vk, flags)))
|
||||
|
||||
def test2():
|
||||
_pkn("ctrl+alt-shift+x")
|
||||
_pkn("ctrl-home")
|
||||
_pkn("Shift-+")
|
||||
_pkn("Shift--")
|
||||
_pkn("Shift+-")
|
||||
_pkn("Shift++")
|
||||
_pkn("LShift-+")
|
||||
_pkn("ctl+home")
|
||||
_pkn("ctl+enter")
|
||||
_pkn("alt+return")
|
||||
_pkn("Alt+/")
|
||||
_pkn("Alt+BadKeyName")
|
||||
_pkn("A") # an ascii char - should be seen as 'a'
|
||||
_pkn("a")
|
||||
_pkn("Shift-A")
|
||||
_pkn("Shift-a")
|
||||
_pkn("a")
|
||||
_pkn("(")
|
||||
_pkn("Ctrl+(")
|
||||
_pkn("Ctrl+Shift-8")
|
||||
_pkn("Ctrl+*")
|
||||
_pkn("{")
|
||||
_pkn("!")
|
||||
_pkn(".")
|
||||
|
||||
if __name__=='__main__':
|
||||
test2()
|
||||
1992
Lib/site-packages/pythonwin/pywin/scintilla/scintillacon.py
Normal file
1992
Lib/site-packages/pythonwin/pywin/scintilla/scintillacon.py
Normal file
File diff suppressed because it is too large
Load diff
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