/***************************************************************************** * Copyright (c) 2011 CEA LIST. * * * 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: * Vincent Lorenzo (CEA LIST) vincent.lorenzo@cea.fr - Initial API and implementation * *****************************************************************************/ package org.eclipse.papyrus.infra.table.common.listener; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.emf.common.command.Command; import org.eclipse.emf.common.command.CompoundCommand; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.facet.infra.query.ModelQuery; import org.eclipse.emf.facet.infra.query.core.AbstractModelQuery; import org.eclipse.emf.facet.infra.query.core.ModelQuerySetCatalog; import org.eclipse.emf.facet.infra.query.core.exception.ModelQueryException; import org.eclipse.emf.facet.infra.query.core.java.ParameterValueList; import org.eclipse.emf.facet.infra.query.runtime.ModelQueryResult; import org.eclipse.emf.facet.widgets.celleditors.ICommandFactoriesRegistry; import org.eclipse.emf.facet.widgets.celleditors.ICommandFactory; import org.eclipse.emf.facet.widgets.nattable.INatTableWidget; import org.eclipse.emf.facet.widgets.nattable.INatTableWidgetProvider; import org.eclipse.emf.facet.widgets.nattable.instance.tableinstance.TableinstancePackage; import org.eclipse.emf.facet.widgets.nattable.internal.NatTableWidget; import org.eclipse.emf.facet.widgets.nattable.internal.TableInstanceCommandFactory; import org.eclipse.emf.facet.widgets.nattable.tableconfiguration.TableConfiguration; import org.eclipse.emf.transaction.TransactionalEditingDomain; import org.eclipse.emf.transaction.TriggerListener; import org.eclipse.gmf.runtime.common.core.command.CommandResult; import org.eclipse.gmf.runtime.emf.commands.core.command.AbstractTransactionalCommand; import org.eclipse.papyrus.commands.wrappers.GMFtoEMFCommandWrapper; import org.eclipse.papyrus.infra.table.common.Activator; import org.eclipse.papyrus.infra.table.instance.papyrustableinstance.PapyrusTableInstance; /** * * This abstract class provides useful method for the TriggerListener used for the table synchronization * */ public abstract class AbstractSynchronizedTableTriggerListener extends TriggerListener { /** * The Papyrus table */ final protected PapyrusTableInstance table; /** * the nattable widget provider */ private INatTableWidgetProvider provider; /** * * Constructor. * * @param table * the table * @param provider * the nattable widget provider */ public AbstractSynchronizedTableTriggerListener(final PapyrusTableInstance table, final INatTableWidgetProvider provider) { this.table = table; this.provider = provider; } /** * * @param domain * the editing domain * @return * the command to do the synchronization */ protected CompoundCommand getSynchronizationCommand(final TransactionalEditingDomain domain) { CompoundCommand command = new CompoundCommand("Command to synchronize table with its context"); //$NON-NLS-1$ //the list of the elements to add in the table final List<EObject> elementsToAdd = new ArrayList<EObject>(); //the list of the element to remove in the table final List<EObject> elementToRemove = new ArrayList<EObject>(); //a new element has been added to the model for(ModelQuery query : this.table.getFillingQueries()) { ModelQuerySetCatalog catalog = ModelQuerySetCatalog.getSingleton(); AbstractModelQuery impl = null; try { impl = catalog.getModelQueryImpl(query); } catch (ModelQueryException e) { Activator.getDefault().log.error(e); } if(impl != null) { ModelQueryResult result = impl.evaluate(this.table.getTable().getContext()); Object value = result.getValue(); if(value instanceof Collection<?>) { //the build the list of the elements to add in the table for(Object currentObject : (Collection<?>)value) { if(currentObject instanceof EObject && !this.table.getTable().getElements().contains(currentObject)) { elementsToAdd.add((EObject)currentObject); } } /* * we build the list of the elements to remove from the table */ for(EObject currentObject : this.table.getTable().getElements()) { if(!((Collection<?>)value).contains(currentObject)) { elementToRemove.add(currentObject); } } } else { //nothing to do for the moment } } } if(!elementsToAdd.isEmpty()) { final List<EObject> forbiddenElements = getForbiddenElement(elementsToAdd); /* * The following line is commented because it doesn't work correctly : The same new object is added many times! */ //command.append(TableInstanceCommandFactory.createAddRowsCommand(elementsToAdd, (NatTableWidget)this.provider.getNatTableWidget())); elementsToAdd.removeAll(forbiddenElements); command.append(getAddElementCommand(domain, elementsToAdd, this.provider.getNatTableWidget())); //we don't display a message because we will get it each time the synchronized table is refreshed //we display a message // if(!forbiddenElements.isEmpty()) { // command.append(new GMFtoEMFCommandWrapper(new AbstractTransactionalCommand(domain, "Display Notification", null) { // // @Override // protected CommandResult doExecuteWithResult(IProgressMonitor monitor, IAdaptable info) throws ExecutionException { // String list = ""; // //TODO, maybe the label provider can manage a list? // ILabelProvider labelProvider = new UMLLabelProvider(); // Iterator<EObject> iter = forbiddenElements.iterator(); // while(iter.hasNext()) { // list += labelProvider.getText(iter.next()); // if(iter.hasNext()) { // list += ", "; // } // } // //new NotificationBuilder().setBuilderClass(CombinedPopupAndViewBuilder.class).setType(Type.WARNING).setTitle("Synchronized Table Message").setMessage("The following elements should be put in the table by the <<FillingQueries>>, but the query <<CanBePresentedInTheTable>> refuses them. " + "\n" + list).run(); // return CommandResult.newOKCommandResult(); // } // })); // } } if(!elementToRemove.isEmpty()) { command.append(getRemoveElementCommand(domain, elementToRemove, this.provider.getNatTableWidget())); } if(!command.isEmpty()) { return command; } return null; } /** * * @param domain * the domain to do the command * @param elementsToAdd * the elements to add in the table * @param widget * the widget * @return * the command to add the elements in the table */ protected Command getAddElementCommand(final TransactionalEditingDomain domain, final List<EObject> elementsToAdd, final INatTableWidget widget) { return new GMFtoEMFCommandWrapper(new AbstractTransactionalCommand(domain, null, null) { @Override protected CommandResult doExecuteWithResult(IProgressMonitor monitor, IAdaptable info) throws ExecutionException { widget.addRows(elementsToAdd); for(EObject current : elementsToAdd) { if(!widget.getTableInstance().getElements().contains(current)) {//we re-test during the execution, to avoid the same element will be added many times widget.addRows(Collections.singletonList(current)); } } // List<EObject> toAdd = new ArrayList<EObject>(); // toAdd.add(current); // Command command = TableInstanceCommandFactory.createAddRowsCommand(toAdd, (NatTableWidget)widget); // if(command != null) { // command.execute(); // } // } // } //I change the implementation of this command, because, when we create a new element in the model explorer, the facet column are not created // for(EObject current : elementsToAdd) { // if(!widget.getTableInstance().getElements().contains(current)) {//we re-test during the execution, to avoid the same element will be added many times // // List<EObject> toAdd = new ArrayList<EObject>(); // toAdd.add(current); // Command command = TableInstanceCommandFactory.createAddRowsCommand(toAdd, (NatTableWidget)widget); // if(command != null) { // command.execute(); // } // } // } return null; } }); } /** * * @param domain * the domain for the command * @param elementsToRemove * the element to remove * @param widget * the widget * @return */ protected Command getRemoveElementCommand(final TransactionalEditingDomain domain, final List<EObject> elementsToRemove, final INatTableWidget widget) { return new GMFtoEMFCommandWrapper(new AbstractTransactionalCommand(domain, null, null) { @Override protected CommandResult doExecuteWithResult(IProgressMonitor monitor, IAdaptable info) throws ExecutionException { for(EObject current : elementsToRemove) { if(widget.getTableInstance().getElements().contains(current)) {//we re-test to avoid to remove the same element many times List<EObject> toRemove = new ArrayList<EObject>(); toRemove.add(current); Command command = createRemoveRowsCommand(domain, toRemove, widget); if(command != null) { command.execute(); } } } return null; } }); } /** * TODO : this method should be provided by the TableInstanceCommandFactory * * @param domain * the domain * @param toRemove * the list of the elements to remove * @param widget * the widget * @return * the command to remove the elements */ private Command createRemoveRowsCommand(final TransactionalEditingDomain domain, final List<EObject> toRemove, final INatTableWidget widget) { ICommandFactory commandFactory = ICommandFactoriesRegistry.INSTANCE.getCommandFactoryFor(domain); CompoundCommand compoundCommand = new CompoundCommand(); for(int i = 0; i < widget.getTableInstance().getRows().size(); i++) { if(toRemove.contains(widget.getTableInstance().getRows().get(i).getElement())) { Command removeRowCommand = commandFactory.createRemoveCommand(domain, widget.getTableInstance(), TableinstancePackage.eINSTANCE.getTableInstance_Rows(), widget.getTableInstance().getRows().get(i)); compoundCommand.append(removeRowCommand); } } if(!compoundCommand.isEmpty()) { return compoundCommand; } return null; } /** * This method allows to filter the elements to add which are forbidden in the table, using the query canBePresentedInTheTable * * @param elementsToAdd * the list of the elements to add in the table * @return * the list of the elements to add which are forbidden in the table */ private List<EObject> getForbiddenElement(final List<EObject> elementsToAdd) { List<EObject> forbiddenElements = new ArrayList<EObject>(); //we need to test that each element to add can be put in the table. So we use the query CanBePresentedInTheTable TableConfiguration tableConfiguration = this.table.getTable().getTableConfiguration(); if(tableConfiguration != null) { ModelQuery query = tableConfiguration.getCanBePresentedInTheTable(); if(query != null) { AbstractModelQuery queryImpl = null; try { queryImpl = ModelQuerySetCatalog.getSingleton().getModelQueryImpl(query); } catch (ModelQueryException e) { Activator.getDefault().log.error(e); } for(EObject current : elementsToAdd) { boolean matched = (query.getScope().size() == 0); Iterator<EClass> queryScopes = query.getScope().iterator(); while(queryScopes.hasNext() && !matched) { EClass eClass = queryScopes.next(); if(eClass.isInstance(current)) { matched = true; } } if(!matched) { forbiddenElements.add(current); } else { ModelQueryResult result = queryImpl.evaluate(current, new ParameterValueList()); if(!result.getValue().equals(Boolean.TRUE)) { forbiddenElements.add(current); } } } } } return forbiddenElements; } }