mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-06 03:50:02 +02:00
GP-4270: Minor fixes
This commit is contained in:
parent
b9f914d57c
commit
1cf7803d88
22 changed files with 295 additions and 183 deletions
|
@ -20,8 +20,10 @@ import java.awt.Point;
|
|||
import java.awt.event.MouseEvent;
|
||||
import java.util.Objects;
|
||||
|
||||
import generic.json.Json;
|
||||
|
||||
/**
|
||||
* A class that holds information used to show a popup menu
|
||||
* A class that holds information used to show a popup menu
|
||||
*/
|
||||
public class PopupMenuContext {
|
||||
|
||||
|
@ -58,4 +60,9 @@ public class PopupMenuContext {
|
|||
}
|
||||
return component;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Json.toString(this);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -74,10 +74,10 @@ public class DefaultDropDownSelectionDataModel<T> implements DropDownTextFieldDa
|
|||
|
||||
@Override
|
||||
public int getIndexOfFirstMatchingEntry(List<T> list, String text) {
|
||||
// The data are sorted such that lower-case is before upper-case and smaller length
|
||||
// matches come before longer matches. If we ever find a case-sensitive exact match,
|
||||
// use that. Otherwise, keep looking for a case-insensitive exact match. The
|
||||
// case-insensitive match is preferred over a non-matching item. Once we get to a
|
||||
// The data are sorted such that lower-case is before upper-case and smaller length
|
||||
// matches come before longer matches. If we ever find a case-sensitive exact match,
|
||||
// use that. Otherwise, keep looking for a case-insensitive exact match. The
|
||||
// case-insensitive match is preferred over a non-matching item. Once we get to a
|
||||
// non-matching item, we can quit.
|
||||
int lastPreferredMatchIndex = -1;
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
|
@ -118,7 +118,7 @@ public class DefaultDropDownSelectionDataModel<T> implements DropDownTextFieldDa
|
|||
|
||||
//==================================================================================================
|
||||
// Inner Classes
|
||||
//==================================================================================================
|
||||
//==================================================================================================
|
||||
|
||||
private class ObjectStringComparator implements Comparator<Object> {
|
||||
Comparator<String> stringComparator = new CaseInsensitiveDuplicateStringComparator();
|
||||
|
|
|
@ -33,7 +33,6 @@ public class ListSelectionDialog<T> extends DialogComponentProvider {
|
|||
|
||||
private DropDownSelectionTextField<T> field;
|
||||
protected boolean cancelled;
|
||||
private RowObjectTableModel<T> userTableModel;
|
||||
private DataToStringConverter<T> searchConverter;
|
||||
private DataToStringConverter<T> descriptionConverter;
|
||||
private List<T> data;
|
||||
|
@ -61,8 +60,12 @@ public class ListSelectionDialog<T> extends DialogComponentProvider {
|
|||
this.data = data;
|
||||
this.searchConverter = searchConverter;
|
||||
this.descriptionConverter = descriptionConverter;
|
||||
|
||||
// Use a separate list for the drop down widget, since it needs to sort its data and we do
|
||||
// not want to change the client data sort.
|
||||
List<T> dropDownData = new ArrayList<>(data);
|
||||
DefaultDropDownSelectionDataModel<T> model = new DefaultDropDownSelectionDataModel<>(
|
||||
new ArrayList<>(data), searchConverter, descriptionConverter) {
|
||||
dropDownData, searchConverter, descriptionConverter) {
|
||||
|
||||
// overridden to return all data for an empty search; this lets the down-arrow
|
||||
// show the full list
|
||||
|
@ -151,14 +154,18 @@ public class ListSelectionDialog<T> extends DialogComponentProvider {
|
|||
}
|
||||
|
||||
private RowObjectTableModel<T> getTableModel() {
|
||||
if (userTableModel != null) {
|
||||
return userTableModel;
|
||||
}
|
||||
|
||||
return new DefaultTableModel();
|
||||
return new DefaultTableModel(data);
|
||||
}
|
||||
|
||||
private class DefaultTableModel extends AbstractGTableModel<T> {
|
||||
|
||||
private List<T> modelData;
|
||||
|
||||
DefaultTableModel(List<T> modelData) {
|
||||
// copy the data so that a call to dispose() will not clear the data in the outer class
|
||||
this.modelData = new ArrayList<>(modelData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getColumnName(int columnIndex) {
|
||||
if (columnIndex == 0) {
|
||||
|
@ -184,7 +191,7 @@ public class ListSelectionDialog<T> extends DialogComponentProvider {
|
|||
|
||||
@Override
|
||||
public List<T> getModelData() {
|
||||
return data;
|
||||
return modelData;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -29,8 +29,6 @@ import utilities.util.reflection.ReflectionUtilities;
|
|||
* determines the appropriate cell object for use by the table column this field represents. It can
|
||||
* then return the appropriate object to display in the table cell for the indicated row object.
|
||||
*
|
||||
* Implementations of this interface must provide a public default constructor.
|
||||
*
|
||||
* @param <ROW_TYPE> The row object class supported by this column
|
||||
* @param <COLUMN_TYPE> The column object class supported by this column
|
||||
* @param <DATA_SOURCE> The object class type that will be passed to see
|
||||
|
@ -95,8 +93,8 @@ public abstract class AbstractDynamicTableColumn<ROW_TYPE, COLUMN_TYPE, DATA_SOU
|
|||
public Class<COLUMN_TYPE> getColumnClass() {
|
||||
@SuppressWarnings("rawtypes")
|
||||
Class<? extends AbstractDynamicTableColumn> implementationClass = getClass();
|
||||
List<Class<?>> typeArguments = ReflectionUtilities.getTypeArguments(
|
||||
AbstractDynamicTableColumn.class, implementationClass);
|
||||
List<Class<?>> typeArguments = ReflectionUtilities
|
||||
.getTypeArguments(AbstractDynamicTableColumn.class, implementationClass);
|
||||
return (Class<COLUMN_TYPE>) typeArguments.get(1);
|
||||
}
|
||||
|
||||
|
@ -106,8 +104,8 @@ public abstract class AbstractDynamicTableColumn<ROW_TYPE, COLUMN_TYPE, DATA_SOU
|
|||
public Class<ROW_TYPE> getSupportedRowType() {
|
||||
@SuppressWarnings("rawtypes")
|
||||
Class<? extends AbstractDynamicTableColumn> implementationClass = getClass();
|
||||
List<Class<?>> typeArguments = ReflectionUtilities.getTypeArguments(
|
||||
AbstractDynamicTableColumn.class, implementationClass);
|
||||
List<Class<?>> typeArguments = ReflectionUtilities
|
||||
.getTypeArguments(AbstractDynamicTableColumn.class, implementationClass);
|
||||
return (Class<ROW_TYPE>) typeArguments.get(0);
|
||||
}
|
||||
|
||||
|
@ -193,7 +191,7 @@ public abstract class AbstractDynamicTableColumn<ROW_TYPE, COLUMN_TYPE, DATA_SOU
|
|||
return getIdentifier().hashCode();
|
||||
}
|
||||
|
||||
// Note: this method is here because the default 'identifier' must be lazy loaded, as
|
||||
// Note: this method is here because the default 'identifier' must be lazy loaded, as
|
||||
// at construction time not all the variables needed are available.
|
||||
private String getIdentifier() {
|
||||
/*
|
||||
|
@ -202,7 +200,7 @@ public abstract class AbstractDynamicTableColumn<ROW_TYPE, COLUMN_TYPE, DATA_SOU
|
|||
-The case where 2 different column classes share the same column header value
|
||||
-The case where a single column class is used repeatedly, with a different
|
||||
column header value each time
|
||||
|
||||
|
||||
Thus, to be unique, we need to combine both the class name and the column header
|
||||
value. The only time this may be an issue is if the column header value changes
|
||||
dynamically--not sure if this actually happens anywhere in our system. If it did,
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* 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.
|
||||
|
@ -20,14 +20,18 @@ import ghidra.framework.plugintool.ServiceProvider;
|
|||
|
||||
/**
|
||||
* This class is meant to be used by DynamicTableColumn implementations that do not care about
|
||||
* the DATA_SOURCE parameter of DynamicTableColumn. This class will stub the default
|
||||
* the DATA_SOURCE parameter of DynamicTableColumn. This class will stub the default
|
||||
* {@link #getValue(Object, Settings, Object, ServiceProvider)} method and
|
||||
* call a version of the method that does not have the DATA_SOURCE parameter.
|
||||
* <p>
|
||||
* Subclasses are not discoverable. To create discoverable columns for the framework, you must
|
||||
* extends {@link DynamicTableColumnExtensionPoint}.
|
||||
*
|
||||
* @param <ROW_TYPE> the row type
|
||||
* @param <COLUMN_TYPE> the column type
|
||||
*/
|
||||
public abstract class AbstractDynamicTableColumnStub<ROW_TYPE, COLUMN_TYPE> extends
|
||||
AbstractDynamicTableColumn<ROW_TYPE, COLUMN_TYPE, Object> {
|
||||
public abstract class AbstractDynamicTableColumnStub<ROW_TYPE, COLUMN_TYPE>
|
||||
extends AbstractDynamicTableColumn<ROW_TYPE, COLUMN_TYPE, Object> {
|
||||
|
||||
@Override
|
||||
public COLUMN_TYPE getValue(ROW_TYPE rowObject, Settings settings, Object data,
|
||||
|
|
|
@ -156,7 +156,7 @@ public class AnyObjectTableModel<T> extends GDynamicColumnTableModel<T, Object>
|
|||
}
|
||||
|
||||
private class MethodColumn extends AbstractDynamicTableColumn<T, Object, Object> {
|
||||
private String name;
|
||||
private String methodName;
|
||||
private Method method;
|
||||
private Class<?> returnType;
|
||||
|
||||
|
@ -166,7 +166,7 @@ public class AnyObjectTableModel<T> extends GDynamicColumnTableModel<T, Object>
|
|||
init(m);
|
||||
}
|
||||
catch (NoSuchMethodException | SecurityException e) {
|
||||
name = "No method: " + methodName;
|
||||
this.methodName = "No method: " + methodName;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -181,12 +181,12 @@ public class AnyObjectTableModel<T> extends GDynamicColumnTableModel<T, Object>
|
|||
|
||||
private void init(Method m) {
|
||||
this.method = m;
|
||||
name = method.getName();
|
||||
if (name.startsWith("get")) {
|
||||
name = name.substring(3);
|
||||
methodName = method.getName();
|
||||
if (methodName.startsWith("get")) {
|
||||
methodName = methodName.substring(3);
|
||||
}
|
||||
|
||||
name = fromCamelCase(name);
|
||||
methodName = fromCamelCase(methodName);
|
||||
returnType = method.getReturnType();
|
||||
}
|
||||
|
||||
|
@ -198,15 +198,15 @@ public class AnyObjectTableModel<T> extends GDynamicColumnTableModel<T, Object>
|
|||
|
||||
@Override
|
||||
public String getColumnName() {
|
||||
return name;
|
||||
return methodName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue(T rowObject, Settings settings, Object dataSource,
|
||||
ServiceProvider sp) throws IllegalArgumentException {
|
||||
if (method == null) {
|
||||
Msg.error(this,
|
||||
"No method '" + name + "' on class" + rowObject.getClass().getSimpleName());
|
||||
Msg.error(this, "No method '" + methodName + "' on class " +
|
||||
rowObject.getClass().getSimpleName());
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
|
|
|
@ -76,7 +76,6 @@ public class GFilterTable<ROW_OBJECT> extends JPanel {
|
|||
}
|
||||
|
||||
private void buildThreadedTable() {
|
||||
@SuppressWarnings("unchecked")
|
||||
GThreadedTablePanel<ROW_OBJECT> tablePanel =
|
||||
createThreadedTablePanel((ThreadedTableModel<ROW_OBJECT, ?>) model);
|
||||
table = tablePanel.getTable();
|
||||
|
|
|
@ -168,6 +168,20 @@ public class GTableWidget<T> extends JPanel {
|
|||
return table.getSelectedRowCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the selection mode of this table.
|
||||
*
|
||||
* @param mode the mode
|
||||
* @see ListSelectionModel#setSelectionMode(int)
|
||||
*/
|
||||
public void setSelectionMode(int mode) {
|
||||
table.getSelectionModel().setSelectionMode(mode);
|
||||
}
|
||||
|
||||
public int getSelectionMode() {
|
||||
return table.getSelectionModel().getSelectionMode();
|
||||
}
|
||||
|
||||
public void addSelectionListener(ObjectSelectedListener<T> l) {
|
||||
gFilterTable.addSelectionListener(l);
|
||||
}
|
||||
|
|
|
@ -17,12 +17,13 @@ package docking.widgets.table;
|
|||
|
||||
import java.util.*;
|
||||
|
||||
import ghidra.util.Msg;
|
||||
|
||||
public class TableColumnDescriptor<ROW_TYPE> {
|
||||
private List<TableColumnInfo> columns = new ArrayList<>();
|
||||
|
||||
public List<DynamicTableColumn<ROW_TYPE, ?, ?>> getAllColumns() {
|
||||
List<DynamicTableColumn<ROW_TYPE, ?, ?>> list =
|
||||
new ArrayList<>();
|
||||
List<DynamicTableColumn<ROW_TYPE, ?, ?>> list = new ArrayList<>();
|
||||
for (TableColumnInfo info : columns) {
|
||||
list.add(info.column);
|
||||
}
|
||||
|
@ -30,8 +31,7 @@ public class TableColumnDescriptor<ROW_TYPE> {
|
|||
}
|
||||
|
||||
public List<DynamicTableColumn<ROW_TYPE, ?, ?>> getDefaultVisibleColumns() {
|
||||
List<DynamicTableColumn<ROW_TYPE, ?, ?>> list =
|
||||
new ArrayList<>();
|
||||
List<DynamicTableColumn<ROW_TYPE, ?, ?>> list = new ArrayList<>();
|
||||
for (TableColumnInfo info : columns) {
|
||||
if (info.isVisible) {
|
||||
list.add(info.column);
|
||||
|
@ -60,20 +60,31 @@ public class TableColumnDescriptor<ROW_TYPE> {
|
|||
return editor.createTableSortState();
|
||||
}
|
||||
|
||||
private int remove(DynamicTableColumn<ROW_TYPE, ?, ?> column) {
|
||||
for (int i = 0; i < columns.size(); i++) {
|
||||
TableColumnDescriptor<ROW_TYPE>.TableColumnInfo info = columns.get(i);
|
||||
if (info.column == column) {
|
||||
columns.remove(i);
|
||||
return i;
|
||||
}
|
||||
public void setVisible(String columnName, boolean visible) {
|
||||
TableColumnInfo info = getColumn(columnName);
|
||||
if (info == null) {
|
||||
Msg.debug(this,
|
||||
"Unable to change visibility state of column '%s'".formatted(columnName));
|
||||
return;
|
||||
}
|
||||
if (visible) {
|
||||
info.isVisible = true;
|
||||
}
|
||||
else {
|
||||
// remove and add a new info to clear any sort state info for a hidden column
|
||||
int index = columns.indexOf(info);
|
||||
columns.set(index, new TableColumnInfo(info.column));
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public void setHidden(DynamicTableColumn<ROW_TYPE, ?, ?> column) {
|
||||
int index = remove(column);
|
||||
columns.add(index, new TableColumnInfo(column));
|
||||
private TableColumnInfo getColumn(String name) {
|
||||
for (TableColumnInfo info : columns) {
|
||||
String columnName = info.column.getColumnName();
|
||||
if (columnName.equals(name)) {
|
||||
return info;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void addHiddenColumn(DynamicTableColumn<ROW_TYPE, ?, ?> column) {
|
||||
|
@ -105,8 +116,8 @@ public class TableColumnDescriptor<ROW_TYPE> {
|
|||
this.column = column;
|
||||
}
|
||||
|
||||
TableColumnInfo(DynamicTableColumn<ROW_TYPE, ?, ?> column, boolean isVisible,
|
||||
int sortIndex, boolean ascending) {
|
||||
TableColumnInfo(DynamicTableColumn<ROW_TYPE, ?, ?> column, boolean isVisible, int sortIndex,
|
||||
boolean ascending) {
|
||||
this.column = column;
|
||||
this.isVisible = isVisible;
|
||||
this.sortIndex = sortIndex;
|
||||
|
|
|
@ -35,9 +35,11 @@ public class IncrementalLoadJob<ROW_OBJECT> extends Job implements ThreadedTable
|
|||
|
||||
/**
|
||||
* Used to signal that the updateManager has finished loading the final contents gathered
|
||||
* by this job.
|
||||
* by this job. By default, the value is 0, which means there is nothing to wait for. If we
|
||||
* flush, this will be set to 1.
|
||||
*/
|
||||
private final CountDownLatch completedCallbackLatch = new CountDownLatch(1);
|
||||
private CountDownLatch completedCallbackLatch = new CountDownLatch(0);
|
||||
private volatile boolean isCancelled = false;
|
||||
|
||||
private volatile IncrementalUpdatingAccumulator incrementalAccumulator;
|
||||
|
||||
|
@ -74,45 +76,49 @@ public class IncrementalLoadJob<ROW_OBJECT> extends Job implements ThreadedTable
|
|||
}
|
||||
|
||||
boolean interrupted = Thread.currentThread().isInterrupted();
|
||||
notifyCompleted(monitor.isCancelled() || interrupted);
|
||||
notifyCompleted(hasBeenCancelled(monitor) || interrupted);
|
||||
|
||||
// all data should have been posted at this point; clean up any data left in the accumulator
|
||||
incrementalAccumulator.clear();
|
||||
}
|
||||
|
||||
private void doExecute(TaskMonitor monitor) {
|
||||
try {
|
||||
threadedModel.doLoad(incrementalAccumulator, monitor);
|
||||
if (!monitor.isCancelled()) { // in case the model didn't call checkCancelled()
|
||||
flush(incrementalAccumulator);
|
||||
}
|
||||
flush(incrementalAccumulator, monitor);
|
||||
}
|
||||
catch (CancelledException e) {
|
||||
// handled by the caller of this method
|
||||
isCancelled = true;
|
||||
}
|
||||
|
||||
if (monitor.isCancelled()) {
|
||||
return; // must leave now or we will block in the call below
|
||||
}
|
||||
|
||||
waitForThreadedTableUpdateManager();
|
||||
}
|
||||
|
||||
private void waitForThreadedTableUpdateManager() {
|
||||
try {
|
||||
completedCallbackLatch.await();
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
// This implies the user has cancelled the job by starting a new one or that we have
|
||||
// been disposed. Whatever the cause, we want to let the control flow continue as
|
||||
// normal.
|
||||
Thread.currentThread().interrupt(); // preserve the interrupt status
|
||||
}
|
||||
/**
|
||||
* This method tracks cancelled from the given monitor and from any cancelled exceptions that
|
||||
* happen during loading. When loading, the client may trigger a cancelled exception even
|
||||
* though the monitor has not been cancelled.
|
||||
* @param monitor the task monitor
|
||||
* @return true if cancelled
|
||||
*/
|
||||
private boolean hasBeenCancelled(TaskMonitor monitor) {
|
||||
return isCancelled || monitor.isCancelled();
|
||||
}
|
||||
|
||||
private void flush(IncrementalUpdatingAccumulator accumulator) {
|
||||
private void flush(IncrementalUpdatingAccumulator accumulator, TaskMonitor monitor) {
|
||||
|
||||
//
|
||||
// Acquire the update manager lock so that it doesn't send out any events while we are
|
||||
// giving it the data we just finished loading.
|
||||
//
|
||||
synchronized (updateManager.getSynchronizingLock()) {
|
||||
|
||||
if (hasBeenCancelled(monitor)) {
|
||||
// Check for cancelled inside of this lock. This guarantees that no events will be
|
||||
// sent out before we can add our listener
|
||||
return;
|
||||
}
|
||||
|
||||
// push the data to the update manager...
|
||||
accumulator.flushData();
|
||||
|
||||
|
@ -135,8 +141,23 @@ public class IncrementalLoadJob<ROW_OBJECT> extends Job implements ThreadedTable
|
|||
// -A block on jobDone() can now complete as we release the lock
|
||||
// -jobDone() will notify listeners in an invokeLater(), which puts it behind ours
|
||||
//
|
||||
completedCallbackLatch = new CountDownLatch(1);
|
||||
Swing.runLater(() -> updateManager.addThreadedTableListener(IncrementalLoadJob.this));
|
||||
}
|
||||
|
||||
waitForThreadedTableUpdateManagerToFinish();
|
||||
}
|
||||
|
||||
private void waitForThreadedTableUpdateManagerToFinish() {
|
||||
try {
|
||||
completedCallbackLatch.await();
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
// This implies the user has cancelled the job by starting a new one or that we have
|
||||
// been disposed. Whatever the cause, we want to let the control flow continue as
|
||||
// normal.
|
||||
Thread.currentThread().interrupt(); // preserve the interrupt status
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyStarted(TaskMonitor monitor) {
|
||||
|
@ -151,14 +172,19 @@ public class IncrementalLoadJob<ROW_OBJECT> extends Job implements ThreadedTable
|
|||
}
|
||||
|
||||
updateManager.removeThreadedTableListener(this);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
updateManager.getTaskMonitor().cancel();
|
||||
// monitor.cancel(); TODO: are we handling this ??
|
||||
super.cancel();
|
||||
isCancelled = true;
|
||||
incrementalAccumulator.cancel();
|
||||
|
||||
// Note: cannot do this here, since the cancel() call may happen asynchronously and after
|
||||
// a call to reload() on the table model. Assume that the model itself has already
|
||||
// cancelled the update manager when the worker queue was cancelled. See
|
||||
// ThreadedTableModel.reload().
|
||||
// updateManager.cancelAllJobs();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -188,14 +214,15 @@ public class IncrementalLoadJob<ROW_OBJECT> extends Job implements ThreadedTable
|
|||
* is being provided to the accumulator.
|
||||
*/
|
||||
private class IncrementalUpdatingAccumulator extends SynchronizedListAccumulator<ROW_OBJECT> {
|
||||
private volatile boolean cancelledOrDone;
|
||||
private volatile boolean isDone;
|
||||
private Runnable runnable = () -> {
|
||||
|
||||
if (cancelledOrDone) {
|
||||
if (isCancelledOrDone()) {
|
||||
// this handles the case where a cancel request came in off the Swing
|
||||
// thread whilst we were already posted
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
updateManager.reloadSpecificData(asList());
|
||||
}
|
||||
|
@ -203,7 +230,7 @@ public class IncrementalLoadJob<ROW_OBJECT> extends Job implements ThreadedTable
|
|||
|
||||
// note: check for cancelled again, as it may have been called after the initial
|
||||
// check above if the cancel call was requested off the Swing thread.
|
||||
if (!cancelledOrDone) {
|
||||
if (!isCancelledOrDone()) {
|
||||
Msg.error(this, "Exception incrementally loading table data", e);
|
||||
}
|
||||
}
|
||||
|
@ -219,8 +246,11 @@ public class IncrementalLoadJob<ROW_OBJECT> extends Job implements ThreadedTable
|
|||
swingUpdateManager.update();
|
||||
}
|
||||
|
||||
private boolean isCancelledOrDone() {
|
||||
return isCancelled || isDone;
|
||||
}
|
||||
|
||||
void cancel() {
|
||||
cancelledOrDone = true;
|
||||
swingUpdateManager.dispose();
|
||||
}
|
||||
|
||||
|
@ -233,7 +263,7 @@ public class IncrementalLoadJob<ROW_OBJECT> extends Job implements ThreadedTable
|
|||
}
|
||||
|
||||
void flushData() {
|
||||
cancelledOrDone = true;
|
||||
isDone = true;
|
||||
swingUpdateManager.dispose();
|
||||
updateManager.reloadSpecificData(asList());
|
||||
}
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* 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.
|
||||
|
|
|
@ -145,6 +145,10 @@ public abstract class ThreadedTableModel<ROW_OBJECT, DATA_SOURCE>
|
|||
updateManager.addThreadedTableListener(new NonIncrementalUpdateManagerListener());
|
||||
}
|
||||
|
||||
startInitialLoad();
|
||||
}
|
||||
|
||||
protected void startInitialLoad() {
|
||||
// We are expecting to be in the swing thread. We want the reload to happen after our
|
||||
// constructor is fully completed since the reload will cause our initialize method to
|
||||
// be called in another thread, thereby creating a possible race condition.
|
||||
|
|
|
@ -36,27 +36,30 @@ public class TestDataKeyModel extends ThreadedTableModelStub<Long> {
|
|||
public final static int STRING_COL = 6;
|
||||
|
||||
private Byte[] bytes = new Byte[] { Byte.valueOf((byte) 0x09), Byte.valueOf((byte) 0x03),
|
||||
Byte.valueOf((byte) 0x0c), Byte.valueOf((byte) 0x55), Byte.valueOf((byte) 0x00), Byte.valueOf((byte) 0xdf),
|
||||
Byte.valueOf((byte) 0xff), Byte.valueOf((byte) 0x03), Byte.valueOf((byte) 0x16), Byte.valueOf((byte) 0x02),
|
||||
Byte.valueOf((byte) 0x03), Byte.valueOf((byte) 0x04), };
|
||||
Byte.valueOf((byte) 0x0c), Byte.valueOf((byte) 0x55), Byte.valueOf((byte) 0x00),
|
||||
Byte.valueOf((byte) 0xdf), Byte.valueOf((byte) 0xff), Byte.valueOf((byte) 0x03),
|
||||
Byte.valueOf((byte) 0x16), Byte.valueOf((byte) 0x02), Byte.valueOf((byte) 0x03),
|
||||
Byte.valueOf((byte) 0x04), };
|
||||
|
||||
private Short[] shorts = new Short[] { Short.valueOf((short) 0x0841), Short.valueOf((short) 0xb0f7),
|
||||
Short.valueOf((short) 0xf130), Short.valueOf((short) 0x84e3), Short.valueOf((short) 0x2976),
|
||||
Short.valueOf((short) 0x17d9), Short.valueOf((short) 0xf146), Short.valueOf((short) 0xc4a5),
|
||||
Short.valueOf((short) 0x88f1), Short.valueOf((short) 0x966d), Short.valueOf((short) 0x966e),
|
||||
Short.valueOf((short) 0x966f), };
|
||||
private Short[] shorts = new Short[] { Short.valueOf((short) 0x0841),
|
||||
Short.valueOf((short) 0xb0f7), Short.valueOf((short) 0xf130), Short.valueOf((short) 0x84e3),
|
||||
Short.valueOf((short) 0x2976), Short.valueOf((short) 0x17d9), Short.valueOf((short) 0xf146),
|
||||
Short.valueOf((short) 0xc4a5), Short.valueOf((short) 0x88f1), Short.valueOf((short) 0x966d),
|
||||
Short.valueOf((short) 0x966e), Short.valueOf((short) 0x966f), };
|
||||
|
||||
private Integer[] ints =
|
||||
new Integer[] { Integer.valueOf(0x039D492B), Integer.valueOf(0x0A161497), Integer.valueOf(0x06AA1497),
|
||||
Integer.valueOf(0x0229EE9E), Integer.valueOf(0xFB7428E1), Integer.valueOf(0xD2B4ED2F),
|
||||
Integer.valueOf(0x0C1F67DE), Integer.valueOf(0x0E61C987), Integer.valueOf(0x0133751F),
|
||||
Integer.valueOf(0x07B39541), Integer.valueOf(0x07B39542), Integer.valueOf(0x07B39542), };
|
||||
private Integer[] ints = new Integer[] { Integer.valueOf(0x039D492B),
|
||||
Integer.valueOf(0x0A161497), Integer.valueOf(0x06AA1497), Integer.valueOf(0x0229EE9E),
|
||||
Integer.valueOf(0xFB7428E1), Integer.valueOf(0xD2B4ED2F), Integer.valueOf(0x0C1F67DE),
|
||||
Integer.valueOf(0x0E61C987), Integer.valueOf(0x0133751F), Integer.valueOf(0x07B39541),
|
||||
Integer.valueOf(0x07B39542), Integer.valueOf(0x07B39542), };
|
||||
|
||||
private Long[] longs = new Long[] { Long.valueOf(0x0000000DFAA00C4FL),
|
||||
Long.valueOf(0x00000001FD7CA6A6L), Long.valueOf(0xFFFFFFF4D0EB4AB8L), Long.valueOf(0x0000000445246143L),
|
||||
Long.valueOf(0xFFFFFFF5696F1780L), Long.valueOf(0x0000000685526E5DL), Long.valueOf(0x00000009A1FD98EEL),
|
||||
Long.valueOf(0x00000004AD2B1869L), Long.valueOf(0x00000002928E64C8L), Long.valueOf(0x000000071CE1DDB2L),
|
||||
Long.valueOf(0x000000071CE1DDB3L), Long.valueOf(0x000000071CE1DDB4L), };
|
||||
private Long[] longs =
|
||||
new Long[] { Long.valueOf(0x0000000DFAA00C4FL), Long.valueOf(0x00000001FD7CA6A6L),
|
||||
Long.valueOf(0xFFFFFFF4D0EB4AB8L), Long.valueOf(0x0000000445246143L),
|
||||
Long.valueOf(0xFFFFFFF5696F1780L), Long.valueOf(0x0000000685526E5DL),
|
||||
Long.valueOf(0x00000009A1FD98EEL), Long.valueOf(0x00000004AD2B1869L),
|
||||
Long.valueOf(0x00000002928E64C8L), Long.valueOf(0x000000071CE1DDB2L),
|
||||
Long.valueOf(0x000000071CE1DDB3L), Long.valueOf(0x000000071CE1DDB4L), };
|
||||
|
||||
private Float[] floats =
|
||||
new Float[] { Float.valueOf((float) 0.143111240), Float.valueOf((float) 0.084097680),
|
||||
|
@ -77,7 +80,7 @@ public class TestDataKeyModel extends ThreadedTableModelStub<Long> {
|
|||
protected String[] strings = new String[] { "one", "two", "THREE", "Four", "FiVe", "sIx",
|
||||
"SeVEn", "EighT", "NINE", "ten", "ten", "ten" };
|
||||
|
||||
private long timeBetweenAddingDataItemsInMillis = 1;
|
||||
private volatile long timeBetweenAddingDataItemsInMillis = 1;
|
||||
|
||||
private volatile IncrementalLoadJob<Long> loadJob = null;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue