All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sf.cuf.model.IndexedAdapter Maven / Gradle / Ivy

The newest version!
package net.sf.cuf.model;

import javax.swing.event.ChangeListener;
import javax.swing.event.ChangeEvent;
import java.util.List;

/**
 * A IndexedAdapter is a ValueModel that takes an entry of
 * a List as its value.
* A IndexedAdapter is simular to an AspectAdapter, it provides * one item of a list as its own value. * To detect changes in the list, the list must be the value * of a ValueModel. * If the the ValueModel holding the list is a SelectionInList, * the index of the IndexedAdapter follows the selection in the * list. * If the list is not wrapped in a ValueModel, a change of * the list can't be detected.
* When the wrapped list changes, the index in that list * is set to NO_SELECTION if there is no IndexProvider.
* We also support the notion of an external update. * @param the type inside the list */ public class IndexedAdapter extends AbstractValueModel implements ValueModel, ExternalUpdate, ChangeListener { /** null or the value model containing our list */ private ValueModel> mTrigger; /** null or the provider of an index inside the list */ private IndexProvider mIndexProvider; /** null or mTrigger if the trigger is a SelectionInList */ private SelectionInList mSelectionInList; /** our source, may be null */ private List mSource; /** NO_SELECTION or the index in our list */ private int mIndex; /** checks if mIndex points to a value inside source, never null */ private IndexValidHolder mIndexInList; /** * Creates a new IndexedAdapter that does not select an entry in the list. * @param pTrigger the list we are indexing into is the trigger's value * @throws IllegalArgumentException if pTrigger or pTrigger.getValue() is null or not * a List */ public IndexedAdapter(final ValueModel> pTrigger) { this(pTrigger, IndexProvider.NO_SELECTION); } /** * Creates a new IndexedAdapter. * @param pTrigger the list we are indexing into is the trigger's value * @param pIndex NO_SELECTION or the initial index in the list * @throws IllegalArgumentException if pTrigger or pTrigger.getValue() is null or not * a List or pIndex is out of range */ public IndexedAdapter(final ValueModel> pTrigger, final int pIndex) { super(); if (pTrigger==null) throw new IllegalArgumentException("trigger must not be null"); Object value= pTrigger.getValue(); if ((value!=null) && !(value instanceof List)) throw new IllegalArgumentException("trigger value must be null or a List," + " not a "+value.getClass().getName()); init(pTrigger.getValue(), pTrigger, pIndex); } /** * Creates a new IndexedAdapter that does not select an entry in the list. * @param pSource the list we are indexing into * @throws IllegalArgumentException if pSource is null */ public IndexedAdapter(final List pSource) { this(pSource, IndexProvider.NO_SELECTION); } /** * Creates a new IndexedAdapter. * @param pSource the list we are indexing into * @param pIndex NO_SELECTION or the initial index in the list * @throws IllegalArgumentException if pSource is null or pIndex is out of range */ public IndexedAdapter(final List pSource, final int pIndex) { super(); if (pSource==null) throw new IllegalArgumentException("source must not be null"); init(pSource, null, pIndex); } /** * Handle common constructor stuff. * @param pSource list we are indexing into, must not be null * @param pTrigger trigger for our aspect, may be null * @param pIndex NO_SELECTION or the index in pSource * @throws IllegalArgumentException if pIndex is out of range */ private void init(final List pSource, final ValueModel> pTrigger, final int pIndex) { mSource = pSource; mTrigger = pTrigger; mIndex = pIndex; setInSetValue(false, false); if (mTrigger instanceof IndexProvider) { mIndexProvider= (IndexProvider) mTrigger; mIndex= mIndexProvider.getIndex(); } else { mIndexProvider= null; } checkIndex(mIndex, mSource); mIndexInList= new IndexValidHolder(mIndex); if (mTrigger!=null) { mTrigger.addChangeListener(this); if (mTrigger instanceof SelectionInList) { mSelectionInList= (SelectionInList)mTrigger; ValueModel indexProvider= mSelectionInList.selectionHolder(); indexProvider.onChangeSend(this, "indexChanged"); } } } /** * Return the Trigger or null if there is no trigger. * @return null or the trigger */ public ValueModel> getTrigger() { return mTrigger; } /** * Returns always true * @return true */ public boolean isEditable() { return true; } /** * Cleanup all resources: disconnect from any input sources (like * other ValueModel's ...), and remove all listeners. */ public void dispose() { super.dispose(); if (mTrigger!=null && !mTrigger.isDisposed()) { mTrigger.removeChangeListener(this); } if (mSelectionInList!=null && !mSelectionInList.isDisposed()) { mSelectionInList.selectionHolder().retractInterestsFor(this); } mIndexInList.dispose(); } /** * Small helper to check the index. * @param pIndex index to check * @param pSource List for the index */ private static void checkIndex(final int pIndex, final List pSource) { int maxSize= IndexProvider.NO_SELECTION; if (pSource!=null) { maxSize = pSource.size(); } if ((pIndex!=IndexProvider.NO_SELECTION) && ((pIndex=maxSize))) { throw new IllegalArgumentException("index out of range, got "+ pIndex+", but list size is "+ maxSize); } } /** * Return the list that is our source. If our trigger is a * SelectionInList, we get the list directly from the SIL and update * our source object. * @return null or the source list */ private List getSource() { if (mSelectionInList!=null) { mSource= mSelectionInList.getValue(); } return mSource; } /** * Set a new value, this will fire a ChangeEvent if the new value * is different from the old value. * If no list is available or no value is selected, nothing happens * @param pValue the new value (null is o.k.) * @param pIsSetForced true if a forced setValue should be done */ public void setValue(final T pValue, final boolean pIsSetForced) { checkDisposed(); if ((getSource()==null) || (mIndex==IndexProvider.NO_SELECTION)) { return; } setInSetValue(true, pIsSetForced); try { mSource.set(mIndex, pValue); fireStateChanged(); } finally { setInSetValue(false, false); } } /** * Get the current value, during a callback this is the new value. * If no list is available or no item is selected, null is returned. * @return null or the value object */ public T getValue() { checkDisposed(); if ((getSource()==null) || (mIndex==IndexProvider.NO_SELECTION)) { return null; } return mSource.get(mIndex); } /** * Set the index, if the index is different from the old index * wie fire a state change. * @param pIndex the new index */ public void setIndex(final int pIndex) { checkDisposed(); checkIndex(pIndex, getSource()); mIndex= pIndex; mIndexInList.setIndex(mIndex); fireStateChanged(); } /** * Get the current index. * @return NO_SELECTION or the current index */ public int getIndex() { checkDisposed(); return mIndex; } /** * Callback from our SelectionInList value model if it's index changed. * @param pEvent not used */ @SuppressWarnings({"UnusedDeclaration"}) public void indexChanged(final ChangeEvent pEvent) { Integer index= mSelectionInList.selectionHolder().getValue(); setIndex(index); } /** * The provided ValueModel can be used to monitor if this IndexedAdapter * holds a "valid" value (index is not NO_SELECTION). * The ValueModel is read-only, and contains either Boolean.TRUE or Boolean.FALSE. * @return a ValueModel with a Boolean value */ public ValueModel isIndexInList() { checkDisposed(); return mIndexInList; } /** * Signal this object that portions of its data changed. * If we have a trigger, we notify it, and assume that it will notify us, * otherwise we notify our children directly. */ public void signalExternalUpdate() { if (mTrigger instanceof ExternalUpdate) { ((ExternalUpdate)mTrigger).signalExternalUpdate(); } else { super.signalExternalUpdate(); } } /** * Invoked when the target of the listener has changed its state. * * @param pEvent a ChangeEvent object */ public void stateChanged(final ChangeEvent pEvent) { checkDisposed(); // ignore callbacks when we are the reason that our model changes if (isInSetValue()) { return; } // should never happen, because we didn't register somewhere if (mTrigger==null) { throw new IllegalStateException("got a callback with no trigger"); } List newList= mTrigger.getValue(); int newIndex= IndexProvider.NO_SELECTION; if (mIndexProvider!=null) { newIndex= mIndexProvider.getIndex(); } else { // otherwise try to keep the old index if (mIndex!=IndexProvider.NO_SELECTION) { if ((newList!=null) && (mIndex>=0) && (mIndex




© 2015 - 2025 Weber Informatics LLC | Privacy Policy