/*******************************************************************************
* Copyright (c) 2007, 2014 compeople AG 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:
* compeople AG - initial API and implementation
*******************************************************************************/
package org.eclipse.riena.internal.ui.ridgets.swt;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import org.eclipse.core.databinding.BindingException;
import org.eclipse.core.databinding.UpdateValueStrategy;
import org.eclipse.core.databinding.conversion.Converter;
import org.eclipse.core.databinding.observable.list.IObservableList;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.jface.databinding.swt.ISWTObservableValue;
import org.eclipse.jface.databinding.swt.SWTObservables;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CCombo;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.riena.ui.ridgets.ICComboRidget;
import org.eclipse.riena.ui.ridgets.IRidget;
import org.eclipse.riena.ui.ridgets.swt.AbstractComboRidget;
/**
* Ridget for {@link CCombo} widgets.
*/
public class CComboRidget extends AbstractComboRidget implements ICComboRidget {
private static final String ORIGINAL_BACKGROUND_KEY = "CCR.orBaKe"; //$NON-NLS-1$
private final ModifyListener modifyListener;
public CComboRidget() {
modifyListener = new CComboModifyListener();
addPropertyChangeListener(IRidget.PROPERTY_ENABLED, new PropertyChangeListener() {
public void propertyChange(final PropertyChangeEvent evt) {
if (getUIControl() != null) {
final boolean isEnabled = ((Boolean) evt.getNewValue()).booleanValue();
updateBgColor(isEnabled);
}
}
});
}
@Override
public CCombo getUIControl() {
return (CCombo) super.getUIControl();
}
@Override
protected void addSelectionListener(final org.eclipse.swt.events.SelectionListener listener) {
getUIControl().addSelectionListener(listener);
}
@Override
protected void addTextModifyListener() {
getUIControl().addModifyListener(modifyListener);
}
@Override
protected void bindUIControl() {
super.bindUIControl();
if (getUIControl() != null) {
updateBgColor(isEnabled());
}
}
@Override
protected void addConverter(final UpdateValueStrategy targetToModelStrategy, final IObservableValue selectionValue) {
final Object selectionType = selectionValue.getValueType();
targetToModelStrategy.setConverter(new Converter(Object.class, selectionType) {
public Object convert(final Object fromObject) {
if (fromObject == null) {
return null;
}
if (fromObject.getClass() == getToType()) {
return fromObject;
}
if (fromObject.toString().isEmpty()) {
return null;
}
return fromObject;
}
});
}
@Override
protected void checkUIControl(final Object uiControl) {
checkType(uiControl, CCombo.class);
if (uiControl != null) {
final int style = ((CCombo) uiControl).getStyle();
if ((style & SWT.READ_ONLY) == 0) {
throw new BindingException("Combo must be READ_ONLY"); //$NON-NLS-1$
}
}
}
@Override
protected void clearUIControlListSelection() {
getUIControl().deselectAll();
// Workaround for an SWT feature: when the user clicks in the list,
// an asynchronous selection event is added to the end of the event
// queue, which will silenty an item. We asynchronously clear the list
// as well
getUIControl().getDisplay().asyncExec(new Runnable() {
public void run() {
final CCombo combo = getUIControl();
if (combo != null && !combo.isDisposed()) {
combo.clearSelection(); // this does not change the text
}
}
});
}
@Override
protected String[] getUIControlItems() {
return getUIControl().getItems();
}
@Override
protected IObservableList getUIControlItemsObservable() {
return SWTObservables.observeItems(getUIControl());
}
@Override
protected ISWTObservableValue getUIControlSelectionObservable() {
return SWTObservables.observeSelection(getUIControl());
}
@Override
protected String getUIControlText() {
return getUIControl().getText();
}
@Override
protected int indexOfInUIControl(final String item) {
return getUIControl().indexOf(item);
}
@Override
protected void removeAllFromUIControl() {
getUIControl().removeAll();
}
@Override
protected void removeSelectionListener(final SelectionListener listener) {
getUIControl().removeSelectionListener(listener);
}
@Override
protected void removeTextModifyListener() {
getUIControl().removeModifyListener(modifyListener);
}
@Override
protected void selectInUIControl(final int index) {
getUIControl().select(index);
}
@Override
protected void setItemsToControl(final String[] arrItems) {
getUIControl().setItems(arrItems);
}
@Override
protected void setItemsToControl(final Object[] arrItems) {
setItemsToControl(getStringArray(arrItems));
}
@Override
protected void setTextToControl(final String text) {
getUIControl().setText(text);
}
@Override
protected void updateEditable() {
// unused
}
// helping methods
//////////////////
/**
* This was introduced as to address Bug 323449.
* <p>
* The Text/CCombo widgets will not change their background to gray when disabled, once a non-null background color has been used in the enabled state.
*/
private void updateBgColor(final boolean isEnabled) {
// pre-condition: control is known to be != null
final CCombo control = getUIControl();
if (isEnabled) {
if (control.getData(ORIGINAL_BACKGROUND_KEY) != null) {
control.setBackground((Color) control.getData(ORIGINAL_BACKGROUND_KEY));
control.setData(ORIGINAL_BACKGROUND_KEY, null);
}
} else {
if (control.getData(ORIGINAL_BACKGROUND_KEY) == null) {
control.setData(ORIGINAL_BACKGROUND_KEY, control.getBackground());
}
final Color disabledBg = control.getDisplay().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND);
// note: the DisabledPainter will paint the DISABLED_MARKER_BACKGROUND over this, so we are good
control.setBackground(disabledBg);
}
updateMarkers();
}
// helping classes
//////////////////
/**
* Keeps the ridget's text value in-sync with the widget's text value
*/
private final class CComboModifyListener implements ModifyListener {
public void modifyText(final ModifyEvent e) {
if (!isOutputOnly()) {
setText(getUIControlText());
}
}
}
}