diff options
Diffstat (limited to 'archive/org.eclipse.qvt.declarative.editor.imp.runtime/src/org/eclipse/imp/preferences/fields/BooleanFieldEditor.java')
-rw-r--r-- | archive/org.eclipse.qvt.declarative.editor.imp.runtime/src/org/eclipse/imp/preferences/fields/BooleanFieldEditor.java | 630 |
1 files changed, 630 insertions, 0 deletions
diff --git a/archive/org.eclipse.qvt.declarative.editor.imp.runtime/src/org/eclipse/imp/preferences/fields/BooleanFieldEditor.java b/archive/org.eclipse.qvt.declarative.editor.imp.runtime/src/org/eclipse/imp/preferences/fields/BooleanFieldEditor.java new file mode 100644 index 000000000..770fa95d3 --- /dev/null +++ b/archive/org.eclipse.qvt.declarative.editor.imp.runtime/src/org/eclipse/imp/preferences/fields/BooleanFieldEditor.java @@ -0,0 +1,630 @@ +/******************************************************************************* +* Copyright (c) 2007 IBM Corporation. +* 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: +* Robert Fuhrer (rfuhrer@watson.ibm.com) - initial API and implementation +*******************************************************************************/ + +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.PreferencePage; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.DisposeEvent; +import org.eclipse.swt.events.DisposeListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.FontData; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.ui.PlatformUI; +import org.osgi.service.prefs.BackingStoreException; + +/** + * FieldEditor implementation for boolean preferences that support the 4-level + * presentation (default, installation, workspace, and project) and "details links". + * Based on the org.eclipse.jface.preference class of the same name. + * @author sutton + * @author rfuhrer + */ +public class BooleanFieldEditor extends ChangeButtonFieldEditor { + /* + * Fields copied from jface's BooleanFieldEditor + */ + + /** + * Style constant (value <code>0</code>) indicating the default + * layout where the field editor's check box appears to the left + * of the label. + */ + public static final int DEFAULT = 0; + + /** + * Style constant (value <code>1</code>) indicating a layout + * where the field editor's label appears on the left + * with a check box on the right. + */ + public static final int SEPARATE_LABEL = 1; + + /** + * Style bits. Either <code>DEFAULT</code> or + * <code>SEPARATE_LABEL</code>. + */ + private int style; + + + /** + * The checkbox control, or <code>null</code> if none. + */ + private Button checkBox = null; + + + /** + * Creates a boolean field editor in the given style. + * + * @param name the name of the preference this field editor works on + * @param labelText the label text of the field editor + * @param style the style, either <code>DEFAULT</code> or + * <code>SEPARATE_LABEL</code> + * @param parent the parent of the field editor's control + * @see #DEFAULT + * @see #SEPARATE_LABEL + */ + public BooleanFieldEditor( + PreferencePage page, PreferencesTab tab, + IPreferencesService service, String level, + String name, String labelText, int style, final Composite parent) + { + super(page, tab, service, level, name, labelText, parent); + this.style = style; + createControl(parent); + } + + + /** + * Creates a boolean field editor. + * + * @param name the name of the preference this field editor works on + * @param labelText the label text of the field editor + * @param parent the parent of the field editor's control + */ + public BooleanFieldEditor( + PreferencePage page, PreferencesTab tab, + IPreferencesService service, String level, String name, String labelText, Composite parent) + { + this(page, tab, service, level, name, labelText, DEFAULT, parent); + } + + @Override + public Composite getHolder() { + return (getChangeControl() != null) ? getChangeControl().getParent() : null; + } + + /* + * Methods related to loading values from the preferences service + * into the preferences store. + * + * All of the "doLoad..." methods should + * - Set isInherited, presentsDefaultValue, and levelFromWhichLoaded + * since these are know directly here and vary from load method to + * load method + * - Call setStringValue(..), which will set previousValue and + * fieldModified (which can be set generally given the old and + * new values), and which will also call valueChanged(), which + */ + + + + /* (non-Javadoc) + * Method declared on FieldEditor. + */ + protected void doLoad() + { + if (getChangeControl() != null) { + boolean value; + if (preferencesLevel != null) { + // The "normal" case, in which field corresponds to a preferences level + value = preferencesService.getBooleanPreference(preferencesLevel, getPreferenceName()); + levelFromWhichLoaded = preferencesLevel; + setInherited(false); + } + else { + // Not normal, exactly, but possible if loading is being done into a + // field that is not associated with a specific level + value = preferencesService.getBooleanPreference(getPreferenceName()); + levelFromWhichLoaded = preferencesService.getApplicableLevel(getPreferenceName(), preferencesLevel); + setInherited(true); + } + setPresentsDefaultValue(IPreferencesService.DEFAULT_LEVEL.equals(levelFromWhichLoaded)); + setBooleanValue(value); + } + + } + + + + /* (non-Javadoc) + * Method declared on FieldEditor. + */ + protected void doLoadDefault() { + if (getChangeControl() != null) { + boolean value = preferencesService.getBooleanPreference(IPreferencesService.DEFAULT_LEVEL, getPreferenceName()); + levelFromWhichLoaded = IPreferencesService.DEFAULT_LEVEL; + setInherited(false); // We're putting the default value here directly, not inheriting it + setPresentsDefaultValue(true); + setBooleanValue(value); // calls valueChanged(); + } + } + + + /* (non-Javadoc) + * + */ + protected void doLoadLevel(String level) { + if (getChangeControl() != null) { + boolean value; + if (preferencesLevel != null) { + value = preferencesService.getBooleanPreference(level, getPreferenceName()); + } else { + value = preferencesService.getBooleanPreference(getPreferenceName()); + } + // We're putting the level's value here directly, not inheriting it, so ... + levelFromWhichLoaded = level; + setInherited(false); + setPresentsDefaultValue(IPreferencesService.DEFAULT_LEVEL.equals(level)); + setBooleanValue(value); // calls valueChanged(); + } + } + + + /* (non-Javadoc) + * Method declared on FieldEditor. + */ + protected void refreshValidState() { + notifyState(true); + } + + + + /* + * Load into the boolean field the value for this preference that is either + * the value defined on this preferences level, if any, or the value inherited + * from the next applicable level, if any. Return the level at which the + * value loaded was found. Load nothing and return null if no value is found. + */ + protected String doLoadWithInheritance() + { + String levelLoaded = null; + + String[] levels = IPreferencesService.levels; + int fieldLevelIndex = preferencesService.getIndexForLevel(preferencesLevel); + + boolean value = false; + int levelAtWhichFound = -1; + + IEclipsePreferences[] nodes = preferencesService.getNodesForLevels(); + + for (int level = fieldLevelIndex; level < levels.length; level++) { + // Must have a node from which to get a value + if (nodes[level] == null) continue; + + // Get the value from the node, not the service, because we can + // check the node to see whether there is a value there for this + // preference + String result = nodes[level].get(getPreferenceName(), null); + if (result != null) { + // We have a value at the node; get it as a boolean + // (presumably we could also convert the result to a boolean) + value = nodes[level].getBoolean(getPreferenceName(), false); + + levelAtWhichFound = level; + levelLoaded = levels[levelAtWhichFound]; + break; + } + } + + String previousLevelFromWhichLoaded = levelFromWhichLoaded; + + // Ok, now have all necessary information to set everything that needs to be set + levelFromWhichLoaded = levelLoaded; + setInherited(fieldLevelIndex != levelAtWhichFound); + setPresentsDefaultValue(IPreferencesService.DEFAULT_LEVEL.equals(levelFromWhichLoaded)); + setPreviousBooleanValue(getBooleanValue()); + boolean valueChanged = previousValue==null || ((Boolean)previousValue).booleanValue()!=value; + boolean levelChanged = previousLevelFromWhichLoaded==null && levelFromWhichLoaded!=null || previousLevelFromWhichLoaded!=null && levelFromWhichLoaded==null || previousLevelFromWhichLoaded != null && !previousLevelFromWhichLoaded.equals(levelFromWhichLoaded); + if (levelChanged || valueChanged) { + setBooleanValue(value); // sets fieldModified and previousValue + } + + if (!isInherited()) + getChangeControl().setBackground(PreferencesUtilities.colorWhite); + else + getChangeControl().setBackground(PreferencesUtilities.colorBluish); + setPresentsDefaultValue(levelAtWhichFound == IPreferencesService.DEFAULT_INDEX); + + return levelLoaded; + } + + + + protected void doStore() + { + boolean value = getBooleanValue(); + + // 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.setBooleanPreference(preferencesLevel, getPreferenceName(), 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 + getChangeControl().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("SBFE.doStore(): BackingStoreException ; node may not have been flushed:" + + "\n\tnode path = " + node.absolutePath() + ", preferences level = " + preferencesLevel); + } + } + + + /* + * Preferences are stored by level, so we need to provide some + * way to represent and set the applicable level. Note that + * preferences can be reset at the default level during exeuction + * but default level preferences are never stored between + * executions. + */ + + + public void setPreferencesLevel(String level) { + if (!preferencesService.isaPreferencesLevel(level)) { + throw new IllegalArgumentException("SafairBooleanFieldEditor.setPreferencesLevel: given level = " + level + " is invalid"); + } + if (level.equals(IPreferencesService.PROJECT_LEVEL) && preferencesService.getProject() == null) { + throw new IllegalStateException("SafairBooleanFieldEditor.setPreferenceLevel: given level is '" + IPreferencesService.PROJECT_LEVEL + + "' but project is not defined for preferences service"); + } + preferencesLevel = level; + } + + + public String getPreferencesLevel() { + return preferencesLevel; + } + + + + /** + * Returns the field editor's value. + * + * @return the current value + */ + public boolean getBooleanValue() { + //return getChangeControl(parent).getSelection(); + return getChangeControl().getSelection(); + } + + + /** + * Set the previous value for this field + * @param value The value to be set + */ + + protected void setPreviousBooleanValue(boolean value) { + previousValue = value ? Boolean.TRUE : Boolean.FALSE; + } + + /** + * Get the previous value for this field + * @return The previous value + */ + protected boolean getPreviousBooleanValue() { + return ((Boolean)previousValue).booleanValue(); + } + + + + /** + * 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(boolean newValue) { + setPreviousBooleanValue(getBooleanValue()); + setInherited(false); + setPresentsDefaultValue(false); + levelFromWhichLoaded = null; + setBooleanValue(newValue); + } + + + + /** + * Sets this field editor's value through the supertype. + * Sets previous value and field modified. + * Also calls valueChanged(..) to signal the change in + * value. + * + * @param value the new value + */ + protected void setBooleanValue(boolean newValue) { + Button button = getChangeControl(); + if (button != null && !button.isDisposed()) { + boolean currentValue = getBooleanValue(); + if (previousValue == null) + setPreviousBooleanValue(!currentValue); + button.setSelection(newValue); + fieldModified = true; +// setModifiedMarkOnLabel(); + valueChanged(); + } else if (button.isDisposed()) { + throw new IllegalStateException("BooleanFieldEditor.setBooleanValue: button is disposed"); + } else if (button == null) { + throw new IllegalStateException("BooleanFieldEditor.setBooleanValue: button is null"); + } + } + + + + + /** + * Should be called whenever there is an update to the field, + * regardless of whether the value has changed or not. + * + * Informs this field editor's listener, if it has one, about a change + * to the value (<code>VALUE</code> property) provided that the old and + * new values are different. + * + * Sets the "modified" mark on the fields label regardless of + * whether the value has changed (on the assumption that the + * field has, or may have, changed in some significant way. + * + * @param oldValue the old value + * @param newValue the new value + */ + protected boolean valueChanged() { + boolean changed = false; + + boolean oldValue = getPreviousBooleanValue(); + boolean newValue = getBooleanValue(); + + if (oldValue != newValue) { + fireStateChanged(VALUE, oldValue, newValue); + changed = true; + } + // Set modify mark in any case because field may + // have changed, e.g., going from inherited to not + // or vice versa, without the value changing + setModifiedMarkOnLabel(); + return changed; + } + +// public static final org.eclipse.swt.graphics.FontData changedFontData = new org.eclipse.swt.graphics.FontData("Monaco", 11, 2); + private static final FontData[] arialFonts = PlatformUI.getWorkbench().getDisplay().getFontList("Arial", true); + private static FontData[] labelFonts; + + /** + * Initialize fonts for use in checkbox labels + * @return true if appropriate fonts available on system; false if not. + */ + private boolean getLabelFonts() { + if (labelFonts==null) { + labelFonts = new FontData[2]; + + for (FontData fd: arialFonts) { + if (fd.getHeight() <=10) { + switch (fd.getStyle()) { + case SWT.NORMAL: + labelFonts[0] = fd; + break; + case SWT.ITALIC: + labelFonts[1] = fd; + break; + } + } + } + } + if (labelFonts[0]==null || labelFonts[1] == null) { // only vary font if reasonable fonts exist for both modified/unmodified + return false; + } + return true; + + } + + /* + * For boolean fields we override the following two methods because + * the means of accessing the text to be modified is different. + * @see org.eclipse.imp.preferences.fields.FieldEditor#setModifyMarkOnLabel() + * @see org.eclipse.imp.preferences.fields.FieldEditor#clearModifyMarkOnLabel() + */ + + + public void setModifiedMarkOnLabel() { + // SMS 27 Nov 2006 + // Don't presume here to deal with inheritance. If called then set mark. + // Let caller worry about whether field is inherited and how that affects + // the marking + // if (isInherited) return; + if (checkBox != null) { +// String labelText = checkBox.getText(); +// if (!labelText.startsWith(Markings.MODIFIED_MARK)) { +// labelText = Markings.MODIFIED_MARK + labelText; +// checkBox.setText(labelText); +// } + // replace changed mark by color to eliminate text-box overflow bug + checkBox.setForeground(PreferencesUtilities.colorRed); // this doesn't work on MacOSX: use font if possible + if (getLabelFonts()==false) return; + checkBox.setFont(new Font(getPage().getShell().getDisplay(), labelFonts[1])); + } + } + + + public void clearModifiedMarkOnLabel() { + if (getLabelFonts()==false) return; + if (checkBox != null) { +// String labelText = checkBox.getText(); +// if (labelText.startsWith(Markings.MODIFIED_MARK)) +// labelText = labelText.substring(1); +// checkBox.setText(labelText); + // replace changed mark by color to eliminate text-box overflow bug + checkBox.setForeground(PreferencesUtilities.colorBlack); // this doesn't work on MacOSX: use font if possible + if (getLabelFonts()==false) return; + checkBox.setFont(new Font(getPage().getShell().getDisplay(), labelFonts[0])); + + } + } + + + + /* + * Returns the change button for this field editor. + * This overrides the corresponding superclass method so that we can set + * a listener on the control for our purposes. + * + */ + public Button getChangeControl() { + if (!parent.isDisposed()) { + if (checkBox == null) { + // Should actually create checkbox if it doesn't exist + // so should really never be null + //checkBox = getChangeControl(parent); + checkBox = new Button(parent, SWT.CHECK | SWT.LEFT); + checkBox.setFont(parent.getFont()); + checkBox.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + // Whenever a new value is set, we have to record the previous value. + // If we're here, that means that the current value has been changed + // using the GUI. Since the value in the GUI has changed, we can't + // use that to retrieve the previous value. But, since this is a + // boolean field, we know that the previous value must have been the + // negation of the current value, so we can set the previous value + // from that. It's important to set the previous value here before + // calling valueChanged(), because valueChanged() can't assume that + // a change has occurred--since a value loaded from the preferences + // service may match the current value of the field--so valueChanged() + // has to compare the new and previous values. To make that comparison + // work, we need to assure that the previous value is set properly here. + setPreviousBooleanValue(!getBooleanValue()); + fieldModified = true; + // Should call setInherited(..) before calling valueChanged() because + // valueChanged() will mark the field as modified, but only if isInherited + // is false, which it now should be + setInherited(false); + levelFromWhichLoaded = preferencesLevel; + setBooleanValue(getBooleanValue()); + // Set presentsDefaultValue to false on the basis that + // we've set it independently of the encoded default value + // even if we're on the default level. + setPresentsDefaultValue(false); + //valueChanged(); + //setPreviousBooleanValue(getBooleanValue()); + } + }); + checkBox.addDisposeListener(new DisposeListener() { + public void widgetDisposed(DisposeEvent event) { + //System.out.println("SBFE.button dispose listener (from getChangeControl): checkBoxNull set to true"); + checkBox = null; + } + }); + } else { + checkParent(checkBox, parent); + } + return checkBox; //getChangeControl(parent); + } + return null; + } + + + + /* + * Additional methods copied from BooleanFieldEditor + */ + + /* (non-Javadoc) + * Method declared on FieldEditor. + */ + protected void adjustForNumColumns(int numColumns) { + if (style == SEPARATE_LABEL) + numColumns--; + ((GridData) checkBox.getLayoutData()).horizontalSpan = numColumns; + } + + /* (non-Javadoc) + * Method declared on FieldEditor. + */ + protected void doFillIntoGrid(Composite parent, int numColumns) { + String text = getLabelText(); + String toolTipText = getToolTipText(); + switch (style) { + case SEPARATE_LABEL: + getLabelControl(parent); + numColumns--; + text = null; + default: + checkBox = getChangeControl(); + GridData gd = new GridData(); + gd.horizontalSpan = numColumns; + checkBox.setLayoutData(gd); + if (text != null) { + checkBox.setText(text); + if (toolTipText != null) { + checkBox.setToolTipText(toolTipText); + } + } + } + } + + @Override + protected void doSetToolTip() { + if (toolTipText != null) { + getChangeControl().setToolTipText(toolTipText); + } + } + + /* (non-Javadoc) + * Method declared on FieldEditor. + */ + public int getNumberOfControls() { + switch (style) { + case SEPARATE_LABEL: + return 2; + default: + return 1; + } + } + + + + +} |