001    /*
002     * Created on Sep 5, 2007
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
005     * the License. You may obtain a copy of the License at
006     *
007     * http://www.apache.org/licenses/LICENSE-2.0
008     *
009     * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
010     * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
011     * specific language governing permissions and limitations under the License.
012     *
013     * Copyright @2007-2010 the original author or authors.
014     */
015    package org.fest.swing.driver;
016    
017    import static org.fest.swing.driver.AbstractButtonTextQuery.textOf;
018    import static org.fest.util.Objects.areEqual;
019    import static org.fest.util.Strings.*;
020    
021    import java.awt.Component;
022    
023    import javax.swing.JMenuItem;
024    import javax.swing.JPopupMenu;
025    
026    import org.fest.swing.annotation.RunsInCurrentThread;
027    import org.fest.swing.core.ComponentMatcher;
028    
029    /**
030     * Matches a <code>{@link JMenuItem}</code> given a simple label or a menu path of the format "menu|submenu|menuitem",
031     * for example "File|Open|Can of worms". Adapted from Abbot's own <code>JMenuItemMatcher</code>.
032     *
033     * @author Yvonne Wang
034     * @author Alex Ruiz
035     */
036    public class JMenuItemMatcher implements ComponentMatcher {
037    
038      private static final String SEPARATOR = "|";
039    
040      private final String label;
041    
042      /**
043       * Creates a new </code>{@link JMenuItemMatcher}</code>.
044       * @param path the path of the menu to match.
045       */
046      public JMenuItemMatcher(String... path) {
047        this.label = join(path).with(SEPARATOR);
048      }
049    
050      /**
051       * Indicates whether the given component is a <code>{@link JMenuItem}</code> whose text matches the path specified
052       * in this matcher.
053       * <p>
054       * <b>Note:</b> This method is <b>not</b> guaranteed to be executed in the event dispatch thread (EDT.) Clients are
055       * responsible for calling this method from the EDT.
056       * </p>
057       * @param c the component to verify.
058       * @return <code>true</code> if the component matches, <code>false</code> otherwise.
059       */
060      @RunsInCurrentThread
061      public boolean matches(Component c) {
062        if (!(c instanceof JMenuItem)) return false;
063        JMenuItem menuItem = (JMenuItem) c;
064        String text = menuItem.getText();
065        return areEqual(label, text) || areEqual(label, pathOf(menuItem));
066      }
067    
068      @RunsInCurrentThread
069      private String pathOf(JMenuItem menuItem) {
070        Component parent = parentOrInvokerOf(menuItem);
071        if (parent instanceof JMenuItem)
072          return concat(pathOf((JMenuItem)parent), SEPARATOR, textOf(menuItem));
073        return textOf(menuItem);
074      }
075    
076      @RunsInCurrentThread
077      private Component parentOrInvokerOf(JMenuItem menuItem) {
078        Component parent = menuItem.getParent();
079        if (parent instanceof JPopupMenu)
080          parent = ((JPopupMenu)parent).getInvoker();
081        return parent;
082      }
083    
084      @Override public String toString() {
085        return concat(getClass().getName(), "[", "label=", quote(label), "]");
086      }
087    }