blob: 27b1a2be56aebb1b1c2037a4be94aaf4e7de8fa9 [file] [log] [blame]
/*
* Copyright 2000-2014 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.codeInsight.daemon.DaemonCodeAnalyzer;
import com.intellij.ide.ui.laf.darcula.ui.DarculaEditorTextFieldBorder;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.DataProvider;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.command.UndoConfirmationPolicy;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.*;
import com.intellij.openapi.editor.colors.*;
import com.intellij.openapi.editor.colors.impl.DelegateColorScheme;
import com.intellij.openapi.editor.event.DocumentEvent;
import com.intellij.openapi.editor.event.DocumentListener;
import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.editor.ex.FocusChangeListener;
import com.intellij.openapi.editor.highlighter.EditorHighlighterFactory;
import com.intellij.openapi.editor.impl.EditorImpl;
import com.intellij.openapi.editor.markup.TextAttributes;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.FileTypes;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.wm.ex.AbstractDelegatingToRootTraversalPolicy;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import com.intellij.ui.components.panels.NonOpaquePanel;
import com.intellij.util.IJSwingUtilities;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.MacUIUtil;
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.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;
/**
* @author max
*/
public class EditorTextField extends NonOpaquePanel implements DocumentListener, TextComponent, DataProvider,
DocumentBasedComponent, FocusListener {
private static final Logger LOG = Logger.getInstance("#com.intellij.ui.EditorTextField");
public static final Key<Boolean> SUPPLEMENTARY_KEY = Key.create("Supplementary");
private Document myDocument;
private final Project myProject;
private FileType myFileType;
private EditorEx myEditor = null;
private Component myNextFocusable = null;
private boolean myWholeTextSelected = false;
private final List<DocumentListener> myDocumentListeners = ContainerUtil.createLockFreeCopyOnWriteList();
private final List<FocusListener> myFocusListeners = ContainerUtil.createLockFreeCopyOnWriteList();
private boolean myIsListenerInstalled = false;
private boolean myIsViewer;
private boolean myIsSupplementary;
private boolean myInheritSwingFont = true;
private Color myEnforcedBgColor = null;
private boolean myOneLineMode; // use getter to access this field! It is allowed to override getter and change initial behaviour
private boolean myEnsureWillComputePreferredSize;
private Dimension myPassivePreferredSize;
private CharSequence myHintText;
private boolean myIsRendererWithSelection = false;
private Color myRendererBg;
private Color myRendererFg;
private int myPreferredWidth = -1;
private final List<EditorSettingsProvider> mySettingsProviders = new ArrayList<EditorSettingsProvider>();
public EditorTextField() {
this("");
}
public EditorTextField(@NotNull String text) {
this(EditorFactory.getInstance().createDocument(text), null, FileTypes.PLAIN_TEXT);
}
public EditorTextField(@NotNull String text, Project project, FileType fileType) {
this(EditorFactory.getInstance().createDocument(text), project, fileType, false, true);
}
public EditorTextField(Document document, Project project, FileType fileType) {
this(document, project, fileType, false, true);
}
public EditorTextField(Document document, Project project, FileType fileType, boolean isViewer) {
this(document, project, fileType, isViewer, true);
}
public EditorTextField(Document document, Project project, FileType fileType, boolean isViewer, boolean oneLineMode) {
myOneLineMode = oneLineMode;
myIsViewer = isViewer;
setDocument(document);
myProject = project;
myFileType = fileType;
setLayout(new BorderLayout());
enableEvents(AWTEvent.KEY_EVENT_MASK);
// todo[dsl,max]
setFocusable(true);
// dsl: this is a weird way of doing things....
super.addFocusListener(new FocusListener() {
@Override
public void focusGained(FocusEvent e) {
requestFocus();
}
@Override
public void focusLost(FocusEvent e) {
}
});
setFocusTraversalPolicyProvider(true);
DelegatingToRootTraversalPolicy policy =
SystemInfo.isJavaVersionAtLeast("1.7") ? new Jdk7DelegatingToRootTraversalPolicy() : new DelegatingToRootTraversalPolicy();
setFocusTraversalPolicy(policy);
setFont(UIManager.getFont("TextField.font"));
}
public void setSupplementary(boolean supplementary) {
myIsSupplementary = supplementary;
if (myEditor != null) {
myEditor.putUserData(SUPPLEMENTARY_KEY, supplementary);
}
}
public void setFontInheritedFromLAF(boolean b) {
myInheritSwingFont = b;
setDocument(myDocument); // reinit editor.
}
@Override
public String getText() {
return myDocument.getText();
}
@Override
public void setBackground(Color bg) {
super.setBackground(bg);
myEnforcedBgColor = bg;
if (myEditor != null) {
myEditor.setBackgroundColor(bg);
}
}
@Override
public JComponent getComponent() {
return this;
}
public void addDocumentListener(DocumentListener listener) {
myDocumentListeners.add(listener);
installDocumentListener();
}
public void removeDocumentListener(DocumentListener listener) {
myDocumentListeners.remove(listener);
uninstallDocumentListener(false);
}
@Override
public void beforeDocumentChange(DocumentEvent event) {
for (DocumentListener documentListener : myDocumentListeners) {
documentListener.beforeDocumentChange(event);
}
}
@Override
public void documentChanged(DocumentEvent event) {
for (DocumentListener documentListener : myDocumentListeners) {
documentListener.documentChanged(event);
}
}
public Project getProject() {
return myProject;
}
@Override
public Document getDocument() {
return myDocument;
}
public void setDocument(Document document) {
if (myDocument != null) {
uninstallDocumentListener(true);
}
myDocument = document;
installDocumentListener();
if (myEditor == null) return;
//MainWatchPanel watches the oldEditor's focus in order to remove debugger combobox when focus is lost
//we should first transfer focus to new oldEditor and only then remove current oldEditor
//MainWatchPanel check that oldEditor.getParent == newEditor.getParent and does not remove oldEditor in such cases
boolean isFocused = isFocusOwner();
Editor editor = myEditor;
myEditor = createEditor();
releaseEditor(editor);
add(myEditor.getComponent(), BorderLayout.CENTER);
validate();
if (isFocused) {
myEditor.getContentComponent().requestFocus();
}
}
private void installDocumentListener() {
if (myDocument != null && !myDocumentListeners.isEmpty() && !myIsListenerInstalled) {
myIsListenerInstalled = true;
myDocument.addDocumentListener(this);
}
}
private void uninstallDocumentListener(boolean force) {
if (myDocument != null && myIsListenerInstalled && (force || myDocumentListeners.isEmpty())) {
myIsListenerInstalled = false;
myDocument.removeDocumentListener(this);
}
}
public void setText(@Nullable final String text) {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
CommandProcessor.getInstance().executeCommand(getProject(), new Runnable() {
@Override
public void run() {
myDocument.replaceString(0, myDocument.getTextLength(), text == null ? "" : text);
if (myEditor != null) {
final CaretModel caretModel = myEditor.getCaretModel();
if (caretModel.getOffset() >= myDocument.getTextLength()) {
caretModel.moveToOffset(myDocument.getTextLength());
}
}
}
}, null, null, UndoConfirmationPolicy.DEFAULT, getDocument());
}
});
}
/**
* Allows to define {@link EditorEx#setPlaceholder(CharSequence) editor's placeholder}. The trick here is that the editor
* is instantiated lazily by the editor text field and provided placeholder text is applied to the editor during its
* actual construction then.
*
* @param text {@link EditorEx#setPlaceholder(CharSequence) editor's placeholder} text to use
*/
public void setPlaceholder(@Nullable CharSequence text) {
myHintText = text;
if (myEditor != null) {
myEditor.setPlaceholder(text);
}
}
public void selectAll() {
if (myEditor != null) {
doSelectAll(myEditor);
}
else {
myWholeTextSelected = true;
}
}
private static void doSelectAll(@NotNull Editor editor) {
editor.getCaretModel().removeSecondaryCarets();
editor.getCaretModel().getPrimaryCaret().setSelection(0, editor.getDocument().getTextLength(), false);
}
public void removeSelection() {
if (myEditor != null) {
myEditor.getSelectionModel().removeSelection();
}
else {
myWholeTextSelected = false;
}
}
public CaretModel getCaretModel() {
return myEditor.getCaretModel();
}
@Override
public boolean isFocusOwner() {
if (myEditor != null) {
return IJSwingUtilities.hasFocus(myEditor.getContentComponent());
}
return super.isFocusOwner();
}
void releaseEditor(@NotNull final Editor editor) {
if (myProject != null && myIsViewer) {
final PsiFile psiFile = PsiDocumentManager.getInstance(myProject).getPsiFile(editor.getDocument());
if (psiFile != null) {
DaemonCodeAnalyzer.getInstance(myProject).setHighlightingEnabled(psiFile, true);
}
}
remove(editor.getComponent());
editor.getContentComponent().removeFocusListener(this);
final Application application = ApplicationManager.getApplication();
final Runnable runnable = new Runnable() {
@Override
public void run() {
if (!editor.isDisposed()) {
EditorFactory.getInstance().releaseEditor(editor);
}
}
};
if (application.isUnitTestMode() || application.isDispatchThread()) {
runnable.run();
}
else {
application.invokeLater(runnable);
}
}
@Override
public void addNotify() {
releaseEditor();
boolean isFocused = isFocusOwner();
initEditor();
super.addNotify();
if (myNextFocusable != null) {
myEditor.getContentComponent().setNextFocusableComponent(myNextFocusable);
myNextFocusable = null;
}
revalidate();
if (isFocused) {
requestFocus();
}
}
private void initEditor() {
myEditor = createEditor();
final JComponent component = myEditor.getComponent();
add(component, BorderLayout.CENTER);
}
@Override
public void removeNotify() {
super.removeNotify();
releaseEditor();
}
private void releaseEditor() {
if (myEditor == null) return;
final Editor editor = myEditor;
myEditor = null;
// releasing an editor implies removing it from a component hierarchy
// invokeLater in required because releaseEditor() may be called from
// removeNotify(), so we need to let swing complete its removeNotify() chain
// and only then execute another removal from the hierarchy. Otherwise
// swing goes nuts because of nested removals and indices get corrupted
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
releaseEditor(editor);
}
});
}
@Override
public void setFont(Font font) {
super.setFont(font);
if (myEditor != null) {
setupEditorFont(myEditor);
}
}
/**
* This option will be used for embedded editor creation. It's ok to override this method if you don't want to configure
* it using class constructor
* @return is one line mode or not
*/
protected boolean isOneLineMode() {
return myOneLineMode;
}
protected void initOneLineMode(final EditorEx editor) {
final boolean isOneLineMode = isOneLineMode();
// set mode in editor
editor.setOneLineMode(isOneLineMode);
EditorColorsManager colorsManager = EditorColorsManager.getInstance();
final EditorColorsScheme defaultScheme =
UIUtil.isUnderDarcula() ? colorsManager.getGlobalScheme() : colorsManager.getScheme(EditorColorsManager.DEFAULT_SCHEME_NAME);
EditorColorsScheme customGlobalScheme = isOneLineMode? defaultScheme : null;
editor.setColorsScheme(editor.createBoundColorSchemeDelegate(customGlobalScheme));
EditorColorsScheme colorsScheme = editor.getColorsScheme();
colorsScheme.setColor(EditorColors.CARET_ROW_COLOR, null);
editor.setColorsScheme(new DelegateColorScheme(colorsScheme) {
@Override
public TextAttributes getAttributes(TextAttributesKey key) {
final TextAttributes attributes = super.getAttributes(key);
if (!isEnabled() && attributes != null) {
return new TextAttributes(UIUtil.getInactiveTextColor(), attributes.getBackgroundColor(), attributes.getEffectColor(), attributes.getEffectType(), attributes.getFontType());
}
return attributes;
}
});
// color scheme settings:
setupEditorFont(editor);
updateBorder(editor);
editor.setBackgroundColor(getBackgroundColor(isEnabled(), colorsScheme));
}
public void setOneLineMode(boolean oneLineMode) {
myOneLineMode = oneLineMode;
}
protected EditorEx createEditor() {
LOG.assertTrue(myDocument != null);
final EditorFactory factory = EditorFactory.getInstance();
EditorEx editor;
if (myIsViewer) {
editor = myProject == null ? (EditorEx)factory.createViewer(myDocument) : (EditorEx)factory.createViewer(myDocument, myProject);
}
else {
editor = myProject == null ? (EditorEx)factory.createEditor(myDocument) : (EditorEx)factory.createEditor(myDocument, myProject);
}
final EditorSettings settings = editor.getSettings();
settings.setAdditionalLinesCount(0);
settings.setAdditionalColumnsCount(1);
settings.setRightMarginShown(false);
settings.setRightMargin(-1);
settings.setFoldingOutlineShown(false);
settings.setLineNumbersShown(false);
settings.setLineMarkerAreaShown(false);
settings.setIndentGuidesShown(false);
settings.setVirtualSpace(false);
settings.setWheelFontChangeEnabled(false);
editor.setHorizontalScrollbarVisible(false);
editor.setVerticalScrollbarVisible(false);
editor.setCaretEnabled(!myIsViewer);
settings.setLineCursorWidth(1);
if (myProject != null && myIsViewer) {
final PsiFile psiFile = PsiDocumentManager.getInstance(myProject).getPsiFile(editor.getDocument());
if (psiFile != null) {
DaemonCodeAnalyzer.getInstance(myProject).setHighlightingEnabled(psiFile, false);
}
}
if (myProject != null && myFileType != null) {
editor.setHighlighter(EditorHighlighterFactory.getInstance().createEditorHighlighter(myProject, myFileType));
}
final EditorColorsScheme colorsScheme = editor.getColorsScheme();
colorsScheme.setColor(EditorColors.CARET_ROW_COLOR, null);
if (!isEnabled()) {
editor.setColorsScheme(new DelegateColorScheme(colorsScheme) {
@Override
public Color getColor(ColorKey key) {
return super.getColor(key);
}
@Override
public TextAttributes getAttributes(TextAttributesKey key) {
final TextAttributes attributes = super.getAttributes(key);
if (!isEnabled()) {
return new TextAttributes(UIUtil.getInactiveTextColor(), attributes.getBackgroundColor(), attributes.getEffectColor(), attributes.getEffectType(), attributes.getFontType());
}
return attributes;
}
});
}
editor.setOneLineMode(myOneLineMode);
editor.getCaretModel().moveToOffset(myDocument.getTextLength());
if (!shouldHaveBorder()) {
editor.setBorder(null);
}
if (myIsViewer) {
editor.getSelectionModel().removeSelection();
}
else if (myWholeTextSelected) {
doSelectAll(editor);
myWholeTextSelected = false;
}
editor.putUserData(SUPPLEMENTARY_KEY, myIsSupplementary);
editor.getContentComponent().setFocusCycleRoot(false);
editor.getContentComponent().addFocusListener(this);
editor.setPlaceholder(myHintText);
initOneLineMode(editor);
if (myIsRendererWithSelection) {
((EditorImpl)editor).setPaintSelection(true);
editor.getColorsScheme().setColor(EditorColors.SELECTION_BACKGROUND_COLOR, myRendererBg);
editor.getColorsScheme().setColor(EditorColors.SELECTION_FOREGROUND_COLOR, myRendererFg);
editor.getSelectionModel().setSelection(0, myDocument.getTextLength());
editor.setBackgroundColor(myRendererBg);
}
for (EditorSettingsProvider provider : mySettingsProviders) {
provider.customizeSettings(editor);
}
return editor;
}
protected void updateBorder(@NotNull final EditorEx editor) {
if (editor.isOneLineMode()
&& !Boolean.TRUE.equals(getClientProperty("JComboBox.isTableCellEditor"))
&& (SwingUtilities.getAncestorOfClass(JTable.class, this) == null || Boolean.TRUE.equals(getClientProperty("JBListTable.isTableCellEditor")))) {
final Container parent = getParent();
if (parent instanceof JTable || parent instanceof CellRendererPane) return;
if (UIUtil.isUnderAquaLookAndFeel() || UIUtil.isUnderDarcula() || UIUtil.isUnderIntelliJLaF()) {
editor.setBorder(UIUtil.isUnderDarcula() || UIUtil.isUnderIntelliJLaF() ? new DarculaEditorTextFieldBorder() : new MacUIUtil.EditorTextFieldBorder(this));
editor.addFocusListener(new FocusChangeListener() {
@Override
public void focusGained(Editor editor) {
repaint();
}
@Override
public void focusLost(Editor editor) {
repaint();
}
});
}
else if (UIUtil.isUnderAlloyLookAndFeel() || UIUtil.isUnderJGoodiesLookAndFeel()) {
editor.setBorder(BorderFactory.createCompoundBorder(UIUtil.getTextFieldBorder(), BorderFactory.createEmptyBorder(1, 1, 1, 1)));
}
else {
editor.setBorder(BorderFactory.createCompoundBorder(UIUtil.getTextFieldBorder(), BorderFactory.createEmptyBorder(2, 2, 2, 2)));
}
}
}
private void setupEditorFont(final EditorEx editor) {
if (myInheritSwingFont) {
editor.getColorsScheme().setEditorFontName(getFont().getFontName());
editor.getColorsScheme().setEditorFontSize(getFont().getSize());
}
}
protected boolean shouldHaveBorder() {
return true;
}
@Override
public void setEnabled(boolean enabled) {
if (isEnabled() != enabled) {
super.setEnabled(enabled);
myIsViewer = !enabled;
EditorEx editor = myEditor;
if (editor == null) {
return;
}
releaseEditor(editor);
initEditor();
revalidate();
}
}
@Override
public Color getBackground() {
final Color color = getBackgroundColor(isEnabled(), EditorColorsManager.getInstance().getGlobalScheme());
return color != null ? color : super.getBackground();
}
private Color getBackgroundColor(boolean enabled, final EditorColorsScheme colorsScheme){
if (myEnforcedBgColor != null) return myEnforcedBgColor;
if (UIUtil.getParentOfType(CellRendererPane.class, this) != null && (UIUtil.isUnderDarcula() || UIUtil.isUnderIntelliJLaF())) {
return getParent().getBackground();
}
if (UIUtil.isUnderDarcula() || UIUtil.isUnderIntelliJLaF()) return UIUtil.getTextFieldBackground();
return enabled
? colorsScheme.getDefaultBackground()
: UIUtil.getInactiveTextFieldBackgroundColor();
}
@Override
protected void addImpl(Component comp, Object constraints, int index) {
if (myEditor == null || comp != myEditor.getComponent()) {
assert false : "You are not allowed to add anything to EditorTextField";
}
super.addImpl(comp, constraints, index);
}
@Override
public Dimension getPreferredSize() {
if (super.isPreferredSizeSet()) {
return super.getPreferredSize();
}
boolean toReleaseEditor = false;
if (myEditor == null && myEnsureWillComputePreferredSize) {
myEnsureWillComputePreferredSize = false;
initEditor();
toReleaseEditor = true;
}
Dimension size = new Dimension(100, 20);
if (myEditor != null) {
final Dimension preferredSize = new Dimension(myEditor.getComponent().getPreferredSize());
if (myPreferredWidth != -1) {
preferredSize.width = myPreferredWidth;
}
final Insets insets = getInsets();
if (insets != null) {
preferredSize.width += insets.left;
preferredSize.width += insets.right;
preferredSize.height += insets.top;
preferredSize.height += insets.bottom;
}
size = preferredSize;
} else if (myPassivePreferredSize != null) {
size = myPassivePreferredSize;
}
if (toReleaseEditor) {
releaseEditor();
myPassivePreferredSize = size;
}
return size;
}
@Override
public Dimension getMinimumSize() {
if (super.isMinimumSizeSet()) {
return super.getMinimumSize();
}
Dimension size = new Dimension(1, 20);
if (myEditor != null) {
size.height = myEditor.getLineHeight();
size = UIUtil.addInsets(size, getInsets());
size = UIUtil.addInsets(size, myEditor.getInsets());
}
return size;
}
public void setPreferredWidth(int preferredWidth) {
myPreferredWidth = preferredWidth;
}
@Override
public Component getNextFocusableComponent() {
if (myEditor == null && myNextFocusable == null) return super.getNextFocusableComponent();
if (myEditor == null) return myNextFocusable;
return myEditor.getContentComponent().getNextFocusableComponent();
}
@Override
public void setNextFocusableComponent(Component aComponent) {
if (myEditor != null) {
myEditor.getContentComponent().setNextFocusableComponent(aComponent);
return;
}
myNextFocusable = aComponent;
}
@Override
protected boolean processKeyBinding(KeyStroke ks, KeyEvent e, int condition, boolean pressed) {
if (e.isConsumed() || myEditor != null && !myEditor.processKeyTyped(e)) {
return super.processKeyBinding(ks, e, condition, pressed);
}
return true;
}
@Override
public void requestFocus() {
if (myEditor != null) {
myEditor.getContentComponent().requestFocus();
myEditor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
}
else {
super.requestFocus();
}
}
@Override
public boolean requestFocusInWindow() {
if (myEditor != null) {
final boolean b = myEditor.getContentComponent().requestFocusInWindow();
myEditor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
return b;
}
else {
return super.requestFocusInWindow();
}
}
/**
*
* @return null if the editor is not initialized (e.g. if the field is not added to a container)
* @see #createEditor()
* @see #addNotify()
*/
@Nullable
public Editor getEditor() {
return myEditor;
}
public JComponent getFocusTarget() {
return myEditor == null ? this : myEditor.getContentComponent();
}
@Override
public synchronized void addFocusListener(FocusListener l) {
myFocusListeners.add(l);
}
@Override
public synchronized void removeFocusListener(FocusListener l) {
myFocusListeners.remove(l);
}
@Override
public void focusGained(FocusEvent e) {
for (FocusListener listener : myFocusListeners) {
listener.focusGained(e);
}
}
@Override
public void focusLost(FocusEvent e) {
for (FocusListener listener : myFocusListeners) {
listener.focusLost(e);
}
}
@Override
public Object getData(String dataId) {
if (myEditor != null && myEditor.isRendererMode()) return null;
if (CommonDataKeys.EDITOR.is(dataId)) {
return myEditor;
}
return null;
}
public void setFileType(FileType fileType) {
setNewDocumentAndFileType(fileType, getDocument());
}
public void setNewDocumentAndFileType(final FileType fileType, Document document) {
myFileType = fileType;
setDocument(document);
}
public void ensureWillComputePreferredSize() {
myEnsureWillComputePreferredSize = true;
}
public void setAsRendererWithSelection(Color backgroundColor, Color foregroundColor) {
myIsRendererWithSelection = true;
myRendererBg = backgroundColor;
myRendererFg = foregroundColor;
}
public void addSettingsProvider(EditorSettingsProvider provider) {
mySettingsProviders.add(provider);
}
public boolean removeSettingsProvider(EditorSettingsProvider provider) {
return mySettingsProviders.remove(provider);
}
private static class Jdk7DelegatingToRootTraversalPolicy extends DelegatingToRootTraversalPolicy {
private boolean invokedFromBeforeOrAfter;
@Override
public Component getFirstComponent(Container aContainer) {
return getDefaultComponent(aContainer);
}
@Override
public Component getLastComponent(Container aContainer) {
return getDefaultComponent(aContainer);
}
@Override
public Component getComponentAfter(Container aContainer, Component aComponent) {
invokedFromBeforeOrAfter = true;
Component after;
try {
after = super.getComponentAfter(aContainer, aComponent);
} finally {
invokedFromBeforeOrAfter = false;
}
return after != aComponent? after: null; // escape our container
}
@Override
public Component getComponentBefore(Container aContainer, Component aComponent) {
Component before = super.getComponentBefore(aContainer, aComponent);
return before != aComponent ? before: null; // escape our container
}
@Override
public Component getDefaultComponent(Container aContainer) {
if (invokedFromBeforeOrAfter) return null; // escape our container
return super.getDefaultComponent(aContainer);
}
}
private static class DelegatingToRootTraversalPolicy extends AbstractDelegatingToRootTraversalPolicy {
@Override
public Component getDefaultComponent(final Container aContainer) {
final Editor editor = aContainer instanceof EditorTextField ? ((EditorTextField)aContainer).getEditor():null;
if (editor != null) return editor.getContentComponent();
return aContainer;
}
}
}