com.google.dart.tools.ui.actions.FormatAllAction.java Source code

Java tutorial

Introduction

Here is the source code for com.google.dart.tools.ui.actions.FormatAllAction.java

Source

/*
 * Copyright (c) 2012, the Dart project authors.
 * 
 * Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 * 
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */
package com.google.dart.tools.ui.actions;

import com.google.dart.tools.core.model.CompilationUnit;
import com.google.dart.tools.core.model.DartElement;
import com.google.dart.tools.core.model.DartModelException;
import com.google.dart.tools.core.model.DartProject;
import com.google.dart.tools.ui.DartToolsPlugin;
import com.google.dart.tools.ui.DartUI;
import com.google.dart.tools.ui.Messages;
import com.google.dart.tools.ui.internal.actions.WorkbenchRunnableAdapter;
import com.google.dart.tools.ui.internal.dialogs.OptionalMessageDialog;
import com.google.dart.tools.ui.internal.text.DartHelpContextIds;
import com.google.dart.tools.ui.internal.text.comment.CommentFormattingContext;
import com.google.dart.tools.ui.internal.text.comment.CommentFormattingStrategy;
import com.google.dart.tools.ui.internal.text.dart.DartFormattingStrategy;
import com.google.dart.tools.ui.internal.util.ExceptionHandler;
import com.google.dart.tools.ui.internal.util.Resources;
import com.google.dart.tools.ui.text.DartPartitions;

import org.eclipse.core.filebuffers.FileBuffers;
import org.eclipse.core.filebuffers.ITextFileBuffer;
import org.eclipse.core.filebuffers.ITextFileBufferManager;
import org.eclipse.core.filebuffers.LocationKind;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.text.DocumentRewriteSession;
import org.eclipse.jface.text.DocumentRewriteSessionType;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IDocumentExtension;
import org.eclipse.jface.text.IDocumentExtension4;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.text.formatter.FormattingContextProperties;
import org.eclipse.jface.text.formatter.IFormattingContext;
import org.eclipse.jface.text.formatter.MultiPassContentFormatter;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.window.Window;
import org.eclipse.ui.IObjectActionDelegate;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchSite;
import org.eclipse.ui.PlatformUI;

import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;

/**
 * Formats the code of the compilation units contained in the selection.
 * <p>
 * The action is applicable to selections containing elements of type <code>CompilationUnit</code>,
 * <code>DartLibrary </code>, and <code>DartProject</code>.
 * </p>
 * <p>
 * This class may be instantiated; it is not intended to be subclassed.
 * </p>
 * Provisional API: This class/interface is part of an interim API that is still under development
 * and expected to change significantly before reaching stability. It is being made available at
 * this early stage to solicit feedback from pioneering adopters on the understanding that any code
 * that uses this API will almost certainly be broken (repeatedly) as the API evolves.
 */
public class FormatAllAction extends SelectionDispatchAction {
    /*
     * (non-Javadoc) Class implements IObjectActionDelegate
     */
    public static class ObjectDelegate implements IObjectActionDelegate {
        private FormatAllAction fAction;

        @Override
        public void run(IAction action) {
            fAction.run();
        }

        @Override
        public void selectionChanged(IAction action, ISelection selection) {
            if (fAction == null) {
                action.setEnabled(false);
            }
        }

        @Override
        public void setActivePart(IAction action, IWorkbenchPart targetPart) {
            fAction = new FormatAllAction(targetPart.getSite());
        }
    }

    private static Map<Object, Object> getFomatterSettings(DartProject project) {
        return new HashMap<Object, Object>(project.getOptions(true));
    }

    private DocumentRewriteSession fRewriteSession;

    /**
     * Creates a new <code>FormatAllAction</code>. The action requires that the selection provided by
     * the site's selection provider is of type <code>
     * org.eclipse.jface.viewers.IStructuredSelection</code>.
     * 
     * @param site the site providing context information for this action
     */
    public FormatAllAction(IWorkbenchSite site) {
        super(site);
        setText(ActionMessages.FormatAllAction_label);
        setToolTipText(ActionMessages.FormatAllAction_tooltip);
        setDescription(ActionMessages.FormatAllAction_description);

        PlatformUI.getWorkbench().getHelpSystem().setHelp(this, DartHelpContextIds.FORMAT_ALL);
    }

    /*
     * (non-Javadoc) Method declared on SelectionDispatchAction.
     */
    @Override
    public void run(IStructuredSelection selection) {
        CompilationUnit[] cus = getCompilationUnits(selection);
        if (cus.length == 0) {
            MessageDialog.openInformation(getShell(), ActionMessages.FormatAllAction_EmptySelection_title,
                    ActionMessages.FormatAllAction_EmptySelection_description);
            return;
        }
        try {
            if (cus.length == 1) {
                DartUI.openInEditor(cus[0]);
            } else {
                int returnCode = OptionalMessageDialog.open("FormatAll", //$NON-NLS-1$
                        getShell(), ActionMessages.FormatAllAction_noundo_title, null,
                        ActionMessages.FormatAllAction_noundo_message, MessageDialog.WARNING,
                        new String[] { IDialogConstants.OK_LABEL, IDialogConstants.CANCEL_LABEL }, 0);
                if (returnCode != OptionalMessageDialog.NOT_SHOWN && returnCode != Window.OK) {
                    return;
                }
            }
        } catch (CoreException e) {
            ExceptionHandler.handle(e, getShell(), ActionMessages.FormatAllAction_error_title,
                    ActionMessages.FormatAllAction_error_message);
        }
        runOnMultiple(cus);
    }

    /*
     * (non-Javadoc) Method declared on SelectionDispatchAction.
     */
    @Override
    public void run(ITextSelection selection) {
    }

    /**
     * Perform format all on the given compilation units.
     * 
     * @param cus The compilation units to format.
     */
    public void runOnMultiple(final CompilationUnit[] cus) {
        try {
            final MultiStatus status = new MultiStatus(DartUI.ID_PLUGIN, IStatus.OK,
                    ActionMessages.FormatAllAction_status_description, null);

            IStatus valEditStatus = Resources.makeCommittable(getResources(cus), getShell());
            if (valEditStatus.matches(IStatus.CANCEL)) {
                return;
            }
            status.merge(valEditStatus);
            if (!status.matches(IStatus.ERROR)) {
                PlatformUI.getWorkbench().getProgressService().run(true, true,
                        new WorkbenchRunnableAdapter(new IWorkspaceRunnable() {
                            @Override
                            public void run(IProgressMonitor monitor) {
                                doRunOnMultiple(cus, status, monitor);
                            }
                        })); // workspace lock
            }
            if (!status.isOK()) {
                String title = ActionMessages.FormatAllAction_multi_status_title;
                ErrorDialog.openError(getShell(), title, null, status);
            }
        } catch (InvocationTargetException e) {
            ExceptionHandler.handle(e, getShell(), ActionMessages.FormatAllAction_error_title,
                    ActionMessages.FormatAllAction_error_message);
        } catch (InterruptedException e) {
            // Canceled by user
        }
    }

    /*
     * (non-Javadoc) Method declared on SelectionDispatchAction.
     */
    @Override
    public void selectionChanged(IStructuredSelection selection) {
        setEnabled(isEnabled(selection));
    }

    /*
     * (non-Javadoc) Method declared on SelectionDispatchAction.
     */
    @Override
    public void selectionChanged(ITextSelection selection) {
        // do nothing
    }

    //  private void collectCompilationUnits(IPackageFragment pack, Collection result)
    //      throws JavaScriptModelException {
    //    result.addAll(Arrays.asList(pack.getJavaScriptUnits()));
    //  }
    //
    //  private void collectCompilationUnits(IPackageFragmentRoot root,
    //      Collection result) throws JavaScriptModelException {
    //    if (root.getKind() == IPackageFragmentRoot.K_SOURCE) {
    //      IJavaScriptElement[] children = root.getChildren();
    //      for (int i = 0; i < children.length; i++) {
    //        collectCompilationUnits((IPackageFragment) children[i], result);
    //      }
    //    }
    //  }

    private void doFormat(IDocument document, Map<Object, Object> options) {
        final IFormattingContext context = new CommentFormattingContext();
        try {
            context.setProperty(FormattingContextProperties.CONTEXT_PREFERENCES, options);
            context.setProperty(FormattingContextProperties.CONTEXT_DOCUMENT, Boolean.valueOf(true));

            final MultiPassContentFormatter formatter = new MultiPassContentFormatter(
                    DartPartitions.DART_PARTITIONING, IDocument.DEFAULT_CONTENT_TYPE);

            formatter.setMasterStrategy(new DartFormattingStrategy());
            formatter.setSlaveStrategy(new CommentFormattingStrategy(), DartPartitions.DART_DOC);
            formatter.setSlaveStrategy(new CommentFormattingStrategy(), DartPartitions.DART_SINGLE_LINE_DOC);
            formatter.setSlaveStrategy(new CommentFormattingStrategy(), DartPartitions.DART_SINGLE_LINE_COMMENT);
            formatter.setSlaveStrategy(new CommentFormattingStrategy(), DartPartitions.DART_MULTI_LINE_COMMENT);

            try {
                startSequentialRewriteMode(document);
                formatter.format(document, context);
            } finally {
                stopSequentialRewriteMode(document);
            }
        } finally {
            context.dispose();
        }
    }

    private void doRunOnMultiple(CompilationUnit[] cus, MultiStatus status, IProgressMonitor monitor)
            throws OperationCanceledException {
        if (monitor == null) {
            monitor = new NullProgressMonitor();
        }
        monitor.setTaskName(ActionMessages.FormatAllAction_operation_description);

        monitor.beginTask("", cus.length * 4); //$NON-NLS-1$
        try {
            Map<Object, Object> lastOptions = null;
            DartProject lastProject = null;

            for (int i = 0; i < cus.length; i++) {
                CompilationUnit cu = cus[i];
                IPath path = cu.getPath();
                if (lastProject == null || !lastProject.equals(cu.getDartProject())) {
                    lastProject = cu.getDartProject();
                    lastOptions = getFomatterSettings(lastProject);
                }
                if (monitor.isCanceled()) {
                    throw new OperationCanceledException();
                }
                if (cu.getResource().getResourceAttributes().isReadOnly()) {
                    String message = Messages.format(ActionMessages.FormatAllAction_read_only_skipped,
                            path.toString());
                    status.add(new Status(IStatus.WARNING, DartUI.ID_PLUGIN, IStatus.WARNING, message, null));
                    continue;
                }

                ITextFileBufferManager manager = FileBuffers.getTextFileBufferManager();
                try {
                    try {
                        manager.connect(path, LocationKind.IFILE, new SubProgressMonitor(monitor, 1));

                        monitor.subTask(path.makeRelative().toString());
                        ITextFileBuffer fileBuffer = manager.getTextFileBuffer(path, LocationKind.IFILE);

                        formatCompilationUnit(fileBuffer, lastOptions);

                        if (fileBuffer.isDirty() && !fileBuffer.isShared()) {
                            fileBuffer.commit(new SubProgressMonitor(monitor, 2), false);
                        } else {
                            monitor.worked(2);
                        }
                    } finally {
                        manager.disconnect(path, LocationKind.IFILE, new SubProgressMonitor(monitor, 1));
                    }
                } catch (CoreException e) {
                    String message = Messages.format(ActionMessages.FormatAllAction_problem_accessing,
                            new String[] { path.toString(), e.getLocalizedMessage() });
                    status.add(new Status(IStatus.WARNING, DartUI.ID_PLUGIN, IStatus.WARNING, message, e));
                }
            }
        } finally {
            monitor.done();
        }
    }

    private void formatCompilationUnit(final ITextFileBuffer fileBuffer, final Map<Object, Object> options) {
        if (fileBuffer.isShared()) {
            getShell().getDisplay().syncExec(new Runnable() {
                @Override
                public void run() {
                    doFormat(fileBuffer.getDocument(), options);
                }
            });
        } else {
            doFormat(fileBuffer.getDocument(), options); // run in context thread
        }
    }

    private CompilationUnit[] getCompilationUnits(IStructuredSelection selection) {
        HashSet<DartElement> result = new HashSet<DartElement>();
        Object[] selected = selection.toArray();
        for (int i = 0; i < selected.length; i++) {
            try {
                if (selected[i] instanceof DartElement) {
                    DartElement elem = (DartElement) selected[i];
                    if (elem.exists()) {
                        switch (elem.getElementType()) {
                        case DartElement.TYPE:
                            if (elem.getParent().getElementType() == DartElement.COMPILATION_UNIT) {
                                result.add(elem.getParent());
                            }
                            break;
                        case DartElement.COMPILATION_UNIT:
                            result.add(elem);
                            break;
                        case DartElement.LIBRARY:
                            //                collectCompilationUnits((DartLibrary) elem, result);
                            break;
                        case DartElement.DART_PROJECT:
                            DartElement[] roots = ((DartProject) elem).getChildren();
                            for (int k = 0; k < roots.length; k++) {
                                //                  collectCompilationUnits(roots[k], result);
                            }
                            break;
                        }
                    }
                }
            } catch (DartModelException e) {
                DartToolsPlugin.log(e);
            }
        }
        return result.toArray(new CompilationUnit[result.size()]);
    }

    private IResource[] getResources(CompilationUnit[] cus) {
        IResource[] res = new IResource[cus.length];
        for (int i = 0; i < res.length; i++) {
            res[i] = cus[i].getResource();
        }
        return res;
    }

    private boolean isEnabled(IStructuredSelection selection) {
        Object[] selected = selection.toArray();
        for (int i = 0; i < selected.length; i++) {
            if (selected[i] instanceof DartElement) {
                DartElement elem = (DartElement) selected[i];
                if (elem.exists()) {
                    switch (elem.getElementType()) {
                    case DartElement.TYPE:
                        // for browsing perspective
                        return elem.getParent().getElementType() == DartElement.COMPILATION_UNIT;
                    case DartElement.COMPILATION_UNIT:
                        return true;
                    case DartElement.LIBRARY:
                        return true;
                    case DartElement.DART_PROJECT:
                        return true;
                    }
                }
            }
        }
        return false;
    }

    @SuppressWarnings("deprecation")
    private void startSequentialRewriteMode(IDocument document) {
        if (document instanceof IDocumentExtension4) {
            IDocumentExtension4 extension = (IDocumentExtension4) document;
            fRewriteSession = extension.startRewriteSession(DocumentRewriteSessionType.SEQUENTIAL);
        } else if (document instanceof IDocumentExtension) {
            IDocumentExtension extension = (IDocumentExtension) document;
            extension.startSequentialRewrite(false);
        }
    }

    @SuppressWarnings("deprecation")
    private void stopSequentialRewriteMode(IDocument document) {
        if (document instanceof IDocumentExtension4) {
            IDocumentExtension4 extension = (IDocumentExtension4) document;
            extension.stopRewriteSession(fRewriteSession);
        } else if (document instanceof IDocumentExtension) {
            IDocumentExtension extension = (IDocumentExtension) document;
            extension.stopSequentialRewrite();
        }
    }

}