/**
* Copyright 2004-2016 Riccardo Solmi. All rights reserved.
* This file is part of the Whole Platform.
*
* The Whole Platform is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The Whole Platform is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the Whole Platform. If not, see <http://www.gnu.org/licenses/>.
*/
package org.whole.lang.ui.requests;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.RequestConstants;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.commands.CompoundCommand;
import org.eclipse.gef.commands.UnexecutableCommand;
import org.eclipse.gef.internal.GEFMessages;
import org.eclipse.gef.requests.GroupRequest;
import org.whole.lang.commons.factories.CommonsEntityAdapterFactory;
import org.whole.lang.commons.factories.CommonsEntityFactory;
import org.whole.lang.model.IEntity;
import org.whole.lang.reflect.EntityDescriptor;
import org.whole.lang.ui.actions.EnablerPredicateFactory;
import org.whole.lang.ui.commands.CompositeAddCommand;
import org.whole.lang.ui.commands.CompositeRemoveCommand;
import org.whole.lang.ui.commands.ReplaceChildCommand;
import org.whole.lang.ui.editparts.IEntityPart;
import org.whole.lang.util.EntityUtils;
import org.whole.lang.visitors.GenericTraversalFactory;
import org.whole.lang.visitors.IBinaryVisitor;
/**
* @author Riccardo Solmi, Enrico Persiani
*/
public class CommandFactory implements ICommandFactory {
private static class SingletonHolder {
private static final ICommandFactory instance = new CommandFactory();
}
public static ICommandFactory instance() {
return SingletonHolder.instance;
}
private Map<String, List<IPartRequestHandler>> handlersMap = new HashMap<String, List<IPartRequestHandler>>(128); // requestType -> list of RequestHandlers
protected final ICommandFactory removeFeature = new ICommandFactory() {
public Command create(PartRequest request) {
IEntity entity = request.getModelEntity();
if (!isSelectionRoot(request))
return null;
ReplaceChildCommand cmd = new ReplaceChildCommand();
cmd.setParent(request.getParentModelEntity());
cmd.setOldChild(entity);
cmd.setNewChild(CommonsEntityFactory.instance.createResolver());
return cmd;
}
};
protected final ICommandFactory removeIndexedFeature = new ICommandFactory() {
public Command create(PartRequest request) {
IEntity entity = request.getModelEntity();
if (!isSelectionRoot(request))
return null;
CompositeRemoveCommand cmd = new CompositeRemoveCommand();
cmd.setComposite(request.getParentModelEntity());
cmd.setChild(entity);
return cmd;
}
};
protected static IEntity createEmpty(IEntity parent, IEntity child) {
EntityDescriptor<?> ed = parent.wGetEntityDescriptor(child);
return CommonsEntityAdapterFactory.createResolver(ed);
}
protected static boolean isSelectionRoot(PartRequest request) {
EditPart parent = request.getPart().getParent();
while (parent != null) {
for (IEntityPart entityPart : request)
if (parent.equals(entityPart))
return false;
parent = parent.getParent();
}
return true;
}
/**
* @see org.whole.lang.e4.ui.actions.DeleteAction#createDeleteCommand(List)
*/
public static Command createDeleteCommand(List<?> objects) {
if (objects.isEmpty())
return null;
if (!(objects.get(0) instanceof EditPart))
return null;
GroupRequest deleteReq =
new GroupRequest(RequestConstants.REQ_DELETE);
deleteReq.setEditParts(objects);
CompoundCommand compoundCmd = new CompoundCommand(
GEFMessages.DeleteAction_ActionDeleteCommandName);
for (int i = 0; i < objects.size(); i++) {
EditPart object = (EditPart) objects.get(i);
Command cmd = object.getCommand(deleteReq);
if (cmd != null) compoundCmd.add(cmd);
}
return compoundCmd;
}
protected final ICommandFactory orphanFeature = new ICommandFactory() {
public Command create(PartRequest request) {
DnDOverCompositeRequest orderedRequest = (DnDOverCompositeRequest) request;
IEntityPart dnDChild = orderedRequest.iterator().next();
return removeFeature.create(new DeletePartRequest(PartRequest.DELETE, dnDChild));
}
};
protected final ICommandFactory orphanIndexedFeature = new ICommandFactory() {
public Command create(PartRequest request) {
DnDOverCompositeRequest orderedRequest = (DnDOverCompositeRequest) request;
IEntityPart dnDChild = orderedRequest.iterator().next();
return removeIndexedFeature.create(new DeletePartRequest(PartRequest.DELETE, dnDChild));
}
};
protected final ICommandFactory moveIndexedFeature = new ICommandFactory() {
public Command create(PartRequest request) {
Command remove = orphanIndexedFeature.create(request);
Command insert = insertIndexedFeature.create(request);
CompoundCommand compound = new CompoundCommand();
compound.add(remove);
compound.add(insert);
return compound.unwrap();
}
};
protected final ICommandFactory unexecutableFeature = new UnexecutableCommandFactory();
protected final ICommandFactory replaceFeature = new ReplaceChildCommandFactory(IFeatureTransformer.IDENTITY);
protected final ICommandFactory replaceClonedFeature = new ReplaceChildCommandFactory(CLONE());
protected final ICommandFactory replaceSharedFeature = new ReplaceChildCommandFactory(SHARE());
protected final ICommandFactory compoundReplaceFeature = new CompoundReplaceChildCommandFactory(IFeatureTransformer.IDENTITY);
protected final ICommandFactory compoundReplaceClonedFeature = new CompoundReplaceChildCommandFactory(CLONE());
protected final ICommandFactory compoundReplaceSharedFeature = new CompoundReplaceChildCommandFactory(SHARE());
protected final ICommandFactory insertIndexedFeature = new CompositeAddCommandFactory(IFeatureTransformer.IDENTITY);
protected final ICommandFactory insertClonedIndexedFeature = new CompositeAddCommandFactory(CLONE());
protected final ICommandFactory insertSharedIndexedFeature = new CompositeAddCommandFactory(SHARE());
protected synchronized void addOverSimpleConstraints(final Object[][] dndRules) {
EnablerPredicateFactory pf = getEnablerPredicateFactory();
List<IPartRequestHandler> cloneList = new ArrayList<IPartRequestHandler>(dndRules.length);
List<IPartRequestHandler> shareList = new ArrayList<IPartRequestHandler>(dndRules.length);
for (Object[] dndRule : dndRules) {
EntityDescriptor<?> dndED = (EntityDescriptor<?>) dndRule[0];
EntityDescriptor<?> targetED = (EntityDescriptor<?>) dndRule[1];
IFeatureTransformer featureTransformer = (IFeatureTransformer) dndRule[2];
boolean isExecutable = (Boolean) dndRule[3];
cloneList.add(new PartRequestHandler(pf.dndSingleOver(dndED, targetED),
isExecutable ? new ReplaceChildCommandFactory(CLONE(featureTransformer)) : unexecutableFeature));
shareList.add(new PartRequestHandler(pf.dndSingleOver(dndED, targetED),
isExecutable ? new ReplaceChildCommandFactory(SHARE(featureTransformer)) : unexecutableFeature));
}
addHandlers(PartRequest.CLONE_CHILD, cloneList);
addHandlers(PartRequest.SHARE_CHILD, shareList);
}
protected synchronized void addOverCompositeConstraints(final Object[][] dndRules) {
EnablerPredicateFactory pf = getEnablerPredicateFactory();
List<IPartRequestHandler> addList = new ArrayList<IPartRequestHandler>(dndRules.length*3);
List<IPartRequestHandler> cloneList = new ArrayList<IPartRequestHandler>(dndRules.length*3);
List<IPartRequestHandler> shareList = new ArrayList<IPartRequestHandler>(dndRules.length*3);
for (Object[] dndRule : dndRules) {
EntityDescriptor<?> dndED = (EntityDescriptor<?>) dndRule[0];
EntityDescriptor<?> targetED = (EntityDescriptor<?>) dndRule[1];
IFeatureTransformer featureTransformer = (IFeatureTransformer) dndRule[2];
boolean isExecutable = (Boolean) dndRule[3];
addList.add(new PartRequestHandler(pf.dndSingleOverResolverIn(dndED, targetED),
isExecutable ? new ReplaceChildCommandFactory(featureTransformer) : unexecutableFeature));
cloneList.add(new PartRequestHandler(pf.dndSingleOverResolverIn(dndED, targetED),
isExecutable ? new ReplaceChildCommandFactory(CLONE(featureTransformer)) : unexecutableFeature));
shareList.add(new PartRequestHandler(pf.dndSingleOverResolverIn(dndED, targetED),
isExecutable ? new ReplaceChildCommandFactory(SHARE(featureTransformer)) : unexecutableFeature));
addList.add(new PartRequestHandler(pf.dndOverResolverIn(dndED, targetED),
isExecutable ? new CompoundReplaceChildCommandFactory(featureTransformer) : unexecutableFeature));
cloneList.add(new PartRequestHandler(pf.dndOverResolverIn(dndED, targetED),
isExecutable ? new CompoundReplaceChildCommandFactory(CLONE(featureTransformer)) : unexecutableFeature));
shareList.add(new PartRequestHandler(pf.dndOverResolverIn(dndED, targetED),
isExecutable ? new CompoundReplaceChildCommandFactory(SHARE(featureTransformer)) : unexecutableFeature));
addList.add(new PartRequestHandler(pf.dndOver(dndED, targetED),
isExecutable ? new CompositeAddCommandFactory(featureTransformer) : unexecutableFeature));
cloneList.add(new PartRequestHandler(pf.dndOver(dndED, targetED),
isExecutable ? new CompositeAddCommandFactory(CLONE(featureTransformer)) : unexecutableFeature));
shareList.add(new PartRequestHandler(pf.dndOver(dndED, targetED),
isExecutable ? new CompositeAddCommandFactory(SHARE(featureTransformer)) : unexecutableFeature));
}
addHandlers(PartRequest.MOVE_ADD_CHILD, addList);
addHandlers(PartRequest.CLONE_CHILD, cloneList);
addHandlers(PartRequest.SHARE_CHILD, shareList);
}
protected EnablerPredicateFactory getEnablerPredicateFactory() {
return EnablerPredicateFactory.instance;
}
protected IFeatureTransformer CLONE() {
return CLONE(IFeatureTransformer.IDENTITY);
}
protected IFeatureTransformer SHARE() {
return SHARE(IFeatureTransformer.IDENTITY);
}
protected IFeatureTransformer CLONE(final IFeatureTransformer innerFeatureTransformer) {
return new IFeatureTransformer() {
public IEntity transform(IEntity newFeature) {
return innerFeatureTransformer.transform(EntityUtils.clone(newFeature));
}
};
}
//FIXME implement share behavior
protected IFeatureTransformer SHARE(final IFeatureTransformer innerFeatureTransformer) {
return new IFeatureTransformer() {
public IEntity transform(IEntity newFeature) {
return innerFeatureTransformer.transform(EntityUtils.clone(newFeature));
}
};
}
protected synchronized void addHandlers(String requestType, List<IPartRequestHandler> handlers) {
List<IPartRequestHandler> handlerList = handlersMap.get(requestType);
if (handlerList == null)
handlersMap.put(requestType, handlers);
else
handlerList.addAll(handlers);
}
protected synchronized void addHandlers(String requestType, IPartRequestHandler[] handlers) {
List<IPartRequestHandler> handlerList = handlersMap.get(requestType);
if (handlerList == null) {
handlerList = new ArrayList<IPartRequestHandler>(handlers.length);
handlersMap.put(requestType, handlerList);
}
for (IPartRequestHandler handler : handlers)
handlerList.add(handler);
}
public Command create(PartRequest request) {
IPartRequestHandler handler;
// tries to handle operation with custom handlers
List<IPartRequestHandler> handlerList = handlersMap.get(request.getRequestType());
if (handlerList != null && !handlerList.isEmpty()) {
Iterator<IPartRequestHandler> handlerIterator = handlerList.iterator();
while (handlerIterator.hasNext()) {
handler = (IPartRequestHandler)handlerIterator.next();
if (handler.canHandlePartRequest(request))
return handler.handlePartRequest(request);
}
}
// handle basic requests
if (EntityUtils.isComposite(request.getModelEntity()) && request.getRequestType() == PartRequest.MOVE_CHILD)
return moveIndexedFeature.create(request);
if (request.getRequestType() == PartRequest.MOVE_ORPHAN_CHILD) {
if (EntityUtils.isComposite(request.getModelEntity()))
return orphanIndexedFeature.create(request);
else
return orphanFeature.create(request);
}
if (request.getRequestType() == PartRequest.DELETE) {
if (EntityUtils.isComposite(request.getParentModelEntity()))
return removeIndexedFeature.create(request);
else //was else if (EntityUtils.isSimple(request.getParentModelEntity()))
return removeFeature.create(request);
}
// handle composite and simple requests
if (isDnDRequest(request)) {
boolean isCompositeAddCommand, isReplaceCommand;
isCompositeAddCommand = isReplaceCommand = request.size()>0;
IEntity targetEntity = request.getModelEntity();
boolean isCloneRequest = request.getRequestType() == PartRequest.CLONE_CHILD;
HashSet<IEntity> targetEntityAncestors = new HashSet<IEntity>();
GenericTraversalFactory tf = GenericTraversalFactory.instance;
IBinaryVisitor ancestorsVisitor = tf.ancestors(tf.collect(tf.identity(), targetEntityAncestors));
ancestorsVisitor.visit(targetEntity);
for (IEntityPart dndPart : request) {
IEntity dndEntity = dndPart.getModelEntity();
if (targetEntityAncestors.contains(dndEntity) && !isCloneRequest)
return UnexecutableCommand.INSTANCE;
EntityDescriptor<?> dndEntityDescriptor = dndEntity.wGetEntityDescriptor();
isCompositeAddCommand &= EntityUtils.isAddable(targetEntity, dndEntityDescriptor) ||
EntityUtils.isComposite(targetEntity);
isReplaceCommand &= EntityUtils.isReplaceable(targetEntity, dndEntityDescriptor);
}
if (isCompositeAddCommand)
return createCompositeAddCommand(request);
else if (isReplaceCommand)
return createReplaceCommand(request);
else
return UnexecutableCommand.INSTANCE;
}
return null;
}
private boolean isDnDRequest(PartRequest request) {
return request.getRequestType() == PartRequest.MOVE_ADD_CHILD ||
request.getRequestType() == PartRequest.CLONE_CHILD ||
request.getRequestType() == PartRequest.SHARE_CHILD;
}
private Command createReplaceCommand(PartRequest request) {
if (request.getRequestType() == PartRequest.MOVE_ADD_CHILD)
return (request.size() == 1 ? replaceFeature : compoundReplaceFeature).create(request);
else if (request.getRequestType() == PartRequest.CLONE_CHILD)
return (request.size() == 1 ? replaceClonedFeature : compoundReplaceClonedFeature).create(request);
else if (request.getRequestType() == PartRequest.SHARE_CHILD)
return (request.size() == 1 ? replaceSharedFeature: compoundReplaceSharedFeature).create(request);
else
return null;
}
private Command createCompositeAddCommand(PartRequest request) {
if (request.getRequestType() == PartRequest.MOVE_ADD_CHILD)
return insertIndexedFeature.create(request);
else if (request.getRequestType() == PartRequest.CLONE_CHILD)
return insertClonedIndexedFeature.create(request);
else if (request.getRequestType() == PartRequest.SHARE_CHILD)
return insertSharedIndexedFeature.create(request);
else
return null;
}
public static class UnexecutableCommandFactory implements ICommandFactory {
public final Command create(PartRequest request) {
return UnexecutableCommand.INSTANCE;
}
};
public static class CompositeAddCommandFactory implements ICommandFactory {
private IFeatureTransformer featureTransformer;
public CompositeAddCommandFactory(IFeatureTransformer featureTransformer) {
this.featureTransformer = featureTransformer;
}
public final Command create(PartRequest request) {
DnDOverCompositeRequest overCompositeRequest = (DnDOverCompositeRequest)request;
CompositeAddCommand cmd = new CompositeAddCommand();
cmd.setComposite(overCompositeRequest.getModelEntity());
cmd.setNewChild(featureTransformer.transform(overCompositeRequest.getDnDChildEntity()));
if (overCompositeRequest.getCompositePrevChild() != null)
cmd.setPrevChild(overCompositeRequest.getCompositePrevChild().getModelEntity());
return cmd;
}
};
public static class ReplaceChildWithEmptyCommandFactory implements ICommandFactory {
public final Command create(PartRequest request) {
ReplaceChildCommand cmd = new ReplaceChildCommand();
cmd.setParent(request.getParentModelEntity());
cmd.setOldChild(request.getModelEntity());
if (request instanceof DnDOverPartRequest) {
DnDOverPartRequest overPartRequest = (DnDOverPartRequest)request;
cmd.setNewChild(createEmpty(request.getParentModelEntity(), ((IEntityPart)overPartRequest.iterator().next()).getModelEntity()));
} else
cmd.setNewChild(createEmpty(request.getParentModelEntity(), request.getModelEntity()));
return cmd;
}
};
public static class ReplaceChildCommandFactory implements ICommandFactory {
private IFeatureTransformer featureTransformer;
public ReplaceChildCommandFactory(IFeatureTransformer featureTransformer) {
this.featureTransformer = featureTransformer;
}
public final Command create(PartRequest request) {
ReplaceChildCommand cmd = new ReplaceChildCommand();
cmd.setParent(request.getParentModelEntity());
cmd.setOldChild(request.getModelEntity());
if (request instanceof DnDOverPartRequest) {
DnDOverPartRequest overPartRequest = (DnDOverPartRequest)request;
cmd.setNewChild(featureTransformer.transform(((IEntityPart)overPartRequest.iterator().next()).getModelEntity()));
} else {
DnDOverCompositeRequest overCompositeRequest = (DnDOverCompositeRequest)request;
cmd.setNewChild(featureTransformer.transform(((IEntityPart)overCompositeRequest.iterator().next()).getModelEntity()));
}
return cmd;
}
};
public static class CompoundReplaceChildCommandFactory implements ICommandFactory {
private IFeatureTransformer featureTransformer;
public CompoundReplaceChildCommandFactory(IFeatureTransformer featureTransformer) {
this.featureTransformer = featureTransformer;
}
public final Command create(PartRequest request) {
CompoundCommand compound = new CompoundCommand();
Iterator<IEntityPart> i = request.iterator();
while (i.hasNext()) {
IEntityPart part = (IEntityPart)i.next();
if (i.hasNext())
compound.add(new CompositeAddCommandFactory(featureTransformer).create(new DnDOverCompositeRequest(PartRequest.MOVE_ADD_CHILD,
(IEntityPart)request.getPart().getParent(),
part,
request.getPart())));
else {
List<IEntityPart> newList = new ArrayList<IEntityPart>(1);
newList.add(part);
compound.add(new ReplaceChildCommandFactory(featureTransformer).create(new DnDOverPartRequest(PartRequest.MOVE_ADD_CHILD,
request.getPart(), newList)));
}
}
return compound.unwrap();
}
};
}