Project

General

Profile

Download (16.7 KB) Statistics
| Branch: | Tag: | Revision:
1
/*******************************************************************************
2
 * Copyright (c) 2003, 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 * IBM Corporation - initial API and implementation
10
 * Oakland Software (Francis Upton - francisu@ieee.org) 
11
 *    bug 197113 Project Explorer drag and drop selection not working properly
12
 *******************************************************************************/
13
package org.eclipse.ui.navigator;
14

    
15
import java.util.ArrayList;
16
import java.util.Iterator;
17
import java.util.List;
18

    
19
import org.eclipse.jface.viewers.IBaseLabelProvider;
20
import org.eclipse.jface.viewers.ISelection;
21
import org.eclipse.jface.viewers.IStructuredSelection;
22
import org.eclipse.jface.viewers.LabelProviderChangedEvent;
23
import org.eclipse.jface.viewers.StructuredSelection;
24
import org.eclipse.jface.viewers.TreeViewer;
25
import org.eclipse.jface.viewers.ViewerSorter;
26
import org.eclipse.swt.dnd.DND;
27
import org.eclipse.swt.events.DisposeEvent;
28
import org.eclipse.swt.events.MouseAdapter;
29
import org.eclipse.swt.events.MouseEvent;
30
import org.eclipse.swt.events.SelectionEvent;
31
import org.eclipse.swt.widgets.Composite;
32
import org.eclipse.swt.widgets.Control;
33
import org.eclipse.swt.widgets.Item;
34
import org.eclipse.swt.widgets.Widget;
35
import org.eclipse.ui.internal.navigator.CommonNavigatorFrameSource;
36
import org.eclipse.ui.internal.navigator.ContributorTrackingSet;
37
import org.eclipse.ui.internal.navigator.NavigatorContentService;
38
//import org.eclipse.ui.internal.navigator.NavigatorDecoratingLabelProvider;
39
import org.eclipse.ui.internal.navigator.NavigatorPipelineService;
40
import org.eclipse.ui.internal.navigator.dnd.NavigatorDnDService;
41
import org.eclipse.ui.internal.navigator.framelist.FrameList;
42

    
43
/**
44
 * 
45
 * Provides the Tree Viewer for the Common Navigator. Content and labels are
46
 * provided by an instance of {@link INavigatorContentService}  which uses
47
 * the ID supplied in the constructor
48
 * {@link CommonViewer#CommonViewer(String, Composite, int)} or through
49
 * {@link NavigatorContentServiceFactory#createContentService(String, org.eclipse.jface.viewers.StructuredViewer)}.
50
 * 
51
 * <p>
52
 * Clients may extend this class.
53
 * </p>
54
 * 
55
 * <p>
56
 * Note that as of 3.2.1 and 3.3, the common viewer caches its selection.
57
 * Clients must not set the selection of the viewer's tree control directly.
58
 * </p>
59
 * 
60
 * @since 3.2
61
 */
62
public class CommonViewer extends TreeViewer {
63

    
64
	private final NavigatorContentService contentService;
65

    
66
	private ISelection cachedSelection;
67
	
68
	private FrameList frameList;
69
	
70
	private CommonNavigator commonNavigator;
71

    
72
	private ICommonViewerMapper _mapper;
73
	
74
	/**
75
	 * <p>
76
	 * Constructs the Tree Viewer for the Common Navigator and the corresponding
77
	 * NavigatorContentService. The NavigatorContentService will provide the
78
	 * Content Provider and Label Provider -- these need not be supplied by
79
	 * clients.
80
	 * <p>
81
	 * For the valid bits to supply in the style mask (aStyle), see
82
	 * documentation provided by {@link TreeViewer}.
83
	 * </p>
84
	 * 
85
	 * @param aViewerId
86
	 *            An id tied to the extensions that is used to focus specific
87
	 *            content to a particular instance of the Common Navigator
88
	 * @param aParent
89
	 *            A Composite parent to contain the actual SWT widget
90
	 * @param aStyle
91
	 *            A style mask that will be used to create the TreeViewer
92
	 *            Composite.
93
	 */
94
	public CommonViewer(String aViewerId, Composite aParent, int aStyle) {
95
		super(aParent, aStyle);
96
		contentService = new NavigatorContentService(aViewerId, this);
97
		init();
98
	}
99

    
100
	/**
101
	 * <p>
102
	 * Initializes the content provider, label provider, and drag and drop
103
	 * support. Should not be called by clients -- this method is invoked when
104
	 * the constructor is invoked.
105
	 * </p>
106
	 */
107
	protected void init() {
108
		setUseHashlookup(true);
109
		setContentProvider(contentService.createCommonContentProvider());
110
		
111
		// RAP [bmichalik]: label provider
112
		setLabelProvider(contentService.createCommonLabelProvider());
113
//		setLabelProvider(new NavigatorDecoratingLabelProvider(contentService.createCommonLabelProvider()));
114
		// RAPEND
115
		
116

    
117
		initDragAndDrop();
118
	}
119

    
120
	void setCommonNavigator(CommonNavigator navigator) {
121
		commonNavigator = navigator;
122
	}
123

    
124
	/**
125
	 * Sets the {@link ICommonViewerMapper} to work with this viewer.
126
	 * 
127
	 * @param mapper
128
	 * @since 3.4
129
	 */
130
	public void setMapper(ICommonViewerMapper mapper) {
131
		_mapper = mapper;
132
	}
133
	
134
	/**
135
	 * Gets the {@link ICommonViewerMapper} assigned to this viewer.
136
	 * 
137
	 * @return the mapper
138
	 * @since 3.4
139
	 */
140
	public ICommonViewerMapper getMapper() {
141
		return _mapper;
142
	}
143
	
144
	/**
145
	 * @return the CommonNavigator
146
	 * @since 3.4
147
	 */
148
	public CommonNavigator getCommonNavigator() {
149
		return commonNavigator;
150
	}
151
	
152
	protected void removeWithoutRefresh(Object[] elements) {
153
		super.remove(elements);
154
	}
155

    
156
	/**
157
	 * <p>
158
	 * Adds DND support to the Navigator. Uses hooks into the extensible
159
	 * framework for DND.
160
	 * </p>
161
	 * <p>
162
	 * By default, the following Transfer types are supported:
163
	 * <ul>
164
	 * <li>LocalSelectionTransfer.getInstance(),
165
	 * <li>PluginTransfer.getInstance()
166
	 * </ul>
167
	 * </p>
168
	 * 
169
	 * @see CommonDragAdapter
170
	 * @see CommonDropAdapter
171
	 */
172
	protected void initDragAndDrop() {
173

    
174
		int operations = DND.DROP_COPY | DND.DROP_MOVE | DND.DROP_LINK;
175

    
176
		CommonDragAdapter dragAdapter = createDragAdapter();
177
		addDragSupport(operations, dragAdapter.getSupportedDragTransfers(),
178
				dragAdapter);
179
		
180
		CommonDropAdapter dropAdapter = createDropAdapter();
181
		addDropSupport(operations, dropAdapter.getSupportedDropTransfers(),
182
				dropAdapter);
183

    
184
		NavigatorDnDService dnd = (NavigatorDnDService)contentService.getDnDService();
185
		dnd.setDropAdaptor(dropAdapter);
186
	}
187

    
188
	
189
	/**
190
	 * Creates the {@link CommonDragAdapter}, this is used to provide a subclass
191
	 * if desired.
192
	 * 
193
	 * @return the CommonDragAdapter
194
	 * 
195
	 * @since 3.4
196
	 */
197
	protected CommonDragAdapter createDragAdapter() {
198
		return new CommonDragAdapter(contentService, this);
199
	}
200
	
201
	
202
	/**
203
	 * Creates the {@link CommonDropAdapter}, this is used to provide a subclass
204
	 * if desired.
205
	 * 
206
	 * @return the CommonDropAdapter
207
	 * 
208
	 * @since 3.4
209
	 */
210
	protected CommonDropAdapter createDropAdapter() {
211
		return new CommonDropAdapter(contentService, this);
212
	}
213
	
214
	
215
	/*
216
	 * @see ContentViewer#handleLabelProviderChanged(LabelProviderChangedEvent)
217
	 */
218
	protected void handleLabelProviderChanged(LabelProviderChangedEvent event) {
219

    
220
		Object[] changed = event.getElements();
221
		if (changed != null) {
222
			List others = new ArrayList();
223
			for (int i = 0; i < changed.length; i++) {
224
				if (changed[i] == null)
225
					continue;
226
				
227
				if (_mapper != null) {
228
					if (_mapper.handlesObject(changed[i])) {
229
						_mapper.objectChanged(changed[i]);
230
						continue;
231
					}
232
				}
233
				others.add(changed[i]);
234
			}
235
			if (others.isEmpty()) {
236
				return;
237
			}
238
			event = new LabelProviderChangedEvent((IBaseLabelProvider) event
239
					.getSource(), others.toArray());
240
		}
241
		super.handleLabelProviderChanged(event);
242
	}
243

    
244
	protected void handleDispose(DisposeEvent event) {
245
		dispose();
246
		super.handleDispose(event);
247
	}
248
 
249
	/**
250
	 * <p>
251
	 * Disposes of the NavigatorContentService, which will dispose the Content
252
	 * and Label providers.
253
	 * </p>
254
	 */
255
	public void dispose() {
256
		if (contentService != null) {
257
			contentService.dispose();
258
		}
259
		clearSelectionCache();
260
	}
261

    
262
	/**
263
	 * Sets this viewer's sorter and triggers refiltering and resorting of this
264
	 * viewer's element. Passing <code>null</code> turns sorting off.
265
	 * 
266
	 * @param sorter
267
	 *            a viewer sorter, or <code>null</code> if none
268
	 */
269
	public void setSorter(ViewerSorter sorter) {
270
		if (sorter != null && sorter instanceof CommonViewerSorter) {
271
			((CommonViewerSorter) sorter).setContentService(contentService);
272
		}
273

    
274
		super.setSorter(sorter);
275
	}
276

    
277
	/**
278
	 * <p>
279
	 * The {@link INavigatorContentService}provides the hook into the framework
280
	 * to provide content from the various extensions.
281
	 * </p>
282
	 * 
283
	 * @return The {@link INavigatorContentService}that was created when the
284
	 *         viewer was created.
285
	 */
286
	public INavigatorContentService getNavigatorContentService() {
287
		return contentService;
288
	}
289

    
290
	/*
291
	 * (non-Javadoc)
292
	 * 
293
	 * @see org.eclipse.jface.viewers.AbstractTreeViewer#add(java.lang.Object,
294
	 *      java.lang.Object[])
295
	 */
296
	public void add(Object parentElement, Object[] childElements) {
297
		NavigatorPipelineService pipeDream = (NavigatorPipelineService) contentService
298
				.getPipelineService();
299

    
300
		PipelinedShapeModification modification = new PipelinedShapeModification(
301
				parentElement, new ContributorTrackingSet(contentService,
302
						childElements));
303

    
304
		pipeDream.interceptAdd(modification);
305

    
306
		Object parent = (parentElement == getInput()) ? getInput()
307
				: modification.getParent();
308

    
309
		super.add(parent, modification.getChildren().toArray());
310
	}
311

    
312
	/**
313
	 * <p>
314
	 * Removals are handled by refreshing the parents of each of the given
315
	 * elements. The parents are determined via calls ot the contentProvider.
316
	 * </p>
317
	 * 
318
	 * @see org.eclipse.jface.viewers.AbstractTreeViewer#remove(java.lang.Object[])
319
	 */
320
	public void remove(Object[] elements) {
321
		NavigatorPipelineService pipeDream = (NavigatorPipelineService) contentService
322
				.getPipelineService();
323

    
324
		PipelinedShapeModification modification = new PipelinedShapeModification(
325
				null, new ContributorTrackingSet(contentService, elements));
326

    
327
		pipeDream.interceptRemove(modification);
328

    
329
		super.remove(modification.getChildren().toArray());
330
	}
331

    
332
	/*
333
	 * (non-Javadoc)
334
	 * 
335
	 * @see org.eclipse.jface.viewers.StructuredViewer#refresh(java.lang.Object,
336
	 *      boolean)
337
	 */
338
	public void refresh(Object element, boolean updateLabels) {
339

    
340
		if(element != getInput()) {
341
			INavigatorPipelineService pipeDream = contentService
342
					.getPipelineService();
343
	
344
			PipelinedViewerUpdate update = new PipelinedViewerUpdate();
345
			update.getRefreshTargets().add(element);
346
			update.setUpdateLabels(updateLabels);
347
			/* if the update is modified */
348
			if (pipeDream.interceptRefresh(update)) {
349
				/* intercept and apply the update */
350
				boolean toUpdateLabels = update.isUpdateLabels();
351
				for (Iterator iter = update.getRefreshTargets().iterator(); iter
352
						.hasNext();) {
353
					super.refresh(iter.next(), toUpdateLabels);
354
				}
355
			} else {
356
				super.refresh(element, updateLabels);
357
			}
358
		} else {
359
			super.refresh(element, updateLabels);
360
		}
361
	}
362
	
363
	/*
364
	 *  (non-Javadoc)
365
	 * @see org.eclipse.jface.viewers.Viewer#setSelection(org.eclipse.jface.viewers.ISelection, boolean)
366
	 */
367
	public void setSelection(ISelection selection, boolean reveal) { 
368

    
369
		if(selection instanceof IStructuredSelection) {
370
			IStructuredSelection sSelection = (IStructuredSelection) selection;
371
			
372
			INavigatorPipelineService pipeDream = contentService
373
					.getPipelineService();
374

    
375
			PipelinedViewerUpdate update = new PipelinedViewerUpdate();
376
			update.getRefreshTargets().addAll(sSelection.toList());
377
			update.setUpdateLabels(false);
378
			/* if the update is modified */
379
			if (pipeDream.interceptRefresh(update)) {
380
				/* intercept and apply the update */ 
381
				super.setSelection(new StructuredSelection(update.getRefreshTargets().toArray()) , reveal);
382
			} else {
383
				super.setSelection(selection, reveal);
384
			}
385
		}
386
	}
387
	
388
    /* (non-Javadoc)
389
     * @see org.eclipse.jface.viewers.ContentViewer#hookControl(Control)
390
     */
391
    protected void hookControl(Control control) {
392
    	super.hookControl(control);
393
        // FIXME - This caching thing should not be here; it's brittle.
394
        // The underlying problem of over-calling of getSelection() should
395
        // be addressed instead (see bugs 144294 and 140032)
396
        // The DragStart event will come before the SelectionEvent on
397
        // some platforms (GTK).  Since DragStart can turn around and
398
        // call getSelection(), we need to clear the cache.
399
        control.addMouseListener(new MouseAdapter() {
400
            public void mouseDown(MouseEvent e) {
401
            	clearSelectionCache();
402
            }
403
        });
404
    }
405

    
406

    
407
	/**
408
	 * Update an item in the tree.
409
	 * 
410
	 * @param item the item in the tree to update
411
	 * @since 3.4
412
	 * 
413
	 */
414
	public void doUpdateItem(Widget item) {
415
		doUpdateItem(item, item.getData(), true);
416
	}
417

    
418
	/*
419
	 * @see StructuredViewer#mapElement(Object, Widget)
420
	 */
421
	protected void mapElement(Object element, Widget item) {
422
		super.mapElement(element, item);
423
		if (_mapper != null && item instanceof Item) {
424
			_mapper.addToMap(element, (Item) item);
425
		}
426
	}
427

    
428
	/*
429
	 * @see StructuredViewer#unmapElement(Object, Widget)
430
	 */
431
	protected void unmapElement(Object element, Widget item) {
432
		if (_mapper != null && item instanceof Item) {
433
			_mapper.removeFromMap(element, (Item) item);
434
		}
435
		super.unmapElement(element, item);
436
	}
437

    
438
	/*
439
	 * @see StructuredViewer#unmapAllElements()
440
	 */
441
	protected void unmapAllElements() {
442
		if (_mapper != null)
443
			_mapper.clearMap();
444
		super.unmapAllElements();
445
	}
446

    
447
	/* (non-Javadoc)
448
	 * @see org.eclipse.jface.viewers.AbstractTreeViewer#setSelectionToWidget(java.util.List, boolean)
449
	 */
450
	protected void setSelectionToWidget(List v, boolean reveal) {
451
		clearSelectionCache();
452
		super.setSelectionToWidget(v, reveal);
453
	}
454
	
455
	/* (non-Javadoc)
456
	 * @see org.eclipse.jface.viewers.AbstractTreeViewer#handleDoubleSelect(org.eclipse.swt.events.SelectionEvent)
457
	 */
458
	protected void handleDoubleSelect(SelectionEvent event) {
459
		clearSelectionCache();
460
		super.handleDoubleSelect(event);
461
	}
462
	
463
	/* (non-Javadoc)
464
	 * @see org.eclipse.jface.viewers.StructuredViewer#handleOpen(org.eclipse.swt.events.SelectionEvent)
465
	 */
466
	protected void handleOpen(SelectionEvent event) {
467
		clearSelectionCache();
468
		super.handleOpen(event);
469
	}
470
	
471
	/* (non-Javadoc)
472
	 * @see org.eclipse.jface.viewers.StructuredViewer#handlePostSelect(org.eclipse.swt.events.SelectionEvent)
473
	 */
474
	protected void handlePostSelect(SelectionEvent e) {
475
		clearSelectionCache();
476
		super.handlePostSelect(e);
477
	}
478
	
479
	/* (non-Javadoc)
480
	 * @see org.eclipse.jface.viewers.StructuredViewer#handleSelect(org.eclipse.swt.events.SelectionEvent)
481
	 */
482
	protected void handleSelect(SelectionEvent event) {
483
		clearSelectionCache();
484
		super.handleSelect(event);
485
	}
486
	
487
	/**
488
	 * Clears the selection cache.
489
	 */
490
	private void clearSelectionCache() {
491
		cachedSelection = null;
492
	}
493
	
494
	/**
495
	 * Returns the current selection.
496
	 * <p>
497
	 * Note that as of 3.2.1 and 3.3, the common viewer caches its selection.
498
	 * Clients must not set the selection of the viewer's tree control directly.
499
	 * </p>
500
	 * 
501
	 * @see org.eclipse.jface.viewers.AbstractTreeViewer#getSelection()
502
	 */
503
	public ISelection getSelection() {
504
		if (cachedSelection == null) {
505
			cachedSelection = super.getSelection();
506
		}
507
		return cachedSelection;
508
	}
509

    
510
	/*
511
	 * (non-Javadoc)
512
	 * 
513
	 * @see org.eclipse.jface.viewers.StructuredViewer#refresh(java.lang.Object)
514
	 */
515
	public void refresh(Object element) {
516
		refresh(element, true);
517
	}
518

    
519
	/*
520
	 * (non-Javadoc)
521
	 * 
522
	 * @see org.eclipse.jface.viewers.StructuredViewer#update(java.lang.Object,
523
	 *      java.lang.String[])
524
	 */
525
	public void update(Object element, String[] properties) {
526
		if(element != getInput()) {
527
			INavigatorPipelineService pipeDream = contentService
528
					.getPipelineService();
529
	
530
			PipelinedViewerUpdate update = new PipelinedViewerUpdate();
531
			update.getRefreshTargets().add(element);
532
			update.setUpdateLabels(true);
533
			/* if the update is modified */
534
			if (pipeDream.interceptUpdate(update)) {
535
				/* intercept and apply the update */ 
536
				for (Iterator iter = update.getRefreshTargets().iterator(); iter
537
						.hasNext();) {
538
					super.update(iter.next(), properties);
539
				}
540
			} else {
541
				super.update(element, properties);
542
			}
543
		} else {
544
			super.update(element, properties);
545
		}
546
	}
547

    
548
	/*
549
	 * (non-Javadoc)
550
	 * 
551
	 * @see java.lang.Object#toString()
552
	 */
553
	public String toString() {
554
		return contentService.toString() + " Viewer"; //$NON-NLS-1$
555
	}
556

    
557
	/*
558
	 * (non-Javadoc)
559
	 * 
560
	 * @see org.eclipse.jface.viewers.AbstractTreeViewer#internalRefresh(java.lang.Object,
561
	 *      boolean)
562
	 */
563
	protected void internalRefresh(Object element, boolean updateLabels) {
564
		if (element == null && getRoot() == null) {
565
			return;
566
		}
567
		super.internalRefresh(element, updateLabels);
568
	}
569

    
570
	/**
571
	 * @noreference This method is not intended to be referenced by clients.
572
	 * @nooverride This method is not intended to be re-implemented or extended by clients.
573
	 * @since 3.4
574
	 */
575
    public void createFrameList() {
576
        CommonNavigatorFrameSource frameSource = new CommonNavigatorFrameSource(commonNavigator);
577
        frameList = new FrameList(frameSource);
578
        frameSource.connectTo(frameList);
579
    }
580
    
581
	/**
582
	 * @return a FrameList
583
	 * @noreference This method is not intended to be referenced by clients.
584
	 * @nooverride This method is not intended to be re-implemented or extended by clients.
585
	 * @since 3.4
586
	 */
587
    public FrameList getFrameList() {
588
        return frameList;
589
    }
590
	
591
	
592
}
(8-8/49)