package com.jetbrains.lang.dart.ide.errorTreeView;
import com.intellij.notification.*;
import com.intellij.notification.impl.NotificationsManagerImpl;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.MessageDialogBuilder;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.ui.popup.Balloon;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.wm.IdeFrame;
import com.intellij.openapi.wm.WindowManager;
import com.intellij.ui.BalloonLayout;
import com.intellij.ui.BalloonLayoutData;
import com.intellij.ui.JBColor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.event.HyperlinkEvent;
/**
* Plugins may define alternative implementations that cause issues to be opened
* for projects other than the Dart plugin. For example, the Flutter plugin may
* send issues to the flutter project on github.
*/
public abstract class DartFeedbackBuilder {
public static final int MAX_URL_LENGTH = 1900;
// NOTIFICATION_GROUP is used to add an error to Event Log tool window. Red balloon is shown separately, like for IDE fatal errors.
// We do not show standard balloon using this NOTIFICATION_GROUP because it is not red enough.
private static final NotificationGroup NOTIFICATION_GROUP =
new NotificationGroup("Dart Analyzer Error", NotificationDisplayType.NONE, true);
private static ExtensionPointName<DartFeedbackBuilder> EP_NAME = ExtensionPointName.create("Dart.feedbackBuilder");
@NotNull
public static DartFeedbackBuilder getFeedbackBuilder() {
final DartFeedbackBuilder[] builders = EP_NAME.getExtensions();
assert builders.length > 0;
return builders[0];
}
/**
* The title should indicate what sort of action will occur (eg open a browser).
*
* @return The string to display in the title of the confirmation dialog.
*/
public String title() {
return "Open Browser";
}
/**
* The prompt should indicate to the user where the issue report will be opened (eg github).
*
* @return The string to display in the confirmation dialog.
*/
public abstract String prompt();
/**
* The label should indicate what is going to happen when clicked (eg send feedback).
*
* @return The string to display as the label of the yes-button in the confirmation dialog.
*/
public String label() {
return "Send feedback";
}
/**
* Perform the action required to send feedback.
*
* @param project the current project
* @param errorMessage additional information for the issue, such as a tack trace
* @param serverLog recent requests made to the analysis server
*/
public abstract void sendFeedback(@NotNull Project project, @Nullable String errorMessage, @Nullable String serverLog);
/**
* Display a standard query dialog and return the user's response.
*
* @param message optional, an additional message to display before the prompt
*/
public boolean showQuery(@Nullable String message) {
return (MessageDialogBuilder.yesNo(title(), message == null ? prompt() : message + "\n" + prompt())
.icon(Messages.getQuestionIcon())
.yesText(label())
.show() == Messages.YES);
}
/**
* Show a notification that allows the user to submit a feedback issue.
*
* @param message an additional message to display before the prompt
* @param project the current project
* @param errorMessage optional, may be used for stack trace
* @param debugLog optional, server traffic log for debugging
*/
public void showNotification(@NotNull String message,
@NotNull Project project,
@Nullable String errorMessage,
@Nullable String debugLog) {
String content = message + "<br><a href=\"\">" + prompt() + "</a>";
NotificationListener listener = new NotificationListener.Adapter() {
@Override
protected void hyperlinkActivated(@NotNull Notification notification, @NotNull HyperlinkEvent e) {
notification.expire();
sendFeedback(project, errorMessage, debugLog);
}
};
Notification notification =
NOTIFICATION_GROUP.createNotification(NOTIFICATION_GROUP.getDisplayId(), content, NotificationType.ERROR, listener);
// this writes to Event Log tool window, but doesn't show balloon (standard balloon is not red enough,
// we want to show a different balloon similar to the IDE fatal error)
notification.notify(project);
// this shows red balloon line in case of an IDE fatal error
ApplicationManager.getApplication()
.invokeLater(() -> showErrorNotification(notification, project), ModalityState.NON_MODAL, project.getDisposed());
}
private static void showErrorNotification(@NotNull Notification notification, @NotNull Project project) {
// Adapted from IdeMessagePanel.showErrorNotification()
IdeFrame myFrame = WindowManager.getInstance().getIdeFrame(project);
BalloonLayout layout = myFrame.getBalloonLayout();
assert layout != null;
BalloonLayoutData layoutData = BalloonLayoutData.createEmpty();
layoutData.fadeoutTime = 5000;
layoutData.fillColor = new JBColor(0XF5E6E7, 0X593D41);
layoutData.borderColor = new JBColor(0XE0A8A9, 0X73454B);
Balloon balloon = NotificationsManagerImpl.createBalloon(myFrame, notification, false, false, new Ref<>(layoutData), project);
layout.add(balloon);
}
}