package buoy.widget;
import buoy.xml.*;
import buoy.xml.delegate.*;
import buoy.event.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
/**
* A BScrollPane is a WidgetContainer with up to five children: an arbitrary "content" Widget that
* fills most of the BScrollPane, optional "row header" and "column header" Widgets along the left
* and top edges, respectively, and optional BScrollBars along the right and bottom edges. It
* displays only a portion of the content, row header, and column header Widgets, and allows the user
* to scroll through them by means of the two BScrollBars.
* <p>
* If the BScrollPane does not have a horizontal and/or vertical scrollbar, then by default it will
* force the corresponding dimension of the content and header Widgets to exactly match the size of the
* visible area. For example, if the content is a BTextArea with word wrap enabled, you would normally
* only have a vertical scrollbar. The width of the BTextArea should then be forced to exactly
* match the width of the visible area, so that words will wrap at the correct place. You can
* override this behavior by calling setForceWidth() and setForceHeight(). For example, you might
* want to control the scroll position through some external means, in which case the BScrollPane
* would not provide scrollbars but should still allow the content Widget to be its preferred size.
*
* @author Peter Eastman
*/
public class BScrollPane extends WidgetContainer
{
private ContentViewport contentPort;
private JViewport rowHeaderPort, colHeaderPort;
private Widget content, rowHeader, colHeader;
private BScrollBar hscroll, vscroll;
private ScrollbarPolicy hPolicy, vPolicy;
private Dimension preferredViewSize, prefSize, minSize;
private boolean forceWidth, forceHeight;
public static final ScrollbarPolicy SCROLLBAR_NEVER = new ScrollbarPolicy();
public static final ScrollbarPolicy SCROLLBAR_AS_NEEDED = new ScrollbarPolicy();
public static final ScrollbarPolicy SCROLLBAR_ALWAYS = new ScrollbarPolicy();
private static final boolean IS_MACINTOSH;
static
{
WidgetEncoder.setPersistenceDelegate(ScrollbarPolicy.class, new StaticFieldDelegate(BScrollPane.class));
String os = System.getProperty("os.name", "").toLowerCase();
IS_MACINTOSH = os.startsWith("mac os x");
}
/**
* Create a new BScrollPane with no content or header Widgets. The horizontal and vertical
* scrollbar policies default to SCROLLBAR_AS_NEEDED.
*/
public BScrollPane()
{
this(SCROLLBAR_AS_NEEDED, SCROLLBAR_AS_NEEDED);
}
/**
* Create a new BScrollPane with the specified Widget as its content. The horizontal and vertical
* scrollbar policies default to SCROLLBAR_AS_NEEDED.
*
* @param contentWidget the Widget to use as the content of the BScrollPane
*/
public BScrollPane(Widget contentWidget)
{
this(SCROLLBAR_AS_NEEDED, SCROLLBAR_AS_NEEDED);
setContent(contentWidget);
}
/**
* Create a new BScrollPane with no content or header Widgets.
*
* @param horizontalPolicy specifies when the horizontal scrollbar should be displayed. This should
* be equal to SCROLLBAR_ALWAYS, SCROLLBAR_AS_NEEDED, or SCROLLBAR_NEVER.
* @param verticalPolicy specifies when the vertical scrollbar should be displayed. This should
* be equal to SCROLLBAR_ALWAYS, SCROLLBAR_AS_NEEDED, or SCROLLBAR_NEVER.
*/
public BScrollPane(ScrollbarPolicy horizontalPolicy, ScrollbarPolicy verticalPolicy)
{
JScrollPane panel = createComponent();
component = panel;
hPolicy = horizontalPolicy;
vPolicy = verticalPolicy;
ChangeListener scrollListener = new ChangeListener() {
public void stateChanged(ChangeEvent e)
{
Point pos = contentPort.getViewPosition();
if (hPolicy != SCROLLBAR_NEVER)
pos.x = hscroll.getValue();
if (vPolicy != SCROLLBAR_NEVER)
pos.y = vscroll.getValue();
contentPort.setViewPositionInternal(pos);
rowHeaderPort.setViewPosition(new Point(0, pos.y));
colHeaderPort.setViewPosition(new Point(pos.x, 0));
}
};
MouseWheelListener wheelListener = new MouseWheelListener() {
public void mouseWheelMoved(MouseWheelEvent ev)
{
BScrollBar bar = null;
if (ev.getSource() == vscroll.getComponent())
bar = vscroll;
else if (ev.getSource() == hscroll.getComponent())
bar = hscroll;
else if (vscroll.isVisible() && vscroll.isEnabled() && vscroll.getExtent() < vscroll.getMaximum())
bar = vscroll;
else if (hscroll.isVisible() && hscroll.isEnabled() && hscroll.getExtent() < hscroll.getMaximum())
bar = hscroll;
else
return;
int direction = (ev.getWheelRotation() > 0 ? 1 : -1);
if (ev.getScrollType() == MouseWheelEvent.WHEEL_BLOCK_SCROLL)
bar.setValue(bar.getValue()+bar.getBlockIncrement(direction)*ev.getWheelRotation());
else
bar.setValue(bar.getValue()+bar.getUnitIncrement(direction)*ev.getScrollAmount()*direction);
}
};
vscroll = new ScrollPaneScrollBar(0, 1, 0, 100, BScrollBar.VERTICAL);
panel.add(vscroll.getComponent());
setAsParent(vscroll);
vscroll.getComponent().getModel().addChangeListener(scrollListener);
vscroll.getComponent().addMouseWheelListener(wheelListener);
hscroll = new ScrollPaneScrollBar(0, 1, 0, 100, BScrollBar.HORIZONTAL);
panel.add(hscroll.getComponent());
setAsParent(hscroll);
hscroll.getComponent().getModel().addChangeListener(scrollListener);
hscroll.getComponent().addMouseWheelListener(wheelListener);
panel.setViewport(contentPort = new ContentViewport());
panel.setRowHeader(rowHeaderPort = new JViewport());
panel.setColumnHeader(colHeaderPort = new JViewport());
rowHeaderPort.setLayout(null);
colHeaderPort.setLayout(null);
rowHeaderPort.setOpaque(false);
colHeaderPort.setOpaque(false);
forceWidth = (hPolicy == SCROLLBAR_NEVER);
forceHeight = (vPolicy == SCROLLBAR_NEVER);
contentPort.addMouseWheelListener(wheelListener);
}
/**
* Create a new BScrollPane with the specified Widget as its content.
*
* @param contentWidget the Widget to use as the content of the BScrollPane
* @param horizontalPolicy specifies when the horizontal scrollbar should be displayed. This should
* be equal to SCROLLBAR_ALWAYS, SCROLLBAR_AS_NEEDED, or SCROLLBAR_NEVER.
* @param verticalPolicy specifies when the vertical scrollbar should be displayed. This should
* be equal to SCROLLBAR_ALWAYS, SCROLLBAR_AS_NEEDED, or SCROLLBAR_NEVER.
*/
public BScrollPane(Widget contentWidget, ScrollbarPolicy horizontalPolicy, ScrollbarPolicy verticalPolicy)
{
this(horizontalPolicy, verticalPolicy);
setContent(contentWidget);
}
/**
* Create the JScrollPane which serves as this Widget's Component. This method is protected so that
* subclasses can override it.
*/
protected JScrollPane createComponent()
{
return new ScrollPaneComponent();
}
public JScrollPane getComponent()
{
return (JScrollPane) component;
}
/**
* Get the content Widget.
*/
public Widget getContent()
{
return content;
}
/**
* Set the content Widget.
*/
public void setContent(Widget widget)
{
if (content != null)
removeAsParent(content);
content = widget;
if (content == null)
contentPort.setView(null);
else
{
setAsParent(content);
contentPort.setView(content.getComponent());
}
invalidateSize();
}
/**
* Get the row header Widget.
*/
public Widget getRowHeader()
{
return rowHeader;
}
/**
* Set the row header Widget.
*/
pub