/* * Copyright (c) 2007 BUSINESS OBJECTS SOFTWARE LIMITED * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of Business Objects nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * SortedListModel.java * * Based on the 'Using TreeSet to provide a sorted JList' tutorial at developers.sun.com. * * The example was modified to pass in a comparator to allow different sorting to be specified. As well * as cleaning up the JavaDoc and making the method names consistent with the DefaultListModel class. * * * On creation of this class, this tutorial made no reference to any license. * The page referencing the code had the following statement: * * Unless otherwise licensed, code in all technical manuals herein (including articles, FAQs, samples) * is provided under this License. * * * The word "Licence" above was hyperlinked to http://developers.sun.com/license/berkeley_license.html. * This read as follows: * * Code sample * License * * Copyright 1994-2006 Sun Microsystems, Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * * Redistribution of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * * Redistribution in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of Sun Microsystems, Inc. or the names of contributors may be * used to endorse or promote products derived from this software without specific * prior written permission. * * This software is provided "AS IS," without a warranty of any kind. * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS * LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE * THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. * * You acknowledge that this software is not designed, licensed or intended for use in * the design, construction, operation or maintenance of any nuclear facility. */ /* * SortedListModel.java * Created: Sep 4, 2004 * By: David Mosimann */ package org.openquark.util.ui; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.NoSuchElementException; import java.util.SortedSet; import java.util.TreeSet; import javax.swing.AbstractListModel; /** * A list model which maintains its contents in sorted order. * The ordering is defined by a provided comparator. * * @param <T> The type of the elements in the list model. */ public class SortedListModel<T> extends AbstractListModel { private static final long serialVersionUID = 8655910160300479643L; /** The sorted model that will store all of the JList elements in sorted order. */ private SortedSet<T> model; /** The current comparator being used to sort the items. Never null. */ private Comparator<T> comparator; /** * Constructor for SortedListModel * @param comparator Used to compare elements that are added to the model and ensure that they * are always in sorted order. Must not be null. */ public SortedListModel(Comparator<T> comparator) { if (comparator == null) { throw new NullPointerException("Argument 'comparator' must not be null."); //$NON-NLS-1$ } // Create a tree set using the comparator this.model = new TreeSet<T>(comparator); this.comparator = comparator; } /** * If an item is changed in a way that would affect its sorted order then the client has two choices. * The item can be removed an added back so that it is reinserted in the correct sorted position or * the client can resort then entire model by calling this method. In general it is preferable for * the client to reinsert the item as it will be much more efficient and this method is only * provided for situations in which that may not be possible. * When finished a contents changed event will be fired. */ public void resort() { // Reuse the setComparator method by simply setting the comparator to itself (resort with // the same comparator) setComparator(comparator); } /** * Changes the comparator that is used to sort the model. The entire model will be rebuilt using * the new comparator. When finished a contents changed event will be fired. * @param newComparator */ public void setComparator(Comparator<T> newComparator) { if (comparator == null) { throw new NullPointerException("Argument 'comparator' must not be null."); //$NON-NLS-1$ } // Create the new model with the new comparator this.comparator = newComparator; SortedSet<T> newModel = new TreeSet<T>(comparator); // Add all of the old items to the model. Note that TreeSet.addAll() has an 'optimal' path // when adding from another TreeSet that doesn't resort the elements so we need to add one // at a time to force the resort. for (final T o : model) { newModel.add(o); } this.model = newModel; // Fire the contents changed event indicating that every item could have changed. fireContentsChanged(this, 0, getSize()); } /** * @return the number of elements in the model */ public int getSize() { return model.size(); } /** * Returns the item at the specified index. * @param index * @return The object at the specified index. * @throws IndexOutOfBoundsException if the index is invalid */ public Object getElementAt(int index) { // Return the appropriate element return model.toArray()[index]; } /** * Adds a new element to the model. The model will be inserted in sorted order and * a contents changed event will be fired. * @param element */ public void addElement(T element) { if (model.add(element)) { fireContentsChanged(this, 0, getSize()); } } /** * All of the objects in the array will be added. The array passed in must be non-null, but * no sorting is assumed. All objects from the array will be added in sorted order. A single * contents changed event will be first after all the objects are added. * @param elements */ public void addAllElements(T[] elements) { Collection<T> c = Arrays.asList(elements); model.addAll(c); fireContentsChanged(this, 0, getSize()); } /** * Removes all of the elements in the model and fires a contents changed event. */ public void clear() { model.clear(); fireContentsChanged(this, 0, getSize()); } /** * @param element * @return True if the element is in the model and false otherwise */ public boolean contains(Object element) { return model.contains(element); } /** * @return Returns the first element in the model. * @throws NoSuchElementException sorted set is empty. */ public Object firstElement() { // Return the appropriate element return model.first(); } /** * @return An iterator for the model. The iterator can not be used to modify the model. */ public Iterator<T> iterator() { return Collections.unmodifiableSet(model).iterator(); } /** * @return Returns the last element in the model. * @throws NoSuchElementException sorted set is empty. */ public Object lastElement() { // Return the appropriate element return model.last(); } /** * Attempts to remove the specified element from the model. If the element is not * in the model then nothing is changed. If the element does exist then it is * removed and a contents changed event is fired. * @param element * @return True if the element was removed and false if the element was not found * in the model. */ public boolean removeElement(Object element) { boolean removed = model.remove(element); if (removed) { fireContentsChanged(this, 0, getSize()); } return removed; } }