/*******************************************************************************
* Copyright (c) 2015, 2015 IBM Corporation and others.
* 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:
* Bruno Medeiros - initial API and implementation
*******************************************************************************/
package melnorme.lang.ide.ui.utils.operations;
import static melnorme.utilbox.core.Assert.AssertNamespace.assertFail;
import static melnorme.utilbox.core.Assert.AssertNamespace.assertNotNull;
import static melnorme.utilbox.core.Assert.AssertNamespace.assertTrue;
import java.lang.reflect.InvocationTargetException;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.progress.IProgressService;
import melnorme.lang.ide.core.LangCoreMessages;
import melnorme.lang.ide.core.utils.EclipseUtils;
import melnorme.lang.tooling.common.ops.Operation;
import melnorme.lang.tooling.common.ops.IOperationMonitor;
import melnorme.lang.tooling.common.ops.ResultOperation;
import melnorme.utilbox.concurrency.OperationCancellation;
import melnorme.utilbox.core.CommonException;
public class WorkbenchOperationExecutor {
protected final boolean allowBackgroundAlready;
protected final boolean executeInUIOnly;
public WorkbenchOperationExecutor() {
this(false);
}
public WorkbenchOperationExecutor(boolean executeInUIOnly) {
super();
this.executeInUIOnly = executeInUIOnly;
this.allowBackgroundAlready = !executeInUIOnly;
}
protected final void runRunnableWithProgress(IRunnableWithProgress progressRunnable)
throws InvocationTargetException, InterruptedException {
if(allowBackgroundAlready && Display.getCurrent() == null) {
assertTrue(executeInUIOnly == false);
// Perform computation directly in this thread, but cancellation won't be possible.
progressRunnable.run(new NullProgressMonitor());
} else {
assertTrue(Display.getCurrent() != null);
doRunRunnableWithProgress(progressRunnable);
}
}
protected void doRunRunnableWithProgress(IRunnableWithProgress progressRunnable)
throws InvocationTargetException, InterruptedException {
IProgressService progressService = PlatformUI.getWorkbench().getProgressService();
progressService.run(!executeInUIOnly, true, progressRunnable);
}
public void execute(Operation coreOperation) throws CommonException, OperationCancellation {
try {
IRunnableWithProgress runnableWithProgress = new IRunnableWithProgress() {
@Override
public void run(IProgressMonitor monitor) throws InvocationTargetException {
try {
coreOperation.execute(EclipseUtils.om(monitor));
} catch(CommonException | OperationCancellation e) {
// wrap exception
throw new InvocationTargetException(e);
}
}
};
runRunnableWithProgress(runnableWithProgress);
} catch (InvocationTargetException ite) {
try {
throw ite.getCause();
} catch(CommonException | OperationCancellation original) {
throw original; // rethrow as original exception
} catch(Throwable e) {
// This should not happen either, unless doRun threw a RuntimeException
throw new CommonException(LangCoreMessages.LangCore_internalError, e);
}
} catch (InterruptedException e) {
// This should not happen
throw new CommonException(LangCoreMessages.LangCore_internalError, e);
}
}
public <R> R callInBackground(Function<IOperationMonitor, R> op) {
AtomicReference<R> resultHolder = new AtomicReference<>();
Operation opWrapper = new Operation() {
@Override
public void execute(IOperationMonitor om) {
R result = op.apply(om);
resultHolder.set(result);
}
};
try {
execute(opWrapper);
} catch(CommonException | OperationCancellation e) {
throw assertFail();
}
return resultHolder.get();
}
public <R> R invokeInBackground(ResultOperation<R> op) throws CommonException, OperationCancellation {
AtomicReference<R> resultHolder = new AtomicReference<>();
execute(new Operation() {
@Override
public void execute(IOperationMonitor om) throws CommonException, OperationCancellation {
R result = op.callOp(om);
resultHolder.set(result);
}
});
return resultHolder.get();
}
/* ----------------- ----------------- */
public static class ProgressMonitorDialogOpRunner extends WorkbenchOperationExecutor {
protected final ProgressMonitorDialog progressMonitorDialog;
public ProgressMonitorDialogOpRunner(Shell shell) {
super();
progressMonitorDialog = assertNotNull(new ProgressMonitorDialog(shell));
}
@Override
protected void doRunRunnableWithProgress(IRunnableWithProgress progressRunnable)
throws InvocationTargetException, InterruptedException {
progressMonitorDialog.run(!executeInUIOnly, true, progressRunnable);
}
}
}