GT-2875 - Unswingable - review fixes

This commit is contained in:
dragonmacher 2019-05-20 15:47:41 -04:00
parent 8dffd377fb
commit 07f0371a50
16 changed files with 395 additions and 374 deletions

View file

@ -15,8 +15,7 @@
*/
package docking.test;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
import static org.junit.Assert.*;
import java.awt.*;
import java.awt.datatransfer.*;
@ -1760,9 +1759,11 @@ public abstract class AbstractDockingTest extends AbstractGenericTest {
*/
public static void setErrorsExpected(boolean expected) {
if (expected) {
Msg.error(AbstractDockingTest.class, ">>>>>>>>>>>>>>>> Expected Exception");
ConcurrentTestExceptionHandler.disable();
}
else {
Msg.error(AbstractDockingTest.class, "<<<<<<<<<<<<<<<< End Expected Exception");
ConcurrentTestExceptionHandler.enable();
}
}

View file

@ -221,7 +221,8 @@ public abstract class DataLoadingConstraintEditor<T> extends AbstractColumnConst
reloadDataButton.setVisible(false);
Task task = new LoadDataTask();
task.addTaskListener(this);
new TaskLauncher(task, (TaskMonitor) taskMonitorComponent);
BackgroundThreadTaskLauncher launcher = new BackgroundThreadTaskLauncher(task);
launcher.run(taskMonitorComponent);
}
@Override

View file

@ -15,29 +15,39 @@
*/
package ghidra.util.task;
import java.util.concurrent.Executor;
import generic.concurrent.GThreadPool;
import ghidra.util.Swing;
import ghidra.util.TaskUtilities;
/**
* Helper class to launch the given task in a background thread This helper will not
* show a task dialog. See {@link TaskLauncher}.
* show a task dialog.
*
* <p>This class is useful when you want to run the task and use a monitor that is embedded
* in some other component.
*
* <p>See {@link TaskLauncher}.
*/
class BackgroundThreadTaskLauncher {
public class BackgroundThreadTaskLauncher {
private Task task;
BackgroundThreadTaskLauncher(Task task) {
public BackgroundThreadTaskLauncher(Task task) {
this.task = task;
}
void run(TaskMonitor monitor) {
public void run(TaskMonitor monitor) {
// add the task here, so we can track it before it is actually started by the thread
TaskUtilities.addTrackedTask(task, monitor);
String name = "Task - " + task.getTaskTitle();
Thread taskThread = new Thread(() -> {
GThreadPool pool = GThreadPool.getSharedThreadPool(Swing.GSWING_THREAD_POOL_NAME);
Executor executor = pool.getExecutor();
executor.execute(() -> {
Thread.currentThread().setName(name);
task.monitoredRun(monitor);
}, name);
taskThread.setPriority(Thread.MIN_PRIORITY);
taskThread.start();
});
}
}

View file

@ -1,32 +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.task;
/**
* Helper class to launch the given task in the current thread. See {@link TaskLauncher}.
*/
class CurrentThreadTaskLauncher {
private Task task;
CurrentThreadTaskLauncher(Task task) {
this.task = task;
}
void run() {
task.monitoredRun(TaskMonitor.DUMMY);
}
}

View file

@ -18,9 +18,7 @@ package ghidra.util.task;
import java.awt.Component;
import java.util.concurrent.TimeUnit;
import javax.swing.SwingUtilities;
import ghidra.util.SystemUtilities;
import ghidra.util.Swing;
import ghidra.util.exception.UnableToSwingException;
/**
@ -232,34 +230,19 @@ public class TaskLauncher {
public TaskLauncher(Task task, Component parent, int delay, int dialogWidth) {
try {
runSwing(task, parent, delay, dialogWidth);
scheduleFromSwingThread(task, parent, delay, dialogWidth);
}
catch (UnableToSwingException e) {
runInThisBackgroundThread(task);
}
}
/**
* Constructor where an external taskMonitor is used. Normally, this class will provide
* the {@link TaskDialog} as the monitor. This constructor is useful when you want to run
* the task and use a monitor that is embedded in some other component.
*
* <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 monitor the monitor to use while running the task.
*/
public TaskLauncher(Task task, TaskMonitor monitor) {
BackgroundThreadTaskLauncher runner = new BackgroundThreadTaskLauncher(task);
runner.run(monitor);
}
private void runSwing(Task task, Component parent, int delay, int dialogWidth)
private void scheduleFromSwingThread(Task task, Component parent, int delay, int dialogWidth)
throws UnableToSwingException {
SwingTaskLauncher swinger = buildSwingLauncher(task, parent, delay, dialogWidth);
if (SwingUtilities.isEventDispatchThread()) {
swinger.run();
TaskRunner runner = createTaskRunner(task, parent, delay, dialogWidth);
if (Swing.isEventDispatchThread()) {
runner.run();
return;
}
@ -271,26 +254,28 @@ public class TaskLauncher {
// This will throw an exception if we could not get the Swing lock. When that happens,
// the task was NOT run.
int timeout = getSwingTimeoutInSeconds();
SystemUtilities.runSwingNow(() -> {
swinger.run();
}, timeout, TimeUnit.SECONDS);
Swing.runNow(() -> runner.run(), timeout, TimeUnit.SECONDS);
}
protected int getSwingTimeoutInSeconds() {
return 2;
}
protected SwingTaskLauncher buildSwingLauncher(Task task, Component parent, int delay,
int dialogWidth) {
return new SwingTaskLauncher(task, parent, delay, dialogWidth);
protected TaskRunner createTaskRunner(Task task, Component parent, int delay, int dialogWidth) {
return new TaskRunner(task, parent, delay, dialogWidth);
}
/**
* Runs the given task in the current thread, which <b>cannot be the Swing thread</b>
*
* @param task the task to run
* @throws IllegalStateException if the given thread is the Swing thread
*/
protected void runInThisBackgroundThread(Task task) {
if (SwingUtilities.isEventDispatchThread()) {
if (Swing.isEventDispatchThread()) {
throw new IllegalStateException("Must not call this method from the Swing thread");
}
CurrentThreadTaskLauncher runner = new CurrentThreadTaskLauncher(task);
runner.run();
task.monitoredRun(TaskMonitor.DUMMY);
}
}

View file

@ -16,17 +16,18 @@
package ghidra.util.task;
import java.awt.Component;
import java.util.concurrent.Executor;
import javax.swing.SwingUtilities;
import generic.concurrent.GThreadPool;
import generic.util.WindowUtilities;
import ghidra.util.*;
import ghidra.util.Swing;
import ghidra.util.TaskUtilities;
/**
* Helper class to launch the given task in a background thread, showing a task dialog if
* this task takes to long. See {@link TaskLauncher}.
*/
class SwingTaskLauncher {
class TaskRunner {
protected Task task;
private Component parent;
@ -43,7 +44,7 @@ class SwingTaskLauncher {
}
};
SwingTaskLauncher(Task task, Component parent, int delay, int dialogWidth) {
TaskRunner(Task task, Component parent, int delay, int dialogWidth) {
this.task = task;
this.parent = parent;
this.delay = delay;
@ -51,26 +52,16 @@ class SwingTaskLauncher {
}
void run() {
// note: we need to be on the Swing thread to create our UI widgets
Swing.assertThisIsTheSwingThread(
"The Task runner is required to be run from the Swing thread");
this.taskDialog = buildTaskDialog(parent);
startBackgroundThread(taskDialog);
taskDialog.show(Math.max(delay, 0));
waitIfNotSwing();
}
private void waitIfNotSwing() {
if (SwingUtilities.isEventDispatchThread() || !task.isModal()) {
return;
}
try {
taskThread.join();
}
catch (InterruptedException e) {
Msg.debug(this, "Task Launcher unexpectedly interrupted waiting for task thread", e);
}
}
protected TaskDialog buildTaskDialog(Component comp) {
@ -80,10 +71,8 @@ class SwingTaskLauncher {
// on the Swing thread to prevent exceptions while painting (as seen when using the
// Nimbus Look and Feel).
//
SystemUtilities.runSwingNow(() -> {
taskDialog = createTaskDialog(comp);
taskDialog.setMinimumSize(dialogWidth, 0);
});
taskDialog = createTaskDialog(comp);
taskDialog.setMinimumSize(dialogWidth, 0);
if (task.isInterruptible() || task.isForgettable()) {
taskDialog.addCancelledListener(monitorChangeListener);
@ -100,21 +89,16 @@ class SwingTaskLauncher {
TaskUtilities.addTrackedTask(task, monitor);
String name = "Task - " + task.getTaskTitle();
taskThread = new Thread(() -> {
GThreadPool pool = GThreadPool.getSharedThreadPool(Swing.GSWING_THREAD_POOL_NAME);
Executor executor = pool.getExecutor();
executor.execute(() -> {
Thread.currentThread().setName(name);
task.monitoredRun(monitor);
taskProcessed();
}, name);
taskThread.setPriority(Thread.MIN_PRIORITY);
taskThread.start();
}
private void taskProcessed() {
if (taskDialog != null) {
taskDialog.taskProcessed();
}
});
}
protected TaskDialog createTaskDialog(Component comp) {
private TaskDialog createTaskDialog(Component comp) {
Component currentParent = comp;
if (currentParent != null) {
currentParent = WindowUtilities.windowForComponent(comp);