blob: c8d43d8a1e54b3411f153502285f234a0a4cd79e [file] [log] [blame]
/**
* Copyright (c) 2002-2010 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 - Initial API and implementation
*/
package org.eclipse.emf.common.ui.celleditor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import org.eclipse.emf.common.CommonPlugin;
import org.eclipse.jface.viewers.ComboBoxCellEditor;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CCombo;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
/**
* This uses a list of objects and a label provider to build a combo box based on model objects rather than on strings.
* If sort is true, the list will be modified to match the order of the sorted labels.
*/
public class ExtendedComboBoxCellEditor extends ComboBoxCellEditor
{
private static class StringPositionPair implements Comparable<StringPositionPair>
{
Comparator<String> comparator = CommonPlugin.INSTANCE.getComparator();
public String key;
public int position;
StringPositionPair(String key, int position)
{
this.key = key;
this.position = position;
}
public int compareTo(StringPositionPair object)
{
if (object == this)
{
return 0;
}
else
{
StringPositionPair that = object;
return comparator.compare(key, that.key);
}
}
}
public static boolean select(String filter, String labelValue)
{
if (filter != null && filter.length() > 0)
{
if (filter.length() > labelValue.length())
{
return false;
}
for (int i = 0; i < filter.length(); i++)
{
if (Character.toLowerCase(filter.charAt(i)) != Character.toLowerCase(labelValue.charAt(i)))
{
return false;
}
}
}
return true;
}
public static <T> String[] createItems(List<T> list, ILabelProvider labelProvider, boolean sorted)
{
return createItems(list, labelProvider, null, sorted);
}
public static <T> String[] createItems(List<T> list, ILabelProvider labelProvider, String filter, boolean sorted)
{
String[] result;
if (filter != null && filter.length() > 0)
{
sorted = true;
}
// If there are objects to populate...
//
if (list != null && list.size() > 0)
{
if (sorted)
{
List<T> unsortedList = new ArrayList<T>(list.size());
if (filter != null && filter.length() > 0)
{
for (int i = 0; i < list.size(); i++)
{
if (select(filter, labelProvider.getText(list.get(i))))
{
unsortedList.add(list.get(i));
}
}
}
else
{
unsortedList.addAll(list);
}
list.clear();
StringPositionPair[] pairs = new StringPositionPair [unsortedList.size()];
for (int i = 0, size = unsortedList.size(); i < size; ++i)
{
Object object = unsortedList.get(i);
pairs[i] = new StringPositionPair(labelProvider.getText(object), i);
}
Arrays.sort(pairs);
// Create a new array.
//
result = new String [unsortedList.size()];
// Fill in the result array with labels and re-populate the original list in order.
//
for (int i = 0, size = unsortedList.size(); i < size; ++i)
{
result[i] = pairs[i].key;
list.add(unsortedList.get(pairs[i].position));
}
}
else
{
// Create a new array.
//
result = new String [list.size()];
// Fill in the array with labels.
//
for (int i = 0, size = list.size(); i < size; ++i)
{
Object object = list.get(i);
result[i] = labelProvider.getText(object);
}
}
}
else
{
result = new String [] { "" };
}
return result;
}
/**
* This keeps track of the list of model objects.
*/
protected List<?> originalList;
protected List<?> list;
protected ILabelProvider labelProvider;
protected boolean sorted;
public ExtendedComboBoxCellEditor(Composite composite, List<?> list, ILabelProvider labelProvider)
{
this(composite, list, labelProvider, false, SWT.READ_ONLY);
}
public ExtendedComboBoxCellEditor(Composite composite, List<?> list, ILabelProvider labelProvider, boolean sorted)
{
this(composite, list, labelProvider, sorted, SWT.READ_ONLY);
}
public ExtendedComboBoxCellEditor(Composite composite, List<?> list, ILabelProvider labelProvider, int style)
{
this(composite, list, labelProvider, false, style);
}
public ExtendedComboBoxCellEditor(Composite composite, List<?> list, ILabelProvider labelProvider, boolean sorted, int style)
{
super(composite, createItems(sorted ? list = new ArrayList<Object>(list) : list, labelProvider, null, sorted), style);
this.originalList = list;
this.list = list;
this.labelProvider = labelProvider;
this.sorted = sorted;
if ((style & SWT.READ_ONLY) != 0)
{
new FilteringAdapter(getControl());
}
}
protected void refreshItems(String filter)
{
CCombo combo = (CCombo)getControl();
if (combo != null && !combo.isDisposed())
{
ArrayList<Object> newList = new ArrayList<Object>(originalList);
String[] items = createItems(newList, labelProvider, filter, sorted);
if (!newList.equals(list))
{
Object previousValue = getValue();
list = newList;
combo.setItems(items);
if (list.contains(previousValue))
{
setValue(previousValue);
}
else if (!list.isEmpty())
{
setValue(list.get(0));
}
}
}
}
@Override
public Object doGetValue()
{
// Get the index into the list via this call to super.
//
int index = (Integer)super.doGetValue();
return index < list.size() && index >= 0 ? list.get((Integer)super.doGetValue()) : null;
}
@Override
public void doSetValue(Object value)
{
// Set the index of the object value in the list via this call to super.
//
int index = list.indexOf(value);
if (index != -1)
{
super.doSetValue(index);
}
}
public class FilteringAdapter implements KeyListener, FocusListener
{
public FilteringAdapter(Control control)
{
control.addKeyListener(this);
control.addFocusListener(this);
}
private StringBuffer filter = new StringBuffer();
private void refreshItems()
{
ExtendedComboBoxCellEditor.this.refreshItems(filter.toString());
}
public void keyPressed(KeyEvent e)
{
e.doit = false;
if (e.keyCode == SWT.DEL || e.keyCode == SWT.BS)
{
if (filter.length() > 0)
{
filter = new StringBuffer(filter.substring(0, filter.length() - 1));
}
}
else if (e.keyCode == SWT.ARROW_UP || e.keyCode == SWT.ARROW_DOWN || e.keyCode == SWT.CR || e.keyCode == SWT.KEYPAD_CR || e.keyCode == SWT.LF)
{
e.doit = true;
}
else if (e.keyCode == SWT.ESC)
{
filter = new StringBuffer();
}
else if (e.character != '\0')
{
filter.append(e.character);
}
if (!e.doit)
{
refreshItems();
}
}
public void keyReleased(KeyEvent e)
{
// Do nothing
}
public void focusGained(FocusEvent e)
{
filter = new StringBuffer();
}
public void focusLost(FocusEvent e)
{
filter = new StringBuffer();
refreshItems();
}
}
}