Bug 572553: [Script Shell] Disable updating variables dropin when hidden

  seems to improve the situation a bit. Still when executing commands
  after 'result = list(range(10000))' takes much longer than expected.

Change-Id: Ia32bb45193da757c3c5f35aecb5baf6d904e424e
diff --git a/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/views/shell/dropins/variables/VariablesContentProvider.java b/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/views/shell/dropins/variables/VariablesContentProvider.java
index eab4f02..a94bdd1 100644
--- a/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/views/shell/dropins/variables/VariablesContentProvider.java
+++ b/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/views/shell/dropins/variables/VariablesContentProvider.java
@@ -14,28 +14,13 @@
 import java.util.Collection;
 import java.util.HashSet;
 
-import org.eclipse.debug.core.model.IBreakpoint;
 import org.eclipse.ease.IReplEngine;
-import org.eclipse.ease.Script;
-import org.eclipse.ease.debugging.model.EaseDebugTarget;
 import org.eclipse.ease.debugging.model.EaseDebugVariable;
 import org.eclipse.jface.viewers.ITreeContentProvider;
 import org.eclipse.jface.viewers.Viewer;
 
 public class VariablesContentProvider implements ITreeContentProvider {
 
-	private static final EaseDebugTarget DUMMY_DEBUG_TARGET = new EaseDebugTarget(null, false, false, false) {
-		@Override
-		protected IBreakpoint[] getBreakpoints(Script script) {
-			return new IBreakpoint[0];
-		}
-
-		@Override
-		public boolean supportsBreakpoint(IBreakpoint breakpoint) {
-			return false;
-		}
-	};
-
 	@Override
 	public void inputChanged(final Viewer viewer, final Object oldInput, final Object newInput) {
 		// older eclipse versions do not have a default implementation
@@ -66,11 +51,7 @@
 			variables.addAll(((IReplEngine) inputElement).getDefinedVariables());
 
 			// add last execution result
-			final EaseDebugVariable lastScriptResult = ((IReplEngine) inputElement).getLastExecutionResult();
-			variables.add(lastScriptResult);
-
-			for (final EaseDebugVariable entry : variables)
-				entry.setParent(DUMMY_DEBUG_TARGET);
+			variables.add(((IReplEngine) inputElement).getLastExecutionResult());
 		}
 
 		return variables.toArray();
diff --git a/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/views/shell/dropins/variables/VariablesDropin.java b/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/views/shell/dropins/variables/VariablesDropin.java
index ffa1cbc..064c69d 100644
--- a/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/views/shell/dropins/variables/VariablesDropin.java
+++ b/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/views/shell/dropins/variables/VariablesDropin.java
@@ -12,6 +12,8 @@
  *******************************************************************************/
 package org.eclipse.ease.ui.views.shell.dropins.variables;
 
+import java.time.Duration;
+
 import org.eclipse.ease.IExecutionListener;
 import org.eclipse.ease.IReplEngine;
 import org.eclipse.ease.IScriptEngine;
@@ -21,6 +23,7 @@
 import org.eclipse.ease.ui.views.shell.dropins.IShellDropin;
 import org.eclipse.jface.layout.TreeColumnLayout;
 import org.eclipse.jface.util.LocalSelectionTransfer;
+import org.eclipse.jface.util.Throttler;
 import org.eclipse.jface.viewers.ColumnWeightData;
 import org.eclipse.jface.viewers.TreeViewer;
 import org.eclipse.jface.viewers.TreeViewerColumn;
@@ -39,6 +42,9 @@
 
 	private TreeViewer fVariablesTree = null;
 	private IReplEngine fEngine;
+	private boolean fIsActive = true;
+
+	private final Throttler fUiUpdater = new Throttler(Display.getDefault(), Duration.ofMillis(500), this::update);
 
 	@Override
 	public void setScriptEngine(IReplEngine engine) {
@@ -53,7 +59,7 @@
 		// set tree input
 		if (fVariablesTree != null) {
 			fVariablesTree.setInput(engine);
-			Display.getDefault().asyncExec(() -> fVariablesTree.refresh());
+			fUiUpdater.throttledExec();
 		}
 	}
 
@@ -85,11 +91,15 @@
 		column2.setText(Messages.VariablesDropin_value);
 		treeViewerColumn2.setLabelProvider(new ContentLabelProvider());
 
-		fVariablesTree.setInput(fEngine);
-
 		fVariablesTree.addDragSupport(DND.DROP_MOVE | DND.DROP_COPY, new Transfer[] { LocalSelectionTransfer.getTransfer(), TextTransfer.getInstance() },
 				new VariablesDragListener(fVariablesTree));
 
+		composite.addListener(SWT.Hide, event -> fIsActive = false);
+		composite.addListener(SWT.Show, event -> {
+			fIsActive = true;
+			update();
+		});
+
 		return composite;
 	}
 
@@ -102,7 +112,7 @@
 	public void notify(IScriptEngine engine, Script script, int status) {
 		switch (status) {
 		case IExecutionListener.SCRIPT_END:
-			Display.getDefault().asyncExec(() -> fVariablesTree.refresh());
+			fUiUpdater.throttledExec();
 			break;
 
 		case IExecutionListener.ENGINE_END:
@@ -110,8 +120,13 @@
 			break;
 
 		default:
-			// nothing to do;
+			// nothing to do
 			break;
 		}
 	}
+
+	public void update() {
+		if (fIsActive)
+			fVariablesTree.refresh();
+	};
 }
diff --git a/plugins/org.eclipse.ease/src/org/eclipse/ease/AbstractReplScriptEngine.java b/plugins/org.eclipse.ease/src/org/eclipse/ease/AbstractReplScriptEngine.java
index 731181e..6e8bec7 100644
--- a/plugins/org.eclipse.ease/src/org/eclipse/ease/AbstractReplScriptEngine.java
+++ b/plugins/org.eclipse.ease/src/org/eclipse/ease/AbstractReplScriptEngine.java
@@ -11,10 +11,10 @@
 package org.eclipse.ease;
 
 import java.util.Collection;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.stream.Collectors;
 
 import org.eclipse.core.runtime.jobs.Job;
 import org.eclipse.ease.debugging.model.EaseDebugLastExecutionResult;
@@ -78,16 +78,8 @@
 
 	@Override
 	public Collection<EaseDebugVariable> getDefinedVariables() {
-		final Collection<EaseDebugVariable> result = new HashSet<>();
-
-		for (final Entry<String, Object> entry : getVariables().entrySet()) {
-			if (acceptVariable(entry.getValue())) {
-				final EaseDebugVariable variable = createVariable(entry.getKey(), entry.getValue());
-				result.add(variable);
-			}
-		}
-
-		return result;
+		return getVariables().entrySet().stream().filter(entry -> acceptVariable(entry.getValue()))
+				.map(entry -> createVariable(entry.getKey(), entry.getValue())).collect(Collectors.toSet());
 	}
 
 	/**
diff --git a/tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/views/shell/dropins/variables/VariablesContentProviderTest.java b/tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/views/shell/dropins/variables/VariablesContentProviderTest.java
new file mode 100644
index 0000000..789748a
--- /dev/null
+++ b/tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/views/shell/dropins/variables/VariablesContentProviderTest.java
@@ -0,0 +1,101 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Christian Pontesegger and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     Christian Pontesegger - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ease.ui.views.shell.dropins.variables;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+
+import org.eclipse.ease.IReplEngine;
+import org.eclipse.ease.debugging.model.EaseDebugValue;
+import org.eclipse.ease.debugging.model.EaseDebugVariable;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+public class VariablesContentProviderTest {
+
+	@Test
+	@DisplayName("hasChildren() == false when element has no child variables")
+	public void hasChildren_false_when_no_child_nodes_are_available() {
+
+		final EaseDebugValue value = mock(EaseDebugValue.class);
+		when(value.getVariables()).thenReturn(new EaseDebugVariable[0]);
+
+		final EaseDebugVariable variable = mock(EaseDebugVariable.class);
+		when(variable.getValue()).thenReturn(value);
+
+		final ITreeContentProvider contentProvider = new VariablesContentProvider();
+		assertFalse(contentProvider.hasChildren(variable));
+	}
+
+	@Test
+	@DisplayName("hasChildren() == true when element has child variables")
+	public void hasChildren_true_when_child_nodes_are_available() {
+
+		final EaseDebugValue value = mock(EaseDebugValue.class);
+		when(value.getVariables()).thenReturn(new EaseDebugVariable[] { mock(EaseDebugVariable.class) });
+
+		final EaseDebugVariable variable = mock(EaseDebugVariable.class);
+		when(variable.getValue()).thenReturn(value);
+
+		final ITreeContentProvider contentProvider = new VariablesContentProvider();
+		assertTrue(contentProvider.hasChildren(variable));
+	}
+
+	@Test
+	@DisplayName("getChildren() is empty when element has no child variables")
+	public void getChildren_is_empty_when_no_child_nodes_are_available() {
+
+		final EaseDebugValue value = mock(EaseDebugValue.class);
+		when(value.getVariables()).thenReturn(new EaseDebugVariable[0]);
+
+		final EaseDebugVariable variable = mock(EaseDebugVariable.class);
+		when(variable.getValue()).thenReturn(value);
+
+		final ITreeContentProvider contentProvider = new VariablesContentProvider();
+		assertArrayEquals(new EaseDebugVariable[0], contentProvider.getChildren(variable));
+	}
+
+	@Test
+	@DisplayName("getChildren() contains nodes when element has child variables")
+	public void getChildren_not_empty_when_child_nodes_are_available() {
+
+		final EaseDebugValue value = mock(EaseDebugValue.class);
+		when(value.getVariables()).thenReturn(new EaseDebugVariable[] { mock(EaseDebugVariable.class) });
+
+		final EaseDebugVariable variable = mock(EaseDebugVariable.class);
+		when(variable.getValue()).thenReturn(value);
+
+		final ITreeContentProvider contentProvider = new VariablesContentProvider();
+		assertEquals(1, contentProvider.getChildren(variable).length);
+	}
+
+	@Test
+	@DisplayName("getElements() contains global scope variables of engine")
+	public void getElements_contains_variables_from_engine() {
+
+		final IReplEngine engine = mock(IReplEngine.class);
+		when(engine.getDefinedVariables()).thenReturn(Arrays.asList(mock(EaseDebugVariable.class), mock(EaseDebugVariable.class)));
+		when(engine.getLastExecutionResult()).thenReturn(mock(EaseDebugVariable.class));
+
+		final ITreeContentProvider contentProvider = new VariablesContentProvider();
+		assertEquals(3, contentProvider.getElements(engine).length);
+	}
+}