package org.eclipse.imp.preferences.fields;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.imp.preferences.IPreferencesService;
import org.eclipse.imp.preferences.PreferencesTab;
import org.eclipse.imp.preferences.PreferencesUtilities;
import org.eclipse.jface.preference.ColorSelector;
import org.eclipse.jface.preference.PreferencePage;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.resource.StringConverter;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.osgi.service.prefs.BackingStoreException;
public class ColorFieldEditor extends ChangeButtonFieldEditor {
public static final RGB COLOR_DEFAULT= new RGB(0,0,0);
public static final String COLOR_DEFAULT_SPEC= StringConverter.asString(COLOR_DEFAULT);
/**
* The color selector, or <code>null</code> if none.
*/
private ColorSelector colorSelector;
public ColorFieldEditor(PreferencePage page, PreferencesTab tab, IPreferencesService service, String level, String name, String labelText, Composite parent) {
super(page, tab, service, level, name, labelText, parent);
createControl(parent);
}
/*
* (non-Javadoc) Method declared on FieldEditor.
*/
protected void adjustForNumColumns(int numColumns) {
((GridData) colorSelector.getButton().getLayoutData()).horizontalSpan= numColumns - 1;
}
/**
* Computes the size of the color image displayed on the button.
* <p>
* This is an internal method and should not be called by clients.
* </p>
*
* @param window
* the window to create a GC on for calculation.
* @return Point The image size
*
*/
protected Point computeImageSize(Control window) {
// Make the image height as high as a corresponding character. This
// makes sure that the button has the same size as a "normal" text
// button.
GC gc= new GC(window);
Font f= JFaceResources.getFontRegistry().get(JFaceResources.DEFAULT_FONT);
gc.setFont(f);
int height= gc.getFontMetrics().getHeight();
gc.dispose();
Point p= new Point(height * 3 - 6, height);
return p;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.preference.FieldEditor#doFillIntoGrid(org.eclipse.swt.widgets.Composite, int)
*/
protected void doFillIntoGrid(Composite parent, int numColumns) {
Control control= getLabelControl(parent);
GridData gd= new GridData();
gd.horizontalSpan= numColumns - 1;
control.setLayoutData(gd);
Button colorButton= getChangeControl(parent);
colorButton.setLayoutData(new GridData());
}
/*
* (non-Javadoc) Method declared on FieldEditor.
*/
public int getNumberOfControls() {
return 2;
}
/**
* Get the color selector used by the receiver.
*
* @return ColorSelector/
*/
public ColorSelector getColorSelector() {
return colorSelector;
}
@Override
public Button getChangeControl() {
if (colorSelector == null)
return null;
return colorSelector.getButton();
}
@Override
public Composite getHolder() {
return getChangeControl().getParent();
}
/**
* Returns the change button for this field editor.
*
* @param parent
* The control to create the button in if required.
* @return the change button
*/
protected Button getChangeControl(Composite parent) {
if (colorSelector == null) {
colorSelector= new ColorSelector(parent);
colorSelector.addListener(new IPropertyChangeListener() {
// forward the property change of the color selector
public void propertyChange(PropertyChangeEvent event) {
ColorFieldEditor.this.fireValueChanged(event.getProperty(), event.getOldValue(), event.getNewValue());
setPresentsDefaultValue(false);
setInherited(false);
fieldModified= true;
}
});
} else {
checkParent(colorSelector.getButton(), parent);
}
return colorSelector.getButton();
}
@Override
protected void doSetToolTip() {
getLabelControl().setToolTipText(toolTipText);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.preference.FieldEditor#setEnabled(boolean, org.eclipse.swt.widgets.Composite)
*/
public void setEnabled(boolean enabled, Composite parent) {
super.setEnabled(enabled, parent);
getChangeControl(parent).setEnabled(enabled);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.preference.FieldEditor#doLoad()
*/
protected void doLoad() {
if (colorSelector == null) {
return;
}
updateColor(preferencesService.getStringPreference(getPreferenceName()));
}
/*
* (non-Javadoc) Method declared on FieldEditor.
*/
protected void doLoadDefault() {
if (colorSelector == null) {
return;
}
updateColor(preferencesService.getStringPreference(IPreferencesService.DEFAULT_LEVEL, getPreferenceName()));
}
@Override
protected void doLoadLevel(String level) {
String colorValue = preferencesService.getStringPreference(level, getPreferenceName());
updateColor(colorValue);
}
private void updateColor(String colorSpec) {
RGB color = StringConverter.asRGB(colorSpec, null);
if (color == null) {
color= COLOR_DEFAULT;
}
colorSelector.setColorValue(color);
}
@Override
protected String doLoadWithInheritance() {
String levelLoaded = null;
String[] levels = IPreferencesService.levels;
// If we're loading with inheritance for some field that is
// not attached to a preferences level then assume that we
// should just search from the bottom up
int startingLevelIdx = (preferencesLevel == null) ? 0 : PREFS_LEVELS_AS_LIST.indexOf(preferencesLevel);
int levelAtWhichFound = -1;
String encodedColorValue = null;
// Search up levels starting from the level of this field
for (int level = startingLevelIdx; level < levels.length; level++) {
encodedColorValue = preferencesService.getRawStringPreference(levels[level], getPreferenceName());
if (encodedColorValue != null) {
levelAtWhichFound = level;
levelLoaded = levels[levelAtWhichFound];
break;
}
}
if (encodedColorValue == null) {
encodedColorValue= COLOR_DEFAULT_SPEC;
}
// TODO should this be calling updateColor() instead of the following?
levelFromWhichLoaded = levelLoaded;
setInherited(startingLevelIdx != levelAtWhichFound);
setPresentsDefaultValue(IPreferencesService.DEFAULT_LEVEL.equals(levelFromWhichLoaded));
fieldModified = true;
// valueChanged(); // should not be called when field set from preference store
previousValue= colorSelector.getColorValue(); // not clear whether this needs to be done on initial load from store
colorSelector.setColorValue(StringConverter.asRGB(encodedColorValue));
updateColor(encodedColorValue);
return levelLoaded;
}
/*
* (non-Javadoc) Method declared on FieldEditor.
*/
protected void doStore() {
RGB value = colorSelector.getColorValue();
// Not inherited, and modified: field must have been set on this level, so store it.
// Storing here should trigger preference-change listeners at each level below this.
preferencesService.setStringPreference(preferencesLevel, getPreferenceName(), StringConverter.asString(value));
// If we've just stored the field, we've addressed any modifications
//System.out.println("SBFE.doStore: setting fieldModified to FALSE");
fieldModified = false;
// If we've stored the field then it's not inherited, so be sure it's
// color indicates that.
// Note that for the checkbox wiget (which is the only one used so far)
// the background color is the color behind the label (not the checkbox
// itself), so it should be light gray like the background in the rest
// of the tab.
// TODO: figure out how to determine the actual prevailing background
// color and use that here
getLabelControl().setBackground(PreferencesUtilities.colorWhite);
// Now write out the node
IEclipsePreferences node = preferencesService.getNodeForLevel(preferencesLevel);
try {
if (node != null) node.flush();
} catch (BackingStoreException e) {
System.err.println("SCFE.doStore(): BackingStoreException; node may not have been flushed:" +
"\n\tnode path = " + node.absolutePath() + ", preferences level = " + preferencesLevel);
}
}
/**
* Set the value of this field directly, from outside of
* the field, without loading a value from the preferences
* service.
*
* Intended for use by external clients of the field.
*
* In addition to setting the value of the field this method
* also sets several attributes to appropriately characterize
* a field that has been set in this way.
*
* @param newValue
*/
public void setFieldValueFromOutside(String newValue) {
previousValue = colorSelector.getColorValue();
setInherited(false);
setPresentsDefaultValue(false);
levelFromWhichLoaded = null;
updateColor(newValue);
}
@Override
protected boolean valueChanged() {
// Check for change in value
boolean valueChanged = inheritanceChanged();
RGB chosenColor= colorSelector.getColorValue();
if (!valueChanged) {
if ((chosenColor != null && previousValue == null) ||
(chosenColor == null && previousValue != null))
{
valueChanged = true;
}
if (chosenColor != null && previousValue != null) {
if (!chosenColor.equals(previousValue)) {
valueChanged = true;
}
}
}
if (valueChanged) {
fireValueChanged(VALUE, previousValue, chosenColor);
fieldModified = true;
previousValue = chosenColor;
setModifiedMarkOnLabel();
}
return valueChanged;
}
}