blob: 67d24e3626b08ab06314601539dd64b222761f14 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2018 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
* Benjamin Muskalla - bug 105041
* Remy Chi Jian Suen - bug 144102
* Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810
* Andrey Loskutov <loskutov@gmx.de> - generified interface, bug 461762
* Mickael Istria (Red Hat Inc.) - Bug 486901
*******************************************************************************/
package org.eclipse.ui.views.navigator;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.Adapters;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IPath;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.commands.ActionHandler;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.viewers.DecoratingLabelProvider;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.ILabelDecorator;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.OpenEvent;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.FileTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.IPartListener;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.IWorkbenchCommandConstants;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchPreferenceConstants;
import org.eclipse.ui.IWorkingSet;
import org.eclipse.ui.IWorkingSetManager;
import org.eclipse.ui.OpenAndLinkWithEditorHelper;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.ResourceWorkingSetFilter;
import org.eclipse.ui.actions.ActionContext;
import org.eclipse.ui.actions.OpenResourceAction;
import org.eclipse.ui.handlers.CollapseAllHandler;
import org.eclipse.ui.handlers.IHandlerService;
import org.eclipse.ui.ide.ResourceUtil;
import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
import org.eclipse.ui.internal.views.helpers.EmptyWorkspaceHelper;
import org.eclipse.ui.internal.views.navigator.ResourceNavigatorMessages;
import org.eclipse.ui.model.WorkbenchContentProvider;
import org.eclipse.ui.model.WorkbenchLabelProvider;
import org.eclipse.ui.part.FileEditorInput;
import org.eclipse.ui.part.ISetSelectionTarget;
import org.eclipse.ui.part.IShowInSource;
import org.eclipse.ui.part.IShowInTarget;
import org.eclipse.ui.part.PluginTransfer;
import org.eclipse.ui.part.ResourceTransfer;
import org.eclipse.ui.part.ShowInContext;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.eclipse.ui.views.framelist.FrameList;
import org.eclipse.ui.views.framelist.TreeFrame;
import org.osgi.framework.FrameworkUtil;
/**
* Implements the Resource Navigator view.
*
* @noextend This class is not intended to be subclassed by clients.
* @noinstantiate This class is not intended to be instantiated by clients.
* @noreference This class is not intended to be referenced by clients.
*
* Planned to be deleted, please see Bug
* https://bugs.eclipse.org/bugs/show_bug.cgi?id=549953
*
* @deprecated as of 3.5, use the Common Navigator Framework classes instead
*/
@Deprecated
public class ResourceNavigator extends ViewPart implements ISetSelectionTarget, IResourceNavigator {
private TreeViewer viewer;
private IDialogSettings settings;
private IMemento memento;
private FrameList frameList;
private ResourceNavigatorActionGroup actionGroup;
private ResourcePatternFilter patternFilter = new ResourcePatternFilter();
private ResourceWorkingSetFilter workingSetFilter = new ResourceWorkingSetFilter();
private boolean linkingEnabled;
private boolean dragDetected;
private Listener dragDetectListener;
/**
* Remembered working set.
*/
private IWorkingSet workingSet;
/**
* Marks whether the working set we're using is currently empty. In this event
* we're effectively not using a working set.
*/
private boolean emptyWorkingSet = false;
/**
* Settings constant for section name (value <code>ResourceNavigator</code>).
*/
private static final String STORE_SECTION = "ResourceNavigator"; //$NON-NLS-1$
/**
* Settings constant for sort order (value
* <code>ResourceViewer.STORE_SORT_TYPE</code>).
*/
private static final String STORE_SORT_TYPE = "ResourceViewer.STORE_SORT_TYPE"; //$NON-NLS-1$
/**
* Settings constant for working set (value
* <code>ResourceWorkingSetFilter.STORE_WORKING_SET</code>).
*/
private static final String STORE_WORKING_SET = "ResourceWorkingSetFilter.STORE_WORKING_SET"; //$NON-NLS-1$
/**
* @deprecated No longer used but preserved to avoid an api change.
*/
@Deprecated
public static final String NAVIGATOR_VIEW_HELP_ID = INavigatorHelpContextIds.RESOURCE_VIEW;
/**
* True iff we've already scheduled an asynchronous call to linkToEditor
*/
private boolean linkScheduled = false;
private EmptyWorkspaceHelper emptyWorkspaceHelper;
// Persistance tags.
private static final String TAG_SORTER = "sorter"; //$NON-NLS-1$
private static final String TAG_FILTERS = "filters"; //$NON-NLS-1$
private static final String TAG_FILTER = "filter"; //$NON-NLS-1$
private static final String TAG_SELECTION = "selection"; //$NON-NLS-1$
private static final String TAG_EXPANDED = "expanded"; //$NON-NLS-1$
private static final String TAG_ELEMENT = "element"; //$NON-NLS-1$
private static final String TAG_IS_ENABLED = "isEnabled"; //$NON-NLS-1$
private static final String TAG_PATH = "path"; //$NON-NLS-1$
private static final String TAG_CURRENT_FRAME = "currentFrame"; //$NON-NLS-1$
private IPartListener partListener = new IPartListener() {
@Override
public void partActivated(IWorkbenchPart part) {
if (part instanceof IEditorPart) {
editorActivated((IEditorPart) part);
}
}
@Override
public void partBroughtToTop(IWorkbenchPart part) {
if (part instanceof IEditorPart) {
editorActivated((IEditorPart) part);
}
}
@Override
public void partClosed(IWorkbenchPart part) {
}
@Override
public void partDeactivated(IWorkbenchPart part) {
}
@Override
public void partOpened(IWorkbenchPart part) {
}
};
private IPropertyChangeListener propertyChangeListener = event -> {
String property = event.getProperty();
Object newValue = event.getNewValue();
Object oldValue = event.getOldValue();
if (IWorkingSetManager.CHANGE_WORKING_SET_REMOVE.equals(property) && oldValue == workingSet) {
setWorkingSet(null);
} else if (IWorkingSetManager.CHANGE_WORKING_SET_NAME_CHANGE.equals(property) && newValue == workingSet) {
updateTitle();
} else if (IWorkingSetManager.CHANGE_WORKING_SET_CONTENT_CHANGE.equals(property) && newValue == workingSet) {
if (workingSet.isAggregateWorkingSet() && workingSet.isEmpty()) {
// act as if the working set has been made null
if (!emptyWorkingSet) {
emptyWorkingSet = true;
workingSetFilter.setWorkingSet(null);
}
} else {
// we've gone from empty to non-empty on our set.
// Restore it.
if (emptyWorkingSet) {
emptyWorkingSet = false;
workingSetFilter.setWorkingSet(workingSet);
}
}
getViewer().refresh();
}
};
private CollapseAllHandler collapseAllHandler;
/**
* Helper to open and activate editors.
*
* @since 3.5
*/
private OpenAndLinkWithEditorHelper openAndLinkWithEditorHelper;
/**
* Constructs a new resource navigator view.
*/
public ResourceNavigator() {
IDialogSettings viewsSettings = PlatformUI
.getDialogSettingsProvider(FrameworkUtil.getBundle(ResourceNavigator.class)).getDialogSettings();
settings = viewsSettings.getSection(STORE_SECTION);
if (settings == null) {
settings = viewsSettings.addNewSection(STORE_SECTION);
}
initLinkingEnabled();
}
/**
* Converts the given selection into a form usable by the viewer, where the
* elements are resources.
*/
private StructuredSelection convertSelection(ISelection selection) {
ArrayList<IResource> list = new ArrayList<>();
if (selection instanceof IStructuredSelection) {
IStructuredSelection ssel = (IStructuredSelection) selection;
for (Object o : ssel) {
IResource resource = Adapters.adapt(o, IResource.class);
if (resource != null) {
list.add(resource);
}
}
}
return new StructuredSelection(list);
}
@Override
public void createPartControl(Composite parent) {
emptyWorkspaceHelper = new EmptyWorkspaceHelper();
Composite displayArea = emptyWorkspaceHelper.getComposite(parent);
TreeViewer viewer = createViewer(displayArea);
this.viewer = viewer;
emptyWorkspaceHelper.setNonEmptyControl(viewer.getControl());
if (memento != null) {
restoreFilters();
restoreLinkingEnabled();
}
frameList = createFrameList();
initDragAndDrop();
updateTitle();
initContextMenu();
initResourceComparator();
initWorkingSetFilter();
// make sure input is set after sorters and filters,
// to avoid unnecessary refreshes
viewer.setInput(getInitialInput());
// make actions after setting input, because some actions
// look at the viewer for enablement (e.g. the Up action)
makeActions();
// Fill the action bars and update the global action handlers'
// enabled state to match the current selection.
getActionGroup().fillActionBars(getViewSite().getActionBars());
updateActionBars(viewer.getStructuredSelection());
getSite().setSelectionProvider(viewer);
getSite().getPage().addPartListener(partListener);
IWorkingSetManager workingSetManager = PlatformUI.getWorkbench().getWorkingSetManager();
workingSetManager.addPropertyChangeListener(propertyChangeListener);
if (memento != null) {
restoreState(memento);
}
memento = null;
// Set help for the view
getSite().getWorkbenchWindow().getWorkbench().getHelpSystem().setHelp(viewer.getControl(), getHelpContextId());
}
/**
* Returns the help context id to use for this view.
*
* @since 2.0
*/
protected String getHelpContextId() {
return INavigatorHelpContextIds.RESOURCE_VIEW;
}
/**
* Initializes and registers the context menu.
*
* @since 2.0
*/
protected void initContextMenu() {
MenuManager menuMgr = new MenuManager("#PopupMenu"); //$NON-NLS-1$
menuMgr.setRemoveAllWhenShown(true);
menuMgr.addMenuListener(ResourceNavigator.this::fillContextMenu);
TreeViewer viewer = getTreeViewer();
Menu menu = menuMgr.createContextMenu(viewer.getTree());
viewer.getTree().setMenu(menu);
getSite().registerContextMenu(menuMgr, viewer);
}
/**
* Creates the viewer.
*
* @param parent the parent composite
* @since 2.0
*/
protected TreeViewer createViewer(Composite parent) {
TreeViewer viewer = new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
viewer.setUseHashlookup(true);
initContentProvider(viewer);
initLabelProvider(viewer);
initFilters(viewer);
initListeners(viewer);
return viewer;
}
/**
* Sets the content provider for the viewer.
*
* @param viewer the viewer
* @since 2.0
*/
protected void initContentProvider(TreeViewer viewer) {
viewer.setContentProvider(new WorkbenchContentProvider());
}
/**
* Sets the label provider for the viewer.
*
* @param viewer the viewer
* @since 2.0
*/
protected void initLabelProvider(TreeViewer viewer) {
viewer.setLabelProvider(new DecoratingLabelProvider(new WorkbenchLabelProvider(),
PlatformUI.getWorkbench().getDecoratorManager().getLabelDecorator()));
}
/**
* Adds the filters to the viewer.
*
* @param viewer the viewer
* @since 2.0
*/
protected void initFilters(TreeViewer viewer) {
viewer.addFilter(patternFilter);
viewer.addFilter(workingSetFilter);
}
/**
* Initializes the linking enabled setting from the preference store.
*/
private void initLinkingEnabled() {
// Try the dialog settings first, which remember the last choice.
String setting = settings.get(IWorkbenchPreferenceConstants.LINK_NAVIGATOR_TO_EDITOR);
if (setting != null) {
linkingEnabled = setting.equals("true"); //$NON-NLS-1$
return;
}
// If not in the dialog settings, check the preference store for the default
// setting.
// Use the UI plugin's preference store since this is a public preference.
linkingEnabled = PlatformUI.getPreferenceStore()
.getBoolean(IWorkbenchPreferenceConstants.LINK_NAVIGATOR_TO_EDITOR);
}
/**
* Adds the listeners to the viewer.
*
* @param viewer the viewer
* @since 2.0
*/
protected void initListeners(final TreeViewer viewer) {
viewer.addSelectionChangedListener(this::handleSelectionChanged);
viewer.addDoubleClickListener(this::handleDoubleClick);
openAndLinkWithEditorHelper = new OpenAndLinkWithEditorHelper(viewer) {
@Override
protected void activate(ISelection selection) {
Object selectedElement = getSingleElement(selection);
if (selectedElement instanceof IFile) {
IEditorInput input = new FileEditorInput((IFile) selectedElement);
final IWorkbenchPage page = getSite().getPage();
IEditorPart editor = page.findEditor(input);
if (editor != null) {
page.activate(editor);
}
}
}
@Override
protected void linkToEditor(ISelection selection) {
if (!linkScheduled) {
// Ensure that if another selection change arrives while we're waiting for the
// *syncExec,
// we only do this work once.
linkScheduled = true;
getSite().getShell().getDisplay().asyncExec(() -> {
// There's no telling what might have changed since the syncExec was scheduled.
// Check to make sure that the widgets haven't been disposed.
linkScheduled = false;
if (viewer == null || viewer.getControl() == null || viewer.getControl().isDisposed()) {
return;
}
if (dragDetected == false) {
// only synchronize with editor when the selection is not the result
// of a drag. Fixes bug 22274.
ResourceNavigator.this.linkToEditor(viewer.getSelection());
}
});
}
}
@Override
protected void open(ISelection selection, boolean activate) {
handleOpen(selection);
}
};
viewer.getControl().addKeyListener(new KeyListener() {
@Override
public void keyPressed(KeyEvent event) {
handleKeyPressed(event);
}
@Override
public void keyReleased(KeyEvent event) {
handleKeyReleased(event);
}
});
openAndLinkWithEditorHelper.setLinkWithEditor(linkingEnabled);
}
@Override
public void dispose() {
getSite().getPage().removePartListener(partListener);
IWorkingSetManager workingSetManager = PlatformUI.getWorkbench().getWorkingSetManager();
workingSetManager.removePropertyChangeListener(propertyChangeListener);
if (collapseAllHandler != null) {
collapseAllHandler.dispose();
}
if (getActionGroup() != null) {
getActionGroup().dispose();
}
Control control = viewer.getControl();
if (dragDetectListener != null && control != null && control.isDisposed() == false) {
control.removeListener(SWT.DragDetect, dragDetectListener);
}
super.dispose();
}
/**
* An editor has been activated. Sets the selection in this navigator to be the
* editor's input, if linking is enabled.
*
* @param editor the active editor
* @since 2.0
*/
protected void editorActivated(IEditorPart editor) {
if (!isLinkingEnabled()) {
return;
}
IFile file = ResourceUtil.getFile(editor.getEditorInput());
if (file != null) {
ISelection newSelection = new StructuredSelection(file);
if (getTreeViewer().getStructuredSelection().equals(newSelection)) {
getTreeViewer().getTree().showSelection();
} else {
getTreeViewer().setSelection(newSelection, true);
}
}
}
/**
* Called when the context menu is about to open. Delegates to the action group
* using the viewer's selection as the action context.
*
* @since 2.0
*/
protected void fillContextMenu(IMenuManager menu) {
IStructuredSelection selection = getViewer().getStructuredSelection();
getActionGroup().setContext(new ActionContext(selection));
getActionGroup().fillContextMenu(menu);
}
@Override
public FrameList getFrameList() {
return frameList;
}
/**
* Returns the initial input for the viewer. Tries to convert the page input to
* a resource, either directly or via IAdaptable. If the resource is a
* container, it uses that. If the resource is a file, it uses its parent
* folder. If a resource could not be obtained, it uses the workspace root.
*
* @since 2.0
*/
protected IAdaptable getInitialInput() {
IResource resource = Adapters.adapt(getSite().getPage().getInput(), IResource.class);
if (resource != null) {
switch (resource.getType()) {
case IResource.FILE:
return resource.getParent();
case IResource.FOLDER:
case IResource.PROJECT:
case IResource.ROOT:
return resource;
default:
// Unknown resource type. Fall through.
break;
}
}
return ResourcesPlugin.getWorkspace().getRoot();
}
/**
* Returns the pattern filter for this view.
*
* @return the pattern filter
* @since 2.0
*/
@Override
public ResourcePatternFilter getPatternFilter() {
return this.patternFilter;
}
/**
* Returns the working set for this view.
*
* @return the working set
* @since 2.0
*/
@Override
public IWorkingSet getWorkingSet() {
return workingSetFilter.getWorkingSet();
}
/**
* Returns the navigator's plugin.
*
* @return the UI plugin for this bundle
*/
public AbstractUIPlugin getPlugin() {
return IDEWorkbenchPlugin.getDefault();
}
/**
* Return the sorter. If a comparator was set using
* {@link #setComparator(ResourceComparator)}, this method will return
* <code>null</code>.
*
* @since 2.0
* @deprecated as of 3.3, use {@link ResourceNavigator#getComparator()}
*/
@Deprecated
@Override
public ResourceSorter getSorter() {
ViewerSorter sorter = getTreeViewer().getSorter();
if (sorter instanceof ResourceSorter) {
return (ResourceSorter) sorter;
}
return null;
}
/**
* Returns the comparator. If a sorter was set using
* {@link #setSorter(ResourceSorter)}, this method will return
* <code>null</code>.
*
* @return the <code>ResourceComparator</code>
* @since 3.3
*/
@Override
public ResourceComparator getComparator() {
ViewerComparator comparator = getTreeViewer().getComparator();
if (comparator instanceof ResourceComparator) {
return (ResourceComparator) comparator;
}
return null;
}
/**
* Returns the resource viewer which shows the resource hierarchy.
*
* @since 2.0
*/
@Override
public TreeViewer getViewer() {
return viewer;
}
/**
* Returns the tree viewer which shows the resource hierarchy.
*
* @return the tree viewer
* @since 2.0
*/
public TreeViewer getTreeViewer() {
return viewer;
}
/**
* Returns the shell to use for opening dialogs. Used in this class, and in the
* actions.
*
* @return the shell
* @deprecated use getViewSite().getShell()
*/
@Deprecated
public Shell getShell() {
return getViewSite().getShell();
}
/**
* Returns the message to show in the status line.
*
* @param selection the current selection
* @return the status line message
* @since 2.0
*/
protected String getStatusLineMessage(IStructuredSelection selection) {
if (selection.size() == 1) {
Object o = selection.getFirstElement();
if (o instanceof IResource) {
return ((IResource) o).getFullPath().makeRelative().toString();
}
return ResourceNavigatorMessages.ResourceNavigator_oneItemSelected;
}
if (selection.size() > 1) {
return NLS.bind(ResourceNavigatorMessages.ResourceNavigator_statusLine, String.valueOf(selection.size()));
}
return ""; //$NON-NLS-1$
}
/**
* Returns the name for the given element. Used as the name for the current
* frame.
*/
String getFrameName(Object element) {
if (element instanceof IResource) {
return ((IResource) element).getName();
}
String text = ((ILabelProvider) getTreeViewer().getLabelProvider()).getText(element);
if (text == null) {
return "";//$NON-NLS-1$
}
return text;
}
/**
* Returns the tool tip text for the given element. Used as the tool tip text
* for the current frame, and for the view title tooltip.
*/
String getFrameToolTipText(Object element) {
if (element instanceof IResource) {
IPath path = ((IResource) element).getFullPath();
if (path.isRoot()) {
return ResourceNavigatorMessages.ResourceManager_toolTip;
}
return path.makeRelative().toString();
}
String text = ((ILabelProvider) getTreeViewer().getLabelProvider()).getText(element);
if (text == null) {
return "";//$NON-NLS-1$
}
return text;
}
/**
* Handles an open event from the viewer. Opens an editor on the selected file.
*
* @param event the open event
* @since 2.0
* @deprecated As of 3.5, replaced by {@link #handleOpen(ISelection)}
*/
@Deprecated
protected void handleOpen(OpenEvent event) {
handleOpen(event.getSelection());
}
/**
* Handles an open event from the viewer. Opens an editor on the selected file.
*
* @param selection the selection
* @since 3.5
*/
protected void handleOpen(ISelection selection) {
if (selection instanceof IStructuredSelection) {
getActionGroup().runDefaultAction((IStructuredSelection) selection);
}
}
/**
* Handles a double-click event from the viewer. Expands or collapses a folder
* when double-clicked.
*
* @param event the double-click event
* @since 2.0
*/
protected void handleDoubleClick(DoubleClickEvent event) {
IStructuredSelection selection = (IStructuredSelection) event.getSelection();
Object element = selection.getFirstElement();
// 1GBZIA0: ITPUI:WIN2000 - Double-clicking in navigator should expand/collapse
// containers
TreeViewer viewer = getTreeViewer();
if (viewer.isExpandable(element)) {
viewer.setExpandedState(element, !viewer.getExpandedState(element));
} else if (selection.size() == 1 && (element instanceof IResource)
&& ((IResource) element).getType() == IResource.PROJECT) {
OpenResourceAction ora = new OpenResourceAction(getSite());
ora.selectionChanged((IStructuredSelection) viewer.getSelection());
if (ora.isEnabled()) {
ora.run();
}
}
}
/**
* Handles a selection changed event from the viewer. Updates the status line
* and the action bars, and links to editor (if option enabled).
*
* @param event the selection event
* @since 2.0
*/
protected void handleSelectionChanged(SelectionChangedEvent event) {
final IStructuredSelection sel = event.getStructuredSelection();
updateStatusLine(sel);
updateActionBars(sel);
dragDetected = false;
}
/**
* Handles a key press event from the viewer. Delegates to the action group.
*
* @param event the key event
* @since 2.0
*/
protected void handleKeyPressed(KeyEvent event) {
getActionGroup().handleKeyPressed(event);
}
/**
* Handles a key release in the viewer. Does nothing by default.
*
* @param event the key event
* @since 2.0
*/
protected void handleKeyReleased(KeyEvent event) {
}
@Override
public void init(IViewSite site, IMemento memento) throws PartInitException {
super.init(site, memento);
this.memento = memento;
}
/**
* Adds drag and drop support to the navigator.
*
* @since 2.0
*/
protected void initDragAndDrop() {
int ops = DND.DROP_COPY | DND.DROP_MOVE | DND.DROP_LINK;
Transfer[] transfers = new Transfer[] { LocalSelectionTransfer.getInstance(), ResourceTransfer.getInstance(),
FileTransfer.getInstance(), PluginTransfer.getInstance() };
TreeViewer viewer = getTreeViewer();
viewer.addDragSupport(ops, transfers, new NavigatorDragAdapter(viewer));
NavigatorDropAdapter adapter = new NavigatorDropAdapter(viewer);
adapter.setFeedbackEnabled(false);
viewer.addDropSupport(ops | DND.DROP_DEFAULT, transfers, adapter);
dragDetectListener = event -> dragDetected = true;
viewer.getControl().addListener(SWT.DragDetect, dragDetectListener);
}
/**
* Creates the frame source and frame list, and connects them.
*
* @since 2.0
*/
protected FrameList createFrameList() {
NavigatorFrameSource frameSource = new NavigatorFrameSource(this);
FrameList frameList = new FrameList(frameSource);
frameSource.connectTo(frameList);
return frameList;
}
/**
* Initializes the sorter.
*
* @deprecated as of 3.3, use {@link ResourceNavigator#initResourceComparator()}
* instead
*/
@Deprecated
protected void initResourceSorter() {
int sortType = ResourceSorter.NAME;
try {
int sortInt = 0;
if (memento != null) {
String sortStr = memento.getString(TAG_SORTER);
if (sortStr != null) {
sortInt = Integer.parseInt(sortStr);
}
} else {
sortInt = settings.getInt(STORE_SORT_TYPE);
}
if (sortInt == ResourceSorter.NAME || sortInt == ResourceSorter.TYPE) {
sortType = sortInt;
}
} catch (NumberFormatException e) {
}
setSorter(new ResourceSorter(sortType));
}
/**
* Initializes the comparator.
*
* @since 3.3
*/
protected void initResourceComparator() {
int sortType = ResourceComparator.NAME;
try {
int sortInt = 0;
if (memento != null) {
String sortStr = memento.getString(TAG_SORTER);
if (sortStr != null) {
sortInt = Integer.parseInt(sortStr);
}
} else {
sortInt = settings.getInt(STORE_SORT_TYPE);
}
if (sortInt == ResourceComparator.NAME || sortInt == ResourceComparator.TYPE) {
sortType = sortInt;
}
} catch (NumberFormatException e) {
}
setComparator(new ResourceComparator(sortType));
}
/**
* Restores the working set filter from the persistence store.
*/
protected void initWorkingSetFilter() {
String workingSetName = settings.get(STORE_WORKING_SET);
IWorkingSet workingSet = null;
if (workingSetName != null && workingSetName.isEmpty() == false) {
IWorkingSetManager workingSetManager = PlatformUI.getWorkbench().getWorkingSetManager();
workingSet = workingSetManager.getWorkingSet(workingSetName);
} else if (PlatformUI.getPreferenceStore()
.getBoolean(IWorkbenchPreferenceConstants.USE_WINDOW_WORKING_SET_BY_DEFAULT)) {
// use the window set by default if the global preference is set
workingSet = getSite().getPage().getAggregateWorkingSet();
}
if (workingSet != null) {
// Only initialize filter. Don't set working set into viewer.
// Working set is set via WorkingSetFilterActionGroup
// during action creation.
workingSetFilter.setWorkingSet(workingSet);
internalSetWorkingSet(workingSet);
}
}
/**
* Returns whether the navigator selection automatically tracks the active
* editor.
*
* @return <code>true</code> if linking is enabled, <code>false</code> if not
* @since 2.0 (this was protected in 2.0, but was made public in 2.1)
*/
@Override
public boolean isLinkingEnabled() {
return linkingEnabled;
}
/**
* Brings the corresponding editor to top if the selected resource is open.
*
* @since 2.0
* @deprecated As of 3.5, replaced by {@link #linkToEditor(ISelection)}
*/
@Deprecated
protected void linkToEditor(IStructuredSelection selection) {
linkToEditor((ISelection) selection);
}
/**
* Brings the corresponding editor to top if the selected resource is open.
*
* @since 3.5
*/
protected void linkToEditor(ISelection selection) {
if (this != this.getSite().getPage().getActivePart())
return;
Object obj = getSingleElement(selection);
if (obj instanceof IFile) {
IFile file = (IFile) obj;
IWorkbenchPage page = getSite().getPage();
IEditorPart editor = ResourceUtil.findEditor(page, file);
if (editor != null) {
page.bringToTop(editor);
return;
}
}
}
/**
* Creates the action group, which encapsulates all actions for the view.
*/
protected void makeActions() {
MainActionGroup group = new MainActionGroup(this);
setActionGroup(group);
IHandlerService service = getSite().getService(IHandlerService.class);
service.activateHandler(IWorkbenchCommandConstants.NAVIGATE_TOGGLE_LINK_WITH_EDITOR,
new ActionHandler(group.toggleLinkingAction));
collapseAllHandler = new CollapseAllHandler(viewer);
service.activateHandler(CollapseAllHandler.COMMAND_ID, collapseAllHandler);
}
/**
* Restores the saved filter settings.
*/
private void restoreFilters() {
IMemento filtersMem = memento.getChild(TAG_FILTERS);
if (filtersMem != null) { // filters have been defined
IMemento children[] = filtersMem.getChildren(TAG_FILTER);
// check if first element has new tag defined, indicates new version
if (children.length > 0 && children[0].getString(TAG_IS_ENABLED) != null) {
ArrayList<String> selectedFilters = new ArrayList<>();
ArrayList unSelectedFilters = new ArrayList();
for (IMemento memento : children) {
if (memento.getString(TAG_IS_ENABLED).equals(String.valueOf(true))) {
selectedFilters.add(memento.getString(TAG_ELEMENT));
} else {
// enabled == false
unSelectedFilters.add(memento.getString(TAG_ELEMENT));
}
}
/*
* merge filters from Memento with selected = true filters from plugins ensure
* there are no duplicates & don't override user preferences
*/
List pluginFilters = FiltersContentProvider.getDefaultFilters();
for (Iterator iter = pluginFilters.iterator(); iter.hasNext();) {
String element = (String) iter.next();
if (!selectedFilters.contains(element) && !unSelectedFilters.contains(element)) {
selectedFilters.add(element);
}
}
// Convert to an array of Strings
String[] patternArray = new String[selectedFilters.size()];
selectedFilters.toArray(patternArray);
getPatternFilter().setPatterns(patternArray);
} else { // filters defined, old version: ignore filters from plugins
String filters[] = new String[children.length];
for (int i = 0; i < children.length; i++) {
filters[i] = children[i].getString(TAG_ELEMENT);
}
getPatternFilter().setPatterns(filters);
}
} else { // no filters defined, old version: ignore filters from plugins
getPatternFilter().setPatterns(new String[0]);
}
}
/**
* Restores the state of the receiver to the state described in the specified
* memento.
*
* @param memento the memento
* @since 2.0
*/
protected void restoreState(IMemento memento) {
TreeViewer viewer = getTreeViewer();
IMemento frameMemento = memento.getChild(TAG_CURRENT_FRAME);
if (frameMemento != null) {
TreeFrame frame = new TreeFrame(viewer);
frame.restoreState(frameMemento);
frame.setName(getFrameName(frame.getInput()));
frame.setToolTipText(getFrameToolTipText(frame.getInput()));
viewer.setSelection(new StructuredSelection(frame.getInput()));
frameList.gotoFrame(frame);
} else {
IContainer container = ResourcesPlugin.getWorkspace().getRoot();
IMemento childMem = memento.getChild(TAG_EXPANDED);
if (childMem != null) {
ArrayList elements = new ArrayList();
for (IMemento mem : childMem.getChildren(TAG_ELEMENT)) {
Object element = container.findMember(mem.getString(TAG_PATH));
if (element != null) {
elements.add(element);
}
}
viewer.setExpandedElements(elements.toArray());
}
childMem = memento.getChild(TAG_SELECTION);
if (childMem != null) {
ArrayList list = new ArrayList();
for (IMemento mem : childMem.getChildren(TAG_ELEMENT)) {
Object element = container.findMember(mem.getString(TAG_PATH));
if (element != null) {
list.add(element);
}
}
viewer.setSelection(new StructuredSelection(list));
}
}
}
/**
* Restores the linking enabled state.
*/
private void restoreLinkingEnabled() {
Integer val = memento.getInteger(IWorkbenchPreferenceConstants.LINK_NAVIGATOR_TO_EDITOR);
if (val != null) {
linkingEnabled = val.intValue() != 0;
}
}
/**
* @see ViewPart#saveState
*/
@Override
public void saveState(IMemento memento) {
TreeViewer viewer = getTreeViewer();
if (viewer == null) {
if (this.memento != null) {
memento.putMemento(this.memento);
}
return;
}
// save sorter
if (getComparator() != null) {
memento.putInteger(TAG_SORTER, getComparator().getCriteria());
} else if (getSorter() != null) {
memento.putInteger(TAG_SORTER, getSorter().getCriteria());
}
// save filters
String filters[] = getPatternFilter().getPatterns();
List selectedFilters = Arrays.asList(filters);
List allFilters = FiltersContentProvider.getDefinedFilters();
IMemento filtersMem = memento.createChild(TAG_FILTERS);
for (Iterator iter = allFilters.iterator(); iter.hasNext();) {
String element = (String) iter.next();
IMemento child = filtersMem.createChild(TAG_FILTER);
child.putString(TAG_ELEMENT, element);
child.putString(TAG_IS_ENABLED, String.valueOf(selectedFilters.contains(element)));
}
if (frameList.getCurrentIndex() > 0) {
// save frame, it's not the "home"/workspace frame
TreeFrame currentFrame = (TreeFrame) frameList.getCurrentFrame();
IMemento frameMemento = memento.createChild(TAG_CURRENT_FRAME);
currentFrame.saveState(frameMemento);
} else {
// save visible expanded elements
Object expandedElements[] = viewer.getVisibleExpandedElements();
if (expandedElements.length > 0) {
IMemento expandedMem = memento.createChild(TAG_EXPANDED);
for (Object expandedElement : expandedElements) {
if (expandedElement instanceof IResource) {
IMemento elementMem = expandedMem.createChild(TAG_ELEMENT);
elementMem.putString(TAG_PATH, ((IResource) expandedElement).getFullPath().toString());
}
}
}
// save selection
Object elements[] = viewer.getStructuredSelection().toArray();
if (elements.length > 0) {
IMemento selectionMem = memento.createChild(TAG_SELECTION);
for (Object selectionElement : elements) {
if (selectionElement instanceof IResource) {
IMemento elementMem = selectionMem.createChild(TAG_ELEMENT);
elementMem.putString(TAG_PATH, ((IResource) selectionElement).getFullPath().toString());
}
}
}
}
saveLinkingEnabled(memento);
}
/**
* Saves the linking enabled state.
*/
private void saveLinkingEnabled(IMemento memento) {
memento.putInteger(IWorkbenchPreferenceConstants.LINK_NAVIGATOR_TO_EDITOR, linkingEnabled ? 1 : 0);
}
/**
* Selects and reveals the specified elements.
*/
@Override
public void selectReveal(ISelection selection) {
StructuredSelection ssel = convertSelection(selection);
if (!ssel.isEmpty()) {
getViewer().getControl().setRedraw(false);
getViewer().setSelection(ssel, true);
getViewer().getControl().setRedraw(true);
}
}
/**
* Saves the filters defined as strings in <code>patterns</code> in the
* preference store.
*/
@Override
public void setFiltersPreference(String[] patterns) {
getPlugin().getPreferenceStore().setValue(ResourcePatternFilter.FILTERS_TAG,
String.join(ResourcePatternFilter.COMMA_SEPARATOR, patterns));
// remove value in old workbench preference store location
IPreferenceStore preferenceStore = IDEWorkbenchPlugin.getDefault().getPreferenceStore();
String storedPatterns = preferenceStore.getString(ResourcePatternFilter.FILTERS_TAG);
if (storedPatterns.length() > 0) {
preferenceStore.setValue(ResourcePatternFilter.FILTERS_TAG, ""); //$NON-NLS-1$
}
}
/**
* @see IWorkbenchPart#setFocus()
*/
@Override
public void setFocus() {
getTreeViewer().getTree().setFocus();
}
/**
* Note: For experimental use only. Sets the decorator for the navigator.
* <p>
* As of 2.0, this method no longer has any effect.
* </p>
*
* @param decorator a label decorator or <code>null</code> for no decorations.
* @deprecated use the decorators extension point instead; see
* IWorkbench.getDecoratorManager()
*/
@Deprecated
public void setLabelDecorator(ILabelDecorator decorator) {
// do nothing
}
/**
* @see IResourceNavigator#setLinkingEnabled(boolean)
* @since 2.1
*/
@Override
public void setLinkingEnabled(boolean enabled) {
this.linkingEnabled = enabled;
// remember the last setting in the dialog settings
settings.put(IWorkbenchPreferenceConstants.LINK_NAVIGATOR_TO_EDITOR, enabled);
// if turning linking on, update the selection to correspond to the active
// editor
if (enabled) {
IEditorPart editor = getSite().getPage().getActiveEditor();
if (editor != null) {
editorActivated(editor);
}
}
openAndLinkWithEditorHelper.setLinkWithEditor(enabled);
}
/**
* Sets the resource sorter.
*
* @param sorter the resource sorter
* @since 2.0
* @deprecated as of 3.3, use
* {@link ResourceNavigator#setComparator(ResourceComparator)}
*/
@Deprecated
@Override
public void setSorter(ResourceSorter sorter) {
TreeViewer viewer = getTreeViewer();
ViewerSorter viewerSorter = viewer.getSorter();
viewer.getControl().setRedraw(false);
if (viewerSorter == sorter) {
viewer.refresh();
} else {
viewer.setSorter(sorter);
}
viewer.getControl().setRedraw(true);
settings.put(STORE_SORT_TYPE, sorter.getCriteria());
// update the sort actions' checked state
updateActionBars((IStructuredSelection) viewer.getSelection());
}
/**
* Sets the resource comparator
*
* @param comparator the resource comparator
* @since 3.3
*/
@Override
public void setComparator(ResourceComparator comparator) {
TreeViewer viewer = getTreeViewer();
ViewerComparator viewerComparator = viewer.getComparator();
viewer.getControl().setRedraw(false);
if (viewerComparator == comparator) {
viewer.refresh();
} else {
viewer.setComparator(comparator);
}
viewer.getControl().setRedraw(true);
settings.put(STORE_SORT_TYPE, comparator.getCriteria());
// update the sort actions' checked state
updateActionBars(viewer.getStructuredSelection());
}
@Override
public void setWorkingSet(IWorkingSet workingSet) {
TreeViewer treeViewer = getTreeViewer();
Object[] expanded = treeViewer.getExpandedElements();
IStructuredSelection structuredSelection = treeViewer.getStructuredSelection();
boolean refreshNeeded = internalSetWorkingSet(workingSet);
workingSetFilter.setWorkingSet(emptyWorkingSet ? null : workingSet);
if (workingSet != null) {
settings.put(STORE_WORKING_SET, workingSet.getName());
} else {
settings.put(STORE_WORKING_SET, ""); //$NON-NLS-1$
}
updateTitle();
if (refreshNeeded) {
treeViewer.refresh();
}
treeViewer.setExpandedElements(expanded);
if (structuredSelection.isEmpty() == false) {
treeViewer.reveal(structuredSelection.getFirstElement());
}
}
/**
* Set the internal working set fields specific to the navigator.
*
* @param workingSet the new working set
* @since 3.2
*/
private boolean internalSetWorkingSet(IWorkingSet workingSet) {
boolean refreshNeeded = !Objects.equals(this.workingSet, workingSet);
this.workingSet = workingSet;
emptyWorkingSet = workingSet != null && workingSet.isAggregateWorkingSet() && workingSet.isEmpty();
return refreshNeeded;
}
/**
* Updates the action bar actions.
*
* @param selection the current selection
* @since 2.0
*/
protected void updateActionBars(IStructuredSelection selection) {
ResourceNavigatorActionGroup group = getActionGroup();
if (group != null) {
group.setContext(new ActionContext(selection));
group.updateActionBars();
}
}
/**
* Updates the message shown in the status line.
*
* @param selection the current selection
*/
protected void updateStatusLine(IStructuredSelection selection) {
String msg = getStatusLineMessage(selection);
getViewSite().getActionBars().getStatusLineManager().setMessage(msg);
}
/**
* Updates the title text and title tool tip. Called whenever the input of the
* viewer changes. Called whenever the input of the viewer changes.
*
* @since 2.0
*/
public void updateTitle() {
Object input = getViewer().getInput();
IWorkspace workspace = ResourcesPlugin.getWorkspace();
IWorkingSet workingSet = workingSetFilter.getWorkingSet();
if (input == null || input.equals(workspace) || input.equals(workspace.getRoot())) {
setContentDescription(""); //$NON-NLS-1$
if (workingSet != null) {
setTitleToolTip(
NLS.bind(ResourceNavigatorMessages.ResourceNavigator_workingSetToolTip, workingSet.getLabel()));
} else {
setTitleToolTip(""); //$NON-NLS-1$
}
} else {
ILabelProvider labelProvider = (ILabelProvider) getTreeViewer().getLabelProvider();
String inputToolTip = getFrameToolTipText(input);
String text = labelProvider.getText(input);
if (text != null) {
setContentDescription(text);
}
if (workingSet != null) {
setTitleToolTip(NLS.bind(ResourceNavigatorMessages.ResourceNavigator_workingSetInputToolTip,
inputToolTip, workingSet.getLabel()));
} else {
setTitleToolTip(inputToolTip);
}
}
}
/**
* Returns the action group.
*
* @return the action group
*/
protected ResourceNavigatorActionGroup getActionGroup() {
return actionGroup;
}
/**
* Sets the action group.
*
* @param actionGroup the action group
*/
protected void setActionGroup(ResourceNavigatorActionGroup actionGroup) {
this.actionGroup = actionGroup;
}
@Override
public <T> T getAdapter(Class<T> adapter) {
if (adapter == IShowInSource.class) {
return adapter.cast(getShowInSource());
}
if (adapter == IShowInTarget.class) {
return adapter.cast(getShowInTarget());
}
return null;
}
/**
* Returns the <code>IShowInSource</code> for this view.
*/
protected IShowInSource getShowInSource() {
return () -> new ShowInContext(getViewer().getInput(), getViewer().getSelection());
}
/**
* Returns the <code>IShowInTarget</code> for this view.
*/
protected IShowInTarget getShowInTarget() {
return context -> {
ArrayList<IResource> toSelect = new ArrayList<>();
ISelection sel = context.getSelection();
if (sel instanceof IStructuredSelection) {
IStructuredSelection ssel = (IStructuredSelection) sel;
for (Object o1 : ssel) {
IResource resource = Adapters.adapt(o1, IResource.class);
if (resource != null) {
toSelect.add(resource);
}
IMarker marker = Adapters.adapt(o1, IMarker.class);
if (marker != null) {
IResource r2 = marker.getResource();
if (r2.getType() != IResource.ROOT) {
toSelect.add(r2);
}
}
}
}
if (toSelect.isEmpty()) {
Object input = context.getInput();
IResource resource = Adapters.adapt(input, IResource.class);
if (resource != null) {
toSelect.add(resource);
}
}
if (!toSelect.isEmpty()) {
selectReveal(new StructuredSelection(toSelect));
return true;
}
return false;
};
}
/**
* Returns the selected element if the selection consists of a single element
* only.
*
* @param s the selection
* @return the selected first element or null
* @since 3.5
*/
protected static final Object getSingleElement(ISelection s) {
if (!(s instanceof IStructuredSelection))
return null;
IStructuredSelection selection = (IStructuredSelection) s;
if (selection.size() != 1)
return null;
return selection.getFirstElement();
}
}