[vcs-log] extract root filter from structure filter

This commit is contained in:
Julia Beliaeva
2014-12-05 18:58:02 +03:00
parent a0ac3ee50e
commit 73b1782947
17 changed files with 357 additions and 113 deletions
@@ -45,6 +45,9 @@ public interface VcsLogFilterCollection {
@Nullable
VcsLogStructureFilter getStructureFilter();
@Nullable
VcsLogRootFilter getRootFilter();
/**
* Returns true if there are no filters in this collection.
*/
@@ -0,0 +1,33 @@
/*
* 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 com.intellij.vcs.log;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
/**
* Tells the log to filter by vcs roots.
*/
public interface VcsLogRootFilter extends VcsLogFilter {
/**
* <p>Returns vcs roots that are visible.</p>
*/
@NotNull
Collection<VirtualFile> getRoots();
}
@@ -26,14 +26,11 @@ import java.util.Collection;
public interface VcsLogStructureFilter extends VcsLogDetailsFilter {
/**
* <p>Returns files from the given VCS root, which are affected by matching commits, and folders containing such files.</p>
* <p>Returns files which are affected by matching commits, and folders containing such files.</p>
*
* <p>That is: the commit A (made in the given VCS root) modifying file f.txt matches this filter,
* if this method returns a set which includes a folder containing f.txt, or the file f.txt itself.</p>
*/
@NotNull
Collection<VirtualFile> getFiles(@NotNull VirtualFile root);
Collection<VirtualFile> getRoots();
Collection<VirtualFile> getFiles();
}
@@ -0,0 +1,35 @@
/*
* 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 com.intellij.vcs.log;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
public class VcsLogRootFilterImpl implements VcsLogRootFilter {
@NotNull private final Collection<VirtualFile> myRoots;
public VcsLogRootFilterImpl(@NotNull Collection<VirtualFile> roots) {
myRoots = roots;
}
@NotNull
@Override
public Collection<VirtualFile> getRoots() {
return myRoots;
}
}
@@ -0,0 +1,91 @@
/*
* 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 com.intellij.vcs.log.data;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.HashSet;
import com.intellij.util.containers.MultiMap;
import com.intellij.vcs.log.VcsLogRootFilter;
import com.intellij.vcs.log.VcsLogStructureFilter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.Set;
public class VcsLogFileFilterUtil {
@NotNull
static Pair<Set<VirtualFile>, MultiMap<VirtualFile, VirtualFile>> collectRoots(@NotNull Collection<VirtualFile> files,
@NotNull Set<VirtualFile> roots) {
Set<VirtualFile> selectedRoots = new HashSet<VirtualFile>();
MultiMap<VirtualFile, VirtualFile> selectedFiles = new MultiMap<VirtualFile, VirtualFile>();
for (VirtualFile file : files) {
if (roots.contains(file)) {
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 Pair.create(selectedRoots, selectedFiles);
}
@NotNull
public static Pair<Set<VirtualFile>, MultiMap<VirtualFile, VirtualFile>> collectRootsAndFiles(@NotNull Set<VirtualFile> roots,
@Nullable VcsLogRootFilter rootFilter,
@Nullable VcsLogStructureFilter structureFilter) {
if (rootFilter == null && structureFilter == null) return Pair.create(roots, MultiMap.<VirtualFile, VirtualFile>create());
if (structureFilter == null) {
return Pair.create((Set<VirtualFile>)new HashSet<VirtualFile>(rootFilter.getRoots()), MultiMap.<VirtualFile, VirtualFile>create());
}
Pair<Set<VirtualFile>, MultiMap<VirtualFile, VirtualFile>> selectedRootsAndFiles = collectRoots(structureFilter.getFiles(), roots);
if (rootFilter == null) {
return selectedRootsAndFiles;
}
return Pair.create(ContainerUtil.union(new HashSet<VirtualFile>(rootFilter.getRoots()), selectedRootsAndFiles.first),
selectedRootsAndFiles.second);
}
@Nullable
public static Set<VirtualFile> collectRoots(@NotNull Set<VirtualFile> roots,
@Nullable VcsLogRootFilter rootFilter,
@Nullable VcsLogStructureFilter structureFilter) {
if (rootFilter == null && structureFilter == null) return null;
Pair<Set<VirtualFile>, MultiMap<VirtualFile, VirtualFile>> rootsAndFiles = collectRootsAndFiles(roots, rootFilter, structureFilter);
return ContainerUtil.union(rootsAndFiles.first, rootsAndFiles.second.keySet());
}
}
@@ -55,7 +55,7 @@ public class VcsLogFiltererImpl implements VcsLogFilterer {
@NotNull final PermanentGraph.SortType initialSortType,
@NotNull final Consumer<VisiblePack> visiblePackConsumer) {
myVisiblePackBuilder = new VisiblePackBuilder(providers, hashMap, topCommitsDetailsCache, detailsGetter);
myFilters = new VcsLogFilterCollectionImpl(null, null, null, null, null, null);
myFilters = new VcsLogFilterCollectionImpl(null, null, null, null, null, null, null);
mySortType = initialSortType;
myTaskController = new SingleTaskController<Request, VisiblePack>(visiblePackConsumer) {
@@ -32,38 +32,28 @@ import java.util.HashSet;
import java.util.Set;
public class VcsLogStructureFilterImpl implements VcsLogDetailsFilter, VcsLogStructureFilter {
@NotNull private final Set<VirtualFile> myRoots;
@NotNull private final MultiMap<VirtualFile, VirtualFile> myRootToFiles;
@NotNull private final Set<VirtualFile> myFiles;
public VcsLogStructureFilterImpl(@NotNull Set<VirtualFile> roots,
@NotNull MultiMap<VirtualFile, VirtualFile> rootToFiles) {
myRoots = roots;
myRootToFiles = rootToFiles;
public VcsLogStructureFilterImpl(@NotNull Set<VirtualFile> files) {
myFiles = files;
}
@NotNull
@Override
public Collection<VirtualFile> getFiles(@NotNull VirtualFile root) {
return myRootToFiles.get(root);
}
@Override
public Collection<VirtualFile> getRoots() {
return ContainerUtil.union(myRoots, myRootToFiles.keySet());
public Collection<VirtualFile> getFiles() {
return myFiles;
}
@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(), myRootToFiles.get(details.getRoot()))) {
if (before != null && matches(before.getFile().getPath())) {
return true;
}
ContentRevision after = change.getAfterRevision();
if (after != null && matches(after.getFile().getPath(), myRootToFiles.get(details.getRoot()))) {
if (after != null && matches(after.getFile().getPath())) {
return true;
}
}
@@ -74,47 +64,12 @@ public class VcsLogStructureFilterImpl implements VcsLogDetailsFilter, VcsLogStr
}
}
private boolean matches(@NotNull final String path, @NotNull Collection<VirtualFile> files) {
return ContainerUtil.find(files, new Condition<VirtualFile>() {
private boolean matches(@NotNull final String path) {
return ContainerUtil.find(myFiles, new Condition<VirtualFile>() {
@Override
public boolean value(VirtualFile file) {
return FileUtil.isAncestor(file.getPath(), path, false);
}
}) != null;
}
@NotNull
public static VcsLogStructureFilterImpl build(@NotNull Collection<VirtualFile> files,
@NotNull VcsLogDataPack dataPack) {
Set<VirtualFile> roots = dataPack.getLogProviders().keySet();
Set<VirtualFile> selectedRoots = new HashSet<VirtualFile>();
MultiMap<VirtualFile, VirtualFile> selectedFiles = new MultiMap<VirtualFile, VirtualFile>();
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);
}
}
@@ -24,11 +24,13 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.HashSet;
import com.intellij.util.containers.MultiMap;
import com.intellij.util.ui.UIUtil;
import com.intellij.vcs.log.*;
import com.intellij.vcs.log.graph.GraphCommit;
import com.intellij.vcs.log.graph.PermanentGraph;
import com.intellij.vcs.log.graph.VisibleGraph;
import com.intellij.vcs.log.impl.VcsLogFilterCollectionImpl;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -63,7 +65,7 @@ class VisiblePackBuilder {
return Pair.create(applyHashFilter(dataPack, hashFilter.getHashes(), sortType), commitCount);
}
Set<Integer> matchingHeads = getMatchingHeads(dataPack.getRefs(), filters);
Set<Integer> matchingHeads = getMatchingHeads(dataPack.getRefs(), dataPack.getLogProviders().keySet(), filters);
List<VcsLogDetailsFilter> detailsFilters = filters.getDetailsFilters();
List<Hash> matchingCommits = null;
boolean canRequestMore = false;
@@ -105,8 +107,8 @@ class VisiblePackBuilder {
}
private VisiblePack applyHashFilter(@NotNull DataPack dataPack,
@NotNull Collection<String> hashes,
@NotNull PermanentGraph.SortType sortType) {
@NotNull Collection<String> hashes,
@NotNull PermanentGraph.SortType sortType) {
final Set<Integer> indices = ContainerUtil.map2SetNotNull(hashes, new Function<String, Integer>() {
@Override
public Integer fun(String partOfHash) {
@@ -124,13 +126,39 @@ class VisiblePackBuilder {
}
@Nullable
private Set<Integer> getMatchingHeads(@NotNull VcsLogRefs refs, @NotNull VcsLogFilterCollection filters) {
private Set<Integer> getMatchingHeads(@NotNull VcsLogRefs refs, Set<VirtualFile> roots, @NotNull VcsLogFilterCollection filters) {
VcsLogBranchFilter branchFilter = filters.getBranchFilter();
if (branchFilter == null) {
return null;
VcsLogRootFilter rootFilter = filters.getRootFilter();
VcsLogStructureFilter structureFilter = filters.getStructureFilter();
if (branchFilter == null && rootFilter == null && structureFilter == null) return null;
Set<Integer> filteredByFile = null;
Set<Integer> filteredByBranch = null;
if (branchFilter != null) {
filteredByBranch = getMatchingHeads(refs, branchFilter);
}
if (rootFilter != null) {
filteredByFile = getMatchingHeads(refs, rootFilter);
}
if (structureFilter != null) {
if (filteredByFile == null) {
filteredByFile = getMatchingHeads(refs, roots, structureFilter);
}
else {
filteredByFile = ContainerUtil.union(filteredByFile, getMatchingHeads(refs, roots, structureFilter));
}
}
final Collection<String> branchNames = new HashSet<String>(branchFilter.getBranchNames());
if (filteredByBranch == null) return filteredByFile;
if (filteredByFile == null) return filteredByBranch;
return new HashSet<Integer>(ContainerUtil.intersection(filteredByBranch, filteredByFile));
}
private Set<Integer> getMatchingHeads(@NotNull VcsLogRefs refs, @NotNull VcsLogBranchFilter filter) {
final Collection<String> branchNames = new HashSet<String>(filter.getBranchNames());
return new HashSet<Integer>(ContainerUtil.mapNotNull(refs.getBranches(), new Function<VcsRef, Integer>() {
@Override
public Integer fun(VcsRef ref) {
@@ -142,6 +170,28 @@ class VisiblePackBuilder {
}));
}
private Set<Integer> getMatchingHeads(@NotNull VcsLogRefs refs, @NotNull VcsLogRootFilter filter) {
Collection<VirtualFile> roots = filter.getRoots();
return getMatchingHeads(refs, roots);
}
private Set<Integer> getMatchingHeads(@NotNull VcsLogRefs refs, @NotNull Collection<VirtualFile> roots) {
Set<Integer> result = new HashSet<Integer>();
for (VcsRef branch : refs.getBranches()) {
if (roots.contains(branch.getRoot())) {
result.add(myHashMap.getCommitIndex(branch.getCommitHash()));
}
}
return result;
}
private Set<Integer> getMatchingHeads(@NotNull VcsLogRefs refs,
@NotNull Set<VirtualFile> vcsRoots,
@NotNull VcsLogStructureFilter filter) {
Pair<Set<VirtualFile>, MultiMap<VirtualFile, VirtualFile>> roots = VcsLogFileFilterUtil.collectRoots(filter.getFiles(), vcsRoots);
return getMatchingHeads(refs, ContainerUtil.union(roots.first, roots.second.keySet()));
}
@NotNull
private List<Hash> filterInMemory(@NotNull PermanentGraph<Integer> permanentGraph,
@NotNull List<VcsLogDetailsFilter> detailsFilters,
@@ -203,17 +253,28 @@ class VisiblePackBuilder {
private static List<Hash> getFilteredDetailsFromTheVcs(@NotNull Map<VirtualFile, VcsLogProvider> providers,
@NotNull VcsLogFilterCollection filterCollection,
int maxCount) throws VcsException {
VcsLogRootFilter rootFilter = filterCollection.getRootFilter();
VcsLogStructureFilter structureFilter = filterCollection.getStructureFilter();
Pair<Set<VirtualFile>, MultiMap<VirtualFile, VirtualFile>> selectedRootsAndFiles =
VcsLogFileFilterUtil.collectRootsAndFiles(providers.keySet(), rootFilter, structureFilter);
Collection<List<TimedVcsCommit>> logs = ContainerUtil.newArrayList();
for (Map.Entry<VirtualFile, VcsLogProvider> entry : providers.entrySet()) {
VirtualFile root = entry.getKey();
if (filterCollection.getStructureFilter() != null && !filterCollection.getStructureFilter().getRoots().contains(root)
|| filterCollection.getUserFilter() != null && filterCollection.getUserFilter().getUserNames(root).isEmpty()) {
if (!selectedRootsAndFiles.first.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;
}
List<TimedVcsCommit> matchingCommits = entry.getValue().getCommitsMatchingFilter(root, filterCollection, maxCount);
VcsLogFilterCollection rootSpecificCollection = filterCollection;
if (rootSpecificCollection.getStructureFilter() != null) {
rootSpecificCollection = replaceStructureFilter(filterCollection, new HashSet<VirtualFile>(selectedRootsAndFiles.second.get(root)));
}
List<TimedVcsCommit> matchingCommits = entry.getValue().getCommitsMatchingFilter(root, rootSpecificCollection, maxCount);
logs.add(matchingCommits);
}
@@ -226,6 +287,15 @@ class VisiblePackBuilder {
});
}
@NotNull
private static VcsLogFilterCollection replaceStructureFilter(@NotNull VcsLogFilterCollection filterCollection,
@NotNull Set<VirtualFile> files) {
return new VcsLogFilterCollectionImpl(filterCollection.getBranchFilter(), filterCollection.getUserFilter(),
filterCollection.getHashFilter(), filterCollection.getDateFilter(),
filterCollection.getTextFilter(), new VcsLogStructureFilterImpl(files),
filterCollection.getRootFilter());
}
@Nullable
private Condition<Integer> getFilterFromCommits(@Nullable List<Hash> filteredCommits) {
if (filteredCommits == null) {
@@ -31,19 +31,22 @@ public class VcsLogFilterCollectionImpl implements VcsLogFilterCollection {
@Nullable private final VcsLogDateFilter myDateFilter;
@Nullable private final VcsLogTextFilter myTextFilter;
@Nullable private final VcsLogStructureFilter myStructureFilter;
@Nullable private final VcsLogRootFilter myRootFilter;
public VcsLogFilterCollectionImpl(@Nullable VcsLogBranchFilter branchFilter,
@Nullable VcsLogUserFilter userFilter,
@Nullable VcsLogHashFilter hashFilter,
@Nullable VcsLogDateFilter dateFilter,
@Nullable VcsLogTextFilter textFilter,
@Nullable VcsLogStructureFilter structureFilter) {
@Nullable VcsLogStructureFilter structureFilter,
@Nullable VcsLogRootFilter rootFilter) {
myBranchFilter = branchFilter;
myUserFilter = userFilter;
myHashFilter = hashFilter;
myDateFilter = dateFilter;
myTextFilter = textFilter;
myStructureFilter = structureFilter;
myRootFilter = rootFilter;
}
@Nullable
@@ -82,6 +85,13 @@ public class VcsLogFilterCollectionImpl implements VcsLogFilterCollection {
return myStructureFilter;
}
@Nullable
@Override
public VcsLogRootFilter getRootFilter() {
return myRootFilter;
}
@Override
public boolean isEmpty() {
return myBranchFilter == null && getDetailsFilters().isEmpty();
@@ -47,6 +47,11 @@ class FilterModel<Filter extends VcsLogFilter> {
return myFilter;
}
@NotNull
public Computable<VcsLogDataPack> getDataPackProvider() {
return myDataPackProvider;
}
@NotNull
VcsLogDataPack getDataPack() {
return myDataPackProvider.compute();
@@ -23,8 +23,7 @@ import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.vcs.log.VcsLogDataPack;
import com.intellij.vcs.log.VcsLogStructureFilter;
import com.intellij.vcs.log.*;
import com.intellij.vcs.log.data.VcsLogStructureFilterImpl;
import com.intellij.vcs.log.ui.VcsStructureChooser;
import org.jetbrains.annotations.NotNull;
@@ -32,18 +31,17 @@ import org.jetbrains.annotations.Nullable;
import java.util.*;
class StructureFilterPopupComponent extends FilterPopupComponent<VcsLogStructureFilter> {
class StructureFilterPopupComponent extends FilterPopupComponent<VcsLogFileFilter> {
private static final int FILTER_LABEL_LENGTH = 20;
public StructureFilterPopupComponent(@NotNull FilterModel<VcsLogStructureFilter> filterModel) {
public StructureFilterPopupComponent(@NotNull FilterModel<VcsLogFileFilter> filterModel) {
super("Structure", filterModel);
}
@NotNull
@Override
protected String getText(@NotNull VcsLogStructureFilter filter) {
Collection<VirtualFile> files = getAllFiles(myFilterModel.getDataPack(), filter);
protected String getText(@NotNull VcsLogFileFilter filter) {
Collection<VirtualFile> files = getAllFiles(filter);
if (files.size() == 0) {
return ALL;
}
@@ -58,20 +56,15 @@ class StructureFilterPopupComponent extends FilterPopupComponent<VcsLogStructure
@Nullable
@Override
protected String getToolTip(@NotNull VcsLogStructureFilter filter) {
return getToolTip(getAllFiles(myFilterModel.getDataPack(), filter));
protected String getToolTip(@NotNull VcsLogFileFilter filter) {
return getToolTip(getAllFiles(filter));
}
@NotNull
private static Collection<VirtualFile> getAllFiles(@NotNull VcsLogDataPack dataPack, @NotNull VcsLogStructureFilter filter) {
private static Collection<VirtualFile> getAllFiles(@NotNull VcsLogFileFilter filter) {
Collection<VirtualFile> result = ContainerUtil.newArrayList();
for (VirtualFile root : dataPack.getLogProviders().keySet()) {
Collection<VirtualFile> files = filter.getFiles(root);
result.addAll(files);
if (files.isEmpty() && filter.getRoots().contains(root)) {
result.add(root);
}
}
if (filter.getRootFilter() != null) result.addAll(filter.getRootFilter().getRoots());
if (filter.getStructureFilter() != null) result.addAll(filter.getStructureFilter().getFiles());
return result;
}
@@ -90,8 +83,9 @@ class StructureFilterPopupComponent extends FilterPopupComponent<VcsLogStructure
}
private boolean isVisible(@NotNull VirtualFile root) {
if (myFilterModel.getFilter() != null) {
return myFilterModel.getFilter().getRoots().contains(root);
VcsLogFileFilter filter = myFilterModel.getFilter();
if (filter != null && filter.getRootFilter() != null) {
return filter.getRootFilter().getRoots().contains(root);
}
else {
return true;
@@ -101,9 +95,11 @@ class StructureFilterPopupComponent extends FilterPopupComponent<VcsLogStructure
private void setVisible(@NotNull VirtualFile root, boolean visible) {
Set<VirtualFile> roots = myFilterModel.getDataPack().getLogProviders().keySet();
VcsLogFileFilter previousFilter = myFilterModel.getFilter();
VcsLogRootFilter rootFilter = previousFilter != null ? previousFilter.getRootFilter() : null;
Collection<VirtualFile> visibleRoots;
VcsLogStructureFilter previousFilter = myFilterModel.getFilter();
if (previousFilter == null) {
if (rootFilter == null) {
if (visible) {
visibleRoots = roots;
}
@@ -113,14 +109,13 @@ class StructureFilterPopupComponent extends FilterPopupComponent<VcsLogStructure
}
else {
if (visible) {
visibleRoots = ContainerUtil.union(new HashSet<VirtualFile>(myFilterModel.getFilter().getRoots()), Collections.singleton(root));
visibleRoots = ContainerUtil.union(new HashSet<VirtualFile>(rootFilter.getRoots()), Collections.singleton(root));
}
else {
visibleRoots = ContainerUtil.subtract(myFilterModel.getFilter().getRoots(), Collections.singleton(root));
visibleRoots = ContainerUtil.subtract(rootFilter.getRoots(), Collections.singleton(root));
}
}
myFilterModel.setFilter(VcsLogStructureFilterImpl.build(visibleRoots, myFilterModel.getDataPack()));
// todo if there are some non-roots in structure filter they will get lost
myFilterModel.setFilter(new VcsLogFileFilter(previousFilter != null ? previousFilter.getStructureFilter() : null, new VcsLogRootFilterImpl(visibleRoots)));
}
@NotNull
@@ -169,12 +164,13 @@ class StructureFilterPopupComponent extends FilterPopupComponent<VcsLogStructure
public void actionPerformed(@NotNull AnActionEvent e) {
Project project = e.getRequiredData(CommonDataKeys.PROJECT);
VcsLogDataPack dataPack = myFilterModel.getDataPack();
VcsLogStructureFilter filter = myFilterModel.getFilter();
Collection<VirtualFile> files = filter == null ? Collections.<VirtualFile>emptySet() : getAllFiles(dataPack, filter);
VcsLogFileFilter filter = myFilterModel.getFilter();
VcsLogRootFilter rootFilter = filter == null ? null : filter.getRootFilter();
Collection<VirtualFile> files = filter == null ? Collections.<VirtualFile>emptySet() : getAllFiles(filter);
VcsStructureChooser chooser = new VcsStructureChooser(project, "Select Files or Folders to Filter", files,
new ArrayList<VirtualFile>(dataPack.getLogProviders().keySet()));
if (chooser.showAndGet()) {
myFilterModel.setFilter(VcsLogStructureFilterImpl.build(chooser.getSelectedFiles(), dataPack));
myFilterModel.setFilter(new VcsLogFileFilter(new VcsLogStructureFilterImpl(new HashSet<VirtualFile>(chooser.getSelectedFiles())), rootFilter));
}
}
}
@@ -31,11 +31,10 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.DocumentAdapter;
import com.intellij.ui.SearchTextFieldWithStoredHistory;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.MultiMap;
import com.intellij.util.ui.UIUtil;
import com.intellij.vcs.log.*;
import com.intellij.vcs.log.data.VcsLogDataHolder;
import com.intellij.vcs.log.data.VcsLogStructureFilterImpl;
import com.intellij.vcs.log.data.VcsLogUiProperties;
import com.intellij.vcs.log.data.*;
import com.intellij.vcs.log.impl.VcsLogFilterCollectionImpl;
import com.intellij.vcs.log.impl.VcsLogHashFilterImpl;
import com.intellij.vcs.log.ui.VcsLogUiImpl;
@@ -49,7 +48,9 @@ import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
*/
@@ -68,7 +69,7 @@ public class VcsLogClassicFilterUi implements VcsLogFilterUi {
@NotNull private final BranchFilterModel myBranchFilterModel;
@NotNull private final FilterModel<VcsLogUserFilter> myUserFilterModel;
@NotNull private final FilterModel<VcsLogDateFilter> myDateFilterModel;
@NotNull private final FilterModel<VcsLogStructureFilter> myStructureFilterModel;
@NotNull private final FilterModel<VcsLogFileFilter> myStructureFilterModel;
@NotNull private final TextFilterModel myTextFilterModel;
public VcsLogClassicFilterUi(@NotNull VcsLogUiImpl ui,
@@ -90,7 +91,7 @@ public class VcsLogClassicFilterUi implements VcsLogFilterUi {
myBranchFilterModel = new BranchFilterModel(dataPackGetter);
myUserFilterModel = new FilterModel<VcsLogUserFilter>(dataPackGetter);
myDateFilterModel = new FilterModel<VcsLogDateFilter>(dataPackGetter);
myStructureFilterModel = new FilterModel<VcsLogStructureFilter>(dataPackGetter);
myStructureFilterModel = new FilterModel<VcsLogFileFilter>(dataPackGetter);
myTextFilterModel = new TextFilterModel(dataPackGetter);
updateUiOnFilterChange();
@@ -103,7 +104,7 @@ public class VcsLogClassicFilterUi implements VcsLogFilterUi {
@Override
public void run() {
myUi.applyFiltersAndUpdateUi();
myBranchFilterModel.onStructureFilterChanged(myStructureFilterModel.getFilter());
myBranchFilterModel.onStructureFilterChanged(new HashSet<VirtualFile>(myLogDataHolder.getRoots()), myStructureFilterModel.getFilter());
}
});
}
@@ -157,7 +158,8 @@ public class VcsLogClassicFilterUi implements VcsLogFilterUi {
filtersFromText.second,
myDateFilterModel.getFilter(),
filtersFromText.first,
myStructureFilterModel.getFilter());
myStructureFilterModel.getFilter() == null ? null : myStructureFilterModel.getFilter().getStructureFilter(),
myStructureFilterModel.getFilter() == null ? null : myStructureFilterModel.getFilter().getRootFilter());
}
@NotNull
@@ -281,11 +283,11 @@ public class VcsLogClassicFilterUi implements VcsLogFilterUi {
super(provider);
}
public void onStructureFilterChanged(@Nullable VcsLogStructureFilter filter) {
public void onStructureFilterChanged(@NotNull Set<VirtualFile> roots, @Nullable VcsLogFileFilter filter) {
if (filter == null) {
myVisibleRoots = null;
} else {
myVisibleRoots = filter.getRoots();
myVisibleRoots = VcsLogFileFilterUtil.collectRoots(roots, filter.getRootFilter(), filter.getStructureFilter());
}
}
@@ -0,0 +1,41 @@
/*
* 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 com.intellij.vcs.log.ui.filter;
import com.intellij.vcs.log.VcsLogFilter;
import com.intellij.vcs.log.VcsLogRootFilter;
import com.intellij.vcs.log.VcsLogStructureFilter;
import org.jetbrains.annotations.Nullable;
public class VcsLogFileFilter implements VcsLogFilter {
@Nullable private final VcsLogStructureFilter myStructureFilter;
@Nullable private final VcsLogRootFilter myRootFilter;
public VcsLogFileFilter(@Nullable VcsLogStructureFilter structureFilter, @Nullable VcsLogRootFilter rootFilter) {
myStructureFilter = structureFilter;
myRootFilter = rootFilter;
}
@Nullable
public VcsLogStructureFilter getStructureFilter() {
return myStructureFilter;
}
@Nullable
public VcsLogRootFilter getRootFilter() {
return myRootFilter;
}
}
@@ -158,9 +158,9 @@ public class BranchesPanel extends JPanel {
}
public void onFiltersChange(@NotNull VcsLogFilterCollection filters) {
VcsLogStructureFilter structureFilter = filters.getStructureFilter();
if (structureFilter != null) {
myRoots = structureFilter.getRoots();
VcsLogRootFilter rootFilter = filters.getRootFilter();
if (rootFilter != null) {
myRoots = rootFilter.getRoots();
}
else {
myRoots = null;
@@ -136,6 +136,12 @@ class GitBekParentFixer {
return null;
}
@Nullable
@Override
public VcsLogRootFilter getRootFilter() {
return null;
}
@Override
public boolean isEmpty() {
return false;
@@ -440,7 +440,7 @@ 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) {
Collection<VirtualFile> files = filterCollection.getStructureFilter().getFiles(root);
Collection<VirtualFile> files = filterCollection.getStructureFilter().getFiles();
if (!files.isEmpty()) {
filterParameters.add("--simplify-merges");
filterParameters.add("--");
@@ -233,7 +233,7 @@ public class HgLogProvider implements VcsLogProvider {
}
if (filterCollection.getStructureFilter() != null) {
for (VirtualFile file : filterCollection.getStructureFilter().getFiles(root)) {
for (VirtualFile file : filterCollection.getStructureFilter().getFiles()) {
filterParameters.add(file.getPath());
}
}