001    /*
002     * Created on Mar 30, 2008
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
005     * in compliance with 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
010     * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
011     * or implied. See the License for the specific language governing permissions and limitations under
012     * the License.
013     *
014     * Copyright @2008-2010 the original author or authors.
015     */
016    package org.fest.swing.core;
017    
018    import static org.fest.swing.edt.GuiActionRunner.execute;
019    import static org.fest.util.Collections.list;
020    
021    import java.awt.Component;
022    import java.util.ArrayList;
023    import java.util.List;
024    
025    import org.fest.swing.annotation.RunsInCurrentThread;
026    import org.fest.swing.annotation.RunsInEDT;
027    import org.fest.swing.edt.GuiQuery;
028    import org.fest.util.VisibleForTesting;
029    
030    /**
031     * Understands lookup of a <code>{@link Component}</code> owning the input focus.
032     *
033     * @author Yvonne Wang
034     * @author Alex Ruiz
035     */
036    public final class FocusOwnerFinder {
037    
038      private static final List<FocusOwnerFinderStrategy> STRATEGIES = new ArrayList<FocusOwnerFinderStrategy>();
039    
040      static {
041        initializeStrategies();
042      }
043    
044      @VisibleForTesting
045      static void initializeStrategies() {
046        replaceStrategiesWith(new ReflectionBasedFocusOwnerFinder(), new HierarchyBasedFocusOwnerFinder());
047      }
048    
049      @VisibleForTesting
050      static void replaceStrategiesWith(FocusOwnerFinderStrategy...strategies) {
051        STRATEGIES.clear();
052        STRATEGIES.addAll(list(strategies));
053      }
054    
055      @VisibleForTesting
056      static List<FocusOwnerFinderStrategy> strategies() {
057        return new ArrayList<FocusOwnerFinderStrategy>(STRATEGIES);
058      }
059    
060      /**
061       * Returns the focus owner. This method is executed in the event dispatch thread.
062       * @return the focus owner.
063       */
064      @RunsInEDT
065      public static Component inEdtFocusOwner() {
066        return execute(new GuiQuery<Component>() {
067          protected Component executeInEDT() {
068            return focusOwner();
069          }
070        });
071      }
072    
073      /**
074       * Returns the focus owner. <b>Note:</b> this method is <b>not</b> executed in the event dispatch thread. Callers are
075       * responsible for calling this method in the event dispatch thread.
076       * <p>
077       * <b>Note:</b> This method is <b>not</b> guaranteed to be executed in the event dispatch thread (EDT.) Clients are
078       * responsible for calling this method from the EDT.
079       * </p>
080       * @return the focus owner.
081       */
082      @RunsInCurrentThread
083      public static Component focusOwner() {
084        for (FocusOwnerFinderStrategy strategy : STRATEGIES) {
085          try {
086            return strategy.focusOwner();
087          } catch (Exception e) {
088            continue;
089          }
090        }
091        return null;
092      }
093    
094      private FocusOwnerFinder() {}
095    }