support operations in DirDiff

This commit is contained in:
Konstantin Bulenkov
2011-08-26 15:08:32 +02:00
parent eb1c974ed4
commit 58b82c868c
10 changed files with 308 additions and 37 deletions
@@ -218,4 +218,38 @@ public abstract class DiffElement<T> implements Disposable {
public DataProvider getDataProvider(Project project) {
return null;
}
/**
* Defines is it possible to perform such operations as copy or delete through Diff Panel
*
* @return <code>true</code> if copy, delete, etc operations are allowed,
* <code>false</code> otherwise
*/
public boolean isOperationsEnabled() {
return false;
}
/**
* Copies element to the container.
*
* @param container file directory or other container
* @param relativePath
* @return <code>true</code> if coping was completed successfully,
* <code>false</code> otherwise
*/
public boolean copyTo(DiffElement<T> container, String relativePath) {
return false;
}
/**
* Deletes element
* @return <code>true</code> if deletion was completed successfully,
* <code>false</code> otherwise
*/
public boolean delete() {
return false;
}
public void refresh() {
}
}
@@ -26,6 +26,7 @@ import com.intellij.openapi.fileEditor.FileEditorProvider;
import com.intellij.openapi.fileEditor.ex.FileEditorProviderManager;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.PlatformIcons;
import org.jetbrains.annotations.NonNls;
@@ -33,6 +34,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.concurrent.Callable;
@@ -175,4 +177,61 @@ public class VirtualFileDiffElement extends DiffElement<VirtualFile> {
}
};
}
@Override
public boolean isOperationsEnabled() {
return true;
}
@Override
public boolean copyTo(DiffElement<VirtualFile> container, String relativePath) {
try {
final File src = new File(myFile.getPath());
final File trg = new File(container.getValue().getPath() + relativePath + src.getName());
FileUtil.copy(src, trg);
//final VirtualFile targetRoot = container.getValue();
//if (targetRoot != null && targetRoot.isDirectory()) {
// VirtualFile target = getSeparator().equals(relativePath) ? targetRoot : targetRoot.findFileByRelativePath(relativePath);
// final String path;
// if (target == null) {
// path = (targetRoot.getPath() + relativePath).replace('/', File.separatorChar);
// new File(path).mkdirs();
// target = targetRoot.findFileByRelativePath(removeSeparators(relativePath));
// }
//
// if (target != null && target.isDirectory()) {
// myFile.copy(this, target, myFile.getName());
// }
// else {
// assert false : "Can't find " + container.getPath() + relativePath;
// }
//
//}
}
catch (IOException e) {//
}
return false;
}
private String removeSeparators(String path) {
final int start = path.startsWith(getSeparator()) ? getSeparator().length() : 0;
final int end = path.endsWith(getSeparator()) ? path.length() - getSeparator().length() : path.length();
return path.substring(start, end);
}
@Override
public boolean delete() {
try {
myFile.delete(this);
}
catch (IOException e) {
return false;
}
return true;
}
@Override
public void refresh() {
myFile.refresh(false, true);
}
}
@@ -64,6 +64,7 @@ public class DTree {
isContainer = container;
}
@NotNull
public Collection<DTree> getChildren() {
init();
if (myChildrenList == null) {
@@ -28,6 +28,7 @@ import static com.intellij.openapi.diff.impl.dir.DirDiffOperation.*;
* @author Konstantin Bulenkov
*/
public class DirDiffElement {
private final DTree myParent;
private final DType myType;
private final DiffElement mySource;
private final long mySourceLength;
@@ -37,7 +38,8 @@ public class DirDiffElement {
private DirDiffOperation myOperation;
private DirDiffOperation myDefaultOperation;
private DirDiffElement(@Nullable DiffElement source, @Nullable DiffElement target, DType type, String name) {
private DirDiffElement(DTree parent, @Nullable DiffElement source, @Nullable DiffElement target, DType type, String name) {
myParent = parent;
myType = type;
mySource = source;
mySourceLength = source == null || source.isContainer() ? -1 : source.getSize();
@@ -75,28 +77,28 @@ public class DirDiffElement {
return timeStamp < 0 ? "" : DateFormatUtil.formatDateTime(timeStamp);
}
public static DirDiffElement createChange(@NotNull DiffElement source, @NotNull DiffElement target) {
return new DirDiffElement(source, target, DType.CHANGED, source.getName());
public static DirDiffElement createChange(DTree parent, @NotNull DiffElement source, @NotNull DiffElement target) {
return new DirDiffElement(parent, source, target, DType.CHANGED, source.getName());
}
public static DirDiffElement createError(@Nullable DiffElement source, @Nullable DiffElement target) {
return new DirDiffElement(source, target, DType.ERROR, source == null ? target.getName() : source.getName());
public static DirDiffElement createError(DTree parent, @Nullable DiffElement source, @Nullable DiffElement target) {
return new DirDiffElement(parent, source, target, DType.ERROR, source == null ? target.getName() : source.getName());
}
public static DirDiffElement createSourceOnly(@NotNull DiffElement source) {
return new DirDiffElement(source, null, DType.SOURCE, null);
public static DirDiffElement createSourceOnly(DTree parent, @NotNull DiffElement source) {
return new DirDiffElement(parent, source, null, DType.SOURCE, null);
}
public static DirDiffElement createTargetOnly(@NotNull DiffElement target) {
return new DirDiffElement(null, target, DType.TARGET, null);
public static DirDiffElement createTargetOnly(DTree parent, @NotNull DiffElement target) {
return new DirDiffElement(parent, null, target, DType.TARGET, null);
}
public static DirDiffElement createDirElement(DiffElement src, DiffElement trg, String name) {
return new DirDiffElement(src, trg, DType.SEPARATOR, name);
public static DirDiffElement createDirElement(DTree parent, DiffElement src, DiffElement trg, String name) {
return new DirDiffElement(parent, src, trg, DType.SEPARATOR, name);
}
public static DirDiffElement createEqual(@NotNull DiffElement source, @NotNull DiffElement target) {
return new DirDiffElement(source, target, DType.EQUAL, source.getName());
public static DirDiffElement createEqual(DTree parent, @NotNull DiffElement source, @NotNull DiffElement target) {
return new DirDiffElement(parent, source, target, DType.EQUAL, source.getName());
}
public DType getType() {
@@ -167,4 +169,8 @@ public class DirDiffElement {
public Icon getIcon() {
return mySource != null ? mySource.getIcon() : myTarget.getIcon();
}
public DTree getParentNode() {
return myParent;
}
}
@@ -109,25 +109,27 @@ public class DirDiffPanel implements Disposable {
myDiffWindow.setTitle(myModel.getTitle());
}
});
new AnAction("Change diff operation") {
@Override
public void actionPerformed(AnActionEvent e) {
changeOperationForSelectedRow();
}
}.registerCustomShortcutSet(CustomShortcutSet.fromString("SPACE"), myTable);
myTable.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (myTable.getRowCount() > 0 && e.getClickCount() > 1) {
final int row = myTable.rowAtPoint(e.getPoint());
final int col = myTable.columnAtPoint(e.getPoint());
if (model.isOperationsEnabled()) {
new AnAction("Change diff operation") {
@Override
public void actionPerformed(AnActionEvent e) {
changeOperationForSelectedRow();
}
}.registerCustomShortcutSet(CustomShortcutSet.fromString("SPACE"), myTable);
myTable.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (myTable.getRowCount() > 0 && e.getClickCount() > 1) {
final int row = myTable.rowAtPoint(e.getPoint());
final int col = myTable.columnAtPoint(e.getPoint());
if (row != -1 && col == ((myTable.getColumnCount() - 1) / 2)) {
changeOperationForSelectedRow();
if (row != -1 && col == ((myTable.getColumnCount() - 1) / 2)) {
changeOperationForSelectedRow();
}
}
}
}
});
});
}
myTable.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
@@ -19,6 +19,7 @@ import com.intellij.ide.diff.DiffElement;
import com.intellij.ide.diff.DirDiffModel;
import com.intellij.ide.diff.DirDiffSettings;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.AccessToken;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
@@ -133,6 +134,14 @@ public class DirDiffTableModel extends AbstractTableModel implements DirDiffMode
getSettings().setFilter(myPanel.getFilter());
}
public boolean isOperationsEnabled() {
return mySrc.isOperationsEnabled() && myTrg.isOperationsEnabled();
}
public List<DirDiffElement> getElements() {
return myElements;
}
private static String prepareText(String text) {
final int LEN = EMPTY_STRING.length();
String right;
@@ -165,15 +174,19 @@ public class DirDiffTableModel extends AbstractTableModel implements DirDiffMode
}
public void reloadModel() {
//System.out.println("Start reloading");
myUpdating.set(true);
final JBLoadingPanel loadingPanel = getLoadingPanel();
loadingPanel.startLoading();
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
public void run() {
//System.out.println("start updating on pooled thread");
try {
updater = new Updater(loadingPanel, 100);
updater.start();
myTree = new DTree(null, "", true);
mySrc.refresh();
myTrg.refresh();
scan(mySrc, myTree, true);
scan(myTrg, myTree, false);
@@ -184,6 +197,7 @@ public class DirDiffTableModel extends AbstractTableModel implements DirDiffMode
}
catch (Exception e) {//
}
//System.out.println("end updating on pooled thread");
}
});
}
@@ -193,6 +207,7 @@ public class DirDiffTableModel extends AbstractTableModel implements DirDiffMode
}
public void applySettings() {
//System.out.println(StringUtil.getThrowableText(new Throwable()));
if (! myUpdating.get()) myUpdating.set(true);
final JBLoadingPanel loadingPanel = getLoadingPanel();
if (!loadingPanel.isLoading()) {
@@ -205,6 +220,7 @@ public class DirDiffTableModel extends AbstractTableModel implements DirDiffMode
final Application app = ApplicationManager.getApplication();
app.executeOnPooledThread(new Runnable() {
public void run() {
//System.out.println("start updating tree");
myTree.updateVisibility(mySettings);
final ArrayList<DirDiffElement> elements = new ArrayList<DirDiffElement>();
fillElements(myTree, elements);
@@ -227,6 +243,7 @@ public class DirDiffTableModel extends AbstractTableModel implements DirDiffMode
} else {
app.invokeLater(uiThread);
}
//System.out.println("stop updating tree");
}
});
}
@@ -240,24 +257,24 @@ public class DirDiffTableModel extends AbstractTableModel implements DirDiffMode
if (!child.isContainer()) {
if (child.isVisible()) {
if (!separatorAdded) {
elements.add(DirDiffElement.createDirElement(tree.getSource(), tree.getTarget(), tree.getPath()));
elements.add(DirDiffElement.createDirElement(tree, tree.getSource(), tree.getTarget(), tree.getPath()));
separatorAdded = true;
}
switch (child.getType()) {
case SOURCE:
elements.add(DirDiffElement.createSourceOnly(child.getSource()));
elements.add(DirDiffElement.createSourceOnly(tree, child.getSource()));
break;
case TARGET:
elements.add(DirDiffElement.createTargetOnly(child.getTarget()));
elements.add(DirDiffElement.createTargetOnly(tree, child.getTarget()));
break;
case CHANGED:
elements.add(DirDiffElement.createChange(child.getSource(), child.getTarget()));
elements.add(DirDiffElement.createChange(tree, child.getSource(), child.getTarget()));
break;
case EQUAL:
elements.add(DirDiffElement.createEqual(child.getSource(), child.getTarget()));
elements.add(DirDiffElement.createEqual(tree, child.getSource(), child.getTarget()));
break;
case ERROR:
elements.add(DirDiffElement.createError(child.getSource(), child.getTarget()));
elements.add(DirDiffElement.createError(tree, child.getSource(), child.getTarget()));
}
}
} else {
@@ -354,6 +371,17 @@ public class DirDiffTableModel extends AbstractTableModel implements DirDiffMode
}
return "";
}
public List<DirDiffElement> getSelectedElements() {
final int[] rows = myTable.getSelectedRows();
final ArrayList<DirDiffElement> elements = new ArrayList<DirDiffElement>();
for (int row : rows) {
final DirDiffElement element = getElementAt(row);
if (element == null || element.isSeparator()) continue;
elements.add(element);
}
return elements;
}
@Override
public String getColumnName(int column) {
@@ -427,6 +455,54 @@ public class DirDiffTableModel extends AbstractTableModel implements DirDiffMode
return mySettings;
}
public void performCopyTo(DirDiffElement element) {
final DiffElement source = element.getSource();
if (source != null) {
final String path = element.getParentNode().getPath();
final AccessToken token = ApplicationManager.getApplication().acquireWriteActionLock(getClass());
try {
source.copyTo(myTrg, path);
} finally {
token.finish();
}
}
}
public void performCopyFrom(DirDiffElement element) {
final DiffElement target = element.getTarget();
if (target != null) {
final String path = element.getParentNode().getPath();
final AccessToken token = ApplicationManager.getApplication().acquireWriteActionLock(getClass());
try {
target.copyTo(mySrc, path);
} finally {
token.finish();
}
}
}
public void performDelete(DirDiffElement element) {
final DiffElement source = element.getSource();
final DiffElement target = element.getTarget();
final int index = myElements.indexOf(element);
if (index != -1) {
myElements.remove(index);
fireTableRowsDeleted(index, index);
}
final AccessToken token = ApplicationManager.getApplication().acquireWriteActionLock(getClass());
try {
if (source != null) {
source.delete();
}
if (target != null) {
target.delete();
}
} finally {
token.finish();
}
}
class Updater extends Thread {
private final JBLoadingPanel myLoadingPanel;
private final int mySleep;
@@ -43,7 +43,7 @@ public abstract class DirDiffAction extends ToggleAction implements DirDiffIcons
@Override
public final void setSelected(AnActionEvent e, boolean state) {
updateState(state);
if (this.getClass() == RefreshDirDiffAction.class) {
if (isFullReload()) {
getModel().reloadModel();
} else {
if (state) {
@@ -54,6 +54,10 @@ public abstract class DirDiffAction extends ToggleAction implements DirDiffIcons
}
}
protected boolean isFullReload() {
return false;
}
@Override
public void update(AnActionEvent e) {
super.update(e);
@@ -43,7 +43,9 @@ public class DirDiffToolbarActions extends ActionGroup {
new EnableRight(model),
Separator.getInstance(),
new ChangeCompareModeGroup(model),
Separator.getInstance()));
Separator.getInstance(),
new SynchronizeDiff(model, false),
new SynchronizeDiff(model, true)));
for (AnAction action : model.getSettings().getExtraActions()) {
actions.add(action);
@@ -43,4 +43,9 @@ public class RefreshDirDiffAction extends DirDiffAction {
public ShortcutSet getShortcut() {
return CustomShortcutSet.fromString("F5");
}
@Override
protected boolean isFullReload() {
return true;
}
}
@@ -0,0 +1,82 @@
/*
* Copyright 2000-2011 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.diff.impl.dir.actions;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CustomShortcutSet;
import com.intellij.openapi.actionSystem.ShortcutSet;
import com.intellij.openapi.diff.impl.dir.DirDiffElement;
import com.intellij.openapi.diff.impl.dir.DirDiffOperation;
import com.intellij.openapi.diff.impl.dir.DirDiffTableModel;
import com.intellij.openapi.util.IconLoader;
import com.intellij.openapi.util.SystemInfo;
import java.util.List;
/**
* @author Konstantin Bulenkov
*/
public class SynchronizeDiff extends DirDiffAction {
private boolean mySelectedOnly;
public SynchronizeDiff(DirDiffTableModel model, boolean selectedOnly) {
super(model,
selectedOnly ? "Synchronize Selected" : "Synchronize All",
IconLoader.getIcon(selectedOnly ? "/actions/resume.png" : "/actions/refreshUsages.png"));
mySelectedOnly = selectedOnly;
}
@Override
protected void updateState(boolean state) {
final List<DirDiffElement> elements = mySelectedOnly ? getModel().getSelectedElements() : getModel().getElements();
for (DirDiffElement element : elements) {
final DirDiffOperation operation = element.getOperation();
if (operation == null) continue;
switch (operation) {
case COPY_TO:
getModel().performCopyTo(element);
break;
case COPY_FROM:
getModel().performCopyFrom(element);
break;
case MERGE:
break;
case EQUAL:
break;
case NONE:
break;
case DELETE:
getModel().performDelete(element);
break;
}
}
}
@Override
public ShortcutSet getShortcut() {
return CustomShortcutSet.fromString(mySelectedOnly ? "ENTER" : SystemInfo.isMac ? "meta ENTER" : "control ENTER");
}
@Override
public boolean isSelected(AnActionEvent e) {
return false;
}
@Override
protected boolean isFullReload() {
return true;
}
}