1 /*******************************************************************************
2  * Copyright (c) 2000, 2018 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *     Benjamin Muskalla - bug 105041
14  *     Remy Chi Jian Suen - bug 144102
15  *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810
16  *     Andrey Loskutov <loskutov@gmx.de> - generified interface, bug 461762
17  *     Mickael Istria (Red Hat Inc.) - Bug 486901
18  *******************************************************************************/
19 
20 package org.eclipse.ui.views.navigator;
21 
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.Iterator;
25 import java.util.List;
26 import java.util.Objects;
27 
28 import org.eclipse.core.resources.IContainer;
29 import org.eclipse.core.resources.IFile;
30 import org.eclipse.core.resources.IMarker;
31 import org.eclipse.core.resources.IResource;
32 import org.eclipse.core.resources.IWorkspace;
33 import org.eclipse.core.resources.ResourcesPlugin;
34 import org.eclipse.core.runtime.Adapters;
35 import org.eclipse.core.runtime.IAdaptable;
36 import org.eclipse.core.runtime.IPath;
37 import org.eclipse.jface.action.IMenuManager;
38 import org.eclipse.jface.action.MenuManager;
39 import org.eclipse.jface.commands.ActionHandler;
40 import org.eclipse.jface.dialogs.IDialogSettings;
41 import org.eclipse.jface.preference.IPreferenceStore;
42 import org.eclipse.jface.util.IPropertyChangeListener;
43 import org.eclipse.jface.viewers.DecoratingLabelProvider;
44 import org.eclipse.jface.viewers.DoubleClickEvent;
45 import org.eclipse.jface.viewers.ILabelDecorator;
46 import org.eclipse.jface.viewers.ILabelProvider;
47 import org.eclipse.jface.viewers.ISelection;
48 import org.eclipse.jface.viewers.IStructuredSelection;
49 import org.eclipse.jface.viewers.OpenEvent;
50 import org.eclipse.jface.viewers.SelectionChangedEvent;
51 import org.eclipse.jface.viewers.StructuredSelection;
52 import org.eclipse.jface.viewers.TreeViewer;
53 import org.eclipse.jface.viewers.ViewerComparator;
54 import org.eclipse.jface.viewers.ViewerSorter;
55 import org.eclipse.osgi.util.NLS;
56 import org.eclipse.swt.SWT;
57 import org.eclipse.swt.dnd.DND;
58 import org.eclipse.swt.dnd.FileTransfer;
59 import org.eclipse.swt.dnd.Transfer;
60 import org.eclipse.swt.events.KeyEvent;
61 import org.eclipse.swt.events.KeyListener;
62 import org.eclipse.swt.widgets.Composite;
63 import org.eclipse.swt.widgets.Control;
64 import org.eclipse.swt.widgets.Listener;
65 import org.eclipse.swt.widgets.Menu;
66 import org.eclipse.swt.widgets.Shell;
67 import org.eclipse.ui.IEditorInput;
68 import org.eclipse.ui.IEditorPart;
69 import org.eclipse.ui.IMemento;
70 import org.eclipse.ui.IPartListener;
71 import org.eclipse.ui.IViewSite;
72 import org.eclipse.ui.IWorkbenchCommandConstants;
73 import org.eclipse.ui.IWorkbenchPage;
74 import org.eclipse.ui.IWorkbenchPart;
75 import org.eclipse.ui.IWorkbenchPreferenceConstants;
76 import org.eclipse.ui.IWorkingSet;
77 import org.eclipse.ui.IWorkingSetManager;
78 import org.eclipse.ui.OpenAndLinkWithEditorHelper;
79 import org.eclipse.ui.PartInitException;
80 import org.eclipse.ui.PlatformUI;
81 import org.eclipse.ui.ResourceWorkingSetFilter;
82 import org.eclipse.ui.actions.ActionContext;
83 import org.eclipse.ui.actions.OpenResourceAction;
84 import org.eclipse.ui.handlers.CollapseAllHandler;
85 import org.eclipse.ui.handlers.IHandlerService;
86 import org.eclipse.ui.ide.ResourceUtil;
87 import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
88 import org.eclipse.ui.internal.views.helpers.EmptyWorkspaceHelper;
89 import org.eclipse.ui.internal.views.navigator.ResourceNavigatorMessages;
90 import org.eclipse.ui.model.WorkbenchContentProvider;
91 import org.eclipse.ui.model.WorkbenchLabelProvider;
92 import org.eclipse.ui.part.FileEditorInput;
93 import org.eclipse.ui.part.ISetSelectionTarget;
94 import org.eclipse.ui.part.IShowInSource;
95 import org.eclipse.ui.part.IShowInTarget;
96 import org.eclipse.ui.part.PluginTransfer;
97 import org.eclipse.ui.part.ResourceTransfer;
98 import org.eclipse.ui.part.ShowInContext;
99 import org.eclipse.ui.part.ViewPart;
100 import org.eclipse.ui.plugin.AbstractUIPlugin;
101 import org.eclipse.ui.views.framelist.FrameList;
102 import org.eclipse.ui.views.framelist.TreeFrame;
103 
104 /**
105  * Implements the Resource Navigator view.
106  *
107  * @noextend This class is not intended to be subclassed by clients.
108  * @noinstantiate This class is not intended to be instantiated by clients.
109  * @noreference This class is not intended to be referenced by clients.
110  *
111  *              Planned to be deleted, please see Bug
112  *              https://bugs.eclipse.org/bugs/show_bug.cgi?id=549953
113  *
114  * @deprecated as of 3.5, use the Common Navigator Framework classes instead
115  */
116 @Deprecated
117 public class ResourceNavigator extends ViewPart implements ISetSelectionTarget, IResourceNavigator {
118 
119 	private TreeViewer viewer;
120 
121 	private IDialogSettings settings;
122 
123 	private IMemento memento;
124 
125 	private FrameList frameList;
126 
127 	private ResourceNavigatorActionGroup actionGroup;
128 
129 	private ResourcePatternFilter patternFilter = new ResourcePatternFilter();
130 
131 	private ResourceWorkingSetFilter workingSetFilter = new ResourceWorkingSetFilter();
132 
133 	private boolean linkingEnabled;
134 
135 	private boolean dragDetected;
136 
137 	private Listener dragDetectListener;
138 	/**
139 	 * Remembered working set.
140 	 */
141 	private IWorkingSet workingSet;
142 
143 	/**
144 	 * Marks whether the working set we're using is currently empty. In this event
145 	 * we're effectively not using a working set.
146 	 */
147 	private boolean emptyWorkingSet = false;
148 
149 	/**
150 	 * Settings constant for section name (value <code>ResourceNavigator</code>).
151 	 */
152 	private static final String STORE_SECTION = "ResourceNavigator"; //$NON-NLS-1$
153 
154 	/**
155 	 * Settings constant for sort order (value
156 	 * <code>ResourceViewer.STORE_SORT_TYPE</code>).
157 	 */
158 	private static final String STORE_SORT_TYPE = "ResourceViewer.STORE_SORT_TYPE"; //$NON-NLS-1$
159 
160 	/**
161 	 * Settings constant for working set (value
162 	 * <code>ResourceWorkingSetFilter.STORE_WORKING_SET</code>).
163 	 */
164 	private static final String STORE_WORKING_SET = "ResourceWorkingSetFilter.STORE_WORKING_SET"; //$NON-NLS-1$
165 
166 	/**
167 	 * @deprecated No longer used but preserved to avoid an api change.
168 	 */
169 	@Deprecated
170 	public static final String NAVIGATOR_VIEW_HELP_ID = INavigatorHelpContextIds.RESOURCE_VIEW;
171 
172 	/**
173 	 * True iff we've already scheduled an asynchronous call to linkToEditor
174 	 */
175 	private boolean linkScheduled = false;
176 
177 	private EmptyWorkspaceHelper emptyWorkspaceHelper;
178 
179 	// Persistance tags.
180 	private static final String TAG_SORTER = "sorter"; //$NON-NLS-1$
181 
182 	private static final String TAG_FILTERS = "filters"; //$NON-NLS-1$
183 
184 	private static final String TAG_FILTER = "filter"; //$NON-NLS-1$
185 
186 	private static final String TAG_SELECTION = "selection"; //$NON-NLS-1$
187 
188 	private static final String TAG_EXPANDED = "expanded"; //$NON-NLS-1$
189 
190 	private static final String TAG_ELEMENT = "element"; //$NON-NLS-1$
191 
192 	private static final String TAG_IS_ENABLED = "isEnabled"; //$NON-NLS-1$
193 
194 	private static final String TAG_PATH = "path"; //$NON-NLS-1$
195 
196 	private static final String TAG_CURRENT_FRAME = "currentFrame"; //$NON-NLS-1$
197 
198 	private IPartListener partListener = new IPartListener() {
199 		@Override
200 		public void partActivated(IWorkbenchPart part) {
201 			if (part instanceof IEditorPart) {
202 				editorActivated((IEditorPart) part);
203 			}
204 		}
205 
206 		@Override
207 		public void partBroughtToTop(IWorkbenchPart part) {
208 			if (part instanceof IEditorPart) {
209 				editorActivated((IEditorPart) part);
210 			}
211 		}
212 
213 		@Override
214 		public void partClosed(IWorkbenchPart part) {
215 		}
216 
217 		@Override
218 		public void partDeactivated(IWorkbenchPart part) {
219 		}
220 
221 		@Override
222 		public void partOpened(IWorkbenchPart part) {
223 		}
224 	};
225 
226 	private IPropertyChangeListener propertyChangeListener = event -> {
227 		String property = event.getProperty();
228 		Object newValue = event.getNewValue();
229 		Object oldValue = event.getOldValue();
230 
231 		if (IWorkingSetManager.CHANGE_WORKING_SET_REMOVE.equals(property) && oldValue == workingSet) {
232 			setWorkingSet(null);
233 		} else if (IWorkingSetManager.CHANGE_WORKING_SET_NAME_CHANGE.equals(property) && newValue == workingSet) {
234 			updateTitle();
235 		} else if (IWorkingSetManager.CHANGE_WORKING_SET_CONTENT_CHANGE.equals(property) && newValue == workingSet) {
236 			if (workingSet.isAggregateWorkingSet() && workingSet.isEmpty()) {
237 				// act as if the working set has been made null
238 				if (!emptyWorkingSet) {
239 					emptyWorkingSet = true;
240 					workingSetFilter.setWorkingSet(null);
241 				}
242 			} else {
243 				// we've gone from empty to non-empty on our set.
244 				// Restore it.
245 				if (emptyWorkingSet) {
246 					emptyWorkingSet = false;
247 					workingSetFilter.setWorkingSet(workingSet);
248 				}
249 			}
250 			getViewer().refresh();
251 		}
252 	};
253 
254 	private CollapseAllHandler collapseAllHandler;
255 
256 	/**
257 	 * Helper to open and activate editors.
258 	 *
259 	 * @since 3.5
260 	 */
261 	private OpenAndLinkWithEditorHelper openAndLinkWithEditorHelper;
262 
263 	/**
264 	 * Constructs a new resource navigator view.
265 	 */
ResourceNavigator()266 	public ResourceNavigator() {
267 		IDialogSettings viewsSettings = getPlugin().getDialogSettings();
268 
269 		settings = viewsSettings.getSection(STORE_SECTION);
270 		if (settings == null) {
271 			settings = viewsSettings.addNewSection(STORE_SECTION);
272 		}
273 
274 		initLinkingEnabled();
275 	}
276 
277 	/**
278 	 * Converts the given selection into a form usable by the viewer, where the
279 	 * elements are resources.
280 	 */
convertSelection(ISelection selection)281 	private StructuredSelection convertSelection(ISelection selection) {
282 		ArrayList<IResource> list = new ArrayList<>();
283 		if (selection instanceof IStructuredSelection) {
284 			IStructuredSelection ssel = (IStructuredSelection) selection;
285 			for (Object o : ssel) {
286 				IResource resource = Adapters.adapt(o, IResource.class);
287 				if (resource != null) {
288 					list.add(resource);
289 				}
290 			}
291 		}
292 		return new StructuredSelection(list);
293 	}
294 
295 	@Override
createPartControl(Composite parent)296 	public void createPartControl(Composite parent) {
297 		emptyWorkspaceHelper = new EmptyWorkspaceHelper();
298 		Composite displayArea = emptyWorkspaceHelper.getComposite(parent);
299 
300 		TreeViewer viewer = createViewer(displayArea);
301 		this.viewer = viewer;
302 
303 		emptyWorkspaceHelper.setNonEmptyControl(viewer.getControl());
304 
305 		if (memento != null) {
306 			restoreFilters();
307 			restoreLinkingEnabled();
308 		}
309 		frameList = createFrameList();
310 		initDragAndDrop();
311 		updateTitle();
312 
313 		initContextMenu();
314 
315 		initResourceComparator();
316 		initWorkingSetFilter();
317 
318 		// make sure input is set after sorters and filters,
319 		// to avoid unnecessary refreshes
320 		viewer.setInput(getInitialInput());
321 
322 		// make actions after setting input, because some actions
323 		// look at the viewer for enablement (e.g. the Up action)
324 		makeActions();
325 
326 		// Fill the action bars and update the global action handlers'
327 		// enabled state to match the current selection.
328 		getActionGroup().fillActionBars(getViewSite().getActionBars());
329 		updateActionBars(viewer.getStructuredSelection());
330 
331 		getSite().setSelectionProvider(viewer);
332 		getSite().getPage().addPartListener(partListener);
333 		IWorkingSetManager workingSetManager =  PlatformUI.getWorkbench().getWorkingSetManager();
334 		workingSetManager.addPropertyChangeListener(propertyChangeListener);
335 
336 		if (memento != null) {
337 			restoreState(memento);
338 		}
339 		memento = null;
340 
341 		// Set help for the view
342 		getSite().getWorkbenchWindow().getWorkbench().getHelpSystem().setHelp(viewer.getControl(), getHelpContextId());
343 	}
344 
345 	/**
346 	 * Returns the help context id to use for this view.
347 	 *
348 	 * @since 2.0
349 	 */
getHelpContextId()350 	protected String getHelpContextId() {
351 		return INavigatorHelpContextIds.RESOURCE_VIEW;
352 	}
353 
354 	/**
355 	 * Initializes and registers the context menu.
356 	 *
357 	 * @since 2.0
358 	 */
initContextMenu()359 	protected void initContextMenu() {
360 		MenuManager menuMgr = new MenuManager("#PopupMenu"); //$NON-NLS-1$
361 		menuMgr.setRemoveAllWhenShown(true);
362 		menuMgr.addMenuListener(manager -> ResourceNavigator.this.fillContextMenu(manager));
363 		TreeViewer viewer = getTreeViewer();
364 		Menu menu = menuMgr.createContextMenu(viewer.getTree());
365 		viewer.getTree().setMenu(menu);
366 		getSite().registerContextMenu(menuMgr, viewer);
367 	}
368 
369 	/**
370 	 * Creates the viewer.
371 	 *
372 	 * @param parent the parent composite
373 	 * @since 2.0
374 	 */
createViewer(Composite parent)375 	protected TreeViewer createViewer(Composite parent) {
376 		TreeViewer viewer = new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
377 		viewer.setUseHashlookup(true);
378 		initContentProvider(viewer);
379 		initLabelProvider(viewer);
380 		initFilters(viewer);
381 		initListeners(viewer);
382 
383 		return viewer;
384 	}
385 
386 	/**
387 	 * Sets the content provider for the viewer.
388 	 *
389 	 * @param viewer the viewer
390 	 * @since 2.0
391 	 */
initContentProvider(TreeViewer viewer)392 	protected void initContentProvider(TreeViewer viewer) {
393 		viewer.setContentProvider(new WorkbenchContentProvider());
394 	}
395 
396 	/**
397 	 * Sets the label provider for the viewer.
398 	 *
399 	 * @param viewer the viewer
400 	 * @since 2.0
401 	 */
initLabelProvider(TreeViewer viewer)402 	protected void initLabelProvider(TreeViewer viewer) {
403 		viewer.setLabelProvider(new DecoratingLabelProvider(new WorkbenchLabelProvider(),
404 				PlatformUI.getWorkbench().getDecoratorManager().getLabelDecorator()));
405 	}
406 
407 	/**
408 	 * Adds the filters to the viewer.
409 	 *
410 	 * @param viewer the viewer
411 	 * @since 2.0
412 	 */
initFilters(TreeViewer viewer)413 	protected void initFilters(TreeViewer viewer) {
414 		viewer.addFilter(patternFilter);
415 		viewer.addFilter(workingSetFilter);
416 	}
417 
418 	/**
419 	 * Initializes the linking enabled setting from the preference store.
420 	 */
initLinkingEnabled()421 	private void initLinkingEnabled() {
422 		// Try the dialog settings first, which remember the last choice.
423 		String setting = settings.get(IWorkbenchPreferenceConstants.LINK_NAVIGATOR_TO_EDITOR);
424 		if (setting != null) {
425 			linkingEnabled = setting.equals("true"); //$NON-NLS-1$
426 			return;
427 		}
428 		// If not in the dialog settings, check the preference store for the default
429 		// setting.
430 		// Use the UI plugin's preference store since this is a public preference.
431 		linkingEnabled = PlatformUI.getPreferenceStore()
432 				.getBoolean(IWorkbenchPreferenceConstants.LINK_NAVIGATOR_TO_EDITOR);
433 	}
434 
435 	/**
436 	 * Adds the listeners to the viewer.
437 	 *
438 	 * @param viewer the viewer
439 	 * @since 2.0
440 	 */
initListeners(final TreeViewer viewer)441 	protected void initListeners(final TreeViewer viewer) {
442 		viewer.addSelectionChangedListener(event -> handleSelectionChanged(event));
443 		viewer.addDoubleClickListener(event -> handleDoubleClick(event));
444 
445 		openAndLinkWithEditorHelper = new OpenAndLinkWithEditorHelper(viewer) {
446 			@Override
447 			protected void activate(ISelection selection) {
448 				Object selectedElement = getSingleElement(selection);
449 				if (selectedElement instanceof IFile) {
450 					IEditorInput input = new FileEditorInput((IFile) selectedElement);
451 					final IWorkbenchPage page = getSite().getPage();
452 					IEditorPart editor = page.findEditor(input);
453 					if (editor != null) {
454 						page.activate(editor);
455 					}
456 				}
457 
458 			}
459 
460 			@Override
461 			protected void linkToEditor(ISelection selection) {
462 				if (!linkScheduled) {
463 					// Ensure that if another selection change arrives while we're waiting for the
464 					// *syncExec,
465 					// we only do this work once.
466 					linkScheduled = true;
467 					getSite().getShell().getDisplay().asyncExec(() -> {
468 						// There's no telling what might have changed since the syncExec was scheduled.
469 						// Check to make sure that the widgets haven't been disposed.
470 						linkScheduled = false;
471 
472 						if (viewer == null || viewer.getControl() == null || viewer.getControl().isDisposed()) {
473 							return;
474 						}
475 
476 						if (dragDetected == false) {
477 							// only synchronize with editor when the selection is not the result
478 							// of a drag. Fixes bug 22274.
479 							ResourceNavigator.this.linkToEditor(viewer.getSelection());
480 						}
481 					});
482 				}
483 			}
484 
485 			@Override
486 			protected void open(ISelection selection, boolean activate) {
487 				handleOpen(selection);
488 			}
489 
490 		};
491 
492 		viewer.getControl().addKeyListener(new KeyListener() {
493 			@Override
494 			public void keyPressed(KeyEvent event) {
495 				handleKeyPressed(event);
496 			}
497 
498 			@Override
499 			public void keyReleased(KeyEvent event) {
500 				handleKeyReleased(event);
501 			}
502 		});
503 
504 		openAndLinkWithEditorHelper.setLinkWithEditor(linkingEnabled);
505 	}
506 
507 	@Override
dispose()508 	public void dispose() {
509 		getSite().getPage().removePartListener(partListener);
510 
511 		IWorkingSetManager workingSetManager = PlatformUI.getWorkbench().getWorkingSetManager();
512 		workingSetManager.removePropertyChangeListener(propertyChangeListener);
513 
514 		if (collapseAllHandler != null) {
515 			collapseAllHandler.dispose();
516 		}
517 
518 		if (getActionGroup() != null) {
519 			getActionGroup().dispose();
520 		}
521 		Control control = viewer.getControl();
522 		if (dragDetectListener != null && control != null && control.isDisposed() == false) {
523 			control.removeListener(SWT.DragDetect, dragDetectListener);
524 		}
525 
526 		super.dispose();
527 	}
528 
529 	/**
530 	 * An editor has been activated. Sets the selection in this navigator to be the
531 	 * editor's input, if linking is enabled.
532 	 *
533 	 * @param editor the active editor
534 	 * @since 2.0
535 	 */
editorActivated(IEditorPart editor)536 	protected void editorActivated(IEditorPart editor) {
537 		if (!isLinkingEnabled()) {
538 			return;
539 		}
540 
541 		IFile file = ResourceUtil.getFile(editor.getEditorInput());
542 		if (file != null) {
543 			ISelection newSelection = new StructuredSelection(file);
544 			if (getTreeViewer().getStructuredSelection().equals(newSelection)) {
545 				getTreeViewer().getTree().showSelection();
546 			} else {
547 				getTreeViewer().setSelection(newSelection, true);
548 			}
549 		}
550 	}
551 
552 	/**
553 	 * Called when the context menu is about to open. Delegates to the action group
554 	 * using the viewer's selection as the action context.
555 	 *
556 	 * @since 2.0
557 	 */
fillContextMenu(IMenuManager menu)558 	protected void fillContextMenu(IMenuManager menu) {
559 		IStructuredSelection selection = getViewer().getStructuredSelection();
560 		getActionGroup().setContext(new ActionContext(selection));
561 		getActionGroup().fillContextMenu(menu);
562 	}
563 
564 	@Override
getFrameList()565 	public FrameList getFrameList() {
566 		return frameList;
567 	}
568 
569 	/**
570 	 * Returns the initial input for the viewer. Tries to convert the page input to
571 	 * a resource, either directly or via IAdaptable. If the resource is a
572 	 * container, it uses that. If the resource is a file, it uses its parent
573 	 * folder. If a resource could not be obtained, it uses the workspace root.
574 	 *
575 	 * @since 2.0
576 	 */
getInitialInput()577 	protected IAdaptable getInitialInput() {
578 		IResource resource = Adapters.adapt(getSite().getPage().getInput(), IResource.class);
579 		if (resource != null) {
580 			switch (resource.getType()) {
581 			case IResource.FILE:
582 				return resource.getParent();
583 			case IResource.FOLDER:
584 			case IResource.PROJECT:
585 			case IResource.ROOT:
586 				return resource;
587 			default:
588 				// Unknown resource type. Fall through.
589 				break;
590 			}
591 		}
592 		return ResourcesPlugin.getWorkspace().getRoot();
593 	}
594 
595 	/**
596 	 * Returns the pattern filter for this view.
597 	 *
598 	 * @return the pattern filter
599 	 * @since 2.0
600 	 */
601 	@Override
getPatternFilter()602 	public ResourcePatternFilter getPatternFilter() {
603 		return this.patternFilter;
604 	}
605 
606 	/**
607 	 * Returns the working set for this view.
608 	 *
609 	 * @return the working set
610 	 * @since 2.0
611 	 */
612 	@Override
getWorkingSet()613 	public IWorkingSet getWorkingSet() {
614 		return workingSetFilter.getWorkingSet();
615 	}
616 
617 	/**
618 	 * Returns the navigator's plugin.
619 	 *
620 	 * @return the UI plugin for this bundle
621 	 */
getPlugin()622 	public AbstractUIPlugin getPlugin() {
623 		return IDEWorkbenchPlugin.getDefault();
624 	}
625 
626 	/**
627 	 * Return the sorter. If a comparator was set using
628 	 * {@link #setComparator(ResourceComparator)}, this method will return
629 	 * <code>null</code>.
630 	 *
631 	 * @since 2.0
632 	 * @deprecated as of 3.3, use {@link ResourceNavigator#getComparator()}
633 	 */
634 	@Deprecated
635 	@Override
getSorter()636 	public ResourceSorter getSorter() {
637 		ViewerSorter sorter = getTreeViewer().getSorter();
638 		if (sorter instanceof ResourceSorter) {
639 			return (ResourceSorter) sorter;
640 		}
641 		return null;
642 	}
643 
644 	/**
645 	 * Returns the comparator. If a sorter was set using
646 	 * {@link #setSorter(ResourceSorter)}, this method will return
647 	 * <code>null</code>.
648 	 *
649 	 * @return the <code>ResourceComparator</code>
650 	 * @since 3.3
651 	 */
652 
653 	@Override
getComparator()654 	public ResourceComparator getComparator() {
655 		ViewerComparator comparator = getTreeViewer().getComparator();
656 		if (comparator instanceof ResourceComparator) {
657 			return (ResourceComparator) comparator;
658 		}
659 		return null;
660 	}
661 
662 	/**
663 	 * Returns the resource viewer which shows the resource hierarchy.
664 	 *
665 	 * @since 2.0
666 	 */
667 	@Override
getViewer()668 	public TreeViewer getViewer() {
669 		return viewer;
670 	}
671 
672 	/**
673 	 * Returns the tree viewer which shows the resource hierarchy.
674 	 *
675 	 * @return the tree viewer
676 	 * @since 2.0
677 	 */
getTreeViewer()678 	public TreeViewer getTreeViewer() {
679 		return viewer;
680 	}
681 
682 	/**
683 	 * Returns the shell to use for opening dialogs. Used in this class, and in the
684 	 * actions.
685 	 *
686 	 * @return the shell
687 	 * @deprecated use getViewSite().getShell()
688 	 */
689 	@Deprecated
getShell()690 	public Shell getShell() {
691 		return getViewSite().getShell();
692 	}
693 
694 	/**
695 	 * Returns the message to show in the status line.
696 	 *
697 	 * @param selection the current selection
698 	 * @return the status line message
699 	 * @since 2.0
700 	 */
getStatusLineMessage(IStructuredSelection selection)701 	protected String getStatusLineMessage(IStructuredSelection selection) {
702 		if (selection.size() == 1) {
703 			Object o = selection.getFirstElement();
704 			if (o instanceof IResource) {
705 				return ((IResource) o).getFullPath().makeRelative().toString();
706 			}
707 			return ResourceNavigatorMessages.ResourceNavigator_oneItemSelected;
708 		}
709 		if (selection.size() > 1) {
710 			return NLS.bind(ResourceNavigatorMessages.ResourceNavigator_statusLine, String.valueOf(selection.size()));
711 		}
712 		return ""; //$NON-NLS-1$
713 	}
714 
715 	/**
716 	 * Returns the name for the given element. Used as the name for the current
717 	 * frame.
718 	 */
getFrameName(Object element)719 	String getFrameName(Object element) {
720 		if (element instanceof IResource) {
721 			return ((IResource) element).getName();
722 		}
723 		String text = ((ILabelProvider) getTreeViewer().getLabelProvider()).getText(element);
724 		if (text == null) {
725 			return "";//$NON-NLS-1$
726 		}
727 		return text;
728 	}
729 
730 	/**
731 	 * Returns the tool tip text for the given element. Used as the tool tip text
732 	 * for the current frame, and for the view title tooltip.
733 	 */
getFrameToolTipText(Object element)734 	String getFrameToolTipText(Object element) {
735 		if (element instanceof IResource) {
736 			IPath path = ((IResource) element).getFullPath();
737 			if (path.isRoot()) {
738 				return ResourceNavigatorMessages.ResourceManager_toolTip;
739 			}
740 			return path.makeRelative().toString();
741 		}
742 
743 		String text = ((ILabelProvider) getTreeViewer().getLabelProvider()).getText(element);
744 		if (text == null) {
745 			return "";//$NON-NLS-1$
746 		}
747 		return text;
748 	}
749 
750 	/**
751 	 * Handles an open event from the viewer. Opens an editor on the selected file.
752 	 *
753 	 * @param event the open event
754 	 * @since 2.0
755 	 * @deprecated As of 3.5, replaced by {@link #handleOpen(ISelection)}
756 	 */
757 	@Deprecated
handleOpen(OpenEvent event)758 	protected void handleOpen(OpenEvent event) {
759 		handleOpen(event.getSelection());
760 	}
761 
762 	/**
763 	 * Handles an open event from the viewer. Opens an editor on the selected file.
764 	 *
765 	 * @param selection the selection
766 	 * @since 3.5
767 	 */
handleOpen(ISelection selection)768 	protected void handleOpen(ISelection selection) {
769 		if (selection instanceof IStructuredSelection) {
770 			getActionGroup().runDefaultAction((IStructuredSelection) selection);
771 		}
772 	}
773 
774 	/**
775 	 * Handles a double-click event from the viewer. Expands or collapses a folder
776 	 * when double-clicked.
777 	 *
778 	 * @param event the double-click event
779 	 * @since 2.0
780 	 */
handleDoubleClick(DoubleClickEvent event)781 	protected void handleDoubleClick(DoubleClickEvent event) {
782 		IStructuredSelection selection = (IStructuredSelection) event.getSelection();
783 		Object element = selection.getFirstElement();
784 
785 		// 1GBZIA0: ITPUI:WIN2000 - Double-clicking in navigator should expand/collapse
786 		// containers
787 		TreeViewer viewer = getTreeViewer();
788 		if (viewer.isExpandable(element)) {
789 			viewer.setExpandedState(element, !viewer.getExpandedState(element));
790 		} else if (selection.size() == 1 && (element instanceof IResource)
791 				&& ((IResource) element).getType() == IResource.PROJECT) {
792 			OpenResourceAction ora = new OpenResourceAction(getSite());
793 			ora.selectionChanged((IStructuredSelection) viewer.getSelection());
794 			if (ora.isEnabled()) {
795 				ora.run();
796 			}
797 		}
798 
799 	}
800 
801 	/**
802 	 * Handles a selection changed event from the viewer. Updates the status line
803 	 * and the action bars, and links to editor (if option enabled).
804 	 *
805 	 * @param event the selection event
806 	 * @since 2.0
807 	 */
handleSelectionChanged(SelectionChangedEvent event)808 	protected void handleSelectionChanged(SelectionChangedEvent event) {
809 		final IStructuredSelection sel = event.getStructuredSelection();
810 		updateStatusLine(sel);
811 		updateActionBars(sel);
812 		dragDetected = false;
813 	}
814 
815 	/**
816 	 * Handles a key press event from the viewer. Delegates to the action group.
817 	 *
818 	 * @param event the key event
819 	 * @since 2.0
820 	 */
handleKeyPressed(KeyEvent event)821 	protected void handleKeyPressed(KeyEvent event) {
822 		getActionGroup().handleKeyPressed(event);
823 	}
824 
825 	/**
826 	 * Handles a key release in the viewer. Does nothing by default.
827 	 *
828 	 * @param event the key event
829 	 * @since 2.0
830 	 */
handleKeyReleased(KeyEvent event)831 	protected void handleKeyReleased(KeyEvent event) {
832 	}
833 
834 	@Override
init(IViewSite site, IMemento memento)835 	public void init(IViewSite site, IMemento memento) throws PartInitException {
836 		super.init(site, memento);
837 		this.memento = memento;
838 	}
839 
840 	/**
841 	 * Adds drag and drop support to the navigator.
842 	 *
843 	 * @since 2.0
844 	 */
initDragAndDrop()845 	protected void initDragAndDrop() {
846 		int ops = DND.DROP_COPY | DND.DROP_MOVE | DND.DROP_LINK;
847 		Transfer[] transfers = new Transfer[] { LocalSelectionTransfer.getInstance(), ResourceTransfer.getInstance(),
848 				FileTransfer.getInstance(), PluginTransfer.getInstance() };
849 		TreeViewer viewer = getTreeViewer();
850 		viewer.addDragSupport(ops, transfers, new NavigatorDragAdapter(viewer));
851 		NavigatorDropAdapter adapter = new NavigatorDropAdapter(viewer);
852 		adapter.setFeedbackEnabled(false);
853 		viewer.addDropSupport(ops | DND.DROP_DEFAULT, transfers, adapter);
854 		dragDetectListener = event -> dragDetected = true;
855 		viewer.getControl().addListener(SWT.DragDetect, dragDetectListener);
856 	}
857 
858 	/**
859 	 * Creates the frame source and frame list, and connects them.
860 	 *
861 	 * @since 2.0
862 	 */
createFrameList()863 	protected FrameList createFrameList() {
864 		NavigatorFrameSource frameSource = new NavigatorFrameSource(this);
865 		FrameList frameList = new FrameList(frameSource);
866 		frameSource.connectTo(frameList);
867 		return frameList;
868 	}
869 
870 	/**
871 	 * Initializes the sorter.
872 	 *
873 	 * @deprecated as of 3.3, use {@link ResourceNavigator#initResourceComparator()}
874 	 *             instead
875 	 */
876 	@Deprecated
initResourceSorter()877 	protected void initResourceSorter() {
878 		int sortType = ResourceSorter.NAME;
879 		try {
880 			int sortInt = 0;
881 			if (memento != null) {
882 				String sortStr = memento.getString(TAG_SORTER);
883 				if (sortStr != null) {
884 					sortInt = Integer.parseInt(sortStr);
885 				}
886 			} else {
887 				sortInt = settings.getInt(STORE_SORT_TYPE);
888 			}
889 			if (sortInt == ResourceSorter.NAME || sortInt == ResourceSorter.TYPE) {
890 				sortType = sortInt;
891 			}
892 		} catch (NumberFormatException e) {
893 		}
894 		setSorter(new ResourceSorter(sortType));
895 	}
896 
897 	/**
898 	 * Initializes the comparator.
899 	 *
900 	 * @since 3.3
901 	 */
initResourceComparator()902 	protected void initResourceComparator() {
903 		int sortType = ResourceComparator.NAME;
904 		try {
905 			int sortInt = 0;
906 			if (memento != null) {
907 				String sortStr = memento.getString(TAG_SORTER);
908 				if (sortStr != null) {
909 					sortInt = Integer.parseInt(sortStr);
910 				}
911 			} else {
912 				sortInt = settings.getInt(STORE_SORT_TYPE);
913 			}
914 			if (sortInt == ResourceComparator.NAME || sortInt == ResourceComparator.TYPE) {
915 				sortType = sortInt;
916 			}
917 		} catch (NumberFormatException e) {
918 		}
919 		setComparator(new ResourceComparator(sortType));
920 	}
921 
922 	/**
923 	 * Restores the working set filter from the persistence store.
924 	 */
initWorkingSetFilter()925 	protected void initWorkingSetFilter() {
926 		String workingSetName = settings.get(STORE_WORKING_SET);
927 
928 		IWorkingSet workingSet = null;
929 
930 		if (workingSetName != null && workingSetName.isEmpty() == false) {
931 			IWorkingSetManager workingSetManager = PlatformUI.getWorkbench().getWorkingSetManager();
932 			workingSet = workingSetManager.getWorkingSet(workingSetName);
933 		} else if (PlatformUI.getPreferenceStore()
934 				.getBoolean(IWorkbenchPreferenceConstants.USE_WINDOW_WORKING_SET_BY_DEFAULT)) {
935 			// use the window set by default if the global preference is set
936 			workingSet = getSite().getPage().getAggregateWorkingSet();
937 		}
938 
939 		if (workingSet != null) {
940 			// Only initialize filter. Don't set working set into viewer.
941 			// Working set is set via WorkingSetFilterActionGroup
942 			// during action creation.
943 			workingSetFilter.setWorkingSet(workingSet);
944 			internalSetWorkingSet(workingSet);
945 		}
946 	}
947 
948 	/**
949 	 * Returns whether the navigator selection automatically tracks the active
950 	 * editor.
951 	 *
952 	 * @return <code>true</code> if linking is enabled, <code>false</code> if not
953 	 * @since 2.0 (this was protected in 2.0, but was made public in 2.1)
954 	 */
955 	@Override
isLinkingEnabled()956 	public boolean isLinkingEnabled() {
957 		return linkingEnabled;
958 	}
959 
960 	/**
961 	 * Brings the corresponding editor to top if the selected resource is open.
962 	 *
963 	 * @since 2.0
964 	 * @deprecated As of 3.5, replaced by {@link #linkToEditor(ISelection)}
965 	 */
966 	@Deprecated
linkToEditor(IStructuredSelection selection)967 	protected void linkToEditor(IStructuredSelection selection) {
968 		linkToEditor((ISelection) selection);
969 	}
970 
971 	/**
972 	 * Brings the corresponding editor to top if the selected resource is open.
973 	 *
974 	 * @since 3.5
975 	 */
linkToEditor(ISelection selection)976 	protected void linkToEditor(ISelection selection) {
977 
978 		if (this != this.getSite().getPage().getActivePart())
979 			return;
980 
981 		Object obj = getSingleElement(selection);
982 		if (obj instanceof IFile) {
983 			IFile file = (IFile) obj;
984 			IWorkbenchPage page = getSite().getPage();
985 			IEditorPart editor = ResourceUtil.findEditor(page, file);
986 			if (editor != null) {
987 				page.bringToTop(editor);
988 				return;
989 			}
990 		}
991 	}
992 
993 	/**
994 	 * Creates the action group, which encapsulates all actions for the view.
995 	 */
makeActions()996 	protected void makeActions() {
997 		MainActionGroup group = new MainActionGroup(this);
998 		setActionGroup(group);
999 
1000 		IHandlerService service = getSite().getService(IHandlerService.class);
1001 		service.activateHandler(IWorkbenchCommandConstants.NAVIGATE_TOGGLE_LINK_WITH_EDITOR,
1002 				new ActionHandler(group.toggleLinkingAction));
1003 		collapseAllHandler = new CollapseAllHandler(viewer);
1004 		service.activateHandler(CollapseAllHandler.COMMAND_ID, collapseAllHandler);
1005 	}
1006 
1007 	/**
1008 	 * Restores the saved filter settings.
1009 	 */
restoreFilters()1010 	private void restoreFilters() {
1011 		IMemento filtersMem = memento.getChild(TAG_FILTERS);
1012 
1013 		if (filtersMem != null) { // filters have been defined
1014 			IMemento children[] = filtersMem.getChildren(TAG_FILTER);
1015 
1016 			// check if first element has new tag defined, indicates new version
1017 			if (children.length > 0 && children[0].getString(TAG_IS_ENABLED) != null) {
1018 				ArrayList<String> selectedFilters = new ArrayList<>();
1019 				ArrayList unSelectedFilters = new ArrayList();
1020 				for (IMemento memento : children) {
1021 					if (memento.getString(TAG_IS_ENABLED).equals(String.valueOf(true))) {
1022 						selectedFilters.add(memento.getString(TAG_ELEMENT));
1023 					} else {
1024 						// enabled == false
1025 						unSelectedFilters.add(memento.getString(TAG_ELEMENT));
1026 					}
1027 				}
1028 
1029 				/*
1030 				 * merge filters from Memento with selected = true filters from plugins ensure
1031 				 * there are no duplicates & don't override user preferences
1032 				 */
1033 				List pluginFilters = FiltersContentProvider.getDefaultFilters();
1034 				for (Iterator iter = pluginFilters.iterator(); iter.hasNext();) {
1035 					String element = (String) iter.next();
1036 					if (!selectedFilters.contains(element) && !unSelectedFilters.contains(element)) {
1037 						selectedFilters.add(element);
1038 					}
1039 				}
1040 
1041 				// Convert to an array of Strings
1042 				String[] patternArray = new String[selectedFilters.size()];
1043 				selectedFilters.toArray(patternArray);
1044 				getPatternFilter().setPatterns(patternArray);
1045 
1046 			} else { // filters defined, old version: ignore filters from plugins
1047 				String filters[] = new String[children.length];
1048 				for (int i = 0; i < children.length; i++) {
1049 					filters[i] = children[i].getString(TAG_ELEMENT);
1050 				}
1051 				getPatternFilter().setPatterns(filters);
1052 			}
1053 		} else { // no filters defined, old version: ignore filters from plugins
1054 			getPatternFilter().setPatterns(new String[0]);
1055 		}
1056 	}
1057 
1058 	/**
1059 	 * Restores the state of the receiver to the state described in the specified
1060 	 * memento.
1061 	 *
1062 	 * @param memento the memento
1063 	 * @since 2.0
1064 	 */
restoreState(IMemento memento)1065 	protected void restoreState(IMemento memento) {
1066 		TreeViewer viewer = getTreeViewer();
1067 		IMemento frameMemento = memento.getChild(TAG_CURRENT_FRAME);
1068 
1069 		if (frameMemento != null) {
1070 			TreeFrame frame = new TreeFrame(viewer);
1071 			frame.restoreState(frameMemento);
1072 			frame.setName(getFrameName(frame.getInput()));
1073 			frame.setToolTipText(getFrameToolTipText(frame.getInput()));
1074 			viewer.setSelection(new StructuredSelection(frame.getInput()));
1075 			frameList.gotoFrame(frame);
1076 		} else {
1077 			IContainer container = ResourcesPlugin.getWorkspace().getRoot();
1078 			IMemento childMem = memento.getChild(TAG_EXPANDED);
1079 			if (childMem != null) {
1080 				ArrayList elements = new ArrayList();
1081 				for (IMemento mem : childMem.getChildren(TAG_ELEMENT)) {
1082 					Object element = container.findMember(mem.getString(TAG_PATH));
1083 					if (element != null) {
1084 						elements.add(element);
1085 					}
1086 				}
1087 				viewer.setExpandedElements(elements.toArray());
1088 			}
1089 			childMem = memento.getChild(TAG_SELECTION);
1090 			if (childMem != null) {
1091 				ArrayList list = new ArrayList();
1092 				for (IMemento mem : childMem.getChildren(TAG_ELEMENT)) {
1093 					Object element = container.findMember(mem.getString(TAG_PATH));
1094 					if (element != null) {
1095 						list.add(element);
1096 					}
1097 				}
1098 				viewer.setSelection(new StructuredSelection(list));
1099 			}
1100 		}
1101 	}
1102 
1103 	/**
1104 	 * Restores the linking enabled state.
1105 	 */
restoreLinkingEnabled()1106 	private void restoreLinkingEnabled() {
1107 		Integer val = memento.getInteger(IWorkbenchPreferenceConstants.LINK_NAVIGATOR_TO_EDITOR);
1108 		if (val != null) {
1109 			linkingEnabled = val.intValue() != 0;
1110 		}
1111 	}
1112 
1113 	/**
1114 	 * @see ViewPart#saveState
1115 	 */
1116 	@Override
saveState(IMemento memento)1117 	public void saveState(IMemento memento) {
1118 		TreeViewer viewer = getTreeViewer();
1119 		if (viewer == null) {
1120 			if (this.memento != null) {
1121 				memento.putMemento(this.memento);
1122 			}
1123 			return;
1124 		}
1125 
1126 		// save sorter
1127 		if (getComparator() != null) {
1128 			memento.putInteger(TAG_SORTER, getComparator().getCriteria());
1129 		} else if (getSorter() != null) {
1130 			memento.putInteger(TAG_SORTER, getSorter().getCriteria());
1131 		}
1132 
1133 		// save filters
1134 		String filters[] = getPatternFilter().getPatterns();
1135 		List selectedFilters = Arrays.asList(filters);
1136 		List allFilters = FiltersContentProvider.getDefinedFilters();
1137 		IMemento filtersMem = memento.createChild(TAG_FILTERS);
1138 		for (Iterator iter = allFilters.iterator(); iter.hasNext();) {
1139 			String element = (String) iter.next();
1140 			IMemento child = filtersMem.createChild(TAG_FILTER);
1141 			child.putString(TAG_ELEMENT, element);
1142 			child.putString(TAG_IS_ENABLED, String.valueOf(selectedFilters.contains(element)));
1143 		}
1144 
1145 		if (frameList.getCurrentIndex() > 0) {
1146 			// save frame, it's not the "home"/workspace frame
1147 			TreeFrame currentFrame = (TreeFrame) frameList.getCurrentFrame();
1148 			IMemento frameMemento = memento.createChild(TAG_CURRENT_FRAME);
1149 			currentFrame.saveState(frameMemento);
1150 		} else {
1151 			// save visible expanded elements
1152 			Object expandedElements[] = viewer.getVisibleExpandedElements();
1153 			if (expandedElements.length > 0) {
1154 				IMemento expandedMem = memento.createChild(TAG_EXPANDED);
1155 				for (Object expandedElement : expandedElements) {
1156 					if (expandedElement instanceof IResource) {
1157 						IMemento elementMem = expandedMem.createChild(TAG_ELEMENT);
1158 						elementMem.putString(TAG_PATH, ((IResource) expandedElement).getFullPath().toString());
1159 					}
1160 				}
1161 			}
1162 			// save selection
1163 			Object elements[] = viewer.getStructuredSelection().toArray();
1164 			if (elements.length > 0) {
1165 				IMemento selectionMem = memento.createChild(TAG_SELECTION);
1166 				for (Object selectionElement : elements) {
1167 					if (selectionElement instanceof IResource) {
1168 						IMemento elementMem = selectionMem.createChild(TAG_ELEMENT);
1169 						elementMem.putString(TAG_PATH, ((IResource) selectionElement).getFullPath().toString());
1170 					}
1171 				}
1172 			}
1173 		}
1174 
1175 		saveLinkingEnabled(memento);
1176 	}
1177 
1178 	/**
1179 	 * Saves the linking enabled state.
1180 	 */
saveLinkingEnabled(IMemento memento)1181 	private void saveLinkingEnabled(IMemento memento) {
1182 		memento.putInteger(IWorkbenchPreferenceConstants.LINK_NAVIGATOR_TO_EDITOR, linkingEnabled ? 1 : 0);
1183 	}
1184 
1185 	/**
1186 	 * Selects and reveals the specified elements.
1187 	 */
1188 	@Override
selectReveal(ISelection selection)1189 	public void selectReveal(ISelection selection) {
1190 		StructuredSelection ssel = convertSelection(selection);
1191 		if (!ssel.isEmpty()) {
1192 			getViewer().getControl().setRedraw(false);
1193 			getViewer().setSelection(ssel, true);
1194 			getViewer().getControl().setRedraw(true);
1195 		}
1196 	}
1197 
1198 	/**
1199 	 * Saves the filters defined as strings in <code>patterns</code> in the
1200 	 * preference store.
1201 	 */
1202 	@Override
setFiltersPreference(String[] patterns)1203 	public void setFiltersPreference(String[] patterns) {
1204 
1205 		StringBuilder sb = new StringBuilder();
1206 
1207 		for (int i = 0; i < patterns.length; i++) {
1208 			if (i != 0) {
1209 				sb.append(ResourcePatternFilter.COMMA_SEPARATOR);
1210 			}
1211 			sb.append(patterns[i]);
1212 		}
1213 
1214 		getPlugin().getPreferenceStore().setValue(ResourcePatternFilter.FILTERS_TAG, sb.toString());
1215 
1216 		// remove value in old workbench preference store location
1217 		IPreferenceStore preferenceStore = IDEWorkbenchPlugin.getDefault().getPreferenceStore();
1218 		String storedPatterns = preferenceStore.getString(ResourcePatternFilter.FILTERS_TAG);
1219 		if (storedPatterns.length() > 0) {
1220 			preferenceStore.setValue(ResourcePatternFilter.FILTERS_TAG, ""); //$NON-NLS-1$
1221 		}
1222 	}
1223 
1224 	/**
1225 	 * @see IWorkbenchPart#setFocus()
1226 	 */
1227 	@Override
setFocus()1228 	public void setFocus() {
1229 		getTreeViewer().getTree().setFocus();
1230 	}
1231 
1232 	/**
1233 	 * Note: For experimental use only. Sets the decorator for the navigator.
1234 	 * <p>
1235 	 * As of 2.0, this method no longer has any effect.
1236 	 * </p>
1237 	 *
1238 	 * @param decorator a label decorator or <code>null</code> for no decorations.
1239 	 * @deprecated use the decorators extension point instead; see
1240 	 *             IWorkbench.getDecoratorManager()
1241 	 */
1242 	@Deprecated
setLabelDecorator(ILabelDecorator decorator)1243 	public void setLabelDecorator(ILabelDecorator decorator) {
1244 		// do nothing
1245 	}
1246 
1247 	/**
1248 	 * @see IResourceNavigator#setLinkingEnabled(boolean)
1249 	 * @since 2.1
1250 	 */
1251 	@Override
setLinkingEnabled(boolean enabled)1252 	public void setLinkingEnabled(boolean enabled) {
1253 		this.linkingEnabled = enabled;
1254 
1255 		// remember the last setting in the dialog settings
1256 		settings.put(IWorkbenchPreferenceConstants.LINK_NAVIGATOR_TO_EDITOR, enabled);
1257 
1258 		// if turning linking on, update the selection to correspond to the active
1259 		// editor
1260 		if (enabled) {
1261 			IEditorPart editor = getSite().getPage().getActiveEditor();
1262 			if (editor != null) {
1263 				editorActivated(editor);
1264 			}
1265 		}
1266 		openAndLinkWithEditorHelper.setLinkWithEditor(enabled);
1267 	}
1268 
1269 	/**
1270 	 * Sets the resource sorter.
1271 	 *
1272 	 * @param sorter the resource sorter
1273 	 * @since 2.0
1274 	 * @deprecated as of 3.3, use
1275 	 *             {@link ResourceNavigator#setComparator(ResourceComparator)}
1276 	 */
1277 	@Deprecated
1278 	@Override
setSorter(ResourceSorter sorter)1279 	public void setSorter(ResourceSorter sorter) {
1280 		TreeViewer viewer = getTreeViewer();
1281 		ViewerSorter viewerSorter = viewer.getSorter();
1282 
1283 		viewer.getControl().setRedraw(false);
1284 		if (viewerSorter == sorter) {
1285 			viewer.refresh();
1286 		} else {
1287 			viewer.setSorter(sorter);
1288 		}
1289 		viewer.getControl().setRedraw(true);
1290 		settings.put(STORE_SORT_TYPE, sorter.getCriteria());
1291 
1292 		// update the sort actions' checked state
1293 		updateActionBars((IStructuredSelection) viewer.getSelection());
1294 	}
1295 
1296 	/**
1297 	 * Sets the resource comparator
1298 	 *
1299 	 * @param comparator the resource comparator
1300 	 * @since 3.3
1301 	 */
1302 	@Override
setComparator(ResourceComparator comparator)1303 	public void setComparator(ResourceComparator comparator) {
1304 		TreeViewer viewer = getTreeViewer();
1305 		ViewerComparator viewerComparator = viewer.getComparator();
1306 
1307 		viewer.getControl().setRedraw(false);
1308 		if (viewerComparator == comparator) {
1309 			viewer.refresh();
1310 		} else {
1311 			viewer.setComparator(comparator);
1312 		}
1313 		viewer.getControl().setRedraw(true);
1314 		settings.put(STORE_SORT_TYPE, comparator.getCriteria());
1315 
1316 		// update the sort actions' checked state
1317 		updateActionBars(viewer.getStructuredSelection());
1318 	}
1319 
1320 	@Override
setWorkingSet(IWorkingSet workingSet)1321 	public void setWorkingSet(IWorkingSet workingSet) {
1322 		TreeViewer treeViewer = getTreeViewer();
1323 		Object[] expanded = treeViewer.getExpandedElements();
1324 		IStructuredSelection structuredSelection = treeViewer.getStructuredSelection();
1325 
1326 		boolean refreshNeeded = internalSetWorkingSet(workingSet);
1327 
1328 		workingSetFilter.setWorkingSet(emptyWorkingSet ? null : workingSet);
1329 		if (workingSet != null) {
1330 			settings.put(STORE_WORKING_SET, workingSet.getName());
1331 		} else {
1332 			settings.put(STORE_WORKING_SET, ""); //$NON-NLS-1$
1333 		}
1334 		updateTitle();
1335 		if (refreshNeeded) {
1336 			treeViewer.refresh();
1337 		}
1338 		treeViewer.setExpandedElements(expanded);
1339 		if (structuredSelection.isEmpty() == false) {
1340 			treeViewer.reveal(structuredSelection.getFirstElement());
1341 		}
1342 	}
1343 
1344 	/**
1345 	 * Set the internal working set fields specific to the navigator.
1346 	 *
1347 	 * @param workingSet the new working set
1348 	 * @since 3.2
1349 	 */
internalSetWorkingSet(IWorkingSet workingSet)1350 	private boolean internalSetWorkingSet(IWorkingSet workingSet) {
1351 		boolean refreshNeeded = !Objects.equals(this.workingSet, workingSet);
1352 		this.workingSet = workingSet;
1353 		emptyWorkingSet = workingSet != null && workingSet.isAggregateWorkingSet() && workingSet.isEmpty();
1354 		return refreshNeeded;
1355 	}
1356 
1357 	/**
1358 	 * Updates the action bar actions.
1359 	 *
1360 	 * @param selection the current selection
1361 	 * @since 2.0
1362 	 */
updateActionBars(IStructuredSelection selection)1363 	protected void updateActionBars(IStructuredSelection selection) {
1364 		ResourceNavigatorActionGroup group = getActionGroup();
1365 		if (group != null) {
1366 			group.setContext(new ActionContext(selection));
1367 			group.updateActionBars();
1368 		}
1369 	}
1370 
1371 	/**
1372 	 * Updates the message shown in the status line.
1373 	 *
1374 	 * @param selection the current selection
1375 	 */
updateStatusLine(IStructuredSelection selection)1376 	protected void updateStatusLine(IStructuredSelection selection) {
1377 		String msg = getStatusLineMessage(selection);
1378 		getViewSite().getActionBars().getStatusLineManager().setMessage(msg);
1379 	}
1380 
1381 	/**
1382 	 * Updates the title text and title tool tip. Called whenever the input of the
1383 	 * viewer changes. Called whenever the input of the viewer changes.
1384 	 *
1385 	 * @since 2.0
1386 	 */
updateTitle()1387 	public void updateTitle() {
1388 		Object input = getViewer().getInput();
1389 		IWorkspace workspace = ResourcesPlugin.getWorkspace();
1390 		IWorkingSet workingSet = workingSetFilter.getWorkingSet();
1391 
1392 		if (input == null || input.equals(workspace) || input.equals(workspace.getRoot())) {
1393 			setContentDescription(""); //$NON-NLS-1$
1394 			if (workingSet != null) {
1395 				setTitleToolTip(
1396 						NLS.bind(ResourceNavigatorMessages.ResourceNavigator_workingSetToolTip, workingSet.getLabel()));
1397 			} else {
1398 				setTitleToolTip(""); //$NON-NLS-1$
1399 			}
1400 		} else {
1401 			ILabelProvider labelProvider = (ILabelProvider) getTreeViewer().getLabelProvider();
1402 			String inputToolTip = getFrameToolTipText(input);
1403 			String text = labelProvider.getText(input);
1404 			if (text != null) {
1405 				setContentDescription(text);
1406 			}
1407 			if (workingSet != null) {
1408 				setTitleToolTip(NLS.bind(ResourceNavigatorMessages.ResourceNavigator_workingSetInputToolTip,
1409 						inputToolTip, workingSet.getLabel()));
1410 			} else {
1411 				setTitleToolTip(inputToolTip);
1412 			}
1413 		}
1414 	}
1415 
1416 	/**
1417 	 * Returns the action group.
1418 	 *
1419 	 * @return the action group
1420 	 */
getActionGroup()1421 	protected ResourceNavigatorActionGroup getActionGroup() {
1422 		return actionGroup;
1423 	}
1424 
1425 	/**
1426 	 * Sets the action group.
1427 	 *
1428 	 * @param actionGroup the action group
1429 	 */
setActionGroup(ResourceNavigatorActionGroup actionGroup)1430 	protected void setActionGroup(ResourceNavigatorActionGroup actionGroup) {
1431 		this.actionGroup = actionGroup;
1432 	}
1433 
1434 	@Override
getAdapter(Class<T> adapter)1435 	public <T> T getAdapter(Class<T> adapter) {
1436 		if (adapter == IShowInSource.class) {
1437 			return adapter.cast(getShowInSource());
1438 		}
1439 		if (adapter == IShowInTarget.class) {
1440 			return adapter.cast(getShowInTarget());
1441 		}
1442 		return null;
1443 	}
1444 
1445 	/**
1446 	 * Returns the <code>IShowInSource</code> for this view.
1447 	 */
getShowInSource()1448 	protected IShowInSource getShowInSource() {
1449 		return () -> new ShowInContext(getViewer().getInput(), getViewer().getSelection());
1450 	}
1451 
1452 	/**
1453 	 * Returns the <code>IShowInTarget</code> for this view.
1454 	 */
getShowInTarget()1455 	protected IShowInTarget getShowInTarget() {
1456 		return context -> {
1457 			ArrayList<IResource> toSelect = new ArrayList<>();
1458 			ISelection sel = context.getSelection();
1459 			if (sel instanceof IStructuredSelection) {
1460 				IStructuredSelection ssel = (IStructuredSelection) sel;
1461 				for (Object o1 : ssel) {
1462 
1463 					IResource resource = Adapters.adapt(o1, IResource.class);
1464 					if (resource != null) {
1465 						toSelect.add(resource);
1466 					}
1467 
1468 					IMarker marker = Adapters.adapt(o1, IMarker.class);
1469 					if (marker != null) {
1470 						IResource r2 = marker.getResource();
1471 						if (r2.getType() != IResource.ROOT) {
1472 							toSelect.add(r2);
1473 						}
1474 					}
1475 				}
1476 			}
1477 			if (toSelect.isEmpty()) {
1478 				Object input = context.getInput();
1479 				IResource resource = Adapters.adapt(input, IResource.class);
1480 				if (resource != null) {
1481 					toSelect.add(resource);
1482 				}
1483 			}
1484 			if (!toSelect.isEmpty()) {
1485 				selectReveal(new StructuredSelection(toSelect));
1486 				return true;
1487 			}
1488 			return false;
1489 		};
1490 	}
1491 
1492 	/**
1493 	 * Returns the selected element if the selection consists of a single element
1494 	 * only.
1495 	 *
1496 	 * @param s the selection
1497 	 * @return the selected first element or null
1498 	 * @since 3.5
1499 	 */
getSingleElement(ISelection s)1500 	protected static final Object getSingleElement(ISelection s) {
1501 		if (!(s instanceof IStructuredSelection))
1502 			return null;
1503 
1504 		IStructuredSelection selection = (IStructuredSelection) s;
1505 		if (selection.size() != 1)
1506 			return null;
1507 
1508 		return selection.getFirstElement();
1509 	}
1510 
1511 }
1512