import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.startup.StartupManager;
import com.intellij.openapi.ui.popup.Balloon;
-import com.intellij.openapi.util.Pair;
-import com.intellij.openapi.util.ShutDownTracker;
-import com.intellij.openapi.util.TextRange;
-import com.intellij.openapi.util.Trinity;
+import com.intellij.openapi.util.*;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.wm.*;
+import com.intellij.ui.BalloonLayoutData;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.ui.content.Content;
import com.intellij.util.Function;
if (target != null) {
IdeFrame frame = WindowManager.getInstance().getIdeFrame(project);
assert frame != null;
- Balloon balloon = NotificationsManagerImpl.createBalloon(frame, myNotification, true, true, null, project);
+ Ref<Object> layoutDataRef = null;
+ if (NotificationsManagerImpl.newEnabled()) {
+ BalloonLayoutData layoutData = new BalloonLayoutData();
+ layoutData.showFullContent = true;
+ layoutData.showSettingButton = false;
+ layoutDataRef = new Ref<>(layoutData);
+ }
+ Balloon balloon = NotificationsManagerImpl.createBalloon(frame, myNotification, true, true, layoutDataRef, project);
balloon.show(target, Balloon.Position.above);
}
}
- private static void hideBalloon(Notification notification1) {
- Balloon balloon = notification1.getBalloon();
+ private static void hideBalloon(Notification notification) {
+ Balloon balloon = notification.getBalloon();
if (balloon != null) {
balloon.hide(true);
}
@Nullable Ref<Object> layoutDataRef,
@NotNull Disposable parentDisposable) {
if (layoutDataRef != null) {
- Balloon balloon = createNewBalloon(windowComponent, notification, showCallout, hideOnClickOutside, layoutDataRef);
- Disposer.register(parentDisposable, balloon);
- return balloon;
+ return createNewBalloon(windowComponent, notification, showCallout, hideOnClickOutside, layoutDataRef, parentDisposable);
}
final JEditorPane text = new JEditorPane();
@NotNull Notification notification,
boolean showCallout,
boolean hideOnClickOutside,
- @NotNull Ref<Object> layoutDataRef) {
- final BalloonLayoutData layoutData = new BalloonLayoutData();
+ @NotNull Ref<Object> layoutDataRef,
+ @NotNull Disposable parentDisposable) {
+ final BalloonLayoutData layoutData = layoutDataRef.isNull() ? new BalloonLayoutData() : (BalloonLayoutData)layoutDataRef.get();
layoutDataRef.set(layoutData);
+ boolean showFullContent = layoutData.showFullContent || notification instanceof NotificationActionProvider;
+
Color foregroundR = Gray._0;
Color foregroundD = Gray._191;
final Color foreground = new JBColor(foregroundR, foregroundD);
int prefSize = new JLabel(NotificationsUtil.buildHtml(notification, null, true, null, fontStyle)).getPreferredSize().width;
String style = prefSize > BalloonLayoutConfiguration.MaxWidth ? BalloonLayoutConfiguration.MaxWidthStyle : null;
+ if (layoutData.showFullContent) {
+ style = prefSize > BalloonLayoutConfiguration.MaxFullContentWidth ? BalloonLayoutConfiguration.MaxFullContentWidthStyle : null;
+ }
+
String textR = NotificationsUtil.buildHtml(notification, style, true, foregroundR, fontStyle);
String textD = NotificationsUtil.buildHtml(notification, style, true, foregroundD, fontStyle);
LafHandler lafHandler = new LafHandler(text, textR, textD);
layoutData.maxScrollHeight = Math.min(layoutData.fullHeight, calculateContentHeight(10));
layoutData.configuration = BalloonLayoutConfiguration.create(notification, layoutData);
- boolean showFullContent = notification instanceof NotificationActionProvider;
-
if (!showFullContent && layoutData.maxScrollHeight != layoutData.fullHeight) {
pane.setViewport(new GradientViewport(text, JBUI.insets(10, 0), true) {
@Nullable
new NotificationBalloonActionProvider(balloon, layout.getTitle(), layoutData, notification.getGroupId()));
}
+ Disposer.register(parentDisposable, balloon);
return balloon;
}
int actionWidth = actionSize.width + expandSize.width;
int width = Math.max(centerWidth, Math.max(titleWidth, actionWidth));
- width = Math.min(width, BalloonLayoutConfiguration.MaxWidth);
+ if (!myLayoutData.showFullContent) {
+ width = Math.min(width, BalloonLayoutConfiguration.MaxWidth);
+ }
width = Math.max(width, BalloonLayoutConfiguration.MinWidth);
return new Dimension(width, height);
private Rectangle myForcedBounds;
- //private CloseButton myCloseRec;
private ActionProvider myActionProvider;
+ private List<ActionButton> myActionButtons;
private final AWTEventListener myAwtActivityListener = new AWTEventListener() {
@Override
if (!cmp.isShowing()) return true;
if (cmp instanceof MenuElement) return false;
- for (ActionButton button : myActionProvider.getActions()) {
- if (cmp == button) return true;
+ if (myActionButtons != null) {
+ for (ActionButton button : myActionButtons) {
+ if (cmp == button) return true;
+ }
}
if (UIUtil.isDescendingFrom(cmp, myComp)) return true;
if (myComp == null || !myComp.isShowing()) return false;
@Override
public void show(final RelativePoint target, final Balloon.Position position) {
- AbstractPosition pos = getAbstractPositionFor(position);
-
- show(target, pos);
+ show(target, getAbstractPositionFor(position));
}
public int getLayer() {
}
private static AbstractPosition getAbstractPositionFor(Position position) {
- AbstractPosition pos = BELOW;
switch (position) {
case atLeft:
- pos = AT_LEFT;
- break;
+ return AT_LEFT;
case atRight:
- pos = AT_RIGHT;
- break;
+ return AT_RIGHT;
case below:
- pos = BELOW;
- break;
+ return BELOW;
case above:
- pos = ABOVE;
- break;
+ return ABOVE;
+ default:
+ return BELOW;
}
- return pos;
}
@Override
public void show(PositionTracker<Balloon> tracker, Balloon.Position position) {
- AbstractPosition pos = BELOW;
- switch (position) {
- case atLeft:
- pos = AT_LEFT;
- break;
- case atRight:
- pos = AT_RIGHT;
- break;
- case below:
- pos = BELOW;
- break;
- case above:
- pos = ABOVE;
- break;
- }
-
- show(tracker, pos);
+ show(tracker, getAbstractPositionFor(position));
}
private Insets getInsetsCopy() {
private Dimension getContentSizeFor(AbstractPosition position) {
Dimension size = myContent.getPreferredSize();
- JBInsets.addTo(size, position.createBorder(this).getBorderInsets());
+ if (myShadowBorderProvider == null) {
+ JBInsets.addTo(size, position.createBorder(this).getBorderInsets());
+ }
return size;
}
};
myActionProvider = new ActionProvider() {
- private ActionButton myCloseButton = new CloseButton(listener);
+ private ActionButton myCloseButton;
@NotNull
@Override
- public List<ActionButton> getActions() {
+ public List<ActionButton> createActions() {
+ myCloseButton = new CloseButton(listener);
return Collections.singletonList(myCloseButton);
}
void paintShadow(@NotNull JComponent component, @NotNull Graphics g);
void paintBorder(@NotNull Rectangle bounds, @NotNull Graphics2D g);
+
+ void paintPointingShape(@NotNull Rectangle bounds, @NotNull Point pointTarget, @NotNull Position position, @NotNull Graphics2D g);
}
@Override
Rectangle forcedBounds,
Dimension preferredSize,
boolean showPointer,
- Point point, Insets containerInsets) {
+ Point point,
+ Insets containerInsets) {
Rectangle bounds = forcedBounds;
if (balloon.myShadowBorderProvider != null) {
balloon.myShadowBorderProvider.paintBorder(bounds, g);
+ if (balloon.myShowPointer) {
+ Position position;
+ if (this == ABOVE) {
+ position = Position.above;
+ }
+ else if (this == BELOW) {
+ position = Position.below;
+ }
+ else if (this == AT_LEFT) {
+ position = Position.atLeft;
+ }
+ else {
+ position = Position.atRight;
+ }
+ balloon.myShadowBorderProvider.paintPointingShape(bounds, pointTarget, position, g);
+ }
cfg.restore();
return;
}
if (bounds.x < targetPoint.x &&
bounds.x + bounds.width > targetPoint.x &&
bounds.y < targetPoint.y &&
- bounds.y + bounds.height < targetPoint.y) {
+ bounds.y + bounds.height > targetPoint.y) {
return false;
}
public interface ActionProvider {
@NotNull
- List<ActionButton> getActions();
+ List<ActionButton> createActions();
void layout(@NotNull Rectangle bounds);
}
return;
}
- //noinspection SSBasedInspection
- SwingUtilities.invokeLater(new Runnable() {
- @Override
- public void run() {
- for (ActionButton button : myActionProvider.getActions()) {
- disposeButton(button);
+ final List<ActionButton> buttons = myActionButtons;
+ myActionButtons = null;
+ if (buttons != null) {
+ //noinspection SSBasedInspection
+ SwingUtilities.invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ for (ActionButton button : buttons) {
+ disposeButton(button);
+ }
}
- }
- });
+ });
+ }
}
public void setAlpha(float alpha) {
if (getParent() != null) {
- for (ActionButton button : myActionProvider.getActions()) {
+ if (myActionButtons == null) {
+ myActionButtons = myActionProvider.createActions();
+ }
+
+ for (ActionButton button : myActionButtons) {
if (button.getParent() == null) {
myLayeredPane.add(button);
myLayeredPane.setLayer(button, JLayeredPane.DRAG_LAYER);
if (isVisible()) {
Rectangle lpBounds = SwingUtilities.convertRectangle(getParent(), bounds, myLayeredPane);
- lpBounds = myPosition.getPointlessContentRec(lpBounds, myBalloon.getPointerLength(myPosition));
+ lpBounds = myPosition
+ .getPointlessContentRec(lpBounds, myBalloon.myShadowBorderProvider == null ? myBalloon.getPointerLength(myPosition) : 0);
myActionProvider.layout(lpBounds);
}
}
public void repaintButton() {
- for (ActionButton button : myActionProvider.getActions()) {
- button.repaint();
+ if (myActionButtons != null) {
+ for (ActionButton button : myActionButtons) {
+ button.repaint();
+ }
}
}
}
public static final int FixedWidth;
public static final int MaxWidth;
+ public static final int MaxFullContentWidth = JBUI.scale(350);
+ public static final String MaxFullContentWidthStyle = "width:" + MaxFullContentWidth + "px;";
+
public static final int MinWidth = JBUI.scale(100);
public static final String MaxWidthStyle;
* @author Alexander Lobas
*/
public class BalloonLayoutData {
+ public boolean showFullContent;
+
public int height;
public int twoLineHeight;
public int fullHeight;
public Runnable closeAll;
public Runnable doLayout;
+
+ public boolean showSettingButton = true;
public Computable<Boolean> showActions;
public Project project;
private final BalloonLayoutData myLayoutData;
private final String myDisplayGroupId;
private final Component myRepaintPanel;
- private final BalloonImpl.ActionButton mySettingButton;
- private final BalloonImpl.ActionButton myCloseButton;
- private final List<BalloonImpl.ActionButton> myActions = new ArrayList<BalloonImpl.ActionButton>();
+ private BalloonImpl.ActionButton mySettingButton;
+ private BalloonImpl.ActionButton myCloseButton;
+ private List<BalloonImpl.ActionButton> myActions;
private static final Rectangle CloseHoverBounds = new JBRectangle(5, 5, 12, 10);
myDisplayGroupId = displayGroupId;
myBalloon = balloon;
myRepaintPanel = repaintPanel;
+ }
+
+ @NotNull
+ @Override
+ public List<BalloonImpl.ActionButton> createActions() {
+ myActions = new ArrayList<BalloonImpl.ActionButton>();
- if (myDisplayGroupId == null || !NotificationsConfigurationImpl.getInstanceImpl().isRegistered(myDisplayGroupId)) {
+ if (!myLayoutData.showSettingButton || myDisplayGroupId == null ||
+ !NotificationsConfigurationImpl.getInstanceImpl().isRegistered(myDisplayGroupId)) {
mySettingButton = null;
}
else {
};
myActions.add(mySettingButton);
- if (repaintPanel != null) {
- layoutData.showActions = new Computable<Boolean>() {
+ if (myRepaintPanel != null) {
+ myLayoutData.showActions = new Computable<Boolean>() {
@Override
public Boolean compute() {
for (BalloonImpl.ActionButton action : myActions) {
}
};
myActions.add(myCloseButton);
- }
- @NotNull
- @Override
- public List<BalloonImpl.ActionButton> getActions() {
return myActions;
}
package com.intellij.ui;
import com.intellij.icons.AllIcons.Ide.Notification.Shadow;
+import com.intellij.openapi.ui.popup.Balloon;
import com.intellij.util.ui.JBInsets;
import org.jetbrains.annotations.NotNull;
g.setColor(myBorderColor);
g.draw(new RoundRectangle2D.Double(bounds.x + 0.5, bounds.y + 0.5, bounds.width - 1, bounds.height - 1, 3, 3));
}
+
+ @Override
+ public void paintPointingShape(@NotNull Rectangle bounds,
+ @NotNull Point pointTarget,
+ @NotNull Balloon.Position position,
+ @NotNull Graphics2D g) {
+ int x, y, length;
+
+ if (position == Balloon.Position.above) {
+ length = INSETS.bottom;
+ x = pointTarget.x;
+ y = bounds.y + bounds.height + length;
+ }
+ else if (position == Balloon.Position.below) {
+ length = INSETS.top;
+ x = pointTarget.x;
+ y = bounds.y - length;
+ }
+ else if (position == Balloon.Position.atRight) {
+ length = INSETS.left;
+ x = bounds.x - length;
+ y = pointTarget.y;
+ }
+ else {
+ length = INSETS.right;
+ x = bounds.x + bounds.width + length;
+ y = pointTarget.y;
+ }
+
+ Polygon p = new Polygon();
+ p.addPoint(x, y);
+
+ length += 2;
+ if (position == Balloon.Position.above) {
+ p.addPoint(x - length, y - length);
+ p.addPoint(x + length, y - length);
+ }
+ else if (position == Balloon.Position.below) {
+ p.addPoint(x - length, y + length);
+ p.addPoint(x + length, y + length);
+ }
+ else if (position == Balloon.Position.atRight) {
+ p.addPoint(x + length, y - length);
+ p.addPoint(x + length, y + length);
+ }
+ else {
+ p.addPoint(x - length, y - length);
+ p.addPoint(x - length, y + length);
+ }
+
+ g.setColor(myFillColor);
+ g.fillPolygon(p);
+
+ g.setColor(myBorderColor);
+
+ length -= 2;
+ if (position == Balloon.Position.above) {
+ g.drawLine(x, y, x - length, y - length);
+ g.drawLine(x, y, x + length, y - length);
+ }
+ else if (position == Balloon.Position.below) {
+ g.drawLine(x, y, x - length, y + length);
+ g.drawLine(x, y, x + length, y + length);
+ }
+ else if (position == Balloon.Position.atRight) {
+ g.drawLine(x, y, x + length, y - length);
+ g.drawLine(x, y, x + length, y + length);
+ }
+ else {
+ g.drawLine(x, y, x - length, y - length);
+ g.drawLine(x, y, x - length, y + length);
+ }
+ }
}
\ No newline at end of file