diff --git a/platform/vcs-log/api/src/com/intellij/vcs/log/VcsLogStructureFilter.java b/platform/vcs-log/api/src/com/intellij/vcs/log/VcsLogStructureFilter.java index 2294fc7c4c3e..bdfd0d1701a4 100644 --- a/platform/vcs-log/api/src/com/intellij/vcs/log/VcsLogStructureFilter.java +++ b/platform/vcs-log/api/src/com/intellij/vcs/log/VcsLogStructureFilter.java @@ -34,4 +34,6 @@ public interface VcsLogStructureFilter extends VcsLogDetailsFilter { @NotNull Collection getFiles(@NotNull VirtualFile root); + Collection getRoots(); + } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogStructureFilterImpl.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogStructureFilterImpl.java index 2354f4f6369e..39fe1c8dc1cb 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogStructureFilterImpl.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogStructureFilterImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * 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. @@ -23,61 +23,47 @@ import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.MultiMap; -import com.intellij.vcs.log.VcsCommitMetadata; -import com.intellij.vcs.log.VcsFullCommitDetails; -import com.intellij.vcs.log.VcsLogDetailsFilter; -import com.intellij.vcs.log.VcsLogStructureFilter; +import com.intellij.vcs.log.*; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; import java.util.Collection; +import java.util.HashSet; +import java.util.Set; public class VcsLogStructureFilterImpl implements VcsLogDetailsFilter, VcsLogStructureFilter { + @NotNull private final Set myRoots; + @NotNull private final MultiMap myRootToFiles; - @NotNull private final Collection myFiles; - @NotNull private final MultiMap myFilesByRoots; - - public VcsLogStructureFilterImpl(@NotNull Collection files, @NotNull Collection roots) { - myFiles = files; - myFilesByRoots = groupFilesByVcsRoots(files, roots); + public VcsLogStructureFilterImpl(@NotNull Set roots, + @NotNull MultiMap rootToFiles) { + myRoots = roots; + myRootToFiles = rootToFiles; } @NotNull - private static MultiMap groupFilesByVcsRoots(@NotNull Collection files, - @NotNull Collection roots) { - MultiMap grouped = MultiMap.create(); - for (VirtualFile file : files) { - VirtualFile root = findBestRoot(file, roots); - if (root != null) { - grouped.putValue(root, file); - } - } - return grouped; + @Override + public Collection getFiles(@NotNull VirtualFile root) { + return myRootToFiles.get(root); } - @Nullable - private static VirtualFile findBestRoot(@NotNull VirtualFile file, @NotNull Collection roots) { - VirtualFile candidate = null; - for (VirtualFile root : roots) { - if (VfsUtilCore.isAncestor(root, file, false)) { - if (candidate == null || VfsUtilCore.isAncestor(candidate, root, true)) { - candidate = root; - } - } - } - return candidate; + @Override + public Collection getRoots() { + return ContainerUtil.union(myRoots, myRootToFiles.keySet()); } @Override public boolean matches(@NotNull VcsCommitMetadata details) { + if (myRoots.contains(details.getRoot())) return true; + if ((details instanceof VcsFullCommitDetails)) { for (Change change : ((VcsFullCommitDetails)details).getChanges()) { ContentRevision before = change.getBeforeRevision(); - if (before != null && matches(before.getFile().getPath())) { + if (before != null && matches(before.getFile().getPath(), myRootToFiles.get(details.getRoot()))) { return true; } ContentRevision after = change.getAfterRevision(); - if (after != null && matches(after.getFile().getPath())) { + if (after != null && matches(after.getFile().getPath(), myRootToFiles.get(details.getRoot()))) { return true; } } @@ -88,8 +74,8 @@ public class VcsLogStructureFilterImpl implements VcsLogDetailsFilter, VcsLogStr } } - private boolean matches(@NotNull final String path) { - return ContainerUtil.find(myFiles, new Condition() { + private boolean matches(@NotNull final String path, @NotNull Collection files) { + return ContainerUtil.find(files, new Condition() { @Override public boolean value(VirtualFile file) { return FileUtil.isAncestor(file.getPath(), path, false); @@ -97,10 +83,38 @@ public class VcsLogStructureFilterImpl implements VcsLogDetailsFilter, VcsLogStr }) != null; } - @Override @NotNull - public Collection getFiles(@NotNull VirtualFile root) { - return myFilesByRoots.get(root); - } + public static VcsLogStructureFilterImpl build(@NotNull Collection files, + @NotNull VcsLogDataPack dataPack) { + Set roots = dataPack.getLogProviders().keySet(); + Set selectedRoots = new HashSet(); + MultiMap selectedFiles = new MultiMap(); + + for (VirtualFile file : files) { + if (roots.contains(file)) { + // no need in details filter + selectedRoots.add(file); + } + else { + VirtualFile candidateAncestorRoot = null; + for (VirtualFile root : roots) { + if (VfsUtilCore.isAncestor(root, file, false)) { + if (candidateAncestorRoot == null || VfsUtilCore.isAncestor(candidateAncestorRoot, root, false)) { + candidateAncestorRoot = root; + } + } + else if (VfsUtilCore.isAncestor(file, root, false)) { + selectedRoots.add(root); + } + } + + if (candidateAncestorRoot != null) { + selectedFiles.putValue(candidateAncestorRoot, file); + } + } + } + + return new VcsLogStructureFilterImpl(selectedRoots, selectedFiles); + } } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VisiblePackBuilder.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VisiblePackBuilder.java index c171707d7dbb..31489526f59f 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VisiblePackBuilder.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VisiblePackBuilder.java @@ -207,7 +207,7 @@ class VisiblePackBuilder { for (Map.Entry entry : providers.entrySet()) { VirtualFile root = entry.getKey(); - if (filterCollection.getStructureFilter() != null && filterCollection.getStructureFilter().getFiles(root).isEmpty() + if (filterCollection.getStructureFilter() != null && !filterCollection.getStructureFilter().getRoots().contains(root) || filterCollection.getUserFilter() != null && filterCollection.getUserFilter().getUserNames(root).isEmpty()) { // there is a structure or user filter, but it doesn't match this root continue; diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/filter/StructureFilterPopupComponent.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/filter/StructureFilterPopupComponent.java index b4d90e8ca94a..601038760071 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/filter/StructureFilterPopupComponent.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/filter/StructureFilterPopupComponent.java @@ -68,7 +68,11 @@ class StructureFilterPopupComponent extends FilterPopupComponent getAllFiles(@NotNull VcsLogDataPack dataPack, @NotNull VcsLogStructureFilter filter) { Collection result = ContainerUtil.newArrayList(); for (VirtualFile root : dataPack.getLogProviders().keySet()) { - result.addAll(filter.getFiles(root)); + Collection files = filter.getFiles(root); + result.addAll(files); + if (files.isEmpty() && filter.getRoots().contains(root)) { + result.add(root); + } } return result; } @@ -107,11 +111,10 @@ class StructureFilterPopupComponent extends FilterPopupComponent files = filter == null ? Collections.emptySet() : getAllFiles(dataPack, filter); - Set roots = dataPack.getLogProviders().keySet(); VcsStructureChooser chooser = new VcsStructureChooser(project, "Select Files or Folders to Filter", files, - new ArrayList(roots)); + new ArrayList(dataPack.getLogProviders().keySet())); if (chooser.showAndGet()) { - myFilterModel.setFilter(new VcsLogStructureFilterImpl(chooser.getSelectedFiles(), roots)); + myFilterModel.setFilter(VcsLogStructureFilterImpl.build(chooser.getSelectedFiles(), dataPack)); } } } diff --git a/plugins/git4idea/src/git4idea/log/GitLogProvider.java b/plugins/git4idea/src/git4idea/log/GitLogProvider.java index d89d2540592a..1abb59c5476f 100644 --- a/plugins/git4idea/src/git4idea/log/GitLogProvider.java +++ b/plugins/git4idea/src/git4idea/log/GitLogProvider.java @@ -440,10 +440,13 @@ public class GitLogProvider implements VcsLogProvider { // note: structure filter must be the last parameter, because it uses "--" which separates parameters from paths if (filterCollection.getStructureFilter() != null) { - filterParameters.add("--simplify-merges"); - filterParameters.add("--"); - for (VirtualFile file : filterCollection.getStructureFilter().getFiles(root)) { - filterParameters.add(file.getPath()); + Collection files = filterCollection.getStructureFilter().getFiles(root); + if (!files.isEmpty()) { + filterParameters.add("--simplify-merges"); + filterParameters.add("--"); + for (VirtualFile file : files) { + filterParameters.add(file.getPath()); + } } }