// ============================================================================ // // Copyright (C) 2006-2016 Talend Inc. - www.talend.com // // This source code is available under agreement available at // %InstallDIR%\features\org.talend.rcp.branding.%PRODUCTNAME%\%PRODUCTNAME%license.txt // // You should have received a copy of the agreement // along with this program; if not, write to Talend SA // 9 rue Pages 92150 Suresnes, France // // ============================================================================ package com.amalto.workbench.widgets.celleditor; import java.text.MessageFormat; import org.eclipse.core.runtime.Assert; import org.eclipse.jface.viewers.CellEditor; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.CCombo; import org.eclipse.swt.events.FocusAdapter; import org.eclipse.swt.events.FocusEvent; import org.eclipse.swt.events.FocusListener; import org.eclipse.swt.events.KeyAdapter; import org.eclipse.swt.events.KeyEvent; 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.SelectionListener; import org.eclipse.swt.events.TraverseEvent; import org.eclipse.swt.events.TraverseListener; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Layout; public abstract class EditableComboBoxDialogCellEditor extends CellEditor { private String[] items; private Composite editor; private CCombo comboBox; private Control contents; private Button button; private FocusListener buttonFocusListener; private ModifyListener modifyListener; private Object value = null; /** */ /** * Internal class for laying out the dialog. */ private class DialogCellLayout extends Layout { @Override public void layout(Composite editor, boolean force) { Rectangle bounds = editor.getClientArea(); Point size = button.computeSize(SWT.DEFAULT, SWT.DEFAULT, force); if (contents != null) { contents.setBounds(0, 0, bounds.width - size.x, bounds.height); } button.setBounds(bounds.width - size.x, 0, size.x, bounds.height); } @Override public Point computeSize(Composite editor, int wHint, int hHint, boolean force) { if (wHint != SWT.DEFAULT && hHint != SWT.DEFAULT) { return new Point(wHint, hHint); } Point contentsSize = contents.computeSize(SWT.DEFAULT, SWT.DEFAULT, force); Point buttonSize = button.computeSize(SWT.DEFAULT, SWT.DEFAULT, force); // Just return the button width to ensure the button is not clipped // if the label is long. // The label will just use whatever extra width there is Point result = new Point(buttonSize.x, Math.max(contentsSize.y, buttonSize.y)); return result; } } // Combo default style private static final int defaultStyle = SWT.NONE; protected FocusAdapter comboFocusListener; public EditableComboBoxDialogCellEditor() { setStyle(defaultStyle); } public EditableComboBoxDialogCellEditor(Composite parent, String[] items) { this(parent, items, defaultStyle); } public EditableComboBoxDialogCellEditor(Composite parent, String[] items, int style) { super(parent, style); setItems(items); } protected Button createButton(Composite parent) { Button result = new Button(parent, SWT.DOWN); result.setText(""); //$NON-NLS-1$ return result; } @Override protected Control createControl(Composite parent) { Font font = parent.getFont(); Color bg = parent.getBackground(); editor = new Composite(parent, getStyle()); editor.setFont(font); editor.setBackground(bg); editor.setLayout(new DialogCellLayout()); contents = createContents(editor); updateContents(value); button = createButton(editor); button.setFont(font); button.addKeyListener(new KeyAdapter() { @Override public void keyReleased(KeyEvent e) { if (e.character == '\u001b') { // Escape fireCancelEditor(); } } }); button.addFocusListener(getButtonFocusListener()); button.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent event) { button.removeFocusListener(getButtonFocusListener()); comboBox.removeFocusListener(getComboFocusListener()); Object newValue = openDialogBox(editor); button.addFocusListener(getButtonFocusListener()); comboBox.addFocusListener(getComboFocusListener()); if (newValue != null) { boolean newValidState = isCorrect(newValue); if (newValidState) { markDirty(); doSetValue(newValue); } else { setErrorMessage(MessageFormat.format(getErrorMessage(), new Object[] { newValue.toString() })); } } focusLost(); } }); setValueValid(true); return editor; } protected Control createContents(Composite cell) { comboBox = new CCombo(cell, getStyle()); comboBox.setFont(cell.getFont()); populateComboBoxItems(); comboBox.addKeyListener(getComboKeyListener()); comboBox.addModifyListener(getComboModifyListener()); comboBox.addSelectionListener(getComboSelectionListener()); comboBox.addTraverseListener(getTraverseListener()); comboBox.addFocusListener(getComboFocusListener()); return comboBox; } protected KeyAdapter getComboKeyListener() { return new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { keyReleaseOccured(e); } }; } private ModifyListener getComboModifyListener() { if (modifyListener == null) { modifyListener = new ModifyListener() { public void modifyText(ModifyEvent e) { editOccured(e); } }; } return modifyListener; } protected SelectionListener getComboSelectionListener() { return new SelectionAdapter() { @Override public void widgetDefaultSelected(SelectionEvent event) { applyEditorValueAndDeactivate(); } @Override public void widgetSelected(SelectionEvent event) { value = comboBox.getText(); } }; } protected TraverseListener getTraverseListener() { return new TraverseListener() { public void keyTraversed(TraverseEvent e) { if (e.detail == SWT.TRAVERSE_ESCAPE || e.detail == SWT.TRAVERSE_RETURN) { e.doit = false; } } }; } protected FocusListener getComboFocusListener() { if (comboFocusListener == null) { this.comboFocusListener = new FocusAdapter() { @Override public void focusLost(FocusEvent e) { if ((!comboBox.isFocusControl()) && !button.isFocusControl()) { EditableComboBoxDialogCellEditor.this.focusLost(); } } }; } return comboFocusListener; } @Override protected Object doGetValue() { return value; } @Override protected void doSetFocus() { if (comboBox != null) { comboBox.setFocus(); } } @Override protected void doSetValue(Object value) { this.value = value; updateContents(value); } private void populateComboBoxItems() { if (comboBox != null && items != null) { comboBox.removeAll(); for (int i = 0; i < items.length; i++) { comboBox.add(items[i], i); } comboBox.setText("");//$NON-NLS-1$ } } protected void applyEditorValueAndDeactivate() { Object newValue = comboBox.getText(); if (newValue != null && !newValue.equals(value.toString())) { boolean newValidState = isCorrect(newValue); if (newValidState) { markDirty(); doSetValue(newValue); } else { setErrorMessage(MessageFormat.format(getErrorMessage(), new Object[] { newValue.toString() })); } } fireApplyEditorValue(); deactivate(); } @Override protected void focusLost() { if (isActivated()) { applyEditorValueAndDeactivate(); } } @Override protected void keyReleaseOccured(KeyEvent keyEvent) { if (keyEvent.character == '\r') { // Return key if (comboBox != null && !comboBox.isDisposed()) { fireCancelEditor(); } } else if (keyEvent.character == '\t') { // tab key applyEditorValueAndDeactivate(); } } protected void editOccured(ModifyEvent e) { String value = comboBox.getText(); if (value == null) { value = "";//$NON-NLS-1$ } Object typedValue = value; boolean oldValidState = isValueValid(); boolean newValidState = isCorrect(typedValue); if (!newValidState) { // try to insert the current value into the error message. setErrorMessage(MessageFormat.format(getErrorMessage(), new Object[] { value })); } valueChanged(oldValidState, newValidState); } private FocusListener getButtonFocusListener() { if (buttonFocusListener == null) { buttonFocusListener = new FocusAdapter() { @Override public void focusLost(FocusEvent e) { EditableComboBoxDialogCellEditor.this.focusLost(); } }; } return buttonFocusListener; } private void updateContents(Object value) { Assert.isTrue(comboBox != null); if (value != null && value instanceof String) { comboBox.removeModifyListener(getComboModifyListener()); comboBox.setText((String) value); comboBox.addModifyListener(getComboModifyListener()); } } public String[] getItems() { return items; } public void setItems(String[] items) { Assert.isNotNull(items); this.items = items; populateComboBoxItems(); } public CCombo getComboBox() { return comboBox; } public Button getButton() { return button; } protected abstract Object openDialogBox(Control cellEditorWindow); }