mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 10:49:34 +02:00
Revert "GP-65 - Error Dialog - updated the error dialog to accumulate errors while it is open instead of repeatedly showing new dialogs"
This reverts commit 6d3ff619fd
.
This commit is contained in:
parent
2892aeadc7
commit
765bd8aa3d
12 changed files with 437 additions and 691 deletions
|
@ -1,47 +0,0 @@
|
||||||
/* ###
|
|
||||||
* IP: GHIDRA
|
|
||||||
*
|
|
||||||
* 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 docking;
|
|
||||||
|
|
||||||
import utility.function.Callback;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A dialog that is meant to be extended for showing exceptions
|
|
||||||
*/
|
|
||||||
abstract class AbstractErrDialog extends DialogComponentProvider {
|
|
||||||
|
|
||||||
// at some point, there are too many exceptions to show
|
|
||||||
protected static final int MAX_EXCEPTIONS = 100;
|
|
||||||
protected static final String TITLE_TEXT = "Multiple Errors";
|
|
||||||
|
|
||||||
private Callback closedCallback = Callback.dummy();
|
|
||||||
|
|
||||||
protected AbstractErrDialog(String title) {
|
|
||||||
super(title, true, false, true, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected final void dialogClosed() {
|
|
||||||
closedCallback.call();
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract void addException(String message, Throwable t);
|
|
||||||
|
|
||||||
abstract int getExceptionCount();
|
|
||||||
|
|
||||||
void setClosedCallback(Callback callback) {
|
|
||||||
closedCallback = Callback.dummyIfNull(callback);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -17,23 +17,16 @@ package docking;
|
||||||
|
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.Window;
|
import java.awt.Window;
|
||||||
|
import java.io.*;
|
||||||
|
|
||||||
|
import docking.widgets.OkDialog;
|
||||||
import docking.widgets.OptionDialog;
|
import docking.widgets.OptionDialog;
|
||||||
import ghidra.util.*;
|
import ghidra.util.*;
|
||||||
import ghidra.util.exception.MultipleCauses;
|
import ghidra.util.exception.MultipleCauses;
|
||||||
|
|
||||||
public class DockingErrorDisplay implements ErrorDisplay {
|
public class DockingErrorDisplay implements ErrorDisplay {
|
||||||
|
|
||||||
/**
|
private static final int TRACE_BUFFER_SIZE = 250;
|
||||||
* Error dialog used to append exceptions.
|
|
||||||
*
|
|
||||||
* <p>While this dialog is showing all new exceptions will be added to the dialog. When
|
|
||||||
* this dialog is closed, this reference will be cleared.
|
|
||||||
*
|
|
||||||
* <p>Note: all use of this variable <b>must be on the Swing thread</b> to avoid thread
|
|
||||||
* visibility issues.
|
|
||||||
*/
|
|
||||||
private static AbstractErrDialog activeDialog;
|
|
||||||
|
|
||||||
ConsoleErrorDisplay consoleDisplay = new ConsoleErrorDisplay();
|
ConsoleErrorDisplay consoleDisplay = new ConsoleErrorDisplay();
|
||||||
|
|
||||||
|
@ -59,8 +52,8 @@ public class DockingErrorDisplay implements ErrorDisplay {
|
||||||
|
|
||||||
private void displayMessage(MessageType messageType, ErrorLogger errorLogger, Object originator,
|
private void displayMessage(MessageType messageType, ErrorLogger errorLogger, Object originator,
|
||||||
Component parent, String title, Object message, Throwable throwable) {
|
Component parent, String title, Object message, Throwable throwable) {
|
||||||
|
|
||||||
int dialogType = OptionDialog.PLAIN_MESSAGE;
|
int dialogType = OptionDialog.PLAIN_MESSAGE;
|
||||||
|
|
||||||
String messageString = message != null ? message.toString() : null;
|
String messageString = message != null ? message.toString() : null;
|
||||||
String rawMessage = HTMLUtilities.fromHTML(messageString);
|
String rawMessage = HTMLUtilities.fromHTML(messageString);
|
||||||
switch (messageType) {
|
switch (messageType) {
|
||||||
|
@ -82,7 +75,7 @@ public class DockingErrorDisplay implements ErrorDisplay {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
showDialog(title, throwable, dialogType, messageString, getWindow(parent));
|
showDialog(title, message, throwable, dialogType, messageString, getWindow(parent));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Component getWindow(Component component) {
|
private Component getWindow(Component component) {
|
||||||
|
@ -92,36 +85,33 @@ public class DockingErrorDisplay implements ErrorDisplay {
|
||||||
return component;
|
return component;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showDialog(final String title, final Throwable throwable,
|
private void showDialog(final String title, final Object message, final Throwable throwable,
|
||||||
final int dialogType, final String messageString, final Component parent) {
|
final int dialogType, final String messageString, final Component parent) {
|
||||||
Swing.runIfSwingOrRunLater(
|
SystemUtilities.runIfSwingOrPostSwingLater(
|
||||||
() -> showDialogOnSwing(title, throwable, dialogType, messageString, parent));
|
() -> doShowDialog(title, message, throwable, dialogType, messageString, parent));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showDialogOnSwing(String title, Throwable throwable,
|
private void doShowDialog(final String title, final Object message, final Throwable throwable,
|
||||||
int dialogType, String messageString, Component parent) {
|
int dialogType, String messageString, Component parent) {
|
||||||
|
DialogComponentProvider dialog = null;
|
||||||
if (activeDialog != null) {
|
if (throwable != null) {
|
||||||
activeDialog.addException(messageString, throwable);
|
dialog = createErrorDialog(title, message, throwable, messageString);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
activeDialog = createErrorDialog(title, throwable, messageString);
|
dialog = new OkDialog(title, messageString, dialogType);
|
||||||
activeDialog.setClosedCallback(() -> {
|
}
|
||||||
activeDialog.setClosedCallback(null);
|
DockingWindowManager.showDialog(parent, dialog);
|
||||||
activeDialog = null;
|
|
||||||
});
|
|
||||||
DockingWindowManager.showDialog(parent, activeDialog);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private AbstractErrDialog createErrorDialog(String title, Throwable throwable,
|
private DialogComponentProvider createErrorDialog(final String title, final Object message,
|
||||||
String messageString) {
|
final Throwable throwable, String messageString) {
|
||||||
|
|
||||||
if (containsMultipleCauses(throwable)) {
|
if (containsMultipleCauses(throwable)) {
|
||||||
return new ErrLogExpandableDialog(title, messageString, throwable);
|
return new ErrLogExpandableDialog(title, messageString, throwable);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ErrLogDialog.createExceptionDialog(title, messageString, throwable);
|
return ErrLogDialog.createExceptionDialog(title, messageString,
|
||||||
|
buildStackTrace(throwable, message == null ? throwable.getMessage() : messageString));
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean containsMultipleCauses(Throwable throwable) {
|
private boolean containsMultipleCauses(Throwable throwable) {
|
||||||
|
@ -135,4 +125,34 @@ public class DockingErrorDisplay implements ErrorDisplay {
|
||||||
|
|
||||||
return containsMultipleCauses(throwable.getCause());
|
return containsMultipleCauses(throwable.getCause());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a displayable stack trace from a Throwable
|
||||||
|
*
|
||||||
|
* @param t the throwable
|
||||||
|
* @param msg message prefix
|
||||||
|
* @return multi-line stack trace
|
||||||
|
*/
|
||||||
|
private String buildStackTrace(Throwable t, String msg) {
|
||||||
|
StringBuffer sb = new StringBuffer(TRACE_BUFFER_SIZE);
|
||||||
|
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
PrintStream ps = new PrintStream(baos);
|
||||||
|
|
||||||
|
if (msg != null) {
|
||||||
|
ps.println(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
t.printStackTrace(ps);
|
||||||
|
sb.append(baos.toString());
|
||||||
|
ps.close();
|
||||||
|
try {
|
||||||
|
baos.close();
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
// shouldn't happen--not really connected to the system
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,35 +20,20 @@ import java.awt.event.ComponentAdapter;
|
||||||
import java.awt.event.ComponentEvent;
|
import java.awt.event.ComponentEvent;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
|
|
||||||
import docking.widgets.ScrollableTextArea;
|
import docking.widgets.ScrollableTextArea;
|
||||||
import docking.widgets.label.GHtmlLabel;
|
import docking.widgets.label.GHtmlLabel;
|
||||||
import docking.widgets.label.GIconLabel;
|
import docking.widgets.label.GIconLabel;
|
||||||
import docking.widgets.table.*;
|
|
||||||
import generic.json.Json;
|
|
||||||
import generic.util.WindowUtilities;
|
import generic.util.WindowUtilities;
|
||||||
import ghidra.docking.settings.Settings;
|
|
||||||
import ghidra.framework.Application;
|
import ghidra.framework.Application;
|
||||||
import ghidra.framework.plugintool.ServiceProvider;
|
|
||||||
import ghidra.framework.plugintool.ServiceProviderStub;
|
|
||||||
import ghidra.util.HTMLUtilities;
|
import ghidra.util.HTMLUtilities;
|
||||||
import ghidra.util.Swing;
|
|
||||||
import ghidra.util.table.column.DefaultTimestampRenderer;
|
|
||||||
import ghidra.util.table.column.GColumnRenderer;
|
|
||||||
import utilities.util.reflection.ReflectionUtilities;
|
|
||||||
|
|
||||||
/**
|
public class ErrLogDialog extends DialogComponentProvider {
|
||||||
* A dialog that takes error text and displays it with an option details button. If there is
|
private static final int TEXT_ROWS = 30;
|
||||||
* an {@link ErrorReporter}, then a button is provided to report the error.
|
|
||||||
*/
|
|
||||||
public class ErrLogDialog extends AbstractErrDialog {
|
|
||||||
private static final int TEXT_ROWS = 20;
|
|
||||||
private static final int TEXT_COLUMNS = 80;
|
private static final int TEXT_COLUMNS = 80;
|
||||||
|
private static final int ERROR_BUFFER_SIZE = 1024;
|
||||||
|
|
||||||
private static final String SEND = "Log Error...";
|
private static final String SEND = "Log Error...";
|
||||||
private static final String DETAIL = "Details >>>";
|
private static final String DETAIL = "Details >>>";
|
||||||
|
@ -61,30 +46,32 @@ public class ErrLogDialog extends AbstractErrDialog {
|
||||||
/** tracks 'details panel' open state across invocations */
|
/** tracks 'details panel' open state across invocations */
|
||||||
private static boolean isShowingDetails = false;
|
private static boolean isShowingDetails = false;
|
||||||
|
|
||||||
private int errorId = 0;
|
|
||||||
|
|
||||||
// state-dependent gui members
|
// state-dependent gui members
|
||||||
private ErrorDetailsSplitPane detailsPane;
|
private ErrorDetailsPanel detailsPanel;
|
||||||
private JButton detailsButton;
|
private JButton detailsButton;
|
||||||
private JButton sendButton;
|
private JButton sendButton;
|
||||||
private JPanel mainPanel;
|
private JPanel mainPanel;
|
||||||
private static ErrorReporter errorReporter;
|
private static ErrorReporter errorReporter;
|
||||||
|
|
||||||
private List<ErrEntry> errors = new ArrayList<>();
|
public static ErrLogDialog createExceptionDialog(String title, String message, String details) {
|
||||||
|
return new ErrLogDialog(title, message, details, true);
|
||||||
public static ErrLogDialog createExceptionDialog(String title, String message, Throwable t) {
|
|
||||||
return new ErrLogDialog(title, message, t);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ErrLogDialog(String title, String message, Throwable throwable) {
|
public static ErrLogDialog createLogMessageDialog(String title, String message,
|
||||||
super(title != null ? title : "Error");
|
String details) {
|
||||||
|
return new ErrLogDialog(title, message, details, false);
|
||||||
ErrEntry error = new ErrEntry(message, throwable);
|
}
|
||||||
errors.add(error);
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
* Used by the Err class's static methods for logging various
|
||||||
|
* kinds of errors: Runtime, System, User, Asserts
|
||||||
|
*/
|
||||||
|
private ErrLogDialog(String title, String message, String details, boolean isException) {
|
||||||
|
super(title != null ? title : "Error", true, false, true, false);
|
||||||
setRememberSize(false);
|
setRememberSize(false);
|
||||||
setRememberLocation(false);
|
setRememberLocation(false);
|
||||||
buildMainPanel(message);
|
buildMainPanel(message, addUsefulReportingInfo(details), isException);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String addUsefulReportingInfo(String details) {
|
private String addUsefulReportingInfo(String details) {
|
||||||
|
@ -140,21 +127,13 @@ public class ErrLogDialog extends AbstractErrDialog {
|
||||||
return errorReporter;
|
return errorReporter;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void buildMainPanel(String message) {
|
private void buildMainPanel(String message, String details, boolean isException) {
|
||||||
|
|
||||||
JPanel introPanel = new JPanel(new BorderLayout(10, 10));
|
JPanel introPanel = new JPanel(new BorderLayout(10, 10));
|
||||||
introPanel.add(
|
introPanel.add(
|
||||||
new GIconLabel(UIManager.getIcon("OptionPane.errorIcon"), SwingConstants.RIGHT),
|
new GIconLabel(UIManager.getIcon("OptionPane.errorIcon"), SwingConstants.RIGHT),
|
||||||
BorderLayout.WEST);
|
BorderLayout.WEST);
|
||||||
introPanel.add(new GHtmlLabel(HTMLUtilities.toHTML(message)) {
|
introPanel.add(new GHtmlLabel(HTMLUtilities.toHTML(message)), BorderLayout.CENTER);
|
||||||
@Override
|
|
||||||
public Dimension getPreferredSize() {
|
|
||||||
// rendering HTML the label can expand larger than the screen; keep it reasonable
|
|
||||||
Dimension size = super.getPreferredSize();
|
|
||||||
size.width = 300;
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
}, BorderLayout.CENTER);
|
|
||||||
|
|
||||||
mainPanel = new JPanel(new BorderLayout(10, 20));
|
mainPanel = new JPanel(new BorderLayout(10, 20));
|
||||||
mainPanel.add(introPanel, BorderLayout.NORTH);
|
mainPanel.add(introPanel, BorderLayout.NORTH);
|
||||||
|
@ -162,15 +141,21 @@ public class ErrLogDialog extends AbstractErrDialog {
|
||||||
sendButton = new JButton(SEND);
|
sendButton = new JButton(SEND);
|
||||||
sendButton.addActionListener(e -> sendDetails());
|
sendButton.addActionListener(e -> sendDetails());
|
||||||
|
|
||||||
|
detailsPanel = new ErrorDetailsPanel();
|
||||||
detailsButton = new JButton(isShowingDetails ? CLOSE : DETAIL);
|
detailsButton = new JButton(isShowingDetails ? CLOSE : DETAIL);
|
||||||
detailsButton.addActionListener(e -> {
|
detailsButton.addActionListener(e -> {
|
||||||
String label = detailsButton.getText();
|
String label = detailsButton.getText();
|
||||||
showDetails(label.equals(DETAIL));
|
showDetails(label.equals(DETAIL));
|
||||||
});
|
});
|
||||||
|
|
||||||
detailsPane = new ErrorDetailsSplitPane();
|
if (isException) {
|
||||||
|
detailsPanel.setExceptionMessage(details);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
detailsPanel.setLogMessage(details);
|
||||||
|
}
|
||||||
|
|
||||||
JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.LEADING, 5, 5));
|
JPanel buttonPanel = new JPanel(new GridLayout(2, 1, 5, 5));
|
||||||
buttonPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
|
buttonPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
|
||||||
if (errorReporter != null) {
|
if (errorReporter != null) {
|
||||||
buttonPanel.add(sendButton);
|
buttonPanel.add(sendButton);
|
||||||
|
@ -178,16 +163,16 @@ public class ErrLogDialog extends AbstractErrDialog {
|
||||||
buttonPanel.add(detailsButton);
|
buttonPanel.add(detailsButton);
|
||||||
|
|
||||||
introPanel.add(buttonPanel, BorderLayout.EAST);
|
introPanel.add(buttonPanel, BorderLayout.EAST);
|
||||||
mainPanel.add(detailsPane, BorderLayout.CENTER);
|
mainPanel.add(detailsPanel, BorderLayout.CENTER);
|
||||||
|
|
||||||
addWorkPanel(mainPanel);
|
addWorkPanel(mainPanel);
|
||||||
|
|
||||||
addOKButton();
|
addOKButton();
|
||||||
setDefaultButton(okButton);
|
|
||||||
|
|
||||||
// show the details panel if it was showing previously
|
// show the details panel if it was showing previously
|
||||||
detailsPane.setVisible(isShowingDetails);
|
detailsPanel.setVisible(isShowingDetails);
|
||||||
detailsPane.selectFirstError();
|
|
||||||
|
// setHelpLocation(new HelpLocation(HelpTopics.INTRO, "Err"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -200,156 +185,56 @@ public class ErrLogDialog extends AbstractErrDialog {
|
||||||
cancelCallback();
|
cancelCallback();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send error details from dialog.
|
||||||
|
*/
|
||||||
private void sendDetails() {
|
private void sendDetails() {
|
||||||
String details = detailsPane.getDetails();
|
String details = detailsPanel.getDetails();
|
||||||
String title = getTitle();
|
String title = getTitle();
|
||||||
close();
|
close();
|
||||||
errorReporter.report(rootPanel, title, details);
|
errorReporter.report(rootPanel, title, details);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* opens and closes the details panel; used also by Err when
|
||||||
|
* showLog is called from SessionGui Help menu to show details
|
||||||
|
* when visible
|
||||||
|
*/
|
||||||
private void showDetails(boolean visible) {
|
private void showDetails(boolean visible) {
|
||||||
isShowingDetails = visible;
|
isShowingDetails = visible;
|
||||||
String label = (visible ? CLOSE : DETAIL);
|
String label = (visible ? CLOSE : DETAIL);
|
||||||
detailsButton.setText(label);
|
detailsButton.setText(label);
|
||||||
detailsPane.setVisible(visible);
|
detailsPanel.setVisible(visible);
|
||||||
repack(); // need to re-pack so the detailsPanel can be hidden correctly
|
repack(); // need to re-pack so the detailsPanel can be hidden correctly
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// custom "pack" so the detailsPanel can be shown/hidden correctly
|
||||||
|
@Override
|
||||||
|
protected void repack() {
|
||||||
|
|
||||||
|
// hide the dialog so that the user doesn't see us resize and then move it, which looks
|
||||||
|
// awkward
|
||||||
|
getDialog().setVisible(false);
|
||||||
|
|
||||||
|
detailsPanel.invalidate(); // force to be invalid so resizes correctly
|
||||||
|
rootPanel.validate();
|
||||||
|
|
||||||
|
super.repack();
|
||||||
|
|
||||||
|
// center the dialog after its size changes for a cleaner appearance
|
||||||
|
DockingDialog dialog = getDialog();
|
||||||
|
Container parent = dialog.getParent();
|
||||||
|
Point centerPoint = WindowUtilities.centerOnComponent(parent, dialog);
|
||||||
|
dialog.setLocation(centerPoint);
|
||||||
|
|
||||||
|
getDialog().setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void dialogShown() {
|
protected void dialogShown() {
|
||||||
|
|
||||||
|
// TODO test that the parent DockingDialog code handles this....
|
||||||
WindowUtilities.ensureOnScreen(getDialog());
|
WindowUtilities.ensureOnScreen(getDialog());
|
||||||
Swing.runLater(() -> okButton.requestFocusInWindow());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
void addException(String message, Throwable t) {
|
|
||||||
|
|
||||||
int n = errors.size();
|
|
||||||
if (n > MAX_EXCEPTIONS) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
errors.add(new ErrEntry(message, t));
|
|
||||||
|
|
||||||
detailsPane.update();
|
|
||||||
|
|
||||||
// signal the new error
|
|
||||||
setTitle(TITLE_TEXT + " (" + n + 1 + ")");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
int getExceptionCount() {
|
|
||||||
return errors.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
private class ErrorDetailsSplitPane extends JSplitPane {
|
|
||||||
|
|
||||||
private final double TOP_PREFERRED_RESIZE_WEIGHT = .80;
|
|
||||||
private ErrorDetailsPanel detailsPanel;
|
|
||||||
private ErrorDetailsTablePanel tablePanel;
|
|
||||||
|
|
||||||
private Dimension openedSize;
|
|
||||||
|
|
||||||
ErrorDetailsSplitPane() {
|
|
||||||
super(VERTICAL_SPLIT);
|
|
||||||
setResizeWeight(TOP_PREFERRED_RESIZE_WEIGHT);
|
|
||||||
|
|
||||||
detailsPanel = new ErrorDetailsPanel();
|
|
||||||
tablePanel = new ErrorDetailsTablePanel();
|
|
||||||
|
|
||||||
setTopComponent(detailsPanel);
|
|
||||||
setBottomComponent(tablePanel);
|
|
||||||
|
|
||||||
addComponentListener(new ComponentAdapter() {
|
|
||||||
@Override
|
|
||||||
public void componentResized(ComponentEvent event) {
|
|
||||||
if (!isShowing()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Rectangle localBounds = getBounds();
|
|
||||||
if (!detailsButton.getText().equals(DETAIL)) {
|
|
||||||
openedSize = new Dimension(localBounds.width, localBounds.height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void selectFirstError() {
|
|
||||||
tablePanel.selectFirstError();
|
|
||||||
}
|
|
||||||
|
|
||||||
String getDetails() {
|
|
||||||
return detailsPanel.getDetails();
|
|
||||||
}
|
|
||||||
|
|
||||||
void setExceptionMessage(String s) {
|
|
||||||
detailsPanel.setExceptionMessage(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
void update() {
|
|
||||||
tablePanel.update();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Dimension getPreferredSize() {
|
|
||||||
Dimension superSize = super.getPreferredSize();
|
|
||||||
if (detailsButton.getText().equals(DETAIL)) {
|
|
||||||
return superSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (openedSize == null) {
|
|
||||||
return superSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
return openedSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private class ErrorDetailsTablePanel extends JPanel {
|
|
||||||
|
|
||||||
private ErrEntryTableModel model;
|
|
||||||
private GTable errorsTable;
|
|
||||||
private GTableFilterPanel<ErrEntry> tableFilterPanel;
|
|
||||||
|
|
||||||
ErrorDetailsTablePanel() {
|
|
||||||
setLayout(new BorderLayout());
|
|
||||||
model = new ErrEntryTableModel();
|
|
||||||
errorsTable = new GTable(model);
|
|
||||||
tableFilterPanel = new GTableFilterPanel<ErrEntry>(errorsTable, model);
|
|
||||||
|
|
||||||
errorsTable.getSelectionManager().addListSelectionListener(e -> {
|
|
||||||
if (e.getValueIsAdjusting()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int firstIndex = errorsTable.getSelectedRow();
|
|
||||||
if (firstIndex == -1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ErrEntry err = tableFilterPanel.getRowObject(firstIndex);
|
|
||||||
detailsPane.setExceptionMessage(err.getDetailsText());
|
|
||||||
});
|
|
||||||
|
|
||||||
JPanel tablePanel = new JPanel(new BorderLayout());
|
|
||||||
tablePanel.add(new JScrollPane(errorsTable), BorderLayout.CENTER);
|
|
||||||
tablePanel.add(tableFilterPanel, BorderLayout.SOUTH);
|
|
||||||
|
|
||||||
add(tablePanel, BorderLayout.CENTER);
|
|
||||||
|
|
||||||
// initialize this value to something small so the full dialog will not consume the
|
|
||||||
// entire screen height
|
|
||||||
setPreferredSize(new Dimension(400, 100));
|
|
||||||
}
|
|
||||||
|
|
||||||
void selectFirstError() {
|
|
||||||
errorsTable.selectRow(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void update() {
|
|
||||||
model.fireTableDataChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -359,178 +244,76 @@ public class ErrLogDialog extends AbstractErrDialog {
|
||||||
*/
|
*/
|
||||||
private class ErrorDetailsPanel extends JPanel {
|
private class ErrorDetailsPanel extends JPanel {
|
||||||
private ScrollableTextArea textDetails;
|
private ScrollableTextArea textDetails;
|
||||||
|
private StringBuffer errorDetailsBuffer;
|
||||||
|
private Dimension closedSize;
|
||||||
|
private Dimension openedSize;
|
||||||
|
|
||||||
private ErrorDetailsPanel() {
|
private ErrorDetailsPanel() {
|
||||||
super(new BorderLayout(0, 0));
|
super(new BorderLayout(0, 0));
|
||||||
|
errorDetailsBuffer = new StringBuffer(ERROR_BUFFER_SIZE);
|
||||||
textDetails = new ScrollableTextArea(TEXT_ROWS, TEXT_COLUMNS);
|
textDetails = new ScrollableTextArea(TEXT_ROWS, TEXT_COLUMNS);
|
||||||
textDetails.setEditable(false);
|
textDetails.setEditable(false);
|
||||||
|
|
||||||
add(textDetails, BorderLayout.CENTER);
|
add(textDetails, BorderLayout.CENTER);
|
||||||
|
|
||||||
validate();
|
validate();
|
||||||
textDetails.scrollToBottom();
|
textDetails.scrollToBottom();
|
||||||
|
|
||||||
|
// set the initial preferred size of this panel
|
||||||
|
// when "closed"
|
||||||
|
Rectangle bounds = getBounds();
|
||||||
|
closedSize = new Dimension(bounds.width, 0);
|
||||||
|
|
||||||
|
addComponentListener(new ComponentAdapter() {
|
||||||
|
@Override
|
||||||
|
public void componentResized(ComponentEvent event) {
|
||||||
|
if (!isShowing()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Rectangle localBounds = getBounds();
|
||||||
|
if (detailsButton.getText().equals(DETAIL)) {
|
||||||
|
closedSize.width = localBounds.width;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
openedSize = new Dimension(localBounds.width, localBounds.height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dimension getPreferredSize() {
|
||||||
|
if (detailsButton.getText().equals(DETAIL)) {
|
||||||
|
return closedSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (openedSize == null) {
|
||||||
|
return super.getPreferredSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
return openedSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* resets the current error buffer to the contents of msg
|
||||||
|
*/
|
||||||
|
private void setLogMessage(String msg) {
|
||||||
|
errorDetailsBuffer = new StringBuffer(msg);
|
||||||
|
textDetails.setText(msg);
|
||||||
|
|
||||||
|
// scroll to bottom so user is viewing the last message
|
||||||
|
textDetails.scrollToBottom();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setExceptionMessage(String message) {
|
private void setExceptionMessage(String msg) {
|
||||||
|
errorDetailsBuffer = new StringBuffer(msg);
|
||||||
String updated = addUsefulReportingInfo(message);
|
textDetails.setText(msg);
|
||||||
textDetails.setText(updated);
|
|
||||||
|
|
||||||
// scroll to the top the see the pertinent part of the exception
|
// scroll to the top the see the pertinent part of the exception
|
||||||
textDetails.scrollToTop();
|
textDetails.scrollToTop();
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getDetails() {
|
private final String getDetails() {
|
||||||
return textDetails.getText();
|
return errorDetailsBuffer.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ErrEntry {
|
|
||||||
|
|
||||||
private String message;
|
|
||||||
private String details;
|
|
||||||
private Date timestamp = new Date();
|
|
||||||
private int myId = ++errorId;
|
|
||||||
|
|
||||||
ErrEntry(String message, Throwable t) {
|
|
||||||
String updated = message;
|
|
||||||
if (HTMLUtilities.isHTML(updated)) {
|
|
||||||
updated = HTMLUtilities.fromHTML(updated);
|
|
||||||
}
|
|
||||||
this.message = updated;
|
|
||||||
|
|
||||||
if (t != null) {
|
|
||||||
this.details = ReflectionUtilities.stackTraceToString(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int getId() {
|
|
||||||
return myId;
|
|
||||||
}
|
|
||||||
|
|
||||||
String getMessage() {
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
|
|
||||||
Date getTimestamp() {
|
|
||||||
return timestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
String getDetailsText() {
|
|
||||||
if (details == null) {
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
return details;
|
|
||||||
}
|
|
||||||
|
|
||||||
String getDetails() {
|
|
||||||
return details;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return Json.toString(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class ErrEntryTableModel extends GDynamicColumnTableModel<ErrEntry, Object> {
|
|
||||||
|
|
||||||
public ErrEntryTableModel() {
|
|
||||||
super(new ServiceProviderStub());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected TableColumnDescriptor<ErrEntry> createTableColumnDescriptor() {
|
|
||||||
TableColumnDescriptor<ErrEntry> descriptor = new TableColumnDescriptor<ErrEntry>();
|
|
||||||
descriptor.addVisibleColumn(new IdColumn(), 1, true);
|
|
||||||
descriptor.addVisibleColumn(new MessageColumn());
|
|
||||||
descriptor.addHiddenColumn(new DetailsColumn());
|
|
||||||
descriptor.addVisibleColumn(new TimestampColumn());
|
|
||||||
return descriptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getName() {
|
|
||||||
return "Unexpectd Errors";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<ErrEntry> getModelData() {
|
|
||||||
return errors;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object getDataSource() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private class IdColumn extends AbstractDynamicTableColumnStub<ErrEntry, Integer> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Integer getValue(ErrEntry rowObject, Settings settings, ServiceProvider sp)
|
|
||||||
throws IllegalArgumentException {
|
|
||||||
return rowObject.getId();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getColumnName() {
|
|
||||||
return "#";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getColumnPreferredWidth() {
|
|
||||||
return 40;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class MessageColumn extends AbstractDynamicTableColumnStub<ErrEntry, String> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getValue(ErrEntry rowObject, Settings settings, ServiceProvider sp)
|
|
||||||
throws IllegalArgumentException {
|
|
||||||
return rowObject.getMessage();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getColumnName() {
|
|
||||||
return "Message";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private class DetailsColumn extends AbstractDynamicTableColumnStub<ErrEntry, String> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getValue(ErrEntry rowObject, Settings settings, ServiceProvider sp)
|
|
||||||
throws IllegalArgumentException {
|
|
||||||
return rowObject.getDetails();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getColumnName() {
|
|
||||||
return "Details";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class TimestampColumn extends AbstractDynamicTableColumnStub<ErrEntry, Date> {
|
|
||||||
|
|
||||||
private GColumnRenderer<Date> renderer = new DefaultTimestampRenderer();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Date getValue(ErrEntry rowObject, Settings settings, ServiceProvider sp)
|
|
||||||
throws IllegalArgumentException {
|
|
||||||
return rowObject.getTimestamp();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getColumnName() {
|
|
||||||
return "Time";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public GColumnRenderer<Date> getColumnRenderer() {
|
|
||||||
return renderer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,12 +32,12 @@ import docking.widgets.label.GHtmlLabel;
|
||||||
import docking.widgets.tree.*;
|
import docking.widgets.tree.*;
|
||||||
import docking.widgets.tree.support.GTreeDragNDropHandler;
|
import docking.widgets.tree.support.GTreeDragNDropHandler;
|
||||||
import ghidra.util.*;
|
import ghidra.util.*;
|
||||||
import ghidra.util.exception.MultipleCauses;
|
import ghidra.util.exception.*;
|
||||||
import ghidra.util.html.HTMLElement;
|
import ghidra.util.html.HTMLElement;
|
||||||
import resources.ResourceManager;
|
import resources.ResourceManager;
|
||||||
import util.CollectionUtils;
|
import util.CollectionUtils;
|
||||||
|
|
||||||
public class ErrLogExpandableDialog extends AbstractErrDialog {
|
public class ErrLogExpandableDialog extends DialogComponentProvider {
|
||||||
public static ImageIcon IMG_REPORT = ResourceManager.loadImage("images/report.png");
|
public static ImageIcon IMG_REPORT = ResourceManager.loadImage("images/report.png");
|
||||||
public static ImageIcon IMG_EXCEPTION = ResourceManager.loadImage("images/exception.png");
|
public static ImageIcon IMG_EXCEPTION = ResourceManager.loadImage("images/exception.png");
|
||||||
public static ImageIcon IMG_FRAME_ELEMENT =
|
public static ImageIcon IMG_FRAME_ELEMENT =
|
||||||
|
@ -53,21 +53,113 @@ public class ErrLogExpandableDialog extends AbstractErrDialog {
|
||||||
private static boolean showingDetails = false;
|
private static boolean showingDetails = false;
|
||||||
|
|
||||||
protected ReportRootNode root;
|
protected ReportRootNode root;
|
||||||
protected GTree tree;
|
protected GTree excTree;
|
||||||
private List<Throwable> errors = new ArrayList<>();
|
|
||||||
|
|
||||||
/** This spacer addresses the optical impression that the message panel changes size when showing details */
|
/** This spacer addresses the optical impression that the message panel changes size when showing details */
|
||||||
protected Component horizontalSpacer;
|
protected Component horizontalSpacer;
|
||||||
protected JButton detailButton;
|
protected JButton detailButton;
|
||||||
protected JButton sendButton;
|
protected JButton sendButton;
|
||||||
|
protected boolean hasConsole = false;
|
||||||
|
|
||||||
protected JPopupMenu popup;
|
protected JPopupMenu popup;
|
||||||
|
|
||||||
protected ErrLogExpandableDialog(String title, String msg, Throwable throwable) {
|
protected static class ExcTreeTransferHandler extends TransferHandler
|
||||||
super(title);
|
implements GTreeDragNDropHandler {
|
||||||
|
|
||||||
errors.add(throwable);
|
protected ReportRootNode root;
|
||||||
|
|
||||||
|
public ExcTreeTransferHandler(ReportRootNode root) {
|
||||||
|
this.root = root;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataFlavor[] getSupportedDataFlavors(List<GTreeNode> transferNodes) {
|
||||||
|
return new DataFlavor[] { DataFlavor.stringFlavor };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Transferable createTransferable(JComponent c) {
|
||||||
|
ArrayList<GTreeNode> nodes = new ArrayList<>();
|
||||||
|
for (TreePath path : ((JTree) c).getSelectionPaths()) {
|
||||||
|
nodes.add((GTreeNode) path.getLastPathComponent());
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return new StringSelection(
|
||||||
|
(String) getTransferData(nodes, DataFlavor.stringFlavor));
|
||||||
|
}
|
||||||
|
catch (UnsupportedFlavorException e) {
|
||||||
|
Msg.debug(this, e.getMessage(), e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getTransferData(List<GTreeNode> transferNodes, DataFlavor flavor)
|
||||||
|
throws UnsupportedFlavorException {
|
||||||
|
if (flavor != DataFlavor.stringFlavor) {
|
||||||
|
throw new UnsupportedFlavorException(flavor);
|
||||||
|
}
|
||||||
|
if (transferNodes.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (transferNodes.size() == 1) {
|
||||||
|
GTreeNode node = transferNodes.get(0);
|
||||||
|
if (node instanceof NodeWithText) {
|
||||||
|
return ((NodeWithText) node).collectReportText(transferNodes, 0).trim();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return root.collectReportText(transferNodes, 0).trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isStartDragOk(List<GTreeNode> dragUserData, int dragAction) {
|
||||||
|
for (GTreeNode node : dragUserData) {
|
||||||
|
if (node instanceof NodeWithText) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSupportedDragActions() {
|
||||||
|
return DnDConstants.ACTION_COPY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSourceActions(JComponent c) {
|
||||||
|
return COPY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDropSiteOk(GTreeNode destUserData, DataFlavor[] flavors, int dropAction) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void drop(GTreeNode destUserData, Transferable transferable, int dropAction) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ErrLogExpandableDialog(String title, String msg, MultipleCauses mc) {
|
||||||
|
this(title, msg, mc.getCauses(), null, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ErrLogExpandableDialog(String title, String msg, Throwable exc) {
|
||||||
|
this(title, msg, Collections.singletonList(exc), HasConsoleText.Util.get(exc), true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ErrLogExpandableDialog(String title, String msg, Collection<Throwable> report) {
|
||||||
|
this(title, msg, report, null, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ErrLogExpandableDialog(String title, String msg, Collection<Throwable> report,
|
||||||
|
String console, boolean modal, boolean hasDismiss) {
|
||||||
|
super(title, modal);
|
||||||
|
|
||||||
|
hasConsole = console != null;
|
||||||
popup = new JPopupMenu();
|
popup = new JPopupMenu();
|
||||||
JMenuItem menuCopy = new JMenuItem("Copy");
|
JMenuItem menuCopy = new JMenuItem("Copy");
|
||||||
menuCopy.setActionCommand((String) TransferHandler.getCopyAction().getValue(Action.NAME));
|
menuCopy.setActionCommand((String) TransferHandler.getCopyAction().getValue(Action.NAME));
|
||||||
|
@ -81,12 +173,13 @@ public class ErrLogExpandableDialog extends AbstractErrDialog {
|
||||||
msgPanel.setLayout(new BorderLayout(16, 16));
|
msgPanel.setLayout(new BorderLayout(16, 16));
|
||||||
msgPanel.setBorder(new EmptyBorder(16, 16, 16, 16));
|
msgPanel.setBorder(new EmptyBorder(16, 16, 16, 16));
|
||||||
{
|
{
|
||||||
JLabel msgText = new GHtmlLabel(getHTML(msg, CollectionUtils.asSet(throwable))) {
|
JLabel msgText = new GHtmlLabel(getHTML(msg, report)) {
|
||||||
@Override
|
@Override
|
||||||
public Dimension getPreferredSize() {
|
public Dimension getPreferredSize() {
|
||||||
// rendering HTML the label can expand larger than the screen; keep it reasonable
|
// when rendering HTML the label can expand larger than the screen;
|
||||||
|
// keep it reasonable
|
||||||
Dimension size = super.getPreferredSize();
|
Dimension size = super.getPreferredSize();
|
||||||
size.width = 300;
|
size.width = 500;
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -113,7 +206,7 @@ public class ErrLogExpandableDialog extends AbstractErrDialog {
|
||||||
msgPanel.add(buttonBox, BorderLayout.EAST);
|
msgPanel.add(buttonBox, BorderLayout.EAST);
|
||||||
|
|
||||||
horizontalSpacer = Box.createVerticalStrut(10);
|
horizontalSpacer = Box.createVerticalStrut(10);
|
||||||
horizontalSpacer.setVisible(showingDetails);
|
horizontalSpacer.setVisible(showingDetails | hasConsole);
|
||||||
msgPanel.add(horizontalSpacer, BorderLayout.SOUTH);
|
msgPanel.add(horizontalSpacer, BorderLayout.SOUTH);
|
||||||
}
|
}
|
||||||
workPanel.add(msgPanel, BorderLayout.NORTH);
|
workPanel.add(msgPanel, BorderLayout.NORTH);
|
||||||
|
@ -121,8 +214,29 @@ public class ErrLogExpandableDialog extends AbstractErrDialog {
|
||||||
Box workBox = Box.createVerticalBox();
|
Box workBox = Box.createVerticalBox();
|
||||||
{
|
{
|
||||||
|
|
||||||
root = new ReportRootNode(getTitle(), CollectionUtils.asSet(throwable));
|
if (hasConsole) {
|
||||||
tree = new GTree(root) {
|
JTextArea consoleText = new JTextArea(console);
|
||||||
|
JScrollPane consoleScroll =
|
||||||
|
new JScrollPane(consoleText, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
|
||||||
|
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED) {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dimension getPreferredSize() {
|
||||||
|
Dimension dim = super.getPreferredSize();
|
||||||
|
dim.height = 400;
|
||||||
|
dim.width = 800; // trial and error?
|
||||||
|
return dim;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
consoleText.setEditable(false);
|
||||||
|
consoleText.setBackground(Color.BLACK);
|
||||||
|
consoleText.setForeground(Color.WHITE);
|
||||||
|
consoleText.setFont(Font.decode("Monospaced"));
|
||||||
|
workBox.add(consoleScroll);
|
||||||
|
}
|
||||||
|
|
||||||
|
root = new ReportRootNode(getTitle(), report);
|
||||||
|
excTree = new GTree(root) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Dimension getPreferredSize() {
|
public Dimension getPreferredSize() {
|
||||||
|
@ -135,19 +249,19 @@ public class ErrLogExpandableDialog extends AbstractErrDialog {
|
||||||
|
|
||||||
for (GTreeNode node : CollectionUtils.asIterable(root.iterator(true))) {
|
for (GTreeNode node : CollectionUtils.asIterable(root.iterator(true))) {
|
||||||
if (node instanceof ReportExceptionNode) {
|
if (node instanceof ReportExceptionNode) {
|
||||||
tree.expandTree(node);
|
excTree.expandTree(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tree.setSelectedNode(root.getChild(0));
|
excTree.setSelectedNode(root.getChild(0));
|
||||||
tree.setVisible(showingDetails);
|
excTree.setVisible(showingDetails);
|
||||||
ExcTreeTransferHandler handler = new ExcTreeTransferHandler(root);
|
ExcTreeTransferHandler handler = new ExcTreeTransferHandler(root);
|
||||||
tree.setDragNDropHandler(handler);
|
excTree.setDragNDropHandler(handler);
|
||||||
tree.setTransferHandler(handler);
|
excTree.setTransferHandler(handler);
|
||||||
ActionMap map = tree.getActionMap();
|
ActionMap map = excTree.getActionMap();
|
||||||
map.put(TransferHandler.getCopyAction().getValue(Action.NAME),
|
map.put(TransferHandler.getCopyAction().getValue(Action.NAME),
|
||||||
TransferHandler.getCopyAction());
|
TransferHandler.getCopyAction());
|
||||||
tree.addMouseListener(new MouseAdapter() {
|
excTree.addMouseListener(new MouseAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public void mousePressed(MouseEvent e) {
|
public void mousePressed(MouseEvent e) {
|
||||||
maybeShowPopup(e);
|
maybeShowPopup(e);
|
||||||
|
@ -165,19 +279,22 @@ public class ErrLogExpandableDialog extends AbstractErrDialog {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
workBox.add(tree);
|
workBox.add(excTree);
|
||||||
}
|
}
|
||||||
workPanel.add(workBox, BorderLayout.CENTER);
|
workPanel.add(workBox, BorderLayout.CENTER);
|
||||||
repack();
|
repack();
|
||||||
|
|
||||||
addWorkPanel(workPanel);
|
addWorkPanel(workPanel);
|
||||||
|
|
||||||
addDismissButton();
|
if (hasDismiss) {
|
||||||
|
addDismissButton();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getHTML(String msg, Collection<Throwable> report) {
|
private String getHTML(String msg, Collection<Throwable> report) {
|
||||||
|
|
||||||
//
|
//
|
||||||
|
// TODO
|
||||||
// Usage question: The content herein will be escaped unless you call addHTMLContenet().
|
// Usage question: The content herein will be escaped unless you call addHTMLContenet().
|
||||||
// Further, clients can provide messages that contain HTML. Is there a
|
// Further, clients can provide messages that contain HTML. Is there a
|
||||||
// use case where we want to show escaped HTML content?
|
// use case where we want to show escaped HTML content?
|
||||||
|
@ -215,6 +332,14 @@ public class ErrLogExpandableDialog extends AbstractErrDialog {
|
||||||
|
|
||||||
String htmlTMsg = addBR(tMsg);
|
String htmlTMsg = addBR(tMsg);
|
||||||
body.addElement("p").addHTMLContent(htmlTMsg);
|
body.addElement("p").addHTMLContent(htmlTMsg);
|
||||||
|
if (t instanceof CausesImportant) { // I choose not to recurse
|
||||||
|
HTMLElement ul = body.addElement("ul");
|
||||||
|
for (Throwable ts : MultipleCauses.Util.iterCauses(t)) {
|
||||||
|
String tsMsg = getMessage(ts);
|
||||||
|
String htmlTSMsg = addBR(tsMsg);
|
||||||
|
ul.addElement("li").addHTMLContent(htmlTSMsg);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return html.toString();
|
return html.toString();
|
||||||
}
|
}
|
||||||
|
@ -232,15 +357,15 @@ public class ErrLogExpandableDialog extends AbstractErrDialog {
|
||||||
return t.getClass().getSimpleName();
|
return t.getClass().getSimpleName();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void detailCallback() {
|
void detailCallback() {
|
||||||
showingDetails = !showingDetails;
|
showingDetails = !showingDetails;
|
||||||
tree.setVisible(showingDetails);
|
excTree.setVisible(showingDetails);
|
||||||
horizontalSpacer.setVisible(showingDetails);
|
horizontalSpacer.setVisible(showingDetails | hasConsole);
|
||||||
detailButton.setText(showingDetails ? CLOSE : DETAIL);
|
detailButton.setText(showingDetails ? CLOSE : DETAIL);
|
||||||
repack();
|
repack();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendCallback() {
|
void sendCallback() {
|
||||||
String details = root.collectReportText(null, 0).trim();
|
String details = root.collectReportText(null, 0).trim();
|
||||||
String title = getTitle();
|
String title = getTitle();
|
||||||
close();
|
close();
|
||||||
|
@ -254,24 +379,6 @@ public class ErrLogExpandableDialog extends AbstractErrDialog {
|
||||||
return dim;
|
return dim;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addException(String message, Throwable t) {
|
|
||||||
|
|
||||||
int n = errors.size();
|
|
||||||
if (n > MAX_EXCEPTIONS) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
errors.add(t);
|
|
||||||
setTitle(TITLE_TEXT + " (" + n + 1 + ")"); // signal the new error
|
|
||||||
root.addNode(new ReportExceptionNode(t));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
int getExceptionCount() {
|
|
||||||
return root.getChildCount();
|
|
||||||
}
|
|
||||||
|
|
||||||
static interface NodeWithText {
|
static interface NodeWithText {
|
||||||
public String getReportText();
|
public String getReportText();
|
||||||
|
|
||||||
|
@ -421,6 +528,9 @@ public class ErrLogExpandableDialog extends AbstractErrDialog {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getReportText() {
|
public String getReportText() {
|
||||||
|
if (exc instanceof HasConsoleText) {
|
||||||
|
return getName() + "\n" + HasConsoleText.Util.get(exc);
|
||||||
|
}
|
||||||
return getName();
|
return getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -551,87 +661,6 @@ public class ErrLogExpandableDialog extends AbstractErrDialog {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class ExcTreeTransferHandler extends TransferHandler
|
|
||||||
implements GTreeDragNDropHandler {
|
|
||||||
|
|
||||||
protected ReportRootNode root;
|
|
||||||
|
|
||||||
public ExcTreeTransferHandler(ReportRootNode root) {
|
|
||||||
this.root = root;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DataFlavor[] getSupportedDataFlavors(List<GTreeNode> transferNodes) {
|
|
||||||
return new DataFlavor[] { DataFlavor.stringFlavor };
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Transferable createTransferable(JComponent c) {
|
|
||||||
ArrayList<GTreeNode> nodes = new ArrayList<>();
|
|
||||||
for (TreePath path : ((JTree) c).getSelectionPaths()) {
|
|
||||||
nodes.add((GTreeNode) path.getLastPathComponent());
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return new StringSelection(
|
|
||||||
(String) getTransferData(nodes, DataFlavor.stringFlavor));
|
|
||||||
}
|
|
||||||
catch (UnsupportedFlavorException e) {
|
|
||||||
Msg.debug(this, e.getMessage(), e);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object getTransferData(List<GTreeNode> transferNodes, DataFlavor flavor)
|
|
||||||
throws UnsupportedFlavorException {
|
|
||||||
if (flavor != DataFlavor.stringFlavor) {
|
|
||||||
throw new UnsupportedFlavorException(flavor);
|
|
||||||
}
|
|
||||||
if (transferNodes.isEmpty()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (transferNodes.size() == 1) {
|
|
||||||
GTreeNode node = transferNodes.get(0);
|
|
||||||
if (node instanceof NodeWithText) {
|
|
||||||
return ((NodeWithText) node).collectReportText(transferNodes, 0).trim();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return root.collectReportText(transferNodes, 0).trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isStartDragOk(List<GTreeNode> dragUserData, int dragAction) {
|
|
||||||
for (GTreeNode node : dragUserData) {
|
|
||||||
if (node instanceof NodeWithText) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getSupportedDragActions() {
|
|
||||||
return DnDConstants.ACTION_COPY;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getSourceActions(JComponent c) {
|
|
||||||
return COPY;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isDropSiteOk(GTreeNode destUserData, DataFlavor[] flavors, int dropAction) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void drop(GTreeNode destUserData, Transferable transferable, int dropAction) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class TransferActionListener implements ActionListener, PropertyChangeListener {
|
class TransferActionListener implements ActionListener, PropertyChangeListener {
|
||||||
|
|
|
@ -102,7 +102,7 @@ public class ScrollableTextArea extends JScrollPane {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Appends the text to the text area maintained in this scroll pane
|
* Appends the text to the text area maintained in this scrollpane
|
||||||
* @param text the text to append.
|
* @param text the text to append.
|
||||||
*/
|
*/
|
||||||
public void append(String text) {
|
public void append(String text) {
|
||||||
|
@ -111,15 +111,13 @@ public class ScrollableTextArea extends JScrollPane {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of lines current set in the text area
|
* Returns the number of lines current set in the text area
|
||||||
* @return the count
|
|
||||||
*/
|
*/
|
||||||
public int getLineCount() {
|
public int getLineCount() {
|
||||||
return textArea.getLineCount();
|
return textArea.getLineCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the tab size set in the text area
|
* Returns the tabsize set in the text area
|
||||||
* @return the size
|
|
||||||
*/
|
*/
|
||||||
public int getTabSize() {
|
public int getTabSize() {
|
||||||
return textArea.getTabSize();
|
return textArea.getTabSize();
|
||||||
|
@ -127,7 +125,6 @@ public class ScrollableTextArea extends JScrollPane {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the total area height of the text area (row height * line count)
|
* Returns the total area height of the text area (row height * line count)
|
||||||
* @return the height
|
|
||||||
*/
|
*/
|
||||||
public int getTextAreaHeight() {
|
public int getTextAreaHeight() {
|
||||||
return (textArea.getAreaHeight());
|
return (textArea.getAreaHeight());
|
||||||
|
@ -135,7 +132,6 @@ public class ScrollableTextArea extends JScrollPane {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the visible height of the text area
|
* Returns the visible height of the text area
|
||||||
* @return the height
|
|
||||||
*/
|
*/
|
||||||
public int getTextVisibleHeight() {
|
public int getTextVisibleHeight() {
|
||||||
return textArea.getVisibleHeight();
|
return textArea.getVisibleHeight();
|
||||||
|
@ -204,7 +200,6 @@ public class ScrollableTextArea extends JScrollPane {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the text contained within the text area
|
* Returns the text contained within the text area
|
||||||
* @return the text
|
|
||||||
*/
|
*/
|
||||||
public String getText() {
|
public String getText() {
|
||||||
return textArea.getText();
|
return textArea.getText();
|
||||||
|
|
|
@ -1,55 +0,0 @@
|
||||||
/* ###
|
|
||||||
* IP: GHIDRA
|
|
||||||
*
|
|
||||||
* 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 ghidra.util.table.column;
|
|
||||||
|
|
||||||
import java.awt.Component;
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
import javax.swing.JLabel;
|
|
||||||
|
|
||||||
import docking.widgets.table.GTableCellRenderingData;
|
|
||||||
import ghidra.docking.settings.Settings;
|
|
||||||
import ghidra.util.DateUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A renderer for clients that wish to display a {@link Date} as a timestamp with the
|
|
||||||
* date and time.
|
|
||||||
*/
|
|
||||||
public class DefaultTimestampRenderer extends AbstractGColumnRenderer<Date> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Component getTableCellRendererComponent(GTableCellRenderingData data) {
|
|
||||||
|
|
||||||
JLabel label = (JLabel) super.getTableCellRendererComponent(data);
|
|
||||||
Date value = (Date) data.getValue();
|
|
||||||
|
|
||||||
if (value != null) {
|
|
||||||
label.setText(DateUtils.formatDateTimestamp(value));
|
|
||||||
}
|
|
||||||
return label;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getFilterString(Date t, Settings settings) {
|
|
||||||
return DateUtils.formatDateTimestamp(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ColumnConstraintFilterMode getColumnConstraintFilterMode() {
|
|
||||||
// This allows for text filtering in the table and date filtering on columns
|
|
||||||
return ColumnConstraintFilterMode.ALLOW_ALL_FILTERS;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -35,7 +35,7 @@ public class DockingErrorDisplayTest extends AbstractDockingTest {
|
||||||
DockingErrorDisplay display = new DockingErrorDisplay();
|
DockingErrorDisplay display = new DockingErrorDisplay();
|
||||||
DefaultErrorLogger logger = new DefaultErrorLogger();
|
DefaultErrorLogger logger = new DefaultErrorLogger();
|
||||||
Exception exception = new Exception("My test exception");
|
Exception exception = new Exception("My test exception");
|
||||||
reportException(display, logger, exception);
|
doDisplay(display, logger, exception);
|
||||||
|
|
||||||
assertErrLogDialog();
|
assertErrLogDialog();
|
||||||
}
|
}
|
||||||
|
@ -46,29 +46,11 @@ public class DockingErrorDisplayTest extends AbstractDockingTest {
|
||||||
DefaultErrorLogger logger = new DefaultErrorLogger();
|
DefaultErrorLogger logger = new DefaultErrorLogger();
|
||||||
Exception nestedException = new Exception("My nested test exception");
|
Exception nestedException = new Exception("My nested test exception");
|
||||||
Exception exception = new Exception("My test exception", nestedException);
|
Exception exception = new Exception("My test exception", nestedException);
|
||||||
reportException(display, logger, exception);
|
doDisplay(display, logger, exception);
|
||||||
|
|
||||||
assertErrLogDialog();
|
assertErrLogDialog();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testDefaultErrorDisplay_MultipleAsynchronousExceptions() {
|
|
||||||
|
|
||||||
DockingErrorDisplay display = new DockingErrorDisplay();
|
|
||||||
DefaultErrorLogger logger = new DefaultErrorLogger();
|
|
||||||
Exception exception = new Exception("My test exception");
|
|
||||||
reportException(display, logger, exception);
|
|
||||||
|
|
||||||
ErrLogDialog dialog = getErrLogDialog();
|
|
||||||
|
|
||||||
assertExceptionCount(dialog, 1);
|
|
||||||
|
|
||||||
reportException(display, logger, new NullPointerException("It is null!"));
|
|
||||||
assertExceptionCount(dialog, 2);
|
|
||||||
|
|
||||||
close(dialog);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMultipleCausesErrorDisplay() {
|
public void testMultipleCausesErrorDisplay() {
|
||||||
DockingErrorDisplay display = new DockingErrorDisplay();
|
DockingErrorDisplay display = new DockingErrorDisplay();
|
||||||
|
@ -76,51 +58,43 @@ public class DockingErrorDisplayTest extends AbstractDockingTest {
|
||||||
|
|
||||||
Throwable firstCause = new Exception("My test exception - first cause");
|
Throwable firstCause = new Exception("My test exception - first cause");
|
||||||
MultipleCauses exception = new MultipleCauses(Collections.singletonList(firstCause));
|
MultipleCauses exception = new MultipleCauses(Collections.singletonList(firstCause));
|
||||||
reportException(display, logger, exception);
|
doDisplay(display, logger, exception);
|
||||||
|
|
||||||
ErrLogExpandableDialog dialog = assertErrLogExpandableDialog();
|
assertErrLogExpandableDialog();
|
||||||
assertExceptionCount(dialog, 1);
|
|
||||||
|
|
||||||
reportException(display, logger, new NullPointerException("It is null!"));
|
|
||||||
assertExceptionCount(dialog, 2);
|
|
||||||
|
|
||||||
close(dialog);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertExceptionCount(AbstractErrDialog errDialog, int n) {
|
private void assertErrLogExpandableDialog() {
|
||||||
|
Window w = waitForWindow(TEST_TITLE, 2000);
|
||||||
|
assertNotNull(w);
|
||||||
|
|
||||||
int actual = errDialog.getExceptionCount();
|
final ErrLogExpandableDialog errDialog =
|
||||||
assertEquals(n, actual);
|
|
||||||
}
|
|
||||||
|
|
||||||
private ErrLogExpandableDialog assertErrLogExpandableDialog() {
|
|
||||||
Window w = waitForWindow(TEST_TITLE);
|
|
||||||
|
|
||||||
ErrLogExpandableDialog errDialog =
|
|
||||||
getDialogComponentProvider(w, ErrLogExpandableDialog.class);
|
getDialogComponentProvider(w, ErrLogExpandableDialog.class);
|
||||||
assertNotNull(errDialog);
|
assertNotNull(errDialog);
|
||||||
return errDialog;
|
|
||||||
|
runSwing(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
errDialog.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertErrLogDialog() {
|
private void assertErrLogDialog() {
|
||||||
Window w = waitForWindow(TEST_TITLE);
|
Window w = waitForWindow(TEST_TITLE, 2000);
|
||||||
assertNotNull(w);
|
assertNotNull(w);
|
||||||
|
|
||||||
ErrLogDialog errDialog = getDialogComponentProvider(w, ErrLogDialog.class);
|
final ErrLogDialog errDialog = getDialogComponentProvider(w, ErrLogDialog.class);
|
||||||
assertNotNull(errDialog);
|
assertNotNull(errDialog);
|
||||||
close(errDialog);
|
|
||||||
|
runSwing(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
errDialog.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private ErrLogDialog getErrLogDialog() {
|
private void doDisplay(final DockingErrorDisplay display, final DefaultErrorLogger logger,
|
||||||
Window w = waitForWindow(TEST_TITLE);
|
|
||||||
assertNotNull(w);
|
|
||||||
|
|
||||||
ErrLogDialog errDialog = getDialogComponentProvider(w, ErrLogDialog.class);
|
|
||||||
assertNotNull(errDialog);
|
|
||||||
return errDialog;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void reportException(final DockingErrorDisplay display, final DefaultErrorLogger logger,
|
|
||||||
final Throwable throwable) {
|
final Throwable throwable) {
|
||||||
runSwing(new Runnable() {
|
runSwing(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* 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 ghidra.util.exception;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
public interface CausesImportant {
|
||||||
|
public static class Util {
|
||||||
|
public static String getMessages(Throwable exc) {
|
||||||
|
if (exc instanceof CausesImportant) {
|
||||||
|
StringBuilder result = new StringBuilder(exc.getMessage());
|
||||||
|
for (Throwable cause : MultipleCauses.Util.iterCauses(exc)) {
|
||||||
|
result.append(
|
||||||
|
StringUtils.join(Arrays.asList(cause.getMessage().split("\n")), "\n\t"));
|
||||||
|
}
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
return exc.getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
* REVIEWED: YES
|
||||||
|
*
|
||||||
|
* 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 ghidra.util.exception;
|
||||||
|
|
||||||
|
public interface HasConsoleText {
|
||||||
|
public String getConsoleText();
|
||||||
|
|
||||||
|
public static class Util {
|
||||||
|
public static String get(Throwable exc) {
|
||||||
|
if (exc instanceof HasConsoleText) {
|
||||||
|
return ((HasConsoleText) exc).getConsoleText();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -89,7 +89,7 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
||||||
|
|
||||||
protected DBHandle dbHandle;
|
protected DBHandle dbHandle;
|
||||||
private AddressMap addrMap;
|
private AddressMap addrMap;
|
||||||
private ErrorHandler errHandler = new DbErrorHandler();
|
private ErrorHandler errHandler;
|
||||||
private DataTypeConflictHandler currentHandler;
|
private DataTypeConflictHandler currentHandler;
|
||||||
|
|
||||||
private CategoryDB root;
|
private CategoryDB root;
|
||||||
|
@ -168,7 +168,12 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
||||||
*/
|
*/
|
||||||
protected DataTypeManagerDB() {
|
protected DataTypeManagerDB() {
|
||||||
this.lock = new Lock("DataTypeManagerDB");
|
this.lock = new Lock("DataTypeManagerDB");
|
||||||
|
errHandler = new ErrorHandler() {
|
||||||
|
@Override
|
||||||
|
public void dbError(IOException e) {
|
||||||
|
Msg.showError(this, null, "IO ERROR", e.getMessage(), e);
|
||||||
|
}
|
||||||
|
};
|
||||||
try {
|
try {
|
||||||
dbHandle = new DBHandle();
|
dbHandle = new DBHandle();
|
||||||
int id = startTransaction("");
|
int id = startTransaction("");
|
||||||
|
@ -208,6 +213,13 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
||||||
") for read-only Datatype Archive: " + packedDBfile.getAbsolutePath());
|
") for read-only Datatype Archive: " + packedDBfile.getAbsolutePath());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
errHandler = new ErrorHandler() {
|
||||||
|
@Override
|
||||||
|
public void dbError(IOException e) {
|
||||||
|
Msg.showError(this, null, "IO ERROR", e.getMessage(), e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Open packed database archive
|
// Open packed database archive
|
||||||
boolean openSuccess = false;
|
boolean openSuccess = false;
|
||||||
PackedDatabase pdb = null;
|
PackedDatabase pdb = null;
|
||||||
|
@ -4077,20 +4089,6 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class DbErrorHandler implements ErrorHandler {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void dbError(IOException e) {
|
|
||||||
|
|
||||||
String message = e.getMessage();
|
|
||||||
if (e instanceof ClosedException) {
|
|
||||||
message = "Data type archive is closed: " + getName();
|
|
||||||
}
|
|
||||||
|
|
||||||
Msg.showError(this, null, "IO ERROR", message, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -499,31 +499,14 @@ public class ReflectionUtilities {
|
||||||
* @return the string
|
* @return the string
|
||||||
*/
|
*/
|
||||||
public static String stackTraceToString(Throwable t) {
|
public static String stackTraceToString(Throwable t) {
|
||||||
return stackTraceToString(t.getMessage(), t);
|
StringBuffer sb = new StringBuffer();
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Turns the given {@link Throwable} into a String version of its
|
|
||||||
* {@link Throwable#printStackTrace()} method.
|
|
||||||
*
|
|
||||||
* @param message the preferred message to use. If null, the throwable message will be used
|
|
||||||
* @param t the throwable
|
|
||||||
* @return the string
|
|
||||||
*/
|
|
||||||
public static String stackTraceToString(String message, Throwable t) {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
|
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
PrintStream ps = new PrintStream(baos);
|
PrintStream ps = new PrintStream(baos);
|
||||||
|
|
||||||
if (message != null) {
|
String msg = t.getMessage();
|
||||||
ps.println(message);
|
if (msg != null) {
|
||||||
}
|
ps.println(msg);
|
||||||
else {
|
|
||||||
String throwableMessage = t.getMessage();
|
|
||||||
if (throwableMessage != null) {
|
|
||||||
ps.println(throwableMessage);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
t.printStackTrace(ps);
|
t.printStackTrace(ps);
|
||||||
|
|
|
@ -55,8 +55,8 @@ public class IntroScreenShots extends GhidraScreenShotGenerator {
|
||||||
@Test
|
@Test
|
||||||
public void testErr_Dialog() {
|
public void testErr_Dialog() {
|
||||||
runSwing(() -> {
|
runSwing(() -> {
|
||||||
ErrLogDialog dialog = ErrLogDialog.createExceptionDialog("Unexpected Error",
|
ErrLogDialog dialog = ErrLogDialog.createLogMessageDialog("Unexpected Error",
|
||||||
"Oops, this is really bad!", new Throwable());
|
"Oops, this is really bad!", "");
|
||||||
DockingWindowManager.showDialog(null, dialog);
|
DockingWindowManager.showDialog(null, dialog);
|
||||||
}, false);
|
}, false);
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue