/*
* 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;
}
}