package com.sap.furcas.runtime.textblocks.shortprettyprint; import java.util.Collection; import java.util.Iterator; import java.util.List; import org.eclipse.emf.ecore.EObject; import com.sap.furcas.metamodel.FURCAS.TCS.LiteralRef; import com.sap.furcas.metamodel.FURCAS.TCS.PrimitiveTemplate; import com.sap.furcas.metamodel.FURCAS.TCS.Property; import com.sap.furcas.metamodel.FURCAS.TCS.SeparatorPArg; import com.sap.furcas.metamodel.FURCAS.TCS.SequenceElement; import com.sap.furcas.metamodel.FURCAS.textblocks.AbstractToken; import com.sap.furcas.metamodel.FURCAS.textblocks.LexedToken; import com.sap.furcas.metamodel.FURCAS.textblocks.OmittedToken; import com.sap.furcas.metamodel.FURCAS.textblocks.TextBlock; import com.sap.furcas.runtime.common.exceptions.ModelAdapterException; import com.sap.furcas.runtime.common.interfaces.IModelElementInvestigator; import com.sap.furcas.runtime.common.util.TCSSpecificOCLEvaluator; import com.sap.furcas.runtime.tcs.PropertyArgumentUtil; import com.sap.furcas.runtime.textblocks.TbNavigationUtil; import com.sap.furcas.utils.Activator; public class ShortPrettyPrinter { private final static boolean doFlyWeight = true; private final IModelElementInvestigator investigator; private final TCSSpecificOCLEvaluator oclEvaluator; public ShortPrettyPrinter(IModelElementInvestigator investigator) { this.investigator = investigator; this.oclEvaluator = new TCSSpecificOCLEvaluator(); // TODO need a consistent OppositeEndFinder } public void makeFlyweight(TextBlock rootBlock) { if (doFlyWeight) { AbstractToken tok = TbNavigationUtil.firstToken(rootBlock); while (tok != null) { if (tok instanceof LexedToken) { if (((LexedToken) tok).getSequenceElement() instanceof Property && PropertyArgumentUtil .containsRefersToArg((Property) ((LexedToken) tok) .getSequenceElement())) { // remember value as secondary id for resolving } else { tok.setValue(null); } } tok = TbNavigationUtil.nextToken(tok); } } } public String resynchronizeToEditableState(AbstractToken token) { String originalValue = token.getValue(); String newValue = token.getValue(); if (doFlyWeight) { if (token instanceof LexedToken) { SequenceElement se = ((LexedToken) token).getSequenceElement(); if (se instanceof Property) { newValue = handlePropertyElement((Property) se, (LexedToken) token); } else if (se instanceof LiteralRef) { newValue = handleLiteralRef((LiteralRef) se); } } if (originalValue != null && newValue != null && originalValue.length() != newValue.length() && originalValue.replaceAll("\"", "").equals(newValue)) { newValue = originalValue; } } return newValue; } private String handleLiteralRef(LiteralRef se) { return se.getReferredLiteral().getValue(); } private String handlePropertyElement(Property se, LexedToken token) { EObject contextObject = null; // it is always the first element as all others do not have a syntax contribution! List<EObject> correspondingElements = token.getParent().getCorrespondingModelElements(); if (!correspondingElements.isEmpty()) { contextObject = correspondingElements.get(0); } else { return token.getValue(); } Object propertyValue = getPropertyValue(se, token, contextObject); String newValue = null; try { if (PropertyArgumentUtil.containsReferenceByPArg(se) && propertyValue instanceof EObject) { newValue = PrettyPrinterUtil.invertReferenceByQuery((EObject) propertyValue, se, oclEvaluator); } else { if (PropertyArgumentUtil.containsRefersToArg(se) && propertyValue instanceof EObject) { propertyValue = investigator.get(propertyValue, PropertyArgumentUtil.getRefersToPArg(se).getPropertyName()); if (propertyValue instanceof Collection<?> && ((Collection<?>) propertyValue).size() > 0) { propertyValue = ((Collection<?>) propertyValue).iterator().next(); } } if (propertyValue != null && !(propertyValue instanceof EObject) && !(propertyValue instanceof Collection<?>)) { newValue = propertyValue.toString(); } } } catch (ModelAdapterException e) { Activator.logger.logError("Failed to short prety print token value", e); } if (newValue == null) { // Failed to retrieve proeprty. Return the same value to keep the textual view intact, return token.getValue(); } else { PrimitiveTemplate template = PropertyArgumentUtil.getAsTemplate(PropertyArgumentUtil.getAsPArg(se)); return PrettyPrinterUtil.escapeUsingSerializer(newValue, template); } } private Object getPropertyValue(Property se, LexedToken token, EObject contextObject) { try { Object propertyValue = investigator.get(contextObject, se.getPropertyReference().getStrucfeature().getName()); if (propertyValue instanceof Collection<?> && ((Collection<?>) propertyValue).size() > 0) { Iterator<?> iter = ((Collection<?>) propertyValue).iterator(); // Need to find out the index of the element represented by the token. // All elements belonging to the same property have the same sequence element. // Counting these elements will give us the index of our token. AbstractToken previousToken = TbNavigationUtil.previousToken(token); while (belongsToSameProperty(se, previousToken) || isWhitespace(previousToken) || isSeparator(previousToken, se)) { if (belongsToSameProperty(se, previousToken)) { iter.next(); } previousToken = TbNavigationUtil.previousToken(previousToken); } propertyValue = iter.next(); } return propertyValue; } catch (ModelAdapterException e) { // element does not have such a property return null; } } private boolean isSeparator(AbstractToken previousToken, Property se) { SeparatorPArg sepParg = PropertyArgumentUtil.getSeparatorPArg(se); if (sepParg == null) { return false; } return sepParg.getSeparatorSequence().getElements().contains(previousToken.getSequenceElement()); } private boolean isWhitespace(AbstractToken previousToken) { return previousToken instanceof OmittedToken; } private boolean belongsToSameProperty(Property se, AbstractToken previousToken) { return previousToken != null && previousToken.getSequenceElement() == se; } }