blob: e98211f8734a2f141f58b1d5cf7916be17bfd14b [file] [log] [blame]
/*
* Copyright 2000-2014 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.externalSystem.service.notification;
import com.intellij.ide.IdeTooltipManager;
import com.intellij.ide.errorTreeView.*;
import com.intellij.notification.Notification;
import com.intellij.notification.NotificationListener;
import com.intellij.openapi.actionSystem.*;
import com.intellij.pom.Navigatable;
import com.intellij.ui.*;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
import javax.swing.text.AttributeSet;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.Style;
import javax.swing.text.StyleConstants;
import javax.swing.text.html.HTML;
import javax.swing.text.html.HTMLDocument;
import javax.swing.tree.TreeCellEditor;
import javax.swing.tree.TreePath;
import java.awt.*;
import java.util.Map;
/**
* @author Vladislav.Soroka
* @since 3/24/2014
*/
public class EditableNotificationMessageElement extends NotificationMessageElement implements EditableMessageElement {
@NotNull private final TreeCellEditor myRightTreeCellEditor;
@NotNull private final Notification myNotification;
@NotNull private final Map<String/*url*/, String/*link text to replace*/> disabledLinks;
public EditableNotificationMessageElement(@NotNull Notification notification,
@NotNull ErrorTreeElementKind kind,
@Nullable GroupingElement parent,
String[] message,
Navigatable navigatable,
String exportText, String rendererTextPrefix) {
super(kind, parent, message, navigatable, exportText, rendererTextPrefix);
myNotification = notification;
disabledLinks = ContainerUtil.newHashMap();
myRightTreeCellEditor = new MyCellEditor();
}
public void addDisabledLink(@NotNull String url, @Nullable String text) {
disabledLinks.put(url, text);
}
@NotNull
@Override
public TreeCellEditor getRightSelfEditor() {
return myRightTreeCellEditor;
}
@Override
public boolean startEditingOnMouseMove() {
return true;
}
public static void disableLink(@NotNull HyperlinkEvent event) {
disableLink(event, null);
}
private static void disableLink(@NotNull final HyperlinkEvent event, @Nullable final String linkText) {
if (event.getSource() instanceof MyJEditorPane) {
UIUtil.invokeLaterIfNeeded(new Runnable() {
@Override
public void run() {
final MyJEditorPane editorPane = (MyJEditorPane)event.getSource();
editorPane.myElement.addDisabledLink(event.getDescription(), linkText);
editorPane.myElement.updateStyle(editorPane, null, null, true, false);
}
});
}
}
protected void updateStyle(@NotNull JEditorPane editorPane, @Nullable JTree tree, Object value, boolean selected, boolean hasFocus) {
super.updateStyle(editorPane, tree, value, selected, hasFocus);
final HTMLDocument htmlDocument = (HTMLDocument)editorPane.getDocument();
final Style linkStyle = htmlDocument.getStyleSheet().getStyle(LINK_STYLE);
StyleConstants.setForeground(linkStyle, IdeTooltipManager.getInstance().getLinkForeground(false));
StyleConstants.setItalic(linkStyle, true);
HTMLDocument.Iterator iterator = htmlDocument.getIterator(HTML.Tag.A);
while (iterator.isValid()) {
boolean disabledLink = false;
final AttributeSet attributes = iterator.getAttributes();
if (attributes instanceof SimpleAttributeSet) {
final Object attribute = attributes.getAttribute(HTML.Attribute.HREF);
if (attribute instanceof String && disabledLinks.containsKey(attribute)) {
disabledLink = true;
//TODO [Vlad] add support for disabled link text update
////final String linkText = disabledLinks.get(attribute);
//if (linkText != null) {
//}
((SimpleAttributeSet)attributes).removeAttribute(HTML.Attribute.HREF);
}
if (attribute == null) {
disabledLink = true;
}
}
if (!disabledLink) {
htmlDocument.setCharacterAttributes(
iterator.getStartOffset(), iterator.getEndOffset() - iterator.getStartOffset(), linkStyle, false);
}
iterator.next();
}
}
private static class MyJEditorPane extends JEditorPane {
@NotNull
private final EditableNotificationMessageElement myElement;
public MyJEditorPane(@NotNull EditableNotificationMessageElement element) {
myElement = element;
}
}
private class MyCellEditor extends AbstractCellEditor implements TreeCellEditor {
private final JEditorPane editorComponent;
@Nullable
private JTree myTree;
private MyCellEditor() {
editorComponent = installJep(new MyJEditorPane(EditableNotificationMessageElement.this));
HyperlinkListener hyperlinkListener = new ActivatedHyperlinkListener();
editorComponent.addHyperlinkListener(hyperlinkListener);
editorComponent.addMouseListener(new PopupHandler() {
@Override
public void invokePopup(Component comp, int x, int y) {
if (myTree == null) return;
final TreePath path = myTree.getLeadSelectionPath();
if (path == null) {
return;
}
DefaultActionGroup group = new DefaultActionGroup();
group.add(ActionManager.getInstance().getAction(IdeActions.ACTION_EDIT_SOURCE));
group.add(ActionManager.getInstance().getAction(IdeActions.ACTION_COPY));
ActionPopupMenu menu = ActionManager.getInstance().createActionPopupMenu(ActionPlaces.COMPILER_MESSAGES_POPUP, group);
menu.getComponent().show(comp, x, y);
}
});
}
@Override
public Component getTreeCellEditorComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row) {
myTree = tree;
updateStyle(editorComponent, tree, value, selected, false);
return editorComponent;
}
@Override
public Object getCellEditorValue() {
return null;
}
private class ActivatedHyperlinkListener implements HyperlinkListener {
@Override
public void hyperlinkUpdate(HyperlinkEvent e) {
if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
final NotificationListener notificationListener = myNotification.getListener();
if (notificationListener != null) {
notificationListener.hyperlinkUpdate(myNotification, e);
}
}
}
}
}
}