package com.onaro.util.jfc; import java.awt.Component; import java.awt.Dimension; import java.awt.GridLayout; import java.awt.LayoutManager; import java.awt.Rectangle; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import javax.swing.AbstractButton; import javax.swing.JComponent; import javax.swing.JPanel; import javax.swing.Scrollable; import javax.swing.SwingConstants; import org.eclipse.core.runtime.IAdaptable; import com.onaro.client.server.AdaptableDataObject; import com.onaro.sanscreen.server.interfaces.ServerInterfacesUtils; import com.onaro.sanscreen.server.interfaces.data.DataObject; import com.onaro.util.jfc.TextComponentFactory.LabelFont; import com.onaro.util.jfc.browser.LinkField; /** * An {@link ISummaryField} component that contains other * IBrowserFields. By default the contained fields are displayed in a * single vertical column, but a different layout can be specified. *

* The highlight state of the compound field tracks that of its * contained fields. */ public class CompoundField extends JPanel implements Scrollable, ISummaryField { private static final long serialVersionUID = 1L; /** * Create a {@link CompoundField} with the default layout. * The default layout is a left-aligned column. * @param name of the field, for testing purposes */ public CompoundField (String name) { super(); setName (name); setLayout (new GridLayout (0, 1, 0, 0)); setOpaque (false); } /** * Create a {@link CompoundField} with the specified layout. * @param name of the field, for testing purposes * @param layout {@link LayoutManager} */ public CompoundField (String name, LayoutManager layout) { super (layout); setName (name); setOpaque (false); } @Override public boolean isHighlighted() { return Highlighter.isHighlighted (this); } @Override public void setHighlight (boolean doHighlight) { Highlighter.setHighlighted (this, doHighlight); } @Override public void clear() { removeAll(); setHighlight (false); } @Override public void validate() { super.validate(); // Update preferred size, to update layout of info pane. See InfoPaneBuilder.addSubFields. Dimension preferredSize = new Dimension(); for(int i = 0; i < getComponentCount(); i++) { Dimension size = getComponent(i).getPreferredSize(); preferredSize.width = Math.max (preferredSize.width, size.width); preferredSize.height += size.height; } setPreferredSize (preferredSize); } @Override public Dimension getPreferredScrollableViewportSize() { return getPreferredSize(); } @Override public boolean getScrollableTracksViewportWidth() { // Stretch or squeeze this to match width of viewport. This will cause text components // to be displayed with ellipses as necessary rather than clipped. return true; } @Override public boolean getScrollableTracksViewportHeight() { // Don't force height of this to match height of viewport. return false; } @Override public int getScrollableBlockIncrement (Rectangle visibleRect, int orientation, int direction) { int count = getComponentCount(); if (count > 0 && orientation == SwingConstants.VERTICAL) { // Move by one row. return getPreferredSize().height / count; } return 0; } @Override public int getScrollableUnitIncrement (Rectangle visibleRect, int orientation, int direction) { // TODO: Figure out how much to move to just completely expose the next row. // For now, we just move by one row. return getScrollableBlockIncrement (visibleRect, orientation, direction); } /** * Creates a {@link DataField} and adds it to this field. * @param text to display in field * @return the created field */ public DataField addDataField (String text) { DataField field = new DataField (getName() + "." + getComponentCount()); //$NON-NLS-1$ field.setValue (text); add (field); return field; } /** * Creates a {@link DataField} and adds it to this field. * @param text to display in field * @param font {@link LabelFont} * @return the created field */ public DataField addDataField (String text, LabelFont font) { DataField field = new DataField (getName() + "." + getComponentCount()); //$NON-NLS-1$ field.setValue (text); field.setFont (font.getFont()); add (field); return field; } /** * Creates a {@link LinkField} and adds it to this field. * @param dataObject target to visit when field is clicked * @param text to display in field * @param font {@link LabelFont} * @return the created field */ public LinkField addLinkField (DataObject dataObject, String text, LabelFont font) { IAdaptable adaptable = new AdaptableDataObject ( dataObject, ServerInterfacesUtils.getCurrentContext()); return addLinkField (adaptable, text, font); } /** * Creates a {@link LinkField} and adds it to this field. * @param link target to visit when field is clicked * @param text to display in field * @param font {@link LabelFont} * @return the created field */ public LinkField addLinkField (IAdaptable link, String text, LabelFont font) { LinkField field = new LinkField (getName() + "." + getComponentCount()); //$NON-NLS-1$ field.setFont (font.getFont()); field.setLink (link, text, getTopLevelAncestor()); add (field); return field; } @Override protected void addImpl (Component comp, Object constraints, int index) { super.addImpl (comp, constraints, index); if (comp instanceof JComponent && comp instanceof ISummaryField) { Highlighter.addForwardingListener (this, (JComponent)comp); } } /* * Adds highlight listeners for each given field that will control the * highlight state of the accordion's controller based on the highlighting * of any controlled fields. */ protected static void addHighlightListeners ( final Accordion control, final CompoundField...fields) { final AbstractButton controller = control.getController(); if (controller instanceof ISummaryField) { final ISummaryField controllerField = (ISummaryField)controller; for (CompoundField field: fields) { Highlighter.addListener (field, new PropertyChangeListener() { @Override public void propertyChange (PropertyChangeEvent event) { // Set the highlighting of the controller based on whether any field is highlighted boolean isControlledHighlighted = false; for (CompoundField controlledField: fields) { if (controlledField.isHighlighted()) { isControlledHighlighted = true; break; } } controllerField.setHighlight (isControlledHighlighted); } }); } } } }