| /******************************************************************************* |
| * Copyright (c) 2011,2013 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.rap.form.fields.smartfield; |
| |
| import java.beans.PropertyChangeEvent; |
| import java.util.HashSet; |
| import java.util.Set; |
| import java.util.concurrent.atomic.AtomicBoolean; |
| import java.util.concurrent.atomic.AtomicReference; |
| |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.rap.rwt.RWT; |
| import org.eclipse.scout.commons.CompareUtility; |
| import org.eclipse.scout.commons.exception.ProcessingException; |
| import org.eclipse.scout.commons.job.JobEx; |
| import org.eclipse.scout.commons.logger.IScoutLogger; |
| import org.eclipse.scout.commons.logger.ScoutLogManager; |
| import org.eclipse.scout.rt.client.ui.action.IAction; |
| import org.eclipse.scout.rt.client.ui.action.menu.IMenu; |
| import org.eclipse.scout.rt.client.ui.form.FormEvent; |
| 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.ISmartField; |
| import org.eclipse.scout.rt.client.ui.form.fields.smartfield.ISmartFieldProposalForm; |
| import org.eclipse.scout.rt.ui.rap.LogicalGridLayout; |
| import org.eclipse.scout.rt.ui.rap.RwtMenuUtility; |
| import org.eclipse.scout.rt.ui.rap.action.AbstractRwtScoutActionPropertyChangeListener; |
| import org.eclipse.scout.rt.ui.rap.ext.IDropDownButtonForPatch; |
| import org.eclipse.scout.rt.ui.rap.ext.MenuAdapterEx; |
| import org.eclipse.scout.rt.ui.rap.ext.StatusLabelEx; |
| import org.eclipse.scout.rt.ui.rap.ext.StyledTextEx; |
| import org.eclipse.scout.rt.ui.rap.ext.custom.StyledText; |
| import org.eclipse.scout.rt.ui.rap.ext.table.TableEx; |
| import org.eclipse.scout.rt.ui.rap.ext.tree.TreeEx; |
| import org.eclipse.scout.rt.ui.rap.extension.UiDecorationExtensionPoint; |
| import org.eclipse.scout.rt.ui.rap.form.fields.IPopupSupport; |
| import org.eclipse.scout.rt.ui.rap.form.fields.LogicalGridDataBuilder; |
| import org.eclipse.scout.rt.ui.rap.form.fields.RwtScoutValueFieldComposite; |
| import org.eclipse.scout.rt.ui.rap.internal.TextFieldEditableSupport; |
| import org.eclipse.scout.rt.ui.rap.keystroke.IRwtKeyStroke; |
| import org.eclipse.scout.rt.ui.rap.keystroke.RwtKeyStroke; |
| import org.eclipse.scout.rt.ui.rap.util.RwtLayoutUtility; |
| import org.eclipse.scout.rt.ui.rap.util.RwtUtility; |
| import org.eclipse.scout.rt.ui.rap.window.RwtScoutPartEvent; |
| import org.eclipse.scout.rt.ui.rap.window.RwtScoutPartListener; |
| import org.eclipse.scout.rt.ui.rap.window.popup.RwtScoutDropDownPopup; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.events.FocusAdapter; |
| import org.eclipse.swt.events.FocusEvent; |
| import org.eclipse.swt.events.MenuDetectEvent; |
| import org.eclipse.swt.events.MenuDetectListener; |
| import org.eclipse.swt.events.MenuEvent; |
| import org.eclipse.swt.events.ModifyEvent; |
| import org.eclipse.swt.events.ModifyListener; |
| import org.eclipse.swt.events.SelectionAdapter; |
| import org.eclipse.swt.events.SelectionEvent; |
| 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.graphics.Point; |
| import org.eclipse.swt.layout.GridData; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Control; |
| import org.eclipse.swt.widgets.Event; |
| import org.eclipse.swt.widgets.Menu; |
| import org.eclipse.swt.widgets.Shell; |
| import org.eclipse.swt.widgets.Table; |
| import org.eclipse.swt.widgets.Tree; |
| import org.eclipse.swt.widgets.Widget; |
| |
| /** |
| * @since 3.8.0 |
| */ |
| public class RwtScoutSmartField extends RwtScoutValueFieldComposite<ISmartField<?>> implements IRwtScoutSmartField, IPopupSupport { |
| private static final IScoutLogger LOG = ScoutLogManager.getLogger(RwtScoutSmartField.class); |
| |
| private IDropDownButtonForPatch m_browseButton; |
| private P_PendingProposalJob m_pendingProposalJob; |
| private Object m_pendingProposalJobLock; |
| private Composite m_smartContainer; |
| // popup |
| private RwtScoutDropDownPopup m_proposalPopup; |
| private final Object m_popupLock = new Object(); |
| private TextFieldEditableSupport m_editableSupport; |
| |
| private P_KeyListener m_tabKeyListener; |
| private P_KeyListener m_shiftTabKeyListener; |
| private Set<IPopupSupportListener> m_popupEventListeners; |
| private Object m_popupEventListenerLock; |
| private P_ScoutActionPropertyChangeListener m_scoutActionPropertyListener; |
| |
| public RwtScoutSmartField() { |
| m_pendingProposalJobLock = new Object(); |
| } |
| |
| @Override |
| protected void initializeUi(Composite parent) { |
| m_popupEventListeners = new HashSet<IPopupSupportListener>(); |
| m_popupEventListenerLock = new Object(); |
| |
| Composite container = getUiEnvironment().getFormToolkit().createComposite(parent); |
| StatusLabelEx label = getUiEnvironment().getFormToolkit().createStatusLabel(container, getScoutObject()); |
| |
| m_smartContainer = getUiEnvironment().getFormToolkit().createComposite(container, SWT.BORDER); |
| m_smartContainer.setData(RWT.CUSTOM_VARIANT, getSmartfieldVariant()); |
| |
| StyledText textField = new StyledTextEx(m_smartContainer, SWT.SINGLE); |
| getUiEnvironment().getFormToolkit().adapt(textField, false, false); |
| // correction to look like a normal text |
| textField.setData(RWT.CUSTOM_VARIANT, getSmartfieldVariant()); |
| |
| m_browseButton = getUiEnvironment().getFormToolkit().createDropDownButton(m_smartContainer, SWT.DROP_DOWN | SWT.NO_FOCUS); |
| |
| setUiContainer(container); |
| setUiLabel(label); |
| setUiField(textField); |
| // prevent the button from grabbing focus |
| m_smartContainer.setTabList(new Control[]{textField}); |
| |
| m_browseButton.addFocusListener(new FocusAdapter() { |
| private static final long serialVersionUID = 1L; |
| |
| @Override |
| public void focusGained(FocusEvent e) { |
| getUiField().setFocus(); |
| } |
| }); |
| |
| // context menu |
| m_browseButton.addMenuDetectListener(new P_RwtMenuDetectListener()); |
| m_browseButton.addMenuListener(new P_ContextMenuListener((Control) getUiBrowseButton(), getUiField())); |
| |
| // listeners |
| getUiField().addModifyListener(new P_ModifyListener()); |
| if (!getScoutObject().isAllowCustomText()) { |
| getUiField().addTraverseListener(new P_TraverseListener()); |
| attachFocusListener(getUiField(), false); |
| } |
| else { |
| attachFocusListener(getUiField(), true); |
| } |
| getUiEnvironment().addKeyStroke(getUiField(), new P_F2KeyStroke(), false); |
| getUiEnvironment().addKeyStroke(getUiField(), new P_KeyListener(SWT.ARROW_DOWN), false); |
| getUiEnvironment().addKeyStroke(getUiField(), new P_KeyListener(SWT.ARROW_UP), false); |
| getUiEnvironment().addKeyStroke(getUiField(), new P_KeyListener(SWT.PAGE_DOWN), false); |
| getUiEnvironment().addKeyStroke(getUiField(), new P_KeyListener(SWT.PAGE_UP), false); |
| |
| P_RwtBrowseButtonListener browseButtonListener = new P_RwtBrowseButtonListener(); |
| getUiBrowseButton().addSelectionListener(browseButtonListener); |
| |
| // layout |
| container.setLayout(new LogicalGridLayout(1, 0)); |
| |
| m_smartContainer.setLayoutData(LogicalGridDataBuilder.createField(((IFormField) getScoutObject()).getGridData())); |
| m_smartContainer.setLayout(RwtLayoutUtility.createGridLayoutNoSpacing(2, false)); |
| |
| GridData textLayoutData = new GridData(SWT.FILL, SWT.FILL, true, true); |
| textField.setLayoutData(textLayoutData); |
| |
| GridData buttonLayoutData = new GridData(SWT.CENTER, SWT.CENTER, false, false); |
| buttonLayoutData.heightHint = 20; |
| buttonLayoutData.widthHint = 20; |
| m_browseButton.setLayoutData(buttonLayoutData); |
| } |
| |
| protected String getSmartfieldVariant() { |
| return VARIANT_SMARTFIELD; |
| } |
| |
| protected String getSmartfieldDisabledVariant() { |
| return VARIANT_SMARTFIELD_DISABLED; |
| } |
| |
| public IDropDownButtonForPatch getUiBrowseButton() { |
| return m_browseButton; |
| } |
| |
| @Override |
| public StyledText getUiField() { |
| return (StyledText) super.getUiField(); |
| } |
| |
| @Override |
| protected void attachScout() { |
| super.attachScout(); |
| setIconIdFromScout(getScoutObject().getIconId()); |
| getUiBrowseButton().setDropdownEnabled(calculateDropDownButtonEnabled()); |
| setProposalFormFromScout(getScoutObject().getProposalForm()); |
| if (m_scoutActionPropertyListener == null) { |
| m_scoutActionPropertyListener = new P_ScoutActionPropertyChangeListener(); |
| } |
| m_scoutActionPropertyListener.attachToScoutMenus(getScoutObject().getMenus()); |
| } |
| |
| private boolean calculateDropDownButtonEnabled() { |
| final AtomicBoolean hasValidMenus = new AtomicBoolean(false); |
| Runnable t = new Runnable() { |
| @Override |
| public void run() { |
| hasValidMenus.set(getScoutObject().getUIFacade().hasValidMenusFromUI()); |
| } |
| }; |
| JobEx job = getUiEnvironment().invokeScoutLater(t, 1200); |
| try { |
| job.join(1200); |
| } |
| catch (InterruptedException ex) { |
| //nop |
| } |
| return hasValidMenus.get(); |
| } |
| |
| @Override |
| protected void detachScout() { |
| // workaround since disposeFieldInternal in AbstractSmartField is never called. |
| hideProposalPopup(); |
| if (m_scoutActionPropertyListener != null) { |
| m_scoutActionPropertyListener.detachFromScoutMenus(getScoutObject().getMenus()); |
| m_scoutActionPropertyListener = null; |
| } |
| super.detachScout(); |
| } |
| |
| @Override |
| protected void setDisplayTextFromScout(String s) { |
| getUiBrowseButton().setDropdownEnabled(calculateDropDownButtonEnabled()); |
| if (!CompareUtility.equals(s, getUiField().getText())) { |
| if (s == null) { |
| s = ""; |
| } |
| StyledText field = getUiField(); |
| field.setText(s); |
| field.setCaretOffset(0); |
| } |
| } |
| |
| @Override |
| protected void setEnabledFromScout(boolean b) { |
| super.setEnabledFromScout(b); |
| m_browseButton.setButtonEnabled(b); |
| getUiField().setEnabled(b); |
| handleDropDownButtonEnabled(); |
| if (b) { |
| m_smartContainer.setData(RWT.CUSTOM_VARIANT, getSmartfieldVariant()); |
| } |
| else { |
| m_smartContainer.setData(RWT.CUSTOM_VARIANT, getSmartfieldDisabledVariant()); |
| } |
| } |
| |
| @Override |
| protected void setFieldEnabled(Control field, boolean enabled) { |
| if (m_editableSupport == null) { |
| m_editableSupport = new TextFieldEditableSupport(getUiField()); |
| } |
| m_editableSupport.setEditable(enabled); |
| } |
| |
| protected void setIconIdFromScout(String s) { |
| boolean iconVisible = s != null; |
| if (m_browseButton.getLayoutData() instanceof GridData) { |
| GridData layoutData = (GridData) m_browseButton.getLayoutData(); |
| layoutData.exclude = !iconVisible; |
| } |
| m_browseButton.setData(RWT.CUSTOM_VARIANT, s); |
| } |
| |
| @Override |
| protected void setBackgroundFromScout(String scoutColor) { |
| setBackgroundFromScout(scoutColor, m_smartContainer); |
| } |
| |
| @Override |
| protected void handleUiFocusGained() { |
| super.handleUiFocusGained(); |
| |
| if (m_proposalPopup == null || getScoutObject().getErrorStatus() != null) { |
| if (isSelectAllOnFocusEnabled()) { |
| getUiField().setSelection(0, getUiField().getText().length()); |
| } |
| } |
| } |
| |
| protected void setProposalFormFromScout(ISmartFieldProposalForm form) { |
| synchronized (m_pendingProposalJobLock) { |
| if (m_pendingProposalJob != null) { |
| m_pendingProposalJob.cancel(); |
| m_pendingProposalJob = null; |
| } |
| } |
| if (form != null) { |
| showProposalPopup(form); |
| } |
| else { |
| hideProposalPopup(); |
| } |
| } |
| |
| protected void showProposalPopup(final ISmartFieldProposalForm form) { |
| // close old |
| hideProposalPopup(); |
| |
| //Prevent showing if it should not be displayed |
| if (getScoutObject().isAllowCustomText() && !getUiField().isFocusControl()) { |
| //If the user writes fast and presses tab before the proposal popup shows up, the popup needs to stay closed |
| getUiEnvironment().invokeScoutLater(new Runnable() { |
| @Override |
| public void run() { |
| try { |
| form.doClose(); |
| } |
| catch (ProcessingException e) { |
| LOG.warn("Closing proposal form failed.", e); |
| } |
| } |
| |
| }, 0); |
| |
| return; |
| } |
| |
| // make sure tab won't go to next field |
| if (!getScoutObject().isAllowCustomText()) { |
| disableTabbing(); |
| } |
| |
| // show new |
| m_proposalPopup = new RwtScoutDropDownPopup(); |
| m_proposalPopup.createPart(form, m_smartContainer, getUiField(), SWT.RESIZE, getUiEnvironment()); |
| m_proposalPopup.setMaxHeightHint(getScoutObject().getProposalFormHeight()); |
| m_proposalPopup.addRwtScoutPartListener(new RwtScoutPartListener() { |
| @Override |
| public void partChanged(RwtScoutPartEvent e) { |
| switch (e.getType()) { |
| case RwtScoutPartEvent.TYPE_OPENING: { |
| notifyPopupEventListeners(IPopupSupportListener.TYPE_OPENING); |
| break; |
| } |
| case RwtScoutPartEvent.TYPE_CLOSING: { |
| hideProposalPopup(); |
| break; |
| } |
| case RwtScoutPartEvent.TYPE_CLOSED: { |
| if (m_proposalPopup != null) { |
| m_proposalPopup = null; |
| notifyPopupEventListeners(IPopupSupportListener.TYPE_CLOSED); |
| } |
| break; |
| } |
| } |
| } |
| }); |
| m_proposalPopup.getShell().addShellListener(new ShellAdapter() { |
| private static final long serialVersionUID = 1L; |
| |
| @Override |
| public void shellClosed(ShellEvent e) { |
| e.doit = false; |
| } |
| }); |
| m_proposalPopup.makeNonFocusable(); |
| // |
| try { |
| // adjust size of popup every time the table/tree changes in the model |
| m_proposalPopup.getShell().setSize(new Point(m_smartContainer.getSize().x, 200)); |
| final TableEx proposalTable = RwtUtility.findChildComponent(m_proposalPopup.getUiContentPane(), TableEx.class); |
| final TreeEx proposalTree = RwtUtility.findChildComponent(m_proposalPopup.getUiContentPane(), TreeEx.class); |
| if (proposalTree != null || proposalTable != null) { |
| form.addFormListener( |
| new FormListener() { |
| @Override |
| public void formChanged(FormEvent e) throws ProcessingException { |
| switch (e.getType()) { |
| case FormEvent.TYPE_STRUCTURE_CHANGED: { |
| Runnable t = new Runnable() { |
| @Override |
| public void run() { |
| optimizePopupSize(m_proposalPopup, proposalTable, proposalTree); |
| } |
| }; |
| getUiEnvironment().invokeUiLater(t); |
| break; |
| } |
| } |
| } |
| }); |
| //enqueue a later display job since there may be waiting display tasks in the queue that change the table/tree |
| getUiEnvironment().getDisplay().asyncExec(new Runnable() { |
| @Override |
| public void run() { |
| optimizePopupSize(m_proposalPopup, proposalTable, proposalTree); |
| } |
| }); |
| //only if table or tree is already filled up, optimize size, otherwise nop |
| if ((proposalTree != null && proposalTree.getItemCount() > 0) || (proposalTable != null && proposalTable.getItemCount() > 0)) { |
| optimizePopupSize(m_proposalPopup, proposalTable, proposalTree); |
| } |
| } |
| m_proposalPopup.showPart(); |
| } |
| catch (Throwable e1) { |
| LOG.error(e1.getLocalizedMessage(), e1); |
| } |
| } |
| |
| private void optimizePopupSize(RwtScoutDropDownPopup popup, TableEx proposalTable, TreeEx proposalTree) { |
| if (popup == null) { |
| return; |
| } |
| int minFormWidth = 0; |
| if (getScoutObject().isActiveFilterEnabled()) { |
| minFormWidth = 230; |
| } |
| if (proposalTable != null) { |
| int scrollbarSize = proposalTable.getVerticalBar() != null ? proposalTable.getVerticalBar().getSize().x + 10 : 0; |
| Point d = proposalTable.getPreferredContentSize(1000); |
| d.x += scrollbarSize; |
| d.x = Math.max(Math.max(m_smartContainer.getSize().x, minFormWidth), Math.min(d.x, 400)); |
| d.y = Math.max(UiDecorationExtensionPoint.getLookAndFeel().getLogicalGridLayoutRowHeight(), Math.min(d.y, 280)); |
| popup.getShell().setSize(d); |
| Composite c = proposalTable; |
| while (c != null && !(c instanceof Shell)) { |
| c.layout(true); |
| c = c.getParent(); |
| } |
| } |
| else if (proposalTree != null) { |
| int scrollbarSize = proposalTree.getVerticalBar() != null ? proposalTree.getVerticalBar().getSize().x + 10 : 0; |
| Point d = proposalTree.getPreferredContentSize(1000, null, 0); |
| d.x += scrollbarSize; |
| d.x = Math.max(Math.max(m_smartContainer.getSize().x, minFormWidth), Math.min(d.x, 400)); |
| d.y = Math.max(UiDecorationExtensionPoint.getLookAndFeel().getLogicalGridLayoutRowHeight(), Math.min(d.x, 280)); |
| popup.getShell().setSize(d); |
| Composite c = proposalTree; |
| while (c != null && !(c instanceof Shell)) { |
| c.layout(true); |
| c = c.getParent(); |
| } |
| } |
| if (popup.getShell() != null && popup.getShell().isVisible()) { |
| popup.autoAdjustBounds(); |
| } |
| } |
| |
| protected boolean hideProposalPopup() { |
| synchronized (m_popupLock) { |
| enableTabbing(); |
| if (m_proposalPopup != null && m_proposalPopup.isVisible()) { |
| m_proposalPopup.closePart(); |
| m_proposalPopup = null; |
| return true; |
| } |
| return false; |
| } |
| } |
| |
| private void enableTabbing() { |
| if (m_tabKeyListener != null) { |
| getUiEnvironment().removeKeyStroke(getUiField(), m_tabKeyListener); |
| } |
| if (m_shiftTabKeyListener != null) { |
| getUiEnvironment().removeKeyStroke(getUiField(), m_shiftTabKeyListener); |
| } |
| } |
| |
| private void disableTabbing() { |
| if (m_tabKeyListener == null) { |
| m_tabKeyListener = new P_KeyListener(SWT.TAB); |
| } |
| if (m_shiftTabKeyListener == null) { |
| m_shiftTabKeyListener = new P_KeyListener(SWT.TAB, SWT.SHIFT); |
| } |
| |
| if (!getUiEnvironment().hasKeyStroke(getUiField(), m_tabKeyListener)) { |
| getUiEnvironment().addKeyStroke(getUiField(), m_tabKeyListener, true); |
| } |
| if (!getUiEnvironment().hasKeyStroke(getUiField(), m_shiftTabKeyListener)) { |
| getUiEnvironment().addKeyStroke(getUiField(), m_shiftTabKeyListener, true); |
| } |
| } |
| |
| protected void requestProposalSupportFromUi(String text, boolean selectCurrentValue, long initialDelay) { |
| synchronized (m_pendingProposalJobLock) { |
| if (m_pendingProposalJob == null) { |
| m_pendingProposalJob = new P_PendingProposalJob(); |
| } |
| else { |
| m_pendingProposalJob.cancel(); |
| } |
| m_pendingProposalJob.update(text, selectCurrentValue); |
| m_pendingProposalJob.schedule(initialDelay); |
| } |
| } |
| |
| private void acceptProposalFromUi() { |
| synchronized (m_pendingProposalJobLock) { |
| if (m_pendingProposalJob != null) { |
| m_pendingProposalJob.cancel(); |
| m_pendingProposalJob = null; |
| } |
| } |
| final String text = getUiField().getText(); |
| // notify Scout |
| Runnable t = new Runnable() { |
| @Override |
| public void run() { |
| getScoutObject().getUIFacade().setTextFromUI(text); |
| } |
| }; |
| getUiEnvironment().invokeScoutLater(t, 0); |
| // end notify |
| } |
| |
| @Override |
| protected IRwtKeyStroke[] getUiKeyStrokes() { |
| return new IRwtKeyStroke[]{ |
| new RwtKeyStroke(SWT.ESC) { |
| @Override |
| public void handleUiAction(Event e) { |
| if (hideProposalPopup()) { |
| e.doit = false; |
| } |
| } |
| }, |
| new RwtKeyStroke(SWT.CR) { |
| @Override |
| public void handleUiAction(Event e) { |
| if (m_proposalPopup != null) { |
| e.doit = false; |
| acceptProposalFromUi(); |
| } |
| } |
| }}; |
| } |
| |
| @Override |
| protected void handleUiInputVerifier(boolean doit) { |
| synchronized (m_pendingProposalJobLock) { |
| if (m_pendingProposalJob != null) { |
| m_pendingProposalJob.cancel(); |
| m_pendingProposalJob = null; |
| } |
| } |
| final String text = getUiField().getText(); |
| // notify Scout |
| Runnable t = new Runnable() { |
| @Override |
| public void run() { |
| getScoutObject().getUIFacade().setTextFromUI(text); |
| } |
| }; |
| JobEx job = getUiEnvironment().invokeScoutLater(t, 0); |
| try { |
| job.join(2345); |
| } |
| catch (InterruptedException e) { |
| //nop |
| } |
| // end notify |
| getUiEnvironment().dispatchImmediateUiJobs(); |
| } |
| |
| protected void handleUiBrowseAction() { |
| if (getUiBrowseButton().isVisible() && getUiBrowseButton().isEnabled()) { |
| requestProposalSupportFromUi(ISmartField.BROWSE_ALL_TEXT, true, 0); |
| } |
| } |
| |
| @Override |
| protected void handleScoutPropertyChange(String name, Object newValue) { |
| super.handleScoutPropertyChange(name, newValue); |
| if (name.equals(ISmartField.PROP_ICON_ID)) { |
| setIconIdFromScout((String) newValue); |
| } |
| else if (name.equals(ISmartField.PROP_PROPOSAL_FORM)) { |
| setProposalFormFromScout((ISmartFieldProposalForm) newValue); |
| } |
| } |
| |
| protected void handleScoutActionPropertyChange(String name, Object newValue) { |
| if (IAction.PROP_INHERIT_ACCESSIBILITY.equals(name) || IAction.PROP_EMPTY_SPACE.equals(name) || |
| IAction.PROP_SINGLE_SELECTION.equals(name) || IAction.PROP_VISIBLE.equals(name)) { |
| handleDropDownButtonEnabled(); |
| } |
| } |
| |
| protected void handleDropDownButtonEnabled() { |
| getUiBrowseButton().setDropdownEnabled(calculateDropDownButtonEnabled()); |
| } |
| |
| protected void handleTextModifiedFromUi(ModifyEvent event) { |
| if (getUpdateUiFromScoutLock().isAcquired()) { |
| return; |
| } |
| if (getUiField().isVisible()) { |
| String text = getUiField().getText(); |
| if (text == null || text.length() == 0) { |
| // allow empty field without proposal |
| if (m_proposalPopup != null) { |
| requestProposalSupportFromUi(text, false, 0); |
| } |
| else { |
| // notify Scout |
| Runnable t = new Runnable() { |
| @Override |
| public void run() { |
| getScoutObject().getUIFacade().setTextFromUI(null); |
| } |
| }; |
| getUiEnvironment().invokeScoutLater(t, 0); |
| // end notify |
| } |
| } |
| else { |
| requestProposalSupportFromUi(text, false, m_proposalPopup != null ? 200 : 0); |
| } |
| } |
| } |
| |
| protected void handleTraverseFromUi(TraverseEvent event) { |
| switch (event.keyCode) { |
| case SWT.ARROW_DOWN: |
| case SWT.ARROW_UP: |
| case SWT.ARROW_LEFT: |
| case SWT.ARROW_RIGHT: |
| case SWT.HOME: |
| case SWT.END: |
| case SWT.PAGE_DOWN: |
| case SWT.PAGE_UP: |
| case SWT.CR: |
| case SWT.ESC: |
| break; |
| default: |
| handleUiInputVerifier(true); |
| } |
| } |
| |
| 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 Menu createMenu() { |
| if (m_browseButton.getMenu() != null) { |
| m_browseButton.getMenu().dispose(); |
| m_browseButton.setMenu(null); |
| } |
| Menu contextMenu = new Menu(m_browseButton.getShell(), SWT.POP_UP); |
| contextMenu.addMenuListener(new P_ContextMenuListener((Control) getUiBrowseButton(), getUiField())); |
| m_browseButton.setMenu(contextMenu); |
| |
| return contextMenu; |
| } |
| |
| private void createAndShowMenu(Point location) { |
| Menu menu = createMenu(); |
| menu.setLocation(location); |
| menu.setVisible(true); |
| } |
| |
| private class P_TraverseListener implements TraverseListener { |
| private static final long serialVersionUID = 1L; |
| |
| @Override |
| public void keyTraversed(TraverseEvent event) { |
| handleTraverseFromUi(event); |
| } |
| } |
| |
| private class P_ModifyListener implements ModifyListener { |
| private static final long serialVersionUID = 1L; |
| |
| @Override |
| public void modifyText(ModifyEvent event) { |
| handleTextModifiedFromUi(event); |
| } |
| } |
| |
| private class P_KeyListener extends RwtKeyStroke { |
| public P_KeyListener(int keyCode) { |
| super(keyCode); |
| } |
| |
| public P_KeyListener(int keyCode, int stateMask) { |
| super(keyCode, stateMask); |
| } |
| |
| @Override |
| public void handleUiAction(Event e) { |
| switch (e.keyCode) { |
| case SWT.TAB: |
| if (m_proposalPopup == null) { |
| enableTabbing(); |
| } |
| break; |
| |
| default: |
| if (m_proposalPopup == null) { |
| requestProposalSupportFromUi(ISmartField.BROWSE_ALL_TEXT, true, 0); |
| e.doit = false; |
| } |
| else { |
| Widget c = null; |
| if (c == null) { |
| c = RwtUtility.findChildComponent(m_proposalPopup.getUiContentPane(), Table.class); |
| } |
| if (c == null) { |
| c = RwtUtility.findChildComponent(m_proposalPopup.getUiContentPane(), Tree.class); |
| } |
| if (RwtUtility.handleNavigationKey(c, e.keyCode)) { |
| e.doit = false; |
| } |
| } |
| break; |
| } |
| } |
| } |
| |
| private class P_PendingProposalJob extends JobEx implements Runnable { |
| |
| private String m_text; |
| private boolean m_selectCurrentValue; |
| |
| public P_PendingProposalJob() { |
| super(""); |
| setSystem(true); |
| } |
| |
| @Override |
| protected IStatus run(IProgressMonitor monitor) { |
| if (monitor.isCanceled()) { |
| return Status.CANCEL_STATUS; |
| } |
| getUiEnvironment().getDisplay().asyncExec(this); |
| return Status.OK_STATUS; |
| } |
| |
| @Override |
| public void run() { |
| synchronized (m_pendingProposalJobLock) { |
| if (m_pendingProposalJob == this) { |
| m_pendingProposalJob = null; |
| } |
| else { |
| return; |
| } |
| } |
| if (getUiField().isDisposed()) { |
| return; |
| } |
| |
| if (getUiField().isFocusControl()) { |
| Runnable t = new Runnable() { |
| @Override |
| public void run() { |
| getScoutObject().getUIFacade().openProposalFromUI(m_text, m_selectCurrentValue); |
| } |
| }; |
| getUiEnvironment().invokeScoutLater(t, 0); |
| } |
| } |
| |
| public void update(String text, boolean selectCurrentValue) { |
| m_text = text; |
| m_selectCurrentValue = selectCurrentValue; |
| } |
| } |
| |
| private class P_ContextMenuListener extends MenuAdapterEx { |
| private static final long serialVersionUID = 1L; |
| |
| public P_ContextMenuListener(Control menuControl, Control keyStrokeWidget) { |
| super(menuControl, keyStrokeWidget); |
| } |
| |
| @Override |
| public void menuShown(MenuEvent e) { |
| super.menuShown(e); |
| |
| final AtomicReference<IMenu[]> scoutMenusRef = new AtomicReference<IMenu[]>(); |
| Runnable t = new Runnable() { |
| @Override |
| public void run() { |
| IMenu[] scoutMenus = getScoutObject().getUIFacade().firePopupFromUI(); |
| scoutMenusRef.set(scoutMenus); |
| } |
| }; |
| JobEx job = RwtScoutSmartField.this.getUiEnvironment().invokeScoutLater(t, 1200); |
| try { |
| job.join(1200); |
| } |
| catch (InterruptedException ex) { |
| //nop |
| } |
| // grab the actions out of the job, when the actions are providden within |
| // the scheduled time the popup will be handled. |
| if (scoutMenusRef.get() != null) { |
| Menu menu = ((Menu) e.getSource()); |
| RwtMenuUtility.fillContextMenu(scoutMenusRef.get(), RwtScoutSmartField.this.getUiEnvironment(), menu); |
| } |
| } |
| } // end class P_ContextMenuListener |
| |
| private class P_RwtBrowseButtonListener extends SelectionAdapter { |
| private static final long serialVersionUID = 1L; |
| |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| getUiField().forceFocus(); |
| handleUiBrowseAction(); |
| } |
| } // end class P_RwtBrowseButtonListener |
| |
| private class P_F2KeyStroke extends RwtKeyStroke { |
| public P_F2KeyStroke() { |
| super(SWT.F2); |
| } |
| |
| @Override |
| public void handleUiAction(Event e) { |
| handleUiBrowseAction(); |
| } |
| } // end class P_F2KeyStroke |
| |
| private class P_RwtMenuDetectListener implements MenuDetectListener { |
| |
| private static final long serialVersionUID = 1L; |
| |
| @Override |
| public void menuDetected(MenuDetectEvent e) { |
| createAndShowMenu(new Point(e.x, e.y)); |
| } |
| |
| } |
| |
| private class P_ScoutActionPropertyChangeListener extends AbstractRwtScoutActionPropertyChangeListener { |
| @Override |
| public void propertyChange(final PropertyChangeEvent e) { |
| if (getUiEnvironment().getDisplay() != null && !getUiEnvironment().getDisplay().isDisposed()) { |
| Runnable t = new Runnable() { |
| @Override |
| public void run() { |
| if (!isUiDisposed()) { |
| try { |
| getUpdateUiFromScoutLock().acquire(); |
| // |
| handleScoutActionPropertyChange(e.getPropertyName(), e.getNewValue()); |
| } |
| finally { |
| getUpdateUiFromScoutLock().release(); |
| } |
| } |
| } |
| }; |
| getUiEnvironment().invokeUiLater(t); |
| } |
| } |
| } // end class P_ScoutActionPropertyChangeListener |
| } |