1/*******************************************************************************
2 * Copyright (c) 2011 Google, Inc.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 *    Google, Inc. - initial API and implementation
10 *******************************************************************************/
11package org.eclipse.wb.internal.core.model.property.editor;
12
13import org.eclipse.wb.core.controls.CCombo3;
14import org.eclipse.wb.core.controls.CComboBox;
15import org.eclipse.wb.internal.core.model.property.Property;
16import org.eclipse.wb.internal.core.model.property.table.PropertyTable;
17import org.eclipse.wb.internal.core.utils.execution.ExecutionUtils;
18import org.eclipse.wb.internal.core.utils.execution.RunnableEx;
19
20import org.eclipse.swt.SWT;
21import org.eclipse.swt.events.FocusAdapter;
22import org.eclipse.swt.events.FocusEvent;
23import org.eclipse.swt.events.KeyAdapter;
24import org.eclipse.swt.events.KeyEvent;
25import org.eclipse.swt.events.SelectionAdapter;
26import org.eclipse.swt.events.SelectionEvent;
27import org.eclipse.swt.graphics.Point;
28import org.eclipse.swt.graphics.Rectangle;
29
30/**
31 * The {@link PropertyEditor} for selecting single value using {@link CComboBox}. This editor has
32 * in-line search-feature and is more suitable (vs {@link AbstractComboPropertyEditor}) for
33 * properties with large lists of value items.
34 *
35 * @author sablin_aa
36 * @author scheglov_ke
37 * @coverage core.model.property.editor
38 */
39public abstract class AbstractComboBoxPropertyEditor extends TextDisplayPropertyEditor {
40  ////////////////////////////////////////////////////////////////////////////
41  //
42  // Editing
43  //
44  ////////////////////////////////////////////////////////////////////////////
45  private CComboBox m_combo;
46  private String m_dropDelayedText;
47
48  @Override
49  public final boolean activate(final PropertyTable propertyTable,
50      final Property property,
51      Point location) throws Exception {
52    m_combo = new CComboBox(propertyTable, SWT.NONE);
53    // initialize
54    addItems(property, m_combo);
55    selectItem(property, m_combo);
56    // install listeners
57    m_combo.addKeyListener(new KeyAdapter() {
58      @Override
59      public void keyPressed(KeyEvent e) {
60        handleKeyPressed(propertyTable, property, e);
61      }
62    });
63    m_combo.addFocusListener(new FocusAdapter() {
64      @Override
65      public void focusLost(FocusEvent e) {
66        propertyTable.deactivateEditor(true);
67      }
68    });
69    m_combo.addSelectionListener(new SelectionAdapter() {
70      @Override
71      public void widgetSelected(SelectionEvent e) {
72        propertyTable.deactivateEditor(true);
73      }
74    });
75    m_combo.setFocus();
76    // schedule showing drop-down, because we don't have bounds yet
77    ExecutionUtils.runAsync(new RunnableEx() {
78      public void run() throws Exception {
79        m_combo.comboDropDown(true);
80        if (m_dropDelayedText != null) {
81          m_combo.setEditText(m_dropDelayedText);
82          m_combo.setEditSelection(m_dropDelayedText.length(), m_dropDelayedText.length());
83          m_dropDelayedText = null;
84        }
85      }
86    });
87    // keep editor active
88    return true;
89  }
90
91  private void handleKeyPressed(PropertyTable propertyTable, Property property, KeyEvent e) {
92    if (e.keyCode == SWT.ESC) {
93      propertyTable.deactivateEditor(false);
94    } else if (e.keyCode == SWT.ARROW_UP || e.keyCode == SWT.ARROW_DOWN) {
95      e.doit = false;
96      propertyTable.deactivateEditor(true);
97      propertyTable.navigate(e);
98    }
99  }
100
101  @Override
102  public final void deactivate(PropertyTable propertyTable, Property property, boolean save) {
103    if (save) {
104      toProperty(propertyTable, property);
105    }
106    if (m_combo != null) {
107      m_combo.dispose();
108      m_combo = null;
109    }
110  }
111
112  private void toProperty(PropertyTable propertyTable, Property property) {
113    try {
114      toPropertyEx(property, m_combo);
115    } catch (Throwable e) {
116      propertyTable.handleException(e);
117    }
118  }
119
120  @Override
121  public void setBounds(Rectangle bounds) {
122    m_combo.setBounds(bounds);
123  }
124
125  @Override
126  public void keyDown(PropertyTable propertyTable, Property property, KeyEvent event)
127      throws Exception {
128    boolean withAlt = (event.stateMask & SWT.ALT) != 0;
129    boolean withCtrl = (event.stateMask & SWT.CTRL) != 0;
130    if (event.character > 0x20 && !(withAlt || withCtrl)) {
131      propertyTable.activateEditor(property, null);
132      m_dropDelayedText = "" + event.character;
133    }
134  }
135
136  ////////////////////////////////////////////////////////////////////////////
137  //
138  // Abstract methods
139  //
140  ////////////////////////////////////////////////////////////////////////////
141  /**
142   * Adds items to given {@link CComboBox}.
143   */
144  protected abstract void addItems(Property property, CComboBox combo) throws Exception;
145
146  /**
147   * Selects current item in given {@link CCombo3}.
148   */
149  protected void selectItem(Property property, CComboBox combo) throws Exception {
150  }
151
152  /**
153   * Transfers data from widget to {@link Property}.
154   */
155  protected abstract void toPropertyEx(Property property, CComboBox combo) throws Exception;
156}
157