Java tutorial
/******************************************************************************* * Copyright (c) 2004, 2009 Tasktop Technologies 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: * Tasktop Technologies - initial API and implementation *******************************************************************************/ package org.eclipse.mylyn.internal.java.ui; import java.util.LinkedHashSet; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; 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.IWorkspaceRunnable; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IMember; import org.eclipse.jdt.core.ISourceRange; import org.eclipse.jdt.core.ISourceReference; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.mylyn.commons.core.StatusHandler; import org.eclipse.mylyn.context.core.AbstractContextListener; import org.eclipse.mylyn.context.core.ContextChangeEvent; import org.eclipse.mylyn.context.core.ContextCore; import org.eclipse.mylyn.context.core.IInteractionElement; /** * @author Mik Kersten */ public class LandmarkMarkerManager extends AbstractContextListener { private static final String ID_MARKER_LANDMARK = "org.eclipse.mylyn.context.ui.markers.landmark"; //$NON-NLS-1$ private final Map<IInteractionElement, Long> markerMap = new ConcurrentHashMap<IInteractionElement, Long>(); private final LandmarkUpdateJob updateJob = new LandmarkUpdateJob( Messages.LandmarkMarkerManager_Updating_Landmark_Markers); public LandmarkMarkerManager() { super(); } @Override public void contextChanged(ContextChangeEvent event) { LinkedHashSet<LandmarkUpdateOperation> runnables = new LinkedHashSet<LandmarkUpdateOperation>(); switch (event.getEventKind()) { case ACTIVATED: case DEACTIVATED: modelUpdated(); break; case CLEARED: if (event.isActiveContext()) { modelUpdated(); } break; case LANDMARKS_ADDED: for (IInteractionElement element : event.getElements()) { LandmarkUpdateOperation runnable = createAddLandmarkMarkerOperation(element); if (runnable != null) { runnables.add(runnable); } } break; case ELEMENTS_DELETED: case LANDMARKS_REMOVED: for (IInteractionElement element : event.getElements()) { LandmarkUpdateOperation runnable = createRemoveLandmarkMarkerOperation(element); if (runnable != null) { runnables.add(runnable); } } break; } updateJob.updateMarkers(runnables); } private void modelUpdated() { try { // remove all known landmark markers LinkedHashSet<LandmarkUpdateOperation> runnables = new LinkedHashSet<LandmarkUpdateOperation>(); for (IInteractionElement node : markerMap.keySet()) { LandmarkUpdateOperation runnable = createRemoveLandmarkMarkerOperation(node); if (runnable != null) { runnables.add(runnable); } } markerMap.clear(); // add any nodes that are landmarks for (IInteractionElement node : ContextCore.getContextManager().getActiveLandmarks()) { LandmarkUpdateOperation runnable = createAddLandmarkMarkerOperation(node); if (runnable != null) { runnables.add(runnable); } } updateJob.updateMarkers(runnables); } catch (Throwable t) { StatusHandler.log(new Status(IStatus.ERROR, JavaUiBridgePlugin.ID_PLUGIN, "Could not update landmark markers", t)); //$NON-NLS-1$ } } private LandmarkUpdateOperation createAddLandmarkMarkerOperation(final IInteractionElement node) { if (node == null || node.getContentType() == null) { return null; } if (JavaStructureBridge.CONTENT_TYPE.equals(node.getContentType())) { final IJavaElement element = JavaCore.create(node.getHandleIdentifier()); if (!element.exists()) { return null; } if (element instanceof IMember) { try { final ISourceRange range = ((IMember) element).getNameRange(); IResource resource = element.getUnderlyingResource(); if (resource instanceof IFile) { LandmarkUpdateOperation runnable = new LandmarkUpdateOperation(resource) { public void run(IProgressMonitor monitor) throws CoreException { IMarker marker = getResource().createMarker(ID_MARKER_LANDMARK); if (marker != null && range != null) { marker.setAttribute(IMarker.CHAR_START, range.getOffset()); marker.setAttribute(IMarker.CHAR_END, range.getOffset() + range.getLength()); marker.setAttribute(IMarker.MESSAGE, "Mylyn Landmark"); marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_INFO); markerMap.put(node, marker.getId()); } } }; return runnable; } } catch (JavaModelException e) { StatusHandler.log( new Status(IStatus.ERROR, JavaUiBridgePlugin.ID_PLUGIN, "Could not update marker", e)); //$NON-NLS-1$ } } } return null; } private LandmarkUpdateOperation createRemoveLandmarkMarkerOperation(final IInteractionElement node) { if (node == null) { return null; } if (JavaStructureBridge.CONTENT_TYPE.equals(node.getContentType())) { IJavaElement element = JavaCore.create(node.getHandleIdentifier()); if (!element.exists()) { return null; } if (element.getAncestor(IJavaElement.COMPILATION_UNIT) != null // stuff // from .class files && element instanceof ISourceReference) { try { IResource resource = element.getUnderlyingResource(); LandmarkUpdateOperation runnable = new LandmarkUpdateOperation(resource) { public void run(IProgressMonitor monitor) throws CoreException { if (getResource() != null) { try { if (markerMap.containsKey(node)) { long id = markerMap.get(node); IMarker marker = getResource().getMarker(id); if (marker != null) { marker.delete(); } } } catch (NullPointerException e) { // FIXME avoid NPE StatusHandler.log(new Status(IStatus.ERROR, JavaUiBridgePlugin.ID_PLUGIN, "Could not update marker", e)); //$NON-NLS-1$ } } } }; return runnable; } catch (JavaModelException e) { // ignore the Java Model errors } } } return null; } /** * IWorkspaceRunnable that has a reference to the resource that it is operating on */ private abstract class LandmarkUpdateOperation implements IWorkspaceRunnable { private final IResource resource; public LandmarkUpdateOperation(IResource resource) { Assert.isNotNull(resource); this.resource = resource; } public IResource getResource() { return resource; } } /** * Job to handle updating the landmark markers in the background */ private class LandmarkUpdateJob extends Job { private static final int NOT_SCHEDULED = -1; private final LinkedHashSet<LandmarkUpdateOperation> queue = new LinkedHashSet<LandmarkUpdateOperation>(); private long scheduleTime = NOT_SCHEDULED; public LandmarkUpdateJob(String name) { super(name); setSystem(true); } public synchronized void updateMarkers(LinkedHashSet<LandmarkUpdateOperation> operations) { queue.addAll(operations); if (queue.size() > 0) { if (scheduleTime == NOT_SCHEDULED) { scheduleTime = System.currentTimeMillis(); schedule(); } } } @Override public IStatus run(IProgressMonitor monitor) { IWorkspace workspace = ResourcesPlugin.getWorkspace(); if (workspace == null) { return Status.CANCEL_STATUS; } LinkedHashSet<LandmarkUpdateOperation> operations = null; synchronized (this) { operations = new LinkedHashSet<LandmarkUpdateOperation>(queue); queue.clear(); scheduleTime = NOT_SCHEDULED; } if (operations != null) { try { monitor.beginTask(Messages.LandmarkMarkerManager_Updating_Landmark_Markers, operations.size()); for (LandmarkUpdateOperation runnable : operations) { try { workspace.run(runnable, runnable.getResource(), IWorkspace.AVOID_UPDATE, monitor); } catch (CoreException e) { StatusHandler.log(new Status(IStatus.ERROR, JavaUiBridgePlugin.ID_PLUGIN, "Could not update landmark marker", e)); //$NON-NLS-1$ } catch (OperationCanceledException e) { return Status.CANCEL_STATUS; } monitor.worked(1); } } finally { monitor.done(); } } return Status.OK_STATUS; } } }