| /* |
| * Copyright 2000-2010 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.ui; |
| |
| import com.intellij.openapi.util.Pair; |
| import com.intellij.util.Function; |
| import gnu.trove.THashSet; |
| import org.jetbrains.annotations.NotNull; |
| |
| import java.awt.*; |
| import java.util.Collections; |
| import java.util.Set; |
| |
| public class ExcludingTraversalPolicy extends FocusTraversalPolicy { |
| private final FocusTraversalPolicy myWrappee; |
| private final Set<Component> myExcludes = new THashSet<Component>(); |
| private final Set<String> myRecursionGuard = new THashSet<String>(); |
| |
| public ExcludingTraversalPolicy(Component... excludes) { |
| this(KeyboardFocusManager.getCurrentKeyboardFocusManager().getDefaultFocusTraversalPolicy(), excludes); |
| } |
| |
| public ExcludingTraversalPolicy(@NotNull FocusTraversalPolicy wrappee, Component... excludes) { |
| myWrappee = wrappee; |
| Collections.addAll(myExcludes, excludes); |
| } |
| |
| public void exclude(Component c) { |
| myExcludes.add(c); |
| } |
| |
| @Override |
| public Component getComponentAfter(Container aContainer, Component aComponent) { |
| try { |
| if (!myRecursionGuard.add("getComponentAfter")) return null; |
| |
| return traverse(aContainer, aComponent, new Function<Pair<Container, Component>, Component>() { |
| public Component fun(Pair<Container, Component> param) { |
| return myWrappee.getComponentAfter(param.first, param.second); |
| } |
| }); |
| } |
| finally { |
| myRecursionGuard.clear(); |
| } |
| } |
| |
| @Override |
| public Component getComponentBefore(Container aContainer, Component aComponent) { |
| try { |
| if (!myRecursionGuard.add("getComponentBefore")) return null; |
| |
| return traverse(aContainer, aComponent, new Function<Pair<Container, Component>, Component>() { |
| public Component fun(Pair<Container, Component> param) { |
| return myWrappee.getComponentBefore(param.first, param.second); |
| } |
| }); |
| } |
| finally { |
| myRecursionGuard.clear(); |
| } |
| } |
| |
| private Component traverse(Container aContainer, Component aComponent, Function<Pair<Container, Component>, Component> func) { |
| Set<Component> loopGuard = new THashSet<Component>(); |
| do { |
| if (!loopGuard.add(aComponent)) return null; |
| aComponent = func.fun(Pair.create(aContainer, aComponent)); |
| } |
| while (aComponent != null && myExcludes.contains(aComponent)); |
| return aComponent; |
| } |
| |
| @Override |
| public Component getFirstComponent(Container aContainer) { |
| try { |
| if (!myRecursionGuard.add("getFirstComponent")) return null; |
| |
| Component result = myWrappee.getFirstComponent(aContainer); |
| if (result == null) return null; |
| return myExcludes.contains(result) ? getComponentAfter(aContainer, result) : result; |
| } |
| finally { |
| myRecursionGuard.clear(); |
| } |
| } |
| |
| @Override |
| public Component getLastComponent(Container aContainer) { |
| try { |
| if (!myRecursionGuard.add("getLastComponent")) return null; |
| |
| Component result = myWrappee.getLastComponent(aContainer); |
| if (result == null) return null; |
| return myExcludes.contains(result) ? getComponentBefore(aContainer, result) : result; |
| } |
| finally { |
| myRecursionGuard.clear(); |
| } |
| } |
| |
| @Override |
| public Component getDefaultComponent(Container aContainer) { |
| try { |
| if (!myRecursionGuard.add("getDefaultComponent")) return null; |
| |
| return getFirstComponent(aContainer); |
| } |
| finally { |
| myRecursionGuard.clear(); |
| } |
| } |
| } |