/******************************************************************************* * Copyright (c) 2009 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.common.utility.internal.model.value; import java.util.EventListener; import org.eclipse.jpt.common.utility.model.listener.PropertyChangeListener; import org.eclipse.jpt.common.utility.model.value.PropertyValueModel; import org.eclipse.jpt.common.utility.model.value.WritablePropertyValueModel; /** * This {@link AspectAdapter} provides basic property change support. * This converts an "aspect" (as defined by subclasses) into * a single {@link #VALUE} property. *

* The typical subclass will override the following methods:

* To notify listeners, subclasses can call {@link #propertyChanged()} * whenever the aspect has changed. */ public abstract class AspectPropertyValueModelAdapter extends AspectAdapter implements WritablePropertyValueModel { /** * Cache the current value of the aspect so we * can pass an "old value" when we fire a property change event. * We need this because the value may be calculated and may * not be in the property change event fired by the subject, * especially when dealing with multiple aspects. */ protected V value; // ********** constructors ********** /** * Construct a property value model adapter for an aspect of the * specified subject. */ protected AspectPropertyValueModelAdapter(PropertyValueModel subjectHolder) { super(subjectHolder); // our value is null when we are not listening to the subject this.value = null; } // ********** PropertyValueModel implementation ********** /** * Return the value of the subject's aspect. */ @Override public final V getValue() { return this.value; } // ********** WritablePropertyValueModel implementation ********** /** * Set the value of the subject's aspect. */ public void setValue(V value) { if (this.subject != null) { this.setValue_(value); } } /** * Set the value of the subject's aspect. * At this point we can be sure the subject is not null. * @see #setValue(Object) */ protected void setValue_(@SuppressWarnings("unused") V value) { throw new RuntimeException("This method was not overridden."); //$NON-NLS-1$ } // ********** AspectAdapter implementation ********** @Override protected Class getListenerClass() { return PropertyChangeListener.class; } @Override protected String getListenerAspectName() { return VALUE; } @Override protected boolean hasListeners() { return this.hasAnyPropertyChangeListeners(VALUE); } @Override protected void fireAspectChanged(Object oldValue, Object newValue) { this.firePropertyChanged(VALUE, oldValue, newValue); } @Override protected void engageSubject() { super.engageSubject(); // synch our value *after* we start listening to the subject, // since its value might change when a listener is added this.value = this.buildValue(); } @Override protected void disengageSubject() { super.disengageSubject(); // clear out our value when we are not listening to the subject this.value = null; } // ********** behavior ********** /** * Return the aspect's value. * At this point the subject may be null. */ protected V buildValue() { return (this.subject == null) ? null : this.buildValue_(); } /** * Return the value of the subject's aspect. * At this point we can be sure the subject is not null. * @see #buildValue() */ protected V buildValue_() { throw new RuntimeException("This method was not overridden."); //$NON-NLS-1$ } /** * This method can be called by subclasses whenever the subject's aspect * has changed; listeners will be notified appropriately. */ protected void propertyChanged() { V old = this.value; this.value = this.buildValue(); this.fireAspectChanged(old, this.value); } @Override public void toString(StringBuilder sb) { sb.append(this.value); } }