1
package org.jdesktop.swingx.plaf;
3
import static javax.swing.BorderFactory.createEmptyBorder;
5
import java.awt.Dimension;
6
import java.awt.Graphics;
7
import java.awt.Graphics2D;
8
import java.awt.Insets;
10
import java.awt.Rectangle;
11
import java.awt.TextComponent;
12
import java.awt.Component.BaselineResizeBehavior;
13
import java.awt.event.FocusAdapter;
14
import java.awt.event.FocusEvent;
15
import java.lang.reflect.Method;
17
import javax.accessibility.Accessible;
18
import javax.swing.JComponent;
19
import javax.swing.border.Border;
20
import javax.swing.plaf.ComponentUI;
21
import javax.swing.plaf.TextUI;
22
import javax.swing.text.BadLocationException;
23
import javax.swing.text.Caret;
24
import javax.swing.text.EditorKit;
25
import javax.swing.text.Highlighter;
26
import javax.swing.text.JTextComponent;
27
import javax.swing.text.Position;
28
import javax.swing.text.View;
29
import javax.swing.text.DefaultHighlighter.DefaultHighlightPainter;
30
import javax.swing.text.Position.Bias;
32
import org.jdesktop.swingx.painter.Painter;
33
import org.jdesktop.swingx.prompt.PromptSupport;
34
import org.jdesktop.swingx.prompt.PromptSupport.FocusBehavior;
38
* Abstract {@link TextUI} class that delegates most work to another
39
* {@link TextUI} and additionally renders a prompt text as specified in the
40
* {@link JTextComponent}s client properties by {@link PromptSupport}.
42
* Subclasses of this class must provide a prompt component used for rendering
46
* @author Peter Weishapl <petw@gmx.net>
49
public abstract class PromptTextUI extends TextUI {
50
protected class PainterHighlighter implements Highlighter {
51
private final Painter painter;
53
private JTextComponent c;
55
public PainterHighlighter(Painter painter) {
56
this.painter = painter;
62
public Object addHighlight(int p0, int p1, HighlightPainter p)
63
throws BadLocationException {
70
public void changeHighlight(Object tag, int p0, int p1)
71
throws BadLocationException {
78
public void deinstall(JTextComponent c) {
85
public Highlight[] getHighlights() {
92
public void install(JTextComponent c) {
99
public void paint(Graphics g) {
100
Graphics2D g2d = (Graphics2D) g.create();
103
painter.paint(g2d, c, c.getWidth(), c.getHeight());
112
public void removeAllHighlights() {
113
// TODO Auto-generated method stub
120
public void removeHighlight(Object tag) {
121
// TODO Auto-generated method stub
126
static final FocusHandler focusHandler = new FocusHandler();
129
* Delegate the hard work to this object.
131
protected final TextUI delegate;
134
* This component ist painted when rendering the prompt text.
136
protected JTextComponent promptComponent;
139
* Creates a new {@link PromptTextUI} which delegates most work to another
144
public PromptTextUI(TextUI delegate) {
145
this.delegate = delegate;
149
* Creates a component which should be used to render the prompt text.
153
protected abstract JTextComponent createPromptComponent();
156
* Calls TextUI#installUI(JComponent) on the delegate and installs a focus
157
* listener on <code>c</code> which repaints the component when it gains or
161
public void installUI(JComponent c) {
162
delegate.installUI(c);
164
JTextComponent txt = (JTextComponent) c;
166
// repaint to correctly highlight text if FocusBehavior is
167
// HIGHLIGHT_LABEL in Metal and Windows LnF
168
txt.addFocusListener(focusHandler);
172
* Delegates, then uninstalls the focus listener.
175
public void uninstallUI(JComponent c) {
176
delegate.uninstallUI(c);
177
c.removeFocusListener(focusHandler);
178
promptComponent = null;
182
* Creates a label component, if none has already been created. Sets the
183
* prompt components properties to reflect the given {@link JTextComponent}s
184
* properties and returns it.
187
* @return the adjusted prompt component
189
public JTextComponent getPromptComponent(JTextComponent txt) {
190
if (promptComponent == null) {
191
promptComponent = createPromptComponent();
193
if (txt.isFocusOwner()
194
&& PromptSupport.getFocusBehavior(txt) == FocusBehavior.HIDE_PROMPT) {
195
promptComponent.setText(null);
197
promptComponent.setText(PromptSupport.getPrompt(txt));
200
promptComponent.getHighlighter().removeAllHighlights();
201
if (txt.isFocusOwner()
202
&& PromptSupport.getFocusBehavior(txt) == FocusBehavior.HIGHLIGHT_PROMPT) {
203
promptComponent.setForeground(txt.getSelectedTextColor());
205
promptComponent.getHighlighter().addHighlight(0,
206
promptComponent.getText().length(),
207
new DefaultHighlightPainter(txt.getSelectionColor()));
208
} catch (BadLocationException e) {
212
promptComponent.setForeground(PromptSupport.getForeground(txt));
215
if (PromptSupport.getFontStyle(txt) == null) {
216
promptComponent.setFont(txt.getFont());
218
promptComponent.setFont(txt.getFont().deriveFont(
219
PromptSupport.getFontStyle(txt)));
222
promptComponent.setBackground(PromptSupport.getBackground(txt));
223
promptComponent.setHighlighter(new PainterHighlighter(PromptSupport
224
.getBackgroundPainter(txt)));
225
promptComponent.setEnabled(txt.isEnabled());
226
promptComponent.setOpaque(txt.isOpaque());
227
promptComponent.setBounds(txt.getBounds());
228
Border b = txt.getBorder();
231
promptComponent.setBorder(txt.getBorder());
233
Insets insets = b.getBorderInsets(txt);
234
promptComponent.setBorder(
235
createEmptyBorder(insets.top, insets.left, insets.bottom, insets.right));
238
promptComponent.setSelectedTextColor(txt.getSelectedTextColor());
239
promptComponent.setSelectionColor(txt.getSelectionColor());
240
promptComponent.setEditable(txt.isEditable());
241
promptComponent.setMargin(txt.getMargin());
243
return promptComponent;
247
* When {@link #shouldPaintPrompt(JTextComponent)} returns true, the prompt
248
* component is retrieved by calling
249
* {@link #getPromptComponent(JTextComponent)} and it's preferred size is
250
* returned. Otherwise super{@link #getPreferredSize(JComponent)} is called.
253
public Dimension getPreferredSize(JComponent c) {
254
JTextComponent txt = (JTextComponent) c;
255
if (shouldPaintPrompt(txt)) {
256
return getPromptComponent(txt).getPreferredSize();
258
return delegate.getPreferredSize(c);
262
* Delegates painting when {@link #shouldPaintPrompt(JTextComponent)}
263
* returns false. Otherwise the prompt component is retrieved by calling
264
* {@link #getPromptComponent(JTextComponent)} and painted. Then the caret
265
* of the given text component is painted.
268
public void paint(Graphics g, final JComponent c) {
269
JTextComponent txt = (JTextComponent) c;
271
if (shouldPaintPrompt(txt)) {
272
paintPromptComponent(g, txt);
274
delegate.paint(g, c);
278
protected void paintPromptComponent(Graphics g, JTextComponent txt) {
279
JTextComponent lbl = getPromptComponent(txt);
282
if (txt.getCaret() != null) {
283
txt.getCaret().paint(g);
288
* Returns if the prompt or the text field should be painted, depending on
289
* the state of <code>txt</code>.
292
* @return true when <code>txt</code> contains not text, otherwise false
294
public boolean shouldPaintPrompt(JTextComponent txt) {
295
return txt.getText() == null || txt.getText().length() == 0;
299
* Calls super.{@link #update(Graphics, JComponent)}, which in turn calls
300
* the paint method of this object.
303
public void update(Graphics g, JComponent c) {
308
* Delegate when {@link #shouldPaintPrompt(JTextComponent)} returns false.
309
* Otherwise get the prompt component's UI and delegate to it. This ensures
310
* that the {@link Caret} is painted on the correct position (this is
311
* important when the text is centered, so that the caret will not be
312
* painted inside the label text)
315
public Rectangle modelToView(JTextComponent t, int pos, Bias bias)
316
throws BadLocationException {
317
if (shouldPaintPrompt(t)) {
318
return getPromptComponent(t).getUI().modelToView(t, pos, bias);
320
return delegate.modelToView(t, pos, bias);
325
* Calls {@link #modelToView(JTextComponent, int, Bias)} with
326
* {@link Bias#Forward}.
329
public Rectangle modelToView(JTextComponent t, int pos)
330
throws BadLocationException {
331
return modelToView(t, pos, Position.Bias.Forward);
334
// ********************* Delegate methods *************************///
335
// ****************************************************************///
338
public boolean contains(JComponent c, int x, int y) {
339
return delegate.contains(c, x, y);
343
public void damageRange(JTextComponent t, int p0, int p1, Bias firstBias,
345
delegate.damageRange(t, p0, p1, firstBias, secondBias);
349
public void damageRange(JTextComponent t, int p0, int p1) {
350
delegate.damageRange(t, p0, p1);
354
public boolean equals(Object obj) {
355
return delegate.equals(obj);
359
public Accessible getAccessibleChild(JComponent c, int i) {
360
return delegate.getAccessibleChild(c, i);
364
public int getAccessibleChildrenCount(JComponent c) {
365
return delegate.getAccessibleChildrenCount(c);
369
public EditorKit getEditorKit(JTextComponent t) {
370
return delegate.getEditorKit(t);
374
public Dimension getMaximumSize(JComponent c) {
375
return delegate.getMaximumSize(c);
379
public Dimension getMinimumSize(JComponent c) {
380
return delegate.getMinimumSize(c);
384
public int getNextVisualPositionFrom(JTextComponent t, int pos, Bias b,
385
int direction, Bias[] biasRet) throws BadLocationException {
387
.getNextVisualPositionFrom(t, pos, b, direction, biasRet);
391
public View getRootView(JTextComponent t) {
392
return delegate.getRootView(t);
396
public String getToolTipText(JTextComponent t, Point pt) {
397
return delegate.getToolTipText(t, pt);
401
public int hashCode() {
402
return delegate.hashCode();
406
public String toString() {
407
return String.format("%s (%s)", getClass().getName(), delegate
412
public int viewToModel(JTextComponent t, Point pt, Bias[] biasReturn) {
413
return delegate.viewToModel(t, pt, biasReturn);
417
public int viewToModel(JTextComponent t, Point pt) {
418
return delegate.viewToModel(t, pt);
422
* Tries to call {@link ComponentUI#getBaseline(int, int)} on the delegate
423
* via Reflection. Workaround to maintain compatibility with Java 5. Ideally
424
* we should also override {@link #getBaselineResizeBehavior(JComponent)},
425
* but that's impossible since the {@link BaselineResizeBehavior} class,
426
* which does not exist in Java 5, is involved.
428
* @return the baseline, or -2 if <code>getBaseline</code> could not be
429
* invoked on the delegate.
432
public int getBaseline(JComponent c, int width, int height) {
434
Method m = delegate.getClass().getMethod("getBaseline",
435
JComponent.class, int.class, int.class);
436
Object o = m.invoke(delegate, new Object[] { c, width, height });
438
} catch (Exception ex) {
445
* Repaint the {@link TextComponent} when it loses or gains the focus.
447
private static final class FocusHandler extends FocusAdapter {
449
public void focusGained(FocusEvent e) {
450
e.getComponent().repaint();
454
public void focusLost(FocusEvent e) {
455
e.getComponent().repaint();
b'\\ No newline at end of file'