Kano001's picture
Upload 498 files
d12bc25 verified
raw
history blame
30.9 kB
# A general purpose MFC CCtrlView view that uses Scintilla.
import array
import os
import re
import string
import struct
import sys
import __main__ # for attribute lookup
import afxres
import win32con
import win32ui
from pywin.mfc import dialog, docview
from . import IDLEenvironment # IDLE emulation.
from . import bindings, control, keycodes, scintillacon
PRINTDLGORD = 1538
IDC_PRINT_MAG_EDIT = 1010
EM_FORMATRANGE = win32con.WM_USER + 57
wordbreaks = "._" + string.ascii_uppercase + string.ascii_lowercase + string.digits
patImport = re.compile("import (?P<name>.*)")
_event_commands = [
# File menu
"win32ui.ID_FILE_LOCATE",
"win32ui.ID_FILE_CHECK",
"afxres.ID_FILE_CLOSE",
"afxres.ID_FILE_NEW",
"afxres.ID_FILE_OPEN",
"afxres.ID_FILE_SAVE",
"afxres.ID_FILE_SAVE_AS",
"win32ui.ID_FILE_SAVE_ALL",
# Edit menu
"afxres.ID_EDIT_UNDO",
"afxres.ID_EDIT_REDO",
"afxres.ID_EDIT_CUT",
"afxres.ID_EDIT_COPY",
"afxres.ID_EDIT_PASTE",
"afxres.ID_EDIT_SELECT_ALL",
"afxres.ID_EDIT_FIND",
"afxres.ID_EDIT_REPEAT",
"afxres.ID_EDIT_REPLACE",
# View menu
"win32ui.ID_VIEW_WHITESPACE",
"win32ui.ID_VIEW_FIXED_FONT",
"win32ui.ID_VIEW_BROWSE",
"win32ui.ID_VIEW_INTERACTIVE",
# Window menu
"afxres.ID_WINDOW_ARRANGE",
"afxres.ID_WINDOW_CASCADE",
"afxres.ID_WINDOW_NEW",
"afxres.ID_WINDOW_SPLIT",
"afxres.ID_WINDOW_TILE_HORZ",
"afxres.ID_WINDOW_TILE_VERT",
# Others
"afxres.ID_APP_EXIT",
"afxres.ID_APP_ABOUT",
]
_extra_event_commands = [
("EditDelete", afxres.ID_EDIT_CLEAR),
("LocateModule", win32ui.ID_FILE_LOCATE),
("GotoLine", win32ui.ID_EDIT_GOTO_LINE),
("DbgBreakpointToggle", win32ui.IDC_DBG_ADD),
("DbgGo", win32ui.IDC_DBG_GO),
("DbgStepOver", win32ui.IDC_DBG_STEPOVER),
("DbgStep", win32ui.IDC_DBG_STEP),
("DbgStepOut", win32ui.IDC_DBG_STEPOUT),
("DbgBreakpointClearAll", win32ui.IDC_DBG_CLEAR),
("DbgClose", win32ui.IDC_DBG_CLOSE),
]
event_commands = []
def _CreateEvents():
for name in _event_commands:
val = eval(name)
name_parts = name.split("_")[1:]
name_parts = [p.capitalize() for p in name_parts]
event = "".join(name_parts)
event_commands.append((event, val))
for name, id in _extra_event_commands:
event_commands.append((name, id))
_CreateEvents()
del _event_commands
del _extra_event_commands
command_reflectors = [
(win32ui.ID_EDIT_UNDO, win32con.WM_UNDO),
(win32ui.ID_EDIT_REDO, scintillacon.SCI_REDO),
(win32ui.ID_EDIT_CUT, win32con.WM_CUT),
(win32ui.ID_EDIT_COPY, win32con.WM_COPY),
(win32ui.ID_EDIT_PASTE, win32con.WM_PASTE),
(win32ui.ID_EDIT_CLEAR, win32con.WM_CLEAR),
(win32ui.ID_EDIT_SELECT_ALL, scintillacon.SCI_SELECTALL),
]
def DoBraceMatch(control):
curPos = control.SCIGetCurrentPos()
charBefore = " "
if curPos:
charBefore = control.SCIGetCharAt(curPos - 1)
charAt = control.SCIGetCharAt(curPos)
braceAtPos = braceOpposite = -1
if charBefore in "[](){}":
braceAtPos = curPos - 1
if braceAtPos == -1:
if charAt in "[](){}":
braceAtPos = curPos
if braceAtPos != -1:
braceOpposite = control.SCIBraceMatch(braceAtPos, 0)
if braceAtPos != -1 and braceOpposite == -1:
control.SCIBraceBadHighlight(braceAtPos)
else:
# either clear them both or set them both.
control.SCIBraceHighlight(braceAtPos, braceOpposite)
def _get_class_attributes(ob):
# Recurse into base classes looking for attributes
items = []
try:
items = items + dir(ob)
for i in ob.__bases__:
for item in _get_class_attributes(i):
if item not in items:
items.append(item)
except AttributeError:
pass
return items
# Supposed to look like an MFC CEditView, but
# also supports IDLE extensions and other source code generic features.
class CScintillaView(docview.CtrlView, control.CScintillaColorEditInterface):
def __init__(self, doc):
docview.CtrlView.__init__(
self,
doc,
"Scintilla",
win32con.WS_CHILD
| win32con.WS_VSCROLL
| win32con.WS_HSCROLL
| win32con.WS_CLIPCHILDREN
| win32con.WS_VISIBLE,
)
self._tabWidth = (
8 # Mirror of what we send to Scintilla - never change this directly
)
self.bAutoCompleteAttributes = 1
self.bShowCallTips = 1
self.bMatchBraces = 0 # Editor option will default this to true later!
self.bindings = bindings.BindingsManager(self)
self.idle = IDLEenvironment.IDLEEditorWindow(self)
self.idle.IDLEExtension("AutoExpand")
# SendScintilla is called so frequently it is worth optimizing.
self.SendScintilla = self._obj_.SendMessage
def _MakeColorizer(self):
ext = os.path.splitext(self.GetDocument().GetPathName())[1]
from . import formatter
return formatter.BuiltinPythonSourceFormatter(self, ext)
# def SendScintilla(self, msg, w=0, l=0):
# return self._obj_.SendMessage(msg, w, l)
def SCISetTabWidth(self, width):
# I need to remember the tab-width for the AutoIndent extension. This may go.
self._tabWidth = width
control.CScintillaEditInterface.SCISetTabWidth(self, width)
def GetTabWidth(self):
return self._tabWidth
def HookHandlers(self):
# Create events for all the menu names.
for name, val in event_commands:
# handler = lambda id, code, tosend=val, parent=parent: parent.OnCommand(tosend, 0) and 0
self.bindings.bind(name, None, cid=val)
# Hook commands that do nothing other than send Scintilla messages.
for command, reflection in command_reflectors:
handler = (
lambda id, code, ss=self.SendScintilla, tosend=reflection: ss(tosend)
and 0
)
self.HookCommand(handler, command)
self.HookCommand(self.OnCmdViewWS, win32ui.ID_VIEW_WHITESPACE)
self.HookCommandUpdate(self.OnUpdateViewWS, win32ui.ID_VIEW_WHITESPACE)
self.HookCommand(
self.OnCmdViewIndentationGuides, win32ui.ID_VIEW_INDENTATIONGUIDES
)
self.HookCommandUpdate(
self.OnUpdateViewIndentationGuides, win32ui.ID_VIEW_INDENTATIONGUIDES
)
self.HookCommand(self.OnCmdViewRightEdge, win32ui.ID_VIEW_RIGHT_EDGE)
self.HookCommandUpdate(self.OnUpdateViewRightEdge, win32ui.ID_VIEW_RIGHT_EDGE)
self.HookCommand(self.OnCmdViewEOL, win32ui.ID_VIEW_EOL)
self.HookCommandUpdate(self.OnUpdateViewEOL, win32ui.ID_VIEW_EOL)
self.HookCommand(self.OnCmdViewFixedFont, win32ui.ID_VIEW_FIXED_FONT)
self.HookCommandUpdate(self.OnUpdateViewFixedFont, win32ui.ID_VIEW_FIXED_FONT)
self.HookCommand(self.OnCmdFileLocate, win32ui.ID_FILE_LOCATE)
self.HookCommand(self.OnCmdEditFind, win32ui.ID_EDIT_FIND)
self.HookCommand(self.OnCmdEditRepeat, win32ui.ID_EDIT_REPEAT)
self.HookCommand(self.OnCmdEditReplace, win32ui.ID_EDIT_REPLACE)
self.HookCommand(self.OnCmdGotoLine, win32ui.ID_EDIT_GOTO_LINE)
self.HookCommand(self.OnFilePrint, afxres.ID_FILE_PRINT)
self.HookCommand(self.OnFilePrint, afxres.ID_FILE_PRINT_DIRECT)
self.HookCommand(self.OnFilePrintPreview, win32ui.ID_FILE_PRINT_PREVIEW)
# Key bindings.
self.HookMessage(self.OnKeyDown, win32con.WM_KEYDOWN)
self.HookMessage(self.OnKeyDown, win32con.WM_SYSKEYDOWN)
# Hook wheeley mouse events
# self.HookMessage(self.OnMouseWheel, win32con.WM_MOUSEWHEEL)
self.HookFormatter()
def OnInitialUpdate(self):
doc = self.GetDocument()
# Enable Unicode
self.SendScintilla(scintillacon.SCI_SETCODEPAGE, scintillacon.SC_CP_UTF8, 0)
self.SendScintilla(scintillacon.SCI_SETKEYSUNICODE, 1, 0)
# Create margins
self.SendScintilla(
scintillacon.SCI_SETMARGINTYPEN, 1, scintillacon.SC_MARGIN_SYMBOL
)
self.SendScintilla(scintillacon.SCI_SETMARGINMASKN, 1, 0xF)
self.SendScintilla(
scintillacon.SCI_SETMARGINTYPEN, 2, scintillacon.SC_MARGIN_SYMBOL
)
self.SendScintilla(
scintillacon.SCI_SETMARGINMASKN, 2, scintillacon.SC_MASK_FOLDERS
)
self.SendScintilla(scintillacon.SCI_SETMARGINSENSITIVEN, 2, 1)
self.GetDocument().HookViewNotifications(
self
) # is there an MFC way to grab this?
self.HookHandlers()
# Load the configuration information.
self.OnWinIniChange(None)
self.SetSel()
self.GetDocument().FinalizeViewCreation(
self
) # is there an MFC way to grab this?
def _GetSubConfigNames(self):
return None # By default we use only sections without sub-sections.
def OnWinIniChange(self, section=None):
self.bindings.prepare_configure()
try:
self.DoConfigChange()
finally:
self.bindings.complete_configure()
def DoConfigChange(self):
# Bit of a hack I dont kow what to do about - these should be "editor options"
from pywin.framework.editor import GetEditorOption
self.bAutoCompleteAttributes = GetEditorOption("Autocomplete Attributes", 1)
self.bShowCallTips = GetEditorOption("Show Call Tips", 1)
# Update the key map and extension data.
configManager.configure(self, self._GetSubConfigNames())
if configManager.last_error:
win32ui.MessageBox(configManager.last_error, "Configuration Error")
self.bMatchBraces = GetEditorOption("Match Braces", 1)
self.ApplyFormattingStyles(1)
def OnDestroy(self, msg):
self.bindings.close()
self.bindings = None
self.idle.close()
self.idle = None
control.CScintillaColorEditInterface.close(self)
return docview.CtrlView.OnDestroy(self, msg)
def OnMouseWheel(self, msg):
zDelta = msg[2] >> 16
vpos = self.GetScrollPos(win32con.SB_VERT)
vpos = vpos - zDelta / 40 # 3 lines per notch
self.SetScrollPos(win32con.SB_VERT, vpos)
self.SendScintilla(
win32con.WM_VSCROLL, (vpos << 16) | win32con.SB_THUMBPOSITION, 0
)
def OnBraceMatch(self, std, extra):
if not self.bMatchBraces:
return
DoBraceMatch(self)
def OnNeedShown(self, std, extra):
notify = self.SCIUnpackNotifyMessage(extra)
# OnNeedShown is called before an edit operation when
# text is folded (as it is possible the text insertion will happen
# in a folded region.) As this happens _before_ the insert,
# we ignore the length (if we are at EOF, pos + length may
# actually be beyond the end of buffer)
self.EnsureCharsVisible(notify.position)
def EnsureCharsVisible(self, start, end=None):
if end is None:
end = start
lineStart = self.LineFromChar(min(start, end))
lineEnd = self.LineFromChar(max(start, end))
while lineStart <= lineEnd:
self.SCIEnsureVisible(lineStart)
lineStart = lineStart + 1
# Helper to add an event to a menu.
def AppendMenu(self, menu, text="", event=None, flags=None, checked=0):
if event is None:
assert flags is not None, "No event or custom flags!"
cmdid = 0
else:
cmdid = self.bindings.get_command_id(event)
if cmdid is None:
# No event of that name - no point displaying it.
print(
'View.AppendMenu(): Unknown event "%s" specified for menu text "%s" - ignored'
% (event, text)
)
return
keyname = configManager.get_key_binding(event, self._GetSubConfigNames())
if keyname is not None:
text = text + "\t" + keyname
if flags is None:
flags = win32con.MF_STRING | win32con.MF_ENABLED
if checked:
flags = flags | win32con.MF_CHECKED
menu.AppendMenu(flags, cmdid, text)
def OnKeyDown(self, msg):
return self.bindings.fire_key_event(msg)
def GotoEndOfFileEvent(self, event):
self.SetSel(-1)
def KeyDotEvent(self, event):
## Don't trigger autocomplete if any text is selected
s, e = self.GetSel()
if s != e:
return 1
self.SCIAddText(".")
if self.bAutoCompleteAttributes:
self._AutoComplete()
# View Whitespace/EOL/Indentation UI.
def OnCmdViewWS(self, cmd, code): # Handle the menu command
viewWS = self.SCIGetViewWS()
self.SCISetViewWS(not viewWS)
def OnUpdateViewWS(self, cmdui): # Update the tick on the UI.
cmdui.SetCheck(self.SCIGetViewWS())
cmdui.Enable()
def OnCmdViewIndentationGuides(self, cmd, code): # Handle the menu command
viewIG = self.SCIGetIndentationGuides()
self.SCISetIndentationGuides(not viewIG)
def OnUpdateViewIndentationGuides(self, cmdui): # Update the tick on the UI.
cmdui.SetCheck(self.SCIGetIndentationGuides())
cmdui.Enable()
def OnCmdViewRightEdge(self, cmd, code): # Handle the menu command
if self.SCIGetEdgeMode() == scintillacon.EDGE_NONE:
mode = scintillacon.EDGE_BACKGROUND
else:
mode = scintillacon.EDGE_NONE
self.SCISetEdgeMode(mode)
def OnUpdateViewRightEdge(self, cmdui): # Update the tick on the UI.
cmdui.SetCheck(self.SCIGetEdgeMode() != scintillacon.EDGE_NONE)
cmdui.Enable()
def OnCmdViewEOL(self, cmd, code): # Handle the menu command
viewEOL = self.SCIGetViewEOL()
self.SCISetViewEOL(not viewEOL)
def OnUpdateViewEOL(self, cmdui): # Update the tick on the UI.
cmdui.SetCheck(self.SCIGetViewEOL())
cmdui.Enable()
def OnCmdViewFixedFont(self, cmd, code): # Handle the menu command
self._GetColorizer().bUseFixed = not self._GetColorizer().bUseFixed
self.ApplyFormattingStyles(0)
# Ensure the selection is visible!
self.ScrollCaret()
def OnUpdateViewFixedFont(self, cmdui): # Update the tick on the UI.
c = self._GetColorizer()
if c is not None:
cmdui.SetCheck(c.bUseFixed)
cmdui.Enable(c is not None)
def OnCmdEditFind(self, cmd, code):
from . import find
find.ShowFindDialog()
def OnCmdEditRepeat(self, cmd, code):
from . import find
find.FindNext()
def OnCmdEditReplace(self, cmd, code):
from . import find
find.ShowReplaceDialog()
def OnCmdFileLocate(self, cmd, id):
line = self.GetLine().strip()
import pywin.framework.scriptutils
m = patImport.match(line)
if m:
# Module name on this line - locate that!
modName = m.group("name")
fileName = pywin.framework.scriptutils.LocatePythonFile(modName)
if fileName is None:
win32ui.SetStatusText("Can't locate module %s" % modName)
return 1 # Let the default get it.
else:
win32ui.GetApp().OpenDocumentFile(fileName)
else:
# Just to a "normal" locate - let the default handler get it.
return 1
return 0
def OnCmdGotoLine(self, cmd, id):
try:
lineNo = int(input("Enter Line Number")) - 1
except (ValueError, KeyboardInterrupt):
return 0
self.SCIEnsureVisible(lineNo)
self.SCIGotoLine(lineNo)
return 0
def SaveTextFile(self, filename, encoding=None):
doc = self.GetDocument()
doc._SaveTextToFile(self, filename, encoding=encoding)
doc.SetModifiedFlag(0)
return 1
def _AutoComplete(self):
def list2dict(l):
ret = {}
for i in l:
ret[i] = None
return ret
self.SCIAutoCCancel() # Cancel old auto-complete lists.
# First try and get an object without evaluating calls
ob = self._GetObjectAtPos(bAllowCalls=0)
# If that failed, try and process call or indexing to get the object.
if ob is None:
ob = self._GetObjectAtPos(bAllowCalls=1)
items_dict = {}
if ob is not None:
try: # Catch unexpected errors when fetching attribute names from the object
# extra attributes of win32ui objects
if hasattr(ob, "_obj_"):
try:
items_dict.update(list2dict(dir(ob._obj_)))
except AttributeError:
pass # object has no __dict__
# normal attributes
try:
items_dict.update(list2dict(dir(ob)))
except AttributeError:
pass # object has no __dict__
if hasattr(ob, "__class__"):
items_dict.update(list2dict(_get_class_attributes(ob.__class__)))
# The object may be a COM object with typelib support - lets see if we can get its props.
# (contributed by Stefan Migowsky)
try:
# Get the automation attributes
items_dict.update(ob.__class__._prop_map_get_)
# See if there is an write only property
# could be optimized
items_dict.update(ob.__class__._prop_map_put_)
# append to the already evaluated list
except AttributeError:
pass
# The object might be a pure COM dynamic dispatch with typelib support - lets see if we can get its props.
if hasattr(ob, "_oleobj_"):
try:
for iTI in range(0, ob._oleobj_.GetTypeInfoCount()):
typeInfo = ob._oleobj_.GetTypeInfo(iTI)
self._UpdateWithITypeInfo(items_dict, typeInfo)
except:
pass
except:
win32ui.SetStatusText(
"Error attempting to get object attributes - %s"
% (repr(sys.exc_info()[0]),)
)
# ensure all keys are strings.
items = [str(k) for k in items_dict.keys()]
# All names that start with "_" go!
items = [k for k in items if not k.startswith("_")]
if not items:
# Heuristics a-la AutoExpand
# The idea is to find other usages of the current binding
# and assume, that it refers to the same object (or at least,
# to an object of the same type)
# Contributed by Vadim Chugunov [[email protected]]
left, right = self._GetWordSplit()
if left == "": # Ignore standalone dots
return None
# We limit our search to the current class, if that
# information is available
minline, maxline, curclass = self._GetClassInfoFromBrowser()
endpos = self.LineIndex(maxline)
text = self.GetTextRange(self.LineIndex(minline), endpos)
try:
l = re.findall(r"\b" + left + "\.\w+", text)
except re.error:
# parens etc may make an invalid RE, but this code wouldnt
# benefit even if the RE did work :-)
l = []
prefix = len(left) + 1
unique = {}
for li in l:
unique[li[prefix:]] = 1
# Assuming traditional usage of self...
if curclass and left == "self":
self._UpdateWithClassMethods(unique, curclass)
items = [
word for word in unique.keys() if word[:2] != "__" or word[-2:] != "__"
]
# Ignore the word currently to the right of the dot - probably a red-herring.
try:
items.remove(right[1:])
except ValueError:
pass
if items:
items.sort()
self.SCIAutoCSetAutoHide(0)
self.SCIAutoCShow(items)
def _UpdateWithITypeInfo(self, items_dict, typeInfo):
import pythoncom
typeInfos = [typeInfo]
# suppress IDispatch and IUnknown methods
inspectedIIDs = {pythoncom.IID_IDispatch: None}
while len(typeInfos) > 0:
typeInfo = typeInfos.pop()
typeAttr = typeInfo.GetTypeAttr()
if typeAttr.iid not in inspectedIIDs:
inspectedIIDs[typeAttr.iid] = None
for iFun in range(0, typeAttr.cFuncs):
funDesc = typeInfo.GetFuncDesc(iFun)
funName = typeInfo.GetNames(funDesc.memid)[0]
if funName not in items_dict:
items_dict[funName] = None
# Inspect the type info of all implemented types
# E.g. IShellDispatch5 implements IShellDispatch4 which implements IShellDispatch3 ...
for iImplType in range(0, typeAttr.cImplTypes):
iRefType = typeInfo.GetRefTypeOfImplType(iImplType)
refTypeInfo = typeInfo.GetRefTypeInfo(iRefType)
typeInfos.append(refTypeInfo)
# TODO: This is kinda slow. Probably need some kind of cache
# here that is flushed upon file save
# Or maybe we don't need the superclass methods at all ?
def _UpdateWithClassMethods(self, dict, classinfo):
if not hasattr(classinfo, "methods"):
# No 'methods' - probably not what we think it is.
return
dict.update(classinfo.methods)
for super in classinfo.super:
if hasattr(super, "methods"):
self._UpdateWithClassMethods(dict, super)
# Find which class definition caret is currently in and return
# indexes of the the first and the last lines of that class definition
# Data is obtained from module browser (if enabled)
def _GetClassInfoFromBrowser(self, pos=-1):
minline = 0
maxline = self.GetLineCount() - 1
doc = self.GetParentFrame().GetActiveDocument()
browser = None
try:
if doc is not None:
browser = doc.GetAllViews()[1]
except IndexError:
pass
if browser is None:
return (minline, maxline, None) # Current window has no browser
if not browser.list:
return (minline, maxline, None) # Not initialized
path = self.GetDocument().GetPathName()
if not path:
return (minline, maxline, None) # No current path
import pywin.framework.scriptutils
curmodule, path = pywin.framework.scriptutils.GetPackageModuleName(path)
try:
clbrdata = browser.list.root.clbrdata
except AttributeError:
return (minline, maxline, None) # No class data for this module.
curline = self.LineFromChar(pos)
curclass = None
# Find out which class we are in
for item in clbrdata.values():
if item.module == curmodule:
item_lineno = (
item.lineno - 1
) # Scintilla counts lines from 0, whereas pyclbr - from 1
if minline < item_lineno <= curline:
minline = item_lineno
curclass = item
if curline < item_lineno < maxline:
maxline = item_lineno
return (minline, maxline, curclass)
def _GetObjectAtPos(self, pos=-1, bAllowCalls=0):
left, right = self._GetWordSplit(pos, bAllowCalls)
if left: # It is an attribute lookup
# How is this for a hack!
namespace = sys.modules.copy()
namespace.update(__main__.__dict__)
# Get the debugger's context.
try:
from pywin.framework import interact
if interact.edit is not None and interact.edit.currentView is not None:
globs, locs = interact.edit.currentView.GetContext()[:2]
if globs:
namespace.update(globs)
if locs:
namespace.update(locs)
except ImportError:
pass
try:
return eval(left, namespace)
except:
pass
return None
def _GetWordSplit(self, pos=-1, bAllowCalls=0):
if pos == -1:
pos = self.GetSel()[0] - 1 # Character before current one
limit = self.GetTextLength()
before = []
after = []
index = pos - 1
wordbreaks_use = wordbreaks
if bAllowCalls:
wordbreaks_use = wordbreaks_use + "()[]"
while index >= 0:
char = self.SCIGetCharAt(index)
if char not in wordbreaks_use:
break
before.insert(0, char)
index = index - 1
index = pos
while index <= limit:
char = self.SCIGetCharAt(index)
if char not in wordbreaks_use:
break
after.append(char)
index = index + 1
return "".join(before), "".join(after)
def OnPrepareDC(self, dc, pInfo):
# print "OnPrepareDC for page", pInfo.GetCurPage(), "of", pInfo.GetFromPage(), "to", pInfo.GetToPage(), ", starts=", self.starts
if dc.IsPrinting():
# Check if we are beyond the end.
# (only do this when actually printing, else messes up print preview!)
if not pInfo.GetPreview() and self.starts is not None:
prevPage = pInfo.GetCurPage() - 1
if prevPage > 0 and self.starts[prevPage] >= self.GetTextLength():
# All finished.
pInfo.SetContinuePrinting(0)
return
dc.SetMapMode(win32con.MM_TEXT)
def OnPreparePrinting(self, pInfo):
flags = (
win32ui.PD_USEDEVMODECOPIES | win32ui.PD_ALLPAGES | win32ui.PD_NOSELECTION
) # Dont support printing just a selection.
# NOTE: Custom print dialogs are stopping the user's values from coming back :-(
# self.prtDlg = PrintDialog(pInfo, PRINTDLGORD, flags)
# pInfo.SetPrintDialog(self.prtDlg)
pInfo.SetMinPage(1)
# max page remains undefined for now.
pInfo.SetFromPage(1)
pInfo.SetToPage(1)
ret = self.DoPreparePrinting(pInfo)
return ret
def OnBeginPrinting(self, dc, pInfo):
self.starts = None
return self._obj_.OnBeginPrinting(dc, pInfo)
def CalculatePageRanges(self, dc, pInfo):
# Calculate page ranges and max page
self.starts = {0: 0}
metrics = dc.GetTextMetrics()
left, top, right, bottom = pInfo.GetDraw()
# Leave space at the top for the header.
rc = (left, top + int((9 * metrics["tmHeight"]) / 2), right, bottom)
pageStart = 0
maxPage = 0
textLen = self.GetTextLength()
while pageStart < textLen:
pageStart = self.FormatRange(dc, pageStart, textLen, rc, 0)
maxPage = maxPage + 1
self.starts[maxPage] = pageStart
# And a sentinal for one page past the end
self.starts[maxPage + 1] = textLen
# When actually printing, maxPage doesnt have any effect at this late state.
# but is needed to make the Print Preview work correctly.
pInfo.SetMaxPage(maxPage)
def OnFilePrintPreview(self, *arg):
self._obj_.OnFilePrintPreview()
def OnFilePrint(self, *arg):
self._obj_.OnFilePrint()
def FormatRange(self, dc, pageStart, lengthDoc, rc, draw):
"""
typedef struct _formatrange {
HDC hdc;
HDC hdcTarget;
RECT rc;
RECT rcPage;
CHARRANGE chrg;} FORMATRANGE;
"""
fmt = "PPIIIIIIIIll"
hdcRender = dc.GetHandleOutput()
hdcFormat = dc.GetHandleAttrib()
fr = struct.pack(
fmt,
hdcRender,
hdcFormat,
rc[0],
rc[1],
rc[2],
rc[3],
rc[0],
rc[1],
rc[2],
rc[3],
pageStart,
lengthDoc,
)
nextPageStart = self.SendScintilla(EM_FORMATRANGE, draw, fr)
return nextPageStart
def OnPrint(self, dc, pInfo):
metrics = dc.GetTextMetrics()
# print "dev", w, h, l, metrics['tmAscent'], metrics['tmDescent']
if self.starts is None:
self.CalculatePageRanges(dc, pInfo)
pageNum = pInfo.GetCurPage() - 1
# Setup the header of the page - docname on left, pagenum on right.
doc = self.GetDocument()
cxChar = metrics["tmAveCharWidth"]
cyChar = metrics["tmHeight"]
left, top, right, bottom = pInfo.GetDraw()
dc.TextOut(0, 2 * cyChar, doc.GetTitle())
pagenum_str = win32ui.LoadString(afxres.AFX_IDS_PRINTPAGENUM) % (pageNum + 1,)
dc.SetTextAlign(win32con.TA_RIGHT)
dc.TextOut(right, 2 * cyChar, pagenum_str)
dc.SetTextAlign(win32con.TA_LEFT)
top = top + int((7 * cyChar) / 2)
dc.MoveTo(left, top)
dc.LineTo(right, top)
top = top + cyChar
rc = (left, top, right, bottom)
nextPageStart = self.FormatRange(
dc, self.starts[pageNum], self.starts[pageNum + 1], rc, 1
)
def LoadConfiguration():
global configManager
# Bit of a hack I dont kow what to do about?
from .config import ConfigManager
configName = rc = win32ui.GetProfileVal("Editor", "Keyboard Config", "default")
configManager = ConfigManager(configName)
if configManager.last_error:
bTryDefault = 0
msg = "Error loading configuration '%s'\n\n%s" % (
configName,
configManager.last_error,
)
if configName != "default":
msg = msg + "\n\nThe default configuration will be loaded."
bTryDefault = 1
win32ui.MessageBox(msg)
if bTryDefault:
configManager = ConfigManager("default")
if configManager.last_error:
win32ui.MessageBox(
"Error loading configuration 'default'\n\n%s"
% (configManager.last_error)
)
configManager = None
LoadConfiguration()