org.eclipse.mylyn.internal.java.ui.LandmarkMarkerManager.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.mylyn.internal.java.ui.LandmarkMarkerManager.java

Source

/*******************************************************************************
 * 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;
        }
    }
}