e4.handler.E4TemplatePreferencePage.java Source code

Java tutorial

Introduction

Here is the source code for e4.handler.E4TemplatePreferencePage.java

Source

/*******************************************************************************
 * Copyright (c) 2000, 2011 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 e4.handler;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import com.google.common.collect.Maps;
import com.google.inject.Inject;
import com.ibm.icu.text.Collator;

import org.bbaw.bts.core.commons.staticAccess.StaticAccessController;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Widget;
import org.eclipse.core.expressions.Expression;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.e4.core.commands.EHandlerService;
import org.eclipse.e4.ui.services.EContextService;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.GroupMarker;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.commands.ActionHandler;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.StatusDialog;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.preference.PreferencePage;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.util.BidiUtils;
import org.eclipse.jface.viewers.CheckStateChangedEvent;
import org.eclipse.jface.viewers.CheckboxTableViewer;
import org.eclipse.jface.viewers.ColumnPixelData;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.ICheckStateListener;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.jface.window.Window;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.ITextListener;
import org.eclipse.jface.text.ITextOperationTarget;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.TextEvent;
import org.eclipse.jface.text.contentassist.ContentAssistant;
import org.eclipse.jface.text.contentassist.IContentAssistProcessor;
import org.eclipse.jface.text.contentassist.IContentAssistant;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.text.source.SourceViewer;
import org.eclipse.jface.text.source.SourceViewerConfiguration;
import org.eclipse.jface.text.templates.ContextTypeRegistry;
import org.eclipse.jface.text.templates.Template;
import org.eclipse.jface.text.templates.TemplateContextType;
import org.eclipse.jface.text.templates.TemplateException;
import org.eclipse.jface.text.templates.persistence.TemplatePersistenceData;
import org.eclipse.jface.text.templates.persistence.TemplateReaderWriter;
import org.eclipse.jface.text.templates.persistence.TemplateStore;
import org.eclipse.ui.ActiveShellExpression;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchCommandConstants;
import org.eclipse.ui.IWorkbenchPreferencePage;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.handlers.IHandlerService;
import org.eclipse.ui.internal.texteditor.NLSUtility;
import org.eclipse.ui.internal.texteditor.SWTUtil;
import org.eclipse.ui.internal.texteditor.TextEditorPlugin;
import org.eclipse.ui.texteditor.ITextEditorActionConstants;
import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds;
import org.eclipse.ui.texteditor.IUpdate;
import org.eclipse.xtext.ui.preferences.StatusInfo;

/**
 * A template preference page allows configuration of the templates for an
 * editor. It provides controls for adding, removing and changing templates as
 * well as enablement, default management and an optional formatter preference.
 * <p>
 * Subclasses need to provide a {@link TemplateStore} and a
 * {@link ContextTypeRegistry} and should set the preference store. They may
 * optionally override {@link #isShowFormatterSetting()}.
 * </p>
 *
 * @since 2.4
 */
public abstract class E4TemplatePreferencePage extends PreferencePage implements IWorkbenchPreferencePage {

    /**
     * Dialog to edit a template. Clients will usually instantiate, but
     * may also extend.
     *
     * @since 3.3
     */
    protected static class EditTemplateDialog extends StatusDialog {

        private class TextViewerAction extends Action implements IUpdate {

            private int fOperationCode = -1;
            private ITextOperationTarget fOperationTarget;

            /**
             * Creates a new action.
             *
             * @param viewer the viewer
             * @param operationCode the opcode
             */
            public TextViewerAction(ITextViewer viewer, int operationCode) {
                fOperationCode = operationCode;
                fOperationTarget = viewer.getTextOperationTarget();
                update();
            }

            /**
             * Updates the enabled state of the action.
             * Fires a property change if the enabled state changes.
             *
             * @see Action#firePropertyChange(String, Object, Object)
             */
            public void update() {
                // XXX: workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=206111
                if (fOperationCode == ITextOperationTarget.REDO || fOperationCode == ITextOperationTarget.REDO)
                    return;

                boolean wasEnabled = isEnabled();
                boolean isEnabled = (fOperationTarget != null && fOperationTarget.canDoOperation(fOperationCode));
                setEnabled(isEnabled);

                if (wasEnabled != isEnabled) {
                    firePropertyChange(ENABLED, wasEnabled ? Boolean.TRUE : Boolean.FALSE,
                            isEnabled ? Boolean.TRUE : Boolean.FALSE);
                }
            }

            /**
             * @see Action#run()
             */
            @Override
            public void run() {
                if (fOperationCode != -1 && fOperationTarget != null) {
                    fOperationTarget.doOperation(fOperationCode);
                }
            }
        }

        private final Template fOriginalTemplate;

        private Text fNameText;
        private Text fDescriptionText;
        private Combo fContextCombo;
        private SourceViewer fPatternEditor;
        private Button fInsertVariableButton;
        private Button fAutoInsertCheckbox;
        private boolean fIsNameModifiable;

        private StatusInfo fValidationStatus;
        private boolean fSuppressError = true; // #4354
        private Map fGlobalActions = new HashMap(10);
        private List fSelectionActions = new ArrayList(3);
        private String[][] fContextTypes;

        protected final Map<String, E4ActionHandler> allHandlers = Maps.newHashMap();

        @Inject
        private ContextTypeRegistry fContextTypeRegistry;

        private final TemplateVariableProcessor fTemplateProcessor = new TemplateVariableProcessor();

        private Template fNewTemplate;

        /**
         * Creates a new dialog.
         *
         * @param parent the shell parent of the dialog
         * @param template the template to edit
         * @param edit whether this is a new template or an existing being edited
         * @param isNameModifiable whether the name of the template may be modified
         * @param registry the context type registry to use
         */
        public EditTemplateDialog(Shell parent, Template template, boolean edit, boolean isNameModifiable,
                ContextTypeRegistry registry) {
            super(parent);

            String title = edit ? TemplatesMessages.EditTemplateDialog_title_edit
                    : TemplatesMessages.EditTemplateDialog_title_new;
            setTitle(title);

            fOriginalTemplate = template;
            fIsNameModifiable = isNameModifiable;

            List contexts = new ArrayList();
            for (Iterator it = registry.contextTypes(); it.hasNext();) {
                TemplateContextType type = (TemplateContextType) it.next();
                contexts.add(new String[] { type.getId(), type.getName() });
            }
            Collections.sort(contexts, new Comparator() {
                Collator fCollator = Collator.getInstance();

                public int compare(Object o1, Object o2) {
                    return fCollator.compare(((String[]) o1)[1], ((String[]) o2)[1]);
                }
            });
            fContextTypes = (String[][]) contexts.toArray(new String[contexts.size()][]);

            fValidationStatus = new StatusInfo();

            fContextTypeRegistry = registry;

            TemplateContextType type = fContextTypeRegistry.getContextType(template.getContextTypeId());
            fTemplateProcessor.setContextType(type);
        }

        /*
         * @see org.eclipse.jface.dialogs.Dialog#isResizable()
         * @since 3.4
         */
        @Override
        protected boolean isResizable() {
            return true;
        }

        /*
         * @see org.eclipse.ui.texteditor.templates.StatusDialog#create()
         */
        @Override
        public void create() {
            super.create();
            // update initial OK button to be disabled for new templates
            boolean valid = fNameText == null || fNameText.getText().trim().length() != 0;
            if (!valid) {
                StatusInfo status = new StatusInfo();
                status.setError(TemplatesMessages.EditTemplateDialog_error_noname);
                updateButtonsEnableState(status);
            }
        }

        /*
         * @see Dialog#createDialogArea(Composite)
         */
        @Override
        protected Control createDialogArea(Composite ancestor) {
            Composite parent = new Composite(ancestor, SWT.NONE);
            GridLayout layout = new GridLayout();
            layout.numColumns = 2;
            layout.marginHeight = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN);
            layout.marginWidth = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN);
            layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
            layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
            parent.setLayout(layout);
            parent.setLayoutData(new GridData(GridData.FILL_BOTH));

            ModifyListener listener = new ModifyListener() {
                public void modifyText(ModifyEvent e) {
                    doTextWidgetChanged(e.widget);
                }
            };

            if (fIsNameModifiable) {
                createLabel(parent, TemplatesMessages.EditTemplateDialog_name);

                Composite composite = new Composite(parent, SWT.NONE);
                composite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
                layout = new GridLayout();
                layout.numColumns = 4;
                layout.marginWidth = 0;
                layout.marginHeight = 0;
                composite.setLayout(layout);

                fNameText = createText(composite);
                fNameText.addModifyListener(listener);
                fNameText.addFocusListener(new FocusListener() {

                    public void focusGained(FocusEvent e) {
                    }

                    public void focusLost(FocusEvent e) {
                        if (fSuppressError) {
                            fSuppressError = false;
                            updateButtons();
                        }
                    }
                });
                BidiUtils.applyBidiProcessing(fNameText, BidiUtils.BTD_DEFAULT);

                createLabel(composite, TemplatesMessages.EditTemplateDialog_context);
                fContextCombo = new Combo(composite, SWT.READ_ONLY);

                for (int i = 0; i < fContextTypes.length; i++) {
                    fContextCombo.add(fContextTypes[i][1]);
                }

                fContextCombo.addModifyListener(listener);
                SWTUtil.setDefaultVisibleItemCount(fContextCombo);

                fAutoInsertCheckbox = createCheckbox(composite, TemplatesMessages.EditTemplateDialog_autoinsert);
                fAutoInsertCheckbox.setSelection(fOriginalTemplate.isAutoInsertable());
            }

            createLabel(parent, TemplatesMessages.EditTemplateDialog_description);

            int descFlags = fIsNameModifiable ? SWT.BORDER : SWT.BORDER | SWT.READ_ONLY;
            fDescriptionText = new Text(parent, descFlags);
            fDescriptionText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

            fDescriptionText.addModifyListener(listener);
            BidiUtils.applyBidiProcessing(fDescriptionText, BidiUtils.BTD_DEFAULT);

            Label patternLabel = createLabel(parent, TemplatesMessages.EditTemplateDialog_pattern);
            patternLabel.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_BEGINNING));
            fPatternEditor = createEditor(parent, fOriginalTemplate.getPattern());

            Label filler = new Label(parent, SWT.NONE);
            filler.setLayoutData(new GridData());

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

            fInsertVariableButton = new Button(composite, SWT.NONE);
            fInsertVariableButton.setLayoutData(getButtonGridData(fInsertVariableButton));
            fInsertVariableButton.setText(TemplatesMessages.EditTemplateDialog_insert_variable);
            fInsertVariableButton.addSelectionListener(new SelectionListener() {
                public void widgetSelected(SelectionEvent e) {
                    fPatternEditor.getTextWidget().setFocus();
                    fPatternEditor.doOperation(ISourceViewer.CONTENTASSIST_PROPOSALS);
                }

                public void widgetDefaultSelected(SelectionEvent e) {
                }
            });

            fDescriptionText.setText(fOriginalTemplate.getDescription());
            if (fIsNameModifiable) {
                fNameText.setText(fOriginalTemplate.getName());
                fNameText.addModifyListener(listener);
                fContextCombo.select(getIndex(fOriginalTemplate.getContextTypeId()));
            } else {
                fPatternEditor.getControl().setFocus();
            }
            initializeActions();

            applyDialogFont(parent);
            return composite;
        }

        private void doTextWidgetChanged(Widget w) {
            if (w == fNameText) {
                fSuppressError = false;
                updateButtons();
            } else if (w == fContextCombo) {
                String contextId = getContextId();
                fTemplateProcessor.setContextType(fContextTypeRegistry.getContextType(contextId));
            } else if (w == fDescriptionText) {
                // oh, nothing
            }
        }

        private String getContextId() {
            if (fContextCombo != null && !fContextCombo.isDisposed()) {
                String name = fContextCombo.getText();
                for (int i = 0; i < fContextTypes.length; i++) {
                    if (name.equals(fContextTypes[i][1])) {
                        return fContextTypes[i][0];
                    }
                }
            }

            return fOriginalTemplate.getContextTypeId();
        }

        private void doSourceChanged(IDocument document) {
            String text = document.get();
            fValidationStatus.setOK();
            TemplateContextType contextType = fContextTypeRegistry.getContextType(getContextId());
            if (contextType != null) {
                try {
                    contextType.validate(text);
                } catch (TemplateException e) {
                    fValidationStatus.setError(e.getLocalizedMessage());
                }
            }

            updateAction(ITextEditorActionConstants.UNDO);
            updateButtons();
        }

        /**
         * Return the grid data for the button.
         *
         * @param button the button
         * @return the grid data
         */
        private static GridData getButtonGridData(Button button) {
            GridData data = new GridData(GridData.FILL_HORIZONTAL);
            // TODO get some button hints.
            //         data.heightHint= SWTUtil.getButtonHeightHint(button);

            return data;
        }

        private static Label createLabel(Composite parent, String name) {
            Label label = new Label(parent, SWT.NULL);
            label.setText(name);
            label.setLayoutData(new GridData());

            return label;
        }

        private static Text createText(Composite parent) {
            Text text = new Text(parent, SWT.BORDER);
            text.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

            return text;
        }

        private static Button createCheckbox(Composite parent, String name) {
            Button button = new Button(parent, SWT.CHECK);
            button.setText(name);
            button.setLayoutData(new GridData());

            return button;
        }

        private SourceViewer createEditor(Composite parent, String pattern) {
            SourceViewer viewer = createViewer(parent);
            viewer.setEditable(true);

            IDocument document = viewer.getDocument();
            if (document != null)
                document.set(pattern);
            else {
                document = new Document(pattern);
                viewer.setDocument(document);
            }

            int nLines = document.getNumberOfLines();
            if (nLines < 5) {
                nLines = 5;
            } else if (nLines > 12) {
                nLines = 12;
            }

            Control control = viewer.getControl();
            GridData data = new GridData(GridData.FILL_BOTH);
            data.widthHint = convertWidthInCharsToPixels(80);
            data.heightHint = convertHeightInCharsToPixels(nLines);
            control.setLayoutData(data);

            viewer.addTextListener(new ITextListener() {
                public void textChanged(TextEvent event) {
                    if (event.getDocumentEvent() != null)
                        doSourceChanged(event.getDocumentEvent().getDocument());
                }
            });

            viewer.addSelectionChangedListener(new ISelectionChangedListener() {
                public void selectionChanged(SelectionChangedEvent event) {
                    updateSelectionDependentActions();
                }
            });

            return viewer;
        }

        /**
         * Creates the viewer to be used to display the pattern. Subclasses may override.
         *
         * @param parent the parent composite of the viewer
         * @return a configured <code>SourceViewer</code>
         */
        protected SourceViewer createViewer(Composite parent) {
            SourceViewer viewer = new SourceViewer(parent, null, null, false,
                    SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);
            SourceViewerConfiguration configuration = new SourceViewerConfiguration() {
                @Override
                public IContentAssistant getContentAssistant(ISourceViewer sourceViewer) {

                    ContentAssistant assistant = new ContentAssistant();
                    assistant.enableAutoActivation(true);
                    assistant.enableAutoInsert(true);
                    assistant.setContentAssistProcessor(fTemplateProcessor, IDocument.DEFAULT_CONTENT_TYPE);
                    return assistant;
                }
            };
            viewer.configure(configuration);
            return viewer;
        }

        private void initializeActions() {
            final ArrayList handlerActivations = new ArrayList(3);
            //         final IHandlerService handlerService= (IHandlerService)PlatformUI.getWorkbench().getAdapter(IHandlerService.class);
            final EHandlerService handlerService = StaticAccessController.getService();
            final Expression expression = new ActiveShellExpression(fPatternEditor.getControl().getShell());

            getShell().addDisposeListener(new DisposeListener() {

                public void widgetDisposed(DisposeEvent e) {
                    //               handlerService.deactivateHandlers(handlerActivations);
                    for (final E4ActionHandler handler : allHandlers.values()) {
                        handlerService.deactivateHandler(handler.getActionDefinitionId(), handler);
                    }
                }
            });

            fPatternEditor.getTextWidget().addFocusListener(new FocusListener() {

                public void focusLost(FocusEvent e) {
                    //               handlerService.deactivateHandlers(handlerActivations);
                    for (final E4ActionHandler handler : allHandlers.values()) {
                        handlerService.deactivateHandler(handler.getActionDefinitionId(), handler);
                    }
                }

                public void focusGained(FocusEvent e) {

                    //               IAction action= (IAction)fGlobalActions.get(ITextEditorActionConstants.REDO);
                    //               handlerActivations.add(handlerService.activateHandler(IWorkbenchCommandConstants.EDIT_REDO, new ActionHandler(action), expression));
                    //               action= (IAction)fGlobalActions.get(ITextEditorActionConstants.UNDO);
                    //               handlerActivations.add(handlerService.activateHandler(IWorkbenchCommandConstants.EDIT_UNDO, new ActionHandler(action), expression));
                    //               action= (IAction)fGlobalActions.get(ITextEditorActionConstants.CONTENT_ASSIST);
                    //               handlerActivations.add(handlerService.activateHandler(ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS, new ActionHandler(action), expression));

                    for (final E4ActionHandler handler : allHandlers.values()) {
                        handlerService.activateHandler(handler.getActionDefinitionId(), handler);
                    }
                }
            });

            TextViewerAction action = new TextViewerAction(fPatternEditor, ITextOperationTarget.UNDO);
            action.setText(TemplatesMessages.EditTemplateDialog_undo);
            fGlobalActions.put(ITextEditorActionConstants.UNDO, action);
            E4ActionHandler handler = new E4ActionHandler(action);
            allHandlers.put(handler.getActionDefinitionId(), handler);

            action = new TextViewerAction(fPatternEditor, ITextOperationTarget.REDO);
            action.setText(TemplatesMessages.EditTemplateDialog_redo);
            fGlobalActions.put(ITextEditorActionConstants.REDO, action);
            handler = new E4ActionHandler(action);
            allHandlers.put(handler.getActionDefinitionId(), handler);

            action = new TextViewerAction(fPatternEditor, ITextOperationTarget.CUT);
            action.setText(TemplatesMessages.EditTemplateDialog_cut);
            fGlobalActions.put(ITextEditorActionConstants.CUT, action);
            handler = new E4ActionHandler(action);
            allHandlers.put(handler.getActionDefinitionId(), handler);

            action = new TextViewerAction(fPatternEditor, ITextOperationTarget.COPY);
            action.setText(TemplatesMessages.EditTemplateDialog_copy);
            fGlobalActions.put(ITextEditorActionConstants.COPY, action);
            handler = new E4ActionHandler(action);
            allHandlers.put(handler.getActionDefinitionId(), handler);

            action = new TextViewerAction(fPatternEditor, ITextOperationTarget.PASTE);
            action.setText(TemplatesMessages.EditTemplateDialog_paste);
            fGlobalActions.put(ITextEditorActionConstants.PASTE, action);
            handler = new E4ActionHandler(action);
            allHandlers.put(handler.getActionDefinitionId(), handler);

            action = new TextViewerAction(fPatternEditor, ITextOperationTarget.SELECT_ALL);
            action.setText(TemplatesMessages.EditTemplateDialog_select_all);
            fGlobalActions.put(ITextEditorActionConstants.SELECT_ALL, action);
            handler = new E4ActionHandler(action);
            allHandlers.put(handler.getActionDefinitionId(), handler);

            action = new TextViewerAction(fPatternEditor, ISourceViewer.CONTENTASSIST_PROPOSALS);
            action.setText(TemplatesMessages.EditTemplateDialog_content_assist);
            fGlobalActions.put(ITextEditorActionConstants.CONTENT_ASSIST, action);
            handler = new E4ActionHandler(action);
            allHandlers.put(handler.getActionDefinitionId(), handler);

            fSelectionActions.add(ITextEditorActionConstants.CUT);
            fSelectionActions.add(ITextEditorActionConstants.COPY);
            fSelectionActions.add(ITextEditorActionConstants.PASTE);

            // create context menu
            MenuManager manager = new MenuManager(null, null);
            manager.setRemoveAllWhenShown(true);
            manager.addMenuListener(new IMenuListener() {
                public void menuAboutToShow(IMenuManager mgr) {
                    fillContextMenu(mgr);
                }
            });

            StyledText text = fPatternEditor.getTextWidget();
            Menu menu = manager.createContextMenu(text);
            text.setMenu(menu);
        }

        private void fillContextMenu(IMenuManager menu) {
            menu.add(new GroupMarker(ITextEditorActionConstants.GROUP_UNDO));
            menu.appendToGroup(ITextEditorActionConstants.GROUP_UNDO,
                    (IAction) fGlobalActions.get(ITextEditorActionConstants.UNDO));
            menu.appendToGroup(ITextEditorActionConstants.GROUP_UNDO,
                    (IAction) fGlobalActions.get(ITextEditorActionConstants.REDO));

            menu.add(new Separator(ITextEditorActionConstants.GROUP_EDIT));
            menu.appendToGroup(ITextEditorActionConstants.GROUP_EDIT,
                    (IAction) fGlobalActions.get(ITextEditorActionConstants.CUT));
            menu.appendToGroup(ITextEditorActionConstants.GROUP_EDIT,
                    (IAction) fGlobalActions.get(ITextEditorActionConstants.COPY));
            menu.appendToGroup(ITextEditorActionConstants.GROUP_EDIT,
                    (IAction) fGlobalActions.get(ITextEditorActionConstants.PASTE));
            menu.appendToGroup(ITextEditorActionConstants.GROUP_EDIT,
                    (IAction) fGlobalActions.get(ITextEditorActionConstants.SELECT_ALL));

            menu.add(new Separator("templates")); //$NON-NLS-1$
            menu.appendToGroup("templates", (IAction) fGlobalActions.get("ContentAssistProposal")); //$NON-NLS-1$ //$NON-NLS-2$
        }

        private void updateSelectionDependentActions() {
            Iterator iterator = fSelectionActions.iterator();
            while (iterator.hasNext())
                updateAction((String) iterator.next());
        }

        private void updateAction(String actionId) {
            IAction action = (IAction) fGlobalActions.get(actionId);
            if (action instanceof IUpdate)
                ((IUpdate) action).update();
        }

        private int getIndex(String contextid) {

            if (contextid == null)
                return -1;

            for (int i = 0; i < fContextTypes.length; i++) {
                if (contextid.equals(fContextTypes[i][0])) {
                    return i;
                }
            }
            return -1;
        }

        private void updateButtons() {
            StatusInfo status;

            boolean valid = fNameText == null || fNameText.getText().trim().length() != 0;
            if (!valid) {
                status = new StatusInfo();
                if (!fSuppressError)
                    status.setError(TemplatesMessages.EditTemplateDialog_error_noname);
            } else if (!isValidPattern(fPatternEditor.getDocument().get())) {
                status = new StatusInfo();
                if (!fSuppressError)
                    status.setError(TemplatesMessages.EditTemplateDialog_error_invalidPattern);
            } else {
                status = fValidationStatus;
            }
            updateStatus(status);
        }

        /**
         * Validates the pattern.
         * <p>
         * The default implementation rejects invalid XML characters.
         * </p>
         * 
         * @param pattern the pattern to verify
         * @return <code>true</code> if the pattern is valid
         * @since 3.7 protected, before it was private
         */
        protected boolean isValidPattern(String pattern) {
            for (int i = 0; i < pattern.length(); i++) {
                char ch = pattern.charAt(i);
                if (!(ch == 9 || ch == 10 || ch == 13 || ch >= 32))
                    return false;
            }
            return true;
        }

        /*
         * @since 3.1
         */
        @Override
        protected void okPressed() {
            String name = fNameText == null ? fOriginalTemplate.getName() : fNameText.getText();
            boolean isAutoInsertable = fAutoInsertCheckbox != null && fAutoInsertCheckbox.getSelection();
            fNewTemplate = new Template(name, fDescriptionText.getText(), getContextId(),
                    fPatternEditor.getDocument().get(), isAutoInsertable);
            super.okPressed();
        }

        /**
         * Returns the created template.
         *
         * @return the created template
         * @since 3.1
         */
        public Template getTemplate() {
            return fNewTemplate;
        }

        /**
         * Returns the content assist processor that
         * suggests template variables.
         *
         * @return the processor to suggest variables
         * @since 3.3
         */
        protected IContentAssistProcessor getTemplateProcessor() {
            return fTemplateProcessor;
        }

        /*
         * @see org.eclipse.jface.dialogs.Dialog#getDialogBoundsSettings()
         * @since 3.2
         */
        @Override
        protected IDialogSettings getDialogBoundsSettings() {
            String sectionName = getClass().getName() + "_dialogBounds"; //$NON-NLS-1$
            IDialogSettings settings = TextEditorPlugin.getDefault().getDialogSettings();
            IDialogSettings section = settings.getSection(sectionName);
            if (section == null)
                section = settings.addNewSection(sectionName);
            return section;
        }

    }

    /**
     * Label provider for templates.
     */
    private class TemplateLabelProvider extends LabelProvider implements ITableLabelProvider {

        /*
         * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnImage(java.lang.Object, int)
         */
        public Image getColumnImage(Object element, int columnIndex) {
            return null;
        }

        /*
         * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnText(java.lang.Object, int)
         */
        public String getColumnText(Object element, int columnIndex) {
            TemplatePersistenceData data = (TemplatePersistenceData) element;
            Template template = data.getTemplate();

            switch (columnIndex) {
            case 0:
                return template.getName();
            case 1:
                TemplateContextType type = fContextTypeRegistry.getContextType(template.getContextTypeId());
                if (type != null)
                    return type.getName();
                return template.getContextTypeId();
            case 2:
                return template.getDescription();
            case 3:
                return template.isAutoInsertable() ? TemplatesMessages.TemplatePreferencePage_on : ""; //$NON-NLS-1$
            default:
                return ""; //$NON-NLS-1$
            }
        }
    }

    /** Qualified key for formatter preference. */
    private static final String DEFAULT_FORMATTER_PREFERENCE_KEY = "org.eclipse.ui.texteditor.templates.preferences.format_templates"; //$NON-NLS-1$

    /** The table presenting the templates. */
    private CheckboxTableViewer fTableViewer;

    /* buttons */
    private Button fAddButton;
    private Button fEditButton;
    private Button fImportButton;
    private Button fExportButton;
    private Button fRemoveButton;
    private Button fRestoreButton;
    private Button fRevertButton;

    /** The viewer displays the pattern of selected template. */
    private SourceViewer fPatternViewer;
    /** Format checkbox. This gets conditionally added. */
    private Button fFormatButton;
    /** The store for our templates. */
    @Inject
    private TemplateStore fTemplateStore;
    /** The context type registry. */
    @Inject
    private ContextTypeRegistry fContextTypeRegistry;

    /**
     * Creates a new template preference page.
     */
    protected E4TemplatePreferencePage() {
        super();

        setDescription(TemplatesMessages.TemplatePreferencePage_message);
    }

    /**
     * Returns the template store.
     *
     * @return the template store
     */
    public TemplateStore getTemplateStore() {
        return fTemplateStore;
    }

    /**
     * Returns the context type registry.
     *
     * @return the context type registry
     */
    public ContextTypeRegistry getContextTypeRegistry() {
        return fContextTypeRegistry;
    }

    /**
     * Sets the template store.
     *
     * @param store the new template store
     */
    public void setTemplateStore(TemplateStore store) {
        fTemplateStore = store;
    }

    /**
     * Sets the context type registry.
     *
     * @param registry the new context type registry
     */
    public void setContextTypeRegistry(ContextTypeRegistry registry) {
        fContextTypeRegistry = registry;
    }

    /*
     * @see org.eclipse.ui.IWorkbenchPreferencePage#init(org.eclipse.ui.IWorkbench)
     */
    public void init(IWorkbench workbench) {
    }

    /*
     * @see PreferencePage#createContents(Composite)
     */
    @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);

        Composite tableComposite = new Composite(innerParent, SWT.NONE);
        GridData data = new GridData(GridData.FILL_BOTH);
        data.widthHint = 360;
        data.heightHint = convertHeightInCharsToPixels(10);
        tableComposite.setLayoutData(data);

        ColumnLayout columnLayout = new ColumnLayout();
        tableComposite.setLayout(columnLayout);
        Table table = new Table(tableComposite,
                SWT.CHECK | 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());

        TableColumn column1 = new TableColumn(table, SWT.NONE);
        column1.setText(TemplatesMessages.TemplatePreferencePage_column_name);
        int minWidth = computeMinimumColumnWidth(gc, TemplatesMessages.TemplatePreferencePage_column_name);
        columnLayout.addColumnData(new ColumnWeightData(2, minWidth, true));

        TableColumn column2 = new TableColumn(table, SWT.NONE);
        column2.setText(TemplatesMessages.TemplatePreferencePage_column_context);
        minWidth = computeMinimumContextColumnWidth(gc);
        columnLayout.addColumnData(new ColumnWeightData(1, minWidth, true));

        TableColumn column3 = new TableColumn(table, SWT.NONE);
        column3.setText(TemplatesMessages.TemplatePreferencePage_column_description);
        minWidth = computeMinimumColumnWidth(gc, TemplatesMessages.TemplatePreferencePage_column_description);
        columnLayout.addColumnData(new ColumnWeightData(3, minWidth, true));

        TableColumn column4 = new TableColumn(table, SWT.NONE);
        column4.setAlignment(SWT.CENTER);
        column4.setText(TemplatesMessages.TemplatePreferencePage_column_autoinsert);
        minWidth = computeMinimumColumnWidth(gc, TemplatesMessages.TemplatePreferencePage_column_autoinsert);
        minWidth = Math.max(minWidth, computeMinimumColumnWidth(gc, TemplatesMessages.TemplatePreferencePage_on));
        columnLayout.addColumnData(new ColumnPixelData(minWidth, false, false));

        gc.dispose();

        fTableViewer = new CheckboxTableViewer(table);
        fTableViewer.setLabelProvider(new TemplateLabelProvider());
        fTableViewer.setContentProvider(new TemplateContentProvider());

        fTableViewer.setComparator(new ViewerComparator() {
            @Override
            public int compare(Viewer viewer, Object object1, Object object2) {
                if ((object1 instanceof TemplatePersistenceData) && (object2 instanceof TemplatePersistenceData)) {
                    Template left = ((TemplatePersistenceData) object1).getTemplate();
                    Template right = ((TemplatePersistenceData) object2).getTemplate();
                    int result = Collator.getInstance().compare(left.getName(), right.getName());
                    if (result != 0)
                        return result;
                    return Collator.getInstance().compare(left.getDescription(), right.getDescription());
                }
                return super.compare(viewer, object1, object2);
            }

            @Override
            public boolean isSorterProperty(Object element, String property) {
                return true;
            }
        });

        fTableViewer.addDoubleClickListener(new IDoubleClickListener() {
            public void doubleClick(DoubleClickEvent e) {
                edit();
            }
        });

        fTableViewer.addSelectionChangedListener(new ISelectionChangedListener() {
            public void selectionChanged(SelectionChangedEvent e) {
                selectionChanged1();
            }
        });

        fTableViewer.addCheckStateListener(new ICheckStateListener() {
            public void checkStateChanged(CheckStateChangedEvent event) {
                TemplatePersistenceData d = (TemplatePersistenceData) event.getElement();
                d.setEnabled(event.getChecked());
            }
        });

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

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

        fAddButton = new Button(buttons, SWT.PUSH);
        fAddButton.setText(TemplatesMessages.TemplatePreferencePage_new);
        fAddButton.setLayoutData(getButtonGridData(fAddButton));
        fAddButton.addListener(SWT.Selection, new Listener() {
            public void handleEvent(Event e) {
                add();
            }
        });

        fEditButton = new Button(buttons, SWT.PUSH);
        fEditButton.setText(TemplatesMessages.TemplatePreferencePage_edit);
        fEditButton.setLayoutData(getButtonGridData(fEditButton));
        fEditButton.addListener(SWT.Selection, new Listener() {
            public void handleEvent(Event e) {
                edit();
            }
        });

        fRemoveButton = new Button(buttons, SWT.PUSH);
        fRemoveButton.setText(TemplatesMessages.TemplatePreferencePage_remove);
        fRemoveButton.setLayoutData(getButtonGridData(fRemoveButton));
        fRemoveButton.addListener(SWT.Selection, new Listener() {
            public void handleEvent(Event e) {
                remove();
            }
        });

        createSeparator(buttons);

        fRestoreButton = new Button(buttons, SWT.PUSH);
        fRestoreButton.setText(TemplatesMessages.TemplatePreferencePage_restore);
        fRestoreButton.setLayoutData(getButtonGridData(fRestoreButton));
        fRestoreButton.addListener(SWT.Selection, new Listener() {
            public void handleEvent(Event e) {
                restoreDeleted();
            }
        });

        fRevertButton = new Button(buttons, SWT.PUSH);
        fRevertButton.setText(TemplatesMessages.TemplatePreferencePage_revert);
        fRevertButton.setLayoutData(getButtonGridData(fRevertButton));
        fRevertButton.addListener(SWT.Selection, new Listener() {
            public void handleEvent(Event e) {
                revert();
            }
        });

        createSeparator(buttons);

        fImportButton = new Button(buttons, SWT.PUSH);
        fImportButton.setText(TemplatesMessages.TemplatePreferencePage_import);
        fImportButton.setLayoutData(getButtonGridData(fImportButton));
        fImportButton.addListener(SWT.Selection, new Listener() {
            public void handleEvent(Event e) {
                import_();
            }
        });

        fExportButton = new Button(buttons, SWT.PUSH);
        fExportButton.setText(TemplatesMessages.TemplatePreferencePage_export);
        fExportButton.setLayoutData(getButtonGridData(fExportButton));
        fExportButton.addListener(SWT.Selection, new Listener() {
            public void handleEvent(Event e) {
                export();
            }
        });

        fPatternViewer = doCreateViewer(parent);

        if (isShowFormatterSetting()) {
            fFormatButton = new Button(parent, SWT.CHECK);
            fFormatButton.setText(TemplatesMessages.TemplatePreferencePage_use_code_formatter);
            GridData gd1 = new GridData();
            gd1.horizontalSpan = 2;
            fFormatButton.setLayoutData(gd1);
            fFormatButton.setSelection(getPreferenceStore().getBoolean(getFormatterPreferenceKey()));
        }

        fTableViewer.setInput(fTemplateStore);
        fTableViewer.setAllChecked(false);
        fTableViewer.setCheckedElements(getEnabledTemplates());

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

        return parent;
    }

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

    /*
     * @since 3.4
     */
    private int computeMinimumContextColumnWidth(GC gc) {
        int width = gc.stringExtent(TemplatesMessages.TemplatePreferencePage_column_context).x;
        Iterator iter = getContextTypeRegistry().contextTypes();
        while (iter.hasNext()) {
            TemplateContextType contextType = (TemplateContextType) iter.next();
            width = Math.max(width, gc.stringExtent(contextType.getName()).x);
        }
        return width;
    }

    /**
     * Creates a separator between buttons.
     *
     * @param parent the parent composite
     * @return a separator
     */
    private Label createSeparator(Composite parent) {
        Label separator = new Label(parent, SWT.NONE);
        separator.setVisible(false);
        GridData gd = new GridData();
        gd.horizontalAlignment = GridData.FILL;
        gd.verticalAlignment = GridData.BEGINNING;
        gd.heightHint = 4;
        separator.setLayoutData(gd);
        return separator;
    }

    /**
     * Returns whether the formatter preference checkbox should be shown.
     *
     * @return <code>true</code> if the formatter preference checkbox should
     *         be shown, <code>false</code> otherwise
     */
    protected boolean isShowFormatterSetting() {
        return true;
    }

    private TemplatePersistenceData[] getEnabledTemplates() {
        List enabled = new ArrayList();
        TemplatePersistenceData[] datas = fTemplateStore.getTemplateData(false);
        for (int i = 0; i < datas.length; i++) {
            if (datas[i].isEnabled())
                enabled.add(datas[i]);
        }
        return (TemplatePersistenceData[]) enabled.toArray(new TemplatePersistenceData[enabled.size()]);
    }

    private SourceViewer doCreateViewer(Composite parent) {
        Label label = new Label(parent, SWT.NONE);
        label.setText(TemplatesMessages.TemplatePreferencePage_preview);
        GridData data = new GridData();
        data.horizontalSpan = 2;
        label.setLayoutData(data);

        SourceViewer viewer = createViewer(parent);

        viewer.setEditable(false);
        Cursor arrowCursor = viewer.getTextWidget().getDisplay().getSystemCursor(SWT.CURSOR_ARROW);
        viewer.getTextWidget().setCursor(arrowCursor);

        // 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 SourceViewer createViewer(Composite parent) {
        SourceViewer viewer = new SourceViewer(parent, null, null, false, SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);
        SourceViewerConfiguration configuration = new SourceViewerConfiguration();
        viewer.configure(configuration);
        IDocument document = new Document();
        viewer.setDocument(document);
        return viewer;
    }

    /**
     * Return the grid data for the button.
     *
     * @param button the button
     * @return the grid data
     */
    private static GridData getButtonGridData(Button button) {
        GridData data = new GridData(GridData.FILL_HORIZONTAL);
        // TODO replace SWTUtil
        //      data.widthHint= SWTUtil.getButtonWidthHint(button);
        //      data.heightHint= SWTUtil.getButtonHeightHint(button);

        return data;
    }

    private void selectionChanged1() {
        updateViewerInput();
        updateButtons();
    }

    /**
     * Updates the pattern viewer.
     */
    protected void updateViewerInput() {
        IStructuredSelection selection = (IStructuredSelection) fTableViewer.getSelection();

        if (selection.size() == 1) {
            TemplatePersistenceData data = (TemplatePersistenceData) selection.getFirstElement();
            Template template = data.getTemplate();
            fPatternViewer.getDocument().set(template.getPattern());
        } else {
            fPatternViewer.getDocument().set(""); //$NON-NLS-1$
        }
    }

    /**
     * Updates the buttons.
     */
    protected void updateButtons() {
        IStructuredSelection selection = (IStructuredSelection) fTableViewer.getSelection();
        int selectionCount = selection.size();
        int itemCount = fTableViewer.getTable().getItemCount();
        boolean canRestore = fTemplateStore.getTemplateData(true).length != fTemplateStore
                .getTemplateData(false).length;
        boolean canRevert = false;
        for (Iterator it = selection.iterator(); it.hasNext();) {
            TemplatePersistenceData data = (TemplatePersistenceData) it.next();
            if (data.isModified()) {
                canRevert = true;
                break;
            }
        }

        fEditButton.setEnabled(selectionCount == 1);
        fExportButton.setEnabled(selectionCount > 0);
        fRemoveButton.setEnabled(selectionCount > 0 && selectionCount <= itemCount);
        fRestoreButton.setEnabled(canRestore);
        fRevertButton.setEnabled(canRevert);
    }

    private void add() {

        Iterator it = fContextTypeRegistry.contextTypes();
        if (it.hasNext()) {
            Template template = new Template("", "", ((TemplateContextType) it.next()).getId(), "", true); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$

            Template newTemplate = editTemplate(template, false, true);
            if (newTemplate != null) {
                TemplatePersistenceData data = new TemplatePersistenceData(newTemplate, true);
                fTemplateStore.add(data);
                fTableViewer.refresh();
                fTableViewer.setChecked(data, true);
                fTableViewer.setSelection(new StructuredSelection(data));
            }
        }
    }

    /**
     * Creates the edit dialog. Subclasses may override this method to provide a
     * custom dialog.
     *
     * @param template the template being edited
     * @param edit whether the dialog should be editable
     * @param isNameModifiable whether the template name may be modified
     * @return an <code>EditTemplateDialog</code> which will be opened.
     * @deprecated not called any longer as of 3.1 - use {@link #editTemplate(Template, boolean, boolean)}
     */
    @Deprecated
    protected Dialog createTemplateEditDialog(Template template, boolean edit, boolean isNameModifiable) {
        return new EditTemplateDialog(getShell(), template, edit, isNameModifiable, fContextTypeRegistry);
    }

    /**
     * Creates the edit dialog. Subclasses may override this method to provide a
     * custom dialog.
     *
     * @param template the template being edited
     * @param edit whether the dialog should be editable
     * @param isNameModifiable whether the template name may be modified
     * @return the created or modified template, or <code>null</code> if the edition failed
     * @since 3.1
     */
    protected Template editTemplate(Template template, boolean edit, boolean isNameModifiable) {
        EditTemplateDialog dialog = new EditTemplateDialog(getShell(), template, edit, isNameModifiable,
                fContextTypeRegistry);
        if (dialog.open() == Window.OK) {
            return dialog.getTemplate();
        }
        return null;
    }

    private void edit() {
        IStructuredSelection selection = (IStructuredSelection) fTableViewer.getSelection();

        Object[] objects = selection.toArray();
        if ((objects == null) || (objects.length != 1))
            return;

        TemplatePersistenceData data = (TemplatePersistenceData) selection.getFirstElement();
        edit(data);
    }

    private void edit(TemplatePersistenceData data) {
        Template oldTemplate = data.getTemplate();
        Template newTemplate = editTemplate(new Template(oldTemplate), true, true);
        if (newTemplate != null) {

            if (!newTemplate.getName().equals(oldTemplate.getName()) && MessageDialog.openQuestion(getShell(),
                    TemplatesMessages.TemplatePreferencePage_question_create_new_title,
                    TemplatesMessages.TemplatePreferencePage_question_create_new_message)) {
                data = new TemplatePersistenceData(newTemplate, true);
                fTemplateStore.add(data);
                fTableViewer.refresh();
            } else {
                data.setTemplate(newTemplate);
                fTableViewer.refresh(data);
            }
            selectionChanged1();
            fTableViewer.setChecked(data, data.isEnabled());
            fTableViewer.setSelection(new StructuredSelection(data));
        }
    }

    private void import_() {
        FileDialog dialog = new FileDialog(getShell());
        dialog.setText(TemplatesMessages.TemplatePreferencePage_import_title);
        dialog.setFilterExtensions(new String[] { TemplatesMessages.TemplatePreferencePage_import_extension });
        String path = dialog.open();

        if (path == null)
            return;

        try {
            TemplateReaderWriter reader = new TemplateReaderWriter();
            File file = new File(path);
            if (file.exists()) {
                InputStream input = new BufferedInputStream(new FileInputStream(file));
                try {
                    TemplatePersistenceData[] datas = reader.read(input, null);
                    for (int i = 0; i < datas.length; i++) {
                        TemplatePersistenceData data = datas[i];
                        fTemplateStore.add(data);
                    }
                } finally {
                    try {
                        input.close();
                    } catch (IOException x) {
                        // ignore
                    }
                }
            }

            fTableViewer.refresh();
            fTableViewer.setAllChecked(false);
            fTableViewer.setCheckedElements(getEnabledTemplates());

        } catch (FileNotFoundException e) {
            openReadErrorDialog(e);
        } catch (IOException e) {
            openReadErrorDialog(e);
        }
    }

    private void export() {
        IStructuredSelection selection = (IStructuredSelection) fTableViewer.getSelection();
        Object[] templates = selection.toArray();

        TemplatePersistenceData[] datas = new TemplatePersistenceData[templates.length];
        for (int i = 0; i != templates.length; i++)
            datas[i] = (TemplatePersistenceData) templates[i];

        export(datas);
    }

    private void export(TemplatePersistenceData[] templates) {
        FileDialog dialog = new FileDialog(getShell(), SWT.SAVE);
        dialog.setText(TemplatesMessages.TemplatePreferencePage_export_title);
        dialog.setFilterExtensions(new String[] { TemplatesMessages.TemplatePreferencePage_export_extension });
        dialog.setFileName(TemplatesMessages.TemplatePreferencePage_export_filename);
        String path = dialog.open();

        if (path == null)
            return;

        File file = new File(path);

        if (file.isHidden()) {
            String title = TemplatesMessages.TemplatePreferencePage_export_error_title;
            String message = NLSUtility.format(TemplatesMessages.TemplatePreferencePage_export_error_hidden,
                    file.getAbsolutePath());
            MessageDialog.openError(getShell(), title, message);
            return;
        }

        if (file.exists() && !file.canWrite()) {
            String title = TemplatesMessages.TemplatePreferencePage_export_error_title;
            String message = NLSUtility.format(TemplatesMessages.TemplatePreferencePage_export_error_canNotWrite,
                    file.getAbsolutePath());
            MessageDialog.openError(getShell(), title, message);
            return;
        }

        if (!file.exists() || confirmOverwrite(file)) {
            OutputStream output = null;
            try {
                output = new BufferedOutputStream(new FileOutputStream(file));
                TemplateReaderWriter writer = new TemplateReaderWriter();
                writer.save(templates, output);
            } catch (IOException e) {
                openWriteErrorDialog(e);
            } finally {
                if (output != null) {
                    try {
                        output.close();
                    } catch (IOException e) {
                        // ignore
                    }
                }
            }
        }
    }

    private boolean confirmOverwrite(File file) {
        return MessageDialog.openQuestion(getShell(), TemplatesMessages.TemplatePreferencePage_export_exists_title,
                NLSUtility.format(TemplatesMessages.TemplatePreferencePage_export_exists_message,
                        file.getAbsolutePath()));
    }

    private void remove() {
        IStructuredSelection selection = (IStructuredSelection) fTableViewer.getSelection();

        Iterator elements = selection.iterator();
        while (elements.hasNext()) {
            TemplatePersistenceData data = (TemplatePersistenceData) elements.next();
            fTemplateStore.delete(data);
        }

        fTableViewer.refresh();
    }

    private void restoreDeleted() {
        fTemplateStore.restoreDeleted();
        fTableViewer.refresh();
        fTableViewer.setCheckedElements(getEnabledTemplates());
        updateButtons();
    }

    private void revert() {
        IStructuredSelection selection = (IStructuredSelection) fTableViewer.getSelection();

        Iterator elements = selection.iterator();
        while (elements.hasNext()) {
            TemplatePersistenceData data = (TemplatePersistenceData) elements.next();
            data.revert();
            fTableViewer.setChecked(data, data.isEnabled());
        }

        selectionChanged1();
        fTableViewer.refresh();
    }

    /*
     * @see Control#setVisible(boolean)
     */
    @Override
    public void setVisible(boolean visible) {
        super.setVisible(visible);
        if (visible)
            setTitle(TemplatesMessages.TemplatePreferencePage_title);
    }

    /*
     * @see PreferencePage#performDefaults()
     */
    @Override
    protected void performDefaults() {
        if (isShowFormatterSetting()) {
            IPreferenceStore prefs = getPreferenceStore();
            fFormatButton.setSelection(prefs.getDefaultBoolean(getFormatterPreferenceKey()));
        }

        fTemplateStore.restoreDefaults(false);

        // refresh
        fTableViewer.refresh();
        fTableViewer.setAllChecked(false);
        fTableViewer.setCheckedElements(getEnabledTemplates());
    }

    /*
     * @see PreferencePage#performOk()
     */
    @Override
    public boolean performOk() {
        if (isShowFormatterSetting()) {
            IPreferenceStore prefs = getPreferenceStore();
            prefs.setValue(getFormatterPreferenceKey(), fFormatButton.getSelection());
        }

        try {
            fTemplateStore.save();
        } catch (IOException e) {
            openWriteErrorDialog(e);
        }

        return super.performOk();
    }

    /**
     * Returns the key to use for the formatter preference.
     *
     * @return the formatter preference key
     */
    protected String getFormatterPreferenceKey() {
        return DEFAULT_FORMATTER_PREFERENCE_KEY;
    }

    /*
     * @see PreferencePage#performCancel()
     */
    @Override
    public boolean performCancel() {
        try {
            fTemplateStore.load();
        } catch (IOException e) {
            openReadErrorDialog(e);
            return false;
        }
        return super.performCancel();
    }

    /*
     * @since 3.2
     */
    private void openReadErrorDialog(IOException ex) {
        IStatus status = new Status(IStatus.ERROR, TextEditorPlugin.PLUGIN_ID, IStatus.OK,
                "Failed to read templates.", ex); //$NON-NLS-1$
        TextEditorPlugin.getDefault().getLog().log(status);
        String title = TemplatesMessages.TemplatePreferencePage_error_read_title;
        String message = TemplatesMessages.TemplatePreferencePage_error_read_message;
        MessageDialog.openError(getShell(), title, message);
    }

    /*
     * @since 3.2
     */
    private void openWriteErrorDialog(IOException ex) {
        IStatus status = new Status(IStatus.ERROR, TextEditorPlugin.PLUGIN_ID, IStatus.OK,
                "Failed to write templates.", ex); //$NON-NLS-1$
        TextEditorPlugin.getDefault().getLog().log(status);
        String title = TemplatesMessages.TemplatePreferencePage_error_write_title;
        String message = TemplatesMessages.TemplatePreferencePage_error_write_message;
        MessageDialog.openError(getShell(), title, message);
    }

    protected SourceViewer getViewer() {
        return fPatternViewer;
    }

    protected TableViewer getTableViewer() {
        return fTableViewer;
    }
}