VCS: apply patch allow dirs striping for selection

This commit is contained in:
irengrig
2009-11-16 22:29:04 +03:00
parent 609c74ff5d
commit 9166eedb0d
8 changed files with 436 additions and 19 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 491 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 491 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 485 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 500 B

@@ -372,7 +372,12 @@ public class ApplyPatchDifferentiatedDialog extends DialogWrapper {
final MyShowDiff diffAction = new MyShowDiff();
diffAction.registerCustomShortcutSet(CommonShortcuts.getDiff(), myCenterPanel);
group.add(diffAction);
group.add(new StripUp());
group.add(new StripDown());
group.add(new ResetStrip());
group.add(new ZeroStrip());
final ActionToolbar toolbar = ActionManager.getInstance().createActionToolbar("APPLY_PATCH", group, true);
myCenterPanel.add(toolbar.getComponent(), gb);
@@ -488,11 +493,22 @@ public class ApplyPatchDifferentiatedDialog extends DialogWrapper {
}
private void updateTree(boolean doInitCheck) {
final List<FilePatchInProgress> patchesToSelect = changes2patches(myChangesTreeList.getSelectedChanges());
final List<FilePatchInProgress.PatchChange> changes = getAllChanges();
final Collection<FilePatchInProgress.PatchChange> included = getIncluded(doInitCheck, changes);
myChangesTreeList.setChangesToDisplay(changes);
myChangesTreeList.setIncludedChanges(included);
myChangesTreeList.repaint();
if ((! doInitCheck) && patchesToSelect != null) {
final List<FilePatchInProgress.PatchChange> toSelect = new ArrayList<FilePatchInProgress.PatchChange>(patchesToSelect.size());
for (FilePatchInProgress.PatchChange change : changes) {
if (patchesToSelect.contains(change.getPatchInProgress())) {
toSelect.add(change);
}
}
myChangesTreeList.select(toSelect);
}
myContainBasedChanges = false;
for (FilePatchInProgress patch : myPatches) {
@@ -540,16 +556,15 @@ public class ApplyPatchDifferentiatedDialog extends DialogWrapper {
} else {
// todo maybe written pretty
final Collection<FilePatchInProgress.PatchChange> includedNow = myChangesTreeList.getIncludedChanges();
final Set<Pair<String, String>> toBeIncluded = new HashSet<Pair<String, String>>();
final Set<FilePatchInProgress> toBeIncluded = new HashSet<FilePatchInProgress>();
for (FilePatchInProgress.PatchChange change : includedNow) {
final FilePatchInProgress patch = change.getPatchInProgress();
toBeIncluded.add(new Pair<String, String>(patch.getPatch().getBeforeName(), patch.getPatch().getAfterName()));
toBeIncluded.add(patch);
}
for (FilePatchInProgress.PatchChange change : changes) {
final FilePatchInProgress patch = change.getPatchInProgress();
final Pair<String, String> pair = new Pair<String, String>(patch.getPatch().getBeforeName(), patch.getPatch().getAfterName());
acceptChange(totalTrinity, change);
if (toBeIncluded.contains(pair) && patch.baseExistsOrAdded()) {
if (toBeIncluded.contains(patch) && patch.baseExistsOrAdded()) {
acceptChange(includedTrinity, change);
included.add(change);
}
@@ -581,6 +596,14 @@ public class ApplyPatchDifferentiatedDialog extends DialogWrapper {
}
}
private List<FilePatchInProgress> changes2patches(final List<FilePatchInProgress.PatchChange> selectedChanges) {
return ObjectsConvertor.convert(selectedChanges, new Convertor<FilePatchInProgress.PatchChange, FilePatchInProgress>() {
public FilePatchInProgress convert(FilePatchInProgress.PatchChange o) {
return o.getPatchInProgress();
}
});
}
private class MapPopup extends BaseListPopupStep<VirtualFile> {
private final Runnable myNewBaseSelector;
@@ -759,6 +782,96 @@ public class ApplyPatchDifferentiatedDialog extends DialogWrapper {
myCallback.consume(this);
}
private class ZeroStrip extends AnAction {
private ZeroStrip() {
super("Remove Directories", "Remove Directories", IconLoader.getIcon("/vcs/stripNull.png"));
}
@Override
public void actionPerformed(AnActionEvent e) {
final List<FilePatchInProgress.PatchChange> selectedChanges = myChangesTreeList.getSelectedChanges();
for (FilePatchInProgress.PatchChange change : selectedChanges) {
change.getPatchInProgress().setZero();
}
updateTree(false);
}
}
private class StripDown extends AnAction {
private StripDown() {
super("Restore Directory", "Restore Directory", IconLoader.getIcon("/vcs/stripDown.png"));
}
@Override
public void update(AnActionEvent e) {
e.getPresentation().setEnabled(isEnabled());
}
@Override
public void actionPerformed(AnActionEvent e) {
if (! isEnabled()) return;
final List<FilePatchInProgress.PatchChange> selectedChanges = myChangesTreeList.getSelectedChanges();
for (FilePatchInProgress.PatchChange change : selectedChanges) {
change.getPatchInProgress().down();
}
updateTree(false);
}
private boolean isEnabled() {
final List<FilePatchInProgress.PatchChange> selectedChanges = myChangesTreeList.getSelectedChanges();
if (selectedChanges.isEmpty()) return false;
for (FilePatchInProgress.PatchChange change : selectedChanges) {
if (! change.getPatchInProgress().canDown()) return false;
}
return true;
}
}
private class StripUp extends AnAction {
private StripUp() {
super("Strip Directory", "Strip Directory", IconLoader.getIcon("/vcs/stripUp.png"));
}
@Override
public void update(AnActionEvent e) {
e.getPresentation().setEnabled(isEnabled());
}
@Override
public void actionPerformed(AnActionEvent e) {
if (! isEnabled()) return;
final List<FilePatchInProgress.PatchChange> selectedChanges = myChangesTreeList.getSelectedChanges();
for (FilePatchInProgress.PatchChange change : selectedChanges) {
change.getPatchInProgress().up();
}
updateTree(false);
}
private boolean isEnabled() {
final List<FilePatchInProgress.PatchChange> selectedChanges = myChangesTreeList.getSelectedChanges();
if (selectedChanges.isEmpty()) return false;
for (FilePatchInProgress.PatchChange change : selectedChanges) {
if (! change.getPatchInProgress().canUp()) return false;
}
return true;
}
}
private class ResetStrip extends AnAction {
private ResetStrip() {
super("Reset Directories", "Reset Directories", IconLoader.getIcon("/vcs/resetStrip.png"));
}
@Override
public void actionPerformed(AnActionEvent e) {
final List<FilePatchInProgress.PatchChange> selectedChanges = myChangesTreeList.getSelectedChanges();
for (FilePatchInProgress.PatchChange change : selectedChanges) {
change.getPatchInProgress().reset();
}
updateTree(false);
}
}
private class MyShowDiff extends AnAction {
private MyShowDiff() {
super("Show Diff", "Show Diff", IconLoader.getIcon("/actions/diff.png"));
@@ -19,9 +19,13 @@ import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diff.DiffRequestFactory;
import com.intellij.openapi.diff.MergeRequest;
import com.intellij.openapi.diff.impl.patch.ApplyPatchException;
import com.intellij.openapi.diff.impl.patch.ApplyPatchStatus;
import com.intellij.openapi.diff.impl.patch.FilePatch;
import com.intellij.openapi.diff.impl.patch.TextFilePatch;
import com.intellij.openapi.diff.impl.patch.formove.PathMerger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vcs.*;
import com.intellij.openapi.vcs.changes.Change;
@@ -37,13 +41,12 @@ import com.intellij.vcsUtil.VcsUtil;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.io.IOException;
import java.util.*;
public class FilePatchInProgress {
public class FilePatchInProgress implements Strippable {
private final TextFilePatch myPatch;
private final PatchStrippable myStrippable;
private final FilePatchStatus myStatus;
private VirtualFile myBase;
@@ -59,6 +62,7 @@ public class FilePatchInProgress {
public FilePatchInProgress(final TextFilePatch patch, final Collection<VirtualFile> autoBases, final VirtualFile baseDir) {
myPatch = patch;
myStrippable = new PatchStrippable(patch);
if (autoBases != null) {
myAutoBases = new ArrayList<VirtualFile>();
final String path = myPatch.getBeforeName() == null ? myPatch.getAfterName() : myPatch.getBeforeName();
@@ -270,4 +274,229 @@ public class FilePatchInProgress {
public Pair<String, String> getKey() {
return new Pair<String, String>(myPatch.getBeforeName(), myPatch.getAfterName());
}
private void refresh() {
myStrippable.applyBackToPatch(myPatch);
setNewBase(myBase);
}
public void reset() {
myStrippable.reset();
refresh();
}
public boolean canDown() {
return myStrippable.canDown();
}
public boolean canUp() {
return myStrippable.canUp();
}
public void up() {
myStrippable.up();
refresh();
}
public void down() {
myStrippable.down();
refresh();
}
public void setZero() {
myStrippable.setZero();
refresh();
}
public String getCurrentPath() {
return myStrippable.getCurrentPath();
}
private static class StripCapablePath implements Strippable {
private final int myStripMax;
private int myCurrentStrip;
private final StringBuilder mySourcePath;
private final int[] myParts;
private StripCapablePath(final String path) {
final String corrected = path.trim().replace('\\', '/');
mySourcePath = new StringBuilder(corrected);
final String[] steps = corrected.split("/");
myStripMax = steps.length - 1;
myParts = new int[steps.length];
int pos = 0;
for (int i = 0; i < steps.length; i++) {
final String step = steps[i];
myParts[i] = pos;
pos += step.length() + 1; // plus 1 for separator
}
myCurrentStrip = 0;
}
public void reset() {
myCurrentStrip = 0;
}
// down - restore dirs...
public boolean canDown() {
return myCurrentStrip > 0;
}
public boolean canUp() {
return myCurrentStrip < myStripMax;
}
public void up() {
if (canUp()) {
++ myCurrentStrip;
}
}
public void down() {
if (canDown()) {
-- myCurrentStrip;
}
}
public void setZero() {
myCurrentStrip = myStripMax;
}
public String getCurrentPath() {
return mySourcePath.substring(myParts[myCurrentStrip]);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
StripCapablePath that = (StripCapablePath)o;
if (!mySourcePath.equals(that.mySourcePath)) return false;
return true;
}
@Override
public int hashCode() {
return mySourcePath.hashCode();
}
}
private static class PatchStrippable implements Strippable {
private final Strippable[] myParts;
private final int myBeforeIdx;
private final int myAfterIdx;
private PatchStrippable(final FilePatch patch) {
final boolean onePath = patch.isDeletedFile() || patch.isNewFile() || Comparing.equal(patch.getAfterName(), patch.getBeforeName());
final int size = onePath ? 1 : 2;
myParts = new Strippable[size];
int cnt = 0;
if (patch.getAfterName() != null) {
myAfterIdx = 0;
myParts[cnt] = new StripCapablePath(patch.getAfterName());
++ cnt;
} else {
myAfterIdx = -1;
}
if (cnt < size) {
myParts[cnt] = new StripCapablePath(patch.getBeforeName());
myBeforeIdx = cnt;
} else {
myBeforeIdx = 0;
}
}
public void reset() {
for (Strippable part : myParts) {
part.reset();
}
}
public boolean canDown() {
boolean result = true;
for (Strippable part : myParts) {
result &= part.canDown();
}
return result;
}
public boolean canUp() {
boolean result = true;
for (Strippable part : myParts) {
result &= part.canUp();
}
return result;
}
public void up() {
for (Strippable part : myParts) {
part.up();
}
}
public void down() {
for (Strippable part : myParts) {
part.down();
}
}
public void setZero() {
for (Strippable part : myParts) {
part.setZero();
}
}
public String getCurrentPath() {
return myParts[0].getCurrentPath();
}
public void applyBackToPatch(final FilePatch patch) {
final String beforeName = patch.getBeforeName();
if (beforeName != null) {
patch.setBeforeName(myParts[myBeforeIdx].getCurrentPath());
}
final String afterName = patch.getAfterName();
if (afterName != null) {
patch.setAfterName(myParts[myAfterIdx].getCurrentPath());
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PatchStrippable that = (PatchStrippable)o;
if (!Arrays.equals(myParts, that.myParts)) return false;
return true;
}
@Override
public int hashCode() {
return Arrays.hashCode(myParts);
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
FilePatchInProgress that = (FilePatchInProgress)o;
if (!myStrippable.equals(that.myStrippable)) return false;
return true;
}
@Override
public int hashCode() {
return myStrippable.hashCode();
}
}
@@ -0,0 +1,32 @@
/*
* Copyright 2000-2009 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.patch;
public interface Strippable {
void reset();// down - restore dirs...
boolean canDown();
boolean canUp();
void up();
void down();
void setZero();
String getCurrentPath();
}
@@ -17,6 +17,7 @@ package com.intellij.openapi.vcs.changes.ui;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.keymap.KeymapManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.EmptyRunnable;
@@ -41,9 +42,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.TreePath;
import javax.swing.tree.*;
import java.awt.*;
import java.awt.event.*;
import java.io.File;
@@ -205,8 +204,10 @@ public abstract class ChangesTreeList<T> extends JPanel {
}
public void setShowFlatten(final boolean showFlatten) {
final List<T> wasSelected = getSelectedChanges();
myShowFlatten = showFlatten;
myCards.show(this, myShowFlatten ? LIST_CARD : TREE_CARD);
select(wasSelected);
if (myList.hasFocus() || myTree.hasFocus()) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
@@ -243,7 +244,7 @@ public abstract class ChangesTreeList<T> extends JPanel {
final DefaultTreeModel model = buildTreeModel(changes, myChangeDecorator);
myTree.setModel(model);
SwingUtilities.invokeLater(new Runnable() {
final Runnable runnable = new Runnable() {
public void run() {
if (myProject.isDisposed()) return;
TreeUtil.expandAll(myTree);
@@ -256,7 +257,7 @@ public abstract class ChangesTreeList<T> extends JPanel {
listSelection = count;
break;
}
count ++;
count++;
}
ChangesBrowserNode root = (ChangesBrowserNode)model.getRoot();
@@ -290,7 +291,12 @@ public abstract class ChangesTreeList<T> extends JPanel {
}
}
}
});
};
if (ApplicationManager.getApplication().isDispatchThread()) {
runnable.run();
} else {
SwingUtilities.invokeLater(runnable);
}
}
protected abstract DefaultTreeModel buildTreeModel(final List<T> changes, final ChangeNodeDecorator changeNodeDecorator);
@@ -658,12 +664,49 @@ public abstract class ChangesTreeList<T> extends JPanel {
}
}
else {
final int count = myTree.getRowCount();
if (count > 0) {
myTree.setSelectionInterval(0, count-1);
final int countTree = myTree.getRowCount();
if (countTree > 0) {
myTree.setSelectionInterval(0, countTree-1);
}
}
}
}
public void select(final List<T> changes) {
final DefaultTreeModel treeModel = (DefaultTreeModel) myTree.getModel();
final TreeNode root = (TreeNode) treeModel.getRoot();
final List<TreePath> treeSelection = new ArrayList<TreePath>(changes.size());
TreeUtil.traverse(root, new TreeUtil.Traverse() {
public boolean accept(Object node) {
final T change = (T) ((DefaultMutableTreeNode) node).getUserObject();
if (changes.contains(change)) {
treeSelection.add(new TreePath(((DefaultMutableTreeNode) node).getPath()));
}
return true;
}
});
myTree.setSelectionPaths(treeSelection.toArray(new TreePath[treeSelection.size()]));
// list
final ListModel model = myList.getModel();
final int size = model.getSize();
final List<Integer> listSelection = new ArrayList<Integer>(changes.size());
for (int i = 0; i < size; i++) {
final T el = (T) model.getElementAt(i);
if (changes.contains(el)) {
listSelection.add(i);
}
}
myList.setSelectedIndices(int2int(listSelection));
}
private static int[] int2int(List<Integer> treeSelection) {
final int[] toPass = new int[treeSelection.size()];
int i = 0;
for (Integer integer : treeSelection) {
toPass[i] = integer;
++ i;
}
return toPass;
}
}