Java tutorial
/* * Copyright 2016 The Bazel Authors. All rights reserved. * * 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.google.idea.blaze.clwb.problemsview; import com.google.idea.blaze.base.scope.output.IssueOutput; import com.google.idea.blaze.base.ui.BlazeProblemsView; import com.intellij.icons.AllIcons; import com.intellij.ide.errorTreeView.ErrorTreeElement; import com.intellij.ide.errorTreeView.ErrorTreeElementKind; import com.intellij.ide.errorTreeView.ErrorViewStructure; import com.intellij.ide.errorTreeView.GroupingElement; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.fileEditor.OpenFileDescriptor; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.IconLoader; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.wm.ToolWindow; import com.intellij.openapi.wm.ToolWindowManager; import com.intellij.pom.Navigatable; import com.intellij.ui.content.Content; import com.intellij.ui.content.ContentFactory; import com.intellij.util.ArrayUtil; import com.intellij.util.concurrency.SequentialTaskExecutor; import com.intellij.util.ui.MessageCategory; import com.intellij.util.ui.UIUtil; import java.util.ArrayList; import java.util.EnumSet; import java.util.List; import java.util.StringTokenizer; import java.util.UUID; import javax.swing.Icon; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.ide.PooledThreadExecutor; /** CLion has no built-in 'Problems' view, so we mostly duplicate the IntelliJ code here. */ public class BlazeProblemsViewConsole implements BlazeProblemsView { private static final Logger LOG = Logger.getInstance(BlazeProblemsViewConsole.class); private static final String BLAZE_PROBLEMS_TOOLWINDOW_ID = "Blaze Problems"; private static final EnumSet<ErrorTreeElementKind> ALL_MESSAGE_KINDS = EnumSet .allOf(ErrorTreeElementKind.class); private final ProblemsViewPanel myPanel; private final SequentialTaskExecutor myViewUpdater = new SequentialTaskExecutor(PooledThreadExecutor.INSTANCE); private final Icon myActiveIcon = AllIcons.Toolwindows.Problems; private final Icon myPassiveIcon = IconLoader.getDisabledIcon(myActiveIcon); private final Project myProject; public static BlazeProblemsViewConsole getImpl(Project project) { BlazeProblemsViewConsole blazeProblemsViewConsole = (BlazeProblemsViewConsole) ServiceManager .getService(project, BlazeProblemsView.class); LOG.assertTrue(blazeProblemsViewConsole != null); return blazeProblemsViewConsole; } public BlazeProblemsViewConsole(final Project project) { myProject = project; myPanel = new ProblemsViewPanel(project); Disposer.register(project, () -> Disposer.dispose(myPanel)); updateIcon(); } public void createToolWindowContent(ToolWindow toolWindow) { final Content content = ContentFactory.SERVICE.getInstance().createContent(myPanel, "", false); toolWindow.getContentManager().addContent(content); Disposer.register(myProject, () -> toolWindow.getContentManager().removeAllContents(true)); updateIcon(); } @Override public final void addMessage(IssueOutput issue, @NotNull UUID sessionId) { final VirtualFile file = issue.getFile() != null ? VfsUtil.findFileByIoFile(issue.getFile(), true /* refresh */) : null; Navigatable navigatable = issue.getNavigatable(); if (navigatable == null && file != null) { // convert 1-indexed line/column numbers to 0-indexed navigatable = new OpenFileDescriptor(myProject, file, issue.getLine() - 1, issue.getColumn() - 1); } final IssueOutput.Category category = issue.getCategory(); final int type = translateCategory(category); final String[] text = convertMessage(issue); final String groupName = file != null ? file.getPresentableUrl() : category.name(); addMessage(type, text, groupName, navigatable, getExportTextPrefix(issue), getRenderTextPrefix(issue), sessionId); } private static int translateCategory(IssueOutput.Category category) { switch (category) { case ERROR: return MessageCategory.ERROR; case WARNING: return MessageCategory.WARNING; case STATISTICS: return MessageCategory.STATISTICS; case INFORMATION: return MessageCategory.INFORMATION; default: LOG.error("Unknown message category: " + category); return 0; } } private static String[] convertMessage(final IssueOutput issue) { String text = issue.getMessage(); if (!text.contains("\n")) { return new String[] { text }; } final List<String> lines = new ArrayList<String>(); StringTokenizer tokenizer = new StringTokenizer(text, "\n", false); while (tokenizer.hasMoreTokens()) { lines.add(tokenizer.nextToken()); } return ArrayUtil.toStringArray(lines); } private static String getExportTextPrefix(IssueOutput issue) { int line = issue.getLine(); if (line >= 0) { return String.format("line: %d", line); } return ""; } private static String getRenderTextPrefix(IssueOutput issue) { int line = issue.getLine(); if (line >= 0) { return String.format("(%d, %d)", line, issue.getColumn()); } return ""; } @Override public void clearOldMessages(@NotNull final UUID currentSessionId) { myViewUpdater.execute(new Runnable() { @Override public void run() { cleanupChildrenRecursively(myPanel.getErrorViewStructure().getRootElement(), currentSessionId); updateIcon(); myPanel.reload(); } }); } private void cleanupChildrenRecursively(@NotNull final Object fromElement, @NotNull UUID currentSessionId) { final ErrorViewStructure structure = myPanel.getErrorViewStructure(); for (ErrorTreeElement element : structure.getChildElements(fromElement)) { if (element instanceof GroupingElement) { if (!currentSessionId.equals(element.getData())) { structure.removeElement(element); } else { cleanupChildrenRecursively(element, currentSessionId); } } else { if (!currentSessionId.equals(element.getData())) { structure.removeElement(element); } } } } public void addMessage(final int type, @NotNull final String[] text, @Nullable final String groupName, @Nullable final Navigatable navigatable, @Nullable final String exportTextPrefix, @Nullable final String rendererTextPrefix, @Nullable final UUID sessionId) { myViewUpdater.execute(() -> { final ErrorViewStructure structure = myPanel.getErrorViewStructure(); final GroupingElement group = structure.lookupGroupingElement(groupName); if (group != null && sessionId != null && !sessionId.equals(group.getData())) { structure.removeElement(group); } if (navigatable != null) { myPanel.addMessage(type, text, groupName, navigatable, exportTextPrefix, rendererTextPrefix, sessionId); } else { myPanel.addMessage(type, text, null, -1, -1, sessionId); } updateIcon(); }); } private void updateIcon() { UIUtil.invokeLaterIfNeeded(() -> { if (!myProject.isDisposed()) { final ToolWindow tw = ToolWindowManager.getInstance(myProject) .getToolWindow(BLAZE_PROBLEMS_TOOLWINDOW_ID); if (tw != null) { final boolean active = myPanel.getErrorViewStructure().hasMessages(ALL_MESSAGE_KINDS); tw.setIcon(active ? myActiveIcon : myPassiveIcon); if (active) { tw.show(null); } } } }); } public void setProgress(String text, float fraction) { myPanel.setProgress(text, fraction); } public void setProgress(String text) { myPanel.setProgressText(text); } public void clearProgress() { myPanel.clearProgressData(); } }