Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenjamin Leipold2017-08-31 16:02:19 +0000
committerMickael Istria2017-11-21 20:16:53 +0000
commit581193006c8ace68b5db141fca66ac661a530576 (patch)
tree6f943cc380df040e82c413234663e9fd24de5bc0
parentdf133d0b691b0f42d3635adc7cdfcc93fa299ac3 (diff)
downloadeclipse.platform.ui-581193006c8ace68b5db141fca66ac661a530576.tar.gz
eclipse.platform.ui-581193006c8ace68b5db141fca66ac661a530576.tar.xz
eclipse.platform.ui-581193006c8ace68b5db141fca66ac661a530576.zip
Bug 520372 - ContentProposalAdapter with autoActivationDelay pops
up although control has already lost focus Added lost changes and moved tests to separate test case. Change-Id: I749a6ef63c610d274028369c47cd697112ffa540 Signed-off-by: Benjamin Leipold <benjamin.leipold@web.de>
-rw-r--r--bundles/org.eclipse.jface/src/org/eclipse/jface/fieldassist/ContentProposalAdapter.java26
-rw-r--r--tests/org.eclipse.ui.tests/Eclipse JFace Tests/org/eclipse/jface/tests/fieldassist/ContentProposalAdapterTest.java229
2 files changed, 255 insertions, 0 deletions
diff --git a/bundles/org.eclipse.jface/src/org/eclipse/jface/fieldassist/ContentProposalAdapter.java b/bundles/org.eclipse.jface/src/org/eclipse/jface/fieldassist/ContentProposalAdapter.java
index 513d690e3cf..7d9b80a2384 100644
--- a/bundles/org.eclipse.jface/src/org/eclipse/jface/fieldassist/ContentProposalAdapter.java
+++ b/bundles/org.eclipse.jface/src/org/eclipse/jface/fieldassist/ContentProposalAdapter.java
@@ -1698,6 +1698,18 @@ public class ContentProposalAdapter {
// We were only listening to traverse events for the popup
if (e.type == SWT.Traverse) {
+ // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=520372
+ // The popup is null so record tab as a means to interrupt
+ // any autoactivation that is pending due to autoactivation
+ // delay.
+ if (popup == null) {
+ switch (e.detail) {
+ case SWT.TRAVERSE_TAB_NEXT:
+ case SWT.TRAVERSE_TAB_PREVIOUS:
+ receivedKeyDown = true;
+ break;
+ }
+ }
return;
}
@@ -1748,6 +1760,20 @@ public class ContentProposalAdapter {
if (triggerKeyStroke == null) {
watchModify = true;
}
+
+ // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=520372
+ // mimic close cases of popup in TargetControlListener
+ if (popup == null) {
+ switch (e.character) {
+ case SWT.CR:
+ case SWT.LF:
+ case SWT.ESC:
+ // Interrupt any autoactivation that is pending due to
+ // autoactivation delay.
+ receivedKeyDown = true;
+ break;
+ }
+ }
}
} else {
// A non-character key has been pressed. Interrupt any
diff --git a/tests/org.eclipse.ui.tests/Eclipse JFace Tests/org/eclipse/jface/tests/fieldassist/ContentProposalAdapterTest.java b/tests/org.eclipse.ui.tests/Eclipse JFace Tests/org/eclipse/jface/tests/fieldassist/ContentProposalAdapterTest.java
new file mode 100644
index 00000000000..4d0bb5eb564
--- /dev/null
+++ b/tests/org.eclipse.ui.tests/Eclipse JFace Tests/org/eclipse/jface/tests/fieldassist/ContentProposalAdapterTest.java
@@ -0,0 +1,229 @@
+/*******************************************************************************
+* Copyright (c) 2017 Benjamin Leipold 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:
+* Benjamin Leipold - initial API and implementation
+*******************************************************************************/
+package org.eclipse.jface.tests.fieldassist;
+
+import org.eclipse.jface.fieldassist.ContentProposalAdapter;
+import org.eclipse.jface.fieldassist.IContentProposalProvider;
+import org.eclipse.jface.fieldassist.SimpleContentProposalProvider;
+import org.eclipse.jface.fieldassist.TextContentAdapter;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+
+import junit.framework.TestCase;
+
+public class ContentProposalAdapterTest extends TestCase {
+
+ /**
+ * A shell that hosts the decorated text control
+ */
+ private Shell controlShell;
+
+ /**
+ * Text control to be decorated by {@code contentProposalAdapter}
+ */
+ private Text text;
+
+ /**
+ * {@code ContentProposalAdapter} to test
+ */
+ private ContentProposalAdapter contentProposalAdapter;
+
+ /**
+ * Display of this test case.
+ */
+ private Display display;
+
+ /**
+ * {@code true} if {@code display} has to be disposed in {@link #tearDown()}
+ */
+ private boolean disposeDisplay;
+
+ /**
+ * The original number of shells at the beginning of the test.
+ */
+ private int originalShellCount;
+
+ /**
+ * bug 520372: ContentProposalAdapter with autoActivationDelay pops up although
+ * control has already lost focus
+ * https://bugs.eclipse.org/bugs/show_bug.cgi?id=520372
+ *
+ * Tests whether no proposal popup was opened if TAB was pressed within
+ * activation delay.
+ */
+ public void testBug520372AutoActivationDelayTab() throws Exception {
+ sendKeyDownToControl('o');
+ sendKeyDownToControl(SWT.TAB);
+ ensurePopupIsUp();
+
+ assertOneShellUp();
+ }
+
+ /**
+ * bug 520372: ContentProposalAdapter with autoActivationDelay pops up although
+ * control has already lost focus
+ * https://bugs.eclipse.org/bugs/show_bug.cgi?id=520372
+ *
+ * Tests whether no proposal popup was opened if CR was pressed within
+ * activation delay.
+ */
+ public void testBug520372AutoActivationDelayCR() throws Exception {
+ sendKeyDownToControl('o');
+ sendKeyDownToControl(SWT.CR);
+ ensurePopupIsUp();
+
+ assertOneShellUp();
+ }
+
+ /**
+ * bug 520372: ContentProposalAdapter with autoActivationDelay pops up although
+ * control has already lost focus
+ * https://bugs.eclipse.org/bugs/show_bug.cgi?id=520372
+ *
+ * Tests whether no proposal popup was opened if ESC was pressed within
+ * activation delay.
+ */
+ public void testBug520372AutoActivationDelayESC() throws Exception {
+ sendKeyDownToControl('o');
+ sendKeyDownToControl(SWT.ESC);
+ ensurePopupIsUp();
+
+ assertOneShellUp();
+ }
+
+ // most of the following code is copied from AbstractFieldAssistTestCase
+
+ @Override
+ final protected void setUp() throws Exception {
+ super.setUp();
+
+ Display display = getDisplay();
+ originalShellCount = display.getShells().length;
+ controlShell = new Shell(display);
+ text = new Text(controlShell, SWT.SINGLE);
+ controlShell.open();
+ spinEventLoop();
+ contentProposalAdapter = createContentProposalAdapter(this.text);
+ assertNotNull(contentProposalAdapter);
+ }
+
+ @Override
+ final protected void tearDown() throws Exception {
+ if (controlShell != null) {
+ spinEventLoop();
+ controlShell.close();
+ }
+ if (display != null) {
+ if (disposeDisplay) {
+ display.dispose();
+ }
+ this.display = null;
+ }
+
+ super.tearDown();
+ }
+
+ private Display getDisplay() {
+ if (display == null) {
+ Display newDisplay = Display.getCurrent();
+ if (newDisplay == null) {
+ newDisplay = new Display();
+ disposeDisplay = true;
+ }
+ display = newDisplay;
+ }
+ return display;
+ }
+
+ /**
+ * Gives focus to the field assist control.
+ */
+ private void sendFocusInToControl() {
+ text.setFocus();
+ spinEventLoop();
+ }
+
+ /**
+ * Sends an SWT KeyDown event for the specified character to the field assist
+ * control.
+ *
+ * @param character
+ * the character that has been pressed
+ */
+ private void sendKeyDownToControl(char character) {
+ // fake a KeyDown event
+ sendFocusInToControl();
+ Event event = new Event();
+ event.type = SWT.KeyDown;
+ event.character = character;
+ assertTrue("unable to post event to display queue for test case", text.getDisplay().post(event));
+ spinEventLoop();
+ }
+
+ private void spinEventLoop() {
+ // spin the event loop again because we have some asyncExec calls in the
+ // ContentProposalAdapter class
+
+ Display disp = getDisplay();
+ while (disp.readAndDispatch()) {
+ }
+ }
+
+ private ContentProposalAdapter createContentProposalAdapter(Control control) {
+ ContentProposalAdapter contentProposalAdapter = new ContentProposalAdapter(control, new TextContentAdapter(),
+ createContentProposalProvider(), null, null);
+ contentProposalAdapter.setAutoActivationDelay(2000);
+ return contentProposalAdapter;
+ }
+
+ private IContentProposalProvider createContentProposalProvider() {
+ SimpleContentProposalProvider proposalProvider = new SimpleContentProposalProvider(getProposals());
+ return proposalProvider;
+ }
+
+ private String[] getProposals() {
+ return new String[] { "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten" };
+ }
+
+ private void ensurePopupIsUp() {
+ // if our autoactivation delay is zero, we use an asyncExec to get the
+ // popup up, hence, we need to spin the event loop
+ if (contentProposalAdapter.getAutoActivationDelay() == 0) {
+ spinEventLoop();
+ } else {
+ long time = System.currentTimeMillis();
+ long target = time + contentProposalAdapter.getAutoActivationDelay();
+ while (target > time) {
+ spinEventLoop(); // remain responsive
+ time = System.currentTimeMillis();
+ }
+ try {
+ Thread.sleep(10);
+ } catch (InterruptedException e) {
+ // nothing to do
+ }
+ spinEventLoop();
+ }
+ }
+
+ /**
+ * Checks that there is only one shell up, the original field assist window.
+ */
+ private void assertOneShellUp() {
+ spinEventLoop();
+ assertEquals("There should only be one shell up, the dialog", originalShellCount + 1,
+ text.getDisplay().getShells().length);
+ }
+}

Back to the top