Skip to main content

Using Comparators to define Event notification order?

58 replies [Last post]
leouser
Offline
Joined: 2005-12-12

Hello,

Im pondering bug: 4178930 Swing models need pre- and post-listeners

And am considering attacking it not from the point of adding pre and post listeners, but allowing the user to define the order in which events are delivered to the various listeners. One way that Im considering is allowing the user to set a Comparator for a specific class of EventListeners. This Comparator would be fed back to the EventListenerList in the particular JComponent and when notification time came it would use that Comparator to define the order.

From the users perspective it would probably be a call like so:
aJComponent.setNotificationOrder(AEventListenerClass.class, tehComparator);

From that users perspective this seems ok. If the user needs to define a simple pre and post listener ordering, he should be able to do this. Or if there is an ordering that isn't as simple as pre-doit-post order he can also do it. A danger would be if he messes with any necessary ordering that Swing is requiring.

Implementing this internally would require somewhere around 42 classes to be worked on. The monkeywrench is this idiom:
listenerList.getListenerList()

which returns the internal array of listeners, and notification is based off of that array. Most likely every case would need to do something different if it had a Comparator for the listener class.

thoughts folks?
BH

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
alexfromsun
Offline
Joined: 2005-09-05

Hello Brian

You know, I still like tagging interface solution,
actually it "tackline" who pointed it at the first page of this thread.

We already have UIResource iterface and tag some resousrces with it to divide LaF dependant resources them from user's ones

So the point is tagging our inner listeners with special interface, it would be easy to tag compound listeners like
AbstractButton.Handler

Actually users are not expected to use that interface for their listeners, just like they usually don't tag Color of Font objects with UIResource interface

This technique is simple, open for third-party components and don't add new addXXXListener() methods

Thanks
alexp

leouser
Offline
Joined: 2005-12-12

Its bad in that if you have the UIInternal interface defined your now stuck with just this order:
SWING POST

If your going to go the route of defining a tagging interface for people to use you might as well give them the flexibility of the EnumOrdering interface. Except instead of a number do it like this:
public EnumOrdering{

public Order getOrder

}

I just fail to see how you can get around changing the ordering by default and enforce it while maintaining backwards compatibility. Its introducing a level of rigidness into a mechanism that is flexible.

BH

alexfromsun
Offline
Joined: 2005-09-05

Hello Brian

Yes, my idea is to divide component's internal listener's from user's ones.

Why should we invent more complicated and painful way with no clear reasons ?

All bugs we discussed seems to were not an issue if component's internal listeners always run before users ones.

I din't get your point about compatibility, now the listeners ordering is unspecified, and it's just wrong to think another way about that, and I really doubt that Swing programmers somehow rely on listeners ordering

If we garanteed to run Swing listeners before user's ones,
we would change spec in backward compatible way

alexp

leouser
Offline
Joined: 2005-12-12

My point is that non-swing listeners run today as PRE listeners. We don't see bug reports for PRE problems because they are already getting that as the behavior today. So in other words, because the conditions are right the reports aren't produced.

I know its not speced, but once you change the default behavior of PRE listeners to POST, the listeners that are functioning because they are running as PRE listeners are going to break.

BH

alexfromsun
Offline
Joined: 2005-09-05

Hello Brian

It looks like we are talking just about our impressions
This issue is quite serious and we need to thoroughly investigate reasons to support implementing that RFE,
and possible solution (with code samples etc.)

It is difficult to decide which solution is preferabble and even can (or should) we fix it or not

alexp

leouser
Offline
Joined: 2005-12-12

An intriguing design within Swing to look at is how the JTree deals with notification of Expansion. It appears to deal with this issue with two interfaces:
TreeWillExpandListener --> deals with PRE
TreeExpansionListener --> deals with POST

Im not sure when the TreeWillExpandListener was added, maybe baked in the cake from the start. But it is illustrative of the fact that there was a need in this case for the user to be able to partition things before and after an Expansion. If there were PRE and POST orderings at the time of designing it, its possible that the TreeWillExpandListener interface could have been eliminated. Though of course the categories would have to map to:
PRE --> before anything really has taken effect
REGULAR --> when things take effect
POST --> after things have taken effect

BH

leouser
Offline
Joined: 2005-12-12

Here is another one of these post-ordering bugs that isn't linked to the main one:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4498762

I actually think I have ran into this bug. I have a JTree which exhibits jumpiness, maybe it is because of this ordering bug.

anyway another one to look at,
BH

leouser
Offline
Joined: 2005-12-12

Here is a report:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4335413

where a mechanism stopped working precisely because the test listeners stopped being notified before the Swing listeners. A change appears to cause the Swing listeners to be notified first, causing the effects of the test listeners not to work anymore.

BH

leouser
Offline
Joined: 2005-12-12

This appears to be another Ordering bug that could use the Marker interface to get the behavior and also a PRE event ordering:

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4130345

BH

leouser
Offline
Joined: 2005-12-12

Here is another report, where the user needs PRE behavior:

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4461719

This appears to caused by the same fix that created the other PRE bug report.

BH

leouser
Offline
Joined: 2005-12-12

Now, Ive taken a complaint about what appears to be event ordering and the JTabbedPane:
http://forums.java.net/jive/thread.jspa?threadID=16393&tstart=0

and created a simulated problem based off the complaint:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.event.*;

public class JTabbedPaneTest implements ChangeListener, Runnable{

int index;
JTabbedPane jtp;
static boolean swap;
boolean cancel;
public void run(){
jtp = new JTabbedPane();
if(swap){
ChangeListener[] cl = jtp.getChangeListeners();
for(ChangeListener cls: cl){
System.out.println(cls);
jtp.removeChangeListener(cls);
}
jtp.addChangeListener(this);
for(ChangeListener cls: cl){
jtp.addChangeListener(cls);
}
}
else jtp.addChangeListener(this);
for(int i = 0; i < 10; i ++){
JPanel jp = new JPanel();
jp.add(new JLabel(String.valueOf(i)));
jtp.add(String.valueOf(i), jp);
}
JFrame jf = new JFrame();
jf.add(jtp);
jf.setSize(300,300);
jf.setVisible(true);
}

public static void main(String ... args){
if(args.length > 0) swap = true;
SwingUtilities.invokeLater(new JTabbedPaneTest());
}

public void stateChanged(ChangeEvent e){
if(jtp.getSelectedIndex() != index){
final JDialog jd = new JDialog();
JPanel jp = new JPanel();
JButton dismiss = new JButton("Close");
jp.add(dismiss);
dismiss.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
jd.setVisible(false);
}
});
JButton cancelb = new JButton("Cancel");
cancelb.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
cancel = true;
jd.setVisible(false);
}
});
jp.add(cancelb);
jd.add(jp);
jd.setModal(true);
jd.setSize(200,200);
jd.show();
if(cancel){
cancel = false;
jtp.setSelectedIndex(index);
}
index = jtp.getSelectedIndex();
}
}

}
---------
In it when a tab is switched the user is prompted if they want to switch or not. This works just fine when running it like so:
java JTabbedPaneTest

but if you run it like this:
java JTabbedPaneTest 0
the UI listeners are swapped so with the application ChangeListener so they run first. This introduces the problem where the swapped to tab is switched to before the user has a chance to confirm that a swap is wanted. Im not sure what the user would do in this case if the Swing listeners always came first, no matter what. Using invokeLater does not solve the problem, the user needs PRE behavior if they want to block the change.

BH

leouser
Offline
Joined: 2005-12-12

theoretically the user should be able to create a special SingleSelectionModel that pops up the Dialog before making any changes or maybe even overriding setSelectedIndex to do the Dialog work. Those are other options, but it doesn't help out that existing code would suddenly act very differently.

BH

leouser
Offline
Joined: 2005-12-12

Intriguingly the problem the user is experiencing doesn't appear to have anything to do with the ordering of the event listeners but because some UI work that was being done after the users listeners had fired is being done before hand.

Arguably, the fix may not be necessary if there were pre and post listeners. I believe its there so the user can focus a widget in a new page within a ChangeListener. If PRE-POST listener were in place the solution for different folks would be:
PRE--> let the ChangeListener decide if the new tab should be selected.
REGULAR--> UIS do their magic, the tab is flipped to.
POST--> Users who want to focus widgets in the newly selected tab can do so since the tab has been selected and the Component is now visible.

BH

coxcu
Offline
Joined: 2003-06-11

Splitting listeners into internal and external isn't enough, because what is internal and external depends on your point of view. Imagine an application built with in-house components using a third-party library built on SwingX. Which listeners are internal and which are external?

alexfromsun
Offline
Joined: 2005-09-05

Hello coxcu

It's nice to see you here !

"Internal" listeners update component's state and appearance
when "external" once are used to build application logic

e.g. Swing adds a bunch of listeners to a button and they are mixed with user's ones so, user's code might see a component in unstable state

I imagince this mechanism is non-private,
so third-party component would be able to mark their listeners as "internal" as well

for example with help of a new marker interface

any comments are welcome !

alexp

leouser
Offline
Joined: 2005-12-12

I don't know if you want to make the marker open to the public. You fall into the trap again of the user not being able to instantly see what order something is going on. If its public what's the maintainablity difference between this and the EventOrdering interface?
You still fall into this unclear situation:
MyListener listener = new MyListener();///implements Internal interface, but we don't know it ... this comment doesn't exist
swingThing.addXListener(listener);

the maintainer finds himself wondering why can't he get the listener in this case to happen after another listener of his. Only latter by inspecting the source of MyListener does it become clear that it implements the Internal interface.

So to recap, if you make the marking mechanism open to the public why would it be better than the other public mechanism we've discused so far? Im not seeing the difference between it and the EventOrdering interace idea, except that the EventOrdering interface is a little more flexible in what you can do with it.

BH

alexfromsun
Offline
Joined: 2005-09-05

Hello Brian

You are right, that might be confusing as well...

But it wouldn't possible to make this mechanism private,
becaue it'll restrict third party components

Mmmm.... so, where is the best solution, I wonder ?

alexp

leouser
Offline
Joined: 2005-12-12

Well the clearest and probably the best in backward compatibility has been your Enum idea:
addXListener(listener, Enum);

drawbacks:
1. expensive in terms of the API. It adds more methods but the user may not care in that they will be very similiar to the existing methods. If altering the existing methods so that they took varargs:
addXListener(listener, Enum ... enums)
was backward compatible, then this might have lowered the API cost. But I don't believe that it is.

2. doesn't address the Ordering within an Ordering problem, but it might be addressable if needed.

---------------
Comparators and EventOrdering solutions seem equally unclear. EventOrdering though is cheaper(in API cost) than the Comparator solution, but it doesn't solve the Ordering within the Ordering problem. The Comparator does though, but it it appears harder to use than the EventOrdering interface. To use it right you have to understand what is being sorted. From my prototypes it is possible to mix the two and escape the Ordering within the Ordering problem, but it still does not solve the lack of clarity problem.

BH

alexfromsun
Offline
Joined: 2005-09-05

Hello Brian

I consulted with a guy who maintains JavaBeans and we agreed that it would be a good idea to implement pre and post listeners as part of JavaBeans specification
(it just a very early thoughts and we are going to investigate this variant)

Current idea is to be able to add complementary

addXXXListener(XXXListener l, enum e)
removeXXXListener(XXXListener l, enum e)

functionality to the current add/remove methods
where enum has three values - pre, post and one more value which stands for the current collection of listeners
I think pre and post listneners will really be enough

With help of pre listeners you'll be able to be notfied that value is about to be changed and can use veto
Post listeners will be notified when a component in a valid state and all paint related work has been done

JavaBeans decoder/encoder would be able to detect if a property supports pre or post listeners and process it correctly

This way pre and post listeners will be supplementary and we wouldn't have to add them for each listener

This solution is clear and compatible

What do you think ?

The main questing is - is it a Swing who only need pre and post listeners or e.g. Java EE guys need it as well ?

Thanks
alexp

leouser
Offline
Joined: 2005-12-12

If you do it at the JavaBean level, it will create a convention for everyone to follow. But its unclear to me how you can get away from not adding things like:
addSelectionModelListener(SelectionModelListener listener, anEnum anenum)

to the Swing classes to get the effect were after. There may be a convention to follow but that doesn't automatically create a mechanism to use.

BH

alexfromsun
Offline
Joined: 2005-09-05

Hello Brian

> If you do it at the JavaBean level, it will create a
> convention for everyone to follow. But its unclear
> to me how you can get away from not adding things
> like:
> addSelectionModelListener(SelectionModelListener
> listener, anEnum anenum)

My idea is to come to agreement about the convention first,after that we'll be able to add such listeners using that convention

> to the Swing classes to get the effect were after.
> There may be a convention to follow but that doesn't
> t automatically create a mechanism to use.

That's correct, we need to find a good API solution first and add new functionality where we need it

What is your opinion about that ?

Thanks
alexp

> BH

leouser
Offline
Joined: 2005-12-12

That sounds excellent. :)

BH

alexfromsun
Offline
Joined: 2005-09-05

Hello Brian

I've thought about pre and post listeners a bit more,
and must say that I don't see any visible advantages they would bring to us.

Let me explain: two bugs which are related to this issue are fixed and I didn't find any issues which can't be fixed without implementing such listeners.

Making listeners to get notified in fixed order doesn't seem
to be what users really need and it will bring unnesessary complication to our API

in the same time dividing listeners to three collection won't help as well, because someone might ask how to order them in each collections

The key point is we don't have enough use cases where we really need something like pre and post listeners.

It might make sense to specify and implement that Swing listeners are always invoked before user's ones,
but again we need strong reasons to do that

Your comments are very welcome

alexp

leouser
Offline
Joined: 2005-12-12

you may have a point there, there is always a workaround by invoking things later. But at the same time its a reoccuring problem. I think that Ive come across 2(which I can't find at this moment) bugs that were not tied to the pre-post bug but were actually manifestations of the bug. Its an unknown how many are still lodged in the database under names that don't immediately make a link back to the bug:
"JTable doesn't update its * when * changes"
Not having a solution of some sort will mean that these types of bugs reports will continue to creap into the database. A users immediate reaction when struck by this type of problem is that there is something wrong with the widget.

The problem with specifying that Swing listener are always notifed before other listeners is that its a change in default behavior. The people who are relying upon the "PRE" aspects currently may be in for a shock if suddenly they become "POST".

The cheapest way of doing this thing and the simplest may be a combination of your idea and Scott's:
interface EventOrdering{
public OrderEnum getOrdering();
}

Just have the client implement the interface and make no changes to the external API. I think that this would be very easy to understand. If a listener does not implement this just have it use "NORMAL" ordering, then it can keep its defaults and not break things.

As to solving the Ordering with the Order problem... well all I can say is if it became an issue or a driving need for the solution then you'd need to provide an override into the process. Probably do it with something cheap like I have outlined with the Comparator approach:
setNotificationOrder(Class listener, OrderEnum, Comparator);
but Id only do that if its really seen as something needed. Im still not sold on the fact that the XAXA scenario is going to happen.

I will say this, from writing plugins for Leo which has pre and post event notification hooks:
"before-something"
"after-something"
its a very nice feature to have. You don't have to sit around and wonder if something that you want to happen is going to happen at the right time... it just is right.

BH

alexfromsun
Offline
Joined: 2005-09-05

Hello Brian

Thank you for your comments

Adding new API is a serious action and we should do it if we have a good reasons only,
I'll probably write a blog and ask the community for more examples where it might help

By the way, fixing the order of user's listeners does look like a bad design for me,
it will lead to a confusing and hard to maintain code with no visible advantages

I would be happy to see strong examples against that

Thanks
alexp

leouser
Offline
Joined: 2005-12-12

That would be most useful to hear. :)

BH

leouser
Offline
Joined: 2005-12-12

You probably are right if you rely upon an EventOrdering interface, it will make things a little obscurer for a maintainer.

Say if you have this code:

TableModelListener tml = new MyListener(); //implements EventOrdering, but its not obvious that it does... in fact this comment doesn't exit
model.addTableModelListener(tml);

now, a new reader looking at this may think, ok the listener is going to the start of the notification list. But due to the fact that it implements EventOrdering and he doesn't know it, his assumption is wrong. He has to go back to the class and see that it does implement EventOrdering to understand where its going to end up.

With this code though, the reader shouldn't be confused or mislead or whatever:
TableModelListener tml = new MyListener();
model.addTableModelListener(tml, OrderEnum.POST);

he can just see from the line that its going to be notified at the end of the notification sequence. There shouldn't be any faulty assumptions.

BH

alexfromsun
Offline
Joined: 2005-09-05

>With this code though, the reader shouldn't be confused or mislead or whatever:
>TableModelListener tml = new MyListener();
>model.addTableModelListener(tml, OrderEnum.POST);

That's right, this code is easier to read
but it doesn't seem to fix the problem

This approach will help only temporary, what if someone wants to specify the order for all OrderEnum.POST listeners ?

Something like pre_post and post_post ?

And I'd like to say again, that I don't see any what real problems we are tring to solve

alexp

leouser
Offline
Joined: 2005-12-12

In terms of real problems, it will help users with problems like this:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4675786

which was closed because its a manifestation of 4178930. Yes the user could just use invokeLater but why should the user have to implement a Runnable to do the work they want to do in the listener?

We can also argue that it may still not be obvious to the user that they need to put their event in the POST notification to get a fresh size. They may still have the perception that something just isn't working in the JList.

BH

alexfromsun
Offline
Joined: 2005-09-05

> In terms of real problems, it will help users with problems like this:
>http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4675786

Will it be fixed if we garantee that Swing listeners to always run before users ones ?

alexp

leouser
Offline
Joined: 2005-12-12

That one I think will be fixed. Also check this fresh bug out:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6427865

It may well be a manifestation of the pre-post problem. By running the example, all I have to do is hit Enter at the end of the text and the "Last character throws exception!"
message is printed out.

But, if I remove all the listeners add the users listener and then re-add all the old ones, it doesn't appear to happen. I haven't proven that it is the order that is the problem yet, but it sure has that smell. It illustrates my point that the pre-post problem is out there masquerading as other bugs.

We have to be careful about specifying that Swing listeners happen before the others. There is at least one bug I think where the UI is switched and the users listeners which were relying on the fact that they were first suddenly become broken. Im going to try to find that so Im clear that this was the problem.

BH

leouser
Offline
Joined: 2005-12-12

Ok my one listener needs to be notified first bug report is this:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4871932

and my memory was flawed, its POST order thats needed here.

BH

alexfromsun
Offline
Joined: 2005-09-05

So, again if we guarantee that Swing listeners
are run before users ones this bug would be fixed

Correct ?

alexp

leouser
Offline
Joined: 2005-12-12

hmmm, this one is a listener that is introduced in Swing but in the AWT. But this does not mean that we can't guarantee its order for the Swing widgets. So in other words, if we extend the guarantee to those yes.

It does seem that the predominant strain of bugs is POST problems. But we need to ask, is this because of how the chips fall today--> is it not normal for the POST bugs to be reported because its a need that isn't filled? What if we flip the ordering as you have suggested, will the inverse suddenly become true? Will there be a stream of PRE bugs coming in now?

BH

alexfromsun
Offline
Joined: 2005-09-05

Hello Brian

When I say Swing listeners, I mean AWT ones too,
acutally I mean all "internal" listeners

I believe that running Swing listeners before users ones,
is a good solution because

- No need to add new methods
- It fixes bugs we discussed
- It is logically correct: we change the component's state,
and it is safe to run user's listeners after intenal once,
i.e. when component is in the consistent state

Since this solition works and easy to implement,
I tend to think that it is the most prefferable way out

Thought ?

alexp

leouser
Offline
Joined: 2005-12-12

Im going to have to think about this one for awhile, Im still pondering if suddenly if any of the listeners that get PRE for free now are going to break.

Of the solutions so far it definately appears the simplest and cheapest in terms of API cost. I don't know if specing it so that its official behavior is good idea at this point, it would lock us in. Leaving it in the "undefined" area leaves us room to manuevour if we have to. That doesn't mean not applying the fix, but doing it quietly.

BH

alexfromsun
Offline
Joined: 2005-09-05

Hello Brian

I consulted with a guy who maintains JavaBeans and we agreed that it would be a good idea to implement pre and post listeners as part of JavaBeans specification
(it just a very early thoughts and we are going to investigate this variant)

Current idea is to be able to add complementary

addXXXListener(XXXListener l, enum e)
removeXXXListener(XXXListener l, enum e)

functionality to the current add/remove methods
where enum has three values - pre, post and one more value which stands for the current collection of listeners
I think pre and post listneners will really be enough

With help of pre listeners you'll be able to be notfied that value is about to be changed and can use veto
Post listeners will be notified when a component in a valid state and all paint related work has been done

JavaBeans decoder/encoder would be able to detect if a property supports pre or post listeners and process it correctly

This way pre and post listeners will be supplementary and we wouldn't have to add them for each listener

The main questing is - is it a Swing who only need pre and post listeners or e.g. Java EE guys need it as well ?

Thanks
alexp

This solution

alexfromsun
Offline
Joined: 2005-09-05

> well, when I started thinking about this I stayed
> away from it because of the expensive nature of it.
> For every addXXX you have to have another method.

That's correct
But probably it would be a reasonable price for the ease of use

>
> When you say collections, Im assuming you mean:
> PreNotificationList
> NormalNotificationList
> PostNotificationList
>

Exactly

..skipped

>
> Maybe it wouldn't be that expensive, if the method
> addition could be watered down to a set of methods:
> addOrderedListener(Class listener, Object listener,
> Enum order);
> removeOrderedListener(Class listener, Object
> listener, Enum order);

This API is definitely shorter but it looks different from existing addXXXListener() methods

let's put it off for a bit

alexp

Scott Violet

I've never seen a situation where you dynamically need to change the
event order. Swing's listeners would have no need to do it, and I can't
imagine a scenario where code I've written would need to. If this really
came up, you could always remove and add the listener back. We shouldn't
design the API around an unusual test case that doesn't seem realistic.

-Scott

swing@javadesktop.org wrote:
> yes, that's one question that Ive had as Ive gone along, how will the user differentiate between the ones they want to move around. A problem I see with the interface is that it becomes hard to change the order.
>
> If a listener is always returning an EventOrder of 1, will that 1 fit in all situations? If the user doesn't have the option of altering the returned value, how can they change the ordering? The user should be able to change how orderings are done.
>
> One idea that I have is to do a mix of the Comparator/EventOrdering interface:
> 1. Have a default Comparator set on the classes that respects the users EventOrdering getEventOrder value
> 2. Allow the user to override the Ordering mechanism, through setting a Comparator on the value.
>
> This way there is an option to create their own ordering mechanism.
>
> One thing Ive thought about is doing the ordering on the array returned by the getListenerList, but I dislike this because it erases the add order history.
>
> Ive got an intial set of diffs of classes that Ive done some work on their event notification ordering(which Ill see if I can get up in Collab land). Im going define a Comparator that tries the EventOrdering interface idea out. Given that Ive seen the orderings work fine so far, I don't question that EventOrdering will work. :)
>
> BH
> [Message sent by forum member 'leouser' (leouser)]
>
> http://forums.java.net/jive/thread.jspa?messageID=124016

leouser
Offline
Joined: 2005-12-12

I didn't particularly mean reordering on the fly--->
in one invocation
ABC

in the next

CBA

more along the lines you get an existing set of listeners whose value returned by getEventOrdering isn't what you want to use.

I don't know if this would ever happen, but say you have 4 listeners, 2 from swing itself. You want one of your listeners to appear between the 2 swing listeners:
X is a swing listener, A a user
AXAX

If the user is stuck with either before or after orderings Im not sure how he is going to stick the listener in between these two. I suppose this situation could come up with a composite widget where you need to react to a change in one part but need to do something with another part before it gets its notification and correspondingly changes.

BH

leouser
Offline
Joined: 2005-12-12

I think a different example of what Im talking about is this bug(which is closed now) but referenced by the bug report:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4688560

If we tried to solve the problem with a EventOrdering but only allowed:
pre middle(swing) post

If the user ran into this bug and assuming that the DefaultCaret is a middle order listener, how would the user fix the problem? He could:
1 Subclass the caret(if thats an option) and change the ordering returned for it.
2. Change the Comparator by which the listeners are sorted so the Caret does its work after the Views are valid.

Im not sure what the bug fix was, maybe it was just a reordering of when something was added. Its quite conceivable that the fixer could have just used an altered Comparator that ensured the DefaultCaret got notified after all the other Swing widgets and not have had to do much of anything beyond that.

BH

tackline
Offline
Joined: 2003-06-19

Having a quick look, it appears that the bug was fixed by adding an invokeLater to DefaultCaret (as suggested in the bug description and evaluation). I guess that kind of hides the bug symptoms rather than completely fixes it.

It looks as if the real problem in this particular case is that the View is fragile, for some reason.

leouser
Offline
Joined: 2005-12-12

yeah, that is kind of hiding the problem. That, I think, has been one of the ways in which users have skirted around making their listener's work happen after the swing listeners have been notified.

For this bug, if you didn't use a custom comparator to solve the problem, one idea Ive had was to set up a range of numbers that are considered Swing ordering numbers
0 < is a pre listener
1 - 10 is a swing listener
11> is a post listener
(this just illustrates what Im thinking).

For the inner swing sort order, a normal listener could just be an int of 5. The DefaultCaret could have used a 6. Then it could still be a swing listener and also be notified after the regular swing listeners. Im not sure what I think about this though...

BH

alexfromsun
Offline
Joined: 2005-09-05

Hello guys

Actually, ordering listeners with numbers or Comparators looks difficult for understanding (and maintaining) the application's behaviour

I wonder what you guys think about ordering not listeners but collections of them

For example: we already have a collection of listeners which get notified in unspecified order

addActionListener(ActionListener l)

the only thing we need to add a new

addActionListener(ActionListener l, EnumValue v)

where "v" specifies if the listener is to notified before model change of after (and probably something else)

This solution is absolutely compatible and easy to implement and understand

Thoughts ?

leouser
Offline
Joined: 2005-12-12

well, when I started thinking about this I stayed away from it because of the expensive nature of it. For every addXXX you have to have another method.

When you say collections, Im assuming you mean:
PreNotificationList
NormalNotificationList
PostNotificationList

And in the notification listeners you'd have to notify each listener list in that order, or a list made up of those lists.

A positive of this approach is that it may be backwards compatible. Im thinking that if you add ordering behavior that modifies by default how listeners are notified then the 10 year pile of workarounds in people's code has a good chance of breaking in each workaround. But with the pre and post Enum approach, Im assuming everything would work as is.

Maybe it wouldn't be that expensive, if the method addition could be watered down to a set of methods:
addOrderedListener(Class listener, Object listener, Enum order);
removeOrderedListener(Class listener, Object listener, Enum order);

It would be great if the the ordering within an ordering problem could be solved with this. When you have a swing listener that is relying upon invokeLater to do its work, it defeats the ordering scheme for the user. He can no longer specify that he wants his listeners work to happen after a specific listener because the work will always happen after his work occurs. That is unless he himself invokes invokeLater for doing his work, but that seems clumsy and frutrating. :D

BH

leouser
Offline
Joined: 2005-12-12

I suppose you could still use the EventOrdering interface in the Enum solution but not make it mandatory to have an Ordering, but use it as a tool to do an ordering within the ordering.

With the DefaultCaret bug, its listener could implement EventOrdering and have it return a 6. Classes that don't implement EventOrdering would be assumed to have a value of 5. With this:
1. You aren't forced to add EventOrdering to every swing listener, nor is the user forced to implement it as well.
2. You can still ensure(somewhat) that your listener will be notified at a certain point in its ordering.

But I don't think this helps solve the,
AXAX problem, where A is a user listener and X is a swing listener.

BH

alexfromsun
Offline
Joined: 2005-09-05

Hello Brian

> I suppose you could still use the EventOrdering
> interface in the Enum solution but not make it
> mandatory to have an Ordering, but use it as a tool
> to do an ordering within the ordering.

My idea is that we probably don't need a way to order listeners in a very particular way

Seems the only thing we need is break all listeners to special groups and notify those group in predictable order

>
> With the DefaultCaret bug, its listener could
> implement EventOrdering and have it return a 6.
> Classes that don't implement EventOrdering would be
> e assumed to have a value of 5. With this:
> 1. You aren't forced to add EventOrdering to every
> swing listener, nor is the user forced to implement
> it as well.
> 2. You can still ensure(somewhat) that your listener
> will be notified at a certain point in its ordering.
>

If we need to insert some new listeners between them, we'll have to fix ordering value of the existing listeners, right ?

> But I don't think this helps solve the,
> AXAX problem, where A is a user listener and X is a
> swing listener.
>

I think the problem that we mix Swing listeners with users ones

What if we have four groups:

1) Listeners which are notified before actual change
(and probably can use a veto)

2) Current bunch of ungroupped listeners

3) Swing listeners which are notified after model's change as well and updating component's visual appearance

4) Listeners which are notified after model's change

Will it help us in solving all problems you mentioned ?

alexp

leouser
Offline
Joined: 2005-12-12

I think that would solve the case the DefaultCaret bug illustrates. Im going to have to think if the AXAX problem is actually a problem or not. It could be that its so exotic/manufactured that the solution may not need to address it.

BH

leouser
Offline
Joined: 2005-12-12

Im starting to consider AXAX as something the user could just do himself. Im trying to think of time or a bug report in the database where Ive seen the user needing to sandwich a user listener in between 2 swing listeners, and I can't.

The cost of addMouseListener(MouseListener ml, OrderEnum order) is starting to seem lighter weight as I think about it. The user will understand what addMouseListener is for, he just needs to understand what the Orders are for. It also seems easily extensible. If at some time a new Order is needed, just add a new enum.

I guess the enums would be:
PRE
NORMAL
TAIL_NORMAL
POST

would it be good to do a HEAD_NORMAL? A category that comes before NORMAL?

I think Im going to do a prototype of this idea, select a good swing class and work with this to see how well it works out.

BH

tackline
Offline
Joined: 2003-06-19

Seems like a sledgehammer to crack a nut to me.

I think you could get away with just firing PL&F listeners before application listeners. The obvious way of identifying PL&F listeners is for them to implement UIResource. PL&F and application can then take responsibility for their own dependencies.

Either way, I guess there may still be problems with components that listen to models, and then forward on events to listeners added to the component.