This is an automated email from the ASF dual-hosted git repository. matthiasblaesing pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/netbeans.git
The following commit(s) were added to refs/heads/master by this push: new 0b9c24ff09 TaskList Model issues broken table model change events new 0291513733 Merge pull request #6882 from matthiasblaesing/tasklist-tablemodel-events 0b9c24ff09 is described below commit 0b9c24ff09791eaf127035188fec1ea86f02770b Author: Matthias Bläsing <mblaes...@doppel-helix.eu> AuthorDate: Tue Dec 26 17:52:35 2023 +0100 TaskList Model issues broken table model change events With JDK21 validation of removeIndexInterval and addIndexInterval methods was improved. This reveals an issue in the table model change events, that are published by the TaskListModel. For example it was observed, that the startRow and endRow indices were issued in the wrong order. This results in: java.lang.IndexOutOfBoundsException: index or length is negative at java.desktop/javax.swing.DefaultListSelectionModel.insertIndexInterval(DefaultListSelectionModel.java:656) at java.desktop/javax.swing.JTable.tableRowsInserted(JTable.java:4539) at java.desktop/javax.swing.JTable.tableChanged(JTable.java:4475) at java.desktop/javax.swing.table.AbstractTableModel.fireTableChanged(AbstractTableModel.java:302) at java.desktop/javax.swing.table.AbstractTableModel.fireTableRowsInserted(AbstractTableModel.java:237) at org.netbeans.modules.tasklist.ui.TaskListModel$1.run(TaskListModel.java:143) at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:318) at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:773) --- .../modules/tasklist/ui/TaskListModel.java | 112 +++++++++++---------- 1 file changed, 60 insertions(+), 52 deletions(-) diff --git a/ide/tasklist.ui/src/org/netbeans/modules/tasklist/ui/TaskListModel.java b/ide/tasklist.ui/src/org/netbeans/modules/tasklist/ui/TaskListModel.java index 9d76326002..6fac576c8d 100644 --- a/ide/tasklist.ui/src/org/netbeans/modules/tasklist/ui/TaskListModel.java +++ b/ide/tasklist.ui/src/org/netbeans/modules/tasklist/ui/TaskListModel.java @@ -20,6 +20,7 @@ package org.netbeans.modules.tasklist.ui; import java.awt.EventQueue; +import java.util.Arrays; import java.util.Comparator; import java.util.List; import javax.swing.table.AbstractTableModel; @@ -37,14 +38,14 @@ import org.openide.util.NbBundle; class TaskListModel extends AbstractTableModel implements TaskList.Listener { protected TaskList taskList; - + protected static final int COL_GROUP = 0; protected static final int COL_DESCRIPTION = 1; protected static final int COL_FILE = 2; protected static final int COL_LOCATION = 3; - // internal list of tasks - needed to recognize deleted row (deleted tasks aren't in taskList when taskRemoved method "arrive") #204655 + // listOfTasks holds the list of tasks relevant for the Swing components. It + // is a copy of the task held by the TaskList instance private List<? extends Task> listOfTasks; - private final Object lock = new Object(); /** Creates a new instance of TaskListModel */ @@ -58,8 +59,7 @@ class TaskListModel extends AbstractTableModel implements TaskList.Listener { @Override public int getRowCount() { - final List<? extends Task> list = taskList.getTasks(); - return list.size(); + return listOfTasks.size(); } @Override @@ -115,65 +115,73 @@ class TaskListModel extends AbstractTableModel implements TaskList.Listener { } protected Task getTaskAtRow( int row ) { - synchronized (lock) { - final List<? extends Task> list = taskList.getTasks(); - if (list.size() > row) { - return list.get(row); - } else { - return null; - } + if (listOfTasks.size() > row) { + return listOfTasks.get(row); + } else { + return null; } } @Override - public void tasksAdded( final List<? extends Task> tasks ) { - if( tasks.isEmpty() ) - return; - final int startRow; - final int endRow; - synchronized (lock) { - startRow = taskList.getTasks().indexOf(tasks.get(0)); - endRow = taskList.getTasks().indexOf(tasks.get(tasks.size() - 1)); - listOfTasks = taskList.getTasks(); - } - if( startRow > -1 && endRow > -1 ) { - EventQueue.invokeLater(new Runnable() { - @Override - public void run() { - fireTableRowsInserted(startRow, endRow); - } - }); + public void tasksAdded(final List<? extends Task> tasks) { + if (! tasks.isEmpty()) { + fireTasksChanged(true, tasks, listOfTasks, taskList.getTasks()); } } @Override - public void tasksRemoved( final List<? extends Task> tasks ) { - if( tasks.isEmpty() ) - return; - - final int startRow; - final int endRow; - synchronized (lock) { - startRow = listOfTasks.indexOf(tasks.get(0)); - endRow = listOfTasks.indexOf(tasks.get(tasks.size() - 1)); - listOfTasks = taskList.getTasks(); + public void tasksRemoved(final List<? extends Task> tasks) { + if (! tasks.isEmpty()) { + fireTasksChanged(false, tasks, listOfTasks, taskList.getTasks()); } - if( startRow > -1 && endRow > -1 ) { - EventQueue.invokeLater(new Runnable() { - @Override - public void run() { - fireTableRowsDeleted( startRow, endRow ); + } + + @SuppressWarnings("AssignmentToCollectionOrArrayFieldFromParameter") + private void fireTasksChanged( + boolean add, + List<? extends Task> changedTasks, + List<? extends Task> oldList, + List<? extends Task> newList + ) { + EventQueue.invokeLater(() -> { + // Get the right list for index identification, for adding the + // indices are taken from the new list, for removal from the old + // list + List<? extends Task> indexTaskList = add ? newList : oldList; + // Find the tasks that were added/removed in the old list (these are the + // relevant indices. + int[] indices = new int[changedTasks.size()]; + for (int i = 0; i < changedTasks.size(); i++) { + indices[i] = indexTaskList.indexOf(changedTasks.get(i)); + } + // Update the list of tasks to the new list + listOfTasks = newList; + + // Ensure the indices are sorted ascending + Arrays.sort(indices); + + // Check that all tasks are found and that they are consecutive. If + // that is the case use fireTableRowsInserted/fireTableRowsDeleted + // with range, else indicate all data has changed + int lastIdx = indices.length - 1; + if (indices[0] < 0 || ((indices[lastIdx] - indices[0]) + 1) != indices.length) { + fireTableDataChanged(); + } else { + if(add) { + fireTableRowsInserted(indices[0], indices[lastIdx]); + } else { + fireTableRowsDeleted(indices[0], indices[lastIdx]); } - }); - } + } + }); } @Override public void cleared() { - synchronized (lock) { + EventQueue.invokeLater(() -> { listOfTasks = taskList.getTasks(); - } - fireTableDataChanged(); + fireTableDataChanged(); + }); } protected int sortingCol = -1; @@ -210,10 +218,10 @@ class TaskListModel extends AbstractTableModel implements TaskList.Listener { comparator = TaskComparator.getDefault(); break; } + // This happens on the EDT (mouseClick) so no need to push it to the + // EDT explicitly taskList.setComparator( comparator ); - synchronized (lock) { - listOfTasks = taskList.getTasks(); - } + listOfTasks = taskList.getTasks(); Settings.getDefault().setSortingColumn( sortingCol ); Settings.getDefault().setAscendingSort( ascending ); --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@netbeans.apache.org For additional commands, e-mail: commits-h...@netbeans.apache.org For further information about the NetBeans mailing lists, visit: https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists