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

de.intarsys.tools.tree.CommonNode Maven / Gradle / Ivy

There is a newer version: 4.11
Show newest version
package de.intarsys.tools.tree;

import de.intarsys.tools.attribute.AttributeMap;
import de.intarsys.tools.attribute.IAttributeSupport;
import de.intarsys.tools.event.AttributeChangedEvent;
import de.intarsys.tools.event.DestroyedEvent;
import de.intarsys.tools.event.Event;
import de.intarsys.tools.event.EventDispatcher;
import de.intarsys.tools.event.EventType;
import de.intarsys.tools.event.INotificationListener;
import de.intarsys.tools.event.INotificationSupport;
import de.intarsys.tools.presentation.IPresentationSupport;

/**
 * A common implementation for a node in a tree. This node wraps a POJO for use
 * in presentation or other contexts.
 * 

* The node factory acts as the "role" in which the POJO wants to be wrapped or * seen. This allows a POJO to be seen differently in different usage contexts * by simply using another factory (role). *

* There are two main usage scenarios: *

* Implement a concrete {@link CommonNode} and {@link CommonNodeFactory} * subclass to determine node behavior. This results in quick and easy to * understand solution. The drawback is the static behavior - if you want to * change some implementation detail down the hierarchy level you have to create * subclasses according to this change up to the root level to ensure the * changed leaf node factory is used. *

* The second scenario involves a callback to a strategy object * {@link INodeHandler} where the node behavior is encapsulated. This allows for * a more generic node implementation with the drawback of a "instanceof" style * of coding in the callback handler. * * @param * The type of the wrapped POJO */ abstract public class CommonNode implements IPresentationSupport, INotificationSupport, IAttributeSupport { private static final CommonNode[] NODES_EMPTY = new CommonNode[0]; /** * Return the node associated with object. If no such node exists it will be * created as a child of parent. *

* The strategy of associating an object o a node is up to the factory. * * @param parent * @param role * @param object * @return Return the UNIQUE node associated with object. */ synchronized public static CommonNode getNode(CommonNode parent, CommonNodeFactory role, Object object) { CommonNode result = role.lookupNode(parent, object); if (result == null) { CommonNodeFactory factory = role.lookupFactory(object); result = factory.createNode(parent, object); role.registerNode(parent, result); } return result; } private AttributeMap attributes; private CommonNode[] cachedChildren; final private EventDispatcher eventDispatcher; final private INotificationListener listenObjectChange = new INotificationListener() { public void handleEvent(Event event) { onEvent(event); } }; final private INotificationListener listenObjectDestroy = new INotificationListener() { public void handleEvent(Event event) { onDestroy(event); } }; final private T object; final private CommonNode parent; private INodeHandler nodeHandler; protected CommonNode(CommonNode parent, T object) { super(); this.parent = parent; if (parent != null) { this.nodeHandler = parent.nodeHandler; } this.object = object; this.eventDispatcher = new EventDispatcher(this); arm(); } /* * (non-Javadoc) * * @see * de.intarsys.tools.event.INotificationSupport#addNotificationListener( * de.intarsys.tools.event.EventType, * de.intarsys.tools.event.INotificationListener) */ public void addNotificationListener(EventType type, INotificationListener listener) { eventDispatcher.addNotificationListener(type, listener); } protected void arm() { if (object instanceof INotificationSupport) { ((INotificationSupport) object).addNotificationListener( AttributeChangedEvent.ID, listenObjectChange); ((INotificationSupport) object).addNotificationListener( DestroyedEvent.ID, listenObjectDestroy); } } protected CommonNode[] basicCreateChildren() { return NODES_EMPTY; } protected String basicGetDescription() { return getTip(); } protected String basicGetIconName() { return null; } protected String basicGetLabel() { return object.toString(); } protected String basicGetObjectDescription() { if (getObject() instanceof IPresentationSupport) { return ((IPresentationSupport) getObject()).getDescription(); } else { return basicGetDescription(); } } protected String basicGetObjectIconName() { if (getObject() instanceof IPresentationSupport) { return ((IPresentationSupport) getObject()).getIconName(); } else { return basicGetIconName(); } } protected String basicGetObjectLabel() { if (getObject() instanceof IPresentationSupport) { return ((IPresentationSupport) getObject()).getLabel(); } else { return basicGetLabel(); } } protected String basicGetObjectTip() { if (getObject() instanceof IPresentationSupport) { return ((IPresentationSupport) getObject()).getTip(); } else { return basicGetTip(); } } protected String basicGetTip() { return getLabel(); } protected boolean basicHasChildren() { return cachedChildren == null || cachedChildren.length != 0; } protected void disarm() { if (object instanceof INotificationSupport) { ((INotificationSupport) object).removeNotificationListener( AttributeChangedEvent.ID, listenObjectChange); ((INotificationSupport) object).removeNotificationListener( DestroyedEvent.ID, listenObjectDestroy); } } /** * Dispose all resources and associations. This object is not reused any * more */ protected void dispose() { disarm(); disposeChildren(); if (attributes != null) { attributes.clear(); } if (eventDispatcher != null) { eventDispatcher.clear(); } } protected void disposeChildren() { if (cachedChildren == null) { return; } for (CommonNode child : cachedChildren) { child.dispose(); } updateChildren(); } synchronized public Object getAttribute(Object key) { if (attributes == null) { return null; } return attributes.getAttribute(key); } /** * Return all child nodes of this. * * @return Return all child nodes of this. */ public CommonNode[] getChildren() { if (cachedChildren == null) { if (nodeHandler == null) { cachedChildren = basicCreateChildren(); } else { cachedChildren = nodeHandler.createChildren(this); } } return cachedChildren; } /* * (non-Javadoc) * * @see de.intarsys.tools.presentation.IPresentationSupport#getDescription() */ public String getDescription() { if (nodeHandler != null) { return nodeHandler.getDescription(this); } return basicGetObjectDescription(); } /* * (non-Javadoc) * * @see de.intarsys.tools.presentation.IPresentationSupport#getIconName() */ public String getIconName() { if (nodeHandler != null) { return nodeHandler.getIconName(this); } return basicGetObjectIconName(); } /* * (non-Javadoc) * * @see de.intarsys.tools.presentation.IPresentationSupport#getLabel() */ public String getLabel() { if (nodeHandler != null) { return nodeHandler.getLabel(this); } return basicGetObjectLabel(); } public INodeHandler getNodeHandler() { return nodeHandler; } /** * The object represented by this node. * * @return The object represented by this node. */ public T getObject() { return object; } /** * The optional parent node. * * @return The optional parent node. */ public CommonNode getParent() { return parent; } /* * (non-Javadoc) * * @see de.intarsys.tools.presentation.IPresentationSupport#getTip() */ public String getTip() { if (nodeHandler != null) { return nodeHandler.getTip(this); } return basicGetObjectTip(); } /** * true if this node has children. * * @return true if this node has children. */ public boolean hasChildren() { if (nodeHandler == null) { return basicHasChildren(); } else { return nodeHandler.hasChildren(this); } } protected boolean isReusable() { return true; } protected void onAttributeChanged(AttributeChangedEvent event) { // redefine to update whatever attribute / children have changed... triggerChange("label", null, null); //$NON-NLS-1$ } protected void onDestroy(Event event) { dispose(); } protected void onEvent(Event event) { if (event instanceof AttributeChangedEvent) { onAttributeChanged((AttributeChangedEvent) event); } } synchronized public Object removeAttribute(Object key) { if (attributes == null) { return null; } return attributes.removeAttribute(key); } /* * (non-Javadoc) * * @see * de.intarsys.tools.event.INotificationSupport#removeNotificationListener * (de.intarsys.tools.event.EventType, * de.intarsys.tools.event.INotificationListener) */ public void removeNotificationListener(EventType type, INotificationListener listener) { eventDispatcher.removeNotificationListener(type, listener); } synchronized public Object setAttribute(Object key, Object value) { if (attributes == null) { attributes = new AttributeMap(); } return attributes.setAttribute(key, value); } public void setNodeHandler(INodeHandler nodeHandler) { this.nodeHandler = nodeHandler; unlinkChildren(); } protected void triggerChange(Object attribute, Object oldValue, Object newValue) { eventDispatcher.triggerEvent(new AttributeChangedEvent(this, attribute, oldValue, newValue)); } protected void unlink() { if (!isReusable()) { dispose(); } } protected void unlinkChildren() { if (cachedChildren == null) { return; } for (CommonNode child : cachedChildren) { child.unlink(); } updateChildren(); } protected void updateChildren() { if (cachedChildren == null) { return; } cachedChildren = null; triggerChange("children", null, null); //$NON-NLS-1$ } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy