/*******************************************************************************
* Copyright (c) 2007, 2014 compeople AG 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:
* compeople AG - initial API and implementation
*******************************************************************************/
package org.eclipse.riena.ui.core.uiprocess;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.core.runtime.jobs.ProgressProvider;
import org.eclipse.riena.core.exception.IExceptionHandlerManager;
import org.eclipse.riena.core.service.Service;
import org.eclipse.riena.internal.ui.core.Activator;
/**
* This class is used in conjunction with {@link UIProcess} and provides a {@link IProgressMonitor} that just synchronizes and delegates to another instance of
* {@link IProgressMonitor}. Serialization is done by a {@link IUISynchronizer}.
*
*/
public class UICallbackDispatcher extends ProgressProvider implements IUIMonitorContainer {
private final IUISynchronizer synchronizer;
private final List<IUIMonitor> uiMonitors;
private final ProcessInfo pInfo;
private JobChangeAdapter jobListener;
/**
* Creates a instance of {@link UICallbackDispatcher}.
*
* @param syncher
* - the {@link IUISynchronizer} for the widget toolkit
*/
public UICallbackDispatcher(final IUISynchronizer syncher) {
this.uiMonitors = Collections.synchronizedList(new ArrayList<IUIMonitor>());
this.synchronizer = syncher;
this.pInfo = new ProcessInfo();
}
public ProcessInfo getProcessInfo() {
return pInfo;
}
/**
* @see IUIMonitorContainer#addUIMonitor(IUIMonitor)
*/
public void addUIMonitor(final IUIMonitor uiMontitor) {
if (uiMonitors.contains(uiMontitor)) {
return;
}
final IProcessInfoAware processInfoAware = (IProcessInfoAware) uiMontitor.getAdapter(IProcessInfoAware.class);
if (processInfoAware != null) {
processInfoAware.setProcessInfo(pInfo);
}
this.uiMonitors.add(uiMontitor);
}
/**
* @return the synchronizer that serializes to the UI-Thread
*/
protected final IUISynchronizer getSyncher() {
return synchronizer;
}
@Override
public final IProgressMonitor createMonitor(final Job job) {
final IProgressMonitor progressMonitor = createThreadSwitcher();
observeJob(job);
return progressMonitor;
}
/**
* @since 5.0
*/
public IProgressMonitor createThreadSwitcher() {
if (null == getSyncher()) {
// no synchronizer available
return new NullProgressMonitor();
}
return new ThreadSwitcher(createWrappedMonitor());
}
private void observeJob(final Job job) {
if (jobListener == null) {
jobListener = new JobChangeAdapter() {
@Override
public void done(final IJobChangeEvent event) {
super.done(event);
jobDone(job);
job.removeJobChangeListener(this);
jobListener = null;
}
};
job.addJobChangeListener(jobListener);
}
}
private List<IUIMonitor> getMonitors() {
return new ArrayList<IUIMonitor>(uiMonitors);
}
/**
* Creates the wrapped {@link IProgressMonitor} which will by serialized to the UI-Thread.
*
* @return The wrapping monitor with a delegate inside
*/
protected IProgressMonitor createWrappedMonitor() {
/**
* Default implementation of a monitor just delegating to the uiProcess Methods. This monitor gets called on the ui-Thread as a delegate of the
* ThreadSwitcher
*/
return new NullProgressMonitor() {
@Override
public void beginTask(final String name, final int totalWork) {
pInfo.setMaxProgress(totalWork);
for (final IUIMonitor monitor : getMonitors()) {
monitor.initialUpdateUI(totalWork);
}
}
@Override
public void worked(final int work) {
for (final IUIMonitor monitor : getMonitors()) {
monitor.updateProgress(work);
}
}
@Override
public void done() {
}
};
}
private void jobDone(final Job job) {
synchronize(new Runnable() {
public void run() {
for (final IUIMonitor monitor : getMonitors()) {
try {
monitor.finalUpdateUI();
uiMonitors.remove(monitor);
} catch (final Exception e) {
Service.get(Activator.getDefault().getContext(), IExceptionHandlerManager.class).handleException(e);
}
}
}
});
}
/**
* This implementation of the ProgressMonitor delegates to another ProgressMonitor and serializes to the UI-Thread of the underlying ui technology.
*/
private final class ThreadSwitcher extends NullProgressMonitor {
private final IProgressMonitor delegate;
public ThreadSwitcher(final IProgressMonitor wrappedMonitor) {
this.delegate = wrappedMonitor;
}
@Override
public void beginTask(final String name, final int totalWork) {
synchronize(new Runnable() {
public void run() {
delegate.beginTask(name, totalWork);
}
});
}
@Override
public void worked(final int work) {
synchronize(new Runnable() {
public void run() {
delegate.worked(work);
}
});
}
@Override
public void done() {
}
}
private void synchronize(final Runnable runnable) {
// check if synchronizer available
if (null == synchronizer) {
return;
}
synchronizer.syncExec(runnable);
}
}