Skip to main content
summaryrefslogblamecommitdiffstats
blob: 497b70aff4544bf83f6e44536a3bb604b947c12d (plain) (tree)
































































































































                                                                                                               
/*******************************************************************************
 * Copyright (c) 2007 Oracle. All rights reserved.
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0, which accompanies this distribution
 * and is available at http://www.eclipse.org/legal/epl-v10.html.
 * 
 * Contributors:
 *     Oracle - initial API and implementation
 ******************************************************************************/
package org.eclipse.jpt.utility.internal.model.value;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import org.eclipse.jpt.utility.internal.CollectionTools;
import org.eclipse.jpt.utility.internal.Range;
import org.eclipse.jpt.utility.internal.model.event.CollectionChangeEvent;

/**
 * An adapter that allows us to make a CollectionValueModel
 * (or ListValueModel) behave like a read-only ListValueModel
 * that keeps its contents sorted and notifies listeners appropriately.
 * 
 * The comparator can be changed at any time; allowing the same
 * adapter to be used with different sort criteria (e.g. when the user
 * wants to sort a list of files first by name, then by date, then by size).
 * 
 * NB: Since we only listen to the wrapped collection when we have
 * listeners ourselves and we can only stay in synch with the wrapped
 * collection while we are listening to it, results to various methods
 * (e.g. #size(), getItem(int)) will be unpredictable whenever
 * we do not have any listeners. This should not be too painful since,
 * most likely, client objects will also be listeners.
 */
public class SortedListValueModelAdapter
	extends CollectionListValueModelAdapter
{
	/**
	 * A comparator used for sorting the elements;
	 * if it is null, we use "natural ordering".
	 */
	protected Comparator comparator;


	// ********** constructors **********

	/**
	 * Wrap the specified collection value model and sort its contents
	 * using the specified comparator.
	 */
	public SortedListValueModelAdapter(CollectionValueModel collectionHolder, Comparator comparator) {
		super(collectionHolder);
		this.comparator = comparator;
	}

	/**
	 * Wrap the specified collection value model and sort its contents
	 * based on the elements' "natural ordering".
	 */
	public SortedListValueModelAdapter(CollectionValueModel collectionHolder) {
		this(collectionHolder, null);
	}

	/**
	 * Wrap the specified list value model and sort its contents
	 * using the specified comparator.
	 */
	public SortedListValueModelAdapter(ListValueModel listHolder, Comparator comparator) {
		this(new ListCollectionValueModelAdapter(listHolder), comparator);
	}

	/**
	 * Wrap the specified list value model and sort its contents
	 * based on the elements' "natural ordering".
	 */
	public SortedListValueModelAdapter(ListValueModel listHolder) {
		this(listHolder, null);
	}


	// ********** accessors **********

	public void setComparator(Comparator comparator) {
		this.comparator = comparator;
		this.sortList();
	}


	// ********** behavior **********

	/**
	 * Sort the internal list before
	 * sending out change notification.
	 */
	@Override
	protected void postBuildList() {
		super.postBuildList();
		Collections.sort(this.list, this.comparator);
	}

	/**
	 * the list will need to be sorted after the item is added
	 */
	@Override
	protected void itemsAdded(CollectionChangeEvent e) {
		// first add the items and notify our listeners...
		super.itemsAdded(e);
		// ...then sort the list
		this.sortList();
	}

	/**
	 * sort the list and notify our listeners, if necessary;
	 */
	protected void sortList() {
		// save the unsorted state of the sorted list so we can minimize the number of "replaced" items
		ArrayList unsortedList = (ArrayList) this.list.clone();
		Collections.sort(this.list, this.comparator);
		Range diffRange = CollectionTools.identityDiffRange(unsortedList, this.list);
		if (diffRange.size > 0) {
			List unsortedItems = unsortedList.subList(diffRange.start, diffRange.end + 1);
			List sortedItems = this.list.subList(diffRange.start, diffRange.end + 1);
			this.fireItemsReplaced(VALUE, diffRange.start, sortedItems, unsortedItems);
		}
	}

}

Back to the top