diff --git a/platform/vcs-log/impl/src/META-INF/vcs-log.xml b/platform/vcs-log/impl/src/META-INF/vcs-log.xml index d935605aea2b..679c6b8d983f 100644 --- a/platform/vcs-log/impl/src/META-INF/vcs-log.xml +++ b/platform/vcs-log/impl/src/META-INF/vcs-log.xml @@ -85,6 +85,7 @@ + @@ -154,6 +155,7 @@ + diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/history/FileHistoryUtil.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/history/FileHistoryUtil.java index e1a851835c79..e0519cbaa44f 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/history/FileHistoryUtil.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/history/FileHistoryUtil.java @@ -58,7 +58,7 @@ public class FileHistoryUtil { return Collections.emptyList(); } - static boolean affectsFile(@NotNull Change change, @NotNull FilePath file, boolean isDeleted) { + public static boolean affectsFile(@NotNull Change change, @NotNull FilePath file, boolean isDeleted) { ContentRevision revision = isDeleted ? change.getBeforeRevision() : change.getAfterRevision(); if (revision == null) return false; return file.equals(revision.getFile()); diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/history/VcsLogFileHistoryProviderImpl.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/history/VcsLogFileHistoryProviderImpl.java index cce449bce610..4d018880c0fe 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/history/VcsLogFileHistoryProviderImpl.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/history/VcsLogFileHistoryProviderImpl.java @@ -8,10 +8,7 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.containers.ContainerUtil; import com.intellij.vcs.log.*; import com.intellij.vcs.log.data.VcsLogData; -import com.intellij.vcs.log.impl.HashImpl; -import com.intellij.vcs.log.impl.VcsLogContentUtil; -import com.intellij.vcs.log.impl.VcsLogManager; -import com.intellij.vcs.log.impl.VcsProjectLog; +import com.intellij.vcs.log.impl.*; import com.intellij.vcs.log.ui.AbstractVcsLogUi; import com.intellij.vcs.log.ui.VcsLogUiImpl; import com.intellij.vcs.log.util.VcsLogUtil; @@ -94,6 +91,7 @@ public class VcsLogFileHistoryProviderImpl implements VcsLogFileHistoryProvider if (firstTime) { VcsLogFilterCollection filters = createFilters(path, hash, root); ui = VcsProjectLog.getInstance(project).getTabsManager().openAnotherLogTab(logManager, filters); + ui.getProperties().set(MainVcsLogUiProperties.SHOW_ONLY_AFFECTED_CHANGES, true); } consumer.accept(ui, firstTime); } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/MainVcsLogUiProperties.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/MainVcsLogUiProperties.java index 4580d55125ff..e3a726976b6b 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/MainVcsLogUiProperties.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/MainVcsLogUiProperties.java @@ -33,6 +33,7 @@ public interface MainVcsLogUiProperties extends VcsLogUiProperties { VcsLogUiProperty TEXT_FILTER_MATCH_CASE = new VcsLogUiProperty<>("TextFilter.MatchCase"); VcsLogUiProperty TEXT_FILTER_REGEX = new VcsLogUiProperty<>("TextFilter.Regex"); VcsLogUiProperty SHOW_CHANGES_FROM_PARENTS = new VcsLogUiProperty<>("Changes.ShowChangesFromParents"); + VcsLogUiProperty SHOW_ONLY_AFFECTED_CHANGES = new VcsLogUiProperty<>("Changes.ShowOnlyAffected"); void addRecentlyFilteredGroup(@NotNull String filterName, @NotNull Collection values); diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogUiPropertiesImpl.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogUiPropertiesImpl.java index 613785e90135..a5670c207a97 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogUiPropertiesImpl.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogUiPropertiesImpl.java @@ -33,6 +33,7 @@ public abstract class VcsLogUiPropertiesImpl RECENTLY_FILTERED_USER_GROUPS = new ArrayDeque<>(); @Deprecated @@ -80,6 +82,9 @@ public abstract class VcsLogUiPropertiesImpl getProperty() { + return MainVcsLogUiProperties.SHOW_ONLY_AFFECTED_CHANGES; + } + + @Override + public void update(@NotNull AnActionEvent e) { + if (!Registry.is("vcs.folder.history.in.log")) { + e.getPresentation().setEnabledAndVisible(false); + } else { + super.update(e); + } + } +} diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/MainFrame.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/MainFrame.java index 29178c9888d6..9f9623464aab 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/MainFrame.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/MainFrame.java @@ -169,6 +169,8 @@ public class MainFrame extends JPanel implements DataProvider, Disposable { public void updateDataPack(@NotNull VisiblePack dataPack, boolean permGraphChanged) { myFilterUi.updateDataPack(dataPack); myGraphTable.updateDataPack(dataPack, permGraphChanged); + VcsLogStructureFilter structureFilter = dataPack.getFilters().get(VcsLogFilterCollection.STRUCTURE_FILTER); + myChangesBrowser.setAffectedPaths(structureFilter != null ? structureFilter.getFiles() : null); } @NotNull diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/VcsLogChangesBrowser.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/VcsLogChangesBrowser.java index f8709b03c258..45039b966e31 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/VcsLogChangesBrowser.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/VcsLogChangesBrowser.java @@ -20,6 +20,7 @@ import com.intellij.openapi.vcs.history.VcsRevisionNumber; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.IdeBorderFactory; import com.intellij.ui.SideBorder; +import com.intellij.ui.SimpleTextAttributes; import com.intellij.ui.components.panels.Wrapper; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; @@ -30,6 +31,7 @@ import com.intellij.vcs.log.VcsShortCommitDetails; import com.intellij.vcs.log.data.LoadingDetails; import com.intellij.vcs.log.data.index.IndexedDetails; import com.intellij.vcs.log.history.FileHistoryKt; +import com.intellij.vcs.log.history.FileHistoryUtil; import com.intellij.vcs.log.impl.MainVcsLogUiProperties; import com.intellij.vcs.log.impl.MergedChange; import com.intellij.vcs.log.impl.MergedChangeDiffRequestProvider; @@ -51,6 +53,7 @@ import static com.intellij.diff.util.DiffUserDataKeysEx.*; import static com.intellij.util.ObjectUtils.notNull; import static com.intellij.util.containers.ContainerUtil.getFirstItem; import static com.intellij.vcs.log.impl.MainVcsLogUiProperties.SHOW_CHANGES_FROM_PARENTS; +import static com.intellij.vcs.log.impl.MainVcsLogUiProperties.SHOW_ONLY_AFFECTED_CHANGES; /** * Change browser for commits in the Log. For merge commits, can display changes to commits parents in separate groups. @@ -66,6 +69,7 @@ public class VcsLogChangesBrowser extends ChangesBrowserBase implements Disposab @NotNull private final Set myRoots = ContainerUtil.newHashSet(); @NotNull private final List myChanges = ContainerUtil.newArrayList(); @NotNull private final Map> myChangesToParents = ContainerUtil.newHashMap(); + @Nullable private Collection myAffectedPaths; @NotNull private final Wrapper myToolbarWrapper; @Nullable private Runnable myModelUpdateListener; @@ -81,7 +85,7 @@ public class VcsLogChangesBrowser extends ChangesBrowserBase implements Disposab myListener = new VcsLogUiProperties.PropertiesChangeListener() { @Override public void onPropertyChanged(@NotNull VcsLogUiProperties.VcsLogUiProperty property) { - if (SHOW_CHANGES_FROM_PARENTS.equals(property)) { + if (SHOW_CHANGES_FROM_PARENTS.equals(property) || SHOW_ONLY_AFFECTED_CHANGES.equals(property)) { myViewer.rebuildTree(); } } @@ -150,6 +154,11 @@ public class VcsLogChangesBrowser extends ChangesBrowserBase implements Disposab if (myModelUpdateListener != null) myModelUpdateListener.run(); } + public void setAffectedPaths(@Nullable Collection paths) { + myAffectedPaths = paths; + myViewer.rebuildTree(); + } + public void setSelectedDetails(@NotNull List detailsList) { myChanges.clear(); myChangesToParents.clear(); @@ -192,15 +201,21 @@ public class VcsLogChangesBrowser extends ChangesBrowserBase implements Disposab @NotNull @Override protected DefaultTreeModel buildTreeModel() { - MyTreeModelBuilder builder = new MyTreeModelBuilder(); - builder.setChanges(myChanges, null); + Collection changes = collectAffectedChanges(myChanges); + Map> changesToParents = ContainerUtil.newHashMap(); + for (Map.Entry> entry : myChangesToParents.entrySet()) { + changesToParents.put(entry.getKey(), collectAffectedChanges(entry.getValue())); + } - if (isShowChangesFromParents() && !myChangesToParents.isEmpty()) { - if (myChanges.isEmpty()) { + MyTreeModelBuilder builder = new MyTreeModelBuilder(); + builder.setChanges(changes, null); + + if (isShowChangesFromParents() && !changesToParents.isEmpty()) { + if (changes.isEmpty()) { builder.addEmptyTextNode("No merged conflicts"); } - for (CommitId commitId : myChangesToParents.keySet()) { - Collection changesFromParent = myChangesToParents.get(commitId); + for (CommitId commitId : changesToParents.keySet()) { + Collection changesFromParent = changesToParents.get(commitId); if (!changesFromParent.isEmpty()) { builder.addChangesFromParentNode(changesFromParent, commitId); } @@ -210,11 +225,30 @@ public class VcsLogChangesBrowser extends ChangesBrowserBase implements Disposab return builder.build(); } + @NotNull + private Collection collectAffectedChanges(@NotNull Collection changes) { + if (!isShowOnlyAffected() || myAffectedPaths == null) return changes; + return ContainerUtil.filter(changes, change -> ContainerUtil.or(myAffectedPaths, filePath -> { + if (filePath.isDirectory()) { + return FileHistoryUtil.affectsDirectory(change, filePath); + } + else { + return FileHistoryUtil.affectsFile(change, filePath, false) || + FileHistoryUtil.affectsFile(change, filePath, true); + } + })); + } + private boolean isShowChangesFromParents() { return myUiProperties.exists(SHOW_CHANGES_FROM_PARENTS) && myUiProperties.get(SHOW_CHANGES_FROM_PARENTS); } + private boolean isShowOnlyAffected() { + return myUiProperties.exists(SHOW_ONLY_AFFECTED_CHANGES) && + myUiProperties.get(SHOW_ONLY_AFFECTED_CHANGES); + } + @NotNull public List getDirectChanges() { return myChanges;