123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722 |
- # A general purpose MFC CCtrlView view that uses Scintilla.
- from . import control
- from . import IDLEenvironment # IDLE emulation.
- from pywin.mfc import docview
- from pywin.mfc import dialog
- from . import scintillacon
- import win32con
- import win32ui
- import afxres
- import string
- import array
- import sys
- import types
- import __main__ # for attribute lookup
- from . import bindings
- from . import keycodes
- import struct
- import re
- import os
- 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 OnDestroy(self, msg):
- self.SendScintilla = None
- return docview.CtrlView.OnDestroy(self, msg)
- 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 [vadimch@yahoo.com]
- 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()
|