diff --git a/bin/mac/libbreakgen.jnilib b/bin/mac/libbreakgen.jnilib index bfbdee970594..00c7ad5a7bae 100644 Binary files a/bin/mac/libbreakgen.jnilib and b/bin/mac/libbreakgen.jnilib differ diff --git a/bin/mac/libbreakgen64.jnilib b/bin/mac/libbreakgen64.jnilib index 3a0315471849..9389a53a215f 100644 Binary files a/bin/mac/libbreakgen64.jnilib and b/bin/mac/libbreakgen64.jnilib differ diff --git a/java/execution/impl/src/com/intellij/execution/runners/ProcessProxyFactoryImpl.java b/java/execution/impl/src/com/intellij/execution/runners/ProcessProxyFactoryImpl.java index e8764d29657d..6af48770e78d 100644 --- a/java/execution/impl/src/com/intellij/execution/runners/ProcessProxyFactoryImpl.java +++ b/java/execution/impl/src/com/intellij/execution/runners/ProcessProxyFactoryImpl.java @@ -54,7 +54,16 @@ public class ProcessProxyFactoryImpl extends ProcessProxyFactory { @Override public boolean isBreakGenLibraryAvailable() { - @NonNls final String libName = SystemInfo.isWindows ? "breakgen.dll" : "libbreakgen.so"; + @NonNls final String libName; + if (SystemInfo.isWindows) { + libName = "breakgen.dll"; + } + else if (SystemInfo.isMac) { + libName = "libbreakgen.jnilib"; + } + else { + libName = "libbreakgen.so"; + } return new File(PathManager.getBinPath() + File.separator + libName).exists(); } } \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/GenerateConstructorHandler.java b/java/java-impl/src/com/intellij/codeInsight/generation/GenerateConstructorHandler.java index 0419d0b848c5..39e6d067c411 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/GenerateConstructorHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/GenerateConstructorHandler.java @@ -84,7 +84,7 @@ public class GenerateConstructorHandler extends GenerateMembersHandlerBase { if (baseClass != null){ ArrayList array = new ArrayList(); for (PsiMethod method : baseClass.getConstructors()) { - if (JavaPsiFacade.getInstance(method.getProject()).getResolveHelper().isAccessible(method, aClass, aClass)) { + if (JavaPsiFacade.getInstance(method.getProject()).getResolveHelper().isAccessible(method, aClass, null)) { array.add(method); } } diff --git a/java/java-impl/src/com/intellij/codeInspection/actions/UnimplementInterfaceAction.java b/java/java-impl/src/com/intellij/codeInspection/actions/UnimplementInterfaceAction.java index d0ac9310e4c4..9275c149ac0f 100644 --- a/java/java-impl/src/com/intellij/codeInspection/actions/UnimplementInterfaceAction.java +++ b/java/java-impl/src/com/intellij/codeInspection/actions/UnimplementInterfaceAction.java @@ -21,12 +21,18 @@ import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.psi.*; +import com.intellij.psi.util.MethodSignature; +import com.intellij.psi.util.MethodSignatureUtil; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.TypeConversionUtil; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.containers.HashMap; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.Collections; import java.util.HashSet; +import java.util.Map; import java.util.Set; public class UnimplementInterfaceAction implements IntentionAction { @@ -55,7 +61,10 @@ public class UnimplementInterfaceAction implements IntentionAction { if (psiClass.getExtendsList() != referenceList && psiClass.getImplementsList() != referenceList) return false; - final PsiElement target = psiReference.resolve(); + PsiJavaCodeReferenceElement referenceElement = getTopLevelRef(psiReference, referenceList); + if (referenceElement == null) return false; + + final PsiElement target = referenceElement.resolve(); if (target == null || !(target instanceof PsiClass)) return false; PsiClass targetClass = (PsiClass)target; @@ -69,6 +78,18 @@ public class UnimplementInterfaceAction implements IntentionAction { return true; } + @Nullable + private static PsiJavaCodeReferenceElement getTopLevelRef(PsiReference psiReference, PsiReferenceList referenceList) { + PsiElement element = psiReference.getElement(); + while (element.getParent() != referenceList) { + element = element.getParent(); + if (element == null) return null; + } + + if (!(element instanceof PsiJavaCodeReferenceElement)) return null; + return (PsiJavaCodeReferenceElement)element; + } + public void invoke(@NotNull final Project project, final Editor editor, final PsiFile file) throws IncorrectOperationException { if (!CodeInsightUtilBase.preparePsiElementForWrite(file)) return; @@ -83,12 +104,22 @@ public class UnimplementInterfaceAction implements IntentionAction { if (psiClass.getExtendsList() != referenceList && psiClass.getImplementsList() != referenceList) return; - final PsiElement target = psiReference.resolve(); + PsiJavaCodeReferenceElement element = getTopLevelRef(psiReference, referenceList); + if (element == null) return; + + final PsiElement target = element.resolve(); if (target == null || !(target instanceof PsiClass)) return; PsiClass targetClass = (PsiClass)target; - psiReference.getElement().delete(); + final Map implementations = new HashMap(); + for (PsiMethod psiMethod : targetClass.getAllMethods()) { + final PsiMethod implementingMethod = MethodSignatureUtil.findMethodBySuperMethod(psiClass, psiMethod, false); + if (implementingMethod != null) { + implementations.put(psiMethod, implementingMethod); + } + } + element.delete(); final Set superMethods = new HashSet(); for (PsiClass aClass : psiClass.getSupers()) { @@ -97,10 +128,8 @@ public class UnimplementInterfaceAction implements IntentionAction { final PsiMethod[] psiMethods = targetClass.getAllMethods(); for (PsiMethod psiMethod : psiMethods) { if (superMethods.contains(psiMethod)) continue; - final PsiMethod[] implementingMethods = psiClass.findMethodsBySignature(psiMethod, false); - for (PsiMethod implementingMethod : implementingMethods) { - implementingMethod.delete(); - } + final PsiMethod impl = implementations.get(psiMethod); + if (impl != null) impl.delete(); } } diff --git a/java/java-impl/src/com/intellij/refactoring/copy/CopyClassesHandler.java b/java/java-impl/src/com/intellij/refactoring/copy/CopyClassesHandler.java index 52b10badd94e..844837ab418c 100644 --- a/java/java-impl/src/com/intellij/refactoring/copy/CopyClassesHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/copy/CopyClassesHandler.java @@ -125,7 +125,7 @@ public class CopyClassesHandler implements CopyHandlerDelegate { CopyClassDialog dialog = new CopyClassDialog(classes.values().iterator().next()[0], defaultTargetDirectory, project, false){ @Override protected String getQualifiedName() { - if (commonPath != null) { + if (commonPath != null && !commonPath.isEmpty()) { return StringUtil.getQualifiedName(super.getQualifiedName(), commonPath.replaceAll("/", ".")); } return super.getQualifiedName(); diff --git a/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MoveClassesOrPackagesHandlerBase.java b/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MoveClassesOrPackagesHandlerBase.java index 7deacc03e155..ec86a76f7c96 100644 --- a/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MoveClassesOrPackagesHandlerBase.java +++ b/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MoveClassesOrPackagesHandlerBase.java @@ -34,6 +34,7 @@ import com.intellij.refactoring.JavaRefactoringSettings; import com.intellij.refactoring.RefactoringBundle; import com.intellij.refactoring.move.MoveCallback; import com.intellij.refactoring.move.MoveHandlerDelegate; +import com.intellij.refactoring.move.moveFilesOrDirectories.MoveFilesOrDirectoriesUtil; import com.intellij.refactoring.util.CommonRefactoringUtil; import com.intellij.refactoring.util.RadioUpDownListener; import com.intellij.refactoring.util.RefactoringUtil; @@ -131,8 +132,13 @@ public class MoveClassesOrPackagesHandlerBase extends MoveHandlerDelegate { processor.run(); } else { + final boolean containsJava = hasJavaFiles(directories[0]); + if (!containsJava) { + MoveFilesOrDirectoriesUtil.doMove(project, new PsiElement[] {directories[0]}, new PsiElement[]{targetContainer}, callback); + return; + } final MoveClassesOrPackagesToNewDirectoryDialog dlg = - new MoveClassesOrPackagesToNewDirectoryDialog(directories[0], new PsiElement[2], false, callback) { + new MoveClassesOrPackagesToNewDirectoryDialog(directories[0], new PsiElement[0], false, callback) { @Override protected void performRefactoring(Project project, final PsiDirectory targetDirectory, @@ -161,6 +167,25 @@ public class MoveClassesOrPackagesHandlerBase extends MoveHandlerDelegate { MoveClassesOrPackagesImpl.doMove(project, elements, targetContainer, callback); } + public static boolean hasJavaFiles(PsiDirectory directory) { + final boolean [] containsJava = new boolean[]{false}; + directory.accept(new JavaRecursiveElementWalkingVisitor() { + @Override + public void visitElement(PsiElement element) { + if (containsJava[0]) return; + if (element instanceof PsiFile || element instanceof PsiDirectory) { + super.visitElement(element); + } + } + + @Override + public void visitJavaFile(PsiJavaFile file) { + containsJava[0] = true; + } + }); + return containsJava[0]; + } + @Override public PsiElement adjustTargetForMove(DataContext dataContext, PsiElement targetContainer) { if (targetContainer instanceof PsiPackage) { diff --git a/java/java-impl/src/com/intellij/refactoring/move/moveFilesOrDirectories/JavaMoveFilesOrDirectoriesHandler.java b/java/java-impl/src/com/intellij/refactoring/move/moveFilesOrDirectories/JavaMoveFilesOrDirectoriesHandler.java index 91c1f33c0c21..0412ec0d99d7 100644 --- a/java/java-impl/src/com/intellij/refactoring/move/moveFilesOrDirectories/JavaMoveFilesOrDirectoriesHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/move/moveFilesOrDirectories/JavaMoveFilesOrDirectoriesHandler.java @@ -24,6 +24,7 @@ import com.intellij.psi.impl.file.JavaDirectoryServiceImpl; import com.intellij.psi.util.PsiUtilBase; import com.intellij.refactoring.copy.JavaCopyFilesOrDirectoriesHandler; import com.intellij.refactoring.move.MoveCallback; +import com.intellij.refactoring.move.moveClassesOrPackages.MoveClassesOrPackagesHandlerBase; import com.intellij.util.ArrayUtil; import com.intellij.util.Function; import com.intellij.util.IncorrectOperationException; @@ -41,6 +42,7 @@ public class JavaMoveFilesOrDirectoriesHandler extends MoveFilesOrDirectoriesHan for (PsiElement element : srcElements) { if (element instanceof PsiDirectory) { allJava &= JavaCopyFilesOrDirectoriesHandler.hasPackages((PsiDirectory)element); + allJava &= MoveClassesOrPackagesHandlerBase.hasJavaFiles((PsiDirectory)element); } else if (element instanceof PsiFile) { allJava &= element instanceof PsiJavaFile && !JspPsiUtil.isInJspFile(element) && diff --git a/java/java-runtime/src/com/intellij/rt/execution/application/AppMain.java b/java/java-runtime/src/com/intellij/rt/execution/application/AppMain.java index 09e6dd5f12aa..1d723e246cae 100644 --- a/java/java-runtime/src/com/intellij/rt/execution/application/AppMain.java +++ b/java/java-runtime/src/com/intellij/rt/execution/application/AppMain.java @@ -38,20 +38,28 @@ public class AppMain { static { String binPath = System.getProperty(PROPERTY_BINPATH) + File.separator; final String osName = System.getProperty("os.name").toLowerCase(); + String arch = System.getProperty("os.arch").toLowerCase(); String libPath = null; if (osName.startsWith("windows")) { - if (System.getProperty("os.arch").equals("amd64")) { + if (arch.equals("amd64")) { libPath = binPath + "breakgen64.dll"; } else { libPath = binPath + "breakgen.dll"; } } else if (osName.startsWith("linux")) { - if (System.getProperty("os.arch").toLowerCase().equals("amd64")) { + if (arch.equals("amd64")) { libPath = binPath + "libbreakgen64.so"; } else { libPath = binPath + "libbreakgen.so"; } + } else if (osName.startsWith("mac")) { + if (arch.endsWith("64")) { + libPath = binPath + "libbreakgen64.jnilib"; + } else { + libPath = binPath + "libbreakgen.jnilib"; + } + } try { if (libPath != null) { @@ -59,7 +67,9 @@ public class AppMain { } } catch (UnsatisfiedLinkError e) { - //Do nothing, unknown os or some other error => no ctrl-break is available + if (new File(libPath).exists() && osName.startsWith("mac")) { + e.printStackTrace(); + } } } @@ -86,19 +96,16 @@ public class AppMain { System.exit(1); } } - } catch (IOException e) { - return; - } catch (IllegalArgumentException iae) { - return; - } catch (SecurityException se) { - return; + } catch (IOException ignored) { + } catch (IllegalArgumentException ignored) { + } catch (SecurityException ignored) { } } }, "Monitor Ctrl-Break"); try { t.setDaemon(true); t.start(); - } catch (Exception e) {} + } catch (Exception ignored) {} String mainClass = args[0]; String[] parms = new String[args.length - 1]; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unimplement/afterGenerics.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unimplement/afterGenerics.java new file mode 100644 index 000000000000..e050a74b282b --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unimplement/afterGenerics.java @@ -0,0 +1,11 @@ +// "Unimplement Interface" "true" +class A { + public String toString() { + return super.toString(); + } + +} + +interface II { + void foo(T ty); +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unimplement/beforeGenerics.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unimplement/beforeGenerics.java new file mode 100644 index 000000000000..efeddf023d92 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unimplement/beforeGenerics.java @@ -0,0 +1,12 @@ +// "Unimplement Interface" "true" +class A implements IItring> { + public String toString() { + return super.toString(); + } + + public void foo(String ty){} +} + +interface II { + void foo(T ty); +} \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/application/options/colors/FontEditorPreview.java b/platform/lang-impl/src/com/intellij/application/options/colors/FontEditorPreview.java index e862f5619662..ae8841587790 100644 --- a/platform/lang-impl/src/com/intellij/application/options/colors/FontEditorPreview.java +++ b/platform/lang-impl/src/com/intellij/application/options/colors/FontEditorPreview.java @@ -47,26 +47,13 @@ public class FontEditorPreview implements PreviewPanel{ } public static String getIDEDemoText() { - String name = ApplicationNamesInfo.getInstance().getFullProductName(); - String language = getLanguage(name); // HACK return - name + " is a full-featured " + language + " IDE\n" + + ApplicationNamesInfo.getInstance().getFullProductName() + + " is a full-featured IDE\n" + "with a high level of usability and outstanding\n" + "advanced code editing and refactoring support.\n"; } - private static String getLanguage(String name) { - if (name.contains("RubyMine")) { - return "Ruby"; - } - - if (name.contains("PyCharm")) { - return "Python"; - } - - return "Java"; - } - static void installTrafficLights(EditorEx editor) { ErrorStripeRenderer renderer = new TrafficLightRenderer(null,null,null,null){ protected DaemonCodeAnalyzerStatus getDaemonCodeAnalyzerStatus(boolean fillErrorsCount, SeverityRegistrar severityRegistrar) { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupCellRenderer.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupCellRenderer.java index bbba75b5f69b..d4d3fa967e6b 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupCellRenderer.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupCellRenderer.java @@ -24,10 +24,13 @@ import com.intellij.ide.ui.UISettings; import com.intellij.openapi.editor.colors.EditorColorsManager; import com.intellij.openapi.editor.colors.EditorColorsScheme; import com.intellij.openapi.editor.colors.EditorFontType; +import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.codeStyle.NameUtil; import com.intellij.ui.LayeredIcon; import com.intellij.ui.SimpleColoredComponent; import com.intellij.ui.SimpleTextAttributes; +import com.intellij.ui.speedSearch.SpeedSearchUtil; import com.intellij.util.ui.EmptyIcon; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; @@ -236,26 +239,25 @@ public class LookupCellRenderer implements ListCellRenderer { return used; } - void renderItemName(LookupElement item, + private void renderItemName(LookupElement item, Color foreground, boolean selected, int style, String name, final SimpleColoredComponent nameComponent) { - final SimpleTextAttributes baseAttrs = new SimpleTextAttributes(style, foreground); + final SimpleTextAttributes base = new SimpleTextAttributes(style, foreground); final String prefix = myLookup.itemPrefix(item); - if (prefix.length() > 0){ - final int i = StringUtil.indexOfIgnoreCase(name, prefix, 0); - if (i >= 0 && !(item instanceof EmptyLookupItem)) { - nameComponent.append(name.substring(0, i), baseAttrs); - nameComponent.append(name.substring(i, i + prefix.length()), - new SimpleTextAttributes(style, selected ? SELECTED_PREFIX_FOREGROUND_COLOR : PREFIX_FOREGROUND_COLOR)); - nameComponent.append(name.substring(i + prefix.length()), baseAttrs); + if (prefix.length() > 0) { + Iterable ranges = new NameUtil.MinusculeMatcher("*" + prefix, NameUtil.MatchingCaseSensitivity.NONE).matchingFragments(name); + if (ranges != null) { + SimpleTextAttributes highlighted = + new SimpleTextAttributes(style, selected ? SELECTED_PREFIX_FOREGROUND_COLOR : PREFIX_FOREGROUND_COLOR); + SpeedSearchUtil.appendColoredFragments(nameComponent, name, ranges, base, highlighted); return; } } - nameComponent.append(name, baseAttrs); + nameComponent.append(name, base); } private int setTypeTextLabel(LookupElement item, diff --git a/platform/lang-impl/src/com/intellij/execution/console/ConsoleHistoryController.java b/platform/lang-impl/src/com/intellij/execution/console/ConsoleHistoryController.java index 04abc29cb262..d66706965d60 100644 --- a/platform/lang-impl/src/com/intellij/execution/console/ConsoleHistoryController.java +++ b/platform/lang-impl/src/com/intellij/execution/console/ConsoleHistoryController.java @@ -29,8 +29,8 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.CaretModel; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.ScrollType; import com.intellij.openapi.editor.actions.ContentChooser; -import com.intellij.openapi.editor.ex.EditorEx; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ex.ProjectEx; import com.intellij.openapi.util.Disposer; @@ -120,9 +120,9 @@ public class ConsoleHistoryController { myHistoryNext.registerCustomShortcutSet(KeyEvent.VK_UP, 0, null); myHistoryPrev.registerCustomShortcutSet(KeyEvent.VK_DOWN, 0, null); } - myHistoryNext.registerCustomShortcutSet(myHistoryNext.getShortcutSet(), myConsole.getConsoleEditor().getComponent()); - myHistoryPrev.registerCustomShortcutSet(myHistoryPrev.getShortcutSet(), myConsole.getConsoleEditor().getComponent()); - myBrowseHistory.registerCustomShortcutSet(myBrowseHistory.getShortcutSet(), myConsole.getConsoleEditor().getComponent()); + myHistoryNext.registerCustomShortcutSet(myHistoryNext.getShortcutSet(), myConsole.getCurrentEditor().getComponent()); + myHistoryPrev.registerCustomShortcutSet(myHistoryPrev.getShortcutSet(), myConsole.getCurrentEditor().getComponent()); + myBrowseHistory.registerCustomShortcutSet(myBrowseHistory.getShortcutSet(), myConsole.getCurrentEditor().getComponent()); } private File getFile() { @@ -214,12 +214,13 @@ public class ConsoleHistoryController { } protected void actionTriggered(final String command) { - final Editor editor = myConsole.getConsoleEditor(); + final Editor editor = myConsole.getCurrentEditor(); final Document document = editor.getDocument(); new WriteCommandAction(myConsole.getProject(), myConsole.getFile()) { protected void run(final Result result) throws Throwable { document.setText(StringUtil.notNullize(command)); editor.getCaretModel().moveToOffset(document.getTextLength()); + editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); } }.execute(); } @@ -247,7 +248,7 @@ public class ConsoleHistoryController { } private boolean canMoveInEditor(final boolean next) { - final EditorEx consoleEditor = myConsole.getConsoleEditor(); + final Editor consoleEditor = myConsole.getCurrentEditor(); final Document document = consoleEditor.getDocument(); final CaretModel caretModel = consoleEditor.getCaretModel(); @@ -283,7 +284,7 @@ public class ConsoleHistoryController { } private void saveHistory(final XmlSerializer out) throws IOException { - out.startDocument(null, null); + out.startDocument(System.getProperty("file.encoding"), null); out.startTag(null, "console-history"); out.attribute(null, "id", myId); for (String s : myModel.getHistory()) { diff --git a/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java b/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java index b8d9a8af9e27..84a174bd6ed7 100644 --- a/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java @@ -293,7 +293,8 @@ public class LanguageConsoleImpl implements Disposable, TypeSafeDataProvider { } public void setPrompt(String prompt) { - myPrompt = prompt; + // always add space to the prompt otherwise it may look ugly + myPrompt = prompt != null && !prompt.endsWith(" ")? prompt + " " : prompt; setPromptInner(myPrompt); } @@ -369,7 +370,6 @@ public class LanguageConsoleImpl implements Disposable, TypeSafeDataProvider { public String addCurrentToHistory(final TextRange textRange, final boolean erase, final boolean preserveMarkup) { final Ref ref = Ref.create(""); - final boolean scrollToEnd = shouldScrollHistoryToEnd(); final Runnable action = new Runnable() { public void run() { ref.set(addTextRangeToHistory(textRange, myConsoleEditor, preserveMarkup)); @@ -384,10 +384,9 @@ public class LanguageConsoleImpl implements Disposable, TypeSafeDataProvider { else { ApplicationManager.getApplication().runReadAction(action); } - if (scrollToEnd) { - scrollHistoryToEnd(); - } - queueUiUpdate(scrollToEnd); + // always scroll to end on user input + scrollHistoryToEnd(); + queueUiUpdate(true); return ref.get(); } diff --git a/platform/lang-impl/src/com/intellij/find/FindUtil.java b/platform/lang-impl/src/com/intellij/find/FindUtil.java index 8d830f886b2b..15d2712b1db7 100644 --- a/platform/lang-impl/src/com/intellij/find/FindUtil.java +++ b/platform/lang-impl/src/com/intellij/find/FindUtil.java @@ -95,6 +95,34 @@ public class FindUtil { } } + public static void configureFindModel(boolean replace, Editor editor, FindModel model) { + String selectedText = editor.getSelectionModel().getSelectedText(); + model.setReplaceState(replace); + if (selectedText != null) { + if (replace) { + if (!StringUtil.isEmpty(selectedText)) { + if (selectedText.indexOf('\n') >= 0) { + model.setGlobal(false); + } + else { + model.setStringToFind(selectedText); + model.setGlobal(true); + } + } else { + model.setGlobal(true); + } + } else { + model.setStringToFind(selectedText); + model.setGlobal(true); + } + + if (model.isGlobal()) { + model.setStringToFind(selectedText); + } + } + model.setPromptOnReplace(false); + } + private enum Direction { UP, DOWN } diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/SwitchToFind.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/SwitchToFind.java index 211f6d81d56c..6ac05693cb50 100644 --- a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/SwitchToFind.java +++ b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/SwitchToFind.java @@ -1,6 +1,8 @@ package com.intellij.find.editorHeaderActions; import com.intellij.find.EditorSearchComponent; +import com.intellij.find.FindModel; +import com.intellij.find.FindUtil; import com.intellij.openapi.actionSystem.ActionManager; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; @@ -24,6 +26,7 @@ public class SwitchToFind extends EditorHeaderAction { @Override public void actionPerformed(AnActionEvent e) { - getEditorSearchComponent().getFindModel().setReplaceState(false); + final FindModel findModel = getEditorSearchComponent().getFindModel(); + FindUtil.configureFindModel(false, getEditorSearchComponent().getEditor(), findModel); } } diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/SwitchToReplace.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/SwitchToReplace.java index ce67a8ce799c..33272a0b0299 100644 --- a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/SwitchToReplace.java +++ b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/SwitchToReplace.java @@ -1,6 +1,8 @@ package com.intellij.find.editorHeaderActions; import com.intellij.find.EditorSearchComponent; +import com.intellij.find.FindModel; +import com.intellij.find.FindUtil; import com.intellij.openapi.actionSystem.ActionManager; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; @@ -23,6 +25,7 @@ public class SwitchToReplace extends EditorHeaderAction { @Override public void actionPerformed(AnActionEvent e) { - getEditorSearchComponent().getFindModel().setReplaceState(true); + final FindModel findModel = getEditorSearchComponent().getFindModel(); + FindUtil.configureFindModel(true, getEditorSearchComponent().getEditor(), findModel); } } diff --git a/platform/lang-impl/src/com/intellij/find/impl/FindSettingsImpl.java b/platform/lang-impl/src/com/intellij/find/impl/FindSettingsImpl.java index 186c2a15db11..d3683eebda79 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/FindSettingsImpl.java +++ b/platform/lang-impl/src/com/intellij/find/impl/FindSettingsImpl.java @@ -110,6 +110,8 @@ public class FindSettingsImpl extends FindSettings implements PersistentStateCom RECENT_FILE_MASKS.add("*.as"); RECENT_FILE_MASKS.add("*.css"); RECENT_FILE_MASKS.add("*.mxml"); + RECENT_FILE_MASKS.add("*.py"); + RECENT_FILE_MASKS.add("*.rb"); } } diff --git a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesProjectViewPane.java b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesProjectViewPane.java index cc1ad6ea1de3..e8784e009f83 100644 --- a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesProjectViewPane.java +++ b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesProjectViewPane.java @@ -102,6 +102,7 @@ public class FavoritesProjectViewPane extends AbstractProjectViewPane { setTreeBuilder(myViewPanel.getBuilder()); myTreeStructure = myViewPanel.getFavoritesTreeStructure(); installComparator(); + enableDnD(); return myViewPanel; } diff --git a/platform/lang-impl/src/com/intellij/ide/util/FileStructureDialog.java b/platform/lang-impl/src/com/intellij/ide/util/FileStructureDialog.java index 24fd16bba1cb..b4da40061a95 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/FileStructureDialog.java +++ b/platform/lang-impl/src/com/intellij/ide/util/FileStructureDialog.java @@ -342,7 +342,6 @@ public class FileStructureDialog extends DialogWrapper { myList.repaint(); // to update match highlighting } }); - myListSpeedSearch.setComparator(createSpeedSearchComparator()); } private boolean hasPrefixShortened(final PropertyChangeEvent evt) { @@ -413,7 +412,7 @@ public class FileStructureDialog extends DialogWrapper { } ArrayList filteredElements = new ArrayList(childElements.length); - SpeedSearchBase.SpeedSearchComparator speedSearchComparator = createSpeedSearchComparator(); + SpeedSearchBase.SpeedSearchComparator speedSearchComparator = new SpeedSearchBase.SpeedSearchComparator(); for (Object child : childElements) { if (child instanceof AbstractTreeNode) { @@ -423,7 +422,7 @@ public class FileStructureDialog extends DialogWrapper { if (name == null) { continue; } - if (!speedSearchComparator.doCompare(enteredPrefix, name)) { + if (speedSearchComparator.matchingFragments(enteredPrefix, name) == null) { continue; } } @@ -439,25 +438,6 @@ public class FileStructureDialog extends DialogWrapper { } } - private static SpeedSearchBase.SpeedSearchComparator createSpeedSearchComparator() { - return new SpeedSearchBase.SpeedSearchComparator() { - public void translateCharacter(final StringBuilder buf, final char ch) { - if (ch == '*') { - if (buf.length() > 0 && "^*)(".indexOf(buf.charAt(buf.length() - 1)) == -1) buf.append(')'); - buf.append(".*"); // overrides '*' handling to skip (,) in parameter lists - } - else { - if (ch == ':') { - if (buf.length() > 0 && "^*)(".indexOf(buf.charAt(buf.length() - 1)) == -1) buf.append(')'); - buf.append(".*"); // get:int should match any getter returning int - buf.append('('); - } - super.translateCharacter(buf, ch); - } - } - }; - } - private class MyTreeActionsOwner implements TreeActionsOwner { private final Set myFilters = new HashSet(); diff --git a/platform/lang-impl/src/com/intellij/openapi/editor/actions/IncrementalFindAction.java b/platform/lang-impl/src/com/intellij/openapi/editor/actions/IncrementalFindAction.java index 761d56877b36..760d88f95feb 100644 --- a/platform/lang-impl/src/com/intellij/openapi/editor/actions/IncrementalFindAction.java +++ b/platform/lang-impl/src/com/intellij/openapi/editor/actions/IncrementalFindAction.java @@ -19,6 +19,7 @@ package com.intellij.openapi.editor.actions; import com.intellij.find.EditorSearchComponent; import com.intellij.find.FindManager; import com.intellij.find.FindModel; +import com.intellij.find.FindUtil; import com.intellij.ide.DataManager; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.actionSystem.PlatformDataKeys; @@ -26,7 +27,6 @@ import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.actionSystem.EditorAction; import com.intellij.openapi.editor.actionSystem.EditorActionHandler; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.text.StringUtil; import javax.swing.*; @@ -49,10 +49,7 @@ public class IncrementalFindAction extends EditorAction { if (!myReplace) { headerComponent.requestFocus(); } - if (myReplace != editorSearchComponent.getFindModel().isReplaceState()){ - editorSearchComponent.getFindModel().setReplaceState(myReplace); - } - configureFindModel(editor, editorSearchComponent.getFindModel()); + FindUtil.configureFindModel(myReplace, editor, editorSearchComponent.getFindModel()); } else { FindManager findManager = FindManager.getInstance(project); FindModel model; @@ -62,7 +59,7 @@ public class IncrementalFindAction extends EditorAction { model = new FindModel(); model.copyFrom(findManager.getFindInFileModel()); } - configureFindModel(editor, model); + FindUtil.configureFindModel(myReplace, editor, model); final EditorSearchComponent header = new EditorSearchComponent(editor, project, model); editor.setHeaderComponent(header); header.requestFocus(); @@ -70,32 +67,6 @@ public class IncrementalFindAction extends EditorAction { } } - private void configureFindModel(Editor editor, FindModel model) { - String selectedText = editor.getSelectionModel().getSelectedText(); - if (selectedText != null) { - if (myReplace) { - if (!StringUtil.isEmpty(selectedText)) { - if (selectedText.indexOf('\n') >= 0) { - model.setGlobal(false); - } - else { - model.setStringToFind(selectedText); - model.setGlobal(true); - } - } else { - model.setGlobal(true); - } - } else { - model.setStringToFind(selectedText); - } - - if (model.isGlobal()) { - model.setStringToFind(selectedText); - } - } - model.setPromptOnReplace(false); - } - public boolean isEnabled(Editor editor, DataContext dataContext) { Project project = PlatformDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext(editor.getComponent())); return project != null && !editor.isOneLineMode(); diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java index 9da2d00e02b7..d6685573880f 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java @@ -443,6 +443,7 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF return getContainingDirectory(); } + @Nullable public PsiDirectory getContainingDirectory() { final VirtualFile parentFile = getViewProvider().getVirtualFile().getParent(); if (parentFile == null) return null; diff --git a/platform/lang-impl/src/com/intellij/refactoring/copy/CopyFilesOrDirectoriesHandler.java b/platform/lang-impl/src/com/intellij/refactoring/copy/CopyFilesOrDirectoriesHandler.java index 8e89079f1fb4..7e7e7768fde5 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/copy/CopyFilesOrDirectoriesHandler.java +++ b/platform/lang-impl/src/com/intellij/refactoring/copy/CopyFilesOrDirectoriesHandler.java @@ -243,22 +243,7 @@ public class CopyFilesOrDirectoriesHandler implements CopyHandlerDelegate { if (elementToCopy instanceof PsiFile) { PsiFile file = (PsiFile)elementToCopy; String name = newName == null ? file.getName() : newName; - final PsiFile existing = targetDirectory.findFile(name); - if (existing!=null) { - int selection = choice == null || choice[0] == -1 ? Messages.showDialog( - String.format("File '%s' already exists in directory '%s'", name, targetDirectory.getVirtualFile().getPath()), - "Copy", - choice == null ? new String[]{"Overwrite", "Skip"} - : new String[]{"Overwrite", "Skip", "Overwrite for all", "Skip for all"}, 0, Messages.getQuestionIcon()) - : choice[0]; - if (choice != null && selection > 1) { - choice[0] = selection % 2; - selection = choice[0]; - } - if (selection == 0 && file != existing) { - existing.delete(); - } else return null; - } + if (checkFileExist(targetDirectory, choice, file, name)) return null; return targetDirectory.copyFileFrom(name, file); } else if (elementToCopy instanceof PsiDirectory) { @@ -290,4 +275,24 @@ public class CopyFilesOrDirectoriesHandler implements CopyHandlerDelegate { throw new IllegalArgumentException("unexpected elementToCopy: " + elementToCopy); } } + + public static boolean checkFileExist(PsiDirectory targetDirectory, int[] choice, PsiFile file, String name) { + final PsiFile existing = targetDirectory.findFile(name); + if (existing!=null) { + int selection = choice == null || choice[0] == -1 ? Messages.showDialog( + String.format("File '%s' already exists in directory '%s'", name, targetDirectory.getVirtualFile().getPath()), + "Copy", + choice == null ? new String[]{"Overwrite", "Skip"} + : new String[]{"Overwrite", "Skip", "Overwrite for all", "Skip for all"}, 0, Messages.getQuestionIcon()) + : choice[0]; + if (choice != null && selection > 1) { + choice[0] = selection % 2; + selection = choice[0]; + } + if (selection == 0 && file != existing) { + existing.delete(); + } else return true; + } + return false; + } } diff --git a/platform/lang-impl/src/com/intellij/refactoring/move/moveFilesOrDirectories/MoveFilesOrDirectoriesUtil.java b/platform/lang-impl/src/com/intellij/refactoring/move/moveFilesOrDirectories/MoveFilesOrDirectoriesUtil.java index 1773a9de6cf3..d63c664005f7 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/move/moveFilesOrDirectories/MoveFilesOrDirectoriesUtil.java +++ b/platform/lang-impl/src/com/intellij/refactoring/move/moveFilesOrDirectories/MoveFilesOrDirectoriesUtil.java @@ -22,9 +22,11 @@ import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.openapi.util.Computable; import com.intellij.psi.*; import com.intellij.refactoring.RefactoringBundle; import com.intellij.refactoring.RefactoringSettings; +import com.intellij.refactoring.copy.CopyFilesOrDirectoriesHandler; import com.intellij.refactoring.move.MoveCallback; import com.intellij.refactoring.move.MoveHandler; import com.intellij.refactoring.util.CommonRefactoringUtil; @@ -32,7 +34,9 @@ import com.intellij.util.Function; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; public class MoveFilesOrDirectoriesUtil { private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.move.moveFilesOrDirectories.MoveFilesOrDirectoriesUtil"); @@ -102,11 +106,25 @@ public class MoveFilesOrDirectoriesUtil { PsiManager manager = PsiManager.getInstance(project); try { - for (PsiElement psiElement : newElements) { + final int[] choice = elements.length > 1 ? new int[]{-1} : null; + final List els = new ArrayList(); + for (int i = 0, newElementsLength = newElements.length; i < newElementsLength; i++) { + final PsiElement psiElement = newElements[i]; + if (psiElement instanceof PsiFile) { + final PsiFile file = (PsiFile)psiElement; + final boolean fileExist = ApplicationManager.getApplication().runWriteAction(new Computable() { + @Override + public Boolean compute() { + return CopyFilesOrDirectoriesHandler.checkFileExist(targetDirectory, choice, file, file.getName()); + } + }); + if (fileExist) continue; + } manager.checkMove(psiElement, targetDirectory); + els.add(psiElement); } - new MoveFilesOrDirectoriesProcessor(project, newElements, targetDirectory, + new MoveFilesOrDirectoriesProcessor(project, els.toArray(new PsiElement[els.size()]), targetDirectory, RefactoringSettings.getInstance().MOVE_SEARCH_FOR_REFERENCES_FOR_FILE, false, false, moveCallback, new Runnable() { public void run() { diff --git a/platform/lvcs-impl/testSrc/com/intellij/history/integration/PatchingTestCase.java b/platform/lvcs-impl/testSrc/com/intellij/history/integration/PatchingTestCase.java index 7056182b1b52..c1f03d8ca360 100644 --- a/platform/lvcs-impl/testSrc/com/intellij/history/integration/PatchingTestCase.java +++ b/platform/lvcs-impl/testSrc/com/intellij/history/integration/PatchingTestCase.java @@ -21,6 +21,7 @@ import com.intellij.openapi.diff.impl.patch.FilePatch; import com.intellij.openapi.diff.impl.patch.PatchReader; import com.intellij.openapi.diff.impl.patch.PatchVirtualFileReader; import com.intellij.openapi.diff.impl.patch.formove.PatchApplier; +import com.intellij.openapi.vcs.changes.LocalChangeList; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; @@ -55,6 +56,6 @@ public abstract class PatchingTestCase extends IntegrationTestCase { patches.add(p); } - new PatchApplier(myProject, myRoot, patches, null, null).execute(); + new PatchApplier(myProject, myRoot, patches, (LocalChangeList) null, null).execute(); } } diff --git a/platform/platform-api/src/com/intellij/openapi/progress/AsynchronousExecution.java b/platform/platform-api/src/com/intellij/openapi/progress/AsynchronousExecution.java new file mode 100644 index 000000000000..72df34aacee3 --- /dev/null +++ b/platform/platform-api/src/com/intellij/openapi/progress/AsynchronousExecution.java @@ -0,0 +1,31 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.progress; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @author irengrig + * Date: 3/30/11 + * Time: 7:55 PM + */ +@Retention(RetentionPolicy.SOURCE) +@Target({ElementType.METHOD}) +public @interface AsynchronousExecution { +} diff --git a/platform/platform-api/src/com/intellij/openapi/progress/ProgressManager.java b/platform/platform-api/src/com/intellij/openapi/progress/ProgressManager.java index 3f4bb6d27e4d..0962c9e473bd 100644 --- a/platform/platform-api/src/com/intellij/openapi/progress/ProgressManager.java +++ b/platform/platform-api/src/com/intellij/openapi/progress/ProgressManager.java @@ -48,6 +48,19 @@ public abstract class ProgressManager { } } + public static void progress(final String text) throws ProcessCanceledException { + progress(text, ""); + } + + public static void progress(final String text, @Nullable String text2) throws ProcessCanceledException { + final ProgressIndicator pi = getInstance().getProgressIndicator(); + if (pi != null) { + pi.checkCanceled(); + pi.setText(text); + pi.setText2(text2 == null ? "" : text2); + } + } + protected abstract void doCheckCanceled() throws ProcessCanceledException; @Deprecated diff --git a/platform/platform-api/src/com/intellij/openapi/ui/LoadingDecorator.java b/platform/platform-api/src/com/intellij/openapi/ui/LoadingDecorator.java index a4012a2abedb..5b2c78eba050 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/LoadingDecorator.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/LoadingDecorator.java @@ -75,7 +75,7 @@ public class LoadingDecorator { } public void startLoading(final boolean takeSnapshot) { - if (isLoading() || myStartRequest) return; + if (isLoading() || myStartRequest || myStartAlarm.isDisposed()) return; myStartRequest = true; if (myDelay > 0) { diff --git a/platform/platform-api/src/com/intellij/ui/speedSearch/SpeedSearchSupply.java b/platform/platform-api/src/com/intellij/ui/speedSearch/SpeedSearchSupply.java index 773373031e77..af56a5e8dda0 100644 --- a/platform/platform-api/src/com/intellij/ui/speedSearch/SpeedSearchSupply.java +++ b/platform/platform-api/src/com/intellij/ui/speedSearch/SpeedSearchSupply.java @@ -16,11 +16,11 @@ package com.intellij.ui.speedSearch; import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.TextRange; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import java.util.regex.Matcher; /** * User: spLeaner @@ -39,5 +39,5 @@ public abstract class SpeedSearchSupply { public abstract boolean isPopupActive(); @Nullable - public abstract Matcher compareAndGetMatcher(@NotNull final String text); + public abstract Iterable matchingFragments(@NotNull final String text); } diff --git a/platform/platform-api/src/com/intellij/ui/speedSearch/SpeedSearchUtil.java b/platform/platform-api/src/com/intellij/ui/speedSearch/SpeedSearchUtil.java index 637a4a8b0188..b8185b42fb9f 100644 --- a/platform/platform-api/src/com/intellij/ui/speedSearch/SpeedSearchUtil.java +++ b/platform/platform-api/src/com/intellij/ui/speedSearch/SpeedSearchUtil.java @@ -16,19 +16,18 @@ package com.intellij.ui.speedSearch; import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.TextRange; import com.intellij.ui.SimpleColoredComponent; import com.intellij.ui.SimpleTextAttributes; import com.intellij.util.Processor; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.UIUtil; -import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import javax.swing.*; import java.awt.*; import java.util.ArrayList; import java.util.List; -import java.util.regex.Matcher; /** * User: spLeaner @@ -43,59 +42,45 @@ public final class SpeedSearchUtil { @NotNull final SimpleColoredComponent simpleColoredComponent) { final SpeedSearchSupply speedSearch = SpeedSearchSupply.getSupply(speedSearchEnabledComponent); if (speedSearch != null) { - final Matcher matcher = speedSearch.compareAndGetMatcher(text); - if (matcher != null) { - final List> searchTerms = new ArrayList>(); - for (int i = 0; i < matcher.groupCount(); i++) { - final int start = matcher.start(i + 1); - if (searchTerms.size() > 0) { - final Pair recent = searchTerms.get(searchTerms.size() - 1); - if (start == recent.second + recent.first.length()) { - searchTerms.set(searchTerms.size() - 1, Pair.create(recent.first + matcher.group(i + 1), recent.second)); - continue; - } - } - - final String group = matcher.group(i + 1); - if (group != null) searchTerms.add(Pair.create(group, start)); - } - - appendFragmentsStrict(text, searchTerms, attributes.getStyle(), attributes.getFgColor(), - selected ? UIUtil.getTreeSelectionBackground() : UIUtil.getTreeTextBackground(), simpleColoredComponent); + final Iterable fragments = speedSearch.matchingFragments(text); + if (fragments != null) { + final Color fg = attributes.getFgColor(); + final Color bg = selected ? UIUtil.getTreeSelectionBackground() : UIUtil.getTreeTextBackground(); + final int style = attributes.getStyle(); + final SimpleTextAttributes plain = new SimpleTextAttributes(style, fg); + final SimpleTextAttributes highlighted = new SimpleTextAttributes(bg, fg, null, style | SimpleTextAttributes.STYLE_SEARCH_MATCH); + appendColoredFragments(simpleColoredComponent, text, fragments, plain, highlighted); + return; } - else { - simpleColoredComponent.append(text, attributes); - } - } else { - simpleColoredComponent.append(text, attributes); } + simpleColoredComponent.append(text, attributes); } - public static void appendFragmentsStrict(@NonNls final String text, @NotNull final List> toHighlight, - final int style, final Color foreground, - final Color background, final SimpleColoredComponent c) { - if (text == null) return; - final SimpleTextAttributes plainAttributes = new SimpleTextAttributes(style, foreground); + public static void appendColoredFragments(final SimpleColoredComponent simpleColoredComponent, + final String text, + Iterable colored, + final SimpleTextAttributes plain, final SimpleTextAttributes highlighted) { + final List> searchTerms = new ArrayList>(); + for (TextRange fragment : colored) { + searchTerms.add(Pair.create(fragment.substring(text), fragment.getStartOffset())); + } final int[] lastOffset = {0}; - ContainerUtil.process(toHighlight, new Processor>() { + ContainerUtil.process(searchTerms, new Processor>() { @Override public boolean process(Pair pair) { if (pair.second > lastOffset[0]) { - c.append(text.substring(lastOffset[0], pair.second), new SimpleTextAttributes(style, foreground)); + simpleColoredComponent.append(text.substring(lastOffset[0], pair.second), plain); } - c.append(text.substring(pair.second, pair.second + pair.first.length()), new SimpleTextAttributes(background, - foreground, null, - style | - SimpleTextAttributes.STYLE_SEARCH_MATCH)); + simpleColoredComponent.append(text.substring(pair.second, pair.second + pair.first.length()), highlighted); lastOffset[0] = pair.second + pair.first.length(); return true; } }); if (lastOffset[0] < text.length()) { - c.append(text.substring(lastOffset[0]), plainAttributes); + simpleColoredComponent.append(text.substring(lastOffset[0]), plain); } } } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/TextChangesStorage.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/TextChangesStorage.java index d2dd97bbdecd..88187b9632d1 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/TextChangesStorage.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/TextChangesStorage.java @@ -243,7 +243,7 @@ public class TextChangesStorage { if (newChangeStart <= storedClientStart && newChangeEnd >= storedClientEnd) { myChanges.remove(i); insertionIndex = i; - newChangeEnd -= changeEntry.change.getText().length(); + newChangeEnd -= changeEntry.change.getDiff(); i--; continue; } diff --git a/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java b/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java index 4cbe9cdea526..64b6801313ec 100644 --- a/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java +++ b/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java @@ -21,13 +21,14 @@ import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.wm.ToolWindowManager; import com.intellij.openapi.wm.ex.ToolWindowManagerAdapter; import com.intellij.openapi.wm.ex.ToolWindowManagerEx; import com.intellij.openapi.wm.ex.ToolWindowManagerListener; import com.intellij.psi.codeStyle.NameUtil; import com.intellij.ui.speedSearch.SpeedSearchSupply; -import com.intellij.util.StringBuilderSpinAllocator; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -46,9 +47,6 @@ import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.util.ListIterator; import java.util.NoSuchElementException; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; public abstract class SpeedSearchBase extends SpeedSearchSupply { private static final Logger LOG = Logger.getInstance("#com.intellij.ui.SpeedSearchBase"); @@ -100,11 +98,11 @@ public abstract class SpeedSearchBase extends SpeedSear @Override - public Matcher compareAndGetMatcher(@NotNull String text) { + public Iterable matchingFragments(@NotNull String text) { if (!isPopupActive()) return null; final SpeedSearchComparator comparator = getComparator(); final String recentSearchText = comparator.getRecentSearchText(); - return recentSearchText != null && recentSearchText.length() > 0 && comparator.doCompare(recentSearchText, text) && !NameUtil.isUseMinusculeHumpMatcher() ? comparator.getRecentSearchMatcher() : null; + return StringUtil.isNotEmpty(recentSearchText) ? comparator.matchingFragments(recentSearchText, text) : null; } /** @@ -154,7 +152,7 @@ public abstract class SpeedSearchBase extends SpeedSear } protected boolean compare(String text, String pattern) { - return myComparator.doCompare(pattern, text); + return myComparator.matchingFragments(pattern, text) != null; } public SpeedSearchComparator getComparator() { @@ -167,7 +165,6 @@ public abstract class SpeedSearchBase extends SpeedSear public static class SpeedSearchComparator { private NameUtil.MinusculeMatcher myMinusculeMatcher; - private Matcher myRecentSearchMatcher; private String myRecentSearchText; private boolean myShouldMatchFromTheBeginning; @@ -179,86 +176,19 @@ public abstract class SpeedSearchBase extends SpeedSear myShouldMatchFromTheBeginning = shouldMatchFromTheBeginning; } - public boolean doCompare(String pattern, String text) { - if (myRecentSearchText != null && - myRecentSearchText.equals(pattern) - ) { - if (NameUtil.isUseMinusculeHumpMatcher()) { - return myMinusculeMatcher.matches(text); - } - - myRecentSearchMatcher.reset(text); - return myRecentSearchMatcher.find(); - } - else { + @Nullable + public Iterable matchingFragments(String pattern, String text) { + if (myRecentSearchText == null || !myRecentSearchText.equals(pattern)) { myRecentSearchText = pattern; - @NonNls final StringBuilder buf = StringBuilderSpinAllocator.alloc(); - - try { - translatePattern(buf, pattern); - - try { - boolean allLowercase = pattern.equals(pattern.toLowerCase()); - final Pattern recentSearchPattern = Pattern.compile(buf.toString(), allLowercase ? Pattern.CASE_INSENSITIVE : 0); - myRecentSearchMatcher = recentSearchPattern.matcher(text); - - if (NameUtil.isUseMinusculeHumpMatcher()) { - myMinusculeMatcher = new NameUtil.MinusculeMatcher(myShouldMatchFromTheBeginning ? pattern : "*" + pattern, false, false); - return myMinusculeMatcher.matches(text); - } - return myRecentSearchMatcher.find(); - } - catch (PatternSyntaxException ex) { - myRecentSearchText = null; - } - } - finally { - StringBuilderSpinAllocator.dispose(buf); - } - - return false; + myMinusculeMatcher = new NameUtil.MinusculeMatcher(myShouldMatchFromTheBeginning ? pattern : "*" + pattern, NameUtil.MatchingCaseSensitivity.NONE); } + return myMinusculeMatcher.matchingFragments(text); } - public void translatePattern(final StringBuilder buf, final String pattern) { - if (myShouldMatchFromTheBeginning) buf.append('^'); // match from the line start - final int len = pattern.length(); - for (int i = 0; i < len; ++i) { - translateCharacter(buf, pattern.charAt(i)); - } - - if (buf.length() > 0 && "*^".indexOf(buf.charAt(buf.length() - 1)) == -1) buf.append(')'); - } public String getRecentSearchText() { return myRecentSearchText; } - - public Matcher getRecentSearchMatcher() { - return myRecentSearchMatcher; - } - - public void translateCharacter(final StringBuilder buf, final char ch) { - if (ch == '*' ) { - buf.append("(\\w|:)"); // ':' for xml tags - } - else if ("{}[].+^$()?".indexOf(ch) != -1) { - // do not bother with other metachars - buf.append('\\'); - } - - if (Character.isUpperCase(ch)) { - if (buf.length() > 0 && "*^".indexOf(buf.charAt(buf.length() - 1)) == -1) buf.append(')'); - // for camel humps - buf.append("[A-Za-z_]*"); - buf.append('('); - } else { - if (buf.length() > 0 && "*^".indexOf(buf.charAt(buf.length() - 1)) != -1) buf.append('('); - } - - if (buf.length() == 0 || buf.length() > 0 && "^".indexOf(buf.charAt(buf.length() - 1)) != -1) buf.append('('); - buf.append(ch); - } } @Nullable diff --git a/platform/platform-impl/testSrc/com/intellij/openapi/editor/impl/TextChangesStorageTest.java b/platform/platform-impl/testSrc/com/intellij/openapi/editor/impl/TextChangesStorageTest.java index fb4b164b0e4f..9829c64eff11 100644 --- a/platform/platform-impl/testSrc/com/intellij/openapi/editor/impl/TextChangesStorageTest.java +++ b/platform/platform-impl/testSrc/com/intellij/openapi/editor/impl/TextChangesStorageTest.java @@ -109,6 +109,13 @@ public class TextChangesStorageTest { checkChanges(c("", 2, 5)); } + @Test + public void adjacentDeletesFromEndToStart() { + delete(5, 6); + delete(4, 5); + checkChanges(c("", 4, 6)); + } + @Test public void singleReplace() { replace("abc", 3, 4); diff --git a/platform/platform-resources-en/src/messages/VcsBundle.properties b/platform/platform-resources-en/src/messages/VcsBundle.properties index 32447cc2761c..a2b6931d54fd 100644 --- a/platform/platform-resources-en/src/messages/VcsBundle.properties +++ b/platform/platform-resources-en/src/messages/VcsBundle.properties @@ -197,8 +197,10 @@ message.text.file.is.up.to.date=File is up-to-date message.text.all.files.are.up.to.date=All files are up-to-date progress.text.synchronizing.files=Synchronizing files... progress.text.updating.done=Updating done +progress.text.updating.canceled=Update canceled message.title.vcs.update.errors={0} Errors toolwindow.title.update.action.info={0} Info +toolwindow.title.update.action.canceled.info={0} Info (Canceled) update.tree.node.size.statistics={0,choice, 0#no items|1#1 item|2#{0, number} items} toolwindow.title.update.project=Update Project ({0}) action.name.group.by.packages=Group by Packages diff --git a/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java b/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java index 7321b2b2631b..117c27e406ee 100644 --- a/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java @@ -49,7 +49,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.File; -import java.io.FileReader; import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; @@ -255,8 +254,8 @@ public abstract class UsefulTestCase extends TestCase { } @NonNls - public static String toString(Collection collection) { - if (collection.isEmpty()) { + public static String toString(Iterable collection) { + if (!collection.iterator().hasNext()) { return ""; } @@ -277,24 +276,28 @@ public abstract class UsefulTestCase extends TestCase { assertOrderedEquals(Arrays.asList(actual), expected); } - public static void assertOrderedEquals(Collection actual, T... expected) { + public static void assertOrderedEquals(Iterable actual, T... expected) { assertOrderedEquals(null, actual, expected); } - public static void assertOrderedEquals(final String errorMsg, Collection actual, T... expected) { + public static void assertOrderedEquals(final String errorMsg, Iterable actual, T... expected) { Assert.assertNotNull(actual); Assert.assertNotNull(expected); assertOrderedEquals(errorMsg, actual, Arrays.asList(expected)); } - public static void assertOrderedEquals(final Collection actual, final Collection expected) { + public static void assertOrderedEquals(final Iterable actual, final Collection expected) { assertOrderedEquals(null, actual, expected); } public static void assertOrderedEquals(final String erroMsg, - final Collection actual, + final Iterable actual, final Collection expected) { - if (!new ArrayList(actual).equals(new ArrayList(expected))) { + ArrayList list = new ArrayList(); + for (T t : actual) { + list.add(t); + } + if (!list.equals(new ArrayList(expected))) { Assert.assertEquals(erroMsg, toString(expected), toString(actual)); Assert.fail(); } diff --git a/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java b/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java index c6b1218acdaf..74a3de79045a 100644 --- a/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java +++ b/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java @@ -15,12 +15,13 @@ */ package com.intellij.psi.codeStyle; -import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.FList; import com.intellij.util.text.StringTokenizer; import org.apache.oro.text.regex.MalformedPatternException; import org.apache.oro.text.regex.Pattern; @@ -28,14 +29,13 @@ import org.apache.oro.text.regex.Perl5Compiler; import org.apache.oro.text.regex.Perl5Matcher; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -import java.text.CharacterIterator; -import java.text.StringCharacterIterator; import java.util.ArrayList; +import java.util.Collections; import java.util.List; public class NameUtil { - private static final Logger LOG = Logger.getInstance("#com.intellij.psi.codeStyle.NameUtil"); private static final Function LOWERCASE_MAPPING = new Function() { public String fun(final String s) { return s.toLowerCase(); @@ -323,61 +323,45 @@ public class NameUtil { return Character.isUpperCase(p) || Character.isDigit(p); } - private static void addAllWords(String word, List result) { - CharacterIterator it = new StringCharacterIterator(word); - StringBuffer b = new StringBuffer(); + private static void addAllWords(String text, List result) { + int start = 0; WordState state = WordState.NO_WORD; - char curPrevUC = '\0'; - for (char c = it.first(); c != CharacterIterator.DONE; c = it.next()) { + for (int i = 0; i < text.length(); i++) { + char c = text.charAt(i); switch (state) { case NO_WORD: if (!isWordStart(c)) { - b.append(c); state = WordState.WORD; } else { state = WordState.PREV_UC; - curPrevUC = c; } break; case PREV_UC: if (!isWordStart(c)) { - b = startNewWord(result, b, curPrevUC); - b.append(c); + start = startNewWord(text, result, start, i - 1); state = WordState.WORD; } else { - b.append(curPrevUC); state = WordState.PREV_UC; - curPrevUC = c; } break; case WORD: if (isWordStart(c)) { - startNewWord(result, b, c); - b.setLength(0); + start = startNewWord(text, result, start, i); state = WordState.PREV_UC; - curPrevUC = c; - } - else { - b.append(c); } break; } } - if (state == WordState.PREV_UC) { - b.append(curPrevUC); - } - result.add(b.toString()); + startNewWord(text, result, start, text.length()); } - private static StringBuffer startNewWord(List result, StringBuffer b, char c) { - if (b.length() > 0) { - result.add(b.toString()); + private static int startNewWord(String word, List result, int start, int end) { + if (end > start) { + result.add(word.substring(start, end)); } - b = new StringBuffer(); - b.append(c); - return b; + return end; } public interface Matcher { @@ -385,23 +369,26 @@ public class NameUtil { } public static Matcher buildCompletionMatcher(String pattern, int exactPrefixLen, boolean allowToUpper, boolean allowToLower) { - return buildMatcher(pattern, buildRegexp(pattern, exactPrefixLen, allowToUpper, allowToLower, false, true), exactPrefixLen > 0, !allowToLower && !allowToUpper); + MatchingCaseSensitivity options = !allowToLower && !allowToUpper ? MatchingCaseSensitivity.ALL : exactPrefixLen > 0 ? MatchingCaseSensitivity.FIRST_LETTER : MatchingCaseSensitivity.NONE; + return buildMatcher(pattern, buildRegexp(pattern, exactPrefixLen, allowToUpper, allowToLower, false, true), options); } public static Matcher buildMatcher(String pattern, int exactPrefixLen, boolean allowToUpper, boolean allowToLower) { - return buildMatcher(pattern, buildRegexp(pattern, exactPrefixLen, allowToUpper, allowToLower), exactPrefixLen > 0, !allowToLower && !allowToUpper); + MatchingCaseSensitivity options = !allowToLower && !allowToUpper ? MatchingCaseSensitivity.ALL : exactPrefixLen > 0 ? MatchingCaseSensitivity.FIRST_LETTER : MatchingCaseSensitivity.NONE; + return buildMatcher(pattern, buildRegexp(pattern, exactPrefixLen, allowToUpper, allowToLower), options); } public static Matcher buildMatcher(String pattern, int exactPrefixLen, boolean allowToUpper, boolean allowToLower, boolean lowerCaseWords) { - return buildMatcher(pattern, buildRegexp(pattern, exactPrefixLen, allowToUpper, allowToLower, lowerCaseWords, false), exactPrefixLen > 0, !allowToLower && !allowToUpper); + MatchingCaseSensitivity options = !allowToLower && !allowToUpper ? MatchingCaseSensitivity.ALL : exactPrefixLen > 0 ? MatchingCaseSensitivity.FIRST_LETTER : MatchingCaseSensitivity.NONE; + return buildMatcher(pattern, buildRegexp(pattern, exactPrefixLen, allowToUpper, allowToLower, lowerCaseWords, false), options); } public static boolean isUseMinusculeHumpMatcher() { return Registry.is("minuscule.humps.matching"); } - private static Matcher buildMatcher(final String pattern, String regexp, boolean firstLetterMatters, boolean caseMatters) { - return isUseMinusculeHumpMatcher() ? new MinusculeMatcher(pattern, firstLetterMatters, caseMatters) : new OptimizedMatcher(pattern, regexp); + private static Matcher buildMatcher(final String pattern, String regexp, MatchingCaseSensitivity options) { + return isUseMinusculeHumpMatcher() ? new MinusculeMatcher(pattern, options) : new OptimizedMatcher(pattern, regexp); } private static class OptimizedMatcher implements Matcher { @@ -481,52 +468,57 @@ public class NameUtil { } } + public enum MatchingCaseSensitivity { + NONE, FIRST_LETTER, ALL + } + public static class MinusculeMatcher implements Matcher { private final char[] myPattern; - private final boolean myFirstLetterCaseMatters; - private final boolean myCaseMatters; + private final MatchingCaseSensitivity myOptions; - public MinusculeMatcher(String pattern, boolean firstLetterCaseMatters, boolean caseMatters) { - myFirstLetterCaseMatters = firstLetterCaseMatters; - myCaseMatters = caseMatters; - if (caseMatters) { - LOG.assertTrue(firstLetterCaseMatters); - } + public MinusculeMatcher(String pattern, MatchingCaseSensitivity options) { + myOptions = options; myPattern = StringUtil.trimEnd(pattern, "* ").replaceAll(":", "\\*:").replaceAll("\\.", "\\*\\.").toCharArray(); } - private boolean matches(int patternIndex, List words, int wordIndex) { + @Nullable + private FList matchName(int patternIndex, List words, int wordIndex, int insideWord, int wordStart) { if (patternIndex == myPattern.length) { - return true; + return FList.emptyList(); } if (wordIndex == words.size()) { - return false; + return null; } String word = words.get(wordIndex); if ('*' == myPattern[patternIndex]) { - return handleAsterisk(patternIndex, words, wordIndex); + return handleAsterisk(patternIndex, words, wordIndex, insideWord, wordStart); } - if (isWordSeparator(word.charAt(0))) { + if (patternIndex == 0 && myOptions != MatchingCaseSensitivity.NONE && word.charAt(insideWord) != myPattern[0]) { + return null; + } + + if (isWordSeparator(word.charAt(insideWord))) { assert word.length() == 1 : "'" + word + "'"; - if (isWordSeparator(myPattern[patternIndex])) { - return matches(patternIndex + 1, words, wordIndex + 1); - } - if (patternIndex == 0 && myFirstLetterCaseMatters) { - return false; + char p = myPattern[patternIndex]; + int nextStart = wordStart + word.length(); + if (isWordSeparator(p)) { + if (myOptions != MatchingCaseSensitivity.NONE && + wordIndex == 0 && words.size() > 1 && patternIndex + 1 < myPattern.length && + isWordSeparator(words.get(1).charAt(0)) && !isWordSeparator(myPattern[patternIndex + 1])) { + return null; + } + + return matchName(patternIndex + 1, words, wordIndex + 1, 0, nextStart); } - return matches(patternIndex, words, wordIndex + 1); + return matchName(patternIndex, words, wordIndex + 1, 0, nextStart); } - if (patternIndex == 0 && myFirstLetterCaseMatters && word.charAt(0) != myPattern[0]) { - return false; - } - - if (StringUtil.toLowerCase(word.charAt(0)) != StringUtil.toLowerCase(myPattern[patternIndex])) { - return false; + if (StringUtil.toLowerCase(word.charAt(insideWord)) != StringUtil.toLowerCase(myPattern[patternIndex])) { + return null; } boolean uppers = isWordStart(myPattern[patternIndex]); @@ -534,20 +526,20 @@ public class NameUtil { int i = 1; while (true) { if (patternIndex + i == myPattern.length) { - return true; + return FList.emptyList().prepend(TextRange.from(wordStart + insideWord, i)); } - if (i == word.length()) { + if (i == word.length() - insideWord) { break; } char p = myPattern[patternIndex + i]; - if (uppers && isWordStart(p) && !myCaseMatters) { + if (uppers && isWordStart(p) && myOptions != MatchingCaseSensitivity.ALL) { p = StringUtil.toLowerCase(p); } else { uppers = false; } - char w = word.charAt(i); - if (!myCaseMatters) { + char w = word.charAt(insideWord + i); + if (myOptions != MatchingCaseSensitivity.ALL) { w = StringUtil.toLowerCase(w); } if (w != p) { @@ -557,49 +549,53 @@ public class NameUtil { } // there's more in the pattern, but no more words if (wordIndex == words.size() - 1) { - if (patternIndex + i == myPattern.length - 1 && ' ' == myPattern[patternIndex + i]) { - return i == word.length(); + if (patternIndex + i == myPattern.length - 1 && ' ' == myPattern[patternIndex + i] && i == word.length() - insideWord) { + return FList.emptyList().prepend(TextRange.from(wordStart + insideWord, i)); } - return false; + return null; } + + int nextWord = wordStart + word.length(); while (i > 0) { - if (matches(patternIndex + i, words, wordIndex + 1)) { - return true; + FList ranges = matchName(patternIndex + i, words, wordIndex + 1, 0, nextWord); + if (ranges != null) { + return ranges.prepend(TextRange.from(wordStart + insideWord, i)); } i--; } - return false; + return null; } - private boolean handleAsterisk(int patternIndex, List words, int wordIndex) { + @Nullable + private FList handleAsterisk(int patternIndex, List words, int wordIndex, int insideWord, int wordStart) { while ('*' == myPattern[patternIndex]) { patternIndex++; if (patternIndex == myPattern.length) { - return true; + return FList.emptyList(); } } String nextChar = String.valueOf(myPattern[patternIndex]); + int fromIndex = insideWord; for (int i = wordIndex; i < words.size(); i++) { String s = words.get(i); - int fromIndex = 0; while (true) { int next = StringUtil.indexOfIgnoreCase(s, nextChar, fromIndex); if (next < 0) { break; } - List newWords = new ArrayList(); - newWords.add(s.substring(next)); - newWords.addAll(words.subList(i + 1, words.size())); - if (matches(patternIndex, newWords, 0)) { - return true; + FList ranges = matchName(patternIndex, words, i, next, wordStart); + if (ranges != null) { + return ranges; } fromIndex = next + 1; } + fromIndex = 0; + wordStart += s.length(); } - return false; + return null; } private static boolean isWordSeparator(char c) { @@ -608,6 +604,11 @@ public class NameUtil { @Override public boolean matches(String name) { + return matchingFragments(name) != null; + } + + @Nullable + public Iterable matchingFragments(String name) { StringTokenizer tokenizer = new StringTokenizer(name, " -_.:/", true); List words = new ArrayList(); while (tokenizer.hasMoreTokens()) { @@ -616,10 +617,10 @@ public class NameUtil { } if (words.isEmpty()) { - return myPattern.length == 0; + return myPattern.length == 0 ? Collections.emptyList() : null; } - return matches(0, words, 0); + return matchName(0, words, 0, 0, 0); } } } diff --git a/platform/vcs-api/src/com/intellij/util/continuation/ContinuationContext.java b/platform/vcs-api/src/com/intellij/util/continuation/ContinuationContext.java index 2a3f66f68e36..017f841458eb 100644 --- a/platform/vcs-api/src/com/intellij/util/continuation/ContinuationContext.java +++ b/platform/vcs-api/src/com/intellij/util/continuation/ContinuationContext.java @@ -16,6 +16,8 @@ package com.intellij.util.continuation; import com.intellij.openapi.vcs.CalledInAny; +import com.intellij.util.Consumer; +import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.Arrays; @@ -30,9 +32,18 @@ public interface ContinuationContext { void last(TaskDescriptor... next); @CalledInAny void last(List next); + @CalledInAny + void after(@NotNull TaskDescriptor inQueue, TaskDescriptor... next); + @CalledInAny void cancelEverything(); + void addExceptionHandler(final Class clazz, final Consumer consumer); + boolean handleException(final Exception e); + + void keepExisting(final Object disaster, final Object cure); + void throwDisaster(final Object disaster, final Object cure); + void suspend(); void ping(); @@ -51,6 +62,23 @@ public interface ContinuationContext { public void cancelEverything() { } + @Override + public void addExceptionHandler(Class clazz, Consumer consumer) { + } + + @Override + public boolean handleException(Exception e) { + return false; + } + + @Override + public void throwDisaster(Object disaster, final Object cure) { + } + + @Override + public void keepExisting(Object disaster, Object cure) { + } + @Override public void next(TaskDescriptor... next) { myList.addAll(0, Arrays.asList(next)); @@ -71,6 +99,20 @@ public interface ContinuationContext { myList.addAll(next); } + @Override + public void after(@NotNull TaskDescriptor inQueue, TaskDescriptor... next) { + int idx = -1; + for (int i = 0; i < myList.size(); i++) { + final TaskDescriptor descriptor = myList.get(i); + if (inQueue == descriptor) { + idx = i; + break; + } + } + assert idx != -1; + myList.addAll(idx, Arrays.asList(next)); + } + @Override public void suspend() { } diff --git a/platform/vcs-api/src/com/intellij/util/continuation/TaskDescriptor.java b/platform/vcs-api/src/com/intellij/util/continuation/TaskDescriptor.java index e00ca9eada04..43cf5f149afd 100644 --- a/platform/vcs-api/src/com/intellij/util/continuation/TaskDescriptor.java +++ b/platform/vcs-api/src/com/intellij/util/continuation/TaskDescriptor.java @@ -18,19 +18,33 @@ package com.intellij.util.continuation; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.HashMap; +import java.util.Map; + public abstract class TaskDescriptor { + private boolean myHaveMagicCure; private final String myName; @NotNull private final Where myWhere; + private final Map mySurviveKit; public TaskDescriptor(final String name, @NotNull final Where where) { myName = name; myWhere = where; + mySurviveKit = new HashMap(); } @Nullable public abstract void run(final ContinuationContext context); + public final void addCure(final Object disaster, final Object cure) { + mySurviveKit.put(disaster, cure); + } + @Nullable + public final Object hasCure(final Object disaster) { + return mySurviveKit.get(disaster); + } + public String getName() { return myName; } @@ -39,4 +53,12 @@ public abstract class TaskDescriptor { public Where getWhere() { return myWhere; } + + public boolean isHaveMagicCure() { + return myHaveMagicCure; + } + + public void setHaveMagicCure(boolean haveMagicCure) { + myHaveMagicCure = haveMagicCure; + } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/diff/impl/patch/formove/PatchApplier.java b/platform/vcs-impl/src/com/intellij/openapi/diff/impl/patch/formove/PatchApplier.java index 2ac0e41e047a..f39ba0bd1da1 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/diff/impl/patch/formove/PatchApplier.java +++ b/platform/vcs-impl/src/com/intellij/openapi/diff/impl/patch/formove/PatchApplier.java @@ -26,6 +26,7 @@ import com.intellij.openapi.diff.impl.patch.apply.ApplyTextFilePatch; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.FileTypes; import com.intellij.openapi.fileTypes.ex.FileTypeChooser; +import com.intellij.openapi.progress.AsynchronousExecution; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.ui.Messages; @@ -46,6 +47,11 @@ import com.intellij.openapi.vfs.newvfs.RefreshSession; import com.intellij.openapi.wm.ToolWindowManager; import com.intellij.util.Consumer; import com.intellij.util.WaitForProgressToShow; +import com.intellij.util.continuation.Continuation; +import com.intellij.util.continuation.ContinuationContext; +import com.intellij.util.continuation.TaskDescriptor; +import com.intellij.util.continuation.Where; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.IOException; @@ -61,17 +67,16 @@ public class PatchApplier { private final VirtualFile myBaseDirectory; private final List myPatches; private final CustomBinaryPatchApplier myCustomForBinaries; - private final LocalChangeList myTargetChangeList; - + private final Consumer> myToTargetListsMover; private final List myRemainingPatches; private final PathsVerifier myVerifier; public PatchApplier(final Project project, final VirtualFile baseDirectory, final List patches, - final LocalChangeList targetChangeList, final CustomBinaryPatchApplier customForBinaries) { + @Nullable final Consumer> toTargetListsMover, final CustomBinaryPatchApplier customForBinaries) { myProject = project; myBaseDirectory = baseDirectory; myPatches = patches; - myTargetChangeList = targetChangeList; + myToTargetListsMover = toTargetListsMover; myCustomForBinaries = customForBinaries; myRemainingPatches = new ArrayList(); myVerifier = new PathsVerifier(myProject, myBaseDirectory, myPatches, new PathsVerifier.BaseMapper() { @@ -87,38 +92,89 @@ public class PatchApplier { }); } - public ApplyPatchStatus execute() { - return execute(true); + public PatchApplier(final Project project, final VirtualFile baseDirectory, final List patches, + final LocalChangeList targetChangeList, final CustomBinaryPatchApplier customForBinaries) { + this(project, baseDirectory, patches, createMover(project, targetChangeList), customForBinaries); } - public ApplyPatchStatus execute(boolean showSuccessNotification) { - myRemainingPatches.addAll(myPatches); + @Nullable + private static Consumer> createMover(final Project project, final LocalChangeList targetChangeList) { + final ChangeListManager clm = ChangeListManager.getInstance(project); + if (targetChangeList == null || clm.getDefaultListName().equals(targetChangeList.getName())) return null; + return new FilesMover(clm, targetChangeList); + } - final ApplyPatchStatus patchStatus = nonWriteActionPreCheck(); - if (ApplyPatchStatus.FAILURE.equals(patchStatus)) return patchStatus; + @AsynchronousExecution + public void execute() { + execute(true); + } - final ApplyPatchStatus applyStatus = ApplicationManager.getApplication().runReadAction(new Computable() { - public ApplyPatchStatus compute() { - final Ref refStatus = new Ref(ApplyPatchStatus.FAILURE); - CommandProcessor.getInstance().executeCommand(myProject, new Runnable() { - public void run() { - refStatus.set(executeWritable()); - } - }, VcsBundle.message("patch.apply.command"), null); - return refStatus.get(); - } - }); - final ApplyPatchStatus status = ApplyPatchStatus.SUCCESS.equals(patchStatus) ? applyStatus : - ApplyPatchStatus.and(patchStatus, applyStatus); - // listeners finished, all 'legal' file additions/deletions with VCS are done - final TriggerAdditionOrDeletion trigger = new TriggerAdditionOrDeletion(myProject); - addSkippedItems(trigger); - trigger.process(); - if(showSuccessNotification || !ApplyPatchStatus.SUCCESS.equals(status)) { - showApplyStatus(myProject, status); + @AsynchronousExecution + public void execute(boolean showSuccessNotification) { + final Continuation continuation = new Continuation(myProject, true); + final ContinuationContext.GatheringContinuationContext initContext = + new ContinuationContext.GatheringContinuationContext(); + scheduleSelf(showSuccessNotification, initContext); + continuation.run(initContext.getList()); + } + + public class ApplyPatchTask extends TaskDescriptor { + private ApplyPatchStatus myStatus; + private final boolean myShowNotification; + + public ApplyPatchTask(final boolean showNotification) { + super("", Where.AWT); + myShowNotification = showNotification; } - refreshFiles(trigger.getAffected()); - return status; + + @Override + public void run(ContinuationContext context) { + myRemainingPatches.addAll(myPatches); + + final ApplyPatchStatus patchStatus = nonWriteActionPreCheck(); + if (ApplyPatchStatus.FAILURE.equals(patchStatus)) { + if (myShowNotification) { + showApplyStatus(myProject, patchStatus); + } + myStatus = patchStatus; + return; + } + + final ApplyPatchStatus applyStatus = ApplicationManager.getApplication().runReadAction(new Computable() { + public ApplyPatchStatus compute() { + final Ref refStatus = new Ref(ApplyPatchStatus.FAILURE); + CommandProcessor.getInstance().executeCommand(myProject, new Runnable() { + public void run() { + refStatus.set(executeWritable()); + } + }, VcsBundle.message("patch.apply.command"), null); + return refStatus.get(); + } + }); + myStatus = ApplyPatchStatus.SUCCESS.equals(patchStatus) ? applyStatus : + ApplyPatchStatus.and(patchStatus, applyStatus); + // listeners finished, all 'legal' file additions/deletions with VCS are done + final TriggerAdditionOrDeletion trigger = new TriggerAdditionOrDeletion(myProject); + addSkippedItems(trigger); + trigger.process(); + if(myShowNotification || !ApplyPatchStatus.SUCCESS.equals(myStatus)) { + showApplyStatus(myProject, myStatus); + } + refreshFiles(trigger.getAffected(), context); + } + + public ApplyPatchStatus getStatus() { + return myStatus; + } + } + + public ApplyPatchTask createApplyPart(final boolean showSuccessNotification) { + return new ApplyPatchTask(showSuccessNotification); + } + + @AsynchronousExecution + public void scheduleSelf(boolean showSuccessNotification, @NotNull final ContinuationContext context) { + context.next(createApplyPart(showSuccessNotification)); } public static ApplyPatchStatus executePatchGroup(final Collection group) { @@ -151,7 +207,7 @@ public class PatchApplier { trigger.process(); for (PatchApplier applier : group) { - applier.refreshFiles(trigger.getAffected()); + applier.refreshFiles(trigger.getAffected(), null); } showApplyStatus(project, result); return result; @@ -223,19 +279,31 @@ public class PatchApplier { } } - protected void refreshFiles(final Collection additionalDirectly) { + protected void refreshFiles(final Collection additionalDirectly, @Nullable final ContinuationContext context) { final List directlyAffected = myVerifier.getDirectlyAffected(); final List indirectlyAffected = myVerifier.getAllAffected(); directlyAffected.addAll(additionalDirectly); + if (context != null) { + context.suspend(); + } final RefreshSession session = RefreshQueue.getInstance().createSession(false, true, new Runnable() { public void run() { if (myProject.isDisposed()) return; final ChangeListManager changeListManager = ChangeListManager.getInstance(myProject); - if ((myTargetChangeList != null) && (! directlyAffected.isEmpty()) && - (! myTargetChangeList.getName().equals(changeListManager.getDefaultListName()))) { - changeListManager.invokeAfterUpdate(new FilesMover(changeListManager, directlyAffected), InvokeAfterUpdateMode.BACKGROUND_CANCELLABLE, + if (! directlyAffected.isEmpty() && myToTargetListsMover != null) { + changeListManager.invokeAfterUpdate(new Runnable() { + @Override + public void run() { + if (myToTargetListsMover != null) { + myToTargetListsMover.consume(directlyAffected); + } + if (context != null) { + context.ping(); + } + } + }, InvokeAfterUpdateMode.BACKGROUND_CANCELLABLE, VcsBundle.message("change.lists.manager.move.changes.to.list"), new Consumer() { public void consume(final VcsDirtyScopeManager vcsDirtyScopeManager) { @@ -246,6 +314,9 @@ public class PatchApplier { final VcsDirtyScopeManager vcsDirtyScopeManager = VcsDirtyScopeManager.getInstance(myProject); // will schedule update vcsDirtyScopeManager.filePathsDirty(directlyAffected, null); + if (context != null) { + context.ping(); + } } } }); @@ -373,18 +444,19 @@ public class PatchApplier { }, null, project); } - private class FilesMover implements Runnable { + private static class FilesMover implements Consumer> { private final ChangeListManager myChangeListManager; - private final List myDirectlyAffected; + private final LocalChangeList myTargetChangeList; - public FilesMover(final ChangeListManager changeListManager, final List directlyAffected) { + public FilesMover(final ChangeListManager changeListManager, final LocalChangeList targetChangeList) { myChangeListManager = changeListManager; - myDirectlyAffected = directlyAffected; + myTargetChangeList = targetChangeList; } - public void run() { + @Override + public void consume(List directlyAffected) { List changes = new ArrayList(); - for(FilePath file: myDirectlyAffected) { + for(FilePath file: directlyAffected) { final Change change = myChangeListManager.getChange(file); if (change != null) { changes.add(change); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/IgnoreUnversionedAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/IgnoreUnversionedAction.java index d37f9d9400b1..b62bf35cba7d 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/IgnoreUnversionedAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/IgnoreUnversionedAction.java @@ -59,7 +59,9 @@ public class IgnoreUnversionedAction extends AnAction { public void update(AnActionEvent e) { List files = e.getData(ChangesListView.UNVERSIONED_FILES_DATA_KEY); - removeNullFiles(files); + if (files != null) { + removeNullFiles(files); + } boolean enabled = files != null && !files.isEmpty(); e.getPresentation().setEnabled(enabled); e.getPresentation().setVisible(enabled); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/ShelveChangesManager.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/ShelveChangesManager.java index 1ec5a83c719f..645b96430f24 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/ShelveChangesManager.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/ShelveChangesManager.java @@ -32,6 +32,7 @@ import com.intellij.openapi.diff.impl.patch.apply.ApplyFilePatchBase; import com.intellij.openapi.diff.impl.patch.formove.CustomBinaryPatchApplier; import com.intellij.openapi.diff.impl.patch.formove.PatchApplier; import com.intellij.openapi.options.StreamProvider; +import com.intellij.openapi.progress.AsynchronousExecution; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.*; @@ -47,6 +48,10 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.Consumer; import com.intellij.util.PathUtil; import com.intellij.util.SmartList; +import com.intellij.util.continuation.Continuation; +import com.intellij.util.continuation.ContinuationContext; +import com.intellij.util.continuation.TaskDescriptor; +import com.intellij.util.continuation.Where; import com.intellij.util.messages.MessageBus; import com.intellij.util.messages.Topic; import com.intellij.util.text.CharArrayCharSequence; @@ -301,48 +306,75 @@ public class ShelveChangesManager implements ProjectComponent, JDOMExternalizabl unshelveChangeList(changeList, changes, binaryFiles, targetChangeList, true); } + @AsynchronousExecution public void unshelveChangeList(final ShelvedChangeList changeList, @Nullable final List changes, @Nullable final List binaryFiles, - final LocalChangeList targetChangeList, + @Nullable final LocalChangeList targetChangeList, boolean showSuccessNotification) { - List remainingPatches = new ArrayList(); + final Continuation continuation = new Continuation(myProject, true); + final ContinuationContext.GatheringContinuationContext initContext = new ContinuationContext.GatheringContinuationContext(); + scheduleUnshelveChangeList(changeList, changes, binaryFiles, targetChangeList, showSuccessNotification, initContext); + continuation.run(initContext.getList()); + } - final List textFilePatches; - try { - textFilePatches = loadTextPatches(changeList, changes, remainingPatches); - } - catch (IOException e) { - LOG.info(e); - PatchApplier.showError(myProject, "Cannot load patch(es): " + e.getMessage(), true); - return; - } - catch (PatchSyntaxException e) { - PatchApplier.showError(myProject, "Cannot load patch(es): " + e.getMessage(), true); - LOG.info(e); - return; - } + @AsynchronousExecution + public void scheduleUnshelveChangeList(final ShelvedChangeList changeList, + @Nullable final List changes, + @Nullable final List binaryFiles, + @Nullable final LocalChangeList targetChangeList, + final boolean showSuccessNotification, final ContinuationContext context) { + context.next(new TaskDescriptor("", Where.AWT) { + @Override + public void run(ContinuationContext context) { + final List remainingPatches = new ArrayList(); - final List patches = new ArrayList(textFilePatches); + final List textFilePatches; + try { + textFilePatches = loadTextPatches(changeList, changes, remainingPatches); + } + catch (IOException e) { + LOG.info(e); + PatchApplier.showError(myProject, "Cannot load patch(es): " + e.getMessage(), true); + return; + } + catch (PatchSyntaxException e) { + PatchApplier.showError(myProject, "Cannot load patch(es): " + e.getMessage(), true); + LOG.info(e); + return; + } - final List remainingBinaries = new ArrayList(); - final List binaryFilesToUnshelve = getBinaryFilesToUnshelve(changeList, binaryFiles, remainingBinaries); + final List patches = new ArrayList(textFilePatches); - for (final ShelvedBinaryFile shelvedBinaryFile : binaryFilesToUnshelve) { - patches.add(new ShelvedBinaryFilePatch(shelvedBinaryFile)); - } + final List remainingBinaries = new ArrayList(); + final List binaryFilesToUnshelve = getBinaryFilesToUnshelve(changeList, binaryFiles, remainingBinaries); - final BinaryPatchApplier binaryPatchApplier = new BinaryPatchApplier(binaryFilesToUnshelve.size()); - final PatchApplier patchApplier = new PatchApplier(myProject, myProject.getBaseDir(), patches, targetChangeList, binaryPatchApplier); - patchApplier.execute(showSuccessNotification); - remainingPatches.addAll(patchApplier.getRemainingPatches()); + for (final ShelvedBinaryFile shelvedBinaryFile : binaryFilesToUnshelve) { + patches.add(new ShelvedBinaryFilePatch(shelvedBinaryFile)); + } - if ((remainingPatches.size() == 0) && remainingBinaries.isEmpty()) { - recycleChangeList(changeList); - } - else { - saveRemainingPatches(changeList, remainingPatches, remainingBinaries); - } + final BinaryPatchApplier binaryPatchApplier = new BinaryPatchApplier(binaryFilesToUnshelve.size()); + final PatchApplier patchApplier = new PatchApplier(myProject, myProject.getBaseDir(), + patches, targetChangeList, binaryPatchApplier); + + // after patch applier part + context.next(new TaskDescriptor("", Where.AWT) { + @Override + public void run(ContinuationContext context) { + remainingPatches.addAll(patchApplier.getRemainingPatches()); + + if ((remainingPatches.size() == 0) && remainingBinaries.isEmpty()) { + recycleChangeList(changeList); + } + else { + saveRemainingPatches(changeList, remainingPatches, remainingBinaries); + } + } + }); + + patchApplier.scheduleSelf(showSuccessNotification, context); + } + }); } private static List loadTextPatches(final ShelvedChangeList changeList, final List changes, final List remainingPatches) diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesListView.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesListView.java index a300b610f603..4082fb6b5412 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesListView.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesListView.java @@ -93,6 +93,7 @@ public class ChangesListView extends Tree implements TypeSafeDataProvider, Advan SmartExpander.installOn(this); myCopyProvider = new TreeCopyProvider(this); new TreeLinkMouseListener(new ChangesBrowserNodeRenderer(myProject, false, false)).install(this); + setCellRenderer(new ChangesBrowserNodeRenderer(myProject, isShowFlatten(), true)); } public DefaultTreeModel getModel() { @@ -142,16 +143,13 @@ public class ChangesListView extends Tree implements TypeSafeDataProvider, Advan @Nullable List ignoredFiles, final List lockedFolders, @Nullable final Map logicallyLockedFiles) { - storeState(); - TreeModelBuilder builder = new TreeModelBuilder(myProject, isShowFlatten()); - final DefaultTreeModel model = builder.buildModel(changeLists, unversionedFiles, locallyDeletedFiles, modifiedWithoutEditing, + final DefaultTreeModel model = builder.buildModel(changeLists, unversionedFiles, locallyDeletedFiles, modifiedWithoutEditing, switchedFiles, switchedRoots, ignoredFiles, lockedFolders, logicallyLockedFiles); + + storeState(); setModel(model); - setCellRenderer(new ChangesBrowserNodeRenderer(myProject, isShowFlatten(), true)); - expandPath(new TreePath(((ChangesBrowserNode)model.getRoot()).getPath())); - restoreState(); } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/ProjectLevelVcsManagerEx.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/ProjectLevelVcsManagerEx.java index 345dd7a69631..c09dea89e31a 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/ProjectLevelVcsManagerEx.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/ProjectLevelVcsManagerEx.java @@ -45,7 +45,10 @@ public abstract class ProjectLevelVcsManagerEx extends ProjectLevelVcsManager { public abstract void notifyDirectoryMappingChanged(); - public abstract UpdateInfoTree showUpdateProjectInfo(UpdatedFiles updatedFiles, String displayActionName, ActionInfo actionInfo); + public abstract UpdateInfoTree showUpdateProjectInfo(UpdatedFiles updatedFiles, + String displayActionName, + ActionInfo actionInfo, + boolean canceled); public abstract void fireDirectoryMappingsChanged(); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/history/FileHistoryPanelImpl.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/history/FileHistoryPanelImpl.java index 5a5b26b6b9f7..6c757de2e853 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/history/FileHistoryPanelImpl.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/history/FileHistoryPanelImpl.java @@ -256,9 +256,11 @@ public class FileHistoryPanelImpl 1)) ? ("#" + myUpdateNumber) : ""); - final UpdateInfoTree updateInfoTree = myProjectLevelVcsManager.showUpdateProjectInfo(myUpdatedFiles, text, myActionInfo); + final UpdateInfoTree updateInfoTree = myProjectLevelVcsManager.showUpdateProjectInfo(myUpdatedFiles, text, myActionInfo, wasCanceled); updateInfoTree.setBefore(myBefore); updateInfoTree.setAfter(myAfter); @@ -603,7 +592,11 @@ public abstract class AbstractCommonUpdateAction extends AbstractVcsAction { } public void onCancel() { - onSuccess(); + try { + onSuccessImpl(true); + } finally { + releaseIfNeeded(); + } } } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/update/RestoreUpdateTree.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/update/RestoreUpdateTree.java index 494855842cdd..b838bb97d25c 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/update/RestoreUpdateTree.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/update/RestoreUpdateTree.java @@ -48,7 +48,8 @@ public class RestoreUpdateTree implements ProjectComponent, JDOMExternalizable { ActionInfo actionInfo = myUpdateInfo.getActionInfo(); if (actionInfo != null) { ProjectLevelVcsManagerEx.getInstanceEx(myProject).showUpdateProjectInfo(myUpdateInfo.getFileInformation(), - VcsBundle.message("action.display.name.update"), actionInfo); + VcsBundle.message("action.display.name.update"), actionInfo, + false); CommittedChangesCache.getInstance(myProject).refreshIncomingChangesAsync(); } myUpdateInfo = null; diff --git a/platform/vcs-impl/src/com/intellij/util/continuation/Continuation.java b/platform/vcs-impl/src/com/intellij/util/continuation/Continuation.java index 733f7390fe14..94c309a4dd6d 100644 --- a/platform/vcs-impl/src/com/intellij/util/continuation/Continuation.java +++ b/platform/vcs-impl/src/com/intellij/util/continuation/Continuation.java @@ -16,6 +16,7 @@ package com.intellij.util.continuation; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.progress.EmptyProgressIndicator; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.Task; import com.intellij.openapi.progress.impl.BackgroundableProcessIndicator; @@ -25,14 +26,14 @@ import com.intellij.openapi.vcs.CalledInAny; import com.intellij.openapi.vcs.CalledInAwt; import com.intellij.openapi.vcs.changes.BackgroundFromStartOption; import com.intellij.util.Consumer; +import com.intellij.util.Processor; import com.intellij.util.WaitForProgressToShow; +import com.intellij.util.concurrency.Semaphore; +import com.sun.tools.javac.code.Attribute; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Arrays; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; +import java.util.*; public class Continuation { private GeneralRunner myGeneralRunner; @@ -55,6 +56,27 @@ public class Continuation { pingRunnerInCorrectThread(); } + public void runAndWait(final TaskDescriptor... tasks) { + runAndWait(Arrays.asList(tasks)); + } + + public void runAndWait(final List tasks) { + final Semaphore semaphore = new Semaphore(); + semaphore.down(); + tasks.add(new TaskDescriptor("", Where.AWT) { + @Override + public void run(ContinuationContext context) { + semaphore.up(); + } + }); + run(tasks); + semaphore.waitFor(); + } + + public void addExceptionHandler(final Class clazz, final Consumer consumer) { + myGeneralRunner.addExceptionHandler(clazz, consumer); + } + public void runIndirect(final Consumer consumer) { consumer.consume(myGeneralRunner); if (myGeneralRunner.isEmpty()) return; @@ -90,6 +112,10 @@ public class Continuation { myGeneralRunner.next(list); } + public boolean isEmpty() { + return myGeneralRunner.isEmpty(); + } + private static class TaskWrapper extends Task.Backgroundable { private final TaskDescriptor myTaskDescriptor; private final GeneralRunner myGeneralRunner; @@ -119,22 +145,69 @@ public class Continuation { private final Project myProject; private final boolean myCancellable; private final List myQueue; - private boolean myTriggerSuspend; - private BackgroundableProcessIndicator myIndicator; + private final Object myQueueLock; + private volatile boolean myTriggerSuspend; + private ProgressIndicator myIndicator; + private final Map myDisasters; + private final Map, Consumer> myHandlersMap; private GeneralRunner(final Project project, boolean cancellable) { myProject = project; myCancellable = cancellable; - myQueue = Collections.synchronizedList(new LinkedList()); + myQueueLock = new Object(); + myQueue = new LinkedList(); + myDisasters = new HashMap(); + myHandlersMap = new HashMap, Consumer>(); + } + + public void addExceptionHandler(final Class clazz, final Consumer consumer) { + synchronized (myQueueLock) { + myHandlersMap.put(clazz, new Consumer() { + @Override + public void consume(Exception e) { + if (! clazz.isAssignableFrom(e.getClass())) { + throw new RuntimeException(e); + } + consumer.consume((T) e); + } + }); + } } public Project getProject() { return myProject; } + public void clearDisasters() { + synchronized (myQueueLock) { + myDisasters.clear(); + } + } + + @Override + public boolean handleException(Exception e) { + synchronized (myQueueLock) { + final Class aClass = e.getClass(); + Consumer consumer = myHandlersMap.get(e.getClass()); + if (consumer != null) { + consumer.consume(e); + return true; + } + for (Map.Entry, Consumer> entry : myHandlersMap.entrySet()) { + if (entry.getKey().isAssignableFrom(aClass)) { + entry.getValue().consume(e); + return true; + } + } + } + return false; + } + @CalledInAny public void cancelEverything() { - myQueue.clear(); + synchronized (myQueueLock) { + myQueue.clear(); + } } public void cancelCurrent() { @@ -147,27 +220,79 @@ public class Continuation { myTriggerSuspend = true; } + @Override + public void keepExisting(Object disaster, Object cure) { + synchronized (myQueueLock) { + for (TaskDescriptor taskDescriptor : myQueue) { + taskDescriptor.addCure(disaster, cure); + } + } + } + + @Override + public void throwDisaster(@NotNull Object disaster, @NotNull final Object cure) { + synchronized (myQueueLock) { + final Iterator iterator = myQueue.iterator(); + while (iterator.hasNext()) { + final TaskDescriptor taskDescriptor = iterator.next(); + if (taskDescriptor.isHaveMagicCure()) continue; + final Object taskCure = taskDescriptor.hasCure(disaster); + if (! cure.equals(taskCure)) { + iterator.remove(); + } + } + myDisasters.put(disaster, cure); + } + } + + @Override + public void after(@NotNull TaskDescriptor inQueue, TaskDescriptor... next) { + synchronized (myQueueLock) { + int idx = -1; + int i = 0; + for (TaskDescriptor descriptor : myQueue) { + if (descriptor == inQueue) { + idx = i; + break; + } + ++ i; + } + assert idx != -1; + myQueue.addAll(idx + 1, Arrays.asList(next)); + } + } + @CalledInAny public void next(TaskDescriptor... next) { - myQueue.addAll(0, Arrays.asList(next)); + synchronized (myQueueLock) { + myQueue.addAll(0, Arrays.asList(next)); + } } public void next(List next) { - myQueue.addAll(0, next); + synchronized (myQueueLock) { + myQueue.addAll(0, next); + } } @Override public void last(List next) { - myQueue.addAll(next); + synchronized (myQueueLock) { + myQueue.addAll(next); + } } @Override public void last(TaskDescriptor... next) { - myQueue.addAll(Arrays.asList(next)); + synchronized (myQueueLock) { + myQueue.addAll(Arrays.asList(next)); + } } public boolean isEmpty() { - return myQueue.isEmpty(); + synchronized (myQueueLock) { + return myQueue.isEmpty(); + } } @CalledInAwt @@ -177,19 +302,34 @@ public class Continuation { while (true) { // stop if project is being disposed if (! myProject.isOpen()) return; - if (myQueue.isEmpty()) return; - if (myTriggerSuspend) { - myTriggerSuspend = false; - return; + + TaskDescriptor current; + synchronized (myQueueLock) { + if (myQueue.isEmpty()) return; + if (myTriggerSuspend) { + myTriggerSuspend = false; + return; + } + current = myQueue.remove(0); + // check if some tasks were scheduled after disaster was thrown, anyway, they should also be checked for cure + if (! current.isHaveMagicCure()) { + for (Map.Entry entry : myDisasters.entrySet()) { + if (! entry.getValue().equals(current.hasCure(entry.getKey()))) { + current = null; + break; + } + } + } + if (current == null) continue; } - TaskDescriptor current = myQueue.remove(0); if (Where.AWT.equals(current.getWhere())) { myIndicator = null; current.run(this); } else { final TaskWrapper task = new TaskWrapper(myProject, current.getName(), myCancellable, current, this); - myIndicator = new BackgroundableProcessIndicator(task); + myIndicator = ApplicationManager.getApplication().isUnitTestMode() ? new EmptyProgressIndicator() : + new BackgroundableProcessIndicator(task); ProgressManagerImpl.runProcessWithProgressAsynchronously(task, myIndicator); return; } diff --git a/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties b/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties index 381cf82b5185..9b8042e92c18 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties +++ b/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties @@ -1282,7 +1282,7 @@ string.can.be.simplified.problem.descriptor=#ref can be simplified string.replace.quickfix=Replace with ''{0}'' instantiating.object.to.get.class.object.replace.quickfix=Replace with direct class object access manual.array.copy.replace.quickfix=Replace with 'System.arrayCopy()' -manual.array.to.collection.copy.replace.quickfix=Replace with 'Collection.addAll(Arrays.asList())' +manual.array.to.collection.copy.replace.quickfix=Replace with 'Collections.addAll(...,...)' method.may.be.static.only.option=Only check private or final methods method.may.be.static.empty.option=Ignore empty methods random.double.for.random.integer.replace.quickfix=Replace with 'nextInt()' @@ -1291,6 +1291,7 @@ string.buffer.to.string.in.concatenation.remove.quickfix=Remove 'toString()' string.concatenation.in.loops.only.option=Only warn if string is repeatedly appended string.concatenation.inside.string.buffer.append.replace.quickfix=Replace with chained append() calls string.equals.empty.string.replace.quickfix=Replace with 'length()==0' +string.equals.empty.string.replace.quickfix2=Replace with 'isEmpty()' tail.recursion.replace.quickfix=Replace tail recursion with iteration if.statement.with.too.many.branches.max.option=Maximum number of branches: if.statement.with.too.many.branches.problem.descriptor='#ref' has too many branches ({0}) #loc diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/ManualArrayToCollectionCopyInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/ManualArrayToCollectionCopyInspection.java index 040d0ecfe925..b0823fec2333 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/ManualArrayToCollectionCopyInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/ManualArrayToCollectionCopyInspection.java @@ -120,11 +120,12 @@ public class ManualArrayToCollectionCopyInspection extends BaseInspection { return null; } final String arrayText = iteratedValue.getText(); - @NonNls final StringBuilder buffer = new StringBuilder(60); + @NonNls final StringBuilder buffer = + new StringBuilder("java.util.Collections.addAll("); buffer.append(collectionText); - buffer.append(".addAll(java.util.Arrays.asList("); + buffer.append(','); buffer.append(arrayText); - buffer.append("));"); + buffer.append(");"); return buffer.toString(); } @@ -189,24 +190,33 @@ public class ManualArrayToCollectionCopyInspection extends BaseInspection { if (toOffsetText == null) { return null; } - @NonNls final StringBuilder buffer = new StringBuilder(); - if (collectionText.length() > 0) { + if (fromOffsetText.equals("0") && + toOffsetText.equals(arrayText + ".length")) { + @NonNls final StringBuilder buffer = + new StringBuilder("java.util.Collections.addAll("); + buffer.append(collectionText); + buffer.append(','); + buffer.append(arrayText); + buffer.append(");"); + return buffer.toString(); + } else { + @NonNls final StringBuilder buffer = new StringBuilder(); buffer.append(collectionText); buffer.append('.'); - } - buffer.append("addAll(java.util.Arrays.asList("); - buffer.append(arrayText); - buffer.append(')'); - if (!fromOffsetText.equals("0") || - !toOffsetText.equals(arrayText + ".length")) { - buffer.append(".subList("); - buffer.append(fromOffsetText); - buffer.append(", "); - buffer.append(toOffsetText); + buffer.append("addAll(java.util.Arrays.asList("); + buffer.append(arrayText); buffer.append(')'); + if (!fromOffsetText.equals("0") || + !toOffsetText.equals(arrayText + ".length")) { + buffer.append(".subList("); + buffer.append(fromOffsetText); + buffer.append(", "); + buffer.append(toOffsetText); + buffer.append(')'); + } + buffer.append(");"); + return buffer.toString(); } - buffer.append(");"); - return buffer.toString(); } private static PsiArrayAccessExpression getArrayAccessExpression( diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/RandomDoubleForRandomIntegerInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/RandomDoubleForRandomIntegerInspection.java index 34722f22cc61..e6ae0cbbad7d 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/RandomDoubleForRandomIntegerInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/RandomDoubleForRandomIntegerInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2007 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2011 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,23 +32,27 @@ import org.jetbrains.annotations.Nullable; public class RandomDoubleForRandomIntegerInspection extends BaseInspection { + @Override @NotNull public String getID() { return "UsingRandomNextDoubleForRandomInteger"; } + @Override @NotNull public String getDisplayName() { return InspectionGadgetsBundle.message( "random.double.for.random.integer.display.name"); } + @Override @NotNull protected String buildErrorString(Object... infos) { return InspectionGadgetsBundle.message( "random.double.for.random.integer.problem.descriptor"); } + @Override public InspectionGadgetsFix buildFix(Object... infos) { return new RandomDoubleForRandomIntegerFix(); } @@ -62,6 +66,7 @@ public class RandomDoubleForRandomIntegerInspection "random.double.for.random.integer.replace.quickfix"); } + @Override public void doFix(Project project, ProblemDescriptor descriptor) throws IncorrectOperationException { final PsiIdentifier name = @@ -103,11 +108,12 @@ public class RandomDoubleForRandomIntegerInspection } } + @Override public BaseInspectionVisitor buildVisitor() { - return new StringEqualsEmptyStringVisitor(); + return new RandomDoubleForRandomIntegerVisitor(); } - private static class StringEqualsEmptyStringVisitor + private static class RandomDoubleForRandomIntegerVisitor extends BaseInspectionVisitor { @Override public void visitMethodCallExpression( diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/StringEqualsEmptyStringInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/StringEqualsEmptyStringInspection.java index 54a922119ff4..20a4130181ee 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/StringEqualsEmptyStringInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/StringEqualsEmptyStringInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2007 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2011 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,7 @@ package com.siyeh.ig.performance; import com.intellij.codeInspection.ProblemDescriptor; import com.intellij.openapi.project.Project; import com.intellij.psi.*; +import com.intellij.psi.search.GlobalSearchScope; import com.intellij.util.IncorrectOperationException; import com.siyeh.HardcodedMethodConstants; import com.siyeh.InspectionGadgetsBundle; @@ -48,16 +49,39 @@ public class StringEqualsEmptyStringInspection extends BaseInspection { @Override public InspectionGadgetsFix buildFix(Object... infos) { - return new StringEqualsEmptyStringFix(); + return new StringEqualsEmptyStringFix((PsiMethodCallExpression)infos[0]); } private static class StringEqualsEmptyStringFix extends InspectionGadgetsFix { + private final boolean useIsEmpty; + + public StringEqualsEmptyStringFix(PsiMethodCallExpression call) { + final Project project = call.getProject(); + final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project); + final GlobalSearchScope scope = call.getResolveScope(); + final PsiClass stringClass = + psiFacade.findClass(CommonClassNames.JAVA_LANG_STRING, + scope); + if (stringClass != null) { + final PsiMethod[] methods = + stringClass.findMethodsByName("isEmpty", false); + useIsEmpty = methods.length > 0; + } else { + useIsEmpty = false; + } + } + @NotNull public String getName() { - return InspectionGadgetsBundle.message( - "string.equals.empty.string.replace.quickfix"); + if (useIsEmpty) { + return InspectionGadgetsBundle.message( + "string.equals.empty.string.replace.quickfix2"); + } else { + return InspectionGadgetsBundle.message( + "string.equals.empty.string.replace.quickfix"); + } } @Override @@ -72,7 +96,8 @@ public class StringEqualsEmptyStringInspection extends BaseInspection { } final PsiExpression call = (PsiExpression)expression.getParent(); final PsiExpression qualifier = expression.getQualifierExpression(); - final String qualifierText = getRemainingText(qualifier); + final String qualifierText = + getRemainingText(qualifier, useIsEmpty); if (call == null) { return; } @@ -80,19 +105,33 @@ public class StringEqualsEmptyStringInspection extends BaseInspection { if (parent instanceof PsiExpression) { final PsiExpression parentExpression = (PsiExpression) parent; if(BoolUtils.isNegation(parentExpression)) { - replaceExpression(parentExpression, - qualifierText + ".length()!=0"); + if (useIsEmpty) { + replaceExpression(parentExpression, + '!' + qualifierText + ".isEmpty()"); + } else { + replaceExpression(parentExpression, + qualifierText + ".length()!=0"); + } + } else { + if (useIsEmpty) { + replaceExpression(call, qualifier + ".isEmpty()"); + } else { + replaceExpression(call, qualifierText + ".length()==0"); + } + } + } else { + if (useIsEmpty) { + replaceExpression(call, qualifierText + ".isEmpty()"); } else { replaceExpression(call, qualifierText + ".length()==0"); } - } else { - replaceExpression(call, qualifierText + ".length()==0"); } } - private static String getRemainingText(PsiExpression qualifier) { + private static String getRemainingText(PsiExpression qualifier, + boolean useIsEmpty) { final String qualifierText; - if (qualifier instanceof PsiMethodCallExpression) { + if (!useIsEmpty && qualifier instanceof PsiMethodCallExpression) { // to replace stringBuffer.toString().equals("") with // stringBuffer.length() == 0 final PsiMethodCallExpression callExpression = @@ -163,7 +202,7 @@ public class StringEqualsEmptyStringInspection extends BaseInspection { // produce uncompilable code (out of merely incorrect code). return; } - registerMethodCallError(call); + registerMethodCallError(call, call); } } } \ No newline at end of file diff --git a/plugins/git4idea/src/git4idea/checkin/GitPushActiveBranchesDialog.java b/plugins/git4idea/src/git4idea/checkin/GitPushActiveBranchesDialog.java index bf0f717ee0e0..13bd919d27bf 100644 --- a/plugins/git4idea/src/git4idea/checkin/GitPushActiveBranchesDialog.java +++ b/plugins/git4idea/src/git4idea/checkin/GitPushActiveBranchesDialog.java @@ -37,6 +37,8 @@ import com.intellij.ui.CheckboxTree; import com.intellij.ui.CheckedTreeNode; import com.intellij.ui.ColoredTreeCellRenderer; import com.intellij.ui.SimpleTextAttributes; +import com.intellij.util.Consumer; +import com.intellij.util.continuation.ContinuationContext; import com.intellij.util.text.DateFormatUtil; import com.intellij.util.ui.UIUtil; import com.intellij.util.ui.tree.TreeUtil; @@ -420,7 +422,7 @@ public class GitPushActiveBranchesDialog extends DialogWrapper { private boolean executeRebase(final List exceptions, RebaseInfo rebaseInfo) { // TODO this is a workaround to attach PushActiveBranched to the new update. // at first we update via rebase - boolean result = new GitUpdateProcess(myProject, new EmptyProgressIndicator(), rebaseInfo.roots, UpdatedFiles.create()).update(true); + boolean result = new GitUpdateProcess(myProject, new EmptyProgressIndicator(), rebaseInfo.roots, UpdatedFiles.create()).update(true, true); // then we reorder commits if (result) { @@ -436,7 +438,7 @@ public class GitPushActiveBranchesDialog extends DialogWrapper { } - private boolean reorderCommitsIfNeeded(@NotNull RebaseInfo rebaseInfo) { + private boolean reorderCommitsIfNeeded(@NotNull final RebaseInfo rebaseInfo) { if (rebaseInfo.reorderedCommits.isEmpty()) { return true; } @@ -446,75 +448,57 @@ public class GitPushActiveBranchesDialog extends DialogWrapper { progressIndicator = new EmptyProgressIndicator(); } String stashMessage = "Uncommitted changes before rebase operation at " + DateFormatUtil.formatDateTime(Clock.getTime()); - GitChangesSaver saver = rebaseInfo.policy == GitVcsSettings.UpdateChangesPolicy.SHELVE ? new GitShelveChangesSaver(myProject, progressIndicator, stashMessage) : new GitStashChangesSaver(myProject, progressIndicator, stashMessage); - - final boolean saveOnFrameDeactivation = myGeneralSettings.isSaveOnFrameDeactivation(); - final boolean syncOnFrameDeactivation = myGeneralSettings.isSyncOnFrameActivation(); - myProjectManager.blockReloadingProjectOnExternalChanges(); - UIUtil.invokeAndWaitIfNeeded(new Runnable() { - @Override public void run() { - ApplicationManager.getApplication().runWriteAction(new Runnable() { - @Override public void run() { - FileDocumentManager.getInstance().saveAllDocuments(); - myGeneralSettings.setSaveOnFrameDeactivation(false); - myGeneralSettings.setSyncOnFrameActivation(false); - } - }); - } - }); - - try { - final Set rootsToReorder = rebaseInfo.reorderedCommits.keySet(); - saver.saveLocalChanges(rootsToReorder); + final GitChangesSaver saver = rebaseInfo.policy == GitVcsSettings.UpdateChangesPolicy.SHELVE ? new GitShelveChangesSaver(myProject, progressIndicator, stashMessage) : new GitStashChangesSaver(myProject, progressIndicator, stashMessage); + final Boolean[] result = new Boolean[1]; + result[0] = false; + new GitUpdateLikeProcess(myProject) { + @Override + protected void runImpl(ContinuationContext context) { try { - GitRebaser rebaser = new GitRebaser(myProject); - for (Map.Entry> rootToCommits: rebaseInfo.reorderedCommits.entrySet()) { - final VirtualFile root = rootToCommits.getKey(); - GitBranch b = GitBranch.current(myProject, root); - if (b == null) { - LOG.info("executeRebase: current branch is null"); - continue; - } - GitBranch t = b.tracked(myProject, root); - if (t == null) { - LOG.info("executeRebase: tracked branch is null"); - continue; - } + final Set rootsToReorder = rebaseInfo.reorderedCommits.keySet(); + saver.saveLocalChanges(rootsToReorder); - final GitRevisionNumber mergeBase = b.getMergeBase(myProject, root, t); - if (mergeBase == null) { - LOG.info("executeRebase: merge base is null for " + b + " and " + t); - continue; - } - - String parentCommit = mergeBase.getRev(); - return rebaser.reoderCommitsIfNeeded(root, parentCommit, rootToCommits.getValue()); - } - - } catch (VcsException e) { - notifyMessage(myProject, "Commits weren't pushed", "Failed to reorder commits", NotificationType.WARNING, true, - Collections.singleton(e)); - } finally { try { - saver.restoreLocalChanges(); + GitRebaser rebaser = new GitRebaser(myProject); + for (Map.Entry> rootToCommits: rebaseInfo.reorderedCommits.entrySet()) { + final VirtualFile root = rootToCommits.getKey(); + GitBranch b = GitBranch.current(myProject, root); + if (b == null) { + LOG.info("executeRebase: current branch is null"); + continue; + } + GitBranch t = b.tracked(myProject, root); + if (t == null) { + LOG.info("executeRebase: tracked branch is null"); + continue; + } + + final GitRevisionNumber mergeBase = b.getMergeBase(myProject, root, t); + if (mergeBase == null) { + LOG.info("executeRebase: merge base is null for " + b + " and " + t); + continue; + } + + String parentCommit = mergeBase.getRev(); + result[0] = rebaser.reoderCommitsIfNeeded(root, parentCommit, rootToCommits.getValue()); + } + } catch (VcsException e) { - LOG.info("Couldn't restore local changes after reordering commits", e); - notifyImportantError(myProject, "Couldn't restore local changes after update", - "Restoring changes saved before update failed with an error.
" + e.getLocalizedMessage()); + notifyMessage(myProject, "Commits weren't pushed", "Failed to reorder commits", NotificationType.WARNING, true, + Collections.singleton(e)); + } finally { + saver.restoreLocalChanges(context); } + } catch (VcsException e) { + LOG.info("Couldn't save local changes", e); + notifyError(myProject, "Couldn't save local changes", + "Tried to save uncommitted changes in " + saver.getSaverName() + " before update, but failed with an error.
" + + "Update was cancelled.", true, e); } - } catch (VcsException e) { - LOG.info("Couldn't save local changes", e); - notifyError(myProject, "Couldn't save local changes", - "Tried to save uncommitted changes in " + saver.getSaverName() + " before update, but failed with an error.
" + - "Update was cancelled.", true, e); - } finally { - myProjectManager.unblockReloadingProjectOnExternalChanges(); - myGeneralSettings.setSaveOnFrameDeactivation(saveOnFrameDeactivation); - myGeneralSettings.setSyncOnFrameActivation(syncOnFrameDeactivation); - } - return false; + } + }.execute(); + return result[0]; } private static class RebaseInfo { diff --git a/plugins/git4idea/src/git4idea/checkout/branches/GitCheckoutProcess.java b/plugins/git4idea/src/git4idea/checkout/branches/GitCheckoutProcess.java index 07e5419d1468..4c930c8f837b 100644 --- a/plugins/git4idea/src/git4idea/checkout/branches/GitCheckoutProcess.java +++ b/plugins/git4idea/src/git4idea/checkout/branches/GitCheckoutProcess.java @@ -22,23 +22,29 @@ import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ex.ProjectManagerEx; +import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Ref; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.changes.*; import com.intellij.openapi.vcs.changes.shelf.ShelveChangesManager; import com.intellij.openapi.vcs.changes.shelf.ShelvedChangeList; +import com.intellij.openapi.vcs.changes.ui.ChangesViewContentManager; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.wm.ToolWindowManager; +import com.intellij.util.Consumer; +import com.intellij.util.continuation.Continuation; +import com.intellij.util.continuation.ContinuationContext; import com.intellij.util.ui.UIUtil; -import com.intellij.vcsUtil.VcsUtil; import git4idea.GitRevisionNumber; import git4idea.GitUtil; import git4idea.checkout.branches.GitBranchConfigurations.BranchChanges; import git4idea.checkout.branches.GitBranchConfigurations.ChangeInfo; import git4idea.checkout.branches.GitBranchConfigurations.ChangeListInfo; import git4idea.commands.*; +import git4idea.ui.GitUIUtil; import git4idea.update.GitStashUtils; import org.jetbrains.annotations.Nullable; @@ -553,77 +559,86 @@ public class GitCheckoutProcess { * @param changes the changes to restore, null means no changes to restore * @return true if changes has been restored successfully */ - private boolean restoreChanges(ProgressIndicator progress, - final BranchChanges changes) { + private void restoreChanges(ProgressIndicator progress, final BranchChanges changes) { if (changes == null) { - return true; + return; } ShelvedChangeList shelve = null; for (ShelvedChangeList changeList : myShelveManager.getShelvedChangeLists()) { if (changeList.PATH.equals(changes.SHELVE_PATH)) { + // todo - why hadn't it interrupted? shelve = changeList; } } if (shelve == null) { //noinspection ThrowableInstanceNeverThrown myExceptions.add(new VcsException("Failed to find shelve with path" + changes.SHELVE_PATH)); - return false; + return; } progress.setText("Refreshing files before restoring shelve: " + shelve.DESCRIPTION); - GitStashUtils.doSystemUnshelve(myProject, shelve, myShelveManager, myChangeManager, myExceptions); - // dirty files and parse changes - final HashMap, String> parsedChanges = new HashMap, String>(); - for (ChangeInfo changeInfo : changes.CHANGES) { - String before = changeInfo.BEFORE_PATH; - String after = changeInfo.AFTER_PATH; - parsedChanges.put(Pair.create(before, after), changeInfo.CHANGE_LIST_NAME); - if (after != null) { - myDirtyScopeManager.fileDirty(VcsUtil.getFilePath(after)); - } - if (before != null) { - myDirtyScopeManager.fileDirty(VcsUtil.getFilePath(before)); - } - } final ShelvedChangeList finalShelve = shelve; - try { - waitForChanges(); - HashMap lists = new HashMap(); - for (LocalChangeList localChangeList : myChangeManager.getChangeLists()) { - lists.put(localChangeList.getName(), localChangeList); + + final Continuation continuation = new Continuation(myProject, true); + final Consumer exceptionConsumer = new Consumer() { + @Override + public void consume(VcsException e) { + GitUIUtil.showTabErrors(myProject, "Failed to restore shelved lists", Collections.singletonList(e)); + ToolWindowManager.getInstance(myProject).notifyByBalloon(ChangesViewContentManager.TOOLWINDOW_ID, MessageType.ERROR, + "Failed to process restore shelved change list: " + + finalShelve.DESCRIPTION + + ". Please restore it manually."); } - LocalChangeList defaultList = myChangeManager.getDefaultChangeList(); - for (ChangeListInfo changeListInfo : changes.CHANGE_LISTS) { - LocalChangeList changeList = lists.get(changeListInfo.NAME); - if (changeList == null) { - changeList = myChangeManager.addChangeList(changeListInfo.NAME, changeListInfo.COMMENT); - lists.put(changeListInfo.NAME, changeList); + }; + continuation.addExceptionHandler(VcsException.class, exceptionConsumer); + final ContinuationContext.GatheringContinuationContext initContext = + new ContinuationContext.GatheringContinuationContext(); + GitStashUtils.doSystemUnshelve(myProject, shelve, myShelveManager, new Runnable() { + @Override + public void run() { + final HashMap, String> parsedChanges = new HashMap, String>(); + for (ChangeInfo changeInfo : changes.CHANGES) { + String before = changeInfo.BEFORE_PATH; + String after = changeInfo.AFTER_PATH; + parsedChanges.put(Pair.create(before, after), changeInfo.CHANGE_LIST_NAME); } - if (changeListInfo.IS_DEFAULT) { - myChangeManager.setDefaultChangeList(changeList); + try { + HashMap lists = new HashMap(); + final List existedChangeLists = myChangeManager.getChangeLists(); + for (LocalChangeList localChangeList : existedChangeLists) { + lists.put(localChangeList.getName(), localChangeList); + } + LocalChangeList defaultList = myChangeManager.getDefaultChangeList(); + for (ChangeListInfo changeListInfo : changes.CHANGE_LISTS) { + LocalChangeList changeList = lists.get(changeListInfo.NAME); + if (changeList == null) { + changeList = myChangeManager.addChangeList(changeListInfo.NAME, changeListInfo.COMMENT); + lists.put(changeListInfo.NAME, changeList); + } + if (changeListInfo.IS_DEFAULT) { + myChangeManager.setDefaultChangeList(changeList); + } + } + for (Change change : defaultList.getChanges()) { + ContentRevision beforeRevision = change.getBeforeRevision(); + String before = beforeRevision == null ? null : beforeRevision.getFile().getPath(); + ContentRevision afterRevision = change.getAfterRevision(); + String after = afterRevision == null ? null : afterRevision.getFile().getPath(); + Pair key = Pair.create(before, after); + String listName = parsedChanges.get(key); + assert listName != null : "List name should be found: " + key; + if (!listName.equals(defaultList.getName())) { + LocalChangeList changeList = lists.get(listName); + assert changeList != null : "Change List should be found: " + listName; + myChangeManager.moveChangesTo(changeList, new Change[]{change}); + } + } + } + catch (Throwable t) { + exceptionConsumer.consume(new VcsException(t)); } } - for (Change change : defaultList.getChanges()) { - ContentRevision beforeRevision = change.getBeforeRevision(); - String before = beforeRevision == null ? null : beforeRevision.getFile().getPath(); - ContentRevision afterRevision = change.getAfterRevision(); - String after = afterRevision == null ? null : afterRevision.getFile().getPath(); - Pair key = Pair.create(before, after); - String listName = parsedChanges.get(key); - assert listName != null : "List name should be found: " + key; - if (!listName.equals(defaultList.getName())) { - LocalChangeList changeList = lists.get(listName); - assert changeList != null : "Change List should be found: " + listName; - myChangeManager.moveChangesTo(changeList, new Change[]{change}); - } - } - return true; - } - catch (Throwable t) { - //noinspection ThrowableInstanceNeverThrown - myExceptions.add( - new VcsException("Failed to process restore shelved change list: " + finalShelve.DESCRIPTION + ". Please restore it manually.", t)); - return false; - } + }, initContext); + continuation.run(initContext.getList()); } /** diff --git a/plugins/git4idea/src/git4idea/history/GitHistoryUtils.java b/plugins/git4idea/src/git4idea/history/GitHistoryUtils.java index 226eef9240fe..9b9ebca04d64 100644 --- a/plugins/git4idea/src/git4idea/history/GitHistoryUtils.java +++ b/plugins/git4idea/src/git4idea/history/GitHistoryUtils.java @@ -36,7 +36,10 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.AsynchConsumer; import com.intellij.util.Consumer; import com.intellij.util.concurrency.Semaphore; -import git4idea.*; +import git4idea.GitBranch; +import git4idea.GitFileRevision; +import git4idea.GitRevisionNumber; +import git4idea.GitUtil; import git4idea.commands.*; import git4idea.config.GitConfigUtil; import git4idea.history.browser.GitCommit; @@ -659,9 +662,9 @@ public class GitHistoryUtils { final ChangeListManager changeManager = ChangeListManager.getInstance(project); final Change change = changeManager.getChange(path); if (change != null && change.getType() == Change.Type.MOVED) { - GitContentRevision r = (GitContentRevision)change.getBeforeRevision(); - assert r != null : "Move change always have beforeRevision"; - path = r.getFile(); + // GitContentRevision r = (GitContentRevision)change.getBeforeRevision(); + assert change.getBeforeRevision() != null : "Move change always have beforeRevision"; + path = change.getBeforeRevision().getFile(); } return path; } diff --git a/plugins/git4idea/src/git4idea/merge/GitMergeUtil.java b/plugins/git4idea/src/git4idea/merge/GitMergeUtil.java index a149f39ade98..41342adb7669 100644 --- a/plugins/git4idea/src/git4idea/merge/GitMergeUtil.java +++ b/plugins/git4idea/src/git4idea/merge/GitMergeUtil.java @@ -170,7 +170,7 @@ public class GitMergeUtil { action.delayTask(new TransactionRunnable() { public void run(List exceptionList) { ProjectLevelVcsManagerEx manager = (ProjectLevelVcsManagerEx)ProjectLevelVcsManager.getInstance(project); - UpdateInfoTree tree = manager.showUpdateProjectInfo(files, actionName, actionInfo); + UpdateInfoTree tree = manager.showUpdateProjectInfo(files, actionName, actionInfo, false); tree.setBefore(beforeLabel); tree.setAfter(LocalHistory.getInstance().putSystemLabel(project, "After update")); } diff --git a/plugins/git4idea/src/git4idea/update/GitChangesSaver.java b/plugins/git4idea/src/git4idea/update/GitChangesSaver.java index 4dc87f34edd1..6c65d9d7f714 100644 --- a/plugins/git4idea/src/git4idea/update/GitChangesSaver.java +++ b/plugins/git4idea/src/git4idea/update/GitChangesSaver.java @@ -17,20 +17,19 @@ package git4idea.update; import com.intellij.notification.Notification; import com.intellij.notification.NotificationListener; -import com.intellij.notification.NotificationType; -import com.intellij.notification.Notifications; -import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.Project; import com.intellij.openapi.vcs.FilePath; import com.intellij.openapi.vcs.VcsException; -import com.intellij.openapi.vcs.changes.*; +import com.intellij.openapi.vcs.changes.Change; +import com.intellij.openapi.vcs.changes.ChangeListManagerEx; +import com.intellij.openapi.vcs.changes.LocalChangeList; +import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.util.ui.UIUtil; -import git4idea.GitVcs; +import com.intellij.util.Consumer; +import com.intellij.util.continuation.ContinuationContext; import git4idea.config.GitVcsSettings; -import git4idea.i18n.GitBundle; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -100,22 +99,10 @@ public abstract class GitChangesSaver { /** * Loads local changes from stash or shelf, and sorts the changes back to the change lists they were before update. + * @param context */ - public void restoreLocalChanges() throws VcsException { - load(); - myDirtyScopeManager.filePathsDirty(getChangedFiles(), null); - restoreChangeLists(); - } - - public void notifyLocalChangesAreNotRestored() { - if (wereChangesSaved()) { - LOG.info("Update is incomplete, changes are not restored"); - Notifications.Bus.notify(new Notification(GitVcs.IMPORTANT_ERROR_NOTIFICATION, "Local changes were not restored", - "Before update your uncommitted changes were saved to " + getSaverName() + "
" + - "Update is not complete, you have unresolved merges in your working tree
" + - "Resolve conflicts, complete update and restore changes manually.", NotificationType.WARNING, - new ShowSavedChangesNotificationListener())); - } + public void restoreLocalChanges(ContinuationContext context) { + load(getRestoreListsRunnable(), context); } public List getChangeLists() { @@ -148,8 +135,10 @@ public abstract class GitChangesSaver { /** * Loads the changes - specific for chosen save strategy. + * @param restoreListsRunnable + * @param exceptionConsumer */ - protected abstract void load() throws VcsException; + protected abstract void load(@Nullable Runnable restoreListsRunnable, ContinuationContext exceptionConsumer); /** * @return true if there were local changes to save. @@ -166,28 +155,23 @@ public abstract class GitChangesSaver { */ protected abstract void showSavedChanges(); - // Move files back to theirs change lists - private void restoreChangeLists() { - UIUtil.invokeLaterIfNeeded(new Runnable() { + private Runnable getRestoreListsRunnable() { + return new Runnable() { public void run() { - myChangeManager.invokeAfterUpdate(new Runnable() { - public void run() { - if (myChangeLists == null) { - return; - } - LOG.info("restoreChangeLists " + myChangeLists); - for (LocalChangeList changeList : myChangeLists) { - final Collection changes = changeList.getChanges(); - LOG.debug( "restoreProjectChangesAfterUpdate.invokeAfterUpdate changeList: " + changeList.getName() + " changes: " + changes.size()); - if (!changes.isEmpty()) { - LOG.debug("After restoring files: moving " + changes.size() + " changes to '" + changeList.getName() + "'"); - myChangeManager.moveChangesTo(changeList, changes.toArray(new Change[changes.size()])); - } - } + if (myChangeLists == null) { + return; + } + LOG.info("restoreChangeLists " + myChangeLists); + for (LocalChangeList changeList : myChangeLists) { + final Collection changes = changeList.getChanges(); + LOG.debug( "restoreProjectChangesAfterUpdate.invokeAfterUpdate changeList: " + changeList.getName() + " changes: " + changes.size()); + if (!changes.isEmpty()) { + LOG.debug("After restoring files: moving " + changes.size() + " changes to '" + changeList.getName() + "'"); + myChangeManager.moveChangesTo(changeList, changes.toArray(new Change[changes.size()])); } - }, InvokeAfterUpdateMode.BACKGROUND_NOT_CANCELLABLE, GitBundle.getString("update.restoring.change.lists"), ModalityState.NON_MODAL); + } } - }); + }; } protected class ShowSavedChangesNotificationListener implements NotificationListener { diff --git a/plugins/git4idea/src/git4idea/update/GitShelveChangesSaver.java b/plugins/git4idea/src/git4idea/update/GitShelveChangesSaver.java index a47348d8900f..3691a7c68677 100644 --- a/plugins/git4idea/src/git4idea/update/GitShelveChangesSaver.java +++ b/plugins/git4idea/src/git4idea/update/GitShelveChangesSaver.java @@ -26,6 +26,8 @@ import com.intellij.openapi.vcs.changes.shelf.ShelveChangesManager; import com.intellij.openapi.vcs.changes.shelf.ShelvedChangeList; import com.intellij.openapi.vcs.changes.shelf.ShelvedChangesViewManager; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.continuation.Continuation; +import com.intellij.util.continuation.ContinuationContext; import git4idea.GitUtil; import git4idea.i18n.GitBundle; import org.jetbrains.annotations.NotNull; @@ -68,17 +70,12 @@ public class GitShelveChangesSaver extends GitChangesSaver { } } - protected void load() throws VcsException { + protected void load(Runnable restoreListsRunnable, ContinuationContext context) { if (myShelvedChangeList != null) { LOG.info("load "); myProgressIndicator.setText(GitBundle.getString("update.unshelving.changes")); if (myShelvedChangeList != null) { - List exceptions = new ArrayList(1); - GitStashUtils.doSystemUnshelve(myProject, myShelvedChangeList, myShelveManager, myChangeManager, exceptions); - if (!exceptions.isEmpty()) { - LOG.info("load " + exceptions, exceptions.get(0)); - throw exceptions.get(0); - } + GitStashUtils.doSystemUnshelve(myProject, myShelvedChangeList, myShelveManager, restoreListsRunnable, context); } } } diff --git a/plugins/git4idea/src/git4idea/update/GitStashChangesSaver.java b/plugins/git4idea/src/git4idea/update/GitStashChangesSaver.java index 9cf6e5bf1705..7045a8d615bc 100644 --- a/plugins/git4idea/src/git4idea/update/GitStashChangesSaver.java +++ b/plugins/git4idea/src/git4idea/update/GitStashChangesSaver.java @@ -19,6 +19,7 @@ import com.intellij.notification.Notification; import com.intellij.notification.NotificationListener; import com.intellij.notification.NotificationType; import com.intellij.notification.Notifications; +import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.Project; @@ -27,20 +28,25 @@ import com.intellij.openapi.vcs.ObjectsConvertor; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.changes.Change; import com.intellij.openapi.vcs.changes.ContentRevision; +import com.intellij.openapi.vcs.changes.InvokeAfterUpdateMode; import com.intellij.openapi.vcs.changes.LocalChangeList; import com.intellij.openapi.vcs.history.VcsRevisionNumber; import com.intellij.openapi.vcs.merge.MergeDialogCustomizer; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.continuation.ContinuationContext; +import com.intellij.util.ui.UIUtil; import git4idea.GitUtil; import git4idea.GitVcs; import git4idea.commands.*; import git4idea.config.GitVcsSettings; import git4idea.convert.GitFileSeparatorConverter; +import git4idea.i18n.GitBundle; import git4idea.merge.GitMergeConflictResolver; import git4idea.ui.GitUIUtil; import git4idea.ui.GitUnstashDialog; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import javax.swing.event.HyperlinkEvent; import java.io.File; @@ -70,15 +76,28 @@ public class GitStashChangesSaver extends GitChangesSaver { } @Override - protected void load() throws VcsException { + protected void load(@Nullable final Runnable restoreListsRunnable, ContinuationContext context) { for (VirtualFile root : myStashedRoots) { - loadRoot(root); + try { + loadRoot(root); + } + catch (VcsException e) { + context.handleException(e); + } } final List files = ObjectsConvertor.fp2jiof(getChangedFiles()); LocalFileSystem.getInstance().refreshIoFiles(files); + if (restoreListsRunnable != null) { + UIUtil.invokeLaterIfNeeded(new Runnable() { + public void run() { + myChangeManager.invokeAfterUpdate(restoreListsRunnable, InvokeAfterUpdateMode.BACKGROUND_NOT_CANCELLABLE, + GitBundle.getString("update.restoring.change.lists"), ModalityState.NON_MODAL); + } + }); + } } - @Override + @Override protected boolean wereChangesSaved() { return !myStashedRoots.isEmpty(); } diff --git a/plugins/git4idea/src/git4idea/update/GitStashUtils.java b/plugins/git4idea/src/git4idea/update/GitStashUtils.java index db8af8d0406c..68fef5735da6 100644 --- a/plugins/git4idea/src/git4idea/update/GitStashUtils.java +++ b/plugins/git4idea/src/git4idea/update/GitStashUtils.java @@ -15,13 +15,18 @@ */ package git4idea.update; +import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.progress.AsynchronousExecution; import com.intellij.openapi.project.Project; +import com.intellij.openapi.vcs.AbstractVcsHelper; import com.intellij.openapi.vcs.FilePath; import com.intellij.openapi.vcs.FileStatus; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.changes.Change; -import com.intellij.openapi.vcs.changes.ChangeListManagerEx; +import com.intellij.openapi.vcs.changes.ChangeListManager; +import com.intellij.openapi.vcs.changes.InvokeAfterUpdateMode; +import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager; import com.intellij.openapi.vcs.changes.shelf.ShelveChangesManager; import com.intellij.openapi.vcs.changes.shelf.ShelvedBinaryFile; import com.intellij.openapi.vcs.changes.shelf.ShelvedChange; @@ -29,7 +34,9 @@ import com.intellij.openapi.vcs.changes.shelf.ShelvedChangeList; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.Consumer; -import com.intellij.util.ui.UIUtil; +import com.intellij.util.continuation.ContinuationContext; +import com.intellij.util.continuation.TaskDescriptor; +import com.intellij.util.continuation.Where; import com.intellij.vcsUtil.VcsUtil; import git4idea.GitUtil; import git4idea.GitVcs; @@ -110,20 +117,87 @@ public class GitStashUtils { * @param project the project * @param shelvedChangeList the shelved change list * @param shelveManager the shelve manager - * @param changeManager the change manager - * @param exceptions the collected exceptions + * @param restoreListsRunnable */ + @AsynchronousExecution public static void doSystemUnshelve(final Project project, final ShelvedChangeList shelvedChangeList, final ShelveChangesManager shelveManager, - final ChangeListManagerEx changeManager, - List exceptions) { - LOG.info("doSystemUnshelve "); - // The changes are temporary copied to the first local change list, the next operation will restore them back + @NotNull final Runnable restoreListsRunnable, + final @NotNull ContinuationContext context) { VirtualFile baseDir = project.getBaseDir(); assert baseDir != null; - String projectPath = baseDir.getPath() + "/"; - // Refresh files that might be affected by unshelve + final String projectPath = baseDir.getPath() + "/"; + + context.next(new TaskDescriptor("Refreshing files before unshelve", Where.POOLED) { + @Override + public void run(ContinuationContext context) { + LOG.info("doSystemUnshelve "); + // The changes are temporary copied to the first local change list, the next operation will restore them back + // Refresh files that might be affected by unshelve + refreshFilesBeforeUnshelve(shelvedChangeList, projectPath); + + LOG.info("doSystemUnshelve files refreshed. unshelving in AWT thread."); + } + }, new TaskDescriptor("", Where.AWT) { + @Override + public void run(ContinuationContext context) { + GitVFSListener l = GitVcs.getInstance(project).getVFSListener(); + l.setEventsSuppressed(true); + + LOG.info("Unshelving in UI thread. shelvedChangeList: " + shelvedChangeList); + // we pass null as target change list for Patch Applier to do NOTHING with change lists + shelveManager.scheduleUnshelveChangeList(shelvedChangeList, shelvedChangeList.getChanges(), + shelvedChangeList.getBinaryFiles(), null, false, context); + } + }, new TaskDescriptor("", Where.AWT) { + @Override + public void run(ContinuationContext context) { + LOG.info("Deleting change list"); + shelveManager.deleteChangeList(shelvedChangeList); + GitVcs.getInstance(project).getVFSListener().setEventsSuppressed(false); + addFilesAfterUnshelve(project, shelvedChangeList, projectPath, context); + ChangeListManager.getInstance(project).invokeAfterUpdate(new Runnable() { + @Override + public void run() { + restoreListsRunnable.run(); + } + }, InvokeAfterUpdateMode.BACKGROUND_NOT_CANCELLABLE_NOT_AWT, "Restoring changelists", ModalityState.NON_MODAL); + } + }); + } + + private static void addFilesAfterUnshelve(Project project, + ShelvedChangeList shelvedChangeList, + String projectPath, ContinuationContext context) { + Collection paths = new ArrayList(); + for (ShelvedChange c : shelvedChangeList.getChanges()) { + if (c.getBeforePath() == null || !c.getBeforePath().equals(c.getAfterPath()) || c.getFileStatus() == FileStatus.ADDED) { + paths.add(VcsUtil.getFilePath(projectPath + c.getAfterPath())); + } + } + for (ShelvedBinaryFile f : shelvedChangeList.getBinaryFiles()) { + if (f.BEFORE_PATH == null || !f.BEFORE_PATH.equals(f.AFTER_PATH) || f.getFileStatus() == FileStatus.ADDED) { + paths.add(VcsUtil.getFilePath(projectPath + f.AFTER_PATH)); + } + } + final VcsDirtyScopeManager dsm = VcsDirtyScopeManager.getInstance(project); + Map> map = GitUtil.sortGitFilePathsByGitRoot(paths); + for (Map.Entry> e : map.entrySet()) { + try { + GitFileUtils.addPaths(project, e.getKey(), e.getValue()); + dsm.filePathsDirty(e.getValue(), null); + } + catch (VcsException e1) { + if (! context.handleException(e1)) { + AbstractVcsHelper.getInstance(project).showError(e1, "Can not add file to Git"); + LOG.error("Vcs Exception not handled"); + } + } + } + } + + private static void refreshFilesBeforeUnshelve(ShelvedChangeList shelvedChangeList, String projectPath) { HashSet filesToRefresh = new HashSet(); for (ShelvedChange c : shelvedChangeList.getChanges()) { if (c.getBeforePath() != null) { @@ -142,45 +216,6 @@ public class GitStashUtils { } } LocalFileSystem.getInstance().refreshIoFiles(filesToRefresh); - LOG.info("doSystemUnshelve files refreshed. unshelving in AWT thread."); - // Do unshevle - UIUtil.invokeAndWaitIfNeeded(new Runnable() { - public void run() { - GitVFSListener l = GitVcs.getInstance(project).getVFSListener(); - l.setEventsSuppressed(true); - try { - LOG.info("Unshelving in UI thread. shelvedChangeList: " + shelvedChangeList); - shelveManager - .unshelveChangeList(shelvedChangeList, shelvedChangeList.getChanges(), shelvedChangeList.getBinaryFiles(), - changeManager.getDefaultChangeList(), false); - LOG.info("Deleting change list"); - shelveManager.deleteChangeList(shelvedChangeList); - } - finally { - l.setEventsSuppressed(false); - } - } - }); - Collection paths = new ArrayList(); - for (ShelvedChange c : shelvedChangeList.getChanges()) { - if (c.getBeforePath() == null || !c.getBeforePath().equals(c.getAfterPath()) || c.getFileStatus() == FileStatus.ADDED) { - paths.add(VcsUtil.getFilePath(projectPath + c.getAfterPath())); - } - } - for (ShelvedBinaryFile f : shelvedChangeList.getBinaryFiles()) { - if (f.BEFORE_PATH == null || !f.BEFORE_PATH.equals(f.AFTER_PATH) || f.getFileStatus() == FileStatus.ADDED) { - paths.add(VcsUtil.getFilePath(projectPath + f.AFTER_PATH)); - } - } - Map> map = GitUtil.sortGitFilePathsByGitRoot(paths); - for (Map.Entry> e : map.entrySet()) { - try { - GitFileUtils.addPaths(project, e.getKey(), e.getValue()); - } - catch (VcsException e1) { - exceptions.add(e1); - } - } } /** diff --git a/plugins/git4idea/src/git4idea/update/GitUpdateEnvironment.java b/plugins/git4idea/src/git4idea/update/GitUpdateEnvironment.java index 63c8fe0240e5..886ce1fb35d9 100644 --- a/plugins/git4idea/src/git4idea/update/GitUpdateEnvironment.java +++ b/plugins/git4idea/src/git4idea/update/GitUpdateEnvironment.java @@ -27,6 +27,10 @@ import com.intellij.openapi.vcs.update.UpdateEnvironment; import com.intellij.openapi.vcs.update.UpdateSession; import com.intellij.openapi.vcs.update.UpdatedFiles; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.continuation.Continuation; +import com.intellij.util.continuation.ContinuationContext; +import com.intellij.util.continuation.TaskDescriptor; +import com.intellij.util.continuation.Where; import git4idea.GitUtil; import git4idea.GitVcs; import git4idea.config.GitVcsSettings; @@ -61,7 +65,8 @@ public class GitUpdateEnvironment implements UpdateEnvironment { @NotNull public UpdateSession updateDirectories(@NotNull FilePath[] filePaths, UpdatedFiles updatedFiles, ProgressIndicator progressIndicator, @NotNull Ref sequentialUpdatesContextRef) throws ProcessCanceledException { Set roots = GitUtil.gitRoots(Arrays.asList(filePaths)); - boolean result = new GitUpdateProcess(myProject, progressIndicator, roots, updatedFiles).update(); + final GitUpdateProcess gitUpdateProcess = new GitUpdateProcess(myProject, progressIndicator, roots, updatedFiles); + boolean result = gitUpdateProcess.update(false, false); return new GitUpdateSession(result); } diff --git a/plugins/git4idea/src/git4idea/update/GitUpdateLikeProcess.java b/plugins/git4idea/src/git4idea/update/GitUpdateLikeProcess.java new file mode 100644 index 000000000000..91469e800a43 --- /dev/null +++ b/plugins/git4idea/src/git4idea/update/GitUpdateLikeProcess.java @@ -0,0 +1,82 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package git4idea.update; + +import com.intellij.ide.GeneralSettings; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.project.ex.ProjectManagerEx; +import com.intellij.util.continuation.Continuation; +import com.intellij.util.continuation.ContinuationContext; +import com.intellij.util.continuation.TaskDescriptor; +import com.intellij.util.continuation.Where; +import com.intellij.util.ui.UIUtil; + +/** + * @author irengrig + * Date: 3/31/11 + * Time: 2:59 PM + */ +public abstract class GitUpdateLikeProcess { + private final Project myProject; + private GeneralSettings myGeneralSettings; + private ProjectManagerEx myProjectManager; + + public GitUpdateLikeProcess(final Project project) { + myProject = project; + myGeneralSettings = GeneralSettings.getInstance(); + myProjectManager = ProjectManagerEx.getInstanceEx(); + } + + public void execute() { + final boolean saveOnFrameDeactivation = myGeneralSettings.isSaveOnFrameDeactivation(); + final boolean syncOnFrameDeactivation = myGeneralSettings.isSyncOnFrameActivation(); + myProjectManager.blockReloadingProjectOnExternalChanges(); + UIUtil.invokeAndWaitIfNeeded(new Runnable() { + @Override + public void run() { + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + FileDocumentManager.getInstance().saveAllDocuments(); + myGeneralSettings.setSaveOnFrameDeactivation(false); + myGeneralSettings.setSyncOnFrameActivation(false); + } + }); + } + }); + + final Continuation continuation = new Continuation(myProject, true); + final ContinuationContext.GatheringContinuationContext initContext = new ContinuationContext.GatheringContinuationContext(); + initContext.next(new TaskDescriptor("Git: updating", Where.POOLED) { + @Override + public void run(final ContinuationContext context) { + runImpl(context); + } + }, new TaskDescriptor("", Where.AWT) { + @Override + public void run(ContinuationContext context) { + myProjectManager.unblockReloadingProjectOnExternalChanges(); + myGeneralSettings.setSaveOnFrameDeactivation(saveOnFrameDeactivation); + myGeneralSettings.setSyncOnFrameActivation(syncOnFrameDeactivation); + } + }); + continuation.runAndWait(initContext.getList()); + } + + protected abstract void runImpl(ContinuationContext context); +} diff --git a/plugins/git4idea/src/git4idea/update/GitUpdateProcess.java b/plugins/git4idea/src/git4idea/update/GitUpdateProcess.java index 46cb33c88244..e647da504b36 100644 --- a/plugins/git4idea/src/git4idea/update/GitUpdateProcess.java +++ b/plugins/git4idea/src/git4idea/update/GitUpdateProcess.java @@ -17,9 +17,7 @@ package git4idea.update; import com.intellij.ide.GeneralSettings; import com.intellij.notification.NotificationType; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ex.ProjectManagerEx; @@ -27,8 +25,9 @@ import com.intellij.openapi.util.Clock; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.update.UpdatedFiles; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.Consumer; +import com.intellij.util.continuation.ContinuationContext; import com.intellij.util.text.DateFormatUtil; -import com.intellij.util.ui.UIUtil; import git4idea.GitBranch; import git4idea.branch.GitBranchPair; import git4idea.merge.GitMergeConflictResolver; @@ -81,7 +80,7 @@ public class GitUpdateProcess { * In case of error shows notification and returns false. If update completes without errors, returns true. */ public boolean update() { - return update(false); + return update(false, true); } /** @@ -96,28 +95,25 @@ public class GitUpdateProcess { * @param forceRebase * @return */ - public boolean update(boolean forceRebase) { + public boolean update(final boolean forceRebase, final boolean restoreChangesRightNow) { LOG.info("update started|" + (forceRebase ? " force rebase" : "")); if (!fetchAndNotify()) { return false; } - final boolean saveOnFrameDeactivation = myGeneralSettings.isSaveOnFrameDeactivation(); - final boolean syncOnFrameDeactivation = myGeneralSettings.isSyncOnFrameActivation(); - myProjectManager.blockReloadingProjectOnExternalChanges(); - UIUtil.invokeAndWaitIfNeeded(new Runnable() { - @Override public void run() { - ApplicationManager.getApplication().runWriteAction(new Runnable() { - @Override public void run() { - FileDocumentManager.getInstance().saveAllDocuments(); - myGeneralSettings.setSaveOnFrameDeactivation(false); - myGeneralSettings.setSyncOnFrameActivation(false); - } - }); + final Boolean[] result = new Boolean[1]; + result[0] = false; + new GitUpdateLikeProcess(myProject) { + @Override + protected void runImpl(ContinuationContext context) { + result[0] = updateImpl(forceRebase, context); } - }); + }.execute(); + return result[0]; + } + private boolean updateImpl(boolean forceRebase, ContinuationContext context) { try { // check if update is possible if (checkRebaseInProgress() || checkMergeInProgress() || checkUnmergedFiles()) { return false; } @@ -148,7 +144,6 @@ public class GitUpdateProcess { mySaver.saveLocalChanges(rootsToSave); // update each root - boolean incomplete = false; boolean success = true; VirtualFile currentlyUpdatedRoot = null; try { @@ -157,9 +152,6 @@ public class GitUpdateProcess { GitUpdater updater = entry.getValue(); GitUpdateResult res = updater.update(); LOG.info("updating root " + currentlyUpdatedRoot + " finished: " + res); - if (res == GitUpdateResult.INCOMPLETE) { - incomplete = true; - } success &= res.isSuccess(); } } catch (VcsException e) { @@ -168,17 +160,7 @@ public class GitUpdateProcess { notifyImportantError(myProject, "Error updating " + rootName, "Updating " + rootName + " failed with an error: " + e.getLocalizedMessage()); } finally { - try { - if (!incomplete) { - mySaver.restoreLocalChanges(); - } else { - mySaver.notifyLocalChangesAreNotRestored(); - } - } catch (VcsException e) { - LOG.info("Couldn't restore local changes after update", e); - notifyImportantError(myProject, "Couldn't restore local changes after update", - "Restoring changes saved before update failed with an error.
" + e.getLocalizedMessage()); - } + restoreLocalChanges(context); } return success; } catch (VcsException e) { @@ -186,12 +168,20 @@ public class GitUpdateProcess { notifyError(myProject, "Couldn't save local changes", "Tried to save uncommitted changes in " + mySaver.getSaverName() + " before update, but failed with an error.
" + "Update was cancelled.", true, e); - } finally { - myProjectManager.unblockReloadingProjectOnExternalChanges(); - myGeneralSettings.setSaveOnFrameDeactivation(saveOnFrameDeactivation); - myGeneralSettings.setSyncOnFrameActivation(syncOnFrameDeactivation); + return false; } - return false; + } + + public void restoreLocalChanges(ContinuationContext context) { + context.addExceptionHandler(VcsException.class, new Consumer() { + @Override + public void consume(VcsException e) { + LOG.info("Couldn't restore local changes after reordering commits", e); + notifyImportantError(myProject, "Couldn't restore local changes after update", + "Restoring changes saved before update failed with an error.
" + e.getLocalizedMessage()); + } + }); + mySaver.restoreLocalChanges(context); } // fetch all roots. If an error happens, return false and notify about errors. diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/MavenModuleWizardStep.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/MavenModuleWizardStep.java index d761d5f3ba1d..2cc11707e3bc 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/MavenModuleWizardStep.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/MavenModuleWizardStep.java @@ -157,17 +157,7 @@ public class MavenModuleWizardStep extends ModuleWizardStep { MavenArchetype info = getArchetypeInfoFromPathComponent(path.getLastPathComponent()); return info.groupId + ":" + info.artifactId + ":" + info.version; } - }).setComparator(new SpeedSearchBase.SpeedSearchComparator(false) { - @Override - public void translateCharacter(StringBuilder buf, char ch) { - if (ch == '*') { - buf.append("(.)*"); - } - else { - super.translateCharacter(buf, ch); - } - } - }); + }).setComparator(new SpeedSearchBase.SpeedSearchComparator(false)); myArchetypeDescriptionField.setEditable(false); myArchetypeDescriptionField.setBackground(UIUtil.getPanelBackground()); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/integrate/SvnIntegrateChangesTask.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/integrate/SvnIntegrateChangesTask.java index 156b9c59dcc7..2307146b8cca 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/integrate/SvnIntegrateChangesTask.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/integrate/SvnIntegrateChangesTask.java @@ -248,7 +248,7 @@ public class SvnIntegrateChangesTask extends Task.Backgroundable { RestoreUpdateTree restoreUpdateTree = RestoreUpdateTree.getInstance(myProject); // action info is actually NOT used restoreUpdateTree.registerUpdateInformation(myAccomulatedFiles.getUpdatedFiles(), ActionInfo.INTEGRATE); - myProjectLevelVcsManager.showUpdateProjectInfo(myAccomulatedFiles.getUpdatedFiles(), myTitle, ActionInfo.INTEGRATE); + myProjectLevelVcsManager.showUpdateProjectInfo(myAccomulatedFiles.getUpdatedFiles(), myTitle, ActionInfo.INTEGRATE, false); } private void doStatus(final Consumer afterStatus) { diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/update/AbstractSvnUpdateIntegrateEnvironment.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/update/AbstractSvnUpdateIntegrateEnvironment.java index 40b60d6d147e..71d0735a70da 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/update/AbstractSvnUpdateIntegrateEnvironment.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/update/AbstractSvnUpdateIntegrateEnvironment.java @@ -89,8 +89,8 @@ public abstract class AbstractSvnUpdateIntegrateEnvironment implements UpdateEnv } }); for (FilePath contentRoot : contentRoots) { - if (progressIndicator != null && progressIndicator.isCanceled()) { - throw new ProcessCanceledException(); + if (progressIndicator != null) { + progressIndicator.checkCanceled(); } final File ioRoot = contentRoot.getIOFile(); if (! ((SvnUpdateContext)context.get()).shouldRunFor(ioRoot)) continue; diff --git a/xml/impl/src/com/intellij/xml/actions/xmlbeans/GenerateInstanceDocumentFromSchemaAction.java b/xml/impl/src/com/intellij/xml/actions/xmlbeans/GenerateInstanceDocumentFromSchemaAction.java index 4299df21b83b..fbb4fd56d5d5 100644 --- a/xml/impl/src/com/intellij/xml/actions/xmlbeans/GenerateInstanceDocumentFromSchemaAction.java +++ b/xml/impl/src/com/intellij/xml/actions/xmlbeans/GenerateInstanceDocumentFromSchemaAction.java @@ -39,10 +39,10 @@ import gnu.trove.THashMap; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.Nullable; +import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; -import java.io.StringBufferInputStream; import java.util.LinkedList; import java.util.List; @@ -57,7 +57,7 @@ public class GenerateInstanceDocumentFromSchemaAction extends AnAction { e.getPresentation().setEnabled(enabled); if (ActionPlaces.isPopupPlace(e.getPlace())) { e.getPresentation().setVisible(enabled); - } + } } public void actionPerformed(AnActionEvent e) { @@ -113,12 +113,12 @@ public class GenerateInstanceDocumentFromSchemaAction extends AnAction { (XmlFile) PsiManager.getInstance(project).findFile(relativeFile), new THashMap(), new Xsd2InstanceUtils.SchemaReferenceProcessor() { - public void processSchema(String schemaFileName, String schemaContent) { + public void processSchema(String schemaFileName, byte[] schemaContent) { try { final String fullFileName = tempDir.getPath() + File.separatorChar + schemaFileName; FileUtils.saveStreamContentAsFile( fullFileName, - new StringBufferInputStream(schemaContent) + new ByteArrayInputStream(schemaContent) ); } catch (IOException e) { throw new RuntimeException(e); @@ -147,26 +147,30 @@ public class GenerateInstanceDocumentFromSchemaAction extends AnAction { final VirtualFile baseDirForCreatedInstanceDocument1 = relativeFileDir; String xmlFileName = baseDirForCreatedInstanceDocument1.getPath() + File.separatorChar + dialog.getOutputFileName(); - FileOutputStream fileOutputStream = null; + FileOutputStream fileOutputStream; try { fileOutputStream = new FileOutputStream(xmlFileName); - fileOutputStream.write(xml.getBytes()); - fileOutputStream.close(); - fileOutputStream = null; + try { + // the generated XML doesn't have any XML declaration -> utf-8 + fileOutputStream.write(xml.getBytes("utf-8")); + } + finally { + fileOutputStream.close(); + } + + final File xmlFile = new File(xmlFileName); + VirtualFile virtualFile = ApplicationManager.getApplication().runWriteAction(new Computable() { + @Nullable + public VirtualFile compute() { + return LocalFileSystem.getInstance().refreshAndFindFileByIoFile(xmlFile); + } + }); + FileEditorManager.getInstance(project).openFile(virtualFile, true); } catch (IOException e) { - e.printStackTrace(); + Messages.showErrorDialog(project, "Could not save generated XML document: " + StringUtil.getMessage(e), XmlBundle.message("error")); } - - final File xmlFile = new File(xmlFileName); - VirtualFile virtualFile = ApplicationManager.getApplication().runWriteAction(new Computable() { - @Nullable - public VirtualFile compute() { - return LocalFileSystem.getInstance().refreshAndFindFileByIoFile(xmlFile); - } - }); - FileEditorManager.getInstance(project).openFile(virtualFile, true); } static boolean isAcceptableFileForGenerateSchemaFromInstanceDocument(VirtualFile virtualFile) { diff --git a/xml/impl/src/com/intellij/xml/actions/xmlbeans/Xsd2InstanceUtils.java b/xml/impl/src/com/intellij/xml/actions/xmlbeans/Xsd2InstanceUtils.java index 0bb9ba882db5..c6c358eda169 100644 --- a/xml/impl/src/com/intellij/xml/actions/xmlbeans/Xsd2InstanceUtils.java +++ b/xml/impl/src/com/intellij/xml/actions/xmlbeans/Xsd2InstanceUtils.java @@ -15,6 +15,7 @@ */ package com.intellij.xml.actions.xmlbeans; +import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiReference; import com.intellij.psi.XmlRecursiveElementVisitor; @@ -28,12 +29,14 @@ import com.intellij.psi.xml.XmlTag; import com.intellij.xml.XmlElementDescriptor; import com.intellij.xml.XmlNSDescriptor; import com.intellij.xml.impl.schema.XmlNSDescriptorImpl; +import com.intellij.xml.util.XmlUtil; import org.apache.xmlbeans.*; import org.apache.xmlbeans.impl.tool.CommandLine; import org.apache.xmlbeans.impl.xsd2inst.SampleXmlUtil; import org.jetbrains.annotations.NotNull; import java.io.File; +import java.io.UnsupportedEncodingException; import java.util.*; @@ -85,7 +88,7 @@ public class Xsd2InstanceUtils { } catch (Exception e) { - throw new IllegalArgumentException("Can not load schema file: " + schemaFiles[i] + ": "); + throw new IllegalArgumentException("Can not load schema file: " + schemaFiles[i] + ": " + e.getLocalizedMessage()); } } @@ -145,7 +148,7 @@ public class Xsd2InstanceUtils { return null; } - + public static List addVariantsFromRootTag(XmlTag rootTag) { PsiMetaData metaData = rootTag.getMetaData(); if (metaData instanceof XmlNSDescriptorImpl) { @@ -217,11 +220,26 @@ public class Xsd2InstanceUtils { } }); - schemaReferenceProcessor.processSchema(fileName, result.toString()); + final VirtualFile virtualFile = file.getVirtualFile(); + final String content = result.toString(); + + byte[] bytes; + if (virtualFile != null) { + bytes = content.getBytes(virtualFile.getCharset()); + } else { + try { + final String charsetName = XmlUtil.extractXmlEncodingFromProlog(content.getBytes()); + bytes = charsetName != null ? content.getBytes(charsetName) : content.getBytes(); + } catch (UnsupportedEncodingException e) { + bytes = content.getBytes(); + } + } + + schemaReferenceProcessor.processSchema(fileName, bytes); return fileName; } public interface SchemaReferenceProcessor { - void processSchema(String schemaFileName, String schemaContent); + void processSchema(String schemaFileName, byte[] schemaContent); } }