/*******************************************************************************
* Copyright (c) 2007 Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is 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:
* Red Hat, Inc. - initial API and implementation
******************************************************************************/
package org.jboss.tools.common.ui.widget.field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.eclipse.jface.viewers.ComboViewer;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseMoveListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
/**
* @author eskimo
*
*/
public class ComboBoxField extends BaseField implements ISelectionChangedListener {
ComboViewer comboControl = null;
List values = new ArrayList();
boolean modifyLock = false;
public ComboBoxField(Composite parent,List values, ILabelProvider labelProvider,
Object value, boolean flatStyle) {
this(parent, values, value, flatStyle);
comboControl.setLabelProvider(labelProvider);
}
public ComboBoxField(Composite parent,List values, Object value, boolean editable) {
this.values = values;
/*
* Used combo box instead of custom combobox(CCombo),
* CCombo looks ugly under MAC OS X
*/
Combo combo;
if(editable==true) {
combo = new Combo(parent, SWT.NONE);
new MouseHandler(combo);
} else {
combo = new Combo(parent, SWT.READ_ONLY);
}
combo.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_WHITE));
comboControl = new ComboViewer(combo);
comboControl.setContentProvider(new IStructuredContentProvider() {
public void dispose() {
}
public void inputChanged(Viewer viewer, Object oldInput,
Object newInput) {
}
public Object[] getElements(Object inputElement) {
return ComboBoxField.this.values.toArray();
}
});
comboControl.addSelectionChangedListener(this);
comboControl.getCombo().addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent e) {
if(modifyLock) return;
modifyLock = true;
try {
firePropertyChange(new Object(), comboControl.getCombo().getText());
} finally {
modifyLock = false;
}
}});
comboControl.setLabelProvider(new ILabelProvider() {
public void addListener(ILabelProviderListener listener) {
}
public void dispose() {
}
public boolean isLabelProperty(Object element, String property) {
return false;
}
public void removeListener(ILabelProviderListener listener) {
}
public Image getImage(Object element) {
return null;
}
public String getText(Object element) {
return element.toString();
}
});
comboControl.setInput(values);
comboControl.setSelection(new StructuredSelection(value), true);
}
public void widgetDefaultSelected(SelectionEvent e) {
}
public void selectionChanged(SelectionChangedEvent event) {
firePropertyChange("", ((StructuredSelection)event.getSelection()).getFirstElement()); //$NON-NLS-1$
}
public Combo getComboControl() {
return comboControl.getCombo();
}
@Override
public Control getControl() {
return getComboControl();
}
public void setValue(Object newValue) {
if(modifyLock) return;
comboControl.setSelection(new StructuredSelection(newValue));
modifyLock = true;
try {
comboControl.getCombo().setText(newValue.toString());
} finally {
modifyLock = false;
}
}
public void setTags(String[] tags,String value) {
values = Arrays.asList(tags);
comboControl.removeSelectionChangedListener(this);
comboControl.refresh(true);
comboControl.addPostSelectionChangedListener(this);
comboControl.setSelection(new StructuredSelection(value));
}
/*
* We can't modify combo, change style of this object,
* if we such functionality please use CCombo
*
*/
public void setEditable(
boolean ediatble) {
//comboControl.getCCombo().setEditable(false);
}
}
class MouseHandler extends MouseAdapter implements MouseMoveListener {
Combo combo;
boolean isSettingFocus = false;
int basePosition = -1;
public MouseHandler(Combo combo) {
this.combo = combo;
combo.addMouseListener(this);
combo.addMouseMoveListener(this);
}
public void mouseDown(MouseEvent e) {
if(isSettingFocus) return;
isSettingFocus = true;
try {
if(!combo.isDisposed()) {
combo.setFocus();
int i = getPosition(e.x);
combo.setSelection(new Point(i,i));
basePosition = i;
}
} finally {
isSettingFocus = false;
}
}
public void mouseDoubleClick(MouseEvent e) {
if(!combo.isDisposed()) {
combo.setSelection(new Point(0, combo.getText().length()));
}
}
public void mouseUp(MouseEvent e) {
basePosition = -1;
}
public void mouseMove(MouseEvent e) {
if(basePosition < 0 || combo.isDisposed()) return;
int i = getPosition(e.x);
combo.setSelection(new Point(basePosition,i));
}
private int getPosition(int x) {
int result = 0;
GC g = new GC(combo);
String text = combo.getText();
int cp = combo.getCaretPosition();
if(cp >= 0) {
x -= combo.getCaretLocation().x - g.stringExtent(text.substring(0, cp)).x;
}
int n = text.length();
int width = g.stringExtent(text.substring(0, n)).x;
if(x < 3) {
result = 0;
} else if(width < x) {
result = n;
} else {
int c1 = 0;
int c2 = n;
while(c2 > c1) {
int c = (c2 + c1 + 1) / 2;
int xi = g.stringExtent(text.substring(0, c)).x;
int w = g.stringExtent(text.substring(c - 1, c)).x;
if(xi - w < x + 3 && xi > x - 1) {
if(xi - w / 2 > x + 3) result = c - 1; else result = c;
break;
}
if(c == c2) {
result = c;
break;
}
if(x > xi) {
c1 = c;
} else {
c2 = c;
}
}
}
g.dispose();
return result;
}
}