GT-3610 - Updated the analysis log message dialog to not stretch the

entirety of the screen; fixed flax in MessageLog
This commit is contained in:
dragonmacher 2020-03-20 18:40:21 -04:00
parent 9e568c9de3
commit d52c417327
11 changed files with 134 additions and 115 deletions

View file

@ -44,6 +44,7 @@ public abstract class AbstractDemanglerAnalyzer extends AbstractAnalyzer {
public AbstractDemanglerAnalyzer(String name, String description) { public AbstractDemanglerAnalyzer(String name, String description) {
super(name, description, AnalyzerType.BYTE_ANALYZER); super(name, description, AnalyzerType.BYTE_ANALYZER);
setPriority(AnalysisPriority.DATA_TYPE_PROPOGATION.before().before().before()); setPriority(AnalysisPriority.DATA_TYPE_PROPOGATION.before().before().before());
setSupportsOneTimeAnalysis();
} }
@Override @Override
@ -58,7 +59,7 @@ public abstract class AbstractDemanglerAnalyzer extends AbstractAnalyzer {
DemanglerOptions options = getOptions(); DemanglerOptions options = getOptions();
if (!validateOptions(options, log)) { if (!validateOptions(options, log)) {
log.error(getName(), "Invalid demangler options--cannot demangle"); log.appendMsg(getName(), "Invalid demangler options--cannot demangle");
return false; return false;
} }

View file

@ -849,9 +849,6 @@ public class AutoAnalysisManager implements DomainObjectListener, DomainObjectCl
for (AutoAnalysisManagerListener listener : listeners) { for (AutoAnalysisManagerListener listener : listeners) {
listener.analysisEnded(this); listener.analysisEnded(this);
} }
if (log.getMsgCount() > 0) {
Msg.info(AutoAnalysisManager.class, log.toString());
}
log.clear(); log.clear();
} }

View file

@ -319,9 +319,16 @@ public class AutoAnalysisPlugin extends Plugin implements AutoAnalysisManagerLis
@Override @Override
public void analysisEnded(AutoAnalysisManager manager) { public void analysisEnded(AutoAnalysisManager manager) {
MessageLog log = manager.getMessageLog(); MessageLog log = manager.getMessageLog();
if (log.getMsgCount() > 0) { if (log.hasMessages()) {
log.write(AutoAnalysisManager.class, "Analysis Log Messages");
String shortMessage = "There were warnings/errors issued during analysis.";
String detailedMessage =
"(These messages are also written to the application log file)\n\n" +
log.toString();
MultiLineMessageDialog dialog = new MultiLineMessageDialog("Auto Analysis Summary", MultiLineMessageDialog dialog = new MultiLineMessageDialog("Auto Analysis Summary",
"There were warnings/errors issued during analysis.", log.toString(), shortMessage, detailedMessage,
MultiLineMessageDialog.WARNING_MESSAGE, false);//modal? MultiLineMessageDialog.WARNING_MESSAGE, false);//modal?
DockingWindowManager.showDialog(null, dialog); DockingWindowManager.showDialog(null, dialog);
} }

View file

@ -499,9 +499,7 @@ public class ExporterDialog extends DialogComponentProvider implements AddressFa
resultsBuffer.append("Format: " + exporter.getName() + "\n\n"); resultsBuffer.append("Format: " + exporter.getName() + "\n\n");
MessageLog log = exporter.getMessageLog(); MessageLog log = exporter.getMessageLog();
if (log != null) {
resultsBuffer.append(log.toString()); resultsBuffer.append(log.toString());
}
HelpLocation helpLocation = new HelpLocation(GenericHelpTopics.ABOUT, "About_Program"); HelpLocation helpLocation = new HelpLocation(GenericHelpTopics.ABOUT, "About_Program");

View file

@ -145,9 +145,11 @@ public class ImportBatchTask extends Task {
Object consumer = new Object(); Object consumer = new Object();
try { try {
MessageLog messageLog = new MessageLog(); MessageLog messageLog = new MessageLog();
List<DomainObject> importedObjects = loadSpec.getLoader().load(byteProvider, List<DomainObject> importedObjects = loadSpec.getLoader()
.load(byteProvider,
fixupProjectFilename(destInfo.second), destInfo.first, loadSpec, fixupProjectFilename(destInfo.second), destInfo.first, loadSpec,
getOptionsFor(batchLoadConfig, loadSpec, byteProvider), messageLog, consumer, getOptionsFor(batchLoadConfig, loadSpec, byteProvider), messageLog,
consumer,
monitor); monitor);
// TODO: accumulate batch results // TODO: accumulate batch results
@ -163,7 +165,7 @@ public class ImportBatchTask extends Task {
Msg.info(this, "Imported " + destInfo.first + "/ " + destInfo.second + ", " + Msg.info(this, "Imported " + destInfo.first + "/ " + destInfo.second + ", " +
totalAppsImported + " of " + totalEnabledApps); totalAppsImported + " of " + totalEnabledApps);
if (messageLog.getMsgCount() > 0) { if (messageLog.hasMessages()) {
Msg.info(this, "Additional info:\n" + messageLog.toString()); Msg.info(this, "Additional info:\n" + messageLog.toString());
} }
} }

View file

@ -74,7 +74,8 @@ public class AndroidProjectCreator {
public void create(TaskMonitor monitor) throws IOException, CancelledException { public void create(TaskMonitor monitor) throws IOException, CancelledException {
createEclipseProjectDirectories(); createEclipseProjectDirectories();
try (ZipFileSystem fs = FileSystemService.getInstance().mountSpecificFileSystem( try (ZipFileSystem fs = FileSystemService.getInstance()
.mountSpecificFileSystem(
apkFile.getFSRL(), ZipFileSystem.class, monitor)) { apkFile.getFSRL(), ZipFileSystem.class, monitor)) {
List<GFile> listing = fs.getListing(null); List<GFile> listing = fs.getListing(null);
processListing(eclipseProjectDirectory, listing, monitor); processListing(eclipseProjectDirectory, listing, monitor);
@ -163,7 +164,8 @@ public class AndroidProjectCreator {
private void processDex(File outputDirectory, GFile dexFile, TaskMonitor monitor) private void processDex(File outputDirectory, GFile dexFile, TaskMonitor monitor)
throws IOException, CancelledException { throws IOException, CancelledException {
try (DexToJarFileSystem fs = FileSystemService.getInstance().mountSpecificFileSystem( try (DexToJarFileSystem fs = FileSystemService.getInstance()
.mountSpecificFileSystem(
dexFile.getFSRL(), DexToJarFileSystem.class, monitor)) { dexFile.getFSRL(), DexToJarFileSystem.class, monitor)) {
GFile jarFile = fs.getJarFile(); GFile jarFile = fs.getJarFile();
processJar(srcDirectory, jarFile.getFSRL(), monitor); processJar(srcDirectory, jarFile.getFSRL(), monitor);
@ -176,7 +178,7 @@ public class AndroidProjectCreator {
JarDecompiler decompiler = new JarDecompiler(jarFile, outputDirectory); JarDecompiler decompiler = new JarDecompiler(jarFile, outputDirectory);
decompiler.decompile(monitor); decompiler.decompile(monitor);
if (decompiler.getLog().getMsgCount() > 0) { if (decompiler.getLog().hasMessages()) {
log.copyFrom(decompiler.getLog()); log.copyFrom(decompiler.getLog());
} }
} }
@ -199,7 +201,8 @@ public class AndroidProjectCreator {
private void processXML(File outputDirectory, GFile containerFile, TaskMonitor monitor) private void processXML(File outputDirectory, GFile containerFile, TaskMonitor monitor)
throws CancelledException { throws CancelledException {
try (AndroidXmlFileSystem fs = FileSystemService.getInstance().mountSpecificFileSystem( try (AndroidXmlFileSystem fs = FileSystemService.getInstance()
.mountSpecificFileSystem(
containerFile.getFSRL(), AndroidXmlFileSystem.class, monitor)) { containerFile.getFSRL(), AndroidXmlFileSystem.class, monitor)) {
GFile xmlFile = fs.getPayloadFile(); GFile xmlFile = fs.getPayloadFile();
copyStream(fs.getInputStream(xmlFile, monitor), outputDirectory, copyStream(fs.getInputStream(xmlFile, monitor), outputDirectory,

View file

@ -128,7 +128,7 @@ public class FileFormatsPlugin extends Plugin implements FrontEndable {
new AndroidProjectCreator(refdFile.file, outputDirectory); new AndroidProjectCreator(refdFile.file, outputDirectory);
creator.create(monitor); creator.create(monitor);
if (creator.getLog().getMsgCount() > 0) { if (creator.getLog().hasMessages()) {
Msg.showInfo(this, getTool().getActiveWindow(), "Export to Eclipse Project", Msg.showInfo(this, getTool().getActiveWindow(), "Export to Eclipse Project",
creator.getLog().toString()); creator.getLog().toString());
} }
@ -194,7 +194,7 @@ public class FileFormatsPlugin extends Plugin implements FrontEndable {
new JarDecompiler(jarFSRL, outputDirectory); new JarDecompiler(jarFSRL, outputDirectory);
decompiler.decompile(monitor); decompiler.decompile(monitor);
if (decompiler.getLog().getMsgCount() > 0) { if (decompiler.getLog().hasMessages()) {
Msg.showInfo(this, gTree, Msg.showInfo(this, gTree,
"Decompiling Jar " + jarFSRL.getName(), "Decompiling Jar " + jarFSRL.getName(),
decompiler.getLog().toString()); decompiler.getLog().toString());

View file

@ -133,7 +133,7 @@ public class GnuDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
return true; return true;
} }
catch (IOException e) { catch (IOException e) {
log.error(getName(), "Invalid options for GNU dangler '" + demanglerName + log.appendMsg(getName(), "Invalid options for GNU dangler '" + demanglerName +
"': " + applicationArguments); "': " + applicationArguments);
log.appendException(e); log.appendException(e);
} }
@ -148,7 +148,7 @@ public class GnuDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
return true; return true;
} }
catch (IOException e) { catch (IOException e) {
log.error(getName(), log.appendMsg(getName(),
"Invalid options for GNU dangler '" + deprecatedName + "': " + "Invalid options for GNU dangler '" + deprecatedName + "': " +
applicationArguments); applicationArguments);
log.appendException(e); log.appendException(e);

View file

@ -108,7 +108,7 @@ class LoadPdbTask extends Task {
Msg.showError(getClass(), null, "Load PDB Failed", message, t); Msg.showError(getClass(), null, "Load PDB Failed", message, t);
} }
if (log.getMsgCount() > 0) { if (log.hasMessages()) {
MultiLineMessageDialog dialog = new MultiLineMessageDialog("Load PDB File", MultiLineMessageDialog dialog = new MultiLineMessageDialog("Load PDB File",
"There were warnings/errors loading the PDB file.", log.toString(), "There were warnings/errors loading the PDB file.", log.toString(),
MultiLineMessageDialog.WARNING_MESSAGE, false); MultiLineMessageDialog.WARNING_MESSAGE, false);

View file

@ -104,34 +104,41 @@ public class MultiLineMessageDialog extends DialogComponentProvider {
// In this case, we are also inserting a <body> that specifies the font-family // In this case, we are also inserting a <body> that specifies the font-family
// to get us back to the same font the rest of the GUI is using. // to get us back to the same font the rest of the GUI is using.
JTextPane textpane = new JTextPane(); JTextPane textPane = new JTextPane();
String fontfamily = textpane.getFont().getFamily(); String fontfamily = textPane.getFont().getFamily();
detailedMessage = "<html><body style=\"font-family: " + fontfamily + "\">" + detailedMessage = "<html><body style=\"font-family: " + fontfamily + "\">" +
detailedMessage.substring(6); detailedMessage.substring(6);
// Set the textpane to not auto-scroll to bottom when adding text // Set the textpane to not auto-scroll to bottom when adding text
DefaultCaret caret = (DefaultCaret) textpane.getCaret(); DefaultCaret caret = (DefaultCaret) textPane.getCaret();
caret.setUpdatePolicy(DefaultCaret.NEVER_UPDATE); caret.setUpdatePolicy(DefaultCaret.NEVER_UPDATE);
textpane.setContentType("text/html"); textPane.setContentType("text/html");
textpane.setText(detailedMessage); textPane.setText(detailedMessage);
textpane.setEditable(false); textPane.setEditable(false);
DockingUtils.setTransparent(textpane); DockingUtils.setTransparent(textPane);
JScrollPane scrollPane = new JScrollPane(textpane); JScrollPane scrollPane = new JScrollPane(textPane);
DockingUtils.setTransparent(scrollPane); DockingUtils.setTransparent(scrollPane);
scrollPane.setBorder(BorderFactory.createEmptyBorder()); scrollPane.setBorder(BorderFactory.createEmptyBorder());
workPanel.add(scrollPane, BorderLayout.CENTER); workPanel.add(scrollPane, BorderLayout.CENTER);
// note: this must be done after adding the text component to the scroll pane
// (seems like the scroll pane is changing the border)
textPane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
} }
else { else {
JTextArea textarea = new JTextArea(detailedMessage); JTextArea textArea = new JTextArea(detailedMessage);
textarea.setEditable(false); textArea.setEditable(false);
DockingUtils.setTransparent(textarea); DockingUtils.setTransparent(textArea);
JScrollPane scrollPane = new JScrollPane(textarea); JScrollPane scrollPane = new JScrollPane(textArea);
DockingUtils.setTransparent(scrollPane); DockingUtils.setTransparent(scrollPane);
scrollPane.setBorder(BorderFactory.createEmptyBorder());
workPanel.add(scrollPane, BorderLayout.CENTER); workPanel.add(scrollPane, BorderLayout.CENTER);
// note: this must be done after adding the text component to the scroll pane
// (seems like the scroll pane is changing the border)
textArea.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
} }
Icon icon = OptionDialog.getIconForMessageType(messageType); Icon icon = OptionDialog.getIconForMessageType(messageType);
@ -147,10 +154,14 @@ public class MultiLineMessageDialog extends DialogComponentProvider {
setFocusComponent(okButton); setFocusComponent(okButton);
setDefaultButton(okButton); setDefaultButton(okButton);
setRememberSize(false); setRememberSize(false);
// A somewhat arbitrary number to prevent the dialog from stretching across the screen
setPreferredSize(600, 300);
} }
@Override @Override
protected void okCallback() { protected void okCallback() {
close(); close();
} }
} }

View file

@ -15,51 +15,41 @@
*/ */
package ghidra.app.util.importer; package ghidra.app.util.importer;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import ghidra.util.Msg; import ghidra.util.Msg;
import ghidra.util.exception.AssertException; import utilities.util.reflection.ReflectionUtilities;
/** /**
* A simple class to handle logging messages and exceptions. A maximum message count size * A simple class to handle logging messages and exceptions. A maximum message count size
* constraint can be set to clip messages after a certain number, but still keep incrementing * constraint can be set to clip messages after a certain number, but still keep incrementing
* a running total. * a running total.
*
* <p>In addition to logging messages, clients can also set a status message. This message may
* later used as the primary error message when reporting to the user.
*/ */
public class MessageLog { public class MessageLog {
/** /**
* The default number of messages to store before clipping * The default number of messages to store before clipping
*/ */
public final static int MAX_COUNT = 500; private final static int MAX_COUNT = 500;
private StringBuffer buffer = new StringBuffer(); private List<String> messages = new ArrayList<>();
private int maxSize; private int maxSize = MAX_COUNT;
private int count; private int count;
private int pos = -1; private String statusMsg = StringUtils.EMPTY;
private String statusMsg;
/**
* Constructs a new message log using the default message count
*/
public MessageLog() {
this(MAX_COUNT);
}
/**
* Constructs a new message log using the specified message count
* @param maxSize the maximum number of messages
*/
public MessageLog(int maxSize) {
this.maxSize = maxSize;
clearStatus();
}
/** /**
* Copies the contents of one message log into this one * Copies the contents of one message log into this one
* @param log the log to copy from * @param log the log to copy from
*/ */
public void copyFrom(MessageLog log) { public void copyFrom(MessageLog log) {
this.buffer = new StringBuffer(log.buffer); for (String otherMessage : log.messages) {
this.maxSize = log.maxSize; add(otherMessage);
this.count = log.count; }
this.pos = log.pos;
} }
/** /**
@ -67,7 +57,7 @@ public class MessageLog {
* @param message the message * @param message the message
*/ */
public void appendMsg(String message) { public void appendMsg(String message) {
msg(message); add(message);
} }
/** /**
@ -78,10 +68,10 @@ public class MessageLog {
*/ */
public void appendMsg(String originator, String message) { public void appendMsg(String originator, String message) {
if (originator == null) { if (originator == null) {
msg(message); add(message);
} }
else { else {
msg(originator + "> " + message); add(originator + "> " + message);
} }
} }
@ -91,7 +81,7 @@ public class MessageLog {
* @param message the message * @param message the message
*/ */
public void appendMsg(int lineNum, String message) { public void appendMsg(int lineNum, String message) {
msg("Line #" + lineNum + " - " + message); add("Line #" + lineNum + " - " + message);
} }
/** /**
@ -99,31 +89,39 @@ public class MessageLog {
* @param t the exception to append to the log * @param t the exception to append to the log
*/ */
public void appendException(Throwable t) { public void appendException(Throwable t) {
if (t instanceof NullPointerException || t instanceof AssertException) { String asString = ReflectionUtilities.stackTraceToString(t);
Msg.error(this, "Exception appended to MessageLog", t); add(asString);
}
else {
Msg.debug(this, "Exception appended to MessageLog", t);
}
String msg = t.toString();
msg(msg);
} }
/** /**
* Returns the message count * Readable method for appending error messages to the log.
* @return the message count *
* <p>Currently does nothing different than {@link #appendMsg(String, String)}.
*
*
* @param originator the originator of the message
* @param message the message
* @deprecated use {@link #appendMsg(String)}
*/ */
public int getMsgCount() { @Deprecated
return count; public void error(String originator, String message) {
appendMsg(originator, message);
}
/**
* Returns true if this log has messages
* @return true if this log has messages
*/
public boolean hasMessages() {
return count > 0;
} }
/** /**
* Clears all messages from this log and resets the count * Clears all messages from this log and resets the count
*/ */
public void clear() { public void clear() {
buffer = new StringBuffer(); messages = new ArrayList<>();
count = 0; count = 0;
pos = -1;
} }
/** /**
@ -138,7 +136,7 @@ public class MessageLog {
* Clear status message * Clear status message
*/ */
public void clearStatus() { public void clearStatus() {
statusMsg = ""; statusMsg = StringUtils.EMPTY;
} }
/** /**
@ -151,39 +149,41 @@ public class MessageLog {
@Override @Override
public String toString() { public String toString() {
if (count > maxSize) { return toStringWithWarning();
if (pos > -1) {
buffer.delete(pos, buffer.length());
}
pos = buffer.length();
buffer.append("\n \n");
buffer.append("There were too many messages to display.\n");
buffer.append("" + (count - maxSize) + " messages have been truncated.");
buffer.append("\n \n");
}
return buffer.toString();
}
private void msg(String msg) {
if (msg == null || msg.length() == 0) {//discard if null...
return;
}
if (count++ < maxSize) {
buffer.append(msg);
buffer.append("\n");
}
} }
/** /**
* Readable method for appending error messages to the log. * Writes this log's contents to the application log
* * @param owner the owning class whose name will appear in the log message
* <p>Currently does nothing different than {@link #appendMsg(String, String)}. * @param messageHeader the message header that will appear before the log messages
*
*
* @param originator the originator of the message
* @param message the message
*/ */
public void error(String originator, String message) { public void write(Class<?> owner, String messageHeader) {
appendMsg(originator, message); String header = StringUtils.defaultIfBlank(messageHeader, "Log Messages");
Msg.info(owner, header + '\n' + toStringWithWarning());
}
private String toStringWithWarning() {
StringBuilder output = new StringBuilder();
if (count > maxSize) {
output.append('\n').append('\n');
output.append("There were too many messages to display.\n");
output.append((count - maxSize)).append(" messages have been truncated.");
output.append('\n').append('\n');
}
for (String s : messages) {
output.append(s).append('\n');
}
return output.toString();
}
private void add(String msg) {
if (StringUtils.isBlank(msg)) {
return;
}
if (count++ < maxSize) {
messages.add(msg);
}
} }
} }