AbstractTextPropertyEditor.java revision 765e52e2d30d0754625b8c7af6c36e93612f15be
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;
15765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.jface.fieldassist.IContentProposalProvider;
16765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.jface.fieldassist.IControlContentAdapter;
17765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.jface.fieldassist.TextContentAdapter;
18765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.jface.viewers.ILabelProvider;
19765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.swt.SWT;
20765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.swt.events.FocusEvent;
21765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.swt.events.FocusListener;
22765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.swt.events.KeyAdapter;
23765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.swt.events.KeyEvent;
24765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.swt.events.KeyListener;
25765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.swt.graphics.Point;
26765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.swt.graphics.Rectangle;
27765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.swt.widgets.Display;
28765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.swt.widgets.Event;
29765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.swt.widgets.Listener;
30765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.swt.widgets.Text;
31765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.wb.internal.core.model.property.Property;
32765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.wb.internal.core.model.property.table.PropertyTable;
33765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
34765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye/**
35765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye * Abstract {@link PropertyEditor} for that uses {@link Text} as control.
36765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye *
37765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye * @author scheglov_ke
38765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye * @coverage core.model.property.editor
39765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye */
40765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyepublic abstract class AbstractTextPropertyEditor extends TextDisplayPropertyEditor {
41765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
42765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
43765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  // Editing
44765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
45765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
46765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private Text m_textControl;
47765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private boolean m_ignoreFocusLost;
48765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
49765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  // BEGIN ADT MODIFICATIONS
50765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  // ContentProposalAdapter which exposes the openProposalPopup method such
51765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  // that we can open the dialog up immediately on focus gain to show all available
52765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  // alternatives (the default implementation requires at least one keytroke before
53765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  // it shows up)
54765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    private static class ImmediateProposalAdapter extends ContentProposalAdapter {
55765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        public ImmediateProposalAdapter(Text control,
56765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye                IControlContentAdapter controlContentAdapter,
57765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye                IContentProposalProvider proposalProvider, KeyStroke keyStroke,
58765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye                char[] autoActivationCharacters) {
59765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            super(control, controlContentAdapter, proposalProvider, keyStroke,
60765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye                    autoActivationCharacters);
61765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
62765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            // On focus gain, start completing
63765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            control.addFocusListener(new FocusListener() {
64765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye                @Override
65765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye                public void focusGained(FocusEvent event) {
66765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye                    openIfNecessary();
67765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye                }
68765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
69765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye                @Override
70765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye                public void focusLost(FocusEvent event) {
71765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye                }
72765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            });
73765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
74765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            /* Triggering on empty is disabled for now: it has the unfortunate side-effect
75765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye               that it's impossible to enter a blank text field - blank matches everything,
76765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye               so the first item will automatically be selected when you press return.
77765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
78765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
79765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            // If you edit the text and delete everything, the normal implementation
80765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            // will close the popup; we'll reopen it
81765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            control.addModifyListener(new ModifyListener() {
82765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye                @Override
83765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye                public void modifyText(ModifyEvent event) {
84765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye                    if (((Text) getControl()).getText().isEmpty()) {
85765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye                        openIfNecessary();
86765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye                    }
87765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye                }
88765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            });
89765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            */
90765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        }
91765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
92765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        private void openIfNecessary() {
93765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            getControl().getDisplay().asyncExec(new Runnable() {
94765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye                @Override
95765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye                public void run() {
96765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye                    if (!isProposalPopupOpen()) {
97765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye                        openProposalPopup();
98765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye                    }
99765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye                }
100765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            });
101765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        }
102765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
103765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  // END ADT MODIFICATIONS
104765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
105765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  @Override
106765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  public boolean activate(final PropertyTable propertyTable, final Property property, Point location)
107765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      throws Exception {
108765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // create Text
109765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    {
110765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      m_textControl = new Text(propertyTable, SWT.NONE);
111765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      new TextControlActionsManager(m_textControl);
112765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      m_textControl.setEditable(isEditable());
113765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
114765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        // BEGIN ADT MODIFICATIONS
115765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        // Add support for field completion, if the property provides an IContentProposalProvider
116765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        // via its the getAdapter method.
117765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        IContentProposalProvider completion = property.getAdapter(IContentProposalProvider.class);
118765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        if (completion != null) {
119765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            ImmediateProposalAdapter adapter = new ImmediateProposalAdapter(
120765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye                    m_textControl, new TextContentAdapter(), completion, null, null);
121765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            adapter.setFilterStyle(ContentProposalAdapter.FILTER_NONE);
122765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            adapter.setProposalAcceptanceStyle(ContentProposalAdapter.PROPOSAL_REPLACE);
123765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            ILabelProvider labelProvider = property.getAdapter(ILabelProvider.class);
124765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            if (labelProvider != null) {
125765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye                adapter.setLabelProvider(labelProvider);
126765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            }
127765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        }
128765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        // END ADT MODIFICATIONS
129765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      m_textControl.setFocus();
130765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
131765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // add listeners
132765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    m_textControl.addKeyListener(new KeyAdapter() {
133765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      @Override
134765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      public void keyPressed(KeyEvent e) {
135765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        try {
136765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          handleKeyPressed(propertyTable, property, e);
137765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        } catch (Throwable ex) {
138765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          propertyTable.deactivateEditor(false);
139765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          propertyTable.handleException(ex);
140765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        }
141765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
142765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    });
143765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    m_textControl.addListener(SWT.FocusOut, new Listener() {
144765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      @Override
145765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    public void handleEvent(Event event) {
146765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        if (!m_ignoreFocusLost) {
147765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          propertyTable.deactivateEditor(true);
148765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        }
149765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
150765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    });
151765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // set data
152765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    toWidget(property);
153765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // keep us active
154765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    return true;
155765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
156765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
157765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  @Override
158765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  public final void setBounds(Rectangle bounds) {
159765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    m_textControl.setBounds(bounds);
160765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
161765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
162765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  @Override
163765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  public final void deactivate(PropertyTable propertyTable, Property property, boolean save) {
164765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    if (save) {
165765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      try {
166765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        toProperty(property);
167765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      } catch (Throwable e) {
168765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        propertyTable.deactivateEditor(false);
169765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        propertyTable.handleException(e);
170765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
171765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
172765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // dispose Text widget
173765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    if (m_textControl != null) {
174765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      m_textControl.dispose();
175765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      m_textControl = null;
176765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
177765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
178765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
179765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  @Override
180765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  public void keyDown(PropertyTable propertyTable, Property property, KeyEvent event)
181765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      throws Exception {
182765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    boolean withAlt = (event.stateMask & SWT.ALT) != 0;
183765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    boolean withCtrl = (event.stateMask & SWT.CTRL) != 0;
184765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    if (event.character != 0 && !(withAlt || withCtrl)) {
185765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      propertyTable.activateEditor(property, null);
186765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      postKeyEvent(SWT.KeyDown, event);
187765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      postKeyEvent(SWT.KeyUp, event);
188765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
189765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
190765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
191765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
192765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * Posts low-level {@link SWT.KeyDown} or {@link SWT.KeyUp} event.
193765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
194765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private static void postKeyEvent(int type, KeyEvent event) {
195765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    Event lowEvent = new Event();
196765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    lowEvent.type = type;
197765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    lowEvent.keyCode = event.keyCode;
198765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    lowEvent.character = event.character;
199765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // post event
200765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    Display.getCurrent().post(lowEvent);
201765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
202765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
203765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
204765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
205765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  // Events
206765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
207765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
208765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
209765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * Handles {@link KeyListener#keyPressed(KeyEvent)}.
210765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
211765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private void handleKeyPressed(PropertyTable propertyTable, Property property, KeyEvent e)
212765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      throws Exception {
213765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    if (e.keyCode == SWT.CR) {
214765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      toProperty(property);
215765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
216765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      // BEGIN ADT MODIFICATIONS
217765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      // After pressing return, dismiss the text cursor to make the value "committed".
218765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      // I'm not sure why this is necessary here and not in WindowBuilder proper.
219765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      propertyTable.deactivateEditor(true);
220765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      // END ADT MODIFICATIONS
221765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    } else if (e.keyCode == SWT.ESC) {
222765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      propertyTable.deactivateEditor(false);
223765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    } else if (e.keyCode == SWT.ARROW_UP || e.keyCode == SWT.ARROW_DOWN) {
224765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      e.doit = false;
225765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      boolean success = toProperty(property);
226765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      // don't allow navigation if current text can not be transferred to property
227765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      if (!success) {
228765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        return;
229765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
230765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      // OK, deactivate and navigate
231765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      propertyTable.deactivateEditor(true);
232765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      propertyTable.navigate(e);
233765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
234765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
235765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
236765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
237765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
238765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  // Implementation
239765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
240765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
241765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private String m_currentText;
242765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
243765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
244765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * Transfers data from {@link Property} to widget.
245765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
246765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private void toWidget(Property property) throws Exception {
247765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // prepare text
248765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    String text = getEditorText(property);
249765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    if (text == null) {
250765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      text = "";
251765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
252765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // set text
253765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    m_currentText = text;
254765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    m_textControl.setText(text);
255765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    m_textControl.selectAll();
256765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
257765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
258765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
259765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * Transfers data from widget to {@link Property}.
260765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   *
261765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * @return <code>true</code> if transfer was successful.
262765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
263765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private boolean toProperty(Property property) throws Exception {
264765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    String text = m_textControl.getText();
265765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // change property only if text was changed
266765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    if (!m_currentText.equals(text)) {
267765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      m_ignoreFocusLost = true;
268765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      try {
269765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        boolean success = setEditorText(property, text);
270765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        if (!success) {
271765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          return false;
272765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        }
273765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      } finally {
274765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        m_ignoreFocusLost = false;
275765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
276765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      // if value was successfully changed, update current text
277765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      m_currentText = text;
278765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
279765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // OK, success
280765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    return true;
281765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
282765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
283765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
284765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
285765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  // Operations
286765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
287765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
288765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
289765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * @return <code>true</code> if this editor can modify text.
290765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
291765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  protected boolean isEditable() {
292765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    return true;
293765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
294765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
295765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
296765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * @return the text to display in {@link Text} control.
297765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
298765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  protected abstract String getEditorText(Property property) throws Exception;
299765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
300765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
301765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * Modifies {@link Property} using given text.
302765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   *
303765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * @return <code>true</code> if {@link Property} was successfully modified.
304765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
305765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  protected abstract boolean setEditorText(Property property, String text) throws Exception;
306765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye}
307