/*******************************************************************************
* Copyright (c) 2009 IBM Corporation.
* 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:
* Robert Fuhrer (rfuhrer@watson.ibm.com) - initial API and implementation
*******************************************************************************/
package org.eclipse.imp.compare;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import org.eclipse.compare.IEncodedStreamContentAccessor;
import org.eclipse.compare.IResourceProvider;
import org.eclipse.compare.ISharedDocumentAdapter;
import org.eclipse.compare.IStreamContentAccessor;
import org.eclipse.compare.ITypedElement;
import org.eclipse.compare.structuremergeviewer.DocumentRangeNode;
import org.eclipse.compare.structuremergeviewer.IStructureComparator;
import org.eclipse.compare.structuremergeviewer.StructureCreator;
import org.eclipse.compare.structuremergeviewer.StructureRootNode;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.imp.editor.ModelTreeNode;
import org.eclipse.imp.language.Language;
import org.eclipse.imp.language.LanguageRegistry;
import org.eclipse.imp.language.ServiceFactory;
import org.eclipse.imp.parser.IParseController;
import org.eclipse.imp.parser.ISourcePositionLocator;
import org.eclipse.imp.services.ICompareNodeIdentifier;
import org.eclipse.imp.services.ILabelProvider;
import org.eclipse.imp.services.base.TreeModelBuilderBase;
import org.eclipse.jface.text.IDocument;
import org.eclipse.swt.graphics.Image;
/**
* @author rfuhrer
*/
public class ModelStructureCreator extends StructureCreator {
public class TreeCompareNode extends DocumentRangeNode implements ITypedElement {
private final Object fASTNode;
/**
* @param treeNode
* @param document
*/
public TreeCompareNode(ModelTreeNode treeNode, IDocument document) {
this(null, treeNode, document);
}
/**
* @param parent
* @param treeNode
* @param document
*/
public TreeCompareNode(DocumentRangeNode parent, ModelTreeNode treeNode, IDocument document) {
super(parent, fCompareNodeIdentifier.getTypeCode(treeNode.getASTNode()), fCompareNodeIdentifier.getID(treeNode.getASTNode()), document,
fSrcPositionLocator.getStartOffset(treeNode.getASTNode()), fSrcPositionLocator.getLength(treeNode.getASTNode()));
fASTNode= treeNode.getASTNode();
}
@Override
public String toString() {
return getTypeCode() + ":" + getId();
}
public Image getImage() {
return (fLabelProvider != null) ? fLabelProvider.getImage(fASTNode) : null;
}
public String getName() {
return (fLabelProvider != null) ? fLabelProvider.getText(fASTNode) : toString();
}
public String getType() {
return "?type?";
}
}
private Language fLanguage;
private ICompareNodeIdentifier fCompareNodeIdentifier;
private ILabelProvider fLabelProvider;
private ISourcePositionLocator fSrcPositionLocator;
/**
*
*/
public ModelStructureCreator() { }
/* (non-Javadoc)
* @see org.eclipse.compare.structuremergeviewer.IStructureCreator#getName()
*/
public String getName() {
return "Structural Comparison";
}
/* (non-Javadoc)
* @see org.eclipse.compare.structuremergeviewer.StructureCreator#createStructureComparator(java.lang.Object, org.eclipse.jface.text.IDocument, org.eclipse.compare.ISharedDocumentAdapter, org.eclipse.core.runtime.IProgressMonitor)
*/
@Override
protected IStructureComparator createStructureComparator(Object input, IDocument document, ISharedDocumentAdapter sharedDocumentAdapter, IProgressMonitor monitor) throws CoreException {
determineLanguage(input, document);
if (fLanguage != null) {
ServiceFactory svcFactory= ServiceFactory.getInstance();
IParseController pc= svcFactory.getParseController(fLanguage);
fCompareNodeIdentifier= svcFactory.getCompareNodeIdentifier(fLanguage);
fLabelProvider= svcFactory.getLabelProvider(fLanguage);
TreeModelBuilderBase builder= svcFactory.getTreeModelBuilder(fLanguage);
fSrcPositionLocator= pc.getSourcePositionLocator();
pc.initialize(null, null, null);
Object astRoot= pc.parse(document.get(), monitor);
DocumentRangeNode compareRoot;
if (astRoot != null) {
ModelTreeNode modelRoot= builder.buildTree(astRoot);
// now visit the model, creating TreeCompareNodes for each ModelTreeNode
compareRoot= buildCompareTree(modelRoot, null, document);
} else {
compareRoot= new StructureRootNode(document, input, this, sharedDocumentAdapter);
}
return compareRoot;
}
return null;
}
private TreeCompareNode buildCompareTree(ModelTreeNode treeNode, DocumentRangeNode parent, IDocument document) {
TreeCompareNode compareNode= new TreeCompareNode(parent, treeNode, document);
for(ModelTreeNode treeChild: treeNode.getChildren()) {
compareNode.addChild(buildCompareTree(treeChild, compareNode, document));
}
return compareNode;
}
private void determineLanguage(Object element, IDocument document) {
if (element instanceof IAdaptable) {
IResourceProvider resProvider= (IResourceProvider) ((IAdaptable) element).getAdapter(IResourceProvider.class);
if (resProvider != null) {
IResource res= resProvider.getResource();
fLanguage= LanguageRegistry.findLanguage(res.getFullPath(), document);
}
} else {
// Could this StructureCreator ever get called for an 'element' that isn't a resource?
}
}
/* (non-Javadoc)
* @see org.eclipse.compare.structuremergeviewer.IStructureCreator#getContents(java.lang.Object, boolean)
*/
public String getContents(Object node, boolean ignoreWhitespace) {
if (node instanceof IStreamContentAccessor) {
IStreamContentAccessor sca = (IStreamContentAccessor) node;
try {
return readString(sca);
} catch (CoreException ex) {
}
}
return null;
}
private static String readString(InputStream is, String encoding) {
if (is == null)
return null;
BufferedReader reader = null;
try {
StringBuffer buffer = new StringBuffer();
char[] part = new char[2048];
int read = 0;
reader = new BufferedReader(new InputStreamReader(is, encoding));
while ((read = reader.read(part)) != -1)
buffer.append(part, 0, read);
return buffer.toString();
} catch (IOException ex) {
// NeedWork
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException ex) {
// silently ignored
}
}
}
return null;
}
public static String readString(IStreamContentAccessor sa) throws CoreException {
InputStream is = sa.getContents();
if (is != null) {
String encoding = null;
if (sa instanceof IEncodedStreamContentAccessor) {
try {
encoding = ((IEncodedStreamContentAccessor) sa).getCharset();
} catch (Exception e) {
}
}
if (encoding == null)
encoding = ResourcesPlugin.getEncoding();
return readString(is, encoding);
}
return null;
}
}