/* * SonarLint for Eclipse * Copyright (C) 2015-2017 SonarSource SA * sonarlint@sonarsource.com * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package org.sonarlint.eclipse.ui.internal.server.actions; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; import javax.annotation.Nullable; import org.eclipse.core.resources.IFile; import org.eclipse.core.runtime.jobs.IJobChangeEvent; import org.eclipse.core.runtime.jobs.IJobChangeListener; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.viewers.IBaseLabelProvider; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IEditorReference; import org.eclipse.ui.IFileEditorInput; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.ide.ResourceUtil; import org.eclipse.ui.texteditor.ITextEditor; import org.sonarlint.eclipse.core.SonarLintLogger; import org.sonarlint.eclipse.core.internal.SonarLintCorePlugin; import org.sonarlint.eclipse.core.internal.TriggerType; import org.sonarlint.eclipse.core.internal.adapter.Adapters; import org.sonarlint.eclipse.core.internal.jobs.AnalyzeProjectJob; import org.sonarlint.eclipse.core.internal.jobs.AnalyzeProjectRequest; import org.sonarlint.eclipse.core.internal.jobs.AnalyzeProjectRequest.FileWithDocument; import org.sonarlint.eclipse.core.internal.resources.SonarLintProjectConfiguration; import org.sonarlint.eclipse.core.internal.server.IServer; import org.sonarlint.eclipse.core.resource.ISonarLintFile; import org.sonarlint.eclipse.core.resource.ISonarLintProject; import org.sonarlint.eclipse.ui.internal.SonarLintProjectDecorator; public class JobUtils { private JobUtils() { // utility class, forbidden constructor } // Make sure you only call this from within a Display, otherwise the workbench is not available // See: http://stackoverflow.com/questions/1265174/nullpointerexception-in-platformui-getworkbench-getactiveworkbenchwindow-get public static void scheduleAnalysisOfOpenFiles(@Nullable ISonarLintProject project, TriggerType triggerType) { Map<ISonarLintProject, List<FileWithDocument>> filesByProject = new HashMap<>(); IWorkbenchWindow workbench = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); if (workbench == null) { SonarLintLogger.get().debug("possible attempt to get workbench window outside of a Display"); return; } IWorkbenchPage page = workbench.getActivePage(); for (IEditorReference ref : page.getEditorReferences()) { try { IEditorInput input = ref.getEditorInput(); collectOpenedFiles(project, filesByProject, page, input); } catch (PartInitException e) { SonarLintLogger.get().error("could not get editor content", e); } } for (Map.Entry<ISonarLintProject, List<FileWithDocument>> entry : filesByProject.entrySet()) { ISonarLintProject aProject = entry.getKey(); if (aProject.isOpen() && SonarLintProjectConfiguration.read(aProject.getScopeContext()).isAutoEnabled()) { AnalyzeProjectRequest request = new AnalyzeProjectRequest(aProject, entry.getValue(), triggerType); new AnalyzeProjectJob(request).schedule(); } } } private static void collectOpenedFiles(@Nullable ISonarLintProject project, Map<ISonarLintProject, List<FileWithDocument>> filesByProject, IWorkbenchPage page, IEditorInput input) { if (input instanceof IFileEditorInput) { IFile file = ((IFileEditorInput) input).getFile(); ISonarLintFile sonarFile = Adapters.adapt(file, ISonarLintFile.class); if (sonarFile != null && (project == null || sonarFile.getProject().equals(project))) { filesByProject.putIfAbsent(sonarFile.getProject(), new ArrayList<>()); IEditorPart editorPart = ResourceUtil.findEditor(page, file); if (editorPart instanceof ITextEditor) { IDocument doc = ((ITextEditor) editorPart).getDocumentProvider().getDocument(editorPart.getEditorInput()); filesByProject.get(sonarFile.getProject()).add(new FileWithDocument(sonarFile, doc)); } else { filesByProject.get(sonarFile.getProject()).add(new FileWithDocument(sonarFile, null)); } } } } public static void scheduleAnalysisOfOpenFiles(List<ISonarLintProject> projects, TriggerType triggerType) { if (Display.getCurrent() != null) { projects.forEach(p -> scheduleAnalysisOfOpenFiles(p, triggerType)); } else { Display.getDefault().asyncExec(() -> projects.forEach(p -> scheduleAnalysisOfOpenFiles(p, triggerType))); } } public static void scheduleAnalysisOfOpenFilesInBoundProjects(IServer server, TriggerType triggerType) { scheduleAnalysisOfOpenFiles(server.getBoundProjects(), triggerType); } public static void scheduleAnalysisOfOpenFiles(Job job, List<ISonarLintProject> projects, TriggerType triggerType) { job.addJobChangeListener(new JobCompletionListener() { @Override public void done(IJobChangeEvent event) { if (event.getResult().isOK()) { scheduleAnalysisOfOpenFiles(projects, triggerType); } } }); } public static void scheduleAnalysisOfOpenFilesInBoundProjects(Job job, IServer server, TriggerType triggerType) { scheduleAnalysisOfOpenFiles(job, server.getBoundProjects(), triggerType); } abstract static class JobCompletionListener implements IJobChangeListener { @Override public void aboutToRun(IJobChangeEvent event) { // nothing to do } @Override public void awake(IJobChangeEvent event) { // nothing to do } @Override public void running(IJobChangeEvent event) { // nothing to do } @Override public void scheduled(IJobChangeEvent event) { // nothing to do } @Override public void sleeping(IJobChangeEvent event) { // nothing to do } } public static void notifyServerViewAfterBindingChange(ISonarLintProject sonarProject, @Nullable String oldServerId) { SonarLintProjectConfiguration projectConfig = SonarLintProjectConfiguration.read(sonarProject.getScopeContext()); String serverId = projectConfig.getServerId(); if (oldServerId != null && !Objects.equals(serverId, oldServerId)) { IServer oldServer = SonarLintCorePlugin.getServersManager().getServer(oldServerId); if (oldServer != null) { oldServer.notifyAllListeners(); } } if (serverId != null) { IServer server = SonarLintCorePlugin.getServersManager().getServer(serverId); if (server != null) { server.notifyAllListeners(); } } IBaseLabelProvider labelProvider = PlatformUI.getWorkbench().getDecoratorManager().getBaseLabelProvider(SonarLintProjectDecorator.ID); if (labelProvider != null) { ((SonarLintProjectDecorator) labelProvider).fireChange(Arrays.asList(sonarProject)); } } }