replaced <code></code> with more concise {@code}
[idea/community.git] / platform / platform-impl / src / com / intellij / openapi / wm / ex / IdeFocusTraversalPolicy.java
1 /*
2  * Copyright 2000-2016 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.intellij.openapi.wm.ex;
17
18 import com.intellij.openapi.diagnostic.Logger;
19 import com.intellij.openapi.editor.impl.EditorComponentImpl;
20 import com.intellij.openapi.fileEditor.impl.EditorWindowHolder;
21 import com.intellij.openapi.util.Computable;
22 import com.intellij.util.ReflectionUtil;
23 import org.jetbrains.annotations.NotNull;
24
25 import javax.swing.*;
26 import javax.swing.text.JTextComponent;
27 import java.awt.*;
28
29 public class IdeFocusTraversalPolicy extends LayoutFocusTraversalPolicyExt {
30   private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.wm.ex.IdeFocusTraversalPolicy");
31
32   protected Component getDefaultComponentImpl(Container focusCycleRoot) {
33     if (!(focusCycleRoot instanceof JComponent)) {
34       return super.getDefaultComponent(focusCycleRoot);
35     }
36     return getPreferredFocusedComponent((JComponent)focusCycleRoot, this);
37   }
38
39   public static JComponent getPreferredFocusedComponent(@NotNull final JComponent component) {
40     return getPreferredFocusedComponent(component, null);
41   }
42
43   /**
44    * @return preferred focused component inside the specified {@code component}.
45    * Method can return component itself if the {@code component} is legal
46    * (JTextFiel)focusable
47    *
48    */
49   public static JComponent getPreferredFocusedComponent(@NotNull final JComponent component, final FocusTraversalPolicy policyToIgnore) {
50     if (!component.isVisible()) {
51       return null;
52     }
53
54     final FocusTraversalPolicy focusTraversalPolicy = getFocusTraversalPolicyAwtImpl(component);
55     if (focusTraversalPolicy != null && focusTraversalPolicy != policyToIgnore) {
56       if (focusTraversalPolicy.getClass().getName().indexOf("LegacyGlueFocusTraversalPolicy") >=0) {
57         return component;
58       }
59
60       Component defaultComponent;
61       if (focusTraversalPolicy instanceof LayoutFocusTraversalPolicyExt) {
62         final LayoutFocusTraversalPolicyExt extPolicy = (LayoutFocusTraversalPolicyExt)focusTraversalPolicy;
63         defaultComponent = extPolicy.queryImpl(() -> extPolicy.getDefaultComponent(component));
64       } else {
65         defaultComponent = focusTraversalPolicy.getDefaultComponent(component);
66       }
67
68       if (defaultComponent instanceof JComponent) {
69         return (JComponent)defaultComponent;
70       }
71     }
72
73     if (component instanceof JTabbedPane) {
74       final JTabbedPane tabbedPane = (JTabbedPane)component;
75       final Component selectedComponent = tabbedPane.getSelectedComponent();
76       if (selectedComponent instanceof JComponent) {
77         return getPreferredFocusedComponent((JComponent)selectedComponent);
78       }
79       return null;
80     }
81
82     if(_accept(component)) {
83       return component;
84     }
85
86     for (Component ca : component.getComponents()) {
87       if (!(ca instanceof JComponent)) {
88         continue;
89       }
90       final JComponent c = getPreferredFocusedComponent((JComponent)ca);
91       if (c != null) {
92         return c;
93       }
94     }
95     return null;
96   }
97
98   private static FocusTraversalPolicy getFocusTraversalPolicyAwtImpl(final JComponent component) {
99     return ReflectionUtil.getField(Container.class, component, FocusTraversalPolicy.class, "focusTraversalPolicy");
100   }
101
102   protected final boolean accept(final Component aComponent) {
103     if (aComponent instanceof JComponent) {
104       return _accept((JComponent)aComponent);
105     }
106     return super.accept(aComponent);
107   }
108
109   private static boolean _accept(final JComponent component) {
110     if (!component.isEnabled() || !component.isVisible() || !component.isFocusable()) {
111       return false;
112     }
113
114     /* TODO[anton,vova] implement Policy in Editor component instead */
115     if (component instanceof EditorComponentImpl || component instanceof EditorWindowHolder) {
116       return true;
117     }
118
119     if(component instanceof JTextComponent){
120       return ((JTextComponent)component).isEditable();
121     }
122
123     return
124       component instanceof AbstractButton ||
125       component instanceof JList ||
126       component instanceof JTree ||
127       component instanceof JTable ||
128       component instanceof JComboBox;
129   }
130 }