package com.isencia.passerelle.workbench.model.editor.ui.cell;
import java.text.MessageFormat;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.swt.SWT;
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.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
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 DialogBrowserEditor extends TextCellEditor {
private Button button;
/**
* Listens for 'focusLost' events and fires the 'apply' event as long
* as the focus wasn't lost because the dialog was opened.
*/
private FocusListener buttonFocusListener;
public DialogBrowserEditor(Composite aComposite) {
super(aComposite);
}
/* (non-Javadoc)
* Method declared on CellEditor.
*/
protected Control createControl(final Composite parent) {
final Composite editor = new Composite(parent, getStyle());
editor.setFont(parent.getFont());
editor.setBackground(parent.getBackground());
editor.setLayout(new DialogCellLayout());
super.createControl(editor);
text.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, true));
button = createButton(editor);
button.setFont(editor.getFont());
button.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false));
button.addKeyListener(new KeyAdapter() {
/* (non-Javadoc)
* @see org.eclipse.swt.events.KeyListener#keyReleased(org.eclipse.swt.events.KeyEvent)
*/
public void keyReleased(KeyEvent e) {
if (e.character == '\u001b') { // Escape
fireCancelEditor();
}
}
});
button.addFocusListener(getButtonFocusListener());
button.addSelectionListener(new SelectionAdapter() {
/* (non-Javadoc)
* @see org.eclipse.swt.events.SelectionListener#widgetSelected(org.eclipse.swt.events.SelectionEvent)
*/
public void widgetSelected(SelectionEvent event) {
// Remove the button's focus listener since it's guaranteed
// to lose focus when the dialog opens
button.removeFocusListener(getButtonFocusListener());
Object newValue = openDialogBox(editor, doGetValue());
// Re-add the listener once the dialog closes
button.addFocusListener(getButtonFocusListener());
if (newValue != null) {
boolean newValidState = isCorrect(newValue);
if (newValidState) {
markDirty();
doSetValue(newValue);
} else {
// try to insert the current value into the error message.
setErrorMessage(MessageFormat.format(getErrorMessage(),
new Object[] { newValue.toString() }));
}
fireApplyEditorValue();
}
}
});
setValueValid(true);
return editor;
}
/**
* Creates the button for this cell editor under the given parent control.
* <p>
* The default implementation of this framework method creates the button
* display on the right hand side of the dialog cell editor. Subclasses
* may extend or reimplement.
* </p>
*
* @param parent the parent control
* @return the new button control
*/
protected Button createButton(Composite parent) {
Button result = new Button(parent, SWT.DOWN);
result.setText("..."); //$NON-NLS-1$
return result;
}
/**
* Return a listener for button focus.
* @return FocusListener
*/
private FocusListener getButtonFocusListener() {
if (buttonFocusListener == null) {
buttonFocusListener = new FocusListener() {
/* (non-Javadoc)
* @see org.eclipse.swt.events.FocusListener#focusGained(org.eclipse.swt.events.FocusEvent)
*/
public void focusGained(FocusEvent e) {
// Do nothing
}
/* (non-Javadoc)
* @see org.eclipse.swt.events.FocusListener#focusLost(org.eclipse.swt.events.FocusEvent)
*/
public void focusLost(FocusEvent e) {
DialogBrowserEditor.this.focusLost();
}
};
}
return buttonFocusListener;
}
/**
* Opens a dialog box under the given parent control and returns the
* dialog's value when it closes, or <code>null</code> if the dialog
* was canceled or no selection was made in the dialog.
* <p>
* This framework method must be implemented by concrete subclasses.
* It is called when the user has pressed the button and the dialog
* box must pop up.
* </p>
*
* @param cellEditorWindow the parent control cell editor's window
* so that a subclass can adjust the dialog box accordingly
* @return the selected value, or <code>null</code> if the dialog was
* canceled or no selection was made in the dialog
*/
protected abstract Object openDialogBox(Control cellEditorWindow, final Object value);
protected void focusLost() {
if (text.isFocusControl() || button.isFocusControl()) return;
if (isActivated()) {
fireApplyEditorValue();
deactivate();
}
}
/**
* Internal class for laying out the dialog.
*/
private class DialogCellLayout extends Layout {
public void layout(Composite editor, boolean force) {
Rectangle bounds = editor.getClientArea();
Point size = button.computeSize(SWT.DEFAULT, SWT.DEFAULT, force);
if (text != null) {
text.setBounds(0, 0, bounds.width - size.x, bounds.height);
}
button.setBounds(bounds.width - size.x, 0, size.x, bounds.height);
}
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 = text.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;
}
}
}