org.eclipse.imp.preferences.fields.FieldEditor.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.imp.preferences.fields.FieldEditor.java

Source

/*******************************************************************************
* 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 java.util.Arrays;
import java.util.List;

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.widgets.Composite;
import org.eclipse.swt.widgets.Label;

/**
 * Points to note:
 * - Preferences service instead of a preference store
 * - Preferences have a level
 *   - Four fixed levels
 *   - Named by strings because ...
 * - Makes some provision for loading, etc. into fields
 *   on pages that are *not* associated with a level (just in case)
 * - Preferences are displayed on a tab on a page
 * - Preference values may be inherited
 * 
 * @author sutton
 *
 */

public abstract class FieldEditor extends org.eclipse.jface.preference.FieldEditor {
    protected static final List<String> PREFS_LEVELS_AS_LIST = Arrays.asList(IPreferencesService.levels);

    /**
    *  The preferences page on which the tab that contains this
    *  field is displayed
    */
    // Relationship to dialogPage in FieldEditor?
    protected PreferencePage prefPage = null;

    /**
     * The preferences tab on which the field is displayed
     */
    protected PreferencesTab prefTab = null;

    /**
     * The preferences service in which the values for this
     * field are stored
     */
    protected IPreferencesService preferencesService = null;

    /**
     * The preferences level with which this field is associated
     */
    protected String preferencesLevel = null;

    /**
     * The Composite control that contains the field
     */
    protected Composite parent = null;

    /**
     *  Whether the value shown for this field is stored on
     *  the level for this field or inherited from a higher level
     */
    protected boolean isInherited = false;

    /**
     *  Whether the value shown for this field was previously stored on
     *  the level for this field or inherited from a higher level
     */
    protected boolean wasInherited = false;

    /**
     * Whether the value stored for this field (if any) can be
     * removed.  (Removal of a value on a lower level will
     * generally result in the inheritance of a value from a
     * higher level.  The effects of removal of values at the
     * top ("default") are not defined and this should generally
     * not be allowed.)
     */
    protected boolean isRemovable = false;

    /**
     * Flags whether the field has an associated "special" 
     * (distinguished) value (the purpose of which is
     * generally field specific)
     */
    protected boolean hasSpecialValue = false;

    /**
     * A general placeholder for a special (distinguished) value
     * that may be associated with this field (the purpose of
     * which is generally field specific)
     */
    // Not sure whether such a general representation will be
    // useful, but it conveys the idea
    protected Object specialValue = null;

    /**
     * Name of the preferences level from which the value
     * displayed by this field was loaded.  If non-null then
     * will generally be one of the four standard level names.
     */
    protected String levelFromWhichLoaded = null;

    /**
     * Whether the value held by the field is the same as the
     * value stored in the corresponding preferences node (that
     * is, the node from which it was most recently loaded or
     * the node into which it was most recently stored)
     */
    protected boolean fieldModified = false;

    protected Object previousValue = null;

    protected String toolTipText = null;

    //
    // Fields in FieldEditor:
    //

    // private String preferenceName has public get and set methods

    // private *** preferenceStore is deprecated (along with any associated methods)

    // private boolean field isDefaultPresented has public read and write methods

    // private String labelText has public (or protected) get and set methods;
    // also settable through init (called by constructors but protected and not
    // apparently limited to use at construction time)

    // private Label label has public and protected get methods; public
    // one creates when first called; no other set methods (makes sense)

    // private field IPropertyChangeListener propertyChangeListener has a public
    // set method but no get method (needed here?)

    // private field DialogPage page has public get and set methods

    // Note:  there is no parent field

    /**
     * Parameterless constructor that mimics the one in FieldEditor
     */
    protected FieldEditor() {
        super();
    }

    /**
     * Creates a field editor, taking the information that is
     * specific to IMP field editors but not that used by
     * field editors in general.  Calls the empty constructor for
     * a field editor.
     * 
     * @param   page   The preferences page on which the tab is shown
     * @param   tab      The tab on which field editor is shown
     * @param   service   The preferences service in which the preference
     *                values are stored
     * @param   level   The level at which this preference is assigned
     */
    // Able to do anything useful without a parent?
    public FieldEditor(PreferencePage page, PreferencesTab tab, IPreferencesService service, String level) {
        super();
        preferencesService = service;
        preferencesLevel = level;
        prefPage = page;
        setPage(prefPage);
        prefTab = tab;
    }

    /**
     * Creates a field editor, taking all of the relevant information
     * (IMP specific and field-editor generic). Calls the non-empty
     * constructor for a field editor.
     * 
     * @param   page   The preferences page on which the tab is shown
     * @param   tab      The tab on which field editor is shown
     * @param   service   The preferences service in which the preference
     *                values are stored
     * @param   level   The level at which this preference is assigned
     * @param   name   The name of this preference
     * @param   labelText   The text used to label the field on the page
     * @param   parent   The composite control that contains this editor
     */
    public FieldEditor(PreferencePage page, PreferencesTab tab, IPreferencesService service, String level,
            String name, String labelText, Composite parent) {
        //super(name, labelText, parent);
        super();
        init(name, labelText);
        preferencesService = service;
        preferencesLevel = level;
        this.parent = parent;
        prefPage = page;
        setPage(prefPage);
        prefTab = tab;
    }

    /*
     * Methods to get and set the preferences level from which the value
     * of this field was loaded (or set)
     */

    /**
     * Get the preferences level from which the value of this field
     * was set.  Should be the name of a preferences level if the
     * value was set from a preferences node, or null if the value
     * was set directly into the field.
     * 
     * @return   The preferencesl level from which the current value
     *          for this field was loaded, or null if the current value
     *          was set directly
     */
    public String getLevelFromWhichLoaded() {
        return levelFromWhichLoaded;
    }

    /*
     * Methods to get and set the isInherited field for this editor
     */

    /**
     * @return      Whether the value displayed for this field is
     *             stored at the level of this field or inherited from
     *             a higher level
     */
    public boolean isInherited() {
        return isInherited;
    }

    /**
     * Sets the field that indicates whether the value displayed for
     * this field is stored on the level for this field or inherited from
     * a higher level.
     * 
     * @param inherited      Whether the value is stored or inherited
     */
    protected void setInherited(boolean inherited) {
        wasInherited = isInherited;
        isInherited = inherited;
    }

    /**
     * @return Whether the inheritance state of this field has changed
     * from its previous value   
     */
    protected boolean inheritanceChanged() {
        return wasInherited != isInherited;
    }

    // Empty is a sting-related concept, not for fields in general
    //
    //   public boolean isEmptyValueAllowed() {
    //      return isEmptyStringAllowed();
    //   }
    //   
    //   public void setEmptyValueAllowed(boolean allowed) {
    //      setEmptyStringAllowed(allowed);
    //   }
    //   
    //
    //   public String getEmptyValue() {
    //      if (isEmptyStringAllowed())
    //         return emptyValue;
    //      throw new IllegalStateException("StringFieldEditor.getEmptyValue:  called when field does not allow an empty value");
    //   }

    /*
     * Methods relating to the removal of field values
     */

    /**
     * @return   Whether the value stored for this field (if any)
     *          can be removed
     */
    public boolean isRemovable() {
        return isRemovable;
    }

    /**
     * Sets whether the value stored for this field (if any)
     * can be removed
     * 
     * @param isRemovable   Whether ...
     */
    public void setRemovable(boolean isRemovable) {
        this.isRemovable = isRemovable;
    }

    ////////////////////////////////////////////////////////////////////////////

    /*
     * Methods related to loading a value for the field.  "Loading" a value for
     * a field means setting the value that the field is to display.
     * Because of multiple preference levels and inheritance of preference values
     * this is a more varied and complicated concern than with FieldEditor.
     */

    /**
     * Initializes this field editor with a preference value from
     * the preference service.
     * 
     * If the field is associated with a specific preference level (the
     * usual case) then the value from that level, if any, is loaded.
     * 
     * If the field is not associated with a specific preference level,
     * then a value obtained from some applicable level may be loaded.
     * (This is a feature that supports preferences pages that are not
     * strictly aligned with preferences levels, unlike the "usual"
     * approach assumed here.)
     * 
     * Because it cannot be guaranteed here that the value that is loaded
     * is not inherited, the flag isDefaultPresented cannot be set to
     * false here (as it can in FieldEditor).
     */
    public void load() {
        if (preferencesService != null) {
            //isDefaultPresented = false;
            doLoad();
            refreshValidState();
        }
    }

    /**
     * Do the work of loading
     */
    abstract protected void doLoad();

    //    // This is an example implementation from the IMP String field editor
    //    // with level-specific and level-independent branches:
    //    {
    //        if (getTextControl() != null) {
    //           String value = null;
    //           if (preferencesLevel != null) {
    //              // The "normal" case, in which field corresponds to a preferences level
    //              value = preferencesService.getStringPreference(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.getStringPreference(getPreferenceName());
    //              levelFromWhichLoaded = preferencesService.getApplicableLevel(getPreferenceName(), preferencesLevel);
    //             setInherited(true);   
    //           }
    //            if (IPreferencesService.DEFAULT_LEVEL.equals(levelFromWhichLoaded))
    //               setPresentsDefaultValue(true);
    //           previousValue = value;
    //            setStringValue(value);
    //        }   
    //    }

    /**
     * Initializes this field editor with the value associated with the
     * default level of the preference store.
     */
    public void loadDefault() {
        if (preferencesService != null) {
            setPresentsDefaultValue(true);
            doLoadDefault();
            refreshValidState();
        }
    }

    /**
     * Do the work of loading the default value into the field.
     * Generally depends on the type of the field. 
     */
    abstract protected void doLoadDefault();

    //  // This is an example implementation from the IMP String field editor:
    //    {
    //        if (getTextControl() != null) {
    //            String value = preferencesService.getStringPreference(IPreferencesService.DEFAULT_LEVEL, getPreferenceName());
    //            setStringValue(value);
    //        }
    //        // empty in FieldEditor:
    //        refreshValidState();
    //        // Comments on valueChanged() says it is not called when 
    //        // a value is initialized or restored from default so
    //        // don't call that here
    //    }

    /**
     * Set this field with the preference value associated with
     * the given level.  Sets presentsDefaultValue to true if the
     * given level is "default".
     */
    public void loadLevel(String level) {
        if (preferencesService != null && preferencesService.isaPreferencesLevel(level)) {
            doLoadLevel(level);
            if (IPreferencesService.DEFAULT_LEVEL.equals(level))
                setPresentsDefaultValue(true);
            // SMS 25 Nov 2006
            // still need to signal valueChanged on default level?
            //           else
            // SMS 15 Nov 2006:  try this if not default level
            valueChanged();
            refreshValidState();
        }
    }

    /**
     * Do the work of loading the value for the given level into the field.
     * Generally depends on the type of the field. 
     */
    abstract protected void doLoadLevel(String level);

    //      // This is an example implementation from the IMP String field editor:
    //      {
    //        if (getTextControl() != null) {
    //           String value = null;
    //           if (preferencesLevel != null) {
    //              value = preferencesService.getStringPreference(level, getPreferenceName());
    //           } else {
    //              value = preferencesService.getStringPreference(getPreferenceName());
    //           }
    //           setStringValue(value);
    //        }
    //        //valueChanged();
    //    }

    /**
     * Set this field with the currently applicable preference value,
     * inheriting the value from a higher level if the value is not
     * stored on the level associated with the field. (The "default"
     * level should always have a value.)
     * 
     * @return   The level from which the value was loaded
     */
    public String loadWithInheritance() {
        if (preferencesService != null) {
            levelFromWhichLoaded = doLoadWithInheritance();
            if (IPreferencesService.DEFAULT_LEVEL.equals(levelFromWhichLoaded))
                setPresentsDefaultValue(true);
            refreshValidState();
        }
        return levelFromWhichLoaded;
    }

    /**   
      * Do the work of setting the currently applicable value for this field,
      * inheriting the value from a higher level if the value is not stored
      * on the level associated with the field. (The "default" level should
      * always have a value.)  Load nothing and return null if no value is found.
      * 
      * Should set varous fields such as levelFromWhichLoaded, previousValue,
      * isInherited, and fieldModified.  Should also adjust the appearance of
      * the field on the preferences page to reflect inherited state.
      * 
      * @return   The level from which the applicable value was loaded or
      *          null if no value found.
      */
    abstract protected String doLoadWithInheritance();

    //  // This is an example implementation from the IMP String field editor:
    //    {
    //       String levelLoaded = null;
    //       
    //       String[] levels = IPreferencesService.levels;
    //       int fieldLevelIndex = 0;
    //
    //       // If we're loading with inheritance for some field that is
    //       // not attached to a preferences level (such as the "applicable"
    //       // field, which inherits values from all of the real fields)
    //       // then assume that we should just search from the bottom up
    //       String tmpPreferencesLevel = 
    //          (preferencesLevel == null)?
    //             levels[0]:
    //             preferencesLevel;
    //       
    //       // Find the index of the level to which this field belongs
    //       for (int i = 0; i < levels.length; i++) {
    //          if (tmpPreferencesLevel.equals(levels[i])) {
    //             fieldLevelIndex = i;
    //             break;
    //          }
    //       }
    //       
    //       String value = null;
    //       int levelAtWhichFound = -1;
    //       
    //       for (int level = fieldLevelIndex; level < levels.length; level++) {
    //             value = preferencesService.getStringPreference(levels[level], getPreferenceName());
    //             if (value == null) continue;
    //             if (value.equals("") && !isEmptyStringAllowed()) continue;
    //             levelAtWhichFound = level;
    //             levelLoaded = levels[levelAtWhichFound];
    //             break;   
    //       }
    //       
    //       // Set the field to the value we found
    //        setStringValue(value);
    //        
    //       // We loaded it at this level or inherited it from some other level
    //       setInherited(fieldLevelIndex != levelAtWhichFound);
    //       
    //       // Since we just loaded some new text, it won't be modified yet
    //       fieldModified = false;
    //       
    //       // TODO:  Check on use of previous value
    //          previousValue = value;
    //          
    //          // Set the background color of the field according to where found
    //        Text text = getTextControl();
    //        if (isInherited())
    //           text.setBackground(PreferencesUtilities.colorBluish);
    //        else
    //           text.setBackground(PreferencesUtilities.colorWhite);
    //     
    //        //System.out.println("doLoadWithInheritance:  preferencesName = " + getPreferenceName() + "; preferenceLevel = " + preferencesLevel + "; levelLoaded = " + levelLoaded);
    //        
    //        return levelLoaded;
    //    }

    /*
     * Methods relating to storing the value of a field.
     */

    /**
     * Store the value in this field, using the preferences service,
     * at the level associated with this field.
     * 
     * Checks many preconditions.  Throws an exception if the preferences
     * service or preferences level is null or if the associated level is
     * the project level but no project is set.  Returns without effect if
     * the value is inherited, if the value is the default value, or if the
     * field is not modified.
     * 
     * Why not store inherited values?  Inherited values are shown for a
     * field when the field has no value of its own.  They are shown because
     * they apply on the field's level but they are not actually set (or stored)
     * on that level.  Since there is no value actually set for the field,
     * there is no value to store for it.  Note that separate controls on
     * a preferene page may make it possible to adopt an inherited value for
     * a field (that is, to copy it into the field), after which it can be stored.
     *   
     * Also sets fieldModified to false (since it was just stored and hasn't
     * been changed yet) and levelFromWhichLoaded to the level associated with
     * the current field.  
     *  
     * @throws   IllegalStateException
     *             if the preferences service is null, if the preferences
     *             level is null, or if the associated level is the project
     *             level but no project is set
     * 
     */
    public void store() {

        // Don't store if the preferences service is null, since that may
        // represent an illegal state and anyway we need to refer to it below
        if (preferencesService == null) {
            throw new IllegalStateException(
                    "FieldEditor.store():  attempt to store when preferences service is null");
        }

        // Can't store the value If there is no valid level (not having a preferences level
        // isn't necessarily an error, but it does prevent storing)
        //if (preferencesLevel == null) return;
        if (preferencesService == null) {
            throw new IllegalStateException(
                    "FieldEditor.store():  attempt to store when preferences level is null");
        }

        // Don't store a value that comes from some other level
        if (isInherited)
            return;
        //if (presentsDefaultValue()) return;

        // Don't bother storing if the field hasn't been modified
        if (!fieldModified)
            return;

        // Don't store the value if the field's level is the project level
        // but no project is selected
        if (IPreferencesService.PROJECT_LEVEL.equals(preferencesLevel) && preferencesService.getProject() == null) {
            throw new IllegalStateException(
                    "FieldEditor.store():  attempt to store project preference when project is not set");
        }

        // If the level is the default level, go ahead and store it even
        // though preferences on the default level aren't persistent:
        // the preference still needs to be stored into the default preference
        // node (since that is needed to put the new value into effect, and
        // why provide a new value if you don't want it to go into effect?)
        // and the flushing of that node doesn't have any effect in any case.
        // In other words, do not return if the level is the default level

        // Store the value
        doStore();

        // If we've just stored the field, we've addressed any modifications
        //System.out.println("STFE.store:  setting fieldModified to FALSE");
        fieldModified = false;
        levelFromWhichLoaded = preferencesLevel;
    }

    /**
     * Do the work of actually storing the value.
     * Generally depends on the specific type of the field.
     * May also need to check field-specific conditions (e.g., whether
     * empty values are allowed).
     * If necessary also adjust appearance of field on the preference
     * page to reflect the non-inherited state.
     */
    abstract protected void doStore();

    //  // This is an example implementation from the IMP String field editor:
    //  {
    //       String    value = getTextControl().getText();
    //       boolean isEmpty = value.equals(emptyValue);         // Want empty value, but can't call method to retrieve it
    //                                              // with fields where empty is not allowed
    //       // getText() will return an empty string if the field is empty,
    //       // and empty strings can be stored in the preferences service,
    //       // but an empty string is recognized by the preferences service
    //       // as a valid value--when usually it is not.  Once it is recognized
    //       // as a valid value, it precludes the searching of subsequent
    //       // levels that might contain a non-empty (and actually valid) value.
    //       // We would like to be able to store a null value with the preferences
    //       // service so as to not short-circuit the search process, but we can't   
    //       // do that.  So, if the field value is empty, we have to eliminate the
    //       // preference entirely.  (Will that work in general???)
    //       if (isEmpty && !isEmptyStringAllowed()) {
    //          // We have an empty value where that isn't allowed, so clear the
    //          // preference.  Expect that clearing the preferences at a level will
    //          // trigger a loading with inheritance at that level
    //          preferencesService.clearPreferenceAtLevel(preferencesLevel, getPreferenceName());
    //          // If the preference value was previously empty (e.g., if previously inherited)
    //          // then clearing the preference node now doesn't cause a change event, so
    //          // doesn't trigger reloading with inheritance.  So we should just load the
    //          // field again to make sure any inheritance occurs if needed
    //          loadWithInheritance();
    //          return;
    //       }
    //       // Shouldn't need this check here now
    //       if (isInherited() && !fieldModified) {   
    //          // We have a value    but it's inherited   
    //          // (left over from after the last time we cleared the field)
    //          // so don't need (or want) to store it   
    //          return;
    //       }
    //       // We have a value (possibly empty, if that is allowed) that has changed
    //       // from the previous value, so store it
    //       preferencesService.setStringPreference(preferencesLevel, getPreferenceName(), value);
    //
    //        // If we've just stored the field, we've addressed any modifications
    //       // Shouldn't need these here now
    //         fieldModified = false;
    //         levelFromWhichLoaded = preferencesLevel;
    //         // If we've stored the field then it's not inherited, so be sure it's
    //         // color indicates that.
    //         // For text fields, the background color is the backgroud color within
    //         // the field, so don't have to worry about matching anything else
    //         getTextControl().setBackground(PreferencesUtilities.colorWhite);
    //       
    //       IEclipsePreferences node = preferencesService.getNodeForLevel(preferencesLevel);
    //       try {
    //          if (node != null) node.flush();
    //       } catch (BackingStoreException e) {
    //          System.err.println("StringFieldEditor.   ():  BackingStoreException flushing node;  node may not have been flushed:" + 
    //                "\n\tnode path = " + node.absolutePath() + ", preferences level = "  + preferencesLevel);
    //       }
    //    }

    /*
     * Methods relating the preferences level associated with this field
     */

    /**
     * Set the preference level associated with this field to the given level.
     * 
     * @param   The string name of a preference level
     * @throws   IllegalArgumentException
     *             if the given value does not denote a preference level         
     */
    public void setPreferencesLevel(String level) {
        if (!preferencesService.isaPreferencesLevel(level)) {
            throw new IllegalArgumentException(
                    "FieldEditor.setPreferencesLevel():  given level = " + level + " is invalid");
        }
        preferencesLevel = level;
    }

    /**
     * @return   The string name of the preference level associated with
     *          this field
     */
    public String getPreferencesLevel() {
        return preferencesLevel;
    }

    /*
     * Subtypes will require methods to get and set the value of the field; these
     * will depend on the type of the value.
     * 
     * The method to set the value should set previousValue to the value
     * in effect at the time of the call, set fieldModified to true, set
     * levelFromWhichLoaded to the level associated with the field, and
     * call valueChanged().  It should also set presentsDefaultValue
     * according to whether the value set is the same as the value that
     * is set on the "default" level (regardless of whether the value has
     * been set from that level).
     */

    /*
     * Subtypes will also require methods to get the applicable UI Control.
     * These methods will be dependent on the type of the field, which will
     * determine the type of control (e.g., TextControl, ChangeControl).
     * 
     * The typical pattern for such methods is to check whether the control
     * exists and, if not, to create it, adding a ModifyListener and a
     * DisposeListener.
     * 
     * If the parent control (a Composite) is needed for obtaining the field's
     * control, then it is also advisable to check whether the paretn is disposed
     * (as attempts to get controls from a disposed parent typically fail).
     * 
     * A null value can be returned if no real control is found.
     */

    /**
     * @return   The parent control of this field
     */
    public Composite getParent() {
        return parent;
    }

    /**
     * @return the "holder" of this field, which can be enabled/disabled as a group
     * (usually different from the parent)
     */
    public abstract Composite getHolder();

    /**
     * Should call the supertype method fireValueChanged() to inform 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.
     * 
     * This hook is <em>not</em> called when the text is initialized 
     * (or reset to the default value) from the preference store.
     * 
     * The means of obtaining the current value (for comparison with the
     * old) will probably depend on the type of the field and its control.
     * 
     * This method should probably not adjust any of the fields associated
     * with the field editor, as those should have been set appropriately
     * at the point where valueChanged() was called.
     */
    abstract protected boolean valueChanged();

    /*
     * FieldEditor contains a method refreshValidState() that has an
     * empty implementation.  That method can be overridden in subtypes
     * to update the validity status of a value.
     */

    /**
     * A utility method to trigger the reevaluation of the
     * validity state of the preferences tab.
     * (Started out doing more; may not be as useful now as
     * it was once expected to be.)
     * Need to promote notification of preference page
     * from field to tab.
     */
    protected boolean notifyState(boolean state) {
        //       if (prefPage != null)
        //          prefPage.setValid(state);
        if (prefTab != null)
            prefTab.setValid(state);

        return state;
    }

    /*
     * Methods related to marking modified fields
     */

    public void setModifiedMarkOnLabel() {
        // SMS 27 Nov 2006:  needed here?  should be up to caller
        //       if (isInherited) return;
        Label label = getLabelControl(parent);
        if (label != null) {
            //           String labelText = label.getText();
            //           if (!labelText.startsWith(Markings.MODIFIED_MARK)) {
            //              labelText = Markings.MODIFIED_MARK + labelText;
            //              label.setText(labelText);
            //           }
            // replace changed mark by color to eliminate text-box overflow bug
            label.setForeground(PreferencesUtilities.colorRed);
        }
    }

    public void clearModifiedMarkOnLabel() {
        Label label = getLabelControl(parent);
        if (label != null) {
            //           String labelText = label.getText();
            //           if (labelText.startsWith(Markings.MODIFIED_MARK))
            //                 labelText = labelText.substring(Markings.MODIFIED_MARK.length());
            //           label.setText(labelText);
            label.setForeground(PreferencesUtilities.colorBlack);
        }
    }

    /*
     * Methods related to error messages
     */

    protected void clearErrorMessage() {
        prefTab.clearErrorMessages(this);
    }

    protected void setErrorMessage(String msg) {
        prefTab.setErrorMessage(this, msg);
    }

    public boolean hasErrorMessage() {
        return prefTab.errorMessages.containsKey(this);
    }

    public String getFieldMessagePrefix() {
        return /*prefTab.getTabItem().getText() + " Tab:  " +*/ getLabelText() + ":  ";
    }

    protected abstract void doSetToolTip();

    public void setToolTipText(String toolTipText) {
        this.toolTipText = toolTipText;
        doSetToolTip();
    }

    public String getToolTipText() {
        return toolTipText;
    }
}