[XSL-LIST Mailing List Archive Home] [By Thread] [By Date]

Re: [xsl] On Sourceforge: Cool: Saxon driving a GUI, interactive XSLT


Subject: Re: [xsl] On Sourceforge: Cool: Saxon driving a GUI, interactive XSLT
From: Gunther Schadow <gunther@xxxxxxxxxxxxxxxxxxxxxx>
Date: Fri, 19 Nov 2004 15:14:31 -0500

M. David Peterson wrote:
> There are several posts I need to follow-up on but this post
> caught my eye in particular as it seems that your project and a
> combination of projects that various members of the Saxon.NET team are
> working may have a lot in common.  

David, thanks for your note. Do you have a list of the other projects?
I went into the XSL list archives, and couldn't find anything from 
subject line keyword search (GUI, Swing, SWT). But I haven't followed
too closely for a while. Always happy to chat and peek into other 
preople's ideas and code.

If you browse the CVS today, you won't find this GUI stuff yet, 
because Sourceforge hasn't updated its CVSweb snapshot yet.

Here are some quick explanations about the approach. You can
define a simple SWT GUI like this:

<display>
  <shell>
    <gridLayout numColumns="2"/>
    <label>Tell me:</label>
    <text id="data"><gridData grabExcessHorizontalSpace="true"/>more</text>
    <button>OK<handle event="selection"/></button>
    <button>CANCEL<handle event="selection"/></button>
    <pack/>
    <open/>
  </shell>
</display>

When you run the swt.xsl transform on this, up pops the following
window: 

+---------------------------------+
|                        [_][-][x]|
+---------------------------------+
| Tell me: [more________________] |
|                                 |
| [OK]     [CANCEL]               |
+---------------------------------+
          
You can click the OK button and the transformer is called back 
with a snippet such as:

<event name="org.eclipse.swt.events.SelectionEvent" target="button"/>

which you can catch by templates such as this:

<xsl:template mode="event" 
     match="event[@name='org.eclipse.swt.events.SelectionEvent' 
              and @target='button']" 
     xmlns:event="java:org.eclipse.swt.events.SelectionEvent"
     xmlns:button="java:org.eclipse.swt.widgets.Button"
     xmlns:textbox="java:org.eclipse.swt.widgets.Text">

<!-- the event Java object -->
  <xsl:param name="event" select="/.."/> 
 
<!-- the button element in the GUI document above -->
  <xsl:param name="current" select="/.."/> 

<!-- fetch the Java button object -->
  <xsl:param name="object" select="fn:get-object-by-element($current)"/>

<!-- do something with all of that -->
  <buttonPressed 
      buttonObjectText="button:getText($object)" 
      buttonElementText="$current/text()"
      textboxObjectText="textbox:getText(fn:get-object-by-id('data'))"
      textboxElementText="$current/ancestor::*//*[@id='data']/text()"/>
</xsl:template>

Now assume we do the following actions after the GUI has started:

1.) change the text in the text box to "Hello Saxon!"

2.) click the O.K. button

then, when the GUI stops (e.g., by closing the SWT Shell window), 
you get the following output:

<display gid="1ef3">
  <shell gid="1e30">
    <gridLayout gid="201a" numColumns="2"/>
    <label gid="203b">Tell me:</label>
    <text gid="2145" id="data"><gridData gid="2138" grabExcessHorizontalSpace="true"/>more</text>
    <button gid="2345">OK<handle event="selection"/></button>
    <button gid="234b">CANCEL<handle event="selection"/></button>
  </shell>
</display>
<buttonPressed 
   buttonObjectText="OK" 
   buttonElementText="OK"
   textboxObjectText="Hello Saxon!"
   textboxElementText="more"/>

As you can see, in the event handler you have access to the event
object as well as to the node of the original GUI document that
had created the GUI object that fired the event. 

You can get to any GUI objects through the hash-map that stores 
the object under the key generate-id() of the node that
created the object and optionally also under the @id key that 
you can specify on any such element.

In the event handlers, you can do pretty much anything. Including
traversing the GUI objects and creating an XML dump of them reflecting
their possibly changed state. Of course, sensible patterns would 
have to be developed as to how one should handle events. This is 
subject to further discovery. One could do monolithic XSLT 
everything, or one could do MVC style and call some Java model
objects. Of course, one could register Java event handlers such
that those events don't cause <event> nodes to be transformed.

The transform that creates all these GUI elements from the input
is itself generated from a file that defines the GUI framework 
and Java object to use. That way, adaption to SWT or Swing or 
whatever else is quite simple. Here is an example of the definition
of the SWT elements that I used in the example above:

<framework ...>

<element name="shell" class="org.eclipse.swt.widgets.Shell">
  <constructor method="wa:makeShell"/>
  <action name="pack" method="pack"/>
  <action name="open" method="open"/>
</element>

<element name="label" class="org.eclipse.swt.widgets.Label">
  <constructor args="swt:NONE()"/>
  <property name="text()" method="setText"/>
</element>

<element name="text" class="org.eclipse.swt.widgets.Text">
  <constructor args="swt:NONE()"/>
  <property name="text()" method="setText"/>
</element>

<element name="button" class="org.eclipse.swt.widgets.Button">
  <constructor args="swt:NONE()"/>
  <property name="text()" method="setText"/>
</element>

<element name="gridLayout" class="org.eclipse.swt.layout.GridLayout">
  <constructor args="" xmlns:composite="java:org.eclipse.swt.widgets.Composite">
    <xsl:sequence select="composite:setLayout($parent,$object)"/>
  </constructor>
  <property name="@numColumns" setter="setInt" field="numColumns"/>
  <property name="@makeColumnsEqualWidth" setter="setBoolean" field="makeColumnsEqualWidth"/>
</element>

<element name="gridData" class="org.eclipse.swt.layout.GridData">
  <constructor  args="" xmlns:control="java:org.eclipse.swt.widgets.Control">
    <xsl:sequence select="control:setLayoutData($parent,$object)"/>
  </constructor>
  <property name="@grabExcessHorizontalSpace" setter="setBoolean" field="grabExcessHorizontalSpace"/>
  <property name="@grabExcessVerticalSpace" setter="setBoolean" field="grabExcessVerticalSpace"/>
  <property name="@horizontalSpan" setter="setInt" field="horizontalSpan"/>
  <property name="@verticalSpan" setter="setInt" field="verticalSpan"/>
  <xsl:variable name="gridDataAlignmentCodes" xmlns:data="java:org.eclipse.swt.layout.GridData">
    <code code="beginning" value="{data:BEGINNING()}"/>
    <code code="end" value="{data:END()}"/>
    <code code="center" value="{data:CENTER()}"/>
    <code code="fill" value="{data:FILL()}"/>
  </xsl:variable>
  <property name="@verticalAlignment" setter="setInt" field="verticalAlignment" map="gridDataAlignmentCodes"/>
  <property name="@horizontalAlignment" setter="setInt" field="horizontalAlignment" map="gridDataAlignmentCodes"/>
</element>

<event name="selection">
  <listener name="org.eclipse.swt.events.SelectionListener" register="addSelectionListener">
    <method name="widgetSelected"/>
  </listener>
</event>

</framework>

Hope this has helped some of the questions you might have.

thanks,
-Gunther




-- 
Gunther Schadow, M.D., Ph.D.                  gschadow@xxxxxxxxxxxxxxx
Associate Professor           Indiana University School of Informatics
Regenstrief Institute, Inc.      Indiana University School of Medicine
tel:1(317)630-7960                       http://aurora.regenstrief.org


Current Thread
Keywords