/* * Copyright 2000-2015 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.openapi.vcs.actions; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.fileEditor.FileEditor; import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.fileEditor.TextEditor; import com.intellij.openapi.progress.ProcessCanceledException; 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.util.Ref; import com.intellij.openapi.vcs.*; import com.intellij.openapi.vcs.annotate.AnnotationProvider; import com.intellij.openapi.vcs.annotate.FileAnnotation; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import java.util.Collections; import java.util.List; import static com.intellij.util.ObjectUtils.assertNotNull; public class AnnotateLocalFileAction { private static final Logger LOG = Logger.getInstance(AnnotateLocalFileAction.class); private static boolean isEnabled(AnActionEvent e) { VcsContext context = VcsContextFactory.SERVICE.getInstance().createContextOn(e); Project project = context.getProject(); if (project == null || project.isDisposed()) return false; VirtualFile file = context.getSelectedFile(); if (file == null || file.isDirectory() || file.getFileType().isBinary()) return false; final AbstractVcs vcs = ProjectLevelVcsManager.getInstance(project).getVcsFor(file); if (vcs == null) return false; final AnnotationProvider annotationProvider = vcs.getAnnotationProvider(); if (annotationProvider == null) return false; final FileStatus fileStatus = FileStatusManager.getInstance(project).getStatus(file); if (fileStatus == FileStatus.UNKNOWN || fileStatus == FileStatus.ADDED || fileStatus == FileStatus.IGNORED) { return false; } return true; } private static boolean isSuspended(AnActionEvent e) { VirtualFile file = assertNotNull(VcsContextFactory.SERVICE.getInstance().createContextOn(e).getSelectedFile()); return VcsAnnotateUtil.getBackgroundableLock(e.getRequiredData(CommonDataKeys.PROJECT), file).isLocked(); } private static boolean isAnnotated(AnActionEvent e) { VcsContext context = VcsContextFactory.SERVICE.getInstance().createContextOn(e); Editor editor = context.getEditor(); if (editor != null) { return editor.getGutter().isAnnotationsShown(); } return ContainerUtil.exists(getEditors(context), editor1 -> editor1.getGutter().isAnnotationsShown()); } private static void perform(AnActionEvent e, boolean selected) { final VcsContext context = VcsContextFactory.SERVICE.getInstance().createContextOn(e); if (!selected) { for (Editor editor : getEditors(context)) { editor.getGutter().closeAllAnnotations(); } } else { Project project = assertNotNull(context.getProject()); VirtualFile selectedFile = assertNotNull(context.getSelectedFile()); Editor editor = context.getEditor(); if (editor == null) { FileEditor[] fileEditors = FileEditorManager.getInstance(project).openFile(selectedFile, false); for (FileEditor fileEditor : fileEditors) { if (fileEditor instanceof TextEditor) { editor = ((TextEditor)fileEditor).getEditor(); } } } LOG.assertTrue(editor != null); doAnnotate(editor, project); } } private static void doAnnotate(@NotNull final Editor editor, @NotNull final Project project) { final VirtualFile file = FileDocumentManager.getInstance().getFile(editor.getDocument()); if (file == null) return; final AbstractVcs vcs = ProjectLevelVcsManager.getInstance(project).getVcsFor(file); if (vcs == null) return; final AnnotationProvider annotationProvider = vcs.getAnnotationProvider(); assert annotationProvider != null; final Ref<FileAnnotation> fileAnnotationRef = new Ref<>(); final Ref<VcsException> exceptionRef = new Ref<>(); VcsAnnotateUtil.getBackgroundableLock(project, file).lock(); final Task.Backgroundable annotateTask = new Task.Backgroundable(project, VcsBundle.message("retrieving.annotations"), true) { @Override public void run(final @NotNull ProgressIndicator indicator) { try { fileAnnotationRef.set(annotationProvider.annotate(file)); } catch (VcsException e) { exceptionRef.set(e); } catch (ProcessCanceledException pce) { throw pce; } catch (Throwable t) { exceptionRef.set(new VcsException(t)); } } @Override public void onCancel() { onSuccess(); } @Override public void onSuccess() { VcsAnnotateUtil.getBackgroundableLock(project, file).unlock(); if (!exceptionRef.isNull()) { LOG.warn(exceptionRef.get()); AbstractVcsHelper.getInstance(project).showErrors(Collections.singletonList(exceptionRef.get()), VcsBundle.message("message.title.annotate")); } if (!fileAnnotationRef.isNull()) { AnnotateToggleAction.doAnnotate(editor, project, file, fileAnnotationRef.get(), vcs); } } }; ProgressManager.getInstance().run(annotateTask); } @NotNull private static List<Editor> getEditors(@NotNull VcsContext context) { Project project = assertNotNull(context.getProject()); VirtualFile file = assertNotNull(context.getSelectedFile()); return VcsAnnotateUtil.getEditors(project, file); } public static class Provider implements AnnotateToggleAction.Provider { @Override public boolean isEnabled(AnActionEvent e) { return AnnotateLocalFileAction.isEnabled(e); } @Override public boolean isSuspended(AnActionEvent e) { return AnnotateLocalFileAction.isSuspended(e); } @Override public boolean isAnnotated(AnActionEvent e) { return AnnotateLocalFileAction.isAnnotated(e); } @Override public void perform(AnActionEvent e, boolean selected) { AnnotateLocalFileAction.perform(e, selected); } } }