001: /*******************************************************************************
002: * Copyright (c) 2000, 2004 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.internal.ui.examples.jspeditor;
011:
012: import java.util.ArrayList;
013: import java.util.List;
014:
015: import org.eclipse.core.runtime.Assert;
016:
017: import org.eclipse.core.resources.IContainer;
018: import org.eclipse.core.resources.IFile;
019: import org.eclipse.core.resources.IMarker;
020:
021: import org.eclipse.jface.text.IRegion;
022: import org.eclipse.jface.text.Position;
023: import org.eclipse.jface.text.reconciler.AbstractReconcileStep;
024: import org.eclipse.jface.text.reconciler.DirtyRegion;
025: import org.eclipse.jface.text.reconciler.IReconcilableModel;
026: import org.eclipse.jface.text.reconciler.IReconcileResult;
027: import org.eclipse.jface.text.reconciler.IReconcileStep;
028: import org.eclipse.jface.text.source.Annotation;
029:
030: import org.eclipse.ui.editors.text.EditorsUI;
031:
032: import org.eclipse.ui.texteditor.AnnotationTypeLookup;
033:
034: import org.eclipse.jdt.core.IBuffer;
035: import org.eclipse.jdt.core.ICompilationUnit;
036: import org.eclipse.jdt.core.IJavaElement;
037: import org.eclipse.jdt.core.IJavaProject;
038: import org.eclipse.jdt.core.IPackageFragment;
039: import org.eclipse.jdt.core.IPackageFragmentRoot;
040: import org.eclipse.jdt.core.IProblemRequestor;
041: import org.eclipse.jdt.core.JavaCore;
042: import org.eclipse.jdt.core.JavaModelException;
043: import org.eclipse.jdt.core.WorkingCopyOwner;
044: import org.eclipse.jdt.core.compiler.IProblem;
045:
046: import org.eclipse.jdt.internal.core.BufferManager;
047:
048: /**
049: * This reconcile step has a Java source document as
050: * input model and maintains a Java working copy as its model.
051: * <p>
052: * FIXME: We do not destroy the temporary working copy at the end.
053: * There are two ways to fix this:
054: * 1. destroy it after each reconcile call ==> no internal model anylonger
055: * 2. add life-cycle to reconcile steps (at least dispose/destroy)
056: * </p>
057: * @since 3.0
058: */
059: public class JavaReconcileStep extends AbstractReconcileStep {
060:
061: private AnnotationTypeLookup fAnnotationTypeLookup = EditorsUI
062: .getAnnotationTypeLookup();
063:
064: private static class TemporaryWorkingCopyOwner extends
065: WorkingCopyOwner {
066:
067: /*
068: * @see org.eclipse.jdt.core.WorkingCopyOwner#createBuffer(org.eclipse.jdt.core.ICompilationUnit)
069: */
070: public IBuffer createBuffer(ICompilationUnit workingCopy) {
071: // FIXME: Don't know how to get a buffer without using internal API.
072: return BufferManager.createBuffer(workingCopy);
073: }
074: }
075:
076: private class ProblemAdapter extends AnnotationAdapter {
077:
078: private IProblem fProblem;
079: private Position fPosition;
080:
081: ProblemAdapter(IProblem problem) {
082: fProblem = problem;
083: }
084:
085: public Position getPosition() {
086: if (fPosition == null)
087: fPosition = createPositionFromProblem();
088: return fPosition;
089: }
090:
091: public Annotation createAnnotation() {
092: int start = fProblem.getSourceStart();
093: if (start < 0)
094: return null;
095:
096: int length = fProblem.getSourceEnd()
097: - fProblem.getSourceStart() + 1;
098: if (length < 0)
099: return null;
100:
101: int type = IMarker.SEVERITY_INFO;
102: if (fProblem.isError())
103: type = IMarker.SEVERITY_ERROR;
104: else if (fProblem.isWarning())
105: type = IMarker.SEVERITY_WARNING;
106:
107: return new Annotation(fAnnotationTypeLookup
108: .getAnnotationType(IMarker.PROBLEM, type), false,
109: fProblem.getMessage());
110: }
111:
112: private Position createPositionFromProblem() {
113: int start = fProblem.getSourceStart();
114: if (start < 0)
115: return null;
116:
117: int length = fProblem.getSourceEnd()
118: - fProblem.getSourceStart() + 1;
119: if (length < 0)
120: return null;
121:
122: return new Position(start, length);
123: }
124: }
125:
126: private class ProblemRequestor implements IProblemRequestor {
127:
128: private List fCollectedProblems;
129: private boolean fIsActive = false;
130: private boolean fIsRunning = false;
131:
132: /*
133: * @see IProblemRequestor#beginReporting()
134: */
135: public void beginReporting() {
136: fIsRunning = true;
137: fCollectedProblems = new ArrayList();
138: }
139:
140: /*
141: * @see IProblemRequestor#acceptProblem(IProblem)
142: */
143: public void acceptProblem(IProblem problem) {
144: if (isActive())
145: fCollectedProblems.add(problem);
146: }
147:
148: /*
149: * @see IProblemRequestor#endReporting()
150: */
151: public void endReporting() {
152: fIsRunning = false;
153:
154: // WAS:
155: // if (!isActive())
156: // return;
157: //
158: // if (isCanceled())
159: // return;
160: }
161:
162: public IReconcileResult[] getReconcileResult() {
163: Assert.isTrue(!fIsRunning);
164:
165: int size = fCollectedProblems.size();
166: IReconcileResult[] result = new IReconcileResult[size];
167:
168: for (int i = 0; i < size; i++)
169: result[i] = new ProblemAdapter(
170: (IProblem) fCollectedProblems.get(i));
171:
172: return result;
173: }
174:
175: /*
176: * @see IProblemRequestor#isActive()
177: */
178: public boolean isActive() {
179: return fIsActive && fCollectedProblems != null
180: && !isCanceled();
181: }
182:
183: /**
184: * Sets the active state of this problem requestor.
185: *
186: * @param isActive the state of this problem requestor
187: */
188: public void setIsActive(boolean isActive) {
189: if (fIsActive != isActive) {
190: fIsActive = isActive;
191: if (fIsActive)
192: startCollectingProblems();
193: else
194: stopCollectingProblems();
195: }
196: }
197:
198: /**
199: * Tells this annotation model to collect temporary problems from now on.
200: */
201: private void startCollectingProblems() {
202: fCollectedProblems = new ArrayList();
203: }
204:
205: /**
206: * Tells this annotation model to no longer collect temporary problems.
207: */
208: private void stopCollectingProblems() {
209: // empty implementation
210: }
211: }
212:
213: /**
214: * Adapts an <code>ICompilationUnit</code> to the <code>ITextModel</code> interface.
215: */
216: class CompilationUnitAdapter implements IReconcilableModel {
217:
218: private ICompilationUnit fCompilationUnit;
219:
220: CompilationUnitAdapter(ICompilationUnit cu) {
221: fCompilationUnit = cu;
222: }
223:
224: private ICompilationUnit getCompilationUnit() {
225: return fCompilationUnit;
226: }
227: }
228:
229: private CompilationUnitAdapter fWorkingCopy;
230: private ProblemRequestor fProblemRequestor;
231: private WorkingCopyOwner fTemporaryWorkingCopyOwner;
232:
233: /**
234: * Creates the last reconcile step of the pipe.
235: */
236: public JavaReconcileStep(IFile jspFile) {
237: Assert.isNotNull(jspFile);
238: fTemporaryWorkingCopyOwner = new TemporaryWorkingCopyOwner();
239: try {
240: fWorkingCopy = new CompilationUnitAdapter(
241: createTemporaryWorkingCopy(jspFile));
242: } catch (JavaModelException e) {
243: e.printStackTrace();
244: }
245: }
246:
247: /**
248: * Creates an intermediate reconcile step which adds
249: * the given step to the pipe.
250: */
251: public JavaReconcileStep(IReconcileStep step, IFile jspFile) {
252: super (step);
253: Assert.isNotNull(jspFile);
254: fTemporaryWorkingCopyOwner = new TemporaryWorkingCopyOwner();
255: try {
256: fWorkingCopy = new CompilationUnitAdapter(
257: createTemporaryWorkingCopy(jspFile));
258: } catch (JavaModelException e) {
259: e.printStackTrace();
260: }
261: }
262:
263: /*
264: * @see AbstractReconcileStep#reconcileModel(DirtyRegion, IRegion)
265: */
266: protected IReconcileResult[] reconcileModel(
267: DirtyRegion dirtyRegion, IRegion subRegion) {
268: Assert.isTrue(getInputModel() instanceof DocumentAdapter,
269: "wrong model"); //$NON-NLS-1$
270:
271: ICompilationUnit cu = fWorkingCopy.getCompilationUnit();
272: // Cannot reconcile if CU could not be built
273: if (cu == null)
274: return null;
275:
276: System.out.println("reconciling java model..."); //$NON-NLS-1$
277:
278: IBuffer buffer;
279: try {
280: buffer = cu.getBuffer();
281: } catch (JavaModelException e) {
282: e.printStackTrace();
283: buffer = null;
284: }
285:
286: if (buffer != null)
287: buffer.setContents(((DocumentAdapter) getInputModel())
288: .getDocument().get());
289:
290: try {
291: synchronized (cu) {
292: fProblemRequestor.setIsActive(true);
293: cu.reconcile(true, getProgressMonitor());
294: }
295: } catch (JavaModelException ex) {
296: ex.printStackTrace();
297: } finally {
298: fProblemRequestor.setIsActive(false);
299: }
300:
301: return fProblemRequestor.getReconcileResult();
302: }
303:
304: /*
305: * @see AbstractReconcileStep#getModel()
306: */
307: public IReconcilableModel getModel() {
308: return fWorkingCopy;
309: }
310:
311: /*
312: * @see org.eclipse.jdt.internal.corext.util.WorkingCopyUtil#getNewWorkingCopy
313: */
314: private ICompilationUnit createTemporaryWorkingCopy(IFile jspFile)
315: throws JavaModelException {
316:
317: IContainer parent = jspFile.getParent();
318: IPackageFragment packageFragment = null;
319: IJavaElement je = JavaCore.create(parent);
320:
321: if (je == null || !je.exists())
322: return null;
323:
324: switch (je.getElementType()) {
325: case IJavaElement.PACKAGE_FRAGMENT:
326: je = je.getParent();
327: // fall through
328:
329: case IJavaElement.PACKAGE_FRAGMENT_ROOT:
330: IPackageFragmentRoot packageFragmentRoot = (IPackageFragmentRoot) je;
331: packageFragment = packageFragmentRoot
332: .getPackageFragment(IPackageFragmentRoot.DEFAULT_PACKAGEROOT_PATH);
333: break;
334:
335: case IJavaElement.JAVA_PROJECT:
336: IJavaProject jProject = (IJavaProject) je;
337:
338: if (!jProject.exists()) {
339: System.out
340: .println("Abort reconciling: cannot create working copy: JSP is not in a Java project"); //$NON-NLS-1$
341: return null;
342: }
343:
344: packageFragmentRoot = null;
345: IPackageFragmentRoot[] packageFragmentRoots = jProject
346: .getPackageFragmentRoots();
347: int i = 0;
348: while (i < packageFragmentRoots.length) {
349: if (!packageFragmentRoots[i].isArchive()
350: && !packageFragmentRoots[i].isExternal()) {
351: packageFragmentRoot = packageFragmentRoots[i];
352: break;
353: }
354: i++;
355: }
356: if (packageFragmentRoot == null) {
357: System.out
358: .println("Abort reconciling: cannot create working copy: JSP is not in a Java project with source package fragment root"); //$NON-NLS-1$
359: return null;
360: }
361: packageFragment = packageFragmentRoot
362: .getPackageFragment(IPackageFragmentRoot.DEFAULT_PACKAGEROOT_PATH);
363: break;
364:
365: default:
366: return null;
367: }
368:
369: fProblemRequestor = new ProblemRequestor();
370:
371: return packageFragment
372: .getCompilationUnit("Demo.java").getWorkingCopy(fTemporaryWorkingCopyOwner, fProblemRequestor, getProgressMonitor()); //$NON-NLS-1$
373: }
374: }
|