content: /**
   *  Copyright (c) 2013-2016 Angelo ZERR.
   *  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:
   *  Angelo Zerr <angelo.zerr@gmail.com> - initial API and implementation
   */
  package tern.eclipse.ide.ui.preferences;
  
  import org.eclipse.jface.preference.FieldEditor;
  import org.eclipse.jface.viewers.ArrayContentProvider;
  import org.eclipse.jface.viewers.ComboViewer;
  import org.eclipse.jface.viewers.IBaseLabelProvider;
  import org.eclipse.jface.viewers.IContentProvider;
  import org.eclipse.jface.viewers.IStructuredContentProvider;
  import org.eclipse.jface.viewers.IStructuredSelection;
  import org.eclipse.jface.viewers.StructuredSelection;
  import org.eclipse.jface.viewers.StructuredViewer;
  import org.eclipse.swt.SWT;
  import org.eclipse.swt.events.SelectionAdapter;
  import org.eclipse.swt.events.SelectionEvent;
  import org.eclipse.swt.layout.GridData;
  import org.eclipse.swt.widgets.Combo;
  import org.eclipse.swt.widgets.Composite;
  import org.eclipse.swt.widgets.Control;
  
  /**
   * A field editor for a combo box that allows the drop-down selection of one of
   * a list of items with label/content provider.
   *
   */
  public abstract class ComboViewerFieldEditor extends FieldEditor {
  
  	/**
  	 * The custom combo box control.
  	 */
  	private ComboViewer viewer;
  	private Object selectedValue;
  	private boolean isValid = true;
  
  	/**
  	 * Create the combo box field editor.
  	 *
  	 * @param name
  	 *            the name of the preference this field editor works on
  	 * @param labelText
  	 *            the label text of the field editor
  	 * @param entryNamesAndValues
  	 *            the names (labels) and underlying values to populate the combo
  	 *            widget. These should be arranged as: { {name1, value1},
  	 *            {name2, value2}, ...}
  	 * @param parent
  	 *            the parent composite
  	 */
  	public ComboViewerFieldEditor(String name, String labelText, Composite parent) {
  		init(name, labelText);
  		createControl(parent);
  		setContentProvider(ArrayContentProvider.getInstance());
  	}
  
  	@Override
  	protected void adjustForNumColumns(int numColumns) {
  		Combo combo = viewer.getCombo();
  		if (numColumns > 1) {
  			Control control = getLabelControl();
  			int left = numColumns;
  			if (control != null) {
  				((GridData) control.getLayoutData()).horizontalSpan = 1;
  				left = left - 1;
  			}
  			((GridData) combo.getLayoutData()).horizontalSpan = left;
  		} else {
  			Control control = getLabelControl();
  			if (control != null) {
  				((GridData) control.getLayoutData()).horizontalSpan = 1;
  			}
  			((GridData) combo.getLayoutData()).horizontalSpan = 1;
  		}
  	}
  
  	@Override
  	protected void doFillIntoGrid(Composite parent, int numColumns) {
  		int comboC = 1;
  		if (numColumns > 1) {
  			comboC = numColumns - 1;
  		}
  		Control control = getLabelControl(parent);
  		GridData gd = new GridData();
  		gd.horizontalSpan = 1;
  		control.setLayoutData(gd);
  		control = getComboBoxControl(parent);
  		gd = new GridData();
  		gd.horizontalSpan = comboC;
  		gd.horizontalAlignment = GridData.FILL;
  		control.setLayoutData(gd);
  		control.setFont(parent.getFont());
  	}
  
  	@Override
  	protected void doLoad() {
  		updateComboForValue(getPreferenceStore().getString(getPreferenceName()));
  	}
  
  	@Override
  	protected void doLoadDefault() {
  		updateComboForValue(getPreferenceStore().getDefaultString(getPreferenceName()));
  	}
  
  	protected void updateComboForValue(String value) {
  		selectedValue = getValueFromPreference(value);
  		if (selectedValue != null) {
  			viewer.setSelection(new StructuredSelection(selectedValue));
  		}
  	}
  
  	@Override
  	protected void doStore() {
  		if (selectedValue == null) {
  			getPreferenceStore().setToDefault(getPreferenceName());
  			return;
  		}
  		getPreferenceStore().setValue(getPreferenceName(), getPreferenceValue(selectedValue));
  	}
  
  	@Override
  	public int getNumberOfControls() {
  		return 2;
  	}
  
  	/*
  	 * Lazily create and return the Combo control.
  	 */
  	private Combo getComboBoxControl(Composite parent) {
  		if (viewer == null) {
  			Combo comboBox = new Combo(parent, SWT.READ_ONLY);
  			comboBox.setFont(parent.getFont());
  			viewer = new ComboViewer(comboBox);
  			comboBox.addSelectionListener(new SelectionAdapter() {
  				@Override
  				public void widgetSelected(SelectionEvent evt) {
  					boolean oldValid = isValid;
  					Object oldValue = selectedValue;
  					selectedValue = viewer.getSelection().isEmpty() ? null
  							: ((IStructuredSelection) viewer.getSelection()).getFirstElement();
  					setPresentsDefaultValue(false);
  					fireValueChanged(VALUE, oldValue, selectedValue);
  
  					refreshValidState();
  					boolean newValid = isValid;
  					if (oldValid != newValid) {
  						fireValueChanged(IS_VALID, oldValid, newValid);
  					}
  				}
  			});
  		}
  		return viewer.getCombo();
  	}
  
  	@Override
  	public void setEnabled(boolean enabled, Composite parent) {
  		super.setEnabled(enabled, parent);
  		getComboBoxControl(parent).setEnabled(enabled);
  	}
  
  	/**
  	 * @param labelProvider
  	 *            the label provider used
  	 * @see StructuredViewer#setLabelProvider(IBaseLabelProvider)
  	 */
  	public void setLabelProvider(IBaseLabelProvider labelProvider) {
  		viewer.setLabelProvider(labelProvider);
  	}
  
  	/**
  	 * @param provider
  	 *            the content provider used
  	 * @see StructuredViewer#setContentProvider(IContentProvider)
  	 * @since 3.7
  	 */
  	public void setContentProvider(IStructuredContentProvider provider) {
  		viewer.setContentProvider(provider);
  	}
  
  	/**
  	 * @param input
  	 *            the input used
  	 * @see StructuredViewer#setInput(Object)
  	 */
  	public void setInput(Object input) {
  		viewer.setInput(input);
  		viewer.getCombo().select(0);
  	}
  
  	protected abstract String getPreferenceValue(Object selectedObject);
  
  	protected abstract Object getValueFromPreference(String preferenceValue);
  
  	public Object getSelectedValue() {
  		return selectedValue;
  	}
  
  	@Override
  	protected void refreshValidState() {
  		isValid = checkState();
  	}
  
  	protected boolean checkState() {
  		return true;
  	}
  
  	@Override
  	public boolean isValid() {
  		return isValid;
  	}
  
  	public ComboViewer getViewer() {
  		return viewer;
  	}
  }
  