GT-2875 - Unswingable - review fixes

This commit is contained in:
dragonmacher 2019-05-21 10:10:13 -04:00
parent bc2fb09ec5
commit 5e8340b7f8
7 changed files with 106 additions and 62 deletions

View file

@ -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
}

View file

@ -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) {

View file

@ -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

View file

@ -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 {

View file

@ -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);
}
}

View file

@ -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) {

View file

@ -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