001/*-----------------------------------------------------------------------+
002 | com.teamscale.ui
003 |                                                                       |
004   $Id$            
005 |                                                                       |
006 | Copyright (c)  2009-2013 CQSE GmbH                                 |
007 +-----------------------------------------------------------------------*/
008package org.conqat.lib.commons.diff;
009
010import java.util.ArrayList;
011import java.util.List;
012
013import org.conqat.lib.commons.string.StringUtils;
014
015/**
016 * Class for calculating a line-based diff.
017 */
018public class LineBasedDiffer extends DifferBase<String> {
019
020        /** Whether to ignore whitespace in each line. */
021        private final boolean ignoreWhitespace;
022
023        /** Constructor. */
024        public LineBasedDiffer(boolean ignoreWhitespace) {
025                this.ignoreWhitespace = ignoreWhitespace;
026        }
027
028        /** {@inheritDoc} */
029        @Override
030        protected String getElementText(String element) {
031                return element;
032        }
033
034        /** {@inheritDoc} */
035        @Override
036        protected String getDiffName() {
037                String diffName = "line-based";
038                if (ignoreWhitespace) {
039                        diffName += " (ignore whitespace)";
040                }
041                return diffName;
042        }
043
044        /** {@inheritDoc} */
045        @Override
046        protected List<TextChunk> getChunks(String elementText, boolean isLeft) {
047                List<String> lines = StringUtils.splitLinesAsList(elementText);
048
049                List<TextChunk> result = new ArrayList<TextChunk>();
050                int offset = 0;
051                int lineNumber = 1;
052                for (String line : lines) {
053                        result.add(createChunkForLine(offset, lineNumber, line));
054                        offset += line.length() + 1;
055                        lineNumber += 1;
056                }
057                return result;
058        }
059
060        /** Creates a chunk for a single line of the element. */
061        private TextChunk createChunkForLine(int offset, int lineNumber, String line) {
062                int startOffset = offset;
063                int endOffset = startOffset + line.length();
064                String comparisonText = line;
065
066                if (ignoreWhitespace) {
067                        comparisonText = line.replaceFirst("^\\s+", StringUtils.EMPTY_STRING);
068                        int removed = endOffset - startOffset - comparisonText.length();
069
070                        startOffset += removed;
071
072                        comparisonText = line.replaceFirst("\\s+$", StringUtils.EMPTY_STRING);
073                        removed = endOffset - startOffset - comparisonText.length();
074                        endOffset -= removed;
075
076                        comparisonText = comparisonText.replaceAll("\\s+", StringUtils.EMPTY_STRING);
077                }
078
079                return new TextChunk(startOffset, endOffset, lineNumber, lineNumber + 1, comparisonText);
080        }
081}