Bug 164475 [Viewers] v3.2/v3.3 TableViewer sort performance much slower than v3.0.1
Used the attached testcase to compare the column sort performance using the TableViewer control on Eclipse version 3.2, 3.2.1 and 3.3 compared to Eclipse version 3.0.1. The time taken is significantly longer, as follows: version | time taken ------------+---------------- 3.0.1 | 2109 3.2 | 8422 3.2.1 | 5641 3.3 | 4266 Testcase used: public class TableViewerTestView extends ViewPart { private TableViewer viewer; private static final int NUM_COLUMNS = 25; protected List list; protected ArrayList elements = null; protected ViewViewerSorter viewViewerSorter = null; protected ViewLabelProvider viewLabelProvider = null; protected long startTime = 0; protected Cursor cursorBusy = null; protected Cursor cursorArrow = null; protected int sortCompares = 0; /* * The content provider class is responsible for providing objects to the view. It can wrap * existing objects in adapters or simply return objects as-is. These objects may be sensitive to * the current input of the view, or ignore it and always show the same content (like Task List, * for example). */ class ViewContentProvider implements IStructuredContentProvider { public void inputChanged(Viewer v, Object oldInput, Object newInput) { if (newInput instanceof ArrayList) { elements = (ArrayList) newInput; } } public void dispose() {} public Object[] getElements(Object parent) { String[] strings = null; if (elements != null) { int size = elements.size(); strings = new String[size]; for (int i = 0; i < size; i++) { strings[i] = elements.get(i).toString(); } } return strings; } } class ViewLabelProvider extends LabelProvider implements ITableLabelProvider { public String getColumnText(Object obj, int index) { String text = obj.toString(); Integer value = new Integer(text); if (index != 0) text = "" + value.intValue() % index; return text; } public Image getColumnImage(Object obj, int index) { Image image = null; if (index == 0) image = getImage(obj); return image; } public Image getImage(Object obj) { return PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJ_ELEMENT); } } class ViewViewerSorter extends ViewerSorter { private int sortIndex = 0; private boolean sortAscending = false; public int compare(Viewer viewer, Object e1, Object e2) { sortCompares++; int retValue = 0; Integer value1 = new Integer(viewLabelProvider.getColumnText(e1, sortIndex)); Integer value2 = new Integer(viewLabelProvider.getColumnText(e2, sortIndex)); if (sortAscending) { retValue = value1.compareTo(value2); } else { retValue = value2.compareTo(value1); } return retValue; } public void setSortColumnIndex(int index) { if (index == sortIndex) { sortAscending = !sortAscending; } else { sortIndex = index; sortAscending = true; } } } /** * The constructor. */ public TableViewerTestView() {} /** * This is a callback that will allow us to create the viewer and initialize it. */ public void createPartControl(Composite parent) { cursorBusy = new Cursor(parent.getDisplay(), SWT.CURSOR_WAIT); cursorArrow = new Cursor(parent.getDisplay(), SWT.CURSOR_ARROW); Composite comp = new Composite(parent, SWT.NONE); GridLayout gridLayout = new GridLayout(); gridLayout.numColumns = 2; comp.setLayout(gridLayout); Button button = new Button(comp, SWT.PUSH); button.setText("Load"); GridData gridData = new GridData(); button.setLayoutData(gridData); button.addSelectionListener(new SelectionListener() { public void widgetDefaultSelected(SelectionEvent e) { // TODO Auto-generated method stub } public void widgetSelected(SelectionEvent e) { startTime = System.currentTimeMillis(); viewer.getTable().getShell().setCursor(cursorBusy); viewer.setInput(elements); viewer.getTable().getShell().setCursor(cursorArrow); list.add("load took: " + (System.currentTimeMillis() - startTime)); list.setSelection(list.getItemCount() - 1); list.showSelection(); } }); list = new List(comp, SWT.BORDER | SWT.V_SCROLL); gridData = new GridData(GridData.FILL_HORIZONTAL); gridData.verticalSpan = 2; list.setLayoutData(gridData); button = new Button(comp, SWT.PUSH); button.setText("Clear"); gridData = new GridData(); button.setLayoutData(gridData); button.addSelectionListener(new SelectionListener() { public void widgetDefaultSelected(SelectionEvent e) { // TODO Auto-generated method stub } public void widgetSelected(SelectionEvent e) { viewer.getTable().removeAll(); } }); elements = new ArrayList(); for (int i = 0; i < 2048; i++) { String name = "" + i; elements.add(name); } viewer = new TableViewer(comp, SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL); Table table = viewer.getTable(); gridData = new GridData(GridData.FILL_BOTH); gridData.horizontalSpan = 2; table.setLayoutData(gridData); viewer.setContentProvider(new ViewContentProvider()); viewLabelProvider = new ViewLabelProvider(); viewer.setLabelProvider(viewLabelProvider); viewViewerSorter = new ViewViewerSorter(); viewer.setSorter(viewViewerSorter); table.setLinesVisible(true); table.setHeaderVisible(true); for (int i = 0; i < NUM_COLUMNS; i++) { TableColumn column = new TableColumn(table, SWT.NONE); column.setText("Column " + i); } // add selection listeners to each of the table columns TableColumn[] tabCols = table.getColumns(); for (int i = 0; i < tabCols.length; i++) { tabCols[i].addListener(SWT.Selection, new Listener() { public void handleEvent(Event e) { columnSelected(e); } }); } if (viewViewerSorter != null) { viewViewerSorter.setSortColumnIndex(0); } viewer.setInput(null); for (int i = 0; i < NUM_COLUMNS; i++) { table.getColumn(i).pack(); } } protected void columnSelected(Event e) { // Get the index of the column selected Table table = viewer.getTable(); TableColumn tabCol = (TableColumn) e.widget; TableColumn[] tabCols = table.getColumns(); int index = 0; for (int i = 0; i < tabCols.length; i++) { if (tabCols[i] == tabCol) { index = i; break; } } viewViewerSorter.setSortColumnIndex(index); // Refresh the table viewer to trigger the sort if (table.getItemCount() > 0) { // only bother if there's something to sort! startTime = System.currentTimeMillis(); sortCompares = 0; viewer.getTable().getShell().setCursor(cursorBusy); viewer.refresh(); list.add("sort took: " + (System.currentTimeMillis() - startTime)); list.setSelection(list.getItemCount() - 1); list.showSelection(); list.add("sort compares: " + sortCompares); list.setSelection(list.getItemCount() - 1); list.showSelection(); viewer.getTable().getShell().setCursor(cursorArrow); } } /** * Passing the focus request to the viewer's control. */ public void setFocus() { viewer.getControl().setFocus(); } }
bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/AbstractTableViewer.java
protected void internalRefresh(Object element, boolean updateLabels) {
		applyEditorValue();
		if (element == null || equals(element, getRoot())) {
			if (virtualManager == null) {
				internalRefreshAll(updateLabels);
			} else {
				internalVirtualRefreshAll();
			}
		} else {
			Widget w = findItem(element);
			if (w != null) {
				updateItem(w, element);
			}
		}
	}
	/**
	 * Refresh all with virtual elements.
	 * 
	 * @since 3.1
	 */
	private void internalVirtualRefreshAll() {
		Object root = getRoot();
		IContentProvider contentProvider = getContentProvider();
		
		if (!(contentProvider instanceof ILazyContentProvider)
				&& (contentProvider instanceof IStructuredContentProvider)) {
			
			if (root != null) {
				virtualManager.cachedElements = getSortedChildren(root);
				doSetItemCount(virtualManager.cachedElements.length);