package com.sap.ide.refactoring.core.textual.prettyprint; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import org.antlr.runtime.Lexer; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.ltk.core.refactoring.RefactoringStatus; import tcs.ClassTemplate; import tcs.ConcreteSyntax; import textblocks.AbstractToken; import textblocks.TextBlock; import textblocks.TextblocksPackage; import com.sap.ide.cts.editor.EditorUtil; import com.sap.ide.cts.editor.prettyprint.imported.SyntaxAndModelMismatchException; import com.sap.ide.cts.editor.prettyprint.textblocks.TextBlockIndex; import com.sap.ide.cts.editor.prettyprint.textblocks.TextBlockTCSExtractorStream; import com.sap.ide.cts.moin.parserfactory.AbstractParserFactory; import com.sap.ide.refactoring.Activator; import com.sap.ide.refactoring.core.RefactoringCoreException; import com.sap.ide.refactoring.core.RefactoringSeverity; import com.sap.ide.refactoring.core.textual.ModelElementDocumentNodeChangeDescriptor; import com.sap.mi.textual.grammar.impl.ObservableInjectingParser; import com.sap.tc.moin.repository.mmi.reflect.RefObject; /** * A wrapper about incremental pretty printers that enables them * to correctly handle the move of an decorated object: the corresponding * TextBlock will be moved as well. * * @author Stephan Erb (d049157) * */ public class BatchPrettyPrinter { private final Map<ModelElementDocumentNodeChangeDescriptor, DelayedIncrementalPrettyPrinter> prettyPrinterPerChange = new HashMap<ModelElementDocumentNodeChangeDescriptor, DelayedIncrementalPrettyPrinter>(); private final Map<ModelElementDocumentNodeChangeDescriptor, TextBlock> printedResulTextBlockPerChange = new HashMap<ModelElementDocumentNodeChangeDescriptor, TextBlock>(); private final RefactoringStatus status = new RefactoringStatus(); private final TextBlockIndex sharedIndex = new TextBlockIndex(); public void queuePrettyPrintJob(ModelElementDocumentNodeChangeDescriptor changeDescriptor) { if (changeDescriptor.documentNode instanceof AbstractToken) { Activator.logWarning("Skipping Token: Can only prettyprint TextBlocks, not Tokens,."); return; } TextBlock textBlockToPrint = (TextBlock) changeDescriptor.documentNode; if (textBlockToPrint.getType() == null || textBlockToPrint.getType().getParseRule() == null) { Activator.logWarning("Ignoring TextBlock in pretty printing due to broken mapping: " + textBlockToPrint); return; } try { prettyPrinterPerChange.put(changeDescriptor, getAndSetupDelayedPrettyPrinter(changeDescriptor)); } catch (Exception e) { Activator.logError(e, "Unable to setup pretty printer for: " + changeDescriptor.modelElement); status.merge(new RefactoringCoreException("Unable to setup pretty printer for: " + changeDescriptor.modelElement, e).asRefactoringStatus(RefactoringSeverity.ERROR)); } } private DelayedIncrementalPrettyPrinter getAndSetupDelayedPrettyPrinter(ModelElementDocumentNodeChangeDescriptor changeDescriptor) { TextBlock textBlockToPrint = (TextBlock) changeDescriptor.documentNode; sharedIndex.index(textBlockToPrint); return new DelayedIncrementalPrettyPrinter(sharedIndex); } public RefactoringStatus run(IProgressMonitor pm) { pm.beginTask("", prettyPrinterPerChange.size()*2); for (Entry<ModelElementDocumentNodeChangeDescriptor, DelayedIncrementalPrettyPrinter> entry : prettyPrinterPerChange.entrySet()) { try { DelayedIncrementalPrettyPrinter prettyPrinter = entry.getValue(); ModelElementDocumentNodeChangeDescriptor changeDescriptor = entry.getKey(); TextBlock result = prettyPrint(prettyPrinter, changeDescriptor); printedResulTextBlockPerChange.put(changeDescriptor, result); } catch (Exception e) { Activator.logError(e, "Unable to pretty print "+ entry.getKey().modelElement); status.merge(new RefactoringCoreException("Unable to pretty print "+ entry.getKey().modelElement, e).asRefactoringStatus(RefactoringSeverity.ERROR)); } finally { pm.worked(1); } } pm.subTask("Construction new TextBlocks models."); for (Entry<ModelElementDocumentNodeChangeDescriptor, DelayedIncrementalPrettyPrinter> entry : prettyPrinterPerChange.entrySet()) { try { if (!printedResulTextBlockPerChange.containsKey(entry.getKey())) { // pretty printing failed with exception; there is nothing to finish ere continue; } DelayedIncrementalPrettyPrinter prettyPrinter = entry.getValue(); prettyPrinter.finish(); } catch (Exception e) { Activator.logError(e, "Unable to finish pretty printing for "+ entry.getKey().modelElement); status.merge(new RefactoringCoreException("Unable to finish pretty printing for "+ entry.getKey().modelElement, e).asRefactoringStatus(RefactoringSeverity.ERROR)); } finally { pm.worked(1); } } pm.done(); return status; } private TextBlock prettyPrint(DelayedIncrementalPrettyPrinter prettyPrinter, ModelElementDocumentNodeChangeDescriptor changeDescriptor) throws SyntaxAndModelMismatchException { TextBlock textBlockToPrint = (TextBlock) changeDescriptor.documentNode; RefObject correspondingModelElement = changeDescriptor.modelElement; assert textBlockToPrint != null && correspondingModelElement != null; ClassTemplate template = (ClassTemplate) textBlockToPrint.getType().getParseRule(); ConcreteSyntax syntax = template.getConcretesyntax(); AbstractParserFactory<? extends ObservableInjectingParser, ? extends Lexer> parserFactory = EditorUtil.constructParserFactoryForSyntax(syntax); TextblocksPackage tbPackage = textBlockToPrint.get___Connection().getPackage(TextblocksPackage.PACKAGE_DESCRIPTOR); TextBlockTCSExtractorStream stream = new TextBlockTCSExtractorStream(tbPackage, textBlockToPrint.get___Partition(), parserFactory); prettyPrinter.prettyPrint(correspondingModelElement, textBlockToPrint, syntax, template, stream); return stream.getPrintedResultRootBlock(); } public TextBlock getPrettyPrinterResultFor(ModelElementDocumentNodeChangeDescriptor changeDescriptor) { if (printedResulTextBlockPerChange.containsKey(changeDescriptor)) { return printedResulTextBlockPerChange.get(changeDescriptor); } else { return null; } } }