blob: db94230899ab9ee203eebdffb33f658955b5bd78 [file] [log] [blame]
/**********************************************************************
* Copyright (c) 2003, 2015 Geoff Longman 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:
* Geoff Longman - Initial API and implementation
* IBM - Tightening integration with existing Platform
* Geoff Longman - added ability to delete the marker selection
**********************************************************************/
package org.eclipse.core.tools.resources.markers;
import org.eclipse.core.resources.IResource;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.List;
import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.*;
import org.eclipse.core.tools.resources.CoreResourcesToolsPlugin;
import org.eclipse.jface.action.*;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
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.*;
import org.eclipse.ui.*;
import org.eclipse.ui.actions.SelectionProviderAction;
import org.eclipse.ui.actions.WorkspaceModifyOperation;
import org.eclipse.ui.ide.IDE.SharedImages;
import org.eclipse.ui.part.EditorPart;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.ui.progress.IProgressService;
import org.eclipse.ui.views.properties.*;
/**
* This is a view that allows one to inspect the state of a resource's markers.
* The view changes when a resource is selected in the workspace.
*/
public class MarkerView extends ViewPart implements ISelectionListener, IResourceChangeListener, IAdaptable {
public static final String MEMENTO_TAG1 = "MarkerView";
public static final String MEMENTO_TAG2 = "IResourcePath";
public static final String NONE_SELECTED = "NONE_SELECTED";
protected static final IStructuredSelection emptySelection = new StructuredSelection();
protected int markerDepth = IResource.DEPTH_ZERO;
protected MarkerExtensionModel model;
protected ReadOnlyMarkerPropertySource propertySource;
protected TreeViewer viewer;
protected Action doubleClickAction;
protected MarkerDepthAction depthZero;
protected MarkerDepthAction depthOne;
protected MarkerDepthAction depthInfinite;
protected DeleteMarkersAction deleteMarkers;
protected IResource currentResource;
protected String errorMsg;
protected String warningMsg;
protected ImageDescriptor oneImageDesc;
protected ImageDescriptor zeroImageDesc;
protected ImageDescriptor infiniteImageDesc;
protected PagePartListener pagePartListener;
protected IWorkbenchPage currentPage;
protected SelectionProvider selectionProvider;
protected MarkerViewPropertySheetPage propertyPage;
class SelectionProvider implements ISelectionProvider {
private List<ISelectionChangedListener> listeners = new ArrayList<ISelectionChangedListener>();
private ISelection selection;
@Override
public void addSelectionChangedListener(ISelectionChangedListener listener) {
listeners.add(listener);
}
@Override
public ISelection getSelection() {
return selection;
}
@Override
public void removeSelectionChangedListener(ISelectionChangedListener listener) {
listeners.remove(listener);
}
@Override
public synchronized void setSelection(ISelection selection) {
this.selection = selection;
SelectionChangedEvent event = new SelectionChangedEvent(this, selection);
for (ISelectionChangedListener listener : listeners) {
listener.selectionChanged(event);
}
}
}
class MarkerViewPropertySheetPage extends PropertySheetPage {
MarkerView view;
public MarkerViewPropertySheetPage(MarkerView view) {
super();
this.view = view;
}
@Override
public void selectionChanged(IWorkbenchPart part, ISelection selection) {
if (part == view)
super.selectionChanged(part, selection);
}
}
class MarkerDepthAction extends Action {
private int depth;
public MarkerDepthAction(int depth, String text, ImageDescriptor image) {
super(text, image);
this.depth = depth;
}
@Override
public void run() {
markerDepth = depth;
updateActionChecks();
if (currentResource != null)
viewer.setInput(currentResource);
}
}
class DeleteMarkersAction extends SelectionProviderAction {
public DeleteMarkersAction(ISelectionProvider provider, String text) {
super(provider, text);
}
@Override
public void selectionChanged(IStructuredSelection selection) {
setEnabled(!selection.isEmpty());
}
@Override
public void run() {
final IStructuredSelection selection = getStructuredSelection();
if (selection.isEmpty())
return;
IRunnableWithProgress op = new WorkspaceModifyOperation() {
@Override
public void execute(IProgressMonitor monitor) {
int count = selection.size();
int deleted = 1;
monitor.beginTask("deleting #" + deleted + " of " + count + " markers.", count);
for (Iterator<?> iter = selection.iterator(); iter.hasNext();) {
IMarker marker = (IMarker) iter.next();
try {
marker.delete();
monitor.worked(1);
deleted++;
monitor.setTaskName("deleting #" + deleted + " of " + count + " markers.");
} catch (CoreException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
monitor.done();
}
};
IProgressService progressService = PlatformUI.getWorkbench().getProgressService();
try {
progressService.busyCursorWhile(op);
} catch (InvocationTargetException e) {
IStatus status = null;
Throwable nested = e.getCause();
String message = nested.getMessage();
if (nested instanceof CoreException)
status = ((CoreException) nested).getStatus();
ErrorDialog.openError(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), "Error", message, status);
} catch (InterruptedException e) {
// Do nothing
}
}
}
class PagePartListener implements IPartListener, IPageListener {
@Override
public void partActivated(IWorkbenchPart part) {
if (part instanceof IEditorPart)
viewer.setInput(part);
}
@Override
public void partBroughtToTop(IWorkbenchPart part) {
if (part instanceof IEditorPart)
viewer.setInput(part);
}
@Override
public void partClosed(IWorkbenchPart part) {
// do nothing
}
@Override
public void partDeactivated(IWorkbenchPart part) {
// do nothing
}
@Override
public void partOpened(IWorkbenchPart part) {
// do nothing
}
@Override
public void pageActivated(IWorkbenchPage page) {
if (currentPage != null)
currentPage.removePartListener(this);
currentPage = page;
page.addPartListener(this);
}
@Override
public void pageClosed(IWorkbenchPage page) {
// do nothing
}
@Override
public void pageOpened(IWorkbenchPage page) {
// do nothing
}
}
class ViewContentProvider implements IStructuredContentProvider, ITreeContentProvider {
IStructuredSelection selection;
IMarker[] markers;
String[] message = new String[1];
@Override
public void inputChanged(Viewer v, Object oldInput, Object newInput) {
errorMsg = null;
warningMsg = null;
markers = null;
if (newInput instanceof IMarker) {
findResourceMarkers(((IMarker) newInput).getResource());
} else if (newInput instanceof IResource) {
findResourceMarkers((IResource) newInput);
return;
} else if (newInput instanceof EditorPart) {
currentResource = ((EditorPart) newInput).getEditorInput().getAdapter(IResource.class);
if (currentResource != null) {
findResourceMarkers(currentResource);
} else {
warningMsg = "Could not obtain an IResource from: " + newInput;
currentResource = null;
}
} else {
// otherwise its a selection
currentResource = null;
selection = (IStructuredSelection) newInput;
if (selection == null || selection.isEmpty()) {
warningMsg = "No selection found";
} else if (selection.size() > 1) {
warningMsg = "Select one resource to view its markers.";
} else {
Object selected = selection.getFirstElement();
if (selected != null) {
if (selected instanceof IMarker) {
currentResource = ((IMarker) selected).getResource();
} else if (selected instanceof IAdaptable) {
currentResource = ((IAdaptable) selected).getAdapter(IResource.class);
}
if (currentResource != null)
findResourceMarkers(currentResource);
else
warningMsg = "Could not obtain an IResource from: " + selected;
}
}
}
if (newInput != null)
setPartName("MarkerView" + (currentResource == null ? "" : " " + currentResource.getFullPath().toString()));
}
protected void findResourceMarkers(IResource resource) {
try {
markers = resource.findMarkers(null, true, markerDepth);
if (markers.length <= 0)
warningMsg = "No markers found for: " + resource.getFullPath();
return;
} catch (CoreException e) {
errorMsg = "Exception" + e.getMessage() + " occured obtaining markers for" + resource.getFullPath();
return;
}
}
@Override
public void dispose() {
// do nothing
}
@Override
public Object[] getElements(Object parent) {
if (parent.equals(viewer.getInput())) {
if (warningMsg != null) {
message[0] = warningMsg;
return message;
}
if (errorMsg != null) {
message[0] = errorMsg;
return message;
}
return getChildren(parent);
}
return getChildren(parent);
}
@Override
public Object getParent(Object child) {
if (child instanceof String || child instanceof IMarker)
return selection;
return null;
}
@Override
public Object[] getChildren(Object parent) {
if (parent == viewer.getInput())
return markers;
return new Object[0];
}
@Override
public boolean hasChildren(Object parent) {
if (parent == viewer.getInput())
return true;
return false;
}
}
class ViewLabelProvider extends LabelProvider {
@Override
public String getText(Object obj) {
try {
if (obj instanceof IMarker) {
IMarker marker = (IMarker) obj;
String message = (String) marker.getAttribute(IMarker.MESSAGE);
String type = marker.getType();
return message == null ? type : message + " : " + type;
}
} catch (CoreException e) {
CoreResourcesToolsPlugin.logProblem(e);
}
return obj.toString();
}
@Override
public Image getImage(Object obj) {
String imageKey = ISharedImages.IMG_OBJ_ELEMENT;
if (obj instanceof String) {
if (warningMsg != null)
imageKey = ISharedImages.IMG_OBJS_WARN_TSK;
else if (errorMsg != null)
imageKey = ISharedImages.IMG_OBJS_ERROR_TSK;
} else if (obj instanceof IMarker) {
try {
IMarker marker = (IMarker) obj;
if (marker.isSubtypeOf(IMarker.BOOKMARK)) {
imageKey = SharedImages.IMG_OBJS_BKMRK_TSK;
} else if (marker.isSubtypeOf(IMarker.PROBLEM)) {
imageKey = ISharedImages.IMG_OBJS_ERROR_TSK;
int severity = marker.getAttribute(IMarker.SEVERITY, IMarker.SEVERITY_WARNING);
switch (severity) {
case IMarker.SEVERITY_ERROR :
imageKey = ISharedImages.IMG_OBJS_ERROR_TSK;
break;
case IMarker.SEVERITY_INFO :
imageKey = ISharedImages.IMG_OBJS_INFO_TSK;
break;
case IMarker.SEVERITY_WARNING :
imageKey = ISharedImages.IMG_OBJS_WARN_TSK;
break;
default :
break;
}
} else if (marker.isSubtypeOf(IMarker.TASK))
imageKey = SharedImages.IMG_OBJS_TASK_TSK;
} catch (CoreException e) {
CoreResourcesToolsPlugin.logProblem(e);
}
}
return PlatformUI.getWorkbench().getSharedImages().getImage(imageKey);
}
}
/**
* The constructor.
*/
public MarkerView() {
zeroImageDesc = CoreResourcesToolsPlugin.createImageDescriptor("zero.gif");
oneImageDesc = CoreResourcesToolsPlugin.createImageDescriptor("one.gif");
infiniteImageDesc = CoreResourcesToolsPlugin.createImageDescriptor("infinity.gif");
model = new MarkerExtensionModel();
propertySource = new ReadOnlyMarkerPropertySource(this, model);
}
/**
* create the viewer and initialize it.
*/
@Override
public void createPartControl(Composite parent) {
IWorkbenchWindow window = CoreResourcesToolsPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow();
ISelectionService sel_service = window.getSelectionService();
sel_service.addSelectionListener(this);
ResourcesPlugin.getWorkspace().addResourceChangeListener(this);
viewer = new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
viewer.setContentProvider(new ViewContentProvider());
viewer.setLabelProvider(new ViewLabelProvider());
viewer.addSelectionChangedListener(new ISelectionChangedListener() {
@Override
public void selectionChanged(SelectionChangedEvent event) {
IStructuredSelection sel = (IStructuredSelection) event.getSelection();
IStructuredSelection newSelection = emptySelection;
if (!sel.isEmpty() && sel.size() == 1) {
Object first = sel.getFirstElement();
if (first instanceof IMarker) {
IMarker marker = (IMarker) first;
propertySource.setSourceMarker(marker);
newSelection = new StructuredSelection(propertySource);
}
}
getSite().getSelectionProvider().setSelection(newSelection);
}
});
pagePartListener = new PagePartListener();
currentPage = window.getActivePage();
window.addPageListener(pagePartListener);
if (currentResource != null) {
viewer.setInput(currentResource);
} else {
IWorkbenchPart activePart = currentPage == null ? null : currentPage.getActivePart();
if (activePart instanceof EditorPart)
viewer.setInput(activePart);
else
viewer.setInput(sel_service.getSelection());
}
makeActions();
hookContextMenu();
contributeToActionBars();
}
@Override
public void dispose() {
super.dispose();
IWorkbenchWindow window = CoreResourcesToolsPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow();
ISelectionService sel_service = window.getSelectionService();
sel_service.removeSelectionListener(this);
ResourcesPlugin.getWorkspace().removeResourceChangeListener(this);
}
void hookContextMenu() {
MenuManager menuMgr = new MenuManager("#PopupMenu"); //$NON-NLS-1$
menuMgr.setRemoveAllWhenShown(true);
menuMgr.addMenuListener(new IMenuListener() {
@Override
public void menuAboutToShow(IMenuManager manager) {
MarkerView.this.fillContextMenu(manager);
}
});
Menu menu = menuMgr.createContextMenu(viewer.getControl());
viewer.getControl().setMenu(menu);
getSite().registerContextMenu(menuMgr, viewer);
}
void contributeToActionBars() {
IActionBars bars = getViewSite().getActionBars();
fillLocalPullDown(bars.getMenuManager());
fillLocalToolBar(bars.getToolBarManager());
}
void fillLocalPullDown(IMenuManager manager) {
manager.add(depthZero);
manager.add(depthOne);
manager.add(depthInfinite);
}
void fillContextMenu(IMenuManager manager) {
manager.add(depthZero);
manager.add(depthOne);
manager.add(depthInfinite);
manager.add(new Separator());
manager.add(deleteMarkers);
manager.add(new Separator());
// Other plug-ins can contribute there actions here
manager.add(new Separator("Additions"));
}
void fillLocalToolBar(IToolBarManager manager) {
manager.add(depthZero);
manager.add(depthOne);
manager.add(depthInfinite);
}
private void makeActions() {
depthZero = new MarkerDepthAction(IResource.DEPTH_ZERO, "IResource.DEPTH_ZERO", zeroImageDesc);
depthOne = new MarkerDepthAction(IResource.DEPTH_ONE, "IResource.DEPTH_ONE", oneImageDesc);
depthInfinite = new MarkerDepthAction(IResource.DEPTH_INFINITE, "IResource.DEPTH_INFINITE", infiniteImageDesc);
deleteMarkers = new DeleteMarkersAction(viewer, "Delete");
updateActionChecks();
}
void updateActionChecks() {
switch (markerDepth) {
case IResource.DEPTH_ZERO :
depthZero.setChecked(true);
depthOne.setChecked(false);
depthInfinite.setChecked(false);
break;
case IResource.DEPTH_ONE :
depthZero.setChecked(false);
depthOne.setChecked(true);
depthInfinite.setChecked(false);
break;
case IResource.DEPTH_INFINITE :
depthZero.setChecked(false);
depthOne.setChecked(false);
depthInfinite.setChecked(true);
break;
default :
depthZero.setChecked(false);
depthOne.setChecked(false);
depthInfinite.setChecked(false);
}
}
/**
* Passing the focus request to the viewer's control.
*/
@Override
public void setFocus() {
viewer.getControl().setFocus();
}
/**
* Pushes the windows selection into the viewer
*
* @see org.eclipse.ui.ISelectionListener#selectionChanged(IWorkbenchPart, ISelection)
*/
@Override
public void selectionChanged(IWorkbenchPart part, ISelection selection) {
if (part instanceof IEditorPart)
viewer.setInput(part);
else if (part != this && !(part instanceof PropertySheet) && selection instanceof IStructuredSelection)
viewer.setInput(selection);
}
/**
* @see org.eclipse.core.resources.IResourceChangeListener#resourceChanged(IResourceChangeEvent)
*/
@Override
public void resourceChanged(IResourceChangeEvent event) {
if (currentResource == null)
return;
IResourceDelta delta = event.getDelta().findMember(currentResource.getFullPath());
if (delta == null)
return;
// could have been called from a non-UI thread.
// handle appropriately
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
viewer.setInput(currentResource);
}
});
}
/**
* @see org.eclipse.core.runtime.IAdaptable#getAdapter(Class)
*/
@Override
public <T> T getAdapter(Class<T> adapter) {
if (adapter == IPropertySheetPage.class) {
propertyPage = new MarkerViewPropertySheetPage(this);
return adapter.cast(propertyPage);
}
return super.getAdapter(adapter);
}
/**
* @see org.eclipse.ui.IViewPart#init(IViewSite, IMemento)
*/
@Override
public void init(IViewSite site, IMemento memento) throws PartInitException {
super.init(site, memento);
if (memento != null)
restoreState(memento);
selectionProvider = new SelectionProvider();
site.setSelectionProvider(selectionProvider);
}
private void restoreState(IMemento memento) {
IMemento child = memento.getChild(MEMENTO_TAG1);
if (child != null) {
child = child.getChild(MEMENTO_TAG2);
if (child != null) {
try {
String resourcePath = child.getTextData();
if (resourcePath != null && !NONE_SELECTED.equals(resourcePath)) {
Path path = new Path(resourcePath);
IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(path);
if (file != null && file.exists()) {
currentResource = file;
}
}
} catch (Exception e) {
}
}
}
}
/**
* @see org.eclipse.ui.IViewPart#saveState(IMemento)
*/
@Override
public void saveState(IMemento memento) {
super.saveState(memento);
IMemento child = memento.createChild(MEMENTO_TAG1);
child = child.createChild(MEMENTO_TAG2);
if (currentResource == null)
child.putTextData(NONE_SELECTED);
else
child.putTextData(currentResource.getFullPath().toString());
}
}