mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 02:39:44 +02:00
GT-2875 - Unswingable - review fixes
This commit is contained in:
parent
bc2fb09ec5
commit
5e8340b7f8
7 changed files with 106 additions and 62 deletions
|
@ -100,7 +100,8 @@ public class DisassociateAction extends DockingAction {
|
|||
monitor -> doDisassociate(synchronizer, typesToDisassociate, allAssociatedTypes, monitor);
|
||||
new TaskBuilder("Disassociate From Archive", r)
|
||||
.setStatusTextAlignment(SwingConstants.LEADING)
|
||||
.launchModal();
|
||||
.launchModal()
|
||||
;
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
|
|
|
@ -103,8 +103,12 @@ public abstract class SyncAction extends DockingAction implements Comparable<Syn
|
|||
return;
|
||||
}
|
||||
|
||||
new TaskLauncher(new SyncTask(synchronizer), null, TaskLauncher.INITIAL_MODAL_DELAY,
|
||||
SwingConstants.LEFT);
|
||||
//@formatter:off
|
||||
TaskBuilder.withTask(new SyncTask(synchronizer))
|
||||
.setStatusTextAlignment(SwingConstants.LEADING)
|
||||
.launchModal()
|
||||
;
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
private void doSync(DataTypeSynchronizer synchronizer, TaskMonitor monitor) {
|
||||
|
|
|
@ -21,6 +21,13 @@
|
|||
|
||||
package ghidra.app.plugin.core.module;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import javax.swing.SwingConstants;
|
||||
|
||||
import docking.ActionContext;
|
||||
import docking.action.DockingAction;
|
||||
import docking.action.MenuData;
|
||||
import ghidra.app.CorePluginPackage;
|
||||
import ghidra.app.plugin.PluginCategoryNames;
|
||||
import ghidra.app.plugin.ProgramPlugin;
|
||||
|
@ -36,14 +43,6 @@ import ghidra.util.exception.CancelledException;
|
|||
import ghidra.util.exception.NotFoundException;
|
||||
import ghidra.util.task.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import javax.swing.SwingConstants;
|
||||
|
||||
import docking.ActionContext;
|
||||
import docking.action.DockingAction;
|
||||
import docking.action.MenuData;
|
||||
|
||||
/**
|
||||
* Plugin to sort Modules and Fragments within a selected Module.
|
||||
* Child Module folders are always name-sorted and placed
|
||||
|
@ -97,10 +96,12 @@ public class ModuleSortPlugin extends ProgramPlugin {
|
|||
return;
|
||||
}
|
||||
|
||||
SortTask sortTask = new SortTask(module, sortType);
|
||||
|
||||
// this blocks until the task is finished
|
||||
new TaskLauncher(sortTask, null, TaskLauncher.INITIAL_MODAL_DELAY, SwingConstants.LEADING);
|
||||
//@formatter:off
|
||||
TaskBuilder.withTask(new SortTask(module, sortType))
|
||||
.setStatusTextAlignment(SwingConstants.LEADING)
|
||||
.launchModal()
|
||||
;
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
private void doSort(ProgramModule parent, GroupComparator comparator, TaskMonitor monitor)
|
||||
|
@ -110,11 +111,11 @@ public class ModuleSortPlugin extends ProgramPlugin {
|
|||
|
||||
monitor.initialize(kids.length);
|
||||
|
||||
for (int i = 0; i < kids.length; i++) {
|
||||
for (Group kid : kids) {
|
||||
monitor.checkCanceled();
|
||||
list.add(kids[i]);
|
||||
if (kids[i] instanceof ProgramModule) {
|
||||
doSort((ProgramModule) kids[i], comparator, monitor);
|
||||
list.add(kid);
|
||||
if (kid instanceof ProgramModule) {
|
||||
doSort((ProgramModule) kid, comparator, monitor);
|
||||
}
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
|
@ -152,9 +153,10 @@ public class ModuleSortPlugin extends ProgramPlugin {
|
|||
private ProgramModule getSelectedModule(Object contextObj) {
|
||||
if (contextObj instanceof ProgramNode) {
|
||||
ProgramNode node = (ProgramNode) contextObj;
|
||||
if (node.isModule() && node.getTree().getSelectionCount() == 1)
|
||||
if (node.isModule() && node.getTree().getSelectionCount() == 1) {
|
||||
return node.getModule();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -244,12 +246,14 @@ public class ModuleSortPlugin extends ProgramPlugin {
|
|||
this.sortType = sortType;
|
||||
if (sortType == SORT_BY_ADDRESS) {
|
||||
setPopupMenuData(new MenuData(SORT_BY_ADDR_MENUPATH, null, "module"));
|
||||
setDescription("Perform a minimum address sort of all fragments contained within a selected folder");
|
||||
setDescription(
|
||||
"Perform a minimum address sort of all fragments contained within a selected folder");
|
||||
}
|
||||
else {
|
||||
setPopupMenuData(new MenuData(SORT_BY_NAME_MENUPATH, null, "module"));
|
||||
|
||||
setDescription("Perform a name sort of all fragments contained within a selected folder");
|
||||
setDescription(
|
||||
"Perform a name sort of all fragments contained within a selected folder");
|
||||
}
|
||||
setEnabled(true); // always enabled
|
||||
setHelpLocation(new HelpLocation("ProgramTreePlugin", "SortByAddressOrName"));
|
||||
|
@ -258,7 +262,7 @@ public class ModuleSortPlugin extends ProgramPlugin {
|
|||
/**
|
||||
* Determine if the Module Sort action should be visible within
|
||||
* the popup menu for the specified active object.
|
||||
* @param activeObj the object under the mouse location for the popup.
|
||||
* @param context the context
|
||||
* @return true if action should be made visible in popup menu.
|
||||
*/
|
||||
@Override
|
||||
|
|
|
@ -54,6 +54,19 @@ import util.CollectionUtils;
|
|||
* .launchModal();
|
||||
* </pre>
|
||||
*
|
||||
* Or,
|
||||
*
|
||||
* <pre>
|
||||
* TaskBuilder.withTask(new AwesomeTask(awesomeStuff)).launchModal();
|
||||
* </pre>
|
||||
*
|
||||
* Or,
|
||||
*
|
||||
* <pre>
|
||||
* {@link TaskLauncher#launch(Task) TaskLauncher.launch}(new AwesomeTask(awesomeStuff));
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
* <p>Note: this class will check to see if it is in a headless environment before launching
|
||||
* its task. This makes it safe to use this class in headed or headless environments.
|
||||
*/
|
||||
|
@ -84,6 +97,21 @@ public class TaskBuilder {
|
|||
return new TaskBuilder(r);
|
||||
}
|
||||
|
||||
/**
|
||||
* A convenience method to start a builder using the given task. The
|
||||
* {@link #setTitle(String) title} of the task will be the value of
|
||||
* {@link Task#getTaskTitle()}.
|
||||
*
|
||||
* <p>This method allows for a more attractive fluent API usage than does the constructor
|
||||
* (see the javadoc header).
|
||||
*
|
||||
* @param t the task
|
||||
* @return this builder
|
||||
*/
|
||||
public static TaskBuilder withTask(Task t) {
|
||||
return new TaskBuilder(t.getTaskTitle(), t);
|
||||
}
|
||||
|
||||
private TaskBuilder(MonitoredRunnable r) {
|
||||
this.runnable = Objects.requireNonNull(r);
|
||||
}
|
||||
|
@ -239,9 +267,9 @@ public class TaskBuilder {
|
|||
}
|
||||
|
||||
if (isModal) {
|
||||
return TaskLauncher.INITIAL_MODAL_DELAY;
|
||||
return TaskLauncher.INITIAL_MODAL_DELAY_MS;
|
||||
}
|
||||
return TaskLauncher.INITIAL_DELAY;
|
||||
return TaskLauncher.INITIAL_DELAY_MS;
|
||||
}
|
||||
|
||||
private class TaskBuilderTask extends Task {
|
||||
|
|
|
@ -31,7 +31,8 @@ import ghidra.util.exception.UnableToSwingException;
|
|||
* see one of the many static convenience methods.
|
||||
*
|
||||
* <a name="modal_usage"></a>
|
||||
* <p><a name="modal_usage"></a>Most clients of this class should not be concerned with where
|
||||
* <p><b><a name="modal_usage">Modal Usage</a></b><br>
|
||||
* Most clients of this class should not be concerned with where
|
||||
* the dialog used by this class will appear. By default, it will be shown over
|
||||
* the active window, which is the desired
|
||||
* behavior for most uses. If you should need a dialog to appear over a non-active window,
|
||||
|
@ -91,7 +92,7 @@ public class TaskLauncher {
|
|||
public void run(TaskMonitor monitor) {
|
||||
runnable.monitoredRun(monitor);
|
||||
}
|
||||
}, null, INITIAL_DELAY);
|
||||
}, null, INITIAL_DELAY_MS);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -120,7 +121,7 @@ public class TaskLauncher {
|
|||
public void run(TaskMonitor monitor) {
|
||||
runnable.monitoredRun(monitor);
|
||||
}
|
||||
}, null, INITIAL_MODAL_DELAY);
|
||||
}, null, INITIAL_MODAL_DELAY_MS);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -161,21 +162,13 @@ public class TaskLauncher {
|
|||
// End Static Launcher Methods
|
||||
//==================================================================================================
|
||||
|
||||
static final int INITIAL_DELAY = 1000;// 1 second
|
||||
static final int INITIAL_DELAY_MS = 1000;
|
||||
|
||||
/** The time, for modal tasks, to try and run before blocking and showing a dialog */
|
||||
public static final int INITIAL_MODAL_DELAY = 500;
|
||||
|
||||
private static Component getParent(Component parent) {
|
||||
if (parent == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (parent.isVisible() ? parent : null);
|
||||
}
|
||||
static final int INITIAL_MODAL_DELAY_MS = 500;
|
||||
|
||||
/**
|
||||
* Constructor for TaskLauncher.
|
||||
* Constructor for TaskLauncher
|
||||
*
|
||||
* <p>This constructor assumes that if a progress dialog is needed, then it should appear
|
||||
* over the active window. If you should need a dialog to appear over a non-active window,
|
||||
|
@ -186,11 +179,11 @@ public class TaskLauncher {
|
|||
*
|
||||
*/
|
||||
public TaskLauncher(Task task) {
|
||||
this(task, null, task.isModal() ? INITIAL_MODAL_DELAY : INITIAL_DELAY);
|
||||
this(task, null, task.isModal() ? INITIAL_MODAL_DELAY_MS : INITIAL_DELAY_MS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for TaskLauncher.
|
||||
* Constructor for TaskLauncher
|
||||
*
|
||||
* <p>See <a href="#modal_usage">notes on modal usage</a>
|
||||
*
|
||||
|
@ -198,49 +191,49 @@ public class TaskLauncher {
|
|||
* @param parent component whose window to use to parent the dialog.
|
||||
*/
|
||||
public TaskLauncher(Task task, Component parent) {
|
||||
this(task, getParent(parent), task.isModal() ? INITIAL_MODAL_DELAY : INITIAL_DELAY);
|
||||
this(task, getParent(parent), task.isModal() ? INITIAL_MODAL_DELAY_MS : INITIAL_DELAY_MS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new TaskLauncher.
|
||||
* Construct a new TaskLauncher
|
||||
*
|
||||
* <p>See <a href="#modal_usage">notes on modal usage</a>
|
||||
*
|
||||
* @param task task to run in another thread (other than the Swing Thread)
|
||||
* @param parent component whose window to use to parent the dialog; null centers the task
|
||||
* dialog over the current window
|
||||
* @param delay number of milliseconds to delay until the task monitor is displayed
|
||||
* @param delayMs number of milliseconds to delay until the task monitor is displayed
|
||||
*/
|
||||
public TaskLauncher(Task task, Component parent, int delay) {
|
||||
this(task, parent, delay, TaskDialog.DEFAULT_WIDTH);
|
||||
public TaskLauncher(Task task, Component parent, int delayMs) {
|
||||
this(task, parent, delayMs, TaskDialog.DEFAULT_WIDTH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new TaskLauncher.
|
||||
* Construct a new TaskLauncher
|
||||
*
|
||||
* <p>See <a href="#modal_usage">notes on modal usage</a>
|
||||
*
|
||||
* @param task task to run in another thread (other than the Swing Thread)
|
||||
* @param parent component whose window to use to parent the dialog; null centers the task
|
||||
* dialog over the current window
|
||||
* @param delay number of milliseconds to delay until the task monitor is displayed
|
||||
* @param delayMs number of milliseconds to delay until the task monitor is displayed
|
||||
* @param dialogWidth The preferred width of the dialog (this allows clients to make a wider
|
||||
* dialog, which better shows long messages).
|
||||
*/
|
||||
public TaskLauncher(Task task, Component parent, int delay, int dialogWidth) {
|
||||
public TaskLauncher(Task task, Component parent, int delayMs, int dialogWidth) {
|
||||
|
||||
try {
|
||||
scheduleFromSwingThread(task, parent, delay, dialogWidth);
|
||||
scheduleFromSwingThread(task, parent, delayMs, dialogWidth);
|
||||
}
|
||||
catch (UnableToSwingException e) {
|
||||
runInThisBackgroundThread(task);
|
||||
}
|
||||
}
|
||||
|
||||
private void scheduleFromSwingThread(Task task, Component parent, int delay, int dialogWidth)
|
||||
private void scheduleFromSwingThread(Task task, Component parent, int delayMs, int dialogWidth)
|
||||
throws UnableToSwingException {
|
||||
|
||||
TaskRunner runner = createTaskRunner(task, parent, delay, dialogWidth);
|
||||
TaskRunner runner = createTaskRunner(task, parent, delayMs, dialogWidth);
|
||||
if (Swing.isEventDispatchThread()) {
|
||||
runner.run();
|
||||
return;
|
||||
|
@ -257,12 +250,15 @@ public class TaskLauncher {
|
|||
Swing.runNow(() -> runner.run(), timeout, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
// template method to allow timeout change
|
||||
protected int getSwingTimeoutInSeconds() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
protected TaskRunner createTaskRunner(Task task, Component parent, int delay, int dialogWidth) {
|
||||
return new TaskRunner(task, parent, delay, dialogWidth);
|
||||
// template method to allow task runner change
|
||||
protected TaskRunner createTaskRunner(Task task, Component parent, int delayMs,
|
||||
int dialogWidth) {
|
||||
return new TaskRunner(task, parent, delayMs, dialogWidth);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -278,4 +274,13 @@ public class TaskLauncher {
|
|||
|
||||
task.monitoredRun(TaskMonitor.DUMMY);
|
||||
}
|
||||
|
||||
private static Component getParent(Component parent) {
|
||||
if (parent == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (parent.isVisible() ? parent : null);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ class TaskRunner {
|
|||
|
||||
protected Task task;
|
||||
private Component parent;
|
||||
private int delay;
|
||||
private int delayMs;
|
||||
private int dialogWidth;
|
||||
private TaskDialog taskDialog;
|
||||
private Thread taskThread;
|
||||
|
@ -44,10 +44,10 @@ class TaskRunner {
|
|||
}
|
||||
};
|
||||
|
||||
TaskRunner(Task task, Component parent, int delay, int dialogWidth) {
|
||||
TaskRunner(Task task, Component parent, int delayMs, int dialogWidth) {
|
||||
this.task = task;
|
||||
this.parent = parent;
|
||||
this.delay = delay;
|
||||
this.delayMs = delayMs;
|
||||
this.dialogWidth = dialogWidth;
|
||||
}
|
||||
|
||||
|
@ -61,7 +61,7 @@ class TaskRunner {
|
|||
|
||||
startBackgroundThread(taskDialog);
|
||||
|
||||
taskDialog.show(Math.max(delay, 0));
|
||||
taskDialog.show(Math.max(delayMs, 0));
|
||||
}
|
||||
|
||||
protected TaskDialog buildTaskDialog(Component comp) {
|
||||
|
|
|
@ -105,8 +105,10 @@ public class Swing {
|
|||
|
||||
/**
|
||||
* Calls the given suppler on the Swing thread, blocking with a
|
||||
* {@link SwingUtilities#invokeAndWait(Runnable)}. Use this method when you need to get
|
||||
* a value while being on the Swing thread.
|
||||
* {@link SwingUtilities#invokeAndWait(Runnable)} if not on the Swing thread.
|
||||
*
|
||||
* <p>Use this method when you are not on the Swing thread and you need to get a value
|
||||
* that is managed/synchronized by the Swing thread.
|
||||
*
|
||||
* <pre>
|
||||
* String value = runNow(() -> label.getText());
|
||||
|
@ -195,9 +197,9 @@ public class Swing {
|
|||
"Timed-out waiting for Swing thread lock in " + timeout + " " + unit);
|
||||
}
|
||||
|
||||
// we've started!
|
||||
// we've started; wait for the runnable with no timeout
|
||||
try {
|
||||
end.await(); // wait FOREVER!
|
||||
end.await();
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
// we sometimes interrupt our tasks intentionally, so don't report it
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue