mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
vcs: new ChangesBrowser implementation
* simplify available API * completely move data manipulation to the implementations * prefer listeners to the explicit "refresh changes" callbacks
This commit is contained in:
committed by
Aleksey Pivovarov
parent
89e6dda095
commit
d489bfccc6
@@ -27,9 +27,9 @@ import com.intellij.openapi.project.DumbAware;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
import com.intellij.openapi.vcs.VcsBundle;
|
||||
import com.intellij.openapi.vcs.changes.ui.ChangesBrowserBase;
|
||||
import com.intellij.openapi.vcs.changes.ui.ChangesBrowserNode;
|
||||
import com.intellij.openapi.vcs.changes.ui.ChangesListView;
|
||||
import com.intellij.openapi.vcs.changes.ui.OldChangesBrowserBase;
|
||||
import com.intellij.openapi.vcs.changes.ui.TreeModelBuilder;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.ui.ScrollPaneFactory;
|
||||
@@ -179,11 +179,11 @@ abstract class SpecificFilesViewDialog extends DialogWrapper {
|
||||
@NotNull
|
||||
protected abstract List<VirtualFile> getFiles();
|
||||
|
||||
protected static ChangesBrowserBase getBrowserBase(@NotNull ChangesListView view) {
|
||||
return ChangesBrowserBase.DATA_KEY.getData(DataManager.getInstance().getDataContext(view));
|
||||
protected static OldChangesBrowserBase getBrowserBase(@NotNull ChangesListView view) {
|
||||
return OldChangesBrowserBase.DATA_KEY.getData(DataManager.getInstance().getDataContext(view));
|
||||
}
|
||||
|
||||
public static void refreshChanges(@NotNull Project project, @Nullable ChangesBrowserBase browser) {
|
||||
public static void refreshChanges(@NotNull Project project, @Nullable OldChangesBrowserBase browser) {
|
||||
if (browser != null) {
|
||||
ChangeListManager.getInstance(project)
|
||||
.invokeAfterUpdate(browser::rebuildList, InvokeAfterUpdateMode.SYNCHRONOUS_CANCELLABLE, "Delete files", null);
|
||||
|
||||
+2
-2
@@ -21,8 +21,8 @@ import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vcs.changes.ChangeListManager;
|
||||
import com.intellij.openapi.vcs.changes.ui.ChangesBrowserBase;
|
||||
import com.intellij.openapi.vcs.changes.ui.IgnoreUnversionedDialog;
|
||||
import com.intellij.openapi.vcs.changes.ui.OldChangesBrowserBase;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -39,7 +39,7 @@ public class IgnoreUnversionedAction extends AnAction {
|
||||
|
||||
if (!ChangeListManager.getInstance(project).isFreezedWithNotification(null)) {
|
||||
List<VirtualFile> files = e.getRequiredData(UNVERSIONED_FILES_DATA_KEY).collect(Collectors.toList());
|
||||
ChangesBrowserBase<?> browser = e.getData(ChangesBrowserBase.DATA_KEY);
|
||||
OldChangesBrowserBase<?> browser = e.getData(OldChangesBrowserBase.DATA_KEY);
|
||||
Runnable callback = browser == null ? null : () -> {
|
||||
browser.rebuildList();
|
||||
//noinspection unchecked
|
||||
|
||||
+2
-2
@@ -25,7 +25,7 @@ import com.intellij.openapi.project.DumbAware;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vcs.VcsDataKeys;
|
||||
import com.intellij.openapi.vcs.changes.Change;
|
||||
import com.intellij.openapi.vcs.changes.ui.ChangesBrowserBase;
|
||||
import com.intellij.openapi.vcs.changes.ui.OldChangesBrowserBase;
|
||||
import com.intellij.openapi.vcs.changes.ui.RollbackChangesDialog;
|
||||
import com.intellij.vcsUtil.RollbackUtil;
|
||||
|
||||
@@ -43,7 +43,7 @@ public class RollbackDialogAction extends AnAction implements DumbAware {
|
||||
FileDocumentManager.getInstance().saveAllDocuments();
|
||||
Change[] changes = e.getData(VcsDataKeys.CHANGES);
|
||||
Project project = e.getData(CommonDataKeys.PROJECT);
|
||||
final ChangesBrowserBase browser = e.getData(ChangesBrowserBase.DATA_KEY);
|
||||
final OldChangesBrowserBase browser = e.getData(OldChangesBrowserBase.DATA_KEY);
|
||||
if (browser != null) {
|
||||
browser.setDataIsDirty(true);
|
||||
}
|
||||
|
||||
+3
-3
@@ -28,8 +28,8 @@ import com.intellij.openapi.vcs.*;
|
||||
import com.intellij.openapi.vcs.changes.Change;
|
||||
import com.intellij.openapi.vcs.changes.ChangeListManagerImpl;
|
||||
import com.intellij.openapi.vcs.changes.LocalChangeList;
|
||||
import com.intellij.openapi.vcs.changes.ui.ChangesBrowserBase;
|
||||
import com.intellij.openapi.vcs.changes.ui.ChangesListView;
|
||||
import com.intellij.openapi.vcs.changes.ui.OldChangesBrowserBase;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.Consumer;
|
||||
@@ -59,13 +59,13 @@ public class ScheduleForAdditionAction extends AnAction implements DumbAware {
|
||||
Project project = e.getRequiredData(CommonDataKeys.PROJECT);
|
||||
List<VirtualFile> unversionedFiles = getUnversionedFiles(e, project).collect(Collectors.toList());
|
||||
|
||||
addUnversioned(project, unversionedFiles, this::isStatusForAddition, e.getData(ChangesBrowserBase.DATA_KEY));
|
||||
addUnversioned(project, unversionedFiles, this::isStatusForAddition, e.getData(OldChangesBrowserBase.DATA_KEY));
|
||||
}
|
||||
|
||||
public static boolean addUnversioned(@NotNull Project project,
|
||||
@NotNull List<VirtualFile> files,
|
||||
@NotNull Condition<FileStatus> unversionedFileCondition,
|
||||
@Nullable ChangesBrowserBase browser) {
|
||||
@Nullable OldChangesBrowserBase browser) {
|
||||
boolean result = true;
|
||||
|
||||
if (!files.isEmpty()) {
|
||||
|
||||
@@ -26,7 +26,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import javax.swing.tree.DefaultTreeModel;
|
||||
import java.util.List;
|
||||
|
||||
public class ChangesBrowser extends ChangesBrowserBase<Change> {
|
||||
public class ChangesBrowser extends OldChangesBrowserBase<Change> {
|
||||
|
||||
public ChangesBrowser(@NotNull Project project,
|
||||
@Nullable List<? extends ChangeList> changeLists,
|
||||
|
||||
+140
-371
@@ -16,182 +16,144 @@
|
||||
package com.intellij.openapi.vcs.changes.ui;
|
||||
|
||||
import com.intellij.diff.DiffDialogHints;
|
||||
import com.intellij.diff.util.DiffUserDataKeysEx;
|
||||
import com.intellij.ide.DeleteProvider;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.diff.DiffManager;
|
||||
import com.intellij.diff.chains.DiffRequestChain;
|
||||
import com.intellij.diff.util.DiffUserDataKeys;
|
||||
import com.intellij.openapi.ListSelection;
|
||||
import com.intellij.openapi.actionSystem.*;
|
||||
import com.intellij.openapi.actionSystem.ex.ActionUtil;
|
||||
import com.intellij.openapi.actionSystem.ex.CheckboxAction;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.fileChooser.actions.VirtualFileDeleteProvider;
|
||||
import com.intellij.openapi.project.DumbAwareAction;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vcs.FilePath;
|
||||
import com.intellij.openapi.vcs.VcsBundle;
|
||||
import com.intellij.openapi.vcs.VcsDataKeys;
|
||||
import com.intellij.openapi.vcs.changes.Change;
|
||||
import com.intellij.openapi.vcs.changes.ChangeList;
|
||||
import com.intellij.openapi.vcs.changes.ContentRevision;
|
||||
import com.intellij.openapi.vcs.changes.RemoteRevisionsCache;
|
||||
import com.intellij.openapi.vcs.changes.actions.diff.ShowDiffAction;
|
||||
import com.intellij.openapi.vcs.changes.actions.diff.ShowDiffContext;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vcs.changes.actions.diff.ChangeDiffRequestProducer;
|
||||
import com.intellij.ui.ScrollPaneFactory;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.intellij.lang.annotations.JdkConstants;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.Border;
|
||||
import javax.swing.tree.DefaultTreeModel;
|
||||
import javax.swing.tree.TreePath;
|
||||
import java.awt.*;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static com.intellij.openapi.vcs.changes.ChangesUtil.getFiles;
|
||||
import static com.intellij.openapi.vcs.changes.ChangesUtil.getNavigatableArray;
|
||||
import static com.intellij.openapi.vcs.changes.ui.ChangesBrowserNode.UNVERSIONED_FILES_TAG;
|
||||
import static com.intellij.openapi.vcs.changes.ui.ChangesListView.*;
|
||||
public abstract class ChangesBrowserBase extends JPanel implements DataProvider {
|
||||
public static final DataKey<ChangesBrowserBase> DATA_KEY =
|
||||
DataKey.create("com.intellij.openapi.vcs.changes.ui.ChangesBrowserBase");
|
||||
|
||||
public abstract class ChangesBrowserBase<T> extends JPanel implements TypeSafeDataProvider, Disposable {
|
||||
private static final Logger LOG = Logger.getInstance(ChangesBrowserBase.class);
|
||||
@NotNull protected final Project myProject;
|
||||
|
||||
// for backgroundable rollback to mark
|
||||
private boolean myDataIsDirty;
|
||||
protected final Class<T> myClass;
|
||||
protected final ChangesTreeList<T> myViewer;
|
||||
protected final JScrollPane myViewerScrollPane;
|
||||
protected ChangeList mySelectedChangeList;
|
||||
protected List<T> myChangesToDisplay;
|
||||
protected final Project myProject;
|
||||
private final boolean myCapableOfExcludingChanges;
|
||||
protected final JPanel myHeaderPanel;
|
||||
private JComponent myBottomPanel;
|
||||
private DefaultActionGroup myToolBarGroup;
|
||||
private String myToggleActionTitle = VcsBundle.message("commit.dialog.include.action.name");
|
||||
protected final ChangesTree myViewer;
|
||||
|
||||
private JComponent myDiffBottomComponent;
|
||||
private final DefaultActionGroup myToolBarGroup = new DefaultActionGroup();
|
||||
private final ActionToolbar myToolbar;
|
||||
private final JScrollPane myViewerScrollPane;
|
||||
private final AnAction myShowDiffAction;
|
||||
|
||||
public static DataKey<ChangesBrowserBase> DATA_KEY = DataKey.create("com.intellij.openapi.vcs.changes.ui.ChangesBrowser");
|
||||
private AnAction myDiffAction;
|
||||
private final VirtualFile myToSelect;
|
||||
@NotNull private final DeleteProvider myDeleteProvider = new VirtualFileDeleteProvider();
|
||||
@Nullable private Runnable myInclusionChangedListener;
|
||||
|
||||
public void setChangesToDisplay(final List<T> changes) {
|
||||
myChangesToDisplay = changes;
|
||||
myViewer.setChangesToDisplay(changes);
|
||||
}
|
||||
|
||||
public void setDecorator(final ChangeNodeDecorator decorator) {
|
||||
myViewer.setChangeDecorator(decorator);
|
||||
}
|
||||
|
||||
protected ChangesBrowserBase(@NotNull final Project project,
|
||||
@NotNull List<T> changes,
|
||||
final boolean capableOfExcludingChanges,
|
||||
final boolean highlightProblems,
|
||||
@Nullable final Runnable inclusionListener,
|
||||
@NotNull ChangesBrowser.MyUseCase useCase,
|
||||
@Nullable VirtualFile toSelect,
|
||||
@NotNull Class<T> clazz) {
|
||||
super(new BorderLayout());
|
||||
setFocusable(false);
|
||||
|
||||
myClass = clazz;
|
||||
myDataIsDirty = false;
|
||||
protected ChangesBrowserBase(@NotNull Project project,
|
||||
boolean showCheckboxes,
|
||||
boolean highlightProblems) {
|
||||
myProject = project;
|
||||
myCapableOfExcludingChanges = capableOfExcludingChanges;
|
||||
myToSelect = toSelect;
|
||||
myViewer = new MyChangesTreeList(this, project, showCheckboxes, highlightProblems);
|
||||
|
||||
ChangeNodeDecorator decorator =
|
||||
ChangesBrowser.MyUseCase.LOCAL_CHANGES.equals(useCase) ? RemoteRevisionsCache.getInstance(myProject).getChangesNodeDecorator() : null;
|
||||
DefaultActionGroup toolbarGroups = new DefaultActionGroup();
|
||||
toolbarGroups.add(myToolBarGroup);
|
||||
toolbarGroups.addSeparator();
|
||||
toolbarGroups.addAll(myViewer.getTreeActions());
|
||||
myToolbar = ActionManager.getInstance().createActionToolbar("ChangesBrowser", toolbarGroups, true);
|
||||
myToolbar.setTargetComponent(this);
|
||||
myViewer.installPopupHandler(myToolBarGroup);
|
||||
|
||||
myViewer = new ChangesTreeList<T>(myProject, changes, capableOfExcludingChanges, highlightProblems, inclusionListener, decorator) {
|
||||
protected DefaultTreeModel buildTreeModel(final List<T> changes, ChangeNodeDecorator changeNodeDecorator) {
|
||||
return ChangesBrowserBase.this.buildTreeModel(changes, changeNodeDecorator, isShowFlatten());
|
||||
}
|
||||
|
||||
protected List<T> getSelectedObjects(final ChangesBrowserNode<?> node) {
|
||||
return ChangesBrowserBase.this.getSelectedObjects(node);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected T getLeadSelectedObject(final ChangesBrowserNode<?> node) {
|
||||
return ChangesBrowserBase.this.getLeadSelectedObject(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setScrollPaneBorder(Border border) {
|
||||
myViewerScrollPane.setBorder(border);
|
||||
}
|
||||
};
|
||||
myViewerScrollPane = ScrollPaneFactory.createScrollPane(myViewer);
|
||||
myHeaderPanel = new JPanel(new BorderLayout());
|
||||
|
||||
myShowDiffAction = new MyShowDiffAction();
|
||||
}
|
||||
|
||||
protected void init() {
|
||||
setLayout(new BorderLayout());
|
||||
setFocusable(false);
|
||||
|
||||
JPanel topPanel = new JPanel(new BorderLayout());
|
||||
topPanel.add(myToolbar.getComponent(), BorderLayout.CENTER);
|
||||
|
||||
JComponent headerPanel = createHeaderPanel();
|
||||
if (headerPanel != null) topPanel.add(headerPanel, BorderLayout.EAST);
|
||||
|
||||
add(topPanel, BorderLayout.NORTH);
|
||||
add(myViewerScrollPane, BorderLayout.CENTER);
|
||||
|
||||
myHeaderPanel.add(createToolbar(), BorderLayout.CENTER);
|
||||
add(myHeaderPanel, BorderLayout.NORTH);
|
||||
|
||||
myBottomPanel = new JPanel(new BorderLayout());
|
||||
add(myBottomPanel, BorderLayout.SOUTH);
|
||||
myToolBarGroup.addAll(createToolbarActions());
|
||||
|
||||
myViewer.installPopupHandler(myToolBarGroup);
|
||||
myViewer.setDoubleClickHandler(getDoubleClickHandler());
|
||||
myShowDiffAction.registerCustomShortcutSet(this, null);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected abstract DefaultTreeModel buildTreeModel(final List<T> changes, ChangeNodeDecorator changeNodeDecorator, boolean showFlatten);
|
||||
|
||||
@NotNull
|
||||
protected abstract List<T> getSelectedObjects(@NotNull ChangesBrowserNode<?> node);
|
||||
protected abstract DefaultTreeModel buildTreeModel(boolean showFlatten);
|
||||
|
||||
|
||||
@Nullable
|
||||
protected abstract T getLeadSelectedObject(@NotNull ChangesBrowserNode<?> node);
|
||||
protected ChangeDiffRequestChain.Producer getDiffRequestProducer(@NotNull Object userObject) {
|
||||
if (userObject instanceof Change) {
|
||||
return ChangeDiffRequestProducer.create(myProject, (Change)userObject);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
protected JComponent createHeaderPanel() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected Runnable getDoubleClickHandler() {
|
||||
return () -> showDiff();
|
||||
protected List<AnAction> createToolbarActions() {
|
||||
return ContainerUtil.list(
|
||||
myShowDiffAction
|
||||
);
|
||||
}
|
||||
|
||||
protected void setInitialSelection(final List<? extends ChangeList> changeLists,
|
||||
@NotNull List<T> changes,
|
||||
final ChangeList initialListSelection) {
|
||||
mySelectedChangeList = initialListSelection;
|
||||
@NotNull
|
||||
protected List<AnAction> createDiffActions() {
|
||||
return ContainerUtil.list(
|
||||
);
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
protected void onDoubleClick() {
|
||||
showDiff();
|
||||
}
|
||||
|
||||
public void addToolbarAction(AnAction action) {
|
||||
protected void onIncludedChanged() {
|
||||
if (myInclusionChangedListener != null) myInclusionChangedListener.run();
|
||||
}
|
||||
|
||||
|
||||
public void selectEntries(@NotNull Collection<?> changes) {
|
||||
myViewer.setSelectedChanges(changes);
|
||||
}
|
||||
|
||||
public void setInclusionChangedListener(@Nullable Runnable value) {
|
||||
myInclusionChangedListener = value;
|
||||
}
|
||||
|
||||
public void addToolbarAction(@NotNull AnAction action) {
|
||||
myToolBarGroup.add(action);
|
||||
}
|
||||
|
||||
public void setDiffBottomComponent(JComponent diffBottomComponent) {
|
||||
myDiffBottomComponent = diffBottomComponent;
|
||||
|
||||
@NotNull
|
||||
public JComponent getPreferredFocusedComponent() {
|
||||
return myViewer.getPreferredFocusedComponent();
|
||||
}
|
||||
|
||||
public void setToggleActionTitle(final String toggleActionTitle) {
|
||||
myToggleActionTitle = toggleActionTitle;
|
||||
}
|
||||
|
||||
public JPanel getHeaderPanel() {
|
||||
return myHeaderPanel;
|
||||
}
|
||||
|
||||
public ChangesTreeList<T> getViewer() {
|
||||
return myViewer;
|
||||
@NotNull
|
||||
public ActionToolbar getToolbar() {
|
||||
return myToolbar;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -199,271 +161,78 @@ public abstract class ChangesBrowserBase<T> extends JPanel implements TypeSafeDa
|
||||
return myViewerScrollPane;
|
||||
}
|
||||
|
||||
public void calcData(DataKey key, DataSink sink) {
|
||||
if (key == VcsDataKeys.CHANGES) {
|
||||
List<Change> list = getSelectedChanges();
|
||||
if (list.isEmpty()) list = getAllChanges();
|
||||
sink.put(VcsDataKeys.CHANGES, list.toArray(new Change[list.size()]));
|
||||
}
|
||||
else if (key == VcsDataKeys.CHANGES_SELECTION) {
|
||||
sink.put(VcsDataKeys.CHANGES_SELECTION, getChangesSelection());
|
||||
}
|
||||
else if (key == VcsDataKeys.CHANGE_LISTS) {
|
||||
sink.put(VcsDataKeys.CHANGE_LISTS, getSelectedChangeLists());
|
||||
}
|
||||
else if (key == VcsDataKeys.CHANGE_LEAD_SELECTION) {
|
||||
final Change highestSelection = ObjectUtils.tryCast(myViewer.getHighestLeadSelection(), Change.class);
|
||||
sink.put(VcsDataKeys.CHANGE_LEAD_SELECTION, (highestSelection == null) ? new Change[]{} : new Change[]{highestSelection});
|
||||
}
|
||||
else if (key == CommonDataKeys.VIRTUAL_FILE_ARRAY) {
|
||||
sink.put(CommonDataKeys.VIRTUAL_FILE_ARRAY, getSelectedFiles().toArray(VirtualFile[]::new));
|
||||
}
|
||||
else if (key == CommonDataKeys.NAVIGATABLE_ARRAY) {
|
||||
sink.put(CommonDataKeys.NAVIGATABLE_ARRAY, getNavigatableArray(myProject, getSelectedFiles()));
|
||||
}
|
||||
else if (VcsDataKeys.IO_FILE_ARRAY.equals(key)) {
|
||||
sink.put(VcsDataKeys.IO_FILE_ARRAY, getSelectedIoFiles());
|
||||
}
|
||||
else if (key == DATA_KEY) {
|
||||
sink.put(DATA_KEY, this);
|
||||
}
|
||||
else if (VcsDataKeys.SELECTED_CHANGES_IN_DETAILS.equals(key)) {
|
||||
final List<Change> selectedChanges = getSelectedChanges();
|
||||
sink.put(VcsDataKeys.SELECTED_CHANGES_IN_DETAILS, selectedChanges.toArray(new Change[selectedChanges.size()]));
|
||||
}
|
||||
else if (UNVERSIONED_FILES_DATA_KEY.equals(key)) {
|
||||
sink.put(UNVERSIONED_FILES_DATA_KEY, getVirtualFiles(myViewer.getSelectionPaths(), UNVERSIONED_FILES_TAG));
|
||||
}
|
||||
else if (PlatformDataKeys.DELETE_ELEMENT_PROVIDER.equals(key)) {
|
||||
sink.put(PlatformDataKeys.DELETE_ELEMENT_PROVIDER, myDeleteProvider);
|
||||
}
|
||||
@NotNull
|
||||
public ChangesTree getViewer() {
|
||||
return myViewer;
|
||||
}
|
||||
|
||||
public void select(List<T> changes) {
|
||||
myViewer.select(changes);
|
||||
}
|
||||
|
||||
public JComponent getBottomPanel() {
|
||||
return myBottomPanel;
|
||||
}
|
||||
|
||||
private class ToggleChangeAction extends CheckboxAction {
|
||||
public ToggleChangeAction() {
|
||||
super(myToggleActionTitle);
|
||||
}
|
||||
|
||||
public boolean isSelected(AnActionEvent e) {
|
||||
T change = ObjectUtils.tryCast(e.getData(VcsDataKeys.CURRENT_CHANGE), myClass);
|
||||
if (change == null) return false;
|
||||
|
||||
return myViewer.isIncluded(change);
|
||||
}
|
||||
|
||||
public void setSelected(AnActionEvent e, boolean state) {
|
||||
T change = ObjectUtils.tryCast(e.getData(VcsDataKeys.CURRENT_CHANGE), myClass);
|
||||
if (change == null) return;
|
||||
|
||||
if (state) {
|
||||
myViewer.includeChange(change);
|
||||
}
|
||||
else {
|
||||
myViewer.excludeChange(change);
|
||||
}
|
||||
@Nullable
|
||||
@Override
|
||||
public Object getData(String dataId) {
|
||||
if (DATA_KEY.is(dataId)) {
|
||||
return this;
|
||||
}
|
||||
return VcsTreeModelData.getData(myProject, myViewer, dataId);
|
||||
}
|
||||
|
||||
protected void showDiffForChanges(Change[] changesArray, final int indexInSelection) {
|
||||
final ShowDiffContext context = new ShowDiffContext(isInFrame() ? DiffDialogHints.FRAME : DiffDialogHints.MODAL);
|
||||
|
||||
context.addActions(createDiffActions());
|
||||
if (myDiffBottomComponent != null) {
|
||||
context.putChainContext(DiffUserDataKeysEx.BOTTOM_PANEL, myDiffBottomComponent);
|
||||
}
|
||||
|
||||
updateDiffContext(context);
|
||||
|
||||
ShowDiffAction.showDiffForChange(myProject, Arrays.asList(changesArray), indexInSelection, context);
|
||||
}
|
||||
|
||||
protected void updateDiffContext(@NotNull ShowDiffContext context) {
|
||||
}
|
||||
|
||||
private boolean canShowDiff() {
|
||||
return ShowDiffAction.canShowDiff(myProject, getChangesSelection().getList());
|
||||
}
|
||||
|
||||
private void showDiff() {
|
||||
ListSelection<Change> selection = getChangesSelection();
|
||||
List<Change> changes = selection.getList();
|
||||
|
||||
Change[] changesArray = changes.toArray(new Change[changes.size()]);
|
||||
showDiffForChanges(changesArray, selection.getSelectedIndex());
|
||||
|
||||
afterDiffRefresh();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected ListSelection<Change> getChangesSelection() {
|
||||
final Change leadSelection = ObjectUtils.tryCast(myViewer.getLeadSelection(), Change.class);
|
||||
List<Change> changes = getSelectedChanges();
|
||||
|
||||
if (changes.size() < 2) {
|
||||
List<Change> allChanges = getAllChanges();
|
||||
if (allChanges.size() > 1 || changes.isEmpty()) {
|
||||
changes = allChanges;
|
||||
}
|
||||
}
|
||||
|
||||
if (leadSelection != null && !changes.contains(leadSelection)) {
|
||||
return ListSelection.createSingleton(leadSelection);
|
||||
}
|
||||
|
||||
return ListSelection.create(changes, leadSelection);
|
||||
}
|
||||
|
||||
protected void afterDiffRefresh() {
|
||||
}
|
||||
|
||||
private static boolean isInFrame() {
|
||||
return ModalityState.current().equals(ModalityState.NON_MODAL);
|
||||
}
|
||||
|
||||
protected List<AnAction> createDiffActions() {
|
||||
List<AnAction> actions = new ArrayList<>();
|
||||
if (myCapableOfExcludingChanges) {
|
||||
actions.add(new ToggleChangeAction());
|
||||
}
|
||||
return actions;
|
||||
}
|
||||
|
||||
public void rebuildList() {
|
||||
myViewer.setChangesToDisplay(getCurrentDisplayedObjects(), myToSelect);
|
||||
}
|
||||
|
||||
public void setAlwayExpandList(final boolean value) {
|
||||
myViewer.setAlwaysExpandList(value);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected JComponent createToolbar() {
|
||||
DefaultActionGroup toolbarGroups = new DefaultActionGroup();
|
||||
myToolBarGroup = new DefaultActionGroup();
|
||||
toolbarGroups.add(myToolBarGroup);
|
||||
buildToolBar(myToolBarGroup);
|
||||
|
||||
toolbarGroups.addSeparator();
|
||||
DefaultActionGroup treeActionsGroup = new DefaultActionGroup();
|
||||
toolbarGroups.add(treeActionsGroup);
|
||||
for (AnAction action : myViewer.getTreeActions()) {
|
||||
treeActionsGroup.add(action);
|
||||
}
|
||||
|
||||
ActionToolbar toolbar = ActionManager.getInstance().createActionToolbar("ChangesBrowser", toolbarGroups, true);
|
||||
toolbar.setTargetComponent(this);
|
||||
return toolbar.getComponent();
|
||||
}
|
||||
|
||||
protected void buildToolBar(final DefaultActionGroup toolBarGroup) {
|
||||
myDiffAction = new DumbAwareAction() {
|
||||
public void update(AnActionEvent e) {
|
||||
e.getPresentation().setEnabled(canShowDiff() || e.getInputEvent() instanceof KeyEvent);
|
||||
}
|
||||
|
||||
public void actionPerformed(AnActionEvent e) {
|
||||
showDiff();
|
||||
}
|
||||
};
|
||||
ActionUtil.copyFrom(myDiffAction, IdeActions.ACTION_SHOW_DIFF_COMMON);
|
||||
myDiffAction.registerCustomShortcutSet(myViewer, null);
|
||||
toolBarGroup.add(myDiffAction);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public abstract List<Change> getCurrentIncludedChanges();
|
||||
|
||||
@NotNull
|
||||
public List<Change> getCurrentDisplayedChanges() {
|
||||
return mySelectedChangeList != null ? ContainerUtil.newArrayList(mySelectedChangeList.getChanges()) : Collections.emptyList();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public abstract List<T> getCurrentDisplayedObjects();
|
||||
|
||||
@NotNull
|
||||
public List<VirtualFile> getIncludedUnversionedFiles() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
public int getUnversionedFilesCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public ChangeList getSelectedChangeList() {
|
||||
return mySelectedChangeList;
|
||||
}
|
||||
|
||||
public JComponent getPreferredFocusedComponent() {
|
||||
return myViewer.getPreferredFocusedComponent();
|
||||
}
|
||||
|
||||
private ChangeList[] getSelectedChangeLists() {
|
||||
if (mySelectedChangeList != null) {
|
||||
return new ChangeList[]{mySelectedChangeList};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private File[] getSelectedIoFiles() {
|
||||
final List<Change> changes = getSelectedChanges();
|
||||
final List<File> files = new ArrayList<>();
|
||||
for (Change change : changes) {
|
||||
final ContentRevision afterRevision = change.getAfterRevision();
|
||||
if (afterRevision != null) {
|
||||
final FilePath file = afterRevision.getFile();
|
||||
final File ioFile = file.getIOFile();
|
||||
files.add(ioFile);
|
||||
}
|
||||
}
|
||||
return files.toArray(new File[files.size()]);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public abstract List<Change> getSelectedChanges();
|
||||
|
||||
@NotNull
|
||||
public abstract List<Change> getAllChanges();
|
||||
|
||||
@NotNull
|
||||
protected Stream<VirtualFile> getSelectedFiles() {
|
||||
return Stream.concat(
|
||||
getFiles(getSelectedChanges().stream()),
|
||||
getVirtualFiles(myViewer.getSelectionPaths(), null)
|
||||
).distinct();
|
||||
}
|
||||
|
||||
public AnAction getDiffAction() {
|
||||
return myDiffAction;
|
||||
return myShowDiffAction;
|
||||
}
|
||||
|
||||
public boolean isDataIsDirty() {
|
||||
return myDataIsDirty;
|
||||
public boolean canShowDiff() {
|
||||
ListSelection<Object> selection = VcsTreeModelData.getListSelection(myViewer);
|
||||
return ContainerUtil.exists(selection.getList(), entry -> getDiffRequestProducer(entry) != null);
|
||||
}
|
||||
|
||||
public void setDataIsDirty(boolean dataIsDirty) {
|
||||
myDataIsDirty = dataIsDirty;
|
||||
public void showDiff() {
|
||||
ListSelection<Object> selection = VcsTreeModelData.getListSelection(myViewer);
|
||||
ListSelection<ChangeDiffRequestChain.Producer> producers = selection.map(this::getDiffRequestProducer);
|
||||
DiffRequestChain chain = new ChangeDiffRequestChain(producers.getList(), producers.getSelectedIndex());
|
||||
updateDiffContext(chain);
|
||||
DiffManager.getInstance().showDiff(myProject, chain, new DiffDialogHints(null, this));
|
||||
}
|
||||
|
||||
public void setSelectionMode(@JdkConstants.TreeSelectionMode int mode) {
|
||||
myViewer.setSelectionMode(mode);
|
||||
protected void updateDiffContext(@NotNull DiffRequestChain chain) {
|
||||
chain.putUserData(DiffUserDataKeys.CONTEXT_ACTIONS, createDiffActions());
|
||||
}
|
||||
|
||||
@Contract(pure = true)
|
||||
@NotNull
|
||||
protected static <T> List<Change> findChanges(@NotNull Collection<T> items) {
|
||||
return ContainerUtil.findAll(items, Change.class);
|
||||
private class MyShowDiffAction extends DumbAwareAction {
|
||||
public MyShowDiffAction() {
|
||||
ActionUtil.copyFrom(this, IdeActions.ACTION_SHOW_DIFF_COMMON);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(AnActionEvent e) {
|
||||
e.getPresentation().setEnabled(canShowDiff() || e.getInputEvent() instanceof KeyEvent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(AnActionEvent e) {
|
||||
showDiff();
|
||||
}
|
||||
}
|
||||
|
||||
static boolean isUnderUnversioned(@NotNull ChangesBrowserNode node) {
|
||||
return isUnderTag(new TreePath(node.getPath()), UNVERSIONED_FILES_TAG);
|
||||
|
||||
private static class MyChangesTreeList extends ChangesTree {
|
||||
@NotNull private final ChangesBrowserBase myViewer;
|
||||
|
||||
public MyChangesTreeList(@NotNull ChangesBrowserBase viewer,
|
||||
@NotNull Project project,
|
||||
boolean showCheckboxes,
|
||||
boolean highlightProblems) {
|
||||
super(project, showCheckboxes, highlightProblems);
|
||||
myViewer = viewer;
|
||||
setDoubleClickHandler(myViewer::onDoubleClick);
|
||||
setInclusionListener(myViewer::onIncludedChanged);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rebuildTree() {
|
||||
DefaultTreeModel newModel = myViewer.buildTreeModel(isShowFlatten());
|
||||
updateTreeModel(newModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -110,7 +110,7 @@ public class CommitChangeListDialog extends DialogWrapper implements CheckinProj
|
||||
@NotNull private final CommitOptionsPanel myCommitOptions;
|
||||
@NotNull private final CommitContext myCommitContext;
|
||||
@NotNull private final ChangeInfoCalculator myChangesInfoCalculator;
|
||||
@NotNull private final ChangesBrowserBase<?> myBrowser;
|
||||
@NotNull private final OldChangesBrowserBase<?> myBrowser;
|
||||
@NotNull private final MyChangeProcessor myDiffDetails;
|
||||
@NotNull private final CommitMessage myCommitMessageArea;
|
||||
@NotNull private final CommitLegendPanel myLegend;
|
||||
|
||||
+1
-1
@@ -54,7 +54,7 @@ import static com.intellij.openapi.util.text.StringUtil.capitalize;
|
||||
import static com.intellij.openapi.util.text.StringUtil.shortenTextWithEllipsis;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
public class MultipleChangeListBrowser extends ChangesBrowserBase<Object> {
|
||||
public class MultipleChangeListBrowser extends OldChangesBrowserBase<Object> {
|
||||
|
||||
@NotNull private final ChangeListChooser myChangeListChooser;
|
||||
@NotNull final ChangeListListener myChangeListListener = new MyChangeListListener();
|
||||
|
||||
+395
@@ -0,0 +1,395 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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.openapi.vcs.changes.ui;
|
||||
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.ide.DataManager;
|
||||
import com.intellij.ide.DeleteProvider;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.actionSystem.*;
|
||||
import com.intellij.openapi.actionSystem.ex.CheckboxAction;
|
||||
import com.intellij.openapi.diff.DiffBundle;
|
||||
import com.intellij.openapi.fileChooser.actions.VirtualFileDeleteProvider;
|
||||
import com.intellij.openapi.project.DumbAware;
|
||||
import com.intellij.openapi.project.DumbAwareAction;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.ComboBox;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.vcs.VcsBundle;
|
||||
import com.intellij.openapi.vcs.VcsConfiguration;
|
||||
import com.intellij.openapi.vcs.VcsDataKeys;
|
||||
import com.intellij.openapi.vcs.changes.*;
|
||||
import com.intellij.openapi.vcs.changes.actions.MoveChangesToAnotherListAction;
|
||||
import com.intellij.openapi.vcs.changes.actions.RollbackDialogAction;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.ui.CollectionComboBoxModel;
|
||||
import com.intellij.ui.ColoredListCellRenderer;
|
||||
import com.intellij.ui.SimpleTextAttributes;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.ui.update.MergingUpdateQueue;
|
||||
import com.intellij.util.ui.update.Update;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.tree.DefaultTreeModel;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ItemEvent;
|
||||
import java.awt.event.ItemListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static com.intellij.openapi.util.text.StringUtil.shortenTextWithEllipsis;
|
||||
import static com.intellij.openapi.vcs.changes.ui.ChangesListView.UNVERSIONED_FILES_DATA_KEY;
|
||||
|
||||
public class MultipleLocalChangeListsBrowser extends ChangesBrowserBase implements Disposable {
|
||||
private final boolean myEnableUnversioned;
|
||||
|
||||
@NotNull private final ChangeListChooser myChangeListChooser;
|
||||
@NotNull private final DeleteProvider myDeleteProvider = new VirtualFileDeleteProvider();
|
||||
|
||||
private final List<Change> myChanges = new ArrayList<>();
|
||||
private final List<VirtualFile> myUnversioned = new ArrayList<>();
|
||||
private boolean myHasHiddenUnversioned;
|
||||
|
||||
@NotNull private LocalChangeList myChangeList;
|
||||
|
||||
public MultipleLocalChangeListsBrowser(@NotNull Project project,
|
||||
boolean showCheckboxes,
|
||||
boolean highlightProblems,
|
||||
boolean enableUnversioned) {
|
||||
super(project, showCheckboxes, highlightProblems);
|
||||
myEnableUnversioned = enableUnversioned;
|
||||
|
||||
myChangeList = ChangeListManager.getInstance(project).getDefaultChangeList();
|
||||
myChangeListChooser = new ChangeListChooser();
|
||||
|
||||
installChangeListListener();
|
||||
|
||||
init();
|
||||
|
||||
updateDisplayedChangeLists();
|
||||
setSelectedChangeList(myChangeList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
}
|
||||
|
||||
private void installChangeListListener() {
|
||||
ChangeListAdapter changeListListener = new MyChangeListListener();
|
||||
ChangeListManager.getInstance(myProject).addChangeListListener(changeListListener);
|
||||
Disposer.register(this, () -> ChangeListManager.getInstance(myProject).removeChangeListListener(changeListListener));
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected JComponent createHeaderPanel() {
|
||||
return myChangeListChooser;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected List<AnAction> createToolbarActions() {
|
||||
List<AnAction> result = new ArrayList<>();
|
||||
result.addAll(super.createToolbarActions());
|
||||
|
||||
result.add(new MyRefreshAction());
|
||||
|
||||
if (myEnableUnversioned) {
|
||||
result.add(new ShowHideUnversionedFilesAction());
|
||||
|
||||
// TODO: do not access DataContext
|
||||
// We do not add "Delete" key shortcut for deleting unversioned files as this shortcut is already used to uncheck checkboxes in the tree.
|
||||
result.add(UnversionedViewDialog.getUnversionedActionGroup());
|
||||
UnversionedViewDialog.registerUnversionedActionsShortcuts(DataManager.getInstance().getDataContext(this), myViewer);
|
||||
}
|
||||
else {
|
||||
// avoid duplicated actions on toolbar
|
||||
result.add(ActionManager.getInstance().getAction(IdeActions.MOVE_TO_ANOTHER_CHANGE_LIST));
|
||||
EmptyAction.registerWithShortcutSet(IdeActions.MOVE_TO_ANOTHER_CHANGE_LIST, CommonShortcuts.getMove(), myViewer);
|
||||
}
|
||||
|
||||
RollbackDialogAction rollbackAction = new RollbackDialogAction();
|
||||
rollbackAction.registerCustomShortcutSet(this, null);
|
||||
result.add(rollbackAction);
|
||||
|
||||
EditSourceForDialogAction editSourceAction = new EditSourceForDialogAction(this);
|
||||
editSourceAction.registerCustomShortcutSet(CommonShortcuts.getEditSource(), this);
|
||||
result.add(editSourceAction);
|
||||
|
||||
result.add(ActionManager.getInstance().getAction("Vcs.CheckinProjectToolbar"));
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected List<AnAction> createDiffActions() {
|
||||
return ContainerUtil.append(
|
||||
super.createDiffActions(),
|
||||
new ToggleChangeDiffAction(),
|
||||
new MoveChangeDiffAction()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
private boolean isShowUnversioned() {
|
||||
return myEnableUnversioned && VcsConfiguration.getInstance(myProject).SHOW_UNVERSIONED_FILES_WHILE_COMMIT;
|
||||
}
|
||||
|
||||
private void setShowUnversioned(boolean value) {
|
||||
VcsConfiguration.getInstance(myProject).SHOW_UNVERSIONED_FILES_WHILE_COMMIT = value;
|
||||
updateDisplayedChanges();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public LocalChangeList getSelectedChangeList() {
|
||||
return myChangeList;
|
||||
}
|
||||
|
||||
public void setSelectedChangeList(@NotNull LocalChangeList list) {
|
||||
myChangeList = list;
|
||||
myChangeListChooser.setToolTipText(list.getName());
|
||||
updateDisplayedChanges();
|
||||
}
|
||||
|
||||
public void updateDisplayedChangeLists() {
|
||||
List<LocalChangeList> changeLists = ChangeListManager.getInstance(myProject).getChangeLists();
|
||||
myChangeListChooser.setAvailableLists(changeLists);
|
||||
}
|
||||
|
||||
public void updateDisplayedChanges() {
|
||||
myChanges.clear();
|
||||
myUnversioned.clear();
|
||||
myHasHiddenUnversioned = false;
|
||||
|
||||
myChanges.addAll(myChangeList.getChanges());
|
||||
|
||||
if (myEnableUnversioned) {
|
||||
List<VirtualFile> unversioned = ChangeListManagerImpl.getInstanceImpl(myProject).getUnversionedFiles();
|
||||
if (isShowUnversioned()) {
|
||||
myUnversioned.addAll(unversioned);
|
||||
}
|
||||
if (!isShowUnversioned() && !unversioned.isEmpty()) {
|
||||
myHasHiddenUnversioned = true;
|
||||
}
|
||||
}
|
||||
|
||||
myViewer.rebuildTree();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected DefaultTreeModel buildTreeModel(boolean showFlatten) {
|
||||
RemoteStatusChangeNodeDecorator decorator = RemoteRevisionsCache.getInstance(myProject).getChangesNodeDecorator();
|
||||
|
||||
TreeModelBuilder builder = new TreeModelBuilder(myProject, showFlatten);
|
||||
builder.setChanges(myChanges, decorator);
|
||||
builder.setUnversioned(myUnversioned);
|
||||
|
||||
if (myHasHiddenUnversioned) {
|
||||
myViewer.getEmptyText()
|
||||
.setText("Unversioned files available. ")
|
||||
.appendText("Show", SimpleTextAttributes.LINK_ATTRIBUTES, e -> setShowUnversioned(true));
|
||||
}
|
||||
else {
|
||||
myViewer.getEmptyText()
|
||||
.setText(DiffBundle.message("diff.count.differences.status.text", 0));
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Object getData(String dataId) {
|
||||
if (UNVERSIONED_FILES_DATA_KEY.is(dataId)) {
|
||||
return VcsTreeModelData.selected(myViewer).userObjectsStream(VirtualFile.class);
|
||||
}
|
||||
else if (PlatformDataKeys.DELETE_ELEMENT_PROVIDER.is(dataId)) {
|
||||
return myDeleteProvider;
|
||||
}
|
||||
else if (VcsDataKeys.CHANGE_LISTS.is(dataId)) {
|
||||
return new ChangeList[]{myChangeList};
|
||||
}
|
||||
return super.getData(dataId);
|
||||
}
|
||||
|
||||
|
||||
private class ChangeListChooser extends JPanel {
|
||||
private final static int MAX_NAME_LEN = 35;
|
||||
@NotNull private final ComboBox<LocalChangeList> myChooser = new ComboBox<>();
|
||||
|
||||
public ChangeListChooser() {
|
||||
myChooser.setEditable(false);
|
||||
myChooser.setRenderer(new ColoredListCellRenderer<LocalChangeList>() {
|
||||
@Override
|
||||
protected void customizeCellRenderer(@NotNull JList<? extends LocalChangeList> list, LocalChangeList value,
|
||||
int index, boolean selected, boolean hasFocus) {
|
||||
String name = shortenTextWithEllipsis(value.getName().trim(), MAX_NAME_LEN, 0);
|
||||
append(name, value.isDefault() ? SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES : SimpleTextAttributes.REGULAR_ATTRIBUTES);
|
||||
}
|
||||
});
|
||||
|
||||
myChooser.addItemListener(new ItemListener() {
|
||||
public void itemStateChanged(ItemEvent e) {
|
||||
if (e.getStateChange() == ItemEvent.SELECTED) {
|
||||
LocalChangeList changeList = (LocalChangeList)myChooser.getSelectedItem();
|
||||
if (changeList != null) {
|
||||
setSelectedChangeList(changeList);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
setLayout(new BorderLayout(4, 2));
|
||||
|
||||
JLabel label = new JLabel(VcsBundle.message("commit.dialog.changelist.label"));
|
||||
label.setLabelFor(myChooser);
|
||||
add(label, BorderLayout.WEST);
|
||||
|
||||
add(myChooser, BorderLayout.CENTER);
|
||||
}
|
||||
|
||||
public void setAvailableLists(@NotNull List<LocalChangeList> lists) {
|
||||
LocalChangeList currentList = ContainerUtil.find(lists, getSelectedChangeList());
|
||||
if (currentList == null) currentList = lists.get(0);
|
||||
|
||||
myChooser.setModel(new CollectionComboBoxModel<>(lists, currentList));
|
||||
myChooser.setEnabled(lists.size() > 1);
|
||||
|
||||
setSelectedChangeList(currentList);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private class ShowHideUnversionedFilesAction extends ToggleAction implements DumbAware {
|
||||
private ShowHideUnversionedFilesAction() {
|
||||
super("Show Unversioned Files", null, AllIcons.Vcs.ShowUnversionedFiles);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSelected(@NotNull AnActionEvent e) {
|
||||
return isShowUnversioned();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelected(@NotNull AnActionEvent e, boolean state) {
|
||||
setShowUnversioned(state);
|
||||
}
|
||||
}
|
||||
|
||||
private class MoveChangeDiffAction extends MoveChangesToAnotherListAction {
|
||||
@Override
|
||||
protected boolean isEnabled(@NotNull AnActionEvent e) {
|
||||
return e.getData(VcsDataKeys.CURRENT_CHANGE) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(@NotNull AnActionEvent e) {
|
||||
Change change = e.getRequiredData(VcsDataKeys.CURRENT_CHANGE);
|
||||
askAndMove(myProject, Collections.singletonList(change), Collections.emptyList());
|
||||
}
|
||||
}
|
||||
|
||||
private class ToggleChangeDiffAction extends CheckboxAction implements DumbAware {
|
||||
public ToggleChangeDiffAction() {
|
||||
super(VcsBundle.message("commit.dialog.include.action.name"));
|
||||
}
|
||||
|
||||
public boolean isSelected(AnActionEvent e) {
|
||||
Change change = e.getData(VcsDataKeys.CURRENT_CHANGE);
|
||||
if (change == null) return false;
|
||||
return myViewer.isIncluded(change);
|
||||
}
|
||||
|
||||
public void setSelected(AnActionEvent e, boolean state) {
|
||||
Change change = e.getData(VcsDataKeys.CURRENT_CHANGE);
|
||||
if (change == null) return;
|
||||
|
||||
if (state) {
|
||||
myViewer.includeChange(change);
|
||||
}
|
||||
else {
|
||||
myViewer.excludeChange(change);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class MyRefreshAction extends DumbAwareAction {
|
||||
public MyRefreshAction() {
|
||||
super("Refresh Changes", null, AllIcons.Actions.Refresh);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(AnActionEvent e) {
|
||||
updateDisplayedChangeLists();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private class MyChangeListListener extends ChangeListAdapter {
|
||||
@NotNull private final MergingUpdateQueue myUpdateQueue =
|
||||
new MergingUpdateQueue("MultipleLocalChangeListsBrowser", 300, true,
|
||||
MultipleLocalChangeListsBrowser.this, MultipleLocalChangeListsBrowser.this);
|
||||
|
||||
private void doUpdate() {
|
||||
myUpdateQueue.queue(new Update("update") {
|
||||
@Override
|
||||
public void run() {
|
||||
updateDisplayedChangeLists();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void changeListAdded(ChangeList list) {
|
||||
doUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void changeListRemoved(ChangeList list) {
|
||||
doUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void changeListRenamed(ChangeList list, String oldName) {
|
||||
doUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void changesRemoved(Collection<Change> changes, ChangeList fromList) {
|
||||
doUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void changesAdded(Collection<Change> changes, ChangeList toList) {
|
||||
doUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void changesMoved(Collection<Change> changes, ChangeList fromList, ChangeList toList) {
|
||||
doUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void changeListUpdateDone() {
|
||||
doUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,472 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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.openapi.vcs.changes.ui;
|
||||
|
||||
import com.intellij.diff.DiffDialogHints;
|
||||
import com.intellij.diff.util.DiffUserDataKeysEx;
|
||||
import com.intellij.ide.DeleteProvider;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.ListSelection;
|
||||
import com.intellij.openapi.actionSystem.*;
|
||||
import com.intellij.openapi.actionSystem.ex.ActionUtil;
|
||||
import com.intellij.openapi.actionSystem.ex.CheckboxAction;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.fileChooser.actions.VirtualFileDeleteProvider;
|
||||
import com.intellij.openapi.project.DumbAwareAction;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vcs.FilePath;
|
||||
import com.intellij.openapi.vcs.VcsBundle;
|
||||
import com.intellij.openapi.vcs.VcsDataKeys;
|
||||
import com.intellij.openapi.vcs.changes.Change;
|
||||
import com.intellij.openapi.vcs.changes.ChangeList;
|
||||
import com.intellij.openapi.vcs.changes.ContentRevision;
|
||||
import com.intellij.openapi.vcs.changes.RemoteRevisionsCache;
|
||||
import com.intellij.openapi.vcs.changes.actions.diff.ShowDiffAction;
|
||||
import com.intellij.openapi.vcs.changes.actions.diff.ShowDiffContext;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.ui.ScrollPaneFactory;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.intellij.lang.annotations.JdkConstants;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.Border;
|
||||
import javax.swing.tree.DefaultTreeModel;
|
||||
import javax.swing.tree.TreePath;
|
||||
import java.awt.*;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static com.intellij.openapi.vcs.changes.ChangesUtil.getFiles;
|
||||
import static com.intellij.openapi.vcs.changes.ChangesUtil.getNavigatableArray;
|
||||
import static com.intellij.openapi.vcs.changes.ui.ChangesBrowserNode.UNVERSIONED_FILES_TAG;
|
||||
import static com.intellij.openapi.vcs.changes.ui.ChangesListView.*;
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link ChangesBrowserBase}
|
||||
*/
|
||||
public abstract class OldChangesBrowserBase<T> extends JPanel implements TypeSafeDataProvider, Disposable {
|
||||
private static final Logger LOG = Logger.getInstance(OldChangesBrowserBase.class);
|
||||
|
||||
// for backgroundable rollback to mark
|
||||
private boolean myDataIsDirty;
|
||||
protected final Class<T> myClass;
|
||||
protected final ChangesTreeList<T> myViewer;
|
||||
protected final JScrollPane myViewerScrollPane;
|
||||
protected ChangeList mySelectedChangeList;
|
||||
protected List<T> myChangesToDisplay;
|
||||
protected final Project myProject;
|
||||
private final boolean myCapableOfExcludingChanges;
|
||||
protected final JPanel myHeaderPanel;
|
||||
private JComponent myBottomPanel;
|
||||
private DefaultActionGroup myToolBarGroup;
|
||||
private String myToggleActionTitle = VcsBundle.message("commit.dialog.include.action.name");
|
||||
|
||||
private JComponent myDiffBottomComponent;
|
||||
|
||||
public static DataKey<OldChangesBrowserBase> DATA_KEY = DataKey.create("com.intellij.openapi.vcs.changes.ui.ChangesBrowser");
|
||||
private AnAction myDiffAction;
|
||||
private final VirtualFile myToSelect;
|
||||
@NotNull private final DeleteProvider myDeleteProvider = new VirtualFileDeleteProvider();
|
||||
|
||||
public void setChangesToDisplay(final List<T> changes) {
|
||||
myChangesToDisplay = changes;
|
||||
myViewer.setChangesToDisplay(changes);
|
||||
}
|
||||
|
||||
public void setDecorator(final ChangeNodeDecorator decorator) {
|
||||
myViewer.setChangeDecorator(decorator);
|
||||
}
|
||||
|
||||
protected OldChangesBrowserBase(@NotNull final Project project,
|
||||
@NotNull List<T> changes,
|
||||
final boolean capableOfExcludingChanges,
|
||||
final boolean highlightProblems,
|
||||
@Nullable final Runnable inclusionListener,
|
||||
@NotNull ChangesBrowser.MyUseCase useCase,
|
||||
@Nullable VirtualFile toSelect,
|
||||
@NotNull Class<T> clazz) {
|
||||
super(new BorderLayout());
|
||||
setFocusable(false);
|
||||
|
||||
myClass = clazz;
|
||||
myDataIsDirty = false;
|
||||
myProject = project;
|
||||
myCapableOfExcludingChanges = capableOfExcludingChanges;
|
||||
myToSelect = toSelect;
|
||||
|
||||
ChangeNodeDecorator decorator =
|
||||
ChangesBrowser.MyUseCase.LOCAL_CHANGES.equals(useCase) ? RemoteRevisionsCache.getInstance(myProject).getChangesNodeDecorator() : null;
|
||||
|
||||
myViewer = new ChangesTreeList<T>(myProject, changes, capableOfExcludingChanges, highlightProblems, inclusionListener, decorator) {
|
||||
protected DefaultTreeModel buildTreeModel(final List<T> changes, ChangeNodeDecorator changeNodeDecorator) {
|
||||
return OldChangesBrowserBase.this.buildTreeModel(changes, changeNodeDecorator, isShowFlatten());
|
||||
}
|
||||
|
||||
protected List<T> getSelectedObjects(final ChangesBrowserNode<?> node) {
|
||||
return OldChangesBrowserBase.this.getSelectedObjects(node);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected T getLeadSelectedObject(final ChangesBrowserNode<?> node) {
|
||||
return OldChangesBrowserBase.this.getLeadSelectedObject(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setScrollPaneBorder(Border border) {
|
||||
myViewerScrollPane.setBorder(border);
|
||||
}
|
||||
};
|
||||
myViewerScrollPane = ScrollPaneFactory.createScrollPane(myViewer);
|
||||
myHeaderPanel = new JPanel(new BorderLayout());
|
||||
}
|
||||
|
||||
protected void init() {
|
||||
add(myViewerScrollPane, BorderLayout.CENTER);
|
||||
|
||||
myHeaderPanel.add(createToolbar(), BorderLayout.CENTER);
|
||||
add(myHeaderPanel, BorderLayout.NORTH);
|
||||
|
||||
myBottomPanel = new JPanel(new BorderLayout());
|
||||
add(myBottomPanel, BorderLayout.SOUTH);
|
||||
|
||||
myViewer.installPopupHandler(myToolBarGroup);
|
||||
myViewer.setDoubleClickHandler(getDoubleClickHandler());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected abstract DefaultTreeModel buildTreeModel(final List<T> changes, ChangeNodeDecorator changeNodeDecorator, boolean showFlatten);
|
||||
|
||||
@NotNull
|
||||
protected abstract List<T> getSelectedObjects(@NotNull ChangesBrowserNode<?> node);
|
||||
|
||||
@Nullable
|
||||
protected abstract T getLeadSelectedObject(@NotNull ChangesBrowserNode<?> node);
|
||||
|
||||
@NotNull
|
||||
protected Runnable getDoubleClickHandler() {
|
||||
return () -> showDiff();
|
||||
}
|
||||
|
||||
protected void setInitialSelection(final List<? extends ChangeList> changeLists,
|
||||
@NotNull List<T> changes,
|
||||
final ChangeList initialListSelection) {
|
||||
mySelectedChangeList = initialListSelection;
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
}
|
||||
|
||||
public void addToolbarAction(AnAction action) {
|
||||
myToolBarGroup.add(action);
|
||||
}
|
||||
|
||||
public void setDiffBottomComponent(JComponent diffBottomComponent) {
|
||||
myDiffBottomComponent = diffBottomComponent;
|
||||
}
|
||||
|
||||
public void setToggleActionTitle(final String toggleActionTitle) {
|
||||
myToggleActionTitle = toggleActionTitle;
|
||||
}
|
||||
|
||||
public JPanel getHeaderPanel() {
|
||||
return myHeaderPanel;
|
||||
}
|
||||
|
||||
public ChangesTreeList<T> getViewer() {
|
||||
return myViewer;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JScrollPane getViewerScrollPane() {
|
||||
return myViewerScrollPane;
|
||||
}
|
||||
|
||||
public void calcData(DataKey key, DataSink sink) {
|
||||
if (key == VcsDataKeys.CHANGES) {
|
||||
List<Change> list = getSelectedChanges();
|
||||
if (list.isEmpty()) list = getAllChanges();
|
||||
sink.put(VcsDataKeys.CHANGES, list.toArray(new Change[list.size()]));
|
||||
}
|
||||
else if (key == VcsDataKeys.CHANGES_SELECTION) {
|
||||
sink.put(VcsDataKeys.CHANGES_SELECTION, getChangesSelection());
|
||||
}
|
||||
else if (key == VcsDataKeys.CHANGE_LISTS) {
|
||||
sink.put(VcsDataKeys.CHANGE_LISTS, getSelectedChangeLists());
|
||||
}
|
||||
else if (key == VcsDataKeys.CHANGE_LEAD_SELECTION) {
|
||||
final Change highestSelection = ObjectUtils.tryCast(myViewer.getHighestLeadSelection(), Change.class);
|
||||
sink.put(VcsDataKeys.CHANGE_LEAD_SELECTION, (highestSelection == null) ? new Change[]{} : new Change[]{highestSelection});
|
||||
}
|
||||
else if (key == CommonDataKeys.VIRTUAL_FILE_ARRAY) {
|
||||
sink.put(CommonDataKeys.VIRTUAL_FILE_ARRAY, getSelectedFiles().toArray(VirtualFile[]::new));
|
||||
}
|
||||
else if (key == CommonDataKeys.NAVIGATABLE_ARRAY) {
|
||||
sink.put(CommonDataKeys.NAVIGATABLE_ARRAY, getNavigatableArray(myProject, getSelectedFiles()));
|
||||
}
|
||||
else if (VcsDataKeys.IO_FILE_ARRAY.equals(key)) {
|
||||
sink.put(VcsDataKeys.IO_FILE_ARRAY, getSelectedIoFiles());
|
||||
}
|
||||
else if (key == DATA_KEY) {
|
||||
sink.put(DATA_KEY, this);
|
||||
}
|
||||
else if (VcsDataKeys.SELECTED_CHANGES_IN_DETAILS.equals(key)) {
|
||||
final List<Change> selectedChanges = getSelectedChanges();
|
||||
sink.put(VcsDataKeys.SELECTED_CHANGES_IN_DETAILS, selectedChanges.toArray(new Change[selectedChanges.size()]));
|
||||
}
|
||||
else if (UNVERSIONED_FILES_DATA_KEY.equals(key)) {
|
||||
sink.put(UNVERSIONED_FILES_DATA_KEY, getVirtualFiles(myViewer.getSelectionPaths(), UNVERSIONED_FILES_TAG));
|
||||
}
|
||||
else if (PlatformDataKeys.DELETE_ELEMENT_PROVIDER.equals(key)) {
|
||||
sink.put(PlatformDataKeys.DELETE_ELEMENT_PROVIDER, myDeleteProvider);
|
||||
}
|
||||
}
|
||||
|
||||
public void select(List<T> changes) {
|
||||
myViewer.select(changes);
|
||||
}
|
||||
|
||||
public JComponent getBottomPanel() {
|
||||
return myBottomPanel;
|
||||
}
|
||||
|
||||
private class ToggleChangeAction extends CheckboxAction {
|
||||
public ToggleChangeAction() {
|
||||
super(myToggleActionTitle);
|
||||
}
|
||||
|
||||
public boolean isSelected(AnActionEvent e) {
|
||||
T change = ObjectUtils.tryCast(e.getData(VcsDataKeys.CURRENT_CHANGE), myClass);
|
||||
if (change == null) return false;
|
||||
|
||||
return myViewer.isIncluded(change);
|
||||
}
|
||||
|
||||
public void setSelected(AnActionEvent e, boolean state) {
|
||||
T change = ObjectUtils.tryCast(e.getData(VcsDataKeys.CURRENT_CHANGE), myClass);
|
||||
if (change == null) return;
|
||||
|
||||
if (state) {
|
||||
myViewer.includeChange(change);
|
||||
}
|
||||
else {
|
||||
myViewer.excludeChange(change);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void showDiffForChanges(Change[] changesArray, final int indexInSelection) {
|
||||
final ShowDiffContext context = new ShowDiffContext(isInFrame() ? DiffDialogHints.FRAME : DiffDialogHints.MODAL);
|
||||
|
||||
context.addActions(createDiffActions());
|
||||
if (myDiffBottomComponent != null) {
|
||||
context.putChainContext(DiffUserDataKeysEx.BOTTOM_PANEL, myDiffBottomComponent);
|
||||
}
|
||||
|
||||
updateDiffContext(context);
|
||||
|
||||
ShowDiffAction.showDiffForChange(myProject, Arrays.asList(changesArray), indexInSelection, context);
|
||||
}
|
||||
|
||||
protected void updateDiffContext(@NotNull ShowDiffContext context) {
|
||||
}
|
||||
|
||||
private boolean canShowDiff() {
|
||||
return ShowDiffAction.canShowDiff(myProject, getChangesSelection().getList());
|
||||
}
|
||||
|
||||
private void showDiff() {
|
||||
ListSelection<Change> selection = getChangesSelection();
|
||||
List<Change> changes = selection.getList();
|
||||
|
||||
Change[] changesArray = changes.toArray(new Change[changes.size()]);
|
||||
showDiffForChanges(changesArray, selection.getSelectedIndex());
|
||||
|
||||
afterDiffRefresh();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected ListSelection<Change> getChangesSelection() {
|
||||
final Change leadSelection = ObjectUtils.tryCast(myViewer.getLeadSelection(), Change.class);
|
||||
List<Change> changes = getSelectedChanges();
|
||||
|
||||
if (changes.size() < 2) {
|
||||
List<Change> allChanges = getAllChanges();
|
||||
if (allChanges.size() > 1 || changes.isEmpty()) {
|
||||
changes = allChanges;
|
||||
}
|
||||
}
|
||||
|
||||
if (leadSelection != null && !changes.contains(leadSelection)) {
|
||||
return ListSelection.createSingleton(leadSelection);
|
||||
}
|
||||
|
||||
return ListSelection.create(changes, leadSelection);
|
||||
}
|
||||
|
||||
protected void afterDiffRefresh() {
|
||||
}
|
||||
|
||||
private static boolean isInFrame() {
|
||||
return ModalityState.current().equals(ModalityState.NON_MODAL);
|
||||
}
|
||||
|
||||
protected List<AnAction> createDiffActions() {
|
||||
List<AnAction> actions = new ArrayList<>();
|
||||
if (myCapableOfExcludingChanges) {
|
||||
actions.add(new ToggleChangeAction());
|
||||
}
|
||||
return actions;
|
||||
}
|
||||
|
||||
public void rebuildList() {
|
||||
myViewer.setChangesToDisplay(getCurrentDisplayedObjects(), myToSelect);
|
||||
}
|
||||
|
||||
public void setAlwayExpandList(final boolean value) {
|
||||
myViewer.setAlwaysExpandList(value);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected JComponent createToolbar() {
|
||||
DefaultActionGroup toolbarGroups = new DefaultActionGroup();
|
||||
myToolBarGroup = new DefaultActionGroup();
|
||||
toolbarGroups.add(myToolBarGroup);
|
||||
buildToolBar(myToolBarGroup);
|
||||
|
||||
toolbarGroups.addSeparator();
|
||||
DefaultActionGroup treeActionsGroup = new DefaultActionGroup();
|
||||
toolbarGroups.add(treeActionsGroup);
|
||||
for (AnAction action : myViewer.getTreeActions()) {
|
||||
treeActionsGroup.add(action);
|
||||
}
|
||||
|
||||
ActionToolbar toolbar = ActionManager.getInstance().createActionToolbar("ChangesBrowser", toolbarGroups, true);
|
||||
toolbar.setTargetComponent(this);
|
||||
return toolbar.getComponent();
|
||||
}
|
||||
|
||||
protected void buildToolBar(final DefaultActionGroup toolBarGroup) {
|
||||
myDiffAction = new DumbAwareAction() {
|
||||
public void update(AnActionEvent e) {
|
||||
e.getPresentation().setEnabled(canShowDiff() || e.getInputEvent() instanceof KeyEvent);
|
||||
}
|
||||
|
||||
public void actionPerformed(AnActionEvent e) {
|
||||
showDiff();
|
||||
}
|
||||
};
|
||||
ActionUtil.copyFrom(myDiffAction, IdeActions.ACTION_SHOW_DIFF_COMMON);
|
||||
myDiffAction.registerCustomShortcutSet(myViewer, null);
|
||||
toolBarGroup.add(myDiffAction);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public abstract List<Change> getCurrentIncludedChanges();
|
||||
|
||||
@NotNull
|
||||
public List<Change> getCurrentDisplayedChanges() {
|
||||
return mySelectedChangeList != null ? ContainerUtil.newArrayList(mySelectedChangeList.getChanges()) : Collections.emptyList();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public abstract List<T> getCurrentDisplayedObjects();
|
||||
|
||||
@NotNull
|
||||
public List<VirtualFile> getIncludedUnversionedFiles() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
public int getUnversionedFilesCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public ChangeList getSelectedChangeList() {
|
||||
return mySelectedChangeList;
|
||||
}
|
||||
|
||||
public JComponent getPreferredFocusedComponent() {
|
||||
return myViewer.getPreferredFocusedComponent();
|
||||
}
|
||||
|
||||
private ChangeList[] getSelectedChangeLists() {
|
||||
if (mySelectedChangeList != null) {
|
||||
return new ChangeList[]{mySelectedChangeList};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private File[] getSelectedIoFiles() {
|
||||
final List<Change> changes = getSelectedChanges();
|
||||
final List<File> files = new ArrayList<>();
|
||||
for (Change change : changes) {
|
||||
final ContentRevision afterRevision = change.getAfterRevision();
|
||||
if (afterRevision != null) {
|
||||
final FilePath file = afterRevision.getFile();
|
||||
final File ioFile = file.getIOFile();
|
||||
files.add(ioFile);
|
||||
}
|
||||
}
|
||||
return files.toArray(new File[files.size()]);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public abstract List<Change> getSelectedChanges();
|
||||
|
||||
@NotNull
|
||||
public abstract List<Change> getAllChanges();
|
||||
|
||||
@NotNull
|
||||
protected Stream<VirtualFile> getSelectedFiles() {
|
||||
return Stream.concat(
|
||||
getFiles(getSelectedChanges().stream()),
|
||||
getVirtualFiles(myViewer.getSelectionPaths(), null)
|
||||
).distinct();
|
||||
}
|
||||
|
||||
public AnAction getDiffAction() {
|
||||
return myDiffAction;
|
||||
}
|
||||
|
||||
public boolean isDataIsDirty() {
|
||||
return myDataIsDirty;
|
||||
}
|
||||
|
||||
public void setDataIsDirty(boolean dataIsDirty) {
|
||||
myDataIsDirty = dataIsDirty;
|
||||
}
|
||||
|
||||
public void setSelectionMode(@JdkConstants.TreeSelectionMode int mode) {
|
||||
myViewer.setSelectionMode(mode);
|
||||
}
|
||||
|
||||
@Contract(pure = true)
|
||||
@NotNull
|
||||
protected static <T> List<Change> findChanges(@NotNull Collection<T> items) {
|
||||
return ContainerUtil.findAll(items, Change.class);
|
||||
}
|
||||
|
||||
static boolean isUnderUnversioned(@NotNull ChangesBrowserNode node) {
|
||||
return isUnderTag(new TreePath(node.getPath()), UNVERSIONED_FILES_TAG);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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.openapi.vcs.changes.ui;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vcs.changes.Change;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.tree.DefaultTreeModel;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public class SimpleChangesBrowser extends ChangesBrowserBase {
|
||||
private final List<Change> myChanges = new ArrayList<>();
|
||||
@Nullable private ChangeNodeDecorator myChangeNodeDecorator;
|
||||
|
||||
public SimpleChangesBrowser(@NotNull Project project,
|
||||
@NotNull List<Change> changes) {
|
||||
this(project, false, false);
|
||||
setChangesToDisplay(changes);
|
||||
}
|
||||
|
||||
public SimpleChangesBrowser(@NotNull Project project,
|
||||
boolean showCheckboxes,
|
||||
boolean highlightProblems) {
|
||||
super(project, showCheckboxes, highlightProblems);
|
||||
init();
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected DefaultTreeModel buildTreeModel(boolean showFlatten) {
|
||||
return TreeModelBuilder.buildFromChanges(myProject, showFlatten, myChanges, myChangeNodeDecorator);
|
||||
}
|
||||
|
||||
|
||||
public void setChangesToDisplay(@NotNull Collection<? extends Change> changes) {
|
||||
myChanges.clear();
|
||||
myChanges.addAll(changes);
|
||||
myViewer.rebuildTree();
|
||||
}
|
||||
|
||||
public void setChangeNodeDecorator(@Nullable ChangeNodeDecorator value) {
|
||||
myChangeNodeDecorator = value;
|
||||
myViewer.rebuildTree();
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
public List<Change> getAllChanges() {
|
||||
return VcsTreeModelData.all(myViewer).userObjects(Change.class);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<Change> getSelectedChanges() {
|
||||
return VcsTreeModelData.selected(myViewer).userObjects(Change.class);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<Change> getIncludedChanges() {
|
||||
return VcsTreeModelData.included(myViewer).userObjects(Change.class);
|
||||
}
|
||||
}
|
||||
@@ -3,10 +3,23 @@
|
||||
// found in the LICENSE file.
|
||||
package com.intellij.openapi.vcs.changes.ui;
|
||||
|
||||
import com.intellij.openapi.ListSelection;
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vcs.FilePath;
|
||||
import com.intellij.openapi.vcs.VcsDataKeys;
|
||||
import com.intellij.openapi.vcs.changes.Change;
|
||||
import com.intellij.openapi.vcs.changes.ChangesUtil;
|
||||
import com.intellij.openapi.vcs.changes.ContentRevision;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.tree.TreePath;
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
@@ -143,5 +156,95 @@ public abstract class VcsTreeModelData {
|
||||
return root.getNodesUnderStream().filter(node -> included.contains(node.getUserObject()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
public static ListSelection<Object> getListSelection(@NotNull JTree tree) {
|
||||
List<Object> entries = selected(tree).userObjects();
|
||||
Object selection = ContainerUtil.getFirstItem(entries);
|
||||
|
||||
if (entries.size() < 2) {
|
||||
List<Object> allEntries = all(tree).userObjects();
|
||||
if (allEntries.size() > 1 || entries.isEmpty()) {
|
||||
entries = allEntries;
|
||||
}
|
||||
}
|
||||
|
||||
return ListSelection.create(entries, selection);
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
public static Object getData(@Nullable Project project, @NotNull JTree tree, String dataId) {
|
||||
if (VcsDataKeys.CHANGES.is(dataId)) {
|
||||
Change[] changes = mapToChange(selected(tree)).toArray(Change[]::new);
|
||||
if (changes.length != 0) return changes;
|
||||
return mapToChange(all(tree)).toArray(Change[]::new);
|
||||
}
|
||||
else if (VcsDataKeys.SELECTED_CHANGES.is(dataId) ||
|
||||
VcsDataKeys.SELECTED_CHANGES_IN_DETAILS.is(dataId)) {
|
||||
return mapToChange(selected(tree)).toArray(Change[]::new);
|
||||
}
|
||||
else if (VcsDataKeys.CHANGES_SELECTION.is(dataId)) {
|
||||
return getListSelection(tree).map(entry -> ObjectUtils.tryCast(entry, Change.class));
|
||||
}
|
||||
else if (VcsDataKeys.CHANGE_LEAD_SELECTION.is(dataId)) {
|
||||
return mapToChange(exactlySelected(tree)).limit(1).toArray(Change[]::new);
|
||||
}
|
||||
else if (CommonDataKeys.VIRTUAL_FILE_ARRAY.is(dataId)) {
|
||||
return mapToVirtualFile(selected(tree)).toArray(VirtualFile[]::new);
|
||||
}
|
||||
else if (CommonDataKeys.NAVIGATABLE_ARRAY.is(dataId)) {
|
||||
if (project == null) return null;
|
||||
return ChangesUtil.getNavigatableArray(project, mapToVirtualFile(selected(tree)));
|
||||
}
|
||||
else if (VcsDataKeys.IO_FILE_ARRAY.is(dataId)) {
|
||||
return mapToIoFile(selected(tree)).toArray(File[]::new);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
private static Stream<Change> mapToChange(@NotNull VcsTreeModelData data) {
|
||||
return data.userObjectsStream().filter(it -> it instanceof Change)
|
||||
.map(entry -> {
|
||||
if (entry instanceof Change) {
|
||||
return (Change)entry;
|
||||
}
|
||||
return null;
|
||||
})
|
||||
.filter(Objects::nonNull);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Stream<VirtualFile> mapToVirtualFile(@NotNull VcsTreeModelData data) {
|
||||
return data.userObjectsStream()
|
||||
.flatMap(entry -> {
|
||||
if (entry instanceof Change) {
|
||||
return ChangesUtil.getPathsCaseSensitive((Change)entry)
|
||||
.map(FilePath::getVirtualFile);
|
||||
}
|
||||
else if (entry instanceof VirtualFile) {
|
||||
return Stream.of((VirtualFile)entry);
|
||||
}
|
||||
return Stream.empty();
|
||||
})
|
||||
.filter(Objects::nonNull);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Stream<File> mapToIoFile(@NotNull VcsTreeModelData data) {
|
||||
return data.userObjectsStream()
|
||||
.map(entry -> {
|
||||
if (entry instanceof Change) {
|
||||
ContentRevision afterRevision = ((Change)entry).getAfterRevision();
|
||||
if (afterRevision == null) return null;
|
||||
return afterRevision.getFile().getIOFile();
|
||||
}
|
||||
return null;
|
||||
})
|
||||
.filter(Objects::nonNull);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user