2 * Copyright 2000-2015 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com.intellij.diff.tools.simple;
18 import com.intellij.diff.comparison.ComparisonManager;
19 import com.intellij.diff.comparison.ComparisonPolicy;
20 import com.intellij.diff.fragments.MergeLineFragment;
21 import com.intellij.diff.util.DiffUtil;
22 import com.intellij.diff.util.Side;
23 import com.intellij.diff.util.TextDiffType;
24 import com.intellij.diff.util.ThreeSide;
25 import com.intellij.openapi.editor.ex.DocumentEx;
26 import com.intellij.openapi.editor.ex.EditorEx;
27 import com.intellij.openapi.util.text.StringUtil;
28 import org.jetbrains.annotations.NotNull;
29 import org.jetbrains.annotations.Nullable;
31 import java.util.List;
33 public abstract class ThreesideDiffChangeBase {
34 @NotNull private ConflictType myType;
36 public ThreesideDiffChangeBase(@NotNull MergeLineFragment fragment,
37 @NotNull List<? extends EditorEx> editors,
38 @NotNull ComparisonPolicy policy) {
39 myType = calcType(fragment, editors, policy);
46 public abstract int getStartLine(@NotNull ThreeSide side);
48 public abstract int getEndLine(@NotNull ThreeSide side);
51 public TextDiffType getDiffType() {
52 return myType.getDiffType();
56 public ConflictType getType() {
60 public boolean isConflict() {
61 return getDiffType() == TextDiffType.CONFLICT;
64 public boolean isChange(@NotNull Side side) {
65 return myType.isChange(side);
73 private static ConflictType calcType(@NotNull MergeLineFragment fragment,
74 @NotNull List<? extends EditorEx> editors,
75 @NotNull ComparisonPolicy policy) {
76 boolean isLeftEmpty = isIntervalEmpty(fragment, ThreeSide.LEFT);
77 boolean isBaseEmpty = isIntervalEmpty(fragment, ThreeSide.BASE);
78 boolean isRightEmpty = isIntervalEmpty(fragment, ThreeSide.RIGHT);
79 assert !isLeftEmpty || !isBaseEmpty || !isRightEmpty;
82 if (isLeftEmpty) { // --=
83 return new ConflictType(TextDiffType.INSERTED, false, true);
85 else if (isRightEmpty) { // =--
86 return new ConflictType(TextDiffType.INSERTED, true, false);
89 boolean equalModifications = compareLeftAndRight(fragment, editors, policy);
90 return new ConflictType(equalModifications ? TextDiffType.INSERTED : TextDiffType.CONFLICT);
94 if (isLeftEmpty && isRightEmpty) { // -=-
95 return new ConflictType(TextDiffType.DELETED);
97 else { // -==, ==-, ===
98 boolean unchangedLeft = compareWithBase(fragment, editors, ThreeSide.LEFT);
99 boolean unchangedRight = compareWithBase(fragment, editors, ThreeSide.RIGHT);
100 assert !unchangedLeft || !unchangedRight;
102 if (unchangedLeft) return new ConflictType(isRightEmpty ? TextDiffType.DELETED : TextDiffType.MODIFIED, false, true);
103 if (unchangedRight) return new ConflictType(isLeftEmpty ? TextDiffType.DELETED : TextDiffType.MODIFIED, true, false);
105 boolean equalModifications = compareLeftAndRight(fragment, editors, policy);
106 return new ConflictType(equalModifications ? TextDiffType.MODIFIED : TextDiffType.CONFLICT);
111 private static boolean compareLeftAndRight(@NotNull MergeLineFragment fragment,
112 @NotNull List<? extends EditorEx> editors,
113 @NotNull ComparisonPolicy policy) {
114 CharSequence content1 = getRangeContent(fragment, editors, ThreeSide.LEFT);
115 CharSequence content2 = getRangeContent(fragment, editors, ThreeSide.RIGHT);
117 if (policy == ComparisonPolicy.IGNORE_WHITESPACES) {
118 if (content1 == null) content1 = "";
119 if (content2 == null) content2 = "";
122 if (content1 == null && content2 == null) return true;
123 if (content1 == null ^ content2 == null) return false;
125 return ComparisonManager.getInstance().isEquals(content1, content2, policy);
128 private static boolean compareWithBase(@NotNull MergeLineFragment fragment,
129 @NotNull List<? extends EditorEx> editors,
130 @NotNull ThreeSide side) {
131 CharSequence content1 = getRangeContent(fragment, editors, ThreeSide.BASE);
132 CharSequence content2 = getRangeContent(fragment, editors, side);
134 return StringUtil.equals(content1, content2);
138 private static CharSequence getRangeContent(@NotNull MergeLineFragment fragment,
139 @NotNull List<? extends EditorEx> editors,
140 @NotNull ThreeSide side) {
141 DocumentEx document = side.select(editors).getDocument();
142 int line1 = fragment.getStartLine(side);
143 int line2 = fragment.getEndLine(side);
144 if (line1 == line2) return null;
145 return DiffUtil.getLinesContent(document, line1, line2);
148 private static boolean isIntervalEmpty(@NotNull MergeLineFragment fragment, @NotNull ThreeSide side) {
149 return fragment.getStartLine(side) == fragment.getEndLine(side);
156 public static class ConflictType {
157 @NotNull private final TextDiffType myType;
158 private final boolean myLeftChange;
159 private final boolean myRightChange;
161 public ConflictType(@NotNull TextDiffType type) {
162 this(type, true, true);
165 public ConflictType(@NotNull TextDiffType type, boolean leftChange, boolean rightChange) {
167 myLeftChange = leftChange;
168 myRightChange = rightChange;
172 public TextDiffType getDiffType() {
176 public boolean isLeftChange() {
180 public boolean isRightChange() {
181 return myRightChange;
184 public boolean isChange(@NotNull Side side) {
185 return side.isLeft() ? myLeftChange : myRightChange;