/** * 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(); } } }