Added docview modules from Peter Yared and Morgan Hua

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@32374 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Robin Dunn 2005-02-25 23:50:26 +00:00
parent 18c45cd6dc
commit d1dc2b32e0
11 changed files with 7059 additions and 0 deletions

View File

@ -232,6 +232,11 @@ controls.
wxMSW: "Alt" key (VK_MENU) now results in WXK_ALT keyboard event, not
WXK_MENU
Added modules from Peter Yared and Morgan Hua that implement the wx
Doc/View framework in pure Python code. See wx.lib.docview for the
base implementation and wx.lib.pydocview for Python-specific
extensions. There are also a couple sample applications located in
samples/docview.

View File

@ -0,0 +1,323 @@
#----------------------------------------------------------------------------
# Name: DocViewDemo.py
# Purpose: Port of the wxWindows docview sample classes
#
# Author: Peter Yared
#
# Created: 8/1/03
# CVS-ID: $Id$
# Copyright: (c) 2003, 2004 ActiveGrid, Inc. (Port of wxWindows classes by Julian Smart et al)
# License: wxWindows license
#----------------------------------------------------------------------------
#----------------------------------------------------------------------
# This isn't the most object oriented code (it is somewhat repetitive,
# but it is true to the wxWindows C++ demos.
#----------------------------------------------------------------------
import wx
import wx.lib.docview
_ = wx.GetTranslation
#----------------------------------------------------------------------
#----------------------------------------------------------------------
# TextEdit document and view classes
class TextEditDocument(wx.lib.docview.Document):
def OnSaveDocument(self, filename):
view = self.GetFirstView()
if not view.GetTextSW().SaveFile(filename):
return False
self.Modify(False)
self.SetDocumentSaved(True)
## if wx.Platform == "__WXMAC__":
## fn = wx.Filename(filename)
## fn.MacSetDefaultTypeAndCreator()
return True
def OnOpenDocument(self, filename):
view = self.GetFirstView()
if not view.GetTextSW().LoadFile(filename):
return False
self.SetFilename(filename, True)
self.Modify(False)
self.UpdateAllViews()
self._savedYet = True
return True
def IsModified(self):
view = self.GetFirstView()
if view:
return wx.lib.docview.Document.IsModified(self) or (view.GetTextSW() and view.GetTextSW().IsModified())
else:
return wx.lib.docview.Document.IsModified(self)
def Modify(self, mod):
view = self.GetFirstView()
wx.lib.docview.Document.Modify(self, mod)
if not mod and view and view.GetTextSW():
view.GetTextSW().DiscardEdits()
class TextEditView(wx.lib.docview.View):
def OnCreate(self, doc, flags):
flags = doc.GetDocumentManager().GetFlags()
if flags & wx.lib.docview.DOC_SDI and doc.GetDocumentManager().GetMaxDocsOpen() == 1:
self._frame = wx.GetApp().GetMainFrame()
self.SetFrame(self._frame)
sizer = wx.BoxSizer()
self._textsw = MyTextWindow(self, self._frame, wx.DefaultPosition, wx.DefaultSize, wx.TE_MULTILINE)
sizer.Add(self._textsw, 1, wx.EXPAND, 0)
self._frame.SetSizer(sizer)
self._frame.Layout()
self.Activate(True)
return True
elif flags & wx.lib.docview.DOC_MDI:
self._frame = wx.lib.docview.DocMDIChildFrame(doc, self, wx.GetApp().GetMainFrame(), -1, wx.GetApp().GetAppName(), (10, 10), (300, 300), wx.DEFAULT_FRAME_STYLE)
self.SetFrame(self._frame)
sizer = wx.BoxSizer()
self._textsw = MyTextWindow(self, self._frame, wx.DefaultPosition, wx.DefaultSize, wx.TE_MULTILINE)
sizer.Add(self._textsw, 1, wx.EXPAND, 0)
self._frame.SetSizer(sizer)
self._frame.Layout()
self.Activate(True)
return True
else: # flags & wx.lib.docview.DOC_SDI
self._frame = wx.GetApp().CreateChildFrame(doc, self)
width, height = self._frame.GetClientSize()
self._textsw = MyTextWindow(self, self._frame, (0, 0), (width, height), wx.TE_MULTILINE)
self._frame.SetTitle(_("TextEditView"))
self._frame.Show(True)
self.Activate(True)
return True
# Since ProcessEvent is not virtual, we have to trap the relevant events using this pseudo-ProcessEvent instead of EVT_MENU
def ProcessEvent(self, event):
id = event.GetId()
if id == wx.ID_UNDO:
self._textsw.Undo()
return True
elif id == wx.ID_REDO:
self._textsw.Redo()
return True
else:
return wx.lib.docview.View.ProcessEvent(self, event)
def GetTextSW(self):
return self._textsw
def OnDraw(self, dc):
pass
def OnClose(self, deleteWindow = True):
if not self.GetDocument().Close():
return False
self.Activate(False)
if deleteWindow:
if self.GetDocument().GetDocumentManager().GetMaxDocsOpen() == 1 and self.GetDocument().GetDocumentManager().GetFlags() & wx.lib.docview.DOC_SDI:
if self._textsw:
self._textsw.Destroy()
return True
else:
self._frame.Destroy()
return True
return True
class MyTextWindow(wx.TextCtrl):
def __init__(self, view, frame, pos, size, style):
wx.TextCtrl.__init__(self, frame, -1, "", pos, size, style)
self._view = view
#----------------------------------------------------------------------
#----------------------------------------------------------------------
# TextEdit Sample Application
class MyApp(wx.PySimpleApp):
def OnInit(self):
demoMode = wx.GetSingleChoiceIndex(_("Select the demo mode"),
_("wxPython DocView Demo"),
[_("SDI Single Document"), _("SDI"), _("MDI")])
if demoMode == 0 or demoMode == 1:
flags = wx.lib.docview.DOC_SDI
elif demoMode == 2:
flags = wx.lib.docview.DOC_MDI
else:
return False
self.SetAppName(_("DocView Demo"))
docManager = wx.lib.docview.DocManager(flags = flags)
docManager.AssociateTemplate(wx.lib.docview.DocTemplate(docManager,
_("Text"),
"*.text;*.txt",
_("Text"),
_(".txt"),
_("Text Document"),
_("Text View"),
TextEditDocument,
TextEditView))
#if wx.Platform == "__WXMAC__":
# wx.FileName.MacRegisterDefaultTypeAndCreator("txt", 'TEXT', 'WXMA')
if demoMode == 0:
docManager.SetMaxDocsOpen(1)
if demoMode == 2: # MDI
self._frame = MyMDIFrame(docManager, None, -1, _("DocView Demo"), (0, 0), (500, 400), wx.DEFAULT_FRAME_STYLE)
else: # SDI
self._frame = MyFrame(docManager, None, -1, _("DocView Demo"), (0, 0), (500, 400), wx.DEFAULT_FRAME_STYLE)
fileMenu = wx.Menu()
editMenu = None
fileMenu.Append(wx.ID_NEW, _("&New..."))
fileMenu.Append(wx.ID_OPEN, _("&Open..."))
if demoMode == 2: # MDI
fileMenu.Append(wx.ID_CLOSE, _("&Close"))
fileMenu.AppendSeparator()
if demoMode == 0 or demoMode == 2: # Single Doc or MDI
fileMenu.Append(wx.ID_SAVE, _("&Save"))
fileMenu.Append(wx.ID_SAVEAS, _("Save &As"))
fileMenu.AppendSeparator()
fileMenu.Append(wx.ID_PRINT, _("&Print"))
fileMenu.Append(wx.ID_PRINT_SETUP, _("Page &Setup"))
fileMenu.Append(wx.ID_PREVIEW, _("Print Pre&view"))
editMenu = wx.Menu()
editMenu.Append(wx.ID_UNDO, _("&Undo"))
editMenu.Append(wx.ID_REDO, _("&Redo"))
self._frame.editMenu = editMenu
fileMenu.AppendSeparator()
fileMenu.Append(wx.ID_EXIT, _("E&xit"))
docManager.FileHistoryUseMenu(fileMenu)
helpMenu = wx.Menu()
helpMenu.Append(wx.ID_ABOUT, _("&About"))
menuBar = wx.MenuBar()
menuBar.Append(fileMenu, _("&File"))
if editMenu:
menuBar.Append(editMenu, _("&Edit"))
menuBar.Append(helpMenu, _("&Help"))
self._frame.SetMenuBar(menuBar)
self._frame.Centre(wx.BOTH)
self._frame.Show(True)
self.SetTopWindow(self._frame)
if demoMode == 0: # Single doc
docManager.OnFileNew(None)
return True
def GetMainFrame(self):
return self._frame
def GetDemoMode(self):
return self._demoMode
def CreateChildFrame(self, doc, view):
subframe = wx.lib.docview.DocChildFrame(doc, view, self.GetMainFrame(), -1, wx.GetApp().GetAppName(), (10, 10), (300, 300), wx.DEFAULT_FRAME_STYLE)
fileMenu = wx.Menu()
fileMenu.Append(wx.ID_NEW, _("&New"))
fileMenu.Append(wx.ID_OPEN, _("&Open"))
fileMenu.Append(wx.ID_CLOSE, _("&Close"))
fileMenu.AppendSeparator()
fileMenu.Append(wx.ID_SAVE, _("&Save"))
fileMenu.Append(wx.ID_SAVEAS, _("Save &As"))
fileMenu.AppendSeparator()
fileMenu.Append(wx.ID_PRINT, _("&Print"))
fileMenu.Append(wx.ID_PRINT_SETUP, _("Page &Setup"))
fileMenu.Append(wx.ID_PREVIEW, _("Print Pre&view"))
editMenu = wx.Menu()
editMenu.Append(wx.ID_UNDO, _("&Undo"))
editMenu.Append(wx.ID_REDO, _("&Redo"))
helpMenu = wx.Menu()
helpMenu.Append(wx.ID_ABOUT, _("&About"))
menuBar = wx.MenuBar()
menuBar.Append(fileMenu, _("&File"))
menuBar.Append(editMenu, _("&Edit"))
menuBar.Append(helpMenu, _("&Help"))
subframe.SetMenuBar(menuBar)
subframe.Centre(wx.BOTH)
return subframe
class MyFrame(wx.lib.docview.DocParentFrame):
def __init__(self, manager, frame, id, title, pos = wx.DefaultPosition, size = wx.DefaultSize, style = wx.DEFAULT_FRAME_STYLE, name = "frame"):
wx.lib.docview.DocParentFrame.__init__(self, manager, frame, id, title, pos, size, style, name)
self._frame = frame
wx.EVT_MENU(self, wx.ID_ABOUT, self.OnAbout)
def OnAbout(self, event):
wx.MessageBox(wx.GetApp().GetAppName(), _("About DocView"))
def GetMainFrame(self):
return self._frame
class MyMDIFrame(wx.lib.docview.DocMDIParentFrame):
def __init__(self, manager, frame, id, title, pos = wx.DefaultPosition, size = wx.DefaultSize, style = wx.DEFAULT_FRAME_STYLE, name = "frame"):
wx.lib.docview.DocMDIParentFrame.__init__(self, manager, frame, id, title, pos, size, style, name)
self._frame = frame
wx.EVT_MENU(self, wx.ID_ABOUT, self.OnAbout)
def OnAbout(self, event):
wx.MessageBox(wx.GetApp().GetAppName(), _("About DocView"))
def GetMainFrame(self):
return self._frame
app = MyApp()
app.MainLoop()

View File

@ -0,0 +1,168 @@
#----------------------------------------------------------------------------
# Name: PyDocViewDemo.py
# Purpose: Demo of Python extensions to the wxWindows docview framework
#
# Author: Peter Yared, Morgan Hua
#
# Created: 5/15/03
# CVS-ID: $Id$
# Copyright: (c) 2003 ActiveGrid, Inc.
# License: wxWindows license
#----------------------------------------------------------------------------
import sys
import wx
import wx.lib.docview
import wx.lib.pydocview
import activegrid.tool.TextEditor as TextEditor
import activegrid.tool.FindService as FindService
import wx.lib.pydocview as WindowMenuService
#----------------------------------------------------------------------------
# Classes
#----------------------------------------------------------------------------
class TextEditorApplication(wx.lib.pydocview.DocApp):
def OnInit(self):
wx.lib.pydocview.DocApp.OnInit(self)
wx.lib.pydocview.DocApp.ShowSplash(self, "activegrid/tool/images/splash.jpg")
self.SetAppName(wx.GetTranslation("wxPython DocView Demo"))
config = wx.Config(self.GetAppName(), style = wx.CONFIG_USE_LOCAL_FILE)
docManager = wx.lib.docview.DocManager(flags = self.GetDefaultDocManagerFlags())
self.SetDocumentManager(docManager)
textTemplate = wx.lib.docview.DocTemplate(docManager,
wx.GetTranslation("Text"),
"*.text;*.txt",
wx.GetTranslation("Text"),
wx.GetTranslation(".txt"),
wx.GetTranslation("Text Document"),
wx.GetTranslation("Text View"),
TextEditor.TextDocument,
TextEditor.TextView)
docManager.AssociateTemplate(textTemplate)
textService = self.InstallService(TextEditor.TextService())
findService = self.InstallService(FindService.FindService())
optionsService = self.InstallService(wx.lib.pydocview.DocOptionsService())
windowMenuService = self.InstallService(WindowMenuService.WindowMenuService())
optionsService.AddOptionsPanel(TextEditor.TextOptionsPanel)
filePropertiesService = self.InstallService(wx.lib.pydocview.FilePropertiesService())
self.SetDefaultIcon(getDocIcon())
if docManager.GetFlags() & wx.lib.docview.DOC_MDI:
frame = wx.lib.pydocview.DocMDIParentFrame(docManager, None, -1, wx.GetApp().GetAppName())
frame.Show(True)
wx.lib.pydocview.DocApp.CloseSplash(self)
self.OpenCommandLineArgs()
if not docManager.GetDocuments() and docManager.GetFlags() & wx.lib.docview.DOC_SDI:
textTemplate.CreateDocument('', wx.lib.docview.DOC_NEW).OnNewDocument()
wx.CallAfter(self.ShowTip, docManager.FindSuitableParent(), wx.CreateFileTipProvider("activegrid/tool/data/tips.txt", 0))
return True
#----------------------------------------------------------------------------
# Menu Bitmaps - generated by encode_bitmaps.py
#----------------------------------------------------------------------------
from wx import ImageFromStream, BitmapFromImage
from wx import EmptyIcon
import cStringIO
def getDocData():
return \
'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00 \x00\x00\x00 \x08\x06\x00\
\x00\x00szz\xf4\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\x05cID\
ATX\x85\xed\x97\xcbo\x1b\xd7\x15\xc6\x7fw^\x1c\x92C\x8a\xa4DQ\xa2)\xd9\xb2%?\
\xe0\xa7\x82\xc0\x85\x83"\xa8\x1b\x17AwYtQtU\xb4\x8b\xa2\x7fH\xfe\x8c\xee\
\x8b\xac\x124\xab\x02E\n\x17h\x01\x17\x86Q7\xaac7~I\xb2hZ\xe2sH\xce\x83s\xef\
\xedB\xa6dI~))\x90E\xf2\x01\x17\x98\xb9s\xe7\x9c\xef\x9c\xf9\xce\xb9w\x840L\
\xbeK\x18\xdf\xa9\xf7\x1f\x08\x00\xa2\xd5ji!\x04\xe3\xf1ma\x9a\x02!\x0c\xe0\
\xa0-\xa55O\xb6\x06t\xfb\x11\xa0\x98\xca\x99\x880\x0c5\xf0R\xe7B\x08\xb4\xde\
\xbd6\xc4\xd8\xee\x0bk\xb5\xde3\'\x84f\x10J\x06aB4R\xd8\x96\xc1\x97\x8f{\xfc\
\xfbq\x97-?\xa2\xe49\x9c\x9d\xf38u\xc4\xa3\x945\xb0\xc6\x8e\r!`\x1f\t!\xd8C\
\x004\x89\xd4\x04\xb1$\x88%#\xa9(f,\xd6\xdb!\xab\x9b\x01\x9b\xbd\x98 \x96\
\xb4z\x11\xa6\x80\xea\x94K\x9ch\xfe\xf5\xa0\xcb\xfa\xd6\x90\xea\xa4\xcb\x99Z\
\x8e\xead\x96\xa2\x97\xc2\x14\t\xd6s\xf3h\x04JC"\xf5\xf3\xa1\x00M.c\xd1\xe9\
\'\xf4\x82\x11\xc3H\xd2\x0f\x13\xda~L\xcb\x8fI\x12\xc9\x953\x93\\\xff\xaa\
\xc9\x17\xb7\xb7\xf8j\xdd\xa7\x13J\x82aB\xad\x94\xe2\x83\xe5)\xba\xc3\x84\
\xde a\xa6\x98\xe2\xc3wf\xb8\xbcX\xa2\xe89(\xa5\x08\x82\xd1\x98\x00\x04qB/\
\x1c\xd1\xf6Gl\xf6"\x9euc\x84\xd0\xfc\xf4\\\x99Oo\xd4\xf9\xe2\xf6\x16w\x9f\
\x0chG\t\xbe\x1f\x13\xf9#\xa63\x16\x1f\xff\xee\x027\xefw\xb9\xf5\xb0K\xc7\
\x8f\x11\xa6`a\xc6\xe5\xdc\xbc\xc7\xfcT\x06/msa~\x82\xa5\xd9\x1c\x8em`\x08\
\xd0Z\xa1\x94\x02\xc0\xb2,\x8b\x8d\xe6\x90\xcfnl\xf0\xf9\xcd\x06\xf1H\x13E\
\x92h0\xa2\x906\xe9\x0eF\xf4#I<\x88\xb9w\xa7I\x9cs\xc8\xa5-\xcae\x97\xa3\x93\
i\xdc\x94\xa0\xe4\xd9\x143\x16\xfd~\xc4\xf4D\x8ak\x17\xa6\xb9z\xae\xcc\xd1r\
\x06\xc76)dm\xb2)\x03\xa5\xf7jLk\xb0\xc6\x9f~\xbd\x19r}\xa5\xc9\xb0\x9fl?\
\x1d)&2\x16n\xe9\x19?_.sf>\xcf\xbd\xc7>x6\xaeka\n0S&~\x980\x88\x12l[\xb08\
\x9b\xe1\xda\xa5\nW\xcfW8;\x9f\'\xefZ;\x02\xd5Z\xa3\xb5~\xae\xa5\xdd\xaa\xb3\
\x94R\x94<\x87\xc5\xaa\xc7\xe9#9V\xee\xb61\x1d\x13\xc7\xb3I\xa7L\xfe[\x1f\
\xf0\xd1\xe5\x19\x96O\x97\x08\x84\xa6\xd1\x0c\xe9\r\x136\xfd\x98F7f\xbd\x19Q\
\xefD\xa4]\x93\xf7O\x95\xf9\xed\xb5\x05\xa6\x0bi\xd0\xa0\xb5\x06\xa5w\x8a\
\xe6\xc5J\x13B`Y\x16\x96\x94\n\xc76\xf9\xd9\xc5il\x03>\x1e\xc6\x94\x8b.\xc7g\
2\xcc\x16]\xc2(a\xbd\x19\xa2\xd0,U\xb2\xfc\xf1\xcf\xab\xb4\xba#\xd2\x9eM\xed\
H\x96 N\xa8\xe4m~\xb4X\xe47W\x8f\x92\xcf\xd8\xe8\xfd\xb9~\x05l\xdb\xde\x16\
\xa1R\x8a\xa9\xbc\xc3\xd5\xf3\x15\x8a\x9e\xc3\xadG\x1dV\xd6|\xfe\xfa\xe5\x16\
\x83@"\xa4f\xf9D\x9eKKE\xe6k9\xaa\x15I\xca1\xc9y\x16\xbd0ay\xa1\xc0\xf2B\x91\
B\xd6\xd9\x8ez\x7f-\xbf\x04\xe3lX\xdb\xcdF\xe3\x98\x06\xd5\x92Kmj\x96l\xc6\
\xa4\xd1\x89\xf8\xc7\x9d6O\x9e\x05\xa8 \xc1\x16P\x9b\xcd\xf2\xd1{U\xfe\xb3\
\xda\xe5\xd1\xd3!A?\xa1\x92Oq\xf1X\x81\x93\xd5\xdc[E\xbd\x1f;e8f\xae\xb5\xe0\
lm\x82\xa7\xa7c\xd67CB\x7fD\xa4!\x1a):\xc3\x84_\xfd\xf8\x08\x1b\xad!\x8f\x1a\
CD\xa4x\xf7x\x81\xc5\x19\x8fl\xcaDJu\xe8v.\xe28\xd6cu\x8e\xb3\xa1\x81`\xa4y\
\xd8\x18\xf0\xc9\xdf\xd6ht\x02\x0c\xd3`\xc2\xb3\t\xa5\xa2\xde\x8eX\xdb\n0\
\x81?\xfc\xfe"\x8b3y,\xcb\xf8F\x04,8\xb8\x0f\x18B\xe0\xa5\x04K\xb3Y~\xf9\xfe\
\x1c\xc3(\xe1\xc6\xd7m>\xffg\x9d\x87\xf7{,\x1d\xcfsr6K\xde5\x01\x81T\x1a\xeb\
%v\xde\x9a\xc0\x9e\x94<7\xa2\xb5&e\x19\x9c\x9d\xcbo\xef\th\xee\xac\xf6xp\xb7\
\x8b\x1f\x8c\xa8\x98i\xe6\xa6\\6\xfd\x98\xf2\xc4\xb6(w\xeb\xfc[\x10x\x81\xca\
\x9e\xe6qy\xb1Dm2\x83e\x18\xdcZ\xed\xd2\xe8\x84,L\xbb\xdc\xaf\x0f\xa8\x163L\
\xe6R\x87\x0b}\xec%\x8e\xe3\x9d\xba\xd9\xcf~,\xcc\xf1\xbc\xd2\xb0\xd9\r\xb8\
\xf9\xa0\xc3\xdf\xef5Yy\xd2\xe7|-\xc7/\xae\xd4\xb8t\xac\x88\x94\xf2\xff\x99\
\x81\x83\x84L\x01\xd5R\x1a\xcb2\t\x13\xcd\xd7\x8d!\xd7\xef\xb4x\xf7D\x89ss\
\x13\x98\xc6\xee\xf9\xe1M\xd0Z\x93$\xc9\xe1\x8edZk\x94\x86r>\xc5\x85\xa3\x05\
\xde;9\x89\xd2\xb0\xb2\xd6\xe3\xee\x86\x8fa\x18\xe3\x85oM\xe0\xb5\x198\x00!P\
J\x03\x9a\xc5J\x86_\xff\xe4\x18\x00\xb7\x1ev\xf8\xd3\xcd\xa7,\xcd\xe6\xb0\
\x0e\x11\x92R\xea\xf5\x1ax\x15\xf3\x9dk\xa0\xd9O\xf8\xcb\xed\x06\x1b\xed\x80\
\x13\x95,\x1f\x9c\x9f\xc6s\xdf\x1c\xd7\xf6\x81$\xc08\xd0\xbb\xdf\x80=;\x1a0\
\x9dw\xb8rj\x92w\x16\nH\xa9h\xf9\x11\xe1H\x1e \xfb*[\x96\x94r\xe7\xe6\xb0\n\
\xd6Z\xa3\x94b\xae\x94"\x97\x12<\xde2\x08\xa2\x98 2\xb0\r\xe7\xb5}AJ\xb9]5\
\xf5z]\x03\xbb\x02\xfa\x06\x10\x80m\x1b\x18\xa6\xc9\xda3\x1f\xd71\xc9\xb9\
\xf6k\xdf\x91R\x12E\x11\xe2\x87\x7f\xc3\xef=\x81\xff\x01\x1d\xae\x83\xc3q\
\xb9\xc6\x9f\x00\x00\x00\x00IEND\xaeB`\x82'
def getDocBitmap():
return BitmapFromImage(getDocImage())
def getDocImage():
stream = cStringIO.StringIO(getDocData())
return ImageFromStream(stream)
def getDocIcon():
icon = EmptyIcon()
icon.CopyFromBitmap(getDocBitmap())
return icon
#----------------------------------------------------------------------------
# Main
#----------------------------------------------------------------------------
sys.stdout = sys.stderr
app = TextEditorApplication(redirect = False)
app.MainLoop()

View File

@ -0,0 +1,521 @@
#----------------------------------------------------------------------------
# Name: FindService.py
# Purpose: Find Service for pydocview
#
# Author: Peter Yared, Morgan Hua
#
# Created: 8/15/03
# CVS-ID: $Id$
# Copyright: (c) 2003-2004 ActiveGrid, Inc.
# License: wxWindows license
#----------------------------------------------------------------------------
import wx
import wx.lib.docview
import wx.lib.pydocview
import re
_ = wx.GetTranslation
#----------------------------------------------------------------------------
# Constants
#----------------------------------------------------------------------------
FIND_MATCHPATTERN = "FindMatchPattern"
FIND_MATCHREPLACE = "FindMatchReplace"
FIND_MATCHCASE = "FindMatchCase"
FIND_MATCHWHOLEWORD = "FindMatchWholeWordOnly"
FIND_MATCHREGEXPR = "FindMatchRegularExpr"
FIND_MATCHWRAP = "FindMatchWrap"
FIND_MATCHUPDOWN = "FindMatchUpDown"
FIND_SYNTAXERROR = -2
SPACE = 10
HALF_SPACE = 5
#----------------------------------------------------------------------------
# Classes
#----------------------------------------------------------------------------
class FindService(wx.lib.pydocview.DocService):
#----------------------------------------------------------------------------
# Constants
#----------------------------------------------------------------------------
FIND_ID = wx.NewId() # for bringing up Find dialog box
FINDONE_ID = wx.NewId() # for doing Find
FIND_PREVIOUS_ID = wx.NewId() # for doing Find Next
FIND_NEXT_ID = wx.NewId() # for doing Find Prev
REPLACE_ID = wx.NewId() # for bringing up Replace dialog box
REPLACEONE_ID = wx.NewId() # for doing a Replace
REPLACEALL_ID = wx.NewId() # for doing Replace All
GOTO_LINE_ID = wx.NewId() # for bringing up Goto dialog box
# Extending bitmasks: wx.FR_WHOLEWORD, wx.FR_MATCHCASE, and wx.FR_DOWN
FR_REGEXP = max([wx.FR_WHOLEWORD, wx.FR_MATCHCASE, wx.FR_DOWN]) << 1
FR_WRAP = FR_REGEXP << 1
def __init__(self):
self._replaceDialog = None
self._findDialog = None
self._findReplaceData = wx.FindReplaceData()
self._findReplaceData.SetFlags(wx.FR_DOWN)
def InstallControls(self, frame, menuBar = None, toolBar = None, statusBar = None, document = None):
""" Install Find Service Menu Items """
editMenu = menuBar.GetMenu(menuBar.FindMenu(_("&Edit")))
editMenu.AppendSeparator()
editMenu.Append(FindService.FIND_ID, _("&Find...\tCtrl+F"), _("Finds the specified text"))
wx.EVT_MENU(frame, FindService.FIND_ID, frame.ProcessEvent)
wx.EVT_UPDATE_UI(frame, FindService.FIND_ID, frame.ProcessUpdateUIEvent)
editMenu.Append(FindService.FIND_PREVIOUS_ID, _("Find &Previous\tShift+F3"), _("Finds the specified text"))
wx.EVT_MENU(frame, FindService.FIND_PREVIOUS_ID, frame.ProcessEvent)
wx.EVT_UPDATE_UI(frame, FindService.FIND_PREVIOUS_ID, frame.ProcessUpdateUIEvent)
editMenu.Append(FindService.FIND_NEXT_ID, _("Find &Next\tF3"), _("Finds the specified text"))
wx.EVT_MENU(frame, FindService.FIND_NEXT_ID, frame.ProcessEvent)
wx.EVT_UPDATE_UI(frame, FindService.FIND_NEXT_ID, frame.ProcessUpdateUIEvent)
editMenu.Append(FindService.REPLACE_ID, _("R&eplace...\tCtrl+H"), _("Replaces specific text with different text"))
wx.EVT_MENU(frame, FindService.REPLACE_ID, frame.ProcessEvent)
wx.EVT_UPDATE_UI(frame, FindService.REPLACE_ID, frame.ProcessUpdateUIEvent)
editMenu.Append(FindService.GOTO_LINE_ID, _("&Go to Line...\tCtrl+G"), _("Goes to a certain line in the file"))
wx.EVT_MENU(frame, FindService.GOTO_LINE_ID, frame.ProcessEvent)
wx.EVT_UPDATE_UI(frame, FindService.GOTO_LINE_ID, frame.ProcessUpdateUIEvent)
# wxBug: wxToolBar::GetToolPos doesn't exist, need it to find cut tool and then insert find in front of it.
toolBar.InsertTool(6, FindService.FIND_ID, getFindBitmap(), shortHelpString = _("Find"), longHelpString = _("Finds the specified text"))
toolBar.InsertSeparator(6)
toolBar.Realize()
frame.Bind(wx.EVT_FIND, frame.ProcessEvent)
frame.Bind(wx.EVT_FIND_NEXT, frame.ProcessEvent)
frame.Bind(wx.EVT_FIND_REPLACE, frame.ProcessEvent)
frame.Bind(wx.EVT_FIND_REPLACE_ALL, frame.ProcessEvent)
def ProcessUpdateUIEvent(self, event):
id = event.GetId()
if id == FindService.FIND_ID:
event.Enable(False)
return True
elif id == FindService.FIND_PREVIOUS_ID:
event.Enable(False)
return True
elif id == FindService.FIND_NEXT_ID:
event.Enable(False)
return True
elif id == FindService.REPLACE_ID:
event.Enable(False)
return True
elif id == FindService.GOTO_LINE_ID:
event.Enable(False)
return True
else:
return False
def ShowFindReplaceDialog(self, findString="", replace = False):
""" Display find/replace dialog box.
Parameters: findString is the default value shown in the find/replace dialog input field.
If replace is True, the replace dialog box is shown, otherwise only the find dialog box is shown.
"""
if replace:
if self._findDialog != None:
# No reason to have both find and replace dialogs up at the same time
self._findDialog.DoClose()
self._findDialog = None
self._replaceDialog = FindReplaceDialog(self.GetDocumentManager().FindSuitableParent(), -1, _("Replace"), size=(320,200), findString=findString)
self._replaceDialog.Show(True)
else:
if self._replaceDialog != None:
# No reason to have both find and replace dialogs up at the same time
self._replaceDialog.DoClose()
self._replaceDialog = None
self._findDialog = FindDialog(self.GetDocumentManager().FindSuitableParent(), -1, _("Find"), size=(320,200), findString=findString)
self._findDialog.Show(True)
def OnFindClose(self, event):
""" Cleanup handles when find/replace dialog is closed """
if self._findDialog != None:
self._findDialog = None
elif self._replaceDialog != None:
self._replaceDialog = None
def GetCurrentDialog(self):
""" return handle to either the find or replace dialog """
if self._findDialog != None:
return self._findDialog
return self._replaceDialog
def GetLineNumber(self, parent):
""" Display Goto Line Number dialog box """
line = -1
dialog = wx.TextEntryDialog(parent, _("Enter line number to go to:"), _("Go to Line"))
if dialog.ShowModal() == wx.ID_OK:
try:
line = int(dialog.GetValue())
if line > 65535:
line = 65535
except:
pass
dialog.Destroy()
# This one is ugly: wx.GetNumberFromUser("", _("Enter line number to go to:"), _("Go to Line"), 1, min = 1, max = 65535, parent = parent)
return line
def DoFind(self, findString, replaceString, text, startLoc, endLoc, down, matchCase, wholeWord, regExpr = False, replace = False, replaceAll = False, wrap = False):
""" Do the actual work of the find/replace.
Returns the tuple (count, start, end, newText).
count = number of string replacements
start = start position of found string
end = end position of found string
newText = new replaced text
"""
flags = 0
if regExpr:
pattern = findString
else:
pattern = re.escape(findString) # Treat the strings as a literal string
if not matchCase:
flags = re.IGNORECASE
if wholeWord:
pattern = r"\b%s\b" % pattern
try:
reg = re.compile(pattern, flags)
except:
# syntax error of some sort
import sys
msgTitle = wx.GetApp().GetAppName()
if not msgTitle:
msgTitle = _("Regular Expression Search")
wx.MessageBox(_("Invalid regular expression \"%s\". %s") % (pattern, sys.exc_value),
msgTitle,
wx.OK | wx.ICON_EXCLAMATION,
self.GetView())
return FIND_SYNTAXERROR, None, None, None
if replaceAll:
newText, count = reg.subn(replaceString, text)
if count == 0:
return -1, None, None, None
else:
return count, None, None, newText
start = -1
if down:
match = reg.search(text, endLoc)
if match == None:
if wrap: # try again, but this time from top of file
match = reg.search(text, 0)
if match == None:
return -1, None, None, None
else:
return -1, None, None, None
start = match.start()
end = match.end()
else:
match = reg.search(text)
if match == None:
return -1, None, None, None
found = None
i, j = match.span()
while i < startLoc and j <= startLoc:
found = match
if i == j:
j = j + 1
match = reg.search(text, j)
if match == None:
break
i, j = match.span()
if found == None:
if wrap: # try again, but this time from bottom of file
match = reg.search(text, startLoc)
if match == None:
return -1, None, None, None
found = None
i, j = match.span()
end = len(text)
while i < end and j <= end:
found = match
if i == j:
j = j + 1
match = reg.search(text, j)
if match == None:
break
i, j = match.span()
if found == None:
return -1, None, None, None
else:
return -1, None, None, None
start = found.start()
end = found.end()
if replace and start != -1:
newText, count = reg.subn(replaceString, text, 1)
return count, start, end, newText
return 0, start, end, None
def SaveFindConfig(self, findString, wholeWord, matchCase, regExpr = None, wrap = None, upDown = None, replaceString = None):
""" Save find/replace patterns and search flags to registry.
findString = search pattern
wholeWord = match whole word only
matchCase = match case
regExpr = use regular expressions in search pattern
wrap = return to top/bottom of file on search
upDown = search up or down from current cursor position
replaceString = replace string
"""
config = wx.ConfigBase_Get()
config.Write(FIND_MATCHPATTERN, findString)
config.WriteInt(FIND_MATCHCASE, matchCase)
config.WriteInt(FIND_MATCHWHOLEWORD, wholeWord)
if replaceString != None:
config.Write(FIND_MATCHREPLACE, replaceString)
if regExpr != None:
config.WriteInt(FIND_MATCHREGEXPR, regExpr)
if wrap != None:
config.WriteInt(FIND_MATCHWRAP, wrap)
if upDown != None:
config.WriteInt(FIND_MATCHUPDOWN, upDown)
def GetFindString(self):
""" Load the search pattern from registry """
return wx.ConfigBase_Get().Read(FIND_MATCHPATTERN, "")
def GetReplaceString(self):
""" Load the replace pattern from registry """
return wx.ConfigBase_Get().Read(FIND_MATCHREPLACE, "")
def GetFlags(self):
""" Load search parameters from registry """
config = wx.ConfigBase_Get()
flags = 0
if config.ReadInt(FIND_MATCHWHOLEWORD, False):
flags = flags | wx.FR_WHOLEWORD
if config.ReadInt(FIND_MATCHCASE, False):
flags = flags | wx.FR_MATCHCASE
if config.ReadInt(FIND_MATCHUPDOWN, False):
flags = flags | wx.FR_DOWN
if config.ReadInt(FIND_MATCHREGEXPR, False):
flags = flags | FindService.FR_REGEXP
if config.ReadInt(FIND_MATCHWRAP, False):
flags = flags | FindService.FR_WRAP
return flags
class FindDialog(wx.Dialog):
""" Find Dialog with regular expression matching and wrap to top/bottom of file. """
def __init__(self, parent, id, title, size, findString=None):
wx.Dialog.__init__(self, parent, id, title, size=size)
config = wx.ConfigBase_Get()
borderSizer = wx.BoxSizer(wx.VERTICAL)
gridSizer = wx.GridBagSizer(SPACE, SPACE)
lineSizer = wx.BoxSizer(wx.HORIZONTAL)
lineSizer.Add(wx.StaticText(self, -1, _("Find what:")), 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, SPACE)
if not findString:
findString = config.Read(FIND_MATCHPATTERN, "")
self._findCtrl = wx.TextCtrl(self, -1, findString, size=(200,-1))
lineSizer.Add(self._findCtrl, 0)
gridSizer.Add(lineSizer, pos=(0,0), span=(1,2))
choiceSizer = wx.BoxSizer(wx.VERTICAL)
self._wholeWordCtrl = wx.CheckBox(self, -1, _("Match whole word only"))
self._wholeWordCtrl.SetValue(config.ReadInt(FIND_MATCHWHOLEWORD, False))
self._matchCaseCtrl = wx.CheckBox(self, -1, _("Match case"))
self._matchCaseCtrl.SetValue(config.ReadInt(FIND_MATCHCASE, False))
self._regExprCtrl = wx.CheckBox(self, -1, _("Regular expression"))
self._regExprCtrl.SetValue(config.ReadInt(FIND_MATCHREGEXPR, False))
self._wrapCtrl = wx.CheckBox(self, -1, _("Wrap"))
self._wrapCtrl.SetValue(config.ReadInt(FIND_MATCHWRAP, False))
choiceSizer.Add(self._wholeWordCtrl, 0, wx.BOTTOM, SPACE)
choiceSizer.Add(self._matchCaseCtrl, 0, wx.BOTTOM, SPACE)
choiceSizer.Add(self._regExprCtrl, 0, wx.BOTTOM, SPACE)
choiceSizer.Add(self._wrapCtrl, 0)
gridSizer.Add(choiceSizer, pos=(1,0), span=(2,1))
self._radioBox = wx.RadioBox(self, -1, _("Direction"), choices = ["Up", "Down"])
self._radioBox.SetSelection(config.ReadInt(FIND_MATCHUPDOWN, 1))
gridSizer.Add(self._radioBox, pos=(1,1), span=(2,1))
buttonSizer = wx.BoxSizer(wx.VERTICAL)
findBtn = wx.Button(self, FindService.FINDONE_ID, _("Find Next"))
findBtn.SetDefault()
wx.EVT_BUTTON(self, FindService.FINDONE_ID, self.OnActionEvent)
cancelBtn = wx.Button(self, wx.ID_CANCEL, _("Cancel"))
wx.EVT_BUTTON(self, wx.ID_CANCEL, self.OnClose)
buttonSizer.Add(findBtn, 0, wx.BOTTOM, HALF_SPACE)
buttonSizer.Add(cancelBtn, 0)
gridSizer.Add(buttonSizer, pos=(0,2), span=(3,1))
borderSizer.Add(gridSizer, 0, wx.ALL, SPACE)
self.Bind(wx.EVT_CLOSE, self.OnClose)
self.SetSizer(borderSizer)
self.Fit()
self._findCtrl.SetFocus()
def SaveConfig(self):
""" Save find patterns and search flags to registry. """
findService = wx.GetApp().GetService(FindService)
if findService:
findService.SaveFindConfig(self._findCtrl.GetValue(),
self._wholeWordCtrl.IsChecked(),
self._matchCaseCtrl.IsChecked(),
self._regExprCtrl.IsChecked(),
self._wrapCtrl.IsChecked(),
self._radioBox.GetSelection(),
)
def DoClose(self):
self.SaveConfig()
self.Destroy()
def OnClose(self, event):
findService = wx.GetApp().GetService(FindService)
if findService:
findService.OnFindClose(event)
self.DoClose()
def OnActionEvent(self, event):
self.SaveConfig()
if wx.GetApp().GetDocumentManager().GetFlags() & wx.lib.docview.DOC_MDI:
if wx.GetApp().GetTopWindow().ProcessEvent(event):
return True
else:
view = wx.GetApp().GetDocumentManager().GetLastActiveView()
if view and view.ProcessEvent(event):
return True
return False
class FindReplaceDialog(FindDialog):
""" Find/Replace Dialog with regular expression matching and wrap to top/bottom of file. """
def __init__(self, parent, id, title, size, findString=None):
wx.Dialog.__init__(self, parent, id, title, size=size)
config = wx.ConfigBase_Get()
borderSizer = wx.BoxSizer(wx.VERTICAL)
gridSizer = wx.GridBagSizer(SPACE, SPACE)
gridSizer2 = wx.GridBagSizer(SPACE, SPACE)
gridSizer2.Add(wx.StaticText(self, -1, _("Find what:")), flag=wx.ALIGN_CENTER_VERTICAL, pos=(0,0))
if not findString:
findString = config.Read(FIND_MATCHPATTERN, "")
self._findCtrl = wx.TextCtrl(self, -1, findString, size=(200,-1))
gridSizer2.Add(self._findCtrl, pos=(0,1))
gridSizer2.Add(wx.StaticText(self, -1, _("Replace with:")), flag=wx.ALIGN_CENTER_VERTICAL, pos=(1,0))
self._replaceCtrl = wx.TextCtrl(self, -1, config.Read(FIND_MATCHREPLACE, ""), size=(200,-1))
gridSizer2.Add(self._replaceCtrl, pos=(1,1))
gridSizer.Add(gridSizer2, pos=(0,0), span=(1,2))
choiceSizer = wx.BoxSizer(wx.VERTICAL)
self._wholeWordCtrl = wx.CheckBox(self, -1, _("Match whole word only"))
self._wholeWordCtrl.SetValue(config.ReadInt(FIND_MATCHWHOLEWORD, False))
self._matchCaseCtrl = wx.CheckBox(self, -1, _("Match case"))
self._matchCaseCtrl.SetValue(config.ReadInt(FIND_MATCHCASE, False))
self._regExprCtrl = wx.CheckBox(self, -1, _("Regular expression"))
self._regExprCtrl.SetValue(config.ReadInt(FIND_MATCHREGEXPR, False))
self._wrapCtrl = wx.CheckBox(self, -1, _("Wrap"))
self._wrapCtrl.SetValue(config.ReadInt(FIND_MATCHWRAP, False))
choiceSizer.Add(self._wholeWordCtrl, 0, wx.BOTTOM, SPACE)
choiceSizer.Add(self._matchCaseCtrl, 0, wx.BOTTOM, SPACE)
choiceSizer.Add(self._regExprCtrl, 0, wx.BOTTOM, SPACE)
choiceSizer.Add(self._wrapCtrl, 0)
gridSizer.Add(choiceSizer, pos=(1,0), span=(2,1))
self._radioBox = wx.RadioBox(self, -1, _("Direction"), choices = ["Up", "Down"])
self._radioBox.SetSelection(config.ReadInt(FIND_MATCHUPDOWN, 1))
gridSizer.Add(self._radioBox, pos=(1,1), span=(2,1))
buttonSizer = wx.BoxSizer(wx.VERTICAL)
findBtn = wx.Button(self, FindService.FINDONE_ID, _("Find Next"))
findBtn.SetDefault()
wx.EVT_BUTTON(self, FindService.FINDONE_ID, self.OnActionEvent)
cancelBtn = wx.Button(self, wx.ID_CANCEL, _("Cancel"))
wx.EVT_BUTTON(self, wx.ID_CANCEL, self.OnClose)
replaceBtn = wx.Button(self, FindService.REPLACEONE_ID, _("Replace"))
wx.EVT_BUTTON(self, FindService.REPLACEONE_ID, self.OnActionEvent)
replaceAllBtn = wx.Button(self, FindService.REPLACEALL_ID, _("Replace All"))
wx.EVT_BUTTON(self, FindService.REPLACEALL_ID, self.OnActionEvent)
buttonSizer.Add(findBtn, 0, wx.BOTTOM, HALF_SPACE)
buttonSizer.Add(replaceBtn, 0, wx.BOTTOM, HALF_SPACE)
buttonSizer.Add(replaceAllBtn, 0, wx.BOTTOM, HALF_SPACE)
buttonSizer.Add(cancelBtn, 0)
gridSizer.Add(buttonSizer, pos=(0,2), span=(3,1))
borderSizer.Add(gridSizer, 0, wx.ALL, SPACE)
self.Bind(wx.EVT_CLOSE, self.OnClose)
self.SetSizer(borderSizer)
self.Fit()
self._findCtrl.SetFocus()
def SaveConfig(self):
""" Save find/replace patterns and search flags to registry. """
findService = wx.GetApp().GetService(FindService)
if findService:
findService.SaveFindConfig(self._findCtrl.GetValue(),
self._wholeWordCtrl.IsChecked(),
self._matchCaseCtrl.IsChecked(),
self._regExprCtrl.IsChecked(),
self._wrapCtrl.IsChecked(),
self._radioBox.GetSelection(),
self._replaceCtrl.GetValue()
)
#----------------------------------------------------------------------------
# Menu Bitmaps - generated by encode_bitmaps.py
#----------------------------------------------------------------------------
from wx import ImageFromStream, BitmapFromImage
import cStringIO
def getFindData():
return \
'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
\x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
\x00\x00\x81IDAT8\x8d\xa5S\xc1\x16\xc0\x10\x0ckk\xff\xff\xc7d\x87\xad^U\r\
\x93S\xe5U$\n\xb3$:\xc1e\x17(\x19Z\xb3$\x9e\xf1DD\xe2\x15\x01x\xea\x93\xef\
\x04\x989\xea\x1b\xf2U\xc0\xda\xb4\xeb\x11\x1f:\xd8\xb5\xff8\x93\xd4\xa9\xae\
@/S\xaaUwJ3\x85\xc0\x81\xee\xeb.q\x17C\x81\xd5XU \x1a\x93\xc6\x18\x8d\x90\
\xe8}\x89\x00\x9a&\x9b_k\x94\x0c\xdf\xd78\xf8\x0b\x99Y\xb4\x08c\x9e\xfe\xc6\
\xe3\x087\xf9\xd0D\x180\xf1#\x8e\x00\x00\x00\x00IEND\xaeB`\x82'
def getFindBitmap():
return BitmapFromImage(getFindImage())
def getFindImage():
stream = cStringIO.StringIO(getFindData())
return ImageFromStream(stream)

View File

@ -0,0 +1,551 @@
#----------------------------------------------------------------------------
# Name: TextEditor.py
# Purpose: Text Editor for pydocview
#
# Author: Peter Yared
#
# Created: 8/15/03
# CVS-ID: $Id$
# Copyright: (c) 2003-2004 ActiveGrid, Inc.
# License: wxWindows license
#----------------------------------------------------------------------------
import wx
import wx.lib.docview
import wx.lib.pydocview
import string
import FindService
_ = wx.GetTranslation
class TextDocument(wx.lib.docview.Document):
def OnSaveDocument(self, filename):
view = self.GetFirstView()
if not view.GetTextCtrl().SaveFile(filename):
return False
self.Modify(False)
self.SetDocumentSaved(True)
#if wx.Platform == "__WXMAC__":
# fn = wx.Filename(filename)
# fn.MacSetDefaultTypeAndCreator()
return True
def OnOpenDocument(self, filename):
view = self.GetFirstView()
if not view.GetTextCtrl().LoadFile(filename):
return False
self.SetFilename(filename, True)
self.Modify(False)
self.UpdateAllViews()
self._savedYet = True
return True
def IsModified(self):
view = self.GetFirstView()
if view and view.GetTextCtrl():
return wx.lib.docview.Document.IsModified(self) or view.GetTextCtrl().IsModified()
else:
return wx.lib.docview.Document.IsModified(self)
def Modify(self, mod):
view = self.GetFirstView()
wx.lib.docview.Document.Modify(self, mod)
if not mod and view and view.GetTextCtrl():
view.GetTextCtrl().DiscardEdits()
class TextView(wx.lib.docview.View):
#----------------------------------------------------------------------------
# Overridden methods
#----------------------------------------------------------------------------
def __init__(self):
wx.lib.docview.View.__init__(self)
self._textCtrl = None
self._wordWrap = wx.ConfigBase_Get().ReadInt("TextEditorWordWrap", True)
def OnCreate(self, doc, flags):
frame = wx.GetApp().CreateDocumentFrame(self, doc, flags)
sizer = wx.BoxSizer()
font, color = self._GetFontAndColorFromConfig()
self._textCtrl = self._BuildTextCtrl(frame, font, color = color)
sizer.Add(self._textCtrl, 1, wx.EXPAND, 0)
frame.SetSizer(sizer)
frame.Layout()
frame.Show(True)
self.Activate()
return True
def _BuildTextCtrl(self, parent, font, color = wx.BLACK, value = "", selection = [0, 0]):
if self._wordWrap:
wordWrapStyle = wx.TE_WORDWRAP
else:
wordWrapStyle = wx.TE_DONTWRAP
textCtrl = wx.TextCtrl(parent, -1, pos = wx.DefaultPosition, size = parent.GetClientSize(), style = wx.TE_MULTILINE | wordWrapStyle)
textCtrl.SetFont(font)
textCtrl.SetForegroundColour(color)
textCtrl.SetValue(value)
return textCtrl
def _GetFontAndColorFromConfig(self):
font = wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.NORMAL)
config = wx.ConfigBase_Get()
fontData = config.Read("TextEditorFont", "")
if fontData:
nativeFont = wx.NativeFontInfo()
nativeFont.FromString(fontData)
font.SetNativeFontInfo(nativeFont)
color = wx.BLACK
colorData = config.Read("TextEditorColor", "")
if colorData:
red = int("0x" + colorData[0:2], 16)
green = int("0x" + colorData[2:4], 16)
blue = int("0x" + colorData[4:6], 16)
color = wx.Color(red, green, blue)
return font, color
def OnCreateCommandProcessor(self):
# Don't create a command processor, it has its own
pass
def OnActivateView(self, activate, activeView, deactiveView):
if activate and self._textCtrl:
# In MDI mode just calling set focus doesn't work and in SDI mode using CallAfter causes an endless loop
if self.GetDocumentManager().GetFlags() & wx.lib.docview.DOC_SDI:
self._textCtrl.SetFocus()
else:
def SetFocusToTextCtrl():
if self._textCtrl: # Need to make sure it is there in case we are in the closeall mode of the MDI window
self._textCtrl.SetFocus()
wx.CallAfter(SetFocusToTextCtrl)
def OnUpdate(self, sender = None, hint = None):
if hint == "Word Wrap":
self.SetWordWrap(wx.ConfigBase_Get().ReadInt("TextEditorWordWrap", True))
elif hint == "Font":
font, color = self._GetFontAndColorFromConfig()
self.SetFont(font, color)
def OnClose(self, deleteWindow = True):
if not wx.lib.docview.View.OnClose(self, deleteWindow):
return False
self.Activate(False)
if deleteWindow:
self.GetFrame().Destroy()
return True
# Since ProcessEvent is not virtual, we have to trap the relevant events using this pseudo-ProcessEvent instead of EVT_MENU
def ProcessEvent(self, event):
id = event.GetId()
if id == wx.ID_UNDO:
if not self._textCtrl:
return False
self._textCtrl.Undo()
return True
elif id == wx.ID_REDO:
if not self._textCtrl:
return False
self._textCtrl.Redo()
return True
elif id == wx.ID_CUT:
if not self._textCtrl:
return False
self._textCtrl.Cut()
return True
elif id == wx.ID_COPY:
if not self._textCtrl:
return False
self._textCtrl.Copy()
return True
elif id == wx.ID_PASTE:
if not self._textCtrl:
return False
self._textCtrl.Paste()
return True
elif id == wx.ID_CLEAR:
if not self._textCtrl:
return False
self._textCtrl.Replace(self._textCtrl.GetSelection()[0], self._textCtrl.GetSelection()[1], '')
return True
elif id == wx.ID_SELECTALL:
if not self._textCtrl:
return False
self._textCtrl.SetSelection(-1, -1)
return True
elif id == TextService.CHOOSE_FONT_ID:
if not self._textCtrl:
return False
self.OnChooseFont(event)
return True
elif id == TextService.WORD_WRAP_ID:
if not self._textCtrl:
return False
self.OnWordWrap(event)
return True
elif id == FindService.FindService.FIND_ID:
self.OnFind()
return True
elif id == FindService.FindService.FIND_PREVIOUS_ID:
self.DoFind(forceFindPrevious = True)
return True
elif id == FindService.FindService.FIND_NEXT_ID:
self.DoFind(forceFindNext = True)
return True
elif id == FindService.FindService.REPLACE_ID:
self.OnFind(replace = True)
return True
elif id == FindService.FindService.FINDONE_ID:
self.DoFind()
return True
elif id == FindService.FindService.REPLACEONE_ID:
self.DoFind(replace = True)
return True
elif id == FindService.FindService.REPLACEALL_ID:
self.DoFind(replaceAll = True)
return True
elif id == FindService.FindService.GOTO_LINE_ID:
self.OnGotoLine(event)
return True
else:
return wx.lib.docview.View.ProcessEvent(self, event)
def ProcessUpdateUIEvent(self, event):
if not self._textCtrl:
return False
hasText = len(self._textCtrl.GetValue()) > 0
id = event.GetId()
if id == wx.ID_UNDO:
event.Enable(self._textCtrl.CanUndo())
return True
elif id == wx.ID_REDO:
event.Enable(self._textCtrl.CanRedo())
return True
if id == wx.ID_CUT:
event.Enable(self._textCtrl.CanCut())
return True
elif id == wx.ID_COPY:
event.Enable(self._textCtrl.CanCopy())
return True
elif id == wx.ID_PASTE:
event.Enable(self._textCtrl.CanPaste())
return True
elif id == wx.ID_CLEAR:
event.Enable(True) # wxBug: No matter what we do, the wxTextCtrl disables the Clear menu item and the menu item traps the Del key and the wxTextCtrl doesn't get it and can't delete the next character
return True
elif id == wx.ID_SELECTALL:
event.Enable(hasText)
return True
elif id == TextService.CHOOSE_FONT_ID:
event.Enable(True)
return True
elif id == TextService.WORD_WRAP_ID:
event.Enable(True)
return True
elif id == FindService.FindService.FIND_ID:
event.Enable(hasText)
return True
elif id == FindService.FindService.FIND_PREVIOUS_ID:
event.Enable(hasText and
self._FindServiceHasString() and
self._textCtrl.GetSelection()[0] > 0)
return True
elif id == FindService.FindService.FIND_NEXT_ID:
event.Enable(hasText and
self._FindServiceHasString() and
self._textCtrl.GetSelection()[0] < len(self._textCtrl.GetValue()))
return True
elif id == FindService.FindService.REPLACE_ID:
event.Enable(hasText)
return True
elif id == FindService.FindService.GOTO_LINE_ID:
event.Enable(True)
return True
else:
return wx.lib.docview.View.ProcessUpdateUIEvent(self, event)
#----------------------------------------------------------------------------
# Methods for TextDocument to call
#----------------------------------------------------------------------------
def GetTextCtrl(self):
return self._textCtrl
#----------------------------------------------------------------------------
# Format methods
#----------------------------------------------------------------------------
def OnChooseFont(self, event):
data = wx.FontData()
data.EnableEffects(True)
data.SetInitialFont(self._textCtrl.GetFont())
data.SetColour(self._textCtrl.GetForegroundColour())
fontDialog = wx.FontDialog(self.GetFrame(), data)
if fontDialog.ShowModal() == wx.ID_OK:
data = fontDialog.GetFontData()
self.SetFont(data.GetChosenFont(), data.GetColour())
fontDialog.Destroy()
def SetFont(self, font, color):
self._textCtrl.SetFont(font)
self._textCtrl.SetForegroundColour(color)
self._textCtrl.Refresh()
self._textCtrl.Layout()
def OnWordWrap(self, event):
self.SetWordWrap(not self.GetWordWrap())
def GetWordWrap(self):
return self._wordWrap
def SetWordWrap(self, wordWrap = True):
self._wordWrap = wordWrap
temp = self._textCtrl
self._textCtrl = self._BuildTextCtrl(temp.GetParent(),
font = temp.GetFont(),
color = temp.GetForegroundColour(),
value = temp.GetValue(),
selection = temp.GetSelection())
self.GetDocument().Modify(temp.IsModified())
temp.Destroy()
#----------------------------------------------------------------------------
# Find methods
#----------------------------------------------------------------------------
def OnFind(self, replace = False):
findService = wx.GetApp().GetService(FindService.FindService)
if findService:
findService.ShowFindReplaceDialog(findString = self._textCtrl.GetStringSelection(), replace = replace)
def DoFind(self, forceFindNext = False, forceFindPrevious = False, replace = False, replaceAll = False):
findService = wx.GetApp().GetService(FindService.FindService)
if not findService:
return
findString = findService.GetFindString()
if len(findString) == 0:
return -1
replaceString = findService.GetReplaceString()
flags = findService.GetFlags()
startLoc, endLoc = self._textCtrl.GetSelection()
wholeWord = flags & wx.FR_WHOLEWORD > 0
matchCase = flags & wx.FR_MATCHCASE > 0
regExp = flags & FindService.FindService.FR_REGEXP > 0
down = flags & wx.FR_DOWN > 0
wrap = flags & FindService.FindService.FR_WRAP > 0
if forceFindPrevious: # this is from function keys, not dialog box
down = False
wrap = False # user would want to know they're at the end of file
elif forceFindNext:
down = True
wrap = False # user would want to know they're at the end of file
# On replace dialog operations, user is allowed to replace the currently highlighted text to determine if it should be replaced or not.
# Typically, it is the text from a previous find operation, but we must check to see if it isn't, user may have moved the cursor or selected some other text accidentally.
# If the text is a match, then replace it.
if replace:
result, start, end, replText = findService.DoFind(findString, replaceString, self._textCtrl.GetStringSelection(), 0, 0, True, matchCase, wholeWord, regExp, replace)
if result > 0:
self._textCtrl.Replace(startLoc, endLoc, replaceString)
self.GetDocument().Modify(True)
wx.GetApp().GetTopWindow().PushStatusText(_("1 occurrence of \"%s\" replaced") % findString)
if down:
startLoc += len(replText) # advance start location past replacement string to new text
endLoc = startLoc
text = self._textCtrl.GetValue()
if wx.Platform == "__WXMSW__":
text = string.replace(text, '\n', '\r\n')
# Find the next matching text occurance or if it is a ReplaceAll, replace all occurances
# Even if the user is Replacing, we should replace here, but only select the text and let the user replace it with the next Replace operation
result, start, end, text = findService.DoFind(findString, replaceString, text, startLoc, endLoc, down, matchCase, wholeWord, regExp, False, replaceAll, wrap)
if result > 0:
self._textCtrl.SetValue(text)
self.GetDocument().Modify(True)
if result == 1:
wx.GetApp().GetTopWindow().PushStatusText(_("1 occurrence of \"%s\" replaced") % findString)
else:
wx.GetApp().GetTopWindow().PushStatusText(_("%i occurrences of \"%s\" replaced") % (result, findString))
elif result == 0:
self._textCtrl.SetSelection(start, end)
self._textCtrl.SetFocus()
wx.GetApp().GetTopWindow().PushStatusText(_("Found \"%s\"") % findString)
else:
wx.GetApp().GetTopWindow().PushStatusText(_("Can't find \"%s\"") % findString)
def _FindServiceHasString(self):
findService = wx.GetApp().GetService(FindService.FindService)
if not findService or not findService.GetFindString():
return False
return True
def OnGotoLine(self, event):
findService = wx.GetApp().GetService(FindService.FindService)
if findService:
line = findService.GetLineNumber(self.GetDocumentManager().FindSuitableParent())
if line > -1:
pos = self._textCtrl.XYToPosition(0, line - 1)
self._textCtrl.SetSelection(pos, pos)
class TextService(wx.lib.pydocview.DocService):
WORD_WRAP_ID = wx.NewId()
CHOOSE_FONT_ID = wx.NewId()
def __init__(self):
wx.lib.pydocview.DocService.__init__(self)
def InstallControls(self, frame, menuBar = None, toolBar = None, statusBar = None, document = None):
if document and document.GetDocumentTemplate().GetDocumentType() != TextDocument:
return
config = wx.ConfigBase_Get()
formatMenuIndex = menuBar.FindMenu(_("&Format"))
if formatMenuIndex > -1:
formatMenu = menuBar.GetMenu(formatMenuIndex)
else:
formatMenu = wx.Menu()
formatMenu = wx.Menu()
if not menuBar.FindItemById(TextService.WORD_WRAP_ID):
formatMenu.AppendCheckItem(TextService.WORD_WRAP_ID, _("Word Wrap"), _("Wraps text horizontally when checked"))
formatMenu.Check(TextService.WORD_WRAP_ID, config.ReadInt("TextEditorWordWrap", True))
wx.EVT_MENU(frame, TextService.WORD_WRAP_ID, frame.ProcessEvent)
wx.EVT_UPDATE_UI(frame, TextService.WORD_WRAP_ID, frame.ProcessUpdateUIEvent)
if not menuBar.FindItemById(TextService.CHOOSE_FONT_ID):
formatMenu.Append(TextService.CHOOSE_FONT_ID, _("Font..."), _("Sets the font to use"))
wx.EVT_MENU(frame, TextService.CHOOSE_FONT_ID, frame.ProcessEvent)
wx.EVT_UPDATE_UI(frame, TextService.CHOOSE_FONT_ID, frame.ProcessUpdateUIEvent)
if formatMenuIndex == -1:
viewMenuIndex = menuBar.FindMenu(_("&View"))
menuBar.Insert(viewMenuIndex + 1, formatMenu, _("&Format"))
def ProcessUpdateUIEvent(self, event):
id = event.GetId()
if id == TextService.CHOOSE_FONT_ID:
event.Enable(False)
return True
elif id == TextService.WORD_WRAP_ID:
event.Enable(False)
return True
else:
return False
class TextOptionsPanel(wx.Panel):
def __init__(self, parent, id):
wx.Panel.__init__(self, parent, id)
SPACE = 10
HALF_SPACE = 5
config = wx.ConfigBase_Get()
self._textFont = wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.NORMAL)
fontData = config.Read("TextEditorFont", "")
if fontData:
nativeFont = wx.NativeFontInfo()
nativeFont.FromString(fontData)
self._textFont.SetNativeFontInfo(nativeFont)
self._originalTextFont = self._textFont
self._textColor = wx.BLACK
colorData = config.Read("TextEditorColor", "")
if colorData:
red = int("0x" + colorData[0:2], 16)
green = int("0x" + colorData[2:4], 16)
blue = int("0x" + colorData[4:6], 16)
self._textColor = wx.Color(red, green, blue)
self._originalTextColor = self._textColor
parent.AddPage(self, _("Text"))
fontLabel = wx.StaticText(self, -1, _("Font:"))
self._sampleTextCtrl = wx.TextCtrl(self, -1, "", size = (125, -1))
self._sampleTextCtrl.SetEditable(False)
chooseFontButton = wx.Button(self, -1, _("Choose Font..."))
wx.EVT_BUTTON(self, chooseFontButton.GetId(), self.OnChooseFont)
self._wordWrapCheckBox = wx.CheckBox(self, -1, _("Wrap words inside text area"))
self._wordWrapCheckBox.SetValue(wx.ConfigBase_Get().ReadInt("TextEditorWordWrap", True))
textPanelBorderSizer = wx.BoxSizer(wx.VERTICAL)
textPanelSizer = wx.BoxSizer(wx.VERTICAL)
textFontSizer = wx.BoxSizer(wx.HORIZONTAL)
textFontSizer.Add(fontLabel, 0, wx.ALIGN_LEFT | wx.RIGHT | wx.TOP, HALF_SPACE)
textFontSizer.Add(self._sampleTextCtrl, 0, wx.ALIGN_LEFT | wx.EXPAND | wx.RIGHT, HALF_SPACE)
textFontSizer.Add(chooseFontButton, 0, wx.ALIGN_RIGHT | wx.LEFT, HALF_SPACE)
textPanelSizer.Add(textFontSizer, 0, wx.ALL, HALF_SPACE)
textPanelSizer.Add(self._wordWrapCheckBox, 0, wx.ALL, HALF_SPACE)
textPanelBorderSizer.Add(textPanelSizer, 0, wx.ALL, SPACE)
self.SetSizer(textPanelBorderSizer)
self.UpdateSampleFont()
def UpdateSampleFont(self):
nativeFont = wx.NativeFontInfo()
nativeFont.FromString(self._textFont.GetNativeFontInfoDesc())
font = wx.NullFont
font.SetNativeFontInfo(nativeFont)
font.SetPointSize(self._sampleTextCtrl.GetFont().GetPointSize()) # Use the standard point size
self._sampleTextCtrl.SetFont(font)
self._sampleTextCtrl.SetForegroundColour(self._textColor)
self._sampleTextCtrl.SetValue(_("%d pt. %s") % (self._textFont.GetPointSize(), self._textFont.GetFaceName()))
self._sampleTextCtrl.Refresh()
self.Layout()
def OnChooseFont(self, event):
data = wx.FontData()
data.EnableEffects(True)
data.SetInitialFont(self._textFont)
data.SetColour(self._textColor)
fontDialog = wx.FontDialog(self, data)
if fontDialog.ShowModal() == wx.ID_OK:
data = fontDialog.GetFontData()
self._textFont = data.GetChosenFont()
self._textColor = data.GetColour()
self.UpdateSampleFont()
fontDialog.Destroy()
def OnOK(self, optionsDialog):
config = wx.ConfigBase_Get()
doWordWrapUpdate = config.ReadInt("TextEditorWordWrap", True) != self._wordWrapCheckBox.GetValue()
config.WriteInt("TextEditorWordWrap", self._wordWrapCheckBox.GetValue())
doFontUpdate = self._originalTextFont != self._textFont or self._originalTextColor != self._textColor
config.Write("TextEditorFont", self._textFont.GetNativeFontInfoDesc())
config.Write("TextEditorColor", "%02x%02x%02x" % (self._textColor.Red(), self._textColor.Green(), self._textColor.Blue()))
if doWordWrapUpdate or doFontUpdate:
for document in optionsDialog.GetDocManager().GetDocuments():
if document.GetDocumentTemplate().GetDocumentType() == TextDocument:
if doWordWrapUpdate:
document.UpdateAllViews(hint = "Word Wrap")
if doFontUpdate:
document.UpdateAllViews(hint = "Font")

View File

@ -0,0 +1,3 @@
Tips for PyDocViewDemo App
wxWindows rules!
Use the source, Luke!

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

3033
wxPython/wx/lib/docview.py Normal file

File diff suppressed because it is too large Load Diff

2455
wxPython/wx/lib/pydocview.py Normal file

File diff suppressed because it is too large Load Diff