001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: * Tom Schindl <tom.schindl@bestsolution.at> - concept of ViewerRow,
011: * fix for 159597, refactoring (bug 153993),
012: * widget-independency (bug 154329), fix for 187826, 191468
013: *******************************************************************************/package org.eclipse.jface.viewers;
014:
015: import org.eclipse.core.runtime.Assert;
016: import org.eclipse.swt.SWT;
017: import org.eclipse.swt.graphics.Point;
018: import org.eclipse.swt.widgets.Composite;
019: import org.eclipse.swt.widgets.Control;
020: import org.eclipse.swt.widgets.Item;
021: import org.eclipse.swt.widgets.Table;
022: import org.eclipse.swt.widgets.TableItem;
023: import org.eclipse.swt.widgets.Widget;
024:
025: /**
026: * A concrete viewer based on a SWT <code>Table</code> control.
027: * <p>
028: * This class is not intended to be subclassed outside the viewer framework. It
029: * is designed to be instantiated with a pre-existing SWT table control and
030: * configured with a domain-specific content provider, table label provider,
031: * element filter (optional), and element sorter (optional).
032: * </p>
033: * <p>
034: * Label providers for table viewers must implement either the
035: * <code>ITableLabelProvider</code> or the <code>ILabelProvider</code>
036: * interface (see <code>TableViewer.setLabelProvider</code> for more details).
037: * </p>
038: * <p>
039: * As of 3.1 the TableViewer now supports the SWT.VIRTUAL flag. If the
040: * underlying table is SWT.VIRTUAL, the content provider may implement
041: * {@link ILazyContentProvider} instead of {@link IStructuredContentProvider}.
042: * Note that in this case, the viewer does not support sorting or filtering.
043: * Also note that in this case, the Widget based APIs may return null if the
044: * element is not specified or not created yet.
045: * </p>
046: * <p>
047: * Users of SWT.VIRTUAL should also avoid using getItems() from the Table within
048: * the TreeViewer as this does not necessarily generate a callback for the
049: * TreeViewer to populate the items. It also has the side effect of creating all
050: * of the items thereby eliminating the performance improvements of SWT.VIRTUAL.
051: * </p>
052: *
053: * @see SWT#VIRTUAL
054: * @see #doFindItem(Object)
055: * @see #internalRefresh(Object, boolean)
056: */
057: public class TableViewer extends AbstractTableViewer {
058: /**
059: * This viewer's table control.
060: */
061: private Table table;
062:
063: /**
064: * The cached row which is reused all over
065: */
066: private TableViewerRow cachedRow;
067:
068: /**
069: * Creates a table viewer on a newly-created table control under the given
070: * parent. The table control is created using the SWT style bits
071: * <code>MULTI, H_SCROLL, V_SCROLL,</code> and <code>BORDER</code>. The
072: * viewer has no input, no content provider, a default label provider, no
073: * sorter, and no filters. The table has no columns.
074: *
075: * @param parent
076: * the parent control
077: */
078: public TableViewer(Composite parent) {
079: this (parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL
080: | SWT.BORDER);
081: }
082:
083: /**
084: * Creates a table viewer on a newly-created table control under the given
085: * parent. The table control is created using the given style bits. The
086: * viewer has no input, no content provider, a default label provider, no
087: * sorter, and no filters. The table has no columns.
088: *
089: * @param parent
090: * the parent control
091: * @param style
092: * SWT style bits
093: */
094: public TableViewer(Composite parent, int style) {
095: this (new Table(parent, style));
096: }
097:
098: /**
099: * Creates a table viewer on the given table control. The viewer has no
100: * input, no content provider, a default label provider, no sorter, and no
101: * filters.
102: *
103: * @param table
104: * the table control
105: */
106: public TableViewer(Table table) {
107: this .table = table;
108: hookControl(table);
109: }
110:
111: public Control getControl() {
112: return table;
113: }
114:
115: /**
116: * Returns this table viewer's table control.
117: *
118: * @return the table control
119: */
120: public Table getTable() {
121: return table;
122: }
123:
124: protected ColumnViewerEditor createViewerEditor() {
125: return new TableViewerEditor(this , null,
126: new ColumnViewerEditorActivationStrategy(this ),
127: ColumnViewerEditor.DEFAULT);
128: }
129:
130: /**
131: * <p>
132: * Sets a new selection for this viewer and optionally makes it visible. The
133: * TableViewer implementation of this method is inefficient for the
134: * ILazyContentProvider as lookup is done by indices rather than elements
135: * and may require population of the entire table in worse case.
136: * </p>
137: * <p>
138: * Use Table#setSelection(int[] indices) and Table#showSelection() if you
139: * wish to set selection more efficiently when using a ILazyContentProvider.
140: * </p>
141: *
142: * @param selection
143: * the new selection
144: * @param reveal
145: * <code>true</code> if the selection is to be made visible,
146: * and <code>false</code> otherwise
147: * @see Table#setSelection(int[])
148: * @see Table#showSelection()
149: */
150: public void setSelection(ISelection selection, boolean reveal) {
151: super .setSelection(selection, reveal);
152: }
153:
154: protected ViewerRow getViewerRowFromItem(Widget item) {
155: if (cachedRow == null) {
156: cachedRow = new TableViewerRow((TableItem) item);
157: } else {
158: cachedRow.setItem((TableItem) item);
159: }
160:
161: return cachedRow;
162: }
163:
164: /**
165: * Create a new row with style at index
166: *
167: * @param style
168: * @param rowIndex
169: * @return ViewerRow
170: * @since 3.3
171: */
172: protected ViewerRow internalCreateNewRowPart(int style, int rowIndex) {
173: TableItem item;
174:
175: if (rowIndex >= 0) {
176: item = new TableItem(table, style, rowIndex);
177: } else {
178: item = new TableItem(table, style);
179: }
180:
181: return getViewerRowFromItem(item);
182: }
183:
184: protected Item getItemAt(Point p) {
185: TableItem[] selection = table.getSelection();
186:
187: if (selection.length == 1) {
188: if (selection[0].getBounds().contains(p)) {
189: return selection[0];
190: }
191: }
192:
193: return table.getItem(p);
194: }
195:
196: // Methods to provide widget independency
197:
198: protected int doGetItemCount() {
199: return table.getItemCount();
200: }
201:
202: protected int doIndexOf(Item item) {
203: return table.indexOf((TableItem) item);
204: }
205:
206: protected void doSetItemCount(int count) {
207: table.setItemCount(count);
208: }
209:
210: protected Item[] doGetItems() {
211: return table.getItems();
212: }
213:
214: protected int doGetColumnCount() {
215: return table.getColumnCount();
216: }
217:
218: protected Widget doGetColumn(int index) {
219: return table.getColumn(index);
220: }
221:
222: protected Item doGetItem(int index) {
223: return table.getItem(index);
224: }
225:
226: protected Item[] doGetSelection() {
227: return table.getSelection();
228: }
229:
230: protected int[] doGetSelectionIndices() {
231: return table.getSelectionIndices();
232: }
233:
234: protected void doClearAll() {
235: table.clearAll();
236: }
237:
238: protected void doResetItem(Item item) {
239: TableItem tableItem = (TableItem) item;
240: int columnCount = Math.max(1, table.getColumnCount());
241: for (int i = 0; i < columnCount; i++) {
242: tableItem.setText(i, ""); //$NON-NLS-1$
243: if (tableItem.getImage(i) != null) {
244: tableItem.setImage(i, null);
245: }
246: }
247: }
248:
249: protected void doRemove(int start, int end) {
250: table.remove(start, end);
251: }
252:
253: protected void doRemoveAll() {
254: table.removeAll();
255: }
256:
257: protected void doRemove(int[] indices) {
258: table.remove(indices);
259: }
260:
261: protected void doShowItem(Item item) {
262: table.showItem((TableItem) item);
263: }
264:
265: protected void doDeselectAll() {
266: table.deselectAll();
267: }
268:
269: protected void doSetSelection(Item[] items) {
270: Assert.isNotNull(items, "Items-Array can not be null"); //$NON-NLS-1$
271:
272: TableItem[] t = new TableItem[items.length];
273: System.arraycopy(items, 0, t, 0, t.length);
274:
275: table.setSelection(t);
276: }
277:
278: protected void doShowSelection() {
279: table.showSelection();
280: }
281:
282: protected void doSetSelection(int[] indices) {
283: table.setSelection(indices);
284: }
285:
286: protected void doClear(int index) {
287: table.clear(index);
288: }
289:
290: protected void doSelect(int[] indices) {
291: table.select(indices);
292: }
293:
294: /**
295: * Refreshes this viewer starting with the given element. Labels are updated
296: * as described in <code>refresh(boolean updateLabels)</code>. The
297: * methods attempts to preserve the selection.
298: * <p>
299: * Unlike the <code>update</code> methods, this handles structural changes
300: * to the given element (e.g. addition or removal of children). If only the
301: * given element needs updating, it is more efficient to use the
302: * <code>update</code> methods.
303: * </p>
304: *
305: * <p>
306: * Subclasses who can provide this feature can open this method for the
307: * public
308: * </p>
309: *
310: * @param element
311: * the element
312: * @param updateLabels
313: * <code>true</code> to update labels for existing elements,
314: * <code>false</code> to only update labels as needed, assuming
315: * that labels for existing elements are unchanged.
316: * @param reveal
317: * <code>true</code> to make the preserved selection visible
318: * afterwards
319: *
320: * @since 3.3
321: */
322: public void refresh(final Object element,
323: final boolean updateLabels, boolean reveal) {
324: if (isBusy())
325: return;
326:
327: if (isCellEditorActive()) {
328: cancelEditing();
329: }
330:
331: preservingSelection(new Runnable() {
332: public void run() {
333: internalRefresh(element, updateLabels);
334: }
335: }, reveal);
336: }
337:
338: /**
339: * Refreshes this viewer with information freshly obtained from this
340: * viewer's model. If <code>updateLabels</code> is <code>true</code>
341: * then labels for otherwise unaffected elements are updated as well.
342: * Otherwise, it assumes labels for existing elements are unchanged, and
343: * labels are only obtained as needed (for example, for new elements).
344: * <p>
345: * Calling <code>refresh(true)</code> has the same effect as
346: * <code>refresh()</code>.
347: * <p>
348: * Note that the implementation may still obtain labels for existing
349: * elements even if <code>updateLabels</code> is false. The intent is
350: * simply to allow optimization where possible.
351: *
352: * @param updateLabels
353: * <code>true</code> to update labels for existing elements,
354: * <code>false</code> to only update labels as needed, assuming
355: * that labels for existing elements are unchanged.
356: * @param reveal
357: * <code>true</code> to make the preserved selection visible
358: * afterwards
359: *
360: * @since 3.3
361: */
362: public void refresh(boolean updateLabels, boolean reveal) {
363: refresh(getRoot(), updateLabels, reveal);
364: }
365: }
|