/* * Copyright (c) 2003-2004 Christopher Lenz and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/cpl-v10.html * * Contributors: * Christopher Lenz - initial API and implementation * * $Id: XMLReconcileStep.java,v 1.2 2006-10-21 23:14:13 pombredanne Exp $ */ package net.sourceforge.phpeclipse.xml.ui.internal.text; import java.util.ArrayList; import java.util.Collections; import java.util.List; import net.sourceforge.phpeclipse.xml.core.model.IXMLDocument; import net.sourceforge.phpeclipse.xml.core.parser.IProblem; import net.sourceforge.phpeclipse.xml.core.parser.IProblemCollector; import net.sourceforge.phpeclipse.xml.ui.internal.editor.XMLDocumentProvider; import org.eclipse.core.resources.IFile; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.Position; import org.eclipse.jface.text.reconciler.AbstractReconcileStep; import org.eclipse.jface.text.reconciler.DirtyRegion; import org.eclipse.jface.text.reconciler.IReconcilableModel; import org.eclipse.jface.text.reconciler.IReconcileResult; import org.eclipse.jface.text.reconciler.IReconcileStep; import org.eclipse.jface.text.source.Annotation; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IFileEditorInput; import org.eclipse.ui.texteditor.IDocumentProvider; import org.eclipse.ui.texteditor.ITextEditor; /** * Implementation of a reconcile step for building the XML parse tree on changes * to the editor content. */ public class XMLReconcileStep extends AbstractReconcileStep { // Inner Classes ----------------------------------------------------------- /** * Adapts an IXMLDocument to the * IReconcilableModel interface. */ private class XMLDocumentAdapter implements IReconcilableModel { private IXMLDocument document; public XMLDocumentAdapter(IXMLDocument document) { this.document = document; } public IXMLDocument getDocument() { return document; } } /** * Implementation of the problem collector interface for creating problem * annotations when there are problems parsing the style sheet. */ private class ProblemCollector implements IProblemCollector { /** * The list of problems added to this collector. */ private List collectedProblems = new ArrayList(); /** * @see IProblemCollector#addProblem(IProblem) */ public void addProblem(IProblem problem) { collectedProblems.add(problem); } /** * Returns the list of problems collected while the CSS source has been * parsed, in the order they were reported. The list returned is * immutable. * * @return the list of collected problems (of type {@link IProblem}) */ public List getProblems() { return Collections.unmodifiableList(collectedProblems); } } /** * Adapter that adapts an {@link IProblem} to an {@link Annotation}. */ private class ProblemAdapter extends AnnotationAdapter { private IProblem problem; private Position position; public ProblemAdapter(IProblem problem) { this.problem = problem; } public Position getPosition() { if (position == null) { position = createPositionFromProblem(); } return position; } public Annotation createAnnotation() { int start = problem.getSourceStart(); if (start < 0) { return null; } int length = problem.getSourceEnd() - start + 1; if (length < 0) { return null; } String type; if (problem.isWarning()) { type = XMLAnnotation.TYPE_ERROR; } else if (problem.isError()) { type = XMLAnnotation.TYPE_WARNING; } else { type = XMLAnnotation.TYPE_INFO; } return new XMLAnnotation(type, false, problem.getMessage()); } private Position createPositionFromProblem() { int start = problem.getSourceStart(); if (start < 0) { return null; } int length = problem.getSourceEnd() - problem.getSourceStart() + 1; if (length < 0) { return null; } return new Position(start, length); } } // Instance Variables ------------------------------------------------------ private ITextEditor editor; private XMLDocumentAdapter xmlDocumentAdapter; // Constructors ------------------------------------------------------------ /** * Default constructor. */ public XMLReconcileStep(ITextEditor editor) { this.editor = editor; xmlDocumentAdapter = new XMLDocumentAdapter(getXMLDocument()); } /** * Constructor. * * @param step * the step to add to the pipe * @param editor * the associated text editor */ public XMLReconcileStep(IReconcileStep step, ITextEditor editor) { super(step); this.editor = editor; xmlDocumentAdapter = new XMLDocumentAdapter(getXMLDocument()); } // AbstractReconcileStep Implementation ------------------------------------ /* * @see AbstractReconcileStep#reconcileModel(DirtyRegion, IRegion) */ protected IReconcileResult[] reconcileModel(DirtyRegion dirtyRegion, IRegion subRegion) { IXMLDocument model = xmlDocumentAdapter.getDocument(); IEditorInput editorInput = null; IFile file = null; if (editor != null) { editorInput = editor.getEditorInput(); } if (editorInput instanceof IFileEditorInput) file = ((IFileEditorInput) editorInput).getFile(); ProblemCollector problemCollector = new ProblemCollector(); model.reconcile(problemCollector, file); List problems = problemCollector.getProblems(); IReconcileResult[] retVal = new IReconcileResult[problems.size()]; for (int i = 0; i < problems.size(); i++) { IProblem problem = (IProblem) problems.get(i); retVal[i] = new ProblemAdapter(problem); } return retVal; } /* * @see AbstractReconcileStep#getModel() */ public IReconcilableModel getModel() { return xmlDocumentAdapter; } // Private Methods Implementation ------------------------------------------ /** * Retrieve the style sheet associated with the editor input. */ private IXMLDocument getXMLDocument() { IDocumentProvider documentProvider = editor.getDocumentProvider(); if (documentProvider instanceof XMLDocumentProvider) { XMLDocumentProvider xmlDocumentProvider = (XMLDocumentProvider) documentProvider; return xmlDocumentProvider.getModel(editor.getEditorInput()); } return null; } }