Sylvain Wallez wrote:
Marc Portier wrote:
<snip />
Well, if you fail to explain to yourself, I understand why we sometimes don't understand your posts ;-D
doh! care to explain this joke to us? ;-)
but I have to admit I mostly need other people around to develop own ideas, makes me a perfect guy for OSS in fact: the ideas are never really only *my* ideas, so I 'm very rarely struggling with idea-ownership, rather the contrary: struggling with idea-lonelyness ;-)
care to textualize some preview on what goes about before we see the code?
Yep. Here it is.
At first, I wanted to add event listeners to widgets (i.e. the _instances_), but that did not work, primarily because a repeater dynamically creates widget instances and secondly because it requires listeners to be painfully defined programmatically each time a form is instanciated (in an action or flowscript).
So event listeners are defined in the form definition. I currently have defined a ValueChangedEvent for data-aware widgets (field, booleanfield, aggregatefield) and ActionEvent for actions. We also need a RepeaterEvent.
Two implementations of EventListenerBuilder exist : one that creates a Java class (classical EventListener) and one that wraps a JavaScript snippet. Just as in DHTML, that snippet has some predefined variable : this (the widget) and event. If called within a flowscript, it also has access to the precious "cocoon" object. I still have to see how to create a "cocoon" object if used out of the flowscript context.
The definition therefore looks like this : <wd:field id="foo"> ... <wd:on-change> <wd:java class="com.my.Listener"/>
hm, this makes these listeners totally stateless, no?
what I mean:
- probably woody is going to instantiate them with a Class.forname() and newInstance() sequence, correct?
- as such they have no initial state other then some defaults (no-argument-constructor)
- consequence: they don't have pointers into our use-case controllers (be it flowscript or apples) like is the case with swing and the usage of anonymous inner classes. Point being: it is going to be hard to callback into your business logic with these events, no?
as a way out I see the following approaches:
1/ keep like above:
so the eventListener doesn't have direct access to the use-case controller, but at least it has access to the Woody Form model, right?
so it could change state-information in the model (userData area or hidden widgets) and as such it becomes available to the use-case-controller since it has a point to the form and can expect it.
What I dislike about this is that the active-event-trigger becomes a passive data element waiting to be read.
2/ have the form-model declare named event-dispatchers which behave like a sort of event-queue-channels
<wd:event-dispatcher type="value-changed" name="foo_changed" />
<wd:field id="foo"> ... <wd:on-change> <wd:java event-dispatcher="foo_changed"/>
and add methods on the form model so the use case controller can register it's own instances to receive events from these named event-queue-channels:
form.registerValueChangedListener( "foo_changed", new ValueChangedListener(){
public void valueChanged(ValueChangedEvent evt){ Widget source = evt.getSource(); Object newValue = evt.getNewValue(); ... EnclosingClass.this.whatEverStateVariable = ...; } });
we avoid the 'dynamic widget instance' problem you mentioned above
and we can easily have eventListeners that can callback into our use case controllers...
obviously from my text I like 2/ the most, since it could also be incrementally added to your current stuff?
what do you think?
<wd:javascript>
var list = this.parent.getWidget("thelist");
list.selectionList = Packages.com.my.App.getSelectionForTheList(this.value);
</wd:javascript>
</wd:on-change>
</wd:field>
Similarily, there's an <on-activate> on <action> widgets.
would probably have chosen on-valueChange and on-action, but that's a matter of taste probably
I reused the JSF patterns for event handling : events are buffered until the current processing phase is finished and fired afterwards, to ensure the widget tree is in a consistent state.
sounds like you already have something like event-dispatchers in place?
I still have to define also the ability for the form to be submitted when a widget's value changes. Considering the car selector example, this would allow to refresh the model list as soon as the maker is changed withouth having to push the "select maker" button.
you mean having a client-side javascript thingy to do a submit-on-change?
I saw Bruno tinkering on something like this, IIRC it was triggering an action (since we didn't have value-changed events)
only downside of it is that you have to add a no-value option to the list which is selected by default in order to trigger the change:
the list then shows the text (select one from the list) otherwise you can't trigger the generation of the select-maker if e.g. the option you want to make is the default selected one :-)
I'm thinking of adding a new "submit-on-change" attribute on <wi:styling>, but I'm wondering if this belongs to the view or to the form definition. Seems better on the view.
yep, that's what Bruno did, if you like, I can check how he did it.
also this links back to another wild idea I'm having
I'm still not quite satisfied with the way the repeater-binding (the not simple one) needs to operate for detecting new/deleted/syill-existing rows in the repeater...
So I hope the way you handle valuechanged can give some inspiration on how to mark the changed state of repeater rows?
Aha ! I was also thinking of an event-driven binding, but kept this wild idea for now : the binding would register itself on the repeater and "collect" modifications.
yep, it is different to what I was thinking but it might serve as an alternative.
what I meant is that the control itself would be remembering what happened to the rows in between two calls to some method that sets a 'resetRowModificationInfo()' which would then be called to set some revision-point between which the control would be remembering some metadata on each of the rows.
of course this borrows from the current way binding is used: once at the start (load) and once at the end (save) of the use case.
looking at how this often maps to talking to a (persistency) backend system I'm not really tempted into changing this usage pattern for now
of course if we agree that stacking up these changes are not part of the concern of the widget itseld, then we will need a listener of some kind to do it for us... still have to think about how the Binding could then get a hold of those results.
BTW: I assume that the ValueChangedEvent is holding both the old and new value?
Of course !
yep, but what I really meant is that I was assuming that the widget was remembering both old and new states (which I realize now it is probably not)
allow event listeners to be written both in Java (classic-style) and in JavaScript (flowscript-style).
Makes sense.
I guess reusing the awt eventhandling interfaces is out of the question?
Using AWTEvent doesn't really makes sense, but the new FormEvent class extends java.util.EventObject, and the listeners extend java.util.EventListener. However, I used the convenient AWTEventMulticaster as the base class for a FormEventMulticaster.
Not that I would consider it as a breaking design point to start using it, but yesterday someone showed me usage of jbeaver (see at http://www.ratundtat.com/index01.htm?menue=40, it's not oss but it didn't look entirely impossible to create something similar.) and I couldn't help dreaming about a common GUI description language that could result into both Swing and Woody based apps...
And SWT... Some of my current wild thoughts is to use Woody and flowscript to build Eclipse plugins. Imagine every component coming with its own Woody form and associated flowscript and binding : building a Cocoon IDE for Eclipse can become quite easy.
yep, but what I meant was this: in order to be able to swap from the one to the other it would be really nice to also be able to re-use the use-case controllers and their accompanying eventListeners...
of course if we go for this event-dispatcher idea that would still hold, no?
From that angle: being able to share your event-controllers might make sense (although wrapping them inside specific listener interfaces should not be that hard)
Sorry, don't understand: what are "event-controllers" ?
sorry here, I started mixing use-case controller (i.e flow-script or apple) and the eventListener... as shown above they often go hand in hand:
some eventListeners only affect the view itself, but some of them really have to callback into the state of the use-case.
<snip />
-marc= -- Marc Portier http://outerthought.org/ Outerthought - Open Source, Java & XML Competence Support Center Read my weblog at http://radio.weblogs.com/0116284/ [EMAIL PROTECTED] [EMAIL PROTECTED]