/* * 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: CssReconcileStep.java,v 1.1 2004-09-02 18:11:48 jsurfer Exp $ */ package net.sourceforge.phpeclipse.css.ui.internal.text; import java.util.ArrayList; import java.util.Collections; import java.util.List; import net.sourceforge.phpeclipse.css.core.model.IStyleSheet; import net.sourceforge.phpeclipse.css.core.parser.IProblem; import net.sourceforge.phpeclipse.css.core.parser.IProblemCollector; import net.sourceforge.phpeclipse.css.core.parser.LexicalErrorException; import net.sourceforge.phpeclipse.css.core.parser.SyntaxErrorException; import net.sourceforge.phpeclipse.css.ui.internal.CssDocumentProvider; 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.texteditor.IDocumentProvider; import org.eclipse.ui.texteditor.ITextEditor; /** * Implementation of a reconcile step for building the CSS parse tree on changes * to the editor content. */ public class CssReconcileStep extends AbstractReconcileStep { // Inner Classes ----------------------------------------------------------- /** * Adapts an IStyleSheet to the IReconcilableModel * interface. */ private class StyleSheetAdapter implements IReconcilableModel { private IStyleSheet styleSheet; public StyleSheetAdapter(IStyleSheet styleSheet) { this.styleSheet = styleSheet; } public IStyleSheet getStyleSheet() { return styleSheet; } } /** * 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; 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() - problem.getSourceStart() + 1; if (length < 0) { return null; } String type = null; if (problem.isWarning()) { type = "org.eclipse.ui.workbench.texteditor.warning"; //$NON-NLS-1$ } else if (problem.isError()) { type = "org.eclipse.ui.workbench.texteditor.error"; //$NON-NLS-1$ } return new Annotation(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 StyleSheetAdapter styleSheetAdapter; // Constructors ------------------------------------------------------------ /** * Default constructor. */ public CssReconcileStep(ITextEditor editor) { this.editor = editor; styleSheetAdapter = new StyleSheetAdapter(getStyleSheet()); } /** * Constructor. * * @param step the step to add to the pipe * @param editor the associated text editor */ public CssReconcileStep(IReconcileStep step, ITextEditor editor) { super(step); this.editor = editor; styleSheetAdapter = new StyleSheetAdapter(getStyleSheet()); } // AbstractReconcileStep Implementation ------------------------------------ /* * @see AbstractReconcileStep#reconcileModel(DirtyRegion, IRegion) */ protected IReconcileResult[] reconcileModel(DirtyRegion dirtyRegion, IRegion subRegion) { IStyleSheet styleSheet = styleSheetAdapter.getStyleSheet(); ProblemCollector problemCollector = new ProblemCollector(); try { styleSheet.reconcile(problemCollector); } catch (LexicalErrorException e) { // Already reported to the problem collector } catch (SyntaxErrorException e) { // Already reported to the problem collector } 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 styleSheetAdapter; } // Private Methods Implementation ------------------------------------------ /** * Retrieve the style sheet associated with the editor input. */ private IStyleSheet getStyleSheet() { IDocumentProvider documentProvider = editor.getDocumentProvider(); if (documentProvider instanceof CssDocumentProvider) { CssDocumentProvider cssDocumentProvider = (CssDocumentProvider) documentProvider; return cssDocumentProvider.getStyleSheet(editor.getEditorInput()); } return null; } }