| /* |
| * Copyright 2000-2013 JetBrains s.r.o. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package com.intellij.openapi.wm; |
| |
| import com.intellij.openapi.actionSystem.CommonDataKeys; |
| import com.intellij.openapi.actionSystem.DataContext; |
| import com.intellij.openapi.application.Application; |
| import com.intellij.openapi.application.ApplicationManager; |
| import com.intellij.openapi.project.Project; |
| import com.intellij.openapi.util.ActionCallback; |
| import com.intellij.openapi.util.Expirable; |
| import com.intellij.openapi.util.ExpirableRunnable; |
| import com.intellij.util.ui.UIUtil; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| |
| import javax.swing.*; |
| import java.awt.*; |
| import java.awt.event.KeyEvent; |
| |
| /** |
| * This class receives focus requests, manages the, and delegates to the awt focus subsystem. All focus requests |
| * should be done through this class. For example, to request focus on a component: |
| * <pre> |
| * IdeFocusManager.getInstance(project).requestFocus(comp, true); |
| * </pre> |
| * This is the preferred way to request focus on components to |
| * <pre> |
| * comp.requestFocus(); |
| * </pre> |
| * |
| * This class is also responsible for delivering key events while focus tranferring is in progress. |
| * <p> |
| * <code>IdeFocusManager</code> instance can be received per project or the global instance. The preferred way is |
| * to use instance <code>IdeFocusManager.getInstance(project)</code>. If no project instance is available, then |
| * <code>IdeFocusManager.getGlobalInstance()</code> can be used. |
| */ |
| |
| public abstract class IdeFocusManager implements FocusRequestor { |
| |
| /** |
| * Finds most suitable component to request focus to. For instance you may pass a JPanel instance, |
| * this method will traverse into it's children to find focusable component |
| * @param comp |
| * @return suitable component to focus |
| */ |
| @Nullable |
| public abstract JComponent getFocusTargetFor(@NotNull final JComponent comp); |
| |
| |
| /** |
| * Executes given runnable after all focus activities are finished |
| * @param runnable |
| */ |
| public abstract void doWhenFocusSettlesDown(@NotNull Runnable runnable); |
| |
| /** |
| * Executes given runnable after all focus activities are finished |
| * @param runnable |
| */ |
| public abstract void doWhenFocusSettlesDown(@NotNull ExpirableRunnable runnable); |
| |
| |
| /** |
| * Finds focused component among descendants of the given component. Descendants may be in child popups and windows |
| * @param comp |
| * @return |
| */ |
| @Nullable |
| public abstract Component getFocusedDescendantFor(final Component comp); |
| |
| /** |
| * Dispatches given key event. This methods should not be called by the user code |
| * @param e |
| * @return true is the event was dispatched, false - otherwise. |
| */ |
| public abstract boolean dispatch(KeyEvent e); |
| |
| /** |
| * Aggregates all key events until given callback object is processed |
| * @param done action callback |
| */ |
| public abstract void typeAheadUntil(ActionCallback done); |
| |
| /** |
| * Reports if any focus activity is being done |
| * @return |
| */ |
| public abstract boolean isFocusBeingTransferred(); |
| |
| /** |
| * Requests default focus. The method should not be called by the user code. |
| * @param forced |
| * @return |
| */ |
| public abstract ActionCallback requestDefaultFocus(boolean forced); |
| |
| /** |
| * Reports of focus transfer is enabled right now. It can be disabled if app is inactive. In this case |
| * all focus requests will be either postponed or executed only if <code>FocusCommand</code> can be executed on an inaactive app. |
| * @see com.intellij.openapi.wm.FocusCommand#canExecuteOnInactiveApp() |
| * @return |
| */ |
| public abstract boolean isFocusTransferEnabled(); |
| |
| /** |
| * Returns <code>Expirable</code> instance for the given counter of focus commands. As any new <code>FocusCommand</code> |
| * is emitted to execute, the counter increments thus making the returned <code>Expirable</code> objects expired. |
| * @param trackOnlyForcedCommands |
| * @return |
| */ |
| public abstract Expirable getTimestamp(boolean trackOnlyForcedCommands); |
| |
| /** |
| * Returns <code>FocusRequestor</code> object which will emit focus requests unless expired. |
| * @see #getTimestamp(boolean) |
| * @return |
| */ |
| public abstract FocusRequestor getFurtherRequestor(); |
| |
| /** |
| * Injects some procedure that will maybe do something with focus after all focus requests are fulfilled and |
| * before focus transfer is reported ready. |
| * @param runnable |
| */ |
| public abstract void revalidateFocus(@NotNull ExpirableRunnable runnable); |
| |
| /** |
| * Enables or disables typeahead |
| * @see #typeAheadUntil(com.intellij.openapi.util.ActionCallback) |
| * @param enabled |
| */ |
| public abstract void setTypeaheadEnabled(boolean enabled); |
| |
| /** |
| * Computes effective focus owner |
| * @return |
| */ |
| public abstract Component getFocusOwner(); |
| |
| /** |
| * Runs runnable for whicj <code>DataContext</code> will no be computed from the current focus owner, |
| * but used the given one |
| * @param context |
| * @param runnable |
| */ |
| public abstract void runOnOwnContext(DataContext context, Runnable runnable); |
| |
| /** |
| * Returns last focused component for the given <code>IdeFrame</code> |
| * @param frame |
| * @return |
| */ |
| @Nullable |
| public abstract Component getLastFocusedFor(@Nullable IdeFrame frame); |
| |
| /** |
| * Returns last focused <code>IdeFrame</code> |
| * @return |
| */ |
| @Nullable |
| public abstract IdeFrame getLastFocusedFrame(); |
| |
| /** |
| * Put the container window to front. May not execute of the app is inactive or under some other conditions. This |
| * is the preferred way to finding the container window and unconditionally calling <code>window.toFront()</code> |
| * @param c |
| */ |
| public abstract void toFront(JComponent c); |
| |
| public static IdeFocusManager getInstance(@Nullable Project project) { |
| if (project == null) return getGlobalInstance(); |
| |
| if (project.isDisposed() || !project.isInitialized()) return getGlobalInstance(); |
| return project.getComponent(IdeFocusManager.class); |
| } |
| |
| @NotNull |
| public static IdeFocusManager findInstanceByContext(@Nullable DataContext context) { |
| IdeFocusManager instance = null; |
| if (context != null) { |
| instance = getInstanceSafe(CommonDataKeys.PROJECT.getData(context)); |
| } |
| |
| if (instance == null) { |
| instance = findByComponent(KeyboardFocusManager.getCurrentKeyboardFocusManager().getActiveWindow()); |
| } |
| |
| if (instance == null) { |
| instance = getGlobalInstance(); |
| } |
| |
| return instance; |
| } |
| |
| @NotNull |
| public static IdeFocusManager findInstanceByComponent(@NotNull Component c) { |
| final IdeFocusManager instance = findByComponent(c); |
| return instance != null ? instance : findInstanceByContext(null); |
| } |
| |
| |
| @Nullable |
| private static IdeFocusManager findByComponent(Component c) { |
| final Component parent = UIUtil.findUltimateParent(c); |
| if (parent instanceof IdeFrame) { |
| return getInstanceSafe(((IdeFrame)parent).getProject()); |
| } |
| return null; |
| } |
| |
| |
| @Nullable |
| private static IdeFocusManager getInstanceSafe(@Nullable Project project) { |
| if (project != null && !project.isDisposed() && project.isInitialized()) { |
| return getInstance(project); |
| } else { |
| return null; |
| } |
| } |
| |
| @NotNull |
| public static IdeFocusManager findInstance() { |
| final Component owner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner(); |
| return owner != null ? findInstanceByComponent(owner) : findInstanceByContext(null); |
| } |
| |
| @NotNull |
| public static IdeFocusManager getGlobalInstance() { |
| IdeFocusManager fm = null; |
| |
| Application app = ApplicationManager.getApplication(); |
| if (app != null && app.hasComponent(IdeFocusManager.class)) { |
| fm = app.getComponent(IdeFocusManager.class); |
| } |
| |
| if (fm == null) { |
| // happens when app is semi-initialized (e.g. when IDEA server dialog is shown) |
| fm = PassThroughIdeFocusManager.getInstance(); |
| } |
| |
| return fm; |
| } |
| |
| } |