Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 339217

Summary: Always toggling selection state in SWTBotMenuItem might be wrong
Product: [Technology] SWTBot Reporter: Marko Tomljenovic <marko.tomljenovic>
Component: SWTBotAssignee: Patrick Tasse <patrick.tasse>
Status: RESOLVED FIXED QA Contact:
Severity: normal    
Priority: P3 CC: dwille, mistria, patrick.tasse
Version: unspecified   
Target Milestone: 2.3.0   
Hardware: PC   
OS: Windows XP   
Whiteboard:

Description Marko Tomljenovic CLA 2011-03-08 08:14:17 EST
Build Identifier: 2.0.3

I am using the following code to execute a context menu entry on a tree item ("open with" -> "xyz editor"). For that I am using the following code:

  /**
   * Clicks the context menu matching the text.<br>
   * ATTENTION: To have the proper context menu make sure that the right element of the control (e.g. tree item) is
   * selected before this method is called.
   * 
   * @param bot : Swt bot control ex: tree, table etc, not a tree item or menu item
   * @param texts the text on the context menu.
   * @throws WidgetNotFoundException if the widget is not found.
   */
  public static void clickContextMenu(final AbstractSWTBot<?> bot, final String... texts) {

    // show
    final MenuItem[] menuItem = new MenuItem[1];
    PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() {

      @Override
      public void run() {
        MenuItem matchedMenuItem = null;
        Control control = (Control) bot.widget;
        Menu menu = control.getMenu();
        for (String text : texts) {
          Matcher<?> matcher = allOf(instanceOf(MenuItem.class), withMnemonic(text));
          matchedMenuItem = show(menu, matcher);
          if (matchedMenuItem != null) {
            menu = matchedMenuItem.getMenu();
          }
          else {
            hide(menu);
            break;
          }
        }
        menuItem[0] = matchedMenuItem;
      }
    });
    if (menuItem[0] == null) {
      System.err.println("Could not find menu: " + Arrays.asList(texts));
      throw new WidgetNotFoundException("Could not find menu: " + Arrays.asList(texts));
    }

    // Hide the parent menu first
    UIThreadRunnable.syncExec(new VoidResult() {

      @Override
      public void run() {
        hide(menuItem[0].getParent());
      }
    });

    new SWTBotMenu(menuItem[0]).click();
  }


  /**
   * Make the given menu visible
   * 
   * @param menu : Menu instance
   * @param matcher : matcher to find an menuitem with in the given Menu
   * @return : Menu item which matches
   */
  public static MenuItem show(final Menu menu, final Matcher<?> matcher) {
    if (menu != null) {
      menu.notifyListeners(SWT.Show, new Event());
      MenuItem[] items = menu.getItems();
      for (final MenuItem menuItem : items) {
        if (matcher.matches(menuItem)) {
          return menuItem;
        }
      }
      menu.notifyListeners(SWT.Hide, new Event());
    }
    return null;
  }

  /**
   * Hide the given menu
   * 
   * @param menu : Menu
   */
  private static void hide(final Menu menu) {
    menu.notifyListeners(SWT.Hide, new Event());
    if (menu.getParentMenu() != null) {
      hide(menu.getParentMenu());
    }
  }

The problem with this implementation is that SWTBotMenuItem.click always toggles the selection of the menu item. But each menu item might have a diffrent logic of defining the selection state. An example where this leads to a problem can be seen below.

What needs to be done is a way to specify whether the selection should be toggled or set to a specific selection state.

Reproducible: Always

Steps to Reproduce:
1. The current default editor for a c file is the C editor.
2. Now I use SWTBot to execute the context menu Open With -> Text Editor
3. Now I want to open the Text Editor again on the file using SWTBot. But this does not work any more because the selection state of the menu item is toggled again (to false) and the eclipse implementation of the open with command verifies that the selection state is set to true.
Comment 1 Marko Tomljenovic CLA 2011-03-08 08:27:23 EST
The default implementation of the SWTBotMenuItem.toggleSelection() method shall look like this:

  /**
   * Toggle the selection of the checkbox if applicable.
   */
  private void toggleSelection() {
    syncExec(new VoidResult() {

      public void run() {
        if (hasStyle(widget, SWT.CHECK))
          widget.setSelection(!widget.getSelection());
        else if (hasStyle(widget, SWT.RADIO)) {
          if (!widget.getSelection())
          widget.setSelection(true);
        }
      }
    });
  }

Checkboxed menu items will always switch their selection state but radio menu items only if the current selection state is false.
Comment 2 Daniel Wille CLA 2015-01-07 17:51:07 EST
I also see this issue. I'm using SWTBot 2.2.1 to use the "Open With" context menu, then select an editor. I fixed the issue by changing the toggleSelection() functionality for a SWT.RADIO style menu to always perform widget.setSelection(true).
Comment 3 Patrick Tasse CLA 2015-06-16 14:09:43 EDT
This might be fixed by https://git.eclipse.org/r/48912 ?

Related to bug 451126 and bug 397649.
Comment 4 Mickael Istria CLA 2015-06-16 14:15:57 EDT
@Patrick: I let you check whether this report is fixed by your patch or not. If it it, feel free to mark is as resolved, assign it to yourself, and put target milestone to 2.3.0.
Comment 5 Patrick Tasse CLA 2015-06-16 15:00:41 EDT
Fixed by https://git.eclipse.org/r/48912.