diff options
| author | Daniel Wiehl | 2014-10-21 12:53:46 +0000 |
|---|---|---|
| committer | Daniel Wiehl | 2014-10-21 12:53:46 +0000 |
| commit | 3d623e62a694178cf6495de5303298c53e0b05eb (patch) | |
| tree | 09ce55336ca5d31c731f7ea8b858db262a0458e1 | |
| parent | b66bccb06c08dc8192c8ea50d1cbd564e7c26ecd (diff) | |
| download | org.eclipse.scout.rt-3d623e62a694178cf6495de5303298c53e0b05eb.tar.gz org.eclipse.scout.rt-3d623e62a694178cf6495de5303298c53e0b05eb.tar.xz org.eclipse.scout.rt-3d623e62a694178cf6495de5303298c53e0b05eb.zip | |
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
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 - } |
