001package com.ganteater.ae.desktop.ui;
002
003import java.awt.BorderLayout;
004import java.awt.Color;
005import java.awt.event.FocusEvent;
006import java.awt.event.FocusListener;
007
008import javax.swing.JLabel;
009import javax.swing.border.EmptyBorder;
010import javax.swing.event.DocumentEvent;
011import javax.swing.event.DocumentListener;
012import javax.swing.text.Document;
013import javax.swing.text.JTextComponent;
014
015/**
016 *  The TextPrompt class will display a prompt over top of a text component when
017 *  the Document of the text field is empty. The Show property is used to
018 *  determine the visibility of the prompt.
019 *
020 *  The Font and foreground Color of the prompt will default to those properties
021 *  of the parent text component. You are free to change the properties after
022 *  class construction.
023 */
024public class TextPrompt extends JLabel
025        implements FocusListener, DocumentListener
026{
027        public enum Show
028        {
029                ALWAYS,
030                FOCUS_GAINED,
031                FOCUS_LOST;
032        }
033
034        private JTextComponent component;
035        private Document document;
036
037        private Show show;
038        private boolean showPromptOnce;
039        private int focusLost;
040
041        public TextPrompt(String text, JTextComponent component)
042        {
043                this(text, component, Show.ALWAYS);
044        }
045
046        public TextPrompt(String text, JTextComponent component, Show show)
047        {
048                this.component = component;
049                setShow( show );
050                document = component.getDocument();
051
052                setText( text );
053                setForeground( component.getForeground().brighter().brighter() );
054                setFont( component.getFont() );
055                setBorder( new EmptyBorder(component.getInsets()) );
056                setHorizontalAlignment(JLabel.LEADING);
057
058                component.addFocusListener( this );
059                document.addDocumentListener( this );
060
061                component.setLayout( new BorderLayout() );
062                component.add( this );
063                checkForPrompt();
064        }
065
066        /**
067         *  Convenience method to change the alpha value of the current foreground
068         *  Color to the specifice value.
069         *
070         *  @param alpha value in the range of 0 - 1.0.
071         */
072        public void changeAlpha(float alpha)
073        {
074                changeAlpha( (int)(alpha * 255) );
075        }
076
077        /**
078         *  Convenience method to change the alpha value of the current foreground
079         *  Color to the specifice value.
080         *
081         *  @param alpha value in the range of 0 - 255.
082         */
083        public void changeAlpha(int alpha)
084        {
085                alpha = alpha > 255 ? 255 : alpha < 0 ? 0 : alpha;
086
087                Color foreground = getForeground();
088                int red = foreground.getRed();
089                int green = foreground.getGreen();
090                int blue = foreground.getBlue();
091
092                Color withAlpha = new Color(red, green, blue, alpha);
093                super.setForeground( withAlpha );
094        }
095
096        /**
097         *  Convenience method to change the style of the current Font. The style
098         *  values are found in the Font class. Common values might be:
099         *  Font.BOLD, Font.ITALIC and Font.BOLD + Font.ITALIC.
100         *
101         *  @param style value representing the the new style of the Font.
102         */
103        public void changeStyle(int style)
104        {
105                setFont( getFont().deriveFont( style ) );
106        }
107
108        /**
109         *  Get the Show property
110         *
111         *  @return the Show property.
112         */
113        public Show getShow()
114        {
115                return show;
116        }
117
118        /**
119         *  Set the prompt Show property to control when the promt is shown.
120         *  Valid values are:
121         *
122         *  Show.AWLAYS (default) - always show the prompt
123         *  Show.Focus_GAINED - show the prompt when the component gains focus
124         *      (and hide the prompt when focus is lost)
125         *  Show.Focus_LOST - show the prompt when the component loses focus
126         *      (and hide the prompt when focus is gained)
127         *
128         *  @param show a valid Show enum
129         */
130        public void setShow(Show show)
131        {
132                this.show = show;
133        }
134
135        /**
136         *  Get the showPromptOnce property
137         *
138         *  @return the showPromptOnce property.
139         */
140        public boolean getShowPromptOnce()
141        {
142                return showPromptOnce;
143        }
144
145        /**
146         *  Show the prompt once. Once the component has gained/lost focus
147         *  once, the prompt will not be shown again.
148         *
149         *  @param showPromptOnce  when true the prompt will only be shown once,
150         *                         otherwise it will be shown repeatedly.
151         */
152        public void setShowPromptOnce(boolean showPromptOnce)
153        {
154                this.showPromptOnce = showPromptOnce;
155        }
156
157        /**
158         *      Check whether the prompt should be visible or not. The visibility
159         *  will change on updates to the Document and on focus changes.
160         */
161        private void checkForPrompt()
162        {
163                //  Text has been entered, remove the prompt
164
165                if (document.getLength() > 0)
166                {
167                        setVisible( false );
168                        return;
169                }
170
171                //  Prompt has already been shown once, remove it
172
173                if (showPromptOnce && focusLost > 0)
174                {
175                        setVisible(false);
176                        return;
177                }
178
179                //  Check the Show property and component focus to determine if the
180                //  prompt should be displayed.
181
182        if (component.hasFocus())
183        {
184                if (show == Show.ALWAYS
185                ||  show ==     Show.FOCUS_GAINED)
186                        setVisible( true );
187                else
188                        setVisible( false );
189        }
190        else
191        {
192                if (show == Show.ALWAYS
193                ||  show ==     Show.FOCUS_LOST)
194                        setVisible( true );
195                else
196                        setVisible( false );
197        }
198        }
199
200//  Implement FocusListener
201
202        public void focusGained(FocusEvent e)
203        {
204                checkForPrompt();
205        }
206
207        public void focusLost(FocusEvent e)
208        {
209                focusLost++;
210                checkForPrompt();
211        }
212
213//  Implement DocumentListener
214
215        public void insertUpdate(DocumentEvent e)
216        {
217                checkForPrompt();
218        }
219
220        public void removeUpdate(DocumentEvent e)
221        {
222                checkForPrompt();
223        }
224
225        public void changedUpdate(DocumentEvent e) {}
226}