2
* $Id: BasicHeaderUI.java,v 1.24 2008/02/29 08:35:12 rah003 Exp $
4
* Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
5
* Santa Clara, California 95054, U.S.A. All rights reserved.
7
* This library is free software; you can redistribute it and/or
8
* modify it under the terms of the GNU Lesser General Public
9
* License as published by the Free Software Foundation; either
10
* version 2.1 of the License, or (at your option) any later version.
12
* This library is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
* Lesser General Public License for more details.
17
* You should have received a copy of the GNU Lesser General Public
18
* License along with this library; if not, write to the Free Software
19
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22
package org.jdesktop.swingx.plaf.basic;
24
import org.jdesktop.swingx.JXHeader;
25
import org.jdesktop.swingx.JXLabel;
26
import org.jdesktop.swingx.JXHeader.IconPosition;
27
import org.jdesktop.swingx.painter.MattePainter;
28
import org.jdesktop.swingx.painter.Painter;
29
import org.jdesktop.swingx.plaf.HeaderUI;
30
import org.jdesktop.swingx.plaf.PainterUIResource;
33
import javax.swing.plaf.ColorUIResource;
34
import javax.swing.plaf.ComponentUI;
35
import javax.swing.plaf.FontUIResource;
36
import javax.swing.plaf.basic.BasicHTML;
37
import javax.swing.text.View;
40
import java.awt.event.HierarchyBoundsAdapter;
41
import java.awt.event.HierarchyBoundsListener;
42
import java.awt.event.HierarchyEvent;
43
import java.beans.PropertyChangeEvent;
44
import java.beans.PropertyChangeListener;
51
public class BasicHeaderUI extends HeaderUI {
52
// Implementation detail. Neeeded to expose getMultiLineSupport() method to allow restoring view
53
// lost after LAF switch
54
protected class DescriptionPane extends JXLabel {
56
public void paint(Graphics g) {
57
// switch off jxlabel default antialiasing
58
((Graphics2D)g).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
59
RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
63
public MultiLineSupport getMultiLineSupport() {
64
return super.getMultiLineSupport();
68
protected JLabel titleLabel;
69
protected DescriptionPane descriptionPane;
70
protected JLabel imagePanel;
71
private PropertyChangeListener propListener;
72
private HierarchyBoundsListener boundsListener;
73
private Color gradientLightColor;
74
private Color gradientDarkColor;
76
/** Creates a new instance of BasicHeaderUI */
77
public BasicHeaderUI() {
81
* Returns an instance of the UI delegate for the specified component.
82
* Each subclass must provide its own static <code>createUI</code>
83
* method that returns an instance of that UI delegate subclass.
84
* If the UI delegate subclass is stateless, it may return an instance
85
* that is shared by multiple components. If the UI delegate is
86
* stateful, then it should return a new instance per component.
87
* The default implementation of this method throws an error, as it
88
* should never be invoked.
90
public static ComponentUI createUI(JComponent c) {
91
return new BasicHeaderUI();
95
* Configures the specified component appropriate for the look and feel.
96
* This method is invoked when the <code>ComponentUI</code> instance is being installed
97
* as the UI delegate on the specified component. This method should
98
* completely configure the component for the look and feel,
99
* including the following:
101
* <li>Install any default property values for color, fonts, borders,
102
* icons, opacity, etc. on the component. Whenever possible,
103
* property values initialized by the client program should <i>not</i>
105
* <li>Install a <code>LayoutManager</code> on the component if necessary.
106
* <li>Create/add any required sub-components to the component.
107
* <li>Create/install event listeners on the component.
108
* <li>Create/install a <code>PropertyChangeListener</code> on the component in order
109
* to detect and respond to component property changes appropriately.
110
* <li>Install keyboard UI (mnemonics, traversal, etc.) on the component.
111
* <li>Initialize any appropriate instance data.
113
* @param c the component where this UI delegate is being installed
116
* @see javax.swing.JComponent#setUI
117
* @see javax.swing.JComponent#updateUI
120
public void installUI(JComponent c) {
122
assert c instanceof JXHeader;
123
JXHeader header = (JXHeader)c;
125
titleLabel = new JLabel();
126
descriptionPane = new DescriptionPane();
127
descriptionPane.setLineWrap(true);
128
descriptionPane.setOpaque(false);
130
installDefaults(header);
132
imagePanel = new JLabel();
133
imagePanel.setIcon(header.getIcon() == null ? UIManager.getIcon("Header.defaultIcon") : header.getIcon());
135
installComponents(header);
136
installListeners(header);
140
* Reverses configuration which was done on the specified component during
141
* <code>installUI</code>. This method is invoked when this
142
* <code>UIComponent</code> instance is being removed as the UI delegate
143
* for the specified component. This method should undo the
144
* configuration performed in <code>installUI</code>, being careful to
145
* leave the <code>JComponent</code> instance in a clean state (no
146
* extraneous listeners, look-and-feel-specific property objects, etc.).
147
* This should include the following:
149
* <li>Remove any UI-set borders from the component.
150
* <li>Remove any UI-set layout managers on the component.
151
* <li>Remove any UI-added sub-components from the component.
152
* <li>Remove any UI-added event/property listeners from the component.
153
* <li>Remove any UI-installed keyboard UI from the component.
154
* <li>Nullify any allocated instance data objects to allow for GC.
156
* @param c the component from which this UI delegate is being removed;
157
* this argument is often ignored,
158
* but might be used if the UI object is stateless
159
* and shared by multiple components
162
* @see javax.swing.JComponent#updateUI
165
public void uninstallUI(JComponent c) {
166
assert c instanceof JXHeader;
167
JXHeader header = (JXHeader)c;
169
uninstallDefaults(header);
170
uninstallListeners(header);
171
uninstallComponents(header);
174
descriptionPane = null;
178
protected void installDefaults(JXHeader h) {
179
gradientLightColor = UIManager.getColor("JXHeader.startBackground");
180
if (gradientLightColor == null) {
182
gradientLightColor = Color.WHITE;
184
gradientDarkColor = UIManager.getColor("JXHeader.background");
185
//for backwards compatibility (mostly for substance and synthetica,
186
//I suspect) I'll fall back on the "control" color if JXHeader.background
188
if (gradientDarkColor == null) {
189
gradientDarkColor = UIManager.getColor("control");
192
Painter p = h.getBackgroundPainter();
193
if (p == null || p instanceof PainterUIResource) {
194
h.setBackgroundPainter(createBackgroundPainter());
198
Font titleFont = h.getTitleFont();
199
if (titleFont == null || titleFont instanceof FontUIResource) {
200
titleFont = UIManager.getFont("JXHeader.titleFont");
201
// fallback to label font
202
titleLabel.setFont(titleFont != null ? titleFont : UIManager.getFont("Label.font"));
205
Color titleForeground = h.getTitleForeground();
206
if (titleForeground == null || titleForeground instanceof ColorUIResource) {
207
titleForeground = UIManager.getColor("JXHeader.titleForeground");
208
// fallback to label foreground
209
titleLabel.setForeground(titleForeground != null ? titleForeground : UIManager.getColor("Label.foreground"));
212
titleLabel.setText(h.getTitle());
214
// description properties
215
Font descFont = h.getDescriptionFont();
216
if (descFont == null || descFont instanceof FontUIResource) {
217
descFont = UIManager.getFont("JXHeader.descriptionFont");
218
// fallback to label font
219
descriptionPane.setFont(descFont != null ? descFont : UIManager.getFont("Label.font"));
222
Color descForeground = h.getDescriptionForeground();
223
if (descForeground == null || descForeground instanceof ColorUIResource) {
224
descForeground = UIManager.getColor("JXHeader.descriptionForeground");
225
// fallback to label foreground
226
descriptionPane.setForeground(descForeground != null ? descForeground : UIManager.getColor("Label.foreground"));
229
descriptionPane.setText(h.getDescription());
232
protected void uninstallDefaults(JXHeader h) {
235
protected void installListeners(final JXHeader header) {
236
propListener = new PropertyChangeListener() {
237
public void propertyChange(PropertyChangeEvent evt) {
238
onPropertyChange(header, evt.getPropertyName(), evt.getOldValue(), evt.getNewValue());
241
boundsListener = new HierarchyBoundsAdapter() {
242
public void ancestorResized(HierarchyEvent e) {
243
if (header == e.getComponent()) {
244
View v = (View) descriptionPane.getClientProperty(BasicHTML.propertyKey);
245
// view might get lost on LAF change ...
247
descriptionPane.putClientProperty(BasicHTML.propertyKey, descriptionPane.getMultiLineSupport().createView(descriptionPane));
248
v = (View) descriptionPane.getClientProperty(BasicHTML.propertyKey);
251
int h = Math.max(descriptionPane.getHeight(), header.getTopLevelAncestor().getHeight());
252
int w = Math.min(header.getTopLevelAncestor().getWidth(), header.getParent().getWidth());
253
// 35 = description pane insets, TODO: obtain dynamically
254
w -= 35 + header.getInsets().left + header.getInsets().right + descriptionPane.getInsets().left + descriptionPane.getInsets().right + imagePanel.getInsets().left + imagePanel.getInsets().right + imagePanel.getWidth() + descriptionPane.getBounds().x;
256
descriptionPane.setSize(w, (int) Math.ceil(v.getPreferredSpan(View.Y_AXIS)));
260
header.addPropertyChangeListener(propListener);
261
header.addHierarchyBoundsListener(boundsListener);
264
protected void uninstallListeners(JXHeader h) {
265
h.removePropertyChangeListener(propListener);
266
h.removeHierarchyBoundsListener(boundsListener);
269
protected void onPropertyChange(JXHeader h, String propertyName, Object oldValue, final Object newValue) {
270
if ("title".equals(propertyName)) {
271
titleLabel.setText(h.getTitle());
272
} else if ("description".equals(propertyName)) {
273
descriptionPane.setText(h.getDescription());
274
} else if ("icon".equals(propertyName)) {
275
imagePanel.setIcon(h.getIcon());
276
} else if ("enabled".equals(propertyName)) {
277
boolean enabled = h.isEnabled();
278
titleLabel.setEnabled(enabled);
279
descriptionPane.setEnabled(enabled);
280
imagePanel.setEnabled(enabled);
281
} else if ("titleFont".equals(propertyName)) {
282
titleLabel.setFont((Font)newValue);
283
} else if ("descriptionFont".equals(propertyName)) {
284
descriptionPane.setFont((Font)newValue);
285
} else if ("titleForeground".equals(propertyName)) {
286
titleLabel.setForeground((Color)newValue);
287
} else if ("descriptionForeground".equals(propertyName)) {
288
descriptionPane.setForeground((Color)newValue);
289
} else if ("iconPosition".equals(propertyName)) {
294
protected void installComponents(JXHeader h) {
295
h.setLayout(new GridBagLayout());
299
private void resetLayout(JXHeader h) {
300
h.remove(titleLabel);
301
h.remove(descriptionPane);
302
h.remove(imagePanel);
303
if (h.getIconPosition() == null || h.getIconPosition() == IconPosition.RIGHT) {
304
h.add(titleLabel, new GridBagConstraints(0, 0, 1, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(12, 12, 0, 11), 0, 0));
305
h.add(descriptionPane, new GridBagConstraints(0, 1, 1, 1, 1.0, 1.0, GridBagConstraints.FIRST_LINE_START, GridBagConstraints.BOTH, new Insets(0, 24, 12, 11), 0, 0));
306
h.add(imagePanel, new GridBagConstraints(1, 0, 1, 2, 0.0, 1.0, GridBagConstraints.FIRST_LINE_END, GridBagConstraints.NONE, new Insets(12, 0, 11, 11), 0, 0));
308
h.add(titleLabel, new GridBagConstraints(1, 0, 1, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(12, 12, 0, 11), 0, 0));
309
h.add(descriptionPane, new GridBagConstraints(1, 1, 1, 1, 1.0, 1.0, GridBagConstraints.FIRST_LINE_START, GridBagConstraints.BOTH, new Insets(0, 24, 12, 11), 0, 0));
310
h.add(imagePanel, new GridBagConstraints(0, 0, 1, 2, 0.0, 1.0, GridBagConstraints.FIRST_LINE_END, GridBagConstraints.NONE, new Insets(12, 11, 0, 11), 0, 0));
314
protected void uninstallComponents(JXHeader h) {
315
h.remove(titleLabel);
316
h.remove(descriptionPane);
317
h.remove(imagePanel);
320
protected Painter createBackgroundPainter() {
321
MattePainter p = new MattePainter(new GradientPaint(0, 0, gradientLightColor, 1, 0, gradientDarkColor));
322
p.setPaintStretched(true);
323
return new PainterUIResource(p);