Merge remote-tracking branch 'origin/master'

This commit is contained in:
Dmitry Jemerov
2012-05-21 14:26:56 +02:00
31 changed files with 1031 additions and 241 deletions
@@ -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.
}
};
}
}
}
@@ -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");
@@ -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);
}
@@ -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);
}
@@ -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) {
@@ -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);
@@ -47,7 +47,7 @@ public class GatheringContinuationContext implements ContinuationContext {
}
@Override
public boolean handleException(Exception e) {
public boolean handleException(Exception e, boolean cancelEveryThing) {
return false;
}
@@ -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);
}
}
@@ -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();
}
@@ -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()), '/');
}
}
@@ -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;
}
}
@@ -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() +
" (" +
+1 -1
View File
@@ -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!/" />