package com.sap.ide.refactoring.core.textual; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.Status; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.Document; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; import org.eclipse.ltk.core.refactoring.Change; import org.eclipse.ltk.core.refactoring.IRefactoringCoreStatusCodes; import org.eclipse.ltk.core.refactoring.NullChange; import org.eclipse.ltk.core.refactoring.RefactoringStatus; import org.eclipse.ltk.core.refactoring.TextEditBasedChange; import org.eclipse.ltk.core.refactoring.TextEditBasedChangeGroup; import com.sap.furcas.metamodel.FURCAS.textblocks.TextBlock; import com.sap.ide.refactoring.Activator; import com.sap.ide.refactoring.model.RefactoringModelUtil; /** * Glue coding to the Eclipe refactoring framework. It is used to present * pretty printing results in the Eclipse preview. * * @author Stephan Erb (d049157) * */ public class TextBlockChange extends TextEditBasedChange { private String preChangeState = ""; private String postChangeState = ""; private final RootElementTextBlockTuple rootTuple; /** * Cache name. We might not be able to construct if afterwards, if the * block is deleted by the pretty printer */ private final String name; private final RefactoringEditorFacade facade; private TextBlock postChangeRootBlock; public TextBlockChange(RefactoringEditorFacade facade, RootElementTextBlockTuple rootTuple) { super("Pretty Print"); this.facade = facade; this.rootTuple = rootTuple; this.name = getName(); fetchPreChangeState(); } @Override public Object getModifiedElement() { return rootTuple.modelElement; } @Override public String getName() { if (name == null) { String syntaxString = ""; try { syntaxString = " in Syntax \"" + rootTuple.textBlock.getType().getParseRule().getConcretesyntax().getName() + "\""; } catch (NullPointerException e) { // do nothing } return "Pretty Print: " + RefactoringModelUtil.getModelElementName(rootTuple.modelElement) + " (" + RefactoringModelUtil.getModelElementType(rootTuple.modelElement) + ")" + syntaxString; } else { return name; } } @Override public void initializeValidationData(IProgressMonitor pm) { } @Override public RefactoringStatus isValid(IProgressMonitor pm) throws OperationCanceledException { return new RefactoringStatus(); } @Override public Change perform(IProgressMonitor pm) { if (changeBelongsToEditorFacade() && postChangeRootBlock != null) { facade.updateRootBlock(postChangeRootBlock); facade.refreshUI(); } return new NullChange(); } private boolean changeBelongsToEditorFacade() { return facade.getDecoratedDomainRootObject().equals(rootTuple.modelElement) && facade.getTextBlocksModel().getRoot().equals(rootTuple.textBlock); } @Override public String getCurrentContent(IProgressMonitor pm) { return preChangeState; } @Override public String getPreviewContent(IProgressMonitor pm) { if (isEnabled()) { return postChangeState; } else { return preChangeState; } } @Override public String getCurrentContent(IRegion region, boolean expandRegionToFullLine, int surroundingLines, IProgressMonitor pm) throws CoreException { return clipToRegion(new Document(getCurrentContent(pm)), region, expandRegionToFullLine, surroundingLines); } @Override public String getPreviewContent(TextEditBasedChangeGroup[] changeGroups, IRegion region, boolean expandRegionToFullLine, int surroundingLines, IProgressMonitor pm) throws CoreException { return clipToRegion(new Document(getPreviewContent(pm)), region, expandRegionToFullLine, surroundingLines); } private String clipToRegion(IDocument document, IRegion region, boolean expandRegionToFullLine, int surroundingLines) throws CoreException { try { if (expandRegionToFullLine) { int startLine = Math.max(document.getLineOfOffset(region.getOffset()) - surroundingLines, 0); int endLine; if (region.getLength() == 0) { // no lines are in the region, so remove one from the // context, // or else spurious changes show up that look like deletes // from the source if (surroundingLines == 0) { // empty: show nothing return ""; } endLine = Math.min(document.getLineOfOffset(region.getOffset()) + surroundingLines - 1, document .getNumberOfLines() - 1); } else { endLine = Math.min(document.getLineOfOffset(region.getOffset() + region.getLength() - 1) + surroundingLines, document.getNumberOfLines() - 1); } int offset = document.getLineInformation(startLine).getOffset(); IRegion endLineRegion = document.getLineInformation(endLine); int length = endLineRegion.getOffset() + endLineRegion.getLength() - offset; return document.get(offset, length); } else { return document.get(region.getOffset(), region.getLength()); } } catch (BadLocationException e) { String message = e.getMessage(); if (message == null) { message = "BadLocationException"; } throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, IRefactoringCoreStatusCodes.BAD_LOCATION, message, e)); } } private void fetchPreChangeState() { System.out.println(">>>PRE"); preChangeState = getTextFromTextBlock(rootTuple.textBlock); } public void fetchPostChangeState(TextBlock modifiedBlock) { if (modifiedBlock == null) { postChangeState = ""; } else { System.out.println(">>>POST"); postChangeState = getTextFromTextBlock(modifiedBlock); postChangeRootBlock = modifiedBlock; } } private String getTextFromTextBlock(TextBlock textBlock) { try { // May fail if the model is invalid TextBlock rootBlock = TbNavigationUtil.getUltraRoot(textBlock); TextBlocksModel model = new TextBlocksModel(rootBlock, /*modelAdapter*/ null); System.out.println(model.get(0, model.getLength())); return model.get(0, model.getLength()); } catch (Exception e) { Activator.logError(e, "Failed to get text from text block model"); return "Failed to retrieve content. See Error log."; } } }