1 /*******************************************************************************
2  * Copyright (c) 2004, 2013 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *******************************************************************************/
14 
15 package org.eclipse.ant.internal.ui.editor.outline;
16 
17 import java.util.ArrayList;
18 import java.util.HashMap;
19 import java.util.Iterator;
20 import java.util.List;
21 import java.util.Map;
22 
23 import org.eclipse.ant.core.AntCorePlugin;
24 import org.eclipse.ant.internal.core.IAntCoreConstants;
25 import org.eclipse.ant.internal.ui.AntUIPlugin;
26 import org.eclipse.ant.internal.ui.model.IAntModel;
27 import org.eclipse.ant.internal.ui.model.IProblem;
28 import org.eclipse.core.resources.IFile;
29 import org.eclipse.core.resources.IMarker;
30 import org.eclipse.core.resources.IResource;
31 import org.eclipse.core.resources.ResourcesPlugin;
32 import org.eclipse.core.resources.WorkspaceJob;
33 import org.eclipse.core.runtime.CoreException;
34 import org.eclipse.core.runtime.IProgressMonitor;
35 import org.eclipse.core.runtime.IStatus;
36 import org.eclipse.core.runtime.Status;
37 import org.eclipse.core.runtime.content.IContentDescription;
38 import org.eclipse.core.runtime.content.IContentType;
39 import org.eclipse.ui.texteditor.MarkerUtilities;
40 
41 public class AntEditorMarkerUpdater {
42 
43 	class AntEditorMarkerUpdaterJob extends WorkspaceJob {
44 
45 		private final List<IProblem> fProblems;
46 
AntEditorMarkerUpdaterJob(List<IProblem> problems)47 		public AntEditorMarkerUpdaterJob(List<IProblem> problems) {
48 			super("Ant editor marker updater job"); //$NON-NLS-1$
49 			fProblems = problems;
50 			setSystem(true);
51 		}
52 
53 		@Override
runInWorkspace(IProgressMonitor monitor)54 		public IStatus runInWorkspace(IProgressMonitor monitor) {
55 			updateMarkers0(fProblems);
56 			return new Status(IStatus.OK, AntUIPlugin.getUniqueIdentifier(), IStatus.OK, IAntCoreConstants.EMPTY_STRING, null);
57 		}
58 	}
59 
60 	private IAntModel fModel = null;
61 	private List<IProblem> fCollectedProblems = new ArrayList<>();
62 	public static final String BUILDFILE_PROBLEM_MARKER = AntUIPlugin.PI_ANTUI + ".buildFileProblem"; //$NON-NLS-1$
63 	private IFile fFile = null;
64 
acceptProblem(IProblem problem)65 	public synchronized void acceptProblem(IProblem problem) {
66 		if (fCollectedProblems.contains(problem)) {
67 			return;
68 		}
69 		fCollectedProblems.add(problem);
70 	}
71 
beginReporting()72 	public synchronized void beginReporting() {
73 		fCollectedProblems.clear();
74 	}
75 
removeProblems()76 	private void removeProblems() {
77 		IFile file = getFile();
78 		if (file == null || !file.exists()) {
79 			return;
80 		}
81 		try {
82 			file.deleteMarkers(BUILDFILE_PROBLEM_MARKER, false, IResource.DEPTH_INFINITE);
83 		}
84 		catch (CoreException e) {
85 			AntUIPlugin.log(e);
86 		}
87 	}
88 
createMarker(IProblem problem)89 	private void createMarker(IProblem problem) {
90 		IFile file = getFile();
91 		Map<String, Object> attributes = getMarkerAttributes(problem);
92 		try {
93 			MarkerUtilities.createMarker(file, attributes, BUILDFILE_PROBLEM_MARKER);
94 		}
95 		catch (CoreException e) {
96 			AntUIPlugin.log(e);
97 		}
98 	}
99 
setModel(IAntModel model)100 	public void setModel(IAntModel model) {
101 		fModel = model;
102 	}
103 
updateMarkers()104 	public synchronized void updateMarkers() {
105 		IFile file = getFile();
106 		if (file != null) {
107 			List<IProblem> problems = new ArrayList<>(fCollectedProblems.size());
108 			Iterator<IProblem> e = fCollectedProblems.iterator();
109 			while (e.hasNext()) {
110 				problems.add(e.next());
111 			}
112 			fCollectedProblems.clear();
113 			AntEditorMarkerUpdaterJob job = new AntEditorMarkerUpdaterJob(problems);
114 			job.setRule(ResourcesPlugin.getWorkspace().getRuleFactory().markerRule(file));
115 			job.schedule();
116 		}
117 	}
118 
updateMarkers0(List<IProblem> problems)119 	private void updateMarkers0(List<IProblem> problems) {
120 		removeProblems();
121 		if (!shouldAddMarkers()) {
122 			return;
123 		}
124 
125 		if (problems.size() > 0) {
126 			Iterator<IProblem> e = problems.iterator();
127 			while (e.hasNext()) {
128 				IProblem problem = e.next();
129 				createMarker(problem);
130 			}
131 		}
132 	}
133 
getFile()134 	private IFile getFile() {
135 		if (fFile == null) {
136 			fFile = fModel.getFile();
137 		}
138 		return fFile;
139 	}
140 
141 	/**
142 	 * Returns the attributes with which a newly created marker will be initialized.
143 	 *
144 	 * @return the initial marker attributes
145 	 */
getMarkerAttributes(IProblem problem)146 	private Map<String, Object> getMarkerAttributes(IProblem problem) {
147 
148 		Map<String, Object> attributes = new HashMap<>(11);
149 		int severity = IMarker.SEVERITY_ERROR;
150 		if (problem.isWarning()) {
151 			severity = IMarker.SEVERITY_WARNING;
152 		}
153 		// marker line numbers are 1-based
154 		MarkerUtilities.setMessage(attributes, problem.getUnmodifiedMessage());
155 		MarkerUtilities.setLineNumber(attributes, problem.getLineNumber());
156 		MarkerUtilities.setCharStart(attributes, problem.getOffset());
157 		MarkerUtilities.setCharEnd(attributes, problem.getOffset() + problem.getLength());
158 		attributes.put(IMarker.SEVERITY, Integer.valueOf(severity));
159 		return attributes;
160 	}
161 
162 	/**
163 	 * Returns whether or not to add markers to the file based on the file's content type. The content type is considered an Ant buildfile if the XML
164 	 * has a root &quot;project&quot; element. Content type is defined in the org.eclipse.ant.core plugin.xml.
165 	 *
166 	 * @return whether or not to add markers to the file based on the files content type
167 	 */
shouldAddMarkers()168 	private boolean shouldAddMarkers() {
169 		IFile file = getFile();
170 		if (file == null || !file.exists()) {
171 			return false;
172 		}
173 		IContentDescription description;
174 		try {
175 			description = file.getContentDescription();
176 		}
177 		catch (CoreException e) {
178 			return false;
179 		}
180 		if (description != null) {
181 			IContentType type = description.getContentType();
182 			return type != null && AntCorePlugin.ANT_BUILDFILE_CONTENT_TYPE.equals(type.getId());
183 		}
184 		return false;
185 	}
186 }
187