blob: 6407e85e3e0d3d6e9a0190a4681a5c5009ff11b1 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005 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.bpel.common.ui.details.viewers;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.runtime.Assert;
import org.eclipse.jface.viewers.IBaseLabelProvider;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.StructuredViewer;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Widget;
/**
* A concrete viewer based on an SWT custom <code>CCombo</code> control.
*/
public class CComboViewer extends StructuredViewer {
private org.eclipse.swt.custom.CCombo combo;
private List<Object> comboMap = new ArrayList<Object>();
/**
* Creates a combo viewer on a newly-created combo control under the given parent.
* The combo control is created using the SWT style bits <code>H_SCROLL, V_SCROLL,</code> and <code>BORDER</code>.
* The viewer has no input, no content provider, a default label provider,
* no sorter, and no filters.
*
* @param parent the parent control
*/
public CComboViewer(Composite parent) {
this(parent, SWT.H_SCROLL | SWT.V_SCROLL /* | SWT.BORDER*/
);
}
/**
* Creates a combo viewer on a newly-created combo control under the given parent.
* The combo control is created using the given SWT style bits.
* The viewer has no input, no content provider, a default label provider,
* no sorter, and no filters.
*
* @param parent the parent control
* @param style the SWT style bits
*/
public CComboViewer(Composite parent, int style) {
this(new org.eclipse.swt.custom.CCombo(parent, style));
}
/**
* Creates a combo viewer on the given combo control.
* The viewer has no input, no content provider, a default label provider,
* no sorter, and no filters.
*
* @param combo the combo control
*/
public CComboViewer(org.eclipse.swt.custom.CCombo curCombo) {
this.combo = curCombo;
hookControl(curCombo);
Listener curListener = new Listener() {
public void handleEvent(Event event) {
switch (event.type) {
case SWT.FocusIn :
{
combo.setFocus(); //* activates the text widget of the combo
break;
}
}
}
};
curCombo.addListener(SWT.FocusIn, curListener);
curCombo.addListener(SWT.FocusOut, curListener);
}
/**
* Adds the given elements to this combo viewer.
* If this viewer does not have a sorter, the elements are added at the end
* in the order given; otherwise the elements are inserted at appropriate positions.
* <p>
* This method should be called (by the content provider) when elements
* have been added to the model, in order to cause the viewer to accurately
* reflect the model. This method only affects the viewer, not the model.
* </p>
*
* @param elements the elements to add
*/
public void add(Object[] elements) {
Object[] filtered = filter(elements);
ILabelProvider labelProvider = (ILabelProvider) getLabelProvider();
for (int i = 0; i < filtered.length; i++) {
Object element = filtered[i];
int ix = indexForElement(element);
combo.add(labelProvider.getText(element), ix);
comboMap.add(ix, element);
mapElement(element, combo); // must map it, since findItem only looks in map, if enabled
}
}
/**
* Adds the given element to this combo viewer.
* If this viewer does not have a sorter, the element is added at the end;
* otherwise the element is inserted at the appropriate position.
* <p>
* This method should be called (by the content provider) when a single element
* has been added to the model, in order to cause the viewer to accurately
* reflect the model. This method only affects the viewer, not the model.
* Note that there is another method for efficiently processing the simultaneous
* addition of multiple elements.
* </p>
*
* @param element the element
*/
public void add(Object element) {
add(new Object[] { element });
}
/* (non-Javadoc)
* Method declared on StructuredViewer.
* Since SWT.Combo doesn't use items we always return the Combo itself.
*/
@Override
protected Widget doFindInputItem(Object element) {
if (element != null && element.equals(getRoot()))
return getCCombo();
return null;
}
/* (non-Javadoc)
* Method declared on StructuredViewer.
* Since SWT.Combo doesn't use items we always return the Combo itself.
*/
@Override
protected Widget doFindItem(Object element) {
if (element != null) {
if (comboMap.contains(element))
return getCCombo();
}
return null;
}
/* (non-Javadoc)
* Method declared on StructuredViewer.
*/
@Override
protected void doUpdateItem(Widget data, Object element, boolean fullMap) {
if (element != null) {
int ix = comboMap.indexOf(element);
if (ix >= 0) {
ILabelProvider labelProvider = (ILabelProvider) getLabelProvider();
combo.setItem(ix, labelProvider.getText(element));
}
}
}
/* (non-Javadoc)
* Method declared on Viewer.
*/
@Override
public Control getControl() {
return combo;
}
/**
* Returns the element with the given index from this combo viewer.
* Returns <code>null</code> if the index is out of range.
*
* @param index the zero-based index
* @return the element at the given index, or <code>null</code> if the
* index is out of range
*/
public Object getElementAt(int index) {
if (index >= 0 && index < comboMap.size())
return comboMap.get(index);
return null;
}
/**
* The combo viewer implementation of this <code>Viewer</code> framework
* method returns the label provider, which in the case of combo
* viewers will be an instance of <code>ILabelProvider</code>.
*/
@Override
public IBaseLabelProvider getLabelProvider() {
return super.getLabelProvider();
}
/**
* Returns this combo viewer's combo control.
*
* @return the combo control
*/
public org.eclipse.swt.custom.CCombo getCCombo() {
return combo;
}
/* (non-Javadoc)
* Method declared on StructuredViewer.
*/
@Override
protected List<Object> getSelectionFromWidget() {
int idx = getCCombo().getSelectionIndex();
if (idx < 0)
return new ArrayList<Object>(0);
ArrayList<Object> list = new ArrayList<Object>(1);
Object e = getElementAt(idx);
if (e != null)
list.add(e);
return list;
}
/*
* Returns the index where the item should be inserted.
*/
protected int indexForElement(Object element) {
ViewerSorter sorter = getSorter();
if (sorter == null)
return combo.getItemCount();
int count = combo.getItemCount();
int min = 0, max = count - 1;
while (min <= max) {
int mid = (min + max) / 2;
Object data = comboMap.get(mid);
int compare = sorter.compare(this, data, element);
if (compare == 0) {
// find first item > element
while (compare == 0) {
++mid;
if (mid >= count) {
break;
}
data = comboMap.get(mid);
compare = sorter.compare(this, data, element);
}
return mid;
}
if (compare < 0)
min = mid + 1;
else
max = mid - 1;
}
return min;
}
/* (non-Javadoc)
* Method declared on Viewer.
*/
@Override
protected void inputChanged(Object input, Object oldInput) {
comboMap.clear();
Object[] children = getSortedChildren(getRoot());
int size = children.length;
org.eclipse.swt.custom.CCombo combo = getCCombo();
combo.removeAll();
String[] labels = new String[size];
for (int i = 0; i < size; i++) {
Object el = children[i];
labels[i] = ((ILabelProvider) getLabelProvider()).getText(el);
comboMap.add(el);
mapElement(el, combo); // must map it, since findItem only looks in map, if enabled
}
combo.setItems(labels);
}
/* (non-Javadoc)
* Method declared on StructuredViewer.
*/
@Override
protected void internalRefresh(Object element) {
if (element == null || element.equals(getRoot())) {
// the parent
if (comboMap != null)
comboMap.clear();
unmapAllElements();
List selection = getSelectionFromWidget();
combo.setRedraw(false);
combo.removeAll();
Object[] children = getSortedChildren(getRoot());
ILabelProvider labelProvider = (ILabelProvider) getLabelProvider();
for (int i = 0; i < children.length; i++) {
Object el = children[i];
combo.add(labelProvider.getText(el), i);
comboMap.add(el);
mapElement(el, combo); // must map it, since findItem only looks in map, if enabled
}
combo.setRedraw(true);
setSelectionToWidget(selection, false);
} else {
doUpdateItem(combo, element, true);
}
}
/**
* Removes the given elements from this combo viewer.
*
* @param elements the elements to remove
*/
private void internalRemove(final Object[] elements) {
Object input = getInput();
for (int i = 0; i < elements.length; ++i) {
if (elements[i].equals(input)) {
setInput(null);
return;
}
int ix = comboMap.indexOf(elements[i]);
if (ix >= 0) {
combo.remove(ix);
comboMap.remove(ix);
unmapElement(elements[i], combo);
}
}
}
/**
* Removes the given elements from this combo viewer.
* The selection is updated if required.
* <p>
* This method should be called (by the content provider) when elements
* have been removed from the model, in order to cause the viewer to accurately
* reflect the model. This method only affects the viewer, not the model.
* </p>
*
* @param elements the elements to remove
*/
public void remove(final Object[] elements) {
preservingSelection(new Runnable() {
public void run() {
internalRemove(elements);
}
});
}
/**
* Removes the given element from this combo viewer.
* The selection is updated if necessary.
* <p>
* This method should be called (by the content provider) when a single element
* has been removed from the model, in order to cause the viewer to accurately
* reflect the model. This method only affects the viewer, not the model.
* Note that there is another method for efficiently processing the simultaneous
* removal of multiple elements.
* </p>
*
* @param element the element
*/
public void remove(Object element) {
remove(new Object[] { element });
}
/*
* Non-Javadoc.
* Method defined on StructuredViewer.
*/
@Override
public void reveal(Object element) {
// Combos do not implement reveal.
}
/**
* The combo viewer implementation of this <code>Viewer</code> framework
* method ensures that the given label provider is an instance
* of <code>ILabelProvider</code>.
*/
@Override
public void setLabelProvider(IBaseLabelProvider labelProvider) {
Assert.isTrue(labelProvider instanceof ILabelProvider);
super.setLabelProvider(labelProvider);
}
/* (non-Javadoc)
* Method declared on StructuredViewer.
*/
@Override
protected void setSelectionToWidget(List in, boolean reveal) {
org.eclipse.swt.custom.CCombo combo = getCCombo();
if (in == null || in.size() == 0) { // clear selection
combo.deselectAll();
} else {
int n = in.size();
int[] ixs = new int[n];
int count = 0;
for (int i = 0; i < n; ++i) {
Object el = in.get(i);
int ix = comboMap.indexOf(el);
if (ix >= 0)
ixs[count++] = ix;
}
if (count < n) {
System.arraycopy(ixs, 0, ixs = new int[count], 0, count);
}
if (ixs.length > 0) {
combo.select(ixs[0]);
// wdg test hack: this might be needed if the combo widget
// is not READ_ONLY. (?)
//combo.setText(combo.getItem(ixs[0]));
}
}
}
/**
* HACK: This is equivalent to setSelection() EXCEPT that it doesn't fire any
* notifications. We have a lot of details pages which are depending on this
* behaviour when they programmatically set the combo's selection through the
* DetailsSectionImpl.refreshCCombo() method.
*/
public void setSelectionNoNotify(ISelection selection, boolean reveal) {
setSelectionToWidget(selection, reveal);
}
}