Bug 2712 - Could speed things up with an upper limit on displayed taks (1GIEY99)
Summary: Could speed things up with an upper limit on displayed taks (1GIEY99)
Status: RESOLVED WONTFIX
Alias: None
Product: Platform
Classification: Eclipse Project
Component: UI (show other bugs)
Version: 2.0   Edit
Hardware: All Windows NT
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: Kevin Haaland CLA
QA Contact:
URL:
Whiteboard:
Keywords: performance
Depends on:
Blocks:
 
Reported: 2001-10-10 22:41 EDT by Tod Creasey CLA
Modified: 2002-03-20 17:01 EST (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Tod Creasey CLA 2001-10-10 22:41:59 EDT
Currently we show all tasks regardless of the number. This can be very slow if there are a 
lot of errors. We should have a default number of displayed errors in order that these huge
listings do not get created.

Here is the suggested implementation for a preferences page

package org.eclipse.ui.internal.dialogs;

import java.text.MessageFormat;
import org.eclipse.jface.preference.*;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.layout.*;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPreferencePage;
import org.eclipse.ui.internal.*;

public class TasksPreferencePage
	extends PreferencePage
	implements IWorkbenchPreferencePage, ModifyListener {

	private static final String POSITIVE_MESSAGE =
		WorkbenchMessages.getString("FileHistory.mustBePositive");
	private static final String INVALID_VALUE_MESSAGE =
		WorkbenchMessages.getString("FileHistory.invalid");
	private static final int FAILED_VALUE = -1;

	Text text;

	/**
	 * @see PreferencePage#createContents(Composite)
	 */
	protected Control createContents(Composite parent) {

		// button group
		Composite composite = new Composite(parent, SWT.NONE);
		GridLayout layout = new GridLayout();
		layout.numColumns = 2;
		composite.setLayout(layout);
		composite.setLayoutData(
			new GridData(GridData.VERTICAL_ALIGN_FILL | GridData.HORIZONTAL_ALIGN_FILL));

		Label label = new Label(composite, SWT.LEFT);
		label.setText("Maximum Displayed Tasks");

		text = new Text(composite, SWT.LEFT | SWT.BORDER);
		GridData data = new GridData();
		text.addModifyListener(this);
		data.horizontalAlignment = GridData.FILL;
		data.grabExcessHorizontalSpace = true;
		data.verticalAlignment = GridData.CENTER;
		data.grabExcessVerticalSpace = false;
		text.setLayoutData(data);

		//Now get the value
		IPreferenceStore store = WorkbenchPlugin.getDefault().getPreferenceStore();
		int displayedTasks = store.getInt(IPreferenceConstants.DISPLAYED_TASKS_COUNT);
		text.setText(String.valueOf(displayedTasks));

		return composite;
	}
	/**
	 * @see IWorkbenchPreferencePage#init(IWorkbench)
	 */
	public void init(IWorkbench workbench) {
	}

	/**
	 * @see ModifyListener#modifyText(ModifyEvent)
	 */
	public void modifyText(ModifyEvent e) {
		setValid(getTaskCount() > 0);
	}

	/**
	 * Get the integer value of the text field
	 */

	private int getTaskCount() {

		int value;

		try {
			value = Integer.parseInt(text.getText());

		} catch (NumberFormatException exception) {
			setErrorMessage(
				MessageFormat.format(
					INVALID_VALUE_MESSAGE,
					new Object[] { exception.getLocalizedMessage()}));
			return FAILED_VALUE;
		}

		//Be sure all values are non zero and positive
		if (value <= 0) {
			setErrorMessage(POSITIVE_MESSAGE);
			return FAILED_VALUE;
		}

		return value;

	}

	/**
	* The default button has been pressed. 
	*/
	protected void performDefaults() {
		IPreferenceStore store = WorkbenchPlugin.getDefault().getPreferenceStore();
		int editorTopValue =
			store.getDefaultInt(IPreferenceConstants.DISPLAYED_TASKS_COUNT);
		this.text.setText(String.valueOf(editorTopValue));
		super.performDefaults();
	}
	/**
	 *	The user has pressed Ok.  Store/apply this page's values appropriately.
	 */
	public boolean performOk() {
		IPreferenceStore store = WorkbenchPlugin.getDefault().getPreferenceStore();

		// store the tasks displayed value
		store.setValue(
			IPreferenceConstants.DISPLAYED_TASKS_COUNT,
			(Integer.valueOf(text.getText()).intValue()));

		return true;
	}

}

And here are the content provider changes

package org.eclipse.ui.views.tasklist;

/*
 * (c) Copyright IBM Corp. 2000, 2001.
 * All Rights Reserved.
 */
import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.*;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.viewers.*;
import org.eclipse.swt.widgets.Control;
import org.eclipse.ui.internal.IPreferenceConstants;
import org.eclipse.ui.internal.WorkbenchPlugin;
import java.text.MessageFormat;
import java.util.*;

/**
 * Task list content provider returns elements that should be
 * in the task list depending on the selection mode.
 * It goes directly to the marker manager and retreives
 * tasks and problems.
 */
/* package */
class TaskListContentProvider
	implements IStructuredContentProvider, IResourceChangeListener {
	private TaskList taskList;
	private TableViewer viewer;
	private IResource input;
	private String summary;
	private String titleSummary;
	/**
	 * The constructor.
	 */
	public TaskListContentProvider(TaskList taskList) {
		this.taskList = taskList;
		this.viewer = taskList.getTableViewer();
	}
	/**
	 * Returns whether we are interested in the given marker delta.
	 */
	protected boolean check(IMarkerDelta markerDelta) {
		return checkType(markerDelta) && checkResource(markerDelta.getResource());
	}
	/**
	 * Returns whether we are interested in markers on the given resource.
	 */
	protected boolean checkResource(IResource resource) {
		if (taskList.showSelections() && !taskList.showChildrenHierarchy()) {
			return resource.equals(taskList.getResource());
		} else {
			return taskList.getResource().getFullPath().isPrefixOf(resource.getFullPath());
		}
	}
	/**
	 * Returns whether we are interested in the type of the given marker.
	 */
	protected boolean checkType(IMarkerDelta markerDelta) {
		String[] types = taskList.getMarkerTypes();
		for (int i = 0; i < types.length; ++i) {
			if (markerDelta.isSubtypeOf(types[i])) {
				return true;
			}
		}
		return false;
	}
	/**
	 * Clears any cached summary info.
	 */
	void clearSummary() {
		summary = null;
		titleSummary = null;
	}
	/**
	 * Computes a one-line summary of the number of tasks and problems being displayed.
	 */
	void computeSummary() {
		try {
			TasksFilter filter = (TasksFilter) taskList.getFilter();
			IMarker[] markers = getMarkers();
			String summaryFmt = TaskListMessages.getString("TaskList.summaryFmt");
			//$NON-NLS-1$
			String unfilteredTitleFmt1 =
				TaskListMessages.getString("TaskList.unfilteredTitleFmt1");
			//$NON-NLS-1$
			String unfilteredTitleFmtN =
				TaskListMessages.getString("TaskList.unfilteredTitleFmtN");
			//$NON-NLS-1$
			String filteredTitleFmt =
				TaskListMessages.getString("TaskList.filteredTitleFmt");
			//$NON-NLS-1$
			if (filter.showAll()) {
				summary =
					MessageFormat.format(
						summaryFmt,
						new Object[] {
							new Integer(markers.length),
							getSummary(Arrays.asList(markers))});
				if (markers.length == 1)
					titleSummary =
						MessageFormat.format(
							unfilteredTitleFmt1,
							new Object[] { new Integer(markers.length)});
				else
					titleSummary =
						MessageFormat.format(
							unfilteredTitleFmtN,
							new Object[] { new Integer(getMaxTasksSetting()), new Integer(markers.length)});

			} else {
				Object[] filtered = filter.filter(null, null, markers);
				summary =
					MessageFormat.format(
						summaryFmt,
						new Object[] {
							new Integer(filtered.length),
							getSummary(Arrays.asList(filtered))});
				titleSummary =
					MessageFormat.format(
						filteredTitleFmt,
						new Object[] {
							new Integer(filtered.length),
							new Integer(getTotalMarkerCount())});
			}
		} catch (CoreException e) {
			summary = titleSummary = ""; //$NON-NLS-1$
		}
	}
	/**
	 * The visual part that is using this content provider is about
	 * to be disposed. Deallocate all allocated SWT resources.
	 */
	public void dispose() {
		if (input != null) {
			input.getWorkspace().removeResourceChangeListener(this);
			input = null;
		}
	}
	/**
	 * Returns all the markers that should be shown for
	 * the current settings.
	 */

	public Object[] getElements(Object parent) {
		try {
			clearSummary();

			IMarker[] result = getMarkers();
			int displayedTasks = getMaxTasksSetting();

			if (displayedTasks < result.length) {
				IMarker[] subset = new IMarker[displayedTasks];
				System.arraycopy(result, 0, subset, 0, displayedTasks);
				return subset;
			}

			return result;
		} catch (CoreException e) {
			return new IMarker[0];
		}
	}

	/**
	 * Return the maximum number of tasks to display
	 */
	private int getMaxTasksSetting() {
		IPreferenceStore store = WorkbenchPlugin.getDefault().getPreferenceStore();
		return store.getInt(IPreferenceConstants.DISPLAYED_TASKS_COUNT);
	}

	/**
	 * Recursively walks over the resource delta and gathers all marker deltas.  Marker
	 * deltas are placed into one of the three given vectors depending on
	 * the type of delta (add, remove, or change).
	 */
	protected void getMarkerDeltas(
		IResourceDelta delta,
		List additions,
		List removals,
		List changes) {
		IMarkerDelta[] markerDeltas = delta.getMarkerDeltas();
		for (int i = 0; i < markerDeltas.length; i++) {
			IMarkerDelta markerDelta = markerDeltas[i];
			IMarker marker = markerDelta.getMarker();
			switch (markerDelta.getKind()) {
				case IResourceDelta.ADDED :
					if (check(markerDelta))
						additions.add(marker);
					break;
				case IResourceDelta.REMOVED :
					if (check(markerDelta))
						removals.add(marker);
					break;
				case IResourceDelta.CHANGED :
					if (check(markerDelta))
						changes.add(marker);
					break;
			}
		}

		//recurse on child deltas
		IResourceDelta[] children = delta.getAffectedChildren();
		for (int i = 0; i < children.length; i++) {
			getMarkerDeltas(children[i], additions, removals, changes);
		}
	}
	/**
	 * Returns the markers to show in the task list.
	 */
	IMarker[] getMarkers() throws CoreException {
		IResource res = taskList.getResource();
		if (!res.exists()) {
			return new IMarker[0];
		}
		int depth = taskList.getResourceDepth();
		String[] types = taskList.getMarkerTypes();
		ArrayList list = new ArrayList();
		for (int i = 0; i < types.length; ++i) {
			IMarker[] markers = res.findMarkers(types[i], true, depth);
			for (int index = 0; index < markers.length; index++) {
				list.add(new TaskListMarker(markers[index]));
			}

		}
		IMarker[] result = new IMarker[list.size()];
		list.toArray(result);

		return result;
	}
	/**
	 * Returns a one-line string containing a summary of the number
	 * of tasks and problems being displayed, for display in the status line.
	 */
	public String getSummary() {
		// cache summary message since computing it takes time
		if (summary == null)
			computeSummary();
		return summary;
	}
	/**
	 * Returns a one-line string containing a summary of the number
	 * of tasks and problems in the given array of markers.
	 */
	String getSummary(List markers) throws CoreException {
		int numTasks = 0;
		int numErrors = 0, numWarnings = 0, numInfos = 0;
		for (Iterator i = markers.iterator(); i.hasNext();) {
			IMarker marker = (IMarker) i.next();
			if (marker.isSubtypeOf(IMarker.TASK)) {
				++numTasks;
			} else
				if (marker.isSubtypeOf(IMarker.PROBLEM)) {
					switch (MarkerUtil.getSeverity(marker)) {
						case IMarker.SEVERITY_ERROR :
							++numErrors;
							break;
						case IMarker.SEVERITY_WARNING :
							++numWarnings;
							break;
						case IMarker.SEVERITY_INFO :
							++numInfos;
							break;
					}
				}
		}
		String fmt = TaskListMessages.getString("TaskList.summaryCountFmt");
		//$NON-NLS-1$
		Object[] args =
			new Object[] {
				new Integer(numTasks),
				new Integer(numErrors),
				new Integer(numWarnings),
				new Integer(numInfos)};
		return MessageFormat.format(fmt, args);
	}
	/**
	 * Returns a one-line string containing a summary of the number items,
	 * for display in the title bar.
	 */
	public String getTitleSummary() {
		// cache summary message since computing it takes time
		if (titleSummary == null)
			computeSummary();
		return titleSummary;
	}
	/**
	 * Returns the count of all markers in the workspace which can be shown in the task list.
	 */
	int getTotalMarkerCount() throws CoreException {
		IResource root = taskList.getWorkspace().getRoot();
		String[] types = TasksFilter.ROOT_TYPES;
		// code below assumes root types, and their subtypes, are non-overlapping
		int count = 0;
		for (int i = 0; i < types.length; ++i) {
			IMarker[] markers = root.findMarkers(types[i], true, IResource.DEPTH_INFINITE);
			count += markers.length;
		}
		return count;
	}
	public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
		if (this.input != null) {
			this.input.getWorkspace().removeResourceChangeListener(this);
		}
		this.input = (IResource) newInput;
		if (this.input != null) {
			this.input.getWorkspace().addResourceChangeListener(
				this,
				IResourceChangeEvent.POST_CHANGE);
		}
		this.viewer = (TableViewer) viewer;
		clearSummary();
	}
	/**
	 * The workbench has changed.  Process the delta and issue updates to the viewer,
	 * inside the UI thread.
	 *
	 * @see IResourceChangeListener#resourceChanged
	 */
	public void resourceChanged(final IResourceChangeEvent event) {

		// gather all marker changes from the delta.
		// be sure to do this in the calling thread, 
		// as the delta is destroyed when this method returns
		final List additions = new ArrayList();
		final List removals = new ArrayList();
		final List changes = new ArrayList();
		getMarkerDeltas(event.getDelta(), additions, removals, changes);

		if (additions.size() + removals.size() + changes.size() == 0) {
			// no changes to markers that we care about
			return;
		}

		clearSummary();

		// do the required viewer updates in the UI thread
		// need to use syncExec; see 1G95PU8: ITPUI:WIN2000 - Changing task description flashes old description
		viewer.getControl().getDisplay().syncExec(new Runnable() {
			public void run() {
				updateViewer(additions, removals, changes);
			}
		});

	}
	/**
	 * Updates the viewer given the lists of added, removed, and changes markers.
	 */
	void updateViewer(List additions, List removals, List changes) {

		// The widget may have been destroyed by the time this is run.  
		// Check for this and do nothing if so.
		Control ctrl = viewer.getControl();
		if (ctrl == null || ctrl.isDisposed())
			return;

		//update the viewer based on the marker changes.
		//process removals before additions, to avoid multiple equal elements in the viewer
		if (removals.size() > 0) {
			// Cancel any open cell editor.  We assume that the one being edited is the one being removed.
			viewer.cancelEditing();
			viewer.remove(removals.toArray());
		}
		if (additions.size() > 0) {
			viewer.add(additions.toArray());
		}
		if (changes.size() > 0) {
			viewer.update(changes.toArray(), null);
		}

		// Update the task list's status message.
		// XXX: Quick and dirty solution here.  
		// Would be better to have a separate model for the tasks and
		// have both the content provider and the task list register for updates.
		// XXX: Do this inside the asyncExec, since we're talking to status line widget.
		taskList.markersChanged();

	}
}

Here is the Preference Constants changes

package org.eclipse.ui.internal;

/*
 * (c) Copyright IBM Corp. 2000, 2001.
 * All Rights Reserved.
 */
 
/**
 * The IPreferenceConstants are the internal constants used by the Workbench.
 */
public interface IPreferenceConstants {
	// (boolean) Whether or not to display the Welcome dialog on startup.
	public static final String WELCOME_DIALOG = "WELCOME_DIALOG"; //$NON-NLS-1$

	// (boolean) Cause all editors to save modified resources prior
	// to running a full or incremental manual build.
	public static final String SAVE_ALL_BEFORE_BUILD = "SAVE_ALL_BEFORE_BUILD"; //$NON-NLS-1$

	// (boolean) Whether or not to automatically run a build
	// when a resource is modified. NOTE: The value is not
	// actually in the preference store but available from
	// IWorkspace. This constant is used solely for property
	// change notification from the preference store so
	// interested parties can listen for all preference changes.
	public static final String AUTO_BUILD = "AUTO_BUILD"; //$NON-NLS-1$

	//Do we show tabs up or down for views
	public static final String VIEW_TAB_POSITION = "VIEW_TAB_POSITION"; //$NON-NLS-1$

	//Do we show tabs up or down for editors
	public static final String EDITOR_TAB_POSITION = "EDITOR_TAB_POSITION"; //$NON-NLS-1$
	
	//What is the number of tasks we display
	public static final String DISPLAYED_TASKS_COUNT = "EDITOR_TAB_POSITION"; //$NON-NLS-1$

}


And the line for the WorkbenchPlugin

protected void initializeDefaultPreferences(IPreferenceStore store) {
	store.setDefault(IPreferenceConstants.AUTO_BUILD, true);
	store.setDefault(IPreferenceConstants.SAVE_ALL_BEFORE_BUILD, false);
	store.setDefault(IPreferenceConstants.WELCOME_DIALOG, true);
	store.setDefault(IWorkbenchPreferenceConstants.LINK_NAVIGATOR_TO_EDITOR, true);
	store.setDefault(IPreferenceConstants.VIEW_TAB_POSITION, SWT.BOTTOM);
	store.setDefault(IPreferenceConstants.EDITOR_TAB_POSITION, SWT.TOP);
	store.setDefault(IPreferenceConstants.DISPLAYED_TASKS_COUNT, 100);
	store.setDefault(
		IWorkbenchPreferenceConstants.OPEN_NEW_PERSPECTIVE,
		IWorkbenchPreferenceConstants.OPEN_PERSPECTIVE_PAGE);
	store.setDefault(
		IWorkbenchPreferenceConstants.SHIFT_OPEN_NEW_PERSPECTIVE,
		IWorkbenchPreferenceConstants.OPEN_PERSPECTIVE_WINDOW);
	store.setDefault(
		IWorkbenchPreferenceConstants.ALTERNATE_OPEN_NEW_PERSPECTIVE,
		IWorkbenchPreferenceConstants.OPEN_PERSPECTIVE_REPLACE);
	store.setDefault(
		IWorkbenchPreferenceConstants.PROJECT_OPEN_NEW_PERSPECTIVE,
		IWorkbenchPreferenceConstants.OPEN_PERSPECTIVE_PAGE);
}
NOTES:
Comment 1 DJ Houghton CLA 2001-10-29 19:11:23 EST
PRODUCT VERSION: 0.9


Comment 2 Tod Creasey CLA 2002-01-22 10:24:11 EST
Still not implemented as of 20020115
Comment 3 Kevin Haaland CLA 2002-03-20 17:01:39 EST
No plans to change this in the workbench.