package com.sap.furcas.ide.editor.action;
import java.util.ArrayList;
import java.util.List;
import org.antlr.runtime.Lexer;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.query.index.IndexFactory;
import org.eclipse.emf.query2.QueryContext;
import org.eclipse.emf.query2.QueryProcessor;
import org.eclipse.emf.query2.QueryProcessorFactory;
import org.eclipse.emf.query2.ResultSet;
import org.eclipse.jface.action.Action;
import org.eclipse.swt.widgets.Event;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.PlatformUI;
import com.sap.furcas.ide.editor.EditorUtil;
import com.sap.furcas.ide.editor.dialogs.ChooseConcreteSyntaxDialog;
import com.sap.furcas.ide.editor.dialogs.PrettyPrinterInfoDialog;
import com.sap.furcas.ide.parserfactory.AbstractParserFactory;
import com.sap.furcas.metamodel.FURCAS.TCS.ClassTemplate;
import com.sap.furcas.metamodel.FURCAS.TCS.ConcreteSyntax;
import com.sap.furcas.metamodel.FURCAS.TCS.ContextTemplate;
import com.sap.furcas.metamodel.FURCAS.TCS.TCSPackage;
import com.sap.furcas.metamodel.FURCAS.TCS.Template;
import com.sap.furcas.metamodel.FURCAS.textblocks.TextBlock;
import com.sap.furcas.metamodel.FURCAS.textblocks.TextblocksPackage;
import com.sap.furcas.modeladaptation.emf.lookup.QueryBasedEcoreMetaModelLookUp;
import com.sap.furcas.prettyprinter.PrettyPrinter;
import com.sap.furcas.runtime.common.interfaces.IMetaModelLookup;
import com.sap.furcas.runtime.common.util.EcoreHelper;
import com.sap.furcas.runtime.common.util.TCSSpecificOCLEvaluator;
import com.sap.furcas.runtime.parser.impl.ObservableInjectingParser;
/**
*
* @author Andreas Landerer
* @version 1.0
*
*/
public class PrettyPrintAction extends Action {
private final EObject modelElement;
private final EClass clazz;
private final boolean openEditorAfterPrettyPrint;
private TextBlock resultBlock;
private final QueryProcessor queryProcessor;
public PrettyPrintAction(EClass clazz, EObject modelElement,
boolean openEditorAfterPrettyPrint) {
super("Pretty Print", PlatformUI.getWorkbench().getSharedImages()
.getImageDescriptor(ISharedImages.IMG_ETOOL_PRINT_EDIT));
this.setDisabledImageDescriptor(PlatformUI
.getWorkbench()
.getSharedImages()
.getImageDescriptor(ISharedImages.IMG_ETOOL_PRINT_EDIT_DISABLED));
this.setId("prettyPrint");
this.clazz = clazz;
this.modelElement = modelElement;
this.openEditorAfterPrettyPrint = openEditorAfterPrettyPrint;
queryProcessor = QueryProcessorFactory.getDefault().createQueryProcessor(IndexFactory.getInstance());
}
@Override
public void runWithEvent(Event event) {
try {
Resource resource = modelElement.eResource();
ResourceSet connection = resource.getResourceSet();
ContextTemplate template = determineTemplate(connection);
ConcreteSyntax syntax = template.getConcreteSyntax();
TextBlock textBlockToReuse = determineTextBlockToReuse(connection,
template);
try {
AbstractParserFactory<? extends ObservableInjectingParser, ? extends Lexer> parserFactory = EditorUtil
.constructParserFactoryForSyntax(syntax);
IMetaModelLookup<EObject> metamodelLookup = new QueryBasedEcoreMetaModelLookUp(connection, parserFactory.getMetamodelURIs());
PrettyPrinter prettyPrinter = new PrettyPrinter(syntax, metamodelLookup, new TCSSpecificOCLEvaluator(), parserFactory);
resultBlock = prettyPrinter.prettyPrint(modelElement, template, textBlockToReuse);
if (resultBlock != null) {
resource.save(null);
PrettyPrinterInfoDialog dialog = new PrettyPrinterInfoDialog(
"Pretty Printer",
"Pretty Printer finished successfully!");
dialog.execute(null);
if (this.openEditorAfterPrettyPrint) {
//FIXME: Open editor
}
} else {
PrettyPrinterInfoDialog dialog = new PrettyPrinterInfoDialog(
"Pretty Printer",
"Model Element was not pretty printed, please try superior model element!");
dialog.execute(null);
}
} catch (Exception e) {
//FIXME: is this the correct way to revert the resource?
resource.unload();
e.printStackTrace();
PrettyPrinterInfoDialog dialog = new PrettyPrinterInfoDialog(
"Pretty Printer",
"Pretty Printer failed with exception, see console!");
dialog.execute(null);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public ContextTemplate determineTemplate(ResourceSet rs) throws Exception {
ContextTemplate template = null;
QueryContext context = EcoreHelper.getQueryContext(rs);
// select corresponding templates
String mqlTemplates = "select template \n"
+ "from [" + EcoreUtil.getURI(TCSPackage.eINSTANCE.getClassTemplate()) + "] as template,"
+ "[" + EcoreUtil.getURI(EcorePackage.eINSTANCE.getEClass()) + "] as class in elements { "
+ "[" + EcoreUtil.getURI(clazz) + "] } "
+ "where template.metaReference = class";
ResultSet resultSet = queryProcessor.execute(mqlTemplates, context);
URI[] resultURIs = resultSet.getUris("template");
List<ContextTemplate> templates = new ArrayList<ContextTemplate>(resultURIs.length);
for (URI uri : resultURIs) {
templates.add((ContextTemplate) rs.getEObject(uri, true));
}
if (templates.size() > 1) {
// search and choose main template
for (Object o : templates) {
if (o instanceof ClassTemplate && ((ClassTemplate) o).isIsMain()) {
template = (ClassTemplate) o;
}
}
if (template == null || template.getConcreteSyntax() == null) {
ChooseConcreteSyntaxDialog dialog = new ChooseConcreteSyntaxDialog(
templates);
Object o = dialog.execute(null);
if (o instanceof ClassTemplate) {
template = (ClassTemplate) o;
}
}
} else if (templates.size() == 1) {
if (templates.iterator().next() instanceof ClassTemplate) {
template = templates.iterator().next();
}
} else {
throw new Exception("No template found to print model element!");
}
return template;
}
public TextBlock determineTextBlockToReuse(ResourceSet rs,
Template template) {
TextBlock oldTextBlock = null;
QueryContext context = EcoreHelper.getQueryContext(rs);
// select corresponding text blocks to model element
String mqlTextBlocks = "select template \n"
+ "from [" + EcoreUtil.getURI(TextblocksPackage.eINSTANCE.getTextBlock()) + "] as tb,"
+ "[" + EcoreUtil.getURI(EcorePackage.eINSTANCE.getEObject()) + "] as me in elements { "
+ "[" + EcoreUtil.getURI(modelElement) + "] } "
+ " as me where tb.correspondingModelElements = me";
ResultSet resultSet = queryProcessor.execute(mqlTextBlocks, context);
URI[] resultURIs = resultSet.getUris("tb");
List<EObject> rootTbs = new ArrayList<EObject>(resultURIs.length);
for (URI uri : resultURIs) {
rootTbs.add(rs.getEObject(uri, true));
}
for (EObject o : rootTbs) {
if (o instanceof TextBlock) {
oldTextBlock = (TextBlock) o;
// if template has no syntax contribution, pretty printing is
// currently not possible
if (oldTextBlock.getType() == null
|| !template.equals(oldTextBlock.getType())) {
oldTextBlock = null;
} else {
break;
}
}
}
return oldTextBlock;
}
public TextBlock getRootBlock() {
return resultBlock;
}
}