mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -29,6 +29,8 @@ import com.intellij.openapi.fileTypes.StdFileTypes;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.module.ModuleType;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
@@ -42,6 +44,7 @@ import com.intellij.util.messages.MessageBusConnection;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.Semaphore;
|
||||
@@ -60,6 +63,7 @@ public class CompilerManagerImpl extends CompilerManager {
|
||||
private final Map<Compiler, Set<FileType>> myCompilerToInputTypes = new HashMap<Compiler, Set<FileType>>();
|
||||
private final Map<Compiler, Set<FileType>> myCompilerToOutputTypes = new HashMap<Compiler, Set<FileType>>();
|
||||
private final Set<ModuleType> myValidationDisabledModuleTypes = new HashSet<ModuleType>();
|
||||
private final Set<LocalFileSystem.WatchRequest> myWatchRoots;
|
||||
|
||||
public CompilerManagerImpl(final Project project, CompilerConfigurationImpl compilerConfiguration, MessageBus messageBus) {
|
||||
myProject = project;
|
||||
@@ -82,6 +86,17 @@ public class CompilerManagerImpl extends CompilerManager {
|
||||
}
|
||||
|
||||
addCompilableFileType(StdFileTypes.JAVA);
|
||||
|
||||
final File projectGeneratedSrcRoot = CompilerPaths.getGeneratedDataDirectory(project);
|
||||
FileUtil.createIfDoesntExist(projectGeneratedSrcRoot);
|
||||
final LocalFileSystem lfs = LocalFileSystem.getInstance();
|
||||
myWatchRoots = lfs.addRootsToWatch(Collections.singletonList(FileUtil.toCanonicalPath(projectGeneratedSrcRoot.getPath())), true);
|
||||
Disposer.register(project, new Disposable() {
|
||||
public void dispose() {
|
||||
lfs.removeWatchedRoots(myWatchRoots);
|
||||
}
|
||||
});
|
||||
|
||||
//
|
||||
//addCompiler(new DummyTransformingCompiler()); // this one is for testing purposes only
|
||||
//addCompiler(new DummySourceGeneratingCompiler(myProject)); // this one is for testing purposes only
|
||||
|
||||
@@ -21,6 +21,8 @@ import com.intellij.codeInsight.highlighting.HighlightManager;
|
||||
import com.intellij.find.FindManager;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ApplicationNamesInfo;
|
||||
import com.intellij.openapi.application.Result;
|
||||
import com.intellij.openapi.command.WriteCommandAction;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.FoldRegion;
|
||||
@@ -127,8 +129,10 @@ public class DuplicatesImpl {
|
||||
}
|
||||
}
|
||||
HighlightManager.getInstance(project).removeSegmentHighlighter(editor, highlighters.get(0));
|
||||
final Runnable action = new Runnable() {
|
||||
public void run() {
|
||||
|
||||
new WriteCommandAction(project, MethodDuplicatesHandler.REFACTORING_NAME) {
|
||||
@Override
|
||||
protected void run(Result result) throws Throwable {
|
||||
try {
|
||||
provider.processMatch(match);
|
||||
}
|
||||
@@ -136,10 +140,7 @@ public class DuplicatesImpl {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//use outer command
|
||||
ApplicationManager.getApplication().runWriteAction(action);
|
||||
}.execute();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
class Test {
|
||||
void foo(<caret>) {
|
||||
}
|
||||
void bar(){foo();}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
class Demo {
|
||||
class MyEvent<T> {}
|
||||
interface MyEventListener<T> {
|
||||
void action(MyEvent<T> event);
|
||||
}
|
||||
|
||||
class Driver {
|
||||
void method() {
|
||||
MyEventListener<Object> l = new MyEventListener<Object>() {
|
||||
public void ac<caret>tion(MyEvent<Object> event) {
|
||||
//To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
class Demo {
|
||||
class MyEvent<T> {}
|
||||
interface MyEventListener<T> {
|
||||
void xxx(MyEvent<T> event);
|
||||
}
|
||||
|
||||
class Driver {
|
||||
void method() {
|
||||
MyEventListener<Object> l = new MyEventListener<Object>() {
|
||||
public void xxx(MyEvent<Object> event) {
|
||||
//To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,10 +25,7 @@ import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.actions.EditorActionUtil;
|
||||
import com.intellij.openapi.editor.ex.EditorEx;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiManager;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.PsiTypeElement;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.refactoring.changeSignature.ChangeSignatureDetectorAction;
|
||||
import com.intellij.refactoring.changeSignature.ChangeSignatureGestureDetector;
|
||||
@@ -100,6 +97,17 @@ public class ChangeSignatureGestureTest extends LightCodeInsightFixtureTestCase
|
||||
doTypingNoBorderTest("int param");
|
||||
}
|
||||
|
||||
public void testOnAnotherMethod() {
|
||||
doTest(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
myFixture.type("int param");
|
||||
final int nextMethodOffset = ((PsiJavaFile)myFixture.getFile()).getClasses()[0].getMethods()[1].getTextOffset();
|
||||
myFixture.getEditor().getCaretModel().moveToOffset(nextMethodOffset);
|
||||
}
|
||||
}, false, ChangeSignatureDetectorAction.CHANGE_SIGNATURE);
|
||||
}
|
||||
|
||||
public void testAddParamChangeReturnType() {
|
||||
doTest(new Runnable() {
|
||||
@Override
|
||||
|
||||
@@ -45,6 +45,10 @@ public class RenameMembersInplaceTest extends LightCodeInsightTestCase {
|
||||
public void testSuperMethod() throws Exception {
|
||||
doTestInplaceRename("xxx");
|
||||
}
|
||||
|
||||
public void testSuperMethodAnonymousInheritor() throws Exception {
|
||||
doTestInplaceRename("xxx");
|
||||
}
|
||||
|
||||
public void testMultipleConstructors() throws Exception {
|
||||
doTestInplaceRename("Bar");
|
||||
|
||||
+11
-11
@@ -126,8 +126,8 @@ public class BaseIndentEnterHandler extends EnterHandlerDelegateAdapter {
|
||||
}
|
||||
else {
|
||||
if (myIndentTokens.contains(type)) {
|
||||
final String singleIndent = getSingleIndent(file, lineIndent);
|
||||
EditorModificationUtil.insertStringAtCaret(editor, "\n" + lineIndent + singleIndent);
|
||||
final String newIndent = getNewIndent(file, lineIndent);
|
||||
EditorModificationUtil.insertStringAtCaret(editor, "\n" + newIndent);
|
||||
return Result.Stop;
|
||||
}
|
||||
|
||||
@@ -137,6 +137,15 @@ public class BaseIndentEnterHandler extends EnterHandlerDelegateAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
protected String getNewIndent(final @NotNull PsiFile file, final @NotNull CharSequence oldIndent) {
|
||||
if (oldIndent.length() > 0 && oldIndent.charAt(oldIndent.length() - 1) == '\t') {
|
||||
return oldIndent + "\t";
|
||||
}
|
||||
final CodeStyleSettings currentSettings = CodeStyleSettingsManager.getSettings(file.getProject());
|
||||
final CommonCodeStyleSettings.IndentOptions indentOptions = currentSettings.getIndentOptions(file.getFileType());
|
||||
return oldIndent + StringUtil.repeatSymbol(' ', indentOptions.INDENT_SIZE);
|
||||
}
|
||||
|
||||
private static int calcLogicalLength(Editor editor, CharSequence lineIndent) {
|
||||
int result = 0;
|
||||
for (int i = 0; i < lineIndent.length(); i++) {
|
||||
@@ -149,15 +158,6 @@ public class BaseIndentEnterHandler extends EnterHandlerDelegateAdapter {
|
||||
return result;
|
||||
}
|
||||
|
||||
protected static String getSingleIndent(final PsiFile file, CharSequence lineIndent) {
|
||||
if (lineIndent.length() > 0 && lineIndent.charAt(lineIndent.length() - 1) == '\t') {
|
||||
return "\t";
|
||||
}
|
||||
CodeStyleSettings currentSettings = CodeStyleSettingsManager.getSettings(file.getProject());
|
||||
CommonCodeStyleSettings.IndentOptions indentOptions = currentSettings.getIndentOptions(file.getFileType());
|
||||
return StringUtil.repeatSymbol(' ', indentOptions.INDENT_SIZE);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private IElementType getNonWhitespaceElementType(final HighlighterIterator iterator, final int lineStartOffset) {
|
||||
while (!iterator.atEnd() && iterator.getStart() >= lineStartOffset) {
|
||||
|
||||
@@ -61,10 +61,7 @@ public class LanguageConsoleViewImpl extends ConsoleViewImpl {
|
||||
return myConsole.getComponent();
|
||||
}
|
||||
|
||||
public JComponent getComponent() {
|
||||
return super.getComponent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JComponent getPreferredFocusableComponent() {
|
||||
return myConsole.getConsoleEditor().getContentComponent();
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ public class TextConsoleBuilderImpl extends TextConsoleBuilder {
|
||||
myScope = scope;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConsoleView getConsole() {
|
||||
final ConsoleView consoleView = createConsole();
|
||||
for (final Filter filter : myFilters) {
|
||||
@@ -53,6 +54,7 @@ public class TextConsoleBuilderImpl extends TextConsoleBuilder {
|
||||
return new ConsoleViewImpl(myProject, myScope, myViewer, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addFilter(final Filter filter) {
|
||||
myFilters.add(filter);
|
||||
}
|
||||
|
||||
+1
-3
@@ -28,7 +28,6 @@ import com.intellij.openapi.actionSystem.TypeSafeDataProvider;
|
||||
import com.intellij.openapi.options.ConfigurationException;
|
||||
import com.intellij.openapi.options.SettingsEditor;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
@@ -60,8 +59,7 @@ public class ConfigurationSettingsEditorWrapper extends SettingsEditor<RunnerAnd
|
||||
myEditor = new ConfigurationSettingsEditor(settings);
|
||||
Disposer.register(this, myEditor);
|
||||
myBeforeRunStepsPanel = new BeforeRunStepsPanel(this);
|
||||
myBeforeLaunchContainer.setLayout(new MigLayout("fill, ins 0"));
|
||||
myBeforeLaunchContainer.add(myBeforeRunStepsPanel, "grow, push");
|
||||
myBeforeLaunchContainer.add(myBeforeRunStepsPanel);
|
||||
doReset(settings);
|
||||
}
|
||||
|
||||
|
||||
+7
-1
@@ -85,7 +85,13 @@ public class ChangeSignatureGestureDetector extends PsiTreeChangeAdapter impleme
|
||||
|
||||
public boolean isChangeSignatureAvailable(@NotNull PsiElement element) {
|
||||
final MyDocumentChangeAdapter adapter = myListenerMap.get(PsiUtilCore.getVirtualFile(element));
|
||||
return adapter != null && adapter.getCurrentInfo() != null;
|
||||
if (adapter != null) {
|
||||
final ChangeInfo currentInfo = adapter.getCurrentInfo();
|
||||
if (currentInfo != null && element.equals(adapter.getInitialChangeInfo().getMethod())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void dismissForElement(PsiElement method) {
|
||||
|
||||
+4
-7
@@ -84,14 +84,11 @@ public class MemberInplaceRenamer extends VariableInplaceRenamer {
|
||||
|
||||
@Override
|
||||
protected PsiElement checkLocalScope() {
|
||||
PsiElement scope = super.checkLocalScope();
|
||||
if (scope == null) {
|
||||
PsiFile currentFile = PsiDocumentManager.getInstance(myProject).getPsiFile(myEditor.getDocument());
|
||||
if (currentFile != null) {
|
||||
return currentFile;
|
||||
}
|
||||
PsiFile currentFile = PsiDocumentManager.getInstance(myProject).getPsiFile(myEditor.getDocument());
|
||||
if (currentFile != null) {
|
||||
return currentFile;
|
||||
}
|
||||
return scope;
|
||||
return super.checkLocalScope();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -20,7 +20,6 @@ import com.intellij.ide.CutProvider;
|
||||
import com.intellij.ide.DeleteProvider;
|
||||
import com.intellij.ide.PasteProvider;
|
||||
import com.intellij.openapi.actionSystem.DataContext;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.LogicalPosition;
|
||||
import com.intellij.openapi.editor.VisualPosition;
|
||||
|
||||
@@ -385,15 +385,19 @@ public class FileUtil extends FileUtilRt {
|
||||
String parentDirPath = file.getParent();
|
||||
if (parentDirPath != null) {
|
||||
final File parentFile = new File(parentDirPath);
|
||||
int parentAttributes = getBooleanAttributes(parentFile);
|
||||
boolean ok = parentAttributes != -1 ? (parentAttributes & (BA_EXISTS | BA_DIRECTORY)) == (BA_EXISTS | BA_DIRECTORY)
|
||||
: parentFile.exists() && parentFile.isDirectory();
|
||||
return ok || parentFile.mkdirs();
|
||||
return createDirectory(parentFile);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean createDirectory(File parentFile) {
|
||||
int parentAttributes = getBooleanAttributes(parentFile);
|
||||
boolean ok = parentAttributes != -1 ? (parentAttributes & (BA_EXISTS | BA_DIRECTORY)) == (BA_EXISTS | BA_DIRECTORY)
|
||||
: parentFile.exists() && parentFile.isDirectory();
|
||||
return ok || parentFile.mkdirs();
|
||||
}
|
||||
|
||||
public static boolean createIfDoesntExist(@NotNull File file) {
|
||||
if (file.exists()) return true;
|
||||
try {
|
||||
|
||||
@@ -38,8 +38,13 @@ public class VcsException extends Exception {
|
||||
myMessages = Collections.singleton(shownMessage);
|
||||
}
|
||||
|
||||
public VcsException(Throwable throwable) {
|
||||
public VcsException(Throwable throwable, final boolean isWarning) {
|
||||
this(throwable.getMessage() != null ? throwable.getMessage() : throwable.getLocalizedMessage(), throwable);
|
||||
this.isWarning = isWarning;
|
||||
}
|
||||
|
||||
public VcsException(Throwable throwable) {
|
||||
this(throwable, false);
|
||||
}
|
||||
|
||||
public VcsException(final String message, final Throwable cause) {
|
||||
@@ -47,6 +52,11 @@ public class VcsException extends Exception {
|
||||
initMessage(message);
|
||||
}
|
||||
|
||||
public VcsException(final String message, final boolean isWarning) {
|
||||
this(message);
|
||||
this.isWarning = isWarning;
|
||||
}
|
||||
|
||||
public VcsException(Collection<String> messages) {
|
||||
myMessages = messages;
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ public interface ContinuationContext extends ContinuationPause {
|
||||
void cancelEverything();
|
||||
|
||||
<T extends Exception> void addExceptionHandler(final Class<T> clazz, final Consumer<T> consumer);
|
||||
boolean handleException(final Exception e);
|
||||
boolean handleException(final Exception e, boolean cancelEveryThing);
|
||||
|
||||
void keepExisting(final Object disaster, final Object cure);
|
||||
void throwDisaster(final Object disaster, final Object cure);
|
||||
|
||||
+1
-1
@@ -47,7 +47,7 @@ public class GatheringContinuationContext implements ContinuationContext {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleException(Exception e) {
|
||||
public boolean handleException(Exception e, boolean cancelEveryThing) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
+77
-45
@@ -18,10 +18,7 @@ package com.intellij.openapi.vcs.changes.patch;
|
||||
import com.intellij.ide.util.PropertiesComponent;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.actionSystem.*;
|
||||
import com.intellij.openapi.diff.impl.patch.PatchReader;
|
||||
import com.intellij.openapi.diff.impl.patch.PatchSyntaxException;
|
||||
import com.intellij.openapi.diff.impl.patch.PatchVirtualFileReader;
|
||||
import com.intellij.openapi.diff.impl.patch.TextFilePatch;
|
||||
import com.intellij.openapi.diff.impl.patch.*;
|
||||
import com.intellij.openapi.fileChooser.FileChooser;
|
||||
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
|
||||
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
|
||||
@@ -33,10 +30,7 @@ import com.intellij.openapi.ui.TextFieldWithBrowseButton;
|
||||
import com.intellij.openapi.ui.popup.JBPopupFactory;
|
||||
import com.intellij.openapi.ui.popup.PopupStep;
|
||||
import com.intellij.openapi.ui.popup.util.BaseListPopupStep;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.Getter;
|
||||
import com.intellij.openapi.util.IconLoader;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.*;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vcs.ObjectsConvertor;
|
||||
import com.intellij.openapi.vcs.VcsBundle;
|
||||
@@ -95,10 +89,22 @@ public class ApplyPatchDifferentiatedDialog extends DialogWrapper {
|
||||
private JLabel myPatchFileLabel;
|
||||
private PatchReader myReader;
|
||||
private CommitContext myCommitContext;
|
||||
private final VirtualFileAdapter myListener;
|
||||
private VirtualFileAdapter myListener;
|
||||
private boolean myCanChangePatchFile;
|
||||
|
||||
public ApplyPatchDifferentiatedDialog(final Project project, final ApplyPatchExecutor callback, final List<ApplyPatchExecutor> executors,
|
||||
@NotNull final ApplyPatchMode applyPatchMode, @NotNull final VirtualFile patchFile) {
|
||||
this(project, callback, executors, applyPatchMode, patchFile, null, null);
|
||||
}
|
||||
|
||||
public ApplyPatchDifferentiatedDialog(final Project project, final ApplyPatchExecutor callback, final List<ApplyPatchExecutor> executors,
|
||||
@NotNull final ApplyPatchMode applyPatchMode, @NotNull final List<TextFilePatch> patches, @Nullable final LocalChangeList defaultList) {
|
||||
this(project, callback, executors, applyPatchMode, null, patches, defaultList);
|
||||
}
|
||||
|
||||
private ApplyPatchDifferentiatedDialog(final Project project, final ApplyPatchExecutor callback, final List<ApplyPatchExecutor> executors,
|
||||
@NotNull final ApplyPatchMode applyPatchMode, @Nullable final VirtualFile patchFile, @Nullable final List<TextFilePatch> patches,
|
||||
@Nullable final LocalChangeList defaultList) {
|
||||
super(project, true);
|
||||
myCallback = callback;
|
||||
myExecutors = executors;
|
||||
@@ -107,18 +113,8 @@ public class ApplyPatchDifferentiatedDialog extends DialogWrapper {
|
||||
|
||||
final FileChooserDescriptor descriptor = createSelectPatchDescriptor();
|
||||
descriptor.setTitle(VcsBundle.message("patch.apply.select.title"));
|
||||
myUpdater = new MyUpdater();
|
||||
myPatchFile = new TextFieldWithBrowseButton();
|
||||
myPatchFile.addBrowseFolderListener(VcsBundle.message("patch.apply.select.title"), "", project, descriptor);
|
||||
myPatchFile.getTextField().getDocument().addDocumentListener(new DocumentAdapter() {
|
||||
protected void textChanged(DocumentEvent e) {
|
||||
setPathFileChangeDefault();
|
||||
myLoadQueue.queue(myUpdater);
|
||||
}
|
||||
});
|
||||
|
||||
myProject = project;
|
||||
myLoadQueue = new ZipperUpdater(500, getDisposable());
|
||||
myPatches = new LinkedList<FilePatchInProgress>();
|
||||
myRecentPathFileChange = new AtomicReference<FilePresentation>();
|
||||
myChangesTreeList = new MyChangeTreeList(project, Collections.<FilePatchInProgress.PatchChange>emptyList(),
|
||||
@@ -138,11 +134,24 @@ public class ApplyPatchDifferentiatedDialog extends DialogWrapper {
|
||||
myCommitLegendPanel.update();
|
||||
}
|
||||
}, new MyChangeNodeDecorator());
|
||||
myReset = new Runnable() {
|
||||
|
||||
myUpdater = new MyUpdater();
|
||||
myPatchFile = new TextFieldWithBrowseButton();
|
||||
myPatchFile.addBrowseFolderListener(VcsBundle.message("patch.apply.select.title"), "", project, descriptor);
|
||||
myPatchFile.getTextField().getDocument().addDocumentListener(new DocumentAdapter() {
|
||||
protected void textChanged(DocumentEvent e) {
|
||||
setPathFileChangeDefault();
|
||||
myLoadQueue.queue(myUpdater);
|
||||
}
|
||||
});
|
||||
|
||||
myLoadQueue = new ZipperUpdater(500, getDisposable());
|
||||
myCanChangePatchFile = applyPatchMode.isCanChangePatchFile();
|
||||
myReset = myCanChangePatchFile ? new Runnable() {
|
||||
public void run() {
|
||||
reset();
|
||||
}
|
||||
};
|
||||
} : EmptyRunnable.getInstance();
|
||||
|
||||
myChangeListChooser = new ChangeListChooserPanel(project, new Consumer<String>() {
|
||||
public void consume(final String errorMessage) {
|
||||
@@ -160,27 +169,48 @@ public class ApplyPatchDifferentiatedDialog extends DialogWrapper {
|
||||
|
||||
init();
|
||||
|
||||
if (patchFile.isValid()) {
|
||||
if (patchFile != null && patchFile.isValid()) {
|
||||
init(patchFile);
|
||||
} else if (patches != null) {
|
||||
init(patches, defaultList);
|
||||
}
|
||||
myPatchFileLabel.setVisible(applyPatchMode.isCanChangePatchFile());
|
||||
myPatchFile.setVisible(applyPatchMode.isCanChangePatchFile());
|
||||
|
||||
myListener = new VirtualFileAdapter() {
|
||||
@Override
|
||||
public void contentsChanged(VirtualFileEvent event) {
|
||||
if (myRecentPathFileChange.get() != null && myRecentPathFileChange.get().getVf() != null &&
|
||||
myRecentPathFileChange.get().getVf().equals(event.getFile())) {
|
||||
myLoadQueue.queue(myUpdater);
|
||||
myPatchFileLabel.setVisible(myCanChangePatchFile);
|
||||
myPatchFile.setVisible(myCanChangePatchFile);
|
||||
|
||||
if (myCanChangePatchFile) {
|
||||
myListener = new VirtualFileAdapter() {
|
||||
@Override
|
||||
public void contentsChanged(VirtualFileEvent event) {
|
||||
if (myRecentPathFileChange.get() != null && myRecentPathFileChange.get().getVf() != null &&
|
||||
myRecentPathFileChange.get().getVf().equals(event.getFile())) {
|
||||
myLoadQueue.queue(myUpdater);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
final VirtualFileManager fileManager = VirtualFileManager.getInstance();
|
||||
fileManager.addVirtualFileListener(myListener);
|
||||
Disposer.register(getDisposable(), new Disposable() {
|
||||
@Override
|
||||
public void dispose() {
|
||||
fileManager.removeVirtualFileListener(myListener);
|
||||
};
|
||||
final VirtualFileManager fileManager = VirtualFileManager.getInstance();
|
||||
fileManager.addVirtualFileListener(myListener);
|
||||
Disposer.register(getDisposable(), new Disposable() {
|
||||
@Override
|
||||
public void dispose() {
|
||||
fileManager.removeVirtualFileListener(myListener);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void init(List<TextFilePatch> patches, final LocalChangeList localChangeList) {
|
||||
final List<FilePatchInProgress> matchedPathes = new AutoMatchIterator(myProject).execute(patches);
|
||||
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
if (localChangeList != null) {
|
||||
myChangeListChooser.setDefaultSelection(localChangeList);
|
||||
}
|
||||
|
||||
myPatches.clear();
|
||||
myPatches.addAll(matchedPathes);
|
||||
updateTree(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -225,7 +255,7 @@ public class ApplyPatchDifferentiatedDialog extends DialogWrapper {
|
||||
patchGroups.putValue(patchInProgress.getBase(), patchInProgress);
|
||||
}
|
||||
final LocalChangeList selected = getSelectedChangeList();
|
||||
executor.apply(patchGroups, selected, myRecentPathFileChange.get().getVf().getName(),
|
||||
executor.apply(patchGroups, selected, myRecentPathFileChange.get() == null ? null : myRecentPathFileChange.get().getVf().getName(),
|
||||
myReader == null ? null : myReader.getAdditionalInfo(ApplyPatchDefaultExecutor.pathsFromGroups(patchGroups)));
|
||||
}
|
||||
|
||||
@@ -369,12 +399,14 @@ public class ApplyPatchDifferentiatedDialog extends DialogWrapper {
|
||||
group.add(new StripDown());
|
||||
group.add(new ResetStrip());
|
||||
group.add(new ZeroStrip());
|
||||
group.add(new AnAction("Refresh", "Refresh", IconLoader.getIcon("/actions/sync.png")) {
|
||||
@Override
|
||||
public void actionPerformed(AnActionEvent e) {
|
||||
myLoadQueue.queue(myUpdater);
|
||||
}
|
||||
});
|
||||
if (myCanChangePatchFile) {
|
||||
group.add(new AnAction("Refresh", "Refresh", IconLoader.getIcon("/actions/sync.png")) {
|
||||
@Override
|
||||
public void actionPerformed(AnActionEvent e) {
|
||||
myLoadQueue.queue(myUpdater);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
final ActionToolbar toolbar = ActionManager.getInstance().createActionToolbar("APPLY_PATCH", group, true);
|
||||
myCenterPanel.add(toolbar.getComponent(), gb);
|
||||
|
||||
@@ -24,7 +24,8 @@ import com.intellij.openapi.vcs.VcsBundle;
|
||||
*/
|
||||
public enum ApplyPatchMode {
|
||||
APPLY(VcsBundle.message("patch.apply.dialog.title"), true),
|
||||
UNSHELVE(VcsBundle.message("unshelve.changes.dialog.title"), false);
|
||||
UNSHELVE(VcsBundle.message("unshelve.changes.dialog.title"), false),
|
||||
APPLY_PATCH_IN_MEMORY(VcsBundle.message("patch.apply.dialog.title"), false);
|
||||
|
||||
private final String myTitle;
|
||||
private final boolean myCanChangePatchFile;
|
||||
|
||||
@@ -77,19 +77,25 @@ abstract class GeneralRunner implements ContinuationContext {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleException(Exception e) {
|
||||
public boolean handleException(Exception e, boolean cancelEveryThing) {
|
||||
synchronized (myQueueLock) {
|
||||
final Class<? extends Exception> aClass = e.getClass();
|
||||
Consumer<Exception> consumer = myHandlersMap.get(e.getClass());
|
||||
if (consumer != null) {
|
||||
consumer.consume(e);
|
||||
return true;
|
||||
}
|
||||
for (Map.Entry<Class<? extends Exception>, Consumer<Exception>> entry : myHandlersMap.entrySet()) {
|
||||
if (entry.getKey().isAssignableFrom(aClass)) {
|
||||
entry.getValue().consume(e);
|
||||
try {
|
||||
final Class<? extends Exception> aClass = e.getClass();
|
||||
Consumer<Exception> consumer = myHandlersMap.get(e.getClass());
|
||||
if (consumer != null) {
|
||||
consumer.consume(e);
|
||||
return true;
|
||||
}
|
||||
for (Map.Entry<Class<? extends Exception>, Consumer<Exception>> entry : myHandlersMap.entrySet()) {
|
||||
if (entry.getKey().isAssignableFrom(aClass)) {
|
||||
entry.getValue().consume(e);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (cancelEveryThing) {
|
||||
cancelEverything();
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -361,7 +361,7 @@ public class GitCommitsSequentialIndex implements GitCommitsSequentially {
|
||||
}
|
||||
catch (VcsException e) {
|
||||
context.cancelEverything();
|
||||
if (! context.handleException(e)) {
|
||||
if (! context.handleException(e, false)) {
|
||||
VcsBalloonProblemNotifier.showOverChangesView(myProject, e.getMessage(), MessageType.ERROR);
|
||||
// and exit, do not ping
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ public class GitStashChangesSaver extends GitChangesSaver {
|
||||
load();
|
||||
}
|
||||
catch (VcsException e) {
|
||||
context.handleException(e);
|
||||
context.handleException(e, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+12
-11
@@ -62,6 +62,8 @@ public class MvcModuleStructureSynchronizer extends AbstractProjectComponent {
|
||||
|
||||
private boolean myOutOfModuleDirectoryCreatedActionAdded;
|
||||
|
||||
public static boolean ourGrailsTestFlag;
|
||||
|
||||
private final ModificationTracker myModificationTracker = new ModificationTracker() {
|
||||
@Override
|
||||
public long getModificationCount() {
|
||||
@@ -244,17 +246,12 @@ public class MvcModuleStructureSynchronizer extends AbstractProjectComponent {
|
||||
StartupManager.getInstance(myProject).runWhenProjectIsInitialized(new DumbAwareRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
runActions();
|
||||
}
|
||||
else {
|
||||
ApplicationManager.getApplication().invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
runActions();
|
||||
}
|
||||
}, ModalityState.NON_MODAL);
|
||||
}
|
||||
ApplicationManager.getApplication().invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
runActions();
|
||||
}
|
||||
}, ModalityState.NON_MODAL);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -295,6 +292,10 @@ public class MvcModuleStructureSynchronizer extends AbstractProjectComponent {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ApplicationManager.getApplication().isUnitTestMode() && !ourGrailsTestFlag) {
|
||||
return;
|
||||
}
|
||||
|
||||
Pair<Object, SyncAction>[] actions = myActions.toArray(new Pair[myActions.size()]);
|
||||
//get module by object and kill duplicates
|
||||
|
||||
|
||||
@@ -99,9 +99,7 @@ public class MavenProjectsTree {
|
||||
result.myRootProjects.addAll(readProjectsRecursively(in, result));
|
||||
}
|
||||
catch (Throwable e) {
|
||||
IOException ioException = new IOException();
|
||||
ioException.initCause(e);
|
||||
throw ioException;
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
|
||||
@@ -111,6 +111,7 @@ public class SvnConfiguration implements PersistentStateComponent<Element> {
|
||||
public boolean IGNORE_SPACES_IN_ANNOTATE = true;
|
||||
public boolean SHOW_MERGE_SOURCES_IN_ANNOTATE = true;
|
||||
public boolean FORCE_UPDATE = false;
|
||||
public Boolean TREE_CONFLICT_MERGE_THEIRS_NEW_INTO_OLD_PLACE;
|
||||
|
||||
public UseAcceleration myUseAcceleration = UseAcceleration.nothing;
|
||||
|
||||
@@ -409,6 +410,10 @@ public class SvnConfiguration implements PersistentStateComponent<Element> {
|
||||
if (cleanupRun != null) {
|
||||
myCleanupRun = Boolean.parseBoolean(cleanupRun.getValue());
|
||||
}
|
||||
final Attribute treeConflictMergeNewFilesPlace = element.getAttribute("TREE_CONFLICT_MERGE_THEIRS_NEW_INTO_OLD_PLACE");
|
||||
if (treeConflictMergeNewFilesPlace != null) {
|
||||
TREE_CONFLICT_MERGE_THEIRS_NEW_INTO_OLD_PLACE = Boolean.parseBoolean(treeConflictMergeNewFilesPlace.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"HardCodedStringLiteral"})
|
||||
@@ -444,6 +449,9 @@ public class SvnConfiguration implements PersistentStateComponent<Element> {
|
||||
element.setAttribute("myUseAcceleration", "" + myUseAcceleration);
|
||||
element.setAttribute("myAutoUpdateAfterCommit", "" + myAutoUpdateAfterCommit);
|
||||
element.setAttribute(CLEANUP_ON_START_RUN, "" + myCleanupRun);
|
||||
if (TREE_CONFLICT_MERGE_THEIRS_NEW_INTO_OLD_PLACE != null) {
|
||||
element.setAttribute("TREE_CONFLICT_MERGE_THEIRS_NEW_INTO_OLD_PLACE", "" + TREE_CONFLICT_MERGE_THEIRS_NEW_INTO_OLD_PLACE);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isAutoUpdateAfterCommit() {
|
||||
|
||||
@@ -49,6 +49,7 @@ import com.intellij.openapi.vcs.versionBrowser.ChangeBrowserSettings;
|
||||
import com.intellij.openapi.vcs.versionBrowser.CommittedChangeList;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.VirtualFileManager;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.ThreeState;
|
||||
import com.intellij.util.containers.Convertor;
|
||||
import com.intellij.util.containers.SoftHashMap;
|
||||
@@ -72,6 +73,8 @@ import org.jetbrains.idea.svn.history.SvnHistoryProvider;
|
||||
import org.jetbrains.idea.svn.rollback.SvnRollbackEnvironment;
|
||||
import org.jetbrains.idea.svn.update.SvnIntegrateEnvironment;
|
||||
import org.jetbrains.idea.svn.update.SvnUpdateEnvironment;
|
||||
import org.tmatesoft.sqljet.core.SqlJetErrorCode;
|
||||
import org.tmatesoft.sqljet.core.SqlJetException;
|
||||
import org.tmatesoft.svn.core.*;
|
||||
import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager;
|
||||
import org.tmatesoft.svn.core.internal.io.dav.DAVRepositoryFactory;
|
||||
@@ -156,6 +159,21 @@ public class SvnVcs extends AbstractVcs<CommittedChangeList> {
|
||||
public static final String SVNKIT_HTTP_SSL_PROTOCOLS = "svnkit.http.sslProtocols";
|
||||
private final SvnExecutableChecker myChecker;
|
||||
|
||||
public static final Processor<Exception> ourBusyExceptionProcessor = new Processor<Exception>() {
|
||||
@Override
|
||||
public boolean process(Exception e) {
|
||||
if (e instanceof SVNException) {
|
||||
if (SVNErrorCode.SQLITE_ERROR.equals(((SVNException)e).getErrorMessage().getErrorCode())) {
|
||||
Throwable cause = ((SVNException)e).getErrorMessage().getCause();
|
||||
if (cause instanceof SqlJetException) {
|
||||
return SqlJetErrorCode.BUSY.equals(((SqlJetException)cause).getErrorCode());
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
public void checkCommandLineVersion() {
|
||||
myChecker.checkExecutableAndNotifyIfNeeded();
|
||||
}
|
||||
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright 2000-2012 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 org.jetbrains.idea.svn.treeConflict;
|
||||
|
||||
import com.intellij.CommonBundle;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.diff.impl.patch.*;
|
||||
import com.intellij.openapi.fileChooser.*;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vcs.FilePath;
|
||||
import com.intellij.openapi.vcs.FilePathImpl;
|
||||
import com.intellij.openapi.vcs.VcsBundle;
|
||||
import com.intellij.openapi.vcs.changes.*;
|
||||
import com.intellij.openapi.vcs.changes.patch.ApplyPatchDefaultExecutor;
|
||||
import com.intellij.openapi.vcs.changes.patch.ApplyPatchExecutor;
|
||||
import com.intellij.openapi.vcs.changes.patch.FilePatchInProgress;
|
||||
import com.intellij.openapi.vcs.changes.patch.PatchWriter;
|
||||
import com.intellij.openapi.vfs.CharsetToolkit;
|
||||
import com.intellij.openapi.vfs.VfsUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.VirtualFileWrapper;
|
||||
import com.intellij.util.WaitForProgressToShow;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created with IntelliJ IDEA.
|
||||
* User: Irina.Chernushina
|
||||
* Date: 5/17/12
|
||||
* Time: 6:02 PM
|
||||
*/
|
||||
public class ApplyPatchSaveToFileExecutor implements ApplyPatchExecutor {
|
||||
private final Project myProject;
|
||||
private final VirtualFile myBaseForPatch;
|
||||
private static final Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.treeConflict.ApplyPatchSaveToFileExecutor");
|
||||
|
||||
public ApplyPatchSaveToFileExecutor(Project project, VirtualFile baseForPatch) {
|
||||
myProject = project;
|
||||
myBaseForPatch = baseForPatch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Save patch to file";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(MultiMap<VirtualFile, FilePatchInProgress> patchGroups,
|
||||
LocalChangeList localList,
|
||||
String fileName,
|
||||
TransparentlyFailedValue<Map<String, Map<String, CharSequence>>, PatchSyntaxException> additionalInfo) {
|
||||
final FileSaverDialog dialog = FileChooserFactory.getInstance().createSaveFileDialog(
|
||||
new FileSaverDescriptor("Save patch to", ""), myProject);
|
||||
final VirtualFile baseDir = myProject.getBaseDir();
|
||||
final VirtualFileWrapper save = dialog.save(baseDir, "TheirsChanges.patch");
|
||||
if (save != null && save.getFile() != null) {
|
||||
final CommitContext commitContext = new CommitContext();
|
||||
|
||||
final VirtualFile baseForPatch = myBaseForPatch == null ? baseDir : myBaseForPatch;
|
||||
try {
|
||||
final List<FilePatch> textPatches = patchGroupsToOneGroup(patchGroups, baseForPatch);
|
||||
commitContext.putUserData(BaseRevisionTextPatchEP.ourPutBaseRevisionTextKey, false);
|
||||
PatchWriter.writePatches(myProject, save.getFile().getPath(), textPatches, commitContext, CharsetToolkit.UTF8_CHARSET);
|
||||
}
|
||||
catch (final IOException e) {
|
||||
LOG.info(e);
|
||||
WaitForProgressToShow.runOrInvokeLaterAboveProgress(new Runnable() {
|
||||
public void run() {
|
||||
Messages.showErrorDialog(myProject, VcsBundle.message("create.patch.error.title", e.getMessage()), CommonBundle.getErrorTitle());
|
||||
}
|
||||
}, null, myProject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static List<FilePatch> patchGroupsToOneGroup(MultiMap<VirtualFile, FilePatchInProgress> patchGroups, VirtualFile baseDir)
|
||||
throws IOException {
|
||||
final List<FilePatch> textPatches = new ArrayList<FilePatch>();
|
||||
final String baseDirPath = baseDir.getPath();
|
||||
|
||||
for (Map.Entry<VirtualFile, Collection<FilePatchInProgress>> entry : patchGroups.entrySet()) {
|
||||
final VirtualFile vf = entry.getKey();
|
||||
final String currBasePath = vf.getPath();
|
||||
final String relativePath = VfsUtil.getRelativePath(vf, baseDir, '/');
|
||||
final boolean toConvert = !StringUtil.isEmptyOrSpaces(relativePath) && !".".equals(relativePath);
|
||||
for (FilePatchInProgress patchInProgress : entry.getValue()) {
|
||||
final TextFilePatch patch = patchInProgress.getPatch();
|
||||
if (toConvert) {
|
||||
//correct paths
|
||||
patch.setBeforeName(convertRelativePath(patch.getBeforeName(), currBasePath, baseDirPath));
|
||||
patch.setAfterName(convertRelativePath(patch.getAfterName(), currBasePath, baseDirPath));
|
||||
}
|
||||
textPatches.add(patch);
|
||||
}
|
||||
}
|
||||
return textPatches;
|
||||
}
|
||||
|
||||
private static String convertRelativePath(String pathInPatch, String currentBase, String baseDirPath) throws IOException {
|
||||
if (StringUtil.isEmptyOrSpaces(pathInPatch)) return pathInPatch;
|
||||
final File currentPath = new File(currentBase, pathInPatch);
|
||||
return FileUtil.getRelativePath(FileUtil.toSystemIndependentName(baseDirPath), FileUtil.toSystemIndependentName(currentPath.getCanonicalPath()), '/');
|
||||
}
|
||||
}
|
||||
+640
@@ -0,0 +1,640 @@
|
||||
/*
|
||||
* Copyright 2000-2012 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 org.jetbrains.idea.svn.treeConflict;
|
||||
|
||||
import com.intellij.CommonBundle;
|
||||
import com.intellij.openapi.application.Application;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diff.impl.patch.*;
|
||||
import com.intellij.openapi.diff.impl.patch.formove.PatchApplier;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
import com.intellij.openapi.ui.MessageType;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vcs.*;
|
||||
import com.intellij.openapi.vcs.changes.*;
|
||||
import com.intellij.openapi.vcs.changes.committed.CommittedChangesTreeBrowser;
|
||||
import com.intellij.openapi.vcs.changes.patch.ApplyPatchDifferentiatedDialog;
|
||||
import com.intellij.openapi.vcs.changes.patch.ApplyPatchExecutor;
|
||||
import com.intellij.openapi.vcs.changes.patch.ApplyPatchMode;
|
||||
import com.intellij.openapi.vcs.changes.patch.FilePatchInProgress;
|
||||
import com.intellij.openapi.vcs.ui.VcsBalloonProblemNotifier;
|
||||
import com.intellij.openapi.vcs.versionBrowser.ChangeBrowserSettings;
|
||||
import com.intellij.openapi.vcs.versionBrowser.CommittedChangeList;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VfsUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.containers.Convertor;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import com.intellij.util.continuation.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.idea.svn.*;
|
||||
import org.jetbrains.idea.svn.history.SvnChangeList;
|
||||
import org.jetbrains.idea.svn.history.SvnRepositoryLocation;
|
||||
import org.tmatesoft.svn.core.SVNDepth;
|
||||
import org.tmatesoft.svn.core.SVNException;
|
||||
import org.tmatesoft.svn.core.SVNNodeKind;
|
||||
import org.tmatesoft.svn.core.wc.SVNRevision;
|
||||
import org.tmatesoft.svn.core.wc.SVNTreeConflictDescription;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Created with IntelliJ IDEA.
|
||||
* User: Irina.Chernushina
|
||||
* Date: 5/18/12
|
||||
* Time: 2:44 PM
|
||||
*/
|
||||
public class MergeFromTheirsResolver {
|
||||
private final SvnVcs myVcs;
|
||||
private final SVNTreeConflictDescription myDescription;
|
||||
private final Change myChange;
|
||||
private final FilePath myOldFilePath;
|
||||
private final FilePath myNewFilePath;
|
||||
private final String myOldPresentation;
|
||||
private final String myNewPresentation;
|
||||
private final SvnRevisionNumber myCommittedRevision;
|
||||
private Boolean myAdd;
|
||||
|
||||
private final List<Change> myTheirsChanges;
|
||||
private final List<Change> myTheirsBinaryChanges;
|
||||
private final List<VcsException> myWarnings;
|
||||
private List<TextFilePatch> myTextPatches;
|
||||
private VirtualFile myBaseForPatch;
|
||||
|
||||
public MergeFromTheirsResolver(SvnVcs vcs, SVNTreeConflictDescription description, Change change, SvnRevisionNumber revision) {
|
||||
myVcs = vcs;
|
||||
myDescription = description;
|
||||
myChange = change;
|
||||
myCommittedRevision = revision;
|
||||
myOldFilePath = myChange.getBeforeRevision().getFile();
|
||||
myNewFilePath = myChange.getAfterRevision().getFile();
|
||||
myBaseForPatch = ApplicationManager.getApplication().runReadAction(new Computable<VirtualFile>() {
|
||||
@Override
|
||||
public VirtualFile compute() {
|
||||
return ChangesUtil.findValidParent(myNewFilePath);
|
||||
}
|
||||
});
|
||||
myOldPresentation = TreeConflictRefreshablePanel.filePath(myOldFilePath);
|
||||
myNewPresentation = TreeConflictRefreshablePanel.filePath(myNewFilePath);
|
||||
|
||||
myTheirsChanges = new ArrayList<Change>();
|
||||
myTheirsBinaryChanges = new ArrayList<Change>();
|
||||
myWarnings = new ArrayList<VcsException>();
|
||||
myTextPatches = Collections.emptyList();
|
||||
}
|
||||
|
||||
public void execute() {
|
||||
int ok = Messages.showOkCancelDialog(myVcs.getProject(), (myChange.isMoved() ?
|
||||
SvnBundle.message("confirmation.resolve.tree.conflict.merge.moved", myOldPresentation, myNewPresentation) :
|
||||
SvnBundle.message("confirmation.resolve.tree.conflict.merge.renamed", myOldPresentation, myNewPresentation)),
|
||||
TreeConflictRefreshablePanel.TITLE, Messages.getQuestionIcon());
|
||||
if (Messages.OK != ok) return;
|
||||
|
||||
FileDocumentManager.getInstance().saveAllDocuments();
|
||||
//final String name = "Merge changes from theirs for: " + myOldPresentation;
|
||||
|
||||
final Continuation fragmented = Continuation.createFragmented(myVcs.getProject(), false);
|
||||
fragmented.addExceptionHandler(VcsException.class, new Consumer<VcsException>() {
|
||||
@Override
|
||||
public void consume(VcsException e) {
|
||||
myWarnings.add(e);
|
||||
if (e.isWarning()) {
|
||||
return;
|
||||
}
|
||||
AbstractVcsHelper.getInstance(myVcs.getProject()).showErrors(myWarnings, TreeConflictRefreshablePanel.TITLE);
|
||||
}
|
||||
});
|
||||
|
||||
final List<TaskDescriptor> tasks = new SmartList<TaskDescriptor>();
|
||||
if (SVNNodeKind.DIR.equals(myDescription.getNodeKind())) {
|
||||
tasks.add(new PreloadChangesContentsForDir());
|
||||
} else {
|
||||
tasks.add(new PreloadChangesContentsForFile());
|
||||
}
|
||||
tasks.add(new ConvertTextPaths());
|
||||
tasks.add(new PatchCreator());
|
||||
tasks.add(new SelectPatchesInApplyPatchDialog());
|
||||
tasks.add(new SelectBinaryFiles());
|
||||
|
||||
fragmented.run(tasks);
|
||||
}
|
||||
|
||||
private void appendResolveConflictToContext(final ContinuationContext context) {
|
||||
context.next(new ResolveConflictInSvn());
|
||||
}
|
||||
|
||||
private void appendTailToContextLast(final ContinuationContext context) {
|
||||
context.last(new ApplyBinaryChanges(), new FinalNotification());
|
||||
}
|
||||
|
||||
private List<Change> filterOutBinary(List<Change> paths) {
|
||||
List<Change> result = null;
|
||||
for (Iterator<Change> iterator = paths.iterator(); iterator.hasNext(); ) {
|
||||
final Change change = iterator.next();
|
||||
if (ChangesUtil.isBinaryChange(change)) {
|
||||
result = (result == null ? new SmartList<Change>() : result);
|
||||
result.add(change);
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private class FinalNotification extends TaskDescriptor {
|
||||
private FinalNotification() {
|
||||
super("", Where.AWT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(ContinuationContext context) {
|
||||
final StringBuilder message = new StringBuilder().append("Theirs changes merged for ").append(myOldPresentation);
|
||||
VcsBalloonProblemNotifier.showOverChangesView(myVcs.getProject(), message.toString(), MessageType.INFO);
|
||||
if (! myWarnings.isEmpty()) {
|
||||
AbstractVcsHelper.getInstance(myVcs.getProject()).showErrors(myWarnings, TreeConflictRefreshablePanel.TITLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class ResolveConflictInSvn extends TaskDescriptor {
|
||||
private ResolveConflictInSvn() {
|
||||
super("Accepting working state", Where.POOLED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(ContinuationContext context) {
|
||||
try {
|
||||
new SvnTreeConflictResolver(myVcs, myOldFilePath, myCommittedRevision, null).resolveSelectMineFull(myDescription);
|
||||
}
|
||||
catch (VcsException e1) {
|
||||
context.handleException(e1, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class ConvertTextPaths extends TaskDescriptor {
|
||||
private ConvertTextPaths() {
|
||||
super("", Where.AWT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(ContinuationContext context) {
|
||||
initAddOption();
|
||||
List<Change> convertedChanges = new SmartList<Change>();
|
||||
try {
|
||||
// revision contents is preloaded, so ok to call in awt
|
||||
convertedChanges = convertPaths(myTheirsChanges);
|
||||
}
|
||||
catch (VcsException e) {
|
||||
context.handleException(e, true);
|
||||
}
|
||||
myTheirsChanges.clear();
|
||||
myTheirsChanges.addAll(convertedChanges);
|
||||
}
|
||||
}
|
||||
|
||||
private class SelectPatchesInApplyPatchDialog extends TaskDescriptor {
|
||||
private SelectPatchesInApplyPatchDialog() {
|
||||
super("", Where.AWT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(ContinuationContext context) {
|
||||
final ChangeListManager clManager = ChangeListManager.getInstance(myVcs.getProject());
|
||||
final LocalChangeList changeList = clManager.getChangeList(myChange);
|
||||
final ApplyPatchDifferentiatedDialog dialog = new ApplyPatchDifferentiatedDialog(myVcs.getProject(),
|
||||
new TreeConflictApplyTheirsPatchExecutor(myVcs, context, myBaseForPatch),
|
||||
Collections.<ApplyPatchExecutor>singletonList(new ApplyPatchSaveToFileExecutor(myVcs.getProject(), myBaseForPatch)),
|
||||
ApplyPatchMode.APPLY_PATCH_IN_MEMORY, myTextPatches, changeList);
|
||||
context.suspend();
|
||||
dialog.show();
|
||||
}
|
||||
}
|
||||
|
||||
private class TreeConflictApplyTheirsPatchExecutor implements ApplyPatchExecutor {
|
||||
private final SvnVcs myVcs;
|
||||
private final ContinuationContext myInner;
|
||||
private final VirtualFile myBaseDir;
|
||||
|
||||
public TreeConflictApplyTheirsPatchExecutor(SvnVcs vcs, ContinuationContext inner, final VirtualFile baseDir) {
|
||||
myVcs = vcs;
|
||||
myInner = inner;
|
||||
myBaseDir = baseDir;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Apply patch";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(MultiMap<VirtualFile, FilePatchInProgress> patchGroups, LocalChangeList localList, String fileName,
|
||||
TransparentlyFailedValue<Map<String, Map<String, CharSequence>>, PatchSyntaxException> additionalInfo) {
|
||||
final List<FilePatch> patches;
|
||||
try {
|
||||
patches = ApplyPatchSaveToFileExecutor.patchGroupsToOneGroup(patchGroups, myBaseDir);
|
||||
}
|
||||
catch (IOException e) {
|
||||
myInner.handleException(e, true);
|
||||
return;
|
||||
}
|
||||
|
||||
final PatchApplier<BinaryFilePatch> patchApplier =
|
||||
new PatchApplier<BinaryFilePatch>(myVcs.getProject(), myBaseDir, patches, localList, null, null);
|
||||
patchApplier.scheduleSelf(false, myInner, true); // 3
|
||||
boolean thereAreCreations = false;
|
||||
for (FilePatch patch : patches) {
|
||||
if (patch.isNewFile() || ! Comparing.equal(patch.getAfterName(), patch.getBeforeName())) {
|
||||
thereAreCreations = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (thereAreCreations) {
|
||||
// restore deletion of old directory:
|
||||
myInner.next(new DirectoryAddition()); // 2
|
||||
}
|
||||
appendResolveConflictToContext(myInner); // 1
|
||||
appendTailToContextLast(myInner); // 4
|
||||
myInner.ping();
|
||||
}
|
||||
}
|
||||
|
||||
private class DirectoryAddition extends TaskDescriptor {
|
||||
private DirectoryAddition() {
|
||||
super("Adding " + myOldPresentation + " to Subversion", Where.POOLED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(ContinuationContext context) {
|
||||
try {
|
||||
myVcs.createWCClient().doAdd(myOldFilePath.getIOFile(), true, true, true, SVNDepth.EMPTY, false, true);
|
||||
}
|
||||
catch (SVNException e) {
|
||||
context.handleException(e, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class PatchCreator extends TaskDescriptor {
|
||||
private PatchCreator() {
|
||||
super("Creating patch for theirs changes", Where.POOLED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(ContinuationContext context) {
|
||||
final Project project = myVcs.getProject();
|
||||
final List<FilePatch> patches;
|
||||
try {
|
||||
patches = IdeaTextPatchBuilder.buildPatch(project, myTheirsChanges, myBaseForPatch.getPath(), false);
|
||||
myTextPatches = ObjectsConvertor.convert(patches, new Convertor<FilePatch, TextFilePatch>() {
|
||||
@Override
|
||||
public TextFilePatch convert(FilePatch o) {
|
||||
return (TextFilePatch)o;
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (VcsException e) {
|
||||
context.handleException(e, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class SelectBinaryFiles extends TaskDescriptor {
|
||||
private SelectBinaryFiles() {
|
||||
super("", Where.AWT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(ContinuationContext context) {
|
||||
if (myTheirsBinaryChanges.isEmpty()) return;
|
||||
final List<Change> converted;
|
||||
try {
|
||||
converted = convertPaths(myTheirsBinaryChanges);
|
||||
}
|
||||
catch (VcsException e) {
|
||||
context.handleException(e, true);
|
||||
return;
|
||||
}
|
||||
if (converted.isEmpty()) return;
|
||||
final Map<FilePath, Change> map = new HashMap<FilePath, Change>();
|
||||
for (Change change : converted) {
|
||||
map.put(ChangesUtil.getFilePath(change), change);
|
||||
}
|
||||
final Collection<FilePath> selected = chooseBinaryFiles(converted, map.keySet());
|
||||
myTheirsBinaryChanges.clear();
|
||||
for (FilePath filePath : selected) {
|
||||
myTheirsBinaryChanges.add(map.get(filePath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class ApplyBinaryChanges extends TaskDescriptor {
|
||||
private ApplyBinaryChanges() {
|
||||
super("", Where.AWT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(final ContinuationContext context) {
|
||||
if (myTheirsBinaryChanges.isEmpty()) return;
|
||||
final Application application = ApplicationManager.getApplication();
|
||||
final VcsException[] exc = new VcsException[1];
|
||||
final List<FilePath> dirtyPaths = new ArrayList<FilePath>();
|
||||
for (final Change change : myTheirsBinaryChanges) {
|
||||
application.runWriteAction(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
if (change.getAfterRevision() != null) {
|
||||
final FilePath file = change.getAfterRevision().getFile();
|
||||
dirtyPaths.add(file);
|
||||
final String parentPath = file.getParentPath().getPath();
|
||||
final VirtualFile parentFile = VfsUtil.createDirectoryIfMissing(parentPath);
|
||||
if (parentFile == null) {
|
||||
context.handleException(new VcsException("Can not create directory: " + parentPath, true), false);
|
||||
return;
|
||||
}
|
||||
final VirtualFile child = parentFile.createChildData(TreeConflictRefreshablePanel.class, file.getName());
|
||||
if (child == null) {
|
||||
context.handleException(new VcsException("Can not create file: " + file.getPath(), true), false);
|
||||
return;
|
||||
}
|
||||
child.setBinaryContent(((BinaryContentRevision) change.getAfterRevision()).getBinaryContent());
|
||||
} else {
|
||||
final FilePath path = change.getBeforeRevision().getFile();
|
||||
dirtyPaths.add(path);
|
||||
final VirtualFile file = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(path.getIOFile());
|
||||
if (file == null) {
|
||||
context.handleException(new VcsException("Can not delete file: " + file.getPath(), true), false);
|
||||
return;
|
||||
}
|
||||
file.delete(TreeConflictRefreshablePanel.class);
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
exc[0] = new VcsException(e);
|
||||
}
|
||||
catch (VcsException e) {
|
||||
exc[0] = e;
|
||||
}
|
||||
}
|
||||
});
|
||||
if (exc[0] != null) {
|
||||
context.handleException(exc[0], true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
VcsDirtyScopeManager.getInstance(myVcs.getProject()).filePathsDirty(dirtyPaths, null);
|
||||
}
|
||||
}
|
||||
|
||||
private Collection<FilePath> chooseBinaryFiles(List<Change> converted, Set<FilePath> paths) {
|
||||
String singleMessage = "";
|
||||
if (paths.size() == 1) {
|
||||
final Change change = converted.get(0);
|
||||
final FileStatus status = change.getFileStatus();
|
||||
final FilePath path = ChangesUtil.getFilePath(change);
|
||||
final String stringPath = TreeConflictRefreshablePanel.filePath(path);
|
||||
if (FileStatus.DELETED.equals(status)) {
|
||||
singleMessage = "Delete binary file " + stringPath + " (according to theirs changes)?";
|
||||
} else if (FileStatus.ADDED.equals(status)) {
|
||||
singleMessage = "Create binary file " + stringPath + " (according to theirs changes)?";
|
||||
} else {
|
||||
singleMessage = "Apply changes to binary file " + stringPath + " (according to theirs changes)?";
|
||||
}
|
||||
}
|
||||
return AbstractVcsHelper.getInstance(myVcs.getProject()).selectFilePathsToProcess(new ArrayList<FilePath>(paths),
|
||||
TreeConflictRefreshablePanel.TITLE, "Select binary files to patch", TreeConflictRefreshablePanel.TITLE,
|
||||
singleMessage, new VcsShowConfirmationOption() {
|
||||
|
||||
@Override
|
||||
public Value getValue() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(Value value) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPersistent() {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private List<Change> convertPaths(List<Change> changesForPatch) throws VcsException {
|
||||
initAddOption();
|
||||
final List<Change> changes = new ArrayList<Change>();
|
||||
for (Change change : changesForPatch) {
|
||||
if (! isUnderOldDir(change, myOldFilePath)) continue;
|
||||
ContentRevision before = null;
|
||||
ContentRevision after = null;
|
||||
if (change.getBeforeRevision() != null) {
|
||||
before = new SimpleContentRevision(change.getBeforeRevision().getContent(),
|
||||
rebasePath(myOldFilePath, myNewFilePath, change.getBeforeRevision().getFile()),
|
||||
change.getBeforeRevision().getRevisionNumber().asString());
|
||||
}
|
||||
if (change.getAfterRevision() != null) {
|
||||
// if addition or move - do not move to the new path
|
||||
if (myAdd && (change.getBeforeRevision() == null || change.isMoved() || change.isRenamed())) {
|
||||
after = change.getAfterRevision();
|
||||
} else {
|
||||
after = new SimpleContentRevision(change.getAfterRevision().getContent(),
|
||||
rebasePath(myOldFilePath, myNewFilePath, change.getAfterRevision().getFile()),
|
||||
change.getAfterRevision().getRevisionNumber().asString());
|
||||
}
|
||||
}
|
||||
changes.add(new Change(before, after));
|
||||
}
|
||||
return changes;
|
||||
}
|
||||
|
||||
private boolean isUnderOldDir(Change change, FilePath path) {
|
||||
if (change.getBeforeRevision() != null) {
|
||||
final boolean isUnder = FileUtil.isAncestor(path.getIOFile(), change.getBeforeRevision().getFile().getIOFile(), true);
|
||||
if (isUnder) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (change.getAfterRevision() != null) {
|
||||
final boolean isUnder = FileUtil.isAncestor(path.getIOFile(), change.getAfterRevision().getFile().getIOFile(), true);
|
||||
if (isUnder) {
|
||||
return isUnder;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private FilePath rebasePath(final FilePath oldBase, final FilePath newBase, final FilePath path) {
|
||||
final String relativePath = FileUtil.getRelativePath(oldBase.getPath(), path.getPath(), File.separatorChar);
|
||||
//if (StringUtil.isEmptyOrSpaces(relativePath)) return path;
|
||||
return ((FilePathImpl) newBase).createChild(relativePath, path.isDirectory());
|
||||
}
|
||||
|
||||
private class PreloadChangesContentsForFile extends TaskDescriptor {
|
||||
private PreloadChangesContentsForFile() {
|
||||
super("Getting base and theirs revisions content", Where.POOLED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(ContinuationContext context) {
|
||||
final SvnContentRevision base = SvnContentRevision.createBaseRevision(myVcs, myNewFilePath, myCommittedRevision.getRevision());
|
||||
final SvnContentRevision remote = SvnContentRevision.createRemote(myVcs, myOldFilePath, SVNRevision.create(
|
||||
myDescription.getSourceRightVersion().getPegRevision()));
|
||||
try {
|
||||
final ContentRevision newBase = new SimpleContentRevision(base.getContent(), myNewFilePath, base.getRevisionNumber().asString());
|
||||
final ContentRevision newRemote = new SimpleContentRevision(remote.getContent(), myNewFilePath, remote.getRevisionNumber().asString());
|
||||
myTheirsChanges.add(new Change(newBase, newRemote));
|
||||
}
|
||||
catch (VcsException e) {
|
||||
context.handleException(e, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class PreloadChangesContentsForDir extends TaskDescriptor {
|
||||
private PreloadChangesContentsForDir() {
|
||||
super("Getting base and theirs revisions content", Where.POOLED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(ContinuationContext context) {
|
||||
final List<Change> changesForPatch;
|
||||
try {
|
||||
final List<CommittedChangeList> lst = loadSvnChangeListsForPatch(myDescription);
|
||||
changesForPatch = CommittedChangesTreeBrowser.collectChanges(lst, true);
|
||||
for (Change change : changesForPatch) {
|
||||
if (change.getBeforeRevision() != null) {
|
||||
preloadRevisionContents(change.getBeforeRevision());
|
||||
}
|
||||
if (change.getAfterRevision() != null) {
|
||||
preloadRevisionContents(change.getAfterRevision());
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (VcsException e) {
|
||||
context.handleException(e, true);
|
||||
return;
|
||||
}
|
||||
final List<Change> binaryChanges = filterOutBinary(changesForPatch);
|
||||
if (binaryChanges != null && ! binaryChanges.isEmpty()) {
|
||||
myTheirsBinaryChanges.addAll(binaryChanges);
|
||||
}
|
||||
if (! changesForPatch.isEmpty()) {
|
||||
myTheirsChanges.addAll(changesForPatch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void preloadRevisionContents(ContentRevision cr) throws VcsException {
|
||||
if (cr instanceof BinaryContentRevision) {
|
||||
((BinaryContentRevision) cr).getBinaryContent();
|
||||
} else {
|
||||
cr.getContent();
|
||||
}
|
||||
}
|
||||
|
||||
private List<CommittedChangeList> loadSvnChangeListsForPatch(SVNTreeConflictDescription description) throws VcsException {
|
||||
long max = description.getSourceRightVersion().getPegRevision();
|
||||
long min = description.getSourceLeftVersion().getPegRevision();
|
||||
|
||||
final ChangeBrowserSettings settings = new ChangeBrowserSettings();
|
||||
settings.USE_CHANGE_BEFORE_FILTER = settings.USE_CHANGE_AFTER_FILTER = true;
|
||||
settings.CHANGE_BEFORE = "" + max;
|
||||
settings.CHANGE_AFTER = "" + min;
|
||||
final List<SvnChangeList> committedChanges = myVcs.getCachingCommittedChangesProvider().getCommittedChanges(
|
||||
settings, new SvnRepositoryLocation(description.getSourceRightVersion().getRepositoryRoot().toString()), 0);
|
||||
final List<CommittedChangeList> lst = new ArrayList<CommittedChangeList>(committedChanges.size() - 1);
|
||||
for (SvnChangeList change : committedChanges) {
|
||||
if (change.getNumber() == min) {
|
||||
continue;
|
||||
}
|
||||
lst.add(change);
|
||||
}
|
||||
return lst;
|
||||
}
|
||||
|
||||
private void initAddOption() {
|
||||
ApplicationManager.getApplication().assertIsDispatchThread();
|
||||
if (myAdd == null) {
|
||||
myAdd = getAddedFilesPlaceOption();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean getAddedFilesPlaceOption() {
|
||||
final SvnConfiguration configuration = SvnConfiguration.getInstance(myVcs.getProject());
|
||||
boolean add = Boolean.TRUE.equals(configuration.TREE_CONFLICT_MERGE_THEIRS_NEW_INTO_OLD_PLACE);
|
||||
if (configuration.TREE_CONFLICT_MERGE_THEIRS_NEW_INTO_OLD_PLACE == null) {
|
||||
if (! containAdditions(myTheirsChanges) && ! containAdditions(myTheirsBinaryChanges)) return false;
|
||||
final int i = Messages.showYesNoDialog("Keep newly created file(s) in their original place?", TreeConflictRefreshablePanel.TITLE, "Keep", "Move",
|
||||
Messages.getQuestionIcon(), new DialogWrapper.DoNotAskOption() {
|
||||
@Override
|
||||
public boolean isToBeShown() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setToBeShown(boolean value, int exitCode) {
|
||||
if (!value) {
|
||||
if (exitCode == 0) {
|
||||
// yes
|
||||
configuration.TREE_CONFLICT_MERGE_THEIRS_NEW_INTO_OLD_PLACE = true;
|
||||
}
|
||||
else {
|
||||
configuration.TREE_CONFLICT_MERGE_THEIRS_NEW_INTO_OLD_PLACE = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canBeHidden() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldSaveOptionsOnCancel() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDoNotShowMessage() {
|
||||
return CommonBundle.message("dialog.options.do.not.ask");
|
||||
}
|
||||
});
|
||||
add = Messages.YES == i;
|
||||
}
|
||||
return add;
|
||||
}
|
||||
|
||||
private boolean containAdditions(final List<Change> changes) {
|
||||
boolean addFound = false;
|
||||
for (Change change : changes) {
|
||||
if (change.getBeforeRevision() == null || change.isMoved() || change.isRenamed()) {
|
||||
addFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return addFound;
|
||||
}
|
||||
}
|
||||
+5
-124
@@ -16,10 +16,9 @@
|
||||
package org.jetbrains.idea.svn.treeConflict;
|
||||
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.application.Application;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diff.impl.patch.BinaryFilePatch;
|
||||
import com.intellij.openapi.diff.impl.patch.FilePatch;
|
||||
import com.intellij.openapi.diff.impl.patch.IdeaTextPatchBuilder;
|
||||
import com.intellij.openapi.diff.impl.patch.*;
|
||||
import com.intellij.openapi.diff.impl.patch.formove.PatchApplier;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.progress.BackgroundTaskQueue;
|
||||
@@ -36,16 +35,16 @@ import com.intellij.openapi.vcs.FilePath;
|
||||
import com.intellij.openapi.vcs.FilePathImpl;
|
||||
import com.intellij.openapi.vcs.VcsException;
|
||||
import com.intellij.openapi.vcs.changes.*;
|
||||
import com.intellij.openapi.vcs.changes.committed.CommittedChangesTreeBrowser;
|
||||
import com.intellij.openapi.vcs.changes.patch.*;
|
||||
import com.intellij.openapi.vcs.history.*;
|
||||
import com.intellij.openapi.vcs.ui.VcsBalloonProblemNotifier;
|
||||
import com.intellij.openapi.vcs.versionBrowser.ChangeBrowserSettings;
|
||||
import com.intellij.openapi.vcs.versionBrowser.CommittedChangeList;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.BeforeAfter;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.containers.Convertor;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import com.intellij.util.continuation.*;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import com.intellij.util.ui.VcsBackgroundTask;
|
||||
@@ -403,87 +402,7 @@ public class TreeConflictRefreshablePanel extends AbstractRefreshablePanel {
|
||||
return new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
final FilePath oldFilePath = myChange.getBeforeRevision().getFile();
|
||||
final FilePath newFilePath = myChange.getAfterRevision().getFile();
|
||||
int ok = Messages.showOkCancelDialog(myVcs.getProject(),
|
||||
(myChange.isMoved() ?
|
||||
SvnBundle.message("confirmation.resolve.tree.conflict.merge.moved", filePath(oldFilePath),
|
||||
filePath(newFilePath)) :
|
||||
SvnBundle.message("confirmation.resolve.tree.conflict.merge.renamed", filePath(oldFilePath),
|
||||
filePath(newFilePath))),
|
||||
TITLE, Messages.getQuestionIcon());
|
||||
if (Messages.OK != ok) return;
|
||||
|
||||
FileDocumentManager.getInstance().saveAllDocuments();
|
||||
final String name = "Merge changes from theirs for: " + filePath(oldFilePath);
|
||||
|
||||
final GatheringContinuationContext cc = new GatheringContinuationContext();
|
||||
cc.addExceptionHandler(VcsException.class, new Consumer<VcsException>() {
|
||||
@Override
|
||||
public void consume(VcsException e) {
|
||||
AbstractVcsHelper.getInstance(myVcs.getProject()).showErrors(Collections.singletonList(e), name);
|
||||
}
|
||||
});
|
||||
cc.next(new TaskDescriptor("Creating patch for theirs changes", Where.POOLED) {
|
||||
@Override
|
||||
public void run(ContinuationContext context) {
|
||||
try {
|
||||
ProgressManager.progress("Getting base and theirs revisions content");
|
||||
final List<Change> changes = new SmartList<Change>();
|
||||
|
||||
if (SVNNodeKind.DIR.equals(description.getNodeKind())) {
|
||||
long max = description.getSourceRightVersion().getPegRevision();
|
||||
long min = description.getSourceLeftVersion().getPegRevision();
|
||||
|
||||
final ChangeBrowserSettings settings = new ChangeBrowserSettings();
|
||||
settings.USE_CHANGE_BEFORE_FILTER = settings.USE_CHANGE_AFTER_FILTER = true;
|
||||
settings.CHANGE_BEFORE = "" + max;
|
||||
settings.CHANGE_AFTER = "" + min;
|
||||
final List<SvnChangeList> committedChanges = myVcs.getCachingCommittedChangesProvider().getCommittedChanges(
|
||||
settings, new SvnRepositoryLocation(description.getSourceRightVersion().getRepositoryRoot().toString()), 0);
|
||||
final List<CommittedChangeList> lst = new ArrayList<CommittedChangeList>(committedChanges.size() - 1);
|
||||
for (SvnChangeList change : committedChanges) {
|
||||
if (change.getNumber() == min) {
|
||||
continue;
|
||||
}
|
||||
lst.add(change);
|
||||
}
|
||||
final List<Change> changesForPatch = CommittedChangesTreeBrowser.collectChanges(lst, true);
|
||||
for (Change change : changesForPatch) {
|
||||
if (! isUnderOldDir(change, oldFilePath)) continue;
|
||||
ContentRevision before = null;
|
||||
ContentRevision after = null;
|
||||
if (change.getBeforeRevision() != null) {
|
||||
before = new SimpleContentRevision(change.getBeforeRevision().getContent(),
|
||||
rebasePath(oldFilePath, newFilePath, change.getBeforeRevision().getFile()),
|
||||
change.getBeforeRevision().getRevisionNumber().asString());
|
||||
}
|
||||
if (change.getAfterRevision() != null) {
|
||||
after = new SimpleContentRevision(change.getAfterRevision().getContent(),
|
||||
rebasePath(oldFilePath, newFilePath, change.getAfterRevision().getFile()),
|
||||
change.getAfterRevision().getRevisionNumber().asString());
|
||||
}
|
||||
changes.add(new Change(before, after));
|
||||
}
|
||||
} else {
|
||||
final SvnContentRevision base = SvnContentRevision.createBaseRevision(myVcs, newFilePath, myCommittedRevision.getRevision());
|
||||
final SvnContentRevision remote = SvnContentRevision.createRemote(myVcs, oldFilePath,
|
||||
SVNRevision.create(
|
||||
description.getSourceRightVersion().getPegRevision()));
|
||||
final ContentRevision newBase = new SimpleContentRevision(base.getContent(), newFilePath, base.getRevisionNumber().asString());
|
||||
final ContentRevision newRemote = new SimpleContentRevision(remote.getContent(), newFilePath, remote.getRevisionNumber().asString());
|
||||
changes.add(new Change(newBase, newRemote));
|
||||
}
|
||||
|
||||
mergeFromTheirs(context, newFilePath, oldFilePath, description, changes);
|
||||
}
|
||||
catch (VcsException e1) {
|
||||
context.handleException(e1);
|
||||
}
|
||||
}
|
||||
});
|
||||
final Continuation fragmented = Continuation.createFragmented(myVcs.getProject(), false);
|
||||
fragmented.run(cc.getList());
|
||||
new MergeFromTheirsResolver(myVcs, description, myChange, myCommittedRevision).execute();
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -510,44 +429,6 @@ public class TreeConflictRefreshablePanel extends AbstractRefreshablePanel {
|
||||
return ((FilePathImpl) newBase).createChild(relativePath, path.isDirectory());
|
||||
}
|
||||
|
||||
private void mergeFromTheirs(ContinuationContext context, final FilePath newFilePath, final FilePath oldFilePath,
|
||||
final SVNTreeConflictDescription description, final List<Change> changes) throws VcsException {
|
||||
|
||||
ProgressManager.progress("Creating patch for theirs changes");
|
||||
final VirtualFile baseForPatch = ApplicationManager.getApplication().runReadAction(new Computable<VirtualFile>() {
|
||||
@Override
|
||||
public VirtualFile compute() {
|
||||
return ChangesUtil.findValidParent(newFilePath);
|
||||
}
|
||||
});
|
||||
final Project project = myVcs.getProject();
|
||||
final List<FilePatch> patches = IdeaTextPatchBuilder.buildPatch(project, changes, baseForPatch.getPath(), false);
|
||||
|
||||
ProgressManager.progress("Applying patch to " + newFilePath.getPath());
|
||||
final ChangeListManager clManager = ChangeListManager.getInstance(project);
|
||||
final LocalChangeList changeList = clManager.getChangeList(myChange);
|
||||
final PatchApplier<BinaryFilePatch> patchApplier =
|
||||
new PatchApplier<BinaryFilePatch>(project, baseForPatch, patches, changeList, null, null);
|
||||
patchApplier.scheduleSelf(false, context, true);
|
||||
context.last(new TaskDescriptor("Accepting working state", Where.POOLED) {
|
||||
@Override
|
||||
public void run(ContinuationContext context) {
|
||||
try {
|
||||
new SvnTreeConflictResolver(myVcs, oldFilePath, myCommittedRevision, null).resolveSelectMineFull(description);
|
||||
}
|
||||
catch (VcsException e1) {
|
||||
context.handleException(e1);
|
||||
}
|
||||
}
|
||||
});
|
||||
context.last(new TaskDescriptor("", Where.AWT) {
|
||||
@Override
|
||||
public void run(ContinuationContext context) {
|
||||
VcsBalloonProblemNotifier.showOverChangesView(myVcs.getProject(), "Theirs changes merged for " + filePath(myPath), MessageType.INFO);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static String filePath(FilePath newFilePath) {
|
||||
return newFilePath.getName() +
|
||||
" (" +
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
<SOURCES />
|
||||
</library>
|
||||
</orderEntry>
|
||||
<orderEntry type="module-library" scope="RUNTIME">
|
||||
<orderEntry type="module-library">
|
||||
<library>
|
||||
<CLASSES>
|
||||
<root url="jar://$MODULE_DIR$/lib/sqljet.jar!/" />
|
||||
|
||||
Reference in New Issue
Block a user