org.eclipse.cdt.internal.ui.language.settings.providers.LanguageSettingsProviderTab.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.cdt.internal.ui.language.settings.providers.LanguageSettingsProviderTab.java

Source

/*******************************************************************************
 * Copyright (c) 2010, 2011 Andrew Gvozdev 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:
 *     Andrew Gvozdev - Initial API and implementation
 *******************************************************************************/
package org.eclipse.cdt.internal.ui.language.settings.providers;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.CheckStateChangedEvent;
import org.eclipse.jface.viewers.CheckboxTableViewer;
import org.eclipse.jface.viewers.ICheckStateListener;
import org.eclipse.jface.viewers.IDecoration;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.ControlListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Link;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Table;
import org.eclipse.ui.dialogs.PreferencesUtil;

import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsEditableProvider;
import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsProvider;
import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsProvidersKeeper;
import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsManager;
import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsSerializableProvider;
import org.eclipse.cdt.core.language.settings.providers.ScannerDiscoveryLegacySupport;
import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
import org.eclipse.cdt.core.settings.model.ICResourceDescription;
import org.eclipse.cdt.ui.CDTSharedImages;
import org.eclipse.cdt.ui.CUIPlugin;
import org.eclipse.cdt.ui.dialogs.ICOptionPage;
import org.eclipse.cdt.ui.language.settings.providers.AbstractLanguageSettingProviderOptionPage;
import org.eclipse.cdt.ui.newui.AbstractCPropertyTab;
import org.eclipse.cdt.utils.ui.controls.TabFolderLayout;

import org.eclipse.cdt.internal.ui.newui.Messages;
import org.eclipse.cdt.internal.ui.newui.StatusMessageLine;

/**
 * This tab presents language settings entries categorized by language
 * settings providers.
 *
 *@noinstantiate This class is not intended to be instantiated by clients.
 *@noextend This class is not intended to be subclassed by clients.
 */
public class LanguageSettingsProviderTab extends AbstractCPropertyTab {
    private static final String WORKSPACE_PREFERENCE_PAGE = "org.eclipse.cdt.ui.preferences.BuildSettingProperties"; //$NON-NLS-1$
    private static final String TEST_PLUGIN_ID_PATTERN = "org.eclipse.cdt.*.tests.*"; //$NON-NLS-1$

    private static final String CLEAR_STR = Messages.LanguageSettingsProviderTab_Clear;
    private static final String RESET_STR = Messages.LanguageSettingsProviderTab_Reset;

    private static final int BUTTON_CLEAR = 0;
    private static final int BUTTON_RESET = 1;
    // there is a separator instead of button #2
    private static final int BUTTON_MOVE_UP = 3;
    private static final int BUTTON_MOVE_DOWN = 4;

    private static final int[] DEFAULT_CONFIGURE_SASH_WEIGHTS = new int[] { 50, 50 };
    private SashForm sashFormProviders;

    private Table tableProviders;
    private CheckboxTableViewer tableProvidersViewer;
    private Group groupOptionsPage;
    private ICOptionPage currentOptionsPage = null;
    private Composite compositeOptionsPage;

    private StatusMessageLine fStatusLine;

    private Button sharedProviderCheckBox = null;
    private Link linkToWorkspacePreferences = null;
    private Button projectStorageCheckBox = null;

    private LanguageSettingsProvidersPage masterPropertyPage = null;

    /**
     * List of providers presented to the user.
     * For global providers included in a configuration this contains references
     * not raw providers.
     */
    private List<ILanguageSettingsProvider> presentedProviders = null;
    private final Map<String, ICOptionPage> optionsPageMap = new HashMap<String, ICOptionPage>();
    private Map<String/*cfgId*/, List<ILanguageSettingsProvider>> initialProvidersByCfg = new HashMap<String, List<ILanguageSettingsProvider>>();

    /**
     * Label provider for language settings providers displayed by this tab.
     */
    private class ProvidersTableLabelProvider extends LanguageSettingsProvidersLabelProvider {
        @Override
        protected String[] getOverlayKeys(ILanguageSettingsProvider provider) {
            String[] overlayKeys = super.getOverlayKeys(provider);
            if (provider.getName() == null) {
                return overlayKeys;
            }

            if (page.isForProject()) {
                if (isEditedForProject(provider)) {
                    overlayKeys[IDecoration.TOP_RIGHT] = CDTSharedImages.IMG_OVR_EDITED;
                } else if (!LanguageSettingsManager.getExtensionProviderIds().contains(provider.getId())) {
                    overlayKeys[IDecoration.TOP_RIGHT] = CDTSharedImages.IMG_OVR_USER;
                } else if (isReconfiguredForProject(provider)) {
                    overlayKeys[IDecoration.TOP_RIGHT] = CDTSharedImages.IMG_OVR_SETTING;
                }
            } else if (page.isForPrefs()) {
                if (isWorkingCopy(provider) && !provider.equals(LanguageSettingsManager
                        .getRawProvider(LanguageSettingsManager.getWorkspaceProvider(provider.getId())))) {
                    overlayKeys[IDecoration.TOP_RIGHT] = CDTSharedImages.IMG_OVR_EDITED;
                } else if (!LanguageSettingsManager.getExtensionProviderIds().contains(provider.getId())) {
                    overlayKeys[IDecoration.TOP_RIGHT] = CDTSharedImages.IMG_OVR_USER;
                } else {
                    ILanguageSettingsProvider rawProvider = LanguageSettingsManager.getRawProvider(provider);
                    if (rawProvider instanceof ILanguageSettingsEditableProvider
                            && !LanguageSettingsManager.isEqualExtensionProvider(rawProvider, false)) {
                        overlayKeys[IDecoration.TOP_RIGHT] = CDTSharedImages.IMG_OVR_SETTING;
                    }
                }
            }

            return overlayKeys;
        }

        @Override
        public String getText(Object element) {
            if (element instanceof ILanguageSettingsProvider) {
                ILanguageSettingsProvider provider = (ILanguageSettingsProvider) element;
                String name = provider.getName();
                if (name != null && (page.isForPrefs() || isPresentedAsShared(provider))) {
                    return name + Messages.LanguageSettingsProvidersLabelProvider_TextDecorator_Shared;
                }
            }
            return super.getText(element);
        }
    }

    /**
     * Returns the provider which is being presented to the user in UI.
     * Used by option pages when there is a need.
     * Warning: Do not cache the result as the provider can be replaced at any time.
     * @param id - id of the provider.
     *
     * @return the provider.
     */
    public ILanguageSettingsProvider getProvider(String id) {
        return findProvider(id, presentedProviders);
    }

    /**
     * Returns the provider equal to provider at the point from which editing started.
     * Used by option pages when there is a need.
     * @param id - id of the provider.
     *
     * @return the initial provider.
     */
    public ILanguageSettingsProvider getInitialProvider(String id) {
        ILanguageSettingsProvider initialProvider = null;
        if (page.isForPrefs()) {
            initialProvider = LanguageSettingsManager.getWorkspaceProvider(id);
        } else {
            ICConfigurationDescription cfgDescription = getConfigurationDescription();
            List<ILanguageSettingsProvider> initialProviders = initialProvidersByCfg.get(cfgDescription.getId());
            initialProvider = findProvider(id, initialProviders);
        }
        return initialProvider;
    }

    /**
     * Check if the provider is a working copy and can be modified.
     */
    private boolean isWorkingCopy(ILanguageSettingsProvider provider) {
        boolean isWorkingCopy = false;
        if (page.isForPrefs()) {
            isWorkingCopy = !LanguageSettingsManager.isWorkspaceProvider(provider);
        } else {
            if (!LanguageSettingsManager.isWorkspaceProvider(provider)) {
                ICConfigurationDescription cfgDescription = getConfigurationDescription();
                List<ILanguageSettingsProvider> initialProviders = initialProvidersByCfg
                        .get(cfgDescription.getId());
                isWorkingCopy = initialProviders != null && !initialProviders.contains(provider);
            }

        }
        return isWorkingCopy;
    }

    /**
     * Returns current working copy of the provider. Creates one if it has not been created yet.
     * A working copy will be discarded if user pushes [Cancel] or it will replace original
     * provider on [Apply] or [OK].
     *
     * This method is used also by option pages when there is a need to modify the provider.
     * Warning: Do not cache the result as the provider can be replaced at any time.
     *
     * @param id - id of the provider.
     * @return working copy of the provider.
     */
    public ILanguageSettingsProvider getWorkingCopy(String id) {
        ILanguageSettingsProvider provider = findProvider(id, presentedProviders);
        if (isWorkingCopy(provider)) {
            return provider;
        }

        ILanguageSettingsProvider rawProvider = LanguageSettingsManager.getRawProvider(provider);
        ILanguageSettingsEditableProvider newProvider = LanguageSettingsManager
                .getProviderCopy((ILanguageSettingsEditableProvider) rawProvider, true);
        if (newProvider != null) {
            replaceSelectedProvider(newProvider);
            // Warning: Do not initializeOptionsPage() here as the method can be called from an existing page
        }

        return newProvider;
    }

    /**
     * Refresh provider item in the table and update buttons.
     * This method is intended for use by an Options Page of the provider.
     *
     * @param provider - provider item in the table to refresh.
     */
    public void refreshItem(ILanguageSettingsProvider provider) {
        tableProvidersViewer.refresh(provider);
        updateButtons();
    }

    /**
     * Check if provider should get "reconfigured" overlay in UI.
     */
    private boolean isReconfiguredForProject(ILanguageSettingsProvider provider) {
        String id = provider.getId();

        ICConfigurationDescription cfgDescription = getConfigurationDescription();
        String[] defaultIds = ((ILanguageSettingsProvidersKeeper) cfgDescription)
                .getDefaultLanguageSettingsProvidersIds();
        List<ILanguageSettingsProvider> providers = ((ILanguageSettingsProvidersKeeper) cfgDescription)
                .getLanguageSettingProviders();

        // check for the provider mismatch in configuration list vs. default list from the tool-chain
        if (defaultIds != null && (Arrays.asList(defaultIds).contains(id) != providers.contains(provider))) {
            return true;
        }

        // check if provider belongs to configuration (i.e. checked in the table)
        if (!providers.contains(provider)) {
            return false;
        }

        // check if "shared" flag matches default shared preference from extension point definition
        if (LanguageSettingsManager.isPreferShared(id) != LanguageSettingsManager.isWorkspaceProvider(provider)) {
            return true;
        }

        // check if configuration provider equals to the default one from extension point
        if (!LanguageSettingsManager.isWorkspaceProvider(provider)
                && !LanguageSettingsManager.isEqualExtensionProvider(provider, false)) {
            return true;
        }

        return false;
    }

    /**
     * Check if provider should get "edited" overlay in UI.
     */
    private boolean isEditedForProject(ILanguageSettingsProvider provider) {
        String id = provider.getId();
        ICConfigurationDescription cfgDescription = getConfigurationDescription();
        List<ILanguageSettingsProvider> initialProviders = initialProvidersByCfg.get(cfgDescription.getId());
        List<ILanguageSettingsProvider> providers = getCheckedProviders();

        // check for the provider mismatch in configuration list vs. initial list
        ILanguageSettingsProvider initialProvider = findProvider(id, initialProviders);
        if ((initialProvider != null) != providers.contains(provider)) {
            return true;
        }

        // check if "shared" flag matches that of initial provider
        if (providers.contains(provider) && LanguageSettingsManager
                .isWorkspaceProvider(initialProvider) != LanguageSettingsManager.isWorkspaceProvider(provider)) {
            return true;
        }

        // check if configuration provider equals to the initial one
        if (!LanguageSettingsManager.isWorkspaceProvider(provider) && !provider.equals(initialProvider)) {
            return true;
        }

        return false;
    }

    /**
     * Checks if the provider should be presented as shared. Unchecked providers are shown as non-shared
     * if they are defined as non-shared in extension point even if in fact shared instance is used to display
     * the options page.
     */
    private boolean isPresentedAsShared(ILanguageSettingsProvider provider) {
        ICConfigurationDescription cfgDescription = getConfigurationDescription();
        List<ILanguageSettingsProvider> providers = ((ILanguageSettingsProvidersKeeper) cfgDescription)
                .getLanguageSettingProviders();
        return LanguageSettingsManager.isWorkspaceProvider(provider)
                && (providers.contains(provider) || LanguageSettingsManager.isPreferShared(provider.getId()));
    }

    /**
     * Find provider with a given ID in the list or {@code null}.
     */
    private ILanguageSettingsProvider findProvider(String id, List<ILanguageSettingsProvider> providers) {
        if (providers != null) {
            for (ILanguageSettingsProvider provider : providers) {
                if (provider.getId().equals(id)) {
                    return provider;
                }
            }
        }
        return null;
    }

    /**
     * Shortcut for getting the currently selected provider.
     * Do not use if you need to change provider's settings or entries, use {@link #getWorkingCopy(String)}.
     */
    private ILanguageSettingsProvider getSelectedProvider() {
        ILanguageSettingsProvider provider = null;

        int pos = tableProviders.getSelectionIndex();
        if (pos >= 0 && pos < tableProviders.getItemCount()) {
            provider = (ILanguageSettingsProvider) tableProvidersViewer.getElementAt(pos);
        }
        return provider;
    }

    /**
     * Shortcut for getting the current configuration description.
     */
    private ICConfigurationDescription getConfigurationDescription() {
        if (page.isForPrefs()) {
            return null;
        }

        return getResDesc().getConfiguration();
    }

    /**
     * Get the list of providers checked in the table in UI.
     * @return
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    private List<ILanguageSettingsProvider> getCheckedProviders() {
        return (List) Arrays.asList(tableProvidersViewer.getCheckedElements());
    }

    /**
     * Replace the selected provider in UI and in configuration.
     */
    private void replaceSelectedProvider(ILanguageSettingsProvider newProvider) {
        int pos = tableProviders.getSelectionIndex();
        boolean isChecked = tableProvidersViewer.getChecked(tableProvidersViewer.getElementAt(pos));

        presentedProviders.set(pos, newProvider);
        tableProvidersViewer.refresh();
        tableProvidersViewer.setChecked(newProvider, isChecked);
        tableProviders.setSelection(pos);

        saveCheckedProviders();
        tableProvidersViewer.refresh(newProvider);
    }

    /**
     * Save checked providers from UI table into configuration.
     */
    private void saveCheckedProviders() {
        ICConfigurationDescription cfgDescription = getConfigurationDescription();
        if (cfgDescription instanceof ILanguageSettingsProvidersKeeper) {
            ((ILanguageSettingsProvidersKeeper) cfgDescription).setLanguageSettingProviders(getCheckedProviders());
        }
    }

    /**
     * Store original providers to be able to tell whether they were changed by user.
     */
    private void trackInitialSettings() {
        if (!page.isForPrefs()) {
            ICConfigurationDescription[] cfgDescriptions = page.getCfgsEditable();
            for (ICConfigurationDescription cfgDescription : cfgDescriptions) {
                if (cfgDescription instanceof ILanguageSettingsProvidersKeeper) {
                    String cfgId = cfgDescription.getId();
                    List<ILanguageSettingsProvider> initialProviders = ((ILanguageSettingsProvidersKeeper) cfgDescription)
                            .getLanguageSettingProviders();
                    initialProvidersByCfg.put(cfgId, initialProviders);
                }
            }
        }
    }

    /**
     * Create table to display providers.
     */
    private void createProvidersPane(Composite parent) {
        Composite composite = new Composite(parent, SWT.BORDER | SWT.SINGLE);
        composite.setLayout(new GridLayout());

        // items checkboxes  only for project properties page
        tableProviders = new Table(composite, page.isForPrefs() ? SWT.NONE : SWT.CHECK);
        tableProviders.setLayoutData(new GridData(GridData.FILL_BOTH));
        tableProviders.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                displaySelectedOptionPage();
                updateButtons();
            }
        });
        tableProvidersViewer = new CheckboxTableViewer(tableProviders);
        tableProvidersViewer.setContentProvider(new ArrayContentProvider());
        tableProvidersViewer.setLabelProvider(new ProvidersTableLabelProvider());

        tableProvidersViewer.addCheckStateListener(new ICheckStateListener() {
            @Override
            public void checkStateChanged(CheckStateChangedEvent event) {
                ILanguageSettingsProvider checkedProvider = (ILanguageSettingsProvider) event.getElement();
                String id = checkedProvider.getId();
                ILanguageSettingsProvider newProvider = null;

                if (event.getChecked()) {
                    if (LanguageSettingsManager.isWorkspaceProvider(checkedProvider)
                            && !LanguageSettingsManager.isPreferShared(id)) {
                        newProvider = getInitialProvider(id);
                        if (newProvider == null) {
                            ILanguageSettingsProvider rawProvider = LanguageSettingsManager
                                    .getRawProvider(checkedProvider);
                            if (rawProvider instanceof ILanguageSettingsEditableProvider) {
                                newProvider = LanguageSettingsManager
                                        .getProviderCopy((ILanguageSettingsEditableProvider) rawProvider, false);
                            }
                        }
                    }
                } else {
                    if (!LanguageSettingsManager.isWorkspaceProvider(checkedProvider)) {
                        newProvider = LanguageSettingsManager.getWorkspaceProvider(id);
                    }
                }

                int pos = presentedProviders.indexOf(checkedProvider);
                tableProviders.setSelection(pos);

                if (newProvider != null) {
                    replaceSelectedProvider(newProvider); // will refresh and save checked providers
                    createOptionsPage(newProvider);
                } else {
                    saveCheckedProviders();
                    tableProvidersViewer.refresh(checkedProvider);
                    // option page is reused
                }

                displaySelectedOptionPage();
                updateButtons();
            }
        });
    }

    /**
     * Change "globality" of a provider.
     */
    private ILanguageSettingsProvider toggleGlobalProvider(ILanguageSettingsProvider provider, boolean toGlobal) {
        ILanguageSettingsProvider newProvider = null;

        String id = provider.getId();
        if (toGlobal) {
            newProvider = LanguageSettingsManager.getWorkspaceProvider(id);
        } else {
            // Toggle to configuration-owned provider
            newProvider = getInitialProvider(id);
            if (newProvider == null || LanguageSettingsManager.isWorkspaceProvider(newProvider)) {
                try {
                    ILanguageSettingsProvider rawProvider = LanguageSettingsManager.getRawProvider(provider);
                    if (rawProvider instanceof ILanguageSettingsEditableProvider) {
                        newProvider = ((ILanguageSettingsEditableProvider) rawProvider).cloneShallow();
                    }
                } catch (CloneNotSupportedException e) {
                    CUIPlugin.log("Error cloning provider " + id, e); //$NON-NLS-1$
                }
            }
        }
        if (newProvider != null) {
            replaceSelectedProvider(newProvider);
            createOptionsPage(newProvider);
            displaySelectedOptionPage();
            updateButtons();
        } else {
            newProvider = provider;
        }

        return newProvider;
    }

    /**
     * Create a check-box for "shared" or "global" property of a provider.
     */
    private void createSharedProviderCheckBox(Composite parent) {
        sharedProviderCheckBox = new Button(parent, SWT.CHECK);
        sharedProviderCheckBox.setText(Messages.LanguageSettingsProviderTab_ShareProviders);
        sharedProviderCheckBox.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                boolean isGlobal = sharedProviderCheckBox.getSelection();
                ILanguageSettingsProvider provider = getSelectedProvider();
                if (isGlobal != LanguageSettingsManager.isWorkspaceProvider(provider)) {
                    // globality changed
                    provider = toggleGlobalProvider(provider, isGlobal);
                }
                projectStorageCheckBox.setSelection(
                        provider instanceof LanguageSettingsSerializableProvider && LanguageSettingsManager
                                .isStoringEntriesInProjectArea((LanguageSettingsSerializableProvider) provider));
            }

            @Override
            public void widgetDefaultSelected(SelectionEvent e) {
                widgetSelected(e);
            }
        });
    }

    /**
     * Create a check-box defining where to store entries of a provider.
     */
    private void createProjectStorageCheckBox(Composite parent) {
        projectStorageCheckBox = new Button(parent, SWT.CHECK);
        projectStorageCheckBox.setLayoutData(new GridData(SWT.END, SWT.NONE, false, false));
        projectStorageCheckBox.setText(Messages.LanguageSettingsProviderTab_StoreEntriesInsideProject);
        projectStorageCheckBox.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                boolean inProjectArea = projectStorageCheckBox.getSelection();
                ILanguageSettingsProvider newProvider = getWorkingCopy(getSelectedProvider().getId());
                LanguageSettingsManager.setStoringEntriesInProjectArea(
                        (LanguageSettingsSerializableProvider) newProvider, inProjectArea);
                replaceSelectedProvider(newProvider);
                createOptionsPage(newProvider);
                displaySelectedOptionPage();
                updateButtons();
            }

            @Override
            public void widgetDefaultSelected(SelectionEvent e) {
                widgetSelected(e);
            }
        });
    }

    /**
     * Create a link to Preferences page.
     */
    private void createLinkToPreferences(final Composite parent, int span) {
        linkToWorkspacePreferences = new Link(parent, SWT.NONE);
        String href = NLS.bind("<a href=\"workspace\">{0}</a>", //$NON-NLS-1$
                Messages.LanguageSettingsProviderTab_WorkspaceSettings);
        linkToWorkspacePreferences.setText(
                NLS.bind(Messages.LanguageSettingsProviderTab_OptionsCanBeChangedInPreferencesDiscoveryTab, href));
        GridData gd = new GridData();
        gd.horizontalSpan = span;
        linkToWorkspacePreferences.setLayoutData(gd);

        linkToWorkspacePreferences.addListener(SWT.Selection, new Listener() {
            @Override
            public void handleEvent(Event event) {
                // Use event.text to tell which link was used
                PreferencesUtil.createPreferenceDialogOn(parent.getShell(), WORKSPACE_PREFERENCE_PAGE, null, null)
                        .open();
            }
        });
    }

    /**
     * Create Options pane.
     */
    private void createOptionsPane(Composite parent) {
        groupOptionsPage = new Group(parent, SWT.SHADOW_ETCHED_IN);
        groupOptionsPage.setText(Messages.LanguageSettingsProviderTab_LanguageSettingsProvidersOptions);
        groupOptionsPage.setLayout(new GridLayout(2, false));

        if (!page.isForPrefs()) {
            createSharedProviderCheckBox(groupOptionsPage);
            createProjectStorageCheckBox(groupOptionsPage);
            createLinkToPreferences(groupOptionsPage, 2);
        }

        // composite to span over 2 columns
        Composite comp = new Composite(groupOptionsPage, SWT.NONE);
        comp.setLayout(new GridLayout());
        GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
        gd.horizontalSpan = 2;
        comp.setLayoutData(gd);

        compositeOptionsPage = new Composite(comp, SWT.NONE);
        compositeOptionsPage.setLayout(new TabFolderLayout());
        compositeOptionsPage.addControlListener(new ControlListener() {
            @Override
            public void controlResized(ControlEvent e) {
                compositeOptionsPage.setBounds(compositeOptionsPage.getParent().getClientArea());
            }

            @Override
            public void controlMoved(ControlEvent e) {
            }
        });
    }

    /**
     * Create sash form.
     */
    private void createSashForm() {
        sashFormProviders = new SashForm(usercomp, SWT.VERTICAL);
        GridLayout layout = new GridLayout();
        sashFormProviders.setLayout(layout);
        GridData gd = new GridData(GridData.FILL_BOTH);
        gd.horizontalSpan = 2;
        sashFormProviders.setLayoutData(gd);

        createProvidersPane(sashFormProviders);
        createOptionsPane(sashFormProviders);

        sashFormProviders.setWeights(DEFAULT_CONFIGURE_SASH_WEIGHTS);
    }

    /**
     * Gray out or restore all controls except enabling check-box.
     */
    private void enableTabControls(boolean enable) {
        sashFormProviders.setEnabled(enable);
        tableProviders.setEnabled(enable);
        compositeOptionsPage.setEnabled(enable);

        buttoncomp.setEnabled(enable);

        if (enable) {
            displaySelectedOptionPage();
        } else {
            if (currentOptionsPage != null) {
                currentOptionsPage.setVisible(false);
            }

            buttonSetEnabled(BUTTON_CLEAR, false);
            buttonSetEnabled(BUTTON_RESET, false);
            buttonSetEnabled(BUTTON_MOVE_UP, false);
            buttonSetEnabled(BUTTON_MOVE_DOWN, false);
        }
    }

    @Override
    public void createControls(Composite parent) {
        super.createControls(parent);

        usercomp.setLayout(new GridLayout());
        GridData gd = (GridData) usercomp.getLayoutData();
        // Discourage settings entry table from trying to show all its items at once, see bug 264330
        gd.heightHint = 1;

        if (page instanceof LanguageSettingsProvidersPage) {
            masterPropertyPage = (LanguageSettingsProvidersPage) page;
        }

        trackInitialSettings();

        createSashForm();

        fStatusLine = new StatusMessageLine(usercomp, SWT.LEFT, 2);
        if (!page.isForPrefs()) {
            enableTabControls(masterPropertyPage.isLanguageSettingsProvidersEnabled());
        }

        String[] buttonLabels;
        if (page.isForPrefs()) {
            buttonLabels = new String[2];
            buttonLabels[BUTTON_CLEAR] = CLEAR_STR;
            buttonLabels[BUTTON_RESET] = RESET_STR;
        } else {
            buttonLabels = new String[5];
            buttonLabels[BUTTON_CLEAR] = CLEAR_STR;
            buttonLabels[BUTTON_RESET] = RESET_STR;
            buttonLabels[BUTTON_MOVE_UP] = MOVEUP_STR;
            buttonLabels[BUTTON_MOVE_DOWN] = MOVEDOWN_STR;
        }
        initButtons(buttonLabels);

        updateData(getResDesc());
    }

    /**
     * Clear entries of the selected provider.
     */
    private void performClear(ILanguageSettingsProvider selectedProvider) {
        if (isWorkingCopy(selectedProvider)) {
            if (selectedProvider instanceof LanguageSettingsSerializableProvider) {
                LanguageSettingsSerializableProvider editableProvider = (LanguageSettingsSerializableProvider) selectedProvider;
                editableProvider.clear();
                tableProvidersViewer.update(selectedProvider, null);
            }
        } else {
            ILanguageSettingsProvider rawProvider = LanguageSettingsManager.getRawProvider(selectedProvider);
            if (rawProvider instanceof ILanguageSettingsEditableProvider) {
                ILanguageSettingsEditableProvider newProvider = LanguageSettingsManager
                        .getProviderCopy((ILanguageSettingsEditableProvider) rawProvider, false);
                if (newProvider != null) {
                    replaceSelectedProvider(newProvider);
                    createOptionsPage(newProvider);
                    displaySelectedOptionPage();
                }
            }
        }
        updateButtons();
    }

    /**
     * Reset settings of the selected provider.
     */
    private void performReset(ILanguageSettingsProvider selectedProvider) {
        String id = selectedProvider.getId();

        ILanguageSettingsProvider newProvider = null;
        if (page.isForPrefs()) {
            newProvider = LanguageSettingsManager.getExtensionProviderCopy(id, true);
            if (newProvider == null) {
                Status status = new Status(IStatus.ERROR, CUIPlugin.PLUGIN_ID, IStatus.ERROR,
                        Messages.GeneralMessages_InternalError_ReportLogToCdtTeam,
                        new Exception("Internal Error getting copy of provider id=" + id)); //$NON-NLS-1$
                fStatusLine.setErrorStatus(status);
                CUIPlugin.log(status);
            }
        } else {
            ICConfigurationDescription cfgDescription = getConfigurationDescription();
            String[] defaultIds = ((ILanguageSettingsProvidersKeeper) cfgDescription)
                    .getDefaultLanguageSettingsProvidersIds();
            boolean isDefault = Arrays.asList(defaultIds).contains(id);
            if (isDefault && !LanguageSettingsManager.isPreferShared(id)) {
                newProvider = LanguageSettingsManager.getExtensionProviderCopy(id, true);
                if (newProvider == null) {
                    Status status = new Status(IStatus.ERROR, CUIPlugin.PLUGIN_ID, IStatus.ERROR,
                            Messages.GeneralMessages_InternalError_ReportLogToCdtTeam,
                            new Exception("Internal Error getting copy of provider id=" + id)); //$NON-NLS-1$
                    fStatusLine.setErrorStatus(status);
                    CUIPlugin.log(status);
                }
            } else {
                newProvider = LanguageSettingsManager.getWorkspaceProvider(id);
            }
            tableProvidersViewer.setChecked(selectedProvider, isDefault);
        }

        if (newProvider != null) {
            replaceSelectedProvider(newProvider);
            createOptionsPage(newProvider);
            displaySelectedOptionPage();
            updateButtons();
        }
    }

    /**
     * Move selected provider in the table.
     */
    private void moveProvider(int oldPos, int newPos) {
        Collections.swap(presentedProviders, oldPos, newPos);
        tableProvidersViewer.refresh();
        tableProviders.showSelection();

        saveCheckedProviders();
        updateButtons();
    }

    /**
     * Move selected provider up.
     */
    private void performMoveUp(ILanguageSettingsProvider selectedProvider) {
        int pos = presentedProviders.indexOf(selectedProvider);
        if (pos > 0) {
            moveProvider(pos, pos - 1);
        }
    }

    /**
     * Move selected provider down.
     */
    private void performMoveDown(ILanguageSettingsProvider selectedProvider) {
        int pos = presentedProviders.indexOf(selectedProvider);
        int last = presentedProviders.size() - 1;
        if (pos >= 0 && pos < last) {
            moveProvider(pos, pos + 1);
        }
    }

    /**
     * Handle pressed buttons.
     */
    @Override
    public void buttonPressed(int buttonIndex) {
        ILanguageSettingsProvider selectedProvider = getSelectedProvider();

        switch (buttonIndex) {
        case BUTTON_CLEAR:
            performClear(selectedProvider);
            break;
        case BUTTON_RESET:
            performReset(selectedProvider);
            break;
        case BUTTON_MOVE_UP:
            performMoveUp(selectedProvider);
            break;
        case BUTTON_MOVE_DOWN:
            performMoveDown(selectedProvider);
            break;
        default:
        }
    }

    /**
     * Updates state for all buttons.
     */
    @Override
    protected void updateButtons() {
        ILanguageSettingsProvider provider = getSelectedProvider();
        boolean isProviderSelected = provider != null;
        boolean canForWorkspace = isProviderSelected && page.isForPrefs();
        boolean canForProject = isProviderSelected && page.isForProject();

        int pos = tableProviders.getSelectionIndex();
        int count = tableProviders.getItemCount();
        int last = count - 1;
        boolean isRangeOk = (pos >= 0 && pos <= last);

        ILanguageSettingsProvider rawProvider = LanguageSettingsManager.getRawProvider(provider);
        boolean isAllowedClearing = rawProvider instanceof ILanguageSettingsEditableProvider
                && rawProvider instanceof LanguageSettingsSerializableProvider
                && LanguageSettingsProviderAssociationManager.isAllowedToClear(rawProvider);

        boolean canClear = isAllowedClearing
                && (canForWorkspace || (canForProject && !LanguageSettingsManager.isWorkspaceProvider(provider)));
        if (rawProvider instanceof LanguageSettingsSerializableProvider) {
            canClear = canClear && !((LanguageSettingsSerializableProvider) rawProvider).isEmpty();
        }

        boolean canResetForProject = canForProject && isReconfiguredForProject(provider);
        boolean canResetForWorkspace = canForWorkspace
                && (rawProvider instanceof ILanguageSettingsEditableProvider
                        && !LanguageSettingsManager.isEqualExtensionProvider(rawProvider, false))
                && (LanguageSettingsManager.getExtensionProviderIds().contains(rawProvider.getId()));
        boolean canReset = canResetForProject || canResetForWorkspace;

        boolean canMoveUp = canForProject && isRangeOk && pos != 0;
        boolean canMoveDown = canForProject && isRangeOk && pos != last;

        buttonSetEnabled(BUTTON_CLEAR, canClear);
        buttonSetEnabled(BUTTON_RESET, canReset);
        buttonSetEnabled(BUTTON_MOVE_UP, canMoveUp);
        buttonSetEnabled(BUTTON_MOVE_DOWN, canMoveDown);
    }

    /**
     * Sort providers displayed in UI. Sorting is by name except test providers are shown
     * on bottom.
     */
    private void sortByName(List<ILanguageSettingsProvider> providers) {
        // ensure sorting by name all unchecked providers
        Collections.sort(providers, new Comparator<ILanguageSettingsProvider>() {
            @Override
            public int compare(ILanguageSettingsProvider prov1, ILanguageSettingsProvider prov2) {
                Boolean isTest1 = prov1.getId().matches(TEST_PLUGIN_ID_PATTERN);
                Boolean isTest2 = prov2.getId().matches(TEST_PLUGIN_ID_PATTERN);
                int result = isTest1.compareTo(isTest2);
                if (result == 0) {
                    String name1 = prov1.getName();
                    String name2 = prov2.getName();
                    if (name1 != null && name2 != null) {
                        result = name1.compareTo(name2);
                    }
                }
                return result;
            }
        });
    }

    /**
     * Initialize providers list.
     */
    private void initializeProviders() {
        // The providers list is formed to consist of configuration providers (checked elements on top of the table)
        // and after that other providers which could be possible added (unchecked) sorted by name.

        List<String> idsList = new ArrayList<String>();

        List<ILanguageSettingsProvider> providers;
        ICConfigurationDescription cfgDescription = getConfigurationDescription();
        if (cfgDescription instanceof ILanguageSettingsProvidersKeeper) {
            providers = new ArrayList<ILanguageSettingsProvider>(
                    ((ILanguageSettingsProvidersKeeper) cfgDescription).getLanguageSettingProviders());
            for (ILanguageSettingsProvider provider : providers) {
                idsList.add(provider.getId());
            }
        } else {
            providers = new ArrayList<ILanguageSettingsProvider>();
        }

        List<ILanguageSettingsProvider> allAvailableProvidersSet = LanguageSettingsManager.getWorkspaceProviders();
        sortByName(allAvailableProvidersSet);

        for (ILanguageSettingsProvider provider : allAvailableProvidersSet) {
            String id = provider.getId();
            if (!idsList.contains(id) && ScannerDiscoveryLegacySupport.isProviderCompatible(id, cfgDescription)) {
                providers.add(provider);
                idsList.add(id);
            }
        }

        // renders better when using temporary
        presentedProviders = providers;

        ILanguageSettingsProvider selectedProvider = getSelectedProvider();
        String selectedId = selectedProvider != null ? selectedProvider.getId() : null;

        tableProvidersViewer.setInput(presentedProviders);
        if (selectedId != null) {
            for (int i = 0; i < presentedProviders.size(); i++) {
                if (selectedId.equals(presentedProviders.get(i).getId())) {
                    tableProviders.setSelection(i);
                    break;
                }
            }
        }
    }

    /**
     * Get option page from {@link LanguageSettingsProviderAssociationManager}.
     */
    private ICOptionPage getOptionsPage(ILanguageSettingsProvider provider) {
        ICOptionPage optionsPage = null;
        if (provider != null) {
            ILanguageSettingsProvider rawProvider = LanguageSettingsManager.getRawProvider(provider);
            if (rawProvider != null) {
                optionsPage = LanguageSettingsProviderAssociationManager.createOptionsPage(rawProvider);
            }

            if (optionsPage instanceof AbstractLanguageSettingProviderOptionPage) {
                ((AbstractLanguageSettingProviderOptionPage) optionsPage).init(this, provider.getId());
            }
        }

        return optionsPage;
    }

    /**
     * Create Options page for a provider.
     */
    private void createOptionsPage(ILanguageSettingsProvider provider) {
        ICOptionPage optionsPage = getOptionsPage(provider);

        if (optionsPage != null) {
            ILanguageSettingsProvider rawProvider = LanguageSettingsManager.getRawProvider(provider);
            boolean isEditableForProject = page.isForProject()
                    && provider instanceof ILanguageSettingsEditableProvider;
            boolean isEditableForPrefs = page.isForPrefs()
                    && rawProvider instanceof ILanguageSettingsEditableProvider;
            boolean isEditable = isEditableForProject || isEditableForPrefs;
            compositeOptionsPage.setEnabled(isEditable);

            String id = (provider != null) ? provider.getId() : null;
            optionsPageMap.put(id, optionsPage);
            optionsPage.setContainer(page);
            optionsPage.createControl(compositeOptionsPage);
            optionsPage.setVisible(false);
            compositeOptionsPage.layout(true);
        }
    }

    /**
     * Display selected option page.
     */
    private void displaySelectedOptionPage() {
        if (currentOptionsPage != null) {
            currentOptionsPage.setVisible(false);
        }

        ILanguageSettingsProvider provider = getSelectedProvider();
        String id = (provider != null) ? provider.getId() : null;

        ILanguageSettingsProvider rawProvider = LanguageSettingsManager.getRawProvider(provider);

        currentOptionsPage = optionsPageMap.get(id);

        if (!page.isForPrefs()) {
            boolean isChecked = tableProvidersViewer.getChecked(provider);
            boolean isShared = isPresentedAsShared(provider);
            boolean isRawProviderEditable = rawProvider instanceof ILanguageSettingsEditableProvider;

            sharedProviderCheckBox.setVisible(provider != null);
            sharedProviderCheckBox.setEnabled(isChecked && isRawProviderEditable);
            sharedProviderCheckBox.setSelection(isShared);

            projectStorageCheckBox.setVisible(rawProvider instanceof LanguageSettingsSerializableProvider);
            projectStorageCheckBox.setEnabled(isChecked && !isShared);
            projectStorageCheckBox.setSelection(
                    provider instanceof LanguageSettingsSerializableProvider && LanguageSettingsManager
                            .isStoringEntriesInProjectArea((LanguageSettingsSerializableProvider) provider));

            linkToWorkspacePreferences.setVisible(isShared && currentOptionsPage != null);
            linkToWorkspacePreferences.setEnabled(isChecked);
        }

        if (currentOptionsPage != null) {
            currentOptionsPage.setVisible(true);

            boolean isEditableForProject = page.isForProject()
                    && provider instanceof ILanguageSettingsEditableProvider;
            boolean isEditableForPrefs = page.isForPrefs()
                    && rawProvider instanceof ILanguageSettingsEditableProvider;
            boolean isEditable = isEditableForProject || isEditableForPrefs;
            currentOptionsPage.getControl().setEnabled(isEditable);
            compositeOptionsPage.setEnabled(isEditable);
            compositeOptionsPage.layout(true);
        }
    }

    /**
     * Populate provider tables and their option pages
     */
    private void updateProvidersTable() {
        ILanguageSettingsProvider selectedProvider = getSelectedProvider();
        String selectedId = selectedProvider != null ? selectedProvider.getId() : null;
        boolean wasChecked = selectedProvider != null && tableProvidersViewer.getChecked(selectedProvider);

        // update viewer if the list of providers changed
        int pos = tableProviders.getSelectionIndex();
        tableProvidersViewer.setInput(presentedProviders);
        tableProviders.setSelection(pos);

        ICConfigurationDescription cfgDescription = getConfigurationDescription();
        if (cfgDescription instanceof ILanguageSettingsProvidersKeeper) {
            List<ILanguageSettingsProvider> cfgProviders = ((ILanguageSettingsProvidersKeeper) cfgDescription)
                    .getLanguageSettingProviders();
            tableProvidersViewer.setCheckedElements(cfgProviders.toArray(new ILanguageSettingsProvider[0]));
        }

        if (selectedId != null) {
            for (int i = 0; i < presentedProviders.size(); i++) {
                ILanguageSettingsProvider provider = presentedProviders.get(i);
                if (selectedId.equals(provider.getId())) {
                    boolean isChecked = tableProvidersViewer.getChecked(provider);
                    if (isChecked || isChecked == wasChecked) {
                        tableProviders.setSelection(i);
                    } else {
                        tableProviders.setSelection(0);
                    }
                    break;
                }
            }
        }
        tableProvidersViewer.refresh();

        optionsPageMap.clear();
        for (ILanguageSettingsProvider provider : presentedProviders) {
            createOptionsPage(provider);
        }

        displaySelectedOptionPage();
    }

    /**
     * Update the tab. Called when configuration changes.
     */
    @Override
    public void updateData(ICResourceDescription rcDes) {
        if (!canBeVisible())
            return;

        ICConfigurationDescription cfgDescription = getConfigurationDescription();
        if (cfgDescription != null) {
            String cfgId = cfgDescription.getId();
            if (!initialProvidersByCfg.containsKey(cfgId)) {
                if (cfgDescription instanceof ILanguageSettingsProvidersKeeper) {
                    List<ILanguageSettingsProvider> initialProviders = ((ILanguageSettingsProvidersKeeper) cfgDescription)
                            .getLanguageSettingProviders();
                    initialProvidersByCfg.put(cfgId, initialProviders);
                }
            }
        }

        if (rcDes != null) {
            if (page.isMultiCfg()) {
                setAllVisible(false, null);
                return;
            } else {
                setAllVisible(true, null);
            }

            if (masterPropertyPage != null) {
                boolean enabled = masterPropertyPage.isLanguageSettingsProvidersEnabled();
                enableTabControls(enabled);
            }
        }

        // for Preference page initialize providers list just once as no configuration here to change
        // and re-initializing could overwrite modified providers in case of switching tabs or pages
        if (!page.isForPrefs() || presentedProviders == null) {
            initializeProviders();
        }
        updateProvidersTable();
        updateButtons();
    }

    @Override
    protected void performDefaults() {
        if (page.isForPrefs() || page.isForProject()) {
            if (MessageDialog.openQuestion(usercomp.getShell(),
                    Messages.LanguageSettingsProviderTab_TitleResetProviders,
                    Messages.LanguageSettingsProviderTab_AreYouSureToResetProviders)) {

                if (page.isForProject()) {
                    // set project LSP enablement to that of workspace
                    masterPropertyPage.setLanguageSettingsProvidersEnabled(
                            ScannerDiscoveryLegacySupport.isLanguageSettingsProvidersFunctionalityEnabled(null));
                    ICConfigurationDescription cfgDescription = getConfigurationDescription();
                    if (cfgDescription instanceof ILanguageSettingsProvidersKeeper) {
                        List<ILanguageSettingsProvider> cfgProviders = new ArrayList<ILanguageSettingsProvider>(
                                ((ILanguageSettingsProvidersKeeper) cfgDescription).getLanguageSettingProviders());
                        String[] defaultIds = ((ILanguageSettingsProvidersKeeper) cfgDescription)
                                .getDefaultLanguageSettingsProvidersIds();
                        List<ILanguageSettingsProvider> newProviders = LanguageSettingsManager
                                .createLanguageSettingsProviders(defaultIds);
                        if (!cfgProviders.equals(newProviders)) {
                            ((ILanguageSettingsProvidersKeeper) cfgDescription)
                                    .setLanguageSettingProviders(newProviders);
                        }
                    }

                } else if (page.isForPrefs()) {
                    presentedProviders = new ArrayList<ILanguageSettingsProvider>();
                    for (String id : LanguageSettingsManager.getExtensionProviderIds()) {
                        ILanguageSettingsProvider provider = LanguageSettingsManager.getWorkspaceProvider(id);
                        ILanguageSettingsProvider rawProvider = LanguageSettingsManager.getRawProvider(provider);
                        if (!LanguageSettingsManager.isEqualExtensionProvider(rawProvider, true)) {
                            ILanguageSettingsProvider extProvider = LanguageSettingsManager
                                    .getExtensionProviderCopy(id, true);
                            if (extProvider != null) {
                                provider = extProvider;
                            }
                        }
                        presentedProviders.add(provider);
                    }
                    sortByName(presentedProviders);
                }
            }

            ICResourceDescription rcDescription = getResDesc();

            updateData(rcDescription);
            // update other tabs
            if (masterPropertyPage != null) {
                masterPropertyPage.informAll(UPDATE, rcDescription);
            }
        }
    }

    @Override
    protected void performApply(ICResourceDescription srcRcDescription, ICResourceDescription destRcDescription) {
        if (!page.isForPrefs()) {
            ICConfigurationDescription sd = srcRcDescription.getConfiguration();
            ICConfigurationDescription dd = destRcDescription.getConfiguration();
            if (sd instanceof ILanguageSettingsProvidersKeeper && dd instanceof ILanguageSettingsProvidersKeeper) {
                List<ILanguageSettingsProvider> newProviders = ((ILanguageSettingsProvidersKeeper) sd)
                        .getLanguageSettingProviders();
                ((ILanguageSettingsProvidersKeeper) dd).setLanguageSettingProviders(newProviders);
            }
        }

        performOK();

        trackInitialSettings();
        updateData(getResDesc());
    }

    @Override
    protected void performOK() {
        // give option pages a chance for provider-specific pre-apply actions
        Collection<ICOptionPage> optionPages = optionsPageMap.values();
        for (ICOptionPage op : optionPages) {
            try {
                op.performApply(null);
            } catch (CoreException e) {
                CUIPlugin.log("Error applying options page", e); //$NON-NLS-1$
            }
        }

        if (page.isForPrefs()) {
            try {
                LanguageSettingsManager.setWorkspaceProviders(presentedProviders);
            } catch (CoreException e) {
                CUIPlugin.log("Error setting user defined providers", e); //$NON-NLS-1$
            }
            initializeProviders();
        }

        if (masterPropertyPage != null && masterPropertyPage.isLanguageSettingsProvidersEnabled()) {
            masterPropertyPage.applyLanguageSettingsProvidersEnabled();
        }
    }

    @Override
    public boolean canBeVisible() {
        if (!ScannerDiscoveryLegacySupport.isLanguageSettingsProvidersFunctionalityEnabled(null)) {
            return false;
        }

        return page.isForPrefs() || page.isForProject();
    }

}