/* * Copyright (c) 2002,2009 Declarative Engineering LLC. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Declarative Engineering LLC * verson 1 which accompanies this distribution, and is available at * http://declarativeengineering.com/legal/DE_Developer_License_v1.txt */ package com.foundation.tcv.swt.server; import com.common.util.*; import com.common.debug.*; import com.foundation.view.*; import com.foundation.controller.IController; import com.foundation.event.*; /* * Encapsulates an object reference used by the view system at runtime, and the class of the runtime reference to allow design type automation. */ public class ValueHolder extends Component implements IValueHolder { /** The class of value held by this value holder. */ private Class heldType = null; /** The current value held by this value holder. */ private IEventEmitter value = null; /** The collection of listeners listening for held value events. */ private LiteHashSet eventListeners = new LiteHashSet(5); /** The collection of listeners listening for held value events. */ private LiteHashSet valueHolderListeners = new LiteHashSet(5, LiteHashSet.DEFAULT_LOAD_FACTOR, LiteHashSet.DEFAULT_COMPARATOR, LiteHashSet.STYLE_COUNT_DUPLICATES); /** The event support used by value holder related associations to listen for held value events. */ private EventSupport eventSupport = null; /** The parent resource from which this holder's value is derived. */ private SingleResourceAssociation parent = new SingleResourceAssociation(this, this, getViewContext(), SingleResourceAssociation.TYPE_OBJECT, false, null); /** Whether the value holder gets its value from a parent. */ private boolean hasParent = false; /** Whether to not warn when an attempt is made to place a value that is not of the correct type. */ private boolean ignoreWarnings = false; /** * ValueHolder constructor. * @param parent The parent container. * @param name The view unqiue name of the component. * @param heldType The type of object to be held by the value holder. */ public ValueHolder(IAbstractContainer parent, String name, Class heldType) { super(parent, name, 0); this.heldType = heldType; }//ValueHolder()// /** * Sets whether the holder supresses warnings relating to attempts at setting the value to an invalid object type. * @param ignoreWarnings Whether to not warn when an attempt is made to place a value that is not of the correct type. */ public void ignoreWarnings(boolean ignoreWarnings) { this.ignoreWarnings = ignoreWarnings; }//ignoreWarnings()// /** * Sets the association container used to access the parent value holder. * @param container The parent association metadata. */ public void setParentAssociation(SingleAssociationContainer container) { verifyThread(); this.parent.setAssociations(container); this.hasParent = true; }//setParentAssociation()// /** * Gets the support object that provides event listening functionality. * @return Will be used to listen for events from IEventEmitter objects. */ protected EventSupport getEventSupport() { if(eventSupport == null) { eventSupport = new EventSupport(null); }//if// return eventSupport; }//getEventSupport()// /** * Gets the value being held by this holder. * @return The currently held value. */ public IEventEmitter getValue() { return value; }//getValue()// /** * Gets the class for the values held by this value holder. * @return The held value type. */ public Class getHeldType() { return heldType; }//getHeldType()// /* (non-Javadoc) * @see com.foundation.view.IValueHolder#registerListener(com.foundation.view.IEventCapableAssociation) */ public void registerListener(IEventCapableAssociation eventAssociation) { IEventEmitter value = getValue(); if((value != null) && (eventAssociation.getEventNumber() != -1) && ((eventAssociation.getValueHolderHeldType() == null) || (eventAssociation.getValueHolderHeldType().isAssignableFrom(value.getClass())))) { getEventSupport().register(value, eventAssociation.getEventNumber(), eventAssociation, true); }//if// eventListeners.add(eventAssociation); }//registerListener()// /* (non-Javadoc) * @see com.foundation.view.IValueHolder#unregisterListener(com.foundation.view.IEventCapableAssociation) */ public void unregisterListener(IEventCapableAssociation eventAssociation) { IEventEmitter value = getValue(); if((value != null) && (eventAssociation.getEventNumber() != -1) && ((eventAssociation.getValueHolderHeldType() == null) || (eventAssociation.getValueHolderHeldType().isAssignableFrom(value.getClass())))) { getEventSupport().unregister(value, eventAssociation.getEventNumber(), eventAssociation); }//if// eventListeners.remove(eventAssociation); }//unregisterListener()// /* (non-Javadoc) * @see com.foundation.view.IValueHolder#registerListener(com.foundation.view.IValueHolderListener) */ public void registerListener(IValueHolderListener listener) { valueHolderListeners.add(listener); }//registerListener()// /* (non-Javadoc) * @see com.foundation.view.IValueHolder#unregisterListener(com.foundation.view.IValueHolderListener) */ public void unregisterListener(IValueHolderListener listener) { valueHolderListeners.remove(listener); }//unregisterListener()// /** * Updates the registered listeners so that they are registered with the new held value and are notified that their attributes may have changed. * @param oldHeldValue The old value held by this value holder. * @param newHeldValue The new value held by this value holder. */ public synchronized void updateRegisteredListeners(IEventEmitter oldHeldValue, IEventEmitter newHeldValue) { IIterator iterator = new LiteHashSet(eventListeners).iterator(); //Unregister and reregister handlers.// while(iterator.hasNext()) { IEventCapableAssociation eventAssociation = (IEventCapableAssociation) iterator.next(); if((oldHeldValue != null) && ((eventAssociation.getValueHolderHeldType() == null) || (eventAssociation.getValueHolderHeldType().isAssignableFrom(value.getClass())))) { getEventSupport().unregister(oldHeldValue, eventAssociation.getEventNumber(), eventAssociation); }//if// if((newHeldValue != null) && ((eventAssociation.getValueHolderHeldType() == null) || (eventAssociation.getValueHolderHeldType().isAssignableFrom(value.getClass())))) { getEventSupport().register(newHeldValue, eventAssociation.getEventNumber(), eventAssociation, true); }//if// }//while// iterator.resetToFront(); while(iterator.hasNext()) { IEventCapableAssociation eventAssociation = (IEventCapableAssociation) iterator.next(); eventAssociation.evaluate(eventAssociation.getEventNumber(), null, 0); }//while// //Notify the listeners so their user can update.// if(valueHolderListeners.getSize() > 0) { Object[] listeners = valueHolderListeners.toArray(); for(int index = 0; index < listeners.length; index++) { IValueHolderListener listener = (IValueHolderListener) listeners[index]; listener.heldValueChanged(); }//while// }//if// }//updateRegisteredListeners()// /** * Sets the value being held. * @param value The held value. */ protected void setValue(IEventEmitter value) { if(value != this.value) { IEventEmitter oldValue = this.value; this.value = value; updateRegisteredListeners(oldValue, value); }//if// }//setValue()// /* (non-Javadoc) * @see com.foundation.tcv.swt.server.AbstractComponent#internalViewInitialize() */ protected void internalViewInitialize() { parent.initialize(); isInitialized(true); }//internalViewInitialize()// /* (non-Javadoc) * @see com.foundation.tcv.swt.server.AbstractComponent#internalViewRelease() */ public void internalViewRelease() { parent.release(); if(getContainer() != null) { getContainer().getComponents().remove(this); }//if// }//internalViewRelease()// /* (non-Javadoc) * @see com.foundation.tcv.swt.server.AbstractComponent#internalViewRefresh() */ protected void internalViewRefresh() { if(isInitialized()) { if(hasParent) { if(parent.refresh()) { Object value = parent.getValue(); if((value == null) || (value instanceof IEventEmitter) && (heldType.isAssignableFrom(value.getClass()))) { setValue((IEventEmitter) value); }//if// else if(!ignoreWarnings) { if(value instanceof IEventEmitter) { Debug.log("Invalid held object. Received a " + value.getClass().getName() + " and was expecting a " + heldType.getName() + " in the ValueHolder named " + getName() + "."); }//if// else { Debug.log("Invalid held object. The class " + value.getClass().getName() + " does not implement " + IEventEmitter.class.getName() + " in the ValueHolder named " + getName() + "."); }//else// }//else if// }//if// }//if// else { IAbstractContainer parent = getContainer(); IController controller = null; while((parent != null) && (controller == null)) { if(parent instanceof IView) { controller = ((IView) parent).getController(); }//if// else { parent = parent.getContainer(); }//else// }//while// if((controller != null) && (controller.getClass().isAssignableFrom(heldType))) { setValue((IEventEmitter) controller); }//if// else if(!controller.getClass().isAssignableFrom(heldType)) { Debug.log("Invalid controller object. Received a " + controller.getClass().getName() + " and was expecting a " + heldType.getName() + " in the ValueHolder named " + getName() + "."); }//else if// }//else// }//if// }//internalViewRefresh()// /* (non-Javadoc) * @see com.foundation.tcv.swt.server.AbstractComponent#internalOnValueChanged(com.foundation.view.SingleResourceAssociation) */ protected void internalOnValueChanged(SingleResourceAssociation resourceAssociation, int flags) { if(isInitialized()) { internalViewRefresh(); }//if// }//internalOnValueChanged()// /* (non-Javadoc) * @see com.foundation.tcv.swt.server.AbstractComponent#getClientClassName() */ protected String getClientClassName() { return StringSupport.EMPTY_STRING; }//getClientClassName()// }//ValueHolder//