diff --git a/images/src/org/intellij/images/fileTypes/impl/ImageFileTypeManagerImpl.java b/images/src/org/intellij/images/fileTypes/impl/ImageFileTypeManagerImpl.java index 761f578bb50f..d1af0a440dd6 100644 --- a/images/src/org/intellij/images/fileTypes/impl/ImageFileTypeManagerImpl.java +++ b/images/src/org/intellij/images/fileTypes/impl/ImageFileTypeManagerImpl.java @@ -23,6 +23,7 @@ import com.intellij.openapi.vfs.VirtualFile; import gnu.trove.THashSet; import org.intellij.images.ImagesBundle; import org.intellij.images.fileTypes.ImageFileTypeManager; +import org.intellij.images.vfs.IfsUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -76,15 +77,16 @@ final class ImageFileTypeManagerImpl extends ImageFileTypeManager implements App } public void createFileTypes(final @NotNull FileTypeConsumer consumer) { - final String[] readerFormatNames = ImageIO.getReaderFormatNames(); final Set processed = new THashSet(); + final String[] readerFormatNames = ImageIO.getReaderFormatNames(); for (String format : readerFormatNames) { - final String s = format.toLowerCase(); - if (processed.contains(s)) continue; - processed.add(s); + final String ext = format.toLowerCase(); + processed.add(ext); } + processed.add(IfsUtil.ICO_FORMAT.toLowerCase()); + consumer.consume(imageFileType, StringUtil.join(processed, FileTypeConsumer.EXTENSION_DELIMITER)); } } diff --git a/images/src/org/intellij/images/vfs/IfsUtil.java b/images/src/org/intellij/images/vfs/IfsUtil.java index 8e67e3f6de9d..bb2f1541f299 100644 --- a/images/src/org/intellij/images/vfs/IfsUtil.java +++ b/images/src/org/intellij/images/vfs/IfsUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,6 +27,9 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.reference.SoftReference; import com.intellij.util.LogicalRoot; import com.intellij.util.LogicalRootsManager; +import org.apache.sanselan.ImageReadException; +import org.apache.sanselan.common.byteSources.ByteSourceArray; +import org.apache.sanselan.formats.ico.IcoImageParser; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -46,9 +49,12 @@ import java.util.Iterator; * @author Alexey Efimov */ public final class IfsUtil { + public static final String ICO_FORMAT = "ico"; + private static final Key TIMESTAMP_KEY = Key.create("Image.timeStamp"); private static final Key FORMAT_KEY = Key.create("Image.format"); private static final Key> BUFFERED_IMAGE_REF_KEY = Key.create("Image.bufferedImage"); + private static final IcoImageParser ICO_IMAGE_PARSER = new IcoImageParser(); /** * Load image data for file and put user data attributes into file. @@ -63,6 +69,17 @@ public final class IfsUtil { if (loadedTimeStamp == null || loadedTimeStamp.longValue() != file.getTimeStamp() || imageRef == null || imageRef.get() == null) { try { final byte[] content = file.contentsToByteArray(); + + if (ICO_FORMAT.equalsIgnoreCase(file.getExtension())) { + try { + final BufferedImage image = ICO_IMAGE_PARSER.getBufferedImage(new ByteSourceArray(content), null); + file.putUserData(FORMAT_KEY, ICO_FORMAT); + file.putUserData(BUFFERED_IMAGE_REF_KEY, new SoftReference(image)); + return true; + } + catch (ImageReadException ignore) { } + } + InputStream inputStream = new ByteArrayInputStream(content, 0, content.length); ImageInputStream imageInputStream = ImageIO.createImageInputStream(inputStream); try { diff --git a/java/compiler/impl/src/com/intellij/compiler/CompileServerManager.java b/java/compiler/impl/src/com/intellij/compiler/CompileServerManager.java index ffbcdd9586d9..649db10233dd 100644 --- a/java/compiler/impl/src/com/intellij/compiler/CompileServerManager.java +++ b/java/compiler/impl/src/com/intellij/compiler/CompileServerManager.java @@ -284,13 +284,7 @@ public class CompileServerManager implements ApplicationComponent{ } try { for (RequestFuture future : futures) { - try { - future.get(); - } - catch (InterruptedException ignored) { - } - catch (java.util.concurrent.ExecutionException ignored) { - } + future.waitFor(); } } finally { @@ -447,7 +441,7 @@ public class CompileServerManager implements ApplicationComponent{ connected = client.connect(NetUtils.getLocalHostString(), port); if (connected) { final RequestFuture setupFuture = sendSetupRequest(client); - setupFuture.get(); + setupFuture.waitFor(); myProcessHandler = processHandler; myClient = client; } diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java b/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java index 857d42b0632b..0b1bf1f4605c 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java @@ -99,7 +99,7 @@ import org.jetbrains.jps.api.RequestFuture; import java.io.*; import java.util.*; -import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; public class CompileDriver { @@ -591,15 +591,10 @@ public class CompileDriver { final Set artifacts = ArtifactCompileScope.getArtifactsToBuild(myProject, compileContext.getCompileScope(), true); final RequestFuture future = compileOnServer(compileContext, modules, artifacts, paths, callback); if (future != null) { - try { - startCancelWatcher(indicator, future); - future.get(); - } - catch (InterruptedException e) { - LOG.error(e); // todo - } - catch (ExecutionException e) { - LOG.error(e); // todo + while (!future.waitFor(200L , TimeUnit.MILLISECONDS)) { + if (indicator.isCanceled()) { + future.cancel(true); + } } } else { @@ -686,27 +681,6 @@ public class CompileDriver { }); } - private static void startCancelWatcher(final ProgressIndicator indicator, final RequestFuture future) { - ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { - public void run() { - while (true) { - try { - Thread.sleep(200L); - if (future.isDone() || future.isCancelled()) { - break; - } - if (indicator.isCanceled()) { - future.cancel(true); - break; - } - } - catch (InterruptedException ignored) { - } - } - } - }); - } - private static List fetchFiles(CompileContextImpl context) { if (context.isRebuild()) { return Collections.emptyList(); diff --git a/java/java-impl/src/com/intellij/codeInsight/ExpectedTypesProvider.java b/java/java-impl/src/com/intellij/codeInsight/ExpectedTypesProvider.java index 128276a52113..dfba4c4c2224 100644 --- a/java/java-impl/src/com/intellij/codeInsight/ExpectedTypesProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/ExpectedTypesProvider.java @@ -590,7 +590,7 @@ public class ExpectedTypesProvider { } return; } - PsiExpression anotherExpr = index > 0 ? operands[0] : operands[1]; + PsiExpression anotherExpr = index > 0 ? operands[0] : index < operands.length ? operands[1] : null; PsiType anotherType = anotherExpr != null ? anotherExpr.getType() : null; IElementType i = expr.getOperationTokenType(); if (i == JavaTokenType.MINUS || diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/AnnotationsHighlightUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/AnnotationsHighlightUtil.java index 8f9282affd6f..017ec0dea27d 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/AnnotationsHighlightUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/AnnotationsHighlightUtil.java @@ -28,6 +28,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; import com.intellij.psi.*; import com.intellij.psi.impl.source.tree.java.PsiAnnotationImpl; +import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.TypeConversionUtil; import com.intellij.util.IncorrectOperationException; @@ -247,6 +248,38 @@ public class AnnotationsHighlightUtil { return highlightInfo; } + public static HighlightInfo checkForeignInnerClassesUsed(final PsiAnnotation annotation) { + final HighlightInfo[] infos = new HighlightInfo[1]; + final PsiAnnotationOwner owner = annotation.getOwner(); + if (owner instanceof PsiModifierList) { + final PsiElement parent = ((PsiModifierList)owner).getParent(); + if (parent instanceof PsiClass) { + annotation.accept(new JavaRecursiveElementWalkingVisitor() { + @Override + public void visitElement(PsiElement element) { + if (infos[0] != null) return; + super.visitElement(element); + } + + @Override + public void visitReferenceExpression(PsiReferenceExpression expression) { + super.visitReferenceExpression(expression); + final PsiElement resolve = expression.resolve(); + if (resolve instanceof PsiField && + ((PsiMember)resolve).hasModifierProperty(PsiModifier.PRIVATE) && + PsiTreeUtil.isAncestor(parent, resolve, true)) { + String description = JavaErrorMessages.message("private.symbol", + HighlightUtil.formatField((PsiField)resolve), + HighlightUtil.formatClass((PsiClass)parent)); + infos[0] = HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, expression, description); + } + } + }); + } + } + return infos[0]; + } + private static PsiField[] getFields(final PsiClass elementTypeClass, @NonNls final String... names) { PsiField[] result = new PsiField[names.length]; for (int i = 0; i < names.length; i++) { diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java index 90ffa0ab8fcf..e8a00be3524b 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java @@ -498,6 +498,7 @@ public class HighlightMethodUtil { AddTypeArgumentsFix.REGISTRAR.registerCastActions(methodCandidates, methodCall, highlightInfo, fixRange); registerMethodAccessLevelIntentions(methodCandidates, methodCall, list, highlightInfo); ChangeMethodSignatureFromUsageFix.registerIntentions(methodCandidates, list, highlightInfo, fixRange); + ConvertDoubleToFloatFix.registerIntentions(methodCandidates, list, highlightInfo, fixRange); WrapExpressionFix.registerWrapAction(methodCandidates, list.getExpressions(), highlightInfo); ChangeParameterClassFix.registerQuickFixActions(methodCall, list, highlightInfo); if (methodCandidates.length == 0) { @@ -1273,6 +1274,7 @@ public class HighlightMethodUtil { if (classReference != null) { ConstructorParametersFixer.registerFixActions(classReference, constructorCall, info, getFixRange(infoElement)); ChangeMethodSignatureFromUsageFix.registerIntentions(results, list, info, null); + ConvertDoubleToFloatFix.registerIntentions(results, list, info, null); PermuteArgumentsFix.registerFix(info, constructorCall, toMethodCandidates(results), getFixRange(list)); ChangeParameterClassFix.registerQuickFixActions(constructorCall, list, info); QuickFixAction.registerQuickFixAction(info, getFixRange(list), new SurroundWithArrayFix(constructorCall), null); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java index 1ac11d19ccaf..5d6a82078bc7 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java @@ -1014,7 +1014,7 @@ public class HighlightUtil { } // true if floating point literal consists of zeros only - private static boolean isFPZero(final String text) { + public static boolean isFPZero(final String text) { for (int i = 0; i < text.length(); i++) { final char c = text.charAt(i); if (Character.isDigit(c) && c != '0') return false; diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java index 8703ff06fd77..1c6f41d71759 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java @@ -184,6 +184,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh if (!myHolder.hasErrorResults()) myHolder.add(AnnotationsHighlightUtil.checkMissingAttributes(annotation)); if (!myHolder.hasErrorResults()) myHolder.add(AnnotationsHighlightUtil.checkTargetAnnotationDuplicates(annotation)); if (!myHolder.hasErrorResults()) myHolder.add(AnnotationsHighlightUtil.checkDuplicateAnnotations(annotation)); + if (!myHolder.hasErrorResults()) myHolder.add(AnnotationsHighlightUtil.checkForeignInnerClassesUsed(annotation)); } @Override public void visitAnnotationArrayInitializer(PsiArrayInitializerMemberValue initializer) { diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ConvertDoubleToFloatFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ConvertDoubleToFloatFix.java new file mode 100644 index 000000000000..cb8122b75a75 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ConvertDoubleToFloatFix.java @@ -0,0 +1,109 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInsight.daemon.impl.quickfix; + +import com.intellij.codeInsight.daemon.impl.HighlightInfo; +import com.intellij.codeInsight.daemon.impl.analysis.HighlightUtil; +import com.intellij.codeInsight.intention.IntentionAction; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.*; +import com.intellij.util.IncorrectOperationException; +import org.jetbrains.annotations.NotNull; + +/** + * User: anna + * Date: 2/10/12 + */ +public class ConvertDoubleToFloatFix implements IntentionAction { + private final PsiExpression myExpression; + + public ConvertDoubleToFloatFix(PsiExpression expression) { + myExpression = expression; + } + + @NotNull + @Override + public String getText() { + return "Convert '" + myExpression.getText() + "' to float"; + } + + @NotNull + @Override + public String getFamilyName() { + return getText(); + } + + @Override + public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { + if (myExpression.isValid()) { + if (!StringUtil.endsWithIgnoreCase(myExpression.getText(), "d")) { + final PsiLiteralExpression expression = (PsiLiteralExpression)createFloatingPointExpression(project); + final Object value = expression.getValue(); + return value instanceof Float && !((Float)value).isInfinite() && !(((Float)value).floatValue() == 0 && !HighlightUtil.isFPZero(expression.getText())); + } + } + return false; + } + + @Override + public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { + myExpression.replace(createFloatingPointExpression(project)); + } + + private PsiExpression createFloatingPointExpression(Project project) { + return JavaPsiFacade.getElementFactory(project).createExpressionFromText(myExpression.getText() + "f", myExpression); + } + + @Override + public boolean startInWriteAction() { + return true; + } + + public static void registerIntentions(@NotNull JavaResolveResult[] candidates, + @NotNull PsiExpressionList list, + @NotNull HighlightInfo highlightInfo, + TextRange fixRange) { + if (candidates.length == 0) return; + PsiExpression[] expressions = list.getExpressions(); + for (JavaResolveResult candidate : candidates) { + registerIntention(expressions, highlightInfo, fixRange, candidate, list); + } + } + + private static void registerIntention(@NotNull PsiExpression[] expressions, + @NotNull HighlightInfo highlightInfo, + TextRange fixRange, + @NotNull JavaResolveResult candidate, + @NotNull PsiElement context) { + if (!candidate.isStaticsScopeCorrect()) return; + PsiMethod method = (PsiMethod)candidate.getElement(); + if (method != null && context.getManager().isInProject(method)) { + final PsiParameter[] parameters = method.getParameterList().getParameters(); + if (parameters.length == expressions.length) { + for (int i = 0, length = parameters.length; i < length; i++) { + PsiParameter parameter = parameters[i]; + final PsiExpression expression = expressions[i]; + if (expression instanceof PsiLiteralExpression && PsiType.FLOAT.equals(parameter.getType()) && PsiType.DOUBLE.equals(expression.getType())) { + QuickFixAction.registerQuickFixAction(highlightInfo, fixRange, new ConvertDoubleToFloatFix(expression), null); + } + } + } + } + } +} diff --git a/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaTypedHandler.java b/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaTypedHandler.java index d684041bc68b..bd44b70fdc28 100644 --- a/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaTypedHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaTypedHandler.java @@ -60,7 +60,7 @@ public class JavaTypedHandler extends TypedHandlerDelegate { } //do not show lookup when typing varargs ellipsis - final PsiElement prevSibling = lastElement.getPrevSibling(); + final PsiElement prevSibling = PsiTreeUtil.prevVisibleLeaf(lastElement); if (prevSibling == null || ".".equals(prevSibling.getText())) return false; PsiElement parent = prevSibling; do { diff --git a/java/java-impl/src/com/intellij/codeInsight/lookup/PackageLookupItem.java b/java/java-impl/src/com/intellij/codeInsight/lookup/PackageLookupItem.java index 4374d9f6b3f4..168d5444ca71 100644 --- a/java/java-impl/src/com/intellij/codeInsight/lookup/PackageLookupItem.java +++ b/java/java-impl/src/com/intellij/codeInsight/lookup/PackageLookupItem.java @@ -33,6 +33,8 @@ class PackageLookupItem extends LookupItem { @Override public void handleInsert(InsertionContext context) { super.handleInsert(context); - AutoPopupController.getInstance(context.getProject()).scheduleAutoPopup(context.getEditor(), null); + if (getTailType() == TailType.DOT || context.getCompletionChar() == '.') { + AutoPopupController.getInstance(context.getProject()).scheduleAutoPopup(context.getEditor(), null); + } } } diff --git a/java/java-impl/src/com/intellij/codeInspection/visibility/VisibilityInspection.java b/java/java-impl/src/com/intellij/codeInspection/visibility/VisibilityInspection.java index d8028dee779f..c1f79c9a9e33 100644 --- a/java/java-impl/src/com/intellij/codeInspection/visibility/VisibilityInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/visibility/VisibilityInspection.java @@ -334,6 +334,9 @@ public class VisibilityInspection extends GlobalJavaInspectionTool { if (accessModifier == PsiModifier.PRIVATE) { if (SUGGEST_PRIVATE_FOR_INNERS) { + if (isInExtendsList(to, fromTopLevel.getElement().getExtendsList())) return false; + if (isInExtendsList(to, fromTopLevel.getElement().getImplementsList())) return false; + if (isInAnnotations(to, fromTopLevel)) return false; return fromTopLevel == toOwner || fromOwner == toTopLevel || toOwner != null && refUtil.getOwnerClass(toOwner) == from; } @@ -354,6 +357,24 @@ public class VisibilityInspection extends GlobalJavaInspectionTool { return false; } + private static boolean isInAnnotations(final RefJavaElement to, final RefClass fromTopLevel) { + final PsiModifierList modifierList = fromTopLevel.getElement().getModifierList(); + if (modifierList == null) return false; + final PsiElement toElement = to.getElement(); + + final boolean [] resolved = new boolean[] {false}; + modifierList.accept(new JavaRecursiveElementWalkingVisitor() { + @Override + public void visitReferenceExpression(PsiReferenceExpression expression) { + if (resolved[0]) return; + super.visitReferenceExpression(expression); + if (expression.resolve() == toElement) { + resolved[0] = true; + } + } + }); + return resolved[0]; + } private static boolean isInExtendsList(final RefJavaElement to, final PsiReferenceList extendsList) { if (extendsList != null) { diff --git a/java/java-impl/src/com/intellij/ide/fileTemplates/JavaCreateFromTemplateHandler.java b/java/java-impl/src/com/intellij/ide/fileTemplates/JavaCreateFromTemplateHandler.java index 56556548f0e4..7507f9dfd68b 100644 --- a/java/java-impl/src/com/intellij/ide/fileTemplates/JavaCreateFromTemplateHandler.java +++ b/java/java-impl/src/com/intellij/ide/fileTemplates/JavaCreateFromTemplateHandler.java @@ -15,6 +15,7 @@ */ package com.intellij.ide.fileTemplates; +import com.intellij.ide.IdeBundle; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.fileTypes.ex.FileTypeManagerEx; @@ -108,6 +109,26 @@ public class JavaCreateFromTemplateHandler implements CreateFromTemplateHandler return false; } + @Override + public boolean isNameRequired() { + return false; + } + + @Override + public String getErrorMessage() { + return IdeBundle.message("title.cannot.create.class"); + } + + @Override + public Properties prepareProperties(Properties props) { + String packageName = props.getProperty(FileTemplate.ATTRIBUTE_PACKAGE_NAME); + if(packageName == null || packageName.length() == 0){ + props = new Properties(props); + props.setProperty(FileTemplate.ATTRIBUTE_PACKAGE_NAME, FileTemplate.ATTRIBUTE_PACKAGE_NAME); + } + return props; + } + public static boolean canCreate(PsiDirectory dir) { return JavaDirectoryService.getInstance().getPackage(dir) != null; } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/HighlightInaccessibleFromClassModifierList.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/HighlightInaccessibleFromClassModifierList.java new file mode 100644 index 000000000000..e02db8fb902f --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/HighlightInaccessibleFromClassModifierList.java @@ -0,0 +1,4 @@ +@SuppressWarnings(ThisClass.FOO) +public class ThisClass { + private static final String FOO = "foo"; +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after1.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after1.java new file mode 100644 index 000000000000..150bd12f3c60 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after1.java @@ -0,0 +1,7 @@ +// "Convert '1e1' to float" "true" +class Test { + void bar() { + foo(1e1f); + } + void foo(float f){} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after2.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after2.java new file mode 100644 index 000000000000..99cdfdf2f2af --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after2.java @@ -0,0 +1,7 @@ +// "Convert '2.' to float" "true" +class Test { + void bar() { + foo(2.f); + } + void foo(float f){} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after3.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after3.java new file mode 100644 index 000000000000..9272f41b2410 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after3.java @@ -0,0 +1,7 @@ +// "Convert '.3' to float" "true" +class Test { + void bar() { + foo(.3f); + } + void foo(float f){} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after4.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after4.java new file mode 100644 index 000000000000..9d3993fd0f27 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after4.java @@ -0,0 +1,7 @@ +// "Convert '0.0' to float" "true" +class Test { + void bar() { + foo(0.0f); + } + void foo(float f){} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after5.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after5.java new file mode 100644 index 000000000000..7e70cf492967 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after5.java @@ -0,0 +1,7 @@ +// "Convert '3.14' to float" "true" +class Test { + void bar() { + foo(3.14f); + } + void foo(float f){} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before1.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before1.java new file mode 100644 index 000000000000..e476b77bc9e0 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before1.java @@ -0,0 +1,7 @@ +// "Convert '1e1' to float" "true" +class Test { + void bar() { + foo(1e1); + } + void foo(float f){} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before2.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before2.java new file mode 100644 index 000000000000..fa67aa86c9bf --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before2.java @@ -0,0 +1,7 @@ +// "Convert '2.' to float" "true" +class Test { + void bar() { + foo(2.); + } + void foo(float f){} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before3.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before3.java new file mode 100644 index 000000000000..3f6fb07e7b48 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before3.java @@ -0,0 +1,7 @@ +// "Convert '.3' to float" "true" +class Test { + void bar() { + foo(.3); + } + void foo(float f){} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before4.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before4.java new file mode 100644 index 000000000000..92cb59d6872e --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before4.java @@ -0,0 +1,7 @@ +// "Convert '0.0' to float" "true" +class Test { + void bar() { + foo(0.0); + } + void foo(float f){} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before5.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before5.java new file mode 100644 index 000000000000..9541ec5647fe --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before5.java @@ -0,0 +1,7 @@ +// "Convert '3.14' to float" "true" +class Test { + void bar() { + foo(3.14); + } + void foo(float f){} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before6.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before6.java new file mode 100644 index 000000000000..1799fb8943ee --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before6.java @@ -0,0 +1,7 @@ +// "Convert '1e-9d' to float" "false" +class Test { + void bar() { + foo(1e-9d); + } + void foo(float f){} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before7.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before7.java new file mode 100644 index 000000000000..fe93892a6b6d --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before7.java @@ -0,0 +1,7 @@ +// "Convert '1e137' to float" "false" +class Test { + void bar() { + foo(1e137); + } + void foo(float f){} +} diff --git a/java/java-tests/testData/fileStructure/filtering/SelectLeafFirst.java b/java/java-tests/testData/fileStructure/filtering/SelectLeafFirst.java new file mode 100644 index 000000000000..45eda4e21e07 --- /dev/null +++ b/java/java-tests/testData/fileStructure/filtering/SelectLeafFirst.java @@ -0,0 +1,13 @@ +class SelectLeafFirst { + void aaa(){} + + void bbb(){} + void clear(){} + void zzz(){} + class ClearClass { + void kkk(){} + void www(){} + void clear(){} + void yyy(){} + } +} \ No newline at end of file diff --git a/java/java-tests/testData/fileStructure/filtering/SelectLeafFirst.tree b/java/java-tests/testData/fileStructure/filtering/SelectLeafFirst.tree new file mode 100644 index 000000000000..69af4146c71c --- /dev/null +++ b/java/java-tests/testData/fileStructure/filtering/SelectLeafFirst.tree @@ -0,0 +1,5 @@ +-SelectLeafFirst.java + -SelectLeafFirst + [clear():void] + -ClearClass + clear():void \ No newline at end of file diff --git a/java/java-tests/testData/fileStructure/filtering/SelectLeafFirst2.java b/java/java-tests/testData/fileStructure/filtering/SelectLeafFirst2.java new file mode 100644 index 000000000000..06d505284632 --- /dev/null +++ b/java/java-tests/testData/fileStructure/filtering/SelectLeafFirst2.java @@ -0,0 +1,13 @@ +class SelectLeafFirst2 { + void aaa(){} + void bbb(){} + void clear(){} + void zzz(){} + class ClearClass { + void kkk(){} + + void www(){} + void clear(){} + void yyy(){} + } +} \ No newline at end of file diff --git a/java/java-tests/testData/fileStructure/filtering/SelectLeafFirst2.tree b/java/java-tests/testData/fileStructure/filtering/SelectLeafFirst2.tree new file mode 100644 index 000000000000..cb8224d167d5 --- /dev/null +++ b/java/java-tests/testData/fileStructure/filtering/SelectLeafFirst2.tree @@ -0,0 +1,5 @@ +-SelectLeafFirst2.java + -SelectLeafFirst2 + clear():void + -ClearClass + [clear():void] \ No newline at end of file diff --git a/java/java-tests/testData/inspection/visibility/usedFromAnnotationsExtendsList/expected.xml b/java/java-tests/testData/inspection/visibility/usedFromAnnotationsExtendsList/expected.xml new file mode 100644 index 000000000000..81532476144b --- /dev/null +++ b/java/java-tests/testData/inspection/visibility/usedFromAnnotationsExtendsList/expected.xml @@ -0,0 +1,22 @@ + + + + ThisClass.java + 5 + Declaration access can be weaker + + + + Can be package local + + + ThisClass.java + 4 + Declaration access can be weaker + + + + Can be package local + + + diff --git a/java/java-tests/testData/inspection/visibility/usedFromAnnotationsExtendsList/src/ThisClass.java b/java/java-tests/testData/inspection/visibility/usedFromAnnotationsExtendsList/src/ThisClass.java new file mode 100644 index 000000000000..67433f26feee --- /dev/null +++ b/java/java-tests/testData/inspection/visibility/usedFromAnnotationsExtendsList/src/ThisClass.java @@ -0,0 +1,9 @@ +import java.util.ArrayList; +@SuppressWarnings(ThisClass.PUBLICFINALNAME) +public class ThisClass extends ArrayList { + public static final String PUBLICFINALNAME = "stuff"; + public static class FF {} + + public static void main(String[] args) { + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java index 7e2951ec1186..55a041c9e77c 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java @@ -176,6 +176,10 @@ public class LightAdvHighlightingJdk7Test extends LightDaemonAnalyzerTestCase { doTest(false, false); } + public void testHighlightInaccessibleFromClassModifierList() throws Exception { + doTest(false, false); + } + public void testDynamicallyAddIgnoredAnnotations() throws Exception { ExtensionPoint point = Extensions.getRootArea().getExtensionPoint(ExtensionPoints.DEAD_CODE_TOOL); EntryPoint extension = new EntryPoint() { diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/ConvertDoubleToFloatFixTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/ConvertDoubleToFloatFixTest.java new file mode 100644 index 000000000000..1f57ad9d67a7 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/ConvertDoubleToFloatFixTest.java @@ -0,0 +1,29 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInsight.daemon.quickFix; + +/** + * @author cdr + */ +public class ConvertDoubleToFloatFixTest extends LightQuickFix15TestCase { + + public void test() throws Exception { doAllTests(); } + + @Override + protected String getBasePath() { + return "/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat"; + } +} diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/VisibilityInspectionTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/VisibilityInspectionTest.java index 4eb8bd32ef39..9cbb9ef2f697 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/VisibilityInspectionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/VisibilityInspectionTest.java @@ -102,4 +102,11 @@ public class VisibilityInspectionTest extends InspectionTestCase { myTool.SUGGEST_PRIVATE_FOR_INNERS = false; doTest("visibility/typeArguments", myTool, false, true); } + + public void testUsedFromAnnotationsExtendsList() throws Exception { + myTool.SUGGEST_PACKAGE_LOCAL_FOR_MEMBERS = true; + myTool.SUGGEST_PACKAGE_LOCAL_FOR_TOP_CLASSES = true; + myTool.SUGGEST_PRIVATE_FOR_INNERS = true; + doTest("visibility/usedFromAnnotationsExtendsList", myTool, false, true); + } } diff --git a/java/java-tests/testSrc/com/intellij/ide/fileStructure/JavaFileStructureFilteringTest.java b/java/java-tests/testSrc/com/intellij/ide/fileStructure/JavaFileStructureFilteringTest.java index 848828f915b6..7875a69ed5b1 100644 --- a/java/java-tests/testSrc/com/intellij/ide/fileStructure/JavaFileStructureFilteringTest.java +++ b/java/java-tests/testSrc/com/intellij/ide/fileStructure/JavaFileStructureFilteringTest.java @@ -29,5 +29,7 @@ public class JavaFileStructureFilteringTest extends JavaFileStructureTestCase { public void testAnonymousType()throws Exception{checkTree("point");} public void testCamel()throws Exception{checkTree("sohe");} public void testCamel2()throws Exception{checkTree("soHe");} + public void testSelectLeafFirst()throws Exception{checkTree("clear");} + public void testSelectLeafFirst2()throws Exception{checkTree("clear");} } diff --git a/jps/jps-builders/src/org/jetbrains/jps/api/RequestFuture.java b/jps/jps-builders/src/org/jetbrains/jps/api/RequestFuture.java index 7ff90b9cdc7a..7366541b20cd 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/api/RequestFuture.java +++ b/jps/jps-builders/src/org/jetbrains/jps/api/RequestFuture.java @@ -79,17 +79,34 @@ public class RequestFuture implements Future { return myDone.get(); } - public Object get() throws InterruptedException, ExecutionException { - while (!isDone()) { - mySemaphore.tryAcquire(100L, TimeUnit.MILLISECONDS); + public void waitFor() { + try { + while (!isDone()) { + mySemaphore.tryAcquire(100L, TimeUnit.MILLISECONDS); + } } + catch (InterruptedException ignored) { + } + } + + public boolean waitFor(long timeout, TimeUnit unit) { + try { + if (!isDone()) { + mySemaphore.tryAcquire(timeout, unit); + } + } + catch (InterruptedException ignored) { + } + return isDone(); + } + + public Object get() throws InterruptedException, ExecutionException { + waitFor(); return null; } public Object get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { - if (!isDone()) { - mySemaphore.tryAcquire(timeout, unit); - } + waitFor(timeout, unit); return null; } diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/CompileContext.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/CompileContext.java index 994633a6ecb0..90bd4e549c4e 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/CompileContext.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/CompileContext.java @@ -23,6 +23,7 @@ import java.util.*; * Date: 9/17/11 */ public class CompileContext extends UserDataHolderBase implements MessageHandler{ + private static final String CANCELED_MESSAGE = "The build has been canceled"; private final CompileScope myScope; private final boolean myIsMake; private final boolean myIsProjectRebuild; @@ -155,28 +156,39 @@ public class CompileContext extends UserDataHolderBase implements MessageHandler return myCompilingTests; } - public CanceledStatus getCancelStatus() { + public final CanceledStatus getCancelStatus() { return myCancelStatus; } + public final boolean isCanceled() { + return getCancelStatus().isCanceled(); + } + + public final void checkCanceled() throws ProjectBuildException { + if (isCanceled()) { + throw new ProjectBuildException(CANCELED_MESSAGE); + } + } + void setCompilingTests(boolean compilingTests) { myCompilingTests = compilingTests; } + void beforeCompileRound(@NotNull ModuleChunk chunk) { + myFsState.beforeNextRoundStart(); + } + + public void afterCompileRound() { + myFsState.clearContextRoundData(); + } + public void onChunkBuildStart(ModuleChunk chunk) { myFsState.setContextChunk(chunk); } - void beforeNextCompileRound(@NotNull ModuleChunk chunk) { - myFsState.beforeNextRoundStart(); - } - - public void clearContextRoundData() { - myFsState.clearContextRoundData(); - } - void onChunkBuildComplete(@NotNull ModuleChunk chunk) throws IOException { myDataManager.flush(true); + myFsState.clearContextChunk(); if (!myErrorsFound && !myCancelStatus.isCanceled()) { final boolean compilingTests = isCompilingTests(); diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/FSState.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/FSState.java index 1c2874f47004..63874bc38d67 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/FSState.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/FSState.java @@ -52,6 +52,10 @@ public class FSState { myContextModules.addAll(chunk.getModules()); } + public void clearContextChunk() { + myContextModules.clear(); + } + public void beforeNextRoundStart() { myLastRoundDelta = myCurrentRoundDelta; myCurrentRoundDelta = new FilesDelta(); @@ -60,7 +64,6 @@ public class FSState { public void clearContextRoundData() { myCurrentRoundDelta = null; myLastRoundDelta = null; - myContextModules.clear(); } public void clearRecompile(RootDescriptor rd) { diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java index 45a26b84ca8a..5270a2c7c27a 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java @@ -24,7 +24,7 @@ import java.io.File; import java.io.IOException; import java.lang.reflect.Field; import java.util.*; -import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; /** * @author Eugene Zhuravlev @@ -34,7 +34,6 @@ public class IncProjectBuilder { private static final Logger LOG = Logger.getInstance("#org.jetbrains.jps.incremental.IncProjectBuilder"); public static final String COMPILE_SERVER_NAME = "COMPILE SERVER"; - private static final String CANCELED_MESSAGE = "The build has been canceled"; private final ProjectDescriptor myProjectDescriptor; private final BuilderRegistry myBuilderRegistry; @@ -119,11 +118,7 @@ public class IncProjectBuilder { if (descriptor != null) { try { final RequestFuture future = descriptor.client.sendShutdownRequest(); - future.get(); - } - catch (InterruptedException ignored) { - } - catch (ExecutionException ignored) { + future.waitFor(500L, TimeUnit.MILLISECONDS); } finally { // ensure process is not running @@ -229,9 +224,7 @@ public class IncProjectBuilder { // check that output and source roots are not overlapping final List filesToDelete = new ArrayList(); for (File outputRoot : rootsToDelete) { - if (myCancelStatus.isCanceled()) { - throw new ProjectBuildException(CANCELED_MESSAGE); - } + context.checkCanceled(); boolean okToDelete = true; if (PathUtil.isUnder(allSourceRoots, outputRoot)) { okToDelete = false; @@ -389,7 +382,7 @@ public class IncProjectBuilder { boolean nextPassRequired; do { nextPassRequired = false; - context.beforeNextCompileRound(chunk); + context.beforeCompileRound(chunk); if (!context.isProjectRebuild()) { syncOutputFiles(context, chunk); @@ -401,9 +394,7 @@ public class IncProjectBuilder { if (buildResult == ModuleLevelBuilder.ExitCode.ABORT) { throw new ProjectBuildException("Builder " + builder.getDescription() + " requested build stop"); } - if (myCancelStatus.isCanceled()) { - throw new ProjectBuildException(CANCELED_MESSAGE); - } + context.checkCanceled(); if (buildResult == ModuleLevelBuilder.ExitCode.ADDITIONAL_PASS_REQUIRED) { if (!nextPassRequired) { // recalculate basis @@ -440,16 +431,14 @@ public class IncProjectBuilder { } while (nextPassRequired); - context.clearContextRoundData(); + context.afterCompileRound(); } } private void runProjectLevelBuilders(CompileContext context) throws ProjectBuildException { for (ProjectLevelBuilder builder : myBuilderRegistry.getProjectLevelBuilders()) { builder.build(context); - if (myCancelStatus.isCanceled()) { - throw new ProjectBuildException(CANCELED_MESSAGE); - } + context.checkCanceled(); } } diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java index ac1d7e09b598..bfde575cf4d9 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java @@ -42,8 +42,8 @@ import java.net.ServerSocket; import java.net.URL; import java.net.URLClassLoader; import java.util.*; -import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; +import java.util.concurrent.TimeUnit; /** * @author Eugene Zhuravlev @@ -257,14 +257,19 @@ public class JavaBuilder extends ModuleLevelBuilder { if (hasSourcesToCompile) { final Set sourcePath = TEMPORARY_SOURCE_ROOTS_KEY.get(context, Collections.emptySet()); - final String chunkName = chunk.getName(); + final String chunkName = getChunkPresentableName(chunk); context.processMessage(new ProgressMessage("Compiling java [" + chunkName + "]")); final boolean compiledOk = compileJava(chunk, files, classpath, platformCp, sourcePath, outs, context, diagnosticSink, outputSink); final Map chunkSourcePath = ProjectPaths.getSourceRootsWithDependents(chunk, context.isCompilingTests()); + + context.checkCanceled(); + final ClassLoader compiledClassesLoader = createInstrumentationClassLoader(classpath, platformCp, chunkSourcePath, outputSink); + context.checkCanceled(); + if (!forms.isEmpty()) { try { context.processMessage(new ProgressMessage("Instrumenting forms [" + chunkName + "]")); @@ -275,6 +280,8 @@ public class JavaBuilder extends ModuleLevelBuilder { } } + context.checkCanceled(); + if (addNotNullAssertions) { try { context.processMessage(new ProgressMessage("Adding NotNull assertions [" + chunkName + "]")); @@ -285,6 +292,8 @@ public class JavaBuilder extends ModuleLevelBuilder { } } + context.checkCanceled(); + if (!compiledOk && diagnosticSink.getErrorCount() == 0) { diagnosticSink.report(new PlainMessageDiagnostic(Diagnostic.Kind.ERROR, "Compilation failed: internal java compiler error")); } @@ -316,6 +325,24 @@ public class JavaBuilder extends ModuleLevelBuilder { return exitCode; } + private static String getChunkPresentableName(ModuleChunk chunk) { + final Set modules = chunk.getModules(); + if (modules.isEmpty()) { + return ""; + } + if (modules.size() == 1) { + return modules.iterator().next().getName(); + } + final StringBuilder buf = new StringBuilder(); + for (Module module : modules) { + if (buf.length() > 0) { + buf.append(","); + } + buf.append(module.getName()); + } + return buf.toString(); + } + private boolean compileJava(ModuleChunk chunk, Collection files, Collection classpath, Collection platformCp, @@ -338,14 +365,10 @@ public class JavaBuilder extends ModuleLevelBuilder { final RequestFuture future = client.sendCompileRequest( options, files, classpath, platformCp, sourcePath, outs, diagnosticSink, classesConsumer ); - try { - future.get(); - } - catch (InterruptedException e) { - e.printStackTrace(System.err); - } - catch (ExecutionException e) { - e.printStackTrace(System.err); + while (!future.waitFor(100L, TimeUnit.MILLISECONDS)) { + if (context.isCanceled()) { + future.cancel(true); + } } rc = future.getResponseHandler().isTerminatedSuccessfully(); } diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/JavacFileManager.java b/jps/jps-builders/src/org/jetbrains/jps/javac/JavacFileManager.java index a7aac0fce6dc..73e238f9bdd7 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/javac/JavacFileManager.java +++ b/jps/jps-builders/src/org/jetbrains/jps/javac/JavacFileManager.java @@ -66,6 +66,18 @@ class JavacFileManager extends ForwardingJavaFileManager sourcePath, Map> outputDirToRoots, final DiagnosticOutputConsumer outConsumer, - final OutputFileConsumer outputSink, @Nullable CanceledStatus canceledStatus) { + final OutputFileConsumer outputSink, + CanceledStatus canceledStatus) { final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); for (File outputDir : outputDirToRoots.keySet()) { outputDir.mkdirs(); } - final JavacFileManager fileManager = new JavacFileManager(new ContextImpl(compiler, outConsumer, outputSink)); + final JavacFileManager fileManager = new JavacFileManager(new ContextImpl(compiler, outConsumer, outputSink, canceledStatus)); fileManager.handleOption("-bootclasspath", Collections.singleton("").iterator()); // this will clear cached stuff fileManager.handleOption("-extdirs", Collections.singleton("").iterator()); // this will clear cached stuff @@ -111,10 +111,15 @@ public class JavacMain { private final StandardJavaFileManager myStdManager; private final DiagnosticOutputConsumer myOutConsumer; private final OutputFileConsumer myOutputFileSink; + private final CanceledStatus myCanceledStatus; - public ContextImpl(@NotNull JavaCompiler compiler, @NotNull DiagnosticOutputConsumer outConsumer, @NotNull OutputFileConsumer sink) { + public ContextImpl(@NotNull JavaCompiler compiler, + @NotNull DiagnosticOutputConsumer outConsumer, + @NotNull OutputFileConsumer sink, + CanceledStatus canceledStatus) { myOutConsumer = outConsumer; myOutputFileSink = sink; + myCanceledStatus = canceledStatus; StandardJavaFileManager stdManager = null; final Class optimizedManagerClass = ClasspathBootstrap.getOptimizedFileManagerClass(); if (optimizedManagerClass != null) { @@ -136,7 +141,7 @@ public class JavacMain { } public boolean isCanceled() { - return false; // todo + return myCanceledStatus.isCanceled(); } public StandardJavaFileManager getStandardFileManager() { diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/JavacServer.java b/jps/jps-builders/src/org/jetbrains/jps/javac/JavacServer.java index 2b75d6dc7673..537cdf6a64e8 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/javac/JavacServer.java +++ b/jps/jps-builders/src/org/jetbrains/jps/javac/JavacServer.java @@ -11,9 +11,9 @@ import org.jboss.netty.handler.codec.protobuf.ProtobufEncoder; import org.jboss.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder; import org.jboss.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender; import org.jetbrains.annotations.NotNull; +import org.jetbrains.jps.api.CanceledStatus; -import javax.tools.Diagnostic; -import javax.tools.JavaFileObject; +import javax.tools.*; import java.io.File; import java.net.InetSocketAddress; import java.util.*; @@ -32,10 +32,11 @@ public class JavacServer { private final ChannelGroup myAllOpenChannels = new DefaultChannelGroup("javac-server"); private final ChannelFactory myChannelFactory; private final ChannelPipelineFactory myPipelineFactory; + private ExecutorService myThreadPool; public JavacServer() { - final ExecutorService threadPool = Executors.newCachedThreadPool(); - myChannelFactory = new NioServerSocketChannelFactory(threadPool, threadPool, 1); + myThreadPool = Executors.newCachedThreadPool(); + myChannelFactory = new NioServerSocketChannelFactory(myThreadPool, myThreadPool, 1); final ChannelRegistrar channelRegistrar = new ChannelRegistrar(); final ChannelHandler compilationRequestsHandler = new CompilationRequestsHandler(); myPipelineFactory = new ChannelPipelineFactory() { @@ -103,7 +104,15 @@ public class JavacServer { } - public static JavacRemoteProto.Message compile(final ChannelHandlerContext ctx, final UUID sessionId, List options, Collection files, Collection classpath, Collection platformCp, Collection sourcePath, Map> outs) { + public static JavacRemoteProto.Message compile(final ChannelHandlerContext ctx, + final UUID sessionId, + List options, + Collection files, + Collection classpath, + Collection platformCp, + Collection sourcePath, + Map> outs, + final CanceledStatus canceledStatus) { final DiagnosticOutputConsumer diagnostic = new DiagnosticOutputConsumer() { public void outputLineAvailable(String line) { Channels.write(ctx.getChannel(), JavacProtoUtil.toMessage(sessionId, JavacProtoUtil.createStdOutputResponse(line))); @@ -122,7 +131,7 @@ public class JavacServer { }; try { - final boolean rc = JavacMain.compile(options, files, classpath, platformCp, sourcePath, outs, diagnostic, outputSink, null/*todo*/); + final boolean rc = JavacMain.compile(options, files, classpath, platformCp, sourcePath, outs, diagnostic, outputSink, canceledStatus); return JavacProtoUtil.toMessage(sessionId, JavacProtoUtil.createBuildCompletedResponse(rc)); } catch (Throwable e) { @@ -131,8 +140,14 @@ public class JavacServer { } } - public static void cancelBuild() { - // todo + private final Set myCancelHandlers = Collections.synchronizedSet(new HashSet()); + + public void cancelBuilds() { + synchronized (myCancelHandlers) { + for (CancelHandler handler : myCancelHandlers) { + handler.cancel(); + } + } } private static List toFiles(List paths) { @@ -145,7 +160,7 @@ public class JavacServer { private class CompilationRequestsHandler extends SimpleChannelHandler { - public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { + public void messageReceived(final ChannelHandlerContext ctx, MessageEvent e) throws Exception { final JavacRemoteProto.Message msg = (JavacRemoteProto.Message)e.getMessage(); final UUID sessionId = JavacProtoUtil.fromProtoUUID(msg.getSessionId()); final JavacRemoteProto.Message.Type messageType = msg.getMessageType(); @@ -172,14 +187,26 @@ public class JavacServer { outs.put(new File(outputGroup.getOutputRoot()), srcRoots); } - reply = compile(ctx, sessionId, options, files, cp, platformCp, srcPath, outs); + final CancelHandler cancelHandler = new CancelHandler(); + myCancelHandlers.add(cancelHandler); + myThreadPool.submit(new Runnable() { + public void run() { + try { + final JavacRemoteProto.Message exitMsg = compile(ctx, sessionId, options, files, cp, platformCp, srcPath, outs, cancelHandler); + Channels.write(ctx.getChannel(), exitMsg); + } + finally { + myCancelHandlers.remove(cancelHandler); + } + } + }); } else if (requestType == JavacRemoteProto.Message.Request.Type.CANCEL){ - cancelBuild(); + cancelBuilds(); reply = JavacProtoUtil.toMessage(sessionId, JavacProtoUtil.createRequestAckResponse()); } else if (requestType == JavacRemoteProto.Message.Request.Type.SHUTDOWN){ - cancelBuild(); + cancelBuilds(); new Thread("StopThread") { public void run() { JavacServer.this.stop(); @@ -213,4 +240,19 @@ public class JavacServer { super.channelOpen(ctx, e); } } + + private static class CancelHandler implements CanceledStatus { + private volatile boolean myIsCanceled = false; + + private CancelHandler() { + } + + public void cancel() { + myIsCanceled = true; + } + + public boolean isCanceled() { + return myIsCanceled; + } + } } \ No newline at end of file diff --git a/platform/core-api/src/com/intellij/psi/util/CachedValuesManager.java b/platform/core-api/src/com/intellij/psi/util/CachedValuesManager.java index e2c805e5cc5e..49391709ed00 100644 --- a/platform/core-api/src/com/intellij/psi/util/CachedValuesManager.java +++ b/platform/core-api/src/com/intellij/psi/util/CachedValuesManager.java @@ -93,17 +93,20 @@ public abstract class CachedValuesManager { } public static class MemoizationKey extends Key { + private final String myName; + public MemoizationKey(@NotNull @NonNls String name) { super(name); + myName = name; } public int hashCode() { - return toString().hashCode(); + return myName.hashCode(); } @Override public boolean equals(Object obj) { - return obj instanceof MemoizationKey && toString().equals(obj.toString()); + return obj instanceof MemoizationKey && myName.equals(((MemoizationKey)obj).myName); } } diff --git a/platform/core-impl/src/com/intellij/openapi/components/impl/ComponentManagerImpl.java b/platform/core-impl/src/com/intellij/openapi/components/impl/ComponentManagerImpl.java index d0153c3796aa..c26dd1c90dc2 100644 --- a/platform/core-impl/src/com/intellij/openapi/components/impl/ComponentManagerImpl.java +++ b/platform/core-impl/src/com/intellij/openapi/components/impl/ComponentManagerImpl.java @@ -124,7 +124,7 @@ public abstract class ComponentManagerImpl extends UserDataHolderBase implements protected synchronized Object createComponent(Class componentInterface) { final Object component = getPicoContainer().getComponentInstance(componentInterface.getName()); - assert component != null : "Can't instantiate component for: " + componentInterface; + LOG.assertTrue(component != null, "Can't instantiate component for: " + componentInterface); return component; } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/TemplateInsertHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/TemplateInsertHandler.java index 4d15a58b1740..531c28aff3ee 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/TemplateInsertHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/TemplateInsertHandler.java @@ -78,7 +78,8 @@ public abstract class TemplateInsertHandler implements InsertHandler { String lookupString = editor.getDocument().getCharsSequence().subSequence(startOffset, endOffset).toString(); lookupItem.setLookupString(lookupString); - final OffsetMap offsetMap = context.getOffsetMap(); + final OffsetMap offsetMap = new OffsetMap(document); + offsetMap.addOffset(CompletionInitializationContext.START_OFFSET, startOffset); offsetMap.addOffset(CompletionInitializationContext.SELECTION_END_OFFSET, endOffset); offsetMap.addOffset(CompletionInitializationContext.IDENTIFIER_END_OFFSET, endOffset); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoComponent.java b/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoComponent.java index 59f6ca91c914..dbc7dc81c0a4 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoComponent.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoComponent.java @@ -79,6 +79,10 @@ class ParameterInfoComponent extends JPanel{ myCurrentParameterIndex = -1; } + public Object getHighlighted() { + return myHighlighted; + } + class MyParameterContext implements ParameterInfoUIContextEx { private int i; public void setupUIComponentPresentation(String text, diff --git a/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoController.java b/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoController.java index 9bf5c61e90cb..31401edbb0ed 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoController.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoController.java @@ -113,20 +113,33 @@ public class ParameterInfoController { int selectedParameterIndex = myComponent.getCurrentParameterIndex(); List params = new ArrayList(objects.length); + final Object highlighted = myComponent.getHighlighted(); for(Object o:objects) { - final Object[] availableParams = myHandler.getParametersForDocumentation(o, context); + if (highlighted != null && !o.equals(highlighted)) continue; + collectParams(context, selectedParameterIndex, params, o); + } - if (availableParams != null && - selectedParameterIndex < availableParams.length && - selectedParameterIndex >= 0 - ) { - params.add(availableParams[selectedParameterIndex]); + //choose anything when highlighted is not applicable + if (highlighted != null && params.isEmpty()) { + for (Object o : objects) { + collectParams(context, selectedParameterIndex, params, o); } } return ArrayUtil.toObjectArray(params); } + private void collectParams(ParameterInfoContext context, int selectedParameterIndex, List params, Object o) { + final Object[] availableParams = myHandler.getParametersForDocumentation(o, context); + + if (availableParams != null && + selectedParameterIndex < availableParams.length && + selectedParameterIndex >= 0 + ) { + params.add(availableParams[selectedParameterIndex]); + } + } + private static ArrayList getAllControllers(Editor editor) { ArrayList array = editor.getUserData(ALL_CONTROLLERS_KEY); if (array == null){ diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionTool.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionTool.java index 9733185e63c3..279ef0b60f33 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionTool.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionTool.java @@ -64,7 +64,7 @@ public abstract class InspectionTool extends InspectionProfileEntry { } public RefManager getRefManager() { - return myContext.getRefManager(); + return getContext().getRefManager(); } public abstract void runInspection(@NotNull AnalysisScope scope, @NotNull InspectionManager manager); diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionToolRegistrar.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionToolRegistrar.java index 6cd4ec9b9344..3cf54d5b3cee 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionToolRegistrar.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionToolRegistrar.java @@ -339,6 +339,11 @@ public class InspectionToolRegistrar { getTool().runInspection(scope, manager); } + @Override + public void initialize(@NotNull GlobalInspectionContextImpl context) { + getTool().initialize(context); + } + @NotNull @Override public JobDescriptor[] getJobDescriptors(GlobalInspectionContext globalInspectionContext) { diff --git a/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java b/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java index 24102411122a..e9c60bb92039 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java @@ -500,7 +500,7 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo } private ModalityState getStateForUpdate() { - return null;//myStateForUpdate != null ? myStateForUpdate.compute() : ModalityState.stateForComponent(this); + return myStateForUpdate != null ? myStateForUpdate.compute() : ModalityState.stateForComponent(this); } private void requestFlushImmediately() { diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/CreateFromTemplateHandler.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/CreateFromTemplateHandler.java index 2caae4e51a95..0eb494ca6d3e 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/CreateFromTemplateHandler.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/CreateFromTemplateHandler.java @@ -35,4 +35,8 @@ public interface CreateFromTemplateHandler { Properties props) throws IncorrectOperationException; boolean canCreate(final PsiDirectory[] dirs); + boolean isNameRequired(); + String getErrorMessage(); + + Properties prepareProperties(Properties props); } diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/DefaultCreateFromTemplateHandler.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/DefaultCreateFromTemplateHandler.java index 91bfa6dda7b9..bf61fb7d5c3a 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/DefaultCreateFromTemplateHandler.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/DefaultCreateFromTemplateHandler.java @@ -16,6 +16,7 @@ package com.intellij.ide.fileTemplates; +import com.intellij.ide.IdeBundle; import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiDirectory; @@ -67,4 +68,19 @@ public class DefaultCreateFromTemplateHandler implements CreateFromTemplateHandl public boolean canCreate(final PsiDirectory[] dirs) { return true; } + + @Override + public boolean isNameRequired() { + return true; + } + + @Override + public String getErrorMessage() { + return IdeBundle.message("title.cannot.create.file"); + } + + @Override + public Properties prepareProperties(Properties props) { + return props; + } } diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateUtil.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateUtil.java index 3ed275e3a9f0..0d0ec3f10408 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateUtil.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateUtil.java @@ -118,7 +118,7 @@ public class FileTemplateUtil{ } public static String[] calculateAttributes(String templateContent, Properties properties, boolean includeDummies) throws ParseException { - final Set unsetAttributes = new HashSet(); + final Set unsetAttributes = new LinkedHashSet(); final Set definedAttributes = new HashSet(); //noinspection HardCodedStringLiteral SimpleNode template = RuntimeSingleton.parse(new StringReader(templateContent), "MyTemplate"); @@ -258,7 +258,7 @@ public class FileTemplateUtil{ } public static PsiElement createFromTemplate(@NotNull final FileTemplate template, - @NonNls @Nullable final String fileName, + @NonNls @Nullable String fileName, @Nullable Properties props, @NotNull final PsiDirectory directory, @Nullable ClassLoader classLoader) throws Exception { @@ -269,9 +269,16 @@ public class FileTemplateUtil{ FileTemplateManager.getInstance().addRecentName(template.getName()); fillDefaultProperties(props, directory); + final CreateFromTemplateHandler handler = findHandler(template); if (fileName != null && props.getProperty(FileTemplate.ATTRIBUTE_NAME) == null) { props.setProperty(FileTemplate.ATTRIBUTE_NAME, fileName); } + else if (fileName == null && handler.isNameRequired()) { + fileName = props.getProperty(FileTemplate.ATTRIBUTE_NAME); + if (fileName == null) { + throw new Exception("File name must be specified"); + } + } //Set escaped references to dummy values to remove leading "\" (if not already explicitely set) String[] dummyRefs = calculateAttributes(template.getText(), props, true); @@ -279,15 +286,10 @@ public class FileTemplateUtil{ props.setProperty(dummyRef, ""); } - if (template.isTemplateOfType(StdFileTypes.JAVA)){ - String packageName = props.getProperty(FileTemplate.ATTRIBUTE_PACKAGE_NAME); - if(packageName == null || packageName.length() == 0){ - props = new Properties(props); - props.setProperty(FileTemplate.ATTRIBUTE_PACKAGE_NAME, FileTemplate.ATTRIBUTE_PACKAGE_NAME); - } - } + props = handler.prepareProperties(props); final Properties props_ = props; + final String fileName_ = fileName; String mergedText = ClassLoaderUtil.runWithClassLoader(classLoader != null ? classLoader : FileTemplateUtil.class.getClassLoader(), new ThrowableComputable() { @Override @@ -304,8 +306,7 @@ public class FileTemplateUtil{ ApplicationManager.getApplication().runWriteAction(new Runnable(){ public void run(){ try{ - CreateFromTemplateHandler handler = findHandler(template); - result [0] = handler.createFromTemplate(project, directory, fileName, template, templateText, finalProps); + result [0] = handler.createFromTemplate(project, directory, fileName_, template, templateText, finalProps); } catch (Exception ex){ commandException[0] = ex; @@ -322,7 +323,7 @@ public class FileTemplateUtil{ return result[0]; } - private static CreateFromTemplateHandler findHandler(final FileTemplate template) { + public static CreateFromTemplateHandler findHandler(final FileTemplate template) { for(CreateFromTemplateHandler handler: Extensions.getExtensions(CreateFromTemplateHandler.EP_NAME)) { if (handler.handlesTemplate(template)) { return handler; diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/actions/AttributesDefaults.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/actions/AttributesDefaults.java index 38f85cb9e1bb..3a53701e0500 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/actions/AttributesDefaults.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/actions/AttributesDefaults.java @@ -32,6 +32,7 @@ public class AttributesDefaults { private final String myDefaultName; private final TextRange myDefaultRange; private final Map> myNamesToValueAndRangeMap = new HashMap>(); + private boolean myFixedName; public AttributesDefaults(@NonNls @Nullable final String defaultName, @Nullable final TextRange defaultRange) { @@ -78,4 +79,13 @@ public class AttributesDefaults { final Pair valueAndRange = myNamesToValueAndRangeMap.get(attributeKey); return valueAndRange == null ? null : valueAndRange.first; } + + public boolean isFixedName() { + return myFixedName; + } + + public AttributesDefaults withFixedName(boolean fixedName) { + myFixedName = fixedName; + return this; + } } diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/actions/CreateFromTemplateActionBase.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/actions/CreateFromTemplateActionBase.java index 93f0f2940212..4d700b0ae1d6 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/actions/CreateFromTemplateActionBase.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/actions/CreateFromTemplateActionBase.java @@ -55,14 +55,18 @@ public abstract class CreateFromTemplateActionBase extends AnAction { } else { FileTemplateManager.getInstance().addRecentName(selectedTemplate.getName()); - PsiElement createdElement = new CreateFromTemplateDialog(project, dir, selectedTemplate, getAttributesDefaults()).create(); + final AttributesDefaults defaults = getAttributesDefaults(dataContext); + final CreateFromTemplateDialog dialog = new CreateFromTemplateDialog(project, dir, selectedTemplate, defaults); + PsiElement createdElement = dialog.create(); if (createdElement != null) { + elementCreated(dialog, createdElement); view.selectElement(createdElement); } } } } + @Nullable protected PsiDirectory getTargetDirectory(DataContext dataContext, IdeView view) { return DirectoryChooserUtil.getOrChooseDirectory(view); } @@ -73,7 +77,10 @@ public abstract class CreateFromTemplateActionBase extends AnAction { protected abstract FileTemplate getTemplate(final Project project, final PsiDirectory dir); @Nullable - public AttributesDefaults getAttributesDefaults() { + public AttributesDefaults getAttributesDefaults(DataContext dataContext) { return null; } + + protected void elementCreated(CreateFromTemplateDialog dialog, PsiElement createdElement) { + } } diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplateDialog.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplateDialog.java index 4a22227d958a..a73db7bcf071 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplateDialog.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplateDialog.java @@ -22,7 +22,6 @@ import com.intellij.ide.fileTemplates.FileTemplate; import com.intellij.ide.fileTemplates.FileTemplateManager; import com.intellij.ide.fileTemplates.FileTemplateUtil; import com.intellij.ide.fileTemplates.actions.AttributesDefaults; -import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.Messages; @@ -65,6 +64,11 @@ public class CreateFromTemplateDialog extends DialogWrapper { myDefaultProperties = defaultProperties == null ? FileTemplateManager.getInstance().getDefaultProperties() : defaultProperties; FileTemplateUtil.fillDefaultProperties(myDefaultProperties, directory); + boolean mustEnterName = FileTemplateUtil.findHandler(template).isNameRequired(); + if (attributesDefaults != null && attributesDefaults.isFixedName()) { + myDefaultProperties.setProperty(FileTemplate.ATTRIBUTE_NAME, attributesDefaults.getDefaultFileName()); + mustEnterName = false; + } String[] unsetAttributes = null; try { @@ -75,7 +79,7 @@ public class CreateFromTemplateDialog extends DialogWrapper { } if (unsetAttributes != null) { - myAttrPanel = new CreateFromTemplatePanel(unsetAttributes, !myTemplate.isTemplateOfType(StdFileTypes.JAVA), attributesDefaults); + myAttrPanel = new CreateFromTemplatePanel(unsetAttributes, mustEnterName, attributesDefaults); myAttrComponent = myAttrPanel.getComponent(); init(); } @@ -110,7 +114,7 @@ public class CreateFromTemplateDialog extends DialogWrapper { } } - private void doCreate(final String fileName) { + private void doCreate(@Nullable final String fileName) { try { myCreatedElement = FileTemplateUtil.createFromTemplate(myTemplate, fileName, myAttrPanel.getProperties(myDefaultProperties), myDirectory); @@ -120,12 +124,16 @@ public class CreateFromTemplateDialog extends DialogWrapper { } } + public Properties getEnteredProperties() { + return myAttrPanel.getProperties(new Properties()); + } + private void showErrorDialog(final Exception e) { Messages.showMessageDialog(myProject, filterMessage(e.getMessage()), getErrorMessage(), Messages.getErrorIcon()); } private String getErrorMessage() { - return myTemplate.isTemplateOfType(StdFileTypes.JAVA) ? IdeBundle.message("title.cannot.create.class") : IdeBundle.message("title.cannot.create.file"); + return FileTemplateUtil.findHandler(myTemplate).getErrorMessage(); } @Nullable diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplatePanel.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplatePanel.java index b42b97ab74f2..4fd7bb5a1e4f 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplatePanel.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplatePanel.java @@ -19,8 +19,7 @@ package com.intellij.ide.fileTemplates.ui; import com.intellij.ide.IdeBundle; import com.intellij.ide.fileTemplates.FileTemplate; import com.intellij.ide.fileTemplates.actions.AttributesDefaults; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.ui.impl.DialogWrapperPeerImpl; +import com.intellij.openapi.ui.DialogWrapperPeer; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.TextRange; import com.intellij.ui.ScrollPaneFactory; @@ -37,8 +36,6 @@ import java.util.Properties; */ public class CreateFromTemplatePanel{ - private static final Logger LOG = Logger.getInstance("#com.intellij.ide.fileTemplates.ui.CreateFromTemplatePanel"); - private JPanel myMainPanel; private JPanel myAttrPanel; private JTextField myFilenameField; @@ -47,7 +44,7 @@ public class CreateFromTemplatePanel{ private int myLastRow = 0; - private int myHorisontalMargin = -1; + private int myHorizontalMargin = -1; private int myVerticalMargin = -1; private final boolean myMustEnterName; private final AttributesDefaults myAttributesDefaults; @@ -57,7 +54,6 @@ public class CreateFromTemplatePanel{ myMustEnterName = mustEnterName; myUnsetAttributes = unsetAttributes; myAttributesDefaults = attributesDefaults; - Arrays.sort(myUnsetAttributes); } public boolean hasSomethingToAsk() { @@ -95,16 +91,16 @@ public class CreateFromTemplatePanel{ return myMainPanel; } - public void ensureFitToScreen(int horisontalMargin, int verticalMargin){ - myHorisontalMargin = horisontalMargin; + public void ensureFitToScreen(int horizontalMargin, int verticalMargin){ + myHorizontalMargin = horizontalMargin; myVerticalMargin = verticalMargin; } private Dimension getMainPanelPreferredSize(Dimension superPreferredSize){ - if((myHorisontalMargin > 0) && (myVerticalMargin > 0)){ + if((myHorizontalMargin > 0) && (myVerticalMargin > 0)){ Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); Dimension preferredSize = superPreferredSize; - Dimension maxSize = new Dimension(screenSize.width - myHorisontalMargin, screenSize.height - myVerticalMargin); + Dimension maxSize = new Dimension(screenSize.width - myHorizontalMargin, screenSize.height - myVerticalMargin); int width = Math.min(preferredSize.width, maxSize.width); int height = Math.min(preferredSize.height, maxSize.height); if(height < preferredSize.height){ @@ -119,8 +115,7 @@ public class CreateFromTemplatePanel{ } private void updateShown() { - final Insets insets = new Insets(2, 2, 2, 2); - myAttrPanel.add(Box.createHorizontalStrut(200), new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insets, 0, 0)); + final Insets insets = new Insets(2, 4, 4, 2); if(myMustEnterName || Arrays.asList(myUnsetAttributes).contains(FileTemplate.ATTRIBUTE_NAME)){ final JLabel filenameLabel = new JLabel(IdeBundle.message("label.file.name")); myAttrPanel.add(filenameLabel, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, insets, 0, 0)); @@ -134,7 +129,7 @@ public class CreateFromTemplatePanel{ // set predefined file name value myFilenameField.setText(fileName); final TextRange selectionRange; - // select range from default attrubutes or select file name without extension + // select range from default attributes or select file name without extension if (myAttributesDefaults.getDefaultFileNameSelection() != null) { selectionRange = myAttributesDefaults.getDefaultFileNameSelection(); } else { @@ -151,15 +146,17 @@ public class CreateFromTemplatePanel{ } } } - myAttrPanel.add(myFilenameField, new GridBagConstraints(0, 2, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insets, 0, 0)); + myAttrPanel.add(myFilenameField, new GridBagConstraints(1, 1, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insets, 0, 0)); } + myLastRow = 2; for (String attribute : myUnsetAttributes) { if (attribute.equals(FileTemplate.ATTRIBUTE_NAME)) { // already asked above continue; } final JLabel label = new JLabel(attribute.replace('_', ' ') + ":"); final JTextField field = new JTextField(); + field.setColumns(30); if (myAttributesDefaults != null) { final String defaultValue = myAttributesDefaults.getDefaultValueFor(attribute); final TextRange selectionRange = myAttributesDefaults.getRangeFor(attribute); @@ -172,9 +169,9 @@ public class CreateFromTemplatePanel{ } } myAttributes.add(new Pair(attribute, field)); - myAttrPanel.add(label, new GridBagConstraints(0, myLastRow * 2 + 3, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, + myAttrPanel.add(label, new GridBagConstraints(0, myLastRow, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, insets, 0, 0)); - myAttrPanel.add(field, new GridBagConstraints(0, myLastRow * 2 + 4, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, + myAttrPanel.add(field, new GridBagConstraints(1, myLastRow, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insets, 0, 0)); myLastRow++; } @@ -194,17 +191,17 @@ public class CreateFromTemplatePanel{ } } - public Properties getProperties(Properties predefinedProperties){ + public Properties getProperties(Properties predefinedProperties) { Properties result = (Properties) predefinedProperties.clone(); for (Pair pair : myAttributes) { - result.put(pair.first, pair.second.getText()); + result.setProperty(pair.first, pair.second.getText()); } return result; } - private void setPredefinedSelectionFor(final JTextField field, final TextRange selectionRange) { + private static void setPredefinedSelectionFor(final JTextField field, final TextRange selectionRange) { field.select(selectionRange.getStartOffset(), selectionRange.getEndOffset()); - field.putClientProperty(DialogWrapperPeerImpl.HAVE_INITIAL_SELECTION, true); + field.putClientProperty(DialogWrapperPeer.HAVE_INITIAL_SELECTION, true); } } diff --git a/platform/lang-impl/src/com/intellij/ide/impl/StructureViewWrapperImpl.java b/platform/lang-impl/src/com/intellij/ide/impl/StructureViewWrapperImpl.java index 911ec07db1db..20cf9e787b77 100644 --- a/platform/lang-impl/src/com/intellij/ide/impl/StructureViewWrapperImpl.java +++ b/platform/lang-impl/src/com/intellij/ide/impl/StructureViewWrapperImpl.java @@ -87,7 +87,7 @@ public class StructureViewWrapperImpl implements StructureViewWrapper, Disposabl myUpdateQueue = new MergingUpdateQueue("StructureView", Registry.intValue("structureView.coalesceTime"), false, myToolWindow.getComponent(), this, myToolWindow.getComponent(), true); myUpdateQueue.setRestartTimerOnAdd(true); - ActionManager.getInstance().addTimerListener(500, new TimerListener() { + final TimerListener timerListener = new TimerListener() { public ModalityState getModalityState() { return ModalityState.stateForComponent(myToolWindow.getComponent()); } @@ -95,6 +95,13 @@ public class StructureViewWrapperImpl implements StructureViewWrapper, Disposabl public void run() { checkUpdate(); } + }; + ActionManager.getInstance().addTimerListener(500, timerListener); + Disposer.register(this, new Disposable() { + @Override + public void dispose() { + ActionManager.getInstance().removeTimerListener(timerListener); + } }); myToolWindow.getComponent().addHierarchyListener(new HierarchyListener() { diff --git a/platform/lang-impl/src/com/intellij/ide/util/FileStructurePopup.java b/platform/lang-impl/src/com/intellij/ide/util/FileStructurePopup.java index 1d6b184ad403..e3658fde5afa 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/FileStructurePopup.java +++ b/platform/lang-impl/src/com/intellij/ide/util/FileStructurePopup.java @@ -818,11 +818,16 @@ public class FileStructurePopup implements Disposable { final Object object = ((DefaultMutableTreeNode)last).getUserObject(); if (object instanceof FilteringTreeStructure.FilteringNode) { FilteringTreeStructure.FilteringNode node = (FilteringTreeStructure.FilteringNode)object; + FilteringTreeStructure.FilteringNode candidate = node; + while (node != null) { elements.add(getPsi(node)); node = node.getParentNode(); } final int size = ContainerUtil.intersection(parents, elements).size(); + if (size == elements.size() - 1 && size == parents.size() && candidate.children().isEmpty()) { + return p.node; + } if (size > max) { max = size; cur.clear(); diff --git a/platform/lang-impl/src/com/intellij/openapi/components/impl/stores/ModuleStoreImpl.java b/platform/lang-impl/src/com/intellij/openapi/components/impl/stores/ModuleStoreImpl.java index 5d0e994a317c..c7304c1774ea 100644 --- a/platform/lang-impl/src/com/intellij/openapi/components/impl/stores/ModuleStoreImpl.java +++ b/platform/lang-impl/src/com/intellij/openapi/components/impl/stores/ModuleStoreImpl.java @@ -28,6 +28,8 @@ import com.intellij.openapi.project.ex.ProjectEx; import com.intellij.openapi.startup.StartupManager; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.ArrayUtil; +import gnu.trove.THashMap; import org.jdom.Attribute; import org.jdom.Element; import org.jetbrains.annotations.NonNls; @@ -100,13 +102,13 @@ public class ModuleStoreImpl extends BaseFileConfigurableStoreImpl implements IM public ModuleFileData(final String rootElementName, Module module) { super(rootElementName); myModule = module; - myOptions = new TreeMap(); + myOptions = new THashMap(2); } protected ModuleFileData(final ModuleFileData storageData) { super(storageData); - myOptions = new TreeMap(storageData.myOptions); + myOptions = new THashMap(storageData.myOptions); myModule = storageData.myModule; } @@ -130,7 +132,8 @@ public class ModuleStoreImpl extends BaseFileConfigurableStoreImpl implements IM final Element root = super.save(); myOptions.put(VERSION_OPTION, Integer.toString(myVersion)); - Set options = myOptions.keySet(); + String[] options = ArrayUtil.toStringArray(myOptions.keySet()); + Arrays.sort(options); for (String option : options) { root.setAttribute(option, myOptions.get(option)); } diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleSchemeImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleSchemeImpl.java index b358c506ae5b..0971828fc653 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleSchemeImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleSchemeImpl.java @@ -133,14 +133,14 @@ public class CodeStyleSchemeImpl implements JDOMExternalizable, CodeStyleScheme, public static CodeStyleSchemeImpl readScheme(Document document) throws InvalidDataException, JDOMException, IOException{ Element root = document.getRootElement(); if (root == null){ - throw new InvalidDataException(); + throw new InvalidDataException("No root element in code style scheme file"); } String schemeName = root.getAttributeValue(NAME); String parentName = root.getAttributeValue(PARENT); - if (schemeName == null){ - throw new InvalidDataException(); + if (schemeName == null) { + throw new InvalidDataException("Name attribute missing in code style scheme file"); } return new CodeStyleSchemeImpl(schemeName, parentName, root); diff --git a/platform/lang-impl/src/com/intellij/refactoring/introduce/inplace/InplaceVariableIntroducer.java b/platform/lang-impl/src/com/intellij/refactoring/introduce/inplace/InplaceVariableIntroducer.java index 21f0e587b203..1a0027304954 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/introduce/inplace/InplaceVariableIntroducer.java +++ b/platform/lang-impl/src/com/intellij/refactoring/introduce/inplace/InplaceVariableIntroducer.java @@ -148,6 +148,11 @@ public abstract class InplaceVariableIntroducer extends In protected void collectAdditionalElementsToRename(List> stringUsages) { } + @Override + protected int restoreCaretOffset(int offset) { + return myCaretRangeMarker.isValid() ? myCaretRangeMarker.getStartOffset() : offset; + } + @Override protected String getCommandName() { return myTitle; diff --git a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/InplaceRefactoring.java b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/InplaceRefactoring.java index 9164e640fa5c..d27119aa63a6 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/InplaceRefactoring.java +++ b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/InplaceRefactoring.java @@ -104,7 +104,7 @@ public abstract class InplaceRefactoring { protected StartMarkAction myMarkAction; protected PsiElement myScope; - private RangeMarker myCaretRangeMarker; + protected RangeMarker myCaretRangeMarker; public InplaceRefactoring(Editor editor, PsiNamedElement elementToRename, Project project) { this(editor, elementToRename, project, elementToRename != null ? elementToRename.getName() : null, @@ -245,6 +245,10 @@ public abstract class InplaceRefactoring { } else { revertState(); + final TemplateState templateState = TemplateManagerImpl.getTemplateState(InjectedLanguageUtil.getTopLevelEditor(myEditor)); + if (templateState != null) { + templateState.gotoEnd(true); + } } return false; } @@ -350,7 +354,7 @@ public abstract class InplaceRefactoring { } protected int restoreCaretOffset(int offset) { - return myCaretRangeMarker.isValid() ? myCaretRangeMarker.getStartOffset() : offset; + return offset; } protected void navigateToAlreadyStarted(Document oldDocument, int exitCode) { diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java index 920ccaba4933..619ac7132312 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java @@ -44,6 +44,7 @@ import com.intellij.openapi.project.*; import com.intellij.openapi.roots.*; import com.intellij.openapi.util.*; import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.vfs.*; import com.intellij.openapi.vfs.ex.VirtualFileManagerEx; import com.intellij.openapi.vfs.newvfs.BulkFileListener; @@ -280,6 +281,7 @@ public class FileBasedIndex implements ApplicationComponent { versionChanged |= registerIndexer(extension, currentVersionCorrupted); } FileUtil.delete(corruptionMarker); + String rebuildNotification = null; if (currentVersionCorrupted) { rebuildNotification = "Index files on disk are corrupted. Indices will be rebuilt."; @@ -287,10 +289,13 @@ public class FileBasedIndex implements ApplicationComponent { else if (versionChanged) { rebuildNotification = "Index file format has changed for some indices. These indices will be rebuilt."; } - if (rebuildNotification != null && !ApplicationManager.getApplication().isHeadlessEnvironment()) { + if (rebuildNotification != null + && !ApplicationManager.getApplication().isHeadlessEnvironment() + && Registry.is("ide.showIndexRebuildMessage")) { new NotificationGroup("Indexing", NotificationDisplayType.BALLOON, false) .createNotification("Index Rebuild", rebuildNotification, NotificationType.INFORMATION, null).notify(null); } + dropUnregisteredIndices(); // check if rebuild was requested for any index during registration diff --git a/platform/platform-impl/src/com/intellij/internal/statistic/connect/StatisticsHttpClientSender.java b/platform/platform-impl/src/com/intellij/internal/statistic/connect/StatisticsHttpClientSender.java index 535b8ad9b53c..c3f3fb4d615d 100644 --- a/platform/platform-impl/src/com/intellij/internal/statistic/connect/StatisticsHttpClientSender.java +++ b/platform/platform-impl/src/com/intellij/internal/statistic/connect/StatisticsHttpClientSender.java @@ -15,6 +15,7 @@ */ package com.intellij.internal.statistic.connect; +import com.intellij.ide.util.PropertiesComponent; import com.intellij.openapi.application.ApplicationNamesInfo; import com.intellij.openapi.updateSettings.impl.UpdateChecker; import com.intellij.openapi.util.text.StringUtil; @@ -39,7 +40,7 @@ public class StatisticsHttpClientSender implements StatisticsDataSender { post.setRequestBody(new NameValuePair[]{ new NameValuePair("content", content), - new NameValuePair("uuid", UpdateChecker.getInstallationUID()), + new NameValuePair("uuid", UpdateChecker.getInstallationUID(PropertiesComponent.getInstance())), new NameValuePair("ide", ApplicationNamesInfo.getInstance().getProductName()), }); diff --git a/platform/platform-impl/src/com/intellij/notification/EventLog.java b/platform/platform-impl/src/com/intellij/notification/EventLog.java index 88c37d54a8f3..acb1dd32c986 100644 --- a/platform/platform-impl/src/com/intellij/notification/EventLog.java +++ b/platform/platform-impl/src/com/intellij/notification/EventLog.java @@ -165,7 +165,7 @@ public class EventLog implements Notifications { content = title + (StringUtil.isNotEmpty(content) ? ": " + content : ""); } - content = StringUtil.replace(StringUtil.convertLineSeparators(content), " ", " "); + content = StringUtil.convertLineSeparators(content); boolean hasHtml = false; while (true) { Matcher tagMatcher = TAG_PATTERN.matcher(content); @@ -248,6 +248,9 @@ public class EventLog implements Notifications { } private static void appendText(Document document, String text) { + text = StringUtil.replace(text, " ", " "); + text = StringUtil.replace(text, "»", ">>"); + text = StringUtil.replace(text, "«", "<<"); document.insertString(document.getTextLength(), StringUtil.unescapeXml(text)); } diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ComponentStoreImpl.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ComponentStoreImpl.java index 2a4de0fe062f..ad9042e4212c 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ComponentStoreImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ComponentStoreImpl.java @@ -32,6 +32,7 @@ import com.intellij.util.ArrayUtil; import com.intellij.util.ReflectionCache; import com.intellij.util.ReflectionUtil; import com.intellij.util.io.fs.IFile; +import gnu.trove.THashMap; import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -44,7 +45,7 @@ import java.util.*; abstract class ComponentStoreImpl implements IComponentStore { private static final Logger LOG = Logger.getInstance("#com.intellij.components.ComponentStoreImpl"); - private final Map myComponents = Collections.synchronizedMap(new TreeMap()); + private final Map myComponents = Collections.synchronizedMap(new THashMap()); private final List mySettingsSavingComponents = Collections.synchronizedList(new ArrayList()); @Nullable private SaveSessionImpl mySession; @@ -470,7 +471,8 @@ abstract class ComponentStoreImpl implements IComponentStore { final StateStorageManager.ExternalizationSession session = storageManager.startExternalization(); - final String[] names = ArrayUtil.toStringArray(myComponents.keySet()); + String[] names = ArrayUtil.toStringArray(myComponents.keySet()); + Arrays.sort(names); for (String name : names) { Object component = myComponents.get(name); diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/CompoundExternalizationSession.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/CompoundExternalizationSession.java index f01ebe3fd15f..9e1b202676ac 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/CompoundExternalizationSession.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/CompoundExternalizationSession.java @@ -16,16 +16,16 @@ package com.intellij.openapi.components.impl.stores; import com.intellij.openapi.components.StateStorage; +import gnu.trove.THashMap; import java.util.Collection; -import java.util.HashMap; import java.util.Map; /** * @author mike */ public class CompoundExternalizationSession { - private final Map mySessions = new HashMap(); + private final Map mySessions = new THashMap(1); public StateStorage.ExternalizationSession getExternalizationSession(StateStorage stateStore) { StateStorage.ExternalizationSession session = mySessions.get(stateStore); diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManagerImpl.java index c30837efe7a9..a8f94b8a3fb5 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManagerImpl.java @@ -31,6 +31,7 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.ArrayUtil; import com.intellij.util.containers.MultiMap; import com.intellij.util.io.fs.IFile; +import gnu.trove.THashMap; import org.jdom.Document; import org.jdom.Element; import org.jdom.JDOMException; @@ -58,8 +59,8 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di } private final Map myMacros = new HashMap(); - private final Map myStorages = new HashMap(); - private final Map myPathToStorage = new HashMap(); + private final Map myStorages = new THashMap(); + private final Map myPathToStorage = new THashMap(); private final TrackingPathMacroSubstitutor myPathMacroSubstitutor; private final String myRootTagName; private Object mySession; @@ -160,7 +161,7 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di } private Map loadVersions() { - TreeMap result = new TreeMap(); + THashMap result = new THashMap(); String filePath = getNotNullVersionsFilePath(); if (filePath != null) { try { @@ -580,8 +581,10 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di public static Element createComponentVersionsXml(Map versions) { Element vers = new Element("versions"); + String[] componentNames = ArrayUtil.toStringArray(versions.keySet()); + Arrays.sort(componentNames); - for (String name : versions.keySet()) { + for (String name : componentNames) { long version = versions.get(name); if (version != 0) { Element element = new Element("component"); diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/XmlElementStorage.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/XmlElementStorage.java index 4b9d7324ba75..b439c3e212dc 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/XmlElementStorage.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/XmlElementStorage.java @@ -26,8 +26,10 @@ import com.intellij.openapi.util.JDOMUtil; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.WriteExternalException; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.ArrayUtil; import com.intellij.util.containers.StringInterner; import com.intellij.util.io.fs.IFile; +import gnu.trove.THashMap; import org.jdom.Attribute; import org.jdom.Document; import org.jdom.Element; @@ -62,7 +64,7 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { protected Integer myProviderUpToDateHash; private boolean mySavingDisabled = false; - private final Map myStorageComponentStates = new TreeMap(); + private final Map myStorageComponentStates = new THashMap(); // at loading we store Element, on setState Integer of hash// at loading we store Element, on setState Integer of hash private final ComponentVersionProvider myLocalVersionProvider; private final ComponentVersionProvider myRemoteVersionProvider; @@ -126,8 +128,6 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { final StorageData storageData = getStorageData(false); final Element state = storageData.getState(componentName); - - if (state != null) { if (!myStorageComponentStates.containsKey(componentName)) { myStorageComponentStates.put(componentName, state); @@ -309,19 +309,20 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { if (element.getAttributes().isEmpty() && element.getChildren().isEmpty()) return; myStorageData.setState(componentName, element); + int hash = JDOMUtil.getTreeHash(element); - Element oldElement = myStorageComponentStates.get(componentName); try { - if (oldElement != null && !JDOMUtil.areElementsEqual(oldElement, element)) { + Object oldElementState = myStorageComponentStates.get(componentName); + + if (oldElementState instanceof Element && !JDOMUtil.areElementsEqual((Element)oldElementState, element) || + oldElementState instanceof Integer && hash != (Integer)oldElementState + ) { myListener.componentStateChanged(componentName); } } finally { - myStorageComponentStates.put(componentName, (Element)element.clone()); + myStorageComponentStates.put(componentName, hash); } - - - } } @@ -396,10 +397,6 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { protected abstract void doSave() throws StateStorageException; - public void clearHash() { - myUpToDateHash = null; - } - protected Integer calcHash() { return null; } @@ -469,10 +466,6 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { return myUpToDateHash != null && myUpToDateHash.equals(hash); } - public boolean isHashUpToDate() { - return isHashUpToDate(calcHash()); - } - protected Document getDocumentToSave() { if (myDocumentToSave != null) return myDocumentToSave; @@ -520,8 +513,7 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { } private Map loadVersions(Document copy) { - - HashMap result = new HashMap(); + THashMap result = new THashMap(); List list = copy.getRootElement().getChildren(COMPONENT); for (Object o : list) { @@ -550,13 +542,13 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { private Integer myHash; public StorageData(final String rootElementName) { - myComponentStates = new TreeMap(); + myComponentStates = new THashMap(); myRootElementName = rootElementName; } protected StorageData(StorageData storageData) { myRootElementName = storageData.myRootElementName; - myComponentStates = new TreeMap(storageData.myComponentStates); + myComponentStates = new THashMap(storageData.myComponentStates); } protected void load(@NotNull Element rootElement) throws IOException { @@ -603,8 +595,9 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { @NotNull protected Element save() { Element rootElement = new Element(myRootElementName); - - for (String componentName : myComponentStates.keySet()) { + String[] componentNames = ArrayUtil.toStringArray(myComponentStates.keySet()); + Arrays.sort(componentNames); + for (String componentName : componentNames) { assert componentName != null; final Element element = myComponentStates.get(componentName); @@ -617,7 +610,7 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { } @Nullable - public Element getState(final String name) { + private Element getState(final String name) { final Element e = myComponentStates.get(name); if (e != null) { @@ -628,7 +621,7 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { return e; } - public void removeState(final String componentName) { + private void removeState(final String componentName) { myComponentStates.remove(componentName); clearHash(); } @@ -799,7 +792,7 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { } private void loadProviderVersions() { - myProviderVersions = new TreeMap(); + myProviderVersions = new THashMap(); for (RoamingType type : RoamingType.values()) { Document doc = null; if (myStreamProvider.isEnabled()) { diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/CheckForUpdateAction.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/CheckForUpdateAction.java index 006173d6e2d0..f9cd94fea2d6 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/CheckForUpdateAction.java +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/CheckForUpdateAction.java @@ -16,6 +16,7 @@ package com.intellij.openapi.updateSettings.impl; import com.intellij.ide.plugins.PluginHostsConfigurable; +import com.intellij.ide.util.PropertiesComponent; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.PlatformDataKeys; @@ -46,7 +47,9 @@ public class CheckForUpdateAction extends AnAction implements DumbAware { ProgressManager.getInstance().run(new Task.Modal(project, "Checking for updates", false) { @Override public void run(@NotNull ProgressIndicator indicator) { - final CheckForUpdateResult result = UpdateChecker.checkForUpdates(true); + final CheckForUpdateResult result = UpdateChecker.checkForUpdates(UpdateSettings.getInstance(), PropertiesComponent.getInstance(), + true + ); final List updatedPlugins = UpdateChecker.updatePlugins(true, hostsConfigurable); ApplicationManager.getApplication().invokeLater(new Runnable() { diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.java index ec767c5fd4c7..ebf23d0ca097 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.java +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.java @@ -148,11 +148,12 @@ public final class UpdateChecker { public static ActionCallback updateAndShowResult() { final ActionCallback result = new ActionCallback(); final Application app = ApplicationManager.getApplication(); - /* + final PropertiesComponent propertiesComponent = PropertiesComponent.getInstance(); + final UpdateSettings updateSettings = UpdateSettings.getInstance(); app.executeOnPooledThread(new Runnable() { @Override public void run() { - final CheckForUpdateResult checkForUpdateResult = checkForUpdates(); + final CheckForUpdateResult checkForUpdateResult = checkForUpdates(updateSettings, propertiesComponent, false); final List updatedPlugins = updatePlugins(false, null); app.invokeLater(new Runnable() { @@ -164,7 +165,6 @@ public final class UpdateChecker { }); } }); - */ return result; } @@ -346,11 +346,11 @@ public final class UpdateChecker { } @NotNull - public static CheckForUpdateResult doCheckForUpdates(final UpdateSettings settings) { + public static CheckForUpdateResult doCheckForUpdates(final UpdateSettings settings, final PropertiesComponent instance) { ApplicationInfo appInfo = ApplicationInfo.getInstance(); BuildNumber currentBuild = appInfo.getBuild(); int majorVersion = Integer.parseInt(appInfo.getMajorVersion()); - final UpdatesXmlLoader loader = new UpdatesXmlLoader(getUpdateUrl(), getInstallationUID(), null); + final UpdatesXmlLoader loader = new UpdatesXmlLoader(getUpdateUrl(), getInstallationUID(instance), null); final UpdatesInfo info; try { info = loader.loadUpdatesInfo(); @@ -366,25 +366,21 @@ public final class UpdateChecker { return strategy.checkForUpdates(); } - @NotNull - public static CheckForUpdateResult checkForUpdates() { - return checkForUpdates(false); - } - - @NotNull - public static CheckForUpdateResult checkForUpdates(final boolean disregardIgnoredBuilds) { + public static CheckForUpdateResult checkForUpdates(final UpdateSettings updateSettings, + final PropertiesComponent propertiesComponent, + final boolean disregardIgnoredBuilds) { if (LOG.isDebugEnabled()) { LOG.debug("enter: auto checkForUpdates()"); } - UserUpdateSettings settings = UpdateSettings.getInstance(); + UserUpdateSettings settings = updateSettings; if (disregardIgnoredBuilds) { settings = new UserUpdateSettings() { @NotNull @Override public List getKnownChannelsIds() { - return UpdateSettings.getInstance().getKnownChannelsIds(); + return updateSettings.getKnownChannelsIds(); } @Override @@ -394,21 +390,21 @@ public final class UpdateChecker { @Override public void setKnownChannelIds(List ids) { - UpdateSettings.getInstance().setKnownChannelIds(ids); + updateSettings.setKnownChannelIds(ids); } @NotNull @Override public ChannelStatus getSelectedChannelStatus() { - return UpdateSettings.getInstance().getSelectedChannelStatus(); + return updateSettings.getSelectedChannelStatus(); } }; } - final CheckForUpdateResult result = doCheckForUpdates(UpdateSettings.getInstance()); + final CheckForUpdateResult result = doCheckForUpdates(updateSettings, propertiesComponent); if (result.getState() == UpdateStrategy.State.LOADED) { - UpdateSettings.getInstance().LAST_TIME_CHECKED = System.currentTimeMillis(); + updateSettings.LAST_TIME_CHECKED = System.currentTimeMillis(); settings.setKnownChannelIds(result.getAllChannelsIds()); } @@ -444,12 +440,13 @@ public final class UpdateChecker { } final InputStream[] inputStreams = new InputStream[]{null}; final Exception[] exception = new Exception[]{null}; + final PropertiesComponent propertiesComponent = PropertiesComponent.getInstance(); Future downloadThreadFuture = ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { public void run() { try { HttpConfigurable.getInstance().prepareURL(url); - String uid = getInstallationUID(); + String uid = getInstallationUID(propertiesComponent); final URL requestUrl = new URL(url + "?build=" + ApplicationInfo.getInstance().getBuild().asString() + "&uid=" + uid + ADDITIONAL_REQUEST_OPTIONS); @@ -477,8 +474,7 @@ public final class UpdateChecker { return inputStreams[0]; } - public static String getInstallationUID() { - final PropertiesComponent propertiesComponent = PropertiesComponent.getInstance(); + public static String getInstallationUID(final PropertiesComponent propertiesComponent) { String uid = ""; if (!propertiesComponent.isValueSet(INSTALLATION_UID)) { try { diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java index d96b8b17f2b8..c5f32e12a57f 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java @@ -200,7 +200,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements } public void fileClosed(FileEditorManager source, VirtualFile file) { - getFocusManagerImpl().doWhenFocusSettlesDown(new ExpirableRunnable.ForProject(myProject) { + getFocusManagerImpl(myProject).doWhenFocusSettlesDown(new ExpirableRunnable.ForProject(myProject) { public void run() { if (!hasOpenEditorFiles()) { focusToolWinowByDefault(null); @@ -351,8 +351,8 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements return myFileEditorManager.getOpenFiles().length > 0; } - private static FocusManagerImpl getFocusManagerImpl() { - return FocusManagerImpl.getInstance(); + private static IdeFocusManager getFocusManagerImpl(Project project) { + return IdeFocusManager.getInstance(project); } public Project getProject() { @@ -619,7 +619,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements }).doWhenRejected(new Runnable() { public void run() { if (forced) { - getFocusManagerImpl().requestFocus(new FocusCommand() { + getFocusManagerImpl(myProject).requestFocus(new FocusCommand() { public ActionCallback run() { final ArrayList cmds = new ArrayList(); @@ -719,7 +719,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements final ArrayList commandList, boolean forced, boolean autoFocusContents) { - if (!getFocusManagerImpl().isUnforcedRequestAllowed() && !forced) return; + if (/*!getFocusManagerImpl(myProject).isUnforcedRequestAllowed() && */!forced) return; if (LOG.isDebugEnabled()) { LOG.debug("enter: activateToolWindowImpl(" + id + ")"); @@ -1873,7 +1873,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements @Override public void hyperlinkUpdate(HyperlinkEvent e) { - if (myBalloon != null) { + if (myBalloon != null && e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { myBalloon.hide(); } if (myListener != null) { @@ -2002,15 +2002,15 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements return; } final WindowInfoImpl info = getInfo(myId); - getFocusManagerImpl().myFocusedComponentAlaram.cancelAllRequests(); + //getFocusManagerImpl(myProject)..cancelAllRequests(); if (!info.isActive()) { - getFocusManagerImpl().myFocusedComponentAlaram.addRequest(new EdtRunnable() { + getFocusManagerImpl(myProject).doWhenFocusSettlesDown(new EdtRunnable() { public void runEdt() { if (!myLayout.isToolWindowRegistered(myId)) return; activateToolWindow(myId, false, false); } - }, 100); + }); } } } @@ -2128,7 +2128,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements } public ActionCallback requestDefaultFocus(final boolean forced) { - return getFocusManagerImpl().requestFocus(new FocusCommand() { + return getFocusManagerImpl(myProject).requestFocus(new FocusCommand() { public ActionCallback run() { return processDefaultFocusRequest(forced); } diff --git a/platform/platform-impl/src/com/intellij/ui/popup/PopupFactoryImpl.java b/platform/platform-impl/src/com/intellij/ui/popup/PopupFactoryImpl.java index 2057539a4037..1e6e8f9940ae 100644 --- a/platform/platform-impl/src/com/intellij/ui/popup/PopupFactoryImpl.java +++ b/platform/platform-impl/src/com/intellij/ui/popup/PopupFactoryImpl.java @@ -208,20 +208,8 @@ public class PopupFactoryImpl extends JBPopupFactory { builder.buildGroup(actionGroup); final List items = builder.getItems(); - int defaultOptionIndex = 0; - if (preselectActionCondition != null) { - for (int i = 0; i < items.size(); i++) { - final AnAction action = items.get(i).getAction(); - if (preselectActionCondition.value(action)) { - defaultOptionIndex = i; - break; - } - } - } - return new ActionPopupStep(items, title, component, showNumbers || honorActionMnemonics && itemsHaveMnemonics(items), - defaultOptionIndex, - false, showDisabledActions); + preselectActionCondition, false, showDisabledActions); } @Override @@ -300,14 +288,42 @@ public class PopupFactoryImpl extends JBPopupFactory { return createActionsStep(actionGroup, dataContext, showNumbers, showDisabledActions, title, component, honorActionMnemonics, 0, false); } - private static ListPopupStep createActionsStep(ActionGroup actionGroup, @NotNull DataContext dataContext, boolean showNumbers, boolean useAlphaAsNumbers, boolean showDisabledActions, - String title, Component component, boolean honorActionMnemonics, int defaultOptionIndex, - final boolean autoSelectionEnabled) { - final ActionStepBuilder builder = new ActionStepBuilder(dataContext, showNumbers, useAlphaAsNumbers, showDisabledActions, honorActionMnemonics); - builder.buildGroup(actionGroup); - final List items = builder.getItems(); + private static ListPopupStep createActionsStep(ActionGroup actionGroup, @NotNull DataContext dataContext, + boolean showNumbers, boolean useAlphaAsNumbers, boolean showDisabledActions, + String title, Component component, boolean honorActionMnemonics, + final int defaultOptionIndex, final boolean autoSelectionEnabled) { + final List items = makeActionItemsFromActionGroup(actionGroup, dataContext, showNumbers, useAlphaAsNumbers, + showDisabledActions, honorActionMnemonics); + return new ActionPopupStep(items, title, component, showNumbers || honorActionMnemonics && itemsHaveMnemonics(items), + new Condition() { + @Override + public boolean value(AnAction action) { + return defaultOptionIndex >= 0 && + defaultOptionIndex < items.size() && + items.get(defaultOptionIndex).getAction().equals(action); + } + }, autoSelectionEnabled, showDisabledActions); + } - return new ActionPopupStep(items, title, component, showNumbers || honorActionMnemonics && itemsHaveMnemonics(items), defaultOptionIndex, + private static List makeActionItemsFromActionGroup(ActionGroup actionGroup, + DataContext dataContext, + boolean showNumbers, + boolean useAlphaAsNumbers, + boolean showDisabledActions, + boolean honorActionMnemonics) { + final ActionStepBuilder builder = new ActionStepBuilder(dataContext, showNumbers, useAlphaAsNumbers, showDisabledActions, + honorActionMnemonics); + builder.buildGroup(actionGroup); + return builder.getItems(); + } + + private static ListPopupStep createActionsStep(ActionGroup actionGroup, @NotNull DataContext dataContext, + boolean showNumbers, boolean useAlphaAsNumbers, boolean showDisabledActions, + String title, Component component, boolean honorActionMnemonics, + Condition preselectActionCondition, boolean autoSelectionEnabled) { + final List items = makeActionItemsFromActionGroup(actionGroup, dataContext, showNumbers, useAlphaAsNumbers, + showDisabledActions, honorActionMnemonics); + return new ActionPopupStep(items, title, component, showNumbers || honorActionMnemonics && itemsHaveMnemonics(items), preselectActionCondition, autoSelectionEnabled, showDisabledActions); } @@ -487,21 +503,35 @@ public class PopupFactoryImpl extends JBPopupFactory { private final boolean myAutoSelectionEnabled; private final boolean myShowDisabledActions; private Runnable myFinalRunnable; + @Nullable private final Condition myPreselectActionCondition; - private ActionPopupStep(@NotNull final List items, - final String title, - Component context, - boolean enableMnemonics, - final int defaultOptionIndex, final boolean autoSelection, boolean showDisabledActions) { + private ActionPopupStep(@NotNull final List items, final String title, Component context, boolean enableMnemonics, + @Nullable Condition preselectActionCondition, final boolean autoSelection, boolean showDisabledActions) { myItems = items; myTitle = title; myContext = context; myEnableMnemonics = enableMnemonics; - myDefaultOptionIndex = defaultOptionIndex; + myDefaultOptionIndex = getDefaultOptionIndexFromSelectCondition(preselectActionCondition, items); + myPreselectActionCondition = preselectActionCondition; myAutoSelectionEnabled = autoSelection; myShowDisabledActions = showDisabledActions; } + private static int getDefaultOptionIndexFromSelectCondition(@Nullable Condition preselectActionCondition, + @NotNull List items) { + int defaultOptionIndex = 0; + if (preselectActionCondition != null) { + for (int i = 0; i < items.size(); i++) { + final AnAction action = items.get(i).getAction(); + if (preselectActionCondition.value(action)) { + defaultOptionIndex = i; + break; + } + } + } + return defaultOptionIndex; + } + @NotNull public List getValues() { return myItems; @@ -552,13 +582,14 @@ public class PopupFactoryImpl extends JBPopupFactory { final DataContext dataContext = myContext != null ? mgr.getDataContext(myContext) : mgr.getDataContext(); if (action instanceof ActionGroup && (!finalChoice || !((ActionGroup)action).canBePerformed(dataContext))) { - return JBPopupFactory.getInstance().createActionsStep((ActionGroup)action, dataContext, myEnableMnemonics, myShowDisabledActions, null, myContext, false); + return createActionsStep((ActionGroup)action, dataContext, myEnableMnemonics, true, myShowDisabledActions, null, myContext, false, + myPreselectActionCondition, false); } else { myFinalRunnable = new Runnable() { public void run() { action.actionPerformed( - new AnActionEvent(null, dataContext, ActionPlaces.UNKNOWN, (Presentation)action.getTemplatePresentation().clone(), + new AnActionEvent(null, dataContext, ActionPlaces.UNKNOWN, action.getTemplatePresentation().clone(), ActionManager.getInstance(), 0)); } }; diff --git a/platform/platform-resources-en/src/misc/registry.properties b/platform/platform-resources-en/src/misc/registry.properties index 45a72e198390..8cc86d0f4215 100644 --- a/platform/platform-resources-en/src/misc/registry.properties +++ b/platform/platform-resources-en/src/misc/registry.properties @@ -99,6 +99,8 @@ editor.mouseSelectionStateResetDeadzone=4 editor.use.new.tabs=true editor.smarterSelectionQuoting=true +ide.showIndexRebuildMessage=false + ide.tabbedPane.bufferedPaint=true ide.tabbedPane.dragOutMultiplier=1.2 @@ -108,6 +110,7 @@ ide.mac.message.dialogs.as.sheets=true ide.mac.inplaceDialogMnemonicsFix=true ide.mac.hide.cursor.when.typing=false ide.mac.show.native.help=false +ide.mac.useNativeClipboard=false debugger.valueTooltipAutoShow=true debugger.valueTooltipAutoShow.description=Auto show tooltip on mouse over @@ -171,8 +174,6 @@ projectView.hide.dot.idea=true show.live.templates.in.completion=false documentation.component.editor.font=false -ide.mac.useNativeClipboard=false - show.all.classes.on.first.completion=false ide.enable.toolwindow.stack=false diff --git a/platform/platform-tests/testSrc/com/intellij/notification/EventLogTest.groovy b/platform/platform-tests/testSrc/com/intellij/notification/EventLogTest.groovy index 3b1360036d49..baf2f08ef1d4 100644 --- a/platform/platform-tests/testSrc/com/intellij/notification/EventLogTest.groovy +++ b/platform/platform-tests/testSrc/com/intellij/notification/EventLogTest.groovy @@ -29,9 +29,9 @@ class EventLogTest extends LightPlatformTestCase { PlatformTestCase.initPlatformLangPrefix() } - public void testNbsp() { - def entry = EventLog.formatForLog(new Notification("xxx", "Title", "Hello world", NotificationType.ERROR)) - assert entry.message == 'Title: Hello world' + public void testHtmlEntities() { + def entry = EventLog.formatForLog(new Notification("xxx", "Title", "Hello world«»", NotificationType.ERROR)) + assert entry.message == 'Title: Hello world<<>>' } public void testParseMultilineText() { diff --git a/platform/usageView/src/com/intellij/usages/impl/UsageViewTreeCellRenderer.java b/platform/usageView/src/com/intellij/usages/impl/UsageViewTreeCellRenderer.java index a4fbf29eccce..33e6e09a3dba 100644 --- a/platform/usageView/src/com/intellij/usages/impl/UsageViewTreeCellRenderer.java +++ b/platform/usageView/src/com/intellij/usages/impl/UsageViewTreeCellRenderer.java @@ -68,6 +68,11 @@ class UsageViewTreeCellRenderer extends ColoredTreeCellRenderer { if (userObject instanceof UsageTarget) { UsageTarget usageTarget = (UsageTarget)userObject; + if (!usageTarget.isValid()) { + append(UsageViewBundle.message("node.invalid"), ourInvalidAttributes); + return; + } + final ItemPresentation presentation = usageTarget.getPresentation(); LOG.assertTrue(presentation != null); if (showAsReadOnly) { diff --git a/platform/util/src/com/intellij/openapi/util/JDOMUtil.java b/platform/util/src/com/intellij/openapi/util/JDOMUtil.java index a7826308a2c6..02076e7106a6 100644 --- a/platform/util/src/com/intellij/openapi/util/JDOMUtil.java +++ b/platform/util/src/com/intellij/openapi/util/JDOMUtil.java @@ -36,6 +36,7 @@ import org.xml.sax.EntityResolver; import org.xml.sax.InputSource; import java.io.*; +import java.lang.ref.SoftReference; import java.net.URL; import java.util.ArrayList; import java.util.Collections; @@ -47,17 +48,7 @@ import java.util.List; */ @SuppressWarnings({"HardCodedStringLiteral"}) public class JDOMUtil { - private static final ThreadLocal ourSaxBuilder = new ThreadLocal(){ - protected SAXBuilder initialValue() { - SAXBuilder saxBuilder = new SAXBuilder(); - saxBuilder.setEntityResolver(new EntityResolver() { - public InputSource resolveEntity(String publicId, String systemId) { - return new InputSource(new CharArrayReader(ArrayUtil.EMPTY_CHAR_ARRAY)); - } - }); - return saxBuilder; - } - }; + private static final ThreadLocal> ourSaxBuilder = new ThreadLocal>(); private JDOMUtil() { } @@ -317,14 +308,27 @@ public class JDOMUtil { @NotNull public static Document loadDocument(char[] chars, int length) throws IOException, JDOMException { - SAXBuilder builder = ourSaxBuilder.get(); - return builder.build(new CharArrayReader(chars, 0, length)); + return getSaxBuilder().build(new CharArrayReader(chars, 0, length)); + } + + private static SAXBuilder getSaxBuilder() { + SoftReference reference = ourSaxBuilder.get(); + SAXBuilder saxBuilder = reference != null ? reference.get() : null; + if (saxBuilder == null) { + saxBuilder = new SAXBuilder(); + saxBuilder.setEntityResolver(new EntityResolver() { + public InputSource resolveEntity(String publicId, String systemId) { + return new InputSource(new CharArrayReader(ArrayUtil.EMPTY_CHAR_ARRAY)); + } + }); + ourSaxBuilder.set(new SoftReference(saxBuilder)); + } + return saxBuilder; } @NotNull public static Document loadDocument(CharSequence seq) throws IOException, JDOMException { - SAXBuilder builder = ourSaxBuilder.get(); - return builder.build(new CharSequenceReader(seq)); + return getSaxBuilder().build(new CharSequenceReader(seq)); } @NotNull @@ -351,10 +355,9 @@ public class JDOMUtil { @NotNull public static Document loadDocument(@NotNull InputStream stream) throws JDOMException, IOException { - SAXBuilder saxBuilder = ourSaxBuilder.get(); InputStreamReader reader = new InputStreamReader(stream, ENCODING); try { - return saxBuilder.build(reader); + return getSaxBuilder().build(reader); } finally { reader.close(); diff --git a/platform/util/src/com/intellij/openapi/util/text/StringHash.java b/platform/util/src/com/intellij/openapi/util/text/StringHash.java index 404a935616b5..e20c15f08a92 100644 --- a/platform/util/src/com/intellij/openapi/util/text/StringHash.java +++ b/platform/util/src/com/intellij/openapi/util/text/StringHash.java @@ -151,5 +151,43 @@ public class StringHash { return h; } + public static int murmur(String data, int seed) { + final int length = data.length(); + // 'm' and 'r' are mixing constants generated offline. + // They're not really 'magic', they just happen to work well. + final int m = 0x5bd1e995; + final int r = 24; + // Initialize the hash to a random value + int h = seed ^ length; + int length4 = length >> 2; + + for (int i = 0; i < length4; i++) { + final int i4 = i << 2; + int k = data.charAt(i4) + (data.charAt(i4 + 1) << 8) + + (data.charAt(i4 + 2) << 16) + (data.charAt(i4 + 3) << 24); + k *= m; + k ^= k >>> r; + k *= m; + h *= m; + h ^= k; + } + + // Handle the last few bytes of the input array + switch (length % 4) { + case 3: + h ^= data.charAt((length & ~3) + 2) << 16; + case 2: + h ^= data.charAt((length & ~3) + 1) << 8; + case 1: + h ^= data.charAt(length & ~3); + h *= m; + } + + h ^= h >>> 13; + h *= m; + h ^= h >>> 15; + + return h; + } } diff --git a/platform/util/src/com/intellij/util/lang/ClasspathCache.java b/platform/util/src/com/intellij/util/lang/ClasspathCache.java index 8b13a3f35a55..658cda05f986 100644 --- a/platform/util/src/com/intellij/util/lang/ClasspathCache.java +++ b/platform/util/src/com/intellij/util/lang/ClasspathCache.java @@ -19,6 +19,7 @@ */ package com.intellij.util.lang; +import com.intellij.openapi.util.text.StringHash; import com.intellij.util.ArrayUtil; import com.intellij.util.SmartList; import com.intellij.util.containers.HashMap; @@ -273,7 +274,7 @@ public class ClasspathCache { } private boolean maybeContains(String name, Loader loader) { - int hash = hashFromNameAndLoader(name, loader, murmur(name, SEED)); + int hash = hashFromNameAndLoader(name, loader, StringHash.murmur(name, SEED)); int hash2 = hashFromNameAndLoader(name, loader, hash); for (int i = 0; i < myHashFunctionCount; ++i) { @@ -283,7 +284,7 @@ public class ClasspathCache { } public void add(String name, Loader loader) { - int hash1 = hashFromNameAndLoader(name, loader, murmur(name, SEED)); + int hash1 = hashFromNameAndLoader(name, loader, StringHash.murmur(name, SEED)); int hash2 = hashFromNameAndLoader(name, loader, hash1); for (int i = 0; i < myHashFunctionCount; ++i) { @@ -292,7 +293,7 @@ public class ClasspathCache { } private int hashFromNameAndLoader(String name, Loader loader, int n) { - int hash = murmur(name, n); + int hash = StringHash.murmur(name, n); int i = loader.getIndex(); while (i > 0) { hash = hash * n + ((i % 10) + '0'); @@ -300,45 +301,6 @@ public class ClasspathCache { } return hash; } - - private static int murmur(String data, int seed) { - final int length = data.length(); - // 'm' and 'r' are mixing constants generated offline. - // They're not really 'magic', they just happen to work well. - final int m = 0x5bd1e995; - final int r = 24; - // Initialize the hash to a random value - int h = seed ^ length; - int length4 = length >> 2; - - for (int i = 0; i < length4; i++) { - final int i4 = i << 2; - int k = data.charAt(i4) + (data.charAt(i4 + 1) << 8) + - (data.charAt(i4 + 2) << 16) + (data.charAt(i4 + 3) << 24); - k *= m; - k ^= k >>> r; - k *= m; - h *= m; - h ^= k; - } - - // Handle the last few bytes of the input array - switch (length % 4) { - case 3: - h ^= data.charAt((length & ~3) + 2) << 16; - case 2: - h ^= data.charAt((length & ~3) + 1) << 8; - case 1: - h ^= data.charAt(length & ~3); - h *= m; - } - - h ^= h >>> 13; - h *= m; - h ^= h >>> 15; - - return h; - } } static class DebugInfo { diff --git a/platform/vcs-impl/src/com/intellij/openapi/diff/impl/patch/formove/PathsVerifier.java b/platform/vcs-impl/src/com/intellij/openapi/diff/impl/patch/formove/PathsVerifier.java index ffca0ed834c2..7ab196a1b4b1 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/diff/impl/patch/formove/PathsVerifier.java +++ b/platform/vcs-impl/src/com/intellij/openapi/diff/impl/patch/formove/PathsVerifier.java @@ -564,7 +564,7 @@ public class PathsVerifier { public Collection doDelayed() { final List result = new LinkedList(); if (! myOverrideExisting.isEmpty()) { - final String title = "Overwrite existing files"; + final String title = "Overwrite Existing Files"; final Collection selected = AbstractVcsHelper.getInstance(myProject).selectFilePathsToProcess( new ArrayList(myOverrideExisting.keySet()), title, "\nThe following files should be created by patch, but they already exist.\nDo you want to overwrite them?\n", title, diff --git a/plugins/android/src/META-INF/plugin.xml b/plugins/android/src/META-INF/plugin.xml index 67a616094d46..879eb049c278 100644 --- a/plugins/android/src/META-INF/plugin.xml +++ b/plugins/android/src/META-INF/plugin.xml @@ -190,11 +190,15 @@ + + + + diff --git a/plugins/android/src/org/jetbrains/android/AndroidRenameHandler.java b/plugins/android/src/org/jetbrains/android/AndroidRenameHandler.java new file mode 100644 index 000000000000..2924d9cd3a3b --- /dev/null +++ b/plugins/android/src/org/jetbrains/android/AndroidRenameHandler.java @@ -0,0 +1,98 @@ +package org.jetbrains.android; + +import com.intellij.ide.TitledHandler; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.actionSystem.LangDataKeys; +import com.intellij.openapi.actionSystem.PlatformDataKeys; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.xml.XmlAttribute; +import com.intellij.psi.xml.XmlAttributeValue; +import com.intellij.psi.xml.XmlTag; +import com.intellij.refactoring.rename.PsiElementRenameHandler; +import com.intellij.refactoring.rename.RenameDialog; +import com.intellij.refactoring.rename.RenameHandler; +import org.jetbrains.android.dom.wrappers.ValueResourceElementWrapper; +import org.jetbrains.annotations.NotNull; + +/** + * @author Eugene.Kudelevsky + */ +public class AndroidRenameHandler implements RenameHandler, TitledHandler { + @Override + public boolean isAvailableOnDataContext(DataContext dataContext) { + final Editor editor = PlatformDataKeys.EDITOR.getData(dataContext); + if (editor == null) { + return false; + } + + final PsiFile file = LangDataKeys.PSI_FILE.getData(dataContext); + if (file == null) { + return false; + } + + return AndroidUsagesTargetProvider.findValueResourceTagInContext(editor, file) != null; + } + + @Override + public boolean isRenaming(DataContext dataContext) { + return isAvailableOnDataContext(dataContext); + } + + @Override + public void invoke(@NotNull Project project, Editor editor, PsiFile file, DataContext dataContext) { + if (file == null || editor == null) { + return; + } + + final XmlTag tag = AndroidUsagesTargetProvider.findValueResourceTagInContext(editor, file); + if (tag == null) { + return; + } + + final XmlAttribute nameAttribute = tag.getAttribute("name"); + if (nameAttribute == null) { + return; + } + + final XmlAttributeValue attributeValue = nameAttribute.getValueElement(); + if (attributeValue == null) { + return; + } + final RenameDialog dialog = new RenameDialog(project, new ValueResourceElementWrapper(attributeValue), null, editor); + + if (ApplicationManager.getApplication().isUnitTestMode()) { + final String name = PsiElementRenameHandler.DEFAULT_NAME.getData(dataContext); + //noinspection TestOnlyProblems + dialog.performRename(name); + dialog.close(DialogWrapper.OK_EXIT_CODE); + } + else { + dialog.show(); + } + } + + @Override + public void invoke(@NotNull Project project, @NotNull PsiElement[] elements, DataContext dataContext) { + final Editor editor = PlatformDataKeys.EDITOR.getData(dataContext); + if (editor == null) { + return; + } + + final PsiFile file = LangDataKeys.PSI_FILE.getData(dataContext); + if (file == null) { + return; + } + + invoke(project, editor, file, dataContext); + } + + @Override + public String getActionTitle() { + return "Rename Android value resource"; + } +} diff --git a/plugins/android/src/org/jetbrains/android/AndroidUsagesTargetProvider.java b/plugins/android/src/org/jetbrains/android/AndroidUsagesTargetProvider.java new file mode 100644 index 000000000000..da7bad1164e4 --- /dev/null +++ b/plugins/android/src/org/jetbrains/android/AndroidUsagesTargetProvider.java @@ -0,0 +1,72 @@ +package org.jetbrains.android; + +import com.android.resources.ResourceFolderType; +import com.intellij.find.findUsages.PsiElement2UsageTargetAdapter; +import com.intellij.openapi.editor.Editor; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.xml.XmlFile; +import com.intellij.psi.xml.XmlTag; +import com.intellij.usages.UsageTarget; +import com.intellij.usages.UsageTargetProvider; +import org.jetbrains.android.facet.AndroidFacet; +import org.jetbrains.android.resourceManagers.ResourceManager; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author Eugene.Kudelevsky + */ +public class AndroidUsagesTargetProvider implements UsageTargetProvider { + @Override + public UsageTarget[] getTargets(Editor editor, PsiFile file) { + if (editor == null || file == null) { + return UsageTarget.EMPTY_ARRAY; + } + + final XmlTag tag = findValueResourceTagInContext(editor, file); + return tag != null + ? new UsageTarget[]{new PsiElement2UsageTargetAdapter(tag)} + : UsageTarget.EMPTY_ARRAY; + } + + @Override + public UsageTarget[] getTargets(PsiElement psiElement) { + return UsageTarget.EMPTY_ARRAY; + } + + @Nullable + static XmlTag findValueResourceTagInContext(@NotNull Editor editor, @NotNull PsiFile file) { + if (!(file instanceof XmlFile)) { + return null; + } + + final AndroidFacet facet = AndroidFacet.getInstance(file); + if (facet == null) { + return null; + } + + if (!ResourceManager.isInResourceSubdirectory(file, ResourceFolderType.VALUES.getName())) { + return null; + } + + final PsiElement element = file.findElementAt(editor.getCaretModel().getOffset()); + if (element == null) { + return null; + } + + final XmlTag tag = PsiTreeUtil.getParentOfType(element, XmlTag.class); + if (tag == null) { + return null; + } + + final String name = tag.getAttributeValue("name"); + if (name == null || name.length() == 0) { + return null; + } + + final XmlTag parentTag = tag.getParentTag(); + return parentTag != null && parentTag.getParentTag() == null ? tag : null; + } +} diff --git a/plugins/android/testData/findUsages/fu1_values.xml b/plugins/android/testData/findUsages/fu1_values.xml new file mode 100644 index 000000000000..7030fd307cf3 --- /dev/null +++ b/plugins/android/testData/findUsages/fu1_values.xml @@ -0,0 +1,5 @@ + + hello + + + \ No newline at end of file diff --git a/plugins/android/testData/findUsages/fu2_values.xml b/plugins/android/testData/findUsages/fu2_values.xml new file mode 100644 index 000000000000..ae503ae09b39 --- /dev/null +++ b/plugins/android/testData/findUsages/fu2_values.xml @@ -0,0 +1,5 @@ + + ng name="hello">hello + + + \ No newline at end of file diff --git a/plugins/android/testData/findUsages/fu3_values.xml b/plugins/android/testData/findUsages/fu3_values.xml new file mode 100644 index 000000000000..0f71c487817f --- /dev/null +++ b/plugins/android/testData/findUsages/fu3_values.xml @@ -0,0 +1,5 @@ + + name="hello">hello + + + \ No newline at end of file diff --git a/plugins/android/testData/findUsages/fu4_values.xml b/plugins/android/testData/findUsages/fu4_values.xml new file mode 100644 index 000000000000..68bcff440083 --- /dev/null +++ b/plugins/android/testData/findUsages/fu4_values.xml @@ -0,0 +1,5 @@ + + hello + + + \ No newline at end of file diff --git a/plugins/android/testData/findUsages/fu5_values.xml b/plugins/android/testData/findUsages/fu5_values.xml new file mode 100644 index 000000000000..88982c39bb12 --- /dev/null +++ b/plugins/android/testData/findUsages/fu5_values.xml @@ -0,0 +1,5 @@ + + >hello + + + \ No newline at end of file diff --git a/plugins/android/testData/findUsages/fu6_values.xml b/plugins/android/testData/findUsages/fu6_values.xml new file mode 100644 index 000000000000..3319786f7050 --- /dev/null +++ b/plugins/android/testData/findUsages/fu6_values.xml @@ -0,0 +1,5 @@ + + hello + + + \ No newline at end of file diff --git a/plugins/android/testData/findUsages/fu7_values.xml b/plugins/android/testData/findUsages/fu7_values.xml new file mode 100644 index 000000000000..cac0b17f269a --- /dev/null +++ b/plugins/android/testData/findUsages/fu7_values.xml @@ -0,0 +1,5 @@ + + hellotring> + + + \ No newline at end of file diff --git a/plugins/android/testData/findUsages/fu8_values.xml b/plugins/android/testData/findUsages/fu8_values.xml new file mode 100644 index 000000000000..b3349b91a06f --- /dev/null +++ b/plugins/android/testData/findUsages/fu8_values.xml @@ -0,0 +1,5 @@ + + hello</string> + + + \ No newline at end of file diff --git a/plugins/android/testData/findUsages/fu9_values.xml b/plugins/android/testData/findUsages/fu9_values.xml new file mode 100644 index 000000000000..2c8a4248c85b --- /dev/null +++ b/plugins/android/testData/findUsages/fu9_values.xml @@ -0,0 +1,8 @@ + + hello + + + str1 + str2 + + \ No newline at end of file diff --git a/plugins/android/testData/rename/layoutStrUsage.xml b/plugins/android/testData/rename/layoutStrUsage.xml new file mode 100644 index 000000000000..72f3d5e274a2 --- /dev/null +++ b/plugins/android/testData/rename/layoutStrUsage.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plugins/android/testData/rename/layoutStrUsage_after.xml b/plugins/android/testData/rename/layoutStrUsage_after.xml new file mode 100644 index 000000000000..a2db8f608af7 --- /dev/null +++ b/plugins/android/testData/rename/layoutStrUsage_after.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plugins/android/testData/rename/strings1.xml b/plugins/android/testData/rename/strings1.xml new file mode 100644 index 000000000000..3a956ed1c142 --- /dev/null +++ b/plugins/android/testData/rename/strings1.xml @@ -0,0 +1,3 @@ + + HellO! + \ No newline at end of file diff --git a/plugins/android/testData/rename/strings2.xml b/plugins/android/testData/rename/strings2.xml new file mode 100644 index 000000000000..a516f0490b97 --- /dev/null +++ b/plugins/android/testData/rename/strings2.xml @@ -0,0 +1,3 @@ + + HellO! + \ No newline at end of file diff --git a/plugins/android/testData/rename/strings3.xml b/plugins/android/testData/rename/strings3.xml new file mode 100644 index 000000000000..9a555511326d --- /dev/null +++ b/plugins/android/testData/rename/strings3.xml @@ -0,0 +1,3 @@ + + HellO!ng> + \ No newline at end of file diff --git a/plugins/android/testData/rename/strings4.xml b/plugins/android/testData/rename/strings4.xml new file mode 100644 index 000000000000..a2cc809bcb54 --- /dev/null +++ b/plugins/android/testData/rename/strings4.xml @@ -0,0 +1,3 @@ + + tring name="str">HellO! + \ No newline at end of file diff --git a/plugins/android/testSrc/org/jetbrains/android/AndroidFindUsagesTest.java b/plugins/android/testSrc/org/jetbrains/android/AndroidFindUsagesTest.java index bdc34d014777..6dd6f4b58898 100644 --- a/plugins/android/testSrc/org/jetbrains/android/AndroidFindUsagesTest.java +++ b/plugins/android/testSrc/org/jetbrains/android/AndroidFindUsagesTest.java @@ -17,21 +17,23 @@ package org.jetbrains.android; import com.intellij.codeInsight.TargetElementUtilBase; +import com.intellij.openapi.actionSystem.DataProvider; +import com.intellij.openapi.editor.ex.EditorEx; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiElement; import com.intellij.testFramework.fixtures.JavaCodeInsightTestFixture; import com.intellij.usageView.UsageInfo; +import com.intellij.usages.PsiElementUsageTarget; +import com.intellij.usages.UsageTarget; +import com.intellij.usages.UsageTargetUtil; +import org.jetbrains.annotations.NonNls; +import java.util.ArrayList; import java.util.Collection; import java.util.List; -import java.util.ArrayList; /** - * Created by IntelliJ IDEA. - * User: Eugene.Kudelevsky - * Date: Aug 5, 2009 - * Time: 4:48:01 PM - * To change this template use File | Settings | File Templates. + * @author Eugene.Kudelevsky */ public class AndroidFindUsagesTest extends AndroidTestCase { private static final String BASE_PATH = "/findUsages/"; @@ -39,13 +41,12 @@ public class AndroidFindUsagesTest extends AndroidTestCase { @Override public void setUp() throws Exception { super.setUp(); - myFixture.copyFileToProject(BASE_PATH + "strings.xml", "res/values/strings.xml"); myFixture.copyFileToProject(BASE_PATH + "picture3.gif", "res/drawable/picture3.gif"); myFixture.copyFileToProject(BASE_PATH + "R.java", "gen/p1/p2/R.java"); } - public List findCodeUsages(String path) throws Throwable { - Collection usages = findElementAtCaret(path, myFixture, BASE_PATH); + public List findCodeUsages(String path, String pathInProject) throws Throwable { + Collection usages = findUsages(path, myFixture, pathInProject); List result = new ArrayList(); for (UsageInfo usage : usages) { if (!usage.isNonCodeUsage) { @@ -56,70 +57,146 @@ public class AndroidFindUsagesTest extends AndroidTestCase { } public void testFileResource() throws Throwable { + myFixture.copyFileToProject(BASE_PATH + "strings.xml", "res/values/strings.xml"); myFixture.copyFileToProject(BASE_PATH + "Class.java", "src/p1/p2/Class.java"); myFixture.copyFileToProject(BASE_PATH + "styles.xml", "res/values/styles.xml"); - Collection references = findCodeUsages("fu1_layout.xml"); + Collection references = findCodeUsages("fu1_layout.xml", "res/layout/fu1_layout.xml"); assertEquals(3, references.size()); } public void testValueResource() throws Throwable { + myFixture.copyFileToProject(BASE_PATH + "strings.xml", "res/values/strings.xml"); myFixture.copyFileToProject(BASE_PATH + "Class.java", "src/p1/p2/Class.java"); - Collection references = findCodeUsages("fu2_layout.xml"); + Collection references = findCodeUsages("fu2_layout.xml", "res/layout/fu2_layout.xml"); + assertEquals(2, references.size()); + } + + public void testValueResource1() throws Throwable { + myFixture.copyFileToProject(BASE_PATH + "Class.java", "src/p1/p2/Class.java"); + myFixture.copyFileToProject(BASE_PATH + "layout.xml", "res/layout/layout.xml"); + Collection references = findCodeUsages("fu1_values.xml", "res/values/fu1_values.xml"); + assertEquals(2, references.size()); + } + + public void testValueResource2() throws Throwable { + myFixture.copyFileToProject(BASE_PATH + "Class.java", "src/p1/p2/Class.java"); + myFixture.copyFileToProject(BASE_PATH + "layout.xml", "res/layout/layout.xml"); + Collection references = findCodeUsages("fu2_values.xml", "res/values/fu2_values.xml"); + assertEquals(2, references.size()); + } + + public void testValueResource3() throws Throwable { + myFixture.copyFileToProject(BASE_PATH + "Class.java", "src/p1/p2/Class.java"); + myFixture.copyFileToProject(BASE_PATH + "layout.xml", "res/layout/layout.xml"); + Collection references = findCodeUsages("fu2_values.xml", "res/values/fu3_values.xml"); + assertEquals(2, references.size()); + } + + public void testValueResource4() throws Throwable { + myFixture.copyFileToProject(BASE_PATH + "Class.java", "src/p1/p2/Class.java"); + myFixture.copyFileToProject(BASE_PATH + "layout.xml", "res/layout/layout.xml"); + Collection references = findCodeUsages("fu2_values.xml", "res/values/fu4_values.xml"); + assertEquals(2, references.size()); + } + + public void testValueResource5() throws Throwable { + myFixture.copyFileToProject(BASE_PATH + "Class.java", "src/p1/p2/Class.java"); + myFixture.copyFileToProject(BASE_PATH + "layout.xml", "res/layout/layout.xml"); + Collection references = findCodeUsages("fu2_values.xml", "res/values/fu5_values.xml"); + assertEquals(2, references.size()); + } + + public void testValueResource6() throws Throwable { + myFixture.copyFileToProject(BASE_PATH + "Class.java", "src/p1/p2/Class.java"); + myFixture.copyFileToProject(BASE_PATH + "layout.xml", "res/layout/layout.xml"); + Collection references = findCodeUsages("fu2_values.xml", "res/values/fu6_values.xml"); + assertEquals(2, references.size()); + } + + public void testValueResource7() throws Throwable { + myFixture.copyFileToProject(BASE_PATH + "Class.java", "src/p1/p2/Class.java"); + myFixture.copyFileToProject(BASE_PATH + "layout.xml", "res/layout/layout.xml"); + Collection references = findCodeUsages("fu2_values.xml", "res/values/fu7_values.xml"); + assertEquals(2, references.size()); + } + + public void testValueResource8() throws Throwable { + myFixture.copyFileToProject(BASE_PATH + "Class.java", "src/p1/p2/Class.java"); + myFixture.copyFileToProject(BASE_PATH + "layout.xml", "res/layout/layout.xml"); + Collection references = findCodeUsages("fu2_values.xml", "res/values/f8_values.xml"); assertEquals(2, references.size()); } public void testValueItemResource() throws Throwable { + myFixture.copyFileToProject(BASE_PATH + "strings.xml", "res/values/strings.xml"); myFixture.copyFileToProject(BASE_PATH + "Class.java", "src/p1/p2/Class.java"); - Collection references = findCodeUsages("fu5_layout.xml"); + Collection references = findCodeUsages("fu5_layout.xml", "res/layout/fu5_layout.xml"); assertEquals(2, references.size()); } public void testFileResourceField() throws Throwable { + myFixture.copyFileToProject(BASE_PATH + "strings.xml", "res/values/strings.xml"); myFixture.copyFileToProject(BASE_PATH + "layout.xml", "res/layout/layout.xml"); - Collection references = findCodeUsages("Fu3.java"); + Collection references = findCodeUsages("Fu3.java", "src/p1/p2/Fu3.java"); assertEquals(2, references.size()); } public void testValueResourceField() throws Throwable { + myFixture.copyFileToProject(BASE_PATH + "strings.xml", "res/values/strings.xml"); myFixture.copyFileToProject(BASE_PATH + "layout.xml", "res/layout/layout.xml"); - Collection references = findCodeUsages("Fu4.java"); + Collection references = findCodeUsages("Fu4.java", "src/p1/p2/Fu4.java"); assertEquals(2, references.size()); } public void testValueItemResourceField() throws Throwable { + myFixture.copyFileToProject(BASE_PATH + "strings.xml", "res/values/strings.xml"); myFixture.copyFileToProject(BASE_PATH + "layout.xml", "res/layout/layout.xml"); - Collection references = findCodeUsages("Fu6.java"); + Collection references = findCodeUsages("Fu6.java", "src/p1/p2/Fu6.java"); assertEquals(2, references.size()); } public void testIdResource() throws Throwable { + myFixture.copyFileToProject(BASE_PATH + "strings.xml", "res/values/strings.xml"); myFixture.copyFileToProject(BASE_PATH + "Class.java", "src/p1/p2/Class.java"); - Collection references = findCodeUsages("fu7_layout.xml"); + Collection references = findCodeUsages("fu7_layout.xml", "res/layout/fu7_layout.xml"); assertEquals(2, references.size()); } public void testIdResourceField() throws Throwable { + myFixture.copyFileToProject(BASE_PATH + "strings.xml", "res/values/strings.xml"); myFixture.copyFileToProject(BASE_PATH + "layout.xml", "res/layout/layout.xml"); - Collection references = findCodeUsages("Fu8.java"); + Collection references = findCodeUsages("Fu8.java", "src/p1/p2/Fu8.java"); assertEquals(2, references.size()); } public void testIdResourceDeclaration() throws Throwable { + myFixture.copyFileToProject(BASE_PATH + "strings.xml", "res/values/strings.xml"); myFixture.copyFileToProject(BASE_PATH + "Class.java", "src/p1/p2/Class.java"); - Collection references = findCodeUsages("fu9_layout.xml"); + Collection references = findCodeUsages("fu9_layout.xml", "res/layout/fu9_layout.xml"); assertEquals(2, references.size()); } public void testStringArray() throws Throwable { + myFixture.copyFileToProject(BASE_PATH + "strings.xml", "res/values/strings.xml"); myFixture.copyFileToProject(BASE_PATH + "Class.java", "src/p1/p2/Class.java"); - Collection references = findCodeUsages("stringArray.xml"); + Collection references = findCodeUsages("stringArray.xml", "res/layout/stringArray.xml"); assertEquals(2, references.size()); } - private static Collection findElementAtCaret(String fileName, JavaCodeInsightTestFixture fixture, String basePath) throws Throwable { - String newFilePath = "res/layout/" + fileName; - VirtualFile file = fixture.copyFileToProject(basePath + fileName, newFilePath); - return findUsages(file, fixture); + private static Collection findUsages(String fileName, final JavaCodeInsightTestFixture fixture, String newFilePath) + throws Throwable { + VirtualFile file = fixture.copyFileToProject(BASE_PATH + fileName, newFilePath); + fixture.configureFromExistingVirtualFile(file); + + final UsageTarget[] targets = UsageTargetUtil.findUsageTargets(new DataProvider() { + @Override + public Object getData(@NonNls String dataId) { + return ((EditorEx)fixture.getEditor()).getDataContext().getData(dataId); + } + }); + + assert targets != null && targets.length > 0 && targets[0] instanceof PsiElementUsageTarget; + return fixture.findUsages(((PsiElementUsageTarget)targets[0]).getElement()); } public static Collection findUsages(VirtualFile file, JavaCodeInsightTestFixture fixture) throws Exception { diff --git a/plugins/android/testSrc/org/jetbrains/android/AndroidRenameTest.java b/plugins/android/testSrc/org/jetbrains/android/AndroidRenameTest.java index 2221080aa23b..6e022c678f55 100644 --- a/plugins/android/testSrc/org/jetbrains/android/AndroidRenameTest.java +++ b/plugins/android/testSrc/org/jetbrains/android/AndroidRenameTest.java @@ -18,8 +18,10 @@ package org.jetbrains.android; import com.android.sdklib.SdkConstants; import com.intellij.codeInsight.TargetElementUtilBase; +import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.ex.EditorEx; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; @@ -28,8 +30,10 @@ import com.intellij.psi.search.GlobalSearchScope; import com.intellij.refactoring.PackageWrapper; import com.intellij.refactoring.move.moveClassesOrPackages.MoveClassesOrPackagesProcessor; import com.intellij.refactoring.move.moveClassesOrPackages.SingleSourceRootMoveDestination; -import com.intellij.refactoring.rename.RenameProcessor; -import com.intellij.refactoring.rename.RenamePsiElementProcessor; +import com.intellij.refactoring.rename.*; +import org.jetbrains.annotations.NonNls; + +import java.io.IOException; /** * Created by IntelliJ IDEA. @@ -132,6 +136,53 @@ public class AndroidRenameTest extends AndroidTestCase { myFixture.checkResultByFile("res/values/strings.xml", BASE_PATH + "strings_after.xml", true); } + public void testValueResource1() throws Throwable { + doTestStringRename("strings1.xml"); + } + + public void testValueResource2() throws Throwable { + doTestStringRename("strings2.xml"); + } + + public void testValueResource3() throws Throwable { + doTestStringRename("strings3.xml"); + } + + public void testValueResource4() throws Throwable { + doTestStringRename("strings4.xml"); + } + + private void doTestStringRename(String fileName) throws IOException { + createManifest(); + VirtualFile file = myFixture.copyFileToProject(BASE_PATH + fileName, "res/values/strings.xml"); + myFixture.configureFromExistingVirtualFile(file); + + myFixture.copyFileToProject(BASE_PATH + "layoutStrUsage.xml", "res/layout/layoutStrUsage.xml"); + myFixture.copyFileToProject(BASE_PATH + "R2.java", R_JAVA_PATH); + + findHandlerAndDoRename(); + + myFixture.checkResultByFile(BASE_PATH + "strings_after.xml"); + myFixture.checkResultByFile(R_JAVA_PATH, BASE_PATH + "R_value_after.java", true); + myFixture.checkResultByFile("res/layout/layoutStrUsage.xml", BASE_PATH + "layoutStrUsage_after.xml", true); + } + + private void findHandlerAndDoRename() throws IOException { + final DataContext editorContext = ((EditorEx)myFixture.getEditor()).getDataContext(); + final DataContext context = new DataContext() { + @Override + public Object getData(@NonNls String dataId) { + return PsiElementRenameHandler.DEFAULT_NAME.getName().equals(dataId) + ? "str1" + : editorContext.getData(dataId); + } + }; + final RenameHandler renameHandler = RenameHandlerRegistry.getInstance().getRenameHandler(context); + assertNotNull(renameHandler); + + renameHandler.invoke(myFixture.getProject(), myFixture.getEditor(), myFixture.getFile(), context); + } + public void testJavaReferenceToFileResource() throws Throwable { createManifest(); VirtualFile file = myFixture.copyFileToProject(BASE_PATH + "R3.java", R_JAVA_PATH); diff --git a/plugins/git4idea/src/META-INF/plugin.xml b/plugins/git4idea/src/META-INF/plugin.xml index 266e2f06b86d..732ef0e79d7f 100644 --- a/plugins/git4idea/src/META-INF/plugin.xml +++ b/plugins/git4idea/src/META-INF/plugin.xml @@ -37,7 +37,7 @@ - + diff --git a/plugins/git4idea/src/git4idea/GitBranch.java b/plugins/git4idea/src/git4idea/GitBranch.java index 1714fe74e304..e04e9cc1677b 100644 --- a/plugins/git4idea/src/git4idea/GitBranch.java +++ b/plugins/git4idea/src/git4idea/GitBranch.java @@ -17,6 +17,7 @@ package git4idea; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vfs.VirtualFile; @@ -91,11 +92,16 @@ public class GitBranch extends GitReference { */ @NotNull public String getShortName() { - String name = getName(); - if (myRemote) { - return name.substring(name.indexOf('/') + 1); - } - return name; + return splitNameOfRemoteBranch(getName()).getSecond(); + } + + /** + * Returns the remote and the "local" name of a remote branch. + * Expects branch in format "origin/master", i.e. remote/branch + */ + public static Pair splitNameOfRemoteBranch(String branchName) { + int firstSlash = branchName.indexOf('/'); + return Pair.create(branchName.substring(0, firstSlash), branchName.substring(firstSlash + 1)); } /** diff --git a/plugins/git4idea/src/git4idea/NotificationManager.java b/plugins/git4idea/src/git4idea/NotificationManager.java index 7977bca38c30..fa1290128cbf 100644 --- a/plugins/git4idea/src/git4idea/NotificationManager.java +++ b/plugins/git4idea/src/git4idea/NotificationManager.java @@ -21,6 +21,7 @@ import com.intellij.notification.NotificationListener; import com.intellij.notification.NotificationType; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.text.StringUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -37,6 +38,12 @@ public class NotificationManager { public void notify(@NotNull NotificationGroup notificationGroup, @NotNull String title, @NotNull String message, @NotNull NotificationType type, @Nullable NotificationListener listener) { + // title can be empty; description can't be neither null, nor empty + if (StringUtil.isEmptyOrSpaces(message)) { + message = title; + title = ""; + } + // if both title and description were empty, then it is a problem in the calling code => Notifications engine assertion will notify. createNotification(notificationGroup, title, message, type, listener).notify(myProject); } diff --git a/plugins/git4idea/src/git4idea/branch/GitBranchOperation.java b/plugins/git4idea/src/git4idea/branch/GitBranchOperation.java index d9676498e5e1..99a5a01bf2e7 100644 --- a/plugins/git4idea/src/git4idea/branch/GitBranchOperation.java +++ b/plugins/git4idea/src/git4idea/branch/GitBranchOperation.java @@ -34,6 +34,7 @@ import com.intellij.util.Function; import com.intellij.util.ui.UIUtil; import git4idea.*; import git4idea.commands.GitMessageWithFilesDetector; +import git4idea.config.GitVcsSettings; import git4idea.merge.GitConflictResolver; import git4idea.repo.GitRepository; import git4idea.util.UntrackedFilesNotifier; @@ -59,18 +60,22 @@ abstract class GitBranchOperation { @NotNull protected final Project myProject; @NotNull private final Collection myRepositories; + @NotNull private final String myCurrentBranchOrRev; @NotNull private final ProgressIndicator myIndicator; + private final GitVcsSettings mySettings; @NotNull private final Collection mySuccessfulRepositories; @NotNull private final Collection myRemainingRepositories; protected GitBranchOperation(@NotNull Project project, @NotNull Collection repositories, - @NotNull ProgressIndicator indicator) { + @NotNull String currentBranchOrRev, @NotNull ProgressIndicator indicator) { myProject = project; myRepositories = repositories; + myCurrentBranchOrRev = currentBranchOrRev; myIndicator = indicator; mySuccessfulRepositories = new ArrayList(); myRemainingRepositories = new ArrayList(myRepositories); + mySettings = GitVcsSettings.getInstance(myProject); } protected abstract void execute(); @@ -159,7 +164,7 @@ abstract class GitBranchOperation { NotificationManager.getInstance(myProject).notify(GitVcs.NOTIFICATION_GROUP_ID, "", message, NotificationType.INFORMATION); } - protected void notifySuccess() { + protected final void notifySuccess() { notifySuccess(getSuccessMessage()); } @@ -242,6 +247,20 @@ abstract class GitBranchOperation { return pluralize("repository", getSuccessfulRepositories().size()); } + /** + * Updates the recently visited branch in the settings. + * This is to be performed after successful checkout operation. + */ + protected void updateRecentBranch() { + if (getRepositories().size() == 1) { + GitRepository repository = myRepositories.iterator().next(); + mySettings.setRecentBranchOfRepository(repository.getRoot().getPath(), myCurrentBranchOrRev); + } + else { + mySettings.setRecentCommonBranch(myCurrentBranchOrRev); + } + } + private void showUnmergedFilesDialogWithRollback() { final AtomicBoolean ok = new AtomicBoolean(); UIUtil.invokeAndWaitIfNeeded(new Runnable() { diff --git a/plugins/git4idea/src/git4idea/branch/GitBranchOperationsProcessor.java b/plugins/git4idea/src/git4idea/branch/GitBranchOperationsProcessor.java index e066aa825424..c8eaed476653 100644 --- a/plugins/git4idea/src/git4idea/branch/GitBranchOperationsProcessor.java +++ b/plugins/git4idea/src/git4idea/branch/GitBranchOperationsProcessor.java @@ -15,18 +15,25 @@ */ package git4idea.branch; +import com.intellij.notification.NotificationType; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.VcsException; import com.intellij.util.ui.UIUtil; +import git4idea.GitBranch; import git4idea.GitExecutionException; import git4idea.GitVcs; +import git4idea.NotificationManager; import git4idea.commands.Git; +import git4idea.commands.GitCommandResult; +import git4idea.commands.GitCompoundResult; import git4idea.history.GitHistoryUtils; import git4idea.history.browser.GitCommit; import git4idea.repo.GitRepository; @@ -38,10 +45,8 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; +import java.util.concurrent.atomic.AtomicBoolean; /** * Executor of Git branching operations. @@ -81,7 +86,7 @@ public final class GitBranchOperationsProcessor { } @NotNull - private String getCurrentBranch() { + private String getCurrentBranchOrRev() { if (myRepositories.size() > 1) { GitMultiRootBranchConfig multiRootBranchConfig = new GitMultiRootBranchConfig(myRepositories); String currentBranch = multiRootBranchConfig.getCurrentBranch(); @@ -121,7 +126,7 @@ public final class GitBranchOperationsProcessor { } private void doCheckoutNewBranch(@NotNull final String name, @NotNull ProgressIndicator indicator) { - new GitCheckoutNewBranchOperation(myProject, myRepositories, name, getCurrentBranch(), indicator).execute(); + new GitCheckoutNewBranchOperation(myProject, myRepositories, name, getCurrentBranchOrRev(), indicator).execute(); } /** @@ -162,19 +167,153 @@ public final class GitBranchOperationsProcessor { } private void doCheckout(@NotNull ProgressIndicator indicator, @NotNull String reference, @Nullable String newBranch) { - new GitCheckoutOperation(myProject, myRepositories, reference, newBranch, getCurrentBranch(), indicator).execute(); + new GitCheckoutOperation(myProject, myRepositories, reference, newBranch, getCurrentBranchOrRev(), indicator).execute(); } public void deleteBranch(final String branchName) { new CommonBackgroundTask(myProject, "Deleting " + branchName, myCallInAwtAfterExecution) { @Override public void execute(@NotNull ProgressIndicator indicator) { - doDelete(branchName, indicator); + new GitDeleteBranchOperation(myProject, myRepositories, branchName, getCurrentBranchOrRev(), indicator).execute(); } }.runInBackground(); } - private void doDelete(final String branchName, ProgressIndicator indicator) { - new GitDeleteBranchOperation(myProject, myRepositories, branchName, getCurrentBranch(), indicator).execute(); + public void deleteRemoteBranch(@NotNull final String branchName) { + final Collection trackingBranches = findTrackingBranches(branchName); + String currentBranch = getCurrentBranchOrRev(); + boolean currentBranchTracksBranchToDelete = false; + if (trackingBranches.contains(currentBranch)) { + currentBranchTracksBranchToDelete = true; + trackingBranches.remove(currentBranch); + } + + final DeleteRemoteBranchDecision decision = confirmBranchDeletion(branchName, trackingBranches, currentBranchTracksBranchToDelete); + + if (decision.delete()) { + new CommonBackgroundTask(myProject, "Deleting " + branchName, myCallInAwtAfterExecution) { + @Override public void execute(@NotNull ProgressIndicator indicator) { + boolean deletedSuccessfully = doDeleteRemote(branchName); + if (deletedSuccessfully) { + final Collection successfullyDeletedLocalBranches = new ArrayList(1); + if (decision.deleteTracking()) { + for (final String branch : trackingBranches) { + indicator.setText("Deleting " + branch); + new GitDeleteBranchOperation(myProject, myRepositories, branch, getCurrentBranchOrRev(), indicator) { + @Override + protected void notifySuccess(@NotNull String message) { + // do nothing - will display a combo notification for all deleted branches below + successfullyDeletedLocalBranches.add(branch); + } + }.execute(); + } + } + notifySuccessfulDeletion(branchName, successfullyDeletedLocalBranches); + } + } + }.runInBackground(); + } + } + + @NotNull + private Collection findTrackingBranches(@NotNull String remoteBranch) { + return new GitMultiRootBranchConfig(myRepositories).getTrackingBranches(remoteBranch); + } + + private boolean doDeleteRemote(String branchName) { + GitCompoundResult result = new GitCompoundResult(myProject); + for (GitRepository repository : myRepositories) { + Pair pair = GitBranch.splitNameOfRemoteBranch(branchName); + GitCommandResult res = Git.push(repository, pair.getFirst(), ":" + pair.getSecond()); + result.append(repository, res); + repository.update(GitRepository.TrackedTopic.BRANCHES); + } + if (!result.totalSuccess()) { + NotificationManager.getInstance(myProject).notifyError("Failed to delete remote branch " + branchName, + result.getErrorOutputWithReposIndication()); + } + return result.totalSuccess(); + } + + private void notifySuccessfulDeletion(@NotNull String remoteBranchName, @NotNull Collection localBranches) { + String message = ""; + if (!localBranches.isEmpty()) { + message = "Also deleted local " + StringUtil.pluralize("branch", localBranches.size()) + ": " + StringUtil.join(localBranches, ", "); + } + NotificationManager.getInstance(myProject).notify(GitVcs.NOTIFICATION_GROUP_ID, "Deleted remote branch " + remoteBranchName, + message, NotificationType.INFORMATION); + } + + private DeleteRemoteBranchDecision confirmBranchDeletion(@NotNull String branchName, @NotNull Collection trackingBranches, + boolean currentBranchTracksBranchToDelete) { + String title = "Delete Remote Branch"; + String message = "Delete remote branch " + branchName; + + boolean delete; + final boolean deleteTracking; + if (trackingBranches.isEmpty()) { + delete = Messages.showYesNoDialog(myProject, message, title, "Delete", "Cancel", Messages.getQuestionIcon()) == Messages.OK; + deleteTracking = false; + } + else { + if (currentBranchTracksBranchToDelete) { + message += "\n\nCurrent branch " + getCurrentBranchOrRev() + " tracks " + branchName + " but won't be deleted."; + } + final String checkboxMessage; + if (trackingBranches.size() == 1) { + checkboxMessage = "Delete tracking local branch " + trackingBranches.iterator().next() + " as well"; + } + else { + checkboxMessage = "Delete tracking local branches " + StringUtil.join(trackingBranches, ", "); + } + + final AtomicBoolean deleteChoice = new AtomicBoolean(); + delete = Messages.OK == Messages.showYesNoDialog(message, title, "Delete", "Cancel", Messages.getQuestionIcon(), new DialogWrapper.DoNotAskOption() { + @Override + public boolean isToBeShown() { + return true; + } + + @Override + public void setToBeShown(boolean value, int exitCode) { + deleteChoice.set(!value); + } + + @Override + public boolean canBeHidden() { + return true; + } + + @Override + public boolean shouldSaveOptionsOnCancel() { + return false; + } + + @Override + public String getDoNotShowMessage() { + return checkboxMessage; + } + }); + deleteTracking = deleteChoice.get(); + } + return new DeleteRemoteBranchDecision(delete, deleteTracking); + } + + private static class DeleteRemoteBranchDecision { + private final boolean delete; + private final boolean deleteTracking; + + private DeleteRemoteBranchDecision(boolean delete, boolean deleteTracking) { + this.delete = delete; + this.deleteTracking = deleteTracking; + } + + public boolean delete() { + return delete; + } + + public boolean deleteTracking() { + return deleteTracking; + } } /** @@ -197,7 +336,7 @@ public final class GitBranchOperationsProcessor { LOG.error("The task to get compare info didn't finish. Repositories: \n" + myRepositories + "\nbranch name: " + branchName); return; } - displayCompareDialog(branchName, getCurrentBranch(), myCompareInfo); + displayCompareDialog(branchName, getCurrentBranchOrRev(), myCompareInfo); } }.runInBackground(); } @@ -247,7 +386,7 @@ public final class GitBranchOperationsProcessor { for (GitRepository repository : myRepositories) { revisions.put(repository, repository.getCurrentRevision()); } - new GitMergeOperation(myProject, myRepositories, branchName, getCurrentBranch(), revisions, indicator).execute(); + new GitMergeOperation(myProject, myRepositories, branchName, getCurrentBranchOrRev(), mySelectedRepository, revisions, indicator).execute(); } /** diff --git a/plugins/git4idea/src/git4idea/branch/GitCheckoutNewBranchOperation.java b/plugins/git4idea/src/git4idea/branch/GitCheckoutNewBranchOperation.java index 27f135bac9a3..553277e329f4 100644 --- a/plugins/git4idea/src/git4idea/branch/GitCheckoutNewBranchOperation.java +++ b/plugins/git4idea/src/git4idea/branch/GitCheckoutNewBranchOperation.java @@ -44,9 +44,8 @@ class GitCheckoutNewBranchOperation extends GitBranchOperation { @NotNull private final String myPreviousBranch; GitCheckoutNewBranchOperation(@NotNull Project project, @NotNull Collection repositories, - @NotNull String newBranchName, @NotNull String previousBranch, - @NotNull ProgressIndicator indicator) { - super(project, repositories, indicator); + @NotNull String newBranchName, @NotNull String previousBranch, @NotNull ProgressIndicator indicator) { + super(project, repositories, previousBranch, indicator); myNewBranchName = newBranchName; myProject = project; myPreviousBranch = previousBranch; @@ -77,6 +76,7 @@ class GitCheckoutNewBranchOperation extends GitBranchOperation { if (!fatalErrorHappened) { notifySuccess(); + updateRecentBranch(); } } diff --git a/plugins/git4idea/src/git4idea/branch/GitCheckoutOperation.java b/plugins/git4idea/src/git4idea/branch/GitCheckoutOperation.java index 6585ce74fd73..e3530b19e040 100644 --- a/plugins/git4idea/src/git4idea/branch/GitCheckoutOperation.java +++ b/plugins/git4idea/src/git4idea/branch/GitCheckoutOperation.java @@ -59,7 +59,7 @@ class GitCheckoutOperation extends GitBranchOperation { GitCheckoutOperation(@NotNull Project project, @NotNull Collection repositories, @NotNull String startPointReference, @Nullable String newBranch, @NotNull String previousBranch, @NotNull ProgressIndicator indicator) { - super(project, repositories, indicator); + super(project, repositories, previousBranch, indicator); myStartPointReference = startPointReference; myNewBranch = newBranch; myPreviousBranch = previousBranch; @@ -104,10 +104,11 @@ class GitCheckoutOperation extends GitBranchOperation { if (!fatalErrorHappened) { notifySuccess(); + updateRecentBranch(); } } - private boolean smartCheckoutOrNotify(@NotNull GitRepository repository, + private boolean smartCheckoutOrNotify(@NotNull GitRepository repository, @NotNull GitMessageWithFilesDetector localChangesOverwrittenByCheckout) { Pair, List> conflictingRepositoriesAndAffectedChanges = getConflictingRepositoriesAndAffectedChanges(repository, localChangesOverwrittenByCheckout, myPreviousBranch, myStartPointReference); diff --git a/plugins/git4idea/src/git4idea/branch/GitDeleteBranchOperation.java b/plugins/git4idea/src/git4idea/branch/GitDeleteBranchOperation.java index 0c4c89fa3f69..b21d46ffc41b 100644 --- a/plugins/git4idea/src/git4idea/branch/GitDeleteBranchOperation.java +++ b/plugins/git4idea/src/git4idea/branch/GitDeleteBranchOperation.java @@ -53,8 +53,8 @@ class GitDeleteBranchOperation extends GitBranchOperation { private final String myCurrentBranch; GitDeleteBranchOperation(@NotNull Project project, @NotNull Collection repositories, - @NotNull String branchName, @NotNull String currentBranch, @NotNull ProgressIndicator indicator) { - super(project, repositories, indicator); + @NotNull String branchName, @NotNull String currentBranch, @NotNull ProgressIndicator indicator) { + super(project, repositories, currentBranch, indicator); myBranchName = branchName; myCurrentBranch = currentBranch; } diff --git a/plugins/git4idea/src/git4idea/branch/GitMergeOperation.java b/plugins/git4idea/src/git4idea/branch/GitMergeOperation.java index fce48e4c0643..5009f1ca5400 100644 --- a/plugins/git4idea/src/git4idea/branch/GitMergeOperation.java +++ b/plugins/git4idea/src/git4idea/branch/GitMergeOperation.java @@ -15,6 +15,8 @@ */ package git4idea.branch; +import com.intellij.notification.Notification; +import com.intellij.notification.NotificationListener; import com.intellij.notification.NotificationType; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressIndicator; @@ -35,6 +37,7 @@ import git4idea.repo.GitRepository; import git4idea.util.GitPreservingProcess; import org.jetbrains.annotations.NotNull; +import javax.swing.event.HyperlinkEvent; import java.util.*; import java.util.concurrent.atomic.AtomicBoolean; @@ -52,6 +55,7 @@ class GitMergeOperation extends GitBranchOperation { @NotNull private final ChangeListManager myChangeListManager; @NotNull private final String myBranchToMerge; @NotNull private final String myCurrentBranch; + @NotNull private final GitRepository myCurrentRepository; @NotNull private final Map myCurrentRevisionsBeforeMerge; // true in value if unstash will be needed after resolving conflicts. @@ -59,13 +63,13 @@ class GitMergeOperation extends GitBranchOperation { private GitPreservingProcess myPreservingProcess; protected GitMergeOperation(@NotNull Project project, @NotNull Collection repositories, - @NotNull String branchToMerge, - @NotNull String currentBranch, + @NotNull String branchToMerge, @NotNull String currentBranch, @NotNull GitRepository currentRepository, @NotNull Map currentRevisionsBeforeMerge, @NotNull ProgressIndicator indicator) { - super(project, repositories, indicator); + super(project, repositories, currentBranch, indicator); myBranchToMerge = branchToMerge; myCurrentBranch = currentBranch; + myCurrentRepository = currentRepository; myCurrentRevisionsBeforeMerge = currentRevisionsBeforeMerge; myChangeListManager = ChangeListManager.getInstance(myProject); } @@ -126,13 +130,28 @@ class GitMergeOperation extends GitBranchOperation { notifySuccess(); } else { - notifySuccess("Already up-to-date."); + notifySuccess("Already up-to-date"); } } restoreLocalChanges(); } + @Override + protected void notifySuccess(@NotNull String message) { + String description = message + "
Delete " + myBranchToMerge + ""; + NotificationManager.getInstance(myProject).notify(GitVcs.NOTIFICATION_GROUP_ID, "", description, NotificationType.INFORMATION, + new NotificationListener() { + @Override + public void hyperlinkUpdate(@NotNull Notification notification, @NotNull HyperlinkEvent event) { + if (event.getEventType() == HyperlinkEvent.EventType.ACTIVATED && event.getDescription().equalsIgnoreCase("delete")) { + new GitBranchOperationsProcessor(myProject, new ArrayList(getRepositories()), myCurrentRepository). + deleteBranch(myBranchToMerge); + } + } + }); + } + private boolean resolveConflicts() { if (!myConflictedRepositories.isEmpty()) { GitMerger merger = new GitMerger(myProject); diff --git a/plugins/git4idea/src/git4idea/branch/GitSmartOperationDialog.java b/plugins/git4idea/src/git4idea/branch/GitSmartOperationDialog.java index 0d8a187664e4..f03b940f4bf8 100644 --- a/plugins/git4idea/src/git4idea/branch/GitSmartOperationDialog.java +++ b/plugins/git4idea/src/git4idea/branch/GitSmartOperationDialog.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,7 +17,6 @@ package git4idea.branch; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.changes.Change; import com.intellij.openapi.vcs.changes.ui.ChangesBrowser; import com.intellij.ui.IdeBorderFactory; @@ -31,6 +30,8 @@ import java.awt.event.ActionEvent; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; +import static com.intellij.openapi.util.text.StringUtil.capitalize; + /** * The dialog that is shown when the error * "Your local changes to the following files would be overwritten by merge/checkout" @@ -46,7 +47,7 @@ class GitSmartOperationDialog extends DialogWrapper { private final Project myProject; private final List myChanges; - @NotNull private final String myCapitalizedOperationTitle; + @NotNull private final String myOperationTitle; private final boolean myForceButton; /** @@ -71,10 +72,10 @@ class GitSmartOperationDialog extends DialogWrapper { super(project); myProject = project; myChanges = changes; - myCapitalizedOperationTitle = StringUtil.capitalize(operationTitle); + myOperationTitle = operationTitle; myForceButton = forceButton; - setOKButtonText("Smart " + myCapitalizedOperationTitle); - setCancelButtonText("Don't " + myCapitalizedOperationTitle); + setOKButtonText("Smart " + capitalize(myOperationTitle)); + setCancelButtonText("Don't " + capitalize(myOperationTitle)); getCancelAction().putValue(FOCUSED_ACTION, Boolean.TRUE); init(); } @@ -82,15 +83,15 @@ class GitSmartOperationDialog extends DialogWrapper { @Override protected Action[] createLeftSideActions() { if (myForceButton) { - return new Action[] {new ForceCheckoutAction(myCapitalizedOperationTitle) }; + return new Action[] {new ForceCheckoutAction(myOperationTitle) }; } return new Action[0]; } @Override protected JComponent createNorthPanel() { - JBLabel description = new JBLabel("Your local changes to the following files would be overwritten by checkout.
" + - "IDEA can stash the changes, checkout and unstash them after that."); + JBLabel description = new JBLabel("Your local changes to the following files would be overwritten by " + myOperationTitle + + ".
IDEA can stash the changes, " + myOperationTitle + " and unstash them after that."); description.setBorder(IdeBorderFactory.createEmptyBorder(0, 0, 10, 0)); return description; } @@ -112,7 +113,7 @@ class GitSmartOperationDialog extends DialogWrapper { private class ForceCheckoutAction extends AbstractAction { ForceCheckoutAction(@NotNull String operationTitle) { - super("Force " + operationTitle); + super("&Force " + capitalize(operationTitle)); } @Override diff --git a/plugins/git4idea/src/git4idea/commands/Git.java b/plugins/git4idea/src/git4idea/commands/Git.java index 27f94bf775b9..bbe265ba0977 100644 --- a/plugins/git4idea/src/git4idea/commands/Git.java +++ b/plugins/git4idea/src/git4idea/commands/Git.java @@ -256,19 +256,27 @@ public class Git { return run(h); } - public static GitCommandResult push(@NotNull GitRepository repository, @NotNull GitPushSpec pushSpec, @NotNull GitLineHandlerListener... listeners) { - final GitLineHandlerPasswordRequestAware h = new GitLineHandlerPasswordRequestAware(repository.getProject(), repository.getRoot(), GitCommand.PUSH); + @NotNull + public static GitCommandResult push(@NotNull GitRepository repository, @NotNull String remote, @NotNull String spec, + @NotNull GitLineHandlerListener... listeners) { + final GitLineHandlerPasswordRequestAware h = new GitLineHandlerPasswordRequestAware(repository.getProject(), repository.getRoot(), + GitCommand.PUSH); h.setSilent(false); - for (GitLineHandlerListener listener : listeners) { h.addLineListener(listener); } + h.addParameters(remote); + h.addParameters(spec); + return run(h, true); + } + + @NotNull + public static GitCommandResult push(@NotNull GitRepository repository, @NotNull GitPushSpec pushSpec, + @NotNull GitLineHandlerListener... listeners) { GitRemote remote = pushSpec.getRemote(); - h.addParameters(remote.getName()); GitBranch remoteBranch = pushSpec.getDest(); String destination = remoteBranch.getName().replaceFirst(remote.getName() + "/", ""); - h.addParameters(pushSpec.getSource().getName() + ":" + destination); - return run(h, true); + return push(repository, remote.getName(), pushSpec.getSource().getName() + ":" + destination); } private static GitCommandResult run(@NotNull GitLineHandler handler) { diff --git a/plugins/git4idea/src/git4idea/config/GitVcsSettings.java b/plugins/git4idea/src/git4idea/config/GitVcsSettings.java index b05c7370d1f8..61ccb83bc04a 100644 --- a/plugins/git4idea/src/git4idea/config/GitVcsSettings.java +++ b/plugins/git4idea/src/git4idea/config/GitVcsSettings.java @@ -26,7 +26,9 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** * Git VCS settings @@ -70,6 +72,8 @@ public class GitVcsSettings implements PersistentStateComponent RECENT_BRANCH_BY_REPOSITORY = new HashMap(); + public String RECENT_COMMON_BRANCH = null; } public GitVcsSettings(GitVcsApplicationSettings appSettings) { @@ -80,11 +84,7 @@ public class GitVcsSettings implements PersistentStateComponent getRecentBranchesByRepository() { + return myState.RECENT_BRANCH_BY_REPOSITORY; + } + + public void setRecentBranchOfRepository(@NotNull String repositoryPath, @NotNull String branch) { + myState.RECENT_BRANCH_BY_REPOSITORY.put(repositoryPath, branch); + } + + @Nullable + public String getRecentCommonBranch() { + return myState.RECENT_COMMON_BRANCH; + } + + public void setRecentCommonBranch(@NotNull String branch) { + myState.RECENT_COMMON_BRANCH = branch; + } + } diff --git a/plugins/git4idea/src/git4idea/stash/GitChangesSaver.java b/plugins/git4idea/src/git4idea/stash/GitChangesSaver.java index 589e847d342b..7b1bb953cf38 100644 --- a/plugins/git4idea/src/git4idea/stash/GitChangesSaver.java +++ b/plugins/git4idea/src/git4idea/stash/GitChangesSaver.java @@ -51,6 +51,11 @@ public abstract class GitChangesSaver { protected GitConflictResolver.Params myParams; + /** + * Refreshes files changed during save or load. + */ + public abstract void refresh(); + /** * Returns an instance of the proper GitChangesSaver depending on the chosen save changes policy. * @return {@link GitStashChangesSaver}, {@link GitShelveChangesSaver} or {@link GitDumbChangesSaver} diff --git a/plugins/git4idea/src/git4idea/stash/GitShelveChangesSaver.java b/plugins/git4idea/src/git4idea/stash/GitShelveChangesSaver.java index ca5aa577ce80..55d2829e6d87 100644 --- a/plugins/git4idea/src/git4idea/stash/GitShelveChangesSaver.java +++ b/plugins/git4idea/src/git4idea/stash/GitShelveChangesSaver.java @@ -89,11 +89,19 @@ public class GitShelveChangesSaver extends GitChangesSaver { return myShelvedChangeList != null; } - @Override public String getSaverName() { + @Override + public String getSaverName() { return "shelf"; } - @Override protected void showSavedChanges() { + @Override + protected void showSavedChanges() { myShelveViewManager.activateView(myShelvedChangeList); } + + @Override + public void refresh() { + // refreshed inside shelve manager + } + } diff --git a/plugins/git4idea/src/git4idea/stash/GitStashChangesSaver.java b/plugins/git4idea/src/git4idea/stash/GitStashChangesSaver.java index 9ce2fe859bde..c81bf8dbc64b 100644 --- a/plugins/git4idea/src/git4idea/stash/GitStashChangesSaver.java +++ b/plugins/git4idea/src/git4idea/stash/GitStashChangesSaver.java @@ -35,8 +35,8 @@ import git4idea.commands.*; import git4idea.config.GitVcsSettings; import git4idea.convert.GitFileSeparatorConverter; import git4idea.merge.GitConflictResolver; -import git4idea.util.GitUIUtil; import git4idea.ui.GitUnstashDialog; +import git4idea.util.GitUIUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -77,11 +77,21 @@ public class GitStashChangesSaver extends GitChangesSaver { } public void load() throws VcsException { + Collection conflictedRoots = new ArrayList(); for (VirtualFile root : myStashedRoots) { - loadRoot(root); + boolean conflict = loadRoot(root); + if (conflict) { + conflictedRoots.add(root); + } + } + + boolean conflictsResolved = new UnstashConflictResolver(myProject, myStashedRoots, myParams).merge(); + if (conflictsResolved) { + LOG.info("load: all conflicts resolved, dropping stash in " + myStashedRoots); + for (VirtualFile root : conflictedRoots) { + GitStashUtils.dropStash(myProject, root); + } } - // we'll refresh more but this way we needn't compute what files under roots etc - LocalFileSystem.getInstance().refreshIoFiles(myChangeManager.getAffectedPaths()); } @Override @@ -89,14 +99,22 @@ public class GitStashChangesSaver extends GitChangesSaver { return !myStashedRoots.isEmpty(); } - @Override public String getSaverName() { + @Override + public String getSaverName() { return "stash"; } - @Override protected void showSavedChanges() { + @Override + protected void showSavedChanges() { GitUnstashDialog.showUnstashDialog(myProject, new ArrayList(myStashedRoots), myStashedRoots.iterator().next(), new HashSet()); } + @Override + public void refresh() { + // we'll refresh more but this way we needn't compute what files under roots etc + LocalFileSystem.getInstance().refreshIoFiles(myChangeManager.getAffectedPaths()); + } + private void stash(Collection roots) throws VcsException { for (VirtualFile root : roots) { final String message = GitHandlerUtil.formatOperationName("Stashing changes from", root); @@ -122,7 +140,11 @@ public class GitStashChangesSaver extends GitChangesSaver { } } - private void loadRoot(final VirtualFile root) throws VcsException { + /** + * Returns true if the root was loaded with conflict. + * False is returned in all other cases: in the case of success and in case of some other error. + */ + private boolean loadRoot(final VirtualFile root) throws VcsException { LOG.info("loadRoot " + root); myProgressIndicator.setText(GitHandlerUtil.formatOperationName("Unstashing changes to", root)); final GitLineHandler handler = new GitLineHandler(myProject, root, GitCommand.STASH); @@ -159,26 +181,21 @@ public class GitStashChangesSaver extends GitChangesSaver { if (failure.get()) { if (conflict.get()) { - boolean conflictsResolved = new UnstashConflictResolver(myProject, root, myStashedRoots, myParams).merge(); - if (conflictsResolved) { - LOG.info("loadRoot " + root + " conflicts resolved, dropping stash"); - GitStashUtils.dropStash(myProject, root); - } + return true; } else { LOG.info("unstash failed " + handler.errors()); GitUIUtil.notifyImportantError(myProject, "Couldn't unstash", "
" + GitUIUtil.stringifyErrors(handler.errors())); } } + return false; } private static class UnstashConflictResolver extends GitConflictResolver { - private final VirtualFile myRoot; private final Set myStashedRoots; - public UnstashConflictResolver(@NotNull Project project, @NotNull VirtualFile root, @NotNull Set stashedRoots, @Nullable Params params) { - super(project, Collections.singleton(root), makeParamsOrUse(params)); - myRoot = root; + public UnstashConflictResolver(@NotNull Project project, @NotNull Set stashedRoots, @Nullable Params params) { + super(project, stashedRoots, makeParamsOrUse(params)); myStashedRoots = stashedRoots; } @@ -206,7 +223,7 @@ public class GitStashChangesSaver extends GitChangesSaver { if (event.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { if (event.getDescription().equals("saver")) { // we don't use #showSavedChanges to specify unmerged root first - GitUnstashDialog.showUnstashDialog(myProject, new ArrayList(myStashedRoots), myRoot, + GitUnstashDialog.showUnstashDialog(myProject, new ArrayList(myStashedRoots), myStashedRoots.iterator().next(), new HashSet()); } else if (event.getDescription().equals("resolve")) { mergeNoProceed(); diff --git a/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopup.java b/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopup.java index 715e459f40ac..395488cd219d 100644 --- a/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopup.java +++ b/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopup.java @@ -27,6 +27,7 @@ import com.intellij.openapi.options.ShowSettingsUtil; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.popup.ListPopup; import com.intellij.openapi.ui.popup.PopupStep; +import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.IconLoader; import com.intellij.ui.popup.PopupFactoryImpl; import com.intellij.ui.popup.WizardPopup; @@ -88,10 +89,33 @@ class GitBranchPopup { String title = createPopupTitle(currentRepository); + Condition preselectActionCondition = new Condition() { + @Override + public boolean value(AnAction action) { + if (action instanceof GitBranchPopupActions.LocalBranchActions) { + GitBranchPopupActions.LocalBranchActions branchAction = (GitBranchPopupActions.LocalBranchActions)action; + String branchName = branchAction.getBranchName(); + + String recentBranch; + List repositories = branchAction.getRepositories(); + if (repositories.size() == 1) { + recentBranch = myVcsSettings.getRecentBranchesByRepository().get(repositories.iterator().next().getRoot().getPath()); + } + else { + recentBranch = myVcsSettings.getRecentCommonBranch(); + } + + if (recentBranch != null && recentBranch.equals(branchName)) { + return true; + } + } + return false; + } + }; myPopup = new PopupFactoryImpl.ActionGroupPopup( title, createActions(), SimpleDataContext.getProjectContext(project), - false, false, false, true, null, -1, null, null) { + false, false, false, true, null, -1, preselectActionCondition, null) { @Override protected WizardPopup createPopup(WizardPopup parent, PopupStep step, Object parentValue) { WizardPopup popup = super.createPopup(parent, step, parentValue); diff --git a/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopupActions.java b/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopupActions.java index ba4d118967ea..692bd47d525d 100644 --- a/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopupActions.java +++ b/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopupActions.java @@ -180,6 +180,16 @@ class GitBranchPopupActions { } } + @NotNull + List getRepositories() { + return myRepositories; + } + + @NotNull + public String getBranchName() { + return myBranchName; + } + @NotNull @Override public AnAction[] getChildren(@Nullable AnActionEvent e) { @@ -241,9 +251,6 @@ class GitBranchPopupActions { } - /** - * Action to delete a branch. - */ private static class DeleteAction extends DumbAwareAction { private final Project myProject; private final List myRepositories; @@ -292,6 +299,7 @@ class GitBranchPopupActions { new CheckoutRemoteBranchAction(myProject, myRepositories, myBranchName, mySelectedRepository), new CompareAction(myProject, myRepositories, myBranchName, mySelectedRepository), new MergeAction(myProject, myRepositories, myBranchName, mySelectedRepository), + new RemoteDeleteAction(myProject, myRepositories, myBranchName, mySelectedRepository) }; } @@ -326,6 +334,28 @@ class GitBranchPopupActions { return myRemoteBranchName.substring(slashPosition+1); } } + + private static class RemoteDeleteAction extends DumbAwareAction { + private final Project myProject; + private final List myRepositories; + private final String myBranchName; + private final GitRepository mySelectedRepository; + + RemoteDeleteAction(@NotNull Project project, @NotNull List repositories, @NotNull String branchName, + @NotNull GitRepository selectedRepository) { + super("Delete"); + myProject = project; + myRepositories = repositories; + myBranchName = branchName; + mySelectedRepository = selectedRepository; + } + + @Override + public void actionPerformed(AnActionEvent e) { + new GitBranchOperationsProcessor(myProject, myRepositories, mySelectedRepository).deleteRemoteBranch(myBranchName); + } + } + } private static class CompareAction extends DumbAwareAction { diff --git a/plugins/git4idea/src/git4idea/ui/branch/GitMultiRootBranchConfig.java b/plugins/git4idea/src/git4idea/ui/branch/GitMultiRootBranchConfig.java index a4040993053e..9aedb95d9477 100644 --- a/plugins/git4idea/src/git4idea/ui/branch/GitMultiRootBranchConfig.java +++ b/plugins/git4idea/src/git4idea/ui/branch/GitMultiRootBranchConfig.java @@ -24,6 +24,7 @@ import git4idea.repo.GitRepository; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -110,6 +111,35 @@ public class GitMultiRootBranchConfig { return trackedRemote + "/" + trackedBranch; } + /** + * Returns local branches which track the given remote branch. Usually there is 0 or 1 such branches. + */ + @NotNull + public Collection getTrackingBranches(@NotNull String remoteBranch) { + Collection trackingBranches = null; + for (GitRepository repository : myRepositories) { + Collection tb = getTrackingBranches(repository, remoteBranch); + if (trackingBranches == null) { + trackingBranches = tb; + } + else { + trackingBranches.retainAll(tb); + } + } + return trackingBranches == null ? Collections.emptyList() : trackingBranches; + } + + @NotNull + public static Collection getTrackingBranches(@NotNull GitRepository repository, @NotNull String remoteBranch) { + Collection trackingBranches = new ArrayList(1); + for (GitBranchTrackInfo trackInfo : repository.getConfig().getBranchTrackInfos()) { + if (remoteBranch.equals(trackInfo.getRemote().getName() + "/" + trackInfo.getRemoteBranch())) { + trackingBranches.add(trackInfo.getBranch()); + } + } + return trackingBranches; + } + @Nullable private static Pair getTrackedBranchAndRemote(@NotNull GitRepository repository, @NotNull String branch) { for (GitBranchTrackInfo trackInfo : repository.getConfig().getBranchTrackInfos()) { diff --git a/plugins/git4idea/src/git4idea/update/GitUpdateProcess.java b/plugins/git4idea/src/git4idea/update/GitUpdateProcess.java index 6f4c81c8aeb6..9e0209a15d0a 100644 --- a/plugins/git4idea/src/git4idea/update/GitUpdateProcess.java +++ b/plugins/git4idea/src/git4idea/update/GitUpdateProcess.java @@ -215,6 +215,7 @@ public class GitUpdateProcess { final ContinuationFinalTasksInserter finalTasksInserter = new ContinuationFinalTasksInserter(context); finalTasksInserter.allNextAreFinal(); mySaver.restoreLocalChanges(context); + mySaver.refresh(); finalTasksInserter.removeFinalPropertyAdder(); } diff --git a/plugins/git4idea/tests/git4idea/branch/GitBranchOperationsTest.java b/plugins/git4idea/tests/git4idea/branch/GitBranchOperationsTest.java index 958213bbd41f..69dc52cb57c4 100644 --- a/plugins/git4idea/tests/git4idea/branch/GitBranchOperationsTest.java +++ b/plugins/git4idea/tests/git4idea/branch/GitBranchOperationsTest.java @@ -492,7 +492,7 @@ public class GitBranchOperationsTest extends AbstractVcsTestCase { public void merge_simple_without_problems() throws Exception { prepareBranchWithCommit("feature", myUltimate, myCommunity, myContrib); doMerge("feature"); - assertNotify(NotificationType.INFORMATION, "Merged feature to master"); + assertNotify(NotificationType.INFORMATION, "Merged feature to master
Delete feature"); assertFile(myUltimate, "unmerged_branch_file", "content"); assertFile(myCommunity, "unmerged_branch_file", "content"); @@ -514,7 +514,7 @@ public class GitBranchOperationsTest extends AbstractVcsTestCase { doMerge("master2"); - assertNotify(NotificationType.INFORMATION, "Already up-to-date."); + assertNotify(NotificationType.INFORMATION, "Already up-to-date
Delete master2"); } @Test @@ -525,7 +525,7 @@ public class GitBranchOperationsTest extends AbstractVcsTestCase { doMerge("master2"); - assertNotify(NotificationType.INFORMATION, "Merged master2 to master"); + assertNotify(NotificationType.INFORMATION, "Merged master2 to master
Delete master2"); assertFile(myCommunity, "unmerged_branch_file", "content"); assertNull(myUltimate.getRoot().findChild("unmerged_branch_file")); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/local/GroovyPostHighlightingPass.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/local/GroovyPostHighlightingPass.java index 6635d44b6086..b29f0906545b 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/local/GroovyPostHighlightingPass.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/local/GroovyPostHighlightingPass.java @@ -86,7 +86,7 @@ public class GroovyPostHighlightingPass extends TextEditorHighlightingPass { if (!fileIndex.isInContent(virtualFile)) { return; } - final UnusedDeclarationInspection deadCodeInspection = (UnusedDeclarationInspection)profile.getInspectionTool(UnusedDeclarationInspection.SHORT_NAME, myFile); + final UnusedDeclarationInspection deadCodeInspection = (UnusedDeclarationInspection)profile.getUnwrappedTool(UnusedDeclarationInspection.SHORT_NAME, myFile); final GlobalUsageHelper usageHelper = new GlobalUsageHelper() { public boolean isCurrentFileAlreadyChecked() { return false; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/parameter/java2groovy/OldReferencesResolver.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/parameter/java2groovy/OldReferencesResolver.java index e5b86d8c915a..eb0d89729d9a 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/parameter/java2groovy/OldReferencesResolver.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/parameter/java2groovy/OldReferencesResolver.java @@ -169,27 +169,30 @@ public class OldReferencesResolver { // "naked" field and methods (should become qualified) else if ((subj instanceof PsiField || subj instanceof PsiMethod) && oldRef.getQualifierExpression() == null) { - boolean isStatic = subj instanceof PsiField && ((PsiField)subj).hasModifierProperty(PsiModifier.STATIC) || - subj instanceof PsiMethod && ((PsiMethod)subj).hasModifierProperty(PsiModifier.STATIC); + PsiElement newResolved = newExpr instanceof GrReferenceExpression ? ((GrReferenceExpression)newExpr).resolve() : null; + if (myInstanceRef != null || !subj.getManager().areElementsEquivalent(newResolved, subj)) { + boolean isStatic = subj instanceof PsiField && ((PsiField)subj).hasModifierProperty(PsiModifier.STATIC) || + subj instanceof PsiMethod && ((PsiMethod)subj).hasModifierProperty(PsiModifier.STATIC); - String name = ((PsiNamedElement)subj).getName(); - boolean shouldBeAt = subj instanceof PsiField && - !PsiTreeUtil.isAncestor(((PsiMember)subj).getContainingClass(), newExpr, true) && - GroovyPropertyUtils.findGetterForField((PsiField)subj) != null; - final GrReferenceExpression fromText = factory.createReferenceExpressionFromText("qualifier." + (shouldBeAt ? "@" : "") + name); - if (isStatic) { - final GrReferenceExpression qualifier = factory.createReferenceElementForClass(((PsiMember)subj).getContainingClass()); - newExpr = newExpr.replace(fromText); - ((GrReferenceExpression)newExpr).setQualifier(qualifier); - newExpr = ((GrReferenceExpression)newExpr).getReferenceNameElement(); - } - else { - if (myInstanceRef != null) { - GrExpression instanceRef = getInstanceRef(factory); - fromText.setQualifier(instanceRef); + String name = ((PsiNamedElement)subj).getName(); + boolean shouldBeAt = subj instanceof PsiField && + !PsiTreeUtil.isAncestor(((PsiMember)subj).getContainingClass(), newExpr, true) && + GroovyPropertyUtils.findGetterForField((PsiField)subj) != null; + final GrReferenceExpression fromText = factory.createReferenceExpressionFromText("qualifier." + (shouldBeAt ? "@" : "") + name); + if (isStatic) { + final GrReferenceExpression qualifier = factory.createReferenceElementForClass(((PsiMember)subj).getContainingClass()); newExpr = newExpr.replace(fromText); + ((GrReferenceExpression)newExpr).setQualifier(qualifier); newExpr = ((GrReferenceExpression)newExpr).getReferenceNameElement(); } + else { + if (myInstanceRef != null) { + GrExpression instanceRef = getInstanceRef(factory); + fromText.setQualifier(instanceRef); + newExpr = newExpr.replace(fromText); + newExpr = ((GrReferenceExpression)newExpr).getReferenceNameElement(); + } + } } } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/extract/closure/ExtractClosureTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/extract/closure/ExtractClosureTest.groovy index e0fc82bc952e..e95a942334fb 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/extract/closure/ExtractClosureTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/extract/closure/ExtractClosureTest.groovy @@ -221,6 +221,38 @@ class ArrowToKneeException extends Exception{} def killMonsters(){2} def collectLoot(){3} def becomeTownGuard(){} +''') + } + + void testDontQualify() { + doTest(''' +class Some { + private static int smth = 1 + private static void doSmth() {} + + void m1() { + println smth + doSmth() + } + void m2() { + m1() + } +} +''', ''' +class Some { + private static int smth = 1 + private static void doSmth() {} + + void m1(Closure closure) { + closure() + } + void m2() { + m1 { + println smth + doSmth() + } + } +} ''') } } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenImporter.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenImporter.java index b46464c7fd95..843f8d2caa97 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenImporter.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenImporter.java @@ -20,7 +20,10 @@ import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleType; import com.intellij.openapi.module.StdModuleTypes; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Pair; +import com.intellij.util.containers.ContainerUtil; +import gnu.trove.THashSet; import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -31,10 +34,7 @@ import org.jetbrains.idea.maven.server.NativeMavenProjectHolder; import org.jetbrains.idea.maven.utils.MavenJDOMUtil; import org.jetbrains.idea.maven.utils.MavenProcessCanceledException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; +import java.util.*; public abstract class MavenImporter { public static ExtensionPointName EXTENSION_POINT_NAME = ExtensionPointName.create("org.jetbrains.idea.maven.importer"); @@ -48,12 +48,37 @@ public abstract class MavenImporter { public static List getSuitableImporters(MavenProject p) { final List result = new ArrayList(); + final Set moduleTypes = new THashSet(); for (MavenImporter importer : EXTENSION_POINT_NAME.getExtensions()) { if (importer.isApplicable(p)) { result.add(importer); + moduleTypes.add(importer.getModuleType()); } } - return result; + + if (moduleTypes.size() <= 1) { + return result; + } + + // This code is reached when several importers say that they are applicable but they want to have different module types. + // Now we select one module type and return only those importers that are ok with it. + // If possible - return at least one importer that explicitly supports packaging of the given maven project. + ModuleType moduleType = result.get(0).getModuleType(); + for (MavenImporter importer : result) { + final List supportedPackagings = new ArrayList(); + importer.getSupportedPackagings(supportedPackagings); + if (supportedPackagings.contains(p.getPackaging())) { + moduleType = importer.getModuleType(); + break; + } + } + + final ModuleType finalModuleType = moduleType; + return ContainerUtil.filter(result, new Condition() { + public boolean value(final MavenImporter importer) { + return importer.getModuleType() == finalModuleType; + } + }); } public boolean isApplicable(MavenProject mavenProject) { diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProject.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProject.java index 767438724e2a..015bd7f96012 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProject.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProject.java @@ -802,17 +802,9 @@ public class MavenProject { @NotNull public ModuleType getModuleType() { - ModuleType typeFromImporter = null; - for (MavenImporter each : getSuitableImporters()) { - final ModuleType moduleType = each.getModuleType(); - if (typeFromImporter != null && !typeFromImporter.equals(moduleType)) { - MavenLog.LOG.error("Incompatible plugins: " + each.getClass().getName() + " wants to create " + - moduleType.getName() + " for project " + getName() + " whereas some other importer requires " + - typeFromImporter.getName()); - } - typeFromImporter = moduleType; - } - return typeFromImporter != null ? typeFromImporter : StdModuleTypes.JAVA; + final List importers = getSuitableImporters(); + // getSuitableImporters() guarantees that all returned importers require the same module type + return importers.size() > 0 ? importers.get(0).getModuleType() : StdModuleTypes.JAVA; } @NotNull diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenEnvironmentRegistrar.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenEnvironmentRegistrar.java index 90daa24baf34..dac328542705 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenEnvironmentRegistrar.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenEnvironmentRegistrar.java @@ -16,15 +16,9 @@ package org.jetbrains.idea.maven.utils; -import com.intellij.ide.highlighter.XmlFileType; -import com.intellij.openapi.application.AccessToken; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.PathMacros; -import com.intellij.openapi.application.WriteAction; import com.intellij.openapi.components.ApplicationComponent; -import com.intellij.openapi.fileTypes.FileTypeManager; import org.jetbrains.annotations.NotNull; -import org.jetbrains.idea.maven.model.MavenConstants; import java.io.File; @@ -37,23 +31,9 @@ public class MavenEnvironmentRegistrar implements ApplicationComponent { } public void initComponent() { - registerFileTypes(); registerPathVariable(); } - private void registerFileTypes() { - // we should not change file types in unit test mode - if (ApplicationManager.getApplication().isUnitTestMode()) return; - - AccessToken accessToken = WriteAction.start(); - try { - FileTypeManager.getInstance().associateExtension(XmlFileType.INSTANCE, MavenConstants.POM_EXTENSION); - } - finally { - accessToken.finish(); - } - } - private void registerPathVariable() { File repository = MavenUtil.resolveLocalRepository(null, null, null); PathMacros macros = PathMacros.getInstance(); diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenFileTypeFactory.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenFileTypeFactory.java new file mode 100644 index 000000000000..05b51b4ea8ac --- /dev/null +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenFileTypeFactory.java @@ -0,0 +1,34 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.idea.maven.utils; + +import com.intellij.ide.highlighter.XmlFileType; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.fileTypes.FileTypeConsumer; +import com.intellij.openapi.fileTypes.FileTypeFactory; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.maven.model.MavenConstants; + +/** + * @author yole + */ +public class MavenFileTypeFactory extends FileTypeFactory { + @Override + public void createFileTypes(@NotNull FileTypeConsumer consumer) { + if (ApplicationManager.getApplication().isUnitTestMode()) return; + consumer.consume(XmlFileType.INSTANCE, MavenConstants.POM_EXTENSION); + } +} diff --git a/plugins/maven/src/main/resources/META-INF/plugin.xml b/plugins/maven/src/main/resources/META-INF/plugin.xml index 8d1e661b9d57..3857f71c8f87 100644 --- a/plugins/maven/src/main/resources/META-INF/plugin.xml +++ b/plugins/maven/src/main/resources/META-INF/plugin.xml @@ -15,6 +15,7 @@ org.intellij.groovy + diff --git a/plugins/svn4ideaOld/testSource/org/jetbrains/idea/svn/SvnChangesCorrectlyRefreshedTest.java b/plugins/svn4ideaOld/testSource/org/jetbrains/idea/svn/SvnChangesCorrectlyRefreshedTest.java index d49a3e711301..fbed7a8a9a7a 100644 --- a/plugins/svn4ideaOld/testSource/org/jetbrains/idea/svn/SvnChangesCorrectlyRefreshedTest.java +++ b/plugins/svn4ideaOld/testSource/org/jetbrains/idea/svn/SvnChangesCorrectlyRefreshedTest.java @@ -89,14 +89,14 @@ public class SvnChangesCorrectlyRefreshedTest extends SvnTestCase { //ChangeListManagerImpl.DEBUG = true; final SubTree subTree = new SubTree(myWorkingCopyDir); checkin(); - sleep(1000); + sleep(100); - editFileInCommand(myProject, subTree.myS1File, "new"); + editFileInCommand(myProject, subTree.myS1File, "new content"); final CharSequence text1 = LoadTextUtil.loadText(subTree.myS1File); - Assert.assertEquals("new", text1.toString()); + Assert.assertEquals("new content", text1.toString()); - sleep(1000); + sleep(100); LocalFileSystem.getInstance().refreshAndFindFileByIoFile(new File(subTree.myS1File.getPath())); VcsDirtyScopeManager.getInstance(myProject).markEverythingDirty(); clManager.ensureUpToDate(false); diff --git a/xml/dom-impl/src/com/intellij/util/xml/impl/DomImplUtil.java b/xml/dom-impl/src/com/intellij/util/xml/impl/DomImplUtil.java index d7d5bfb5d9dc..822aa9f0c701 100644 --- a/xml/dom-impl/src/com/intellij/util/xml/impl/DomImplUtil.java +++ b/xml/dom-impl/src/com/intellij/util/xml/impl/DomImplUtil.java @@ -21,6 +21,7 @@ import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiErrorElement; import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiInvalidElementAccessException; import com.intellij.psi.impl.source.tree.TreeElement; import com.intellij.psi.xml.*; import com.intellij.util.ReflectionCache; @@ -149,14 +150,19 @@ public class DomImplUtil { } return ContainerUtil.findAll(tag.getSubTags(), new Condition() { public boolean value(XmlTag childTag) { - if (!childTag.isValid()) { - LOG.error("tag.getSubTags() returned invalid, " + - "tag=" + tag + ", " + - "containing file: " + tag.getContainingFile() + - "subTag.parent=" + childTag.getNode().getTreeParent()); - return false; + try { + return isNameSuitable(name, childTag.getLocalName(), childTag.getName(), childTag.getNamespace(), file); + } + catch (PsiInvalidElementAccessException e) { + if (!childTag.isValid()) { + LOG.error("tag.getSubTags() returned invalid, " + + "tag=" + tag + ", " + + "containing file: " + tag.getContainingFile() + + "subTag.parent=" + childTag.getNode().getTreeParent()); + return false; + } + throw e; } - return isNameSuitable(name, childTag.getLocalName(), childTag.getName(), childTag.getNamespace(), file); } }); } diff --git a/xml/dom-impl/src/com/intellij/util/xml/impl/DomInvocationHandler.java b/xml/dom-impl/src/com/intellij/util/xml/impl/DomInvocationHandler.java index 44d69049c9a7..b7480910ed49 100644 --- a/xml/dom-impl/src/com/intellij/util/xml/impl/DomInvocationHandler.java +++ b/xml/dom-impl/src/com/intellij/util/xml/impl/DomInvocationHandler.java @@ -132,8 +132,6 @@ public abstract class DomInvocationHandler subTags = tagsGetter.fun(this); if (subTags.isEmpty()) return Collections.emptyList(); diff --git a/xml/dom-impl/src/com/intellij/util/xml/impl/DomRootInvocationHandler.java b/xml/dom-impl/src/com/intellij/util/xml/impl/DomRootInvocationHandler.java index f03e9b9b3782..d504a0a14401 100644 --- a/xml/dom-impl/src/com/intellij/util/xml/impl/DomRootInvocationHandler.java +++ b/xml/dom-impl/src/com/intellij/util/xml/impl/DomRootInvocationHandler.java @@ -89,7 +89,6 @@ public class DomRootInvocationHandler extends DomInvocationHandler result = new SmartList(); final DomInvocationHandler handler = DomManagerImpl.getDomInvocationHandler(element); if (handler != null) { - handler.assertValid(); for (int i = 0; i < myCount; i++) { result.add(handler.getFixedChild(Pair.create(this, i)).getProxy()); } diff --git a/xml/dom-impl/src/com/intellij/util/xml/impl/GetCompositeCollectionInvocation.java b/xml/dom-impl/src/com/intellij/util/xml/impl/GetCompositeCollectionInvocation.java index b4457905f8c6..37c6602922c4 100644 --- a/xml/dom-impl/src/com/intellij/util/xml/impl/GetCompositeCollectionInvocation.java +++ b/xml/dom-impl/src/com/intellij/util/xml/impl/GetCompositeCollectionInvocation.java @@ -33,7 +33,6 @@ class GetCompositeCollectionInvocation implements Invocation { } public Object invoke(final DomInvocationHandler handler, final Object[] args) throws Throwable { - handler.assertValid(); Map map = new THashMap(); for (final CollectionChildDescriptionImpl qname : myQnames) { for (DomElement element : handler.getCollectionChildren(qname, qname.getTagsGetter())) { diff --git a/xml/dom-impl/src/com/intellij/util/xml/impl/GetFixedChildInvocation.java b/xml/dom-impl/src/com/intellij/util/xml/impl/GetFixedChildInvocation.java index fb22399fdf08..689a01f5a22f 100644 --- a/xml/dom-impl/src/com/intellij/util/xml/impl/GetFixedChildInvocation.java +++ b/xml/dom-impl/src/com/intellij/util/xml/impl/GetFixedChildInvocation.java @@ -13,7 +13,6 @@ public class GetFixedChildInvocation implements Invocation { } public Object invoke(final DomInvocationHandler handler, final Object[] args) throws Throwable { - handler.assertValid(); return handler.getFixedChild(myPair).getProxy(); } } diff --git a/xml/dom-impl/src/com/intellij/util/xml/impl/GetInvocation.java b/xml/dom-impl/src/com/intellij/util/xml/impl/GetInvocation.java index 9f833cf1fd63..a59f30d4dd7d 100644 --- a/xml/dom-impl/src/com/intellij/util/xml/impl/GetInvocation.java +++ b/xml/dom-impl/src/com/intellij/util/xml/impl/GetInvocation.java @@ -30,7 +30,6 @@ public class GetInvocation implements Invocation { } public Object invoke(final DomInvocationHandler handler, final Object[] args) throws Throwable { - handler.assertValid(); if (myConverter == Converter.EMPTY_CONVERTER) { return getValueInner(handler, myConverter); } diff --git a/xml/impl/src/com/intellij/xml/refactoring/XmlTagRenameHandler.java b/xml/impl/src/com/intellij/xml/refactoring/XmlTagRenameHandler.java index 8d4ed2a0bda8..e2531e7956fc 100644 --- a/xml/impl/src/com/intellij/xml/refactoring/XmlTagRenameHandler.java +++ b/xml/impl/src/com/intellij/xml/refactoring/XmlTagRenameHandler.java @@ -23,6 +23,7 @@ package com.intellij.xml.refactoring; import com.intellij.featureStatistics.FeatureUsageTracker; +import com.intellij.ide.TitledHandler; import com.intellij.lang.Language; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.actionSystem.LangDataKeys; @@ -45,7 +46,7 @@ import com.intellij.xml.impl.schema.AnyXmlElementDescriptor; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class XmlTagRenameHandler implements RenameHandler { +public class XmlTagRenameHandler implements RenameHandler, TitledHandler { private static final Logger LOG = Logger.getInstance("#com.intellij.xml.refactoring.XmlTagRenameHandler"); @@ -74,6 +75,11 @@ public class XmlTagRenameHandler implements RenameHandler { return isAvailableOnDataContext(dataContext); } + @Override + public String getActionTitle() { + return "Rename XML tag"; + } + private static boolean isInplaceRenameAvailable(final Editor editor) { return editor.getSettings().isVariableInplaceRenameEnabled(); }