Skip to main content
aboutsummaryrefslogblamecommitdiffstats
blob: 5420b78d84328907095cf8145888a23fe358d7aa (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
                                                                                
                                                        











                                                                                
                              


                                                                       






                                                                  




                                                               
   


                                                     
 
                                                               
                                          
 
                                                                        




                                                              


                                                         

                                                               
         
 



                                                                
                                                                              
                                     
                                                 

                                                                           



                                               




                                                                                 
                                                                          







                                                                         

 
                                                              
 
                                       


                                           

                                                                
         
 


                                                                               
                                 

                                              
 





                                                        
 






                                                                      



                                                             
                                     
                                       


                 
                                                                      



                                                
                                                  
                                   

         

                                          
                                                                   
         
 




                                                                           
                                                  
         
 



                                                      
                                         


                                                                                        
                                                                              
         
 



                                                         
                                            



                                                                                           
 
 
                                                     
 
           


                                                                            
           
                                                           



                                         
                                      
                                                                                   
                                    
 
                                                
                                             

                                                                    
                 
 

                                                                           
                                                              
 


                                                       

                                                                                

                 
 

                                                                   
 
                                                                                         

                               
                                            

                                                                                        

                                                                      

                 
 
                                                            
                                                                          
         
 
                                                                 
                                                                         


         
/*******************************************************************************
 * Copyright (c) 2007, 2008 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.Iterator;
import java.util.List;
import java.util.ListIterator;

import org.eclipse.jpt.utility.internal.CollectionTools;
import org.eclipse.jpt.utility.internal.iterators.ReadOnlyListIterator;
import org.eclipse.jpt.utility.model.Model;
import org.eclipse.jpt.utility.model.event.StateChangeEvent;
import org.eclipse.jpt.utility.model.listener.ChangeListener;
import org.eclipse.jpt.utility.model.listener.ListChangeListener;
import org.eclipse.jpt.utility.model.listener.StateChangeListener;
import org.eclipse.jpt.utility.model.value.ListValueModel;
import org.eclipse.jpt.utility.model.value.PropertyValueModel;

/**
 * This extension of AspectAdapter provides ListChange support
 * by adapting a subject's state change events to a minimum set
 * of list change events.
 */
public abstract class ListCurator<S extends Model, E>
	extends AspectAdapter<S>
	implements ListValueModel<E>
{
	/** How the list looked before the last state change */
	private final ArrayList<E> record;

	/** A listener that listens for the subject's state to change */
	private final StateChangeListener stateChangeListener;


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

	/**
	 * Construct a Curator for the specified subject.
	 */
	protected ListCurator(S subject) {
		this(new StaticPropertyValueModel<S>(subject));
	}

	/**
	 * Construct a curator for the specified subject holder.
	 * The subject holder cannot be null.
	 */
	protected ListCurator(PropertyValueModel<? extends S> subjectHolder) {
		super(subjectHolder);
		this.record = new ArrayList<E>();
		this.stateChangeListener = this.buildStateChangeListener();
	}


	// ********** initialization **********

	/**
	 * The subject's state has changed, do inventory and report to listeners.
	 */
	protected StateChangeListener buildStateChangeListener() {
		return new StateChangeListener() {
			public void stateChanged(StateChangeEvent event) {
				ListCurator.this.submitInventoryReport();
			}
			@Override
			public String toString() {
				return "state change listener";
			}
		};
	}


	// ********** ListValueModel implementation **********

	public Iterator<E> iterator() {
		return this.listIterator();
	}

	public ListIterator<E> listIterator() {
		return new ReadOnlyListIterator<E>(this.record);
	}

	/**
	 * Return the item at the specified index of the subject's list aspect.
	 */
	public E get(int index) {
		return this.record.get(index);
	}

	/**
	 * Return the size of the subject's list aspect.
	 */
	public int size() {
		return this.record.size();
	}

	/**
	 * Return an array manifestation of the subject's list aspect.
	 */
	public Object[] toArray() {
		return this.record.toArray();
	}


	// ********** AspectAdapter implementation **********

	@Override
	protected Object getValue() {
		return this.iterator();
	}

	@Override
	protected Class<? extends ChangeListener> getListenerClass() {
		return ListChangeListener.class;
	}

	@Override
	protected String getListenerAspectName() {
		return LIST_VALUES;
	}

	@Override
	protected boolean hasListeners() {
		return this.hasAnyListChangeListeners(LIST_VALUES);
	}

	/**
	 * The aspect has changed, notify listeners appropriately.
	 */
	@Override
	protected void fireAspectChange(Object oldValue, Object newValue) {
		this.fireListChanged(LIST_VALUES);
	}

	/**
	 * The subject is not null - add our listener.
	 */
	@Override
	protected void engageSubject_() {
		((Model) this.subject).addStateChangeListener(this.stateChangeListener);
		// synch our list *after* we start listening to the subject,
		// since its value might change when a listener is added
		CollectionTools.addAll(this.record, this.iteratorForRecord());
	}

	/**
	 * The subject is not null - remove our listener.
	 */
	@Override
	protected void disengageSubject_() {
		((Model) this.subject).removeStateChangeListener(this.stateChangeListener);
		// clear out the list when we are not listening to the subject
		this.record.clear();
	}


	// ********** ListCurator protocol **********

	/**
	 * This is intended to be different from #ListValueModel.iterator().
	 * It is intended to be used only when the subject changes or the
	 * subject's "state" changes (as signified by a state change event).
	 */
	protected abstract Iterator<E> iteratorForRecord();


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

	void submitInventoryReport() {
		List<E> newRecord = CollectionTools.list(this.iteratorForRecord());
		int recordIndex = 0;

		// add items from the new record
		for (E newItem : newRecord) {
			this.inventoryNewItem(recordIndex, newItem);
			recordIndex++;
		}

		// clean out items that are no longer in the new record
		for (recordIndex = 0; recordIndex < this.record.size(); ) {
			E item = this.record.get(recordIndex);

			if (newRecord.contains(item)) {
				recordIndex++;
			} else {
				this.removeItemFromInventory(recordIndex, item);
			}
		}
	}

	private void inventoryNewItem(int recordIndex, E newItem) {
		List<E> rec = new ArrayList<E>(this.record);

		if ((recordIndex < rec.size()) && rec.get(recordIndex).equals(newItem)) {
			return;
		}
		if (rec.contains(newItem)) {
			this.removeItemFromInventory(recordIndex, rec.get(recordIndex));
			this.inventoryNewItem(recordIndex, newItem);
		} else {
			this.addItemToInventory(recordIndex, newItem);
		}
	}

	private void addItemToInventory(int index, E item) {
		this.addItemToList(index, item, this.record, LIST_VALUES);
	}

	private void removeItemFromInventory(int index, E item) {
		this.removeItemFromList(index, this.record, LIST_VALUES);
	}

}

Back to the top