Uploaded Test files

This commit is contained in:
Batuhan Berk Başoğlu 2020-11-12 11:05:57 -05:00
parent f584ad9d97
commit 2e81cb7d99
16627 changed files with 2065359 additions and 102444 deletions

View file

@ -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

View file

@ -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

View file

@ -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)

View 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()

View 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)

View 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)

View 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()

View file

@ -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)

View 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