From 810074407e85cbcdb1e39a1410b1015afc4fa591 Mon Sep 17 00:00:00 2001 From: Denis Zhdanov Date: Tue, 29 Mar 2011 19:18:59 +0400 Subject: [PATCH] IDEA-67172 "Empty text" feature in EditorTextField Added ability to specify editor's 'placeholder text' --- .../injected/editor/EditorWindow.java | 5 +++ .../intellij/openapi/editor/ex/EditorEx.java | 11 +++++++ .../openapi/editor/impl/EditorImpl.java | 33 +++++++++++++++++++ .../src/com/intellij/ui/EditorTextField.java | 17 ++++++++++ 4 files changed, 66 insertions(+) diff --git a/platform/lang-impl/src/com/intellij/injected/editor/EditorWindow.java b/platform/lang-impl/src/com/intellij/injected/editor/EditorWindow.java index 9dc07440394e..0c6e623eedd0 100644 --- a/platform/lang-impl/src/com/intellij/injected/editor/EditorWindow.java +++ b/platform/lang-impl/src/com/intellij/injected/editor/EditorWindow.java @@ -625,4 +625,9 @@ public class EditorWindow extends UserDataHolderBase implements EditorEx { public void setSoftWrapAppliancePlace(@NotNull SoftWrapAppliancePlaces place) { myDelegate.setSoftWrapAppliancePlace(place); } + + @Override + public void setPlaceholder(@Nullable CharSequence text) { + myDelegate.setPlaceholder(text); + } } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/ex/EditorEx.java b/platform/platform-impl/src/com/intellij/openapi/editor/ex/EditorEx.java index 16a41791ad59..6a26f36dca1b 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/ex/EditorEx.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/ex/EditorEx.java @@ -164,4 +164,15 @@ public interface EditorEx extends Editor { * @param place soft wraps appliance appliance use-case */ void setSoftWrapAppliancePlace(@NotNull SoftWrapAppliancePlaces place); + + /** + * Allows to define 'placeholder text' for the current editor, i.e. virtual text that will be represented until + * any user data is entered and current editor is not focused. + *

+ * Feel free to see the detailed feature + * definition here. + * + * @param text virtual text to show until user data is entered or the editor is focused + */ + void setPlaceholder(@Nullable CharSequence text); } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java index d06e648d25de..b9d337a82627 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java @@ -259,6 +259,10 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi private char[] myPrefixText; private TextAttributes myPrefixAttributes; private final IndentsModel myIndentsModel; + + @Nullable + private CharSequence myPlaceholderText; + private int myLastPaintedPlaceholderWidth; static { ourCaretBlinkingCommand = new RepaintCursorCommand(); @@ -1549,6 +1553,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi paintLineMarkersSeparators(g, clip, docMarkup); paintLineMarkersSeparators(g, clip, myMarkupModel); paintText(g, clip); + paintPlaceholderText(g, clip); paintSegmentHighlightersBorderAndAfterEndOfLine(g, clip); BorderEffect borderEffect = new BorderEffect(this, g); borderEffect.paintHighlighters(getHighlighter()); @@ -1625,6 +1630,11 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi return myTextDrawingCallback; } + @Override + public void setPlaceholder(@Nullable CharSequence text) { + myPlaceholderText = text; + } + private Color getBackgroundColor(final TextAttributes attributes) { final Color attrColor = attributes.getBackgroundColor(); return attrColor == myScheme.getDefaultBackground() ? getBackgroundColor() : attrColor; @@ -2331,6 +2341,29 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi flushCachedChars(g); } + private void paintPlaceholderText(Graphics g, Rectangle clip) { + CharSequence hintText = myPlaceholderText; + if (myDocument.getTextLength() > 0 || hintText == null || hintText.length() == 0) { + return; + } + + if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() == myEditorComponent) { + // There is a possible case that placeholder text was painted and the editor gets focus now. We want to over-paint previuosly + // used placeholder text then. + myLastBackgroundColor = getBackgroundColor(); + myLastBackgroundPosition = new Point(0, 0); + myLastBackgroundWidth = myLastPaintedPlaceholderWidth; + flushBackground(g, clip); + } + else { + myLastPaintedPlaceholderWidth = drawString( + g, CharArrayUtil.fromSequence(hintText), 0, hintText.length(), new Point(0, 0), clip, null, null, Font.PLAIN, + myFoldingModel.getPlaceholderAttributes().getForegroundColor() + ); + flushCachedChars(g); + } + } + private boolean paintSelection() { return !isOneLineMode() || IJSwingUtilities.hasFocus(getContentComponent()); } diff --git a/platform/platform-impl/src/com/intellij/ui/EditorTextField.java b/platform/platform-impl/src/com/intellij/ui/EditorTextField.java index 410b47c0cf23..688c44987eb4 100644 --- a/platform/platform-impl/src/com/intellij/ui/EditorTextField.java +++ b/platform/platform-impl/src/com/intellij/ui/EditorTextField.java @@ -76,6 +76,7 @@ public class EditorTextField extends NonOpaquePanel implements DocumentListener, private boolean myCenterByHeight = true; private boolean myEnsureWillComputePreferredSize; private Dimension myPassivePreferredSize; + private CharSequence myHintText; public EditorTextField() { this(""); @@ -250,6 +251,20 @@ public class EditorTextField extends NonOpaquePanel implements DocumentListener, }); } + /** + * 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) { myEditor.getSelectionModel().setSelection(0, myDocument.getTextLength()); @@ -485,6 +500,8 @@ public class EditorTextField extends NonOpaquePanel implements DocumentListener, editor.putUserData(SUPPLEMENTARY_KEY, myIsSupplementary); editor.getContentComponent().setFocusCycleRoot(false); + + editor.setPlaceholder(myHintText); initOneLineMode(editor);