/****************************************************************************** * Copyright (c) 2006, 2009 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: * IBM Corporation - initial API and implementation ****************************************************************************/ package org.eclipse.gmf.runtime.diagram.ui; import java.lang.ref.WeakReference; import org.eclipse.emf.transaction.ResourceSetChangeEvent; import org.eclipse.emf.transaction.TransactionalEditingDomain; import org.eclipse.gmf.runtime.common.ui.util.DisplayUtils; import org.eclipse.gmf.runtime.diagram.core.listener.DiagramEventBroker; import org.eclipse.swt.widgets.Display; /** * This is an extension of the DiagramEventBroker that has special handling for notifications that * occurs from a worker thread / non-UI thread. If the notification occurs on the main thread * then execution is delegated to the super class immediately. If execution is not on the main thread * then there are 2 scenarios that have to be considered. * * The first scenario is for a long operation * that has been executed with a progress meter, where the progress meter is displaying UI on the main * thread and there is a background thread that is being executed that the progress meter is monitoring. * For this scenario, the UI updates on the diagram viewer have been disabled so as to avoid concurrency * issues. When notifications are handled, they are synchronized to the main thread to avoid * SWTExceptions when UI tries to access SWT resources when updating figures or other UI. * * The second scenario is for when a job has been executed on a worker thread, but has not been executed * through the OperationHistory. Consequently, there is no hook for turning off display updates. This * means that if the notifications were to continue on the worker thread, then the display could update * at the same time on the main thread thereby causing concurrent modification errors and other errors. * In this case, we need to resynchronize the notifications with the main thread. In order to do this * it is necessary to run the notifications in an synchronous runnable that will run immediately * on the main thread. * * @author sshaw * @since 1.2 */ public class DiagramEventBrokerThreadSafe extends DiagramEventBroker { WeakReference editingDomainRef; public DiagramEventBrokerThreadSafe(TransactionalEditingDomain editingDomain) { super(); editingDomainRef = new WeakReference(editingDomain); } /* (non-Javadoc) * @see org.eclipse.gmf.runtime.diagram.core.listener.DiagramEventBroker#resourceSetChanged(org.eclipse.emf.transaction.ResourceSetChangeEvent) */ public void resourceSetChanged(ResourceSetChangeEvent event) { if (shouldSynchronizeWithMainThread(event)) { // force synchronization with the main thread final ResourceSetChangeEvent eventToHandle = event; TransactionalEditingDomain editingDomain = (TransactionalEditingDomain)editingDomainRef.get(); if (editingDomain != null) { DisplayUtils.getDisplay().syncExec(editingDomain.createPrivilegedRunnable(new Runnable() { public void run() { internal_resourceSetChanged(eventToHandle); } })); return; } } super.resourceSetChanged(event); } private boolean shouldSynchronizeWithMainThread(ResourceSetChangeEvent event) { if (Display.getCurrent() == null) return true; return false; } private void internal_resourceSetChanged(ResourceSetChangeEvent event) { super.resourceSetChanged(event); } }