/** * This file Copyright (c) 2005-2008 Aptana, Inc. This program is * dual-licensed under both the Aptana Public License and the GNU General * Public license. You may elect to use one or the other of these licenses. * * This program is distributed in the hope that it will be useful, but * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or * NONINFRINGEMENT. Redistribution, except as permitted by whichever of * the GPL or APL you select, is prohibited. * * 1. For the GPL license (GPL), you can redistribute and/or modify this * program under the terms of the GNU General Public License, * Version 3, as published by the Free Software Foundation. You should * have received a copy of the GNU General Public License, Version 3 along * with this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Aptana provides a special exception to allow redistribution of this file * with certain other free and open source software ("FOSS") code and certain additional terms * pursuant to Section 7 of the GPL. You may view the exception and these * terms on the web at http://www.aptana.com/legal/gpl/. * * 2. For the Aptana Public License (APL), this program and the * accompanying materials are made available under the terms of the APL * v1.0 which accompanies this distribution, and is available at * http://www.aptana.com/legal/apl/. * * You may view the GPL, Aptana's exception and additional terms, and the * APL in the file titled license.html at the root of the corresponding * plugin containing this source file. * * Any modifications to this file must keep this entire header intact. */ package com.aptana.ide.editors.unified.errors; import java.util.Hashtable; import java.util.Map; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceRuleFactory; import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.resources.IWorkspaceRunnable; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.jobs.ISchedulingRule; import com.aptana.ide.core.IdeLog; import com.aptana.ide.core.StringUtils; import com.aptana.ide.editors.UnifiedEditorsPlugin; /** * A listener for files that are part of a project * * @author Ingo Muschenetz */ public class ProjectFileErrorListener extends FileErrorListener { IFile file; /** * Creates a new listener * * @param file */ public ProjectFileErrorListener(IFile file) { this.file = file; } /** * Activated when errors change in the document * * @param errors * The list of errors to run through */ public void onErrorsChanged(final IFileError[] errors) { try { // Performance fix: schedule the error handling as a single workspace update so that we don't trigger a // bunch of resource updated events while problem markers are being added to the file. IWorkspaceRunnable runnable = new IWorkspaceRunnable() { public void run(IProgressMonitor monitor) { doHandleErrorsJob(errors); } }; ResourcesPlugin.getWorkspace().run(runnable, getMarkerRule(file), IWorkspace.AVOID_UPDATE, new NullProgressMonitor()); } catch (CoreException e) { IdeLog.logError(UnifiedEditorsPlugin.getDefault(), Messages.ProjectFileErrorListener_ErrorUpdatingMarkers, e); // } } private void doHandleErrorsJob(IFileError[] errors) { synchronized (this) // prevent simultaneous error updates on the same file { if (ResourcesPlugin.getWorkspace().isTreeLocked()) { // Note from Spike (1/26/2005): if this occurs, we will have problems getting the problem markers // updated in the file. // Robin had put in a fix to try alleviate this that we no longer think is necessary now that errors are // handled as // an atomic update via a IWorkspaceRunnable. If we see this error, we should consider putting that fix // back in. // If this exception is never seen again, we can remove this check. IdeLog.logError(UnifiedEditorsPlugin.getDefault(), Messages.ProjectFileErrorListener_ErrorUpdatingErrors, new IllegalStateException( Messages.ProjectFileErrorListener_TreeLocked)); // } if (file == null || !file.exists()) { return; } try { Map<String, IMarker> h = new Hashtable<String, IMarker>(); // get the list of existing problem markers IMarker[] problemMarkers = file.findMarkers(IMarker.PROBLEM, false, IResource.DEPTH_INFINITE); for (IMarker m : problemMarkers) { String key = createAnnotationKey(m); if (!h.containsKey(key)) { h.put(key, m); } } for (IFileError errorNode : errors) { String key = createAnnotationKey(errorNode.getMessage(), errorNode.getOffset(), errorNode .getLength()); if (!h.containsKey(key)) { applyErrorToProblemMarker(errorNode, file); } else { h.remove(key); } } // remove the old annotations for (IMarker marker : h.values()) { if (marker == null) continue; if (marker.getType().equals(IMarker.PROBLEM)) // Only remove generic problems (which is what we // apply here) marker.delete(); } } catch (Exception e) { IdeLog.logError(UnifiedEditorsPlugin.getDefault(), Messages.ProjectFileErrorListener_ErrorHere, e); } } } /** * Creates a new "key" from an annotation * * @param annotation * @param offset * @param length * @return Returns a hashtable key for the annotation */ private String createAnnotationKey(String annotationText, int offset, int length) { return offset + ":" + length + ":" + annotationText; //$NON-NLS-1$ //$NON-NLS-2$ } /** * Creates a new "key" from an annotation * * @param marker * @return Returns a hashtable key for the annotation */ private String createAnnotationKey(IMarker marker) { String markerText; try { markerText = (String) marker.getAttribute(IMarker.MESSAGE); int markerStart = marker.getAttribute(IMarker.CHAR_START, 0); int markerEnd = marker.getAttribute(IMarker.CHAR_END, 0); return markerStart + ":" + (markerEnd - markerStart) + ":" + markerText; //$NON-NLS-1$ //$NON-NLS-2$ } catch (CoreException e) { return StringUtils.EMPTY; } } private static void applyErrorToProblemMarker(IFileError errorNode, IFile file) { try { IMarker problemMarker = file.createMarker(IMarker.PROBLEM); problemMarker.setAttribute(IMarker.TRANSIENT, true); problemMarker.setAttribute(IMarker.SEVERITY, errorNode.getSeverity()); problemMarker.setAttribute(IMarker.CHAR_START, errorNode.getOffset()); problemMarker.setAttribute(IMarker.CHAR_END, errorNode.getOffset() + errorNode.getLength()); problemMarker.setAttribute(IMarker.MESSAGE, errorNode.getMessage()); problemMarker.setAttribute(IMarker.LINE_NUMBER, errorNode.getLineNumber()); } catch (CoreException e1) { IdeLog.logError(UnifiedEditorsPlugin.getDefault(), Messages.ProjectFileErrorListener_Error, e1); } } private static ISchedulingRule getMarkerRule(IResource resource) { ISchedulingRule rule = null; if (resource != null) { IResourceRuleFactory ruleFactory = ResourcesPlugin.getWorkspace().getRuleFactory(); rule = ruleFactory.markerRule(resource); } return rule; } }