blob: ec6683f35b920be3e67d20ec054a1dc80b2afaad [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2001, 2008 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.wst.xsd.ui.internal.adt.design.directedit;
import java.text.MessageFormat;
import org.eclipse.jface.viewers.ComboBoxCellEditor;
import org.eclipse.jface.window.Window;
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.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.TraverseEvent;
import org.eclipse.swt.events.TraverseListener;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.TypedListener;
import org.eclipse.wst.xsd.ui.internal.adt.edit.ComponentReferenceEditManager;
import org.eclipse.wst.xsd.ui.internal.adt.edit.IComponentDialog;
import org.eclipse.wst.xsd.ui.internal.adt.editor.Messages;
/*
* This wraps the ComboBoxCellEditor.
* We need to apply and deactivate the combo on a single click (not on a double click like
* the ComboBoxCellEditor).
*/
public class ADTComboBoxCellEditor extends ComboBoxCellEditor
{
private static final int adtDefaultStyle = SWT.NONE;
/**
* Used to determine if the value should be applied to the cell.
*/
private boolean continueApply;
private boolean isTraversing = false;
private Object selectedValue;
private ComponentReferenceEditManager componentReferenceEditManager;
// This prevents the cell editor from being deactivated while handling the New or Browse selection.
private boolean isHandlingSelection = false;
/**
* Creates a new cell editor with a combo containing the given list of choices
* and parented under the given control. The cell editor value is the
* zero-based index of the selected item. Initially, the cell editor has no
* cell validator and the first item in the list is selected.
*
* @param parent
* the parent control
* @param items
* the list of strings for the combo box
*/
public ADTComboBoxCellEditor(Composite parent, String[] items, ComponentReferenceEditManager editManager)
{
super(parent, items, adtDefaultStyle | SWT.READ_ONLY);
setItems(items);
componentReferenceEditManager = editManager;
}
private void removeListeners(CCombo comboBox, int event)
{
Listener [] listeners = comboBox.getListeners(event);
int length = listeners.length;
for (int i = 0; i < length; i++)
{
Listener l = listeners[i];
if (l instanceof TypedListener)
{
TypedListener typedListener = (TypedListener)l;
String className = typedListener.getEventListener().getClass().getCanonicalName();
// It's possible that there are other typed listeners added to the CCombo.
// Currently there are none, but as an extra check, I want to ensure
// I'm removing the ones added from the inherited class.
// I've tested this and I know it removes the following:
// org.eclipse.jface.viewers.ComboBoxCellEditor$2
// org.eclipse.jface.viewers.ComboBoxCellEditor$4
// which are indeed the ones I'm customizing
if (className != null && className.contains("org.eclipse.jface.viewers.ComboBoxCellEditor"))
{
comboBox.removeListener(event, l);
}
}
}
}
/*
* (non-Javadoc) Method declared on CellEditor.
*/
protected Control createControl(Composite parent)
{
CCombo comboBox = (CCombo)super.createControl(parent);
comboBox.setFont(parent.getFont());
// Need to remove the listeners added from ComboBoxCellEditor
removeListeners(comboBox, SWT.Selection);
removeListeners(comboBox, SWT.DefaultSelection);
removeListeners(comboBox, SWT.FocusIn);
removeListeners(comboBox, SWT.FocusOut);
// Now add our custom listeners
comboBox.addSelectionListener(new SelectionAdapter()
{
public void widgetDefaultSelected(SelectionEvent event)
{
// Want the same behaviour since hitting return on Browse or New should launch the dialogs,
// and not immediately apply the value
// applyEditorValueAndDeactivate();
widgetSelected(event);
}
public void widgetSelected(SelectionEvent event)
{
continueApply = true;
CCombo comboBox = getCCombo();
isHandlingSelection = true;
Object newValue = null;
try
{
int selection = comboBox.getSelectionIndex();
if (isTraversing)
{
isTraversing = false;
return;
}
String[] items = getItems();
String stringSelection = items[selection];
if (stringSelection.equals(Messages._UI_ACTION_BROWSE))
{
continueApply = true;
newValue = invokeDialog(componentReferenceEditManager.getBrowseDialog());
}
else if (stringSelection.equals(Messages._UI_ACTION_NEW))
{
continueApply = true;
newValue = invokeDialog(componentReferenceEditManager.getNewDialog());
}
}
finally
{
isHandlingSelection = false;
}
if (continueApply)
{
if (newValue == null)
{
int index = comboBox.getSelectionIndex();
if (index != -1)
{
selectedValue = comboBox.getItem(index);
}
}
else
{
selectedValue = newValue;
}
applyEditorValueAndDeactivate();
focusLost();
}
}
});
comboBox.addTraverseListener(new TraverseListener()
{
public void keyTraversed(TraverseEvent e)
{
if (e.detail == SWT.TRAVERSE_ARROW_NEXT || e.detail == SWT.TRAVERSE_ARROW_PREVIOUS)
{
isTraversing = true;
}
}
});
comboBox.addFocusListener(new FocusAdapter()
{
public void focusLost(FocusEvent e)
{
if (!isHandlingSelection)
ADTComboBoxCellEditor.this.focusLost();
}
});
return comboBox;
}
private Object invokeDialog(IComponentDialog dialog)
{
Object newValue = null;
if (dialog == null)
{
return null;
}
//dialog.setInitialComponent(setObject);
if (dialog.createAndOpen() == Window.OK)
{
newValue = dialog.getSelectedComponent();
}
else
{
continueApply = false;
focusLost();
}
return newValue;
}
public Object getSelectedValue()
{
return selectedValue;
}
protected CCombo getCCombo()
{
return (CCombo)getControl();
}
///////// ComboBox cell editor
void applyEditorValueAndDeactivate()
{
// must set the selection before getting value
CCombo comboBox = getCCombo();
String[] items = getItems();
int selection = comboBox.getSelectionIndex();
Object newValue = doGetValue();
markDirty();
boolean isValid = isCorrect(newValue);
setValueValid(isValid);
if (!isValid)
{
// Only format if the 'index' is valid
if (items.length > 0 && selection >= 0 && selection < items.length)
{
// try to insert the current value into the error message.
setErrorMessage(MessageFormat.format(getErrorMessage(), new Object[] { items[selection] }));
}
else
{
// Since we don't have a valid index, assume we're using an
// 'edit'
// combo so format using its text value
setErrorMessage(MessageFormat.format(getErrorMessage(), new Object[] { comboBox.getText() }));
}
}
fireApplyEditorValue();
deactivate();
}
}