org.eclipse.ui.internal.editors.text.LinkedModeConfigurationBlock.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.ui.internal.editors.text.LinkedModeConfigurationBlock.java

Source

/*******************************************************************************
 * Copyright (c) 2000, 2009 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 org.eclipse.ui.internal.editors.text;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

import com.ibm.icu.text.Collator;

import org.osgi.service.prefs.BackingStoreException;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.FontMetrics;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.RGB;
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.Label;

import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.preferences.InstanceScope;

import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.preference.ColorSelector;
import org.eclipse.jface.preference.PreferenceConverter;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ComboViewer;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.StructuredViewer;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerComparator;

import org.eclipse.ui.texteditor.AnnotationPreference;
import org.eclipse.ui.texteditor.MarkerAnnotationPreferences;

import org.eclipse.ui.editors.text.EditorsUI;

/**
 * Configures the linked mode preferences. The preferences belong to
 * org.eclipse.ui.editors. However, as they are chiefly used in the java editor,
 * we keep the preferences here for the time being.
 *
 * @since 3.2 (in jdt.ui since 3.1)
 */
class LinkedModeConfigurationBlock implements IPreferenceConfigurationBlock {

    private static final String EXIT = "org.eclipse.ui.internal.workbench.texteditor.link.exit"; //$NON-NLS-1$
    private static final String TARGET = "org.eclipse.ui.internal.workbench.texteditor.link.target"; //$NON-NLS-1$
    private static final String MASTER = "org.eclipse.ui.internal.workbench.texteditor.link.master"; //$NON-NLS-1$
    private static final String SLAVE = "org.eclipse.ui.internal.workbench.texteditor.link.slave"; //$NON-NLS-1$

    private static final class ListItem {
        final String label;
        final String colorKey;
        final String highlightKey;
        final String textStyleKey;
        final String textKey;
        final List validStyles;

        ListItem(String label, String colorKey, String textKey, String highlightKey, String textStyleKey,
                List validStyles) {
            this.label = label;
            this.colorKey = colorKey;
            this.highlightKey = highlightKey;
            this.textKey = textKey;
            this.textStyleKey = textStyleKey;
            this.validStyles = validStyles;
        }
    }

    private static final class ItemContentProvider implements IStructuredContentProvider {

        public Object[] getElements(Object inputElement) {
            return (ListItem[]) inputElement;
        }

        public void dispose() {
        }

        public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
        }
    }

    private final class ItemLabelProvider extends LabelProvider {

        public String getText(Object element) {
            return ((ListItem) element).label;
        }
    }

    private static class ArrayLabelProvider extends LabelProvider {
        public String getText(Object element) {
            return ((String[]) element)[0].toString();
        }
    }

    final static String[] HIGHLIGHT = new String[] { TextEditorMessages.LinkedModeConfigurationBlock_HIGHLIGHT,
            "unused" }; //$NON-NLS-1$
    final static String[] UNDERLINE = new String[] { TextEditorMessages.LinkedModeConfigurationBlock_UNDERLINE,
            AnnotationPreference.STYLE_UNDERLINE };
    final static String[] BOX = new String[] { TextEditorMessages.LinkedModeConfigurationBlock_BOX,
            AnnotationPreference.STYLE_BOX };
    final static String[] DASHED_BOX = new String[] { TextEditorMessages.LinkedModeConfigurationBlock_DASHED_BOX,
            AnnotationPreference.STYLE_DASHED_BOX };
    final static String[] IBEAM = new String[] { TextEditorMessages.LinkedModeConfigurationBlock_IBEAM,
            AnnotationPreference.STYLE_IBEAM };
    final static String[] SQUIGGLES = new String[] { TextEditorMessages.LinkedModeConfigurationBlock_SQUIGGLES,
            AnnotationPreference.STYLE_SQUIGGLES };

    private ColorSelector fAnnotationForegroundColorEditor;

    private Button fShowInTextCheckBox;

    private StructuredViewer fAnnotationTypeViewer;
    private final ListItem[] fListModel;

    private ComboViewer fDecorationViewer;
    private FontMetrics fFontMetrics;
    protected static final int INDENT = 20;
    private OverlayPreferenceStore fStore;

    private ArrayList fMasterSlaveListeners = new ArrayList();

    private OverlayPreferenceStore getPreferenceStore() {
        return fStore;
    }

    public LinkedModeConfigurationBlock(OverlayPreferenceStore store) {
        fStore = store;
        final MarkerAnnotationPreferences prefs = EditorsPlugin.getDefault().getMarkerAnnotationPreferences();
        getPreferenceStore().addKeys(createOverlayStoreKeys(prefs));
        fListModel = createAnnotationTypeListModel(prefs);
    }

    private OverlayPreferenceStore.OverlayKey[] createOverlayStoreKeys(MarkerAnnotationPreferences preferences) {
        ArrayList overlayKeys = new ArrayList();

        Iterator e = preferences.getAnnotationPreferences().iterator();
        while (e.hasNext()) {
            AnnotationPreference info = (AnnotationPreference) e.next();

            if (isLinkedModeAnnotation(info)) {
                overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.STRING,
                        info.getColorPreferenceKey()));
                overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN,
                        info.getTextPreferenceKey()));
                overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.STRING,
                        info.getTextStylePreferenceKey()));
                overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN,
                        info.getHighlightPreferenceKey()));
            }
        }

        OverlayPreferenceStore.OverlayKey[] keys = new OverlayPreferenceStore.OverlayKey[overlayKeys.size()];
        overlayKeys.toArray(keys);
        return keys;
    }

    private boolean isLinkedModeAnnotation(AnnotationPreference info) {
        final Object type = info.getAnnotationType();
        return type.equals(MASTER) || (type.equals(SLAVE)) || (type.equals(TARGET)) || (type.equals(EXIT));
    }

    private ListItem[] createAnnotationTypeListModel(MarkerAnnotationPreferences preferences) {
        ArrayList listModelItems = new ArrayList();
        Iterator e = preferences.getAnnotationPreferences().iterator();

        while (e.hasNext()) {
            AnnotationPreference info = (AnnotationPreference) e.next();
            if (isLinkedModeAnnotation(info)) {
                String label = info.getPreferenceLabel();
                List styles = getStyles(info.getAnnotationType());
                listModelItems.add(new ListItem(label, info.getColorPreferenceKey(), info.getTextPreferenceKey(),
                        info.getHighlightPreferenceKey(), info.getTextStylePreferenceKey(), styles));
            }
        }

        ListItem[] items = new ListItem[listModelItems.size()];
        listModelItems.toArray(items);
        return items;
    }

    private List getStyles(Object type) {
        if (type.equals(MASTER))
            return Arrays.asList(new String[][] { BOX, DASHED_BOX, HIGHLIGHT, UNDERLINE, SQUIGGLES });
        if (type.equals(SLAVE))
            return Arrays.asList(new String[][] { BOX, DASHED_BOX, HIGHLIGHT, UNDERLINE, SQUIGGLES });
        if (type.equals(TARGET))
            return Arrays.asList(new String[][] { BOX, DASHED_BOX, HIGHLIGHT, UNDERLINE, SQUIGGLES });
        if (type.equals(EXIT))
            return Arrays.asList(new String[][] { IBEAM });
        return new ArrayList();
    }

    /**
     * Creates page for hover preferences.
     *
     * @param parent the parent composite
     * @return the control for the preference page
     */
    public Control createControl(Composite parent) {
        OverlayPreferenceStore store = getPreferenceStore();
        store.load();
        store.start();

        initializeDialogUnits(parent);

        Composite composite = new Composite(parent, SWT.NONE);
        GridLayout layout = new GridLayout();
        layout.marginHeight = 0;
        layout.marginWidth = 0;
        composite.setLayout(layout);

        Label label = new Label(composite, SWT.LEFT);
        label.setText(TextEditorMessages.LinkedModeConfigurationBlock_annotationPresentationOptions);
        GridData gd = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
        label.setLayoutData(gd);

        Composite editorComposite = new Composite(composite, SWT.NONE);
        layout = new GridLayout();
        layout.numColumns = 2;
        layout.marginHeight = 0;
        layout.marginWidth = 0;
        editorComposite.setLayout(layout);
        gd = new GridData(SWT.FILL, SWT.FILL, true, true);
        editorComposite.setLayoutData(gd);

        fAnnotationTypeViewer = new TableViewer(editorComposite, SWT.SINGLE | SWT.V_SCROLL | SWT.BORDER);
        fAnnotationTypeViewer.setLabelProvider(new ItemLabelProvider());
        fAnnotationTypeViewer.setContentProvider(new ItemContentProvider());
        gd = new GridData(SWT.BEGINNING, SWT.BEGINNING, false, false);
        gd.heightHint = convertHeightInCharsToPixels(5);
        fAnnotationTypeViewer.getControl().setLayoutData(gd);

        Composite optionsComposite = new Composite(editorComposite, SWT.NONE);
        layout = new GridLayout();
        layout.marginHeight = 0;
        layout.marginWidth = 0;
        layout.numColumns = 2;
        optionsComposite.setLayout(layout);
        optionsComposite.setLayoutData(new GridData(SWT.BEGINNING, SWT.BEGINNING, false, false));

        // we only allow to set either "show in text" or "highlight in text", but not both

        fShowInTextCheckBox = new Button(optionsComposite, SWT.CHECK);
        fShowInTextCheckBox.setText(TextEditorMessages.LinkedModeConfigurationBlock_labels_showIn);
        gd = new GridData(GridData.FILL_HORIZONTAL);
        gd.horizontalAlignment = GridData.BEGINNING;
        fShowInTextCheckBox.setLayoutData(gd);

        fDecorationViewer = new ComboViewer(optionsComposite, SWT.READ_ONLY);
        fDecorationViewer.setContentProvider(new ArrayContentProvider());
        fDecorationViewer.setLabelProvider(new ArrayLabelProvider());
        fDecorationViewer.setComparator(new ViewerComparator(Collator.getInstance()));

        gd = new GridData(GridData.FILL_HORIZONTAL);
        gd.horizontalAlignment = GridData.BEGINNING;
        fDecorationViewer.getControl().setLayoutData(gd);
        fDecorationViewer.setInput(new Object[] { HIGHLIGHT, SQUIGGLES, BOX, DASHED_BOX, UNDERLINE, IBEAM });

        label = new Label(optionsComposite, SWT.LEFT);
        label.setText(TextEditorMessages.LinkedModeConfigurationBlock_color);
        gd = new GridData();
        gd.horizontalAlignment = GridData.BEGINNING;
        label.setLayoutData(gd);

        fAnnotationForegroundColorEditor = new ColorSelector(optionsComposite);
        Button foregroundColorButton = fAnnotationForegroundColorEditor.getButton();
        gd = new GridData(GridData.FILL_HORIZONTAL);
        gd.horizontalAlignment = GridData.BEGINNING;
        foregroundColorButton.setLayoutData(gd);

        createDependency(fShowInTextCheckBox, new Control[] { label, foregroundColorButton });

        fAnnotationTypeViewer.addSelectionChangedListener(new ISelectionChangedListener() {
            public void selectionChanged(SelectionChangedEvent event) {
                handleAnnotationListSelection();
            }
        });

        fShowInTextCheckBox.addSelectionListener(new SelectionListener() {
            public void widgetDefaultSelected(SelectionEvent e) {
                // do nothing
            }

            public void widgetSelected(SelectionEvent e) {
                ListItem item = getSelectedItem();
                final boolean value = fShowInTextCheckBox.getSelection();
                if (value) {
                    // enable whatever is in the combo
                    String[] decoration = (String[]) ((IStructuredSelection) fDecorationViewer.getSelection())
                            .getFirstElement();
                    if (HIGHLIGHT.equals(decoration))
                        getPreferenceStore().setValue(item.highlightKey, true);
                    else
                        getPreferenceStore().setValue(item.textKey, true);
                } else {
                    // disable both
                    getPreferenceStore().setValue(item.textKey, false);
                    getPreferenceStore().setValue(item.highlightKey, false);
                }
                getPreferenceStore().setValue(item.textKey, value);
                updateDecorationViewer(item, false);
            }
        });

        foregroundColorButton.addSelectionListener(new SelectionListener() {
            public void widgetDefaultSelected(SelectionEvent e) {
                // do nothing
            }

            public void widgetSelected(SelectionEvent e) {
                ListItem item = getSelectedItem();
                PreferenceConverter.setValue(getPreferenceStore(), item.colorKey,
                        fAnnotationForegroundColorEditor.getColorValue());
            }
        });

        fDecorationViewer.addSelectionChangedListener(new ISelectionChangedListener() {

            /*
             * @see org.eclipse.jface.viewers.ISelectionChangedListener#selectionChanged(org.eclipse.jface.viewers.SelectionChangedEvent)
             */
            public void selectionChanged(SelectionChangedEvent event) {
                String[] decoration = (String[]) ((IStructuredSelection) fDecorationViewer.getSelection())
                        .getFirstElement();
                ListItem item = getSelectedItem();

                if (fShowInTextCheckBox.getSelection()) {
                    if (HIGHLIGHT.equals(decoration)) {
                        getPreferenceStore().setValue(item.highlightKey, true);
                        getPreferenceStore().setValue(item.textKey, false);
                        getPreferenceStore().setValue(item.textStyleKey, AnnotationPreference.STYLE_NONE);
                    } else {
                        getPreferenceStore().setValue(item.highlightKey, false);
                        getPreferenceStore().setValue(item.textKey, true);
                        getPreferenceStore().setValue(item.textStyleKey, decoration[1]);
                    }
                }
            }
        });

        return composite;

    }

    /*
     * @see org.eclipse.ui.internal.editors.text.IPreferenceConfigurationBlock#applyData(java.lang.Object)
     * @since 3.4
     */
    public void applyData(Object data) {
    }

    /**
     * Returns the number of pixels corresponding to the width of the given number of characters.
     * <p>
     * This method may only be called after <code>initializeDialogUnits</code> has been called.
     * </p>
     * <p>
     * Clients may call this framework method, but should not override it.
     * </p>
     *
     * @param chars the number of characters
     * @return the number of pixels
     */
    protected int convertWidthInCharsToPixels(int chars) {
        // test for failure to initialize for backward compatibility
        if (fFontMetrics == null)
            return 0;
        return Dialog.convertWidthInCharsToPixels(fFontMetrics, chars);
    }

    /**
     * Returns the number of pixels corresponding to the height of the given number of characters.
     * <p>
     * This method may only be called after <code>initializeDialogUnits</code> has been called.
     * </p>
     * <p>
     * Clients may call this framework method, but should not override it.
     * </p>
     *
     * @param chars the number of characters
     * @return the number of pixels
     */
    protected int convertHeightInCharsToPixels(int chars) {
        // test for failure to initialize for backward compatibility
        if (fFontMetrics == null)
            return 0;
        return Dialog.convertHeightInCharsToPixels(fFontMetrics, chars);
    }

    /**
     * Initializes the computation of horizontal and vertical dialog units based on the size of
     * current font.
     * <p>
     * This method must be called before any of the dialog unit based conversion methods are called.
     * </p>
     *
     * @param testControl a control from which to obtain the current font
     */
    protected void initializeDialogUnits(Control testControl) {
        // Compute and store a font metric
        GC gc = new GC(testControl);
        gc.setFont(JFaceResources.getDialogFont());
        fFontMetrics = gc.getFontMetrics();
        gc.dispose();
    }

    private void handleAnnotationListSelection() {
        ListItem item = getSelectedItem();

        RGB rgb = PreferenceConverter.getColor(getPreferenceStore(), item.colorKey);
        fAnnotationForegroundColorEditor.setColorValue(rgb);

        boolean highlight = item.highlightKey == null ? false : getPreferenceStore().getBoolean(item.highlightKey);
        boolean showInText = item.textKey == null ? false : getPreferenceStore().getBoolean(item.textKey);
        fShowInTextCheckBox.setSelection(showInText || highlight);

        updateDecorationViewer(item, true);
    }

    /*
     * @see org.eclipse.jdt.internal.ui.preferences.IPreferenceConfigurationBlock#initialize()
     */
    public void initialize() {
        initializeFields();

        fAnnotationTypeViewer.setInput(fListModel);
        fAnnotationTypeViewer.getControl().getDisplay().asyncExec(new Runnable() {
            public void run() {
                if (fAnnotationTypeViewer != null && !fAnnotationTypeViewer.getControl().isDisposed()) {
                    fAnnotationTypeViewer.setSelection(new StructuredSelection(fListModel[0]));
                    initializeFields();
                }
            }
        });
    }

    private ListItem getSelectedItem() {
        return (ListItem) ((IStructuredSelection) fAnnotationTypeViewer.getSelection()).getFirstElement();
    }

    private void updateDecorationViewer(ListItem item, boolean changed) {
        // decoration selection: if the checkbox is enabled, there is
        // only one case where the combo is not enabled: if both the highlight and textStyle keys are null
        final boolean enabled = fShowInTextCheckBox.getSelection()
                && !(item.highlightKey == null && item.textStyleKey == null);
        fDecorationViewer.getControl().setEnabled(enabled);

        if (changed) {
            String[] selection = null;
            ArrayList list = new ArrayList();

            list.addAll(item.validStyles);

            if (getPreferenceStore().getBoolean(item.highlightKey))
                selection = HIGHLIGHT;

            // set selection
            if (selection == null) {
                String val = getPreferenceStore().getString(item.textStyleKey);
                for (Iterator iter = list.iterator(); iter.hasNext();) {
                    String[] elem = (String[]) iter.next();
                    if (elem[1].equals(val)) {
                        selection = elem;
                        break;
                    }
                }
            }

            fDecorationViewer.setInput(list.toArray(new Object[list.size()]));
            if (selection == null)
                selection = (String[]) list.get(0);
            fDecorationViewer.setSelection(new StructuredSelection((Object) selection), true);
        }
    }

    public void performOk() {
        getPreferenceStore().propagate();

        try {
            Platform.getPreferencesService().getRootNode().node(InstanceScope.SCOPE).node(EditorsUI.PLUGIN_ID)
                    .flush();
        } catch (BackingStoreException e) {
            EditorsPlugin.log(e);
        }
    }

    public void performDefaults() {
        getPreferenceStore().loadDefaults();

        /*
         * Only call super after updating fShowInTextCheckBox, so that
         * the master-slave dependencies get properly updated.
         */
        handleAnnotationListSelection();

        initializeFields();
    }

    public void dispose() {
        OverlayPreferenceStore store = getPreferenceStore();
        if (store != null) {
            store.stop();
        }
    }

    protected void createDependency(final Button master, final Control slave) {
        createDependency(master, new Control[] { slave });
    }

    protected void createDependency(final Button master, final Control[] slaves) {
        Assert.isTrue(slaves.length > 0);
        indent(slaves[0]);
        SelectionListener listener = new SelectionListener() {
            public void widgetSelected(SelectionEvent e) {
                boolean state = master.getSelection();
                for (int i = 0; i < slaves.length; i++) {
                    slaves[i].setEnabled(state);
                }
            }

            public void widgetDefaultSelected(SelectionEvent e) {
            }
        };
        master.addSelectionListener(listener);
        fMasterSlaveListeners.add(listener);
    }

    protected static void indent(Control control) {
        ((GridData) control.getLayoutData()).horizontalIndent += INDENT;
    }

    private void initializeFields() {

        // Update slaves
        Iterator iter = fMasterSlaveListeners.iterator();
        while (iter.hasNext()) {
            SelectionListener listener = (SelectionListener) iter.next();
            listener.widgetSelected(null);
        }
    }

    /*
     * @see org.eclipse.ui.internal.editors.text.IPreferenceConfigurationBlock#canPerformOk()
     */
    public boolean canPerformOk() {
        return true;
    }

}