001: /*******************************************************************************
002: * Copyright (c) 2003, 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: *******************************************************************************/package org.eclipse.ui.navigator;
011:
012: import java.util.Arrays;
013: import java.util.Iterator;
014: import java.util.List;
015:
016: import org.eclipse.jface.viewers.DecoratingLabelProvider;
017: import org.eclipse.jface.viewers.IBaseLabelProvider;
018: import org.eclipse.jface.viewers.ISelection;
019: import org.eclipse.jface.viewers.IStructuredSelection;
020: import org.eclipse.jface.viewers.LabelProviderChangedEvent;
021: import org.eclipse.jface.viewers.StructuredSelection;
022: import org.eclipse.jface.viewers.TreeViewer;
023: import org.eclipse.jface.viewers.ViewerSorter;
024: import org.eclipse.swt.dnd.DND;
025: import org.eclipse.swt.events.DisposeEvent;
026: import org.eclipse.swt.events.SelectionEvent;
027: import org.eclipse.swt.widgets.Composite;
028: import org.eclipse.swt.widgets.Widget;
029: import org.eclipse.ui.PlatformUI;
030: import org.eclipse.ui.internal.navigator.ContributorTrackingSet;
031: import org.eclipse.ui.internal.navigator.NavigatorContentService;
032: import org.eclipse.ui.internal.navigator.NavigatorPipelineService;
033:
034: /**
035: *
036: * Provides the Tree Viewer for the Common Navigator. Content and labels are
037: * provided by an instance of {@link INavigatorContentService} which uses
038: * the ID supplied in the constructor
039: * {@link CommonViewer#CommonViewer(String, Composite, int)} or through
040: * {@link NavigatorContentServiceFactory#createContentService(String, org.eclipse.jface.viewers.StructuredViewer)}.
041: *
042: * <p>
043: * Clients may extend this class.
044: * </p>
045: *
046: * <p>
047: * Note that as of 3.2.1 and 3.3, the common viewer caches its selection.
048: * Clients must not set the selection of the viewer's tree control directly.
049: * </p>
050: *
051: * @since 3.2
052: */
053: public class CommonViewer extends TreeViewer {
054:
055: private final NavigatorContentService contentService;
056:
057: private ISelection cachedSelection;
058:
059: /**
060: * <p>
061: * Constructs the Tree Viewer for the Common Navigator and the corresponding
062: * NavigatorContentService. The NavigatorContentService will provide the
063: * Content Provider and Label Provider -- these need not be supplied by
064: * clients.
065: * <p>
066: * For the valid bits to supply in the style mask (aStyle), see
067: * documentation provided by {@link TreeViewer}.
068: * </p>
069: *
070: * @param aViewerId
071: * An id tied to the extensions that is used to focus specific
072: * content to a particular instance of the Common Navigator
073: * @param aParent
074: * A Composite parent to contain the actual SWT widget
075: * @param aStyle
076: * A style mask that will be used to create the TreeViewer
077: * Composite.
078: */
079: public CommonViewer(String aViewerId, Composite aParent, int aStyle) {
080: super (aParent, aStyle);
081: contentService = new NavigatorContentService(aViewerId, this );
082: init();
083: }
084:
085: /**
086: * <p>
087: * Initializes the content provider, label provider, and drag and drop
088: * support. Should not be called by clients -- this method is invoked when
089: * the constructor is invoked.
090: * </p>
091: */
092: protected void init() {
093: setUseHashlookup(true);
094: setContentProvider(contentService.createCommonContentProvider());
095: DecoratingLabelProvider decoratingProvider = new DecoratingLabelProvider(
096: contentService.createCommonLabelProvider(), PlatformUI
097: .getWorkbench().getDecoratorManager()
098: .getLabelDecorator());
099: setLabelProvider(decoratingProvider);
100: initDragAndDrop();
101:
102: }
103:
104: protected void removeWithoutRefresh(Object[] elements) {
105: super .remove(elements);
106: }
107:
108: /**
109: * <p>
110: * Adds DND support to the Navigator. Uses hooks into the extensible
111: * framework for DND.
112: * </p>
113: * <p>
114: * By default, the following Transfer types are supported:
115: * <ul>
116: * <li>LocalSelectionTransfer.getInstance(),
117: * <li>PluginTransfer.getInstance()
118: * </ul>
119: * </p>
120: *
121: * @see CommonDragAdapter
122: * @see CommonDropAdapter
123: */
124: protected void initDragAndDrop() {
125:
126: /* Handle Drag and Drop */
127: int operations = DND.DROP_COPY | DND.DROP_MOVE;
128:
129: CommonDragAdapter dragAdapter = new CommonDragAdapter(
130: contentService, this );
131: addDragSupport(operations, dragAdapter
132: .getSupportedDragTransfers(), dragAdapter);
133:
134: CommonDropAdapter dropAdapter = new CommonDropAdapter(
135: contentService, this );
136: addDropSupport(operations, dropAdapter
137: .getSupportedDropTransfers(), dropAdapter);
138:
139: }
140:
141: /*
142: * (non-Javadoc)
143: *
144: * @see org.eclipse.jface.viewers.AbstractTreeViewer#createTreeItem(org.eclipse.swt.widgets.Widget,
145: * java.lang.Object, int)
146: */
147: protected void createTreeItem(Widget parent, final Object element,
148: int index) {
149: try {
150: super .createTreeItem(parent, element, index);
151: } catch (Exception ex) {
152: ex.printStackTrace();
153: } catch (Error e) {
154: e.printStackTrace();
155: }
156:
157: }
158:
159: /*
160: * @see ContentViewer#handleLabelProviderChanged(LabelProviderChangedEvent)
161: */
162: protected void handleLabelProviderChanged(
163: LabelProviderChangedEvent event) {
164:
165: Object[] changed = event.getElements();
166: if (changed != null) {
167: List others = Arrays.asList(changed);
168: for (Iterator iter = others.iterator(); iter.hasNext();) {
169: if (iter.next() == null)
170: iter.remove();
171: }
172: if (others.isEmpty()) {
173: return;
174: }
175: event = new LabelProviderChangedEvent(
176: (IBaseLabelProvider) event.getSource(), others
177: .toArray());
178: }
179: super .handleLabelProviderChanged(event);
180: }
181:
182: protected void handleDispose(DisposeEvent event) {
183: dispose();
184: super .handleDispose(event);
185: }
186:
187: /**
188: * <p>
189: * Disposes of the NavigatorContentService, which will dispose the Content
190: * and Label providers.
191: * </p>
192: */
193: public void dispose() {
194: if (contentService != null) {
195: contentService.dispose();
196: }
197: clearSelectionCache();
198: }
199:
200: /**
201: * Sets this viewer's sorter and triggers refiltering and resorting of this
202: * viewer's element. Passing <code>null</code> turns sorting off.
203: *
204: * @param sorter
205: * a viewer sorter, or <code>null</code> if none
206: */
207: public void setSorter(ViewerSorter sorter) {
208: if (sorter != null && sorter instanceof CommonViewerSorter) {
209: ((CommonViewerSorter) sorter)
210: .setContentService(contentService);
211: }
212:
213: super .setSorter(sorter);
214: }
215:
216: /**
217: * <p>
218: * The {@link INavigatorContentService}provides the hook into the framework
219: * to provide content from the various extensions.
220: * </p>
221: *
222: * @return The {@link INavigatorContentService}that was created when the
223: * viewer was created.
224: */
225: public INavigatorContentService getNavigatorContentService() {
226: return contentService;
227: }
228:
229: /*
230: * (non-Javadoc)
231: *
232: * @see org.eclipse.jface.viewers.AbstractTreeViewer#add(java.lang.Object,
233: * java.lang.Object[])
234: */
235: public void add(Object parentElement, Object[] childElements) {
236: // TODO Intercept ADD for the pipeline service.
237:
238: NavigatorPipelineService pipeDream = (NavigatorPipelineService) contentService
239: .getPipelineService();
240:
241: PipelinedShapeModification modification = new PipelinedShapeModification(
242: parentElement, new ContributorTrackingSet(
243: contentService, childElements));
244:
245: pipeDream.interceptAdd(modification);
246:
247: Object parent = (parentElement == getInput()) ? getInput()
248: : modification.getParent();
249:
250: super .add(parent, modification.getChildren().toArray());
251:
252: }
253:
254: /**
255: * <p>
256: * Removals are handled by refreshing the parents of each of the given
257: * elements. The parents are determined via calls ot the contentProvider.
258: * </p>
259: *
260: * @see org.eclipse.jface.viewers.AbstractTreeViewer#remove(java.lang.Object[])
261: */
262: public void remove(Object[] elements) {
263:
264: // TODO Intercept REMOVE for the pipeline service.
265:
266: NavigatorPipelineService pipeDream = (NavigatorPipelineService) contentService
267: .getPipelineService();
268:
269: PipelinedShapeModification modification = new PipelinedShapeModification(
270: null, new ContributorTrackingSet(contentService,
271: elements));
272:
273: pipeDream.interceptRemove(modification);
274:
275: super .remove(modification.getChildren().toArray());
276: }
277:
278: /*
279: * (non-Javadoc)
280: *
281: * @see org.eclipse.jface.viewers.StructuredViewer#refresh(java.lang.Object,
282: * boolean)
283: */
284: public void refresh(Object element, boolean updateLabels) {
285:
286: if (element != getInput()) {
287:
288: INavigatorPipelineService pipeDream = contentService
289: .getPipelineService();
290:
291: PipelinedViewerUpdate update = new PipelinedViewerUpdate();
292: update.getRefreshTargets().add(element);
293: update.setUpdateLabels(updateLabels);
294: /* if the update is modified */
295: if (pipeDream.interceptRefresh(update)) {
296: /* intercept and apply the update */
297: boolean toUpdateLabels = update.isUpdateLabels();
298: for (Iterator iter = update.getRefreshTargets()
299: .iterator(); iter.hasNext();) {
300: super .refresh(iter.next(), toUpdateLabels);
301: }
302: } else {
303: super .refresh(element, updateLabels);
304: }
305: } else {
306: super .refresh(element, updateLabels);
307: }
308: }
309:
310: /*
311: * (non-Javadoc)
312: * @see org.eclipse.jface.viewers.Viewer#setSelection(org.eclipse.jface.viewers.ISelection, boolean)
313: */
314: public void setSelection(ISelection selection, boolean reveal) {
315:
316: if (selection instanceof IStructuredSelection) {
317: IStructuredSelection sSelection = (IStructuredSelection) selection;
318:
319: INavigatorPipelineService pipeDream = contentService
320: .getPipelineService();
321:
322: PipelinedViewerUpdate update = new PipelinedViewerUpdate();
323: update.getRefreshTargets().addAll(sSelection.toList());
324: update.setUpdateLabels(false);
325: /* if the update is modified */
326: if (pipeDream.interceptRefresh(update)) {
327: /* intercept and apply the update */
328: super .setSelection(new StructuredSelection(update
329: .getRefreshTargets().toArray()), reveal);
330: } else {
331: super .setSelection(selection, reveal);
332: }
333: }
334: }
335:
336: /* (non-Javadoc)
337: * @see org.eclipse.jface.viewers.AbstractTreeViewer#setSelectionToWidget(java.util.List, boolean)
338: */
339: protected void setSelectionToWidget(List v, boolean reveal) {
340: clearSelectionCache();
341: super .setSelectionToWidget(v, reveal);
342: }
343:
344: /* (non-Javadoc)
345: * @see org.eclipse.jface.viewers.AbstractTreeViewer#handleDoubleSelect(org.eclipse.swt.events.SelectionEvent)
346: */
347: protected void handleDoubleSelect(SelectionEvent event) {
348: clearSelectionCache();
349: super .handleDoubleSelect(event);
350: }
351:
352: /* (non-Javadoc)
353: * @see org.eclipse.jface.viewers.StructuredViewer#handleOpen(org.eclipse.swt.events.SelectionEvent)
354: */
355: protected void handleOpen(SelectionEvent event) {
356: clearSelectionCache();
357: super .handleOpen(event);
358: }
359:
360: /* (non-Javadoc)
361: * @see org.eclipse.jface.viewers.StructuredViewer#handlePostSelect(org.eclipse.swt.events.SelectionEvent)
362: */
363: protected void handlePostSelect(SelectionEvent e) {
364: clearSelectionCache();
365: super .handlePostSelect(e);
366: }
367:
368: /* (non-Javadoc)
369: * @see org.eclipse.jface.viewers.StructuredViewer#handleSelect(org.eclipse.swt.events.SelectionEvent)
370: */
371: protected void handleSelect(SelectionEvent event) {
372: clearSelectionCache();
373: super .handleSelect(event);
374: }
375:
376: /**
377: * Clears the selection cache.
378: */
379: private void clearSelectionCache() {
380: cachedSelection = null;
381: }
382:
383: /**
384: * Returns the current selection.
385: * <p>
386: * Note that as of 3.2.1 and 3.3, the common viewer caches its selection.
387: * Clients must not set the selection of the viewer's tree control directly.
388: * </p>
389: *
390: * @see org.eclipse.jface.viewers.AbstractTreeViewer#getSelection()
391: */
392: public ISelection getSelection() {
393: if (cachedSelection == null) {
394: cachedSelection = super .getSelection();
395: }
396: return cachedSelection;
397: }
398:
399: /*
400: * (non-Javadoc)
401: *
402: * @see org.eclipse.jface.viewers.StructuredViewer#refresh(java.lang.Object)
403: */
404: public void refresh(Object element) {
405: refresh(element, true);
406: }
407:
408: /*
409: * (non-Javadoc)
410: *
411: * @see org.eclipse.jface.viewers.StructuredViewer#update(java.lang.Object,
412: * java.lang.String[])
413: */
414: public void update(Object element, String[] properties) {
415:
416: if (element != getInput()) {
417: INavigatorPipelineService pipeDream = contentService
418: .getPipelineService();
419:
420: PipelinedViewerUpdate update = new PipelinedViewerUpdate();
421: update.getRefreshTargets().add(element);
422: update.setUpdateLabels(true);
423: /* if the update is modified */
424: if (pipeDream.interceptUpdate(update)) {
425: /* intercept and apply the update */
426: for (Iterator iter = update.getRefreshTargets()
427: .iterator(); iter.hasNext();) {
428: super .update(iter.next(), properties);
429: }
430: } else {
431: super .update(element, properties);
432: }
433: } else {
434: super .update(element, properties);
435: }
436: }
437:
438: /*
439: * (non-Javadoc)
440: *
441: * @see java.lang.Object#toString()
442: */
443: public String toString() {
444: return contentService.toString() + " Viewer"; //$NON-NLS-1$
445: }
446:
447: /*
448: * (non-Javadoc)
449: *
450: * @see org.eclipse.jface.viewers.AbstractTreeViewer#internalRefresh(java.lang.Object,
451: * boolean)
452: */
453: protected void internalRefresh(Object element, boolean updateLabels) {
454: if (element == null && getRoot() == null) {
455: return;
456: }
457: super.internalRefresh(element, updateLabels);
458: }
459:
460: }
|