org.jdesktop.swingx.plaf.basic.BasicTitledPanelUI Maven / Gradle / Ivy
Show all versions of swingx-all Show documentation
/*
* $Id$
*
* Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
* Santa Clara, California 95054, U.S.A. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package org.jdesktop.swingx.plaf.basic;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.LookAndFeel;
import javax.swing.UIManager;
import javax.swing.plaf.BorderUIResource;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource;
import org.jdesktop.swingx.JXPanel;
import org.jdesktop.swingx.JXTitledPanel;
import org.jdesktop.swingx.SwingXUtilities;
import org.jdesktop.swingx.plaf.TitledPanelUI;
/**
* All TitledPanels contain a title section and a content section. The default
* implementation for the title section relies on a Gradient background. All
* title sections can have components embedded to the "left" or
* "right" of the Title.
*
* @author Richard Bair
* @author Jeanette Winzenburg
* @author rah003
*
*/
public class BasicTitledPanelUI extends TitledPanelUI {
private static final Logger LOG = Logger.getLogger(BasicTitledPanelUI.class.getName());
/**
* JLabel used for the title in the Title section of the JTitledPanel.
*/
protected JLabel caption;
/**
* The Title section panel.
*/
protected JXPanel topPanel;
/**
* Listens to changes in the title of the JXTitledPanel component
*/
protected PropertyChangeListener titleChangeListener;
protected JComponent left;
protected JComponent right;
/** Creates a new instance of BasicTitledPanelUI */
public BasicTitledPanelUI() {
}
/**
* Returns an instance of the UI delegate for the specified component.
* Each subclass must provide its own static createUI
* method that returns an instance of that UI delegate subclass.
* If the UI delegate subclass is stateless, it may return an instance
* that is shared by multiple components. If the UI delegate is
* stateful, then it should return a new instance per component.
* The default implementation of this method throws an error, as it
* should never be invoked.
*/
public static ComponentUI createUI(JComponent c) {
return new BasicTitledPanelUI();
}
/**
* Configures the specified component appropriate for the look and feel.
* This method is invoked when the ComponentUI
instance is being installed
* as the UI delegate on the specified component. This method should
* completely configure the component for the look and feel,
* including the following:
*
* - Install any default property values for color, fonts, borders,
* icons, opacity, etc. on the component. Whenever possible,
* property values initialized by the client program should not
* be overridden.
*
- Install a
LayoutManager
on the component if necessary.
* - Create/add any required sub-components to the component.
*
- Create/install event listeners on the component.
*
- Create/install a
PropertyChangeListener
on the component in order
* to detect and respond to component property changes appropriately.
* - Install keyboard UI (mnemonics, traversal, etc.) on the component.
*
- Initialize any appropriate instance data.
*
* @param c the component where this UI delegate is being installed
*
* @see #uninstallUI
* @see javax.swing.JComponent#setUI
* @see javax.swing.JComponent#updateUI
*/
@Override
public void installUI(JComponent c) {
assert c instanceof JXTitledPanel;
JXTitledPanel titledPanel = (JXTitledPanel)c;
installDefaults(titledPanel);
caption = createAndConfigureCaption(titledPanel);
topPanel = createAndConfigureTopPanel(titledPanel);
installComponents(titledPanel);
installListeners(titledPanel);
}
protected void installDefaults(JXTitledPanel titledPanel) {
installProperty(titledPanel, "titlePainter", UIManager.get("JXTitledPanel.titlePainter"));
installProperty(titledPanel, "titleForeground", UIManager.getColor("JXTitledPanel.titleForeground"));
installProperty(titledPanel, "titleFont", UIManager.getFont("JXTitledPanel.titleFont"));
LookAndFeel.installProperty(titledPanel, "opaque", false);
}
protected void uninstallDefaults(JXTitledPanel titledPanel) {
}
protected void installComponents(JXTitledPanel titledPanel) {
topPanel.add(caption, new GridBagConstraints(1, 0, 1, 1, 1.0, 1.0, GridBagConstraints.NORTHWEST,
GridBagConstraints.HORIZONTAL, getCaptionInsets(), 0, 0));
if (titledPanel.getClientProperty(JXTitledPanel.RIGHT_DECORATION) instanceof JComponent) {
setRightDecoration((JComponent) titledPanel.getClientProperty(JXTitledPanel.RIGHT_DECORATION));
}
if (titledPanel.getClientProperty(JXTitledPanel.LEFT_DECORATION) instanceof JComponent) {
setLeftDecoration((JComponent) titledPanel.getClientProperty(JXTitledPanel.LEFT_DECORATION));
}
// swingx#500
if (!(titledPanel.getLayout() instanceof BorderLayout)){
titledPanel.setLayout(new BorderLayout());
}
titledPanel.add(topPanel, BorderLayout.NORTH);
// fix #1063-swingx: must respect custom border
if (SwingXUtilities.isUIInstallable(titledPanel.getBorder())) {
// use uiresource border
// old was: BorderFactory.createRaisedBevelBorder());
titledPanel.setBorder(BorderUIResource.getRaisedBevelBorderUIResource());
}
}
protected void uninstallComponents(JXTitledPanel titledPanel) {
titledPanel.remove(topPanel);
}
protected Insets getCaptionInsets() {
return UIManager.getInsets("JXTitledPanel.captionInsets");
}
protected JXPanel createAndConfigureTopPanel(JXTitledPanel titledPanel) {
JXPanel topPanel = new JXPanel();
topPanel.setBackgroundPainter(titledPanel.getTitlePainter());
topPanel.setBorder(BorderFactory.createEmptyBorder());
topPanel.setLayout(new GridBagLayout());
topPanel.setOpaque(false);
return topPanel;
}
protected JLabel createAndConfigureCaption(final JXTitledPanel titledPanel) {
JLabel caption = new JLabel(titledPanel.getTitle()){
//#501
@Override
public void updateUI(){
super.updateUI();
setForeground(titledPanel.getTitleForeground());
setFont(titledPanel.getTitleFont());
}
};
caption.setFont(titledPanel.getTitleFont());
caption.setForeground(titledPanel.getTitleForeground());
return caption;
}
/**
* Reverses configuration which was done on the specified component during
* installUI
. This method is invoked when this
* UIComponent
instance is being removed as the UI delegate
* for the specified component. This method should undo the
* configuration performed in installUI
, being careful to
* leave the JComponent
instance in a clean state (no
* extraneous listeners, look-and-feel-specific property objects, etc.).
* This should include the following:
*
* - Remove any UI-set borders from the component.
*
- Remove any UI-set layout managers on the component.
*
- Remove any UI-added sub-components from the component.
*
- Remove any UI-added event/property listeners from the component.
*
- Remove any UI-installed keyboard UI from the component.
*
- Nullify any allocated instance data objects to allow for GC.
*
* @param c the component from which this UI delegate is being removed;
* this argument is often ignored,
* but might be used if the UI object is stateless
* and shared by multiple components
*
* @see #installUI
* @see javax.swing.JComponent#updateUI
*/
@Override
public void uninstallUI(JComponent c) {
assert c instanceof JXTitledPanel;
JXTitledPanel titledPanel = (JXTitledPanel) c;
uninstallListeners(titledPanel);
// JW: this is needed to make the gradient paint work correctly...
// LF changes will remove the left/right components...
topPanel.removeAll();
titledPanel.remove(topPanel);
titledPanel.putClientProperty(JXTitledPanel.LEFT_DECORATION, left);
titledPanel.putClientProperty(JXTitledPanel.RIGHT_DECORATION, right);
caption = null;
topPanel = null;
titledPanel = null;
left = null;
right = null;
}
protected void installListeners(final JXTitledPanel titledPanel) {
titleChangeListener = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals("title")) {
caption.setText((String)evt.getNewValue());
} else if (evt.getPropertyName().equals("titleForeground")) {
caption.setForeground((Color)evt.getNewValue());
} else if (evt.getPropertyName().equals("titleFont")) {
caption.setFont((Font)evt.getNewValue());
} else if ("titlePainter".equals(evt.getPropertyName())) {
topPanel.setBackgroundPainter(titledPanel.getTitlePainter());
topPanel.repaint();
}
}
};
titledPanel.addPropertyChangeListener(titleChangeListener);
}
protected void uninstallListeners(JXTitledPanel titledPanel) {
titledPanel.removePropertyChangeListener(titleChangeListener);
}
protected void installProperty(JComponent c, String propName, Object value) {
try {
BeanInfo bi = Introspector.getBeanInfo(c.getClass());
for (PropertyDescriptor pd : bi.getPropertyDescriptors()) {
if (pd.getName().equals(propName)) {
Method m = pd.getReadMethod();
Object oldVal = m.invoke(c);
if (oldVal == null || oldVal instanceof UIResource) {
m = pd.getWriteMethod();
m.invoke(c, value);
}
}
}
} catch (Exception e) {
LOG.log(Level.FINE, "Failed to install property " + propName, e);
}
}
/**
* Paints the specified component appropriate for the look and feel.
* This method is invoked from the ComponentUI.update
method when
* the specified component is being painted. Subclasses should override
* this method and use the specified Graphics
object to
* render the content of the component.
*
* PENDING JW: we don't need this, do we - remove!
*
* @param g the Graphics
context in which to paint
* @param c the component being painted;
* this argument is often ignored,
* but might be used if the UI object is stateless
* and shared by multiple components
*
* @see #update
*/
@Override
public void paint(Graphics g, JComponent c) {
super.paint(g, c);
}
/**
* Adds the given JComponent as a decoration on the right of the title
* @param decoration
*/
@Override
public void setRightDecoration(JComponent decoration) {
if (right != null) topPanel.remove(right);
right = decoration;
if (right != null) {
topPanel.add(decoration, new GridBagConstraints(2, 0, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, UIManager.getInsets("JXTitledPanel.rightDecorationInsets"), 0, 0));
}
}
@Override
public JComponent getRightDecoration() {
return right;
}
/**
* Adds the given JComponent as a decoration on the left of the title
* @param decoration
*/
@Override
public void setLeftDecoration(JComponent decoration) {
if (left != null) topPanel.remove(left);
left = decoration;
if (left != null) {
topPanel.add(left, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, UIManager.getInsets("JXTitledPanel.leftDecorationInsets"), 0, 0));
}
}
@Override
public JComponent getLeftDecoration() {
return left;
}
/**
* @return the Container acting as the title bar for this component
*/
@Override
public Container getTitleBar() {
return topPanel;
}
}