/* * Geotoolkit.org - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 2010-2012, Open Source Geospatial Foundation (OSGeo) * (C) 2010-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.internal.swing; import javax.swing.AbstractListModel; import org.apache.sis.util.ArraysExt; /** * An implementation of {@link AbstractListModel} based on an array. The list content can be * specified by a call to the {@link #setElements(Object[])} method. The later method detects * the changes in the array content and invokes a {@code fireXXX} method with the smallest * range of changes that it can compute. * * @param <E> Type of elements contained in this model. * * @author Martin Desruisseaux (Geomatys) * @version 3.11 * * @since 3.11 * @module */ @SuppressWarnings("serial") public final class ArrayListModel<E> extends AbstractListModel<E> { /** * The elements in this model, or {@code null} if none. */ private E[] elements; /** * Creates a new, initially empty, list. */ public ArrayListModel() { } /** * Sets the elements in this list. This method does <strong>not</strong> clone the given array. * We allow this shortcut to ourself because this class is not in a public package. * * @param newElements The new elements of this list, or {@code null} if none. */ public void setElements(E[] newElements) { if (newElements != null && newElements.length == 0) { newElements = null; } int lower = 0; // Index of the first element inserted. int keept = 0; // Number of old elements which were keept. final E[] old = elements; if (old != null) { int upper = old.length - 1; if (newElements != null) { int newUpper = newElements.length - 1; final int length = Math.min(upper, newUpper); while (lower < length && old[lower].equals(newElements[lower])) { lower++; } while (upper > lower && old[upper].equals(newElements[newUpper])) { upper--; newUpper--; } } /* * [lower ... upper] (inclusive) is now the range of lines to remove or to change. */ if (upper >= lower) { if (newElements != null && old.length == newElements.length) { elements = newElements; fireContentsChanged(this, lower, upper); return; } final int numRemoved = (upper - lower) + 1; elements = ArraysExt.remove(old, lower, numRemoved); fireIntervalRemoved(this, lower, upper); keept = old.length - numRemoved; } } elements = newElements; if (newElements != null) { final int upper = lower + (newElements.length - 1) - keept; // Inclusive if (upper >= lower) { fireIntervalAdded(this, lower, upper); } } } /** * Returns the number of elements in this list. */ @Override public int getSize() { final E[] elements = this.elements; return (elements != null) ? elements.length : 0; } /** * Returns the element at the given index. * * @param index The index of the element to return. */ @Override public E getElementAt(final int index) { return elements[index]; } }