CVS: /nondist/sandbox/other/jonathan README,NONE,1.1 anygui.dtd,NONE,1.1 anygui_xml.py,NONE,1.1 fooo,NONE,1.1 sample.py,NONE,1.1 sample.xml,NONE,1.1
Magnus Lie Hetland <[email protected]> Wed, 11 Sep 2002 08:56:52 -0700
| Newsgroups | gmane.comp.python.anygui.cvs |
|---|---|
| Message-ID | <[email protected]> |
Update of /cvsroot/anygui//nondist/sandbox/other/jonathan
In directory usw-pr-cvs1:/tmp/cvs-serv6567/other/jonathan
Added Files:
README anygui.dtd anygui_xml.py fooo sample.py sample.xml
Log Message:
--- NEW FILE: README ---
Basic XML support prototype by Jonathan Claggett.
Email describing the code (2002-09-11):
Hello Magnus,
About a month ago, I volunterred to work on a Glade-like xml reader for
anygui. Well, I've completed a working first pass at the concept and
would like to run it by you (and the rest of the Anygui developers). I
have to say that XML is quite nifty once you've wrapped your head around
it.
At this point, I've got:
- an XML DTD which tries to mimic anygui's API,
- a SAX handler which reads the aforementioned XML files, creating
anygui components along the way and
- some chessy sample code which I've been using for testing.
I haven't tested the canvas component or the menu components since the
version of anygui that I installed didn't know about those components.
However, the rest of the components seem to be working.
I've attached the above files to this e-mail for your review (The
attachments are why I haven't sent this out to the anygui maling list as
a whole). Please feel free forward the code, check it in, or do whatever
else you want to do with it. The sample code is run by putting all these
files in a directory and running: python sample.py.
Enjoy,
Jonathan
--- NEW FILE: anygui.dtd ---
<!ENTITY % menu_components "menu | menucommand | menucheck | menuseparator">
<!ENTITY % components "
button | canvas | checkbox | frame | label | listbox | radiogroup |
textarea | textfield">
<!ENTITY % core_attributes "id ID #REQUIRED">
<!ENTITY % core_visible_attributes "
%core_attributes;
x CDATA #IMPLIED
y CDATA #IMPLIED
width CDATA #IMPLIED
height CDATA #IMPLIED
geometry CDATA #IMPLIED
hmove (true|false) #IMPLIED
vmove (true|false) #IMPLIED
hstretch (true|false) #IMPLIED
vstretch (true|false) #IMPLIED
visible (true|false) #IMPLIED
enabled (true|false) #IMPLIED">
<!ELEMENT anygui ((application | window)*, link*)>
<!ELEMENT link EMPTY>
<!ATTLIST link
source IDREF #IMPLIED
handler CDATA #REQUIRED
event CDATA #IMPLIED
weak (true|false) #IMPLIED
loop (true|false) #IMPLIED>
<!ELEMENT application (window*)>
<!ATTLIST application %core_attributes;>
<!ELEMENT button (#PCDATA)>
<!ATTLIST button %core_visible_attributes;>
<!ELEMENT canvas (#PCDATA)>
<!ATTLIST canvas %core_visible_attributes;>
<!ELEMENT checkbox (#PCDATA)>
<!ATTLIST checkbox %core_visible_attributes;
on (true|false) #IMPLIED>
<!ELEMENT frame ( ( %components; )* )>
<!ATTLIST frame %core_visible_attributes;>
<!ELEMENT label (#PCDATA)>
<!ATTLIST label %core_visible_attributes;>
<!ELEMENT listbox (listitem*)>
<!ATTLIST listbox %core_visible_attributes;
selection CDATA #IMPLIED>
<!ELEMENT listitem (#PCDATA)>
<!ATTLIST listitem
selection CDATA #IMPLIED>
<!ELEMENT menubar ( (%menu_components;)* )>
<!ATTLIST menubar %core_attributes;
contents CDATA #IMPLIED
enabled (true|false) #IMPLIED>
<!ELEMENT menu ( (%menu_components;)* )>
<!ATTLIST menu %core_attributes;
contents CDATA #IMPLIED
enabled (true|false) #IMPLIED>
<!ELEMENT menucheck (#PCDATA)>
<!ATTLIST menucheck %core_attributes;
enabled (true|false) #IMPLIED>
<!ELEMENT menucommand (#PCDATA)>
<!ATTLIST menucommand %core_attributes;
enabled (true|false) #IMPLIED>
<!ELEMENT menuseparator (#PCDATA)>
<!ATTLIST menuseparator %core_attributes;
enabled (true|false) #IMPLIED>
<!ELEMENT radiobutton (#PCDATA)>
<!ATTLIST radiobutton %core_visible_attributes;
value CDATA #REQUIRED
on (true|false) #IMPLIED>
<!ELEMENT radiogroup (radiobutton*)>
<!ATTLIST radiogroup %core_attributes;>
<!ELEMENT textarea (#PCDATA)>
<!ATTLIST textarea %core_visible_attributes;
editable (true|false) #IMPLIED
selection CDATA #IMPLIED>
<!ELEMENT textfield (#PCDATA)>
<!ATTLIST textfield %core_visible_attributes;
editable (true|false) #IMPLIED
selection CDATA #IMPLIED>
<!ELEMENT window ( (menubar | %components;)* )>
<!ATTLIST window %core_visible_attributes;
title CDATA #IMPLIED>
--- NEW FILE: anygui_xml.py ---
from anygui import *
from xml.sax import saxlib, saxexts
# Anygui XML parser - used to build GUI's from xml files.
#
# The XML parser works through a SAX handler class and a supporting cast of XML
# tag handler classes. The SAX handler passes incoming tags and their
# attributes off to an appropriate XML tag handler. Here is the current class
# heirarchy for the XML tag handlers:
#
# + BaseTag: A trivial tag handler which remembers the parent tag.
# + AttrTag: Adds attribute parsing functionality.
# - LinkTag: handler responsible for <link> tags.
# + ComponentTag: Adds component creation functionality.
# - ${COMPONENT}Tag: $COMPONENT stands for various anygui components.
class BaseTag(object):
def __init__(self, parent, components, event_handlers):
self.parent = parent
self.components = components
self.event_handlers = event_handlers
self.component = None
def start(self, name, attr):
pass
def char(self, text, start, length):
pass
def end(self, name):
return self.parent
class AttrTag(BaseTag):
def start(self, name, attr):
self.options = {}
self.define_attr_filters() # self.attr_filters is defined here
# Convert attributes into options
for key,value in attr.items():
if self.attr_filters.has_key(key):
filter = self.attr_filters[key]
self.options[key.encode()] = filter(value)
else:
print 'Warning: Unknown option: %s (value = %s)' % (key, value)
# These functions are used to convert xml attribute values into
# standard anygui option values.
def filter_string(self, str): return str
def filter_eval(self, str): return eval(str)
def filter_eval_list(self, str): return eval('[' + str + ']')
def filter_boolean(self, str): return str == 'true'
def define_attr_filters(self):
self.attr_filters = {}
class ComponentTag(AttrTag):
def start(self, name, attr):
AttrTag.start(self, name, attr)
id = self.options['id']
del self.options['id']
self.create_component() # self.component is defined here
self.components[id] = self.component
self.add_component()
# I was lazy and defined all possible component attributes at once. As a
# result, these attributes do not apply to all components. Since the DTD
# knows which attributes belong to which component, this isn't really
# shouldn't be too much of an issue.
def define_attr_filters(self):
self.attr_filters = {
'id': self.filter_string,
'x': self.filter_eval,
'y': self.filter_eval,
'width': self.filter_eval,
'height': self.filter_eval,
'geometry': self.filter_eval_list,
'hmove': self.filter_boolean,
'vmove': self.filter_boolean,
'hstretch': self.filter_boolean,
'vstretch': self.filter_boolean,
'visible': self.filter_boolean,
'enabled': self.filter_boolean,
'value': self.filter_eval,
'on': self.filter_boolean,
'items': self.filter_eval_list,
'selection': self.filter_eval,
'contents': self.filter_eval_list,
'editable': self.filter_boolean,
'title': self.filter_string,
}
def add_component(self):
if self.parent.component != None:
self.parent.component.add(self.component)
def create_component(self):
pass # other classes must redfine this method!
def char(self, text, start, length):
self.component.set(text = text[start:start+length].strip())
class ApplicationTag(ComponentTag):
def create_component(self):
self.component = Application(**self.options)
class ButtonTag(ComponentTag):
def create_component(self):
self.component = Button(**self.options)
class CanvasTag(ComponentTag):
def create_component(self):
self.component = Canvas(**self.options)
class CheckBoxTag(ComponentTag):
def create_component(self):
self.component = CheckBox(**self.options)
class FrameTag(ComponentTag):
def create_component(self):
self.component = Frame(**self.options)
class LabelTag(ComponentTag):
def create_component(self):
self.component = Label(**self.options)
class LinkTag(AttrTag):
def start(self, name, attr):
AttrTag.start(self, name, attr)
if self.options.has_key('source'):
source = self.components[self.options['source']]
else:
source = 'any'
if self.options.has_key('event'):
event = self.options['event']
else:
event = 'default'
if self.options.has_key('weak'):
weak = self.options['weak']
else:
weak = 0
if self.options.has_key('loop'):
weak = self.options['loop']
else:
loop = 0
if self.event_handlers.has_key(self.options['handler']):
handler = self.event_handlers[self.options['handler']]
link(source, event, handler, weak=weak, loop=loop)
def define_attr_filters(self):
self.attr_filters = {
'source': self.filter_string,
'handler': self.filter_string,
'event': self.filter_string,
'weak': self.filter_boolean,
'loop': self.filter_boolean,
}
class ListBoxTag(ComponentTag):
def create_component(self):
self.component = ListBox(**self.options)
self.items = []
self.selection = self.options.get('selection', -1)
def end(self, name):
self.component.items = self.items
self.component.selection = self.selection
return ComponentTag.end(self, name)
class ListItemTag(BaseTag):
def char(self, text, start, length):
self.parent.items.append(text[start:start+length].strip())
class MenuTag(ComponentTag):
def create_component(self):
self.component = Menu(**self.options)
class MenuBarTag(ComponentTag):
def create_component(self):
self.component = MenuBar(**self.options)
class MenuCheckTag(ComponentTag):
def create_component(self):
self.component = MenuCheck(**self.options)
class MenuCommandTag(ComponentTag):
def create_component(self):
self.component = MenuCommand(**self.options)
class MenuSeparatorTag(ComponentTag):
def create_component(self):
self.component = MenuSeparator(**self.options)
class RadioButtonTag(ComponentTag):
def add_component(self):
ComponentTag.add_component(self)
# Add radio buttons to their grandparents too.
if self.parent.parent.component != None:
self.parent.parent.component.add(self.component)
def create_component(self):
self.component = RadioButton(**self.options)
class RadioGroupTag(ComponentTag):
def add_component(self):
pass # don't add radio groups to the component heirarchy.
def create_component(self):
self.component = RadioGroup(**self.options)
class TextAreaTag(ComponentTag):
def create_component(self):
self.component = TextArea(**self.options)
class TextFieldTag(ComponentTag):
def create_component(self):
self.component = TextField(**self.options)
class WindowTag(ComponentTag):
def create_component(self):
self.component = Window(**self.options)
class AnyguiHandler(saxlib.HandlerBase):
"""SAX Handler for anygui xml files"""
def __init__(self, event_handlers):
self.components = {}
self.tag = None
# map the XML tag handler classes to XML tags.
self.tag_classes = {
'anygui': BaseTag,
'application': ApplicationTag,
'button': ButtonTag,
'canvas': CanvasTag,
'checkbox': CheckBoxTag,
'frame': FrameTag,
'label': LabelTag,
'listbox': ListBoxTag,
'listitem': ListItemTag,
'link': LinkTag,
'menu': MenuTag,
'menubar': MenuBarTag,
'menucheck': MenuCheckTag,
'menucommand': MenuCommandTag,
'menuseparator': MenuSeparatorTag,
'radiogroup': RadioGroupTag,
'radiobutton': RadioButtonTag,
'textarea': TextAreaTag,
'textfield': TextFieldTag,
'window': WindowTag,
}
# build a dictionary out of the passed in event handlers using their
# function names as the key.
self.event_handlers = {}
for func in event_handlers:
self.event_handlers[func.func_name] = func
def startElement(self, name, attr):
if self.tag_classes.has_key(name):
tag_class = self.tag_classes[name]
else:
print 'Warning: Unknown Tag: %s' % (name)
tag_class = BaseTag
self.tag = tag_class(self.tag, self.components, self.event_handlers)
self.tag.start(name, attr)
def endElement(self, name):
self.tag = self.tag.end(name)
def characters(self, text, start, length):
self.tag.char(text, start, length)
# load an anygui XML file returning a dictionary of created components
def load(file_name, event_handlers=[]):
handler = AnyguiHandler(event_handlers)
parser = saxexts.XMLValParserFactory.make_parser()
parser.setDocumentHandler(handler)
file = open(file_name, 'r')
parser.parseFile(file)
file.close()
return handler.components
--- NEW FILE: fooo ---
Hello Magnus,
About a month ago, I volunterred to work on a Glade-like xml reader for
anygui. Well, I've completed a working first pass at the concept and
would like to run it by you (and the rest of the Anygui developers). I
have to say that XML is quite nifty once you've wrapped your head around
it.
At this point, I've got:
- an XML DTD which tries to mimic anygui's API,
- a SAX handler which reads the aforementioned XML files, creating
anygui components along the way and
- some chessy sample code which I've been using for testing.
I haven't tested the canvas component or the menu components since the
version of anygui that I installed didn't know about those components.
However, the rest of the components seem to be working.
I've attached the above files to this e-mail for your review (The
attachments are why I haven't sent this out to the anygui maling list as
a whole). Please feel free forward the code, check it in, or do whatever
else you want to do with it. The sample code is run by putting all these
files in a directory and running: python sample.py.
Enjoy,
Jonathan
--- NEW FILE: sample.py ---
import anygui_xml as gui
def on_button(event):
print 'button was pressed!'
components = gui.load('sample.xml', event_handlers=[on_button])
components['app1'].run()
--- NEW FILE: sample.xml ---
<?xml version = "1.0"?>
<!DOCTYPE anygui SYSTEM "anygui.dtd">
<anygui>
<application id="app1">
<window title="demo window (this is dynamic)" id="window1">
<button id="button1" x="20" y="70">
Click me
</button>
<label id="label2">
junk goes here
</label>
<button id="button2" geometry="120,70,100,30">
Don't click me!
</button>
<checkbox id="checkbox1" x="120" y="100" width="200" on="true">
Checking this does nothing...
</checkbox>
<radiogroup id="radiogroup1">
<radiobutton id="rbutton1" value="1" x="10" y="150">
selection 1
</radiobutton>
<radiobutton id="rbutton2" value="2" x="10" y="170" on="true">
selection 2
</radiobutton>
<radiobutton id="rbutton3" value="3" geometry="10,190,200,15" >
Last selection
</radiobutton>
</radiogroup>
</window>
<window title="a second window" id="window2" x="40" y="40">
<textfield id="textfield1">Remove this text</textfield>
<frame id="frame1" geometry="30,30,300,230">
<textarea id="textarea1" width="200" height="100">
To be or not to be. That is the question.
- Hamlet
</textarea>
</frame>
</window>
<window id="window3" title="testing list boxes" x="80" y="80">
<listbox id="listbox1" selection="1" geometry="10,10,200,40">
<listitem>Text goes here</listitem>
<listitem>blah, blah, blah</listitem>
<listitem>yuck, blah, bllpp</listitem>
</listbox>
</window>
</application>
<link source="button1" handler="on_button" weak="true"/>
</anygui>
-------------------------------------------------------
In remembrance
www.osdn.com/911/