org.csstudio.diirt.util.preferences.BasePreferencePage.java Source code

Java tutorial

Introduction

Here is the source code for org.csstudio.diirt.util.preferences.BasePreferencePage.java

Source

/**
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 * Copyright (C) 2016 European Spallation Source ERIC.
 * 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
 */
package org.csstudio.diirt.util.preferences;

import static org.csstudio.diirt.util.core.preferences.DIIRTPreferences.PREF_CONFIGURATION_DIRECTORY;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Supplier;

import org.csstudio.diirt.util.core.preferences.DIIRTPreferences;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.preference.FieldEditor;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.preference.PreferencePage;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPreferencePage;
import org.eclipse.ui.PlatformUI;
import org.eclipse.wb.swt.SWTResourceManager;

/**
 * @author Claudio Rosati, European Spallation Source ERIC
 * @version 1.0.0 16 Nov 2016
 */
public abstract class BasePreferencePage extends PreferencePage implements IWorkbenchPreferencePage {

    private static final Set<BasePreferencePage> DIIRT_PAGES = new HashSet<>();

    private Editor directoryEditor = null;
    private final Map<FieldEditor, Editor> editors = new HashMap<>();

    public BasePreferencePage() {
        DIIRT_PAGES.add(this);
    }

    /**
     * Initialize the preference page.
     */
    @Override
    public void init(IWorkbench arg0) {
    }

    /**
     * Add the given {@code editor} field to this page.
     *
     * @param editor The {@link FieldEditor} to tbe added and updated.
     * @param parent The {@link Composite} owning the given {@code editor}.
     * @param canBeDefaulted {@code true} if the given {@code editor} can be
     *            restored to its default value.
     * @param storedGetter The {@link Supplier} of the editor's stored value.
     *            Can be {@code null} if the editor's caption foreground
     *            should not be initially updated.
     */
    protected void addField(FieldEditor editor, Composite parent, boolean canBeDefaulted,
            Supplier<Object> storedGetter) {
        addField(editor, parent, canBeDefaulted, null, storedGetter);
    }

    /**
     * Add the given {@code editor} field to this page. The editor's
     * caption foreground will be updated when the editor's value changes.
     *
     * @param fieldEditor The {@link FieldEditor} to be added and updated.
     * @param parent The {@link Composite} owning the given {@code editor}.
     * @param canBeDefaulted {@code true} if the given {@code editor} can be
     *            restored to its default value.
     * @param defaultGetter The {@link Supplier} of the editor's default value.
     *            Can be {@code null} if the editor's caption foreground
     *            should not be updated when the editor's value changes.
     * @param storedGetter The {@link Supplier} of the editor's stored value.
     *            Can be {@code null} if the editor's caption foreground
     *            should not be initially updated.
     */
    protected void addField(FieldEditor fieldEditor, Composite parent, boolean canBeDefaulted,
            Supplier<Object> defaultGetter, Supplier<Object> storedGetter) {
        addField(fieldEditor, parent, canBeDefaulted, defaultGetter, storedGetter, null);
    }

    /**
     * Add the given {@code editor} field to this page. The editor's
     * caption foreground will be updated when the editor's value changes.
     *
     * @param fieldEditor The {@link FieldEditor} to be added and updated.
     * @param parent The {@link Composite} owning the given {@code editor}.
     * @param canBeDefaulted {@code true} if the given {@code editor} can be
     *            restored to its default value.
     * @param defaultGetter The {@link Supplier} of the editor's default value.
     *            Can be {@code null} if the editor's caption foreground
     *            should not be updated when the editor's value changes.
     * @param storedGetter The {@link Supplier} of the editor's stored value.
     *            Can be {@code null} if the editor's caption foreground
     *            should not be initially updated.
     * @param listener Called when a field editor fires a value property change.
     */
    protected void addField(FieldEditor fieldEditor, Composite parent, boolean canBeDefaulted,
            Supplier<Object> defaultGetter, Supplier<Object> storedGetter, IPropertyChangeListener listener) {

        final IPreferenceStore store = getPreferenceStore();
        final Editor editor = new Editor(fieldEditor, parent, canBeDefaulted, defaultGetter, storedGetter);

        fieldEditor.getLabelControl(parent).setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
        fieldEditor.setPage(this);
        fieldEditor.setPreferenceStore(store);
        fieldEditor.load();
        fieldEditor.setPropertyChangeListener(e -> {
            if (FieldEditor.VALUE.equals(e.getProperty())) {

                if (storedGetter != null) {
                    editor.setRestartRequired(!Objects.equals(e.getNewValue(), storedGetter.get()));
                }

                editor.updateCaptionColor(e.getNewValue());

                if (listener != null) {
                    listener.propertyChange(e);
                }

            }
        });

        editor.updateCaptionColor();
        editors.put(fieldEditor, editor);

        if (PREF_CONFIGURATION_DIRECTORY.equals(fieldEditor.getPreferenceName())) {
            directoryEditor = editor;
        }

    }

    /**
     * Clear the warning message.
     */
    protected void clearWarning() {
        Display.getDefault().syncExec(() -> setMessage(null, NONE));
    }

    protected GridData createIntegerFieldEditorGridData() {

        GridData gd = new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1);

        gd.minimumWidth = 80;
        gd.widthHint = 80;

        return gd;

    }

    @Override
    public void dispose() {

        DIIRT_PAGES.remove(this);

        super.dispose();

    }

    @Override
    public boolean performCancel() {

        DIIRTPreferencesPlugin.get().performCancel();

        return true;

    }

    @Override
    public boolean performOk() {

        editors.keySet().stream().forEach(e -> e.store());
        DIIRTPreferencesPlugin.get().performFlush();

        if (editors.values().stream().anyMatch(e -> e.isRestartRequired())) {

            boolean restart = MessageDialog.openConfirm(getShell(), Messages.BPP_performOk_title,
                    Messages.BPP_performOk_message);

            if (restart) {

                editors.keySet().stream().forEach(e -> e.store());

                new Job("Restarting after DIIRT preferences changed") {
                    @Override
                    protected IStatus run(IProgressMonitor m) {

                        Display.getDefault().asyncExec(() -> PlatformUI.getWorkbench().restart());

                        return Status.OK_STATUS;

                    }
                }.schedule(500L);

                return super.performOk();

            } else {
                return false;
            }

        } else {
            return super.performOk();
        }

    }

    @Override
    protected IPreferenceStore doGetPreferenceStore() {
        return DIIRTPreferencesPlugin.get().getPreferenceStore();
    }

    /**
     * Initialize widgets with values from the preferences store.
     *
     * @param store The data store.
     * @return The DIIRT configuration path.
     */
    protected String initializeValues(IPreferenceStore store) {

        String confDir = DIIRTPreferences.get().getDIIRTHome();

        if (verifyAndNotifyWarning(confDir)) {
            reloadEditors();
        }

        DIIRTPreferencesPlugin.get().initializeCancelStore();

        return confDir;

    }

    /**
     * Displays an error message.
     *
     * @param message The message to be displayed.
     */
    protected void notifyError(final String message) {
        notifyMessage(message, ERROR);
    }

    /**
     * Displays an information message.
     *
     * @param message The message to be displayed.
     */
    protected void notifyInformation(final String message) {
        notifyMessage(message, INFORMATION);
    }

    /**
     * Displays a message.
     *
     * @param message The message to be displayed.
     * @param type The type of the message: {@link #NONE}, {@link #INFORMATION}, {@link #WARNING}, or {@link #ERROR}.
     */
    protected void notifyMessage(final String message, int type) {

        final int ftype;

        switch (type) {
        case NONE:
        case INFORMATION:
        case WARNING:
        case ERROR:
            ftype = type;
            break;
        default:
            ftype = NONE;
            break;
        }

        Display.getDefault().syncExec(() -> setMessage(message, message != null ? ftype : NONE));

    }

    /**
     * Displays a warning message.
     *
     * @param message The message to be displayed.
     */
    protected void notifyWarning(final String message) {
        notifyMessage(message, WARNING);
    }

    @Override
    protected void performApply() {
        editors.keySet().stream().forEach(e -> e.store());
    }

    @Override
    protected void performDefaults() {

        super.performDefaults();

        editors.entrySet().stream().filter(e -> e.getValue().isCanBeDefaulted()).forEach(e -> {

            e.getKey().loadDefault();

            Editor editor = e.getValue();
            Supplier<Object> defaultGetter = editor.getDefaultGetter();

            if (defaultGetter != null) {
                editor.updateCaptionColor(defaultGetter.get());
            }

        });

    }

    /**
     * Updates the colors of all editors in the page.
     */
    protected void reloadEditors() {
        editors.entrySet().stream().forEach(e -> {
            e.getKey().load();
            e.getValue().updateCaptionColor();
        });
    }

    /**
     * Updates the colors of all editors inside all DIIRT pages.
     */
    protected final void reloadEditorsForAllPages() {
        DIIRT_PAGES.stream().forEach(p -> p.reloadEditors());
    }

    /**
     * Updates the color of the given {@code editor}'s caption, depending on
     * the current value compared with the default one. If they are equals, the
     * caption foreground color will be {@link SWT#COLOR_WIDGET_FOREGROUND},
     * otherwise {@link SWT#COLOR_BLUE}.
     *
     * @param editor The {@link FieldEditor} whose caption's color must be
     *            updated.
     * @param parent The {@link Composite} owning the given {@code editor}.
     * @param defaultValue The {@code editor}'s default value.
     * @param currentValue The {@code editor}'s current value.
     */
    protected void updateCaptionColor(final FieldEditor editor, final Composite parent, Object defaultValue,
            Object currentValue) {

        final Color captionColor = Objects.equals(defaultValue, currentValue)
                ? SWTResourceManager.getColor(SWT.COLOR_WIDGET_FOREGROUND)
                : SWTResourceManager.getColor(SWT.COLOR_BLUE);

        Display.getDefault().asyncExec(() -> {

            Label l = editor.getLabelControl(parent);

            if (!l.isDisposed()) {
                l.setForeground(captionColor);
            }

        });

    }

    /**
     * Updates the color of the given {@code editor}'s caption, depending on
     * the current {@code error} value. If {@code false}, the caption foreground
     * color will be {@link SWT#COLOR_WIDGET_FOREGROUND}, otherwise
     * {@link SWT#COLOR_RED}.
     *
     * @param editor The {@link FieldEditor} whose caption's color must be
     *            updated.
     * @param parent The {@link Composite} owning the given {@code editor}.
     * @param error {@code true} if the caption must be colored in
     *            {@link SWT#COLOR_RED}.
     * @param tooltip The tooltip assigned to the {@code editor}'s caption.
     */
    protected void updateCaptionColor(final Composite parent, final FieldEditor editor, boolean error,
            final String tooltip) {

        final Color captionColor = error ? SWTResourceManager.getColor(SWT.COLOR_RED)
                : SWTResourceManager.getColor(SWT.COLOR_WIDGET_FOREGROUND);

        Display.getDefault().asyncExec(() -> {

            Label l = editor.getLabelControl(parent);

            if (!l.isDisposed()) {
                l.setForeground(captionColor);
                l.setToolTipText(tooltip);
            }

        });

    }

    /**
     * @param path The path to be verified.
     * @return {@code true} if the path is a valid one pointing to a DIIRT
     *         configuration directory.
     */
    protected boolean verifyAndNotifyWarning(final String path) {

        String message = DIIRTPreferences.resolveAndVerifyDIIRTPath(path);

        if (message == null) {

            if (directoryEditor != null) {
                directoryEditor.updateCaptionColor(false);
            }

            return true;

        } else {

            if (directoryEditor != null) {
                directoryEditor.updateCaptionColor(true, message);
            }

            DIIRTPreferencesPlugin.LOGGER.warning(message);

            return false;

        }

    }

    private class Editor {

        private final FieldEditor editor;
        private final Composite parent;
        private final boolean canBeDefaulted;
        private final Supplier<Object> defaultGetter;
        private boolean restartRequired = false;
        private final Supplier<Object> storedGetter;

        protected Editor(FieldEditor editor, Composite parent, boolean canBeDefaulted,
                Supplier<Object> defaultGetter, Supplier<Object> storedGetter) {
            this.editor = editor;
            this.parent = parent;
            this.canBeDefaulted = canBeDefaulted;
            this.defaultGetter = defaultGetter;
            this.storedGetter = storedGetter;
        }

        Supplier<Object> getDefaultGetter() {
            return defaultGetter;
        }

        boolean isCanBeDefaulted() {
            return canBeDefaulted;
        }

        boolean isRestartRequired() {
            return restartRequired;
        }

        void updateCaptionColor() {
            if (storedGetter != null) {
                updateCaptionColor(storedGetter.get());
            }
        }

        void updateCaptionColor(final Object value) {
            if (defaultGetter != null) {
                BasePreferencePage.this.updateCaptionColor(editor, parent, defaultGetter.get(), value);
            }
        }

        void updateCaptionColor(final boolean error) {
            BasePreferencePage.this.updateCaptionColor(parent, editor, error, null);
        }

        void updateCaptionColor(final boolean error, final String tooltip) {
            BasePreferencePage.this.updateCaptionColor(parent, editor, error, tooltip);
        }

        void setRestartRequired(boolean restartRequired) {
            this.restartRequired = restartRequired;
        }

    }

}