/*
* AP(r) Computer Science GridWorld Case Study:
* Copyright(c) 2002-2006 College Entrance Examination Board
* (http://www.collegeboard.com).
*
* This code is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation.
*
* This code 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 General Public License for more details.
*
* @author Julie Zelenski
* @author Cay Horstmann
*/
package info.gridworld.gui;
import java.awt.Point;
import java.awt.Dimension;
import java.awt.Color;
import javax.swing.*;
/**
* A <code>PseudoInfiniteViewport</code> is a <code>JViewport</code>
* subclass that translates scroll actions into pan actions across an unbounded
* view. <br />
* This code is not tested on the AP CS A and AB exams. It contains GUI
* implementation details that are not intended to be understood by AP CS
* students.
*/
public class PseudoInfiniteViewport extends JViewport
{
/**
* The Pannable interface contains those methods the view installed in a
* PseudoInfiniteViewport needs to support to enable panning behavior along
* with scrolling.
*/
public interface Pannable
{
void panBy(int hDelta, int vDelta);
boolean isPannableUnbounded();
void showPanTip();
}
private JScrollPane scrollParent;
private Point panPoint = new Point(0, 0);
/**
* Construct a new PseudoInfiniteViewport object for the given scrollpane.
* @param parent the JScrollPane for which this will be the viewport
*/
public PseudoInfiniteViewport(JScrollPane parent)
{
scrollParent = parent;
setBackground(Color.lightGray);
}
/**
* Sets the view position (upper left) to a new point. Overridden from
* JViewport to do a pan, instead of scroll, on an unbounded view.
* @param pt the Point to become the upper left
*/
public void setViewPosition(Point pt)
{
boolean isAdjusting = scrollParent.getVerticalScrollBar()
.getValueIsAdjusting()
|| scrollParent.getHorizontalScrollBar().getValueIsAdjusting();
boolean changed = true;
if (viewIsUnbounded())
{
int hDelta = pt.x - panPoint.x;
int vDelta = pt.y - panPoint.y;
if (hDelta != 0 && vDelta == 0)
getPannableView().panBy(hDelta, vDelta);
else if (vDelta != 0 && hDelta == 0)
getPannableView().panBy(hDelta, vDelta);
else
changed = false; // no pan action was taken
panPoint = pt;
if (!panPoint.equals(getPanCenterPoint()) && !isAdjusting)
{ // needs recentering
panPoint = getPanCenterPoint();
fireStateChanged(); // update scrollbars to match
}
}
else
// ordinary scroll behavior
{
changed = !getViewPosition().equals(pt);
super.setViewPosition(pt);
}
if (changed || isAdjusting)
getPannableView().showPanTip(); // briefly show tip
}
/**
* Returns current view position (upper left). Overridden from JViewport to
* use pan center point for unbounded view.
*/
public Point getViewPosition()
{
return (viewIsUnbounded() ? getPanCenterPoint() : super
.getViewPosition());
}
/**
* Returns current view size. Overridden from JViewport to use preferred
* virtual size for unbounded view.
*/
public Dimension getViewSize()
{
return (viewIsUnbounded() ? getView().getPreferredSize() : super
.getViewSize());
}
// some simple private helpers
private Pannable getPannableView()
{
return (Pannable) getView();
}
private boolean viewIsUnbounded()
{
Pannable p = getPannableView();
return (p != null && p.isPannableUnbounded());
}
private Point getPanCenterPoint()
{
Dimension size = getViewSize();
return new Point(size.width / 2, size.height / 2);
}
}