/* * 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.jetbrains.lang.dart.ide.actions; import com.intellij.codeInsight.hint.HintManager; import com.intellij.codeInsight.hint.HintManagerImpl; import com.intellij.codeInsight.hint.HintUtil; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.actionSystem.Presentation; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiFile; import com.intellij.psi.search.FileTypeIndex; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.GlobalSearchScopesCore; import com.intellij.ui.LightweightHint; import com.intellij.util.SmartList; import com.jetbrains.lang.dart.DartFileType; import com.jetbrains.lang.dart.analyzer.DartAnalysisServerService; import com.jetbrains.lang.dart.ide.DartWritingAccessProvider; import com.jetbrains.lang.dart.sdk.DartSdk; import com.jetbrains.lang.dart.sdk.DartSdkLibUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.util.List; /** * An abstract {@link AnAction} for processing a single Dart file open in the editor, * or a group of selected Dart files. */ public abstract class AbstractDartFileProcessingAction extends AnAction implements DumbAware { public AbstractDartFileProcessingAction(@Nullable String text, @Nullable String description, @Nullable Icon icon) { super(text, description, icon); } @Override public void actionPerformed(final AnActionEvent event) { final Project project = event.getProject(); if (project == null) return; final DartSdk sdk = DartSdk.getDartSdk(project); if (sdk == null || !DartAnalysisServerService.isDartSdkVersionSufficient(sdk)) return; PsiDocumentManager.getInstance(project).commitAllDocuments(); final Editor editor = event.getData(CommonDataKeys.EDITOR); if (editor != null) { final PsiFile psiFile = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument()); if (!isApplicableFile(psiFile)) return; runOverEditor(project, editor, psiFile); } else { final VirtualFile[] filesAndDirs = CommonDataKeys.VIRTUAL_FILE_ARRAY.getData(event.getDataContext()); if (filesAndDirs != null && DartAnalysisServerService.getInstance(project).serverReadyForRequest(project)) { final List<VirtualFile> files = getApplicableVirtualFiles(project, filesAndDirs); runOverFiles(project, files); } } } @NotNull protected abstract String getActionTextForEditor(); @NotNull protected abstract String getActionTextForFiles(); protected abstract void runOverEditor(@NotNull final Project project, @NotNull final Editor editor, @NotNull final PsiFile psiFile); protected abstract void runOverFiles(@NotNull final Project project, @NotNull final List<VirtualFile> dartFiles); @Override public void update(final AnActionEvent event) { final Presentation presentation = event.getPresentation(); final Project project = event.getProject(); if (project == null) { presentation.setEnabledAndVisible(false); return; } final DartSdk sdk = DartSdk.getDartSdk(project); if (sdk == null || !DartAnalysisServerService.isDartSdkVersionSufficient(sdk)) { presentation.setEnabledAndVisible(false); return; } final Editor editor = event.getData(CommonDataKeys.EDITOR); if (editor != null) { final PsiFile psiFile = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument()); // visible for any Dart file, but enabled for applicable only presentation.setVisible(psiFile != null && psiFile.getFileType() == DartFileType.INSTANCE); presentation.setEnabled(isApplicableFile(psiFile)); presentation.setText(getActionTextForEditor()); return; } final VirtualFile[] filesAndDirs = CommonDataKeys.VIRTUAL_FILE_ARRAY.getData(event.getDataContext()); if (filesAndDirs == null) { presentation.setEnabledAndVisible(false); return; } presentation.setEnabledAndVisible(mayHaveApplicableDartFiles(project, filesAndDirs)); presentation.setText(getActionTextForFiles()); } public static void showHintLater(@NotNull final Editor editor, @NotNull final String text, final boolean error) { ApplicationManager.getApplication().invokeLater(() -> { final JComponent component = error ? HintUtil.createErrorLabel(text) : HintUtil.createInformationLabel(text); final LightweightHint hint = new LightweightHint(component); HintManagerImpl.getInstanceImpl().showEditorHint(hint, editor, HintManager.UNDER, HintManager.HIDE_BY_ANY_KEY | HintManager.HIDE_BY_TEXT_CHANGE | HintManager.HIDE_BY_SCROLLING, 0, false); }, ModalityState.NON_MODAL, o -> editor.isDisposed() || !editor.getComponent().isShowing()); } @NotNull private static List<VirtualFile> getApplicableVirtualFiles(@NotNull final Project project, @NotNull final VirtualFile[] filesAndDirs) { final List<VirtualFile> result = new SmartList<>(); GlobalSearchScope dirScope = null; for (VirtualFile fileOrDir : filesAndDirs) { if (fileOrDir.isDirectory()) { if (dirScope == null) { dirScope = GlobalSearchScopesCore.directoryScope(project, fileOrDir, true); } else { dirScope = dirScope.union(GlobalSearchScopesCore.directoryScope(project, fileOrDir, true)); } } else if (isApplicableFile(project, fileOrDir)) { result.add(fileOrDir); } } if (dirScope != null) { for (VirtualFile file : FileTypeIndex .getFiles(DartFileType.INSTANCE, GlobalSearchScope.projectScope(project).intersectWith(dirScope))) { if (isApplicableFile(project, file)) { result.add(file); } } } return result; } private static boolean isApplicableFile(@NotNull final Project project, @NotNull final VirtualFile file) { if (file.getFileType() != DartFileType.INSTANCE) return false; final Module module = ModuleUtilCore.findModuleForFile(file, project); if (module == null) return false; if (!DartSdkLibUtil.isDartSdkEnabled(module)) return false; if (DartWritingAccessProvider.isInDartSdkOrDartPackagesFolder(project, file)) return false; return true; } private static boolean isApplicableFile(@Nullable final PsiFile psiFile) { if (psiFile == null || psiFile.getVirtualFile() == null || psiFile.getFileType() != DartFileType.INSTANCE) return false; final Module module = ModuleUtilCore.findModuleForPsiElement(psiFile); if (module == null) return false; if (!DartSdkLibUtil.isDartSdkEnabled(module)) return false; if (DartWritingAccessProvider.isInDartSdkOrDartPackagesFolder(psiFile)) return false; return true; } private static boolean mayHaveApplicableDartFiles(@NotNull final Project project, @NotNull final VirtualFile[] files) { for (VirtualFile fileOrDir : files) { if (!fileOrDir.isDirectory() && isApplicableFile(project, fileOrDir)) { return true; } if (fileOrDir.isDirectory() && ProjectRootManager.getInstance(project).getFileIndex().isInContent(fileOrDir) && FileTypeIndex.containsFileOfType(DartFileType.INSTANCE, GlobalSearchScopesCore.directoryScope(project, fileOrDir, true))) { return true; } } return false; } }