/******************************************************************************* * Copyright (c) 2014 SWTBot Committers and others * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Matt Biggs - initial API and implementation * Stef Bolton - initial API and implementation *******************************************************************************/ package org.eclipse.swtbot.e4.finder.finders; import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.List; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.MenuItem; import org.eclipse.swt.widgets.Shell; import org.eclipse.swtbot.swt.finder.finders.UIThreadRunnable; import org.eclipse.swtbot.swt.finder.results.ArrayResult; import org.eclipse.swtbot.swt.finder.results.ListResult; import org.eclipse.swtbot.swt.finder.results.WidgetResult; import org.eclipse.swtbot.swt.finder.utils.SWTUtils; import org.hamcrest.Matcher; /** * Finds menus matching a particular matcher. * * @see UIThreadRunnable * @author Ketan Padegaonkar <KetanPadegaonkar [at] gmail [dot] com> * @author Stef Bolton - This was causing huge menu flicker in e4 so this version suppresses the HIDE/SHOW notifications which were seemingly redundant. * @version $Id$ * * @deprecated Use org.eclipse.swtbot.swt.finder.finders.MenuFinder instead. */ @Deprecated public class MenuFinder { /** The display */ protected final Display display; /** * Creates a MenuFinder. */ public MenuFinder() { display = SWTUtils.display(); } /** * Finds a menu matching the given item in all available shells. If recursive is set, it will attempt to find the * controls recursively in each of the menus it that is found. * * @param matcher the matcher that can match menus and menu items. * @return all menus in all shells that match the matcher. */ public List<MenuItem> findMenus(Matcher<MenuItem> matcher) { return findMenus(getShells(), matcher, true); } /** * Finds all the menus using the given matcher in the set of shells provided. If recursive is set, it will attempt * to find the controls recursively in each of the menus it that is found. * * @param shells the shells to probe for menus. * @param matcher the matcher that can match menus and menu items. * @param recursive if set to true, will find sub-menus as well. * @return all menus in the specified shells that match the matcher. */ public List<MenuItem> findMenus(Shell[] shells, Matcher<MenuItem> matcher, boolean recursive) { LinkedHashSet<MenuItem> result = new LinkedHashSet<MenuItem>(); for (Shell shell : shells) result.addAll(findMenus(shell, matcher, recursive)); return new ArrayList<MenuItem>(result); } /** * Finds the menus in the given shell using the given matcher. If recursive is set, it will attempt to find the * controls recursively in each of the menus it that is found. * * @param shell the shell to probe for menus. * @param matcher the matcher that can match menus and menu items. * @param recursive if set to true, will find sub-menus as well. * @return all menus in the specified shell that match the matcher. */ public List<MenuItem> findMenus(final Shell shell, Matcher<MenuItem> matcher, boolean recursive) { LinkedHashSet<MenuItem> result = new LinkedHashSet<MenuItem>(); result.addAll(findMenus(menuBar(shell), matcher, recursive)); return new ArrayList<MenuItem>(result); } /** * Gets the menu bar in the given shell. * * @param shell the shell. * @return the menu in the shell. * @see Shell#getMenuBar() */ protected Menu menuBar(final Shell shell) { return UIThreadRunnable.syncExec(display, new WidgetResult<Menu>() { public Menu run() { return shell.getMenuBar(); } }); } /** * Finds all the menus in the given menu bar matching the given matcher. If recursive is set, it will attempt to * find the controls recursively in each of the menus it that is found. * * @param bar the menu bar * @param matcher the matcher that can match menus and menu items. * @param recursive if set to true, will find sub-menus as well. * @return all menus in the specified menubar that match the matcher. */ public List<MenuItem> findMenus(final Menu bar, final Matcher<MenuItem> matcher, final boolean recursive) { return UIThreadRunnable.syncExec(display, new ListResult<MenuItem>() { public List<MenuItem> run() { return findMenusInternal(bar, matcher, recursive); } }); } /** * Gets all of the shells in the current display. * * @return all shells in the display. * @see Display#getShells() */ protected Shell[] getShells() { return UIThreadRunnable.syncExec(display, new ArrayResult<Shell>() { public Shell[] run() { return display.getShells(); } }); } /** * @param bar * @param matcher * @param recursive * @return */ private List<MenuItem> findMenusInternal(final Menu bar, final Matcher<MenuItem> matcher, final boolean recursive) { LinkedHashSet<MenuItem> result = new LinkedHashSet<MenuItem>(); if (bar != null) { bar.notifyListeners(SWT.Show, new Event()); MenuItem[] items = bar.getItems(); for (MenuItem menuItem : items) { if (isSeparator(menuItem)) { continue; } if (matcher.matches(menuItem)) result.add(menuItem); if (recursive) result.addAll(findMenusInternal(menuItem.getMenu(), matcher, recursive)); } // Do not close menus which contain the item we're looking for - this destroys dynamic menu contributions // giving us the SWT MenuItem but without a E4 model attached (and therefore cannot be used). // @see https://bugs.eclipse.org/bugs/show_bug.cgi?id=469581 if (result.isEmpty()) { bar.notifyListeners(SWT.Hide, new Event()); } } return new ArrayList<MenuItem>(result); } private boolean isSeparator(MenuItem menuItem) { // FIXME see https://bugs.eclipse.org/bugs/show_bug.cgi?id=208188 // FIXED > 20071101 https://bugs.eclipse.org/bugs/show_bug.cgi?id=208188#c2 return (menuItem.getStyle() & SWT.SEPARATOR) != 0; } }