/* * Copyright (c) 2014, the Dart project authors. * * Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.eclipse.org/legal/epl-v10.html * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package com.google.dart.tools.wst.ui; import com.google.dart.engine.context.AnalysisContext; import com.google.dart.engine.html.ast.HtmlUnit; import com.google.dart.engine.internal.element.angular.AngularApplication; import com.google.dart.engine.source.Source; import com.google.dart.engine.utilities.general.ObjectUtilities; import com.google.dart.tools.core.DartCoreDebug; import com.google.dart.tools.core.analysis.model.AnalysisListener; import com.google.dart.tools.core.analysis.model.Project; import com.google.dart.tools.core.analysis.model.ResolvedHtmlEvent; import com.google.dart.tools.core.internal.builder.AnalysisWorker; import com.google.dart.tools.ui.internal.text.dart.DartUpdateSourceHelper; import org.eclipse.jface.text.DocumentEvent; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IDocumentListener; import org.eclipse.jface.text.IRegion; import org.eclipse.wst.sse.ui.internal.reconcile.validator.ISourceValidator; import org.eclipse.wst.validation.internal.provisional.core.IReporter; import org.eclipse.wst.validation.internal.provisional.core.IValidationContext; import org.eclipse.wst.validation.internal.provisional.core.IValidator; /** * Bridge between WST HTML document and resolved {@link HtmlUnit}. */ public class HtmlReconcilerHook implements ISourceValidator, IValidator { private IDocumentListener documentListener = new IDocumentListener() { @Override public void documentAboutToBeChanged(DocumentEvent event) { } @Override public void documentChanged(DocumentEvent event) { sourceChanged(document.get()); } }; private IDocument document; private StructuredDocumentDartInfo documentInfo; private HtmlUnit resolvedUnit; private AngularApplication application; private AnalysisListener analysisListener; public HtmlReconcilerHook() { } @Override public void cleanup(IReporter reporter) { // Not used, but WST expects IValidator } @Override public void connect(IDocument document) { if (DartCoreDebug.ENABLE_ANALYSIS_SERVER) { return; } this.document = document; this.documentInfo = StructuredDocumentDartInfo.create(document); // we need it if (documentInfo == null) { return; } // track changes document.addDocumentListener(documentListener); HtmlReconcilerManager.getInstance().reconcileWith(document, this); // remember resolved HtmlUnit analysisListener = new AnalysisListener.Empty() { @Override public void resolvedHtml(ResolvedHtmlEvent event) { StructuredDocumentDartInfo info = documentInfo; if (info != null) { AnalysisContext eventContext = event.getContext(); Source eventSource = event.getSource(); if (eventContext == info.getContext() && ObjectUtilities.equals(eventSource, info.getSource())) { resolvedUnit = event.getUnit(); application = eventContext.getAngularApplicationWithHtml(eventSource); } } } }; AnalysisWorker.addListener(analysisListener); // force reconcile sourceChanged(document.get()); } @Override public void disconnect(IDocument document) { AnalysisWorker.removeListener(analysisListener); sourceChanged(null); // clean up document.removeDocumentListener(documentListener); DartReconcilerManager.getInstance().reconcileWith(document, null); this.document = null; this.documentInfo = null; this.resolvedUnit = null; } public AngularApplication getApplication() { return application; } public AnalysisContext getContext() { StructuredDocumentDartInfo info = documentInfo; return info != null ? info.getContext() : null; } public HtmlUnit getResolvedUnit() { return resolvedUnit; } public Source getSource() { StructuredDocumentDartInfo info = documentInfo; return info != null ? info.getSource() : null; } @Override public void validate(IRegion dirtyRegion, IValidationContext helper, IReporter reporter) { // Not used, but WST expects IValidator } @Override @SuppressWarnings("restriction") public void validate(IValidationContext helper, IReporter reporter) throws org.eclipse.wst.validation.internal.core.ValidationException { // Not used, but WST expects IValidator } /** * Notify the context that the source has changed. * <p> * Note, that {@link Source} is updated in {@link AnalysisContext} in the background thread, so * there is a small probability that some operation will be initiated on not-quite-synchronized * content. But it is better than nothing for now... * * @param code the new source code or {@code null} if the source should be pulled from disk */ private void sourceChanged(String code) { if (documentInfo != null) { AnalysisContext context = documentInfo.getContext(); if (context != null) { Project project = documentInfo.getProject(); Source source = documentInfo.getSource(); DartUpdateSourceHelper.getInstance().updateWithDelay(project, context, source, code); } } } }