1765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye/*******************************************************************************
2765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye * Copyright (c) 2011 Google, Inc.
3765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye * All rights reserved. This program and the accompanying materials
4765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye * are made available under the terms of the Eclipse Public License v1.0
5765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye * which accompanies this distribution, and is available at
6765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye * http://www.eclipse.org/legal/epl-v10.html
7765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye *
8765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye * Contributors:
9765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye *    Google, Inc. - initial API and implementation
10765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye *******************************************************************************/
11765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyepackage org.eclipse.wb.internal.core.model.property.editor;
12765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
13765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.jface.bindings.keys.KeyStroke;
14765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.jface.fieldassist.ContentProposalAdapter;
151f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbyeimport org.eclipse.jface.fieldassist.IContentProposal;
161f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbyeimport org.eclipse.jface.fieldassist.IContentProposalListener;
171f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbyeimport org.eclipse.jface.fieldassist.IContentProposalListener2;
18765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.jface.fieldassist.IContentProposalProvider;
19765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.jface.fieldassist.IControlContentAdapter;
20765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.jface.fieldassist.TextContentAdapter;
21765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.jface.viewers.ILabelProvider;
22765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.swt.SWT;
23765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.swt.events.FocusEvent;
24765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.swt.events.FocusListener;
25765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.swt.events.KeyAdapter;
26765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.swt.events.KeyEvent;
27765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.swt.events.KeyListener;
28765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.swt.graphics.Point;
29765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.swt.graphics.Rectangle;
30765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.swt.widgets.Display;
31765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.swt.widgets.Event;
32765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.swt.widgets.Listener;
33765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.swt.widgets.Text;
34765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.wb.internal.core.model.property.Property;
35765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.wb.internal.core.model.property.table.PropertyTable;
36765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
37765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye/**
38765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye * Abstract {@link PropertyEditor} for that uses {@link Text} as control.
39765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye *
40765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye * @author scheglov_ke
41765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye * @coverage core.model.property.editor
42765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye */
43765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyepublic abstract class AbstractTextPropertyEditor extends TextDisplayPropertyEditor {
44765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
45765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
46765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  // Editing
47765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
48765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
49765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private Text m_textControl;
50765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private boolean m_ignoreFocusLost;
51765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
52765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  // BEGIN ADT MODIFICATIONS
53765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  // ContentProposalAdapter which exposes the openProposalPopup method such
54765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  // that we can open the dialog up immediately on focus gain to show all available
55765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  // alternatives (the default implementation requires at least one keytroke before
56765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  // it shows up)
571f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye    private class ImmediateProposalAdapter extends ContentProposalAdapter
581f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye        implements FocusListener, IContentProposalListener, IContentProposalListener2 {
591f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye        private final PropertyTable m_propertyTable;
60767eb85ab3a32c1a9621eca167863e625b0927ccTor Norbye        private final IContentProposalProvider m_proposalProvider;
611f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye        public ImmediateProposalAdapter(
621f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye                Text control,
63765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye                IControlContentAdapter controlContentAdapter,
641f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye                IContentProposalProvider proposalProvider,
651f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye                KeyStroke keyStroke,
661f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye                char[] autoActivationCharacters,
671f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye                PropertyTable propertyTable) {
68765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            super(control, controlContentAdapter, proposalProvider, keyStroke,
69765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye                    autoActivationCharacters);
701f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye            m_propertyTable = propertyTable;
71767eb85ab3a32c1a9621eca167863e625b0927ccTor Norbye            m_proposalProvider = proposalProvider;
72765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
73765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            // On focus gain, start completing
741f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye            control.addFocusListener(this);
75765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
761f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye            // Listen on popup open and close events, in order to disable
771f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye            // focus handling on the textfield during those events.
781f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye            // This is necessary since otherwise as soon as the user clicks
791f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye            // on the popup with the mouse, the text field loses focus, and
801f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye            // then instantly closes the popup -- without the selection being
811f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye            // applied. See for example
821f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye            //   http://dev.eclipse.org/viewcvs/viewvc.cgi/org.eclipse.jface.snippets/
831f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye            //      Eclipse%20JFace%20Snippets/org/eclipse/jface/snippets/viewers/
841f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye            //      Snippet060TextCellEditorWithContentProposal.java?view=markup
851f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye            // for another example of this technique.
861f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye            addContentProposalListener((IContentProposalListener) this);
871f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye            addContentProposalListener((IContentProposalListener2) this);
88765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
89765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            /* Triggering on empty is disabled for now: it has the unfortunate side-effect
90765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye               that it's impossible to enter a blank text field - blank matches everything,
91765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye               so the first item will automatically be selected when you press return.
92765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
93765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
94765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            // If you edit the text and delete everything, the normal implementation
95765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            // will close the popup; we'll reopen it
96765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            control.addModifyListener(new ModifyListener() {
97765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye                @Override
98765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye                public void modifyText(ModifyEvent event) {
99765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye                    if (((Text) getControl()).getText().isEmpty()) {
100765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye                        openIfNecessary();
101765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye                    }
102765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye                }
103765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            });
104765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            */
105765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        }
106765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
107765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        private void openIfNecessary() {
108767eb85ab3a32c1a9621eca167863e625b0927ccTor Norbye            if (m_textControl == null || m_textControl.isDisposed() ||
109767eb85ab3a32c1a9621eca167863e625b0927ccTor Norbye                    m_proposalProvider.getProposals(m_textControl.getText(),
110767eb85ab3a32c1a9621eca167863e625b0927ccTor Norbye                            m_textControl.getCaretPosition()).length == 0) {
111767eb85ab3a32c1a9621eca167863e625b0927ccTor Norbye                return;
112767eb85ab3a32c1a9621eca167863e625b0927ccTor Norbye            }
113767eb85ab3a32c1a9621eca167863e625b0927ccTor Norbye
114765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            getControl().getDisplay().asyncExec(new Runnable() {
115765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye                @Override
116765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye                public void run() {
117765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye                    if (!isProposalPopupOpen()) {
118765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye                        openProposalPopup();
119765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye                    }
120765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye                }
121765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            });
122765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        }
1231f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye
1241f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye        // ---- Implements FocusListener ----
1251f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye
1261f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye        @Override
1271f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye        public void focusGained(FocusEvent event) {
1281f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye            openIfNecessary();
1291f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye        }
1301f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye
1311f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye        @Override
1321f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye        public void focusLost(FocusEvent event) {
1331f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye        }
1341f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye
1351f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye        // ---- Implements IContentProposalListener ----
1361f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye
1371f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye        @Override
1381f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye        public void proposalAccepted(IContentProposal proposal) {
1391f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye            closeProposalPopup();
1401f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye            m_propertyTable.deactivateEditor(true);
1411f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye        }
1421f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye
1431f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye        // ---- Implements IContentProposalListener2 ----
1441f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye
1451f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye        @Override
1461f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye        public void proposalPopupClosed(ContentProposalAdapter adapter) {
1471f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye            m_ignoreFocusLost = false;
1481f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye        }
1491f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye
1501f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye        @Override
1511f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye        public void proposalPopupOpened(ContentProposalAdapter adapter) {
1521f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye            m_ignoreFocusLost = true;
1531f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye        }
154765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
155765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  // END ADT MODIFICATIONS
156765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
157765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  @Override
158765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  public boolean activate(final PropertyTable propertyTable, final Property property, Point location)
159765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      throws Exception {
160765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // create Text
161765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    {
162765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      m_textControl = new Text(propertyTable, SWT.NONE);
1631f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye
1641f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye      @SuppressWarnings("unused")
1651f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye      TextControlActionsManager manager = new TextControlActionsManager(m_textControl);
1661f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye
167765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      m_textControl.setEditable(isEditable());
168765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
169765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        // BEGIN ADT MODIFICATIONS
170765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        // Add support for field completion, if the property provides an IContentProposalProvider
171765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        // via its the getAdapter method.
172765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        IContentProposalProvider completion = property.getAdapter(IContentProposalProvider.class);
173765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        if (completion != null) {
174765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            ImmediateProposalAdapter adapter = new ImmediateProposalAdapter(
1751f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye                    m_textControl, new TextContentAdapter(), completion, null, null,
1761f6650ac4338fe0eab9874f72cee21c231412d31Tor Norbye                    propertyTable);
177765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            adapter.setFilterStyle(ContentProposalAdapter.FILTER_NONE);
178765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            adapter.setProposalAcceptanceStyle(ContentProposalAdapter.PROPOSAL_REPLACE);
179765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            ILabelProvider labelProvider = property.getAdapter(ILabelProvider.class);
180765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            if (labelProvider != null) {
181765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye                adapter.setLabelProvider(labelProvider);
182765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            }
183765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        }
184765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        // END ADT MODIFICATIONS
185765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      m_textControl.setFocus();
186765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
187765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // add listeners
188765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    m_textControl.addKeyListener(new KeyAdapter() {
189765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      @Override
190765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      public void keyPressed(KeyEvent e) {
191765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        try {
192765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          handleKeyPressed(propertyTable, property, e);
193765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        } catch (Throwable ex) {
194765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          propertyTable.deactivateEditor(false);
195765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          propertyTable.handleException(ex);
196765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        }
197765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
198765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    });
199765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    m_textControl.addListener(SWT.FocusOut, new Listener() {
200765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      @Override
201765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    public void handleEvent(Event event) {
202765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        if (!m_ignoreFocusLost) {
203765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          propertyTable.deactivateEditor(true);
204765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        }
205765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
206765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    });
207765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // set data
208765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    toWidget(property);
209765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // keep us active
210765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    return true;
211765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
212765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
213765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  @Override
214765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  public final void setBounds(Rectangle bounds) {
215765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    m_textControl.setBounds(bounds);
216765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
217765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
218765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  @Override
219765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  public final void deactivate(PropertyTable propertyTable, Property property, boolean save) {
220765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    if (save) {
221765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      try {
222765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        toProperty(property);
223765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      } catch (Throwable e) {
224765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        propertyTable.deactivateEditor(false);
225765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        propertyTable.handleException(e);
226765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
227765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
228765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // dispose Text widget
229765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    if (m_textControl != null) {
230765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      m_textControl.dispose();
231765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      m_textControl = null;
232765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
233765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
234765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
235765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  @Override
236765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  public void keyDown(PropertyTable propertyTable, Property property, KeyEvent event)
237765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      throws Exception {
238765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    boolean withAlt = (event.stateMask & SWT.ALT) != 0;
239765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    boolean withCtrl = (event.stateMask & SWT.CTRL) != 0;
240765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    if (event.character != 0 && !(withAlt || withCtrl)) {
241765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      propertyTable.activateEditor(property, null);
242765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      postKeyEvent(SWT.KeyDown, event);
243765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      postKeyEvent(SWT.KeyUp, event);
244765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
245765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
246765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
247765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
248765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * Posts low-level {@link SWT.KeyDown} or {@link SWT.KeyUp} event.
249765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
250765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private static void postKeyEvent(int type, KeyEvent event) {
251765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    Event lowEvent = new Event();
252765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    lowEvent.type = type;
253765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    lowEvent.keyCode = event.keyCode;
254765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    lowEvent.character = event.character;
255765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // post event
256765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    Display.getCurrent().post(lowEvent);
257765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
258765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
259765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
260765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
261765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  // Events
262765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
263765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
264765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
265765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * Handles {@link KeyListener#keyPressed(KeyEvent)}.
266765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
267765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private void handleKeyPressed(PropertyTable propertyTable, Property property, KeyEvent e)
268765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      throws Exception {
269765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    if (e.keyCode == SWT.CR) {
270765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      toProperty(property);
271765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
272765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      // BEGIN ADT MODIFICATIONS
273765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      // After pressing return, dismiss the text cursor to make the value "committed".
274765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      // I'm not sure why this is necessary here and not in WindowBuilder proper.
275765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      propertyTable.deactivateEditor(true);
276765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      // END ADT MODIFICATIONS
277765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    } else if (e.keyCode == SWT.ESC) {
278765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      propertyTable.deactivateEditor(false);
279765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    } else if (e.keyCode == SWT.ARROW_UP || e.keyCode == SWT.ARROW_DOWN) {
280765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      e.doit = false;
281765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      boolean success = toProperty(property);
282765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      // don't allow navigation if current text can not be transferred to property
283765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      if (!success) {
284765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        return;
285765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
286765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      // OK, deactivate and navigate
287765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      propertyTable.deactivateEditor(true);
288765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      propertyTable.navigate(e);
289765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
290765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
291765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
292765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
293765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
294765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  // Implementation
295765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
296765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
297765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private String m_currentText;
298765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
299765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
300765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * Transfers data from {@link Property} to widget.
301765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
302765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private void toWidget(Property property) throws Exception {
303765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // prepare text
304765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    String text = getEditorText(property);
305765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    if (text == null) {
306765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      text = "";
307765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
308765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // set text
309765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    m_currentText = text;
310765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    m_textControl.setText(text);
311765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    m_textControl.selectAll();
312765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
313765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
314765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
315765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * Transfers data from widget to {@link Property}.
316765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   *
317765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * @return <code>true</code> if transfer was successful.
318765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
319765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private boolean toProperty(Property property) throws Exception {
320f38ceabb9b297d5fec04b992695424853967ba74Tor Norbye    // BEGIN ADT MODIFICATIONS
321f38ceabb9b297d5fec04b992695424853967ba74Tor Norbye    if (m_textControl == null) {
322f38ceabb9b297d5fec04b992695424853967ba74Tor Norbye      return false;
323f38ceabb9b297d5fec04b992695424853967ba74Tor Norbye    }
324f38ceabb9b297d5fec04b992695424853967ba74Tor Norbye    // END ADT MODIFICATIONS
325765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    String text = m_textControl.getText();
326765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // change property only if text was changed
327765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    if (!m_currentText.equals(text)) {
328765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      m_ignoreFocusLost = true;
329765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      try {
330765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        boolean success = setEditorText(property, text);
331765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        if (!success) {
332765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          return false;
333765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        }
334765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      } finally {
335765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        m_ignoreFocusLost = false;
336765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
337765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      // if value was successfully changed, update current text
338765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      m_currentText = text;
339765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
340765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // OK, success
341765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    return true;
342765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
343765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
344765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
345765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
346765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  // Operations
347765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
348765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
349765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
350765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * @return <code>true</code> if this editor can modify text.
351765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
352765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  protected boolean isEditable() {
353765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    return true;
354765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
355765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
356765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
357765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * @return the text to display in {@link Text} control.
358765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
359765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  protected abstract String getEditorText(Property property) throws Exception;
360765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
361765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
362765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * Modifies {@link Property} using given text.
363765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   *
364765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * @return <code>true</code> if {@link Property} was successfully modified.
365765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
366765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  protected abstract boolean setEditorText(Property property, String text) throws Exception;
367765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye}
368