blob: 0f38a499c5373b103dc3afb781b5b8452c89630c [file] [log] [blame]
/*
* Copyright 2000-2014 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 git4idea.history.wholeTree;
import com.intellij.openapi.diff.impl.patch.formove.FilePathComparator;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Couple;
import com.intellij.openapi.vcs.BigArray;
import com.intellij.openapi.vcs.GroupingMerger;
import com.intellij.openapi.vcs.changes.committed.DateChangeListGroupingStrategy;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.containers.*;
import com.intellij.util.ui.ColumnInfo;
import git4idea.history.browser.GitHeavyCommit;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.table.AbstractTableModel;
import java.util.*;
import java.util.HashMap;
import java.util.HashSet;
/**
* @author irengrig
*/
public class BigTableTableModel extends AbstractTableModel {
public final static Object LOADING = new Object();
public static final String STASH = "Stash";
// should be grouped
@Nullable
private Map<VirtualFile, SkeletonBuilder> mySkeletonBuilder;
@Nullable
private Map<VirtualFile, TreeNavigationImpl> myNavigation;
@Nullable
private List<VirtualFile> myOrder;
private Map<VirtualFile, Integer> myAdditions;
// end group
private final BidirectionalMap<InnerIdx, Integer> myIdxMap;
// for faster drawing
private final Map<VirtualFile, TreeSet<Integer>> myRepoIdxMap;
// index of NEXT
private final Map<VirtualFile, Integer> myRunningRepoIdxs;
@NotNull
private final List<ColumnInfo> myColumns;
private RootsHolder myRootsHolder;
@Nullable
private StepList<CommitI> myLines;
private int myCutCount;
private DetailsCache myCache;
private Runnable myInit;
private CommitGroupingStrategy myStrategy;
private Comparator<CommitI> myCurrentComparator;
private int myCommitIdxInterval;
private int myNumEventsInGroup;
private final Set<VirtualFile> myActiveRoots;
private final CommitGroupingStrategy myDefaultStrategy;
private final CommitGroupingStrategy myNoGrouping;
private final Map<VirtualFile,Couple<AbstractHash>> myStashTops;
private final Map<VirtualFile, TreeHighlighter> myTreeHighlighter;
public BigTableTableModel(@NotNull final List<ColumnInfo> columns, Runnable init) {
myColumns = columns;
myInit = init;
myIdxMap = new BidirectionalMap<InnerIdx, Integer>();
myRunningRepoIdxs = new HashMap<VirtualFile, Integer>();
myRepoIdxMap = new HashMap<VirtualFile, TreeSet<Integer>>();
myActiveRoots = new HashSet<VirtualFile>();
myCurrentComparator = CommitIReorderingInsideOneRepoComparator.getInstance();
final DateChangeListGroupingStrategy delegate = new DateChangeListGroupingStrategy();
myDefaultStrategy = new CommitGroupingStrategy() {
@Override
public void beforeStart() {
delegate.beforeStart();
}
@Override
public String getGroupName(CommitI commit) {
return delegate.getGroupName(new Date(commit.getTime()));
}
};
myStrategy = myDefaultStrategy;
myLines = new BigArray<CommitI>(10);
myCutCount = -1;
myCommitIdxInterval = 50;
myNumEventsInGroup = 20;
myNoGrouping = new CommitGroupingStrategy() {
@Override
public String getGroupName(CommitI commit) {
return null;
}
@Override
public void beforeStart() {
}
};
myStashTops = new HashMap<VirtualFile, Couple<AbstractHash>>();
myTreeHighlighter = new HashMap<VirtualFile, TreeHighlighter>();
}
public boolean isForRoot(final VirtualFile root, final int idx) {
return myRepoIdxMap.get(root).contains(idx);
}
public int getAbsoluteForRelative(final VirtualFile root, final int insideRepoIdx) {
return myIdxMap.get(new InnerIdx(root, insideRepoIdx));
}
public int getPreviousAbsoluteIdx(final int idx) {
final VirtualFile root = getCommitAt(idx).selectRepository(myRootsHolder.getRoots());
final List<InnerIdx> keysByValue = myIdxMap.getKeysByValue(idx);
if (keysByValue == null) {
// this is for group header
return -1;
} else {
for (InnerIdx innerIdx : keysByValue) {
if (innerIdx.getRoot().equals(root)) {
if (innerIdx.getInsideRepoIdx() == 0) return -1;
return myIdxMap.get(new InnerIdx(root, innerIdx.getInsideRepoIdx() - 1));
}
}
}
//assert false;
return -1;
}
public void setCommitIdxInterval(int commitIdxInterval) {
myCommitIdxInterval = commitIdxInterval;
}
public void setNumEventsInGroup(int numEventsInGroup) {
myNumEventsInGroup = numEventsInGroup;
}
public ColumnInfo getColumnInfo(final int column) {
return myColumns.get(column);
}
@Override
public String getColumnName(int column) {
return myColumns.get(column).getName();
}
@Override
public int getColumnCount() {
return myColumns.size();
}
int getTrueCount() {
return myLines == null ? 0 : myLines.getSize();
}
@Override
public int getRowCount() {
if (myInit != null) {
final Runnable init = myInit;
myInit = null;
init.run();
}
if (myCutCount > 0) {
return myCutCount;
}
return myLines == null ? 0 : myLines.getSize();
}
public CommitI getCommitAt(final int row) {
if (myLines == null) return null;
if (row >= myLines.getSize()) return null;
return myLines.get(row);
}
public int getTotalWires() {
if (mySkeletonBuilder == null) return -1;
int wires = 0;
for (Map.Entry<VirtualFile, SkeletonBuilder> entry : mySkeletonBuilder.entrySet()) {
SkeletonBuilder skeletonBuilder = entry.getValue();
if (myActiveRoots.contains(entry.getKey())) {
wires += skeletonBuilder.getMaxWireNum();
}
}
return wires;
}
@Nullable
public List<Integer> getWiresGroups() {
if (mySkeletonBuilder == null) return null;
final List<Integer> result = new ArrayList<Integer>(myOrder.size());
for (VirtualFile file : myOrder) {
if (myActiveRoots.contains(file)) {
result.add(mySkeletonBuilder.get(file).getMaxWireNum());
}
}
return result;
}
public int getCorrectedWire(final CommitI commitI) {
if (mySkeletonBuilder == null) return -1;
final VirtualFile file = commitI.selectRepository(myRootsHolder.getRoots());
if (! myAdditions.containsKey(file)) return commitI.getWireNumber();
return myAdditions.get(file) + commitI.getWireNumber();
}
public int getRepoCorrection(final VirtualFile root) {
return myAdditions.get(root);
}
public Map<VirtualFile, WireEventsIterator> getGroupIterators(final int firstRow) {
final Map<VirtualFile, WireEventsIterator> map = new HashMap<VirtualFile, WireEventsIterator>();
for (VirtualFile virtualFile : mySkeletonBuilder.keySet()) {
if (myActiveRoots.contains(virtualFile)) {
map.put(virtualFile, new WiresGroupIterator(firstRow, virtualFile));
}
}
return map;
}
// todo should be removed once we move to inside-repository indexes calculation
public Map<VirtualFile, WireEventsIterator> getAllGroupIterators(final int firstRow) {
final Map<VirtualFile, WireEventsIterator> map = new HashMap<VirtualFile, WireEventsIterator>();
for (VirtualFile virtualFile : mySkeletonBuilder.keySet()) {
map.put(virtualFile, new WiresGroupIterator(firstRow, virtualFile));
}
return map;
}
public void stashFor(VirtualFile root, Couple<AbstractHash> hash) {
myStashTops.put(root, hash);
}
public boolean isStashed(final CommitI commitI) {
final Couple<AbstractHash> pair =
myStashTops.get(commitI.selectRepository(myRootsHolder.getRoots()));
return pair != null && (pair.getFirst() != null && pair.getFirst().equals(commitI.getHash()) ||
pair.getSecond() != null && pair.getSecond().equals(commitI.getHash()));
}
public void setHeadIfEmpty(VirtualFile root, AbstractHash headHash) {
final TreeHighlighter treeHighlighter = myTreeHighlighter.get(root);
if (treeHighlighter != null && treeHighlighter.getPoint() == null) {
setHead(root, headHash);
}
}
public void setHead(VirtualFile root, AbstractHash headHash) {
final TreeHighlighter treeHighlighter = myTreeHighlighter.get(root);
if (treeHighlighter != null) {
if (! treeHighlighter.isDumb() && headHash.equals(treeHighlighter.getPoint())) return; // already ok
treeHighlighter.setPoint(headHash);
treeHighlighter.update(0);
}
}
public void setDumbHighlighter(VirtualFile root) {
final TreeHighlighter treeHighlighter = myTreeHighlighter.get(root);
if (treeHighlighter != null) {
if (treeHighlighter.isDumb()) return;
treeHighlighter.setDumb();
}
}
/*private static class IdxPair {
public int myReal;
public int myInside;
private IdxPair(int real, int inside) {
myReal = real;
myInside = inside;
}
}
private IdxPair getLess(final int x, final VirtualFile root) {
int idx = x;
while (idx >= 0) {
final List<InnerIdx> keysByValue = myIdxMap.getKeysByValue(idx);
if (keysByValue != null) {
for (InnerIdx innerIdx : keysByValue) {
if (innerIdx.getRoot().equals(root)) {
return new IdxPair(idx, innerIdx.getInsideRepoIdx());
}
}
}
-- idx;
}
return new IdxPair(0,0);
}*/
class WiresGroupIterator implements WireEventsIterator {
private final int myFirstIdxAbs;
private List<Integer> myFirstUsed;
private final VirtualFile myRoot;
private final int myOffset;
private final Iterator<WireEvent> myWireEventsIterator;
private Integer myFloor;
private int myIdx;
WiresGroupIterator(int firstIdxAbs, VirtualFile root) {
myFirstIdxAbs = firstIdxAbs;
myRoot = root;
myOffset = myAdditions.containsKey(myRoot) ? myAdditions.get(myRoot) : 0;
myFirstUsed = new ArrayList<Integer>();
TreeNavigationImpl navigation = myNavigation.get(myRoot);
// get less idx
/*final IdxPair less = getLess(firstIdxAbs, root);
myFloor = less.myReal;
myIdx = less.myInside;*/
final ReadonlyList<CommitI> wrapper = createWrapper(myRoot);
myFloor = myRepoIdxMap.get(myRoot).floor(firstIdxAbs);
if (myFloor == null) {
myIdx = 0;
myFloor = myRepoIdxMap.get(myRoot).isEmpty() ? 0 : myRepoIdxMap.get(myRoot).first();
} else {
final List<InnerIdx> keysByValue = myIdxMap.getKeysByValue(myFloor);
myIdx = -1;
for (InnerIdx innerIdx : keysByValue) {
if (innerIdx.getRoot().equals(myRoot)) {
myIdx = innerIdx.getInsideRepoIdx();
break;
}
}
assert myIdx != -1;
}
final List<Integer> used = navigation.getUsedWires(myIdx, wrapper, mySkeletonBuilder.get(myRoot).getFutureConvertor()).getUsed();
for (Integer integer : used) {
myFirstUsed.add(integer + myOffset);
}
myWireEventsIterator = navigation.createWireEventsIterator(myIdx);
}
@Override
public Integer getFloor() {
return myFloor;
}
@Override
public Iterator<WireEventI> getWireEventsIterator() {
return new Iterator<WireEventI>() {
@Override
public boolean hasNext() {
return myWireEventsIterator.hasNext();
}
@Override
public WireEventI next() {
final WireEventI next = myWireEventsIterator.next();
final Convertor<Integer, Integer> innerToOuter = new Convertor<Integer, Integer>() {
@Override
public Integer convert(Integer o) {
if (o == -1) return -1;
final int insideRepoIdx = o.intValue();
final Integer integer = myIdxMap.get(new InnerIdx(myRoot, insideRepoIdx));
assert integer != null;
return integer;
}
};
final Convertor<int[], int[]> arraysConvertor = new Convertor<int[], int[]>() {
@Override
public int[] convert(int[] o) {
if (o == null) return null;
final int[] result = new int[o.length];
for (int i = 0; i < o.length; i++) {
int i1 = o[i];
result[i] = innerToOuter.convert(i1);
}
return result;
}
};
return new WireEventI() {
@Override
public int getCommitIdx() {
return innerToOuter.convert(next.getCommitIdx());
}
@Override
public int[] getWireEnds() {
return arraysConvertor.convert(next.getWireEnds());
}
@Override
public int[] getCommitsEnds() {
return arraysConvertor.convert(next.getCommitsEnds());
}
@Override
public int[] getCommitsStarts() {
return arraysConvertor.convert(next.getCommitsStarts());
}
@Override
public int[] getFutureWireStarts() {
// these are wire numbers
return next.getFutureWireStarts();
}
@Override
public boolean isEnd() {
return next.isEnd();
}
@Override
public boolean isStart() {
return next.isStart();
}
@Override
public int getWaitStartsNumber() {
return next.getWaitStartsNumber();
}
};
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
@Override
public List<Integer> getFirstUsed() {
return myFirstUsed;
}
}
public int getLastForRoot(final VirtualFile root) {
final TreeSet<Integer> integers = myRepoIdxMap.get(root);
if (integers.isEmpty()) return -1;
return integers.last();
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
final ColumnInfo column = myColumns.get(columnIndex);
if (myLines == null) return column.getPreferredStringValue();
final CommitI commitI = myLines.get(rowIndex);
if (commitI == null) return column.getPreferredStringValue();
if (commitI.holdsDecoration()) return columnIndex == 0 ? commitI.getDecorationString() : "";
final GitHeavyCommit details = myCache.convert(commitI.selectRepository(myRootsHolder.getRoots()), commitI.getHash());
if (details == null) return LOADING;
return column.valueOf(details);
}
public MultiMap<VirtualFile, AbstractHash> getMissing(final int startRow, final int endRow) {
if (myLines == null || myRootsHolder == null) return MultiMap.emptyInstance();
final MultiMap<VirtualFile, AbstractHash> result = new MultiMap<VirtualFile, AbstractHash>();
for (int i = startRow; i <= endRow; i++) {
final CommitI commitI = myLines.get(i);
if (commitI.holdsDecoration()) continue;
final AbstractHash hash = commitI.getHash();
final VirtualFile root = commitI.selectRepository(myRootsHolder.getRoots());
if (myCache.convert(root, commitI.getHash()) == null) {
result.putValue(root, hash);
}
}
return result;
}
public void clear(boolean noFilters, boolean noStartingPoints) {
if (noFilters) {
myCurrentComparator = CommitIComparator.getInstance();
myNavigation = new HashMap<VirtualFile, TreeNavigationImpl>();
mySkeletonBuilder = new HashMap<VirtualFile, SkeletonBuilder>();
myAdditions = new HashMap<VirtualFile, Integer>();
myOrder = new ArrayList<VirtualFile>(myRootsHolder.getRoots());
Collections.sort(myOrder, FilePathComparator.getInstance());
for (VirtualFile vf : myOrder) {
final TreeNavigationImpl navigation = new TreeNavigationImpl(myCommitIdxInterval, myNumEventsInGroup);// try to adjust numbers
final SkeletonBuilder skeletonBuilder = new SkeletonBuilder(navigation);
myNavigation.put(vf, navigation);
mySkeletonBuilder.put(vf, skeletonBuilder);
myAdditions.put(vf, 0);
myRepoIdxMap.put(vf, new TreeSet<Integer>());
myRunningRepoIdxs.put(vf, 0);
myIdxMap.clear();
}
for (VirtualFile virtualFile : myOrder) {
if (! myTreeHighlighter.containsKey(virtualFile)) {
myTreeHighlighter.put(virtualFile, new TreeHighlighter(this, virtualFile, -1));
}
}
for (Iterator<VirtualFile> iterator = myTreeHighlighter.keySet().iterator(); iterator.hasNext(); ) {
VirtualFile root = iterator.next();
if (! myOrder.contains(root)) {
iterator.remove();
} else {
final TreeHighlighter highlighter = myTreeHighlighter.get(root);
highlighter.setPoint(highlighter.getPoint());
}
}
} else {
myCurrentComparator = CommitIReorderingInsideOneRepoComparator.getInstance();
myAdditions = null;
mySkeletonBuilder = null;
myNavigation = null;
myOrder = null;
myTreeHighlighter.clear();
}
myLines = new BigArray<CommitI>(10);
myCutCount = -1;
}
@Nullable
public List<VirtualFile> getOrder() {
return myOrder;
}
public void cutAt(final int lastShownItemIdx) {
myCutCount = lastShownItemIdx + 1;
}
public void restore() {
myCutCount = -1;
}
public void appendData(final List<CommitI> lines, final List<List<AbstractHash>> parents) {
if (mySkeletonBuilder == null) {
Collections.sort(lines, myCurrentComparator);
}
myStrategy.beforeStart();
// find those ..... long awaited start idx by stupid long iteration since
// items can NOT be ordered by simple rule
final int[] parentsIdx = new int[1];
parentsIdx[0] = 0;
int idxFrom = findIdx(lines);
final CommitI commitI = lines.get(0);
final VirtualFile listRoot = commitI.selectRepository(myRootsHolder.getRoots());
final ReadonlyList<CommitI> wrapperList = createWrapper(listRoot);
int recountFrom = new GroupingMerger<CommitI, String>() {
@Override
protected CommitI wrapItem(CommitI commitI) {
if (mySkeletonBuilder != null && ! commitI.holdsDecoration()) {
return new WireNumberCommitDecoration(commitI);
}
return super.wrapItem(commitI);
}
@Override
protected void afterConsumed(CommitI commitI, int i) {
if (mySkeletonBuilder != null && ! commitI.holdsDecoration()) {
final VirtualFile root = commitI.selectRepository(myRootsHolder.getRoots());
final Integer innerIdx = myRunningRepoIdxs.get(root);
myIdxMap.put(new InnerIdx(root, innerIdx), i);
myRepoIdxMap.get(root).add(i);
myRunningRepoIdxs.put(root, innerIdx + 1);
mySkeletonBuilder.get(root).consume(commitI, parents.get(parentsIdx[0]), wrapperList, innerIdx);
++ parentsIdx[0];
}
}
@Override
protected boolean filter(CommitI commitI) {
return !commitI.holdsDecoration();
}
@Override
protected void willBeRecountFrom(int idx, int wasSize) {
if (mySkeletonBuilder != null) {
for (int i = idx; i < wasSize; i++) {
//myIdxMap.removeValue(i);
for (VirtualFile root : myOrder) {
myRepoIdxMap.get(root).remove(i);
}
}
}
}
@Override
protected String getGroup(CommitI commitI) {
if (getCurrentGroup() == null) {
final Couple<AbstractHash> stashTop = myStashTops.get(commitI.selectRepository(myRootsHolder.getRoots()));
if (stashTop != null && (Comparing.equal(stashTop.getFirst(), commitI.getHash()))) {
return STASH;
}
}
if (STASH.equals(getCurrentGroup())) { // index on <branchname>: <short hash> <base commit description>
final VirtualFile root = commitI.selectRepository(myRootsHolder.getRoots());
final Couple<AbstractHash> stashTop = myStashTops.get(root);
if (stashTop != null && (Comparing.equal(stashTop.getSecond(), commitI.getHash()))) {
return STASH;
}
}
return myStrategy.getGroupName(commitI);
}
@Override
protected CommitI wrapGroup(String s, CommitI item) {
return new GroupHeaderDatePseudoCommit(s, item.getTime() - 1);
}
@Override
protected void oldBecame(int was, int is) {
if (mySkeletonBuilder != null) {
final List<InnerIdx> keys = myIdxMap.getKeysByValue(was);
final VirtualFile root = myLines.get(is).selectRepository(myRootsHolder.getRoots());
//final VirtualFile wasRoot = myLines.get(was).selectRepository(myRootsHolder.getRoots());
assert ! root.equals(listRoot);
//myRepoIdxMap.get(wasRoot).remove(was);
myRepoIdxMap.get(root).add(is);
InnerIdx found = null;
for (InnerIdx key : keys) {
if (key.getRoot().equals(root)) {
found = key;
break;
}
}
assert found != null;
myIdxMap.put(found, is);
}
}
}.firstPlusSecond(myLines, new ReadonlyList.ArrayListWrapper<CommitI>(lines), myCurrentComparator, mySkeletonBuilder == null ? -1 : idxFrom);
if (mySkeletonBuilder != null) {
final TreeNavigationImpl treeNavigation = myNavigation.get(listRoot);
treeNavigation.recalcIndex(wrapperList, mySkeletonBuilder.get(listRoot).getFutureConvertor());
calculateAdditions();
for (VirtualFile root : myOrder) {
final TreeHighlighter treeHighlighter = myTreeHighlighter.get(root);
if (treeHighlighter != null) {
treeHighlighter.update(recountFrom);
}
}
}
}
private void calculateAdditions() {
if (mySkeletonBuilder != null) {
int size = 0;
myAdditions.clear();
for (VirtualFile file : myOrder) {
if (myActiveRoots.contains(file)) {
myAdditions.put(file, size);
size += mySkeletonBuilder.get(file).getMaxWireNum();
}
}
}
}
public boolean isInCurrentBranch(final int idx) {
if (mySkeletonBuilder == null || myTreeHighlighter.isEmpty()) return false;
final CommitI commitAt = getCommitAt(idx);
if (commitAt.holdsDecoration()) return false;
final VirtualFile root = commitAt.selectRepository(myRootsHolder.getRoots());
final TreeHighlighter treeHighlighter = myTreeHighlighter.get(root);
return treeHighlighter != null && treeHighlighter.isIncluded(commitAt.getHash());
}
public Map<Integer, Set<Integer>> getGrey(final VirtualFile root,
final int from,
final int to,
int repoCorrection,
Set<Integer> wireModificationSet) {
if (mySkeletonBuilder == null || myTreeHighlighter.isEmpty()) return Collections.emptyMap();
final TreeHighlighter highlighter = myTreeHighlighter.get(root);
return highlighter.getGreyForInterval(from, to, repoCorrection, wireModificationSet);
}
private ReadonlyList<CommitI> createWrapper(final VirtualFile root) {
return new ReadonlyList<CommitI>() {
@Override
public CommitI get(int idx) {
return myLines.get(myIdxMap.get(new InnerIdx(root, idx)));
}
@Override
public int getSize() {
return myRunningRepoIdxs.get(root);
}
};
}
private int findIdx(List<CommitI> lines) {
final VirtualFile targetRepo = lines.get(0).selectRepository(myRootsHolder.getRoots());
final long time = lines.get(0).getTime();
for (int i = myLines.getSize() - 1; i >= 0; i--) {
final CommitI current = myLines.get(i);
if (current.holdsDecoration()) continue;
if (current.selectRepository(myRootsHolder.getRoots()).equals(targetRepo)) {
return i + 1; // will be equal to list size sometimes, is that ok?
} else {
if (current.getTime() > time) {
return i;
}
}
}
return 0;
}
public void setCache(DetailsCache cache) {
myCache = cache;
}
public void setRootsHolder(RootsHolder rootsHolder) {
myRootsHolder = rootsHolder;
}
public RootsHolder getRootsHolder() {
return myRootsHolder;
}
public void setStrategy(CommitGroupingStrategy strategy) {
myStrategy = strategy;
}
public void useDateGroupingStrategy() {
myStrategy = myDefaultStrategy;
}
public void useNoGroupingStrategy() {
myStrategy = myNoGrouping;
}
public void printNavigation() {
for (Map.Entry<VirtualFile, TreeNavigationImpl> entry : myNavigation.entrySet()) {
if (entry.getKey().getPath().contains("inner")) {
entry.getValue().printSelf();
}
}
}
public static class InnerIdx {
private final VirtualFile myRoot;
private final int myInsideRepoIdx;
public InnerIdx(VirtualFile root, int insideRepoIdx) {
myRoot = root;
myInsideRepoIdx = insideRepoIdx;
}
public VirtualFile getRoot() {
return myRoot;
}
public int getInsideRepoIdx() {
return myInsideRepoIdx;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
InnerIdx innerIdx = (InnerIdx)o;
if (myInsideRepoIdx != innerIdx.myInsideRepoIdx) return false;
if (!myRoot.equals(innerIdx.myRoot)) return false;
return true;
}
@Override
public int hashCode() {
int result = myRoot.hashCode();
result = 31 * result + myInsideRepoIdx;
return result;
}
}
public Set<VirtualFile> getActiveRoots() {
return myActiveRoots;
}
public void setActiveRoots(final Collection<VirtualFile> files) {
myActiveRoots.clear();
myActiveRoots.addAll(files);
for (TreeHighlighter highlighter : myTreeHighlighter.values()) {
//highlighter.reset();
highlighter.update(0);
}
calculateAdditions();
}
}