com.intellij.velocity.inspections.DefineInCommentIntention.java Source code

Java tutorial

Introduction

Here is the source code for com.intellij.velocity.inspections.DefineInCommentIntention.java

Source

/*
 * Copyright 2000-2009 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
 *
 * 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.intellij.velocity.inspections;

import java.io.IOException;
import java.util.Collection;

import javax.swing.Icon;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.mustbe.consulo.roots.ContentFolderScopes;
import com.intellij.codeInsight.FileModificationService;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInsight.template.Template;
import com.intellij.codeInsight.template.TemplateManager;
import com.intellij.openapi.application.Result;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.ui.popup.PopupStep;
import com.intellij.openapi.ui.popup.util.BaseListPopupStep;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.velocity.VelocityBundle;
import com.intellij.velocity.VtlFileIndex;
import com.intellij.velocity.VtlIcons;
import com.intellij.velocity.psi.PsiUtil;
import com.intellij.velocity.psi.files.VtlFile;
import com.intellij.velocity.psi.files.VtlFileViewProvider;
import com.intellij.velocity.psi.reference.VtlReferenceExpression;

/**
 * @author Alexey Chmutov
 */
public abstract class DefineInCommentIntention implements IntentionAction {
    private final String myText;
    private final String myFamilyName;
    public static final String VELOCITY_IMPLICIT_VM = "velocity_implicit.vm";

    public DefineInCommentIntention(@NotNull String text, @NotNull String familyName) {
        myText = text;
        myFamilyName = familyName;
    }

    @Override
    @NotNull
    public String getText() {
        return myText;
    }

    @Override
    @NotNull
    public String getFamilyName() {
        return myFamilyName;
    }

    @Override
    public final boolean isAvailable(@NotNull final Project project, final Editor editor, final PsiFile file) {
        return file.getViewProvider() instanceof VtlFileViewProvider && getReferenceElement(editor, file) != null
                && ModuleUtil.findModuleForPsiElement(file) != null;
    }

    @Nullable
    protected PsiElement getReferenceElement(@NotNull final Editor editor, @NotNull final PsiFile file) {
        final VtlReferenceExpression ref = Util.findReferenceExpression(editor, file);
        return ref != null && ref.multiResolve(false).length == 0 && isAvailable(ref) ? ref : null;
    }

    protected boolean isAvailable(@NotNull VtlReferenceExpression ref) {
        return true;
    }

    protected void defineInComment(final Editor editor, final PsiFile fileWithVarReference,
            final PsiFile fileToInsertComment, final boolean addFileReference) {
        final PsiElement ref = getReferenceElement(editor, fileWithVarReference);
        assert ref != null;
        final Project project = fileWithVarReference.getProject();
        if (!FileModificationService.getInstance().prepareFileForWrite(fileToInsertComment)) {
            return;
        }

        final PsiDocumentManager documentManager = PsiDocumentManager.getInstance(project);
        final Document documentToInsertComment = documentManager.getDocument(fileToInsertComment);
        assert documentToInsertComment != null;
        new WriteCommandAction(project) {
            @Override
            protected void run(Result result) throws Throwable {
                Editor editor = FileEditorManager.getInstance(project).openTextEditor(
                        new OpenFileDescriptor(project, fileToInsertComment.getViewProvider().getVirtualFile(), 0),
                        true);
                assert editor != null;
                assert documentToInsertComment == editor.getDocument();
                int insertionIndex = documentToInsertComment.getText().startsWith(
                        VtlFileIndex.IMPLICIT_INCLUDE_MARKER) ? VtlFileIndex.IMPLICIT_INCLUDE_MARKER.length() : 0;
                editor.getCaretModel().moveToOffset(insertionIndex);
                TemplateManager manager = TemplateManager.getInstance(project);
                final Template template = manager.createTemplate("", "");
                final String relativePath = addFileReference
                        ? PsiUtil.getRelativePath(fileToInsertComment, fileWithVarReference)
                        : null;
                prepareTemplate(template, ref, relativePath, fileToInsertComment);
                manager.startTemplate(editor, template);
            }
        }.execute();
    }

    protected abstract void prepareTemplate(@NotNull Template template, @NotNull PsiElement element,
            @Nullable String relativePath, @NotNull PsiFile fileToInsertComment);

    protected void chooseTargetFile(final PsiFile file, final Editor editor, final boolean addFileReference) {
        final Collection<VtlFile> implicitlyIncludedFiles = VtlFileIndex.getImplicitlyIncludedFiles(file);
        if (implicitlyIncludedFiles.size() == 1) {
            defineInComment(editor, file, implicitlyIncludedFiles.iterator().next(), addFileReference);
            return;
        }

        if (implicitlyIncludedFiles.size() < 1) {
            final VtlFile newTargetFile = new WriteCommandAction<VtlFile>(file.getProject()) {
                @Override
                protected void run(Result<VtlFile> result) throws Throwable {
                    final VirtualFile virtualFile = createVelocityImplicitVmFile();
                    if (virtualFile == null) {
                        return;
                    }
                    VfsUtil.saveText(virtualFile, VtlFileIndex.IMPLICIT_INCLUDE_MARKER);
                    final PsiFile psiFile = file.getManager().findFile(virtualFile);
                    if (psiFile instanceof VtlFile) {
                        result.setResult((VtlFile) psiFile);
                    }
                }

                @Nullable
                private VirtualFile createVelocityImplicitVmFile() throws IOException {
                    final Module module = ModuleUtil.findModuleForPsiElement(file);
                    final VirtualFile[] roots = ModuleRootManager.getInstance(module)
                            .getContentFolderFiles(ContentFolderScopes.all(false));
                    if (roots.length > 0) {
                        return roots[0].createChildData(this, VELOCITY_IMPLICIT_VM);
                    }
                    final PsiDirectory psiDirectory = file.getContainingDirectory();
                    return psiDirectory == null ? null
                            : psiDirectory.getVirtualFile().createChildData(this, VELOCITY_IMPLICIT_VM);
                }
            }.execute().getResultObject();
            if (newTargetFile != null) {
                defineInComment(editor, file, newTargetFile, addFileReference);
            }
            return;
        }

        final BaseListPopupStep<VtlFile> step = new BaseListPopupStep<VtlFile>(
                VelocityBundle.message("choose.external.definitions.file"),
                implicitlyIncludedFiles.toArray(new VtlFile[implicitlyIncludedFiles.size()])) {
            @NotNull
            @Override
            public String getTextFor(final VtlFile value) {
                return value.getViewProvider().getVirtualFile().getName();
            }

            @Override
            public PopupStep onChosen(final VtlFile selectedValue, final boolean finalChoice) {
                if (finalChoice) {
                    defineInComment(editor, file, selectedValue, addFileReference);
                }
                return super.onChosen(selectedValue, finalChoice);
            }

            @Override
            public boolean isSpeedSearchEnabled() {
                return true;
            }

            @Override
            public Icon getIconFor(final VtlFile aValue) {
                return VtlIcons.VTL_ICON;
            }
        };
        JBPopupFactory.getInstance().createListPopup(step).showInBestPositionFor(editor);
    }

    @Override
    public boolean startInWriteAction() {
        return true;
    }
}