blob: 612292f22cfb5532df3f5f4bae3705d8a656c60a [file] [log] [blame]
/*
* Copyright 2000-2011 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.openapi.diff.impl.dir;
import com.intellij.ide.diff.*;
import com.intellij.util.containers.HashMap;
import com.intellij.util.containers.SortedList;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import static com.intellij.ide.diff.DiffType.ERROR;
/**
* @author Konstantin Bulenkov
*/
public class DTree {
private static final Comparator<DTree> COMPARATOR = new Comparator<DTree>() {
@Override
public int compare(DTree o1, DTree o2) {
final boolean b1 = o1.isContainer();
final boolean b2 = o2.isContainer();
return (b1 && b2) || (!b1 && !b2)
? o1.getName().compareToIgnoreCase(o2.getName())
: b1 ? 1 : -1;
}
};
private boolean myExpanded = true;
@Nullable private final DTree myParent;
private HashMap<String, DTree> myChildren;
private String myName;
private final boolean isContainer;
private SortedList<DTree> myChildrenList;
private DiffElement<?> mySource;
private DiffElement<?> myTarget;
private DiffType myType;
private boolean myVisible = true;
private String mySeparator = null;
private String myPath = null;
public DTree(@Nullable DTree parent, @NotNull String name, boolean container) {
this.myParent = parent;
this.myName = name;
isContainer = container;
}
@NotNull
public Collection<DTree> getChildren() {
init();
if (myChildrenList == null) {
myChildrenList = new SortedList<DTree>(COMPARATOR);
myChildrenList.addAll(myChildren.values());
}
return myChildrenList;
}
public DTree addChild(@NotNull DiffElement element, boolean source) {
init();
myChildrenList = null;
final DTree node;
final String name = element.getName();
if (myChildren.containsKey(name)) {
node = myChildren.get(name);
} else {
node = new DTree(this, name, element.isContainer());
myChildren.put(name, node);
}
if (source) {
node.setSource(element);
} else {
node.setTarget(element);
}
return node;
}
public DiffElement<?> getSource() {
return mySource;
}
public void setSource(DiffElement<?> source) {
mySource = source;
}
public DiffElement<?> getTarget() {
return myTarget;
}
public void setTarget(DiffElement<?> target) {
myTarget = target;
}
private void init() {
if (myChildren == null) {
myChildren = new HashMap<String, DTree>();
}
}
public String getName() {
return myName;
}
@Nullable
public DTree getParent() {
return myParent;
}
public boolean isExpanded() {
return myExpanded;
}
public void setExpanded(boolean expanded) {
this.myExpanded = expanded;
}
public boolean isContainer() {
return isContainer;
}
@Override
public String toString() {
return myName;
}
public void update(DirDiffSettings settings) {
for (DTree tree : getChildren()) {
final DiffElement<?> src = tree.getSource();
final DiffElement<?> trg = tree.getTarget();
if (src instanceof DiffErrorElement || trg instanceof DiffErrorElement) {
tree.setType(ERROR);
} else if (src == null && trg != null) {
tree.setType(DiffType.TARGET);
} else if (src != null && trg == null) {
tree.setType(DiffType.SOURCE);
} else {
assert src != null;
DiffType dtype = src.getSize() == trg.getSize() ? DiffType.EQUAL : DiffType.CHANGED;
if (dtype == DiffType.EQUAL) {
switch (settings.compareMode) {
case CONTENT:
dtype = isEqual(src, trg) ? DiffType.EQUAL : DiffType.CHANGED;
break;
case TIMESTAMP:
dtype = Math.abs(src.getTimeStamp() - trg.getTimeStamp()) <= settings.compareTimestampAccuracy ? DiffType.EQUAL : DiffType.CHANGED;
break;
}
}
tree.setType(dtype);
}
tree.update(settings);
}
}
public boolean isVisible() {
return myVisible;
}
public void updateVisibility(DirDiffSettings settings) {
if (getChildren().isEmpty()) {
if (myType == ERROR) {
myVisible = true;
return;
}
if (myType != DiffType.SEPARATOR && !"".equals(settings.getFilter())) {
if (!settings.getFilterPattern().matcher(getName()).matches()) {
myVisible = false;
return;
}
}
if (myType == null) {
myVisible = true;
} else {
switch (myType) {
case SOURCE:
myVisible = settings.showNewOnSource;
break;
case TARGET:
myVisible = settings.showNewOnTarget;
break;
case SEPARATOR:
case ERROR:
myVisible = true;
break;
case CHANGED:
myVisible = settings.showDifferent;
break;
case EQUAL:
myVisible = settings.showEqual;
break;
}
}
} else {
myVisible = false;
for (DTree child : myChildren.values()) {
child.updateVisibility(settings);
myVisible = myVisible || child.isVisible();
}
}
}
public void reset() {
myChildren.clear();
}
public void remove(DTree node) {
init();
final boolean removed = myChildrenList.remove(node);
if (removed) {
for (String key : myChildren.keySet()) {
if (myChildren.get(key) == node) {
myChildren.remove(key);
return;
}
}
}
}
private static boolean isEqual(DiffElement file1, DiffElement file2) {
if (file1.isContainer() || file2.isContainer()) return false;
if (file1.getSize() != file2.getSize()) return false;
try {
return Arrays.equals(file1.getContent(), file2.getContent());
}
catch (IOException e) {
return false;
}
}
public DiffType getType() {
return myType;
}
public void setType(DiffType type) {
this.myType = type;
}
public String getPath() {
if (myPath == null) {
final DTree parent = getParent();
if (parent != null) {
myPath = parent.getPath() + getName() + (isContainer ? getSeparator() : "");
} else {
myPath = getName() + (isContainer ? getSeparator() : "");
}
}
return myPath;
}
private String getSeparator() {
if (mySeparator == null) {
mySeparator = mySource != null ? mySource.getSeparator() : myTarget != null ? myTarget.getSeparator() : "";
}
return mySeparator;
}
}