/******************************************************************************* * Copyright (c) 2000, 2017 IBM Corporation 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: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.dltk.internal.testing.ui; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.nio.charset.StandardCharsets; import org.eclipse.compare.CompareConfiguration; import org.eclipse.compare.CompareViewerPane; import org.eclipse.compare.IEncodedStreamContentAccessor; import org.eclipse.compare.ITypedElement; import org.eclipse.compare.contentmergeviewer.TextMergeViewer; import org.eclipse.compare.structuremergeviewer.DiffNode; import org.eclipse.core.runtime.CoreException; import org.eclipse.dltk.internal.testing.model.TestElement; import org.eclipse.dltk.testing.DLTKTestingMessages; import org.eclipse.dltk.testing.DLTKTestingPlugin; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.IDialogSettings; import org.eclipse.jface.dialogs.TrayDialog; import org.eclipse.jface.text.DocumentEvent; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITypedRegion; import org.eclipse.jface.text.Region; import org.eclipse.jface.text.TextAttribute; import org.eclipse.jface.text.TextPresentation; import org.eclipse.jface.text.TextViewer; import org.eclipse.jface.text.presentation.IPresentationDamager; import org.eclipse.jface.text.presentation.IPresentationReconciler; import org.eclipse.jface.text.presentation.IPresentationRepairer; import org.eclipse.jface.text.presentation.PresentationReconciler; import org.eclipse.jface.text.source.ISourceViewer; import org.eclipse.jface.text.source.SourceViewer; import org.eclipse.jface.text.source.SourceViewerConfiguration; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.StyleRange; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.PlatformUI; public class CompareResultDialog extends TrayDialog { private static final String PREFIX_SUFFIX_PROPERTY = "org.eclipse.jdt.internal.junit.ui.CompareResultDialog.prefixSuffix"; //$NON-NLS-1$ private static class CompareResultMergeViewer extends TextMergeViewer { private CompareResultMergeViewer(Composite parent, int style, CompareConfiguration configuration) { super(parent, style, configuration); } @Override protected void createControls(Composite composite) { super.createControls(composite); PlatformUI.getWorkbench().getHelpSystem().setHelp(composite, IDLTKTestingHelpContextIds.RESULT_COMPARE_DIALOG); } // protected void createToolItems(ToolBarManager tbm) { // ResourceBundle bundle= CompareUI.getResourceBundle(); // tbm.add(new IgnoreWhiteSpaceAction(bundle, // getCompareConfiguration())); // super.createToolItems(tbm); // } @Override protected void configureTextViewer(TextViewer textViewer) { if (textViewer instanceof SourceViewer) { int[] prefixSuffixOffsets = (int[]) getCompareConfiguration() .getProperty(PREFIX_SUFFIX_PROPERTY); ((SourceViewer) textViewer) .configure(new CompareResultViewerConfiguration( prefixSuffixOffsets)); } } } private static class CompareResultViewerConfiguration extends SourceViewerConfiguration { private static class SimpleDamagerRepairer implements IPresentationDamager, IPresentationRepairer { private IDocument fDocument; private final int[] fPrefixSuffixOffsets2; public SimpleDamagerRepairer(int[] prefixSuffixOffsets) { fPrefixSuffixOffsets2 = prefixSuffixOffsets; } @Override public void setDocument(IDocument document) { fDocument = document; } @Override public IRegion getDamageRegion(ITypedRegion partition, DocumentEvent event, boolean changed) { return new Region(0, fDocument.getLength()); } @Override public void createPresentation(TextPresentation presentation, ITypedRegion damage) { int prefix = fPrefixSuffixOffsets2[0]; int suffix = fPrefixSuffixOffsets2[1]; TextAttribute attr = new TextAttribute( Display.getDefault().getSystemColor(SWT.COLOR_RED), null, SWT.BOLD); presentation.addStyleRange(new StyleRange(prefix, fDocument.getLength() - suffix - prefix, attr.getForeground(), attr.getBackground(), attr.getStyle())); } } private final int[] fPrefixSuffixOffsets; public CompareResultViewerConfiguration(int[] prefixSuffixOffsets) { fPrefixSuffixOffsets = prefixSuffixOffsets; } @Override public IPresentationReconciler getPresentationReconciler( ISourceViewer sourceViewer) { PresentationReconciler reconciler = new PresentationReconciler(); SimpleDamagerRepairer dr = new SimpleDamagerRepairer( fPrefixSuffixOffsets); reconciler.setDamager(dr, IDocument.DEFAULT_CONTENT_TYPE); reconciler.setRepairer(dr, IDocument.DEFAULT_CONTENT_TYPE); return reconciler; } } private static class CompareElement implements ITypedElement, IEncodedStreamContentAccessor { private String fContent; public CompareElement(String content) { fContent = content; } @Override public String getName() { return "<no name>"; //$NON-NLS-1$ } @Override public Image getImage() { return null; } @Override public String getType() { return "txt"; //$NON-NLS-1$ } @Override public InputStream getContents() { return new ByteArrayInputStream( fContent.getBytes(StandardCharsets.UTF_8)); } @Override public String getCharset() throws CoreException { return "UTF-8"; //$NON-NLS-1$ } } private TextMergeViewer fViewer; private String fExpected; private String fActual; private String fTestName; /** * Lengths of common prefix and suffix. Note: this array is passed to the * DamagerRepairer and the lengths are updated on content change. */ private final int[] fPrefixSuffix = new int[2]; public CompareResultDialog(Shell parentShell, TestElement element) { super(parentShell); setShellStyle(SWT.DIALOG_TRIM | SWT.RESIZE | SWT.MAX); setFailedTest(element); } private void setFailedTest(TestElement failedTest) { fTestName = failedTest.getTestName(); fExpected = failedTest.getExpected(); fActual = failedTest.getActual(); computePrefixSuffix(); } @Override protected IDialogSettings getDialogBoundsSettings() { return DLTKTestingPlugin.getDefault() .getDialogSettingsSection(getClass().getName()); } private void computePrefixSuffix() { int end = Math.min(fExpected.length(), fActual.length()); int i = 0; for (; i < end; i++) if (fExpected.charAt(i) != fActual.charAt(i)) break; fPrefixSuffix[0] = i; int j = fExpected.length() - 1; int k = fActual.length() - 1; int l = 0; for (; k >= i && j >= i; k--, j--) { if (fExpected.charAt(j) != fActual.charAt(k)) break; l++; } fPrefixSuffix[1] = l; } @Override protected void configureShell(Shell newShell) { super.configureShell(newShell); newShell.setText(DLTKTestingMessages.CompareResultDialog_title); PlatformUI.getWorkbench().getHelpSystem().setHelp(newShell, IDLTKTestingHelpContextIds.RESULT_COMPARE_DIALOG); } @Override protected void createButtonsForButtonBar(Composite parent) { createButton(parent, IDialogConstants.OK_ID, DLTKTestingMessages.CompareResultDialog_labelOK, true); } @Override protected Control createDialogArea(Composite parent) { Composite composite = (Composite) super.createDialogArea(parent); GridLayout layout = new GridLayout(); layout.numColumns = 1; composite.setLayout(layout); CompareViewerPane pane = new CompareViewerPane(composite, SWT.BORDER | SWT.FLAT); pane.setText(fTestName); GridData data = new GridData( GridData.FILL_HORIZONTAL | GridData.FILL_VERTICAL); data.widthHint = convertWidthInCharsToPixels(120); data.heightHint = convertHeightInCharsToPixels(13); pane.setLayoutData(data); Control previewer = createPreviewer(pane); pane.setContent(previewer); GridData gd = new GridData(GridData.FILL_BOTH); previewer.setLayoutData(gd); applyDialogFont(parent); return composite; } private Control createPreviewer(Composite parent) { final CompareConfiguration compareConfiguration = new CompareConfiguration(); compareConfiguration.setLeftLabel( DLTKTestingMessages.CompareResultDialog_expectedLabel); compareConfiguration.setLeftEditable(false); compareConfiguration.setRightLabel( DLTKTestingMessages.CompareResultDialog_actualLabel); compareConfiguration.setRightEditable(false); compareConfiguration.setProperty(CompareConfiguration.IGNORE_WHITESPACE, Boolean.FALSE); compareConfiguration.setProperty(PREFIX_SUFFIX_PROPERTY, fPrefixSuffix); fViewer = new CompareResultMergeViewer(parent, SWT.NONE, compareConfiguration); setCompareViewerInput(); Control control = fViewer.getControl(); control.addDisposeListener(e -> compareConfiguration.dispose()); return control; } private void setCompareViewerInput() { if (!fViewer.getControl().isDisposed()) fViewer.setInput(new DiffNode(new CompareElement(fExpected), new CompareElement(fActual))); } public void setInput(TestElement failedTest) { setFailedTest(failedTest); setCompareViewerInput(); } }