/*******************************************************************************
* Copyright (c) 2011 SAP AG 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:
* SAP AG - initial API and implementation
******************************************************************************/
package com.sap.furcas.ide.editor.commands;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.transaction.RecordingCommand;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import com.sap.furcas.ide.editor.CtsActivator;
import com.sap.furcas.metamodel.FURCAS.TCS.ClassTemplate;
import com.sap.furcas.metamodel.FURCAS.TCS.ConcreteSyntax;
import com.sap.furcas.metamodel.FURCAS.textblocks.TextBlock;
import com.sap.furcas.metamodel.FURCAS.textblocks.Version;
import com.sap.furcas.prettyprinter.PrettyPrinter;
import com.sap.furcas.runtime.parser.PartitionAssignmentHandler;
import com.sap.furcas.runtime.tcs.MessageHelper;
import com.sap.furcas.runtime.tcs.TcsUtil;
import com.sap.furcas.runtime.textblocks.TbUtil;
import com.sap.furcas.runtime.textblocks.modifcation.TbChangeUtil;
import com.sap.ide.cts.parser.incremental.IncrementalParserFacade;
import com.sap.ide.cts.parser.incremental.MappingRecoveringTextBlocksValidator;
import com.sap.ide.cts.parser.incremental.TextBlockMappingRecoveringFailedException;
/**
* Does everything that is required to create a valid TextBlocks model
* for a given root object. Existing TextBlocks are re-used if available
* and recovered if needed, in order to extract their information (comments, formatting, ...)
*
* In any case, a fresh TextBlocks model is created. This is to make sure that the TextBlocks
* model is always valid and up-to-date (as expected by the incremental parser).
*
* @author Stephan Erb
*/
public class SetupTextBlocksModelCommand extends RecordingCommand {
private final IncrementalParserFacade parserFacade;
private final EObject rootObject;
private final TextBlock rootBlock;
private TextBlock resultBlock;
private final ConcreteSyntax syntax;
private final ClassTemplate mainTemplate;
private final PartitionAssignmentHandler partitionHandler;
public SetupTextBlocksModelCommand(TransactionalEditingDomain domain, EObject rootObject, TextBlock rootBlock,
IncrementalParserFacade parserFacade, PartitionAssignmentHandler partitionHandler) {
super(domain, "Initialize TextBlocks Model");
this.rootObject = rootObject;
this.rootBlock = rootBlock;
this.parserFacade = parserFacade;
this.partitionHandler = partitionHandler;
this.syntax = parserFacade.getParserScope().getSyntax();
this.mainTemplate = TcsUtil.getMainClassTemplate(syntax);
}
@Override
protected void doExecute() {
PrettyPrinter prettyPrinter = createPrettyPrinter();
try {
if (rootBlock != null) {
boolean wasNeeded = recoverOldBlock();
if (wasNeeded || TbUtil.getNewestVersion(rootBlock).getVersion() == Version.REFERENCE) {
resultBlock = prettyPrinter.prettyPrint(rootObject, rootBlock);
TbChangeUtil.deleteOtherVersions(rootBlock);
TbChangeUtil.delete(rootBlock);
} else {
resultBlock = rootBlock; // keep current one.
}
} else {
resultBlock = prettyPrinter.prettyPrint(rootObject);
}
} catch (Exception e) {
CtsActivator.logger.logError("Failed to initialize textual view", e);
throw new RuntimeException("Failed to initialize textual view", e);
}
setupPartitioning();
}
protected boolean recoverOldBlock() {
MappingRecoveringTextBlocksValidator validator = new MappingRecoveringTextBlocksValidator(parserFacade);
if (validator.hasBrokenMapping(rootBlock)) {
try {
validator.recoverMappingLink(rootBlock, mainTemplate);
} catch (TextBlockMappingRecoveringFailedException e) {
CtsActivator.logger.logError("Mapping recovery failed. Creating new textual view", e);
}
assertCorrectTextBlockType(rootBlock, mainTemplate);
return true;
}
return false;
}
protected void setupPartitioning() {
if (resultBlock.eResource() == null) {
// It is not optimal to do this here, as it is meant to be the task
// of the parser facade. However, the invariant that each textblock
// is always assigned to a resources makes the implementation of the
// rest of the editor much easier. (Currently required to calculated
// marker positions within the current document).
partitionHandler.setDefaultPartition(rootObject.eResource());
partitionHandler.assignToDefaultTextBlocksPartition(resultBlock);
}
}
protected PrettyPrinter createPrettyPrinter() {
return new PrettyPrinter(syntax, parserFacade.getParserScope().getMetamodelLookup(),
parserFacade.getOclEvaluator(), parserFacade.getParserFactory());
}
private static void assertCorrectTextBlockType(TextBlock rootBlock, ClassTemplate rootTemplate) {
if (rootBlock != null && !TbUtil.isTextBlockOfType(rootTemplate, rootBlock)) {
throw new RuntimeException("Main template " + MessageHelper.getTemplateName(rootTemplate) +
" does not fit the given TextBlocks model.");
}
}
public TextBlock getResultBlock() {
return resultBlock;
}
}