GP-825 - Task Dialog - fixed expanding task dialog

This commit is contained in:
dragonmacher 2021-04-26 12:53:23 -04:00
parent ec22f78db9
commit 9c9dcc927a
5 changed files with 102 additions and 64 deletions

View file

@ -485,7 +485,7 @@ public class AutoAnalysisManager implements DomainObjectListener, DomainObjectCl
* NOTE: method may only be invoked within the analysis thread * NOTE: method may only be invoked within the analysis thread
* (i.e., by an Analyzer or AnalysisWorker). Care must be taken to control depth * (i.e., by an Analyzer or AnalysisWorker). Care must be taken to control depth
* of yield, although this may be difficult to control. * of yield, although this may be difficult to control.
* @param monitor * @param monitor the monitor
*/ */
private void yield(Integer limitPriority, TaskMonitor monitor) { private void yield(Integer limitPriority, TaskMonitor monitor) {
@ -516,7 +516,7 @@ public class AutoAnalysisManager implements DomainObjectListener, DomainObjectCl
* (i.e., lower values correspond to higher priority) will be permitted to run. A value * (i.e., lower values correspond to higher priority) will be permitted to run. A value
* of null will allow all pending analysis to complete (excluding any tasks which had * of null will allow all pending analysis to complete (excluding any tasks which had
* previously yielded). * previously yielded).
* @param monitor * @param monitor the monitor
* @throws IllegalStateException if not invoked from the analysis thread. * @throws IllegalStateException if not invoked from the analysis thread.
*/ */
public void waitForAnalysis(final Integer limitPriority, TaskMonitor monitor) { public void waitForAnalysis(final Integer limitPriority, TaskMonitor monitor) {
@ -626,7 +626,7 @@ public class AutoAnalysisManager implements DomainObjectListener, DomainObjectCl
* yield method so that their limit-priority may be established during the yield. * yield method so that their limit-priority may be established during the yield.
* <br> * <br>
* If analysis is performed, a summary of task execution times will be printed to the log. * If analysis is performed, a summary of task execution times will be printed to the log.
* @param monitor * @param monitor the monitor
*/ */
public void startAnalysis(TaskMonitor monitor) { public void startAnalysis(TaskMonitor monitor) {
startAnalysis(monitor, true); startAnalysis(monitor, true);
@ -642,7 +642,7 @@ public class AutoAnalysisManager implements DomainObjectListener, DomainObjectCl
* performed in which all queued tasks of a higher priority (smaller priority value) than the current * performed in which all queued tasks of a higher priority (smaller priority value) than the current
* task will be executed prior to this method returning. AnalysisWorker's should use the * task will be executed prior to this method returning. AnalysisWorker's should use the
* yield method so that their limit-priority may be established during the yield. * yield method so that their limit-priority may be established during the yield.
* @param monitor * @param monitor the monitor
* @param printTaskTimes if true and analysis is performed, a summary of task execution times * @param printTaskTimes if true and analysis is performed, a summary of task execution times
* will be printed to the log. * will be printed to the log.
*/ */
@ -722,7 +722,7 @@ public class AutoAnalysisManager implements DomainObjectListener, DomainObjectCl
/** /**
* Start auto-analysis if it is ENABLED and not yet running. * Start auto-analysis if it is ENABLED and not yet running.
* @param monitor * @param monitor the monitor
* @param yield if true the current thread is the analysis thread and is yielding to the currently * @param yield if true the current thread is the analysis thread and is yielding to the currently
* executing task. * executing task.
* @param limitPriority the threshold priority value. All queued tasks with a priority value * @param limitPriority the threshold priority value. All queued tasks with a priority value
@ -1204,7 +1204,8 @@ public class AutoAnalysisManager implements DomainObjectListener, DomainObjectCl
/** /**
* Get the time taken by a named task * Get the time taken by a named task
* The names of tasks that have run can be retrieved using getTimedTasks * The names of tasks that have run can be retrieved using getTimedTasks
* @param taskName * @param map the times by task names
* @param taskName the task name
* @return the time taken by a named task * @return the time taken by a named task
*/ */
public long getTaskTime(Map<String, Long> map, String taskName) { public long getTaskTime(Map<String, Long> map, String taskName) {
@ -1230,8 +1231,7 @@ public class AutoAnalysisManager implements DomainObjectListener, DomainObjectCl
if (currentTime > 0) { if (currentTime > 0) {
totalTime += currentTime; totalTime += currentTime;
} }
Long l = new Long(totalTime); return totalTime;
return l.longValue();
} }
private void addToTaskTime(String taskName, long time) { private void addToTaskTime(String taskName, long time) {
@ -1252,7 +1252,8 @@ public class AutoAnalysisManager implements DomainObjectListener, DomainObjectCl
} }
/** /**
* Print out the time for each task that ran for this auto analysis run. * Get a summary of the time for each task that ran for this auto analysis run
* @return the string summary
*/ */
public String getTaskTimesString() { public String getTaskTimesString() {
@ -1331,11 +1332,12 @@ public class AutoAnalysisManager implements DomainObjectListener, DomainObjectCl
* follow-on analysis of those changes. If false it is critical that the worker be associated with a modal * follow-on analysis of those changes. If false it is critical that the worker be associated with a modal
* task dialog which will prevent unrelated concurrent changes being made to the program while * task dialog which will prevent unrelated concurrent changes being made to the program while
* the worker is active. * the worker is active.
* @param workerMonitor * @param workerMonitor the worker's monitor
* @return boolean value returned by worker.analysisWorkerCallback * @return boolean value returned by worker.analysisWorkerCallback
* @throws InvocationTargetException if worker throws exception while running (see cause) * @throws InvocationTargetException if worker throws exception while running (see cause)
* @throws InterruptedException if caller's thread is interrupted. If this occurs a cancel * @throws InterruptedException if caller's thread is interrupted. If this occurs a cancel
* condition will be forced on the workerMonitor so that the worker will stop running. * condition will be forced on the workerMonitor so that the worker will stop running.
* @throws CancelledException if the job is cancelled
* @see AnalysisPriority for priority values * @see AnalysisPriority for priority values
*/ */
public boolean scheduleWorker(AnalysisWorker worker, Object workerContext, public boolean scheduleWorker(AnalysisWorker worker, Object workerContext,
@ -1472,17 +1474,17 @@ public class AutoAnalysisManager implements DomainObjectListener, DomainObjectCl
private class JointTaskMonitor implements TaskMonitor { private class JointTaskMonitor implements TaskMonitor {
TaskMonitor dominantMonitor; private TaskMonitor primaryMonitor;
TaskMonitor slaveMonitor; private TaskMonitor secondaryMonitor;
JointTaskMonitor(TaskMonitor dominantMonitor, TaskMonitor slaveMonitor) { JointTaskMonitor(TaskMonitor primaryMonitor, TaskMonitor secondaryMonitor) {
this.dominantMonitor = dominantMonitor; this.primaryMonitor = primaryMonitor;
this.slaveMonitor = slaveMonitor; this.secondaryMonitor = secondaryMonitor;
} }
@Override @Override
public boolean isCancelled() { public boolean isCancelled() {
return dominantMonitor.isCancelled() || slaveMonitor.isCancelled(); return primaryMonitor.isCancelled() || secondaryMonitor.isCancelled();
} }
@Override @Override
@ -1502,86 +1504,86 @@ public class AutoAnalysisManager implements DomainObjectListener, DomainObjectCl
@Override @Override
public void setMessage(String message) { public void setMessage(String message) {
dominantMonitor.setMessage(message); primaryMonitor.setMessage(message);
slaveMonitor.setMessage(message); secondaryMonitor.setMessage(message);
} }
@Override @Override
public String getMessage() { public String getMessage() {
return dominantMonitor.getMessage(); return primaryMonitor.getMessage();
} }
@Override @Override
public void setProgress(long value) { public void setProgress(long value) {
dominantMonitor.setProgress(value); primaryMonitor.setProgress(value);
slaveMonitor.setProgress(value); secondaryMonitor.setProgress(value);
} }
@Override @Override
public void initialize(long max) { public void initialize(long max) {
dominantMonitor.initialize(max); primaryMonitor.initialize(max);
slaveMonitor.initialize(max); secondaryMonitor.initialize(max);
} }
@Override @Override
public void setMaximum(long max) { public void setMaximum(long max) {
dominantMonitor.setMaximum(max); primaryMonitor.setMaximum(max);
slaveMonitor.setMaximum(max); secondaryMonitor.setMaximum(max);
} }
@Override @Override
public long getMaximum() { public long getMaximum() {
return Math.max(dominantMonitor.getMaximum(), slaveMonitor.getMaximum()); return Math.max(primaryMonitor.getMaximum(), secondaryMonitor.getMaximum());
} }
@Override @Override
public void checkCanceled() throws CancelledException { public void checkCanceled() throws CancelledException {
dominantMonitor.checkCanceled(); primaryMonitor.checkCanceled();
slaveMonitor.checkCanceled(); secondaryMonitor.checkCanceled();
} }
@Override @Override
public void incrementProgress(long incrementAmount) { public void incrementProgress(long incrementAmount) {
dominantMonitor.incrementProgress(incrementAmount); primaryMonitor.incrementProgress(incrementAmount);
slaveMonitor.incrementProgress(incrementAmount); secondaryMonitor.incrementProgress(incrementAmount);
} }
@Override @Override
public long getProgress() { public long getProgress() {
return Math.max(dominantMonitor.getProgress(), slaveMonitor.getProgress()); return Math.max(primaryMonitor.getProgress(), secondaryMonitor.getProgress());
} }
@Override @Override
public void cancel() { public void cancel() {
dominantMonitor.cancel(); primaryMonitor.cancel();
slaveMonitor.cancel(); secondaryMonitor.cancel();
} }
@Override @Override
public void addCancelledListener(CancelledListener listener) { public void addCancelledListener(CancelledListener listener) {
dominantMonitor.addCancelledListener(listener); primaryMonitor.addCancelledListener(listener);
} }
@Override @Override
public void removeCancelledListener(CancelledListener listener) { public void removeCancelledListener(CancelledListener listener) {
dominantMonitor.addCancelledListener(listener); primaryMonitor.addCancelledListener(listener);
} }
@Override @Override
public void setCancelEnabled(boolean enable) { public void setCancelEnabled(boolean enable) {
dominantMonitor.setCancelEnabled(enable); primaryMonitor.setCancelEnabled(enable);
slaveMonitor.setCancelEnabled(enable); secondaryMonitor.setCancelEnabled(enable);
} }
@Override @Override
public boolean isCancelEnabled() { public boolean isCancelEnabled() {
return dominantMonitor.isCancelEnabled(); return primaryMonitor.isCancelEnabled();
} }
@Override @Override
public void clearCanceled() { public void clearCanceled() {
dominantMonitor.clearCanceled(); primaryMonitor.clearCanceled();
slaveMonitor.clearCanceled(); secondaryMonitor.clearCanceled();
} }
} }

View file

@ -37,8 +37,7 @@ import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.util.Msg; import ghidra.util.Msg;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
import ghidra.util.task.Task; import ghidra.util.task.*;
import ghidra.util.task.TaskMonitor;
class LoadPdbTask extends Task { class LoadPdbTask extends Task {
private File pdbFile; private File pdbFile;
@ -59,8 +58,15 @@ class LoadPdbTask extends Task {
@Override @Override
public void run(final TaskMonitor monitor) { public void run(final TaskMonitor monitor) {
final MessageLog log = new MessageLog();
WrappingTaskMonitor wrappedMonitor = new WrappingTaskMonitor(monitor) {
@Override
public void initialize(long max) {
// don't let called clients change our monitor type; we don't show progress
}
};
MessageLog log = new MessageLog();
AnalysisWorker worker = new AnalysisWorker() { AnalysisWorker worker = new AnalysisWorker() {
@Override @Override
@ -74,11 +80,11 @@ class LoadPdbTask extends Task {
try { try {
if (useMsDiaParser) { if (useMsDiaParser) {
if (!parseWithMsDiaParser(log, monitor)) { if (!parseWithMsDiaParser(log, wrappedMonitor)) {
return false; return false;
} }
} }
else if (!parseWithNewParser(log, monitor)) { else if (!parseWithNewParser(log, wrappedMonitor)) {
return false; return false;
} }
analyzeSymbols(currentMonitor, log); analyzeSymbols(currentMonitor, log);
@ -92,7 +98,7 @@ class LoadPdbTask extends Task {
try { try {
AutoAnalysisManager.getAnalysisManager(program) AutoAnalysisManager.getAnalysisManager(program)
.scheduleWorker(worker, null, true, monitor); .scheduleWorker(worker, null, true, wrappedMonitor);
if (log.hasMessages()) { 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(),

View file

@ -17,6 +17,8 @@ package pdb;
import java.io.File; import java.io.File;
import javax.swing.SwingConstants;
import docking.action.MenuData; import docking.action.MenuData;
import docking.widgets.OptionDialog; import docking.widgets.OptionDialog;
import docking.widgets.filechooser.GhidraFileChooser; import docking.widgets.filechooser.GhidraFileChooser;
@ -36,6 +38,7 @@ import ghidra.program.util.GhidraProgramUtilities;
import ghidra.util.HelpLocation; import ghidra.util.HelpLocation;
import ghidra.util.Msg; import ghidra.util.Msg;
import ghidra.util.filechooser.ExtensionFileFilter; import ghidra.util.filechooser.ExtensionFileFilter;
import ghidra.util.task.TaskBuilder;
import ghidra.util.task.TaskLauncher; import ghidra.util.task.TaskLauncher;
//@formatter:off //@formatter:off
@ -134,8 +137,12 @@ public class PdbPlugin extends Plugin {
// note: We intentionally use a 0-delay here. Our underlying task may show modal // note: We intentionally use a 0-delay here. Our underlying task may show modal
// dialog prompts. We want the task progress dialog to be showing before any // dialog prompts. We want the task progress dialog to be showing before any
// promts appear. // prompts appear.
LoadPdbTask task = new LoadPdbTask(program, pdb, useMsDiaParser, restrictions, service); LoadPdbTask task = new LoadPdbTask(program, pdb, useMsDiaParser, restrictions, service);
TaskBuilder.withTask(task)
.setStatusTextAlignment(SwingConstants.LEADING)
.setLaunchDelay(0);
new TaskLauncher(task, null, 0); new TaskLauncher(task, null, 0);
} }
catch (Exception pe) { catch (Exception pe) {

View file

@ -33,37 +33,40 @@ import util.CollectionUtils;
* the {@link Task} interface, which means less boiler-plate code. * the {@link Task} interface, which means less boiler-plate code.
* *
* <P>An example of usage: * <P>An example of usage:
* <pre>{@literal * <pre>
* MonitoredRunnable r = * {@literal
* monitor -> doWork(parameter, monitor); * MonitoredRunnable r =
* new TaskBuilder("Task Title", r) * monitor -> doWork(parameter, monitor);
* .setHasProgress(true) *
* .setCanCancel(true) * new TaskBuilder("Task Title", r)
* .setStatusTextAlignment(SwingConstants.LEADING) * .setHasProgress(true)
* .launchModal(); * .setCanCancel(true)
* .setStatusTextAlignment(SwingConstants.LEADING)
* .launchModal();
* }</pre> * }</pre>
* *
* Or, * Or,
* *
* <pre>{@literal * <pre>
* TaskBuilder.withRunnable(monitor -> doWork(parameter, monitor)) * {@literal
* .setTitle("Task Title") * TaskBuilder.withRunnable(monitor -> doWork(parameter, monitor))
* .setHasProgress(true) * .setTitle("Task Title")
* .setCanCancel(true) * .setHasProgress(true)
* .setStatusTextAlignment(SwingConstants.LEADING) * .setCanCancel(true)
* .launchModal(); * .setStatusTextAlignment(SwingConstants.LEADING)
* .launchModal();
* }</pre> * }</pre>
* *
* Or, * Or,
* *
* <pre> * <pre>
* TaskBuilder.withTask(new AwesomeTask(awesomeStuff)).launchModal(); * TaskBuilder.withTask(new AwesomeTask(awesomeStuff)).launchModal();
* </pre> * </pre>
* *
* Or, * Or,
* *
* <pre> * <pre>
* {@link TaskLauncher#launch(Task) TaskLauncher.launch}(new AwesomeTask(awesomeStuff)); * {@link TaskLauncher#launch(Task) TaskLauncher.launch}(new AwesomeTask(awesomeStuff));
* </pre> * </pre>
* *
* *

View file

@ -205,11 +205,26 @@ public class TaskDialog extends DialogComponentProvider implements TaskMonitor {
return userSaysYes; return userSaysYes;
} }
private boolean isInstalled(Component c) {
Component[] components = mainPanel.getComponents();
for (Component component : components) {
if (c == component) {
return true;
}
}
return false;
}
/** /**
* Adds the panel that contains the progress bar to the dialog * Adds the panel that contains the progress bar to the dialog
*/ */
private void installProgressMonitor() { private void installProgressMonitor() {
Swing.runIfSwingOrRunLater(() -> { Swing.runIfSwingOrRunLater(() -> {
if (isInstalled(monitorComponent)) {
return;
}
mainPanel.removeAll(); mainPanel.removeAll();
mainPanel.add(monitorComponent, BorderLayout.CENTER); mainPanel.add(monitorComponent, BorderLayout.CENTER);
repack(); repack();
@ -222,6 +237,11 @@ public class TaskDialog extends DialogComponentProvider implements TaskMonitor {
*/ */
private void installActivityDisplay() { private void installActivityDisplay() {
Swing.runIfSwingOrRunLater(() -> { Swing.runIfSwingOrRunLater(() -> {
if (isInstalled(activityPanel)) {
return;
}
mainPanel.removeAll(); mainPanel.removeAll();
mainPanel.add(activityPanel, BorderLayout.CENTER); mainPanel.add(activityPanel, BorderLayout.CENTER);
repack(); repack();