org.eclipse.tm4e.ui.internal.preferences.GrammarPreferencePage.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.tm4e.ui.internal.preferences.GrammarPreferencePage.java

Source

/*******************************************************************************
 * Copyright (c) 2000, 2017 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
 *     Nicolaj Hoess <nicohoess@gmail.com> - Editor templates pref page: Allow to sort by column - https://bugs.eclipse.org/203722
 *     Angelo Zerr <angelo.zerr@gmail.com> - Adapt org.eclipse.ui.texteditor.templates.TemplatePreferencePage for TextMate grammar
 *******************************************************************************/
package org.eclipse.tm4e.ui.internal.preferences;

import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.stream.Collectors;

import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.layout.TableColumnLayout;
import org.eclipse.jface.preference.PreferencePage;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.util.BidiUtils;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.window.Window;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.GC;
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.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.TabItem;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.tm4e.core.grammar.IGrammar;
import org.eclipse.tm4e.registry.IGrammarDefinition;
import org.eclipse.tm4e.registry.IGrammarRegistryManager;
import org.eclipse.tm4e.registry.TMEclipseRegistryPlugin;
import org.eclipse.tm4e.registry.WorkingCopyGrammarRegistryManager;
import org.eclipse.tm4e.ui.TMUIPlugin;
import org.eclipse.tm4e.ui.internal.TMUIMessages;
import org.eclipse.tm4e.ui.internal.themes.WorkingCopyThemeManager;
import org.eclipse.tm4e.ui.internal.widgets.ColumnSelectionAdapter;
import org.eclipse.tm4e.ui.internal.widgets.ColumnViewerComparator;
import org.eclipse.tm4e.ui.internal.widgets.ContentTypesBindingWidget;
import org.eclipse.tm4e.ui.internal.widgets.GrammarDefinitionContentProvider;
import org.eclipse.tm4e.ui.internal.widgets.GrammarDefinitionLabelProvider;
import org.eclipse.tm4e.ui.internal.widgets.GrammarInfoWidget;
import org.eclipse.tm4e.ui.internal.widgets.TMViewer;
import org.eclipse.tm4e.ui.internal.widgets.ThemeAssociationsWidget;
import org.eclipse.tm4e.ui.internal.wizards.TextMateGrammarImportWizard;
import org.eclipse.tm4e.ui.snippets.ISnippet;
import org.eclipse.tm4e.ui.snippets.ISnippetManager;
import org.eclipse.tm4e.ui.themes.ITheme;
import org.eclipse.tm4e.ui.themes.IThemeAssociation;
import org.eclipse.tm4e.ui.themes.IThemeManager;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPreferencePage;
import org.osgi.service.prefs.BackingStoreException;

/**
 * A grammar preference page allows configuration of the TextMate grammar It
 * provides controls for adding, removing and changing grammar as well as
 * enablement, default management.
 */
public class GrammarPreferencePage extends PreferencePage implements IWorkbenchPreferencePage {

    public final static String PAGE_ID = "org.eclipse.tm4e.ui.preferences.GrammarPreferencePage";

    // Managers
    private IGrammarRegistryManager grammarRegistryManager;
    private IThemeManager themeManager;
    private ISnippetManager snippetManager;

    // Grammar list
    private TableViewer grammarViewer;
    private Button grammarNewButton;
    private Button grammarRemoveButton;

    // General tab
    private GrammarInfoWidget grammarInfoWidget;
    // Content type tab
    private ContentTypesBindingWidget contentTypesWidget;
    // Theme associations tab
    private ThemeAssociationsWidget themeAssociationsWidget;
    // Preview
    private TMViewer previewViewer;

    public GrammarPreferencePage() {
        super();
        setDescription(TMUIMessages.GrammarPreferencePage_description);
        setGrammarRegistryManager(
                new WorkingCopyGrammarRegistryManager(TMEclipseRegistryPlugin.getGrammarRegistryManager()));
        setThemeManager(new WorkingCopyThemeManager(TMUIPlugin.getThemeManager()));
        setSnippetManager(TMUIPlugin.getSnippetManager());
    }

    /**
     * Returns the grammar registry manager.
     * 
     * @return the grammar registry manager.
     */
    public IGrammarRegistryManager getGrammarRegistryManager() {
        return grammarRegistryManager;
    }

    /**
     * Set the grammar registry manager.
     * 
     * @param grammarRegistryManager
     */
    public void setGrammarRegistryManager(IGrammarRegistryManager grammarRegistryManager) {
        this.grammarRegistryManager = grammarRegistryManager;
    }

    /**
     * Returns the theme manager.
     * 
     * @return the theme manager.
     */
    public IThemeManager getThemeManager() {
        return themeManager;
    }

    /**
     * Set the theme manager.
     * 
     * @param themeManager
     */
    public void setThemeManager(IThemeManager themeManager) {
        this.themeManager = themeManager;
    }

    public ISnippetManager getSnippetManager() {
        return snippetManager;
    }

    public void setSnippetManager(ISnippetManager snippetManager) {
        this.snippetManager = snippetManager;
    }

    @Override
    protected Control createContents(Composite ancestor) {
        Composite parent = new Composite(ancestor, SWT.NONE);
        GridLayout layout = new GridLayout();
        layout.numColumns = 2;
        layout.marginHeight = 0;
        layout.marginWidth = 0;
        parent.setLayout(layout);

        Composite innerParent = new Composite(parent, SWT.NONE);
        GridLayout innerLayout = new GridLayout();
        innerLayout.numColumns = 2;
        innerLayout.marginHeight = 0;
        innerLayout.marginWidth = 0;
        innerParent.setLayout(innerLayout);
        GridData gd = new GridData(GridData.FILL_BOTH);
        gd.horizontalSpan = 2;
        innerParent.setLayoutData(gd);

        createGrammarListContent(innerParent);
        createGrammarDetailContent(innerParent);

        previewViewer = doCreateViewer(innerParent);
        grammarViewer.setInput(grammarRegistryManager);

        updateButtons();
        Dialog.applyDialogFont(parent);
        innerParent.layout();

        return parent;
    }

    /**
     * Create grammar list content.
     * 
     * @param parent
     */
    private void createGrammarListContent(Composite parent) {
        Composite tableComposite = new Composite(parent, SWT.NONE);
        GridData data = new GridData(GridData.FILL_BOTH);
        data.widthHint = 360;
        data.heightHint = convertHeightInCharsToPixels(10);
        tableComposite.setLayoutData(data);

        TableColumnLayout columnLayout = new TableColumnLayout();
        tableComposite.setLayout(columnLayout);
        Table table = new Table(tableComposite,
                SWT.BORDER | SWT.MULTI | SWT.FULL_SELECTION | SWT.H_SCROLL | SWT.V_SCROLL);

        table.setHeaderVisible(true);
        table.setLinesVisible(true);

        GC gc = new GC(getShell());
        gc.setFont(JFaceResources.getDialogFont());

        ColumnViewerComparator viewerComparator = new ColumnViewerComparator();

        grammarViewer = new TableViewer(table);

        TableColumn column1 = new TableColumn(table, SWT.NONE);
        column1.setText(TMUIMessages.GrammarPreferencePage_column_scopeName);
        int minWidth = computeMinimumColumnWidth(gc, TMUIMessages.GrammarPreferencePage_column_scopeName);
        columnLayout.setColumnData(column1, new ColumnWeightData(2, minWidth, true));
        column1.addSelectionListener(new ColumnSelectionAdapter(column1, grammarViewer, 0, viewerComparator));

        TableColumn column2 = new TableColumn(table, SWT.NONE);
        column2.setText(TMUIMessages.GrammarPreferencePage_column_path);
        minWidth = computeMinimumColumnWidth(gc, TMUIMessages.GrammarPreferencePage_column_path);
        columnLayout.setColumnData(column2, new ColumnWeightData(2, minWidth, true));
        column2.addSelectionListener(new ColumnSelectionAdapter(column2, grammarViewer, 1, viewerComparator));

        TableColumn column3 = new TableColumn(table, SWT.NONE);
        column3.setText(TMUIMessages.GrammarPreferencePage_column_pluginId);
        minWidth = computeMinimumColumnWidth(gc, TMUIMessages.GrammarPreferencePage_column_pluginId);
        columnLayout.setColumnData(column3, new ColumnWeightData(2, minWidth, true));
        column3.addSelectionListener(new ColumnSelectionAdapter(column3, grammarViewer, 2, viewerComparator));

        gc.dispose();

        grammarViewer.setLabelProvider(new GrammarDefinitionLabelProvider());
        grammarViewer.setContentProvider(new GrammarDefinitionContentProvider());
        grammarViewer.setComparator(viewerComparator);

        grammarViewer.addSelectionChangedListener(new ISelectionChangedListener() {

            @Override
            public void selectionChanged(SelectionChangedEvent e) {
                IStructuredSelection selection = grammarViewer.getStructuredSelection();
                if (selection.isEmpty()) {
                    return;
                }
                IGrammarDefinition definition = (IGrammarDefinition) (selection).getFirstElement();
                // Update button
                grammarRemoveButton.setEnabled(definition.getPluginId() != null);
                themeAssociationsWidget.getNewButton().setEnabled(false);
                themeAssociationsWidget.getRemoveButton().setEnabled(false);
                // Select grammar
                selectGrammar(definition);
            }

            private void selectGrammar(IGrammarDefinition definition) {
                String scopeName = definition.getScopeName();
                // Fill "General" tab
                fillGeneralTab(scopeName);
                // Fill "Content type" tab
                fillContentTypeTab(scopeName);
                // Fill "Theme" tab
                IThemeAssociation selectedAssociation = fillThemeTab(definition);
                // Fill preview
                fillPreview(scopeName, selectedAssociation);
            }

            private void fillGeneralTab(String scopeName) {
                IGrammar grammar = grammarRegistryManager.getGrammarForScope(scopeName);
                grammarInfoWidget.refresh(grammar);
            }

            private void fillContentTypeTab(String scopeName) {
                // Load the content type binding for the given grammar
                String[] contentTypes = grammarRegistryManager.getContentTypesForScope(scopeName);
                contentTypesWidget.setInput(contentTypes);
            }

            private IThemeAssociation fillThemeTab(IGrammarDefinition definition) {
                IThemeAssociation selectedAssociation = null;
                IStructuredSelection oldSelection = (IStructuredSelection) themeAssociationsWidget.getSelection();
                // Load the theme associations for the given grammar
                IThemeAssociation[] themeAssociations = themeAssociationsWidget.setGrammarDefinition(definition);
                // Try to keep selection
                if (!oldSelection.isEmpty()
                        && Arrays.asList(themeAssociations).contains(oldSelection.getFirstElement())) {
                    selectedAssociation = (IThemeAssociation) oldSelection.getFirstElement();
                    themeAssociationsWidget.setSelection(oldSelection);
                } else {
                    selectedAssociation = themeAssociations != null && themeAssociations.length > 0
                            ? themeAssociations[0]
                            : null;
                    if (selectedAssociation != null) {
                        themeAssociationsWidget.setSelection(new StructuredSelection(selectedAssociation));
                    }
                }
                return selectedAssociation;
            }

            private void fillPreview(String scopeName, IThemeAssociation selectedAssociation) {
                // Preview the grammar
                IGrammar grammar = grammarRegistryManager.getGrammarForScope(scopeName);
                if (selectedAssociation != null) {
                    setPreviewTheme(selectedAssociation.getThemeId());
                }
                previewViewer.setGrammar(grammar);

                // Snippet
                ISnippet[] snippets = snippetManager.getSnippets(scopeName);
                if (snippets != null && snippets.length > 0) {
                    // TODO: manage list of snippet for the given scope.
                    previewViewer.setText(snippets[0].getContent());
                }
            }

        });

        // Specify default sorting
        table.setSortColumn(column1);
        table.setSortDirection(viewerComparator.getDirection());

        BidiUtils.applyTextDirection(grammarViewer.getControl(), BidiUtils.BTD_DEFAULT);

        Composite buttons = new Composite(parent, SWT.NONE);
        buttons.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_BEGINNING));
        GridLayout layout = new GridLayout();
        layout.marginHeight = 0;
        layout.marginWidth = 0;
        buttons.setLayout(layout);

        grammarNewButton = new Button(buttons, SWT.PUSH);
        grammarNewButton.setText(TMUIMessages.Button_new);
        grammarNewButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
        grammarNewButton.addListener(SWT.Selection, new Listener() {

            @Override
            public void handleEvent(Event e) {
                add();
            }

            private void add() {
                // Open import wizard for TextMate grammar.
                TextMateGrammarImportWizard wizard = new TextMateGrammarImportWizard(false);
                wizard.setGrammarRegistryManager(grammarRegistryManager);
                WizardDialog dialog = new WizardDialog(getShell(), wizard);
                if (dialog.open() == Window.OK) {
                    // User grammar was saved, refresh the list of grammar and
                    // select the created grammar.
                    IGrammarDefinition created = wizard.getCreatedDefinition();
                    grammarViewer.refresh();
                    grammarViewer.setSelection(new StructuredSelection(created));
                }
            }
        });

        grammarRemoveButton = new Button(buttons, SWT.PUSH);
        grammarRemoveButton.setText(TMUIMessages.Button_remove);
        grammarRemoveButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
        grammarRemoveButton.addListener(SWT.Selection, new Listener() {

            @Override
            public void handleEvent(Event e) {
                remove();
            }

            private void remove() {
                Collection<IGrammarDefinition> definitions = getSelectedUserGrammarDefinitions();
                if (!definitions.isEmpty()) {
                    for (IGrammarDefinition definition : definitions) {
                        grammarRegistryManager.unregisterGrammarDefinition(definition);
                    }
                    grammarViewer.refresh();
                }
            }
        });
    }

    /**
     * Create detail grammar content which is filled when a grammar is selected in
     * the grammar list.
     * 
     * @param parent
     */
    private void createGrammarDetailContent(Composite parent) {
        TabFolder folder = new TabFolder(parent, SWT.NONE);

        GridData gd = new GridData(GridData.FILL_HORIZONTAL);
        gd.horizontalSpan = 2;
        folder.setLayoutData(gd);

        createGeneralTab(folder);
        createContentTypeTab(folder);
        createThemeTab(folder);
        createInjectionTab(folder);
    }

    /**
     * Create "General" tab
     * 
     * @param folder
     */
    private void createGeneralTab(TabFolder folder) {
        TabItem tab = new TabItem(folder, SWT.NONE);
        tab.setText(TMUIMessages.GrammarPreferencePage_tab_general_text);

        Composite parent = new Composite(folder, SWT.NONE);
        parent.setLayout(new GridLayout());
        parent.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

        grammarInfoWidget = new GrammarInfoWidget(parent, SWT.NONE);
        grammarInfoWidget.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

        tab.setControl(parent);

    }

    /**
     * Create "Content type" tab
     * 
     * @param folder
     */
    private void createContentTypeTab(TabFolder folder) {
        TabItem tab = new TabItem(folder, SWT.NONE);
        tab.setText(TMUIMessages.GrammarPreferencePage_tab_contentType_text);

        Composite parent = new Composite(folder, SWT.NONE);
        parent.setLayout(new GridLayout());
        parent.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

        contentTypesWidget = new ContentTypesBindingWidget(parent, SWT.NONE);
        contentTypesWidget.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

        tab.setControl(parent);
    }

    /**
     * Create "Theme" tab
     * 
     * @param folder
     */
    private void createThemeTab(TabFolder folder) {
        TabItem tab = new TabItem(folder, SWT.NONE);
        tab.setText(TMUIMessages.GrammarPreferencePage_tab_theme_text);

        Composite parent = new Composite(folder, SWT.NONE);
        parent.setLayout(new GridLayout());
        parent.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

        themeAssociationsWidget = new ThemeAssociationsWidget(themeManager, parent, SWT.NONE);
        GridData data = new GridData(GridData.FILL_HORIZONTAL);
        data.horizontalSpan = 2;
        themeAssociationsWidget.setLayoutData(data);
        themeAssociationsWidget.addSelectionChangedListener(new ISelectionChangedListener() {

            @Override
            public void selectionChanged(SelectionChangedEvent e) {
                IThemeAssociation association = (IThemeAssociation) ((IStructuredSelection) e.getSelection())
                        .getFirstElement();
                selectTheme(association);
            }

            private void selectTheme(IThemeAssociation association) {
                themeAssociationsWidget.getNewButton()
                        .setEnabled(association != null /* && association.getPluginId() == null */);
                themeAssociationsWidget.getRemoveButton()
                        .setEnabled(association != null /* && association.getPluginId() == null */);
                if (association != null) {
                    setPreviewTheme(association.getThemeId());
                }
            }
        });

        tab.setControl(parent);
    }

    private void setPreviewTheme(String themeId) {
        ITheme theme = themeManager.getThemeById(themeId);
        if (theme != null) {
            previewViewer.setTheme(theme);
        }
    }

    /**
     * Create "Injection" tab
     * 
     * @param folder
     */
    private void createInjectionTab(TabFolder folder) {
        TabItem tab = new TabItem(folder, SWT.NONE);
        tab.setText(TMUIMessages.GrammarPreferencePage_tab_injection_text);

        Composite parent = new Composite(folder, SWT.NONE);
        parent.setLayout(new GridLayout());
        parent.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

        // TODO: manage UI injection

        tab.setControl(parent);
    }

    private int computeMinimumColumnWidth(GC gc, String string) {
        return gc.stringExtent(string).x + 10; // pad 10 to accommodate table
        // header trimmings
    }

    private void updateButtons() {
        grammarRemoveButton.setEnabled(false);

    }

    @Override
    public void setVisible(boolean visible) {
        super.setVisible(visible);
        if (visible)
            setTitle(TMUIMessages.GrammarPreferencePage_title);
    }

    @Override
    public void init(IWorkbench workbench) {

    }

    private TMViewer doCreateViewer(Composite parent) {
        Label label = new Label(parent, SWT.NONE);
        label.setText(TMUIMessages.GrammarPreferencePage_preview);
        GridData data = new GridData();
        data.horizontalSpan = 2;
        label.setLayoutData(data);

        TMViewer viewer = createViewer(parent);

        // Don't set caret to 'null' as this causes
        // https://bugs.eclipse.org/293263
        // viewer.getTextWidget().setCaret(null);

        Control control = viewer.getControl();
        data = new GridData(GridData.FILL_BOTH);
        data.horizontalSpan = 2;
        data.heightHint = convertHeightInCharsToPixels(5);
        control.setLayoutData(data);

        return viewer;
    }

    /**
     * Creates, configures and returns a source viewer to present the template
     * pattern on the preference page. Clients may override to provide a custom
     * source viewer featuring e.g. syntax coloring.
     *
     * @param parent
     *            the parent control
     * @return a configured source viewer
     */
    protected TMViewer createViewer(Composite parent) {
        return new TMViewer(parent, null, null, false, SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);
    }

    @Override
    public boolean performOk() {
        try {
            // Save the working copy if there are some changed.
            grammarRegistryManager.save();
            themeManager.save();
        } catch (BackingStoreException e) {
            e.printStackTrace();
            return false;
        }
        return super.performOk();
    }

    /**
     * Returns list of selected grammar definitions which was created by the user.
     * 
     * @return list of selected grammar definitions which was created by the user.
     */
    private Collection<IGrammarDefinition> getSelectedUserGrammarDefinitions() {
        IStructuredSelection selection = grammarViewer.getStructuredSelection();
        if (selection.isEmpty()) {
            return Collections.emptyList();
        }
        return ((Collection<IGrammarDefinition>) selection.toList()).stream()
                .filter(definition -> definition.getPluginId() == null).collect(Collectors.toList());

    }
}