/*
* JBoss, Home of Professional Open Source.
*
* See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing.
*
* See the AUTHORS.txt file distributed with this work for a full listing of individual contributors.
*/
package org.teiid.designer.diagram.ui.custom;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.teiid.designer.core.ModelerCore;
import org.teiid.designer.core.notification.util.NotificationUtilities;
import org.teiid.designer.core.transaction.SourcedNotification;
import org.teiid.designer.core.workspace.ModelResource;
import org.teiid.designer.diagram.ui.DiagramUiConstants;
import org.teiid.designer.diagram.ui.PluginConstants;
import org.teiid.designer.diagram.ui.connection.NodeConnectionModel;
import org.teiid.designer.diagram.ui.editor.DiagramEditorUtil;
import org.teiid.designer.diagram.ui.model.DiagramModelNode;
import org.teiid.designer.diagram.ui.model.LabelModelNode;
import org.teiid.designer.diagram.ui.notation.uml.model.UmlClassifierNode;
import org.teiid.designer.diagram.ui.pakkage.PackageDiagramModelFactory;
import org.teiid.designer.diagram.ui.util.DiagramUiUtilities;
import org.teiid.designer.metamodels.diagram.AbstractDiagramEntity;
import org.teiid.designer.metamodels.diagram.Diagram;
import org.teiid.designer.metamodels.diagram.DiagramLink;
import org.teiid.designer.ui.viewsupport.ModelObjectUtilities;
import org.teiid.designer.ui.viewsupport.ModelUtilities;
/**
* PackageDiagramModelFactory
*
* @since 8.0
*/
public class CustomDiagramModelFactory extends PackageDiagramModelFactory {
private static final String KEY_CUSTOM_DIAGRAM_NAME = "DiagramNames.customDiagram"; //$NON-NLS-1$
private static final String THIS_CLASS = "CustomDiagramModelFactory"; //$NON-NLS-1$
private String errorMessage;
/**
*
*/
public CustomDiagramModelFactory() {
}
/**
* Create a DiagramModelNode.
*/
@Override
public DiagramModelNode createModel( Object baseObject,
String sNotationId,
IProgressMonitor monitor ) {
// Return null if the baseObject is not a org.teiid.designer.metamodels.diagram.Diagram
if (!(baseObject instanceof Diagram)) {
return null;
}
HashMap nodeMap = new HashMap();
setSNotationId(sNotationId);
Diagram diagram = (Diagram)baseObject;
DiagramModelNode diagramModelNode = null;
List contents = null;
// Create base diagram node.
diagramModelNode = new CustomDiagramNode(diagram, Util.getString(KEY_CUSTOM_DIAGRAM_NAME));
// go get the contents based on the diagram only. DiagramEntity's hold the reference to their objects
// and nothing else.
contents = getDiagramContents(diagram);
if (!contents.isEmpty()) {
Iterator iter = contents.iterator();
if (getGenerator() != null) {
while (iter.hasNext()) {
// Get current EObject
errorMessage = null;
EObject eObj = (EObject)iter.next();
// Get a DiagramEntity
DiagramModelNode childModelNode = getGenerator().createModel(eObj, diagram);
if (childModelNode != null) {
nodeMap.put(eObj, childModelNode);
childModelNode.setParent(diagramModelNode);
diagramModelNode.addChild(childModelNode);
diagramModelNode.update(DiagramUiConstants.DiagramNodeProperties.CHILDREN);
diagramModelNode.update(DiagramUiConstants.DiagramNodeProperties.LAYOUT);
} else {
String name = DiagramUiUtilities.getEObjectLabel(eObj);
errorMessage = Util.getString(Errors.MODEL_NODE_FAILURE) + " for object = " + name; //$NON-NLS-1$
Util.log(IStatus.WARNING, errorMessage);
}
}
} else {
Util.log(IStatus.WARNING, Util.getString(Errors.MODEL_GENERATOR_FAILURE));
}
if (!diagramModelNode.getChildren().isEmpty()) {
// ----------------
// Let's create a map containing binary associations keyed to the EObject reference
HashMap connMap = new HashMap();
// Let's get contents, and get associations for each object
List realAssociations = new ArrayList();
List currentChildren = diagramModelNode.getChildren();
iter = currentChildren.iterator();
while (iter.hasNext()) {
DiagramModelNode childModelNode = (DiagramModelNode)iter.next();
List childAssList = childModelNode.getAssociations(nodeMap);
NodeConnectionModel nextConnection = null;
NodeConnectionModel nextRealConnection = null;
Iterator innerIter = null;
Iterator subIter = childAssList.iterator();
while (subIter.hasNext()) {
boolean connExists = false;
nextConnection = (NodeConnectionModel)subIter.next();
// Check the map first if the reference object != null
if (nextConnection.getModelObject() != null) {
Object existingConn = connMap.get(nextConnection.getModelObject());
if (existingConn != null) connExists = true;
} else {
// no reference object, so we have to walk through all connections and check .equals()
innerIter = realAssociations.iterator();
while (innerIter.hasNext() && !connExists) {
nextRealConnection = (NodeConnectionModel)innerIter.next();
if (nextRealConnection != null && nextRealConnection.equals(nextConnection)) connExists = true;
}
}
// if the connection still doesn't exist, then add to list and to map.
if (!connExists) {
if (nextConnection.getModelObject() != null) {
connMap.put(nextConnection.getModelObject(), nextConnection);
}
realAssociations.add(nextConnection);
}
}
}
iter = realAssociations.iterator();
while (iter.hasNext()) {
NodeConnectionModel nextAssociation = (NodeConnectionModel)iter.next();
((DiagramModelNode)nextAssociation.getSourceNode()).addSourceConnection(nextAssociation);
((DiagramModelNode)nextAssociation.getTargetNode()).addTargetConnection(nextAssociation);
List labelNodes = nextAssociation.getLabelNodes();
if (labelNodes != null && !labelNodes.isEmpty()) {
Iterator labelIter = labelNodes.iterator();
LabelModelNode nextNode = null;
while (labelIter.hasNext()) {
nextNode = (LabelModelNode)labelIter.next();
diagramModelNode.addChild(nextNode);
}
}
}
}
}
return diagramModelNode;
}
/**
* @see org.teiid.designer.diagram.ui.model.DiagramModelFactoryImpl#currentDiagramRemoved(org.teiid.designer.metamodels.diagram.Diagram)
* @since 4.2
*/
@Override
protected boolean currentDiagramRemoved( Diagram theDiagram ) {
boolean isRemoved = false;
if (theDiagram == null) {
isRemoved = true;
} else if (theDiagram.eResource() == null) {
isRemoved = true;
// check the eContainer.
if ((theDiagram.eContainer() == null) && diagramIsTransient(theDiagram)) {
isRemoved = false;
}
}
return isRemoved;
}
private List getDiagramContents( Diagram customDiagram ) {
List contents = new ArrayList();
if (customDiagram != null) {
List diagramChildren = customDiagram.eContents();
if (diagramChildren != null && !diagramChildren.isEmpty()) {
AbstractDiagramEntity nextDE = null;
Iterator iter = diagramChildren.iterator();
while (iter.hasNext()) {
nextDE = (AbstractDiagramEntity)iter.next();
if (!(nextDE instanceof DiagramLink) && nextDE.getModelObject() != null) {
contents.add(nextDE.getModelObject());
}
}
} else contents = Collections.EMPTY_LIST;
}
return contents;
}
private boolean isValidDiagram( DiagramModelNode diagramModelNode ) {
boolean result = false;
Diagram diagram = (Diagram)diagramModelNode.getModelObject();
if (diagram != null && diagram.getTarget() != null) {
ModelResource mr = ModelUtilities.getModelResourceForModelObject(diagram);
if (mr != null) {
String type = diagram.getType();
if (type != null) {
if (type.equals(PluginConstants.CUSTOM_DIAGRAM_TYPE_ID)) result = true;
}
}
}
return result;
}
/* (non-Javadoc)
* @See org.teiid.designer.diagram.ui.model.DiagramModelFactory#notifyModel(org.eclipse.emf.common.notify.Notification)
*/
@Override
public boolean notifyModel( Notification notification,
DiagramModelNode diagramModelNode,
String sDiagramTypeId ) {
boolean currentDiagramOK = true;
Diagram diagram = (Diagram)diagramModelNode.getModelObject();
if (currentDiagramRemoved(diagram)) currentDiagramOK = false;
if (currentDiagramOK && isValidDiagram(diagramModelNode) && shouldHandleNotification(notification, diagramModelNode)) {
boolean requiredStart = false;
boolean succeeded = false;
boolean handleConstruction = !DiagramEditorUtil.isDiagramUnderConstruction(diagram);
try {
if (handleConstruction) {
DiagramEditorUtil.setDiagramUnderConstruction(diagram);
}
// -------------------------------------------------
// Let's wrap this in a transaction!!! that way all constructed objects and layout properties
// will result in only one transaction?
// -------------------------------------------------
requiredStart = ModelerCore.startTxn(false, false, "Update Custom Diagram", this); //$NON-NLS-1$$
CustomDiagramNotificationHelper helper = new CustomDiagramNotificationHelper(
notification,
(Diagram)diagramModelNode.getModelObject(),
this);
handleMoves(helper.getMovedEObjects(), diagramModelNode);
handleAdds(helper.getAddNotifications(), diagramModelNode);
handleRemoves(helper.getRemoveNotifications(), diagramModelNode);
handleChanges(helper.getChangedNotifications(), diagramModelNode);
add(new ArrayList(helper.getUndoAddedEObjects()), diagramModelNode);
succeeded = true;
} catch (Exception ex) {
DiagramUiConstants.Util.log(IStatus.ERROR, ex, ex.getClass().getName() + ":" + THIS_CLASS + ".notifyModel()"); //$NON-NLS-1$ //$NON-NLS-2$
} finally {
if (requiredStart) {
if (succeeded) {
ModelerCore.commitTxn();
} else {
ModelerCore.rollbackTxn();
}
if (handleConstruction) {
DiagramEditorUtil.setDiagramConstructionComplete(diagram, true);
}
}
}
}
return currentDiagramOK;
}
private boolean shouldHandleNotification( Notification notification,
DiagramModelNode diagramModelNode ) {
boolean shouldHandle = false;
Diagram currentDiagram = (Diagram)diagramModelNode.getModelObject();
ModelResource diagramMR = ModelUtilities.getModelResourceForModelObject(currentDiagram);
if (diagramMR != null) {
if (notification instanceof SourcedNotification) {
Object source = ((SourcedNotification)notification).getSource();
if (source == null || !source.equals(this)) {
Collection notifications = ((SourcedNotification)notification).getNotifications();
Iterator iter = notifications.iterator();
Notification nextNotification = null;
while (iter.hasNext() && !shouldHandle) {
nextNotification = (Notification)iter.next();
Object targetObject = ModelerCore.getModelEditor().getChangedObject(nextNotification);
if (targetObject != null && targetObject instanceof EObject) {
// Custom Diagrams don't care what model resources are... can have other model objects
// in other model custom diagrams.
shouldHandle = true;
}
}
}
} else { // SINGLE NOTIFICATION
Object targetObject = ModelerCore.getModelEditor().getChangedObject(notification);
if (targetObject != null && targetObject instanceof EObject) {
// Custom Diagrams don't care what model resources are... can have other model objects
// in other model custom diagrams.
shouldHandle = true;
}
}
}
return shouldHandle;
}
@Override
public Diagram getDiagram( EObject someTarget ) {
ModelResource modelResource = ModelUtilities.getModelResourceForModelObject(someTarget);
try {
List returnedDiagrams = modelResource.getModelDiagrams().getDiagrams(someTarget);
if (returnedDiagrams.size() == 1) {
return (Diagram)returnedDiagrams.get(0);
}
// Find the one for custom diagram
Iterator iter = returnedDiagrams.iterator();
while (iter.hasNext()) {
Diagram nextDiagram = (Diagram)iter.next();
if (nextDiagram.getType() != null && nextDiagram.getType().equals(PluginConstants.CUSTOM_DIAGRAM_TYPE_ID)) return nextDiagram;
}
} catch (CoreException e) {
e.printStackTrace();
}
return null;
}
public void add( EObject someTarget,
DiagramModelNode customDiagramModelNode,
boolean updateAssociations ) {
DiagramModelNode newNode = getGenerator().createModel(someTarget, (Diagram)customDiagramModelNode.getModelObject());
if (newNode != null) {
customDiagramModelNode.addChild(newNode);
if (updateAssociations) updateAssociations(customDiagramModelNode, customDiagramModelNode);
}
}
public void add( List targets,
DiagramModelNode customDiagramModelNode ) {
Iterator iter = targets.iterator();
EObject nextTarget = null;
List newChildren = new ArrayList(targets.size());
while (iter.hasNext()) {
nextTarget = (EObject)iter.next();
DiagramModelNode newNode = getGenerator().createModel(nextTarget, (Diagram)customDiagramModelNode.getModelObject());
if (newNode != null) {
newNode.setParent(customDiagramModelNode);
newChildren.add(newNode);
}
}
if (!newChildren.isEmpty()) {
customDiagramModelNode.addChildren(newChildren);
updateAssociations(customDiagramModelNode, customDiagramModelNode);
}
}
@Override
protected void updateAssociations( DiagramModelNode diagramModelNode,
DiagramModelNode diagramNode ) {
super.updateAssociations(diagramModelNode, diagramNode);
HashMap nodeMap = getNodeMap(diagramNode);
if (diagramModelNode instanceof CustomDiagramNode) {
// Need to get new list of associations that should exist between visible components.
// Let's get contents, and get associations for each object
NodeConnectionModel nextAssociation = null;
List realAssociations = new ArrayList();
List currentChildren = diagramModelNode.getChildren();
Iterator iter = currentChildren.iterator();
while (iter.hasNext()) {
DiagramModelNode childModelNode = (DiagramModelNode)iter.next();
if (childModelNode != null) {
List allAssociations = childModelNode.getAssociations(nodeMap);
if (allAssociations != null && !allAssociations.isEmpty()) {
Iterator subIter = allAssociations.iterator();
Object nextAss = null;
while (subIter.hasNext()) {
nextAss = subIter.next();
if (!realAssociations.contains(nextAss)) {
realAssociations.add(nextAss);
}
}
}
}
}
// Remove old associations.
List staleAssociations = getStaleAssociations(realAssociations, diagramModelNode);
List changedNodes = new ArrayList(cleanUpStaleAssociations(staleAssociations, diagramModelNode));
HashMap updatedNodes = new HashMap();
iter = changedNodes.iterator();
while (iter.hasNext()) {
updatedNodes.put(iter.next(), "x"); //$NON-NLS-1$
}
// Add new associations if they don't exist.
iter = realAssociations.iterator();
while (iter.hasNext()) {
nextAssociation = (NodeConnectionModel)iter.next();
if (!associationExists(diagramModelNode, nextAssociation)) {
((DiagramModelNode)nextAssociation.getSourceNode()).addSourceConnection(nextAssociation);
((DiagramModelNode)nextAssociation.getTargetNode()).addTargetConnection(nextAssociation);
// Keep a list of new end nodes so we can tell them to fire
// an updateAssociations() call...
if (updatedNodes.get(nextAssociation.getSourceNode()) == null) updatedNodes.put(nextAssociation.getSourceNode(),
"x"); //$NON-NLS-1$
if (updatedNodes.get(nextAssociation.getTargetNode()) == null) updatedNodes.put(nextAssociation.getTargetNode(),
"x"); //$NON-NLS-1$
List labelNodes = nextAssociation.getLabelNodes();
if (labelNodes != null && !labelNodes.isEmpty()) {
Iterator labelIter = labelNodes.iterator();
LabelModelNode nextNode = null;
while (labelIter.hasNext()) {
nextNode = (LabelModelNode)labelIter.next();
diagramModelNode.addChild(nextNode);
}
}
}
}
// call updateLabels in case info changes. (i.e names, labels, etc...)
iter = getCurrentAssociations(diagramModelNode).iterator();
while (iter.hasNext()) {
nextAssociation = (NodeConnectionModel)iter.next();
nextAssociation.updateLabels();
((DiagramModelNode)nextAssociation.getSourceNode()).updateAssociations();
((DiagramModelNode)nextAssociation.getTargetNode()).updateAssociations();
}
if (!updatedNodes.isEmpty()) {
iter = updatedNodes.keySet().iterator();
DiagramModelNode nextNode = null;
while (iter.hasNext()) {
nextNode = (DiagramModelNode)iter.next();
nextNode.updateAssociations();
}
}
}
}
public void remove( List targets,
DiagramModelNode customDiagramModelNode ) {
Iterator iter = targets.iterator();
EObject nextTarget = null;
// List staleDiagramEntities = new ArrayList(targets.size());
List oldChildren = new ArrayList(targets.size());
while (iter.hasNext()) {
nextTarget = (EObject)iter.next();
DiagramModelNode oldNode = getModelNode(customDiagramModelNode, nextTarget);
if (oldNode != null) {
// if( newNode.getDiagramModelObject() != null )
// staleDiagramEntities.add(newNode.getDiagramModelObject());
removeAllAssociationsFromNode(oldNode, customDiagramModelNode);
oldChildren.add(oldNode);
}
}
if (!oldChildren.isEmpty()) {
customDiagramModelNode.removeChildren(oldChildren, true);
}
}
public void clear( DiagramModelNode customDiagramModelNode ) {
List currentChildren = new ArrayList(customDiagramModelNode.getChildren());
if (!currentChildren.isEmpty()) {
Iterator iter = currentChildren.iterator();
DiagramModelNode nextNode = null;
// List staleDiagramEntities = new ArrayList(currentChildren.size());
while (iter.hasNext()) {
nextNode = (DiagramModelNode)iter.next();
if (nextNode != null) {
removeAllAssociationsFromNode(nextNode, customDiagramModelNode);
}
}
if (!currentChildren.isEmpty()) {
customDiagramModelNode.removeChildren(currentChildren, true);
}
}
}
private void performAdd( Notification notification,
DiagramModelNode customDiagramModelNode ) {
boolean performedChange = false;
if (NotificationUtilities.isEObjectNotifier(notification)) {
// we know that the object is not a child of a model resource !!!!!
Object target = ModelerCore.getModelEditor().getChangedObject(notification);
if (!(target instanceof EObject) || target instanceof Diagram || target instanceof AbstractDiagramEntity) return;
EObject targetObject = (EObject)target;
if (NotificationUtilities.addedChildrenParentIsNotifier(notification)) {
boolean isNested = false;
// Now we check to see if the target object is already in diagram
DiagramModelNode targetNode = getNodeInDiagram(customDiagramModelNode, targetObject);
// if still null, check if it's nested
if (targetNode == null) {
isNested = true;
targetNode = getModelNode(customDiagramModelNode, targetObject);
}
if (targetNode != null) {
// This case where the node is in package diagram and we need to delegate to the object node to add a child
// We have a match, get the added children and hand them off to the generator to construct
// and add to this the corresponding targetNode
EObject[] newChildren = NotificationUtilities.getAddedChildren(notification);
if (newChildren.length > 0) {
EObject childParent = newChildren[0].eContainer();
DiagramModelNode parentNode = getModelNode(customDiagramModelNode, childParent);
if (parentNode != null) {
if (parentNode instanceof UmlClassifierNode) {
((UmlClassifierNode)parentNode).reconcile();
} else {
for (int iChild = 0; iChild < newChildren.length; iChild++) {
DiagramModelNode newNode = getGenerator().createChildModel(parentNode, newChildren[iChild]);
if (newNode != null) performedChange = true;
}
}
}
if (performedChange) updateAssociations(parentNode, customDiagramModelNode);
}
}
if (isNested) {
EObject parentEObject = targetObject.eContainer();
DiagramModelNode parentNode = getModelNode(customDiagramModelNode, parentEObject);
if (parentNode != null) {
parentNode.updateForChild(false);
}
}
}
}
}
private void performRemove( Notification notification,
DiagramModelNode customDiagramModelNode ) {
if (NotificationUtilities.isEObjectNotifier(notification)) {
// we know that the object is not a child of a model resource !!!!!
Object target = ModelerCore.getModelEditor().getChangedObject(notification);
if (!(target instanceof EObject) || target instanceof Diagram || target instanceof AbstractDiagramEntity) return;
EObject targetObject = (EObject)target;
DiagramModelNode parentNode = getModelNode(customDiagramModelNode, targetObject);
DiagramModelNode removedNode = null;
EObject[] removedChildren = NotificationUtilities.getRemovedChildren(notification);
for (int iChild = 0; iChild < removedChildren.length; iChild++) {
removedNode = getModelNode(customDiagramModelNode, removedChildren[iChild]);
if (removedNode != null) {
if (parentNode != null) {
if (!(parentNode instanceof UmlClassifierNode)) {
parentNode.removeChild(removedNode, false);
}
updateAssociations(parentNode, customDiagramModelNode);
} else {
removeAllAssociationsFromNode(removedNode, customDiagramModelNode);
customDiagramModelNode.removeChild(removedNode, false);
}
}
}
if (parentNode != null && parentNode instanceof UmlClassifierNode) {
((UmlClassifierNode)parentNode).reconcile();
}
} else {
Object target = ModelerCore.getModelEditor().getChangedObject(notification);
if (target instanceof Resource) {
DiagramModelNode removedNode = null;
EObject[] removedChildren = NotificationUtilities.getRemovedChildren(notification);
for (int iChild = 0; iChild < removedChildren.length; iChild++) {
removedNode = getModelNode(customDiagramModelNode, removedChildren[iChild]);
if (removedNode != null) {
removeAllAssociationsFromNode(removedNode, customDiagramModelNode);
customDiagramModelNode.removeChild(removedNode, false);
}
}
}
}
}
@Override
protected void performChange( Notification notification,
DiagramModelNode customDiagramModelNode ) {
super.performChange(notification, customDiagramModelNode);
// We need to handle the case where the location/path of any object in diagram is updated when
// changed (i.e. rename Catagory/schema should update path for any classifier under that container)
EObject targetObject = NotificationUtilities.getEObject(notification);
if (targetObject != null) {
Collection diagramChildren = getDiagramContents((Diagram)customDiagramModelNode.getModelObject());
Iterator iter = diagramChildren.iterator();
EObject modelEObject = null;
Object nextObj = null;
while (iter.hasNext()) {
nextObj = iter.next();
if (nextObj instanceof EObject) {
modelEObject = (EObject)nextObj;
if (ModelObjectUtilities.isDescendant(targetObject, modelEObject)) {
DiagramModelNode targetNode = getModelNode(customDiagramModelNode, modelEObject);
if (targetNode != null) {
getGenerator().performUpdate(targetNode, null);
targetNode.update(DiagramUiConstants.DiagramNodeProperties.SIZE);
targetNode.update(DiagramUiConstants.DiagramNodeProperties.NAME);
}
}
}
}
}
}
private void handleMoves( Collection movedEObjects,
DiagramModelNode customDiagramModelNode ) {
if (movedEObjects != null && !movedEObjects.isEmpty()) {
DiagramModelNode targetNode = null;
EObject nextEObj = null;
Iterator iter = movedEObjects.iterator();
while (iter.hasNext()) {
nextEObj = (EObject)iter.next();
targetNode = getModelNode(customDiagramModelNode, nextEObj);
if (targetNode != null) {
getGenerator().performUpdate(targetNode, null);
}
}
}
}
private void handleRemoves( Collection removeNotifications,
DiagramModelNode customDiagramModelNode ) {
if (removeNotifications != null && !removeNotifications.isEmpty()) {
Notification nextNotification = null;
Iterator iter = removeNotifications.iterator();
while (iter.hasNext()) {
nextNotification = (Notification)iter.next();
performRemove(nextNotification, customDiagramModelNode);
}
}
}
private void handleAdds( Collection addNotifications,
DiagramModelNode customDiagramModelNode ) {
if (addNotifications != null && !addNotifications.isEmpty()) {
Notification nextNotification = null;
Iterator iter = addNotifications.iterator();
while (iter.hasNext()) {
nextNotification = (Notification)iter.next();
performAdd(nextNotification, customDiagramModelNode);
}
}
}
private void handleChanges( Collection changeNotifications,
DiagramModelNode customDiagramModelNode ) {
if (changeNotifications != null && !changeNotifications.isEmpty()) {
Notification nextNotification = null;
Iterator iter = changeNotifications.iterator();
while (iter.hasNext()) {
nextNotification = (Notification)iter.next();
performChange(nextNotification, customDiagramModelNode);
}
}
}
}