com.intellij.byteCodeViewer.ShowByteCodeAction.java Source code

Java tutorial

Introduction

Here is the source code for com.intellij.byteCodeViewer.ShowByteCodeAction.java

Source

/*
 * Copyright 2000-2013 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.byteCodeViewer;

import com.intellij.codeInsight.documentation.DocumentationManager;
import com.intellij.codeInsight.lookup.LookupManager;
import com.intellij.compiler.impl.TranslatingCompilerFilesMonitor;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.ui.popup.JBPopup;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
import com.intellij.psi.util.PsiUtilBase;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.ui.popup.NotLookupOrSearchCondition;
import com.intellij.ui.popup.PopupPositionManager;
import com.intellij.util.Processor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

/**
 * @author anna
 * @since 5/4/12
 */
public class ShowByteCodeAction extends AnAction {
    @Override
    public void update(AnActionEvent e) {
        e.getPresentation().setEnabled(false);
        e.getPresentation().setIcon(AllIcons.Toolwindows.Documentation);
        final Project project = e.getData(CommonDataKeys.PROJECT);
        if (project != null) {
            final PsiElement psiElement = getPsiElement(e.getDataContext(), project,
                    e.getData(CommonDataKeys.EDITOR));
            if (psiElement != null) {
                if (psiElement.getContainingFile() instanceof PsiClassOwner
                        && ByteCodeViewerManager.getContainingClass(psiElement) != null) {
                    e.getPresentation().setEnabled(true);
                }
            }
        }
    }

    @Override
    public void actionPerformed(AnActionEvent e) {
        final DataContext dataContext = e.getDataContext();
        final Project project = CommonDataKeys.PROJECT.getData(dataContext);
        if (project == null)
            return;
        final Editor editor = CommonDataKeys.EDITOR.getData(dataContext);

        final PsiElement psiElement = getPsiElement(dataContext, project, editor);
        if (psiElement == null)
            return;

        final String psiElementTitle = ByteCodeViewerManager.getInstance(project).getTitle(psiElement);

        final VirtualFile virtualFile = PsiUtilCore.getVirtualFile(psiElement);
        if (virtualFile == null)
            return;

        final SmartPsiElementPointer element = SmartPointerManager.getInstance(project)
                .createSmartPsiElementPointer(psiElement);
        ProgressManager.getInstance().run(new Task.Backgroundable(project, "Searching byte code...") {
            private String myByteCode;
            private String myErrorMessage;
            private String myErrorTitle;

            @Override
            public void run(@NotNull ProgressIndicator indicator) {
                if (ProjectRootManager.getInstance(project).getFileIndex().isInContent(virtualFile)
                        && TranslatingCompilerFilesMonitor.getInstance().isMarkedForCompilation(project,
                                virtualFile)) {
                    myErrorMessage = "Unable to show byte code for '" + psiElementTitle
                            + "'. Class file does not exist or is out-of-date.";
                    myErrorTitle = "Class File Out-Of-Date";
                } else {
                    myByteCode = ApplicationManager.getApplication().runReadAction(new Computable<String>() {
                        @Override
                        public String compute() {
                            return ByteCodeViewerManager.getByteCode(psiElement);
                        }
                    });
                }
            }

            @Override
            public void onSuccess() {
                if (project.isDisposed())
                    return;

                if (myErrorMessage != null && myTitle != null) {
                    Messages.showWarningDialog(project, myErrorMessage, myErrorTitle);
                    return;
                }
                final PsiElement targetElement = element.getElement();
                if (targetElement == null)
                    return;

                final ByteCodeViewerManager codeViewerManager = ByteCodeViewerManager.getInstance(project);
                if (codeViewerManager.hasActiveDockedDocWindow()) {
                    codeViewerManager.doUpdateComponent(targetElement, myByteCode);
                } else {
                    if (myByteCode == null) {
                        Messages.showErrorDialog(project,
                                "Unable to parse class file for '" + psiElementTitle + "'.", "Byte Code not Found");
                        return;
                    }
                    final ByteCodeViewerComponent component = new ByteCodeViewerComponent(project, null);
                    component.setText(myByteCode, targetElement);
                    Processor<JBPopup> pinCallback = new Processor<JBPopup>() {
                        @Override
                        public boolean process(JBPopup popup) {
                            codeViewerManager.recreateToolWindow(targetElement, targetElement);
                            popup.cancel();
                            return false;
                        }
                    };

                    final JBPopup popup = JBPopupFactory.getInstance().createComponentPopupBuilder(component, null)
                            .setRequestFocusCondition(project, NotLookupOrSearchCondition.INSTANCE)
                            .setProject(project)
                            .setDimensionServiceKey(project, DocumentationManager.JAVADOC_LOCATION_AND_SIZE, false)
                            .setResizable(true).setMovable(true)
                            .setRequestFocus(LookupManager.getActiveLookup(editor) == null)
                            .setTitle(psiElementTitle + " Bytecode").setCouldPin(pinCallback).createPopup();
                    Disposer.register(popup, component);

                    PopupPositionManager.positionPopupInBestPosition(popup, editor, dataContext);
                }
            }
        });
    }

    @Nullable
    private static PsiElement getPsiElement(DataContext dataContext, Project project, Editor editor) {
        PsiElement psiElement = null;
        if (editor == null) {
            psiElement = CommonDataKeys.PSI_ELEMENT.getData(dataContext);
        } else {
            final PsiFile file = PsiUtilBase.getPsiFileInEditor(editor, project);
            final Editor injectedEditor = InjectedLanguageUtil.getEditorForInjectedLanguageNoCommit(editor, file);
            if (injectedEditor != null) {
                PsiFile psiFile = PsiUtilBase.getPsiFileInEditor(injectedEditor, project);
                psiElement = psiFile != null ? psiFile.findElementAt(injectedEditor.getCaretModel().getOffset())
                        : null;
            }

            if (file != null && psiElement == null) {
                psiElement = file.findElementAt(editor.getCaretModel().getOffset());
            }
        }

        return psiElement;
    }
}