IDEA-149210 Rework IDE notifications

This commit is contained in:
Alexander Lobas
2016-03-23 23:28:55 +03:00
parent 44fff2bed7
commit 5047448771
8 changed files with 104 additions and 81 deletions
@@ -188,7 +188,7 @@ public class LinkLabel<T> extends JLabel {
private final JBRectangle textR = new JBRectangle();
private final JBRectangle viewR = new JBRectangle();
private boolean isInClickableArea(Point pt) {
protected boolean isInClickableArea(Point pt) {
iconR.clear();
textR.clear();
final Insets insets = getInsets(null);
@@ -34,7 +34,6 @@ import com.intellij.openapi.ui.popup.Balloon;
import com.intellij.openapi.util.*;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.wm.*;
import com.intellij.openapi.wm.impl.IdeFrameImpl;
import com.intellij.ui.BalloonLayoutData;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.ui.content.Content;
@@ -49,9 +48,7 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.event.HyperlinkEvent;
import java.awt.*;
import java.util.*;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -93,14 +90,8 @@ public class EventLog {
}
}
public static void showNotification(@NotNull String groupId, @NotNull String id) {
Window frame = IdeFrameImpl.getActiveFrame();
if (frame instanceof IdeFrame) {
Project project = ((IdeFrame)frame).getProject();
if (project != null) {
getProjectComponent(project).showNotification(groupId, id);
}
}
public static void showNotification(@NotNull Project project, @NotNull String groupId, @NotNull String id) {
getProjectComponent(project).showNotification(groupId, id);
}
private static EventLog getApplicationComponent() {
@@ -478,7 +469,7 @@ public class EventLog {
});
}
void showNotification(@NotNull final String groupId, @NotNull final String id) {
private void showNotification(@NotNull final String groupId, @NotNull final String id) {
ToolWindow eventLog = getEventLog(myProject);
if (eventLog != null) {
activate(eventLog, groupId, new Runnable() {
@@ -30,4 +30,7 @@ public class NotificationGroupBean extends AbstractExtensionPointBean {
@Attribute("replaceTitle")
public String replaceTitle;
@Attribute("shortTitle")
public String shortTitle;
}
@@ -35,6 +35,7 @@ public class NotificationParentGroup {
private static Map<NotificationParentGroupBean, List<NotificationParentGroupBean>> myChildren;
private static Map<String, NotificationParentGroupBean> myGroupToParent;
private static Map<String, String> myReplaceTitles;
private static Map<String, String> myShortTitles;
private static void prepareInfo() {
if (myParents == null) {
@@ -60,6 +61,7 @@ public class NotificationParentGroup {
myGroupToParent = new HashMap<>();
myReplaceTitles = new HashMap<>();
myShortTitles = new HashMap<>();
for (NotificationGroupBean bean : EP_CHILD_NAME.getExtensions()) {
NotificationParentGroupBean parent = myParents.get(bean.parentId);
if (parent != null) {
@@ -68,6 +70,9 @@ public class NotificationParentGroup {
if (bean.replaceTitle != null) {
myReplaceTitles.put(bean.groupId, bean.replaceTitle);
}
if (bean.shortTitle != null) {
myShortTitles.put(bean.groupId, bean.shortTitle);
}
}
}
}
@@ -79,6 +84,12 @@ public class NotificationParentGroup {
return myReplaceTitles.get(groupId);
}
@Nullable
public static String getShortTitle(@NotNull String groupId) {
prepareInfo();
return myShortTitles.get(groupId);
}
@NotNull
public static List<NotificationParentGroupBean> getChildren(@NotNull NotificationParentGroupBean parent) {
prepareInfo();
@@ -50,8 +50,10 @@ import com.intellij.ui.components.labels.LinkListener;
import com.intellij.ui.components.panels.HorizontalLayout;
import com.intellij.ui.components.panels.NonOpaquePanel;
import com.intellij.util.ArrayUtil;
import com.intellij.util.FontUtil;
import com.intellij.util.Function;
import com.intellij.util.IconUtil;
import com.intellij.util.ui.AbstractLayoutManager;
import com.intellij.util.ui.ButtonlessScrollBarUI;
import com.intellij.util.ui.JBUI;
import com.intellij.util.ui.UIUtil;
@@ -68,6 +70,7 @@ import javax.swing.text.BadLocationException;
import java.awt.*;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.geom.Rectangle2D;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
@@ -249,7 +252,7 @@ public class NotificationsManagerImpl extends NotificationsManager {
layoutDataRef.set(layoutData);
}
else {
List<BalloonLayoutData.MergeInfo> mergeData = ((BalloonLayoutImpl)layout).preMerge(notification);
BalloonLayoutData.MergeInfo mergeData = ((BalloonLayoutImpl)layout).preMerge(notification);
if (mergeData != null) {
BalloonLayoutData layoutData = new BalloonLayoutData();
layoutData.mergeData = mergeData;
@@ -494,7 +497,6 @@ public class NotificationsManagerImpl extends NotificationsManager {
if (NotificationsConfigurationImpl.getSettings(notification.getGroupId()).isShouldLog()) {
layoutData.groupId = notification.getGroupId();
layoutData.id = notification.id;
layoutData.status = EventLog.formatForLog(notification, "").status;
}
}
else {
@@ -502,7 +504,7 @@ public class NotificationsManagerImpl extends NotificationsManager {
}
layoutDataRef.set(layoutData);
boolean actions = !notification.getActions().isEmpty() || layoutData.mergeData != null;
boolean actions = !notification.getActions().isEmpty();
boolean showFullContent = layoutData.showFullContent || notification instanceof NotificationActionProvider;
Color foregroundR = Gray._0;
@@ -732,7 +734,11 @@ public class NotificationsManagerImpl extends NotificationsManager {
}
if (buttons == null && actions) {
createActionPanel(notification, layoutData.mergeData, centerPanel, layoutData.configuration.actionGap);
createActionPanel(notification, centerPanel, layoutData.configuration.actionGap);
}
if (layoutData.mergeData != null) {
createMergeAction(layoutData, content);
}
text.setSize(text.getPreferredSize());
@@ -775,10 +781,7 @@ public class NotificationsManagerImpl extends NotificationsManager {
return balloon;
}
private static void createActionPanel(@NotNull final Notification notification,
@Nullable final List<BalloonLayoutData.MergeInfo> mergeData,
@NotNull JPanel centerPanel,
int gap) {
private static void createActionPanel(@NotNull final Notification notification, @NotNull JPanel centerPanel, int gap) {
JPanel actionPanel = new NonOpaquePanel(new HorizontalLayout(gap, SwingConstants.CENTER));
centerPanel.add(BorderLayout.SOUTH, actionPanel);
@@ -815,45 +818,61 @@ public class NotificationsManagerImpl extends NotificationsManager {
}
}, action));
}
}
if (mergeData != null) {
final int size = mergeData.size();
if (size == 1) {
actionPanel.add(
HorizontalLayout.RIGHT,
new LinkLabel<BalloonLayoutData.MergeInfo>("History", null, new LinkListener<BalloonLayoutData.MergeInfo>() {
@Override
public void linkSelected(LinkLabel aSource, BalloonLayoutData.MergeInfo info) {
EventLog.showNotification(info.groupId, info.id);
}
}, mergeData.get(0)) {
@Override
protected String getStatusBarText() {
return getLinkData().status;
}
});
}
else {
actionPanel.add(
HorizontalLayout.RIGHT,
new DropDownAction("History", new LinkListener<Void>() {
@Override
public void linkSelected(LinkLabel link, Void aLinkData) {
DefaultActionGroup group = new DefaultActionGroup();
for (int i = 0; i < size; i++) {
BalloonLayoutData.MergeInfo info = mergeData.get(i);
group.add(new AnAction(String.valueOf(i + 1), info.status, null) {
@Override
public void actionPerformed(AnActionEvent e) {
EventLog.showNotification(info.groupId, info.id);
}
});
}
showPopup(link, group);
}
}));
}
private static void createMergeAction(@NotNull final BalloonLayoutData layoutData, @NotNull JPanel panel) {
StringBuilder title = new StringBuilder().append(layoutData.mergeData.count).append(" more");
String shortTitle = NotificationParentGroup.getShortTitle(layoutData.groupId);
if (shortTitle != null) {
title.append(" from ").append(shortTitle);
}
LinkLabel<BalloonLayoutData> action = new LinkLabel<BalloonLayoutData>(
title.toString(), null,
new LinkListener<BalloonLayoutData>() {
@Override
public void linkSelected(LinkLabel aSource, BalloonLayoutData layoutData) {
EventLog.showNotification(layoutData.project, layoutData.groupId, layoutData.mergeData.linkId);
}
}, layoutData) {
@Override
protected boolean isInClickableArea(Point pt) {
return true;
}
@Override
protected Color getTextColor() {
return new JBColor(0x666666, 0x8C8C8C);
}
};
action.setFont(FontUtil.minusOne(action.getFont()));
action.setHorizontalAlignment(SwingConstants.CENTER);
action.setPaintUnderline(false);
AbstractLayoutManager layout = new AbstractLayoutManager() {
@Override
public Dimension preferredLayoutSize(Container parent) {
return new Dimension(parent.getWidth(), JBUI.scale(20) + 2);
}
@Override
public void layoutContainer(Container parent) {
parent.getComponent(0).setBounds(2, 1, parent.getWidth() - 4, JBUI.scale(20));
}
};
JPanel mergePanel = new NonOpaquePanel(layout) {
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(new JBColor(0xE3E3E3, 0x3A3C3D));
((Graphics2D)g).fill(new Rectangle2D.Double(1.5, 1, getWidth() - 2.5, getHeight() - 2));
g.setColor(new JBColor(0xDBDBDB, 0x353738));
((Graphics2D)g).draw(new Rectangle2D.Double(2, 0, getWidth() - 3.5, 0.5));
}
};
mergePanel.add(action);
panel.add(BorderLayout.SOUTH, mergePanel);
}
public static int calculateContentHeight(int lines) {
@@ -17,8 +17,7 @@ package com.intellij.ui;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Computable;
import java.util.List;
import org.jetbrains.annotations.NotNull;
/**
* @author Alexander Lobas
@@ -26,8 +25,7 @@ import java.util.List;
public class BalloonLayoutData {
public String groupId;
public String id;
public String status;
public List<MergeInfo> mergeData;
public MergeInfo mergeData;
public boolean showFullContent;
@@ -50,17 +48,18 @@ public class BalloonLayoutData {
public Runnable lafHandler;
public MergeInfo getMergeInfo() {
MergeInfo info = new MergeInfo();
info.groupId = groupId;
info.id = id;
info.status = status;
return info;
@NotNull
public MergeInfo merge() {
return mergeData == null ? new MergeInfo(id, 1) : new MergeInfo(mergeData.linkId, mergeData.count + 1);
}
public static class MergeInfo {
public String groupId;
public String id;
public String status;
public String linkId;
public int count;
public MergeInfo(@NotNull String linkId, int count) {
this.linkId = linkId;
this.count = count;
}
}
}
@@ -109,6 +109,7 @@ public class BalloonLayoutImpl implements BalloonLayout {
Balloon merge = merge(layoutData);
if (merge == null) {
if (NotificationsManagerImpl.newEnabled() &&
getVisibleCount() > 0 &&
layoutData instanceof BalloonLayoutData &&
((BalloonLayoutData)layoutData).groupId != null) {
int index = -1;
@@ -123,7 +124,7 @@ public class BalloonLayoutImpl implements BalloonLayout {
}
}
if (count == getVisibleCount()) {
if (count > 0 && count == getVisibleCount()) {
remove(myBalloons.get(index));
}
}
@@ -186,17 +187,12 @@ public class BalloonLayoutImpl implements BalloonLayout {
}
@Nullable
public List<BalloonLayoutData.MergeInfo> preMerge(@NotNull Notification notification) {
public BalloonLayoutData.MergeInfo preMerge(@NotNull Notification notification) {
Balloon balloon = merge(notification.getGroupId());
if (balloon != null) {
BalloonLayoutData layoutData = myLayoutData.get(balloon);
if (layoutData != null) {
List<BalloonLayoutData.MergeInfo> mergeData = new ArrayList<>();
if (layoutData.mergeData != null) {
mergeData.addAll(layoutData.mergeData);
}
mergeData.add(layoutData.getMergeInfo());
return mergeData;
return layoutData.merge();
}
}
return null;
@@ -218,9 +214,8 @@ public class BalloonLayoutImpl implements BalloonLayout {
myBalloons.remove(balloon);
BalloonLayoutData layoutData = myLayoutData.remove(balloon);
if (layoutData != null) {
layoutData.id = null;
layoutData.groupId = null;
layoutData.status = null;
layoutData.id = null;
layoutData.mergeData = null;
}
if (hide) {
@@ -40,4 +40,9 @@ public class FontUtil {
public static String spaceAndThinSpace() {
return " " + canDisplay(UIUtil.getLabelFont(), '\u2009', " ");
}
@NotNull
public static Font minusOne(@NotNull Font font) {
return font.deriveFont(font.getSize() - 1f);
}
}