Uploaded Test files
This commit is contained in:
parent
f584ad9d97
commit
2e81cb7d99
16627 changed files with 2065359 additions and 102444 deletions
|
@ -0,0 +1,200 @@
|
|||
# ModuleBrowser.py - A view that provides a module browser for an editor document.
|
||||
import pywin.mfc.docview
|
||||
import win32ui
|
||||
import win32con
|
||||
import commctrl
|
||||
import win32api
|
||||
from pywin.tools import hierlist, browser
|
||||
import pywin.framework.scriptutils
|
||||
import afxres
|
||||
|
||||
import pyclbr
|
||||
|
||||
class HierListCLBRModule(hierlist.HierListItem):
|
||||
def __init__(self, modName, clbrdata):
|
||||
self.modName = modName
|
||||
self.clbrdata = clbrdata
|
||||
def GetText(self):
|
||||
return self.modName
|
||||
def GetSubList(self):
|
||||
ret = []
|
||||
for item in self.clbrdata.values():
|
||||
if item.__class__ != pyclbr.Class: # ie, it is a pyclbr Function instance (only introduced post 1.5.2)
|
||||
ret.append(HierListCLBRFunction( item ) )
|
||||
else:
|
||||
ret.append(HierListCLBRClass( item) )
|
||||
ret.sort()
|
||||
return ret
|
||||
def IsExpandable(self):
|
||||
return 1
|
||||
|
||||
class HierListCLBRItem(hierlist.HierListItem):
|
||||
def __init__(self, name, file, lineno, suffix = ""):
|
||||
self.name = str(name)
|
||||
self.file = file
|
||||
self.lineno = lineno
|
||||
self.suffix = suffix
|
||||
def __lt__(self, other):
|
||||
return self.name < other.name
|
||||
def __eq__(self, other):
|
||||
return self.name == other.name
|
||||
def GetText(self):
|
||||
return self.name + self.suffix
|
||||
def TakeDefaultAction(self):
|
||||
if self.file:
|
||||
pywin.framework.scriptutils.JumpToDocument(self.file, self.lineno, bScrollToTop = 1)
|
||||
else:
|
||||
win32ui.SetStatusText("Can not locate the source code for this object.")
|
||||
def PerformItemSelected(self):
|
||||
if self.file is None:
|
||||
msg = "%s - source can not be located." % (self.name, )
|
||||
else:
|
||||
msg = "%s defined at line %d of %s" % (self.name, self.lineno, self.file)
|
||||
win32ui.SetStatusText(msg)
|
||||
|
||||
class HierListCLBRClass(HierListCLBRItem):
|
||||
def __init__(self, clbrclass, suffix = ""):
|
||||
try:
|
||||
name = clbrclass.name
|
||||
file = clbrclass.file
|
||||
lineno = clbrclass.lineno
|
||||
self.super = clbrclass.super
|
||||
self.methods = clbrclass.methods
|
||||
except AttributeError:
|
||||
name = clbrclass
|
||||
file = lineno = None
|
||||
self.super = []; self.methods = {}
|
||||
HierListCLBRItem.__init__(self, name, file, lineno, suffix)
|
||||
def GetSubList(self):
|
||||
r1 = []
|
||||
for c in self.super:
|
||||
r1.append(HierListCLBRClass(c, " (Parent class)"))
|
||||
r1.sort()
|
||||
r2=[]
|
||||
for meth, lineno in self.methods.items():
|
||||
r2.append(HierListCLBRMethod(meth, self.file, lineno))
|
||||
r2.sort()
|
||||
return r1+r2
|
||||
def IsExpandable(self):
|
||||
return len(self.methods) + len(self.super)
|
||||
def GetBitmapColumn(self):
|
||||
return 21
|
||||
|
||||
class HierListCLBRFunction(HierListCLBRItem):
|
||||
def __init__(self, clbrfunc, suffix = ""):
|
||||
name = clbrfunc.name
|
||||
file = clbrfunc.file
|
||||
lineno = clbrfunc.lineno
|
||||
HierListCLBRItem.__init__(self, name, file, lineno, suffix)
|
||||
def GetBitmapColumn(self):
|
||||
return 22
|
||||
|
||||
class HierListCLBRMethod(HierListCLBRItem):
|
||||
def GetBitmapColumn(self):
|
||||
return 22
|
||||
|
||||
class HierListCLBRErrorItem(hierlist.HierListItem):
|
||||
def __init__(self, text):
|
||||
self.text = text
|
||||
def GetText(self):
|
||||
return self.text
|
||||
def GetSubList(self):
|
||||
return [HierListCLBRErrorItem(self.text)]
|
||||
def IsExpandable(self):
|
||||
return 0
|
||||
|
||||
class HierListCLBRErrorRoot(HierListCLBRErrorItem):
|
||||
def IsExpandable(self):
|
||||
return 1
|
||||
|
||||
class BrowserView(pywin.mfc.docview.TreeView):
|
||||
def OnInitialUpdate(self):
|
||||
self.list = None
|
||||
rc = self._obj_.OnInitialUpdate()
|
||||
self.HookMessage(self.OnSize, win32con.WM_SIZE)
|
||||
self.bDirty = 0
|
||||
self.destroying = 0
|
||||
return rc
|
||||
|
||||
def DestroyBrowser(self):
|
||||
self.DestroyList()
|
||||
|
||||
def OnActivateView(self, activate, av, dv):
|
||||
# print "AV", self.bDirty, activate
|
||||
if activate:
|
||||
self.CheckRefreshList()
|
||||
return self._obj_.OnActivateView(activate, av, dv)
|
||||
|
||||
def _MakeRoot(self):
|
||||
path = self.GetDocument().GetPathName()
|
||||
if not path:
|
||||
return HierListCLBRErrorRoot("Error: Can not browse a file until it is saved")
|
||||
else:
|
||||
mod, path = pywin.framework.scriptutils.GetPackageModuleName(path)
|
||||
if self.bDirty:
|
||||
what = "Refreshing"
|
||||
# Hack for pyclbr being too smart
|
||||
try:
|
||||
del pyclbr._modules[mod]
|
||||
except (KeyError, AttributeError):
|
||||
pass
|
||||
else:
|
||||
what = "Building"
|
||||
win32ui.SetStatusText("%s class list - please wait..." % (what,), 1)
|
||||
win32ui.DoWaitCursor(1)
|
||||
try:
|
||||
reader = pyclbr.readmodule_ex # new version post 1.5.2
|
||||
except AttributeError:
|
||||
reader = pyclbr.readmodule
|
||||
try:
|
||||
data = reader(mod, [path])
|
||||
if data:
|
||||
return HierListCLBRModule(mod, data)
|
||||
else:
|
||||
return HierListCLBRErrorRoot("No Python classes in module.")
|
||||
|
||||
finally:
|
||||
win32ui.DoWaitCursor(0)
|
||||
win32ui.SetStatusText(win32ui.LoadString(afxres.AFX_IDS_IDLEMESSAGE))
|
||||
|
||||
def DestroyList(self):
|
||||
self.destroying = 1
|
||||
list = getattr(self, "list", None) # If the document was not successfully opened, we may not have a list.
|
||||
self.list = None
|
||||
if list is not None:
|
||||
list.HierTerm()
|
||||
self.destroying = 0
|
||||
|
||||
def CheckMadeList(self):
|
||||
if self.list is not None or self.destroying: return
|
||||
self.rootitem = root = self._MakeRoot()
|
||||
self.list = list = hierlist.HierListWithItems( root, win32ui.IDB_BROWSER_HIER)
|
||||
list.HierInit(self.GetParentFrame(), self)
|
||||
list.SetStyle(commctrl.TVS_HASLINES | commctrl.TVS_LINESATROOT | commctrl.TVS_HASBUTTONS)
|
||||
|
||||
def CheckRefreshList(self):
|
||||
if self.bDirty:
|
||||
if self.list is None:
|
||||
self.CheckMadeList()
|
||||
else:
|
||||
new_root = self._MakeRoot()
|
||||
if self.rootitem.__class__==new_root.__class__==HierListCLBRModule:
|
||||
self.rootitem.modName = new_root.modName
|
||||
self.rootitem.clbrdata = new_root.clbrdata
|
||||
self.list.Refresh()
|
||||
else:
|
||||
self.list.AcceptRoot(self._MakeRoot())
|
||||
self.bDirty = 0
|
||||
|
||||
def OnSize(self, params):
|
||||
lparam = params[3]
|
||||
w = win32api.LOWORD(lparam)
|
||||
h = win32api.HIWORD(lparam)
|
||||
if w != 0:
|
||||
self.CheckMadeList()
|
||||
elif w == 0:
|
||||
self.DestroyList()
|
||||
return 1
|
||||
|
||||
def _UpdateUIForState(self):
|
||||
self.bDirty = 1
|
|
@ -0,0 +1,90 @@
|
|||
# __init__ for the Pythonwin editor package.
|
||||
#
|
||||
# We used to support optional editors - eg, color or non-color.
|
||||
#
|
||||
# This really isnt necessary with Scintilla, and scintilla
|
||||
# is getting so deeply embedded that it was too much work.
|
||||
|
||||
import win32ui, sys, win32con
|
||||
|
||||
defaultCharacterFormat = (-402653169, 0, 200, 0, 0, 0, 49, 'Courier New')
|
||||
|
||||
##def GetDefaultEditorModuleName():
|
||||
## import pywin
|
||||
## # If someone has set pywin.editormodulename, then this is what we use
|
||||
## try:
|
||||
## prefModule = pywin.editormodulename
|
||||
## except AttributeError:
|
||||
## prefModule = win32ui.GetProfileVal("Editor","Module", "")
|
||||
## return prefModule
|
||||
##
|
||||
##def WriteDefaultEditorModule(module):
|
||||
## try:
|
||||
## module = module.__name__
|
||||
## except:
|
||||
## pass
|
||||
## win32ui.WriteProfileVal("Editor", "Module", module)
|
||||
|
||||
def LoadDefaultEditor():
|
||||
pass
|
||||
## prefModule = GetDefaultEditorModuleName()
|
||||
## restorePrefModule = None
|
||||
## mod = None
|
||||
## if prefModule:
|
||||
## try:
|
||||
## mod = __import__(prefModule)
|
||||
## except 'xx':
|
||||
## msg = "Importing your preferred editor ('%s') failed.\n\nError %s: %s\n\nAn attempt will be made to load the default editor.\n\nWould you like this editor disabled in the future?" % (prefModule, sys.exc_info()[0], sys.exc_info()[1])
|
||||
## rc = win32ui.MessageBox(msg, "Error importing editor", win32con.MB_YESNO)
|
||||
## if rc == win32con.IDNO:
|
||||
## restorePrefModule = prefModule
|
||||
## WriteDefaultEditorModule("")
|
||||
## del rc
|
||||
##
|
||||
## try:
|
||||
## # Try and load the default one - dont catch errors here.
|
||||
## if mod is None:
|
||||
## prefModule = "pywin.framework.editor.color.coloreditor"
|
||||
## mod = __import__(prefModule)
|
||||
##
|
||||
## # Get at the real module.
|
||||
## mod = sys.modules[prefModule]
|
||||
##
|
||||
## # Do a "from mod import *"
|
||||
## globals().update(mod.__dict__)
|
||||
##
|
||||
## finally:
|
||||
## # Restore the users default editor if it failed and they requested not to disable it.
|
||||
## if restorePrefModule:
|
||||
## WriteDefaultEditorModule(restorePrefModule)
|
||||
|
||||
def GetEditorOption(option, defaultValue, min=None, max = None):
|
||||
rc = win32ui.GetProfileVal("Editor", option, defaultValue)
|
||||
if min is not None and rc < min: rc = defaultValue
|
||||
if max is not None and rc > max: rc = defaultValue
|
||||
return rc
|
||||
|
||||
def SetEditorOption(option, newValue):
|
||||
win32ui.WriteProfileVal("Editor", option, newValue)
|
||||
|
||||
def DeleteEditorOption(option):
|
||||
try:
|
||||
win32ui.WriteProfileVal("Editor", option, None)
|
||||
except win32ui.error:
|
||||
pass
|
||||
|
||||
# Load and save font tuples
|
||||
def GetEditorFontOption(option, default = None):
|
||||
if default is None: default = defaultCharacterFormat
|
||||
fmt = GetEditorOption( option, "" )
|
||||
if fmt == "": return default
|
||||
try:
|
||||
return eval(fmt)
|
||||
except:
|
||||
print("WARNING: Invalid font setting in registry - setting ignored")
|
||||
return default
|
||||
|
||||
def SetEditorFontOption(option, newValue):
|
||||
SetEditorOption(option, str(newValue))
|
||||
|
||||
from pywin.framework.editor.color.coloreditor import editorTemplate
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -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)
|
|
@ -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()
|
|
@ -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)
|
|
@ -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)
|
|
@ -0,0 +1,76 @@
|
|||
# frame.py - The MDI frame window for an editor.
|
||||
import pywin.framework.window
|
||||
import win32ui
|
||||
import win32con
|
||||
import afxres
|
||||
|
||||
from . import ModuleBrowser
|
||||
|
||||
class EditorFrame(pywin.framework.window.MDIChildWnd):
|
||||
def OnCreateClient(self, cp, context):
|
||||
|
||||
# Create the default view as specified by the template (ie, the editor view)
|
||||
view = context.template.MakeView(context.doc)
|
||||
# Create the browser view.
|
||||
browserView = ModuleBrowser.BrowserView(context.doc)
|
||||
view2 = context.template.MakeView(context.doc)
|
||||
|
||||
splitter = win32ui.CreateSplitter()
|
||||
style = win32con.WS_CHILD | win32con.WS_VISIBLE
|
||||
splitter.CreateStatic (self, 1, 2, style, win32ui.AFX_IDW_PANE_FIRST)
|
||||
sub_splitter = self.sub_splitter = win32ui.CreateSplitter()
|
||||
sub_splitter.CreateStatic (splitter, 2, 1, style, win32ui.AFX_IDW_PANE_FIRST+1)
|
||||
|
||||
# Note we must add the default view first, so that doc.GetFirstView() returns the editor view.
|
||||
sub_splitter.CreateView(view, 1, 0, (0,0))
|
||||
splitter.CreateView (browserView, 0, 0, (0,0))
|
||||
sub_splitter.CreateView(view2,0, 0, (0,0))
|
||||
|
||||
## print "First view is", context.doc.GetFirstView()
|
||||
## print "Views are", view, view2, browserView
|
||||
## print "Parents are", view.GetParent(), view2.GetParent(), browserView.GetParent()
|
||||
## print "Splitter is", splitter
|
||||
## print "sub splitter is", sub_splitter
|
||||
## Old
|
||||
## splitter.CreateStatic (self, 1, 2)
|
||||
## splitter.CreateView(view, 0, 1, (0,0)) # size ignored.
|
||||
## splitter.CreateView (browserView, 0, 0, (0, 0))
|
||||
|
||||
# Restrict the size of the browser splitter (and we can avoid filling
|
||||
# it until it is shown)
|
||||
splitter.SetColumnInfo(0, 10, 20)
|
||||
# And the active view is our default view (so it gets initial focus)
|
||||
self.SetActiveView(view)
|
||||
|
||||
def GetEditorView(self):
|
||||
# In a multi-view (eg, splitter) environment, get
|
||||
# an editor (ie, scintilla) view
|
||||
# Look for the splitter opened the most!
|
||||
if self.sub_splitter is None:
|
||||
return self.GetDlgItem(win32ui.AFX_IDW_PANE_FIRST)
|
||||
v1 = self.sub_splitter.GetPane(0,0)
|
||||
v2 = self.sub_splitter.GetPane(1,0)
|
||||
r1 = v1.GetWindowRect()
|
||||
r2 = v2.GetWindowRect()
|
||||
if r1[3]-r1[1] > r2[3]-r2[1]:
|
||||
return v1
|
||||
return v2
|
||||
|
||||
def GetBrowserView(self):
|
||||
# XXX - should fix this :-)
|
||||
return self.GetActiveDocument().GetAllViews()[1]
|
||||
|
||||
def OnClose(self):
|
||||
doc=self.GetActiveDocument()
|
||||
if not doc.SaveModified():
|
||||
## Cancel button selected from Save dialog, do not actually close
|
||||
## print 'close cancelled'
|
||||
return 0
|
||||
## So the 'Save' dialog doesn't come up twice
|
||||
doc._obj_.SetModifiedFlag(False)
|
||||
|
||||
# Must force the module browser to close itself here (OnDestroy for the view itself is too late!)
|
||||
self.sub_splitter = None # ensure no circles!
|
||||
self.GetBrowserView().DestroyBrowser()
|
||||
return self._obj_.OnClose()
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
import string
|
||||
import win32ui
|
||||
import win32api
|
||||
from pywin.mfc import docview
|
||||
import pywin.framework.window
|
||||
import os
|
||||
from . import frame
|
||||
|
||||
ParentEditorTemplate=docview.DocTemplate
|
||||
class EditorTemplateBase(ParentEditorTemplate):
|
||||
def __init__(self, res=win32ui.IDR_TEXTTYPE, makeDoc=None, makeFrame=None, makeView=None):
|
||||
if makeFrame is None: makeFrame = frame.EditorFrame
|
||||
ParentEditorTemplate.__init__(self, res, makeDoc, makeFrame, makeView)
|
||||
|
||||
def _CreateDocTemplate(self, resourceId):
|
||||
assert 0, "You must override this"
|
||||
def CreateWin32uiDocument(self):
|
||||
assert 0, "You must override this"
|
||||
def GetFileExtensions(self):
|
||||
return ".txt", ".py"
|
||||
def MatchDocType(self, fileName, fileType):
|
||||
doc = self.FindOpenDocument(fileName)
|
||||
if doc: return doc
|
||||
ext = os.path.splitext(fileName)[1].lower()
|
||||
if ext in self.GetFileExtensions():
|
||||
return win32ui.CDocTemplate_Confidence_yesAttemptNative
|
||||
return win32ui.CDocTemplate_Confidence_maybeAttemptForeign
|
||||
|
||||
def InitialUpdateFrame(self, frame, doc, makeVisible=1):
|
||||
self._obj_.InitialUpdateFrame(frame, doc, makeVisible) # call default handler.
|
||||
doc._UpdateUIForState()
|
||||
|
||||
def GetPythonPropertyPages(self):
|
||||
"""Returns a list of property pages
|
||||
"""
|
||||
from . import configui
|
||||
return [configui.EditorPropertyPage(), configui.EditorWhitespacePropertyPage()]
|
||||
|
||||
def OpenDocumentFile(self, filename, bMakeVisible = 1):
|
||||
if filename is not None:
|
||||
try:
|
||||
path = os.path.split(filename)[0]
|
||||
# print "The editor is translating", `filename`,"to",
|
||||
filename = win32api.FindFiles(filename)[0][8]
|
||||
filename = os.path.join(path, filename)
|
||||
# print `filename`
|
||||
except (win32api.error, IndexError) as details:
|
||||
pass
|
||||
# print "Couldnt get the full filename!", details
|
||||
return self._obj_.OpenDocumentFile(filename, bMakeVisible)
|
|
@ -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
|
||||
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue