Bug 567578 - Fix Invalid Thread Access

Wrap execution into a runnable and execute it directly if possible to
not cause side effects to existing code (eg., tests).

Change-Id: I702722e290bc4b46636177653e67522369b1823a
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/packageview/PackageExplorerPart.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/packageview/PackageExplorerPart.java
index 6281a20..de86f00 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/packageview/PackageExplorerPart.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/packageview/PackageExplorerPart.java
@@ -109,6 +109,7 @@
 import org.eclipse.jdt.core.JavaCore;
 import org.eclipse.jdt.core.JavaModelException;
 
+import org.eclipse.jdt.internal.core.manipulation.MembersOrderPreferenceCacheCommon;
 import org.eclipse.jdt.internal.corext.util.Messages;
 
 import org.eclipse.jdt.ui.IPackagesViewPart;
@@ -125,8 +126,8 @@
 import org.eclipse.jdt.internal.ui.dnd.JdtViewerDropSupport;
 import org.eclipse.jdt.internal.ui.filters.OutputFolderFilter;
 import org.eclipse.jdt.internal.ui.javaeditor.EditorUtility;
-import org.eclipse.jdt.internal.ui.preferences.MembersOrderPreferenceCache;
 import org.eclipse.jdt.internal.ui.util.JavaUIHelp;
+import org.eclipse.jdt.internal.ui.util.SWTUtil;
 import org.eclipse.jdt.internal.ui.util.SelectionUtil;
 import org.eclipse.jdt.internal.ui.viewsupport.AppearanceAwareLabelProvider;
 import org.eclipse.jdt.internal.ui.viewsupport.BasicElementLabels;
@@ -1189,23 +1190,25 @@
 		if (fViewer == null)
 			return;
 
-		boolean refreshViewer= false;
+		SWTUtil.execDirectOrAsyncIfNecessary(fViewer::getControl, ()-> {
+			boolean refreshViewer= false;
 
-		if (PreferenceConstants.SHOW_CU_CHILDREN.equals(event.getProperty())) {
-			boolean showCUChildren= PreferenceConstants.getPreferenceStore().getBoolean(PreferenceConstants.SHOW_CU_CHILDREN);
-			((StandardJavaElementContentProvider)fViewer.getContentProvider()).setProvideMembers(showCUChildren);
+			if (PreferenceConstants.SHOW_CU_CHILDREN.equals(event.getProperty())) {
+				boolean showCUChildren= PreferenceConstants.getPreferenceStore().getBoolean(PreferenceConstants.SHOW_CU_CHILDREN);
+				((StandardJavaElementContentProvider)fViewer.getContentProvider()).setProvideMembers(showCUChildren);
 
-			refreshViewer= true;
-		} else if (MembersOrderPreferenceCache.isMemberOrderProperty(event.getProperty())) {
-			refreshViewer= true;
-		} else if (PreferenceConstants.APPEARANCE_SORT_LIBRARY_ENTRIES_BY_NAME.equals(event.getProperty())) {
-			// set new comparator, since it might evaluate this property on construction
-			setComparator();
-			refreshViewer = true;
-		}
+				refreshViewer= true;
+			} else if (MembersOrderPreferenceCacheCommon.isMemberOrderProperty(event.getProperty())) {
+				refreshViewer= true;
+			} else if (PreferenceConstants.APPEARANCE_SORT_LIBRARY_ENTRIES_BY_NAME.equals(event.getProperty())) {
+				// set new comparator, since it might evaluate this property on construction
+				setComparator();
+				refreshViewer = true; // is this really necessary? setComparator() calls refresh if the comparator changes
+			}
 
-		if (refreshViewer)
-			fViewer.refresh();
+			if (refreshViewer)
+				fViewer.refresh();
+		});
 	}
 
 	@Override
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/util/SWTUtil.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/util/SWTUtil.java
index c1889f9..b1c76e2 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/util/SWTUtil.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/util/SWTUtil.java
@@ -13,6 +13,8 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.ui.util;
 
+import java.util.function.Supplier;
+
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.accessibility.ACC;
 import org.eclipse.swt.accessibility.AccessibleAdapter;
@@ -25,6 +27,7 @@
 import org.eclipse.swt.widgets.Caret;
 import org.eclipse.swt.widgets.Combo;
 import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
 import org.eclipse.swt.widgets.Menu;
 import org.eclipse.swt.widgets.ScrollBar;
 import org.eclipse.swt.widgets.Shell;
@@ -38,6 +41,8 @@
 import org.eclipse.jface.layout.PixelConverter;
 import org.eclipse.jface.resource.JFaceResources;
 
+import org.eclipse.ui.PlatformUI;
+
 
 /**
  * Utility class to simplify access to some SWT resources.
@@ -168,6 +173,32 @@
 		textField.setBackground(textField.getDisplay().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND));
 	}
 
+	/**
+	 * Executes a given runnable directly if this thread is the UI thread or submits the runnable
+	 * to {@link Display#asyncExec(Runnable)} of the provided control otherwise.
+	 * <p>
+	 * The control will be checked for {@link Control#isDisposed()} before executing the runnable.
+	 *
+	 * @param supplier supplier for a {@link Control} to use
+	 * @param r the runnable
+	 */
+	public static void execDirectOrAsyncIfNecessary(Supplier<Control> supplier, Runnable r) {
+		if(Display.getCurrent() != null) {
+			Control ctrl = supplier.get();
+			if (ctrl != null && !ctrl.isDisposed()) {
+				r.run();
+			}
+		} else {
+			PlatformUI.getWorkbench().getDisplay().asyncExec(() -> {
+				Control ctrl = supplier.get();
+				if (ctrl != null && !ctrl.isDisposed()) {
+					r.run();
+				}
+			});
+		}
+
+	}
+
 	private SWTUtil() {
 	}