/* * Geotoolkit.org - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 2001-2012, Open Source Geospatial Foundation (OSGeo) * (C) 2009-2012, Geomatys * * 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; * version 2.1 of the License. * * 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. */ package org.geotoolkit.gui.swing; import java.io.Serializable; import javax.swing.BoundedRangeModel; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; /** * Scroll down a panel when new lines are added. This helper class require only the reference * to the underlying {@link BoundedRangeModel}. If the model's value is equals to its maximal * value and this maximal value increase, then this class increase the model's value as well. * Example of use: * * {@preformat java * DefaultTableModel table = new DefaultTableModel(); * JScrollPane pane = new JScrollPane(new JTable(table)); * AutoScroll autos = new AutoScrool(pane.getVerticalScrollBar().getModel()); * // etc... * * // Now, add the new item to the table. The table * // will be scrolled down automatically if needed. * table.addRow(...); * } * * @author Martin Desruisseaux (IRD) * @version 3.02 * * @since 2.0 * @module */ @SuppressWarnings("serial") class AutoScroll implements ChangeListener, Serializable { /** * The model for the vertical scrollbar. */ private final BoundedRangeModel model; /** * Properties of the {@link BoundedRangeModel} the last time {@link #sync} has been invoked. */ private int value, extent, maximum; /** * {@code true} if the current viewport is at the bottom of the scroll area. */ private boolean viewBottom; /** * Constructs a new {@code AutoScroll} for the specified model. */ public AutoScroll(final BoundedRangeModel model) { this.model = model; model.addChangeListener(this); sync(); } /** * Disposes any resources hold by this object. * This method deregisters any listeners. */ final void dispose() { model.removeChangeListener(this); } /** * Copies current model's state into {@link #value}, * {@link #extent} and {@link #maximum} fields. */ private void sync() { value = model.getValue(); extent = model.getExtent(); maximum = model.getMaximum(); } /** * Invoked automatically when the upper limit of {@link BoundedRangeModel} has increased. * If the last row was visible prior the addition of new rows, then this method scrolls * down the model in order to show the new rows. */ @Override public void stateChanged(final ChangeEvent event) { final int oldValue = value; final int oldExtent = extent; final int oldMaximum = maximum; sync(); if (viewBottom = oldValue + oldExtent >= oldMaximum) { if (value == oldValue && extent >= oldExtent && maximum > oldMaximum) { model.setValue(oldValue + (maximum - oldMaximum)); } } } /** * Returns {@code true} if the current viewport is at the bottom of the scroll area. */ final boolean isViewBottom() { return viewBottom; } /** * Changes the current value by the given amount, provided that it does not result in * a value out of bounds. Otherwise this method does nothing. */ final void conditionalScroll(final int delta) { final int value = model.getValue() + delta; if (value >= model.getMinimum() && value + model.getExtent() <= model.getMaximum()) { model.setValue(value); } } }