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,

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


Back to the top