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

Hi Igor,

mail.apptech.nichost.ru wrote:
Hello

Ok.  But how the first approach (extending SelectionEvent and modifying
EVENT_ORDER) can have an unexpected side effects?
There are no side effects that I am aware of. We could give this a try. Would you mind to open a bug? If you can come up with an implementation, feel also free to attach it.

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


_______________________________________________
rap-dev mailing list
rap-dev@xxxxxxxxxxx
https://dev.eclipse.org/mailman/listinfo/rap-dev


Back to the top