001package org.jdesktop.swingx.prompt; 002 003import java.awt.Color; 004import java.awt.Font; 005 006import javax.swing.text.JTextComponent; 007 008import org.jdesktop.swingx.JXFormattedTextField; 009import org.jdesktop.swingx.JXTextArea; 010import org.jdesktop.swingx.JXTextField; 011import org.jdesktop.swingx.painter.Painter; 012import org.jdesktop.swingx.painter.Painters; 013import org.jdesktop.swingx.plaf.PromptTextUI; 014import org.jdesktop.swingx.plaf.TextUIWrapper; 015 016/** 017 * <p> 018 * Sets prompt text, foreground, background and {@link FocusBehavior} properties 019 * on a JTextComponent by calling 020 * {@link JTextComponent#putClientProperty(Object, Object)}. These properties 021 * are used by {@link PromptTextUI} instances to render the prompt of a text 022 * component. 023 * </p> 024 * 025 * <p> 026 * This class is used by {@link JXTextField}, {@link JXFormattedTextField} and 027 * {@link JXTextArea} to get and set prompt properties. {@link PromptTextUI} 028 * retrieves these properties using PromptSupport. 029 * </p> 030 * 031 * @see JXTextField 032 * @see JXFormattedTextField 033 * @see JXTextArea 034 * @see PromptTextUI 035 * 036 * @author Peter Weishapl <petw@gmx.net> 037 * @author Karl Schaefer 038 */ 039public final class PromptSupport { 040 /** 041 * The prompt text property. 042 */ 043 public static final String PROMPT = "promptText"; 044 045 /** 046 * The color of the prompt text property. 047 */ 048 public static final String FOREGROUND = "promptForeground"; 049 050 /** 051 * The prompt background property. 052 */ 053 public static final String BACKGROUND = "promptBackground"; 054 055 /** 056 * The prompt background property. 057 */ 058 public static final String BACKGROUND_PAINTER = "promptBackgroundPainter"; 059 060 /** 061 * The focus behavior property. 062 */ 063 public static final String FOCUS_BEHAVIOR = "focusBehavior"; 064 065 /** 066 * The font style property, if different from the components font. 067 */ 068 public static final String FONT_STYLE = "promptFontStyle"; 069 070 /** 071 * <p> 072 * Determines how the {@link JTextComponent} is rendered when focused and no 073 * text is present. 074 * </p> 075 */ 076 public static enum FocusBehavior { 077 /** 078 * Keep the prompt text visible. 079 */ 080 SHOW_PROMPT, 081 /** 082 * Highlight the prompt text as it would be selected. 083 */ 084 HIGHLIGHT_PROMPT, 085 /** 086 * Hide the prompt text. 087 */ 088 HIDE_PROMPT 089 }; 090 091 private PromptSupport() { 092 //prevent instantiation 093 } 094 095 /** 096 * <p> 097 * Convenience method to set the <code>promptText</code> and 098 * <code>promptTextColor</code> on a {@link JTextComponent}. 099 * </p> 100 * <p> 101 * If <code>stayOnUIChange</code> is true, The prompt support will stay 102 * installed, even when the text components UI changes. See 103 * {@link #install(JTextComponent, boolean)}. 104 * </p> 105 * 106 * @param promptText 107 * @param promptForeground 108 * @param promptBackground 109 * @param textComponent 110 */ 111 public static void init(String promptText, Color promptForeground, Color promptBackground, 112 final JTextComponent textComponent) { 113 if (promptText != null && promptText.length() > 0) { 114 setPrompt(promptText, textComponent); 115 } 116 if (promptForeground != null) { 117 setForeground(promptForeground, textComponent); 118 } 119 if (promptBackground != null) { 120 setBackground(promptBackground, textComponent); 121 } 122 } 123 124 /** 125 * Get the {@link FocusBehavior} of <code>textComponent</code>. 126 * 127 * @param textComponent 128 * @return the {@link FocusBehavior} or {@link FocusBehavior#HIDE_PROMPT} if 129 * none is set 130 */ 131 public static FocusBehavior getFocusBehavior(JTextComponent textComponent) { 132 FocusBehavior fb = (FocusBehavior) textComponent.getClientProperty(FOCUS_BEHAVIOR); 133 if (fb == null) { 134 fb = FocusBehavior.HIDE_PROMPT; 135 } 136 return fb; 137 } 138 139 /** 140 * Sets the {@link FocusBehavior} on <code>textComponent</code> and 141 * repaints the component to reflect the changes, if it is the focus owner. 142 * 143 * @param focusBehavior 144 * @param textComponent 145 */ 146 public static void setFocusBehavior(FocusBehavior focusBehavior, JTextComponent textComponent) { 147 textComponent.putClientProperty(FOCUS_BEHAVIOR, focusBehavior); 148 if (textComponent.isFocusOwner()) { 149 textComponent.repaint(); 150 } 151 } 152 153 /** 154 * Get the prompt text of <code>textComponent</code>. 155 * 156 * @param textComponent 157 * @return the prompt text 158 */ 159 public static String getPrompt(JTextComponent textComponent) { 160 return (String) textComponent.getClientProperty(PROMPT); 161 } 162 163 /** 164 * <p> 165 * Sets the prompt text on <code>textComponent</code>. Also sets the 166 * tooltip text to the prompt text if <code>textComponent</code> has no 167 * tooltip text or the current tooltip text is the same as the current 168 * prompt text. 169 * </p> 170 * <p> 171 * Calls {@link #install(JTextComponent)} to ensure that the 172 * <code>textComponent</code>s UI is wrapped by the appropriate 173 * {@link PromptTextUI}. 174 * </p> 175 * 176 * @param promptText 177 * @param textComponent 178 */ 179 public static void setPrompt(String promptText, JTextComponent textComponent) { 180 TextUIWrapper.getDefaultWrapper().install(textComponent, true); 181 182 // display prompt as tooltip by default 183 if (textComponent.getToolTipText() == null || textComponent.getToolTipText().equals(getPrompt(textComponent))) { 184 textComponent.setToolTipText(promptText); 185 } 186 187 textComponent.putClientProperty(PROMPT, promptText); 188 textComponent.repaint(); 189 } 190 191 /** 192 * Get the foreground color of the prompt text. If no color has been set, 193 * the <code>textComponent</code>s disabled text color will be returned. 194 * 195 * @param textComponent 196 * @return the color of the prompt text or 197 * {@link JTextComponent#getDisabledTextColor()} if none is set 198 */ 199 public static Color getForeground(JTextComponent textComponent) { 200 if (textComponent.getClientProperty(FOREGROUND) == null) { 201 return textComponent.getDisabledTextColor(); 202 } 203 return (Color) textComponent.getClientProperty(FOREGROUND); 204 } 205 206 /** 207 * Sets the foreground color of the prompt on <code>textComponent</code> 208 * and repaints the component to reflect the changes. This color will be 209 * used when no text is present. 210 * 211 * @param promptTextColor 212 * @param textComponent 213 */ 214 public static void setForeground(Color promptTextColor, JTextComponent textComponent) { 215 textComponent.putClientProperty(FOREGROUND, promptTextColor); 216 textComponent.repaint(); 217 } 218 219 /** 220 * Get the background color of the <code>textComponent</code>, when no 221 * text is present. If no color has been set, the <code>textComponent</code>s 222 * background color color will be returned. 223 * 224 * @param textComponent 225 * @return the the background color of the text component, when no text is 226 * present 227 */ 228 public static Color getBackground(JTextComponent textComponent) { 229 if (textComponent.getClientProperty(BACKGROUND) == null) { 230 return textComponent.getBackground(); 231 } 232 return (Color) textComponent.getClientProperty(BACKGROUND); 233 } 234 235 /** 236 * <p> 237 * Sets the prompts background color on <code>textComponent</code> and 238 * repaints the component to reflect the changes. This background color will 239 * only be used when no text is present. 240 * </p> 241 * <p> 242 * Calls {@link #install(JTextComponent)} to ensure that the 243 * <code>textComponent</code>s UI is wrapped by the appropriate 244 * {@link PromptTextUI}. 245 * </p> 246 * 247 * @param background 248 * @param textComponent 249 */ 250 public static void setBackground(Color background, JTextComponent textComponent) { 251 TextUIWrapper.getDefaultWrapper().install(textComponent, true); 252 253 textComponent.putClientProperty(BACKGROUND, background); 254 textComponent.repaint(); 255 } 256 257 /** 258 * Get the background painter of the <code>textComponent</code>, when no 259 * text is present. If no painter has been set, then {@code null} will be returned. 260 * 261 * @param textComponent 262 * @return the background painter of the text component 263 */ 264 @SuppressWarnings("unchecked") 265 public static <T extends JTextComponent> Painter<? super T> getBackgroundPainter(T textComponent) { 266 Painter<? super T> painter = (Painter<? super T>) textComponent.getClientProperty(BACKGROUND_PAINTER); 267 268 if (painter == null) { 269 painter = Painters.EMPTY_PAINTER; 270 } 271 272 return painter; 273 } 274 275 /** 276 * <p> 277 * Sets the prompts background painter on <code>textComponent</code> and 278 * repaints the component to reflect the changes. This background painter will 279 * only be used when no text is present. 280 * </p> 281 * <p> 282 * Calls {@link #install(JTextComponent)} to ensure that the 283 * <code>textComponent</code>s UI is wrapped by the appropriate 284 * {@link PromptTextUI}. 285 * </p> 286 * 287 * @param background 288 * @param textComponent 289 */ 290 public static <T extends JTextComponent> void setBackgroundPainter(Painter<? super T> background, T textComponent) { 291 TextUIWrapper.getDefaultWrapper().install(textComponent, true); 292 293 textComponent.putClientProperty(BACKGROUND_PAINTER, background); 294 textComponent.repaint(); 295 } 296 297 /** 298 * <p> 299 * Set the style of the prompt font, if different from the 300 * <code>textComponent</code>s font. 301 * </p> 302 * <p> 303 * Allowed values are {@link Font#PLAIN}, {@link Font#ITALIC}, 304 * {@link Font#BOLD}, a combination of {@link Font#BOLD} and 305 * {@link Font#ITALIC} or <code>null</code> if the prompt font should be 306 * the same as the <code>textComponent</code>s font. 307 * </p> 308 * 309 * @param fontStyle 310 * @param textComponent 311 */ 312 public static void setFontStyle(Integer fontStyle, JTextComponent textComponent) { 313 textComponent.putClientProperty(FONT_STYLE, fontStyle); 314 textComponent.revalidate(); 315 textComponent.repaint(); 316 } 317 318 /** 319 * Returns the font style of the prompt text, or <code>null</code> if the 320 * prompt's font style should not differ from the <code>textComponent</code>s 321 * font. 322 * 323 * @param textComponent 324 * @return font style of the prompt text 325 */ 326 public static Integer getFontStyle(JTextComponent textComponent) { 327 return (Integer) textComponent.getClientProperty(FONT_STYLE); 328 } 329}