/* * <copyright> * * Copyright (c) 2014, IETR/INSA of Rennes * 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: * SAP AG - initial API, implementation and documentation * * </copyright> * */ package net.sf.orcc.xdf.ui.features; import java.util.Collection; import java.util.Collections; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.emf.transaction.RecordingCommand; import org.eclipse.emf.transaction.TransactionalEditingDomain; import org.eclipse.emf.transaction.util.TransactionUtil; import org.eclipse.graphiti.features.IFeatureProvider; import org.eclipse.graphiti.features.context.IContext; import org.eclipse.graphiti.features.context.ICustomContext; import org.eclipse.graphiti.features.custom.AbstractCustomFeature; /** * <p> * This class should be used if for some reason a CustomFeature can be long to * execute. It runs {@link #execute(ICustomContext, IProgressMonitor)} in a * Command on top of current TransactionalEditingDomain. This command itself is * run in a Job, and can use the associated IProgressMonitor * </p> * <p> * This is useful to indicate to user that the job is running, but eclipse is * not crashing * </p> * * @author Antoine Lorence * */ public abstract class AbstractTimeConsumingCustomFeature extends AbstractCustomFeature { public AbstractTimeConsumingCustomFeature(IFeatureProvider fp) { super(fp); } /** * Concrete code to execute. Sub-classes should use correctly given monitor: * create tasks (and eventually sub-tasks), notify for worked and done tasks * and check if user cancelled the task. * * @param context * The CustomFeature context * @param monitor * The monitor used to manage progress bar and Job cancellation * @return The execution status */ protected abstract void execute(ICustomContext context, IProgressMonitor monitor); /** * Callback executed just before job scheduling, in the Feature execution * Thread. Default implementation is empty. */ protected void beforeJobExecution() { } /** * Callback launched immediately after job execution in the Job Thread. * Default implementation is empty. */ protected void afterJobExecution() { } /** * Initialize the Job. * * @param context * The CustomContext that will be given to * {@link #execute(ICustomContext, IProgressMonitor)}. * @return The Job instance */ protected Job initializeJob(final ICustomContext context) { return new Job(getName()) { @Override protected IStatus run(final IProgressMonitor monitor) { final TransactionalEditingDomain editDomain = TransactionUtil .getEditingDomain(getDiagram()); final RecordingCommand command = new RecordingCommand( editDomain, getName()) { private IStatus result = null; @Override protected void doExecute() { try { AbstractTimeConsumingCustomFeature.this.execute( context, monitor); result = Status.OK_STATUS; } catch (OperationCanceledException e) { result = Status.CANCEL_STATUS; } } @Override public Collection<?> getResult() { return result == null ? Collections.EMPTY_LIST : Collections.singletonList(result); } }; // Execute (synchrnously) the defined command in a proper EMF // transaction editDomain.getCommandStack().execute(command); // Update the diagram dirtiness state getDiagramBehavior().getDiagramContainer().updateDirtyState(); // Callback afterJobExecution(); return (IStatus) command.getResult().iterator().next(); } }; } /** * Initialize parameters of the given Job * * @param job * The Job instance to configure */ protected void configureJob(Job job) { job.setUser(true); job.setPriority(Job.LONG); } // Prevent sub-classes from overriding this method @Override final public void execute(IContext context) { super.execute(context); } // Prevent sub-classes from overriding this method @Override final public void execute(ICustomContext context) { final Job job = initializeJob(context); configureJob(job); // Callback beforeJobExecution(); // Job is run job.schedule(); } // Prevent sub-classes from overriding this method @Override final public boolean hasDoneChanges() { return false; } }