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/compileServer/incremental/generics/overrideAnnotatedAnonymousNotRecompile.log b/java/java-tests/testData/compileServer/incremental/generics/overrideAnnotatedAnonymousNotRecompile.log index 4be3d1f3669d..33badcc6d70d 100644 --- a/java/java-tests/testData/compileServer/incremental/generics/overrideAnnotatedAnonymousNotRecompile.log +++ b/java/java-tests/testData/compileServer/incremental/generics/overrideAnnotatedAnonymousNotRecompile.log @@ -4,3 +4,10 @@ End of files Compiling files: src/packageA/Base.java End of files +Cleaning output files: +out/production/OverrideAnnotatedAnonymousNotRecompile/packageA/Derived$1.class +out/production/OverrideAnnotatedAnonymousNotRecompile/packageA/Derived.class +End of files +Compiling files: +src/packageA/Derived.java +End of files diff --git a/java/java-tests/testData/compileServer/incremental/membersChange/deleteMethodImplementation4.log b/java/java-tests/testData/compileServer/incremental/membersChange/deleteMethodImplementation4.log index 30038ec68e16..db72b0f2704d 100644 --- a/java/java-tests/testData/compileServer/incremental/membersChange/deleteMethodImplementation4.log +++ b/java/java-tests/testData/compileServer/incremental/membersChange/deleteMethodImplementation4.log @@ -5,8 +5,10 @@ Compiling files: src/Base.java End of files Cleaning output files: +out/production/DeleteMethodImplementation4/BaseImpl.class out/production/DeleteMethodImplementation4/BaseImplImpl.class End of files Compiling files: +src/BaseImpl.java src/BaseImplImpl.java End of files diff --git a/java/java-tests/testData/compileServer/incremental/membersChange/deleteMethodImplementation5.log b/java/java-tests/testData/compileServer/incremental/membersChange/deleteMethodImplementation5.log index c8a95e08349b..a36940f74f64 100644 --- a/java/java-tests/testData/compileServer/incremental/membersChange/deleteMethodImplementation5.log +++ b/java/java-tests/testData/compileServer/incremental/membersChange/deleteMethodImplementation5.log @@ -4,3 +4,9 @@ End of files Compiling files: src/Base.java End of files +Cleaning output files: +out/production/DeleteMethodImplementation5/BaseImpl.class +End of files +Compiling files: +src/BaseImpl.java +End of files diff --git a/java/java-tests/testData/compileServer/incremental/membersChange/deleteMethodImplementation6.log b/java/java-tests/testData/compileServer/incremental/membersChange/deleteMethodImplementation6.log index 0548319f9020..e4bd38375b69 100644 --- a/java/java-tests/testData/compileServer/incremental/membersChange/deleteMethodImplementation6.log +++ b/java/java-tests/testData/compileServer/incremental/membersChange/deleteMethodImplementation6.log @@ -4,3 +4,9 @@ End of files Compiling files: src/BaseImpl.java End of files +Cleaning output files: +out/production/DeleteMethodImplementation6/BaseImplImpl.class +End of files +Compiling files: +src/BaseImplImpl.java +End of files 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/jps/jps-builders/testSrc/org/jetbrains/ether/GenericTest.java b/jps/jps-builders/testSrc/org/jetbrains/ether/GenericTest.java index facc69d594e6..5fded763c906 100644 --- a/jps/jps-builders/testSrc/org/jetbrains/ether/GenericTest.java +++ b/jps/jps-builders/testSrc/org/jetbrains/ether/GenericTest.java @@ -72,7 +72,7 @@ public class GenericTest extends IncrementalTestCase { public void testChangeToCovariantMethodInBase3() throws Exception { doTest(); } - + */ public void testChangeVarargSignature() throws Exception { doTest(); } @@ -80,7 +80,6 @@ public class GenericTest extends IncrementalTestCase { public void testChangeVarargSignature1() throws Exception { doTest(); } - */ public void testCovariance() throws Exception { doTest(); @@ -114,7 +113,7 @@ public class GenericTest extends IncrementalTestCase { doTest(); } - /* Not working yet + /* Not working yet */ public void testOverrideAnnotatedAnonymousNotRecompile() throws Exception { doTest(); } @@ -122,7 +121,6 @@ public class GenericTest extends IncrementalTestCase { public void testOverrideAnnotatedInner() throws Exception { doTest(); } - */ public void testParamTypes() throws Exception { doTest(); diff --git a/jps/jps-builders/testSrc/org/jetbrains/ether/IncrementalTestCase.java b/jps/jps-builders/testSrc/org/jetbrains/ether/IncrementalTestCase.java index 48ed13b9920e..6160a0126ced 100644 --- a/jps/jps-builders/testSrc/org/jetbrains/ether/IncrementalTestCase.java +++ b/jps/jps-builders/testSrc/org/jetbrains/ether/IncrementalTestCase.java @@ -177,7 +177,7 @@ public abstract class IncrementalTestCase extends TestCase { finally { try { closeAppender(); - delete(new File(workDir)); + //delete(new File(workDir)); } finally { Logger.setFactory(oldFactory); diff --git a/jps/jps-builders/testSrc/org/jetbrains/ether/MemberChangeTest.java b/jps/jps-builders/testSrc/org/jetbrains/ether/MemberChangeTest.java index 7fbcc9becf45..cfe091f05825 100644 --- a/jps/jps-builders/testSrc/org/jetbrains/ether/MemberChangeTest.java +++ b/jps/jps-builders/testSrc/org/jetbrains/ether/MemberChangeTest.java @@ -116,11 +116,9 @@ public class MemberChangeTest extends IncrementalTestCase { doTest(); } - /* Not working yet public void testDeleteMethodImplementation4() throws Exception { doTest(); } - */ public void testDeleteMethodImplementation5() throws Exception { doTest(); diff --git a/jps/model/src/org/jetbrains/ether/dependencyView/Mappings.java b/jps/model/src/org/jetbrains/ether/dependencyView/Mappings.java index d5d3bd1957c0..cc586037d2b9 100644 --- a/jps/model/src/org/jetbrains/ether/dependencyView/Mappings.java +++ b/jps/model/src/org/jetbrains/ether/dependencyView/Mappings.java @@ -1103,47 +1103,55 @@ public class Mappings { } if ((m.access & Opcodes.ACC_ABSTRACT) == 0) { + final Collection> overriding = u.findOverridingMethods(m, it, false); + + for (final Pair p : overriding) { + final DependencyContext.S fName = myClassToSourceFile.get(p.second.name); + affectedFiles.add(new File(myContext.getValue(fName))); + } + for (DependencyContext.S p : propagated) { - final ClassRepr s = u.reprByName(p); + if (!p.equals(it.name)) { + final ClassRepr s = u.reprByName(p); - if (s != null) { - final Collection> overridenInS = u.findOverridenMethods(m, s); + if (s != null) { + final Collection> overridenInS = u.findOverridenMethods(m, s); - overridenInS.addAll(overridenMethods); + overridenInS.addAll(overridenMethods); - boolean allAbstract = true; - boolean visited = false; + boolean allAbstract = true; + boolean visited = false; - for (Pair pp : overridenInS) { - final ClassRepr cc = pp.second; + for (Pair pp : overridenInS) { + final ClassRepr cc = pp.second; + + if (cc == myMockClass) { + visited = true; + continue; + } + + if (cc.name.equals(it.name)) { + continue; + } - if (cc == myMockClass) { visited = true; - continue; + allAbstract = ((pp.first.access & Opcodes.ACC_ABSTRACT) > 0) || ((cc.access & Opcodes.ACC_INTERFACE) > 0); + + if (!allAbstract) { + break; + } } - if (cc.name.equals(it.name)) { - continue; - } + if (allAbstract && visited) { + final DependencyContext.S source = myClassToSourceFile.get(p); - visited = true; - allAbstract = ((pp.first.access & Opcodes.ACC_ABSTRACT) > 0) || ((cc.access & Opcodes.ACC_INTERFACE) > 0); - - if (!allAbstract) { - break; - } - } - - if (allAbstract && visited) { - final DependencyContext.S source = myClassToSourceFile.get(p); - - if (source != null) { - final String f = myContext.getValue(source); - debug( - "Removed method is not abstract & is overrides some abstract method which is not then over-overriden in subclass ", - p); - debug("Affecting subclass source file ", f); - affectedFiles.add(new File(f)); + if (source != null) { + final String f = myContext.getValue(source); + debug("Removed method is not abstract & overrides some abstract method which is not then over-overriden in subclass ", + p); + debug("Affecting subclass source file ", f); + affectedFiles.add(new File(f)); + } } } } @@ -1597,19 +1605,19 @@ public class Mappings { for (DependencyContext.S f : delta.getChangedFiles()) { mySourceFileToClasses.remove(f); final Collection classes = delta.mySourceFileToClasses.get(f); - if (classes != null){ + if (classes != null) { mySourceFileToClasses.put(f, classes); } mySourceFileToUsages.remove(f); final Collection clusters = delta.mySourceFileToUsages.get(f); - if (clusters != null){ + if (clusters != null) { mySourceFileToUsages.put(f, clusters); } mySourceFileToAnnotationUsages.remove(f); final Collection usages = delta.mySourceFileToAnnotationUsages.get(f); - if (usages != null){ + if (usages != null) { mySourceFileToAnnotationUsages.put(f, usages); } } @@ -1637,7 +1645,7 @@ public class Mappings { depClasses.retainAll(changedClasses); - if (! classChanged && depClasses.isEmpty()) { + if (!classChanged && depClasses.isEmpty()) { continue; } } 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/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/notification/impl/NotificationsManagerImpl.java b/platform/platform-impl/src/com/intellij/notification/impl/NotificationsManagerImpl.java index f4475fd7937d..7af1d81950b4 100644 --- a/platform/platform-impl/src/com/intellij/notification/impl/NotificationsManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/notification/impl/NotificationsManagerImpl.java @@ -154,7 +154,7 @@ public class NotificationsManagerImpl extends NotificationsManager implements No case BALLOON: default: Balloon balloon = notifyByBalloon(notification, type, project); - if (!settings.isShouldLog()) { + if (!settings.isShouldLog() || type == NotificationDisplayType.STICKY_BALLOON) { if (balloon == null) { notification.expire(); } else { 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 c7ac33742fe9..3cba80b1fe26 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 (!FocusManagerImpl.getInstance().isUnforcedRequestAllowed() && !forced) return; if (LOG.isDebugEnabled()) { LOG.debug("enter: activateToolWindowImpl(" + id + ")"); @@ -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-resources-en/src/messages/IdeBundle.properties b/platform/platform-resources-en/src/messages/IdeBundle.properties index f985fba72fd6..77fc75407f13 100644 --- a/platform/platform-resources-en/src/messages/IdeBundle.properties +++ b/platform/platform-resources-en/src/messages/IdeBundle.properties @@ -246,7 +246,7 @@ message.nothing.to.show.in.structure.view=Nothing to show in the Structure View error.license.collision=This license is being used elsewhere on the network by {0}.\nOnly one active computer at a time can use the license.\nWould you like to re-activate this computer?\nClick Yes to re-activate, or No to shutdown {1}. title.license.collision.detected=License Collision Detected message.licensed.to=Licensed to {0} -title.enter.license.data=Enter License Data +title.enter.license.data=Enter {0} License message.purchase.or.upgrade=For information on how to upgrade your evaluation software please go to {0} message.expiration.date=Expiration date: {0} message.educational.license=1-Year Educational License. {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/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsDirtyScopeManagerImpl.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsDirtyScopeManagerImpl.java index 3fa1acb67898..decb13a4393a 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsDirtyScopeManagerImpl.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsDirtyScopeManagerImpl.java @@ -17,6 +17,7 @@ package com.intellij.openapi.vcs.changes; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.ProjectComponent; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.project.DumbAwareRunnable; import com.intellij.openapi.project.Project; @@ -32,6 +33,7 @@ import com.intellij.util.Consumer; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import sun.reflect.Reflection; import java.util.ArrayList; import java.util.Collection; @@ -40,6 +42,8 @@ import java.util.Collection; * @author max */ public class VcsDirtyScopeManagerImpl extends VcsDirtyScopeManager implements ProjectComponent { + private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vcs.changes.VcsDirtyScopeManagerImpl"); + private final Project myProject; private final ChangeListManager myChangeListManager; private final ProjectLevelVcsManager myVcsManager; @@ -100,6 +104,10 @@ public class VcsDirtyScopeManagerImpl extends VcsDirtyScopeManager implements Pr public void markEverythingDirty() { if ((! myProject.isOpen()) || myProject.isDisposed() || myVcsManager.getAllActiveVcss().length == 0) return; + if (LOG.isDebugEnabled()) { + LOG.debug("everything dirty: " + Reflection.getCallerClass(1)); + } + final LifeDrop lifeDrop = myLife.doIfAlive(new Runnable() { public void run() { myDirtBuilder.everythingDirty(); @@ -160,6 +168,10 @@ public class VcsDirtyScopeManagerImpl extends VcsDirtyScopeManager implements Pr || dirsConverted != null && ! dirsConverted.isEmpty(); if (! haveStuff) return; + if (LOG.isDebugEnabled()) { + LOG.debug("paths dirty: " + filesConverted + "; " + dirsConverted + "; " + Reflection.getCallerClass(2)); + } + takeDirt(new Consumer() { public void consume(final DirtBuilder dirt) { if (filesConverted != null) { @@ -218,6 +230,10 @@ public class VcsDirtyScopeManagerImpl extends VcsDirtyScopeManager implements Pr final boolean haveStuff = filesConverted != null && ! filesConverted.isEmpty() || dirsConverted != null && ! dirsConverted.isEmpty(); if (! haveStuff) return; + if (LOG.isDebugEnabled()) { + LOG.debug("files dirty: " + filesConverted + "; " + dirsConverted + "; " + Reflection.getCallerClass(2)); + } + takeDirt(new Consumer() { public void consume(final DirtBuilder dirt) { if (filesConverted != null) { @@ -240,6 +256,9 @@ public class VcsDirtyScopeManagerImpl extends VcsDirtyScopeManager implements Pr try { final AbstractVcs vcs = myGuess.getVcsForDirty(file); if (vcs == null) return; + if (LOG.isDebugEnabled()) { + LOG.debug("file dirty: " + file + "; " + Reflection.getCallerClass(2)); + } final VcsRoot root = new VcsRoot(vcs, file); takeDirt(new Consumer() { public void consume(DirtBuilder dirtBuilder) { @@ -254,6 +273,9 @@ public class VcsDirtyScopeManagerImpl extends VcsDirtyScopeManager implements Pr try { final AbstractVcs vcs = myGuess.getVcsForDirty(file); if (vcs == null) return; + if (LOG.isDebugEnabled()) { + LOG.debug("file dirty: " + file + "; " + Reflection.getCallerClass(1)); + } final FilePathUnderVcs root = new FilePathUnderVcs(file, vcs); takeDirt(new Consumer() { public void consume(DirtBuilder dirtBuilder) { @@ -272,6 +294,9 @@ public class VcsDirtyScopeManagerImpl extends VcsDirtyScopeManager implements Pr try { final AbstractVcs vcs = myGuess.getVcsForDirty(dir); if (vcs == null) return; + if (LOG.isDebugEnabled()) { + LOG.debug("dir dirty recursively: " + dir + "; " + Reflection.getCallerClass(2)); + } final VcsRoot root = new VcsRoot(vcs, dir); takeDirt(new Consumer() { public void consume(DirtBuilder dirtBuilder) { @@ -286,6 +311,9 @@ public class VcsDirtyScopeManagerImpl extends VcsDirtyScopeManager implements Pr try { final AbstractVcs vcs = myGuess.getVcsForDirty(path); if (vcs == null) return; + if (LOG.isDebugEnabled()) { + LOG.debug("dir dirty recursively: " + path + "; " + Reflection.getCallerClass(2)); + } final FilePathUnderVcs root = new FilePathUnderVcs(path, vcs); takeDirt(new Consumer() { public void consume(DirtBuilder dirtBuilder) { diff --git a/plugins/android-designer/src/com/intellij/android/designer/AndroidDesignerEditor.java b/plugins/android-designer/src/com/intellij/android/designer/AndroidDesignerEditor.java index c9010998e262..10495dcd338d 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/AndroidDesignerEditor.java +++ b/plugins/android-designer/src/com/intellij/android/designer/AndroidDesignerEditor.java @@ -15,8 +15,12 @@ */ package com.intellij.android.designer; +import com.intellij.android.designer.designSurface.AndroidDesignerEditorPanel; +import com.intellij.designer.componentTree.TreeComponentDecorator; +import com.intellij.designer.designSurface.DesignerEditorPanel; import com.intellij.openapi.fileEditor.FileEditorState; import com.intellij.openapi.fileEditor.FileEditorStateLevel; +import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.designer.DesignerEditor; @@ -30,6 +34,11 @@ public final class AndroidDesignerEditor extends DesignerEditor { super(project, file); } + @Override + protected DesignerEditorPanel createDesignerPanel(Module module, VirtualFile file) { + return new AndroidDesignerEditorPanel(module, file); + } + @NotNull @Override public String getName() { diff --git a/plugins/android-designer/src/com/intellij/android/designer/componentTree/AndroidTreeDecorator.java b/plugins/android-designer/src/com/intellij/android/designer/componentTree/AndroidTreeDecorator.java new file mode 100644 index 000000000000..adfb60d15977 --- /dev/null +++ b/plugins/android-designer/src/com/intellij/android/designer/componentTree/AndroidTreeDecorator.java @@ -0,0 +1,32 @@ +/* + * 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.android.designer.componentTree; + +import com.intellij.android.designer.model.RadViewComponent; +import com.intellij.designer.componentTree.TreeComponentDecorator; +import com.intellij.designer.model.RadComponent; +import com.intellij.ui.ColoredTreeCellRenderer; + +/** + * @author Alexander Lobas + */ +public final class AndroidTreeDecorator extends TreeComponentDecorator { + @Override + public void decorate(RadComponent component, ColoredTreeCellRenderer renderer) { + RadViewComponent view = (RadViewComponent)component; + renderer.append(view.getTitle()); + } +} \ No newline at end of file diff --git a/plugins/android-designer/src/com/intellij/android/designer/designSurface/AndroidDesignerEditorPanel.java b/plugins/android-designer/src/com/intellij/android/designer/designSurface/AndroidDesignerEditorPanel.java new file mode 100644 index 000000000000..07e1434d8dd0 --- /dev/null +++ b/plugins/android-designer/src/com/intellij/android/designer/designSurface/AndroidDesignerEditorPanel.java @@ -0,0 +1,79 @@ +/* + * 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.android.designer.designSurface; + +import com.intellij.android.designer.componentTree.AndroidTreeDecorator; +import com.intellij.android.designer.model.RadViewComponent; +import com.intellij.designer.componentTree.TreeComponentDecorator; +import com.intellij.designer.designSurface.DesignerEditorPanel; +import com.intellij.designer.model.RadComponent; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import java.io.InputStream; + +/** + * @author Alexander Lobas + */ +public final class AndroidDesignerEditorPanel extends DesignerEditorPanel { + private final TreeComponentDecorator myTreeDecorator = new AndroidTreeDecorator(); + + public AndroidDesignerEditorPanel(@NotNull Module module, @NotNull VirtualFile file) { + super(module, file); + + // (temp code) TODO: use platform DOM + + try { + InputStream stream = file.getInputStream(); + SAXParser parser = SAXParserFactory.newInstance().newSAXParser(); + parser.parse(stream, new DefaultHandler() { + RadViewComponent myComponent; + + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { + myComponent = new RadViewComponent(myComponent, qName); + if (myRootComponent == null) { + myRootComponent = myComponent; + } + } + + @Override + public void endElement(String uri, String localName, String qName) throws SAXException { + if (myComponent != null) { + myComponent = (RadViewComponent)myComponent.getParent(); + } + } + }); + stream.close(); + } + catch (Throwable e) { + e.printStackTrace(); // TODO + } + } + + @Override + public TreeComponentDecorator getTreeDecorator() { + return myTreeDecorator; + } +} \ No newline at end of file diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/RadViewComponent.java b/plugins/android-designer/src/com/intellij/android/designer/model/RadViewComponent.java new file mode 100644 index 000000000000..e0226f6c0320 --- /dev/null +++ b/plugins/android-designer/src/com/intellij/android/designer/model/RadViewComponent.java @@ -0,0 +1,48 @@ +/* + * 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.android.designer.model; + +import com.intellij.designer.model.RadComponent; + +import java.util.ArrayList; +import java.util.List; + +/** + * TODO: now dummy implementation for tests + * + * @author Alexander Lobas + */ +public class RadViewComponent extends RadComponent { + private final String myTitle; + private final List myChildren = new ArrayList(); + + public RadViewComponent(RadViewComponent parent, String title) { + myTitle = title; + setParent(parent); + if (parent != null) { + parent.getChildren().add(this); + } + } + + @Override + public List getChildren() { + return myChildren; + } + + public String getTitle() { + return myTitle; + } +} \ No newline at end of file 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/GitBranchOperationsProcessor.java b/plugins/git4idea/src/git4idea/branch/GitBranchOperationsProcessor.java index 887983904b2c..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. @@ -168,13 +173,147 @@ public final class GitBranchOperationsProcessor { 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, getCurrentBranchOrRev(), 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; + } } /** 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/ui/branch/GitBranchPopupActions.java b/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopupActions.java index fa6e23495187..692bd47d525d 100644 --- a/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopupActions.java +++ b/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopupActions.java @@ -251,9 +251,6 @@ class GitBranchPopupActions { } - /** - * Action to delete a branch. - */ private static class DeleteAction extends DumbAwareAction { private final Project myProject; private final List myRepositories; @@ -302,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) }; } @@ -336,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/groovy/src/org/jetbrains/plugins/groovy/codeInspection/local/GroovyPostHighlightingPass.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/local/GroovyPostHighlightingPass.java index c61ef6fb13b9..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 @@ -25,7 +25,6 @@ import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.codeInspection.InspectionProfile; import com.intellij.codeInspection.ProblemHighlightType; import com.intellij.codeInspection.deadCode.UnusedDeclarationInspection; -import com.intellij.codeInspection.ex.InspectionToolWrapper; import com.intellij.lang.annotation.Annotation; import com.intellij.lang.annotation.AnnotationHolder; import com.intellij.lang.annotation.AnnotationSession; @@ -87,8 +86,7 @@ public class GroovyPostHighlightingPass extends TextEditorHighlightingPass { if (!fileIndex.isInContent(virtualFile)) { return; } - final InspectionToolWrapper wrapper = (InspectionToolWrapper)profile.getInspectionTool(UnusedDeclarationInspection.SHORT_NAME, myFile); - final UnusedDeclarationInspection deadCodeInspection = wrapper != null ? (UnusedDeclarationInspection)wrapper.getTool() : null; + final UnusedDeclarationInspection deadCodeInspection = (UnusedDeclarationInspection)profile.getUnwrappedTool(UnusedDeclarationInspection.SHORT_NAME, myFile); final GlobalUsageHelper usageHelper = new GlobalUsageHelper() { public boolean isCurrentFileAlreadyChecked() { return false; 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/ui-designer/ui-designer-new/src/com/intellij/designer/DesignerEditor.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/DesignerEditor.java index a6142f90d025..c245d1ae760f 100644 --- a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/DesignerEditor.java +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/DesignerEditor.java @@ -45,9 +45,11 @@ public abstract class DesignerEditor extends UserDataHolderBase implements FileE if (module == null) { throw new IllegalArgumentException("No module for file " + file + " in project " + project); } - myDesignerPanel = new DesignerEditorPanel(module, file); + myDesignerPanel = createDesignerPanel(module, file); } + protected abstract DesignerEditorPanel createDesignerPanel(Module module, VirtualFile file); + public final DesignerEditorPanel getDesignerPanel() { return myDesignerPanel; } diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/DesignerToolWindowManager.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/DesignerToolWindowManager.java index d3f218f925f0..2c709447b264 100644 --- a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/DesignerToolWindowManager.java +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/DesignerToolWindowManager.java @@ -16,8 +16,10 @@ package com.intellij.designer; import com.intellij.designer.componentTree.ComponentTree; +import com.intellij.designer.componentTree.ComponentTreeBuilder; import com.intellij.designer.designSurface.DesignerEditorPanel; import com.intellij.designer.propertyTable.PropertyTablePanel; +import com.intellij.ide.util.treeView.AbstractTreeBuilder; import com.intellij.openapi.components.ProjectComponent; import com.intellij.openapi.fileEditor.FileEditor; import com.intellij.openapi.fileEditor.FileEditorManager; @@ -26,6 +28,7 @@ import com.intellij.openapi.fileEditor.FileEditorManagerListener; import com.intellij.openapi.project.Project; import com.intellij.openapi.startup.StartupManager; import com.intellij.openapi.ui.Splitter; +import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.IconLoader; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.wm.ToolWindow; @@ -53,6 +56,7 @@ public final class DesignerToolWindowManager implements ProjectComponent { private final FileEditorManager myFileEditorManager; private ToolWindow myToolWindow; private ComponentTree myComponentTree; + private AbstractTreeBuilder myTreeBuilder; private PropertyTablePanel myPropertyTablePanel; private boolean myToolWindowReady; private boolean myToolWindowDisposed; @@ -91,12 +95,20 @@ public final class DesignerToolWindowManager implements ProjectComponent { public void projectClosed() { if (!myToolWindowDisposed) { myToolWindowDisposed = true; + clearTreeBuilder(); myComponentTree = null; myPropertyTablePanel = null; myToolWindow = null; } } + private void clearTreeBuilder() { + if (myTreeBuilder != null) { + Disposer.dispose(myTreeBuilder); + myTreeBuilder = null; + } + } + public static DesignerToolWindowManager getInstance(Project project) { return project.getComponent(DesignerToolWindowManager.class); } @@ -128,10 +140,15 @@ public final class DesignerToolWindowManager implements ProjectComponent { } initToolWindow(); } + clearTreeBuilder(); + myComponentTree.newModel(); if (designer == null) { + myComponentTree.setDecorator(null); myToolWindow.setAvailable(false, null); } else { + myComponentTree.setDecorator(designer.getTreeDecorator()); + myTreeBuilder = new ComponentTreeBuilder(myComponentTree, designer); myToolWindow.setAvailable(true, null); myToolWindow.show(null); } diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/ComponentTree.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/ComponentTree.java index d49a48b92079..742dc769f312 100644 --- a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/ComponentTree.java +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/ComponentTree.java @@ -15,10 +15,15 @@ */ package com.intellij.designer.componentTree; +import com.intellij.designer.designSurface.DesignerEditorPanel; +import com.intellij.designer.model.RadComponent; import com.intellij.openapi.actionSystem.DataProvider; +import com.intellij.ui.ColoredTreeCellRenderer; import com.intellij.ui.treeStructure.Tree; +import com.intellij.util.ui.tree.TreeUtil; import org.jetbrains.annotations.NonNls; +import javax.swing.*; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; @@ -26,12 +31,62 @@ import javax.swing.tree.DefaultTreeModel; * @author Alexander Lobas */ public final class ComponentTree extends Tree implements DataProvider { + private TreeComponentDecorator myDecorator; + public ComponentTree() { - super(new DefaultTreeModel(new DefaultMutableTreeNode())); + newModel(); + + installCellRenderer(); + + setRootVisible(false); + setShowsRootHandles(true); + + // Enable tooltips + ToolTipManager.sharedInstance().registerComponent(this); + + // Install convenient keyboard navigation + TreeUtil.installActions(this); + + // TODO: Popup menu + + // TODO: F2 should start inplace editing + + // TODO: DND + } + + public void newModel() { + setModel(new DefaultTreeModel(new DefaultMutableTreeNode())); + } + + public void setDecorator(TreeComponentDecorator decorator) { + myDecorator = decorator; } @Override public Object getData(@NonNls String dataId) { - return null; //To change body of implemented methods use File | Settings | File Templates. + return null; //TODO + } + + private void installCellRenderer() { + setCellRenderer(new ColoredTreeCellRenderer() { + @Override + public void customizeCellRenderer(JTree tree, + Object value, + boolean selected, + boolean expanded, + boolean leaf, + int row, + boolean hasFocus) { + DefaultMutableTreeNode node = (DefaultMutableTreeNode)value; + if (myDecorator != null && node.getUserObject() instanceof TreeNodeDescriptor) { + TreeNodeDescriptor descriptor = (TreeNodeDescriptor)node.getUserObject(); + if (descriptor.getElement() instanceof RadComponent) { + RadComponent component = (RadComponent)descriptor.getElement(); + // TODO: support more parameters and attributes + myDecorator.decorate(component, this); + } + } + } + }); } } \ No newline at end of file diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/ComponentTreeBuilder.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/ComponentTreeBuilder.java new file mode 100644 index 000000000000..300ec7d98fe2 --- /dev/null +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/ComponentTreeBuilder.java @@ -0,0 +1,36 @@ +/* + * 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.designer.componentTree; + +import com.intellij.designer.designSurface.DesignerEditorPanel; +import com.intellij.ide.util.treeView.AbstractTreeBuilder; +import com.intellij.ide.util.treeView.AbstractTreeStructure; +import com.intellij.ide.util.treeView.NodeDescriptor; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import javax.swing.tree.DefaultTreeModel; +import java.util.Comparator; + +/** + * @author Alexander Lobas + */ +public final class ComponentTreeBuilder extends AbstractTreeBuilder { + public ComponentTreeBuilder(ComponentTree tree, DesignerEditorPanel designer) { + super(tree, (DefaultTreeModel)tree.getModel(), new TreeContentProvider(designer), null); // TODO: comparator? + initRootNode(); + } +} \ No newline at end of file diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/TreeComponentDecorator.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/TreeComponentDecorator.java new file mode 100644 index 000000000000..243cd6b0ed59 --- /dev/null +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/TreeComponentDecorator.java @@ -0,0 +1,26 @@ +/* + * 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.designer.componentTree; + +import com.intellij.designer.model.RadComponent; +import com.intellij.ui.ColoredTreeCellRenderer; + +/** + * @author Alexander Lobas + */ +public abstract class TreeComponentDecorator { + public abstract void decorate(RadComponent component, ColoredTreeCellRenderer renderer); // TODO: more parameters and attributes +} \ No newline at end of file diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/TreeContentProvider.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/TreeContentProvider.java new file mode 100644 index 000000000000..0c30ca3c7b3e --- /dev/null +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/TreeContentProvider.java @@ -0,0 +1,83 @@ +/* + * 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.designer.componentTree; + +import com.intellij.designer.designSurface.DesignerEditorPanel; +import com.intellij.designer.model.RadComponent; +import com.intellij.ide.util.treeView.AbstractTreeStructure; +import com.intellij.ide.util.treeView.NodeDescriptor; +import com.intellij.util.ArrayUtil; +import org.jetbrains.annotations.NotNull; + +/** + * @author Alexander Lobas + */ +public final class TreeContentProvider extends AbstractTreeStructure { + private final DesignerEditorPanel myDesigner; + private final Object myTreeRoot = new Object(); + + public TreeContentProvider(DesignerEditorPanel designer) { + myDesigner = designer; + } + + @Override + public Object getRootElement() { + return myTreeRoot; + } + + @Override + public Object[] getChildElements(Object element) { + if (element == myTreeRoot) { + return myDesigner.getTreeRoots(); + } + else if (element instanceof RadComponent) { + RadComponent component = (RadComponent)element; + return component.getTreeChildren(); + } + else { + throw new IllegalArgumentException("Unknown element: " + element); + } + } + + @Override + public Object getParentElement(Object element) { + if (element instanceof RadComponent) { + RadComponent component = (RadComponent)element; + return component.getParent(); + } + return null; + } + + @NotNull + @Override + public NodeDescriptor createDescriptor(Object element, NodeDescriptor parentDescriptor) { + if (element == myTreeRoot || element instanceof RadComponent) { + return new TreeNodeDescriptor(parentDescriptor, element); + } + else { + throw new IllegalArgumentException("Unknown element: " + element); + } + } + + @Override + public boolean hasSomethingToCommit() { + return false; + } + + @Override + public void commit() { + } +} \ No newline at end of file diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/TreeNodeDescriptor.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/TreeNodeDescriptor.java new file mode 100644 index 000000000000..aea7d02606fc --- /dev/null +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/TreeNodeDescriptor.java @@ -0,0 +1,42 @@ +/* + * 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.designer.componentTree; + +import com.intellij.ide.util.treeView.NodeDescriptor; +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.Nullable; + +/** + * @author Alexander Lobas + */ +public final class TreeNodeDescriptor extends NodeDescriptor { + private final Object myElement; + + public TreeNodeDescriptor(@Nullable NodeDescriptor parentDescriptor, Object element) { + super(null, parentDescriptor); + myElement = element; + } + + @Override + public boolean update() { + return false; + } + + @Override + public Object getElement() { + return myElement; + } +} \ No newline at end of file diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/designSurface/DesignerEditorPanel.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/designSurface/DesignerEditorPanel.java index ce2b88de7e52..1e7953eeae7d 100644 --- a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/designSurface/DesignerEditorPanel.java +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/designSurface/DesignerEditorPanel.java @@ -15,9 +15,12 @@ */ package com.intellij.designer.designSurface; +import com.intellij.designer.componentTree.TreeComponentDecorator; +import com.intellij.designer.model.RadComponent; import com.intellij.openapi.actionSystem.DataProvider; import com.intellij.openapi.module.Module; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.ArrayUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -27,7 +30,9 @@ import java.awt.*; /** * @author Alexander Lobas */ -public final class DesignerEditorPanel extends JPanel implements DataProvider { +public abstract class DesignerEditorPanel extends JPanel implements DataProvider { + protected RadComponent myRootComponent; + public DesignerEditorPanel(@NotNull Module module, @NotNull VirtualFile file) { setLayout(new BorderLayout()); add(new JLabel("Design Surface", JLabel.CENTER), BorderLayout.CENTER); @@ -45,4 +50,10 @@ public final class DesignerEditorPanel extends JPanel implements DataProvider { public JComponent getPreferredFocusedComponent() { return null; // TODO: Auto-generated method stub } + + public Object[] getTreeRoots() { + return myRootComponent == null ? ArrayUtil.EMPTY_OBJECT_ARRAY : new Object[]{myRootComponent}; + } + + public abstract TreeComponentDecorator getTreeDecorator(); } \ No newline at end of file diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/RadComponent.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/RadComponent.java index 65488fd1e5a2..e208e5817728 100644 --- a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/RadComponent.java +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/RadComponent.java @@ -16,14 +16,19 @@ package com.intellij.designer.model; import com.intellij.designer.propertyTable.Property; +import com.intellij.util.containers.hash.HashMap; +import org.jetbrains.annotations.NotNull; +import java.util.Collections; import java.util.List; +import java.util.Map; /** * @author Alexander Lobas */ public abstract class RadComponent { private RadComponent myParent; + private final Map myClientProperties = new HashMap(); public RadComponent getRoot() { return myParent == null ? this : myParent.getRoot(); @@ -38,10 +43,22 @@ public abstract class RadComponent { } public List getChildren() { - return null; + return Collections.emptyList(); + } + + public Object[] getTreeChildren() { + return getChildren().toArray(); } public List getProperties() { return null; } + + public final Object getClientProperty(@NotNull Object key) { + return myClientProperties.get(key); + } + + public final void putClientProperty(@NotNull Object key, Object value) { + myClientProperties.put(key, value); + } } \ No newline at end of file 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); }