Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
RE: [rap-dev] Radio buttons and selection events

Hello

Ok.  But how the first approach (extending SelectionEvent and modifying
EVENT_ORDER) can have an unexpected side effects?
And this problem not only in RadioGroupFieldEditor. This can be reproduced
in any other place where using radios with selection listeners.

I am sure the approach with tagging events on the client-side is the best
approach. But I still think that I can use the first suggested approach as a
temporary solution. Is there any other problems with this approach?

Thank you, Igor

-----Original Message-----
From: rap-dev-bounces@xxxxxxxxxxx [mailto:rap-dev-bounces@xxxxxxxxxxx] On
Behalf Of Rudiger Herrmann
Sent: Friday, April 17, 2009 10:00 PM
To: RAP project development-related communication
Subject: Re: [rap-dev] Radio buttons and selection events

Hi Igor,

hacking the accept method would break its contract certainly have side
effects as it is used in various places.

The solution which I would prefer would be to tag the events on the
client-side with a sequential number. Then they could be processed on the
server-side in the same order as they ocured. This of course is a larger
task.

To solve the problem in the meanwhile, I would rather change the
RadioGroupFieldEditor.

Thanks,
Rüdiger

mail.apptech.nichost.ru wrote:
> Hello
> 
> I found some problem with radio buttons.
> 
> Look, for example, at org.eclipse.jface.preference.RadioGroupFieldEditor.
> 
> Find line 267. You will see, that some selection event listener is 
> added to all of the radios in group. How it should work? The user selects
the radio.
> The old selected radio becomes an unselected (first selection event). 
> The new radio becames selected (second selection event). As you can 
> see in
> RadioGroupFieldEditor#267 the order of this two events has a big 
> matter (unselect - the first, select - the second). It is working fine 
> on RCP
> 
> But.
> 
> It works wrong on RAP. The problem is in 
> org.eclipse.swt.internal.widgets.WidgetTreeVisitor#accept method.
> As you can see the WidgetTreeVisitor#accept method will be called for 
> each item in the collection of siblings in that order in wich they was 
> added there. So if you have 4 radios and the last one is selected and 
> you try to select the third (or second or first) one the selected 
> event will process before the unselected event.
> 
> It is incorrect.
> 
> There are few ways to deal with this problem. The first and second one 
> is just for fun. The third one, I think, is correct.
> 
> 1) The first solution is to create DeselectionEvent (in 
> org.eclipse.swt.events package, or in some other package to mark it as
> internal):
> 
> public class DeselectionEvent extends SelectionEvent {
> 
>   public DeselectionEvent( Widget widget, Widget item, int id, 
> Rectangle bounds, String text, boolean doit, int detail ) {
>     super( widget, item, id, bounds, text, doit, detail );
>   }
> 
>   public DeselectionEvent( Widget widget, Widget item, int id ) {
>     super( widget, item, id );
>   }
> 
>   public DeselectionEvent( Event e ) {
>     super( e );
>   }
>   
> }
> 
> You also have to change a org.eclipse.swt.events.TypedEvent#EVENT_ORDER:
> 
> private static final Class[] EVENT_ORDER = {
>     ControlEvent.class,
>     ActivateEvent.class,
>     ShowEvent.class,
>     DisposeEvent.class,
>     SetDataEvent.class,
>     MouseEvent.class,
>     VerifyEvent.class,
>     ModifyEvent.class,
>     TreeEvent.class,
>     CTabFolderEvent.class,
>     ExpandEvent.class,
>     FocusEvent.class,
>     DeselectionEvent.class,	 // added
>     SelectionEvent.class,
>     LocationEvent.class,
>     ShellEvent.class,
>     MenuEvent.class,
>     KeyEvent.class
>   };
> 
> And finally change the
> org.eclipse.swt.internal.widgets.buttonkit.RadioButtonDelegateLCA. 
> Change readData method: to:
> 
> void readData( final Button button ) {
>   // [if] The selection event is based on the request "selection"
parameter
>   // and not on the selection event, because it is not possible to fire
the
>   // same event (Id) from javascript for two widgets (selected and 
> unselected
>   // radio button) at the same time.
>   if( ButtonLCAUtil.readSelection( button ) ) {
>     processSelectionEvent( button, button.getSelection() );
>   }
>   ControlLCAUtil.processMouseEvents( button );
>   ControlLCAUtil.processKeyEvents( button ); }
> 
> And processSelectionEvent method:
> 
> private static void processSelectionEvent( final Button button, 
> boolean selected ) {
>   if( SelectionEvent.hasListener( button ) ) {
>     Rectangle bounds  = WidgetLCAUtil.readBounds( button,
>                                                   button.getBounds() );
>     int type = SelectionEvent.WIDGET_SELECTED;
>     
>     SelectionEvent event;
>     if( selected ) {
>       event = new SelectionEvent( button, null, type, bounds, null, 
> true, SWT.NONE );
>     } else {
>       event = new DeselectionEvent( button, null, type, bounds, null, 
> true, SWT.NONE );
>     }
>     event.processEvent();
>   }
> }
> 
> Alternative you can change the logic of 
> TypedEvent#getScheduledEvents() and add a new variable in 
> SelectionEvent that will tell to that method if the component is 
> selected. But it is the same approach. There is only one problem in 
> such approach. The developers will see the DeselectionEvent instead of 
> SelectionEvent in their applications. But it is not a big problem. I use
this approach my application.
> 
> 2) This bug can be fixed with only JS (but it will be necessary to use 
> two requests instead of one: one to make a unselect event and the 
> other to make a select event)
> 
> 3) It is possible to make all changes in WidgetTreeVisitor#accept method:
> 
> public static void accept( final Widget root, final WidgetTreeVisitor 
> visitor ) {
>   if( root instanceof Group ) {
>     Composite composite = ( Composite )root;
>     if( visitor.visit( composite ) ) {
>       handleMenus( composite, visitor );
>       handleItems( root, visitor );
>       Control[] children = composite.getChildren();
>       Set accepted = new HashSet();
>       for (int i=0; i<children.length; i++) {
>         if (children[i] instanceof Button &&
> ((Button)children[i]).getSelection()) {
>           accept( children[ i ], visitor );
>           accepted.add( children[ i ] );
>         }
>       }
>       for( int i = 0; i < children.length; i++ ) {
>         if (!accepted.contains( children[ i ] )) {
>           accept( children[ i ], visitor );
>         }
>       }
>     }
>   } else if( root instanceof Composite) {
>     Composite composite = ( Composite )root;
>     if( visitor.visit( composite ) ) {
>       handleMenus( composite, visitor );
>       handleItems( root, visitor );
>       Control[] children = composite.getChildren();
>       for( int i = 0; i < children.length; i++ ) {
>         accept( children[ i ], visitor );
>       }
>     }
>   } else if( ItemHolder.isItemHolder( root ) ) {
>     if( visitor.visit( root ) ) {
>       handleItems( root, visitor );
>     }
>   } else {
>     visitor.visit( root );
>   }
> }
> 
> But it looks like a temporary solution. There is only one advantage in 
> this
> approach: the developers will see the SelectionEvent as they can see 
> it on RCP in selection listeners.
> 
> Thank you, Igor
> 
> 
> _______________________________________________
> rap-dev mailing list
> rap-dev@xxxxxxxxxxx
> https://dev.eclipse.org/mailman/listinfo/rap-dev
_______________________________________________
rap-dev mailing list
rap-dev@xxxxxxxxxxx
https://dev.eclipse.org/mailman/listinfo/rap-dev




Back to the top