Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Wiehl2014-10-21 12:53:46 +0000
committerDaniel Wiehl2014-10-21 12:53:46 +0000
commit3d623e62a694178cf6495de5303298c53e0b05eb (patch)
tree09ce55336ca5d31c731f7ea8b858db262a0458e1
parentb66bccb06c08dc8192c8ea50d1cbd564e7c26ecd (diff)
downloadorg.eclipse.scout.rt-3d623e62a694178cf6495de5303298c53e0b05eb.tar.gz
org.eclipse.scout.rt-3d623e62a694178cf6495de5303298c53e0b05eb.tar.xz
org.eclipse.scout.rt-3d623e62a694178cf6495de5303298c53e0b05eb.zip
Bug 443555/Bug 441045: SWT: Smartfield does not work in Linux and Mac OS
X https://bugs.eclipse.org/bugs/show_bug.cgi?id=443555 https://bugs.eclipse.org/bugs/show_bug.cgi?id=441045 Fixed the various problems when requesting the proposal popup and accepting proposals in form-fields as well as in cell-editors. The main issue was that the popup dialog became the active shell and focus owner which triggered to many verify events. Furthermore, the event and focus handling of cell-editors that open a Shell was facilitated and improved to have the same behavior as in a smartfield cell editor. Change-Id: I0e81c1bd8aba7eaa1722d8b0bd6802f64e6eb1ea
-rw-r--r--org.eclipse.scout.rt.client/src/org/eclipse/scout/rt/client/ui/form/fields/smartfield/AbstractContentAssistFieldLookupRowFetcher.java3
-rw-r--r--org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/AbstractSwtEnvironment.java28
-rw-r--r--org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/basic/table/celleditor/FormFieldPopupEvent.java42
-rw-r--r--org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/basic/table/celleditor/IFormFieldPopupEventListener.java18
-rw-r--r--org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/basic/table/celleditor/IFormFieldPopupListener.java48
-rw-r--r--org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/basic/table/celleditor/SwtScoutFormFieldPopup.java453
-rw-r--r--org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/basic/table/celleditor/SwtScoutTableCellEditor.java516
-rw-r--r--org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/form/fields/IPopupSupport.java48
-rw-r--r--org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/form/fields/datefield/SwtScoutDateField.java38
-rw-r--r--org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/form/fields/datefield/SwtScoutTimeField.java37
-rw-r--r--org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/form/fields/smartfield/SwtScoutSmartField.java161
-rw-r--r--org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/window/SwtScoutPartEvent.java53
-rw-r--r--org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/window/SwtScoutPartListener.java22
-rw-r--r--org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/window/popup/SwtScoutDropDownPopup.java246
-rw-r--r--org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/window/popup/SwtScoutPopup.java214
15 files changed, 676 insertions, 1251 deletions
diff --git a/org.eclipse.scout.rt.client/src/org/eclipse/scout/rt/client/ui/form/fields/smartfield/AbstractContentAssistFieldLookupRowFetcher.java b/org.eclipse.scout.rt.client/src/org/eclipse/scout/rt/client/ui/form/fields/smartfield/AbstractContentAssistFieldLookupRowFetcher.java
index c6e973da02..535bb8d6bd 100644
--- a/org.eclipse.scout.rt.client/src/org/eclipse/scout/rt/client/ui/form/fields/smartfield/AbstractContentAssistFieldLookupRowFetcher.java
+++ b/org.eclipse.scout.rt.client/src/org/eclipse/scout/rt/client/ui/form/fields/smartfield/AbstractContentAssistFieldLookupRowFetcher.java
@@ -78,7 +78,8 @@ public abstract class AbstractContentAssistFieldLookupRowFetcher<KEY_TYPE> imple
}
protected void setResult(IContentAssistFieldDataFetchResult<KEY_TYPE> result) {
- propertySupport.setProperty(PROP_SEARCH_RESULT, result);
+ // Always propagate the event of an executed search to the listeners even if the search result did not change. Thus, the proposal popup is opened for every search.
+ propertySupport.setPropertyAlwaysFire(PROP_SEARCH_RESULT, result);
}
@Override
diff --git a/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/AbstractSwtEnvironment.java b/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/AbstractSwtEnvironment.java
index 58c2eecbf7..9a10e9b0ca 100644
--- a/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/AbstractSwtEnvironment.java
+++ b/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/AbstractSwtEnvironment.java
@@ -83,8 +83,6 @@ import org.eclipse.scout.rt.ui.swt.util.ScoutFormToolkit;
import org.eclipse.scout.rt.ui.swt.util.SwtIconLocator;
import org.eclipse.scout.rt.ui.swt.util.SwtUtility;
import org.eclipse.scout.rt.ui.swt.window.ISwtScoutPart;
-import org.eclipse.scout.rt.ui.swt.window.SwtScoutPartEvent;
-import org.eclipse.scout.rt.ui.swt.window.SwtScoutPartListener;
import org.eclipse.scout.rt.ui.swt.window.desktop.editor.AbstractScoutEditorPart;
import org.eclipse.scout.rt.ui.swt.window.desktop.editor.ScoutFormEditorInput;
import org.eclipse.scout.rt.ui.swt.window.desktop.tray.ISwtScoutTray;
@@ -139,7 +137,7 @@ import org.osgi.framework.Bundle;
/**
* <h3>SwtEnvironment</h3> ...
- *
+ *
* @since 1.0.0 06.03.2008
*/
public abstract class AbstractSwtEnvironment extends AbstractPropertyObserver implements ISwtEnvironment {
@@ -1110,30 +1108,8 @@ public abstract class AbstractSwtEnvironment extends AbstractPropertyObserver im
if (owner == null) {
return null;
}
- Rectangle ownerBounds = getPopupOwnerBounds();
- if (ownerBounds == null) {
- ownerBounds = owner.getBounds();
- Point pDisp = owner.toDisplay(0, 0);
- ownerBounds.x = pDisp.x;
- ownerBounds.y = pDisp.y;
- }
- final SwtScoutPopup popup = new SwtScoutPopup(this, owner, ownerBounds, SWT.RESIZE);
+ final SwtScoutPopup popup = new SwtScoutPopup(this, owner, true, SWT.RESIZE);
popup.setMaxHeightHint(280);
- popup.addSwtScoutPartListener(new SwtScoutPartListener() {
- @Override
- public void partChanged(SwtScoutPartEvent e) {
- switch (e.getType()) {
- case SwtScoutPartEvent.TYPE_CLOSED: {
- popup.closePart();
- break;
- }
- case SwtScoutPartEvent.TYPE_CLOSING: {
- popup.closePart();
- break;
- }
- }
- }
- });
//close popup when PARENT shell is activated or closed
owner.getShell().addShellListener(new ShellAdapter() {
@Override
diff --git a/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/basic/table/celleditor/FormFieldPopupEvent.java b/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/basic/table/celleditor/FormFieldPopupEvent.java
deleted file mode 100644
index a377b386e0..0000000000
--- a/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/basic/table/celleditor/FormFieldPopupEvent.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2010 BSI Business Systems Integration AG.
- * 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:
- * BSI Business Systems Integration AG - initial API and implementation
- ******************************************************************************/
-package org.eclipse.scout.rt.ui.swt.basic.table.celleditor;
-
-import java.util.EventObject;
-
-import org.eclipse.scout.rt.client.ui.form.fields.IFormField;
-
-public class FormFieldPopupEvent extends EventObject {
-
- private static final long serialVersionUID = 1L;
-
- public static final int TYPE_OK = 1 << 0;
- public static final int TYPE_CANCEL = 1 << 1;
- public static final int TYPE_OPEN = 1 << 2;
- public static final int TYPE_FOCUS_NEXT = 1 << 3;
- public static final int TYPE_FOCUS_BACK = 1 << 4;
-
- private int m_type;
-
- public FormFieldPopupEvent(IFormField source, int type) {
- super(source);
- m_type = type;
- }
-
- public int getType() {
- return m_type;
- }
-
- @Override
- public IFormField getSource() {
- return (IFormField) super.getSource();
- }
-}
diff --git a/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/basic/table/celleditor/IFormFieldPopupEventListener.java b/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/basic/table/celleditor/IFormFieldPopupEventListener.java
deleted file mode 100644
index a7e45cbe64..0000000000
--- a/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/basic/table/celleditor/IFormFieldPopupEventListener.java
+++ /dev/null
@@ -1,18 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2010 BSI Business Systems Integration AG.
- * 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:
- * BSI Business Systems Integration AG - initial API and implementation
- ******************************************************************************/
-package org.eclipse.scout.rt.ui.swt.basic.table.celleditor;
-
-import java.util.EventListener;
-
-public interface IFormFieldPopupEventListener extends EventListener {
-
- void handleEvent(FormFieldPopupEvent event);
-}
diff --git a/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/basic/table/celleditor/IFormFieldPopupListener.java b/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/basic/table/celleditor/IFormFieldPopupListener.java
new file mode 100644
index 0000000000..3d65599457
--- /dev/null
+++ b/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/basic/table/celleditor/IFormFieldPopupListener.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2010 BSI Business Systems Integration AG.
+ * 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:
+ * BSI Business Systems Integration AG - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.scout.rt.ui.swt.basic.table.celleditor;
+
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * Listener to be notified about form-field and traversal events of {@link SwtScoutFormFieldPopup}.
+ */
+public interface IFormFieldPopupListener {
+
+ /**
+ * Event constant to indicate the content to be stored. (e.g. because of an <code>OK</code> keystroke, traversal event
+ * or due to popup deactivation)
+ */
+ int TYPE_OK = 1 << 0;
+
+ /**
+ * Event constant to indicate the content to be discarded (e.g. because of an <code>ESC</code> keystroke).
+ */
+ int TYPE_CANCEL = 1 << 1;
+
+ /**
+ * Event constant to indicate that a traversal event occured.
+ */
+ int TYPE_FOCUS_NEXT = 1 << 2;
+
+ /**
+ * Event constant to indicate that a traversal event occured.
+ */
+ int TYPE_FOCUS_BACK = 1 << 3;
+
+ /**
+ * Callback to indicate a popup event occured. Thereby, the {@link Shell} is not closed.
+ *
+ * @param event
+ * <em>bitwise OR</em> encoded style constant to describe the event.
+ */
+ void handleEvent(int event);
+}
diff --git a/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/basic/table/celleditor/SwtScoutFormFieldPopup.java b/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/basic/table/celleditor/SwtScoutFormFieldPopup.java
index 7ec4a6cd81..34237ff424 100644
--- a/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/basic/table/celleditor/SwtScoutFormFieldPopup.java
+++ b/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/basic/table/celleditor/SwtScoutFormFieldPopup.java
@@ -10,12 +10,14 @@
******************************************************************************/
package org.eclipse.scout.rt.ui.swt.basic.table.celleditor;
-import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
-import java.util.concurrent.atomic.AtomicReference;
+import java.util.Set;
import org.eclipse.scout.commons.annotations.Order;
import org.eclipse.scout.commons.exception.ProcessingException;
+import org.eclipse.scout.commons.holders.Holder;
import org.eclipse.scout.commons.logger.IScoutLogger;
import org.eclipse.scout.commons.logger.ScoutLogManager;
import org.eclipse.scout.rt.client.ui.form.AbstractForm;
@@ -24,23 +26,21 @@ import org.eclipse.scout.rt.client.ui.form.IForm;
import org.eclipse.scout.rt.client.ui.form.fields.IFormField;
import org.eclipse.scout.rt.client.ui.form.fields.groupbox.AbstractGroupBox;
import org.eclipse.scout.rt.ui.swt.basic.SwtScoutComposite;
-import org.eclipse.scout.rt.ui.swt.form.ISwtScoutForm;
-import org.eclipse.scout.rt.ui.swt.window.SwtScoutPartEvent;
-import org.eclipse.scout.rt.ui.swt.window.SwtScoutPartListener;
+import org.eclipse.scout.rt.ui.swt.form.fields.ISwtScoutFormField;
+import org.eclipse.scout.rt.ui.swt.util.SwtUtility;
import org.eclipse.scout.rt.ui.swt.window.popup.SwtScoutDropDownPopup;
import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.ControlAdapter;
-import org.eclipse.swt.events.ControlEvent;
+import org.eclipse.swt.events.PaintEvent;
+import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.events.ShellAdapter;
import org.eclipse.swt.events.ShellEvent;
import org.eclipse.swt.events.TraverseEvent;
import org.eclipse.swt.events.TraverseListener;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Event;
/**
- * Wraps a {@link IFormField} to be displayed as popup cell editor
+ * Wraps a {@link IFormField} to be displayed as popup cell editor.
*/
public class SwtScoutFormFieldPopup extends SwtScoutComposite<IFormField> {
@@ -54,118 +54,223 @@ public class SwtScoutFormFieldPopup extends SwtScoutComposite<IFormField> {
private int m_minHeight;
private int m_prefHeight;
private int m_style;
- private SwtScoutPartListener m_popupEventListener;
- private List<IFormFieldPopupEventListener> m_eventListeners = new ArrayList<IFormFieldPopupEventListener>();
- private Object m_eventListenerLock = new Object();
+ private Control m_swtFormField;
+
+ private final Set<IFormFieldPopupListener> m_listeners = Collections.synchronizedSet(new HashSet<IFormFieldPopupListener>());
public SwtScoutFormFieldPopup(Composite owner) {
m_owner = owner;
- m_style = SWT.NO_TRIM;
- m_popupEventListener = new P_PopupEventListener();
+ m_style = SWT.NO_TRIM; // no trim area on the popup Shell.
}
@Override
protected void initializeSwt(Composite parent) {
super.initializeSwt(parent);
- // create form to hold the form field
- final AtomicReference<IForm> formRef = new AtomicReference<IForm>();
- Runnable runnable = new Runnable() {
- @Override
- public void run() {
- try {
- P_Form form = new P_Form();
- form.setAutoAddRemoveOnDesktop(false);
- form.startForm();
- formRef.set(form);
- }
- catch (Throwable t) {
- LOG.error("failed to start popup form", t);
- }
- synchronized (formRef) {
- formRef.notifyAll();
- }
- }
- };
- synchronized (formRef) {
- getEnvironment().invokeScoutLater(runnable, 2345);
- try {
- formRef.wait(2345);
- }
- catch (InterruptedException t) {
- //nop
- }
- }
-
- IForm form = formRef.get();
- if (form == null) {
- LOG.error("No popup form available");
- return;
- }
-
- // create popup in reference to cell editor (owner)
- m_swtScoutPopup = new P_SwtScoutDropDownPopup(m_owner, m_style);
+ // Create the Popup-Shell but do not make it visible yet; This is done the time the owner component is painted.
+ m_swtScoutPopup = new SwtScoutDropDownPopup(getEnvironment(), m_owner, true, m_style);
m_swtScoutPopup.setPopupOnField(true);
m_swtScoutPopup.setHeightHint(m_prefHeight);
m_swtScoutPopup.setWidthHint(m_prefWidth);
m_swtScoutPopup.getShell().setMinimumSize(m_minWidth, m_minHeight);
- m_swtScoutPopup.getShell().addTraverseListener(new TraverseListener() {
+ // Listener to be notified about traversal events and keystrokes occurred on the popup.
+ final TraverseListener traverseListener = new TraverseListener() {
@Override
- public void keyTraversed(TraverseEvent event) {
- switch (event.detail) {
+ public void keyTraversed(TraverseEvent e) {
+ switch (e.detail) {
+ case SWT.TRAVERSE_TAB_NEXT: {
+ e.doit = false;
+ notifyListeners(IFormFieldPopupListener.TYPE_OK | IFormFieldPopupListener.TYPE_FOCUS_NEXT);
+ break;
+ }
+ case SWT.TRAVERSE_TAB_PREVIOUS: {
+ e.doit = false;
+ notifyListeners(IFormFieldPopupListener.TYPE_OK | IFormFieldPopupListener.TYPE_FOCUS_BACK);
+ break;
+ }
case SWT.TRAVERSE_ESCAPE: {
- event.doit = false;
- closePopup(FormFieldPopupEvent.TYPE_CANCEL);
+ e.doit = false;
+ notifyListeners(IFormFieldPopupListener.TYPE_CANCEL);
break;
}
case SWT.TRAVERSE_RETURN: {
- event.doit = false;
- closePopup(FormFieldPopupEvent.TYPE_OK);
+ e.doit = false;
+ notifyListeners(IFormFieldPopupListener.TYPE_OK);
break;
}
}
}
- });
+ };
- // install popup listener
- m_swtScoutPopup.addSwtScoutPartListener(m_popupEventListener);
+ // Listener to handle Shell deactivation events.
+ m_swtScoutPopup.addShellListener(new ShellAdapter() {
- // open popup
- try {
- m_swtScoutPopup.showForm(form);
- // install traversal keystrokes on inner form
- installTraverseKeyStrokes(m_swtScoutPopup.getSwtContentPane());
- }
- catch (Throwable t) {
- LOG.error("failed to show popup form", t);
- }
+ @Override
+ public void shellDeactivated(ShellEvent e) {
+ notifyListeners(IFormFieldPopupListener.TYPE_OK);
+ }
+ });
- // add control listener to adjust popup location
- m_owner.addControlListener(new ControlAdapter() {
+ // Defer opening the Shell to be positioned at the location of the owner component.
+ m_owner.addPaintListener(new PaintListener() {
@Override
- public void controlResized(ControlEvent e) {
- // invoke at next reasonable time to guarantee proper location
- getSwtContainer().getDisplay().asyncExec(new Runnable() {
-
- @Override
- public void run() {
- if (m_swtScoutPopup != null) {
- m_swtScoutPopup.autoAdjustBounds();
- }
+ public void paintControl(PaintEvent e) {
+ if (m_owner.isDisposed()) {
+ return; // do not open the Shell if the owner is already disposed.
+ }
+ m_owner.removePaintListener(this);
+
+ // Create the Form to contain the form-field.
+ final IForm form = createForm();
+ if (form != null) {
+ m_swtScoutPopup.showForm(form);
+ m_swtFormField = findSwtFormField(m_swtScoutPopup.getUiForm().getSwtField(), getScoutObject());
+ if (m_swtFormField == null) {
+ LOG.warn("UI-FormField could not be found in UI-Form");
}
- });
+
+ // Install listener to be notified about traversal events.
+ installTraverseListener(m_swtScoutPopup.getShell(), traverseListener);
+ }
+ else {
+ LOG.error("Failed to create the Form for the form-field.");
+ }
}
+
});
setSwtContainer(m_owner);
}
- private class P_Form extends AbstractForm {
+ public void setMinWidth(int minWidth) {
+ m_minWidth = minWidth;
+ }
+
+ public void setPrefWidth(int prefWidth) {
+ m_prefWidth = prefWidth;
+ }
+
+ public void setMinHeight(int minHeight) {
+ m_minHeight = minHeight;
+ }
+
+ public void setPrefHeight(int prefHeight) {
+ m_prefHeight = prefHeight;
+ }
+
+ /**
+ * Closes the popup.
+ */
+ public void closePopup() {
+ m_swtScoutPopup.closePart();
+ }
+
+ /**
+ * Touches the field to write its UI value back to the model.
+ */
+ public void touch() {
+ if (m_swtFormField != null && !m_swtFormField.isDisposed()) {
+ SwtUtility.runSwtInputVerifier(m_swtFormField);
+ }
+ }
+
+ public void addListener(IFormFieldPopupListener listener) {
+ m_listeners.add(listener);
+ }
+
+ public void removeListener(IFormFieldPopupListener listener) {
+ m_listeners.remove(listener);
+ }
+
+ private void notifyListeners(int eventType) {
+ for (IFormFieldPopupListener listener : m_listeners) {
+ listener.handleEvent(eventType);
+ }
+ }
+
+ /**
+ * Installs the given traverse listener on the given control and its child controls.
+ */
+ private void installTraverseListener(Control control, TraverseListener listener) {
+ control.addTraverseListener(listener);
+ if (control instanceof Composite) {
+ Composite composite = (Composite) control;
+ for (Control child : composite.getChildren()) {
+ installTraverseListener(child, listener);
+ }
+ }
+ }
+
+ /**
+ * @return creates the {@link IForm} that contains the {@link IFormField}.
+ */
+ private IForm createForm() {
+ final Holder<IForm> result = new Holder<IForm>();
+ Runnable runnable = new Runnable() {
+ @Override
+ public void run() {
+ try {
+ P_Form form = new P_Form(getScoutObject());
+ form.setAutoAddRemoveOnDesktop(false);
+ form.startForm();
+ result.setValue(form);
+ }
+ catch (Exception e) {
+ LOG.error("Failed to create and start popup form.", e);
+ }
+ }
+ };
+
+ try {
+ getEnvironment().invokeScoutLater(runnable, 2345).join(2345);
+ }
+ catch (InterruptedException e) {
+ LOG.warn("Interrupted while waiting for the popup form to be started.", e);
+ }
+
+ return result.getValue();
+ }
+
+ /**
+ * Finds the <code>FormField</code> {@link Control} that represents the {@link IFormField} in the hierarchy of the
+ * given {@link Control}.
+ *
+ * @param control
+ * container.
+ * @param formField
+ * {@link IFormField}.
+ * @return {@link Control} or <code>null</code> if not found.
+ */
+ private static Control findSwtFormField(Control control, IFormField formField) {
+ Object o = control.getData(ISwtScoutFormField.CLIENT_PROPERTY_SCOUT_OBJECT);
+ if (o == formField) {
+ return control;
+ }
+
+ if (control instanceof Composite) {
+ for (Control child : ((Composite) control).getChildren()) {
+ Control candiate = findSwtFormField(child, formField);
+ if (candiate != null) {
+ return candiate;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * {@link IForm} to contain the {@link IFormField}.
+ */
+ private static class P_Form extends AbstractForm {
+
+ private final IFormField m_formField;
- public P_Form() throws ProcessingException {
- super();
+ public P_Form(IFormField formField) throws ProcessingException {
+ super(false);
+ m_formField = formField;
+ callInitializer();
}
@Override
@@ -201,7 +306,7 @@ public class SwtScoutFormFieldPopup extends SwtScoutComposite<IFormField> {
@Override
protected void injectFieldsInternal(List<IFormField> fieldList) {
- fieldList.add(getScoutObject());
+ fieldList.add(m_formField);
}
@Override
@@ -228,180 +333,4 @@ public class SwtScoutFormFieldPopup extends SwtScoutComposite<IFormField> {
private class FormHandler extends AbstractFormHandler {
}
}
-
- /**
- * Touch the field to write its UI value back to the model
- */
- public void touch() {
- if (m_swtScoutPopup != null) {
- touch(m_swtScoutPopup.getSwtContentPane());
- }
- }
-
- private void touch(Control control) {
- if (control == null || control.isDisposed()) {
- return;
- }
- Event event = new Event();
- event.widget = control;
- control.notifyListeners(SWT.Traverse, event);
-
- if (control instanceof Composite) {
- Composite composite = (Composite) control;
- for (Control child : composite.getChildren()) {
- touch(child);
- }
- }
- }
-
- private void installTraverseKeyStrokes(Control control) {
- control.addTraverseListener(new TraverseListener() {
- @Override
- public void keyTraversed(TraverseEvent e) {
- switch (e.detail) {
- case SWT.TRAVERSE_TAB_NEXT: {
- e.doit = false;
- closePopup(FormFieldPopupEvent.TYPE_OK | FormFieldPopupEvent.TYPE_FOCUS_NEXT);
- break;
- }
- case SWT.TRAVERSE_TAB_PREVIOUS: {
- e.doit = false;
- closePopup(FormFieldPopupEvent.TYPE_OK | FormFieldPopupEvent.TYPE_FOCUS_BACK);
- break;
- }
- }
- }
- });
- if (control instanceof Composite) {
- Composite composite = (Composite) control;
- for (Control child : composite.getChildren()) {
- installTraverseKeyStrokes(child);
- }
- }
- }
-
- public void addEventListener(IFormFieldPopupEventListener eventListener) {
- synchronized (m_eventListenerLock) {
- m_eventListeners.add(eventListener);
- }
- }
-
- public void removeEventListener(IFormFieldPopupEventListener eventListener) {
- synchronized (m_eventListenerLock) {
- m_eventListeners.remove(eventListener);
- }
- }
-
- protected void notifyEventListeners(FormFieldPopupEvent event) {
- IFormFieldPopupEventListener[] eventListeners;
- synchronized (m_eventListenerLock) {
- eventListeners = m_eventListeners.toArray(new IFormFieldPopupEventListener[m_eventListeners.size()]);
- }
- for (IFormFieldPopupEventListener eventListener : eventListeners) {
- eventListener.handleEvent(event);
- }
- }
-
- public void closePopup(int type) {
- touch();
- m_swtScoutPopup.removeSwtScoutPartListener(m_popupEventListener);
- m_swtScoutPopup.closePart();
- m_swtScoutPopup = null;
-
- // notify listeners
- notifyEventListeners(new FormFieldPopupEvent(getScoutObject(), type));
- }
-
- public SwtScoutDropDownPopup getPopup() {
- return m_swtScoutPopup;
- }
-
- public boolean isClosed() {
- return m_swtScoutPopup == null || m_swtScoutPopup.getSwtContentPane() == null || m_swtScoutPopup.getSwtContentPane().isDisposed();
- }
-
- public ISwtScoutForm getInnerSwtScoutForm() {
- return m_swtScoutPopup.getUiForm();
- }
-
- public int getMinWidth() {
- return m_minWidth;
- }
-
- public void setMinWidth(int minWidth) {
- m_minWidth = minWidth;
- }
-
- public int getPrefWidth() {
- return m_prefWidth;
- }
-
- public void setPrefWidth(int prefWidth) {
- m_prefWidth = prefWidth;
- }
-
- public int getMinHeight() {
- return m_minHeight;
- }
-
- public void setMinHeight(int minHeight) {
- m_minHeight = minHeight;
- }
-
- public int getPrefHeight() {
- return m_prefHeight;
- }
-
- public void setPrefHeight(int prefHeight) {
- m_prefHeight = prefHeight;
- }
-
- public int getStyle() {
- return m_style;
- }
-
- public void setStyle(int style) {
- m_style = style;
- }
-
- private class P_PopupEventListener implements SwtScoutPartListener {
-
- @Override
- public void partChanged(SwtScoutPartEvent e) {
- if (e.getType() == SwtScoutPartEvent.TYPE_CLOSED) {
- closePopup(FormFieldPopupEvent.TYPE_OK);
- }
- }
- }
-
- private class P_SwtScoutDropDownPopup extends SwtScoutDropDownPopup {
-
- private ShellAdapter m_shellListener;
-
- public P_SwtScoutDropDownPopup(Control ownerComponent, int style) {
- super(getEnvironment(), ownerComponent, null, style);
- }
-
- @Override
- protected void installFocusListener() {
- if (m_shellListener == null) {
- m_shellListener = new ShellAdapter() {
- @Override
- public void shellDeactivated(ShellEvent e) {
- closePart();
- fireSwtScoutPartEvent(new SwtScoutPartEvent(P_SwtScoutDropDownPopup.this, SwtScoutPartEvent.TYPE_CLOSED));
- }
- };
- getShell().addShellListener(m_shellListener);
- }
- }
-
- @Override
- protected void uninstallFocusLostListener() {
- if (m_shellListener != null) {
- getShell().removeShellListener(m_shellListener);
- }
- m_shellListener = null;
- }
- }
}
diff --git a/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/basic/table/celleditor/SwtScoutTableCellEditor.java b/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/basic/table/celleditor/SwtScoutTableCellEditor.java
index c17d7a533e..e9cf44603c 100644
--- a/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/basic/table/celleditor/SwtScoutTableCellEditor.java
+++ b/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/basic/table/celleditor/SwtScoutTableCellEditor.java
@@ -10,20 +10,18 @@
******************************************************************************/
package org.eclipse.scout.rt.ui.swt.basic.table.celleditor;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
-
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ColumnViewerEditorActivationEvent;
import org.eclipse.jface.viewers.ColumnViewerEditorDeactivationEvent;
import org.eclipse.jface.viewers.ICellModifier;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.ViewerCell;
+import org.eclipse.scout.commons.BooleanUtility;
import org.eclipse.scout.commons.CompareUtility;
+import org.eclipse.scout.commons.holders.BooleanHolder;
+import org.eclipse.scout.commons.holders.Holder;
+import org.eclipse.scout.commons.logger.IScoutLogger;
+import org.eclipse.scout.commons.logger.ScoutLogManager;
import org.eclipse.scout.rt.client.ui.basic.table.ITable;
import org.eclipse.scout.rt.client.ui.basic.table.ITableRow;
import org.eclipse.scout.rt.client.ui.basic.table.TableUtility;
@@ -36,17 +34,16 @@ import org.eclipse.scout.rt.ui.swt.basic.ISwtScoutComposite;
import org.eclipse.scout.rt.ui.swt.basic.table.ISwtScoutTable;
import org.eclipse.scout.rt.ui.swt.basic.table.SwtScoutTable;
import org.eclipse.scout.rt.ui.swt.extension.UiDecorationExtensionPoint;
-import org.eclipse.scout.rt.ui.swt.form.ISwtScoutForm;
-import org.eclipse.scout.rt.ui.swt.form.fields.IPopupSupport;
-import org.eclipse.scout.rt.ui.swt.form.fields.IPopupSupport.IPopupSupportListener;
import org.eclipse.scout.rt.ui.swt.keystroke.SwtKeyStroke;
import org.eclipse.scout.rt.ui.swt.util.SwtUtility;
import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.TraverseEvent;
import org.eclipse.swt.events.TraverseListener;
+import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
@@ -57,12 +54,12 @@ import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.Widget;
/**
- * <h3>SwtScoutTableCellEditor</h3> ...
- *
- * @author imo
- * @since 1.0.8 30.06.2010
+ * Editable support for {@link ITable} in SWT-UI.
*/
public class SwtScoutTableCellEditor {
+
+ private static final IScoutLogger LOG = ScoutLogManager.getLogger(SwtScoutTableCellEditor.class);
+
private static final String DUMMY_VALUE = "Dummy";
private final ISwtScoutTable m_tableComposite;
@@ -95,7 +92,7 @@ public class SwtScoutTableCellEditor {
columnPropertyNames[i] = "" + scoutCol.getColumnIndex();
if (scoutCol.isEditable()) {
hasEditors = true;
- newEditors[i] = new P_SwtCellEditor(viewer.getTable());
+ newEditors[i] = new P_SwtCellEditor(viewer.getTable(), scoutCol);
}
}
else {
@@ -121,77 +118,32 @@ public class SwtScoutTableCellEditor {
}
}
- protected Control getEditorControl(Composite parent, ITableRow scoutRow, IColumn<?> scoutCol) {
- //no caching
- Control swtEditorControl = null;
- ISwtScoutComposite<? extends IFormField> editorComposite = createEditorComposite(parent, scoutRow, scoutCol);
- if (editorComposite != null) {
- decorateEditorComposite(editorComposite, scoutRow, scoutCol);
- swtEditorControl = editorComposite.getSwtContainer();
- }
- return swtEditorControl;
- }
-
@SuppressWarnings("unchecked")
- protected ISwtScoutComposite<? extends IFormField> createEditorComposite(Composite parent, final ITableRow scoutRow, final IColumn<?> scoutCol) {
- final AtomicReference<IFormField> fieldRef = new AtomicReference<IFormField>();
- if (scoutRow != null && scoutCol != null) {
- Runnable t = new Runnable() {
- @Override
- public void run() {
- fieldRef.set(m_tableComposite.getScoutObject().getUIFacade().prepareCellEditFromUI(scoutRow, scoutCol));
- synchronized (fieldRef) {
- fieldRef.notifyAll();
- }
- }
- };
- synchronized (fieldRef) {
- m_tableComposite.getEnvironment().invokeScoutLater(t, 2345);
- try {
- fieldRef.wait(2345);
- }
- catch (InterruptedException e) {
- //nop
- }
- }
- }
- IFormField formField = fieldRef.get();
+ protected Control createEditorControl(Composite parent, final ITableRow scoutRow, final IColumn<?> scoutCol) {
+ IFormField formField = createFormField(scoutRow, scoutCol);
if (formField == null) {
return null;
}
ISwtScoutComposite swtScoutFormField;
if (formField instanceof IStringField && ((IStringField) formField).isMultilineText()) {
- // for fields to be presented as popup dialog
- swtScoutFormField = createEditorCompositesPopup(parent, formField, scoutRow, scoutCol);
+ // open a separate Shell to edit the content.
+ swtScoutFormField = createEditorCompositePopup(parent, formField, scoutRow, scoutCol);
}
else {
swtScoutFormField = m_tableComposite.getEnvironment().createFormField(parent, formField);
}
- // If the SWT field uses a @{Shell} to edit its value, the focus on the table gets lost while the shell is open.
- // To prevent the cell editor from being closed, the focus lost listener must be uninstalled for the time the shell is open.
- if (swtScoutFormField instanceof IPopupSupport) {
- ((IPopupSupport) swtScoutFormField).addPopupEventListener(new IPopupSupportListener() {
-
- @Override
- public void handleEvent(int eventType) {
- if (eventType == IPopupSupportListener.TYPE_OPENING) {
- getFocusLostListener().suspend();
- }
- else if (eventType == IPopupSupportListener.TYPE_CLOSED) {
- getFocusLostListener().resume();
- }
- }
- });
+ if (swtScoutFormField != null) {
+ decorateEditorComposite(swtScoutFormField, scoutRow, scoutCol);
+ return swtScoutFormField.getSwtContainer();
+ }
+ else {
+ return null;
}
- return swtScoutFormField;
}
- protected ISwtScoutComposite<? extends IFormField> createEditorCompositesPopup(Composite parent, IFormField formField, final ITableRow scoutRow, final IColumn<?> scoutCol) {
- // uninstall focus lost listener as new shell is used for popup
- getFocusLostListener().suspend();
-
+ protected ISwtScoutComposite<? extends IFormField> createEditorCompositePopup(final Composite parent, IFormField formField, final ITableRow scoutRow, final IColumn<?> scoutCol) {
// overwrite layout properties
GridData gd = formField.getGridData();
gd.h = 1;
@@ -211,18 +163,18 @@ public class SwtScoutTableCellEditor {
prefHeight = Math.max(prefHeight, minHeight);
prefWidth = Math.max(prefWidth, minWidth);
- // create placeholder field to represent the cell editor
- Composite cellEditorComposite = new Composite(parent, SWT.NONE);
+ // Create placeholder field to represent the cell editor
+ final Composite cellEditorComposite = new Composite(parent, SWT.NONE);
- // create popup dialog to wrap the form field
+ // Create popup dialog to wrap the form field
final SwtScoutFormFieldPopup formFieldDialog = new SwtScoutFormFieldPopup(cellEditorComposite);
formFieldDialog.setPrefHeight(prefHeight);
formFieldDialog.setPrefWidth(prefWidth);
formFieldDialog.setMinHeight(minHeight);
formFieldDialog.setMinWidth(minWidth);
- formFieldDialog.createField(parent, formField, m_tableComposite.getEnvironment());
- // register custom cell modifier to touch the field in order to write its value back to the model
+ // == ICellModifier ==
+ // Replace default cell-modifier strategy to touch form-field to be written back to the model.
final ICellModifier defaultCellModifier = m_tableComposite.getSwtTableViewer().getCellModifier();
m_tableComposite.getSwtTableViewer().setCellModifier(new P_SwtCellModifier() {
@@ -233,103 +185,96 @@ public class SwtScoutTableCellEditor {
}
});
- // register custom focus delegate to request the field's focus
+ // == IFocusDelegate ==
+ // Replace default focus handling strategy.
final IFocusDelegate defaultFocusDelegate = cellEditor.getFocusDelegate();
cellEditor.setFocusDelegate(new IFocusDelegate() {
@Override
public void doSetFocus() {
- ISwtScoutForm swtScoutForm = formFieldDialog.getInnerSwtScoutForm();
- if (swtScoutForm != null) {
- requestFocus(swtScoutForm.getSwtContainer());
- }
+ // NOOP: Focus is set the time the Shell is opened.
}
});
- // listener to receive events about the popup's state
- final IFormFieldPopupEventListener popupListener = new IFormFieldPopupEventListener() {
+ // == IFormFieldPopupListener ==
+ // To receive events about the popup's state. The popup is not closed yet but the cell-editor closed.
+ final IFormFieldPopupListener formFieldPopupListener = new IFormFieldPopupListener() {
@Override
- public void handleEvent(FormFieldPopupEvent event) {
- if ((event.getType() & FormFieldPopupEvent.TYPE_OK) > 0) {
- // save cell editor
- cellEditor.stopCellEditing();
+ public void handleEvent(int event) {
+ if ((event & IFormFieldPopupListener.TYPE_OK) > 0) {
+ cellEditor.stopCellEditing(); // save cell editor
}
- else if ((event.getType() & FormFieldPopupEvent.TYPE_CANCEL) > 0) {
- // cancel cell editor
- cellEditor.cancelCellEditing();
+ else if ((event & IFormFieldPopupListener.TYPE_CANCEL) > 0) {
+ cellEditor.cancelCellEditing(); // cancel cell editor
}
// traversal control
- if ((event.getType() & FormFieldPopupEvent.TYPE_FOCUS_BACK) > 0) {
+ if ((event & IFormFieldPopupListener.TYPE_FOCUS_BACK) > 0) {
enqueueEditNextTableCell(scoutRow, scoutCol, false);
}
- else if ((event.getType() & FormFieldPopupEvent.TYPE_FOCUS_NEXT) > 0) {
+ else if ((event & IFormFieldPopupListener.TYPE_FOCUS_NEXT) > 0) {
enqueueEditNextTableCell(scoutRow, scoutCol, true);
}
}
};
- formFieldDialog.addEventListener(popupListener);
+ formFieldDialog.addListener(formFieldPopupListener);
- // register listener to intercept the cell editor's events in order to properly close the popup.
- // This is crucial if the editor is deactivated programmatically or if another cell is activated.
- cellEditor.addDeactivateListener(new IDeactivateListener() {
+ // == DisposeListener ==
+ // To close the Shell if the cell-editor is disposed.
+ cellEditorComposite.addDisposeListener(new DisposeListener() {
@Override
- public void canceled(ColumnViewerEditorDeactivationEvent event) {
- restoreDefault();
- closePopup(FormFieldPopupEvent.TYPE_OK);
- }
+ public void widgetDisposed(DisposeEvent e) {
+ formFieldDialog.removeListener(formFieldPopupListener); // ignore resulting popup events.
- @Override
- public void saved(ColumnViewerEditorDeactivationEvent event) {
- restoreDefault();
- closePopup(FormFieldPopupEvent.TYPE_CANCEL);
- }
-
- private void restoreDefault() {
- // restore default focus delegate
+ // Restore default focus delegate and cell modifier.
cellEditor.setFocusDelegate(defaultFocusDelegate);
- // restore default cell modifier
m_tableComposite.getSwtTableViewer().setCellModifier(defaultCellModifier);
- // remove this listener on the cell editor
- cellEditor.removeDeactivateListener(this);
- }
- private void closePopup(int popupEvent) {
- if (formFieldDialog.isClosed()) {
- return;
- }
- // remove popup listener to not receive events on the dialog's state because the cell editor is already closing
- formFieldDialog.removeEventListener(popupListener);
- // close the popup
- formFieldDialog.closePopup(popupEvent);
+ // Close the popup Shell.
+ // The asyncExec is a workaround so that other cell-editors can be activated immediately.
+ // Note: If being dirty, 'Viewer#refresh()' in TableEx prevents the cell from being activated immediately.
+ e.display.asyncExec(new Runnable() {
+
+ @Override
+ public void run() {
+ formFieldDialog.closePopup();
+ }
+ });
}
});
+ // Open the popup for the form field.
+ formFieldDialog.createField(parent, formField, m_tableComposite.getEnvironment());
+
return formFieldDialog;
}
- private TableColumn getSwtColumn(IColumn<?> scoutCol) {
- for (TableColumn swtCol : m_tableComposite.getSwtTableViewer().getTable().getColumns()) {
- IColumn<?> candidate = (IColumn<?>) swtCol.getData(SwtScoutTable.KEY_SCOUT_COLUMN);
- if (candidate != null && CompareUtility.equals(candidate.getColumnId(), scoutCol.getColumnId())) {
- return swtCol;
- }
+ protected IFormField createFormField(final ITableRow scoutRow, final IColumn<?> scoutCol) {
+ if (scoutRow == null || scoutCol == null) {
+ return null;
}
- return null;
- }
- private int getSwtColumnIndex(TableColumn swtCol) {
- Table table = m_tableComposite.getSwtTableViewer().getTable();
- for (int i = 0; i < table.getColumnCount(); i++) {
- if (table.getColumn(i) == swtCol) {
- return i;
+ final Holder<IFormField> result = new Holder<IFormField>();
+ Runnable t = new Runnable() {
+ @Override
+ public void run() {
+ result.setValue(m_tableComposite.getScoutObject().getUIFacade().prepareCellEditFromUI(scoutRow, scoutCol));
}
+ };
+ try {
+ m_tableComposite.getEnvironment().invokeScoutLater(t, 2345).join(2345);
}
- return -1;
+ catch (InterruptedException e) {
+ LOG.warn("Interrupted while waiting for the Form-Field to be created.", e);
+ }
+ return result.getValue();
}
+ /**
+ * Callback to be overwritten to customize the {@link IFormField}.
+ */
protected void decorateEditorComposite(ISwtScoutComposite<? extends IFormField> editorComposite, final ITableRow scoutRow, final IColumn<?> scoutCol) {
}
@@ -382,26 +327,24 @@ public class SwtScoutTableCellEditor {
return null;
}
- protected P_FocusLostListener getFocusLostListener() {
- return m_focusLostListener;
- }
-
- private boolean requestFocus(Control control) {
- if (control == null || control.isDisposed()) {
- return false;
- }
- if (control.setFocus()) {
- return true;
+ private TableColumn getSwtColumn(IColumn<?> scoutCol) {
+ for (TableColumn swtCol : m_tableComposite.getSwtTableViewer().getTable().getColumns()) {
+ IColumn<?> candidate = (IColumn<?>) swtCol.getData(SwtScoutTable.KEY_SCOUT_COLUMN);
+ if (candidate != null && CompareUtility.equals(candidate.getColumnId(), scoutCol.getColumnId())) {
+ return swtCol;
+ }
}
+ return null;
+ }
- if (control instanceof Composite) {
- for (Control child : ((Composite) control).getChildren()) {
- if (requestFocus(child)) {
- return true;
- }
+ private int getSwtColumnIndex(TableColumn swtCol) {
+ Table table = m_tableComposite.getSwtTableViewer().getTable();
+ for (int i = 0; i < table.getColumnCount(); i++) {
+ if (table.getColumn(i) == swtCol) {
+ return i;
}
}
- return false;
+ return -1;
}
private class P_SwtCellModifier implements ICellModifier {
@@ -422,50 +365,48 @@ public class SwtScoutTableCellEditor {
final ITable table = m_tableComposite.getScoutObject();
final ITableRow row = (ITableRow) element;
final IColumn<?> column = getScoutColumn(property);
- //make a safe model call
- final AtomicBoolean b = new AtomicBoolean();
- synchronized (b) {
- Runnable r = new Runnable() {
- @Override
- public void run() {
- // try first
- synchronized (b) {
- try {
- if (table != null && row != null && column != null) {
- b.set(table.isCellEditable(row, column));
- }
- }
- catch (Throwable ex) {
- //fast access: ignore
- }
- b.notifyAll();
- }
+
+ final BooleanHolder result = new BooleanHolder();
+ Runnable r = new Runnable() {
+ @Override
+ public void run() {
+ if (table != null && row != null && column != null) {
+ result.setValue(table.isCellEditable(row, column));
}
- };
- m_tableComposite.getEnvironment().invokeScoutLater(r, 2345);
- try {
- b.wait(2345);
- }
- catch (InterruptedException e) {
- //nop
}
+ };
+ try {
+ m_tableComposite.getEnvironment().invokeScoutLater(r, 2345).join(2345);
}
- return b.get();
+ catch (InterruptedException e) {
+ LOG.warn("Interrupted while waiting for the model to determine the cell's editability.", e);
+ }
+ return BooleanUtility.nvl(result.getValue(), false);
}
}
+ /**
+ * Statefull per-column cell-editor which is used for all cells of a column.
+ */
private class P_SwtCellEditor extends CellEditor {
private Composite m_container;
private Object m_value;
private ITableRow m_editScoutRow;
- private IColumn<?> m_editScoutCol;
private IFocusDelegate m_focusDelegate;
- private ConcurrentHashMap<IDeactivateListener, Object> m_deactivateListeners;
+ private IColumn<?> m_scoutCol;
+ private ViewerCell m_cell;
+ private Image m_image;
- protected P_SwtCellEditor(Composite parent) {
+ /**
+ * @param parent
+ * the table.
+ * @param scoutCol
+ * the scout column this cell editor is used for.
+ */
+ protected P_SwtCellEditor(Composite parent, IColumn<?> scoutCol) {
super(parent);
+ m_scoutCol = scoutCol;
m_focusDelegate = new P_FocusDelegate();
- m_deactivateListeners = new ConcurrentHashMap<IDeactivateListener, Object>();
}
@Override
@@ -478,16 +419,6 @@ public class SwtScoutTableCellEditor {
public Point computeSize(int wHint, int hHint, boolean changed) {
return new Point(wHint, hHint);
}
-
- @Override
- public void setBounds(Rectangle rect) {
- // ensure the check image is not visible in editor case
- if (m_editScoutCol instanceof IBooleanColumn) {
- rect.x = Math.max(0, rect.x - 16);
- rect.width = Math.max(0, rect.width + 16);
- }
- super.setBounds(rect);
- }
};
m_container.setLayout(new FillLayout());
m_tableComposite.getEnvironment().addKeyStroke(m_container, new SwtKeyStroke(SWT.ESC) {
@@ -518,9 +449,7 @@ public class SwtScoutTableCellEditor {
@Override
protected void doSetFocus() {
- if (m_focusDelegate != null) {
- m_focusDelegate.doSetFocus();
- }
+ m_focusDelegate.doSetFocus();
}
@Override
@@ -535,57 +464,63 @@ public class SwtScoutTableCellEditor {
@Override
public void activate(ColumnViewerEditorActivationEvent e) {
- getFocusLostListener().install();
- getFocusLostListener().suspend(); // is only resumed if editor gets the focus in @{link P_SwtCellEditor#doSetFocus()}. Otherwise, a focus lost event might be consumed and the editor closed
+ // Install a focus-lost listener on the table widget to close an active cell-editor when the table looses the focus.
+ m_focusLostListener.install();
- m_editScoutRow = null;
- m_editScoutCol = null;
- if (e.getSource() instanceof ViewerCell) {
- ViewerCell cell = (ViewerCell) e.getSource();
- TableViewer viewer = m_tableComposite.getSwtTableViewer();
- TableColumn swtCol = viewer.getTable().getColumn(cell.getColumnIndex());
- IColumn<?> scoutCol = (IColumn<?>) swtCol.getData(SwtScoutTable.KEY_SCOUT_COLUMN);
- ITableRow scoutRow = (ITableRow) cell.getElement();
- //no edit on boolean column when mouse was clicked
+ if (!(e.getSource() instanceof ViewerCell)) {
+ return;
+ }
+
+ m_cell = (ViewerCell) e.getSource();
+ m_editScoutRow = (ITableRow) m_cell.getElement();
+
+ if (m_scoutCol instanceof IBooleanColumn) {
if (e.sourceEvent instanceof MouseEvent) {
- if (scoutCol instanceof IBooleanColumn) {
- return;
- }
+ return; // no edit-mode when a boolean cell was clicked by mouse.
}
- if (scoutRow != null && scoutCol != null) {
- m_editScoutRow = scoutRow;
- m_editScoutCol = scoutCol;
- @SuppressWarnings("unused")
- Control control = getEditorControl(m_container, scoutRow, scoutCol);
+ else {
+ // hide the checkbox image when editing a boolean value in traversal-mode.
+ m_image = m_cell.getImage();
+ m_cell.setImage(null);
}
- m_container.layout(true, true);
- m_container.setVisible(true);
}
+
+ // create the cell editor widget.
+ if (m_editScoutRow != null) {
+ createEditorControl(m_container, m_editScoutRow, m_scoutCol);
+ }
+
+ m_container.layout(true, true);
+ m_container.setVisible(true);
}
@Override
protected void deactivate(ColumnViewerEditorDeactivationEvent e) {
- getFocusLostListener().uninstall();
-
- // notify cell editor deactivate listeners
- for (IDeactivateListener listener : m_deactivateListeners.keySet()) {
- if (e.eventType == ColumnViewerEditorDeactivationEvent.EDITOR_SAVED) {
- listener.saved(e);
- }
- else {
- listener.canceled(e);
- }
+ // restore the cell's image if being unset in CellEditor#activate.
+ if (m_cell != null && m_image != null) {
+ m_cell.setImage(m_image);
}
+ m_cell = null;
+ m_image = null;
m_editScoutRow = null;
- m_editScoutCol = null;
+
+ // Dispose the cell-editor; in turn, any Shell opened by the editor is closed as well.
for (Control c : m_container.getChildren()) {
c.dispose();
}
- super.deactivate(e);
if (e.eventType == ColumnViewerEditorDeactivationEvent.EDITOR_CANCELED) {
cancelEditorFromSwt();
}
+
+ super.deactivate(e);
+
+ m_focusLostListener.uninstall();
+ }
+
+ @Override
+ protected boolean dependsOnExternalFocusListener() {
+ return false;
}
public void stopCellEditing() {
@@ -606,19 +541,13 @@ public class SwtScoutTableCellEditor {
m_focusDelegate = focusDelegate;
}
- public void addDeactivateListener(IDeactivateListener listener) {
- m_deactivateListeners.put(listener, new Object());
- }
-
- public void removeDeactivateListener(IDeactivateListener listener) {
- m_deactivateListeners.remove(listener);
- }
-
private class P_FocusDelegate implements IFocusDelegate {
@Override
public void doSetFocus() {
+ // traverse the focus to the cell editor's control so that the user can start editing immediately without having to click into the widget first.
m_container.traverse(SWT.TRAVERSE_TAB_NEXT);
+
Control focusControl = m_container.getDisplay().getFocusControl();
if (focusControl != null && SwtUtility.isAncestorOf(m_container, focusControl)) {
focusControl.addTraverseListener(new TraverseListener() {
@@ -632,27 +561,24 @@ public class SwtScoutTableCellEditor {
}
case SWT.TRAVERSE_TAB_NEXT: {
e.doit = false;
- ITableRow scoutRow = m_editScoutRow;
- IColumn<?> scoutCol = m_editScoutCol;
+ ITableRow currentScoutRow = m_editScoutRow; // memorize the current row because being set to null when the cell editor is deactivated.
fireApplyEditorValue();
deactivate();
- enqueueEditNextTableCell(scoutRow, scoutCol, true);
+ enqueueEditNextTableCell(currentScoutRow, m_scoutCol, true); // traverse the focus to the next editable cell.
break;
}
case SWT.TRAVERSE_TAB_PREVIOUS: {
e.doit = false;
- ITableRow scoutRow = m_editScoutRow;
- IColumn<?> scoutCol = m_editScoutCol;
+ ITableRow currentScoutRow = m_editScoutRow; // memorize the current row because being set to null when the cell editor is deactivated.
fireApplyEditorValue();
deactivate();
- enqueueEditNextTableCell(scoutRow, scoutCol, false);
+ enqueueEditNextTableCell(currentScoutRow, m_scoutCol, false); // traverse the focus to the next editable cell.
break;
}
}
}
});
}
- getFocusLostListener().resume(); // because listener was suspended after activation
}
}
}
@@ -663,115 +589,73 @@ public class SwtScoutTableCellEditor {
*/
private class P_FocusLostListener implements Listener {
- private final Lock m_suspendLock = new ReentrantLock();
- private AtomicInteger m_suspendCounter = new AtomicInteger();
-
/**
- * Uninstalls this listener on the table widget
- */
- public void uninstall() {
- m_tableComposite.getEnvironment().getDisplay().removeFilter(SWT.FocusIn, this);
- m_suspendCounter.set(0);
- }
-
- /**
- * Installs this listener on the table widget
+ * Installs listening for focus-lost events on the table widget.
*/
public void install() {
m_tableComposite.getEnvironment().getDisplay().addFilter(SWT.FocusIn, this);
- m_suspendCounter.set(0);
}
/**
- * <p>
- * To resume listening for focus lost events.
- * </p>
- * <p>
- * Please note that this request is put onto a stack meaning that you have to call
- * {@link P_FocusLostListener#resume()} as many times as you called {@link P_FocusLostListener#suspend()} to resume
- * listening for focus lost events.
- * </p>
- * <p>
- * <small>Counterpart of {@link P_FocusLostListener#suspend()}.</small>
- * </p>
+ * Uninstalls listening for focus-lost events on the table widget.
*/
- public void resume() {
- m_suspendLock.lock();
- try {
- if (m_suspendCounter.decrementAndGet() < 0) { // negative values are not allowed
- m_suspendCounter.set(0);
- }
- }
- finally {
- m_suspendLock.unlock();
- }
- }
-
- /**
- * <p>
- * To suspend listening for focus lost events.
- * </p>
- * <p>
- * Please note that this request is put onto a stack meaning that you have to call
- * {@link P_FocusLostListener#resume()} as many times as you called {@link P_FocusLostListener#suspend()} to resume
- * listening for focus lost events.
- * </p>
- * <p>
- * <small>Counterpart of {@link P_FocusLostListener#resume()}.</small>
- * </p>
- */
- public void suspend() {
- m_suspendLock.lock();
- try {
- m_suspendCounter.incrementAndGet();
- }
- finally {
- m_suspendLock.unlock();
- }
- }
-
- public boolean isSuspended() {
- return m_suspendCounter.get() > 0;
+ public void uninstall() {
+ m_tableComposite.getEnvironment().getDisplay().removeFilter(SWT.FocusIn, this);
}
@Override
public void handleEvent(Event event) {
- if (isSuspended()) {
- return;
- }
-
Widget w = event.widget;
if (w == null || !(w instanceof Control) || w.isDisposed()) {
return;
}
+
+ // Sanity check whether a cell-editor is active.
TableViewer viewer = m_tableComposite.getSwtTableViewer();
if (!viewer.isCellEditorActive()) {
return;
}
- Control candidate = (Control) w;
- Control tableControl = m_tableComposite.getSwtTableViewer().getControl();
+ Control focusOwner = (Control) w;
+ Table table = m_tableComposite.getSwtTableViewer().getTable();
+
+ // Check if the table is the focus owner.
+ if (SwtUtility.isAncestorOf(table, focusOwner)) {
+ return;
+ }
- if (!SwtUtility.isAncestorOf(tableControl, candidate)) {
- for (CellEditor editor : viewer.getCellEditors()) {
- if (editor != null && editor.isActivated() && editor instanceof P_SwtCellEditor) {
- ((P_SwtCellEditor) editor).stopCellEditing();
- break;
+ // Check if a Shell opened by the cell-editor is the focus owner.
+ if (focusOwner.getShell() != table.getShell()) {
+ Composite parentFocusOwner = focusOwner.getShell().getParent();
+ while (parentFocusOwner != null) {
+ if (parentFocusOwner.getShell() == table.getShell()) {
+ return; // focus owner is a derrived Shell.
+ }
+ else {
+ parentFocusOwner = parentFocusOwner.getShell().getParent();
}
}
}
+
+ // Close the cell-editor because a control other than the table is focus owner.
+ for (CellEditor editor : viewer.getCellEditors()) {
+ if (editor != null && editor.isActivated() && editor instanceof P_SwtCellEditor) {
+ ((P_SwtCellEditor) editor).stopCellEditing();
+ break;
+ }
+ }
}
}
/**
- * Delegate to process focus events on cell editor
+ * Delegate to process focus events on cell editor.
*/
private interface IFocusDelegate {
void doSetFocus();
}
/**
- * Listener to get notified about deactivation event
+ * Listener to get notified about deactivation events.
*/
private interface IDeactivateListener {
void canceled(ColumnViewerEditorDeactivationEvent event);
diff --git a/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/form/fields/IPopupSupport.java b/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/form/fields/IPopupSupport.java
deleted file mode 100644
index 675b325660..0000000000
--- a/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/form/fields/IPopupSupport.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2010 BSI Business Systems Integration AG.
- * 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:
- * BSI Business Systems Integration AG - initial API and implementation
- ******************************************************************************/
-package org.eclipse.scout.rt.ui.swt.form.fields;
-
-/**
- * Fields that open popup dialogs to edit their value (e.g.
- * {@link org.eclipse.scout.rt.ui.swt.form.fields.datefield.SwtScoutDateField SwtScoutDateField},
- * {@link org.eclipse.scout.rt.ui.swt.form.fields.datefield.SwtScoutTimeField SwtScoutTimeField},
- * {@link org.eclipse.scout.rt.ui.swt.form.fields.smartfield.SwtScoutSmartField SwtScoutSmartField}) should implement
- * this interface. This allows listeners to be
- * notified about the popup state. Especially, this is crucial if the field is used inline within an editable table
- * to handle focus-lost events properly (see
- * {@link org.eclipse.scout.rt.ui.swt.basic.table.celleditor.SwtScoutTableCellEditor.P_FocusLostListener
- * SwtScoutTableCellEditor.P_FocusLostListener}).
- */
-public interface IPopupSupport {
-
- /**
- * To register a listener to receive events about the popup state
- *
- * @param listener
- */
- void addPopupEventListener(IPopupSupportListener listener);
-
- void removePopupEventListener(IPopupSupportListener listener);
-
- interface IPopupSupportListener {
-
- /**
- * the popup is opening but not yet open
- */
- int TYPE_OPENING = 1 << 1;
- /**
- * the popup is closed
- */
- int TYPE_CLOSED = 1 << 2;
-
- void handleEvent(int eventType);
- }
-}
diff --git a/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/form/fields/datefield/SwtScoutDateField.java b/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/form/fields/datefield/SwtScoutDateField.java
index 6144b8cfdf..92704a683e 100644
--- a/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/form/fields/datefield/SwtScoutDateField.java
+++ b/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/form/fields/datefield/SwtScoutDateField.java
@@ -14,8 +14,6 @@ import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.text.DateFormat;
import java.util.Date;
-import java.util.HashSet;
-import java.util.Set;
import org.eclipse.scout.commons.CompareUtility;
import org.eclipse.scout.commons.holders.Holder;
@@ -29,7 +27,6 @@ import org.eclipse.scout.rt.ui.swt.action.menu.SwtContextMenuMarkerComposite;
import org.eclipse.scout.rt.ui.swt.action.menu.SwtScoutContextMenu;
import org.eclipse.scout.rt.ui.swt.action.menu.text.StyledTextAccess;
import org.eclipse.scout.rt.ui.swt.ext.StatusLabelEx;
-import org.eclipse.scout.rt.ui.swt.form.fields.IPopupSupport;
import org.eclipse.scout.rt.ui.swt.form.fields.LogicalGridDataBuilder;
import org.eclipse.scout.rt.ui.swt.form.fields.SwtScoutBasicFieldComposite;
import org.eclipse.scout.rt.ui.swt.form.fields.datefield.chooser.DateChooserDialog;
@@ -49,7 +46,7 @@ import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
-public class SwtScoutDateField extends SwtScoutBasicFieldComposite<IDateField> implements ISwtScoutDateField, IPopupSupport {
+public class SwtScoutDateField extends SwtScoutBasicFieldComposite<IDateField> implements ISwtScoutDateField {
public static final int TYPE_TIME_CHOOSER = 1;
public static final int TYPE_DATE_CHOOSER = 2;
@@ -58,16 +55,11 @@ public class SwtScoutDateField extends SwtScoutBasicFieldComposite<IDateField> i
private boolean m_hasTime;
private TextFieldEditableSupport m_editableSupport;
- private Set<IPopupSupportListener> m_popupEventListeners;
- private Object m_popupEventListenerLock;
private SwtContextMenuMarkerComposite m_menuMarkerComposite;
private SwtScoutContextMenu m_contextMenu;
@Override
protected void initializeSwt(Composite parent) {
- m_popupEventListeners = new HashSet<IPopupSupportListener>();
- m_popupEventListenerLock = new Object();
-
Composite container = getEnvironment().getFormToolkit().createComposite(parent);
StatusLabelEx label = getEnvironment().getFormToolkit().createStatusLabel(container, getEnvironment(), getScoutObject());
@@ -268,37 +260,12 @@ public class SwtScoutDateField extends SwtScoutBasicFieldComposite<IDateField> i
getSwtField().setSelection(0, 0);
}
- private void notifyPopupEventListeners(int eventType) {
- IPopupSupportListener[] listeners;
- synchronized (m_popupEventListenerLock) {
- listeners = m_popupEventListeners.toArray(new IPopupSupportListener[m_popupEventListeners.size()]);
- }
- for (IPopupSupportListener listener : listeners) {
- listener.handleEvent(eventType);
- }
- }
-
- @Override
- public void addPopupEventListener(IPopupSupportListener listener) {
- synchronized (m_popupEventListenerLock) {
- m_popupEventListeners.add(listener);
- }
- }
-
- @Override
- public void removePopupEventListener(IPopupSupportListener listener) {
- synchronized (m_popupEventListenerLock) {
- m_popupEventListeners.remove(listener);
- }
- }
-
private void handleSwtDateChooserAction() {
if (getDateChooserButton().isVisible() && getDateChooserButton().isEnabled()) {
Date oldDate = getScoutObject().getValue();
if (oldDate == null) {
oldDate = new Date();
}
- notifyPopupEventListeners(IPopupSupportListener.TYPE_OPENING);
try {
DateChooserDialog dialog = new DateChooserDialog(getSwtField().getShell(), oldDate, getEnvironment());
final Date newDate = dialog.openDateChooser(getSwtField());
@@ -316,7 +283,6 @@ public class SwtScoutDateField extends SwtScoutBasicFieldComposite<IDateField> i
}
}
finally {
- notifyPopupEventListeners(IPopupSupportListener.TYPE_CLOSED);
if (!getSwtField().isDisposed()) {
getSwtField().setFocus();
}
@@ -330,7 +296,6 @@ public class SwtScoutDateField extends SwtScoutBasicFieldComposite<IDateField> i
if (d == null) {
d = new Date();
}
- notifyPopupEventListeners(IPopupSupportListener.TYPE_OPENING);
try {
TimeChooserDialog dialog = new TimeChooserDialog(getSwtField().getShell(), d, getEnvironment());
Date newDate = dialog.openDateChooser(getSwtField());
@@ -340,7 +305,6 @@ public class SwtScoutDateField extends SwtScoutBasicFieldComposite<IDateField> i
}
}
finally {
- notifyPopupEventListeners(IPopupSupportListener.TYPE_CLOSED);
if (!getSwtField().isDisposed()) {
getSwtField().setFocus();
}
diff --git a/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/form/fields/datefield/SwtScoutTimeField.java b/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/form/fields/datefield/SwtScoutTimeField.java
index ebea2c4568..b08d4bc100 100644
--- a/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/form/fields/datefield/SwtScoutTimeField.java
+++ b/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/form/fields/datefield/SwtScoutTimeField.java
@@ -12,8 +12,6 @@ package org.eclipse.scout.rt.ui.swt.form.fields.datefield;
import java.text.DateFormat;
import java.util.Date;
-import java.util.HashSet;
-import java.util.Set;
import org.eclipse.scout.commons.CompareUtility;
import org.eclipse.scout.commons.holders.Holder;
@@ -22,7 +20,6 @@ import org.eclipse.scout.rt.client.ui.form.fields.datefield.IDateField;
import org.eclipse.scout.rt.shared.AbstractIcons;
import org.eclipse.scout.rt.ui.swt.LogicalGridLayout;
import org.eclipse.scout.rt.ui.swt.ext.StatusLabelEx;
-import org.eclipse.scout.rt.ui.swt.form.fields.IPopupSupport;
import org.eclipse.scout.rt.ui.swt.form.fields.LogicalGridDataBuilder;
import org.eclipse.scout.rt.ui.swt.form.fields.SwtScoutBasicFieldComposite;
import org.eclipse.scout.rt.ui.swt.form.fields.datefield.chooser.TimeChooserDialog;
@@ -38,18 +35,12 @@ import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
-public class SwtScoutTimeField extends SwtScoutBasicFieldComposite<IDateField> implements ISwtScoutTimeField, IPopupSupport {
+public class SwtScoutTimeField extends SwtScoutBasicFieldComposite<IDateField> implements ISwtScoutTimeField {
private Button m_timeChooserButton;
private TextFieldEditableSupport m_editableSupport;
- private Set<IPopupSupportListener> m_popupEventListeners;
- private Object m_popupEventListenerLock;
-
@Override
protected void initializeSwt(Composite parent) {
- m_popupEventListeners = new HashSet<IPopupSupportListener>();
- m_popupEventListenerLock = new Object();
-
Composite container = getEnvironment().getFormToolkit().createComposite(parent);
StatusLabelEx label = getEnvironment().getFormToolkit().createStatusLabel(container, getEnvironment(), getScoutObject());
@@ -194,7 +185,6 @@ public class SwtScoutTimeField extends SwtScoutBasicFieldComposite<IDateField> i
if (d == null) {
d = new Date();
}
- notifyPopupEventListeners(IPopupSupportListener.TYPE_OPENING);
try {
TimeChooserDialog dialog = new TimeChooserDialog(getSwtField().getShell(), d, getEnvironment());
Date newDate = dialog.openDateChooser(getSwtField());
@@ -204,7 +194,6 @@ public class SwtScoutTimeField extends SwtScoutBasicFieldComposite<IDateField> i
}
}
finally {
- notifyPopupEventListeners(IPopupSupportListener.TYPE_CLOSED);
if (!getSwtField().isDisposed()) {
getSwtField().setFocus();
}
@@ -212,30 +201,6 @@ public class SwtScoutTimeField extends SwtScoutBasicFieldComposite<IDateField> i
}
}
- private void notifyPopupEventListeners(int eventType) {
- IPopupSupportListener[] listeners;
- synchronized (m_popupEventListenerLock) {
- listeners = m_popupEventListeners.toArray(new IPopupSupportListener[m_popupEventListeners.size()]);
- }
- for (IPopupSupportListener listener : listeners) {
- listener.handleEvent(eventType);
- }
- }
-
- @Override
- public void addPopupEventListener(IPopupSupportListener listener) {
- synchronized (m_popupEventListenerLock) {
- m_popupEventListeners.add(listener);
- }
- }
-
- @Override
- public void removePopupEventListener(IPopupSupportListener listener) {
- synchronized (m_popupEventListenerLock) {
- m_popupEventListeners.remove(listener);
- }
- }
-
private class P_SwtBrowseButtonListener extends SelectionAdapter {
@Override
public void widgetSelected(SelectionEvent e) {
diff --git a/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/form/fields/smartfield/SwtScoutSmartField.java b/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/form/fields/smartfield/SwtScoutSmartField.java
index 79a7e832cf..6f76b4ed85 100644
--- a/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/form/fields/smartfield/SwtScoutSmartField.java
+++ b/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/form/fields/smartfield/SwtScoutSmartField.java
@@ -12,8 +12,6 @@ package org.eclipse.scout.rt.ui.swt.form.fields.smartfield;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
-import java.util.HashSet;
-import java.util.Set;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
@@ -30,27 +28,21 @@ import org.eclipse.scout.rt.client.ui.form.FormListener;
import org.eclipse.scout.rt.client.ui.form.fields.IFormField;
import org.eclipse.scout.rt.client.ui.form.fields.smartfield.IContentAssistField;
import org.eclipse.scout.rt.client.ui.form.fields.smartfield.IContentAssistFieldProposalForm;
+import org.eclipse.scout.rt.client.ui.form.fields.smartfield.ISmartField;
import org.eclipse.scout.rt.ui.swt.LogicalGridLayout;
import org.eclipse.scout.rt.ui.swt.action.menu.SwtContextMenuMarkerComposite;
import org.eclipse.scout.rt.ui.swt.action.menu.SwtScoutContextMenu;
import org.eclipse.scout.rt.ui.swt.action.menu.text.StyledTextAccess;
import org.eclipse.scout.rt.ui.swt.ext.StatusLabelEx;
-import org.eclipse.scout.rt.ui.swt.form.fields.IPopupSupport;
import org.eclipse.scout.rt.ui.swt.form.fields.LogicalGridDataBuilder;
import org.eclipse.scout.rt.ui.swt.form.fields.SwtScoutValueFieldComposite;
import org.eclipse.scout.rt.ui.swt.internal.TextFieldEditableSupport;
import org.eclipse.scout.rt.ui.swt.keystroke.SwtKeyStroke;
import org.eclipse.scout.rt.ui.swt.util.SwtLayoutUtility;
import org.eclipse.scout.rt.ui.swt.util.SwtUtility;
-import org.eclipse.scout.rt.ui.swt.window.SwtScoutPartEvent;
-import org.eclipse.scout.rt.ui.swt.window.SwtScoutPartListener;
import org.eclipse.scout.rt.ui.swt.window.popup.SwtScoutDropDownPopup;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyledText;
-import org.eclipse.swt.events.FocusAdapter;
-import org.eclipse.swt.events.FocusEvent;
-import org.eclipse.swt.events.MouseAdapter;
-import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.ShellAdapter;
@@ -61,15 +53,14 @@ import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Table;
+
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.Widget;
/**
- * <h3>SwtScoutSmartField</h3> ...
- *
- * @since 1.0.0 10.04.2008
+ * Implementation of the {@link ISmartField} in SWT-UI.
*/
-public class SwtScoutSmartField extends SwtScoutValueFieldComposite<IContentAssistField<?, ?>> implements ISwtScoutSmartField, IPopupSupport {
+public class SwtScoutSmartField extends SwtScoutValueFieldComposite<IContentAssistField<?, ?>> implements ISwtScoutSmartField {
private static final IScoutLogger LOG = ScoutLogManager.getLogger(SwtScoutSmartField.class);
private Button m_browseButton;
@@ -80,9 +71,6 @@ public class SwtScoutSmartField extends SwtScoutValueFieldComposite<IContentAssi
private final Object m_popupLock = new Object();
private TextFieldEditableSupport m_editableSupport;
- private Set<IPopupSupportListener> m_popupEventListeners;
- private Object m_popupEventListenerLock;
-
private SwtContextMenuMarkerComposite m_menuMarkerComposite;
private SwtScoutContextMenu m_contextMenu;
@@ -92,9 +80,6 @@ public class SwtScoutSmartField extends SwtScoutValueFieldComposite<IContentAssi
@Override
protected void initializeSwt(Composite parent) {
- m_popupEventListeners = new HashSet<IPopupSupportListener>();
- m_popupEventListenerLock = new Object();
-
Composite container = getEnvironment().getFormToolkit().createComposite(parent);
StatusLabelEx label = getEnvironment().getFormToolkit().createStatusLabel(container, getEnvironment(), getScoutObject());
@@ -107,30 +92,16 @@ public class SwtScoutSmartField extends SwtScoutValueFieldComposite<IContentAssi
m_contextMenu.getSwtMenu().setVisible(true);
}
});
- StyledText textField = getEnvironment().getFormToolkit().createStyledText(m_menuMarkerComposite, SWT.SINGLE);
+ final StyledText textField = getEnvironment().getFormToolkit().createStyledText(m_menuMarkerComposite, SWT.SINGLE);
textField.setAlignment(SwtUtility.getHorizontalAlignment(getScoutObject().getGridData().horizontalAlignment));
textField.setMargins(2, 2, 2, 2);
textField.setWrapIndent(textField.getIndent());
m_browseButton = getEnvironment().getFormToolkit().createButton(container, "", SWT.PUSH);
- // to ensure the text is validated on a context menu call this mouse
- // listener is used.
- m_browseButton.addMouseListener(new MouseAdapter() {
- @Override
- public void mouseDown(MouseEvent e) {
- handleSwtInputVerifier();
- }
-
- @Override
- public void mouseUp(MouseEvent e) {
- if (e.button == 1) {
- handleSwtBrowseAction();
- }
- }
- });
- m_browseButton.addFocusListener(new FocusAdapter() {
+ m_browseButton.addSelectionListener(new SelectionAdapter() {
@Override
- public void focusGained(FocusEvent e) {
- getSwtField().setFocus();
+ public void widgetSelected(SelectionEvent e) {
+ textField.setFocus(); // make the textfield the focus owner so that the user can immediately start narrowing the search.
+ handleSwtBrowseAction();
}
});
@@ -309,29 +280,14 @@ public class SwtScoutSmartField extends SwtScoutValueFieldComposite<IContentAssi
// show new
if (form != null) {
if (getSwtField().isFocusControl()) {
- m_proposalPopup = new SwtScoutDropDownPopup(getEnvironment(), getSwtField(), getSwtField(), SWT.RESIZE);
+ m_proposalPopup = new SwtScoutDropDownPopup(getEnvironment(), getSwtField(), false, SWT.RESIZE);
m_proposalPopup.setMaxHeightHint(getScoutObject().getProposalFormHeight());
- m_proposalPopup.addSwtScoutPartListener(new SwtScoutPartListener() {
+ m_proposalPopup.addShellListener(new ShellAdapter() {
+
@Override
- public void partChanged(SwtScoutPartEvent e) {
- switch (e.getType()) {
- case SwtScoutPartEvent.TYPE_OPENING: {
- notifyPopupEventListeners(IPopupSupportListener.TYPE_OPENING);
- break;
- }
- case SwtScoutPartEvent.TYPE_CLOSING: {
- hideProposalPopup();
- break;
- }
- case SwtScoutPartEvent.TYPE_CLOSED: {
- if (m_proposalPopup != null) {
- m_proposalPopup = null;
- notifyPopupEventListeners(IPopupSupportListener.TYPE_CLOSED);
- }
- break;
- }
- }
+ public void shellDeactivated(ShellEvent e) {
+ hideProposalPopup(); // Hide the proposal popup if being the active Shell and the user activated another Shell (e.g. the owner Shell or switched the application).
}
});
m_proposalPopup.getShell().addShellListener(new ShellAdapter() {
@@ -340,41 +296,36 @@ public class SwtScoutSmartField extends SwtScoutValueFieldComposite<IContentAssi
e.doit = false;
}
});
- m_proposalPopup.makeNonFocusable();
- try {
- //add a listener whenever the form changes
- m_proposalPopup.showForm(form);
- form.addFormListener(new FormListener() {
- @Override
- public void formChanged(FormEvent e) throws ProcessingException {
- switch (e.getType()) {
- case FormEvent.TYPE_STRUCTURE_CHANGED:
- Runnable job = new Runnable() {
- @Override
- public void run() {
- if (m_proposalPopup != null) {
- m_proposalPopup.autoAdjustBounds();
- }
+ m_proposalPopup.showForm(form);
+
+ //add a listener whenever the form changes
+ form.addFormListener(new FormListener() {
+ @Override
+ public void formChanged(FormEvent e) throws ProcessingException {
+ switch (e.getType()) {
+ case FormEvent.TYPE_STRUCTURE_CHANGED:
+ Runnable job = new Runnable() {
+ @Override
+ public void run() {
+ if (m_proposalPopup != null) {
+ m_proposalPopup.autoAdjustBounds();
}
- };
- getEnvironment().invokeSwtLater(job);
- break;
- }
+ }
+ };
+ getEnvironment().invokeSwtLater(job);
+ break;
}
- });
- //enqueue a later display job since there may be waiting display tasks in the queue that change the table/tree
- getSwtField().getDisplay().asyncExec(new Runnable() {
- @Override
- public void run() {
- if (m_proposalPopup != null) {
- m_proposalPopup.autoAdjustBounds();
- }
+ }
+ });
+ //enqueue a later display job since there may be waiting display tasks in the queue that change the table/tree
+ getSwtField().getDisplay().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ if (m_proposalPopup != null) {
+ m_proposalPopup.autoAdjustBounds();
}
- });
- }
- catch (ProcessingException e1) {
- LOG.error(e1.getMessage(), e1);
- }
+ }
+ });
}
else {
Runnable t = new Runnable() {
@@ -385,7 +336,7 @@ public class SwtScoutSmartField extends SwtScoutValueFieldComposite<IContentAssi
form.doClose();
}
catch (ProcessingException e) {
- LOG.error("could not close smartfield-form", e);
+ LOG.error("Failed to close smartfield form.", e);
}
}
};
@@ -550,10 +501,10 @@ public class SwtScoutSmartField extends SwtScoutValueFieldComposite<IContentAssi
else {
Widget c = null;
if (c == null) {
- c = SwtUtility.findChildComponent(m_proposalPopup.getSwtContentPane(), Table.class);
+ c = SwtUtility.findChildComponent(m_proposalPopup.getShellContentPane(), Table.class);
}
if (c == null) {
- c = SwtUtility.findChildComponent(m_proposalPopup.getSwtContentPane(), Tree.class);
+ c = SwtUtility.findChildComponent(m_proposalPopup.getShellContentPane(), Tree.class);
}
SwtUtility.handleNavigationKey(c, event.keyCode);
}
@@ -572,30 +523,6 @@ public class SwtScoutSmartField extends SwtScoutValueFieldComposite<IContentAssi
}
}
- private void notifyPopupEventListeners(int eventType) {
- IPopupSupportListener[] listeners;
- synchronized (m_popupEventListenerLock) {
- listeners = m_popupEventListeners.toArray(new IPopupSupportListener[m_popupEventListeners.size()]);
- }
- for (IPopupSupportListener listener : listeners) {
- listener.handleEvent(eventType);
- }
- }
-
- @Override
- public void addPopupEventListener(IPopupSupportListener listener) {
- synchronized (m_popupEventListenerLock) {
- m_popupEventListeners.add(listener);
- }
- }
-
- @Override
- public void removePopupEventListener(IPopupSupportListener listener) {
- synchronized (m_popupEventListenerLock) {
- m_popupEventListeners.remove(listener);
- }
- }
-
private class P_UiFieldListener implements Listener {
@Override
diff --git a/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/window/SwtScoutPartEvent.java b/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/window/SwtScoutPartEvent.java
deleted file mode 100644
index 89d4ca96ed..0000000000
--- a/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/window/SwtScoutPartEvent.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2010 BSI Business Systems Integration AG.
- * 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:
- * BSI Business Systems Integration AG - initial API and implementation
- ******************************************************************************/
-package org.eclipse.scout.rt.ui.swt.window;
-
-import java.util.EventObject;
-
-public class SwtScoutPartEvent extends EventObject {
- private static final long serialVersionUID = 1L;
-
- /**
- * the part is opening but not yet open
- */
- public static final int TYPE_OPENING = 10;
-
- /**
- * the part is open but not yet active
- */
- public static final int TYPE_OPENED = 20;
- /**
- * the part is active
- */
- public static final int TYPE_ACTIVATED = 30;
- /**
- * the part is requesting closing but remains open
- */
- public static final int TYPE_CLOSING = 40;
- /**
- * the part is closed
- */
- public static final int TYPE_CLOSED = 50;
-
- private int m_type;
-
- public boolean doit = true;
-
- public SwtScoutPartEvent(ISwtScoutPart source, int type) {
- super(source);
- m_type = type;
- }
-
- public int getType() {
- return m_type;
- }
-
-}
diff --git a/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/window/SwtScoutPartListener.java b/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/window/SwtScoutPartListener.java
deleted file mode 100644
index 4084ca41ed..0000000000
--- a/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/window/SwtScoutPartListener.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2010 BSI Business Systems Integration AG.
- * 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:
- * BSI Business Systems Integration AG - initial API and implementation
- ******************************************************************************/
-package org.eclipse.scout.rt.ui.swt.window;
-
-import java.util.EventListener;
-
-/**
- * This observer runs in the swt thread
- */
-public interface SwtScoutPartListener extends EventListener {
-
- void partChanged(SwtScoutPartEvent e);
-
-}
diff --git a/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/window/popup/SwtScoutDropDownPopup.java b/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/window/popup/SwtScoutDropDownPopup.java
index 9f06014c09..0f6da0334c 100644
--- a/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/window/popup/SwtScoutDropDownPopup.java
+++ b/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/window/popup/SwtScoutDropDownPopup.java
@@ -10,41 +10,49 @@
******************************************************************************/
package org.eclipse.scout.rt.ui.swt.window.popup;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
import org.eclipse.scout.commons.logger.IScoutLogger;
import org.eclipse.scout.commons.logger.ScoutLogManager;
import org.eclipse.scout.rt.ui.swt.DefaultValidateRoot;
import org.eclipse.scout.rt.ui.swt.ISwtEnvironment;
import org.eclipse.scout.rt.ui.swt.IValidateRoot;
-import org.eclipse.scout.rt.ui.swt.window.ISwtScoutPart;
-import org.eclipse.scout.rt.ui.swt.window.SwtScoutPartEvent;
import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.FocusAdapter;
-import org.eclipse.swt.events.FocusEvent;
-import org.eclipse.swt.events.FocusListener;
-import org.eclipse.swt.events.MouseAdapter;
-import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.ScrollBar;
+import org.eclipse.swt.widgets.Shell;
/**
- * Popup window bound to a component (ownerComponent). The popup closes when
- * there is either a click outside this window or the component loses focus
- * (focusComponent), or the component becomes invisible.
+ * <p>
+ * Popup window bound to a {@link Control}.
+ * </p>
+ * Additionaly, a {@link SWT#Dispose}-event is fired when the {@link Control ownerComponent} or one of its ancestors is
+ * being scrolled, resized or moved.
*/
public class SwtScoutDropDownPopup extends SwtScoutPopup {
+
private static final IScoutLogger LOG = ScoutLogManager.getLogger(SwtScoutDropDownPopup.class);
- private Composite m_focusComponent;
- private FocusListener m_focusComponentListener;
- private boolean m_nonFocusable;
- private P_ScrollBarListener m_scrollbarListener;
+ private final Listener m_viewPortChangedListener = new P_ViewPortChangedListener();
+ private Set<ScrollBar> scrollBars;
- public SwtScoutDropDownPopup(ISwtEnvironment env, Control ownerComponent, Composite focusComponent, int style) {
- super(env, ownerComponent, ownerComponent.getBounds(), style);
- m_focusComponent = focusComponent;
+ /**
+ * @param env
+ * {@link ISwtEnvironment}.
+ * @param ownerComponent
+ * the {@link Control} the popup is bound to.
+ * @param takeFocusOnOpen
+ * A boolean indicating whether focus should be taken by this popup when it opens.
+ * @param style
+ * the style of control to construct
+ */
+ public SwtScoutDropDownPopup(ISwtEnvironment env, Control ownerComponent, boolean takeFocusOnOpen, int style) {
+ super(env, ownerComponent, takeFocusOnOpen, style);
getShell().setData(IValidateRoot.VALIDATE_ROOT_DATA, new DefaultValidateRoot(getShell()) {
@Override
@@ -54,162 +62,108 @@ public class SwtScoutDropDownPopup extends SwtScoutPopup {
});
}
- public void makeNonFocusable() {
- m_nonFocusable = true;
+ @Override
+ protected void onPopupOpened() {
+ // Install listener to close the popup if being scrolled.
+ scrollBars = findScrollbarsInHierarchy(getOwnerComponent());
+ installScrollListeners(scrollBars, m_viewPortChangedListener);
+
+ // Install listener to close the popup if being moved or resized.
+ getOwnerComponent().getShell().addListener(SWT.Move, m_viewPortChangedListener);
+ getOwnerComponent().getShell().addListener(SWT.Resize, m_viewPortChangedListener);
+
+ super.onPopupOpened();
}
@Override
- protected void handleSwtWindowOpened() {
- // add listener to adjust location
- if (getOwnerComponent() != null && !getOwnerComponent().isDisposed()) {
- if (m_scrollbarListener == null) {
- m_scrollbarListener = new P_ScrollBarListener();
- }
- reqAddScrollbarListener(m_scrollbarListener, getOwnerComponent());
- getOwnerComponent().getShell().addListener(SWT.Move, m_scrollbarListener);
+ protected void onPopupClosed() {
+ // Uninstall listener to close the popup if being scrolled.
+ uninstallScrollListeners(scrollBars, m_viewPortChangedListener);
+ scrollBars = null;
+
+ // Uninstall listener to close the popup if being moved or resized.
+ Shell shell = getOwnerShell();
+ if (shell != null) {
+ getOwnerComponent().getShell().removeListener(SWT.Move, m_viewPortChangedListener);
+ getOwnerComponent().getShell().removeListener(SWT.Resize, m_viewPortChangedListener);
}
- installFocusListener();
- //
- fireSwtScoutPartEvent(new SwtScoutPartEvent(SwtScoutDropDownPopup.this, SwtScoutPartEvent.TYPE_OPENED));
- fireSwtScoutPartEvent(new SwtScoutPartEvent(SwtScoutDropDownPopup.this, SwtScoutPartEvent.TYPE_ACTIVATED));
- if (m_nonFocusable) {
- if (getShell().getDisplay().getActiveShell() == getShell()) {
- m_focusComponent.setFocus();
- }
- if (!m_focusComponent.isFocusControl()) {
- closePart();
- fireSwtScoutPartEvent(new SwtScoutPartEvent(SwtScoutDropDownPopup.this, SwtScoutPartEvent.TYPE_CLOSED));
- }
- }
+ super.onPopupClosed();
}
- protected void installFocusListener() {
- if (m_focusComponentListener != null) {
- return;
- }
- if (m_focusComponent == null || m_focusComponent.isDisposed()) {
- return;
+ /**
+ * Adds the given listener to the given scrollbars.
+ */
+ private static void installScrollListeners(Set<ScrollBar> scrollBars, Listener listener) {
+ for (ScrollBar scrollBar : scrollBars) {
+ scrollBar.addListener(SWT.Selection, listener);
}
-
- m_focusComponentListener = new FocusAdapter() {
- @Override
- public void focusLost(FocusEvent e) {
- // defer decision until it is known who is new focus owner
- getShell().getDisplay().asyncExec(new Runnable() {
- @Override
- public void run() {
- if (getShell().isDisposed()) {
- return;
- }
- if (getShell() == getShell().getDisplay().getActiveShell()) {
- Control c = getShell().getDisplay().getFocusControl();
- if (c != null && c != getShell() && c.getShell() == getShell()) {
- c.addMouseListener(new MouseAdapter() {
- @Override
- public void mouseUp(MouseEvent event) {
- if (!((Control) event.getSource()).isDisposed()) {
- ((Control) event.getSource()).removeMouseListener(this);
- }
- if (!m_focusComponent.isDisposed()) {
- m_focusComponent.setFocus();
- }
- }
- });
- }
- else {
- m_focusComponent.setFocus();
- }
- }
- else {
- closePart();
- fireSwtScoutPartEvent(new SwtScoutPartEvent(SwtScoutDropDownPopup.this, SwtScoutPartEvent.TYPE_CLOSED));
- }
- }
- });
- }
- };
- m_focusComponent.addFocusListener(m_focusComponentListener);
}
- protected void uninstallFocusLostListener() {
- if (m_focusComponent == null || m_focusComponentListener == null) {
+ /**
+ * Removes the given listener from them given scrollbars.
+ */
+ private static void uninstallScrollListeners(Set<ScrollBar> scrollBars, Listener listener) {
+ if (scrollBars == null) {
return;
}
- if (!m_focusComponent.isDisposed()) {
- m_focusComponent.removeFocusListener(m_focusComponentListener);
- }
- m_focusComponentListener = null;
- }
-
- @Override
- protected void handleSwtWindowClosed() {
- if (getOwnerComponent() != null && !getOwnerComponent().isDisposed() && m_scrollbarListener != null) {
- reqRemoveScrollbarListener(m_scrollbarListener, getOwnerComponent());
- if (getOwnerComponent().getShell() != null && !getOwnerComponent().getShell().isDisposed()) {
- getOwnerComponent().getShell().removeListener(SWT.Move, m_scrollbarListener);
+ for (ScrollBar scrollBar : scrollBars) {
+ if (!scrollBar.isDisposed()) {
+ scrollBar.removeListener(SWT.Selection, listener);
}
}
- m_scrollbarListener = null;
- //
- uninstallFocusLostListener();
- super.handleSwtWindowClosed();
}
/**
- * <h3>P_ScrollBarListener</h3> ensures the location and size of the popup in
- * case of resizing, moving.
- *
- * @since 1.0.9 13.08.2008
+ * Finds the scrollbars in the ancestor hierarchy of the given control.
*/
- private class P_ScrollBarListener implements Listener {
- @Override
- public void handleEvent(Event event) {
- closePart();
- }
- } // end private class
-
- private void reqRemoveScrollbarListener(Listener l, Control control) {
+ private static Set<ScrollBar> findScrollbarsInHierarchy(Control control) {
+ final Set<ScrollBar> scrollBars = new HashSet<ScrollBar>();
if (!(control instanceof Composite)) {
- return;
+ return Collections.emptySet();
}
- Composite composite = (Composite) control;
- if (composite.getData(ISwtScoutPart.MARKER_SCOLLED_FORM) != null) {
- composite.removeListener(SWT.Resize, l);
- composite.removeListener(SWT.Move, l);
- ScrollBar hBar = composite.getHorizontalBar();
- if (hBar != null) {
+ final Composite composite = (Composite) control;
- hBar.removeListener(SWT.Selection, l);
- }
- ScrollBar vBar = composite.getVerticalBar();
- if (vBar != null) {
- vBar.removeListener(SWT.Selection, l);
- }
+ final ScrollBar hBar = composite.getHorizontalBar();
+ if (hBar != null) {
+ scrollBars.add(hBar);
+ }
+ final ScrollBar vBar = composite.getVerticalBar();
+ if (vBar != null) {
+ scrollBars.add(vBar);
}
- reqRemoveScrollbarListener(l, composite.getParent());
+
+ scrollBars.addAll(findScrollbarsInHierarchy(control.getParent()));
+
+ return scrollBars;
}
- private void reqAddScrollbarListener(Listener l, Control control) {
- if (!(control instanceof Composite)) {
- return;
+ /**
+ * @return Shell of the owner component or <code>null</code> if already disposed.
+ */
+ private Shell getOwnerShell() {
+ final Control ownerComponent = getOwnerComponent();
+ if (ownerComponent.isDisposed()) {
+ return null;
}
- Composite composite = (Composite) control;
- if (control.getData(ISwtScoutPart.MARKER_SCOLLED_FORM) != null) {
- control.addListener(SWT.Resize, l);
- control.addListener(SWT.Move, l);
- ScrollBar hBar = composite.getHorizontalBar();
- if (hBar != null) {
-
- hBar.addListener(SWT.Selection, l);
- }
- ScrollBar vBar = composite.getVerticalBar();
- if (vBar != null) {
- vBar.addListener(SWT.Selection, l);
- }
+ final Shell shell = ownerComponent.getShell();
+ if (shell.isDisposed()) {
+ return null;
+ }
+ return shell;
+ }
+
+ private class P_ViewPortChangedListener implements Listener {
+ @Override
+ public void handleEvent(Event event) {
+ if (getShell().isDisposed()) {
+ return;
+ }
+ // viewport changes are propagated as Shell deactivation events.
+ event.type = SWT.Deactivate;
+ getShell().notifyListeners(SWT.Deactivate, event);
}
- reqAddScrollbarListener(l, control.getParent());
}
}
diff --git a/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/window/popup/SwtScoutPopup.java b/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/window/popup/SwtScoutPopup.java
index 2b0c5d07c2..94384a98cf 100644
--- a/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/window/popup/SwtScoutPopup.java
+++ b/org.eclipse.scout.rt.ui.swt/src/org/eclipse/scout/rt/ui/swt/window/popup/SwtScoutPopup.java
@@ -10,10 +10,6 @@
******************************************************************************/
package org.eclipse.scout.rt.ui.swt.window.popup;
-import java.util.EventListener;
-
-import org.eclipse.scout.commons.EventListenerList;
-import org.eclipse.scout.commons.exception.ProcessingException;
import org.eclipse.scout.commons.logger.IScoutLogger;
import org.eclipse.scout.commons.logger.ScoutLogManager;
import org.eclipse.scout.rt.client.ui.form.IForm;
@@ -22,11 +18,8 @@ import org.eclipse.scout.rt.ui.swt.extension.UiDecorationExtensionPoint;
import org.eclipse.scout.rt.ui.swt.form.ISwtScoutForm;
import org.eclipse.scout.rt.ui.swt.util.SwtUtility;
import org.eclipse.scout.rt.ui.swt.window.ISwtScoutPart;
-import org.eclipse.scout.rt.ui.swt.window.SwtScoutPartEvent;
-import org.eclipse.scout.rt.ui.swt.window.SwtScoutPartListener;
import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.DisposeEvent;
-import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.events.ShellListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
@@ -37,23 +30,20 @@ import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.forms.widgets.Form;
/**
- * Popup window bound to a component (ownerComponent). The popup closes when
- * there is either a click outside this window or the component loses focus
- * (focusComponent), or the component becomes invisible.
+ * Popup window bound to a {@link Control}.
*/
public class SwtScoutPopup implements ISwtScoutPart {
+
private static final IScoutLogger LOG = ScoutLogManager.getLogger(SwtScoutPopup.class);
+
public static final String PROP_POPUP_OWNER = "propPopupOwner";
private ISwtEnvironment m_env;
private Control m_ownerComponent;
- private Rectangle m_ownerBounds;
- private Shell m_swtWindow;
- private Composite m_swtWindowContentPane;
- private EventListenerList m_listenerList;
+ private Shell m_shell;
+ private Composite m_shellContentPane;
private IForm m_scoutForm;
private boolean m_positionBelowReferenceField;
- private boolean m_opened;
private boolean m_popupOnField;
private int m_widthHint;
@@ -63,35 +53,54 @@ public class SwtScoutPopup implements ISwtScoutPart {
private ISwtScoutForm m_uiForm;
- public SwtScoutPopup(ISwtEnvironment env, Control ownerComponent, Rectangle ownerBounds, int style) {
+ /**
+ * Flag indicating whether focus should be taken when the dialog is opened.
+ */
+ private boolean m_takeFocusOnOpen = false;
+
+ /**
+ * @param env
+ * {@link ISwtEnvironment}.
+ * @param ownerComponent
+ * the {@link Control} the popup is bound to.
+ * @param takeFocusOnOpen
+ * A boolean indicating whether focus should be taken by this popup when it opens.
+ * @param style
+ * the style of control to construct
+ */
+ public SwtScoutPopup(ISwtEnvironment env, Control ownerComponent, boolean takeFocusOnOpen, int style) {
m_env = env;
+ m_takeFocusOnOpen = takeFocusOnOpen;
+
+ // ensure the popup to be in front if not taking the focus when it opens. (SWT.ON_TOP is required for Mac OS X).
+ if (!m_takeFocusOnOpen) {
+ style |= SWT.ON_TOP | SWT.NO_FOCUS;
+ }
+
m_positionBelowReferenceField = true;
m_ownerComponent = ownerComponent;
- m_ownerBounds = ownerBounds;
- m_listenerList = new EventListenerList();
m_widthHint = SWT.DEFAULT;
m_heightHint = SWT.DEFAULT;
m_maxHeightHint = SWT.DEFAULT;
m_maxWidthHint = SWT.DEFAULT;
- m_swtWindow = new Shell(ownerComponent.getShell(), style);
- m_swtWindow.setData("extendedStyle", SWT.POP_UP);
- m_swtWindow.setLayout(new FillLayout());
- m_swtWindow.addDisposeListener(new P_SwtWindowDisposeListener());
+ m_shell = new Shell(ownerComponent.getShell(), style);
+ m_shell.setData("extendedStyle", SWT.POP_UP);
+ m_shell.setLayout(new FillLayout());
// content pane
- m_swtWindowContentPane = env.getFormToolkit().createComposite(m_swtWindow, SWT.NONE);
- m_swtWindowContentPane.setLayout(new FillLayout());
+ m_shellContentPane = env.getFormToolkit().createComposite(m_shell, SWT.NONE);
+ m_shellContentPane.setLayout(new FillLayout());
}
@Override
public void setBusy(boolean b) {
- //nop
+ // NOOP
}
public Shell getShell() {
- return m_swtWindow;
+ return m_shell;
}
public void setBounds(Rectangle bounds) {
@@ -99,22 +108,10 @@ public class SwtScoutPopup implements ISwtScoutPart {
getShell().layout(true, true);
}
- public boolean isPopupOnField() {
- return m_popupOnField;
- }
-
public void setPopupOnField(boolean popupOnField) {
m_popupOnField = popupOnField;
}
- public boolean isPopupBelow() {
- return m_positionBelowReferenceField;
- }
-
- public int getWidthHint() {
- return m_widthHint;
- }
-
public void setWidthHint(int widthHint) {
if (widthHint > 0) {
m_widthHint = widthHint;
@@ -124,10 +121,6 @@ public class SwtScoutPopup implements ISwtScoutPart {
}
}
- public int getHeightHint() {
- return m_heightHint;
- }
-
public void setHeightHint(int heightHint) {
if (heightHint > 0) {
m_heightHint = heightHint;
@@ -137,10 +130,6 @@ public class SwtScoutPopup implements ISwtScoutPart {
}
}
- public int getMaxHeightHint() {
- return m_maxHeightHint;
- }
-
public void setMaxHeightHint(int maxHeightHint) {
if (maxHeightHint > 0) {
m_maxHeightHint = maxHeightHint;
@@ -150,10 +139,6 @@ public class SwtScoutPopup implements ISwtScoutPart {
}
}
- public int getMaxWidthHint() {
- return m_maxWidthHint;
- }
-
public void setMaxWidthHint(int maxWidthHint) {
if (maxWidthHint > 0) {
m_maxWidthHint = maxWidthHint;
@@ -163,39 +148,36 @@ public class SwtScoutPopup implements ISwtScoutPart {
}
}
- public void showForm(IForm scoutForm) throws ProcessingException {
- m_opened = true;
- if (m_scoutForm == null) {
- m_scoutForm = scoutForm;
- m_uiForm = m_env.createForm(getSwtContentPane(), scoutForm);
- autoAdjustBounds();
- if (m_opened) {
- handleSwtWindowOpening();
- //open and activate, do NOT just call setVisible(true)
- m_swtWindow.open();
- autoAdjustBounds();
- if (m_opened) {
- handleSwtWindowOpened();
- }
- }
+ /**
+ * Opens the popup with the given {@link IForm}.
+ */
+ public void showForm(IForm scoutForm) {
+ if (m_scoutForm != null) {
+ throw new IllegalStateException("The popup is already opened.");
+ }
+
+ m_scoutForm = scoutForm;
+ m_uiForm = m_env.createForm(m_shellContentPane, scoutForm);
+ autoAdjustBounds();
+
+ // open the window
+ if (m_takeFocusOnOpen) {
+ m_shell.open(); // open the popup, mark it visible, make it the focus owner and ask the window manager to make it the shell active.
+
}
else {
- throw new ProcessingException("The popup is already open. The form '" + scoutForm.getTitle() + " (" + scoutForm.getClass().getName() + ")' can not be opened!");
+ m_shell.setVisible(true); // open the popup without making it the active shell and the focus owner.
}
+ autoAdjustBounds();
+ onPopupOpened();
}
@Override
public void closePart() {
- m_opened = false;
- try {
- if (!m_swtWindow.isDisposed()) {
- m_swtWindow.setVisible(false);
- m_swtWindow.dispose();
- }
- }
- catch (Throwable t) {
- LOG.error("Failed closing popup for " + m_scoutForm, t);
+ if (!m_shell.isDisposed()) {
+ m_shell.dispose(); // directly dispose the Shell to not make it the focus owner while closing.
+ onPopupClosed();
}
}
@@ -219,7 +201,7 @@ public class SwtScoutPopup implements ISwtScoutPart {
return;
}
if (m_ownerComponent.isDisposed()) {
- LOG.warn("Unexpected: Owner component of popup is disposed");
+ LOG.warn("Failed to adjust popup bounds because owner component is disposed");
return;
}
//invalidate all layouts
@@ -261,83 +243,61 @@ public class SwtScoutPopup implements ISwtScoutPart {
}
}
- public Composite getSwtContentPane() {
- return m_swtWindowContentPane;
- }
-
- public void addSwtScoutPartListener(SwtScoutPartListener listener) {
- m_listenerList.add(SwtScoutPartListener.class, listener);
+ public Composite getShellContentPane() {
+ return m_shellContentPane;
}
- public void removeSwtScoutPartListener(SwtScoutPartListener listener) {
- m_listenerList.remove(SwtScoutPartListener.class, listener);
+ public void addShellListener(ShellListener listener) {
+ m_shell.addShellListener(listener);
}
- protected void fireSwtScoutPartEvent(SwtScoutPartEvent e) {
- if (m_swtWindow != null) {
- EventListener[] listeners = m_listenerList.getListeners(SwtScoutPartListener.class);
- if (listeners != null && listeners.length > 0) {
- for (EventListener listener : listeners) {
- try {
- ((SwtScoutPartListener) listener).partChanged(e);
- }
- catch (Throwable t) {
- LOG.error("Unexpected:", t);
- }
- }
- }
- }
+ public void removeShellListener(ShellListener listener) {
+ m_shell.removeShellListener(listener);
}
@Override
public boolean isVisible() {
- return m_swtWindow != null && m_swtWindow.getVisible();
+ return !m_shell.isDisposed() && m_shell.getVisible();
}
@Override
public void activate() {
- m_swtWindow.getShell().setActive();
+ if (!m_shell.isDisposed()) {
+ m_shell.setActive();
+ }
}
@Override
public boolean isActive() {
- return m_swtWindow != null && m_swtWindow.getDisplay().getActiveShell() == m_swtWindow;
+ return m_shell.isDisposed() && m_shell.getDisplay().getActiveShell() == m_shell;
}
@Override
public void setStatusLineMessage(Image image, String message) {
- // void
+ // NOOP
}
- protected void handleSwtWindowOpening() {
- fireSwtScoutPartEvent(new SwtScoutPartEvent(SwtScoutPopup.this, SwtScoutPartEvent.TYPE_OPENING));
+ /**
+ * Called after the popup was opened.
+ */
+ protected void onPopupOpened() {
}
- protected void handleSwtWindowOpened() {
- fireSwtScoutPartEvent(new SwtScoutPartEvent(SwtScoutPopup.this, SwtScoutPartEvent.TYPE_OPENED));
- fireSwtScoutPartEvent(new SwtScoutPartEvent(SwtScoutPopup.this, SwtScoutPartEvent.TYPE_ACTIVATED));
+ /**
+ * Called after the popup was closed.
+ */
+ protected void onPopupClosed() {
+ if (m_scoutForm != null) {
+ m_env.invokeScoutLater(new Runnable() {
+ @Override
+ public void run() {
+ m_scoutForm.getUIFacade().fireFormKilledFromUI();
+ }
+ }, 0);
+ }
}
protected Control getOwnerComponent() {
return m_ownerComponent;
}
-
- protected void handleSwtWindowClosed() {
- fireSwtScoutPartEvent(new SwtScoutPartEvent(SwtScoutPopup.this, SwtScoutPartEvent.TYPE_CLOSED));
- Runnable job = new Runnable() {
- @Override
- public void run() {
- m_scoutForm.getUIFacade().fireFormKilledFromUI();
- }
- };
- m_env.invokeScoutLater(job, 0);
- }
-
- private class P_SwtWindowDisposeListener implements DisposeListener {
- @Override
- public void widgetDisposed(DisposeEvent e) {
- handleSwtWindowClosed();
- }
- }// end private class
-
}

Back to the top