vcs: non-modal: Show number of changed blocks to commit for partial changes in Local Changes tree

GitOrigin-RevId: 34d3f5c917327079b85d14e73226117b6d329a02
This commit is contained in:
Konstantin Kolosovsky
2019-07-02 06:52:16 +03:00
committed by intellij-monorepo-bot
parent c86ca18257
commit e15afc8c96
5 changed files with 59 additions and 43 deletions
@@ -46,10 +46,7 @@ import com.intellij.util.ui.components.BorderLayoutPanel;
import com.intellij.util.ui.tree.TreeUtil;
import com.intellij.util.xmlb.annotations.Attribute;
import com.intellij.util.xmlb.annotations.XCollection;
import com.intellij.vcs.commit.ChangesViewCommitPanel;
import com.intellij.vcs.commit.ChangesViewCommitWorkflow;
import com.intellij.vcs.commit.ChangesViewCommitWorkflowHandler;
import com.intellij.vcs.commit.CommitWorkflowManager;
import com.intellij.vcs.commit.*;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -66,6 +63,7 @@ import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Stream;
import static com.intellij.openapi.actionSystem.EmptyAction.registerWithShortcutSet;
@@ -220,6 +218,11 @@ public class ChangesViewManager implements ChangesViewI, ProjectComponent, Persi
return myCommitWorkflowHandler != null;
}
@NotNull
private Function<ChangeNodeDecorator, ChangeNodeDecorator> getChangeDecoratorProvider() {
return baseDecorator -> new PartialCommitChangeNodeDecorator(myProject, baseDecorator, () -> isAllowExcludeFromCommit());
}
@NotNull
private SimpleToolWindowPanel createChangeViewComponent() {
ActionToolbar changesToolbar = createChangesToolbar();
@@ -365,7 +368,7 @@ public class ChangesViewManager implements ChangesViewI, ProjectComponent, Persi
List<VirtualFile> unversionedFiles = changeListManager.getUnversionedFiles();
TreeModelBuilder treeModelBuilder = new TreeModelBuilder(myProject, myView.getGrouping())
.setChangeLists(changeLists, Registry.is("vcs.skip.single.default.changelist"))
.setChangeLists(changeLists, Registry.is("vcs.skip.single.default.changelist"), getChangeDecoratorProvider())
.setLocallyDeletedPaths(changeListManager.getDeletedFiles())
.setModifiedWithoutEditing(changeListManager.getModifiedWithoutEditing())
.setSwitchedFiles(changeListManager.getSwitchedFilesMap())
@@ -1,4 +1,4 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.openapi.vcs.changes;
import com.intellij.openapi.application.ApplicationManager;
@@ -33,7 +33,7 @@ public class RemoteRevisionsCache implements VcsListener {
private final ProjectLevelVcsManager myVcsManager;
private final RemoteStatusChangeNodeDecorator myChangeDecorator;
@NotNull private final RemoteStatusChangeNodeDecorator myChangeDecorator;
private final Project myProject;
private final Object myLock;
private final Map<String, RemoteDifferenceStrategy> myKinds;
@@ -186,6 +186,7 @@ public class RemoteRevisionsCache implements VcsListener {
}
}
@NotNull
public RemoteStatusChangeNodeDecorator getChangesNodeDecorator() {
return myChangeDecorator;
}
@@ -25,14 +25,12 @@ import com.intellij.openapi.vcs.changes.actions.RollbackDialogAction;
import com.intellij.openapi.vcs.changes.actions.diff.UnversionedDiffRequestProducer;
import com.intellij.openapi.vcs.changes.actions.diff.lst.LocalChangeListDiffTool;
import com.intellij.openapi.vcs.ex.ExclusionState;
import com.intellij.openapi.vcs.ex.LocalRange;
import com.intellij.openapi.vcs.ex.PartialLocalLineStatusTracker;
import com.intellij.openapi.vcs.impl.LineStatusTrackerManager;
import com.intellij.openapi.vcs.impl.PartialChangesUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.CollectionComboBoxModel;
import com.intellij.ui.ColoredListCellRenderer;
import com.intellij.ui.SimpleColoredComponent;
import com.intellij.ui.SimpleTextAttributes;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.JBUI;
@@ -40,6 +38,7 @@ import com.intellij.util.ui.ThreeStateCheckBox.State;
import com.intellij.util.ui.tree.TreeUtil;
import com.intellij.util.ui.update.MergingUpdateQueue;
import com.intellij.util.ui.update.Update;
import com.intellij.vcs.commit.PartialCommitChangeNodeDecorator;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -54,7 +53,6 @@ import java.util.stream.Stream;
import static com.intellij.openapi.util.text.StringUtil.shortenTextWithEllipsis;
import static com.intellij.openapi.vcs.changes.ui.ChangesListView.UNVERSIONED_FILES_DATA_KEY;
import static com.intellij.util.FontUtil.spaceAndThinSpace;
import static com.intellij.util.ui.update.MergingUpdateQueue.ANY_COMPONENT;
class MultipleLocalChangeListsBrowser extends CommitDialogChangesBrowser implements Disposable {
@@ -263,8 +261,8 @@ class MultipleLocalChangeListsBrowser extends CommitDialogChangesBrowser impleme
@NotNull
@Override
protected DefaultTreeModel buildTreeModel() {
MyChangeNodeDecorator decorator = new MyChangeNodeDecorator();
PartialCommitChangeNodeDecorator decorator =
new PartialCommitChangeNodeDecorator(myProject, RemoteRevisionsCache.getInstance(myProject).getChangesNodeDecorator());
TreeModelBuilder builder = new TreeModelBuilder(myProject, getGrouping());
builder.setChanges(myChanges, decorator);
builder.setUnversioned(myUnversioned);
@@ -367,33 +365,6 @@ class MultipleLocalChangeListsBrowser extends CommitDialogChangesBrowser impleme
return unversionedFilesNode.isManyFiles();
}
private class MyChangeNodeDecorator implements ChangeNodeDecorator {
private final ChangeNodeDecorator myRemoteRevisionsDecorator = RemoteRevisionsCache.getInstance(myProject).getChangesNodeDecorator();
@Override
public void decorate(@NotNull Change change, @NotNull SimpleColoredComponent renderer, boolean isShowFlatten) {
PartialLocalLineStatusTracker tracker = PartialChangesUtil.getPartialTracker(myProject, change);
if (tracker != null) {
List<LocalRange> ranges = tracker.getRanges();
if (ranges != null) {
int rangesToCommit = ContainerUtil.count(ranges, it -> it.getChangelistId().equals(myChangeList.getId()) && !it.isExcludedFromCommit());
if (rangesToCommit != 0 && rangesToCommit != ranges.size()) {
renderer.append(String.format(spaceAndThinSpace() + "%s of %s changes", rangesToCommit, ranges.size()),
SimpleTextAttributes.GRAY_ITALIC_ATTRIBUTES);
}
}
}
myRemoteRevisionsDecorator.decorate(change, renderer, isShowFlatten);
}
@Override
public void preDecorate(@NotNull Change change, @NotNull ChangesBrowserNodeRenderer renderer, boolean isShowFlatten) {
myRemoteRevisionsDecorator.preDecorate(change, renderer, isShowFlatten);
}
}
private class ChangeListChooser extends JPanel {
private final static int MAX_NAME_LEN = 35;
@NotNull private final ComboBox<LocalChangeList> myChooser = new ComboBox<>();
@@ -138,7 +138,7 @@ public class TreeModelBuilder implements ChangesViewModelBuilder {
@NotNull Collection<? extends ChangeList> changeLists,
boolean skipSingleDefaultChangelist) {
return new TreeModelBuilder(project, grouping)
.setChangeLists(changeLists, skipSingleDefaultChangelist)
.setChangeLists(changeLists, skipSingleDefaultChangelist, null)
.build();
}
@@ -197,7 +197,9 @@ public class TreeModelBuilder implements ChangesViewModelBuilder {
}
@NotNull
public TreeModelBuilder setChangeLists(@NotNull Collection<? extends ChangeList> changeLists, boolean skipSingleDefaultChangeList) {
public TreeModelBuilder setChangeLists(@NotNull Collection<? extends ChangeList> changeLists,
boolean skipSingleDefaultChangeList,
@Nullable Function<ChangeNodeDecorator, ChangeNodeDecorator> changeDecoratorProvider) {
assert myProject != null;
final RemoteRevisionsCache revisionsCache = RemoteRevisionsCache.getInstance(myProject);
boolean skipChangeListNode = skipSingleDefaultChangeList && isSingleBlankChangeList(changeLists);
@@ -219,7 +221,8 @@ public class TreeModelBuilder implements ChangesViewModelBuilder {
for (int i = 0; i < changes.size(); i++) {
Change change = changes.get(i);
RemoteStatusChangeNodeDecorator decorator = new RemoteStatusChangeNodeDecorator(revisionsCache, listRemoteState, i);
RemoteStatusChangeNodeDecorator baseDecorator = new RemoteStatusChangeNodeDecorator(revisionsCache, listRemoteState, i);
ChangeNodeDecorator decorator = changeDecoratorProvider != null ? changeDecoratorProvider.apply(baseDecorator) : baseDecorator;
insertChangeNode(change, changesParent, createChangeNode(change, decorator));
}
}
@@ -233,7 +236,8 @@ public class TreeModelBuilder implements ChangesViewModelBuilder {
return ((LocalChangeList) single).isBlank();
}
protected ChangesBrowserNode createChangeNode(Change change, ChangeNodeDecorator decorator) {
@NotNull
protected ChangesBrowserNode createChangeNode(@NotNull Change change, @Nullable ChangeNodeDecorator decorator) {
return new ChangesBrowserChangeNode(myProject, change, decorator);
}
@@ -0,0 +1,37 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.vcs.commit
import com.intellij.openapi.project.Project
import com.intellij.openapi.vcs.changes.Change
import com.intellij.openapi.vcs.changes.ChangeListChange
import com.intellij.openapi.vcs.changes.ui.ChangeNodeDecorator
import com.intellij.openapi.vcs.changes.ui.ChangesBrowserNodeRenderer
import com.intellij.openapi.vcs.impl.PartialChangesUtil
import com.intellij.ui.SimpleColoredComponent
import com.intellij.ui.SimpleTextAttributes.GRAY_ITALIC_ATTRIBUTES
import com.intellij.util.FontUtil.spaceAndThinSpace
class PartialCommitChangeNodeDecorator @JvmOverloads constructor(
private val project: Project,
private val baseDecorator: ChangeNodeDecorator,
private val isVisible: () -> Boolean = { true }
) : ChangeNodeDecorator {
override fun decorate(change: Change, renderer: SimpleColoredComponent, isShowFlatten: Boolean) {
if (isVisible()) appendPartialCommitState(change, renderer)
baseDecorator.decorate(change, renderer, isShowFlatten)
}
private fun appendPartialCommitState(change: Change, renderer: SimpleColoredComponent) {
val changeListId = (change as? ChangeListChange)?.changeListId ?: return
val ranges = PartialChangesUtil.getPartialTracker(project, change)?.getRanges() ?: return
val rangesToCommit = ranges.count { it.changelistId == changeListId && !it.isExcludedFromCommit }
if (rangesToCommit != 0 && rangesToCommit != ranges.size) {
renderer.append(spaceAndThinSpace()).append("$rangesToCommit of ${ranges.size} changes", GRAY_ITALIC_ATTRIBUTES)
}
}
override fun preDecorate(change: Change, renderer: ChangesBrowserNodeRenderer, isShowFlatten: Boolean) =
baseDecorator.preDecorate(change, renderer, isShowFlatten)
}