| /********************************************************************** |
| * Copyright (c) 2002, 2015 Geoff Longman and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Geoff Longman - Initial API and implementation |
| * IBM - Tightening integration with existing Platform |
| **********************************************************************/ |
| package org.eclipse.core.tools.resources; |
| |
| import org.eclipse.jface.action.Action; |
| |
| import java.util.*; |
| import org.eclipse.core.resources.*; |
| import org.eclipse.core.runtime.IAdaptable; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.tools.SpyView; |
| import org.eclipse.jface.action.*; |
| 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.Display; |
| import org.eclipse.ui.*; |
| |
| /** |
| * This spy view displays a tree-based representation of resource deltas from |
| * resource change events. |
| */ |
| public class ResourceChangeView extends SpyView implements IResourceChangeListener { |
| class DeltaNode implements IAdaptable { |
| private ArrayList<DeltaNode> children; |
| private int deltaFlags = -1; |
| private int deltaKind = -1; |
| private DeltaNode parent = null; |
| private IPath path; |
| private IResource resource; |
| |
| public DeltaNode() { |
| children = new ArrayList<DeltaNode>(); |
| } |
| |
| public DeltaNode(IResourceDelta delta) { |
| this(); |
| populateFromDelta(delta); |
| } |
| |
| public void addChild(DeltaNode child) { |
| children.add(child); |
| child.setParent(this); |
| } |
| |
| @Override |
| @SuppressWarnings("unchecked") |
| public <T> T getAdapter(Class<T> key) { |
| if (key != IResource.class) |
| return null; |
| return (T) resource; |
| } |
| |
| public DeltaNode[] getChildren() { |
| return children.toArray(new DeltaNode[children.size()]); |
| } |
| |
| public int getDeltaFlags() { |
| return deltaFlags; |
| } |
| |
| public int getDeltaKind() { |
| return deltaKind; |
| } |
| |
| public DeltaNode getParent() { |
| return parent; |
| } |
| |
| public IPath getPath() { |
| return path; |
| } |
| |
| public IResource getResource() { |
| return resource; |
| } |
| |
| public boolean hasChildren() { |
| return children.size() > 0; |
| } |
| |
| public void populateFromDelta(IResourceDelta delta) { |
| deltaFlags = delta.getFlags(); |
| deltaKind = delta.getKind(); |
| path = delta.getFullPath(); |
| resource = delta.getResource(); |
| IResourceDelta[] deltaChildren = delta.getAffectedChildren(); |
| for (int i = 0; i < deltaChildren.length; i++) |
| addChild(new DeltaNode(deltaChildren[i])); |
| } |
| |
| public void removeChild(DeltaNode child) { |
| children.remove(child); |
| child.setParent(null); |
| } |
| |
| public void setParent(DeltaNode parent) { |
| this.parent = parent; |
| } |
| |
| @Override |
| public String toString() { |
| return resource.getName(); |
| } |
| } |
| |
| class FilterAction extends Action { |
| private int type; |
| |
| public FilterAction(String text, int eventType) { |
| super(text); |
| type = eventType; |
| } |
| |
| /** |
| * @see org.eclipse.jface.action.IAction#run() |
| */ |
| @Override |
| public void run() { |
| typeFilter = type; |
| for (Action action : eventActions) { |
| action.setChecked(action.equals(this)); |
| } |
| } |
| } |
| |
| class FilterPhantoms extends Action { |
| public FilterPhantoms() { |
| super("Show Phantoms"); //$NON-NLS-1$ |
| } |
| |
| @Override |
| public void run() { |
| showPhantoms = !showPhantoms; |
| setChecked(showPhantoms); |
| } |
| } |
| |
| class ResourceEventNode extends DeltaNode { |
| private int eventType; |
| |
| public ResourceEventNode(IResourceChangeEvent event) { |
| super(event.getDelta()); |
| eventType = event.getType(); |
| } |
| |
| public int getEventType() { |
| return eventType; |
| } |
| } |
| |
| class ViewContentProvider implements IStructuredContentProvider, ITreeContentProvider { |
| private DeltaNode invisibleRoot; |
| |
| @Override |
| public void dispose() { |
| // do nothing |
| } |
| |
| @Override |
| public Object[] getChildren(Object parent) { |
| return ((DeltaNode) parent).getChildren(); |
| } |
| |
| @Override |
| public Object[] getElements(Object parent) { |
| |
| if (parent.equals(rootObject)) { |
| if (invisibleRoot == null) { |
| if (rootObject instanceof IResourceChangeEvent) { |
| initialize(rootObject); |
| } else { |
| initialize(); |
| } |
| } |
| return getChildren(invisibleRoot); |
| } |
| return getChildren(parent); |
| } |
| |
| @Override |
| public Object getParent(Object child) { |
| return ((DeltaNode) child).getParent(); |
| } |
| |
| @Override |
| public boolean hasChildren(Object parent) { |
| return ((DeltaNode) parent).hasChildren(); |
| } |
| |
| /* |
| * We will set up a dummy model to initialize tree hierarchy. |
| */ |
| private void initialize() { |
| invisibleRoot = new DeltaNode(); |
| } |
| |
| private void initialize(Object input) { |
| if (!(input instanceof IResourceChangeEvent)) |
| return; |
| IResourceChangeEvent evt = (IResourceChangeEvent) input; |
| ResourceEventNode root = new ResourceEventNode(evt); |
| invisibleRoot = new DeltaNode(); |
| invisibleRoot.addChild(root); |
| } |
| |
| @Override |
| public void inputChanged(Viewer v, Object oldInput, Object newInput) { |
| invisibleRoot = null; |
| } |
| } |
| |
| class ViewLabelProvider extends LabelProvider { |
| |
| private String getEventTypeAsString(int eventType) { |
| switch (eventType) { |
| case IResourceChangeEvent.POST_BUILD : |
| return "POST_BUILD"; //$NON-NLS-1$ |
| case IResourceChangeEvent.POST_CHANGE : |
| return "POST_CHANGE"; //$NON-NLS-1$ |
| case IResourceChangeEvent.PRE_BUILD : |
| return "PRE_BUILD"; //$NON-NLS-1$ |
| } |
| return null; |
| } |
| |
| /** |
| * Return a string representation of the change flags found |
| * within a resource change event. |
| */ |
| private String getFlagsAsString(int flags) { |
| StringBuffer buffer = new StringBuffer(); |
| if ((IResourceDelta.ADDED & flags) != 0) { |
| buffer.append("-"); //$NON-NLS-1$ |
| buffer.append("ADDED"); //$NON-NLS-1$ |
| } |
| if ((IResourceDelta.ADDED_PHANTOM & flags) != 0 && showPhantoms) { |
| buffer.append("-"); //$NON-NLS-1$ |
| buffer.append("ADDED_PHANTOM"); //$NON-NLS-1$ |
| } |
| if ((IResourceDelta.ALL_WITH_PHANTOMS & flags) != 0 && showPhantoms) { |
| buffer.append("-"); //$NON-NLS-1$ |
| buffer.append("ALL_WITH_PHANTOMS"); //$NON-NLS-1$ |
| } |
| if ((IResourceDelta.CHANGED & flags) != 0) { |
| buffer.append("-"); //$NON-NLS-1$ |
| buffer.append("CHANGED"); //$NON-NLS-1$ |
| } |
| if ((IResourceDelta.CONTENT & flags) != 0) { |
| buffer.append("-"); //$NON-NLS-1$ |
| buffer.append("CONTENT"); //$NON-NLS-1$ |
| } |
| if ((IResourceDelta.DESCRIPTION & flags) != 0) { |
| buffer.append("-"); //$NON-NLS-1$ |
| buffer.append("DESCRIPTION"); //$NON-NLS-1$ |
| } |
| if ((IResourceDelta.MARKERS & flags) != 0) { |
| buffer.append("-"); //$NON-NLS-1$ |
| buffer.append("MARKERS"); //$NON-NLS-1$ |
| } |
| if ((IResourceDelta.MOVED_FROM & flags) != 0) { |
| buffer.append("-"); //$NON-NLS-1$ |
| buffer.append("MOVED_FROM"); //$NON-NLS-1$ |
| } |
| if ((IResourceDelta.MOVED_TO & flags) != 0) { |
| buffer.append("-"); //$NON-NLS-1$ |
| buffer.append("MOVED_TO"); //$NON-NLS-1$ |
| } |
| if ((IResourceDelta.NO_CHANGE & flags) != 0) { |
| buffer.append("-"); //$NON-NLS-1$ |
| buffer.append("NO_CHANGE"); //$NON-NLS-1$ |
| } |
| if ((IResourceDelta.OPEN & flags) != 0) { |
| buffer.append("-"); //$NON-NLS-1$ |
| buffer.append("OPEN"); //$NON-NLS-1$ |
| } |
| if ((IResourceDelta.REMOVED & flags) != 0) { |
| buffer.append("-"); |
| buffer.append("REMOVED"); |
| } |
| if ((IResourceDelta.REMOVED_PHANTOM & flags) != 0 && showPhantoms) { |
| buffer.append("-"); //$NON-NLS-1$ |
| buffer.append("REMOVED_PHANTOM"); //$NON-NLS-1$ |
| } |
| if ((IResourceDelta.REPLACED & flags) != 0) { |
| buffer.append("-"); //$NON-NLS-1$ |
| buffer.append("REPLACED"); //$NON-NLS-1$ |
| } |
| if ((IResourceDelta.SYNC & flags) != 0) { |
| buffer.append("-"); //$NON-NLS-1$ |
| buffer.append("SYNC"); //$NON-NLS-1$ |
| } |
| if ((IResourceDelta.TYPE & flags) != 0) { |
| buffer.append("-"); //$NON-NLS-1$ |
| buffer.append("TYPE"); //$NON-NLS-1$ |
| } |
| return buffer.toString(); |
| } |
| |
| @Override |
| public Image getImage(Object obj) { |
| DeltaNode node = (DeltaNode) obj; |
| String imageKey; |
| switch (node.getResource().getType()) { |
| case IResource.ROOT : |
| imageKey = ISharedImages.IMG_OBJ_FOLDER; |
| break; |
| case IResource.PROJECT : |
| imageKey = org.eclipse.ui.ide.IDE.SharedImages.IMG_OBJ_PROJECT; |
| break; |
| case IResource.FOLDER : |
| imageKey = ISharedImages.IMG_OBJ_FOLDER; |
| break; |
| case IResource.FILE : |
| default : |
| imageKey = ISharedImages.IMG_OBJ_FILE; |
| break; |
| } |
| return PlatformUI.getWorkbench().getSharedImages().getImage(imageKey); |
| } |
| |
| private String getKindAsString(int kind) { |
| if (kind == -1) |
| return ""; //$NON-NLS-1$ |
| return " kind(" + getFlagsAsString(kind) + ") "; //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| |
| @Override |
| public String getText(Object obj) { |
| StringBuffer buffer = new StringBuffer(obj.toString()); |
| if (obj instanceof ResourceEventNode) { |
| buffer.append("Workspace Root - "); //$NON-NLS-1$ |
| buffer.append(getEventTypeAsString(((ResourceEventNode) obj).getEventType())); |
| } |
| buffer.append(getKindAsString(((DeltaNode) obj).getDeltaKind())); |
| buffer.append(getFlagsAsString(((DeltaNode) obj).getDeltaFlags())); |
| return buffer.toString(); |
| } |
| } |
| |
| protected Set<Action> eventActions = new HashSet<Action>(); |
| private Action PHANTOMS; |
| private Action POST_BUILD; |
| |
| private Action POST_CHANGE; |
| |
| private Action PRE_BUILD; |
| |
| protected Object rootObject = ResourcesPlugin.getWorkspace(); |
| |
| protected boolean showPhantoms = false; |
| |
| protected int typeFilter = IResourceChangeEvent.POST_CHANGE; |
| |
| protected TreeViewer viewer; |
| |
| /** |
| * The constructor. |
| */ |
| public ResourceChangeView() { |
| super(); |
| } |
| |
| /** |
| * This is a callback that will allow us |
| * to create the viewer and initialize it. |
| */ |
| @Override |
| public void createPartControl(Composite parent) { |
| viewer = new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL); |
| viewer.setContentProvider(new ViewContentProvider()); |
| viewer.setLabelProvider(new ViewLabelProvider()); |
| viewer.setInput(rootObject); |
| |
| initializeActions(); |
| |
| IActionBars bars = getViewSite().getActionBars(); |
| IMenuManager menuMgr = bars.getMenuManager(); |
| menuMgr.addMenuListener(new IMenuListener() { |
| @Override |
| public void menuAboutToShow(final IMenuManager manager) { |
| fillPullDownBar(manager); |
| } |
| }); |
| fillPullDownBar(menuMgr); |
| |
| // register for all types of events and then filter out the one that we |
| // want based on the action settings. |
| ResourcesPlugin.getWorkspace().addResourceChangeListener(this, IResourceChangeEvent.POST_BUILD | IResourceChangeEvent.POST_CHANGE | IResourceChangeEvent.PRE_BUILD); |
| } |
| |
| /** |
| * @see org.eclipse.ui.IWorkbenchPart#dispose() |
| */ |
| @Override |
| public void dispose() { |
| super.dispose(); |
| ResourcesPlugin.getWorkspace().removeResourceChangeListener(this); |
| } |
| |
| /* |
| * The content provider class is responsible for |
| * providing objects to the view. It can wrap |
| * existing objects in adapters or simply return |
| * objects as-is. These objects may be sensitive |
| * to the current input of the view, or ignore |
| * it and always show the same content |
| * (like Task List, for example). |
| */ |
| |
| protected void fillPullDownBar(IMenuManager manager) { |
| manager.removeAll(); |
| |
| for (Action action : eventActions) |
| manager.add(action); |
| manager.add(new Separator("phantoms")); //$NON-NLS-1$ |
| manager.add(PHANTOMS); |
| } |
| |
| private void initializeActions() { |
| // create the actions for the drop-down menu |
| POST_BUILD = new FilterAction("POST_BUILD", IResourceChangeEvent.POST_BUILD); //$NON-NLS-1$ |
| POST_CHANGE = new FilterAction("POST_CHANGE", IResourceChangeEvent.POST_CHANGE); //$NON-NLS-1$ |
| // default event type |
| POST_CHANGE.setChecked(true); |
| PRE_BUILD = new FilterAction("PRE_BUILD", IResourceChangeEvent.PRE_BUILD); //$NON-NLS-1$ |
| eventActions.add(POST_BUILD); |
| eventActions.add(POST_CHANGE); |
| eventActions.add(PRE_BUILD); |
| PHANTOMS = new FilterPhantoms(); |
| } |
| |
| /** |
| * @see org.eclipse.core.resources.IResourceChangeListener#resourceChanged(IResourceChangeEvent) |
| */ |
| @Override |
| public void resourceChanged(IResourceChangeEvent event) { |
| if (event.getType() != typeFilter) |
| return; |
| setRoot(event); |
| } |
| |
| private void setRoot(IResourceChangeEvent event) { |
| if (viewer == null) |
| return; |
| Display display = viewer.getControl().getDisplay(); |
| if (display == null) |
| return; |
| rootObject = event; |
| display.asyncExec(new Runnable() { |
| @Override |
| public void run() { |
| viewer.getControl().setRedraw(false); |
| viewer.setInput(ResourceChangeView.this.rootObject); |
| viewer.expandAll(); |
| viewer.getControl().setRedraw(true); |
| } |
| }); |
| } |
| } |