/* * Copyright 2000-2010 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.intellij.application.options; import com.intellij.openapi.Disposable; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.diff.DiffContent; import com.intellij.openapi.diff.actions.MergeOperations; import com.intellij.openapi.diff.impl.ComparisonPolicy; import com.intellij.openapi.diff.impl.fragments.Fragment; import com.intellij.openapi.diff.impl.fragments.FragmentHighlighterImpl; import com.intellij.openapi.diff.impl.fragments.LineFragment; import com.intellij.openapi.diff.impl.highlighting.DiffMarkup; import com.intellij.openapi.diff.impl.highlighting.FragmentSide; import com.intellij.openapi.diff.impl.processing.TextCompareProcessor; import com.intellij.openapi.diff.impl.util.TextDiffType; import com.intellij.openapi.diff.impl.util.TextDiffTypeEnum; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.ex.EditorEx; import com.intellij.openapi.editor.markup.GutterIconRenderer; import com.intellij.openapi.editor.markup.SeparatorPlacement; import com.intellij.openapi.fileEditor.FileEditor; import com.intellij.openapi.util.TextRange; import com.intellij.util.diff.FilesTooBigForDiffException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; /** * Allows to calculate difference between two versions of document (before and after code style setting value change). * <p/> * Not thread-safe. * * @author Denis Zhdanov * @since 10/14/10 2:44 PM */ public class ChangesDiffCalculator implements Disposable { private static final Logger LOG = Logger.getInstance("#com.intellij.application.options.ChangesDiffCalculator"); private final BaseMarkup myOldMarkup = new BaseMarkup(FragmentSide.SIDE1, this); private final ChangesCollector myNewMarkup = new ChangesCollector(this); private final TextCompareProcessor myCompareProcessor = new TextCompareProcessor(ComparisonPolicy.DEFAULT); public Collection<TextRange> calculateDiff(@NotNull final Document beforeDocument, @NotNull final Document currentDocument) { myNewMarkup.ranges.clear(); myOldMarkup.document = beforeDocument; myNewMarkup.document = currentDocument; List<LineFragment> lineFragments; try { lineFragments = myCompareProcessor.process(beforeDocument.getText(), currentDocument.getText()); } catch (FilesTooBigForDiffException e) { LOG.info(e); return Collections.emptyList(); } final FragmentHighlighterImpl fragmentHighlighter = new FragmentHighlighterImpl(myOldMarkup, myNewMarkup); for (Iterator<LineFragment> iterator = lineFragments.iterator(); iterator.hasNext();) { LineFragment fragment = iterator.next(); fragmentHighlighter.setIsLast(!iterator.hasNext()); fragment.highlight(fragmentHighlighter); } return new ArrayList<TextRange>(myNewMarkup.ranges); } @Override public void dispose() { } /** * Base {@link DiffMarkup} implementation that does nothing. */ @SuppressWarnings({"ConstantConditions"}) private static class BaseMarkup extends DiffMarkup { public Document document; private final FragmentSide mySide; BaseMarkup(@NotNull FragmentSide side, @NotNull Disposable parentDisposable) { super(null, parentDisposable); mySide = side; } @Override public FragmentSide getSide() { return mySide; } @Override public DiffContent getContent() { return null; } @Override public EditorEx getEditor() { return null; } @Nullable @Override public Document getDocument() { return document; } @Override public void addLineMarker(int line, TextDiffType type, SeparatorPlacement separatorPlacement) { } @Override public void addAction(MergeOperations.Operation operation, int lineStartOffset) { } @Override public void highlightText(@NotNull Fragment fragment, GutterIconRenderer gutterIconRenderer) { } @Override public FileEditor getFileEditor() { return null; } } private static class ChangesCollector extends BaseMarkup { private static final Set<TextDiffTypeEnum> INTERESTED_DIFF_TYPES = EnumSet.of(TextDiffTypeEnum.INSERT, TextDiffTypeEnum.DELETED, TextDiffTypeEnum.CHANGED); public final List<TextRange> ranges = new ArrayList<TextRange>(); ChangesCollector(@NotNull Disposable parentDisposable) { super(FragmentSide.SIDE2, parentDisposable); } @Override public void highlightText(@NotNull Fragment fragment, GutterIconRenderer gutterIconRenderer) { TextRange currentRange = fragment.getRange(FragmentSide.SIDE2); if (INTERESTED_DIFF_TYPES.contains(fragment.getType())) { ranges.add(currentRange); } } } }