mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
New error reporter with ability for plugins to report their exception to their bugtracking systems.
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
package com.intellij.openapi.diagnostic;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* Created by IntelliJ IDEA.
|
||||
* User: max
|
||||
* Date: Feb 17, 2005
|
||||
* Time: 9:11:44 PM
|
||||
* To change this template use File | Settings | File Templates.
|
||||
*/
|
||||
public interface ErrorReportSubmitter {
|
||||
String getReportActionText();
|
||||
SubmittedReportInfo submit(IdeaLoggingEvent[] events, Component parentComponent);
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.intellij.openapi.diagnostic;
|
||||
|
||||
/**
|
||||
* Created by IntelliJ IDEA.
|
||||
* User: max
|
||||
* Date: Feb 17, 2005
|
||||
* Time: 9:42:38 PM
|
||||
* To change this template use File | Settings | File Templates.
|
||||
*/
|
||||
public class SubmittedReportInfo {
|
||||
public static class SubmissionStatus {
|
||||
public static SubmissionStatus NEW_ISSUE = new SubmissionStatus("NEW_ISSUE");
|
||||
public static SubmissionStatus DUPLICATE = new SubmissionStatus("DUPLICATE");
|
||||
public static SubmissionStatus FAILED = new SubmissionStatus("FAILED");
|
||||
private String myName;
|
||||
|
||||
private SubmissionStatus(String name) {
|
||||
myName = name;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "SubmissionStatus[" + myName + "]";
|
||||
}
|
||||
}
|
||||
|
||||
private String myURL;
|
||||
private String myLinkText;
|
||||
private SubmissionStatus myStatus;
|
||||
|
||||
public SubmittedReportInfo(final String URL, final String linkText, final SubmissionStatus status) {
|
||||
myURL = URL;
|
||||
myLinkText = linkText;
|
||||
myStatus = status;
|
||||
}
|
||||
|
||||
public String getURL() {
|
||||
return myURL;
|
||||
}
|
||||
|
||||
public String getLinkText() {
|
||||
return myLinkText;
|
||||
}
|
||||
|
||||
public SubmissionStatus getStatus() {
|
||||
return myStatus;
|
||||
}
|
||||
}
|
||||
@@ -10,69 +10,31 @@ import com.intellij.openapi.application.ex.ApplicationManagerEx;
|
||||
import com.intellij.openapi.diagnostic.ErrorLogger;
|
||||
import com.intellij.openapi.diagnostic.IdeaLoggingEvent;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import jetbrains.fbq.diagnostic.MessagePool;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.io.File;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author kir
|
||||
*/
|
||||
public class DefaultIdeaErrorLogger implements ErrorLogger {
|
||||
|
||||
private static boolean ourOomOccured = false;
|
||||
private final List<IdeaLoggingEvent> myEventsCache = Collections.synchronizedList(new ArrayList<IdeaLoggingEvent>());
|
||||
|
||||
public boolean canHandle(IdeaLoggingEvent event) {
|
||||
return !DialogAppender.RELEASE_BUILD ||
|
||||
ApplicationManagerEx.getApplicationEx().isInternal() ||
|
||||
return !DialogAppender.RELEASE_BUILD || ApplicationManagerEx.getApplicationEx().isInternal() ||
|
||||
event.getThrowable() instanceof OutOfMemoryError;
|
||||
}
|
||||
|
||||
/** @noinspection ThrowablePrintStackTrace*/
|
||||
public void handle(IdeaLoggingEvent event) {
|
||||
showDialog(event);
|
||||
}
|
||||
|
||||
private void showDialog(IdeaLoggingEvent event) {
|
||||
try {
|
||||
if (event.getThrowable() instanceof OutOfMemoryError) {
|
||||
processOOMError(event);
|
||||
}
|
||||
else {
|
||||
if (ourOomOccured) {
|
||||
SwingUtilities.invokeAndWait(new Runnable() {
|
||||
public void run() {
|
||||
JOptionPane.showMessageDialog(JOptionPane.getRootFrame(),
|
||||
"OutOfMemoryException occured before this problem and " +
|
||||
"it can be the reason of current one. So we recommend " +
|
||||
"you to restart your IDEA.", "Error", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
myEventsCache.add(event);
|
||||
SwingUtilities.invokeAndWait(new Runnable() {
|
||||
public void run() {
|
||||
while (myEventsCache.size() > 0) {
|
||||
IdeaLoggingEvent event = myEventsCache.get(0);
|
||||
ErrorOccuredDialog errorOccuredDialog = new ErrorOccuredDialog(event);
|
||||
errorOccuredDialog.show();
|
||||
|
||||
if (errorOccuredDialog.isShouldClose()) {
|
||||
try {
|
||||
ApplicationManager.getApplication().exit();
|
||||
}
|
||||
catch (Throwable e) {
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
myEventsCache.remove(0);
|
||||
}
|
||||
}
|
||||
});
|
||||
else if (!ourOomOccured) {
|
||||
MessagePool.getInstance().addIdeFatalMessage(event);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
|
||||
@@ -0,0 +1,173 @@
|
||||
package com.intellij.diagnostic;
|
||||
|
||||
import com.intellij.errorreport.ErrorReportSender;
|
||||
import com.intellij.errorreport.bean.ErrorBean;
|
||||
import com.intellij.errorreport.bean.NotifierBean;
|
||||
import com.intellij.errorreport.error.InternalEAPException;
|
||||
import com.intellij.errorreport.error.NewBuildException;
|
||||
import com.intellij.errorreport.error.NoSuchEAPUserException;
|
||||
import com.intellij.errorreport.error.ThreadClosedException;
|
||||
import com.intellij.errorreport.itn.ITNProxy;
|
||||
import com.intellij.ide.BrowserUtil;
|
||||
import com.intellij.idea.IdeaLogger;
|
||||
import com.intellij.openapi.diagnostic.ErrorReportSubmitter;
|
||||
import com.intellij.openapi.diagnostic.IdeaLoggingEvent;
|
||||
import com.intellij.openapi.diagnostic.SubmittedReportInfo;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.util.net.IOExceptionDialog;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Created by IntelliJ IDEA.
|
||||
* User: max
|
||||
* Date: Feb 17, 2005
|
||||
* Time: 11:12:23 PM
|
||||
* To change this template use File | Settings | File Templates.
|
||||
*/
|
||||
public class ITNReporter implements ErrorReportSubmitter {
|
||||
private static int previousExceptionThreadId = 0;
|
||||
private static boolean wasException = false;
|
||||
private static final String URL_HEADER = "http://www.intellij.net/tracker/idea/viewSCR?publicId=";
|
||||
|
||||
public String getReportActionText() {
|
||||
return "Report to JetBrains";
|
||||
}
|
||||
|
||||
public SubmittedReportInfo submit(IdeaLoggingEvent[] events, Component parentComponent) {
|
||||
return sendError(events[0], parentComponent);
|
||||
}
|
||||
|
||||
/**
|
||||
* @noinspection ThrowablePrintStackTrace
|
||||
*/
|
||||
private SubmittedReportInfo sendError(IdeaLoggingEvent event, Component parentComponent) {
|
||||
NotifierBean notifierBean = new NotifierBean();
|
||||
ErrorBean errorBean = new ErrorBean();
|
||||
errorBean.autoInit();
|
||||
errorBean.setLastAction(IdeaLogger.ourLastActionId);
|
||||
|
||||
int threadId = 0;
|
||||
SubmittedReportInfo.SubmissionStatus submissionStatus = SubmittedReportInfo.SubmissionStatus.FAILED;
|
||||
|
||||
do {
|
||||
// prepare
|
||||
try {
|
||||
ErrorReportSender sender = ErrorReportSender.getInstance();
|
||||
|
||||
sender.prepareError(event.getThrowable());
|
||||
|
||||
EAPSendErrorDialog dlg = new EAPSendErrorDialog();
|
||||
dlg.show();
|
||||
|
||||
notifierBean.setItnLogin(ErrorReportConfigurable.getInstance().ITN_LOGIN);
|
||||
notifierBean.setItnPassword(ErrorReportConfigurable.getInstance().getPlainItnPassword());
|
||||
|
||||
String description = dlg.getErrorDescription();
|
||||
String message = event.getMessage();
|
||||
|
||||
errorBean.setDescription("User description: " + description + "\n" +
|
||||
(message != null ? "Error message: " + message + "\n" : ""));
|
||||
|
||||
if (dlg.isShouldSend()) {
|
||||
threadId = sender.sendError(notifierBean, errorBean);
|
||||
|
||||
if (previousExceptionThreadId != 0) {
|
||||
ITNProxy.postNewComment(ErrorReportConfigurable.getInstance().ITN_LOGIN,
|
||||
ErrorReportConfigurable.getInstance().getPlainItnPassword(),
|
||||
threadId, "Previous exception is: " +
|
||||
URL_HEADER +
|
||||
previousExceptionThreadId);
|
||||
}
|
||||
previousExceptionThreadId = threadId;
|
||||
|
||||
if (wasException) {
|
||||
ITNProxy.postNewComment(ErrorReportConfigurable.getInstance().ITN_LOGIN,
|
||||
ErrorReportConfigurable.getInstance().getPlainItnPassword(),
|
||||
threadId, "There was at least one exception before this one.");
|
||||
}
|
||||
|
||||
wasException = true;
|
||||
submissionStatus = SubmittedReportInfo.SubmissionStatus.NEW_ISSUE;
|
||||
|
||||
if (Messages.showYesNoDialog(parentComponent,
|
||||
"Error report successfuly sent. \nRequest #" + threadId +
|
||||
" created. Do you want to open the related request in ITN?",
|
||||
ReportMessages.ERROR_REPORT, Messages.getQuestionIcon()) == 0) {
|
||||
try {
|
||||
BrowserUtil.launchBrowser(URL_HEADER + threadId);
|
||||
}
|
||||
catch (IllegalThreadStateException e) {
|
||||
// it's OK
|
||||
// browser is not exited
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
catch (NoSuchEAPUserException e) {
|
||||
if (ReportMessages.isEAP) e.printStackTrace();
|
||||
if (Messages.showYesNoDialog(parentComponent, "ITN authorization failed. Do you want to try again?",
|
||||
ReportMessages.ERROR_REPORT, Messages.getErrorIcon()) != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (InternalEAPException e) {
|
||||
if (ReportMessages.isEAP) e.printStackTrace();
|
||||
if (Messages.showYesNoDialog(parentComponent, "ITN posting failed. Do you want to try again?",
|
||||
ReportMessages.ERROR_REPORT, Messages.getErrorIcon()) != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
if (ReportMessages.isEAP) e.printStackTrace();
|
||||
if (!IOExceptionDialog.showErrorDialog(e, "Error Report", "Error report sending failed.")) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (NewBuildException e) {
|
||||
if (ReportMessages.isEAP) e.printStackTrace();
|
||||
Messages.showMessageDialog(parentComponent,
|
||||
"New EAP build " + e.getMessage() + " is available.", "Warning",
|
||||
Messages.getWarningIcon());
|
||||
break;
|
||||
}
|
||||
catch (ThreadClosedException e) {
|
||||
submissionStatus = SubmittedReportInfo.SubmissionStatus.DUPLICATE;
|
||||
threadId = e.getThreadId();
|
||||
if (ReportMessages.isEAP) e.printStackTrace();
|
||||
if (Messages.showYesNoDialog(parentComponent,
|
||||
"This error already closed with status: " + e.getMessage() + "." +
|
||||
" You don't need to post it, thank you. Do you want to open it in tracker?",
|
||||
ReportMessages.ERROR_REPORT, Messages.getQuestionIcon()) == 0) {
|
||||
try {
|
||||
BrowserUtil.launchBrowser(URL_HEADER + threadId);
|
||||
}
|
||||
catch (IllegalThreadStateException ex) {
|
||||
// it's OK
|
||||
// browser is not exited
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
catch (Exception e) {
|
||||
if (ReportMessages.isEAP) e.printStackTrace();
|
||||
if (Messages.showYesNoDialog(parentComponent, "Sending failed. Do you want to try again?",
|
||||
ReportMessages.ERROR_REPORT, Messages.getErrorIcon()) != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
while (true);
|
||||
|
||||
return new SubmittedReportInfo(submissionStatus != SubmittedReportInfo.SubmissionStatus.FAILED ? URL_HEADER + threadId : null,
|
||||
String.valueOf(threadId),
|
||||
submissionStatus);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.intellij.ide.plugins;
|
||||
|
||||
import com.intellij.diagnostic.ErrorHandlerExtension;
|
||||
import com.intellij.diagnostic.ITNReporter;
|
||||
import com.intellij.ide.plugins.cl.IdeaClassLoader;
|
||||
import com.intellij.ide.plugins.cl.PluginClassLoader;
|
||||
import com.intellij.ide.startup.StartupActionScriptManager;
|
||||
@@ -7,6 +9,7 @@ import com.intellij.openapi.application.PathManager;
|
||||
import com.intellij.openapi.application.ex.ApplicationManagerEx;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.extensions.*;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.JDOMUtil;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.graph.CachingSemiGraph;
|
||||
@@ -38,6 +41,7 @@ public class PluginManager {
|
||||
//Logger is lasy-initialized in order not to use it outside the appClassLoader
|
||||
private static Logger ourLogger = null;
|
||||
public static final String COMPONENT_EXTENSION_POINT = "com.intellij.component";
|
||||
public static final String ERROR_HANDLER_EXTENSION_POINT = "com.intellij.errorHandler";
|
||||
|
||||
private static Logger getLogger() {
|
||||
if (ourLogger == null) {
|
||||
@@ -132,6 +136,11 @@ public class PluginManager {
|
||||
public void areaDisposing(String areaClass, AreaInstance areaInstance) {
|
||||
}
|
||||
}, LoadingOrder.FIRST);
|
||||
|
||||
Extensions.getRootArea().registerExtensionPoint(ERROR_HANDLER_EXTENSION_POINT, ErrorHandlerExtension.class.getName());
|
||||
final ErrorHandlerExtension defaultErrorHandler = new ErrorHandlerExtension();
|
||||
defaultErrorHandler.setHandlerClass(ITNReporter.class.getName());
|
||||
Extensions.getRootArea().getExtensionPoint(ERROR_HANDLER_EXTENSION_POINT).registerExtension(defaultErrorHandler);
|
||||
}
|
||||
|
||||
public static boolean shouldLoadPlugins() {
|
||||
@@ -624,7 +633,7 @@ public class PluginManager {
|
||||
final PluginDescriptor[] plugins = getPlugins();
|
||||
for (int i = 0; i < plugins.length; i++) {
|
||||
final PluginDescriptor plugin = plugins[i];
|
||||
if (name.equals(plugin.getName())) {
|
||||
if (Comparing.equal(name, plugin.getName())) {
|
||||
return plugin;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -377,7 +377,10 @@ public abstract class ComponentManagerImpl extends UserDataHolderBase implements
|
||||
if (isComponentSuitable(options)) {
|
||||
ClassLoader loader = findLoader(descriptor.getPluginName());
|
||||
try {
|
||||
registerComponent(Class.forName(descriptor.getInterface(), true, loader), Class.forName(descriptor.getImplementation(), true, loader), options, true,
|
||||
registerComponent(Class.forName(descriptor.getInterface(), true, loader),
|
||||
Class.forName(descriptor.getImplementation(), true, loader),
|
||||
options,
|
||||
true,
|
||||
isTrue(options, "lazy"));
|
||||
}
|
||||
catch (Exception e) {
|
||||
|
||||
@@ -2,11 +2,13 @@ package com.intellij.openapi.wm.impl.status;
|
||||
|
||||
import com.intellij.ide.ui.UISettings;
|
||||
import com.intellij.ide.ui.UISettingsListener;
|
||||
import com.intellij.openapi.actionSystem.impl.EmptyIcon;
|
||||
import com.intellij.openapi.actionSystem.ActionManager;
|
||||
import com.intellij.openapi.actionSystem.impl.EmptyIcon;
|
||||
import com.intellij.openapi.util.IconLoader;
|
||||
import com.intellij.openapi.wm.ex.StatusBarEx;
|
||||
import com.intellij.ui.EdgeBorder;
|
||||
import jetbrains.fbq.diagnostic.IdeMessagePanel;
|
||||
import jetbrains.fbq.diagnostic.MessagePool;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.Border;
|
||||
@@ -23,6 +25,7 @@ public class StatusBarImpl extends JPanel implements StatusBarEx {
|
||||
protected final MemoryUsagePanel myMemoryUsagePanel = new MemoryUsagePanel();
|
||||
protected final TextPanel myStatusPanel = new TextPanel(new String[]{"Insert", "Overwrite"},false);
|
||||
protected final TogglePopupHintsPanel myPopupHintsPanel;
|
||||
protected final IdeMessagePanel myMessagePanel = new IdeMessagePanel(MessagePool.getInstance());
|
||||
protected String myInfo = "";
|
||||
private final Icon myLockedIcon = IconLoader.getIcon("/nodes/lockedSingle.png");
|
||||
private final Icon myUnlockedIcon = myLockedIcon != null ? EmptyIcon.create(myLockedIcon.getIconWidth(), myLockedIcon.getIconHeight()) : null;
|
||||
@@ -92,8 +95,11 @@ public class StatusBarImpl extends JPanel implements StatusBarEx {
|
||||
myPopupHintsPanel.setOpaque(false);
|
||||
rightPanel.add(myPopupHintsPanel, gbConstraints);
|
||||
|
||||
myMessagePanel.setOpaque(false);
|
||||
rightPanel.add(myMessagePanel, gbConstraints);
|
||||
|
||||
// myMemoryUsagePanel.setOpaque(false);
|
||||
myMemoryUsagePanel.setBorder(BorderFactory.createEmptyBorder(4, 3, 2, 3));
|
||||
// myMemoryUsagePanel.setOpaque(false);
|
||||
rightPanel.add(myMemoryUsagePanel, gbConstraints);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2004 by JetBrains s.r.o. All Rights Reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
package jetbrains.fbq.diagnostic;
|
||||
|
||||
import com.intellij.openapi.diagnostic.SubmittedReportInfo;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
|
||||
public abstract class AbstractMessage {
|
||||
|
||||
private boolean myIsRead = false;
|
||||
private SubmittedReportInfo mySubmissionInfo;
|
||||
private String myScrID;
|
||||
|
||||
private final Date myDate;
|
||||
|
||||
public AbstractMessage() {
|
||||
myDate = Calendar.getInstance().getTime();
|
||||
}
|
||||
|
||||
public abstract String getThrowableText();
|
||||
public abstract Throwable getThrowable();
|
||||
public abstract String getMessage();
|
||||
|
||||
public boolean isRead() {
|
||||
return myIsRead;
|
||||
}
|
||||
|
||||
public void setRead(boolean aReadFlag) {
|
||||
myIsRead = aReadFlag;
|
||||
}
|
||||
|
||||
public void setSubmitted(SubmittedReportInfo info) {
|
||||
mySubmissionInfo = info;
|
||||
}
|
||||
|
||||
public SubmittedReportInfo getSubmissionInfo() {
|
||||
return mySubmissionInfo;
|
||||
}
|
||||
|
||||
public boolean isSumbitted() {
|
||||
return mySubmissionInfo != null &&
|
||||
(mySubmissionInfo.getStatus() == SubmittedReportInfo.SubmissionStatus.NEW_ISSUE ||
|
||||
mySubmissionInfo.getStatus() == SubmittedReportInfo.SubmissionStatus.DUPLICATE);
|
||||
}
|
||||
|
||||
public Date getDate() {
|
||||
return myDate;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2004 by JetBrains s.r.o. All Rights Reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
package jetbrains.fbq.diagnostic;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class GroupedLogMessage extends AbstractMessage {
|
||||
|
||||
private List<AbstractMessage> myMessages;
|
||||
|
||||
public GroupedLogMessage(List<AbstractMessage> messages) {
|
||||
myMessages = messages;
|
||||
}
|
||||
|
||||
public List<AbstractMessage> getMessages() {
|
||||
return myMessages;
|
||||
}
|
||||
|
||||
public String getThrowableText() {
|
||||
StringBuffer result = new StringBuffer();
|
||||
for (int i = 0; i < myMessages.size(); i++) {
|
||||
AbstractMessage each = myMessages.get(i);
|
||||
result.append(each.getThrowableText() + "\n\n\n");
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
public Throwable getThrowable() {
|
||||
return myMessages.get(0).getThrowable();
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return myMessages.get(0).getMessage();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,411 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2004 by JetBrains s.r.o. All Rights Reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
package jetbrains.fbq.diagnostic;
|
||||
|
||||
/**
|
||||
* @author kir
|
||||
*/
|
||||
|
||||
import com.intellij.diagnostic.ErrorHandlerExtension;
|
||||
import com.intellij.diagnostic.PluginException;
|
||||
import com.intellij.ide.BrowserUtil;
|
||||
import com.intellij.ide.plugins.PluginDescriptor;
|
||||
import com.intellij.ide.plugins.PluginManager;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.ErrorReportSubmitter;
|
||||
import com.intellij.openapi.diagnostic.IdeaLoggingEvent;
|
||||
import com.intellij.openapi.extensions.Extensions;
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.ui.Splitter;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.ui.SimpleColoredComponent;
|
||||
import com.intellij.ui.SimpleTextAttributes;
|
||||
import jetbrains.fbq.ide.reporter.ScrData;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.ListSelectionEvent;
|
||||
import javax.swing.event.ListSelectionListener;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
|
||||
public class IdeErrorsDialog extends DialogWrapper implements MessagePoolListener {
|
||||
private JTextPane myDetailsPane;
|
||||
private List myFatalErrors;
|
||||
private JList myHeadersList;
|
||||
private DefaultListModel myHeadersModel = new DefaultListModel();
|
||||
private final MessagePool myMessagePool;
|
||||
|
||||
public IdeErrorsDialog(MessagePool messagePool) {
|
||||
super(JOptionPane.getRootFrame(), false);
|
||||
|
||||
myMessagePool = messagePool;
|
||||
myHeadersList = new JList(myHeadersModel);
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
public void newEntryAdded() {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
rebuildHeaders();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void poolCleared() {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
doOKAction();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected Action[] createActions() {
|
||||
return new Action[]{new SubmitBugAction(), new ShutdownAction(), new ClearFatalsAction(), new CloseAction()};
|
||||
}
|
||||
|
||||
public JComponent getPreferredFocusedComponent() {
|
||||
return myHeadersList;
|
||||
}
|
||||
|
||||
protected JComponent createCenterPanel() {
|
||||
setTitle("IDE Fatal Errors");
|
||||
|
||||
rebuildHeaders();
|
||||
JPanel root = new JPanel(new BorderLayout());
|
||||
|
||||
JPanel headersPanel = new JPanel(new BorderLayout());
|
||||
headersPanel.add(new JLabel("Messages:"), BorderLayout.NORTH);
|
||||
myHeadersList.setCellRenderer(new CellRenderer());
|
||||
headersPanel.add(new JScrollPane(myHeadersList), BorderLayout.CENTER);
|
||||
|
||||
JPanel detailsPanel = new JPanel(new BorderLayout());
|
||||
detailsPanel.add(new JLabel("Details:"), BorderLayout.NORTH);
|
||||
myDetailsPane = new JTextPane();
|
||||
myDetailsPane.setEditable(false);
|
||||
detailsPanel.add(new JScrollPane(myDetailsPane), BorderLayout.CENTER);
|
||||
|
||||
Splitter splitter = new Splitter(true, .5f);
|
||||
splitter.setFirstComponent(headersPanel);
|
||||
splitter.setSecondComponent(detailsPanel);
|
||||
|
||||
root.add(splitter, BorderLayout.CENTER);
|
||||
|
||||
root.setPreferredSize(new Dimension(600, 550));
|
||||
|
||||
myHeadersList.addListSelectionListener(new ListSelectionListener() {
|
||||
public void valueChanged(ListSelectionEvent e) {
|
||||
if (myHeadersList.isSelectionEmpty() || myHeadersList.getModel().getSize() == 0) {
|
||||
hideMessageDetails();
|
||||
return;
|
||||
}
|
||||
|
||||
showMessageDetails(getMessageAt(myHeadersList.getSelectedIndex()));
|
||||
}
|
||||
});
|
||||
|
||||
myHeadersList.addMouseListener(new MouseAdapter() {
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
if (e.getClickCount() % 2 == 0) {
|
||||
final AbstractMessage logMessage = getMessageAt(myHeadersList.getSelectedIndex());
|
||||
if (logMessage.isSumbitted()) {
|
||||
String url = logMessage.getSubmissionInfo().getURL();
|
||||
if (url != null) {
|
||||
BrowserUtil.launchBrowser(url);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
moveSelectionToEarliestMessage();
|
||||
return root;
|
||||
}
|
||||
|
||||
private AbstractMessage getMessageAt(int aIndex) {
|
||||
return (AbstractMessage)((ArrayList)myHeadersList.getModel().getElementAt(aIndex)).get(0);
|
||||
}
|
||||
|
||||
private void moveSelectionToEarliestMessage() {
|
||||
for (int i = myHeadersList.getModel().getSize() - 1; i > 0; i--) {
|
||||
final AbstractMessage each = getMessageAt(i);
|
||||
if (!each.isRead()) {
|
||||
myHeadersList.setSelectedIndex(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (myHeadersList.isSelectionEmpty() && myHeadersList.getModel().getSize() > 0) {
|
||||
myHeadersList.setSelectedIndex(0);
|
||||
}
|
||||
}
|
||||
|
||||
private void rebuildHeaders() {
|
||||
|
||||
final int selectedIndex = myHeadersList.getSelectedIndex();
|
||||
|
||||
myHeadersModel.removeAllElements();
|
||||
myFatalErrors = myMessagePool.getFatalErrors(true, true);
|
||||
Collections.reverse(myFatalErrors);
|
||||
|
||||
Map<String, ArrayList<AbstractMessage>> hash2Messages = buildHashcode2MessageListMap(myFatalErrors);
|
||||
|
||||
final Iterator<ArrayList<AbstractMessage>> messageLists = hash2Messages.values().iterator();
|
||||
while (messageLists.hasNext()) {
|
||||
myHeadersModel.addElement(messageLists.next());
|
||||
}
|
||||
|
||||
if (selectedIndex < myHeadersModel.getSize()) {
|
||||
myHeadersList.setSelectedIndex(selectedIndex);
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, ArrayList<AbstractMessage>> buildHashcode2MessageListMap(List aErrors) {
|
||||
Map<String, ArrayList<AbstractMessage>> hash2Messages = new LinkedHashMap<String, ArrayList<AbstractMessage>>();
|
||||
for (int i = 0; i < aErrors.size(); i++) {
|
||||
final AbstractMessage each = (AbstractMessage)aErrors.get(i);
|
||||
final String hashcode = ScrData.getThrowableHashCode(each.getThrowable());
|
||||
ArrayList<AbstractMessage> list;
|
||||
if (hash2Messages.containsKey(hashcode)) {
|
||||
list = hash2Messages.get(hashcode);
|
||||
}
|
||||
else {
|
||||
list = new ArrayList<AbstractMessage>();
|
||||
hash2Messages.put(hashcode, list);
|
||||
}
|
||||
list.add(0, each);
|
||||
}
|
||||
return hash2Messages;
|
||||
}
|
||||
|
||||
private void showMessageDetails(AbstractMessage aMessage) {
|
||||
myDetailsPane.setText(aMessage.getThrowableText());
|
||||
myDetailsPane.setCaretPosition(0);
|
||||
}
|
||||
|
||||
private void hideMessageDetails() {
|
||||
myDetailsPane.setText("");
|
||||
}
|
||||
|
||||
public static String findPluginName(Throwable t) {
|
||||
StackTraceElement[] elements = t.getStackTrace();
|
||||
for (int i = 0; i < elements.length; i++) {
|
||||
StackTraceElement element = elements[i];
|
||||
String className = element.getClassName();
|
||||
if (PluginManager.isPluginClass(className) &&
|
||||
!className.startsWith("com.intellij") &&
|
||||
!className.startsWith("org.jetbrains")) {
|
||||
return PluginManager.getPluginByClassName(className);
|
||||
}
|
||||
}
|
||||
|
||||
if (t instanceof NoSuchMethodException) {
|
||||
// check is method called from plugin classes
|
||||
if (t.getMessage() != null) {
|
||||
String className = "";
|
||||
StringTokenizer tok = new StringTokenizer(t.getMessage(), ".");
|
||||
while (tok.hasMoreTokens()) {
|
||||
String token = tok.nextToken();
|
||||
if (token.length() > 0 && Character.isJavaIdentifierStart(token.charAt(0))) {
|
||||
className += token;
|
||||
}
|
||||
}
|
||||
|
||||
if (PluginManager.isPluginClass(className)) {
|
||||
return PluginManager.getPluginByClassName(className);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (t instanceof ClassNotFoundException) {
|
||||
// check is class from plugin classes
|
||||
if (t.getMessage() != null) {
|
||||
String className = t.getMessage();
|
||||
|
||||
if (PluginManager.isPluginClass(className)) {
|
||||
return PluginManager.getPluginByClassName(className);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (t instanceof PluginException) {
|
||||
return ((PluginException)t).getDescriptor().getName();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static class CellRenderer extends DefaultListCellRenderer {
|
||||
private SimpleColoredComponent myComponent = new SimpleColoredComponent();
|
||||
|
||||
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
|
||||
ArrayList<AbstractMessage> messageList = (ArrayList<AbstractMessage>)value;
|
||||
AbstractMessage message = messageList.get(0);
|
||||
String prefix = messageList.size() > 1 ? "(" + messageList.size() + ") " : "";
|
||||
|
||||
myComponent.clear();
|
||||
final Color unimportantColor = new Color(102, 102, 102);
|
||||
final String text = message.getMessage();
|
||||
|
||||
final SimpleTextAttributes grayed = new SimpleTextAttributes(Font.PLAIN, unimportantColor);
|
||||
final SimpleTextAttributes blue = new SimpleTextAttributes(Font.PLAIN, Color.blue);
|
||||
|
||||
if (!message.isRead() && !message.isSumbitted()) {
|
||||
myComponent.append(prefix + text, new SimpleTextAttributes(Font.BOLD, Color.black));
|
||||
}
|
||||
else if (message.isSumbitted()) {
|
||||
myComponent.append(prefix, grayed);
|
||||
|
||||
myComponent.append("Submitted: #" + message.getSubmissionInfo().getLinkText(), blue);
|
||||
myComponent.append(":" + text, blue);
|
||||
myComponent.append(" (double-click to open in browser)", grayed);
|
||||
}
|
||||
else if (message.isRead()) {
|
||||
myComponent.append(prefix + text, grayed);
|
||||
}
|
||||
|
||||
myComponent.setBackground(isSelected ? list.getSelectionBackground() : list.getBackground());
|
||||
return myComponent;
|
||||
}
|
||||
}
|
||||
|
||||
private class ShutdownAction extends AbstractAction {
|
||||
public ShutdownAction() {
|
||||
super("Shut_down");
|
||||
}
|
||||
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
myMessagePool.setJvmIsShuttingDown();
|
||||
ApplicationManager.getApplication().exit();
|
||||
}
|
||||
}
|
||||
|
||||
private class ClearFatalsAction extends AbstractAction {
|
||||
public ClearFatalsAction() {
|
||||
super("_Clear And Close");
|
||||
}
|
||||
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
myMessagePool.clearFatals();
|
||||
doOKAction();
|
||||
}
|
||||
}
|
||||
|
||||
private class SubmitBugAction extends AbstractAction {
|
||||
public SubmitBugAction() {
|
||||
super("_Report To JetBrains");
|
||||
putValue(DEFAULT, Boolean.TRUE);
|
||||
}
|
||||
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if (myHeadersList.isSelectionEmpty()) {
|
||||
Messages.showMessageDialog("Please first select error to report", "Cannot Report", Messages.getInformationIcon());
|
||||
myHeadersList.requestFocus();
|
||||
return;
|
||||
}
|
||||
|
||||
final int selectedIndex = myHeadersList.getSelectedIndex();
|
||||
final AbstractMessage logMessage = getMessageAt(selectedIndex);
|
||||
|
||||
if (logMessage.isSumbitted()) {
|
||||
// Messages.showMessageDialog("This error was already submitted: #" + logMessage.getScrID(), "Already Submitted", Messages.getInformationIcon());
|
||||
Messages.showMessageDialog("This error was already submitted", "Already Submitted", Messages.getInformationIcon());
|
||||
return;
|
||||
}
|
||||
|
||||
reportMessage(logMessage);
|
||||
rebuildHeaders();
|
||||
myHeadersList.setSelectedIndex(selectedIndex);
|
||||
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
myHeadersList.requestFocus();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void reportMessage(final AbstractMessage logMessage) {
|
||||
final String pluginName = findPluginName(logMessage.getThrowable());
|
||||
final Object[] reporters = Extensions.getRootArea().getExtensionPoint(PluginManager.ERROR_HANDLER_EXTENSION_POINT).getExtensions();
|
||||
ErrorReportSubmitter submitter = null;
|
||||
for (int i = 0; i < reporters.length; i++) {
|
||||
ErrorHandlerExtension reporterBean = (ErrorHandlerExtension)reporters[i];
|
||||
if (Comparing.equal(pluginName, reporterBean.getPluginName())) {
|
||||
final PluginDescriptor plugin = PluginManager.getPlugin(pluginName);
|
||||
final ClassLoader loader;
|
||||
if (plugin != null) {
|
||||
loader = plugin.getLoader();
|
||||
}
|
||||
else {
|
||||
loader = getClass().getClassLoader();
|
||||
}
|
||||
|
||||
try {
|
||||
final Class submitterClass = Class.forName(reporterBean.getHandlerClass(), true, loader);
|
||||
submitter = (ErrorReportSubmitter)submitterClass.newInstance();
|
||||
}
|
||||
catch (Exception e) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (submitter != null) {
|
||||
logMessage.setSubmitted(submitter.submit(getEvents(logMessage), getContentPane()));
|
||||
}
|
||||
}
|
||||
|
||||
private IdeaLoggingEvent[] getEvents(final AbstractMessage logMessage) {
|
||||
if (logMessage instanceof GroupedLogMessage) {
|
||||
final List<AbstractMessage> messages = ((GroupedLogMessage)logMessage).getMessages();
|
||||
IdeaLoggingEvent[] res = new IdeaLoggingEvent[messages.size()];
|
||||
for (int i = 0; i < res.length; i++) {
|
||||
res[i] = getEvent(messages.get(i));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
return new IdeaLoggingEvent[]{getEvent(logMessage)};
|
||||
}
|
||||
|
||||
private IdeaLoggingEvent getEvent(final AbstractMessage logMessage) {
|
||||
return new IdeaLoggingEvent(logMessage.getMessage(), logMessage.getThrowable());
|
||||
}
|
||||
}
|
||||
|
||||
protected void doOKAction() {
|
||||
markAllAsRead();
|
||||
super.doOKAction();
|
||||
}
|
||||
|
||||
private void markAllAsRead() {
|
||||
for (int i = 0; i < myFatalErrors.size(); i++) {
|
||||
AbstractMessage each = (AbstractMessage)myFatalErrors.get(i);
|
||||
each.setRead(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void doCancelAction() {
|
||||
markAllAsRead();
|
||||
super.doCancelAction();
|
||||
}
|
||||
|
||||
protected class CloseAction extends AbstractAction {
|
||||
public CloseAction() {
|
||||
putValue(Action.NAME, "C_lose");
|
||||
}
|
||||
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
doOKAction();
|
||||
}
|
||||
}
|
||||
|
||||
protected String getDimensionServiceKey() {
|
||||
return "IdeErrosDialog";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,275 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2004 by JetBrains s.r.o. All Rights Reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
package jetbrains.fbq.diagnostic;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.IconLoader;
|
||||
import jetbrains.fbq.ui.messager.Callout;
|
||||
import jetbrains.fbq.util.awt.RelativePoint;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
|
||||
public class IdeMessagePanel extends JPanel implements MessagePoolListener {
|
||||
|
||||
private static final Logger LOG = Logger.getInstance("#jetbrains.fbq.diagnostic.IdeMessagePanel");
|
||||
|
||||
private IconPane myIdeFatal;
|
||||
|
||||
private IconPane[] myIcons;
|
||||
private static final String INTERNAL_ERROR_NOTICE =
|
||||
"<html><body><b>IDE internal error occured."+
|
||||
"<br>Click to see details and post bug report to JetBrains.</b></body></html>";
|
||||
|
||||
private long myPreviousExceptionTimeStamp;
|
||||
private IdeErrorsDialog myDialog;
|
||||
private boolean myOpeningInProgress;
|
||||
private final MessagePool myMessagePool;
|
||||
|
||||
public IdeMessagePanel(MessagePool messagePool) {
|
||||
super(new BorderLayout());
|
||||
myIdeFatal = new IconPane(IconLoader.getIcon("/general/ideFatalError.png"), "No new IDE fatal errors", new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
openFatals();
|
||||
}
|
||||
});
|
||||
|
||||
myIdeFatal.setVerticalAlignment(JLabel.CENTER);
|
||||
|
||||
myIcons = new IconPane[]{myIdeFatal};
|
||||
add(myIdeFatal, BorderLayout.CENTER);
|
||||
|
||||
myMessagePool = messagePool;
|
||||
messagePool.addListener(this);
|
||||
|
||||
new Blinker().start();
|
||||
updateFatalErrorsIcon();
|
||||
}
|
||||
|
||||
private void openFatals() {
|
||||
if (myDialog != null) return;
|
||||
if (myOpeningInProgress) return;
|
||||
myOpeningInProgress = true;
|
||||
|
||||
new Thread() {
|
||||
public void run() {
|
||||
try {
|
||||
while(isOtherModalWindowActive()) {
|
||||
if (myDialog != null) return;
|
||||
sleep(300);
|
||||
}
|
||||
|
||||
_openFatals();
|
||||
} catch (InterruptedException e) {}
|
||||
finally {
|
||||
myOpeningInProgress = false;
|
||||
}
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
|
||||
private void _openFatals() {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
myDialog = new IdeErrorsDialog(myMessagePool) {
|
||||
protected void doOKAction() {
|
||||
super.doOKAction();
|
||||
disposeDialog(this);
|
||||
}
|
||||
|
||||
public void doCancelAction() {
|
||||
super.doCancelAction();
|
||||
disposeDialog(this);
|
||||
}
|
||||
};
|
||||
|
||||
myMessagePool.addListener(myDialog);
|
||||
if (!isOtherModalWindowActive()) {
|
||||
myDialog.show();
|
||||
}
|
||||
else {
|
||||
myDialog.close(0);
|
||||
disposeDialog(myDialog);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void disposeDialog(final IdeErrorsDialog listDialog) {
|
||||
myMessagePool.removeListener(listDialog);
|
||||
updateFatalErrorsIcon();
|
||||
myDialog = null;
|
||||
}
|
||||
|
||||
public void newEntryAdded() {
|
||||
updateFatalErrorsIcon();
|
||||
|
||||
long lastExceptionTimestamp = System.currentTimeMillis();
|
||||
if ((lastExceptionTimestamp - myPreviousExceptionTimeStamp > 1000) && myMessagePool.hasUnreadMessages()){
|
||||
showErrorCallout();
|
||||
}
|
||||
|
||||
/*
|
||||
if (isOtherModalWindowActive()) {
|
||||
showErrorCallout();
|
||||
openFatals();
|
||||
} else if ((lastExceptionTimestamp - myPreviousExceptionTimeStamp > 1000)){
|
||||
openFatals();
|
||||
}
|
||||
*/
|
||||
myPreviousExceptionTimeStamp = lastExceptionTimestamp;
|
||||
}
|
||||
|
||||
private void showErrorCallout() {
|
||||
if (isShowing()) {
|
||||
Callout.showText(RelativePoint.getCenterOf(myIdeFatal), Callout.NORTH_WEST, INTERNAL_ERROR_NOTICE);
|
||||
}
|
||||
}
|
||||
|
||||
public void poolCleared() {
|
||||
updateFatalErrorsIcon();
|
||||
}
|
||||
|
||||
private boolean isOtherModalWindowActive() {
|
||||
final Window window = getActiveModalWindow();
|
||||
if (window == null) return false;
|
||||
|
||||
if (myDialog != null) {
|
||||
return myDialog.getWindow() != window;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private Window getActiveModalWindow() {
|
||||
final KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
|
||||
final Window activeWindow = manager.getActiveWindow();
|
||||
if (activeWindow instanceof JDialog) {
|
||||
if (((JDialog) activeWindow).isModal()) {
|
||||
return activeWindow;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void updateFatalErrorsIcon() {
|
||||
if (myMessagePool.getFatalErrors(true, true).size() == 0) {
|
||||
myIdeFatal.deactivate();
|
||||
} else {
|
||||
myIdeFatal.activate(INTERNAL_ERROR_NOTICE, true);
|
||||
}
|
||||
}
|
||||
|
||||
private class Blinker extends Thread {
|
||||
/** @noinspection BusyWait*/
|
||||
public void run() {
|
||||
while(true) {
|
||||
try {
|
||||
sleep(1000);
|
||||
setBlinkedIconsVisibilityTo(false);
|
||||
sleep(1000);
|
||||
setBlinkedIconsVisibilityTo(true);
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setBlinkedIconsVisibilityTo(boolean aVisible) {
|
||||
for (int i = 0; i < myIcons.length; i++) {
|
||||
final IdeMessagePanel.IconPane each = myIcons[i];
|
||||
each.getIconWrapper().setVisible(aVisible || !each.shouldBlink());
|
||||
each.paintImmediately(each.getBounds());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class IconPane extends JLabel {
|
||||
|
||||
private IconWrapper myIcon;
|
||||
private String myEmptyText;
|
||||
private boolean myIsActive;
|
||||
private ActionListener myListener;
|
||||
|
||||
public IconPane(Icon aIcon, String aEmptyText, ActionListener aListener) {
|
||||
myIcon = new IconWrapper(aIcon);
|
||||
myEmptyText = aEmptyText;
|
||||
myListener = aListener;
|
||||
setIcon(myIcon);
|
||||
|
||||
addMouseListener(new MouseAdapter() {
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
if (myIsActive) {
|
||||
myListener.actionPerformed(null);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
deactivate();
|
||||
}
|
||||
|
||||
public IconWrapper getIconWrapper() {
|
||||
return myIcon;
|
||||
}
|
||||
|
||||
public void activate(String aDisplayingText, boolean aShouldBlink) {
|
||||
setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
|
||||
myIsActive = true;
|
||||
myIcon.setIconPainted(true);
|
||||
setToolTipText(aDisplayingText);
|
||||
repaint();
|
||||
}
|
||||
|
||||
public void deactivate() {
|
||||
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
|
||||
myIsActive = false;
|
||||
myIcon.setIconPainted(false);
|
||||
setToolTipText(myEmptyText);
|
||||
repaint();
|
||||
}
|
||||
|
||||
public boolean shouldBlink() {
|
||||
return myMessagePool.hasUnreadMessages();
|
||||
}
|
||||
}
|
||||
|
||||
private static class IconWrapper implements Icon {
|
||||
private Icon myIcon;
|
||||
private boolean myEnabled;
|
||||
private boolean myShouldPaint = true;
|
||||
|
||||
public IconWrapper(Icon aIcon) {
|
||||
myIcon = aIcon;
|
||||
}
|
||||
|
||||
public void setIconPainted(boolean aPainted) {
|
||||
myEnabled = aPainted;
|
||||
}
|
||||
|
||||
public int getIconHeight() {
|
||||
return myIcon.getIconHeight();
|
||||
}
|
||||
|
||||
public int getIconWidth() {
|
||||
return myIcon.getIconWidth();
|
||||
}
|
||||
|
||||
public void paintIcon(Component c, Graphics g, int x, int y) {
|
||||
if (myEnabled && myShouldPaint) {
|
||||
myIcon.paintIcon(c, g, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
public void setVisible(final boolean visible) {
|
||||
myShouldPaint = visible;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2004 by JetBrains s.r.o. All Rights Reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
package jetbrains.fbq.diagnostic;
|
||||
|
||||
import com.intellij.openapi.diagnostic.IdeaLoggingEvent;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import org.apache.log4j.spi.LoggingEvent;
|
||||
|
||||
public class LogMessage extends AbstractMessage {
|
||||
|
||||
static final String NO_MESSAGE = "No message";
|
||||
|
||||
private String myHeader = NO_MESSAGE;
|
||||
private final Throwable myThrowable;
|
||||
|
||||
public LogMessage(LoggingEvent aEvent) {
|
||||
super();
|
||||
|
||||
myThrowable = aEvent.getThrowableInformation() == null ? null : aEvent.getThrowableInformation().getThrowable();
|
||||
|
||||
if (aEvent.getMessage().toString().length() == 0) {
|
||||
myHeader = getThrowable().toString();
|
||||
} else {
|
||||
myHeader = aEvent.getMessage().toString();
|
||||
}
|
||||
}
|
||||
|
||||
public LogMessage(IdeaLoggingEvent aEvent) {
|
||||
super();
|
||||
|
||||
myThrowable = aEvent.getThrowable();
|
||||
|
||||
if (StringUtil.isNotEmpty(aEvent.getMessage())) {
|
||||
myHeader = aEvent.getMessage();
|
||||
}
|
||||
|
||||
if (myThrowable != null && StringUtil.isNotEmpty(myThrowable.getMessage())) {
|
||||
if (myHeader != NO_MESSAGE ) {
|
||||
if (!myHeader.endsWith(": ") && !myHeader.endsWith(":")) {
|
||||
myHeader += ": ";
|
||||
}
|
||||
myHeader += myThrowable.getMessage();
|
||||
}
|
||||
else {
|
||||
myHeader = myThrowable.getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Throwable getThrowable() {
|
||||
return myThrowable;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return myHeader;
|
||||
}
|
||||
|
||||
public String getThrowableText() {
|
||||
return StringUtil.getThrowableText(getThrowable());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2004 by JetBrains s.r.o. All Rights Reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
package jetbrains.fbq.diagnostic;
|
||||
|
||||
import com.intellij.openapi.diagnostic.IdeaLoggingEvent;
|
||||
import org.apache.log4j.Category;
|
||||
import org.apache.log4j.Priority;
|
||||
import org.apache.log4j.spi.LoggingEvent;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class MessagePool {
|
||||
|
||||
private static int MAX_POOL_SIZE_FOR_FATALS = 100;
|
||||
|
||||
private static MessagePool ourInstance;
|
||||
|
||||
private List<AbstractMessage> myIdeFatals = new ArrayList<AbstractMessage>();
|
||||
|
||||
private Set<MessagePoolListener> myListeners = new HashSet<MessagePoolListener>();
|
||||
|
||||
private MessageGrouper myFatalsGrouper;
|
||||
private boolean ourJvmIsShuttingDown = false;
|
||||
|
||||
MessagePool(int maxGroupSize, int timeout) {
|
||||
myFatalsGrouper = new MessageGrouper("Fatal Errors Grouper", timeout, maxGroupSize);
|
||||
}
|
||||
|
||||
public static MessagePool getInstance() {
|
||||
if (ourInstance == null) {
|
||||
ourInstance = new MessagePool(20, 1000);
|
||||
}
|
||||
|
||||
return ourInstance;
|
||||
}
|
||||
|
||||
public void addIdeFatalMessage(LoggingEvent aEvent) {
|
||||
addIdeFatalMessage(new LogMessage(aEvent));
|
||||
}
|
||||
|
||||
public void addIdeFatalMessage(IdeaLoggingEvent aEvent) {
|
||||
addIdeFatalMessage(new LogMessage(aEvent));
|
||||
}
|
||||
|
||||
private void addIdeFatalMessage(LogMessage message) {
|
||||
if (myIdeFatals.size() < MAX_POOL_SIZE_FOR_FATALS) {
|
||||
myFatalsGrouper.add(message);
|
||||
} else if (myIdeFatals.size() == MAX_POOL_SIZE_FOR_FATALS) {
|
||||
myFatalsGrouper.add(new LogMessage(new LoggingEvent("Too many IDE fatal errors. Monitoring stoppped.", Category.getRoot(), Priority.ERROR, null, new Exception())));
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isFatalErrorsPoolEmpty() {
|
||||
return myIdeFatals.isEmpty();
|
||||
}
|
||||
|
||||
public boolean hasUnreadMessages() {
|
||||
for (int i = 0; i < myIdeFatals.size(); i++) {
|
||||
AbstractMessage message = myIdeFatals.get(i);
|
||||
if (!message.isRead()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public List<AbstractMessage> getFatalErrors(boolean aIncludeReadMessages, boolean aIncludeSubmittedMessages) {
|
||||
List<AbstractMessage> result = new ArrayList<AbstractMessage>();
|
||||
for (int i = 0; i < myIdeFatals.size(); i++) {
|
||||
AbstractMessage each = myIdeFatals.get(i);
|
||||
if (!each.isRead() && !each.isSumbitted()) {
|
||||
result.add(each);
|
||||
} else if ((each.isRead() && aIncludeReadMessages) || (each.isSumbitted() && aIncludeSubmittedMessages)) {
|
||||
result.add(each);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void clearFatals() {
|
||||
myIdeFatals.clear();
|
||||
notifyListenersClear();
|
||||
}
|
||||
|
||||
public void addListener(MessagePoolListener aListener) {
|
||||
myListeners.add(aListener);
|
||||
}
|
||||
|
||||
public void removeListener(MessagePoolListener aListener) {
|
||||
myListeners.remove(aListener);
|
||||
}
|
||||
|
||||
private void notifyListenersAdd() {
|
||||
if (ourJvmIsShuttingDown) return;
|
||||
for (Iterator<MessagePoolListener> iterator = myListeners.iterator(); iterator.hasNext();) {
|
||||
iterator.next().newEntryAdded();
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyListenersClear() {
|
||||
final MessagePoolListener[] messagePoolListeners = myListeners.toArray(new MessagePoolListener[myListeners.size()]);
|
||||
for (int i = 0; i < messagePoolListeners.length; i++) {
|
||||
messagePoolListeners[i].poolCleared();
|
||||
}
|
||||
}
|
||||
|
||||
public void setJvmIsShuttingDown() {
|
||||
ourJvmIsShuttingDown = true;
|
||||
}
|
||||
|
||||
private class MessageGrouper extends Thread {
|
||||
|
||||
private int myTimeOut;
|
||||
private int myMaxGroupSize;
|
||||
|
||||
private final List<AbstractMessage> myMessages = new ArrayList<AbstractMessage>();
|
||||
private int myAccumulatedTime;
|
||||
|
||||
public MessageGrouper(String name, int timeout, int maxGroupSize) {
|
||||
setName(name);
|
||||
myTimeOut = timeout;
|
||||
myMaxGroupSize = maxGroupSize;
|
||||
start();
|
||||
}
|
||||
|
||||
/** @noinspection BusyWait*/
|
||||
public void run() {
|
||||
while (true) {
|
||||
try {
|
||||
sleep(50);
|
||||
myAccumulatedTime += 50;
|
||||
if (myAccumulatedTime > myTimeOut) {
|
||||
synchronized(myMessages) {
|
||||
if (myMessages.size() > 0) {
|
||||
post();
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void post() {
|
||||
AbstractMessage message;
|
||||
if (myMessages.size() == 1) {
|
||||
message = myMessages.get(0);
|
||||
} else {
|
||||
message = new GroupedLogMessage(new ArrayList<AbstractMessage>(myMessages));
|
||||
}
|
||||
myMessages.clear();
|
||||
myIdeFatals.add(message);
|
||||
notifyListenersAdd();
|
||||
myAccumulatedTime = 0;
|
||||
}
|
||||
|
||||
public void add(AbstractMessage message) {
|
||||
myAccumulatedTime = 0;
|
||||
synchronized(myMessages) {
|
||||
myMessages.add(message);
|
||||
if (myMessages.size() >= myMaxGroupSize) {
|
||||
post();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2004 by JetBrains s.r.o. All Rights Reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
package jetbrains.fbq.diagnostic;
|
||||
|
||||
public interface MessagePoolListener {
|
||||
|
||||
void newEntryAdded();
|
||||
void poolCleared();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2004 by JetBrains s.r.o. All Rights Reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
package jetbrains.fbq.ide.reporter;
|
||||
|
||||
public class ConnectionException extends Exception {
|
||||
|
||||
public ConnectionException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public ConnectionException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public ConnectionException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user