com.aptana.formatter.ui.preferences.OptionsConfigurationBlock.java Source code

Java tutorial

Introduction

Here is the source code for com.aptana.formatter.ui.preferences.OptionsConfigurationBlock.java

Source

/*******************************************************************************
 * Copyright (c) 2005, 2007 IBM Corporation and others.
 * 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:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package com.aptana.formatter.ui.preferences;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ProjectScope;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.preferences.IScopeContext;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.preferences.IWorkbenchPreferenceContainer;
import org.eclipse.ui.preferences.IWorkingCopyManager;
import org.eclipse.ui.preferences.WorkingCopyManager;
import org.osgi.service.prefs.BackingStoreException;

import com.aptana.core.logging.IdeLog;
import com.aptana.core.util.EclipseUtil;
import com.aptana.formatter.IDebugScopes;
import com.aptana.formatter.preferences.PreferenceKey;
import com.aptana.formatter.ui.epl.FormatterUIEplPlugin;
import com.aptana.formatter.ui.util.IStatusChangeListener;

/**
 * Direct port from the jdt ui, this class should not be extended by anyone but the internal ui.
 * 
 * @see com.aptana.ui.preferences.AbstractOptionsBlock
 */
public abstract class OptionsConfigurationBlock {

    private static final String REBUILD_COUNT_KEY = "preferences_build_requested"; //$NON-NLS-1$

    private final IStatusChangeListener fContext;
    protected final IProject fProject; // project or null
    protected final PreferenceKey[] fAllKeys;
    protected IScopeContext[] fLookupOrder;

    private Shell fShell;

    private final IWorkingCopyManager fManager;
    private IWorkbenchPreferenceContainer fContainer;

    // null when project specific settings are turned off
    private Map<PreferenceKey, String> fDisabledProjectSettings;

    // used to prevent multiple dialogs that ask for a rebuild
    private int fRebuildCount;

    public OptionsConfigurationBlock(IStatusChangeListener context, IProject project, PreferenceKey[] allKeys,
            IWorkbenchPreferenceContainer container) {
        fContext = context;
        fProject = project;
        fAllKeys = allKeys;
        fContainer = container;
        if (container == null) {
            fManager = new WorkingCopyManager();
        } else {
            fManager = container.getWorkingCopyManager();
        }

        if (fProject != null) {
            fLookupOrder = new IScopeContext[] { new ProjectScope(fProject), EclipseUtil.instanceScope(),
                    EclipseUtil.defaultScope() };
        } else {
            fLookupOrder = new IScopeContext[] { EclipseUtil.instanceScope(), EclipseUtil.defaultScope() };
        }

        testIfOptionsComplete(allKeys);
        if (fProject == null || hasProjectSpecificOptions(fProject)) {
            fDisabledProjectSettings = null;
        } else {
            fDisabledProjectSettings = new HashMap<PreferenceKey, String>();
            for (int i = 0; i < allKeys.length; i++) {
                PreferenceKey curr = allKeys[i];
                fDisabledProjectSettings.put(curr, curr.getStoredValue(fLookupOrder, false, fManager));
            }
        }

        fRebuildCount = getRebuildCount();
    }

    protected final IWorkbenchPreferenceContainer getPreferenceContainer() {
        return fContainer;
    }

    private void testIfOptionsComplete(PreferenceKey[] allKeys) {
        for (PreferenceKey key : allKeys) {
            validateValuePresenceFor(key);
        }
    }

    protected void validateValuePresenceFor(PreferenceKey key) {
        if (key.getStoredValue(fLookupOrder, false, fManager) == null) {
            IdeLog.logError(FormatterUIEplPlugin.getDefault(),
                    MessageFormat.format("preference option missing: {0} ({1})", key, this.getClass().getName()), //$NON-NLS-1$
                    IDebugScopes.DEBUG);
        }
    }

    private int getRebuildCount() {
        return fManager.getWorkingCopy(EclipseUtil.defaultScope().getNode(FormatterUIEplPlugin.PLUGIN_ID))
                .getInt(REBUILD_COUNT_KEY, 0);
    }

    private void incrementRebuildCount() {
        fRebuildCount++;
        fManager.getWorkingCopy(EclipseUtil.defaultScope().getNode(FormatterUIEplPlugin.PLUGIN_ID))
                .putInt(REBUILD_COUNT_KEY, fRebuildCount);
    }

    public boolean hasProjectSpecificOptions(IProject project) {
        if (project != null) {
            IScopeContext projectContext = new ProjectScope(project);
            PreferenceKey[] allKeys = fAllKeys;
            for (int i = 0; i < allKeys.length; i++) {
                if (allKeys[i].getStoredValue(projectContext, fManager) != null) {
                    return true;
                }
            }
        }
        return false;
    }

    protected Shell getShell() {
        return fShell;
    }

    protected void setShell(Shell shell) {
        fShell = shell;
    }

    protected abstract Control createContents(Composite parent);

    protected String getValue(PreferenceKey key) {
        if (fDisabledProjectSettings != null) {
            return fDisabledProjectSettings.get(key);
        }
        return key.getStoredValue(fLookupOrder, false, fManager);
    }

    protected boolean getBooleanValue(PreferenceKey key) {
        return Boolean.valueOf(getValue(key)).booleanValue();
    }

    protected String setValue(PreferenceKey key, String value) {
        if (fDisabledProjectSettings != null) {
            return fDisabledProjectSettings.put(key, value);
        }
        String oldValue = getValue(key);
        key.setStoredValue(fLookupOrder[0], value, fManager);
        return oldValue;
    }

    protected String setValue(PreferenceKey key, boolean value) {
        return setValue(key, String.valueOf(value));
    }

    private boolean getChanges(IScopeContext currContext, List<PreferenceKey> changedSettings) {
        // complete when project settings are enabled
        boolean completeSettings = fProject != null && fDisabledProjectSettings == null;
        boolean needsBuild = false;

        /*
         * XXX: need to rework this once there are options this affects - this can cause an illegal state exception -
         * probably due to the fact that key binding is different from the jdt implementation
         */
        for (int i = 0; i < fAllKeys.length; i++) {
            try {
                PreferenceKey key = fAllKeys[i];
                String oldVal = key.getStoredValue(currContext, null);
                String val = key.getStoredValue(currContext, fManager);
                if (val == null) {
                    if (oldVal != null) {
                        changedSettings.add(key);
                        needsBuild |= !oldVal.equals(key.getStoredValue(fLookupOrder, true, fManager));
                    } else if (completeSettings) {
                        key.setStoredValue(currContext, key.getStoredValue(fLookupOrder, true, fManager), fManager);
                        changedSettings.add(key);
                        // no build needed
                    }
                } else if (!val.equals(oldVal)) {
                    changedSettings.add(key);
                    needsBuild |= oldVal != null || !val.equals(key.getStoredValue(fLookupOrder, true, fManager));
                }
            } catch (IllegalStateException e) {
                if (FormatterUIEplPlugin.DEBUG) {
                    e.printStackTrace();
                }
            }
        }
        return needsBuild;
    }

    public void useProjectSpecificSettings(boolean enable) {
        boolean hasProjectSpecificOption = fDisabledProjectSettings == null;
        if (enable != hasProjectSpecificOption && fProject != null) {
            if (enable) {
                for (int i = 0; i < fAllKeys.length; i++) {
                    PreferenceKey curr = fAllKeys[i];
                    String val = fDisabledProjectSettings.get(curr);
                    curr.setStoredValue(fLookupOrder[0], val, fManager);
                }
                fDisabledProjectSettings = null;
            } else {
                fDisabledProjectSettings = new HashMap<PreferenceKey, String>();
                for (int i = 0; i < fAllKeys.length; i++) {
                    PreferenceKey curr = fAllKeys[i];
                    String oldSetting = curr.getStoredValue(fLookupOrder, false, fManager);
                    fDisabledProjectSettings.put(curr, oldSetting);
                }
            }
        }
    }

    public boolean performOk() {
        return processChanges(fContainer);
    }

    public boolean performApply() {
        // apply directly
        return processChanges(null);
    }

    protected boolean processChanges(IWorkbenchPreferenceContainer container) {
        IScopeContext currContext = fLookupOrder[0];

        List<PreferenceKey> changedOptions = new ArrayList<PreferenceKey>();
        boolean needsBuild = getChanges(currContext, changedOptions);
        if (changedOptions.isEmpty()) {
            return true;
        }
        if (needsBuild) {
            int count = getRebuildCount();
            if (count > fRebuildCount) {
                needsBuild = false; // build already requested
                fRebuildCount = count;
            }
        }

        boolean doBuild = false;
        if (needsBuild) {
            IPreferenceChangeRebuildPrompt prompt = getPreferenceChangeRebuildPrompt(fProject == null,
                    changedOptions);
            if (prompt != null) {
                MessageDialog dialog = new MessageDialog(getShell(), prompt.getTitle(), null, prompt.getMessage(),
                        MessageDialog.QUESTION, new String[] { IDialogConstants.YES_LABEL,
                                IDialogConstants.NO_LABEL, IDialogConstants.CANCEL_LABEL },
                        2);
                int res = dialog.open();
                if (res == 0) {
                    doBuild = true;
                } else if (res != 1) {
                    return false; // cancel pressed
                }
            }
        }
        if (container != null) {
            // no need to apply the changes to the original store: will be done
            // by the page container
            if (doBuild) { // post build
                incrementRebuildCount();
                for (Job job : createBuildJobs(fProject)) {
                    container.registerUpdateJob(job);
                }
            }
        } else {
            // apply changes right away
            try {
                fManager.applyChanges();
            } catch (BackingStoreException e) {
                IdeLog.logError(FormatterUIEplPlugin.getDefault(), e, IDebugScopes.DEBUG);
                return false;
            }
            if (doBuild) {
                for (Job job : createBuildJobs(fProject)) {
                    job.schedule();
                }
            }

        }
        return true;
    }

    /**
     * Create build Jobs for the given project.
     * 
     * @param project
     * @return Job array for building the given project
     */
    protected abstract Job[] createBuildJobs(IProject project);

    public void performDefaults() {
        for (int i = 0; i < fAllKeys.length; i++) {
            PreferenceKey curr = fAllKeys[i];
            String origValue = curr.getStoredValue(fLookupOrder, true, fManager);
            setValue(curr, origValue);
        }
    }

    /**
     * Returns the prompt that should be used in the popup box that indicates a project build needs to occur.
     * <p>
     * Default implementation returns <code>null</code>. Clients should override to return context appropriate message.
     * </p>
     * 
     * @param workspaceSettings
     *            <code>true</code> if workspace settings were changed, <code>false</code> if project settings were
     *            changed
     * @param changedOptions
     *            options that were actually changed. Could be used to test if particular option was changed.
     * @return
     */
    protected IPreferenceChangeRebuildPrompt getPreferenceChangeRebuildPrompt(boolean workspaceSettings,
            Collection<PreferenceKey> changedOptions) {
        return null;
    }

    public void dispose() {
    }

    protected void statusChanged(IStatus status) {
        fContext.statusChanged(status);
    }
}