blob: 6e31cee1c7a730ec8049b2cd134ec769cd91aec6 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 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 - Initial API and implementation
*******************************************************************************/
package org.eclipse.core.tools.resources;
import java.util.*;
import org.eclipse.core.internal.localstore.IHistoryStore;
import org.eclipse.core.internal.resources.FileState;
import org.eclipse.core.internal.resources.Workspace;
import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.jface.action.*;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.*;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.ui.*;
import org.eclipse.ui.editors.text.EditorsUI;
import org.eclipse.ui.part.DrillDownAdapter;
import org.eclipse.ui.part.ViewPart;
/**
* Tree viewer class used to construct a view on the local history store. The
* tree navigates over the actual contents of the history store rather than
* going to the navigator and asking each file for its list of file states. This allows
* the browser to see the deleted files for containers.
*/
public class LocalHistoryBrowserView extends ViewPart {
TreeViewer viewer;
DrillDownAdapter drillDownAdapter;
Action refreshAction;
Action doubleClickAction;
class NameSorter extends ViewerComparator {
// empty impl
}
class FileStateEditorInput implements IStorageEditorInput {
private IFileState state;
public FileStateEditorInput(IFileState state) {
super();
this.state = state;
}
@Override
public IStorage getStorage() {
return state;
}
@Override
public boolean exists() {
return false;
}
@Override
public ImageDescriptor getImageDescriptor() {
return null;
}
@Override
public String getName() {
if (state instanceof FileState)
return ((FileState) state).getUUID() + " (" + state.getFullPath() + ')'; //$NON-NLS-1$
return state.getFullPath().toString();
}
@Override
public IPersistableElement getPersistable() {
return null;
}
@Override
public String getToolTipText() {
return null;
}
@Override
public <T> T getAdapter(Class<T> adapter) {
return null;
}
}
class Node {
Node parent;
String name;
ArrayList<Object> children;
public Node(Node parent, String name) {
super();
this.parent = parent;
this.name = name;
this.children = new ArrayList<>();
}
public void addChild(Object child) {
children.add(child);
}
public String getName() {
return name;
}
public Node getParent() {
return parent;
}
public Object[] getChildren() {
return children.toArray(new Object[0]);
}
public Object getChild(String childName) {
for (Object child : children) {
if (child instanceof Node) {
if (((Node) child).getName().equals(childName))
return child;
}
}
return null;
}
@Override
public String toString() {
return name;
}
}
class ViewContentProvider implements IStructuredContentProvider, ITreeContentProvider {
private IHistoryStore store = ((Workspace) ResourcesPlugin.getWorkspace()).getFileSystemManager().getHistoryStore();
private Node invisibleRoot;
@Override
public void inputChanged(Viewer v, Object oldInput, Object newInput) {
// do nothing
}
@Override
public void dispose() {
// do nothing
}
@Override
public Object[] getElements(Object parent) {
if (parent.equals(getViewSite())) {
if (invisibleRoot == null)
initialize();
return getChildren(invisibleRoot);
}
return getChildren(parent);
}
@Override
public Object getParent(Object child) {
return child instanceof Node ? ((Node) child).getParent() : null;
}
@Override
public Object[] getChildren(Object parent) {
return parent instanceof Node ? ((Node) parent).getChildren() : new Object[0];
}
@Override
public boolean hasChildren(Object parent) {
return parent instanceof Node ? ((Node) parent).getChildren().length != 0 : false;
}
public void initialize() {
invisibleRoot = new Node(null, "/"); //$NON-NLS-1$
Set<IPath> allFiles = store.allFiles(Path.ROOT, IResource.DEPTH_INFINITE, null);
for (IPath path : allFiles) {
Node current = invisibleRoot;
String[] segments = path.segments();
for (int i = 0; i < segments.length; i++) {
Object child = current.getChild(segments[i]);
if (child == null) {
child = new Node(current, segments[i]);
current.addChild(child);
}
current = (Node) child;
}
IFileState[] states = store.getStates(path, null);
for (int i = 0; i < states.length; i++)
current.addChild(states[i]);
}
}
}
class ViewLabelProvider extends LabelProvider {
@Override
public String getText(Object obj) {
return obj.toString();
}
@Override
public Image getImage(Object obj) {
String imageKey = ISharedImages.IMG_OBJ_FOLDER;
if (obj instanceof IFileState)
imageKey = ISharedImages.IMG_OBJ_ELEMENT;
return PlatformUI.getWorkbench().getSharedImages().getImage(imageKey);
}
}
public LocalHistoryBrowserView() {
super();
}
@Override
public void createPartControl(Composite parent) {
viewer = new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
drillDownAdapter = new DrillDownAdapter(viewer);
viewer.setContentProvider(new ViewContentProvider());
viewer.setLabelProvider(new ViewLabelProvider());
viewer.setInput(getViewSite());
viewer.setComparator(new NameSorter());
makeActions();
hookContextMenu();
hookDoubleClickAction();
contributeToActionBars();
}
private void hookContextMenu() {
MenuManager menuMgr = new MenuManager("#PopupMenu"); //$NON-NLS-1$
menuMgr.setRemoveAllWhenShown(true);
menuMgr.addMenuListener(LocalHistoryBrowserView.this::fillContextMenu);
Menu menu = menuMgr.createContextMenu(viewer.getControl());
viewer.getControl().setMenu(menu);
getSite().registerContextMenu(menuMgr, viewer);
}
private void contributeToActionBars() {
IActionBars bars = getViewSite().getActionBars();
fillLocalPullDown(bars.getMenuManager());
fillLocalToolBar(bars.getToolBarManager());
}
private void fillLocalPullDown(IMenuManager manager) {
manager.add(refreshAction);
}
protected void fillContextMenu(IMenuManager manager) {
manager.add(refreshAction);
manager.add(new Separator());
drillDownAdapter.addNavigationActions(manager);
// Other plug-ins can contribute there actions here
manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
}
private void fillLocalToolBar(IToolBarManager manager) {
manager.add(refreshAction);
manager.add(new Separator());
drillDownAdapter.addNavigationActions(manager);
}
private void makeActions() {
refreshAction = new Action() {
@Override
public void run() {
((ViewContentProvider) viewer.getContentProvider()).initialize();
showMessage("View refreshed."); //$NON-NLS-1$
}
};
refreshAction.setText("Refresh View"); //$NON-NLS-1$
refreshAction.setToolTipText("Refresh View"); //$NON-NLS-1$
refreshAction.setImageDescriptor(ImageDescriptor.createFromURLSupplier(true, () -> LocalHistoryBrowserView.class.getResource("/icons/refresh.gif"))); //$NON-NLS-1$
doubleClickAction = new Action() {
@Override
public void run() {
ISelection selection = viewer.getSelection();
Object obj = ((IStructuredSelection) selection).getFirstElement();
if (obj instanceof IFileState) {
// Show the file contents
IFileState state = (IFileState) obj;
IWorkbench workbench = PlatformUI.getWorkbench();
IEditorRegistry editorRegistry = workbench.getEditorRegistry();
IEditorDescriptor descriptor = editorRegistry.getDefaultEditor(state.getName());
String editorID = descriptor == null ? EditorsUI.DEFAULT_TEXT_EDITOR_ID : descriptor.getId();
IWorkbenchPage page = workbench.getActiveWorkbenchWindow().getActivePage();
try {
page.openEditor(new FileStateEditorInput(state), editorID);
} catch (PartInitException e) {
e.printStackTrace();
}
} else if (obj instanceof Node) {
// TODO expand/collapse tree node
}
}
};
}
private void hookDoubleClickAction() {
viewer.addDoubleClickListener(event -> doubleClickAction.run());
}
protected void showMessage(String message) {
MessageDialog.openInformation(viewer.getControl().getShell(), "Local History Browser", message); //$NON-NLS-1$
}
/**
* Passing the focus request to the viewer's control.
*/
@Override
public void setFocus() {
viewer.getControl().setFocus();
}
}