com.headwire.aem.tooling.intellij.console.ConsoleLogConsole.java Source code

Java tutorial

Introduction

Here is the source code for com.headwire.aem.tooling.intellij.console.ConsoleLogConsole.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.headwire.aem.tooling.intellij.console;

import com.intellij.execution.filters.HyperlinkInfo;
import com.intellij.execution.impl.ConsoleViewUtil;
import com.intellij.execution.impl.EditorHyperlinkSupport;
import com.intellij.execution.ui.ConsoleViewContentType;
import com.intellij.icons.AllIcons;
import com.intellij.notification.Notification;
import com.intellij.notification.NotificationType;
import com.intellij.notification.impl.NotificationsManagerImpl;
import com.intellij.openapi.actionSystem.ActionGroup;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.ActionPlaces;
import com.intellij.openapi.actionSystem.ActionPopupMenu;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
import com.intellij.openapi.actionSystem.IdeActions;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.EditorFactory;
import com.intellij.openapi.editor.ScrollType;
import com.intellij.openapi.editor.colors.EditorColorsManager;
import com.intellij.openapi.editor.colors.TextAttributesKey;
import com.intellij.openapi.editor.event.EditorMouseEvent;
import com.intellij.openapi.editor.ex.EditorMarkupModel;
import com.intellij.openapi.editor.markup.HighlighterLayer;
import com.intellij.openapi.editor.markup.HighlighterTargetArea;
import com.intellij.openapi.editor.markup.MarkupModel;
import com.intellij.openapi.editor.markup.RangeHighlighter;
import com.intellij.openapi.editor.markup.TextAttributes;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.project.ProjectManagerAdapter;
import com.intellij.openapi.util.NotNullLazyValue;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.ui.JBColor;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.util.EditorPopupHandler;
import com.intellij.util.text.DateFormatUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.swing.SwingUtilities;
import java.awt.Color;
import java.awt.Font;
import java.awt.Point;
import java.awt.Window;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by Andreas Schaefer (Headwire.com) on 5/6/15.
 */
public class ConsoleLogConsole {
    private final NotNullLazyValue<Editor> myLogEditor = new NotNullLazyValue<Editor>() {
        @NotNull
        @Override
        protected Editor compute() {
            return createLogEditor();
        }
    };

    private final NotNullLazyValue<EditorHyperlinkSupport> myHyperlinkSupport = new NotNullLazyValue<EditorHyperlinkSupport>() {
        @NotNull
        @Override
        protected EditorHyperlinkSupport compute() {
            return new EditorHyperlinkSupport(myLogEditor.getValue(), myProjectModel.getProject());
        }
    };
    private final ConsoleLogModel myProjectModel;

    ConsoleLogConsole(ConsoleLogModel model) {
        myProjectModel = model;
    }

    private Editor createLogEditor() {
        Project project = myProjectModel.getProject();
        final Editor editor = ConsoleViewUtil.setupConsoleEditor(project, false, false);
        myProjectModel.getProject().getMessageBus().connect().subscribe(ProjectManager.TOPIC,
                new ProjectManagerAdapter() {
                    @Override
                    public void projectClosed(Project project) {
                        if (project == myProjectModel.getProject()) {
                            EditorFactory.getInstance().releaseEditor(editor);
                        }
                    }
                });

        ((EditorMarkupModel) editor.getMarkupModel()).setErrorStripeVisible(true);

        final ClearLogAction clearLog = new ClearLogAction(this);
        clearLog.registerCustomShortcutSet(
                ActionManager.getInstance().getAction(IdeActions.CONSOLE_CLEAR_ALL).getShortcutSet(),
                editor.getContentComponent());

        editor.addEditorMouseListener(new EditorPopupHandler() {
            public void invokePopup(final EditorMouseEvent event) {
                final ActionManager actionManager = ActionManager.getInstance();
                final ActionPopupMenu menu = actionManager.createActionPopupMenu(ActionPlaces.EDITOR_POPUP,
                        createPopupActions(actionManager, clearLog));
                final MouseEvent mouseEvent = event.getMouseEvent();
                menu.getComponent().show(mouseEvent.getComponent(), mouseEvent.getX(), mouseEvent.getY());
            }
        });
        return editor;
    }

    private DefaultActionGroup createPopupActions(ActionManager actionManager, ClearLogAction action) {
        AnAction[] children = ((ActionGroup) actionManager.getAction(IdeActions.GROUP_CONSOLE_EDITOR_POPUP))
                .getChildren(null);
        DefaultActionGroup group = new DefaultActionGroup(children);
        group.addSeparator();
        group.add(action);
        return group;
    }

    void doPrintNotification(final Notification notification) {
        Editor editor = myLogEditor.getValue();
        if (editor.isDisposed()) {
            return;
        }

        Document document = editor.getDocument();
        boolean scroll = document.getTextLength() == editor.getCaretModel().getOffset()
                || !editor.getContentComponent().hasFocus();

        Long notificationTime = myProjectModel.getNotificationTime(notification);
        if (notificationTime == null) {
            return;
        }

        String date = DateFormatUtil.formatTimeWithSeconds(notificationTime) + " ";
        append(document, date);

        int startLine = document.getLineCount() - 1;

        ConsoleLog.LogEntry pair = ConsoleLog.formatForLog(notification,
                StringUtil.repeatSymbol(' ', date.length()));

        final NotificationType type = notification.getType();
        TextAttributesKey key = type == NotificationType.ERROR ? ConsoleViewContentType.LOG_ERROR_OUTPUT_KEY
                : type == NotificationType.INFORMATION ? ConsoleViewContentType.NORMAL_OUTPUT_KEY
                        : ConsoleViewContentType.LOG_WARNING_OUTPUT_KEY;

        int msgStart = document.getTextLength();
        String message = pair.message;
        append(document, message);

        TextAttributes attributes = EditorColorsManager.getInstance().getGlobalScheme().getAttributes(key);
        int layer = HighlighterLayer.CARET_ROW + 1;
        editor.getMarkupModel().addRangeHighlighter(msgStart, document.getTextLength(), layer, attributes,
                HighlighterTargetArea.EXACT_RANGE);

        for (Pair<TextRange, HyperlinkInfo> link : pair.links) {
            final RangeHighlighter rangeHighlighter = myHyperlinkSupport.getValue().createHyperlink(
                    link.first.getStartOffset() + msgStart, link.first.getEndOffset() + msgStart, null,
                    link.second);
            if (link.second instanceof ConsoleLog.ShowBalloon) {
                ((ConsoleLog.ShowBalloon) link.second).setRangeHighlighter(rangeHighlighter);
            }
        }

        append(document, "\n");

        if (scroll) {
            editor.getCaretModel().moveToOffset(document.getTextLength());
            editor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE);
        }

        if (notification.isImportant()) {
            highlightNotification(notification, pair.status, startLine, document.getLineCount() - 1);
        }
    }

    private void highlightNotification(final Notification notification, String message, final int line1,
            final int line2) {

        final MarkupModel markupModel = myLogEditor.getValue().getMarkupModel();
        TextAttributes bold = new TextAttributes(null, null, null, null, Font.BOLD);
        final List<RangeHighlighter> lineColors = new ArrayList<RangeHighlighter>();
        for (int line = line1; line < line2; line++) {
            final RangeHighlighter lineHighlighter = markupModel.addLineHighlighter(line,
                    HighlighterLayer.CARET_ROW + 1, bold);
            Color color = notification.getType() == NotificationType.ERROR ? JBColor.RED
                    : notification.getType() == NotificationType.WARNING ? JBColor.YELLOW : JBColor.GREEN;
            lineHighlighter.setErrorStripeMarkColor(color);
            lineHighlighter.setErrorStripeTooltip(message);
            lineColors.add(lineHighlighter);

        }

        final Document document = myLogEditor.getValue().getDocument();

        final Runnable removeHandler = new Runnable() {
            @Override
            public void run() {
                TextAttributes expired = EditorColorsManager.getInstance().getGlobalScheme()
                        .getAttributes(ConsoleViewContentType.LOG_EXPIRED_ENTRY);
                TextAttributes italic = new TextAttributes(null, null, null, null, Font.ITALIC);
                for (RangeHighlighter colorHighlighter : lineColors) {
                    if (colorHighlighter.isValid()) {
                        int line = document.getLineNumber(colorHighlighter.getStartOffset());

                        markupModel.addLineHighlighter(line, HighlighterLayer.CARET_ROW + 1, expired);

                        for (RangeHighlighter highlighter : myHyperlinkSupport.getValue()
                                .findAllHyperlinksOnLine(line)) {
                            markupModel.addRangeHighlighter(highlighter.getStartOffset(),
                                    highlighter.getEndOffset(), HighlighterLayer.CARET_ROW + 2, italic,
                                    HighlighterTargetArea.EXACT_RANGE);
                            myHyperlinkSupport.getValue().removeHyperlink(highlighter);
                        }
                    }
                    markupModel.removeHighlighter(colorHighlighter);
                }
            }
        };
        if (!notification.isExpired()) {
            myProjectModel.removeHandlers.put(notification, removeHandler);
        } else {
            removeHandler.run();
        }
    }

    public Editor getConsoleEditor() {
        return myLogEditor.getValue();
    }

    @Nullable
    public RelativePoint getRangeHighlighterLocation(RangeHighlighter range) {
        Editor editor = myLogEditor.getValue();
        Project project = editor.getProject();
        Window window = NotificationsManagerImpl.findWindowForBalloon(project);
        if (range != null && window != null) {
            Point point = editor.visualPositionToXY(editor.offsetToVisualPosition(range.getStartOffset()));
            return new RelativePoint(window,
                    SwingUtilities.convertPoint(editor.getContentComponent(), point, window));
        }
        return null;
    }

    private static void append(Document document, String s) {
        document.insertString(document.getTextLength(), s);
    }

    public static class ClearLogAction extends DumbAwareAction {
        private ConsoleLogConsole myConsole;

        public ClearLogAction(ConsoleLogConsole console) {
            super("Clear All", "Clear the contents of the Event Log", AllIcons.Actions.GC);
            myConsole = console;
        }

        @Override
        public void update(AnActionEvent e) {
            Editor editor = e.getData(CommonDataKeys.EDITOR);
            e.getPresentation().setEnabled(editor != null && editor.getDocument().getTextLength() > 0);
        }

        public void actionPerformed(final AnActionEvent e) {
            ConsoleLogModel model = myConsole.myProjectModel;
            for (Notification notification : model.getNotifications()) {
                notification.expire();
                model.removeNotification(notification);
            }
            model.setStatusMessage(null, 0);
            final Editor editor = e.getData(CommonDataKeys.EDITOR);
            if (editor != null) {
                editor.getDocument().deleteString(0, editor.getDocument().getTextLength());
            }
        }
    }
}