blob: 1689c027d66b6da1f25e002b8040c7caca5896b9 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010 BSI Business Systems Integration AG.
* 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:
* BSI Business Systems Integration AG - initial API and implementation
******************************************************************************/
package org.eclipse.scout.rt.client.ui.form.fields.composer;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import org.eclipse.scout.commons.CollectionUtility;
import org.eclipse.scout.commons.ConfigurationUtility;
import org.eclipse.scout.commons.StringUtility;
import org.eclipse.scout.commons.annotations.ClassId;
import org.eclipse.scout.commons.annotations.ConfigOperation;
import org.eclipse.scout.commons.annotations.FormData;
import org.eclipse.scout.commons.annotations.FormData.DefaultSubtypeSdkCommand;
import org.eclipse.scout.commons.annotations.FormData.SdkCommand;
import org.eclipse.scout.commons.annotations.Order;
import org.eclipse.scout.commons.exception.ProcessingException;
import org.eclipse.scout.commons.logger.IScoutLogger;
import org.eclipse.scout.commons.logger.ScoutLogManager;
import org.eclipse.scout.commons.xmlparser.SimpleXmlElement;
import org.eclipse.scout.rt.client.extension.ui.form.fields.IFormFieldExtension;
import org.eclipse.scout.rt.client.extension.ui.form.fields.composer.ComposerFieldChains.ComposerFieldCreateAdditionalOrNodeChain;
import org.eclipse.scout.rt.client.extension.ui.form.fields.composer.ComposerFieldChains.ComposerFieldCreateAttributeNodeChain;
import org.eclipse.scout.rt.client.extension.ui.form.fields.composer.ComposerFieldChains.ComposerFieldCreateDataModelChain;
import org.eclipse.scout.rt.client.extension.ui.form.fields.composer.ComposerFieldChains.ComposerFieldCreateEitherNodeChain;
import org.eclipse.scout.rt.client.extension.ui.form.fields.composer.ComposerFieldChains.ComposerFieldCreateEntityNodeChain;
import org.eclipse.scout.rt.client.extension.ui.form.fields.composer.ComposerFieldChains.ComposerFieldCreateRootNodeChain;
import org.eclipse.scout.rt.client.extension.ui.form.fields.composer.ComposerFieldChains.ComposerFieldResolveAttributePathChain;
import org.eclipse.scout.rt.client.extension.ui.form.fields.composer.ComposerFieldChains.ComposerFieldResolveEntityPathChain;
import org.eclipse.scout.rt.client.extension.ui.form.fields.composer.ComposerFieldChains.ComposerFieldResolveRootPathForTopLevelAttributeChain;
import org.eclipse.scout.rt.client.extension.ui.form.fields.composer.ComposerFieldChains.ComposerFieldResolveRootPathForTopLevelEntityChain;
import org.eclipse.scout.rt.client.extension.ui.form.fields.composer.IComposerFieldExtension;
import org.eclipse.scout.rt.client.ui.basic.cell.Cell;
import org.eclipse.scout.rt.client.ui.basic.tree.AbstractTree;
import org.eclipse.scout.rt.client.ui.basic.tree.ITree;
import org.eclipse.scout.rt.client.ui.basic.tree.ITreeNode;
import org.eclipse.scout.rt.client.ui.basic.tree.ITreeVisitor;
import org.eclipse.scout.rt.client.ui.basic.tree.TreeAdapter;
import org.eclipse.scout.rt.client.ui.basic.tree.TreeEvent;
import org.eclipse.scout.rt.client.ui.form.fields.AbstractFormField;
import org.eclipse.scout.rt.client.ui.form.fields.composer.node.AttributeNode;
import org.eclipse.scout.rt.client.ui.form.fields.composer.node.EitherOrNode;
import org.eclipse.scout.rt.client.ui.form.fields.composer.node.EntityNode;
import org.eclipse.scout.rt.client.ui.form.fields.composer.node.RootNode;
import org.eclipse.scout.rt.shared.AbstractIcons;
import org.eclipse.scout.rt.shared.data.form.fields.AbstractFormFieldData;
import org.eclipse.scout.rt.shared.data.form.fields.composer.AbstractComposerData;
import org.eclipse.scout.rt.shared.data.form.fields.composer.ComposerAttributeNodeData;
import org.eclipse.scout.rt.shared.data.form.fields.composer.ComposerEitherOrNodeData;
import org.eclipse.scout.rt.shared.data.form.fields.composer.ComposerEntityNodeData;
import org.eclipse.scout.rt.shared.data.form.fields.treefield.AbstractTreeFieldData;
import org.eclipse.scout.rt.shared.data.form.fields.treefield.TreeNodeData;
import org.eclipse.scout.rt.shared.data.model.AttributePath;
import org.eclipse.scout.rt.shared.data.model.DataModelAttributeOp;
import org.eclipse.scout.rt.shared.data.model.DataModelConstants;
import org.eclipse.scout.rt.shared.data.model.DataModelUtility;
import org.eclipse.scout.rt.shared.data.model.EntityPath;
import org.eclipse.scout.rt.shared.data.model.IDataModel;
import org.eclipse.scout.rt.shared.data.model.IDataModelAttribute;
import org.eclipse.scout.rt.shared.data.model.IDataModelAttributeOp;
import org.eclipse.scout.rt.shared.data.model.IDataModelEntity;
import org.eclipse.scout.rt.shared.services.common.exceptionhandler.IExceptionHandlerService;
import org.eclipse.scout.service.SERVICES;
@SuppressWarnings("deprecation")
@ClassId("8e7f7eb8-be18-48e5-9efe-8a5b3459e247")
@FormData(value = AbstractComposerData.class, sdkCommand = SdkCommand.USE, defaultSubtypeSdkCommand = DefaultSubtypeSdkCommand.CREATE)
public abstract class AbstractComposerField extends AbstractFormField implements IComposerField {
private static final IScoutLogger LOG = ScoutLogManager.getLogger(AbstractComposerField.class);
private IComposerFieldUIFacade m_uiFacade;
private ITree m_tree;
private SimpleXmlElement m_initValue;
private IDataModel m_dataModel;
public AbstractComposerField() {
this(true);
}
public AbstractComposerField(boolean callInitializer) {
super(callInitializer);
}
@Override
public IDataModel getDataModel() {
return m_dataModel;
}
@Override
public void setDataModel(IDataModel dm) {
m_dataModel = dm;
}
/**
* The default creates a data model with the inner entities and attributes
* <p>
* Other implementations may use a data model defined in the shared area
*/
@ConfigOperation
@Order(97)
protected IDataModel execCreateDataModel() {
ComposerFieldDataModel m = new ComposerFieldDataModel(this);
m.init();
return m;
}
/**
* see {@link #interceptResolveEntityPath(EntityNode)}
*/
@ConfigOperation
@Order(98)
protected void execResolveRootPathForTopLevelEntity(IDataModelEntity e, List<IDataModelEntity> lifeList) {
IDataModelEntity tmp = (e != null ? e.getParentEntity() : null);
while (tmp != null) {
lifeList.add(0, tmp);
tmp = tmp.getParentEntity();
}
}
/**
* see {@link #interceptResolveAttributePath(AttributeNode)}
*/
@ConfigOperation
@Order(98)
protected void execResolveRootPathForTopLevelAttribute(IDataModelAttribute a, List<IDataModelEntity> lifeList) {
IDataModelEntity tmp = (a != null ? a.getParentEntity() : null);
while (tmp != null) {
lifeList.add(0, tmp);
tmp = tmp.getParentEntity();
}
}
/**
* For {@link #exportFormFieldData(AbstractFormFieldData)}, {@link AbstractTree#exportTreeData(AbstractTreeFieldData)}
* and {@link #storeXML(SimpleXmlElement)} it is necessary to export {@link IDataModelEntity} and
* {@link IDataModelAttribute} as external strings. see {@link EntityPath}
* <p>
* This callback completes an entity path to its root. The parameter path contains the entity path represented in the
* composer tree of {@link EntityNode}s, the last element is the deepest tree node.
* <p>
* The default traverses the tree up to the root and collects all non-null {@link EntityNode#getEntity()}
* <p>
* This is prefixed with {@link #interceptResolveRootPathForTopLevelEntity(IDataModelEntity, List)}
*/
@ConfigOperation
@Order(99)
protected EntityPath execResolveEntityPath(EntityNode node) {
LinkedList<IDataModelEntity> list = new LinkedList<IDataModelEntity>();
EntityNode tmp = node;
while (tmp != null) {
if (tmp.getEntity() != null) {
list.add(0, tmp.getEntity());
}
//next
tmp = tmp.getAncestorNode(EntityNode.class);
}
if (list.size() > 0) {
interceptResolveRootPathForTopLevelEntity(list.get(0), list);
}
return new EntityPath(list);
}
/**
* see {@link #execResolveEntityPathForEntityExport(EntityNode)}, {@link AttributePath} for more details
* <p>
* The path in the composer tree is prefixed with
* {@link #interceptResolveRootPathForTopLevelAttribute(IDataModelAttribute, List)}
*/
@ConfigOperation
@Order(99)
protected AttributePath execResolveAttributePath(AttributeNode node) {
LinkedList<IDataModelEntity> list = new LinkedList<IDataModelEntity>();
if (node == null) {
return null;
}
EntityNode tmp = node.getAncestorNode(EntityNode.class);
while (tmp != null) {
if (tmp.getEntity() != null) {
list.add(0, tmp.getEntity());
}
//next
tmp = tmp.getAncestorNode(EntityNode.class);
}
if (list.size() > 0) {
interceptResolveRootPathForTopLevelEntity(list.get(0), list);
}
else {
interceptResolveRootPathForTopLevelAttribute(node.getAttribute(), list);
}
return new AttributePath(list, node.getAttribute());
}
/*
* Configuration
*/
private Class<? extends ITree> getConfiguredTree() {
Class<?>[] dca = ConfigurationUtility.getDeclaredPublicClasses(getClass());
List<Class<ITree>> f = ConfigurationUtility.filterClasses(dca, ITree.class);
if (f.size() == 1) {
return CollectionUtility.firstElement(f);
}
else {
for (Class<? extends ITree> c : f) {
if (c.getDeclaringClass() != AbstractComposerField.class) {
return c;
}
}
return null;
}
}
/**
* Override this method to decorate or enhance new nodes whenever they are created
*
* @return the new node, must not be null
* <p>
* Normally overrides call super. {@link #interceptCreateRootNode()}
*/
@ConfigOperation
@Order(100)
protected RootNode execCreateRootNode() {
return new RootNode(this);
}
/**
* Override this method to decorate or enhance new nodes whenever they are created
*
* @return the new node or null to ignore the add of a new node of this type
* <p>
* Normally overrides call super. {@link #execCreateEntityNode(ITreeNode, IDataModelEntity, boolean, Object[],
* List<String>)}
*/
@ConfigOperation
@Order(110)
protected EntityNode execCreateEntityNode(ITreeNode parentNode, IDataModelEntity e, boolean negated, List<? extends Object> values, List<String> texts) {
EntityNode node = new EntityNode(this, e);
node.setValues(values);
node.setTexts(texts);
node.setNegative(negated);
node.setStatus(ITreeNode.STATUS_INSERTED);
return node;
}
/**
* Override this method to decorate or enhance new nodes whenever they are created
*
* @return the new node or null to ignore the add of a new node of this type
* <p>
* Normally overrides call super. {@link #execCreateAttributeNode(ITreeNode, IDataModelAttribute, Integer,
* IComposerOp, Object[], List<String>)}
*/
@ConfigOperation
@Order(120)
protected AttributeNode execCreateAttributeNode(ITreeNode parentNode, IDataModelAttribute a, Integer aggregationType, IDataModelAttributeOp op, List<? extends Object> values, List<String> texts) {
if (aggregationType != null && aggregationType == DataModelConstants.AGGREGATION_NONE) {
aggregationType = null;
}
AttributeNode node = new AttributeNode(this, a);
node.setAggregationType(aggregationType);
node.setOp(op);
node.setValues(values);
node.setTexts(texts);
node.setStatus(ITreeNode.STATUS_INSERTED);
return node;
}
/**
* Override this method to decorate or enhance new nodes whenever they are created
*
* @return the new node or null to ignore the add of a new node of this type
* <p>
* Normally overrides call super.{@link #interceptCreateEitherNode(ITreeNode, boolean)}
*/
@ConfigOperation
@Order(130)
protected EitherOrNode execCreateEitherNode(ITreeNode parentNode, boolean negated) {
EitherOrNode node = new EitherOrNode(this, true);
node.setNegative(negated);
node.setStatus(ITreeNode.STATUS_INSERTED);
return node;
}
/**
* Override this method to decorate or enhance new nodes whenever they are created
*
* @return the new node or null to ignore the add of a new node of this type
* <p>
* Normally overrides call super.{@link #interceptCreateAdditionalOrNode(ITreeNode, boolean)}
*/
@ConfigOperation
@Order(140)
protected EitherOrNode execCreateAdditionalOrNode(ITreeNode eitherOrNode, boolean negated) {
EitherOrNode node = new EitherOrNode(this, false);
node.setNegative(negated);
node.setStatus(ITreeNode.STATUS_INSERTED);
return node;
}
@Override
protected void initConfig() {
m_uiFacade = new P_UIFacade();
super.initConfig();
m_dataModel = interceptCreateDataModel();
// tree
try {
List<ITree> contributedTrees = m_contributionHolder.getContributionsByClass(ITree.class);
m_tree = CollectionUtility.firstElement(contributedTrees);
if (m_tree == null) {
Class<? extends ITree> configuredTree = getConfiguredTree();
if (configuredTree != null) {
m_tree = ConfigurationUtility.newInnerInstance(this, configuredTree);
}
}
if (m_tree != null) {
RootNode rootNode = interceptCreateRootNode();
rootNode.getCellForUpdate().setText(getLabel());
m_tree.setRootNode(rootNode);
m_tree.setNodeExpanded(rootNode, true);
m_tree.setEnabled(isEnabled());
m_tree.addTreeListener(
new TreeAdapter() {
@Override
public void treeChanged(TreeEvent e) {
switch (e.getType()) {
case TreeEvent.TYPE_NODES_DELETED:
case TreeEvent.TYPE_NODES_INSERTED:
case TreeEvent.TYPE_NODES_UPDATED: {
checkSaveNeeded();
checkEmpty();
break;
}
}
}
}
);
// local enabled listener
addPropertyChangeListener(PROP_ENABLED, new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent e) {
if (m_tree != null) {
m_tree.setEnabled(isEnabled());
}
}
});
}
else {
LOG.warn("there is no inner class of type ITree in " + getClass().getName());
}
}
catch (Exception e) {
SERVICES.getService(IExceptionHandlerService.class).handleException(new ProcessingException("error creating tree for composer field '" + getClass().getName() + "'.", e));
}
}
/*
* Runtime
*/
@Override
protected void initFieldInternal() throws ProcessingException {
getTree().initTree();
super.initFieldInternal();
}
@Override
protected void disposeFieldInternal() {
super.disposeFieldInternal();
getTree().disposeTree();
}
@Override
public final ITree getTree() {
return m_tree;
}
@Override
public void exportFormFieldData(AbstractFormFieldData target) throws ProcessingException {
if (m_tree != null) {
AbstractTreeFieldData treeFieldData = (AbstractTreeFieldData) target;
m_tree.exportTreeData(treeFieldData);
}
}
@Override
public void importFormFieldData(AbstractFormFieldData source, boolean valueChangeTriggersEnabled) throws ProcessingException {
AbstractTreeFieldData treeFieldData = (AbstractTreeFieldData) source;
if (treeFieldData.isValueSet()) {
if (m_tree != null) {
try {
if (!valueChangeTriggersEnabled) {
setValueChangeTriggerEnabled(false);
}
//
m_tree.importTreeData(treeFieldData);
}
finally {
if (!valueChangeTriggersEnabled) {
setValueChangeTriggerEnabled(true);
}
}
}
}
}
@Override
public List<IDataModelAttribute> getAttributes() {
return m_dataModel.getAttributes();
}
@Override
public List<IDataModelEntity> getEntities() {
return m_dataModel.getEntities();
}
@Override
public void loadXML(SimpleXmlElement x) throws ProcessingException {
super.loadXML(x);
ITree tree = getTree();
try {
tree.setTreeChanging(true);
//
getTree().removeAllChildNodes(getTree().getRootNode());
loadXMLRec(x, getTree().getRootNode());
}
finally {
tree.setTreeChanging(false);
}
}
private void loadXMLRec(SimpleXmlElement x, ITreeNode parent) {
// build tree
for (SimpleXmlElement xmlElem : x.getChildren()) {
if ("attribute".equals(xmlElem.getName())) {
String id = xmlElem.getStringAttribute("id");
IDataModelAttributeOp op;
Integer aggregationType;
try {
op = DataModelAttributeOp.create(xmlElem.getIntAttribute("op", DataModelConstants.OPERATOR_EQ));
aggregationType = xmlElem.getIntAttribute("aggregationType", 0);
if (aggregationType == 0) {
aggregationType = null;
}
}
catch (Exception e) {
LOG.warn("read op", e);
continue;
}
ArrayList<Object> valueList = new ArrayList<Object>();
try {
for (int i = 1; i <= 5; i++) {
String valueName = (i == 1 ? "value" : "value" + i);
if (xmlElem.hasAttribute(valueName)) {
valueList.add(xmlElem.getObjectAttribute(valueName, null));
}
}
}
catch (Exception e) {
LOG.warn("read value for attribute " + id, e);
continue;
}
ArrayList<String> displayValueList = new ArrayList<String>();
for (int i = 1; i <= 5; i++) {
String displayValueName = (i == 1 ? "displayValue" : "displayValue" + i);
if (xmlElem.hasAttribute(displayValueName)) {
displayValueList.add(xmlElem.getStringAttribute(displayValueName, null));
}
}
// find definition
AttributePath attPath = DataModelUtility.externalIdToAttributePath(getDataModel(), id);
IDataModelAttribute foundAtt = (attPath != null ? attPath.getAttribute() : null);
if (foundAtt == null) {
LOG.warn("cannot find attribute with id=" + id);
continue;
}
ITreeNode node = addAttributeNode(parent, foundAtt, aggregationType, op, valueList, displayValueList);
if (node != null) {
// add children recursive
loadXMLRec(xmlElem, node);
}
}
else if ("entity".equals(xmlElem.getName())) {
String id = xmlElem.getStringAttribute("id");
boolean negated = xmlElem.getStringAttribute("negated", "false").equalsIgnoreCase("true");
String text = xmlElem.getStringAttribute("displayValues", null);
// find definition
EntityPath entityPath = DataModelUtility.externalIdToEntityPath(getDataModel(), id);
IDataModelEntity foundEntity = (entityPath != null ? entityPath.lastElement() : null);
if (foundEntity == null) {
LOG.warn("cannot find entity with id=" + id);
continue;
}
ITreeNode node = addEntityNode(parent, foundEntity, negated, null, text != null ? Collections.singletonList(text) : null);
if (node != null) {
// add children recursive
loadXMLRec(xmlElem, node);
}
}
else if ("or".equals(xmlElem.getName())) {
boolean beginning = xmlElem.getStringAttribute("begin", "false").equalsIgnoreCase("true");
boolean negated = xmlElem.getStringAttribute("negated", "false").equalsIgnoreCase("true");
ITreeNode node = null;
if (beginning) {
node = addEitherNode(parent, negated);
}
else {
// find last EitherOrNode
EitherOrNode orNode = null;
for (ITreeNode n : parent.getChildNodes()) {
if (n instanceof EitherOrNode && ((EitherOrNode) n).isBeginOfEitherOr()) {
orNode = (EitherOrNode) n;
}
}
if (orNode != null) {
node = addAdditionalOrNode(orNode, negated);
}
}
if (node != null) {
// add children recursive
loadXMLRec(xmlElem, node);
}
}
}
}
@Override
public void storeXML(SimpleXmlElement x) throws ProcessingException {
super.storeXML(x);
storeXMLRec(x, getTree().getRootNode());
}
private void createDataModelEntityPathRec(EntityNode node, List<IDataModelEntity> list) {
}
private void storeXMLRec(SimpleXmlElement x, ITreeNode parent) {
for (ITreeNode node : parent.getChildNodes()) {
if (node instanceof EntityNode) {
EntityNode entityNode = (EntityNode) node;
SimpleXmlElement xEntity = new SimpleXmlElement("entity");
xEntity.setAttribute("id", DataModelUtility.entityPathToExternalId(getDataModel(), interceptResolveEntityPath(entityNode)));
xEntity.setAttribute("negated", (entityNode.isNegative() ? "true" : "false"));
List<String> texts = entityNode.getTexts();
xEntity.setAttribute("displayValues", CollectionUtility.hasElements(texts) ? StringUtility.emptyIfNull(CollectionUtility.firstElement(texts)) : null);
x.addChild(xEntity);
// recursion
storeXMLRec(xEntity, node);
}
else if (node instanceof AttributeNode) {
AttributeNode attNode = (AttributeNode) node;
SimpleXmlElement xAtt = new SimpleXmlElement("attribute");
xAtt.setAttribute("id", DataModelUtility.attributePathToExternalId(getDataModel(), interceptResolveAttributePath(attNode)));
IDataModelAttributeOp op = attNode.getOp();
try {
xAtt.setAttribute("op", op.getOperator());
if (attNode.getAggregationType() != null) {
xAtt.setIntAttribute("aggregationType", attNode.getAggregationType());
}
}
catch (Exception e) {
LOG.warn("write op " + op, e);
}
List<String> texts = attNode.getTexts();
if (CollectionUtility.hasElements(texts)) {
Iterator<String> it = texts.iterator();
xAtt.setAttribute("displayValue", StringUtility.emptyIfNull(it.next()));
int i = 2;
while (it.hasNext()) {
xAtt.setAttribute(("displayValue" + i), StringUtility.emptyIfNull(it.next()));
i++;
}
}
List<Object> values = attNode.getValues();
if (values != null) {
int i = 0;
for (Object value : values) {
String valueName = (i == 0 ? "value" : "value" + (i + 1));
try {
xAtt.setObjectAttribute(valueName, value);
}
catch (Exception e) {
LOG.warn("write value[" + i + "] for attribute " + attNode.getAttribute() + ": " + value, e);
}
i++;
}
}
x.addChild(xAtt);
}
else if (node instanceof EitherOrNode) {
EitherOrNode orNode = (EitherOrNode) node;
SimpleXmlElement xOr = new SimpleXmlElement("or");
xOr.setAttribute("begin", "" + orNode.isBeginOfEitherOr());
xOr.setAttribute("negated", (orNode.isNegative() ? "true" : "false"));
x.addChild(xOr);
// recursion
storeXMLRec(xOr, node);
}
}
}
@Override
public void resetValue() {
if (m_initValue == null) {
getTree().removeAllChildNodes(getTree().getRootNode());
}
else {
try {
loadXML(m_initValue);
}
catch (ProcessingException e) {
LOG.error("unexpected error occured while restoring initial value", e);
getTree().removeAllChildNodes(getTree().getRootNode());
}
}
checkSaveNeeded();
checkEmpty();
}
@Override
public EntityNode addEntityNode(ITreeNode parentNode, IDataModelEntity e, boolean negated, List<? extends Object> values, List<String> texts) {
EntityNode node = interceptCreateEntityNode(parentNode, e, negated, values, texts);
if (node != null) {
getTree().addChildNode(parentNode, node);
getTree().setNodeExpanded(node, true);
}
return node;
}
@Override
public EitherOrNode addEitherNode(ITreeNode parentNode, boolean negated) {
EitherOrNode node = interceptCreateEitherNode(parentNode, negated);
if (node != null) {
getTree().addChildNode(parentNode, node);
getTree().setNodeExpanded(node, true);
}
return node;
}
@Override
public EitherOrNode addAdditionalOrNode(ITreeNode eitherOrNode, boolean negated) {
EitherOrNode node = interceptCreateAdditionalOrNode(eitherOrNode, negated);
if (node != null) {
getTree().addChildNode(eitherOrNode.getChildNodeIndex() + 1, eitherOrNode.getParentNode(), node);
getTree().setNodeExpanded(node, true);
}
return node;
}
@Override
public AttributeNode addAttributeNode(ITreeNode parentNode, IDataModelAttribute a, Integer aggregationType, IDataModelAttributeOp op, List<? extends Object> values, List<String> texts) {
AttributeNode node = interceptCreateAttributeNode(parentNode, a, aggregationType, op, values, texts);
if (node != null) {
getTree().addChildNode(parentNode, node);
}
return node;
}
public void updateInitialValue() {
try {
// clone composer field by storing as XML
SimpleXmlElement element = new SimpleXmlElement();
storeXML(element);
m_initValue = element;
}
catch (ProcessingException e) {
LOG.warn("unexpected error occured while storing initial value", e);
}
}
@Override
protected boolean execIsSaveNeeded() throws ProcessingException {
boolean b = false;
if (b == false && m_tree.getDeletedNodeCount() > 0) {
b = true;
}
if (b == false && m_tree.getInsertedNodeCount() > 0) {
b = true;
}
if (b == false && m_tree.getUpdatedNodeCount() > 0) {
b = true;
}
return b;
}
@Override
protected void execMarkSaved() throws ProcessingException {
try {
m_tree.setTreeChanging(true);
//
ITreeVisitor v = new ITreeVisitor() {
@Override
public boolean visit(ITreeNode node) {
if (!node.isStatusNonchanged()) {
node.setStatusInternal(ITreeNode.STATUS_NON_CHANGED);
m_tree.updateNode(node);
}
return true;
}
};
m_tree.visitNode(m_tree.getRootNode(), v);
m_tree.clearDeletedNodes();
updateInitialValue();
}
finally {
m_tree.setTreeChanging(false);
}
}
@Override
protected boolean execIsEmpty() throws ProcessingException {
if (m_tree.getRootNode() != null && m_tree.getRootNode().getChildNodeCount() > 0) {
return false;
}
return true;
}
@Override
public IComposerFieldUIFacade getUIFacade() {
return m_uiFacade;
}
/**
* ui facade
*/
private class P_UIFacade implements IComposerFieldUIFacade {
}
/**
* inner tree type
*/
public class Tree extends AbstractTree {
@Override
protected boolean getConfiguredRootNodeVisible() {
return true;
}
@Override
protected TreeNodeData exportTreeNodeData(ITreeNode node, AbstractTreeFieldData treeData) throws ProcessingException {
if (node instanceof EntityNode) {
EntityNode enode = (EntityNode) node;
String externalId = DataModelUtility.entityPathToExternalId(getDataModel(), interceptResolveEntityPath(enode));
if (externalId == null) {
if (LOG.isInfoEnabled()) {
LOG.info("could not find entity data for: " + enode.getEntity());
}
return null;
}
ComposerEntityNodeData data = new ComposerEntityNodeData();
data.setEntityExternalId(externalId);
data.setNegative(enode.isNegative());
return data;
}
else if (node instanceof AttributeNode) {
AttributeNode anode = (AttributeNode) node;
String externalId = DataModelUtility.attributePathToExternalId(getDataModel(), interceptResolveAttributePath(anode));
if (externalId == null) {
if (LOG.isInfoEnabled()) {
LOG.info("could not find attribute data for: " + anode.getAttribute());
}
return null;
}
ComposerAttributeNodeData data = new ComposerAttributeNodeData();
data.setAttributeExternalId(externalId);
data.setNegative(false);
data.setAggregationType(anode.getAggregationType());
data.setOperator(anode.getOp().getOperator());
data.setValues(anode.getValues());
data.setTexts(anode.getTexts());
return data;
}
else if (node instanceof EitherOrNode) {
EitherOrNode eonode = (EitherOrNode) node;
ComposerEitherOrNodeData data = new ComposerEitherOrNodeData();
data.setNegative(eonode.isNegative());
data.setBeginOfEitherOr(eonode.isBeginOfEitherOr());
return data;
}
else {
return null;
}
}
@Override
protected ITreeNode importTreeNodeData(ITreeNode parentNode, AbstractTreeFieldData treeData, TreeNodeData nodeData) throws ProcessingException {
if (nodeData instanceof ComposerEntityNodeData) {
ComposerEntityNodeData enodeData = (ComposerEntityNodeData) nodeData;
String externalId = enodeData.getEntityExternalId();
EntityPath entityPath = DataModelUtility.externalIdToEntityPath(getDataModel(), externalId);
IDataModelEntity e = (entityPath != null ? entityPath.lastElement() : null);
if (e == null) {
LOG.warn("could not find entity for: " + enodeData.getEntityExternalId());
return null;
}
return addEntityNode(parentNode, e, enodeData.isNegative(), null, enodeData.getTexts());
}
else if (nodeData instanceof ComposerAttributeNodeData) {
ComposerAttributeNodeData anodeData = (ComposerAttributeNodeData) nodeData;
String externalId = anodeData.getAttributeExternalId();
AttributePath attPath = DataModelUtility.externalIdToAttributePath(getDataModel(), externalId);
IDataModelAttribute a = (attPath != null ? attPath.getAttribute() : null);
if (a == null) {
LOG.warn("could not find attribute for: " + anodeData.getAttributeExternalId());
return null;
}
IDataModelAttributeOp op;
try {
op = DataModelAttributeOp.create(anodeData.getOperator());
}
catch (Exception e) {
LOG.warn("read op " + anodeData.getOperator(), e);
return null;
}
return addAttributeNode(parentNode, a, anodeData.getAggregationType(), op, anodeData.getValues(), anodeData.getTexts());
}
else if (nodeData instanceof ComposerEitherOrNodeData) {
ComposerEitherOrNodeData eonodeData = (ComposerEitherOrNodeData) nodeData;
if (eonodeData.isBeginOfEitherOr()) {
return addEitherNode(parentNode, eonodeData.isNegative());
}
else {
// Bugzilla 400056: get sibling either/or node, must be latest child
ITreeNode eitherOrNode = parentNode.getChildNode(parentNode.getChildNodeCount() - 1);
return addAdditionalOrNode(eitherOrNode, eonodeData.isNegative());
}
}
else {
return null;
}
}
@Override
protected void execDecorateCell(ITreeNode node, Cell cell) throws ProcessingException {
node.decorateCell();
if (getIconId() != null) {
cell.setIconId(getIconId());
}
else {
if (node instanceof RootNode) {
cell.setIconId(AbstractIcons.ComposerFieldRoot);
}
else if (node instanceof EntityNode) {
cell.setIconId(AbstractIcons.ComposerFieldEntity);
}
else if (node instanceof AttributeNode) {
if (((AttributeNode) node).getAggregationType() != null) {
cell.setIconId(AbstractIcons.ComposerFieldAggregation);
}
else {
cell.setIconId(AbstractIcons.ComposerFieldAttribute);
}
}
else if (node instanceof EitherOrNode) {
cell.setIconId(AbstractIcons.ComposerFieldEitherOrNode);
}
}
}
}
protected final EntityPath interceptResolveEntityPath(EntityNode node) {
List<? extends IFormFieldExtension<? extends AbstractFormField>> extensions = getAllExtensions();
ComposerFieldResolveEntityPathChain chain = new ComposerFieldResolveEntityPathChain(extensions);
return chain.execResolveEntityPath(node);
}
protected final void interceptResolveRootPathForTopLevelEntity(IDataModelEntity e, List<IDataModelEntity> lifeList) {
List<? extends IFormFieldExtension<? extends AbstractFormField>> extensions = getAllExtensions();
ComposerFieldResolveRootPathForTopLevelEntityChain chain = new ComposerFieldResolveRootPathForTopLevelEntityChain(extensions);
chain.execResolveRootPathForTopLevelEntity(e, lifeList);
}
protected final RootNode interceptCreateRootNode() {
List<? extends IFormFieldExtension<? extends AbstractFormField>> extensions = getAllExtensions();
ComposerFieldCreateRootNodeChain chain = new ComposerFieldCreateRootNodeChain(extensions);
return chain.execCreateRootNode();
}
protected final AttributePath interceptResolveAttributePath(AttributeNode node) {
List<? extends IFormFieldExtension<? extends AbstractFormField>> extensions = getAllExtensions();
ComposerFieldResolveAttributePathChain chain = new ComposerFieldResolveAttributePathChain(extensions);
return chain.execResolveAttributePath(node);
}
protected final AttributeNode interceptCreateAttributeNode(ITreeNode parentNode, IDataModelAttribute a, Integer aggregationType, IDataModelAttributeOp op, List<? extends Object> values, List<String> texts) {
List<? extends IFormFieldExtension<? extends AbstractFormField>> extensions = getAllExtensions();
ComposerFieldCreateAttributeNodeChain chain = new ComposerFieldCreateAttributeNodeChain(extensions);
return chain.execCreateAttributeNode(parentNode, a, aggregationType, op, values, texts);
}
protected final IDataModel interceptCreateDataModel() {
List<? extends IFormFieldExtension<? extends AbstractFormField>> extensions = getAllExtensions();
ComposerFieldCreateDataModelChain chain = new ComposerFieldCreateDataModelChain(extensions);
return chain.execCreateDataModel();
}
protected final EitherOrNode interceptCreateEitherNode(ITreeNode parentNode, boolean negated) {
List<? extends IFormFieldExtension<? extends AbstractFormField>> extensions = getAllExtensions();
ComposerFieldCreateEitherNodeChain chain = new ComposerFieldCreateEitherNodeChain(extensions);
return chain.execCreateEitherNode(parentNode, negated);
}
protected final void interceptResolveRootPathForTopLevelAttribute(IDataModelAttribute a, List<IDataModelEntity> lifeList) {
List<? extends IFormFieldExtension<? extends AbstractFormField>> extensions = getAllExtensions();
ComposerFieldResolveRootPathForTopLevelAttributeChain chain = new ComposerFieldResolveRootPathForTopLevelAttributeChain(extensions);
chain.execResolveRootPathForTopLevelAttribute(a, lifeList);
}
protected final EitherOrNode interceptCreateAdditionalOrNode(ITreeNode eitherOrNode, boolean negated) {
List<? extends IFormFieldExtension<? extends AbstractFormField>> extensions = getAllExtensions();
ComposerFieldCreateAdditionalOrNodeChain chain = new ComposerFieldCreateAdditionalOrNodeChain(extensions);
return chain.execCreateAdditionalOrNode(eitherOrNode, negated);
}
protected final EntityNode interceptCreateEntityNode(ITreeNode parentNode, IDataModelEntity e, boolean negated, List<? extends Object> values, List<String> texts) {
List<? extends IFormFieldExtension<? extends AbstractFormField>> extensions = getAllExtensions();
ComposerFieldCreateEntityNodeChain chain = new ComposerFieldCreateEntityNodeChain(extensions);
return chain.execCreateEntityNode(parentNode, e, negated, values, texts);
}
protected static class LocalComposerFieldExtension<OWNER extends AbstractComposerField> extends LocalFormFieldExtension<OWNER> implements IComposerFieldExtension<OWNER> {
public LocalComposerFieldExtension(OWNER owner) {
super(owner);
}
@Override
public EntityPath execResolveEntityPath(ComposerFieldResolveEntityPathChain chain, EntityNode node) {
return getOwner().execResolveEntityPath(node);
}
@Override
public void execResolveRootPathForTopLevelEntity(ComposerFieldResolveRootPathForTopLevelEntityChain chain, IDataModelEntity e, List<IDataModelEntity> lifeList) {
getOwner().execResolveRootPathForTopLevelEntity(e, lifeList);
}
@Override
public RootNode execCreateRootNode(ComposerFieldCreateRootNodeChain chain) {
return getOwner().execCreateRootNode();
}
@Override
public AttributePath execResolveAttributePath(ComposerFieldResolveAttributePathChain chain, AttributeNode node) {
return getOwner().execResolveAttributePath(node);
}
@Override
public AttributeNode execCreateAttributeNode(ComposerFieldCreateAttributeNodeChain chain, ITreeNode parentNode, IDataModelAttribute a, Integer aggregationType, IDataModelAttributeOp op, List<? extends Object> values, List<String> texts) {
return getOwner().execCreateAttributeNode(parentNode, a, aggregationType, op, values, texts);
}
@Override
public IDataModel execCreateDataModel(ComposerFieldCreateDataModelChain chain) {
return getOwner().execCreateDataModel();
}
@Override
public EitherOrNode execCreateEitherNode(ComposerFieldCreateEitherNodeChain chain, ITreeNode parentNode, boolean negated) {
return getOwner().execCreateEitherNode(parentNode, negated);
}
@Override
public void execResolveRootPathForTopLevelAttribute(ComposerFieldResolveRootPathForTopLevelAttributeChain chain, IDataModelAttribute a, List<IDataModelEntity> lifeList) {
getOwner().execResolveRootPathForTopLevelAttribute(a, lifeList);
}
@Override
public EitherOrNode execCreateAdditionalOrNode(ComposerFieldCreateAdditionalOrNodeChain chain, ITreeNode eitherOrNode, boolean negated) {
return getOwner().execCreateAdditionalOrNode(eitherOrNode, negated);
}
@Override
public EntityNode execCreateEntityNode(ComposerFieldCreateEntityNodeChain chain, ITreeNode parentNode, IDataModelEntity e, boolean negated, List<? extends Object> values, List<String> texts) {
return getOwner().execCreateEntityNode(parentNode, e, negated, values, texts);
}
}
@Override
protected IComposerFieldExtension<? extends AbstractComposerField> createLocalExtension() {
return new LocalComposerFieldExtension<AbstractComposerField>(this);
}
}