blob: 92420c243d79c4a00de8c43f291689566f94b0c6 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2001, 2004 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
* Jens Lukowski/Innoopract - initial renaming/restructuring
*
*******************************************************************************/
package org.eclipse.wst.sse.ui.internal.reconcile;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.ITypedRegion;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.reconciler.DirtyRegion;
import org.eclipse.wst.sse.core.internal.model.ModelLifecycleEvent;
import org.eclipse.wst.sse.core.internal.provisional.IModelLifecycleListener;
import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
import org.eclipse.wst.sse.core.internal.provisional.IndexedRegion;
import org.eclipse.wst.sse.core.internal.provisional.StructuredModelManager;
import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument;
import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocumentRegion;
/**
* An IStructuredModel aware Region Processor.
* Adds ModelLifecycle listener. ModelLifecycle listener notifies
* us that some reinitialization needs to take place.
*
* Model aware "process()"
* Implements a DOM based "contains()" method using IStructuredModel.
*
*/
public class StructuredRegionProcessor extends DocumentRegionProcessor implements IModelLifecycleListener {
protected void process(DirtyRegion dirtyRegion) {
if(getDocument() == null)
return;
// use structured model to determine area to process
IStructuredModel sModel = StructuredModelManager.getModelManager().getExistingModelForRead(getDocument());
try {
if(sModel != null) {
int start = dirtyRegion.getOffset();
IndexedRegion ir = sModel.getIndexedRegion(start);
if(ir != null) {
int end = ir.getEndOffset();
ITypedRegion[] unfiltered = computePartitioning(start, end);
// remove duplicate typed regions (partitions)
// that are handled by the same "total scope" strategy
ITypedRegion[] filtered = filterTotalScopeRegions(unfiltered);
// iterate dirty partitions
for (int i = 0; i < filtered.length; i++) {
process(filtered[i]);
}
}
}
}
finally {
if(sModel != null)
sModel.releaseFromRead();
}
}
private void process(ITypedRegion partition) {
IStructuredDocumentRegion[] sdRegions = ((IStructuredDocument)getDocument()).getStructuredDocumentRegions(partition.getOffset(), partition.getLength());
Position coverage = getNodeCoverage(sdRegions);
DirtyRegion nodeDirtyRegion = createDirtyRegion(coverage.offset, coverage.length, DirtyRegion.INSERT);
// we only run extension point strategy now
if (getValidatorStrategy() != null)
getValidatorStrategy().reconcile(partition, nodeDirtyRegion);
}
/**
* Expands coverage based on DOM.
*
* @return node coverage as a position
*/
protected Position getNodeCoverage(IStructuredDocumentRegion[] sdRegions) {
int start = -1;
int end = -1;
for (int i = 0; i < sdRegions.length; i++) {
if(!sdRegions[i].isDeleted()) {
IndexedRegion corresponding = getCorrespondingNode(sdRegions[i]);
if(corresponding != null) {
if (start == -1 || start > corresponding.getStartOffset())
start = corresponding.getStartOffset();
if (end == -1 || end < corresponding.getEndOffset())
end = corresponding.getEndOffset();
}
}
}
return new Position(start, end-start);
}
/**
* Returns the corresponding node for the StructuredDocumentRegion.
*
* @param sdRegion
* @return the corresponding node for sdRegion
*/
protected IndexedRegion getCorrespondingNode(IStructuredDocumentRegion sdRegion) {
IStructuredModel sModel = StructuredModelManager.getModelManager().getExistingModelForRead(getDocument());
IndexedRegion indexedRegion = null;
try {
if (sModel != null)
indexedRegion = sModel.getIndexedRegion(sdRegion.getStart());
} finally {
if (sModel != null)
sModel.releaseFromRead();
}
return indexedRegion;
}
/**
* @see org.eclipse.wst.sse.ui.internal.reconcile.DirtyRegionProcessor#contains(org.eclipse.jface.text.reconciler.DirtyRegion,
* org.eclipse.jface.text.reconciler.DirtyRegion)
*/
protected boolean contains(DirtyRegion root, DirtyRegion possible) {
// this method is a performance hit
// look for alternatives
boolean contains = false;
IStructuredModel sModel = getStructuredModelForRead(getDocument());
try {
if(sModel != null) {
IndexedRegion rootRegion = sModel.getIndexedRegion(root.getOffset());
IndexedRegion possRegion = sModel.getIndexedRegion(possible.getOffset());
if (rootRegion != null && possRegion != null) {
int rootStart = rootRegion.getStartOffset();
int rootEnd = rootRegion.getEndOffset();
int possStart = possRegion.getStartOffset();
int possEnd = possRegion.getEndOffset();
if (rootStart <= possStart && rootEnd >= possEnd)
contains = true;
if (DEBUG)
System.out.println("checking if [" + rootStart + ":" + rootEnd + "] contains [" + possStart + ":" + possEnd + "] ... " + contains); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
}
}
}
finally {
if (sModel != null)
sModel.releaseFromRead();
}
return contains;
}
/**
* Remember to release model after use!!
*
* @return
*/
public IStructuredModel getStructuredModelForRead(IDocument doc) {
IStructuredModel sModel = null;
if (doc != null)
sModel = StructuredModelManager.getModelManager().getExistingModelForRead(doc);
return sModel;
}
/**
* @param document
*/
private void hookUpModelLifecycleListener(IDocument document) {
IStructuredModel sModel = getStructuredModelForRead(document);
try {
if (sModel != null) {
sModel.addModelLifecycleListener(this);
}
}
finally {
if (sModel != null)
sModel.releaseFromRead();
}
}
/**
* @see org.eclipse.wst.sse.core.internal.provisional.IModelLifecycleListener#processPostModelEvent(org.eclipse.wst.sse.core.internal.model.ModelLifecycleEvent)
*/
public void processPostModelEvent(ModelLifecycleEvent event) {
// if underlying StructuredDocument changed, need to reconnect it
// here...
// ex. file is modified outside the workbench
if (event.getType() == ModelLifecycleEvent.MODEL_DOCUMENT_CHANGED) {
// check that it's this model that changed
IStructuredModel thisModel = getStructuredModelForRead(getDocument());
try {
if (thisModel != null && event.getModel().equals(thisModel)) {
IStructuredDocument sDoc = event.getModel().getStructuredDocument();
if (DEBUG) {
System.out.println("======================================================"); //$NON-NLS-1$
System.out.println("StructuredRegionProcessor: DOCUMENT MODEL CHANGED TO: "); //$NON-NLS-1$
System.out.println(sDoc.get());
System.out.println("======================================================"); //$NON-NLS-1$
}
setDocument(sDoc);
// propagate document change
// setDocumentOnAllStrategies(sDoc);
// ensure that the document is re-reconciled
setEntireDocumentDirty(sDoc);
}
}
finally {
if (thisModel != null)
thisModel.releaseFromRead();
}
}
}
/**
* @see org.eclipse.wst.sse.core.internal.provisional.IModelLifecycleListener#processPreModelEvent(org.eclipse.wst.sse.core.internal.model.ModelLifecycleEvent)
*/
public void processPreModelEvent(ModelLifecycleEvent event) {
if (event.getType() == ModelLifecycleEvent.MODEL_DOCUMENT_CHANGED) {
getDirtyRegionQueue().clear();
// note: old annotations are removed via the strategies on
// AbstractStructuredTextReconcilingStrategy#setDocument(...)
}
}
/**
* Reinitializes listeners and sets new document onall strategies.
*
* @see org.eclipse.jface.text.reconciler.AbstractReconciler#reconcilerDocumentChanged(IDocument)
*/
protected void reconcilerDocumentChanged(IDocument newDocument) {
IDocument currentDoc = getDocument();
// unhook old lifecycle listner
unhookModelLifecycleListener(currentDoc);
// add new lifecycle listener
if (newDocument != null)
hookUpModelLifecycleListener(newDocument);
// hooks up new document listener
// sets document on all strategies
super.reconcilerDocumentChanged(newDocument);
}
/**
* @param document
*/
private void unhookModelLifecycleListener(IDocument document) {
IStructuredModel sModel = getStructuredModelForRead(document);
try {
if (sModel != null)
sModel.removeModelLifecycleListener(this);
}
finally {
if (sModel != null)
sModel.releaseFromRead();
}
}
public void uninstall() {
// removes model listeners
unhookModelLifecycleListener(getDocument());
super.uninstall();
}
/**
* We already know content type from when we created the model, so just use that.
*/
protected String getContentType(IDocument doc) {
String contentTypeId = null;
IStructuredModel sModel = null;
try {
sModel = StructuredModelManager.getModelManager().getExistingModelForRead(doc);
if (sModel != null) {
contentTypeId = sModel.getContentTypeIdentifier();
}
} finally {
if (sModel != null)
sModel.releaseFromRead();
}
return contentTypeId;
}
}