#!/usr/bin/env python
#
# $Id: redemo2.py,v 1.3 2001/11/03 11:05:22 doughellmann Exp $
#
# Copyright 2001 Doug Hellmann.
#
#
# All Rights Reserved
#
# Permission to use, copy, modify, and distribute this software and
# its documentation for any purpose and without fee is hereby
# granted, provided that the above copyright notice appear in all
# copies and that both that copyright notice and this permission
# notice appear in supporting documentation, and that the name of Doug
# Hellmann not be used in advertising or publicity pertaining to
# distribution of the software without specific, written prior
# permission.
#
# DOUG HELLMANN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
# NO EVENT SHALL DOUG HELLMANN BE LIABLE FOR ANY SPECIAL, INDIRECT OR
# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
# OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
"""Extension of Guido's regular expression demonstration utility.
This app is based on the 'Demos/tkinger/guido/redemo.py' module provided
as part of the Python 1.5.2 source distribution.
"""
__rcs_info__ = {
#
# Creation Information
#
'module_name' : '$RCSfile: redemo2.py,v $',
'rcs_id' : '$Id: redemo2.py,v 1.3 2001/11/03 11:05:22 doughellmann Exp $',
'creator' : 'Doug Hellmann <doug@hellfly.net>',
'project' : 'PmwContribD',
'created' : 'Tue, 20-Mar-2001 17:02:34 EST',
#
# Current Information
#
'author' : '$Author: doughellmann $',
'version' : '$Revision: 1.3 $',
'date' : '$Date: 2001/11/03 11:05:22 $',
}
#
# Import system modules
#
from Tkinter import *
import tkFileDialog, tkMessageBox
import re
import Pmw
import time
#
# Import Local modules
#
from GuiAppD import GuiAppD
#
# Module
#
class PmwReDemo(GuiAppD):
"""Extension of Guido's regular expression demonstration utility.
This sample application illustrates how to use the GuiAppD class
to construct a basic GUI application.
*This app is based on the 'Demos/tkinger/guido/redemo.py' module
provided as part of the Python 1.5.2 source distribution.*
"""
appname = 'Pmw Regular Expression Demo'
appversion = '0.2'
AUTOSCAN = 'auto'
TIME_THRESHOLD = 5.0
def appInit(self):
"Initialize the application, before the GUI is built."
GuiAppD.appInit(self)
return
def createMenuBar(self):
"""Create the menu bar for the application.
In this case, add an *Open...* button to the file menu.
"""
self.addMenuItem('File',
'command',
'Load text sample to scan',
label='Open...',
command=self.importTextSample,
acceleratorKey='o',
)
GuiAppD.createMenuBar(self)
return
def importTextSample(self, *ignore):
"Import a text file as the string to be searched."
filename = tkFileDialog.askopenfilename(
filetypes=[('Text files', '*.txt'),
('StructuredText files', '*.stx'),
('Python Source files', '*.py'),
('C Source files', '*.c'),
('All files', '*'),
],
)
if filename:
#body = open(filename, 'rt').read()
text = self.component('stringdisplay')
text.settext('')
text.importfile(filename)
self.reevaluate()
else:
pass
return
def createInterface(self):
"""Create the UI for the application.
The main window is already created, so all widgets are
parented by 'self.interior()'.
"""
self.promptdisplay = self.createcomponent(
'instructions', (), None,
Label,
(self.interior(),),
text='Enter a Python re module-style regular expression'
)
self.promptdisplay.pack(side=TOP, fill=X)
self.autoscan = StringVar(self.interior())
self.autoscan.set(self.AUTOSCAN)
self.regexdisplay = self.createcomponent(
'regexdisplay', (), None,
Pmw.EntryField,
(self.interior(),),
labelpos='w',
label_pyclass=Checkbutton,
label_text='Auto-scan',
label_offvalue=0,
label_onvalue='auto',
label_variable=self.autoscan,
label_command=self.recompile,
modifiedcommand=self.recompile,
)
self.bind(self.component('regexdisplay_label'),
'Automatically run search when inputs are changed.')
self.regexdisplay.pack(fill=X)
self.regexdisplay.focus_set()
self.statusdisplay = self.createcomponent(
'statusdisplay', (), None,
Label,
(self.interior(),),
text="",
anchor=W,
)
self.statusdisplay.pack(side=TOP, fill=X)
self.addoptionbuttons()
self.showframe = Frame(self.interior())
self.showframe.pack(fill=X, anchor=W)
self.showvar = StringVar(self.interior())
self.showvar.set("first")
self.showfirstradio = self.createcomponent(
'showfirstradio', (), None,
Radiobutton,
(self.showframe,),
text="Highlight first match",
variable=self.showvar,
value="first",
command=self.recompile,
)
self.bind(self.showfirstradio, 'Show only the first match for the expression.')
self.showfirstradio.pack(side=LEFT)
self.showallradio = self.createcomponent(
'showallradio', (), None,
Radiobutton,
(self.showframe,),
text="Highlight all matches",
variable=self.showvar,
value="all",
command=self.recompile,
)
self.bind(self.showallradio, 'Show all matches for the expression.')
self.showallradio.pack(side=LEFT)
self.stringdisplay = self.createcomponent(
'stringdisplay', (), None,
Pmw.ScrolledText,
(self.interior(),),
text_width=80,
text_height=15,
labelpos='n',
label_text="\nEnter a string to search:",
)
self.stringdisplay.pack(fill=BOTH, expand=1)
self.stringdisplay.tag_configure("hit", background="yellow")
self.grouplist = self.createcomponent(
'grouplist', (), None,
Pmw.ScrolledListBox,
(self.interior(),),
labelpos='nw',
label_text='Group(s):',
)
self.bind(self.grouplist, 'Show the contents of groups defined in expression.')
self.grouplist.pack(expand=1, fill=BOTH)
self.regexdisplay.bind('<Key>', self.recompile)
self.stringdisplay.bind('<Key>', self.reevaluate)
self.compiled = None
self.recompile()
btags = self.regexdisplay.bindtags()
self.regexdisplay.bindtags(btags[1:] + btags[:1])
btags = self.stringdisplay.bindtags()
self.stringdisplay.bindtags(btags[1:] + btags[:1])
return
def addoptionbuttons(self):
"""Create the option buttons for controlling regex match behavior.
This function is the same as the original except for minor
mods to accomodate being part of a Pmw-based app instead of a
straight Tk app.
"""
self.frames = []
self.boxes = []
self.vars = []
frame = Frame(self.interior())
frame.pack(fill=X)
for name, descrip in (
('IGNORECASE', 'Scan without paying attention to upper or lower case'),
('LOCALE', 'Do not know what this is'),
('MULTILINE', 'Allow expressions to match across lines'),
('DOTALL', 'Include line-breaks as characters matched by dot.'),
('VERBOSE', 'Verbose input mode for expression'),
):
val = getattr(re, name)
var = IntVar()
box = Checkbutton(frame,
variable=var,
text=name,
offvalue=0,
onvalue=val,
command=self.recompile)
self.bind(box, descrip, descrip)
box.pack(side=LEFT)
self.boxes.append(box)
self.vars.append(var)
return
def getflags(self):
"Returns bit-field with flag settings."
flags = 0
for var in self.vars:
flags = flags | var.get()
flags = flags
return flags
def recompile(self, event=None):
"Recompile the regex."
regular_expression = self.regexdisplay.get()
if not regular_expression:
return
try:
self.compiled = re.compile(regular_expression,
self.getflags())
bg = self.promptdisplay['background']
self.statusdisplay.config(text="", background=bg)
except re.error, msg:
self.compiled = None
self.statusdisplay.config(
text="re.error: %s" % str(msg),
background="red")
if self.autoscan.get() == self.AUTOSCAN:
self.reevaluate()
return
def reevaluate(self, event=None):
"Re-evalutate the regex match against the buffer."
try:
self.stringdisplay.tag_remove("hit", "1.0", END)
except TclError:
pass
try:
self.stringdisplay.tag_remove("hit0", "1.0", END)
except TclError:
pass
self.grouplist.delete(0, END)
if not self.compiled:
return
self.stringdisplay.tag_configure("hit", background="yellow",
relief=RAISED, borderwidth=1)
self.stringdisplay.tag_configure("hit0", background="orange",
relief=RAISED, borderwidth=1)
text = self.stringdisplay.get("1.0", END)
last = 0
nmatches = 0
self.updateProgress(0, len(text))
starttime = time.time()
extended_run_check = 'Have not asked'
while last <= len(text):
self.updateProgress(last)
m = self.compiled.search(text, last)
if m is None:
break
first, last = m.span()
if last == first:
last = first+1
tag = "hit0"
else:
tag = "hit"
pfirst = "1.0 + %d chars" % first
plast = "1.0 + %d chars" % last
self.stringdisplay.tag_add(tag, pfirst, plast)
if nmatches == 0:
self.stringdisplay.yview_pickplace(pfirst)
groups = list(m.groups())
groups.insert(0, m.group())
groups.insert(0, 'MATCHED:%d - %d' % (first, last))
for i in range(len(groups)):
g = "%2d: %s" % (i, `groups[i]`)
self.grouplist.insert(END, g)
nmatches = nmatches + 1
if self.showvar.get() == "first":
break
endtime = time.time()
elapsedtime = (endtime - starttime)
#
# Short circuit the time consumption test because the
# user previously told us to finish.
#
if extended_run_check == 'Finish scanning':
continue
if elapsedtime > self.TIME_THRESHOLD:
dialog = Pmw.MessageDialog(
self.interior(),
title='Slow Expression Warning',
defaultbutton=0,
buttons=('One more', 'Finish scanning', 'Cancel'),
message_text='This expression seems to be taking a considerable time to run.\nContinue?',
)
dialog.iconname('Slow Expression Warning')
extended_run_check = dialog.activate()
#
# Break out because the user said not to continue
#
if extended_run_check == 'Cancel':
break
if nmatches == 0:
self.statusdisplay.config(text="(no match)",
background="yellow")
else:
self.statusdisplay.config(text="")
self.updateProgress(0,0)
return
# Main function, run when invoked as a stand-alone Python program.
def main():
"Run the application."
PmwReDemo().run()
return
if __name__ == '__main__':
main()
|