mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 02:39:44 +02:00
Merge branch 'dragonmacher-task-launcher-backgrounding-update'
This commit is contained in:
commit
8cdfe79def
28 changed files with 605 additions and 318 deletions
|
@ -32,8 +32,9 @@ public class MoveBlockTask extends ProgramTask {
|
||||||
private Address currentStart;
|
private Address currentStart;
|
||||||
private Address newStart;
|
private Address newStart;
|
||||||
private MoveBlockListener listener;
|
private MoveBlockListener listener;
|
||||||
private boolean wasCancelled;
|
private boolean cancelled;
|
||||||
private boolean status;
|
private String statusMessage;
|
||||||
|
private boolean success;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a background command for moving memory blocks. The memory block
|
* Creates a background command for moving memory blocks. The memory block
|
||||||
|
@ -62,58 +63,53 @@ public class MoveBlockTask extends ProgramTask {
|
||||||
Memory mem = program.getMemory();
|
Memory mem = program.getMemory();
|
||||||
MemoryBlock block = mem.getBlock(currentStart);
|
MemoryBlock block = mem.getBlock(currentStart);
|
||||||
monitor.setMessage("Moving Memory Block ...");
|
monitor.setMessage("Moving Memory Block ...");
|
||||||
String msg = "";
|
statusMessage = "";
|
||||||
Throwable cause = null;
|
Throwable cause = null;
|
||||||
try {
|
try {
|
||||||
mem.moveBlock(block, newStart, monitor);
|
mem.moveBlock(block, newStart, monitor);
|
||||||
if (monitor.isCancelled()) {
|
if (monitor.isCancelled()) {
|
||||||
wasCancelled = true;
|
cancelled = true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
status = true;
|
success = true;
|
||||||
listener.moveBlockCompleted(this);
|
listener.moveBlockCompleted(this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (OutOfMemoryError e) {
|
catch (OutOfMemoryError e) {
|
||||||
msg = "Insufficient memory to complete operation";
|
statusMessage = "Insufficient memory to complete operation";
|
||||||
cause = e;
|
cause = e;
|
||||||
}
|
}
|
||||||
catch (NotFoundException exc) {
|
catch (NotFoundException e) {
|
||||||
msg = "Memory block not found";
|
statusMessage = "Memory block not found";
|
||||||
cause = exc;
|
cause = e;
|
||||||
}
|
}
|
||||||
catch (MemoryConflictException exc) {
|
catch (MemoryConflictException | MemoryBlockException | IllegalArgumentException e) {
|
||||||
msg = exc.getMessage();
|
statusMessage = e.getMessage();
|
||||||
cause = exc;
|
|
||||||
}
|
|
||||||
catch (MemoryBlockException exc) {
|
|
||||||
msg = exc.getMessage();
|
|
||||||
cause = exc;
|
|
||||||
}
|
|
||||||
catch (IllegalArgumentException e) {
|
|
||||||
msg = e.getMessage();
|
|
||||||
cause = e;
|
cause = e;
|
||||||
}
|
}
|
||||||
catch (Throwable t) {
|
catch (Throwable t) {
|
||||||
Msg.error(this, "Unexpected Exception: " + t.getMessage(), t);
|
Msg.error(this, "Unexpected Exception: " + t.getMessage(), t);
|
||||||
msg = t.getMessage();
|
statusMessage = t.getMessage();
|
||||||
if (msg == null) {
|
if (statusMessage == null) {
|
||||||
msg = t.toString();
|
statusMessage = t.toString();
|
||||||
}
|
}
|
||||||
cause = t;
|
cause = t;
|
||||||
}
|
}
|
||||||
|
|
||||||
monitor.setMessage(msg);
|
|
||||||
listener.moveBlockCompleted(this);
|
listener.moveBlockCompleted(this);
|
||||||
throw new RollbackException(msg, cause);
|
throw new RollbackException(statusMessage, cause);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isCancelled() {
|
public boolean isCancelled() {
|
||||||
return wasCancelled;
|
return cancelled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean getStatus() {
|
public boolean wasSuccessful() {
|
||||||
return status;
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStatusMessage() {
|
||||||
|
return statusMessage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1467,12 +1467,22 @@ public class AutoAnalysisManager implements DomainObjectListener, DomainObjectCl
|
||||||
// ignore
|
// ignore
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isIndeterminate() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setMessage(String message) {
|
public void setMessage(String message) {
|
||||||
dominantMonitor.setMessage(message);
|
dominantMonitor.setMessage(message);
|
||||||
slaveMonitor.setMessage(message);
|
slaveMonitor.setMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMessage() {
|
||||||
|
return dominantMonitor.getMessage();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setProgress(long value) {
|
public void setProgress(long value) {
|
||||||
dominantMonitor.setProgress(value);
|
dominantMonitor.setProgress(value);
|
||||||
|
|
|
@ -29,9 +29,9 @@ import ghidra.framework.plugintool.PluginTool;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.address.AddressFactory;
|
import ghidra.program.model.address.AddressFactory;
|
||||||
import ghidra.util.HelpLocation;
|
import ghidra.util.HelpLocation;
|
||||||
|
import ghidra.util.Swing;
|
||||||
import ghidra.util.layout.PairLayout;
|
import ghidra.util.layout.PairLayout;
|
||||||
import ghidra.util.task.BackgroundThreadTaskLauncher;
|
import ghidra.util.task.TaskBuilder;
|
||||||
import ghidra.util.task.TaskMonitorAdapter;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dialog that uses a model to validate the fields for moving a block of memory.
|
* Dialog that uses a model to validate the fields for moving a block of memory.
|
||||||
|
@ -49,15 +49,6 @@ public class MoveBlockDialog extends DialogComponentProvider implements MoveBloc
|
||||||
private MoveBlockModel model;
|
private MoveBlockModel model;
|
||||||
private PluginTool tool;
|
private PluginTool tool;
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor for MoveBlockDialog.
|
|
||||||
*
|
|
||||||
* @param dialog
|
|
||||||
* @param title
|
|
||||||
* @param modal
|
|
||||||
* @param includeStatus
|
|
||||||
* @param includeButtons
|
|
||||||
*/
|
|
||||||
MoveBlockDialog(MoveBlockModel model, PluginTool tool) {
|
MoveBlockDialog(MoveBlockModel model, PluginTool tool) {
|
||||||
super("Move Memory Block");
|
super("Move Memory Block");
|
||||||
this.model = model;
|
this.model = model;
|
||||||
|
@ -69,33 +60,22 @@ public class MoveBlockDialog extends DialogComponentProvider implements MoveBloc
|
||||||
addCancelButton();
|
addCancelButton();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.app.plugin.contrib.memory.MoveBlockListener#moveBlockCompleted(boolean,
|
|
||||||
* java.lang.String)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void moveBlockCompleted(final MoveBlockTask cmd) {
|
public void moveBlockCompleted(MoveBlockTask task) {
|
||||||
Runnable r = () -> {
|
|
||||||
if (cmd.getStatus()) {
|
|
||||||
close();
|
|
||||||
model.dispose();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
setCursor(Cursor.getDefaultCursor());
|
setCursor(Cursor.getDefaultCursor());
|
||||||
setOkEnabled(false);
|
boolean success = task.wasSuccessful();
|
||||||
if (cmd.isCancelled()) {
|
setOkEnabled(success);
|
||||||
tool.setStatusInfo(getStatusText());
|
setStatusText(task.getStatusMessage());
|
||||||
|
|
||||||
|
Swing.runLater(() -> {
|
||||||
|
if (success) {
|
||||||
close();
|
close();
|
||||||
model.dispose();
|
model.dispose();
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
};
|
|
||||||
SwingUtilities.invokeLater(r);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.app.plugin.contrib.memory.MoveBlockListener#stateChanged()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void stateChanged() {
|
public void stateChanged() {
|
||||||
setOkEnabled(false);
|
setOkEnabled(false);
|
||||||
|
@ -138,18 +118,20 @@ public class MoveBlockDialog extends DialogComponentProvider implements MoveBloc
|
||||||
setOkEnabled(false);
|
setOkEnabled(false);
|
||||||
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
||||||
|
|
||||||
BackgroundThreadTaskLauncher launcher = new BackgroundThreadTaskLauncher(model.makeTask());
|
MoveBlockTask task = model.makeTask();
|
||||||
launcher.run(new TaskMonitorAdapter() {
|
|
||||||
@Override
|
//@formatter:off
|
||||||
public void setMessage(String message) {
|
TaskBuilder.withTask(task)
|
||||||
setStatusText(message);
|
.setParent(this.getComponent())
|
||||||
}
|
.launchModal()
|
||||||
});
|
;
|
||||||
|
//@formatter:on
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void cancelCallback() {
|
protected void cancelCallback() {
|
||||||
close();
|
close();
|
||||||
|
model.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
private JPanel buildMainPanel() {
|
private JPanel buildMainPanel() {
|
||||||
|
|
|
@ -17,15 +17,10 @@ package ghidra.app.plugin.core.memory;
|
||||||
|
|
||||||
import ghidra.app.cmd.memory.MoveBlockListener;
|
import ghidra.app.cmd.memory.MoveBlockListener;
|
||||||
import ghidra.app.cmd.memory.MoveBlockTask;
|
import ghidra.app.cmd.memory.MoveBlockTask;
|
||||||
import ghidra.framework.model.DomainObject;
|
import ghidra.framework.model.*;
|
||||||
import ghidra.framework.model.DomainObjectChangedEvent;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.framework.model.DomainObjectListener;
|
|
||||||
import ghidra.program.model.address.Address;
|
|
||||||
import ghidra.program.model.address.AddressFactory;
|
|
||||||
import ghidra.program.model.address.AddressOverflowException;
|
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.model.mem.MemoryBlock;
|
import ghidra.program.model.mem.MemoryBlock;
|
||||||
import ghidra.util.task.Task;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Model for moving a memory block; this class does validation of the new start
|
* Model for moving a memory block; this class does validation of the new start
|
||||||
|
@ -172,11 +167,11 @@ class MoveBlockModel implements DomainObjectListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start the task that will move the block.
|
* Create the task that will move the block
|
||||||
*
|
*
|
||||||
* @param delay number of ms to delay until the progress dialog is displayed
|
* @return the new task
|
||||||
*/
|
*/
|
||||||
Task makeTask() {
|
MoveBlockTask makeTask() {
|
||||||
return new MoveBlockTask(program, block.getStart(), newStartAddr, listener);
|
return new MoveBlockTask(program, block.getStart(), newStartAddr, listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -57,6 +57,11 @@ public class HeadlessTimedTaskMonitor implements TaskMonitor {
|
||||||
// stub
|
// stub
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMessage() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setProgress(long value) {
|
public void setProgress(long value) {
|
||||||
// stub
|
// stub
|
||||||
|
@ -82,6 +87,11 @@ public class HeadlessTimedTaskMonitor implements TaskMonitor {
|
||||||
// stub
|
// stub
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isIndeterminate() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void checkCanceled() throws CancelledException {
|
public void checkCanceled() throws CancelledException {
|
||||||
if (isCancelled()) {
|
if (isCancelled()) {
|
||||||
|
|
|
@ -30,7 +30,7 @@ import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.model.mem.MemoryBlock;
|
import ghidra.program.model.mem.MemoryBlock;
|
||||||
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
|
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
|
||||||
import ghidra.test.TestEnv;
|
import ghidra.test.TestEnv;
|
||||||
import ghidra.util.task.*;
|
import ghidra.util.task.TaskBuilder;
|
||||||
|
|
||||||
public class MoveBlockModelTest extends AbstractGhidraHeadedIntegrationTest
|
public class MoveBlockModelTest extends AbstractGhidraHeadedIntegrationTest
|
||||||
implements MoveBlockListener {
|
implements MoveBlockListener {
|
||||||
|
@ -42,7 +42,7 @@ public class MoveBlockModelTest extends AbstractGhidraHeadedIntegrationTest
|
||||||
private MemoryBlock block;
|
private MemoryBlock block;
|
||||||
|
|
||||||
private volatile boolean moveCompleted;
|
private volatile boolean moveCompleted;
|
||||||
private volatile boolean status;
|
private volatile boolean success;
|
||||||
private volatile String errMsg;
|
private volatile String errMsg;
|
||||||
|
|
||||||
private Program buildProgram1(String programName) throws Exception {
|
private Program buildProgram1(String programName) throws Exception {
|
||||||
|
@ -134,7 +134,7 @@ public class MoveBlockModelTest extends AbstractGhidraHeadedIntegrationTest
|
||||||
|
|
||||||
// wait until the we get the move complete notification
|
// wait until the we get the move complete notification
|
||||||
waitForCondition(() -> moveCompleted && notepad.canLock());
|
waitForCondition(() -> moveCompleted && notepad.canLock());
|
||||||
assertTrue("Error message= [" + errMsg + "], ", status);
|
assertTrue("Error message= [" + errMsg + "], ", success);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -145,7 +145,7 @@ public class MoveBlockModelTest extends AbstractGhidraHeadedIntegrationTest
|
||||||
|
|
||||||
// wait until the we get the move complete notification
|
// wait until the we get the move complete notification
|
||||||
waitForCondition(() -> moveCompleted && notepad.canLock());
|
waitForCondition(() -> moveCompleted && notepad.canLock());
|
||||||
assertTrue("Error message= [" + errMsg + "], ", status);
|
assertTrue("Error message= [" + errMsg + "], ", success);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -177,7 +177,7 @@ public class MoveBlockModelTest extends AbstractGhidraHeadedIntegrationTest
|
||||||
waitForCondition(() -> moveCompleted && x8051.canLock());
|
waitForCondition(() -> moveCompleted && x8051.canLock());
|
||||||
setErrorsExpected(false);
|
setErrorsExpected(false);
|
||||||
|
|
||||||
assertFalse("Error message= [" + errMsg + "], ", status);
|
assertFalse("Error message= [" + errMsg + "], ", success);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -242,15 +242,10 @@ public class MoveBlockModelTest extends AbstractGhidraHeadedIntegrationTest
|
||||||
assertNotNull(errMsg);
|
assertNotNull(errMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void launch(Task task) {
|
private void launch(MoveBlockTask task) {
|
||||||
|
|
||||||
BackgroundThreadTaskLauncher launcher = new BackgroundThreadTaskLauncher(task);
|
TaskBuilder.withTask(task).launchModal();
|
||||||
launcher.run(new TaskMonitorAdapter() {
|
errMsg = task.getStatusMessage();
|
||||||
@Override
|
|
||||||
public void setMessage(String message) {
|
|
||||||
errMsg = message;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Address getNotepadAddr(int offset) {
|
private Address getNotepadAddr(int offset) {
|
||||||
|
@ -265,7 +260,7 @@ public class MoveBlockModelTest extends AbstractGhidraHeadedIntegrationTest
|
||||||
@Override
|
@Override
|
||||||
public void moveBlockCompleted(MoveBlockTask cmd) {
|
public void moveBlockCompleted(MoveBlockTask cmd) {
|
||||||
moveCompleted = true;
|
moveCompleted = true;
|
||||||
this.status = cmd.getStatus();
|
this.success = cmd.wasSuccessful();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -221,8 +221,8 @@ public abstract class DataLoadingConstraintEditor<T> extends AbstractColumnConst
|
||||||
reloadDataButton.setVisible(false);
|
reloadDataButton.setVisible(false);
|
||||||
Task task = new LoadDataTask();
|
Task task = new LoadDataTask();
|
||||||
task.addTaskListener(this);
|
task.addTaskListener(this);
|
||||||
BackgroundThreadTaskLauncher launcher = new BackgroundThreadTaskLauncher(task);
|
|
||||||
launcher.run(taskMonitorComponent);
|
TaskBuilder.withTask(task).launchInBackground(taskMonitorComponent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -30,15 +30,15 @@ import ghidra.util.TaskUtilities;
|
||||||
*
|
*
|
||||||
* <p>See {@link TaskLauncher}.
|
* <p>See {@link TaskLauncher}.
|
||||||
*/
|
*/
|
||||||
public class BackgroundThreadTaskLauncher {
|
class BackgroundThreadTaskLauncher {
|
||||||
|
|
||||||
private Task task;
|
private Task task;
|
||||||
|
|
||||||
public BackgroundThreadTaskLauncher(Task task) {
|
BackgroundThreadTaskLauncher(Task task) {
|
||||||
this.task = task;
|
this.task = task;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void run(TaskMonitor monitor) {
|
void run(TaskMonitor monitor) {
|
||||||
// add the task here, so we can track it before it is actually started by the thread
|
// add the task here, so we can track it before it is actually started by the thread
|
||||||
TaskUtilities.addTrackedTask(task, monitor);
|
TaskUtilities.addTrackedTask(task, monitor);
|
||||||
|
|
||||||
|
@ -49,5 +49,6 @@ public class BackgroundThreadTaskLauncher {
|
||||||
Thread.currentThread().setName(name);
|
Thread.currentThread().setName(name);
|
||||||
task.monitoredRun(monitor);
|
task.monitoredRun(monitor);
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,158 @@
|
||||||
|
/* ###
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
import ghidra.util.datastruct.WeakDataStructureFactory;
|
||||||
|
import ghidra.util.datastruct.WeakSet;
|
||||||
|
import ghidra.util.exception.CancelledException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A task monitor that tracks all monitor state, but is not attached to any UI component
|
||||||
|
*
|
||||||
|
* <p><b>Synchronization Policy</b>:<br>
|
||||||
|
* We wish for this class to be performant. Thus, we do not synchronize the methods of this
|
||||||
|
* class, nor do we make the values thread visible via <code>volatile</code> or by any of
|
||||||
|
* the Java concurrent structures (e.g., {@link AtomicBoolean}). In order to keep the values of
|
||||||
|
* this class's fields update-to-date, we have chosen to synchronize the package-level client of
|
||||||
|
* this class. <b>If this class is ever made public, then most of the methods herein need to
|
||||||
|
* be synchronized to prevent race conditions and to provide visibility.
|
||||||
|
*/
|
||||||
|
class BasicTaskMonitor implements TaskMonitor {
|
||||||
|
|
||||||
|
private WeakSet<CancelledListener> listeners =
|
||||||
|
WeakDataStructureFactory.createCopyOnReadWeakSet();
|
||||||
|
|
||||||
|
private String message;
|
||||||
|
private long progress;
|
||||||
|
private long maxProgress;
|
||||||
|
|
||||||
|
private boolean cancelEnabled = true;
|
||||||
|
private boolean isCancelled;
|
||||||
|
private boolean isIndeterminate;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addCancelledListener(CancelledListener l) {
|
||||||
|
listeners.add(l);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeCancelledListener(CancelledListener l) {
|
||||||
|
listeners.remove(l);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void incrementProgress(long incrementAmount) {
|
||||||
|
setProgress(progress + incrementAmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getProgress() {
|
||||||
|
return progress;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCancelled() {
|
||||||
|
return isCancelled;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void checkCanceled() throws CancelledException {
|
||||||
|
if (isCancelled) {
|
||||||
|
throw new CancelledException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setMessage(String message) {
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setProgress(long value) {
|
||||||
|
progress = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize(long maxValue) {
|
||||||
|
setMaximum(maxValue);
|
||||||
|
setProgress(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setMaximum(long max) {
|
||||||
|
this.maxProgress = max;
|
||||||
|
if (progress > max) {
|
||||||
|
progress = max;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setIndeterminate(boolean indeterminate) {
|
||||||
|
isIndeterminate = indeterminate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setCancelEnabled(boolean enable) {
|
||||||
|
cancelEnabled = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCancelEnabled() {
|
||||||
|
return cancelEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cancel() {
|
||||||
|
boolean wasCancelled = isCancelled;
|
||||||
|
isCancelled = true;
|
||||||
|
if (!wasCancelled) {
|
||||||
|
notifyCancelledListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clearCanceled() {
|
||||||
|
isCancelled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getMaximum() {
|
||||||
|
return maxProgress;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isIndeterminate() {
|
||||||
|
return isIndeterminate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setShowProgressValue(boolean showProgressValue) {
|
||||||
|
// stub
|
||||||
|
}
|
||||||
|
|
||||||
|
private void notifyCancelledListeners() {
|
||||||
|
for (CancelledListener listener : listeners) {
|
||||||
|
listener.cancelled();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -255,6 +255,22 @@ public class TaskBuilder {
|
||||||
new TaskLauncher(t, parent, delay, dialogWidth);
|
new TaskLauncher(t, parent, delay, dialogWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs the task in a background thread with the given monitor that cannot be null. This
|
||||||
|
* is a special case for clients that already have a task monitor widget in their UI and
|
||||||
|
* they wish to let it show the progress of the given task while not blocking the Swing
|
||||||
|
* thread.
|
||||||
|
*
|
||||||
|
* @param monitor the task monitor; may not be null
|
||||||
|
*/
|
||||||
|
public void launchInBackground(TaskMonitor monitor) {
|
||||||
|
// validate(); // not needed since we are in the background
|
||||||
|
Objects.requireNonNull(monitor);
|
||||||
|
BackgroundThreadTaskLauncher launcher =
|
||||||
|
new BackgroundThreadTaskLauncher(new TaskBuilderTask(false));
|
||||||
|
launcher.run(monitor);
|
||||||
|
}
|
||||||
|
|
||||||
private void validate() {
|
private void validate() {
|
||||||
if (title == null) {
|
if (title == null) {
|
||||||
throw new NullPointerException("Task title cannot be null");
|
throw new NullPointerException("Task title cannot be null");
|
||||||
|
|
|
@ -18,6 +18,7 @@ package ghidra.util.task;
|
||||||
import java.awt.BorderLayout;
|
import java.awt.BorderLayout;
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
|
|
||||||
|
@ -50,14 +51,13 @@ public class TaskDialog extends DialogComponentProvider implements TaskMonitor {
|
||||||
private Runnable shouldCancelRunnable;
|
private Runnable shouldCancelRunnable;
|
||||||
private boolean taskDone;
|
private boolean taskDone;
|
||||||
private JPanel mainPanel;
|
private JPanel mainPanel;
|
||||||
private ChompingBitsAnimationPanel chompingBitsPanel;
|
private JPanel activityPanel;
|
||||||
private TaskMonitorComponent monitorComponent;
|
private TaskMonitorComponent monitorComponent;
|
||||||
|
|
||||||
/** Runnable that updates the primary message label in the dialog */
|
|
||||||
private Runnable updatePrimaryMessageRunnable;
|
|
||||||
|
|
||||||
/** If not null, then the value of the string has yet to be rendered */
|
/** If not null, then the value of the string has yet to be rendered */
|
||||||
private String newPrimaryMessage;
|
private AtomicReference<String> newMessage = new AtomicReference<>();
|
||||||
|
private SwingUpdateManager messageUpdater =
|
||||||
|
new SwingUpdateManager(100, 250, () -> setStatusText(newMessage.getAndSet(null)));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
|
@ -112,7 +112,7 @@ public class TaskDialog extends DialogComponentProvider implements TaskMonitor {
|
||||||
|
|
||||||
private void setup(boolean canCancel, boolean hasProgress) {
|
private void setup(boolean canCancel, boolean hasProgress) {
|
||||||
monitorComponent = new TaskMonitorComponent(false, false);
|
monitorComponent = new TaskMonitorComponent(false, false);
|
||||||
chompingBitsPanel = new ChompingBitsAnimationPanel();
|
activityPanel = new ChompingBitsAnimationPanel();
|
||||||
|
|
||||||
setCancelEnabled(canCancel);
|
setCancelEnabled(canCancel);
|
||||||
setRememberLocation(false);
|
setRememberLocation(false);
|
||||||
|
@ -122,12 +122,7 @@ public class TaskDialog extends DialogComponentProvider implements TaskMonitor {
|
||||||
close();
|
close();
|
||||||
dispose();
|
dispose();
|
||||||
};
|
};
|
||||||
updatePrimaryMessageRunnable = () -> {
|
|
||||||
setStatusText(newPrimaryMessage);
|
|
||||||
synchronized (TaskDialog.this) {
|
|
||||||
newPrimaryMessage = null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
shouldCancelRunnable = () -> {
|
shouldCancelRunnable = () -> {
|
||||||
int currentTaskID = taskID.get();
|
int currentTaskID = taskID.get();
|
||||||
|
|
||||||
|
@ -160,10 +155,9 @@ public class TaskDialog extends DialogComponentProvider implements TaskMonitor {
|
||||||
*
|
*
|
||||||
* @return true if the task should be cancelled
|
* @return true if the task should be cancelled
|
||||||
*/
|
*/
|
||||||
protected boolean promptToVerifyCancel() {
|
private boolean promptToVerifyCancel() {
|
||||||
boolean userSaysYes = OptionDialog.showYesNoDialog(getComponent(), "Cancel?",
|
boolean userSaysYes = OptionDialog.showYesNoDialog(getComponent(), "Cancel?",
|
||||||
"Do you really want to cancel \"" + getTitle() + "\"?") == OptionDialog.OPTION_ONE;
|
"Do you really want to cancel \"" + getTitle() + "\"?") == OptionDialog.OPTION_ONE;
|
||||||
|
|
||||||
return userSaysYes;
|
return userSaysYes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,13 +173,13 @@ public class TaskDialog extends DialogComponentProvider implements TaskMonitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the panel that contains the chomping bits animation to the dialog. This should only be
|
* Adds the panel that contains the activity panel (e.g., the eating bits animation) to the
|
||||||
* called if the dialog has no need to display progress.
|
* dialog. This should only be called if the dialog has no need to display progress.
|
||||||
*/
|
*/
|
||||||
private void installActivityDisplay() {
|
private void installActivityDisplay() {
|
||||||
SystemUtilities.runIfSwingOrPostSwingLater(() -> {
|
SystemUtilities.runIfSwingOrPostSwingLater(() -> {
|
||||||
mainPanel.removeAll();
|
mainPanel.removeAll();
|
||||||
mainPanel.add(chompingBitsPanel, BorderLayout.CENTER);
|
mainPanel.add(activityPanel, BorderLayout.CENTER);
|
||||||
repack();
|
repack();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -203,77 +197,11 @@ public class TaskDialog extends DialogComponentProvider implements TaskMonitor {
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setShowProgressValue(boolean showProgressValue) {
|
|
||||||
monitorComponent.setShowProgressValue(showProgressValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the percentage done
|
|
||||||
*
|
|
||||||
* @param param The percentage of the task completed.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void setProgress(long param) {
|
|
||||||
monitorComponent.setProgress(param);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void initialize(long max) {
|
|
||||||
if (monitorComponent.isIndeterminate()) {
|
|
||||||
// don't show the progress bar if we have already been marked as indeterminate (this
|
|
||||||
// allows us to prevent low-level algorithms from changing the display settings).
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!monitorComponent.isShowing()) {
|
|
||||||
installProgressMonitor();
|
|
||||||
}
|
|
||||||
|
|
||||||
monitorComponent.initialize(max);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setMaximum(long max) {
|
|
||||||
monitorComponent.setMaximum(max);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getMaximum() {
|
|
||||||
return monitorComponent.getMaximum();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the <code>indeterminate</code> property of the progress bar,
|
|
||||||
* which determines whether the progress bar is in determinate
|
|
||||||
* or indeterminate mode.
|
|
||||||
* An indeterminate progress bar continuously displays animation
|
|
||||||
* indicating that an operation of unknown length is occurring.
|
|
||||||
* By default, this property is <code>false</code>.
|
|
||||||
* Some look and feels might not support indeterminate progress bars;
|
|
||||||
* they will ignore this property.
|
|
||||||
*
|
|
||||||
* @see JProgressBar
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void setIndeterminate(final boolean indeterminate) {
|
|
||||||
monitorComponent.setIndeterminate(indeterminate);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void cancelCallback() {
|
protected void cancelCallback() {
|
||||||
SwingUtilities.invokeLater(shouldCancelRunnable);
|
SwingUtilities.invokeLater(shouldCancelRunnable);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
synchronized public void setMessage(String str) {
|
|
||||||
boolean invoke = (newPrimaryMessage == null);
|
|
||||||
if (invoke) {
|
|
||||||
newPrimaryMessage = str;
|
|
||||||
SwingUtilities.invokeLater(updatePrimaryMessageRunnable);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setCancelEnabled(boolean enable) {
|
public void setCancelEnabled(boolean enable) {
|
||||||
monitorComponent.setCancelEnabled(enable);
|
monitorComponent.setCancelEnabled(enable);
|
||||||
|
@ -300,11 +228,6 @@ public class TaskDialog extends DialogComponentProvider implements TaskMonitor {
|
||||||
return taskDone;
|
return taskDone;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isCancelled() {
|
|
||||||
return monitorComponent.isCancelled();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows the dialog window centered on the parent window.
|
* Shows the dialog window centered on the parent window.
|
||||||
* Dialog display is delayed if delay greater than zero.
|
* Dialog display is delayed if delay greater than zero.
|
||||||
|
@ -382,6 +305,71 @@ public class TaskDialog extends DialogComponentProvider implements TaskMonitor {
|
||||||
SystemUtilities.runSwingNow(disposeTask);
|
SystemUtilities.runSwingNow(disposeTask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
// TaskMonitor Methods
|
||||||
|
//==================================================================================================
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setMessage(String str) {
|
||||||
|
newMessage.set(str);
|
||||||
|
messageUpdater.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMessage() {
|
||||||
|
return monitorComponent.getMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setShowProgressValue(boolean showProgressValue) {
|
||||||
|
monitorComponent.setShowProgressValue(showProgressValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setProgress(long progress) {
|
||||||
|
monitorComponent.setProgress(progress);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize(long max) {
|
||||||
|
if (monitorComponent.isIndeterminate()) {
|
||||||
|
// don't show the progress bar if we have already been marked as indeterminate (this
|
||||||
|
// allows us to prevent low-level algorithms from changing the display settings).
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!monitorComponent.isShowing()) {
|
||||||
|
installProgressMonitor();
|
||||||
|
}
|
||||||
|
|
||||||
|
monitorComponent.initialize(max);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setMaximum(long max) {
|
||||||
|
monitorComponent.setMaximum(max);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getMaximum() {
|
||||||
|
return monitorComponent.getMaximum();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setIndeterminate(final boolean indeterminate) {
|
||||||
|
monitorComponent.setIndeterminate(indeterminate);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isIndeterminate() {
|
||||||
|
return monitorComponent.isIndeterminate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCancelled() {
|
||||||
|
return monitorComponent.isCancelled();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void cancel() {
|
public synchronized void cancel() {
|
||||||
if (monitorComponent.isCancelled()) {
|
if (monitorComponent.isCancelled()) {
|
||||||
|
@ -421,4 +409,8 @@ public class TaskDialog extends DialogComponentProvider implements TaskMonitor {
|
||||||
public void removeCancelledListener(CancelledListener listener) {
|
public void removeCancelledListener(CancelledListener listener) {
|
||||||
monitorComponent.removeCancelledListener(listener);
|
monitorComponent.removeCancelledListener(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
// End TaskMonitor Methods
|
||||||
|
//==================================================================================================
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,10 +16,8 @@
|
||||||
package ghidra.util.task;
|
package ghidra.util.task;
|
||||||
|
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import ghidra.util.Swing;
|
import ghidra.util.Swing;
|
||||||
import ghidra.util.exception.UnableToSwingException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class to initiate a Task in a new Thread, and to show a progress dialog that indicates
|
* Class to initiate a Task in a new Thread, and to show a progress dialog that indicates
|
||||||
|
@ -30,14 +28,6 @@ import ghidra.util.exception.UnableToSwingException;
|
||||||
* {@link #TaskLauncher(Task, Component, int, int)}. Alternatively, for simpler uses,
|
* {@link #TaskLauncher(Task, Component, int, int)}. Alternatively, for simpler uses,
|
||||||
* see one of the many static convenience methods.
|
* see one of the many static convenience methods.
|
||||||
*
|
*
|
||||||
* <p><b>Important Usage Note:</b><br>
|
|
||||||
* For clients that are not on the Swing thread the behavior of this class is designed to
|
|
||||||
* prevent deadlocks. When called from a non-Swing thread, this class will attempt to show a
|
|
||||||
* modal dialog. However, if more than {@link #getSwingTimeoutInSeconds()} elapses while waiting
|
|
||||||
* for the Swing thread, then this class will <b>give up on using the Swing thread and will not
|
|
||||||
* create a background thread</b>. Instead, the client code will be run in the client thread.
|
|
||||||
*
|
|
||||||
* <a name="modal_usage"></a>
|
|
||||||
* <p><b><a name="modal_usage">Modal Usage</a></b><br>
|
* <p><b><a name="modal_usage">Modal Usage</a></b><br>
|
||||||
* Most clients of this class should not be concerned with where
|
* 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 dialog used by this class will appear. By default, it will be shown over
|
||||||
|
@ -229,37 +219,8 @@ public class TaskLauncher {
|
||||||
*/
|
*/
|
||||||
public TaskLauncher(Task task, Component parent, int delayMs, int dialogWidth) {
|
public TaskLauncher(Task task, Component parent, int delayMs, int dialogWidth) {
|
||||||
|
|
||||||
try {
|
|
||||||
scheduleFromSwingThread(task, parent, delayMs, dialogWidth);
|
|
||||||
}
|
|
||||||
catch (UnableToSwingException e) {
|
|
||||||
runInThisBackgroundThread(task);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void scheduleFromSwingThread(Task task, Component parent, int delayMs, int dialogWidth)
|
|
||||||
throws UnableToSwingException {
|
|
||||||
|
|
||||||
TaskRunner runner = createTaskRunner(task, parent, delayMs, dialogWidth);
|
TaskRunner runner = createTaskRunner(task, parent, delayMs, dialogWidth);
|
||||||
if (Swing.isEventDispatchThread()) {
|
|
||||||
runner.run();
|
runner.run();
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Not on the Swing thread. Try to execute on the Swing thread, timing-out if it takes
|
|
||||||
// too long (this prevents deadlocks).
|
|
||||||
//
|
|
||||||
|
|
||||||
// This will throw an exception if we could not get the Swing lock. When that happens,
|
|
||||||
// the task was NOT run.
|
|
||||||
int timeout = getSwingTimeoutInSeconds();
|
|
||||||
Swing.runNow(() -> runner.run(), timeout, TimeUnit.SECONDS);
|
|
||||||
}
|
|
||||||
|
|
||||||
// template method to allow timeout change; used by tests
|
|
||||||
protected int getSwingTimeoutInSeconds() {
|
|
||||||
return 2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// template method to allow task runner change; used by tests
|
// template method to allow task runner change; used by tests
|
||||||
|
@ -275,7 +236,7 @@ public class TaskLauncher {
|
||||||
* @throws IllegalStateException if the given thread is the Swing thread
|
* @throws IllegalStateException if the given thread is the Swing thread
|
||||||
*/
|
*/
|
||||||
protected void runInThisBackgroundThread(Task task) {
|
protected void runInThisBackgroundThread(Task task) {
|
||||||
if (Swing.isEventDispatchThread()) {
|
if (Swing.isSwingThread()) {
|
||||||
throw new IllegalStateException("Must not call this method from the Swing thread");
|
throw new IllegalStateException("Must not call this method from the Swing thread");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -155,6 +155,11 @@ public class TaskMonitorComponent extends JPanel implements TaskMonitor {
|
||||||
startUpdateTimer();
|
startUpdateTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized String getMessage() {
|
||||||
|
return progressMessage;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void setProgress(long value) {
|
public synchronized void setProgress(long value) {
|
||||||
if (progress == value) {
|
if (progress == value) {
|
||||||
|
|
|
@ -16,12 +16,12 @@
|
||||||
package ghidra.util.task;
|
package ghidra.util.task;
|
||||||
|
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
import generic.concurrent.GThreadPool;
|
import generic.concurrent.GThreadPool;
|
||||||
import generic.util.WindowUtilities;
|
import generic.util.WindowUtilities;
|
||||||
import ghidra.util.Swing;
|
import ghidra.util.*;
|
||||||
import ghidra.util.TaskUtilities;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper class to launch the given task in a background thread, showing a task dialog if
|
* Helper class to launch the given task in a background thread, showing a task dialog if
|
||||||
|
@ -29,20 +29,13 @@ import ghidra.util.TaskUtilities;
|
||||||
*/
|
*/
|
||||||
class TaskRunner {
|
class TaskRunner {
|
||||||
|
|
||||||
protected Task task;
|
private Task task;
|
||||||
private Component parent;
|
private Component parent;
|
||||||
private int delayMs;
|
private int delayMs;
|
||||||
private int dialogWidth;
|
private int dialogWidth;
|
||||||
|
|
||||||
private TaskDialog taskDialog;
|
private TaskDialog taskDialog;
|
||||||
private Thread taskThread;
|
private CountDownLatch finished = new CountDownLatch(1);
|
||||||
private CancelledListener monitorChangeListener = () -> {
|
|
||||||
if (task.isInterruptible()) {
|
|
||||||
taskThread.interrupt();
|
|
||||||
}
|
|
||||||
if (task.isForgettable()) {
|
|
||||||
taskDialog.close(); // close the dialog and forget about the task
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
TaskRunner(Task task, Component parent, int delayMs, int dialogWidth) {
|
TaskRunner(Task task, Component parent, int delayMs, int dialogWidth) {
|
||||||
this.task = task;
|
this.task = task;
|
||||||
|
@ -53,37 +46,40 @@ class TaskRunner {
|
||||||
|
|
||||||
void run() {
|
void run() {
|
||||||
|
|
||||||
// note: we need to be on the Swing thread to create our UI widgets
|
BasicTaskMonitor internalMonitor = new BasicTaskMonitor();
|
||||||
Swing.assertThisIsTheSwingThread(
|
WrappingTaskMonitor monitor = new WrappingTaskMonitor(internalMonitor);
|
||||||
"The Task runner is required to be run from the Swing thread");
|
startTaskThread(monitor);
|
||||||
|
|
||||||
this.taskDialog = buildTaskDialog(parent);
|
Swing.runIfSwingOrRunLater(() -> showTaskDialog(monitor));
|
||||||
|
waitForModalTask();
|
||||||
startBackgroundThread(taskDialog);
|
|
||||||
|
|
||||||
taskDialog.show(Math.max(delayMs, 0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected TaskDialog buildTaskDialog(Component comp) {
|
private void waitForModalTask() {
|
||||||
|
|
||||||
//
|
if (!task.isModal()) {
|
||||||
// This class may be used by background threads. Make sure that our GUI creation is
|
return; // we do not wait for non-modal tasks
|
||||||
// on the Swing thread to prevent exceptions while painting (as seen when using the
|
|
||||||
// Nimbus Look and Feel).
|
|
||||||
//
|
|
||||||
taskDialog = createTaskDialog(comp);
|
|
||||||
taskDialog.setMinimumSize(dialogWidth, 0);
|
|
||||||
|
|
||||||
if (task.isInterruptible() || task.isForgettable()) {
|
|
||||||
taskDialog.addCancelledListener(monitorChangeListener);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
taskDialog.setStatusJustification(task.getStatusTextAlignment());
|
try {
|
||||||
|
// fun note: if this is the Swing thread, then it will not wait, as the Swing thread
|
||||||
return taskDialog;
|
// was blocked by the modal dialog in the call before this one
|
||||||
|
finished.await();
|
||||||
|
}
|
||||||
|
catch (InterruptedException e) {
|
||||||
|
Msg.debug(this, "Task Launcher unexpectedly interrupted waiting for task thread", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startBackgroundThread(TaskMonitor monitor) {
|
// protected to allow for dependency injection
|
||||||
|
protected TaskDialog buildTaskDialog(Component comp, TaskMonitor monitor) {
|
||||||
|
|
||||||
|
TaskDialog dialog = createTaskDialog(comp);
|
||||||
|
dialog.setMinimumSize(dialogWidth, 0);
|
||||||
|
dialog.setStatusJustification(task.getStatusTextAlignment());
|
||||||
|
return dialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startTaskThread(TaskMonitor monitor) {
|
||||||
|
|
||||||
// add the task here, so we can track it before it is actually started by the thread
|
// add the task here, so we can track it before it is actually started by the thread
|
||||||
TaskUtilities.addTrackedTask(task, monitor);
|
TaskUtilities.addTrackedTask(task, monitor);
|
||||||
|
@ -93,20 +89,61 @@ class TaskRunner {
|
||||||
Executor executor = pool.getExecutor();
|
Executor executor = pool.getExecutor();
|
||||||
executor.execute(() -> {
|
executor.execute(() -> {
|
||||||
Thread.currentThread().setName(name);
|
Thread.currentThread().setName(name);
|
||||||
|
|
||||||
|
try {
|
||||||
task.monitoredRun(monitor);
|
task.monitoredRun(monitor);
|
||||||
taskDialog.taskProcessed();
|
}
|
||||||
|
finally {
|
||||||
|
taskFinished();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private TaskDialog createTaskDialog(Component comp) {
|
private TaskDialog createTaskDialog(Component comp) {
|
||||||
Component currentParent = comp;
|
Component centerOverComponent = comp;
|
||||||
|
Component currentParent = centerOverComponent;
|
||||||
if (currentParent != null) {
|
if (currentParent != null) {
|
||||||
currentParent = WindowUtilities.windowForComponent(comp);
|
currentParent = WindowUtilities.windowForComponent(comp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentParent == null) {
|
if (currentParent == null) {
|
||||||
return new TaskDialog(task);
|
centerOverComponent = null;
|
||||||
}
|
}
|
||||||
return new TaskDialog(comp, task);
|
|
||||||
|
return new TaskDialog(centerOverComponent, task) {
|
||||||
|
|
||||||
|
// note: we override this method here to help with the race condition where the
|
||||||
|
// TaskRunner does not yet know about the task dialog, but the background
|
||||||
|
// thread has actually finished the work.
|
||||||
|
@Override
|
||||||
|
public synchronized boolean isCompleted() {
|
||||||
|
return super.isCompleted() || isFinished();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showTaskDialog(WrappingTaskMonitor monitor) {
|
||||||
|
|
||||||
|
Swing.assertThisIsTheSwingThread("Must be on the Swing thread build the Task Dialog");
|
||||||
|
|
||||||
|
taskDialog = buildTaskDialog(parent, monitor);
|
||||||
|
monitor.setDelegate(taskDialog); // initialize the dialog to the current state of the monitor
|
||||||
|
taskDialog.show(Math.max(delayMs, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*testing*/ boolean isFinished() {
|
||||||
|
return finished.getCount() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void taskFinished() {
|
||||||
|
finished.countDown();
|
||||||
|
|
||||||
|
// Do this later on the Swing thread to handle the race condition where the dialog
|
||||||
|
// did not exist at the time of this call, but was in the process of being created
|
||||||
|
Swing.runLater(() -> {
|
||||||
|
if (taskDialog != null) {
|
||||||
|
taskDialog.taskProcessed();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,6 +64,14 @@ public class AbstractTaskTest extends AbstractDockingTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void assertNoDialogShown() {
|
||||||
|
if (dialogSpy == null) {
|
||||||
|
return; // not shown
|
||||||
|
}
|
||||||
|
|
||||||
|
assertFalse(dialogSpy.wasShown());
|
||||||
|
}
|
||||||
|
|
||||||
protected void waitForTask() throws Exception {
|
protected void waitForTask() throws Exception {
|
||||||
threadsFinished.await(2, TimeUnit.SECONDS);
|
threadsFinished.await(2, TimeUnit.SECONDS);
|
||||||
}
|
}
|
||||||
|
@ -97,18 +105,18 @@ public class AbstractTaskTest extends AbstractDockingTest {
|
||||||
|
|
||||||
return new TaskRunner(task, parent, delay, dialogWidth) {
|
return new TaskRunner(task, parent, delay, dialogWidth) {
|
||||||
@Override
|
@Override
|
||||||
protected TaskDialog buildTaskDialog(Component comp) {
|
protected TaskDialog buildTaskDialog(Component comp, TaskMonitor monitor) {
|
||||||
dialogSpy = new TaskDialogSpy(task);
|
dialogSpy = new TaskDialogSpy(task) {
|
||||||
|
@Override
|
||||||
|
public synchronized boolean isCompleted() {
|
||||||
|
return super.isCompleted() || isFinished();
|
||||||
|
}
|
||||||
|
};
|
||||||
return dialogSpy;
|
return dialogSpy;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected int getSwingTimeoutInSeconds() {
|
|
||||||
return 1; // speed-up for tests
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void runInThisBackgroundThread(Task task) {
|
protected void runInThisBackgroundThread(Task task) {
|
||||||
didRunInBackground.set(true);
|
didRunInBackground.set(true);
|
||||||
|
|
|
@ -27,6 +27,21 @@ public class TaskDialogTest extends AbstractTaskTest {
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testModalDialogWithoutDependencyInjection() throws Exception {
|
||||||
|
|
||||||
|
//
|
||||||
|
// A version of the test to use all of the real dialog internals of the
|
||||||
|
// TaskRunner, which are usually replaced with test versions.
|
||||||
|
//
|
||||||
|
|
||||||
|
FastModalTask task = new FastModalTask();
|
||||||
|
|
||||||
|
new TaskLauncher(task);
|
||||||
|
|
||||||
|
waitForTasks(); // make sure we don't timeout
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testModalDialog_FastTask_NoDialog() throws Exception {
|
public void testModalDialog_FastTask_NoDialog() throws Exception {
|
||||||
|
|
||||||
|
@ -62,7 +77,7 @@ public class TaskDialogTest extends AbstractTaskTest {
|
||||||
waitForTask();
|
waitForTask();
|
||||||
|
|
||||||
assertFalse(dialogSpy.wasShown());
|
assertFalse(dialogSpy.wasShown());
|
||||||
assertSwingThreadFinishedBeforeTask();
|
assertNoDialogShown();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -111,5 +126,4 @@ public class TaskDialogTest extends AbstractTaskTest {
|
||||||
|
|
||||||
assertFalse(dialogSpy.isCancelEnabled());
|
assertFalse(dialogSpy.isCancelEnabled());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,15 +40,20 @@ import ghidra.util.task.TaskMonitor;
|
||||||
* On ConcurrentQs that only allow one task to run at a time, when a task is cancelled,
|
* On ConcurrentQs that only allow one task to run at a time, when a task is cancelled,
|
||||||
* the next task can begin. Most likely, the thread that was running the cancelled
|
* the next task can begin. Most likely, the thread that was running the cancelled
|
||||||
* task won't be free, and a new thread will be used to start running the next task.
|
* task won't be free, and a new thread will be used to start running the next task.
|
||||||
|
*
|
||||||
|
* @param <I> the input type
|
||||||
|
* @param <R> the output type
|
||||||
*/
|
*/
|
||||||
class FutureTaskMonitor<I, R> extends FutureTask<R> implements TaskMonitor {
|
class FutureTaskMonitor<I, R> extends FutureTask<R> implements TaskMonitor {
|
||||||
|
|
||||||
private final ConcurrentQ<I, R> queue;
|
private final ConcurrentQ<I, R> queue;
|
||||||
private final I item;
|
private final I item;
|
||||||
private final long id;
|
private final long id;
|
||||||
|
private volatile String lastMessage;
|
||||||
private volatile long currentProgress;
|
private volatile long currentProgress;
|
||||||
private volatile long maxProgress;
|
private volatile long maxProgress;
|
||||||
private volatile CancelledListener cancelledListener;
|
private volatile CancelledListener cancelledListener;
|
||||||
|
private volatile boolean isIndeterminate;
|
||||||
|
|
||||||
FutureTaskMonitor(ConcurrentQ<I, R> queue, Callable<R> callable, I item, long id) {
|
FutureTaskMonitor(ConcurrentQ<I, R> queue, Callable<R> callable, I item, long id) {
|
||||||
super(callable);
|
super(callable);
|
||||||
|
@ -103,6 +108,11 @@ class FutureTaskMonitor<I, R> extends FutureTask<R> implements TaskMonitor {
|
||||||
queue.progressMessageChanged(id, item, message);
|
queue.progressMessageChanged(id, item, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMessage() {
|
||||||
|
return lastMessage;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initialize(long max) {
|
public void initialize(long max) {
|
||||||
currentProgress = 0;
|
currentProgress = 0;
|
||||||
|
@ -123,9 +133,15 @@ class FutureTaskMonitor<I, R> extends FutureTask<R> implements TaskMonitor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setIndeterminate(boolean indeterminate) {
|
public void setIndeterminate(boolean indeterminate) {
|
||||||
|
this.isIndeterminate = indeterminate;
|
||||||
queue.progressModeChanged(id, item, indeterminate);
|
queue.progressModeChanged(id, item, indeterminate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isIndeterminate() {
|
||||||
|
return isIndeterminate;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getProgress() {
|
public long getProgress() {
|
||||||
return currentProgress;
|
return currentProgress;
|
||||||
|
|
|
@ -220,28 +220,6 @@ public abstract class Task implements MonitoredRunnable {
|
||||||
return isModal;
|
return isModal;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isInterruptible() {
|
|
||||||
return isInterruptible;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setInterruptible(boolean interruptible) {
|
|
||||||
this.isInterruptible = interruptible;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if this task should be left alone to die when cancelled, as opposed to being
|
|
||||||
* interrupted
|
|
||||||
*
|
|
||||||
* @return true if forgettable
|
|
||||||
*/
|
|
||||||
public boolean isForgettable() {
|
|
||||||
return isForgettable;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setForgettable(boolean isForgettable) {
|
|
||||||
this.isForgettable = isForgettable;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the task listener on this task. It is a programming error to call this method more
|
* Sets the task listener on this task. It is a programming error to call this method more
|
||||||
* than once or to call this method if a listener was passed into the constructor of this class.
|
* than once or to call this method if a listener was passed into the constructor of this class.
|
||||||
|
|
|
@ -67,6 +67,11 @@ public class TaskMonitorAdapter implements TaskMonitor {
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMessage() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setProgress(long value) {
|
public void setProgress(long value) {
|
||||||
// do nothing
|
// do nothing
|
||||||
|
@ -105,6 +110,11 @@ public class TaskMonitorAdapter implements TaskMonitor {
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isIndeterminate() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void setCancelEnabled(boolean enable) {
|
public synchronized void setCancelEnabled(boolean enable) {
|
||||||
cancelEnabled = enable;
|
cancelEnabled = enable;
|
||||||
|
@ -134,6 +144,8 @@ public class TaskMonitorAdapter implements TaskMonitor {
|
||||||
}
|
}
|
||||||
cancelled = false;
|
cancelled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO this seems like a mistake, to notify of 'cancelled' when clearning
|
||||||
notifyChangeListeners();
|
notifyChangeListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -136,6 +136,11 @@ public class TaskMonitorSplitter {
|
||||||
parent.setIndeterminate(indeterminate);
|
parent.setIndeterminate(indeterminate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isIndeterminate() {
|
||||||
|
return parent.isIndeterminate();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initialize(long newMax) {
|
public void initialize(long newMax) {
|
||||||
setMaximum(newMax);
|
setMaximum(newMax);
|
||||||
|
@ -152,7 +157,11 @@ public class TaskMonitorSplitter {
|
||||||
@Override
|
@Override
|
||||||
public void setMessage(String message) {
|
public void setMessage(String message) {
|
||||||
parent.setMessage(message);
|
parent.setMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMessage() {
|
||||||
|
return parent.getMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -139,6 +139,11 @@ public class TimeoutTaskMonitor implements TaskMonitor {
|
||||||
delegate.setMessage(message);
|
delegate.setMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMessage() {
|
||||||
|
return delegate.getMessage();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setProgress(long value) {
|
public void setProgress(long value) {
|
||||||
delegate.setProgress(value);
|
delegate.setProgress(value);
|
||||||
|
@ -164,6 +169,11 @@ public class TimeoutTaskMonitor implements TaskMonitor {
|
||||||
delegate.setIndeterminate(indeterminate);
|
delegate.setIndeterminate(indeterminate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isIndeterminate() {
|
||||||
|
return delegate.isIndeterminate();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void checkCanceled() throws CancelledException {
|
public void checkCanceled() throws CancelledException {
|
||||||
if (didTimeout()) {
|
if (didTimeout()) {
|
||||||
|
|
|
@ -15,16 +15,30 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.util.task;
|
package ghidra.util.task;
|
||||||
|
|
||||||
|
import ghidra.util.datastruct.WeakDataStructureFactory;
|
||||||
|
import ghidra.util.datastruct.WeakSet;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An implementation of the {@link TaskMonitor} interface that simply wraps a delegate task
|
* An implementation of the {@link TaskMonitor} interface that simply wraps a delegate task
|
||||||
* monitor. This is useful for classes that wish to wrap a task monitor, changing behavior
|
* monitor. This is useful for classes that wish to wrap a task monitor, changing behavior
|
||||||
* as needed by overriding a subset of methods.
|
* as needed by overriding a subset of methods.
|
||||||
|
*
|
||||||
|
* <p><b>Synchronization Policy</b>:<br>
|
||||||
|
* We wish for this class to be performant. Thus, we do not synchronize the methods of this
|
||||||
|
* class. The {@link #setDelegate(TaskMonitor)} is synchronized to ensure thread visibility
|
||||||
|
* for the state of the delegate monitor.
|
||||||
|
*
|
||||||
|
* <p>When calling {@link #setDelegate(TaskMonitor)} there is the potential for the values being
|
||||||
|
* transferred to become inconsistent with any new values being set. We have decided that this
|
||||||
|
* does not much matter for the overall progress or the messages on the monitor. However, most
|
||||||
|
* of the other setter methods could lead to bad behavior if they are inconsistent.
|
||||||
*/
|
*/
|
||||||
public class WrappingTaskMonitor implements TaskMonitor {
|
public class WrappingTaskMonitor implements TaskMonitor {
|
||||||
|
|
||||||
protected final TaskMonitor delegate;
|
private WeakSet<CancelledListener> listeners =
|
||||||
|
WeakDataStructureFactory.createCopyOnReadWeakSet();
|
||||||
|
protected TaskMonitor delegate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
|
@ -35,8 +49,36 @@ public class WrappingTaskMonitor implements TaskMonitor {
|
||||||
this.delegate = delegate;
|
this.delegate = delegate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the delegate of this wrapper to be the new value. The new delegate will be
|
||||||
|
* initialized with the current values of the existing delegate.
|
||||||
|
*
|
||||||
|
* @param newDelegate the new delegate
|
||||||
|
*/
|
||||||
|
public synchronized void setDelegate(TaskMonitor newDelegate) {
|
||||||
|
|
||||||
|
// if the existing monitor has already been cancelled, then do not apply the state
|
||||||
|
if (delegate.isCancelled()) {
|
||||||
|
newDelegate.cancel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (CancelledListener l : listeners) {
|
||||||
|
newDelegate.addCancelledListener(l);
|
||||||
|
delegate.removeCancelledListener(l);
|
||||||
|
}
|
||||||
|
|
||||||
|
newDelegate.setMaximum(delegate.getMaximum());
|
||||||
|
newDelegate.setProgress(delegate.getProgress());
|
||||||
|
newDelegate.setMessage(delegate.getMessage());
|
||||||
|
newDelegate.setIndeterminate(delegate.isIndeterminate());
|
||||||
|
newDelegate.setCancelEnabled(delegate.isCancelEnabled());
|
||||||
|
|
||||||
|
this.delegate = newDelegate;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isCancelled() {
|
public synchronized boolean isCancelled() {
|
||||||
return delegate.isCancelled();
|
return delegate.isCancelled();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,6 +92,11 @@ public class WrappingTaskMonitor implements TaskMonitor {
|
||||||
delegate.setMessage(message);
|
delegate.setMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMessage() {
|
||||||
|
return delegate.getMessage();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setProgress(long value) {
|
public void setProgress(long value) {
|
||||||
delegate.setProgress(value);
|
delegate.setProgress(value);
|
||||||
|
@ -61,7 +108,7 @@ public class WrappingTaskMonitor implements TaskMonitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setMaximum(long max) {
|
public synchronized void setMaximum(long max) {
|
||||||
delegate.setMaximum(max);
|
delegate.setMaximum(max);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,10 +118,15 @@ public class WrappingTaskMonitor implements TaskMonitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setIndeterminate(boolean indeterminate) {
|
public synchronized void setIndeterminate(boolean indeterminate) {
|
||||||
delegate.setIndeterminate(indeterminate);
|
delegate.setIndeterminate(indeterminate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isIndeterminate() {
|
||||||
|
return delegate.isIndeterminate();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void checkCanceled() throws CancelledException {
|
public void checkCanceled() throws CancelledException {
|
||||||
delegate.checkCanceled();
|
delegate.checkCanceled();
|
||||||
|
@ -91,22 +143,24 @@ public class WrappingTaskMonitor implements TaskMonitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void cancel() {
|
public synchronized void cancel() {
|
||||||
delegate.cancel();
|
delegate.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addCancelledListener(CancelledListener listener) {
|
public synchronized void addCancelledListener(CancelledListener listener) {
|
||||||
|
listeners.add(listener);
|
||||||
delegate.addCancelledListener(listener);
|
delegate.addCancelledListener(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeCancelledListener(CancelledListener listener) {
|
public synchronized void removeCancelledListener(CancelledListener listener) {
|
||||||
|
listeners.remove(listener);
|
||||||
delegate.removeCancelledListener(listener);
|
delegate.removeCancelledListener(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setCancelEnabled(boolean enable) {
|
public synchronized void setCancelEnabled(boolean enable) {
|
||||||
delegate.setCancelEnabled(enable);
|
delegate.setCancelEnabled(enable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,7 +170,7 @@ public class WrappingTaskMonitor implements TaskMonitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void clearCanceled() {
|
public synchronized void clearCanceled() {
|
||||||
delegate.clearCanceled();
|
delegate.clearCanceled();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ class LockingTaskMonitor implements TaskMonitor {
|
||||||
* be done in a try/finally block to avoid accidentally locking the
|
* be done in a try/finally block to avoid accidentally locking the
|
||||||
* domain object indefinitely.
|
* domain object indefinitely.
|
||||||
* @param dobj domain object
|
* @param dobj domain object
|
||||||
* @param hasProgress
|
* @param hasProgress true if this monitorhas progress
|
||||||
* @param title task title
|
* @param title task title
|
||||||
*/
|
*/
|
||||||
LockingTaskMonitor(DomainObjectAdapterDB dobj, boolean hasProgress, String title) {
|
LockingTaskMonitor(DomainObjectAdapterDB dobj, boolean hasProgress, String title) {
|
||||||
|
@ -119,6 +119,11 @@ class LockingTaskMonitor implements TaskMonitor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized String getMessage() {
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @see ghidra.util.task.TaskMonitor#setProgress(int)
|
* @see ghidra.util.task.TaskMonitor#setProgress(int)
|
||||||
*/
|
*/
|
||||||
|
@ -165,6 +170,11 @@ class LockingTaskMonitor implements TaskMonitor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isIndeterminate() {
|
||||||
|
return indeterminate;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @see ghidra.util.task.TaskMonitor#setCancelEnabled(boolean)
|
* @see ghidra.util.task.TaskMonitor#setCancelEnabled(boolean)
|
||||||
*/
|
*/
|
||||||
|
@ -206,9 +216,6 @@ class LockingTaskMonitor implements TaskMonitor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* @see ghidra.util.task.TaskMonitor#checkCanceled()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void checkCanceled() throws CancelledException {
|
public void checkCanceled() throws CancelledException {
|
||||||
if (isCancelled()) {
|
if (isCancelled()) {
|
||||||
|
@ -216,17 +223,11 @@ class LockingTaskMonitor implements TaskMonitor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.util.task.TaskMonitor#incrementProgress(int)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void incrementProgress(long incrementAmount) {
|
public void incrementProgress(long incrementAmount) {
|
||||||
setProgress(curProgress + incrementAmount);
|
setProgress(curProgress + incrementAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.util.task.TaskMonitor#getProgress()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public long getProgress() {
|
public long getProgress() {
|
||||||
return curProgress;
|
return curProgress;
|
||||||
|
|
|
@ -102,6 +102,11 @@ public class GTaskMonitor implements TaskMonitor, CancelledListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isIndeterminate() {
|
||||||
|
return indeterminate;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void checkCanceled() throws CancelledException {
|
public void checkCanceled() throws CancelledException {
|
||||||
if (isCancelled) {
|
if (isCancelled) {
|
||||||
|
@ -163,6 +168,7 @@ public class GTaskMonitor implements TaskMonitor, CancelledListener {
|
||||||
return showProgressValue;
|
return showProgressValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String getMessage() {
|
public String getMessage() {
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ public class Swing {
|
||||||
|
|
||||||
private static final String SWING_TIMEOUT_SECONDS_PROPERTY =
|
private static final String SWING_TIMEOUT_SECONDS_PROPERTY =
|
||||||
Swing.class.getName().toLowerCase() + ".timeout.seconds";
|
Swing.class.getName().toLowerCase() + ".timeout.seconds";
|
||||||
private static final int SWING_TIMEOUT_SECONDS_DEFAULT_VALUE = 10;
|
private static final int SWING_TIMEOUT_SECONDS_DEFAULT_VALUE = 20;
|
||||||
|
|
||||||
private static int loadTimeout() {
|
private static int loadTimeout() {
|
||||||
String timeoutString = System.getProperty(SWING_TIMEOUT_SECONDS_PROPERTY,
|
String timeoutString = System.getProperty(SWING_TIMEOUT_SECONDS_PROPERTY,
|
||||||
|
@ -61,7 +61,7 @@ public class Swing {
|
||||||
*
|
*
|
||||||
* @return true if this is the event dispatch thread -OR- is in headless mode.
|
* @return true if this is the event dispatch thread -OR- is in headless mode.
|
||||||
*/
|
*/
|
||||||
public static boolean isEventDispatchThread() {
|
public static boolean isSwingThread() {
|
||||||
if (isInHeadlessMode()) {
|
if (isInHeadlessMode()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -94,7 +94,7 @@ public class Swing {
|
||||||
return; // squash during production mode
|
return; // squash during production mode
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isEventDispatchThread()) {
|
if (!isSwingThread()) {
|
||||||
Throwable t =
|
Throwable t =
|
||||||
ReflectionUtilities.filterJavaThrowable(new AssertException(errorMessage));
|
ReflectionUtilities.filterJavaThrowable(new AssertException(errorMessage));
|
||||||
Msg.error(SystemUtilities.class, errorMessage, t);
|
Msg.error(SystemUtilities.class, errorMessage, t);
|
||||||
|
|
|
@ -422,7 +422,7 @@ public class SystemUtilities {
|
||||||
* @return true if this is the event dispatch thread -OR- is in headless mode.
|
* @return true if this is the event dispatch thread -OR- is in headless mode.
|
||||||
*/
|
*/
|
||||||
public static boolean isEventDispatchThread() {
|
public static boolean isEventDispatchThread() {
|
||||||
return Swing.isEventDispatchThread();
|
return Swing.isSwingThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -33,7 +33,11 @@ class StubTaskMonitor implements TaskMonitor {
|
||||||
@Override
|
@Override
|
||||||
public void setMessage(String message) {
|
public void setMessage(String message) {
|
||||||
// stub
|
// stub
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMessage() {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -64,6 +68,11 @@ class StubTaskMonitor implements TaskMonitor {
|
||||||
// stub
|
// stub
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isIndeterminate() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void checkCanceled() throws CancelledException {
|
public void checkCanceled() throws CancelledException {
|
||||||
// stub
|
// stub
|
||||||
|
|
|
@ -56,6 +56,12 @@ public interface TaskMonitor {
|
||||||
*/
|
*/
|
||||||
public void setMessage(String message);
|
public void setMessage(String message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the last set message of this monitor
|
||||||
|
* @return the message
|
||||||
|
*/
|
||||||
|
public String getMessage();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the current progress value
|
* Sets the current progress value
|
||||||
* @param value progress value
|
* @param value progress value
|
||||||
|
@ -91,6 +97,12 @@ public interface TaskMonitor {
|
||||||
*/
|
*/
|
||||||
public void setIndeterminate(boolean indeterminate);
|
public void setIndeterminate(boolean indeterminate);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if this monitor shows no progress
|
||||||
|
* @return true if this monitor shows no progress
|
||||||
|
*/
|
||||||
|
public boolean isIndeterminate();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check to see if this monitor has been canceled
|
* Check to see if this monitor has been canceled
|
||||||
* @throws CancelledException if monitor has been cancelled
|
* @throws CancelledException if monitor has been cancelled
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue