Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: debcdbd4395b289e3e504fba5ce584041814b4e6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
/*******************************************************************************
 * Copyright (c) 2004, 2013 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.jface.viewers.deferred;

import java.util.Comparator;

import org.eclipse.core.runtime.Assert;
import org.eclipse.jface.viewers.AcceptAllFilter;
import org.eclipse.jface.viewers.IFilter;
import org.eclipse.jface.viewers.ILazyContentProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Table;

/**
 * Content provider that performs sorting and filtering in a background thread.
 * Requires a <code>TableViewer</code> created with the <code>SWT.VIRTUAL</code>
 * flag and an <code>IConcurrentModel</code> as input.
 * <p>
 * The sorter and filter must be set directly on the content provider.
 * Any sorter or filter on the TableViewer will be ignored. 
 * </p>
 *  
 * <p>
 * The real implementation is in <code>BackgroundContentProvider</code>. This 
 * object is a lightweight wrapper that adapts the algorithm to work with 
 * <code>TableViewer</code>.
 * </p>
 * 
 * @since 3.1
 */
public class DeferredContentProvider implements ILazyContentProvider {

	private int limit = -1;
	private BackgroundContentProvider provider;
	private Comparator sortOrder;
	private IFilter filter = AcceptAllFilter.getInstance();
	private AbstractVirtualTable table;
	
	private static final class TableViewerAdapter extends AbstractVirtualTable {
		
		private TableViewer viewer;
		
		/**
		 * @param viewer
		 */
		public TableViewerAdapter(TableViewer viewer) {
			this.viewer = viewer;
		}
		
		@Override
		public void clear(int index) {
			viewer.clear(index);
		}
		
		@Override
		public void replace(Object element, int itemIndex) {
			viewer.replace(element, itemIndex);
		}
		
		@Override
		public void setItemCount(int total) {
			viewer.setItemCount(total);
		}
		
		@Override
		public int getItemCount() {
			return viewer.getTable().getItemCount();
		}
		
		@Override
		public int getTopIndex() {
			return Math.max(viewer.getTable().getTopIndex() - 1, 0);
		}
		
		@Override
		public int getVisibleItemCount() {
			Table table = viewer.getTable();
			Rectangle rect = table.getClientArea ();
			int itemHeight = table.getItemHeight ();
			int headerHeight = table.getHeaderHeight ();
			return (rect.height - headerHeight + itemHeight - 1) / (itemHeight + table.getGridLineWidth());
		}
		
		@Override
		public Control getControl() {
			return viewer.getControl();
		}
		
	}

	/**
	 * Create a DeferredContentProvider with the given sort order.
	 * @param sortOrder a comparator that sorts the content.
	 */
	public DeferredContentProvider(Comparator sortOrder) {
		this.sortOrder = sortOrder;
	}

	@Override
	public void dispose() {
		setProvider(null);
	}

	@Override
	public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
		if (newInput == null) {
			setProvider(null);
			return;
		}
		
		Assert.isTrue(newInput instanceof IConcurrentModel);
		Assert.isTrue(viewer instanceof TableViewer);
		IConcurrentModel model = (IConcurrentModel)newInput;
		
		this.table = new TableViewerAdapter((TableViewer)viewer);
		
		BackgroundContentProvider newProvider = new BackgroundContentProvider(
				table,
				model, sortOrder); 
		
		setProvider(newProvider);
		
		newProvider.setLimit(limit);
		newProvider.setFilter(filter);
	}
	
	/**
	 * Sets the sort order for this content provider. This sort order takes priority
	 * over anything that was supplied to the <code>TableViewer</code>.
	 * 
	 * @param sortOrder new sort order. The comparator must be able to support being
	 * used in a background thread.
	 */
	public void setSortOrder(Comparator sortOrder) {
		Assert.isNotNull(sortOrder);
		this.sortOrder = sortOrder;
		if (provider != null) {
			provider.setSortOrder(sortOrder);
		}
	}
	
	/**
	 * Sets the filter for this content provider. This filter takes priority over
	 * anything that was supplied to the <code>TableViewer</code>. The filter
	 * must be capable of being used in a background thread.
	 * 
	 * @param toSet filter to set
	 */
	public void setFilter(IFilter toSet) {
		this.filter = toSet;
		if (provider != null) {
			provider.setFilter(toSet);
		}
	}
	
	/**
	 * Sets the maximum number of rows in the table. If the model contains more
	 * than this number of elements, only the top elements will be shown based on
	 * the current sort order. 
	 * 
	 * @param limit maximum number of rows to show or -1 if unbounded
	 */
	public void setLimit(int limit) {
		this.limit = limit;
		if (provider != null) {
			provider.setLimit(limit);
		}
	}
	
	/**
	 * Returns the current maximum number of rows or -1 if unbounded
	 * 
	 * @return the current maximum number of rows or -1 if unbounded
	 */
	public int getLimit() {
		return limit;
	}
	
	@Override
	public void updateElement(int element) {
		if (provider != null) {
			provider.checkVisibleRange(element);
		}
	}
	
	private void setProvider(BackgroundContentProvider newProvider) {
		if (provider != null) {
			provider.dispose();
		}
		
		provider = newProvider;
	}

}

Back to the top