diff --git a/bin/idea.properties b/bin/idea.properties index be34798ed34e..a9cd05389fd5 100644 --- a/bin/idea.properties +++ b/bin/idea.properties @@ -99,4 +99,11 @@ sun.java2d.pmoffscreen=false # Maximum size (kilobytes) IDEA will load for showing past file contents - # in Show Diff or when calculating Digest Diff #--------------------------------------------------------------------- -#idea.max.vcs.loaded.size.kb=20480 \ No newline at end of file +#idea.max.vcs.loaded.size.kb=20480 + +#--------------------------------------------------------------------- +# IDEA file chooser peeks inside directories to detect whether they contain a valid project +# (to mark such directories with a corresponding icon). +# Uncommenting the option prevents this behavior outside of user home directory. +#--------------------------------------------------------------------- +#idea.chooser.lookup.for.project.dirs=false diff --git a/java/execution/impl/src/com/intellij/execution/applet/AppletConfiguration.java b/java/execution/impl/src/com/intellij/execution/applet/AppletConfiguration.java index 9d00cad60172..f69ad997c8dc 100644 --- a/java/execution/impl/src/com/intellij/execution/applet/AppletConfiguration.java +++ b/java/execution/impl/src/com/intellij/execution/applet/AppletConfiguration.java @@ -35,6 +35,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; import com.intellij.refactoring.listeners.RefactoringElementListener; +import com.intellij.util.SmartList; import com.intellij.util.xmlb.SmartSerializer; import com.intellij.util.xmlb.annotations.Transient; import org.jdom.Element; @@ -46,7 +47,6 @@ import java.io.FileWriter; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; -import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -74,7 +74,7 @@ public class AppletConfiguration extends ModuleBasedConfiguration parameters = new ArrayList(); - for (final Element element : parentNode.getChildren(PARAMETER_ELEMENT_NAME)) { - parameters.add(new AppletParameter(element.getAttributeValue(NAME_ATTR), element.getAttributeValue(VALUE_ATTR))); + + List paramList = parentNode.getChildren(PARAMETER_ELEMENT_NAME); + if (paramList.isEmpty()) { + myAppletParameters = null; + } + else { + List parameters = new SmartList(); + for (Element element : paramList) { + parameters.add(new AppletParameter(element.getAttributeValue(NAME_ATTR), element.getAttributeValue(VALUE_ATTR))); + } + myAppletParameters = parameters.toArray(new AppletParameter[parameters.size()]); } - myAppletParameters = parameters.toArray(new AppletParameter[parameters.size()]); } @Override @@ -208,7 +214,6 @@ public class AppletConfiguration extends ModuleBasedConfiguration getInteriorRange(PsiCodeBlock codeBlock) { - PsiElement[] children = codeBlock.getChildren(); - if (children.length == 0) return Pair.create(codeBlock, codeBlock); - int start; - for (start=0; start start;end--) { - PsiElement child = children[end]; - if (child instanceof PsiWhiteSpace) continue; - if (child instanceof PsiJavaToken && ((PsiJavaToken)child).getTokenType() == JavaTokenType.RBRACE) continue; - break; - } - return Pair.create(children[start], children[end]); - } - @Override @Nullable public ProblemDescriptor[] checkFile(@NotNull PsiFile file, @NotNull InspectionManager manager, boolean isOnTheFly) { @@ -92,15 +70,15 @@ public class DefaultFileTemplateUsageInspection extends BaseJavaLocalInspectionT return true; } - public static LocalQuickFix createEditFileTemplateFix(final FileTemplate templateToEdit, final ReplaceWithFileTemplateFix replaceTemplateFix) { - return new MyLocalQuickFix(templateToEdit, replaceTemplateFix); + public static LocalQuickFix createEditFileTemplateFix(FileTemplate templateToEdit, ReplaceWithFileTemplateFix replaceTemplateFix) { + return new EditFileTemplateFix(templateToEdit, replaceTemplateFix); } - private static class MyLocalQuickFix implements LocalQuickFix { + private static class EditFileTemplateFix implements LocalQuickFix { private final FileTemplate myTemplateToEdit; private final ReplaceWithFileTemplateFix myReplaceTemplateFix; - public MyLocalQuickFix(FileTemplate templateToEdit, ReplaceWithFileTemplateFix replaceTemplateFix) { + public EditFileTemplateFix(FileTemplate templateToEdit, ReplaceWithFileTemplateFix replaceTemplateFix) { myTemplateToEdit = templateToEdit; myReplaceTemplateFix = replaceTemplateFix; } @@ -120,11 +98,10 @@ public class DefaultFileTemplateUsageInspection extends BaseJavaLocalInspectionT @Override public void applyFix(@NotNull final Project project, @NotNull final ProblemDescriptor descriptor) { final FileTemplateConfigurable configurable = new FileTemplateConfigurable(); - SwingUtilities.invokeLater(new Runnable(){ + ApplicationManager.getApplication().invokeLater(new Runnable() { @Override public void run() { configurable.setTemplate(myTemplateToEdit, null); - boolean ok = ShowSettingsUtil.getInstance().editConfigurable(project, configurable); if (ok) { WriteCommandAction.runWriteCommandAction(project, new Runnable() { diff --git a/java/java-impl/src/com/intellij/codeInspection/defaultFileTemplateUsage/FileHeaderChecker.java b/java/java-impl/src/com/intellij/codeInspection/defaultFileTemplateUsage/FileHeaderChecker.java index a3db2c3d31f8..0b40ae38b1d0 100644 --- a/java/java-impl/src/com/intellij/codeInspection/defaultFileTemplateUsage/FileHeaderChecker.java +++ b/java/java-impl/src/com/intellij/codeInspection/defaultFileTemplateUsage/FileHeaderChecker.java @@ -20,97 +20,86 @@ import com.intellij.codeInspection.*; import com.intellij.ide.fileTemplates.FileTemplate; import com.intellij.ide.fileTemplates.FileTemplateManager; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.Document; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Ref; -import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.psi.JavaRecursiveElementWalkingVisitor; -import com.intellij.psi.PsiDocumentManager; +import com.intellij.psi.JavaPsiFacade; +import com.intellij.psi.PsiComment; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.javadoc.PsiDocComment; -import com.intellij.util.IncorrectOperationException; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.util.containers.ContainerUtil; import gnu.trove.TIntObjectHashMap; -import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import java.io.IOException; -import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; +import java.util.List; import java.util.Properties; import java.util.regex.Matcher; import java.util.regex.Pattern; /** - * @author Alexey + * @author cdr */ public class FileHeaderChecker { private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.defaultFileTemplateUsage.FileHeaderChecker"); - static ProblemDescriptor checkFileHeader(@NotNull final PsiFile file, @NotNull InspectionManager manager, boolean onTheFly) { + static ProblemDescriptor checkFileHeader(@NotNull PsiFile file, @NotNull InspectionManager manager, boolean onTheFly) { TIntObjectHashMap offsetToProperty = new TIntObjectHashMap(); FileTemplate defaultTemplate = FileTemplateManager.getInstance().getDefaultTemplate(FileTemplateManager.FILE_HEADER_TEMPLATE_NAME); Pattern pattern = getTemplatePattern(defaultTemplate, file.getProject(), offsetToProperty); Matcher matcher = pattern.matcher(file.getViewProvider().getContents()); - if (matcher.matches()) { - final int startOffset = matcher.start(1); - final int endOffset = matcher.end(1); - final Ref docComment = new Ref(); - file.accept(new JavaRecursiveElementWalkingVisitor(){ - @Override public void visitElement(PsiElement element) { - if (docComment.get() != null) return; - TextRange range = element.getTextRange(); - if (!range.contains(startOffset) && !range.contains(endOffset)) return; - super.visitElement(element); - } - @Override public void visitDocComment(PsiDocComment comment) { - docComment.set(comment); - } - }); - PsiDocComment element = docComment.get(); - if (element == null) return null; - LocalQuickFix[] quickFix = createQuickFix(matcher, offsetToProperty); - final String description = InspectionsBundle.message("default.file.template.description"); - return manager.createProblemDescriptor(element, description, onTheFly, quickFix, ProblemHighlightType.GENERIC_ERROR_OR_WARNING); + if (!matcher.matches()) { + return null; } - return null; + + PsiComment element = PsiTreeUtil.findElementOfClassAtRange(file, matcher.start(1), matcher.end(1), PsiComment.class); + if (element == null) { + return null; + } + + LocalQuickFix[] fixes = createQuickFix(matcher, offsetToProperty); + String description = InspectionsBundle.message("default.file.template.description"); + return manager.createProblemDescriptor(element, description, onTheFly, fixes, ProblemHighlightType.GENERIC_ERROR_OR_WARNING); } - public static Pattern getTemplatePattern(@NotNull FileTemplate template, @NotNull Project project, @NotNull TIntObjectHashMap offsetToProperty) { + public static Pattern getTemplatePattern(@NotNull FileTemplate template, + @NotNull Project project, + @NotNull TIntObjectHashMap offsetToProperty) { String templateText = template.getText().trim(); String regex = templateToRegex(templateText, offsetToProperty, project); regex = StringUtil.replace(regex, "with", "(?:with|by)"); - regex = ".*("+regex+").*"; + regex = ".*(" + regex + ").*"; return Pattern.compile(regex, Pattern.DOTALL); } private static Properties computeProperties(final Matcher matcher, final TIntObjectHashMap offsetToProperty) { Properties properties = new Properties(FileTemplateManager.getInstance().getDefaultProperties()); + int[] offsets = offsetToProperty.keys(); Arrays.sort(offsets); - for (int i = 0; i < offsets.length; i++) { final int offset = offsets[i]; String propName = offsetToProperty.get(offset); int groupNum = i + 2; // first group is whole doc comment String propValue = matcher.group(groupNum); - properties.put(propName, propValue); + properties.setProperty(propName, propValue); } + return properties; } - private static LocalQuickFix[] createQuickFix(final Matcher matcher, - final TIntObjectHashMap offsetToProperty) { + private static LocalQuickFix[] createQuickFix(final Matcher matcher, final TIntObjectHashMap offsetToProperty) { final FileTemplate template = FileTemplateManager.getInstance().getPattern(FileTemplateManager.FILE_HEADER_TEMPLATE_NAME); - final ReplaceWithFileTemplateFix replaceTemplateFix = new ReplaceWithFileTemplateFix() { + ReplaceWithFileTemplateFix replaceTemplateFix = new ReplaceWithFileTemplateFix() { @Override - public void applyFix(@NotNull final Project project, @NotNull final ProblemDescriptor descriptor) { + public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { PsiElement element = descriptor.getPsiElement(); if (element == null || !element.isValid()) return; if (!CodeInsightUtil.preparePsiElementsForWrite(element)) return; + String newText; try { newText = template.getText(computeProperties(matcher, offsetToProperty)); @@ -119,49 +108,30 @@ public class FileHeaderChecker { LOG.error(e); return; } - try { - int offset = element.getTextRange().getStartOffset(); - PsiFile psiFile = element.getContainingFile(); - if (psiFile == null) return; - PsiDocumentManager documentManager = PsiDocumentManager.getInstance(psiFile.getProject()); - Document document = documentManager.getDocument(psiFile); - if (document == null) return; - element.delete(); - documentManager.doPostponedOperationsAndUnblockDocument(document); - documentManager.commitDocument(document); - - document.insertString(offset, newText); - } - catch (IncorrectOperationException e) { - LOG.error(e); - } - catch (IllegalStateException e) { - LOG.error("Cannot create doc comment from text: '" + newText + "'", e); - } + PsiDocComment newComment = JavaPsiFacade.getElementFactory(project).createDocCommentFromText(newText); + element.replace(newComment); } }; - final LocalQuickFix editFileTemplateFix = DefaultFileTemplateUsageInspection.createEditFileTemplateFix(template, replaceTemplateFix); - if (template.isDefault()) { - return new LocalQuickFix[]{editFileTemplateFix}; - } - return new LocalQuickFix[]{replaceTemplateFix,editFileTemplateFix}; + + LocalQuickFix editFileTemplateFix = DefaultFileTemplateUsageInspection.createEditFileTemplateFix(template, replaceTemplateFix); + return template.isDefault() ? new LocalQuickFix[]{editFileTemplateFix} : new LocalQuickFix[]{replaceTemplateFix, editFileTemplateFix}; } - private static String templateToRegex(@NotNull String text, @NotNull TIntObjectHashMap offsetToProperty, @NotNull Project project) { - String regex = text; - @NonNls Collection properties = new ArrayList((Collection)FileTemplateManager.getInstance().getDefaultProperties(project).keySet()); + private static String templateToRegex(String text, TIntObjectHashMap offsetToProperty, Project project) { + List properties = ContainerUtil.newArrayList(FileTemplateManager.getInstance().getDefaultProperties(project).keySet()); properties.add("PACKAGE_NAME"); - regex = escapeRegexChars(regex); + String regex = escapeRegexChars(text); // first group is a whole file header int groupNumber = 1; - for (String name : properties) { - String escaped = escapeRegexChars("${"+name+"}"); + for (Object property : properties) { + String name = property.toString(); + String escaped = escapeRegexChars("${" + name + "}"); boolean first = true; - for (int i = regex.indexOf(escaped); i!=-1 && i i) { @@ -170,7 +140,7 @@ public class FileHeaderChecker { } } offsetToProperty.put(i, name); - regex = regex.substring(0,i) + replacement + regex.substring(i+escaped.length()); + regex = regex.substring(0, i) + replacement + regex.substring(i + escaped.length()); if (first) { groupNumber++; first = false; @@ -181,18 +151,18 @@ public class FileHeaderChecker { } private static String escapeRegexChars(String regex) { - regex = StringUtil.replace(regex,"|", "\\|"); - regex = StringUtil.replace(regex,".", "\\."); - regex = StringUtil.replace(regex,"*", "\\*"); - regex = StringUtil.replace(regex,"+", "\\+"); - regex = StringUtil.replace(regex,"?", "\\?"); - regex = StringUtil.replace(regex,"$", "\\$"); - regex = StringUtil.replace(regex,"(", "\\("); - regex = StringUtil.replace(regex,")", "\\)"); - regex = StringUtil.replace(regex,"[", "\\["); - regex = StringUtil.replace(regex,"]", "\\]"); - regex = StringUtil.replace(regex,"{", "\\{"); - regex = StringUtil.replace(regex,"}", "\\}"); + regex = StringUtil.replace(regex, "|", "\\|"); + regex = StringUtil.replace(regex, ".", "\\."); + regex = StringUtil.replace(regex, "*", "\\*"); + regex = StringUtil.replace(regex, "+", "\\+"); + regex = StringUtil.replace(regex, "?", "\\?"); + regex = StringUtil.replace(regex, "$", "\\$"); + regex = StringUtil.replace(regex, "(", "\\("); + regex = StringUtil.replace(regex, ")", "\\)"); + regex = StringUtil.replace(regex, "[", "\\["); + regex = StringUtil.replace(regex, "]", "\\]"); + regex = StringUtil.replace(regex, "{", "\\{"); + regex = StringUtil.replace(regex, "}", "\\}"); return regex; } } diff --git a/java/java-impl/src/com/intellij/codeInspection/miscGenerics/RedundantArrayForVarargsCallInspection.java b/java/java-impl/src/com/intellij/codeInspection/miscGenerics/RedundantArrayForVarargsCallInspection.java index 13f09cb8edd9..f5e0e5102b5b 100644 --- a/java/java-impl/src/com/intellij/codeInspection/miscGenerics/RedundantArrayForVarargsCallInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/miscGenerics/RedundantArrayForVarargsCallInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -15,6 +15,7 @@ */ package com.intellij.codeInspection.miscGenerics; +import com.intellij.codeInsight.AnnotationUtil; import com.intellij.codeInsight.ExpectedTypeInfo; import com.intellij.codeInsight.ExpectedTypesProvider; import com.intellij.codeInsight.FileModificationService; @@ -31,6 +32,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; +import java.util.Collections; import java.util.List; /** @@ -93,7 +95,8 @@ public class RedundantArrayForVarargsCallInspection extends GenericsInspectionTo return; } PsiMethod method = (PsiMethod)element; - if (!method.isVarArgs()) { + if (!method.isVarArgs() || + AnnotationUtil.isAnnotated(method, Collections.singletonList("java.lang.invoke.MethodHandle.PolymorphicSignature"))) { return; } PsiParameter[] parameters = method.getParameterList().getParameters(); diff --git a/java/java-impl/src/com/intellij/psi/impl/cache/impl/idCache/JavaFilterLexer.java b/java/java-impl/src/com/intellij/psi/impl/cache/impl/idCache/JavaFilterLexer.java index 44207d32b640..8ea446e46786 100644 --- a/java/java-impl/src/com/intellij/psi/impl/cache/impl/idCache/JavaFilterLexer.java +++ b/java/java-impl/src/com/intellij/psi/impl/cache/impl/idCache/JavaFilterLexer.java @@ -58,7 +58,9 @@ public class JavaFilterLexer extends BaseFilterLexer { if (tokenType == JavaTokenType.IDENTIFIER || tokenType == JavaTokenType.LONG_LITERAL || tokenType == JavaTokenType.INTEGER_LITERAL - || tokenType == JavaTokenType.CHARACTER_LITERAL) { + || tokenType == JavaTokenType.CHARACTER_LITERAL + || tokenType == JavaTokenType.ARROW + || tokenType == JavaTokenType.DOUBLE_COLON) { addOccurrenceInToken(UsageSearchContext.IN_CODE); } else if (tokenType == JavaTokenType.STRING_LITERAL) { diff --git a/java/java-indexing-impl/src/com/intellij/psi/impl/java/stubs/index/JavaMethodParameterTypesIndex.java b/java/java-indexing-impl/src/com/intellij/psi/impl/java/stubs/index/JavaMethodParameterTypesIndex.java deleted file mode 100644 index 23f4ffac729e..000000000000 --- a/java/java-indexing-impl/src/com/intellij/psi/impl/java/stubs/index/JavaMethodParameterTypesIndex.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2000-2014 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. - */ - -/* - * @author max - */ -package com.intellij.psi.impl.java.stubs.index; - -import com.intellij.openapi.project.Project; -import com.intellij.psi.PsiMethod; -import com.intellij.psi.impl.search.JavaSourceFilterScope; -import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.psi.stubs.StringStubIndexExtension; -import com.intellij.psi.stubs.StubIndex; -import com.intellij.psi.stubs.StubIndexKey; -import org.jetbrains.annotations.NotNull; - -import java.util.Collection; - -public class JavaMethodParameterTypesIndex extends StringStubIndexExtension { - - private static final JavaMethodParameterTypesIndex ourInstance = new JavaMethodParameterTypesIndex(); - public static JavaMethodParameterTypesIndex getInstance() { - return ourInstance; - } - - @NotNull - @Override - public StubIndexKey getKey() { - return JavaStubIndexKeys.METHOD_TYPES; - } - - @Override - public Collection get(@NotNull final String s, @NotNull final Project project, @NotNull final GlobalSearchScope scope) { - return StubIndex.getElements(getKey(), s, project, new JavaSourceFilterScope(scope), PsiMethod.class); - } -} \ No newline at end of file diff --git a/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaFunctionalExpressionSearcher.java b/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaFunctionalExpressionSearcher.java index cb5d6be103fd..8fbe6ef11a5c 100644 --- a/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaFunctionalExpressionSearcher.java +++ b/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaFunctionalExpressionSearcher.java @@ -15,37 +15,39 @@ */ package com.intellij.psi.impl.search; +import com.intellij.ide.highlighter.JavaFileType; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.module.impl.scopes.ModulesScope; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.LanguageLevelModuleExtension; import com.intellij.openapi.roots.ModuleRootManager; +import com.intellij.openapi.roots.ProjectFileIndex; +import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.util.Computable; +import com.intellij.openapi.util.Ref; +import com.intellij.openapi.vfs.VirtualFile; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; -import com.intellij.psi.impl.java.stubs.JavaMethodElementType; -import com.intellij.psi.impl.java.stubs.index.JavaMethodParameterTypesIndex; -import com.intellij.psi.search.EverythingGlobalScope; -import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.psi.search.SearchScope; +import com.intellij.psi.search.*; import com.intellij.psi.search.searches.FunctionalExpressionSearch; -import com.intellij.psi.search.searches.MethodReferencesSearch; -import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.PsiUtilCore; +import com.intellij.util.CommonProcessors; import com.intellij.util.Processor; import com.intellij.util.QueryExecutor; import com.intellij.util.containers.HashSet; import org.jetbrains.annotations.NotNull; import java.util.Collection; -import java.util.LinkedHashSet; import java.util.Set; public class JavaFunctionalExpressionSearcher implements QueryExecutor { + private static final Logger LOG = Logger.getInstance("#" + JavaFunctionalExpressionSearcher.class.getName()); + @Override public boolean execute(@NotNull final FunctionalExpressionSearch.SearchParameters queryParameters, @NotNull final Processor consumer) { @@ -98,102 +100,74 @@ public class JavaFunctionalExpressionSearcher implements QueryExecutor lambdaCandidates = ApplicationManager.getApplication().runReadAction(new Computable>() { + + final ProjectFileIndex index = ProjectRootManager.getInstance(project).getFileIndex(); + final HashSet files = new HashSet(); + CommonProcessors.CollectProcessor processor = new CommonProcessors.CollectProcessor(files) { @Override - public Collection compute() { - final String functionalInterfaceName = aClass.getName(); - final GlobalSearchScope useClassScope = classScope instanceof GlobalSearchScope ? (GlobalSearchScope)classScope : scope; - JavaMethodParameterTypesIndex parameterTypesIndex = JavaMethodParameterTypesIndex.getInstance(); - LinkedHashSet methods = new LinkedHashSet(parameterTypesIndex.get(functionalInterfaceName, project, useClassScope)); - methods.addAll(parameterTypesIndex.get(JavaMethodElementType.TYPE_PARAMETER_PSEUDO_NAME, project, - GlobalSearchScope.allScope(project))); - return methods; + protected boolean accept(VirtualFile virtualFile) { + return scope.contains(virtualFile) && virtualFile.getFileType() == JavaFileType.INSTANCE && index.isInSource(virtualFile); } - }); - for (PsiMethod psiMethod : lambdaCandidates) { - for (final PsiReference ref : MethodReferencesSearch.search(psiMethod, scope, false)) { - boolean accepted = ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public Boolean compute() { - final PsiElement refElement = ref.getElement(); - if (refElement != null) { - final PsiElement candidateElement = refElement.getParent(); - if (candidateElement instanceof PsiCallExpression) { - final PsiExpressionList argumentList = ((PsiCallExpression)candidateElement).getArgumentList(); - if (argumentList != null) { - final PsiExpression[] args = argumentList.getExpressions(); - for (PsiExpression arg : args) { - if (arg instanceof PsiFunctionalExpression) { - final PsiFunctionalExpression functionalExpression = (PsiFunctionalExpression)arg; - final PsiType functionalType = functionalExpression.getFunctionalInterfaceType(); - if (PsiUtil.resolveClassInType(functionalType) == aClass) { - if (!consumer.process(functionalExpression)) return false; - } - } - } - } - } - } - return true; - } - }); - if (!accepted) return false; - } - } + }; - for (final PsiReference reference : ReferencesSearch.search(aClass, scope)) { - boolean accepted = ApplicationManager.getApplication().runReadAction(new Computable() { + final PsiSearchHelperImpl helper = (PsiSearchHelperImpl)PsiSearchHelper.SERVICE.getInstance(project); + helper.processFilesWithText(scope, UsageSearchContext.IN_CODE, true, "::", processor); + helper.processFilesWithText(scope, UsageSearchContext.IN_CODE, true, "->", processor); + LOG.info("#files: " + files.size()); + + final PsiManager psiManager = PsiManager.getInstance(project); + for (final VirtualFile file : files) { + if (!ApplicationManager.getApplication().runReadAction(new Computable() { @Override public Boolean compute() { - final PsiElement element = reference.getElement(); - if (element != null) { - final PsiElement parent = element.getParent(); - if (parent instanceof PsiTypeElement) { - final PsiElement gParent = parent.getParent(); - if (gParent instanceof PsiVariable) { - final PsiExpression initializer = PsiUtil.skipParenthesizedExprDown(((PsiVariable)gParent).getInitializer()); - if (initializer instanceof PsiFunctionalExpression) { - if (!consumer.process((PsiFunctionalExpression)initializer)) return false; - } - for (PsiReference varRef : ReferencesSearch.search(parent, scope)) { - final PsiElement varElement = varRef.getElement(); - if (varElement != null) { - final PsiElement varElementParent = varElement.getParent(); - if (varElementParent instanceof PsiAssignmentExpression && - ((PsiAssignmentExpression)varElementParent).getLExpression() == varElement) { - final PsiExpression rExpression = PsiUtil.skipParenthesizedExprDown(((PsiAssignmentExpression)varElementParent).getRExpression()); - if (rExpression instanceof PsiFunctionalExpression) { - if (!consumer.process((PsiFunctionalExpression)rExpression)) return false; - } - } - } - } - } else if (gParent instanceof PsiMethod) { - final PsiReturnStatement[] returnStatements = ApplicationManager.getApplication().runReadAction( - new Computable() { - @Override - public PsiReturnStatement[] compute() { - return PsiUtil.findReturnStatements((PsiMethod)gParent); - } - }); - for (PsiReturnStatement returnStatement : returnStatements) { - final PsiExpression returnValue = returnStatement.getReturnValue(); - if (returnValue instanceof PsiFunctionalExpression) { - if (!consumer.process((PsiFunctionalExpression)returnValue)) return false; - } - } - } + return processFileWithFunctionalInterfaces(aClass, consumer, psiManager, file); + } + })) return false; + } + return true; + } + + private static boolean processFileWithFunctionalInterfaces(final PsiClass aClass, + final Processor consumer, + final PsiManager psiManager, VirtualFile file) { + final PsiFile psiFile = psiManager.findFile(file); + if (psiFile != null) { + final Ref ref = new Ref(true); + psiFile.accept(new JavaRecursiveElementWalkingVisitor() { + @Override + public void visitElement(PsiElement element) { + if (!ref.get()) { + return; + } + super.visitElement(element); + } + + private void visitFunctionalExpression(PsiFunctionalExpression expression) { + PsiType functionalInterfaceType = expression.getFunctionalInterfaceType(); + if (psiManager.areElementsEquivalent(PsiUtil.resolveClassInType(functionalInterfaceType), aClass)) { + if (!consumer.process(expression)) { + ref.set(false); } } + } - return true; + @Override + public void visitLambdaExpression(PsiLambdaExpression expression) { + super.visitLambdaExpression(expression); + visitFunctionalExpression(expression); + } + + @Override + public void visitMethodReferenceExpression(PsiMethodReferenceExpression expression) { + super.visitMethodReferenceExpression(expression); + visitFunctionalExpression(expression); } }); - if (!accepted) return false; - + if (!ref.get()) return false; } return true; } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/JavaMethodElementType.java b/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/JavaMethodElementType.java index 53033115a85c..06369c9f7379 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/JavaMethodElementType.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/JavaMethodElementType.java @@ -50,7 +50,6 @@ import java.util.Set; * @author max */ public abstract class JavaMethodElementType extends JavaStubElementType { - public static final String TYPE_PARAMETER_PSEUDO_NAME = "$TYPE_PARAMETER$"; public JavaMethodElementType(@NonNls final String name) { super(name); } @@ -150,35 +149,5 @@ public abstract class JavaMethodElementType extends JavaStubElementType methodTypeParams = null; - for (StubElement stubElement : stub.getChildrenStubs()) { - if (stubElement instanceof PsiTypeParameterListStub) { - for (Object tStub : stubElement.getChildrenStubs()) { - if (tStub instanceof PsiTypeParameterStub) { - if (methodTypeParams == null) { - methodTypeParams = new HashSet(); - } - methodTypeParams.add(((PsiTypeParameterStub)tStub).getName()); - } - } - } - else if (stubElement instanceof PsiParameterListStub) { - for (StubElement paramStub : ((PsiParameterListStub)stubElement).getChildrenStubs()) { - if (paramStub instanceof PsiParameterStub) { - TypeInfo type = ((PsiParameterStub)paramStub).getType(false); - if (type.arrayCount > 0) continue; - String typeName = type.getShortTypeText(); - if (TypeConversionUtil.isPrimitive(typeName) || TypeConversionUtil.isPrimitiveWrapper(typeName)) continue; - sink.occurrence(JavaStubIndexKeys.METHOD_TYPES, typeName); - if (methodTypeParams != null && methodTypeParams.contains(typeName)) { - sink.occurrence(JavaStubIndexKeys.METHOD_TYPES, TYPE_PARAMETER_PSEUDO_NAME); - methodTypeParams = null; - } - } - } - break; - } - } } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/index/JavaStubIndexKeys.java b/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/index/JavaStubIndexKeys.java index a3e247f73de8..e8760f5f95fa 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/index/JavaStubIndexKeys.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/index/JavaStubIndexKeys.java @@ -29,7 +29,6 @@ public class JavaStubIndexKeys { public static final StubIndexKey JVM_STATIC_MEMBERS_NAMES = StubIndexKey.createIndexKey("jvm.static.member.name"); public static final StubIndexKey JVM_STATIC_MEMBERS_TYPES = StubIndexKey.createIndexKey("jvm.static.member.type"); public static final StubIndexKey ANONYMOUS_BASEREF = StubIndexKey.createIndexKey("java.anonymous.baseref"); - public static final StubIndexKey METHOD_TYPES = StubIndexKey.createIndexKey("java.method.parameter.types"); public static final StubIndexKey CLASS_SHORT_NAMES = StubIndexKey.createIndexKey("java.class.shortname"); public static final StubIndexKey CLASS_FQN = StubIndexKey.createIndexKey("java.class.fqn"); diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/JavaFileElementType.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/JavaFileElementType.java index eedf4abf13cb..cec30eb3c8af 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/JavaFileElementType.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/JavaFileElementType.java @@ -38,7 +38,7 @@ import java.io.IOException; * @author max */ public class JavaFileElementType extends ILightStubFileElementType { - public static final int STUB_VERSION = 18; + public static final int STUB_VERSION = 19; public JavaFileElementType() { super("java.FILE", JavaLanguage.INSTANCE); diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java index f7b73ba5eee2..95baff29ef69 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java @@ -105,7 +105,7 @@ public class ExpressionCompatibilityConstraint extends InputOutputConstraintForm if (typeParams != null) { PsiSubstitutor siteSubstitutor = - resolveResult instanceof MethodCandidateInfo && method != null && !method.isConstructor() ? ((MethodCandidateInfo)resolveResult).getSiteSubstitutor() : PsiSubstitutor.EMPTY; + resolveResult instanceof MethodCandidateInfo && method != null && !method.isConstructor() ? ((MethodCandidateInfo)resolveResult).getSiteSubstitutor() : candidateProperties != null ? candidateProperties.getSubstitutor() : PsiSubstitutor.EMPTY; final InferenceSession callSession = new InferenceSession(typeParams, siteSubstitutor, myExpression.getManager(), myExpression); callSession.propagateVariables(session.getInferenceVariables()); if (method != null) { diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/PsiMethodReferenceCompatibilityConstraint.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/PsiMethodReferenceCompatibilityConstraint.java index b5e4188e1644..45018296d888 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/PsiMethodReferenceCompatibilityConstraint.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/PsiMethodReferenceCompatibilityConstraint.java @@ -169,13 +169,13 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm } LOG.assertTrue(referencedMethodReturnType != null, method); - session.initBounds(myExpression, method.getTypeParameters()); - - if (!PsiTreeUtil.isContextAncestor(containingClass, myExpression, false) || + if (!PsiTreeUtil.isContextAncestor(containingClass, myExpression, false) || PsiUtil.getEnclosingStaticElement(myExpression, containingClass) != null) { session.initBounds(myExpression, containingClass.getTypeParameters()); } + session.initBounds(myExpression, method.getTypeParameters()); + //if i) the method reference elides NonWildTypeArguments, // ii) the compile-time declaration is a generic method, and // iii) the return type of the compile-time declaration mentions at least one of the method's type parameters; diff --git a/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java b/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java index 3318d15b747a..dd171de90d18 100644 --- a/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java +++ b/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java @@ -231,7 +231,8 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ final PsiMethod method = ((MethodCandidateInfo)conflict).getElement(); for (HierarchicalMethodSignature methodSignature : method.getHierarchicalMethodSignature().getSuperSignatures()) { final PsiMethod superMethod = methodSignature.getMethod(); - if (!CommonClassNames.JAVA_LANG_OBJECT.equals(superMethod.getContainingClass().getQualifiedName())) { + final PsiClass aClass = superMethod.getContainingClass(); + if (aClass != null && !CommonClassNames.JAVA_LANG_OBJECT.equals(aClass.getQualifiedName())) { superMethods.add(superMethod); } } @@ -513,7 +514,7 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ if (varargsPosition) { if (type1 instanceof PsiEllipsisType && type2 instanceof PsiEllipsisType && params1.length == params2.length && - (!JavaVersionService.getInstance().isAtLeast(class1, JavaSdkVersion.JDK_1_7) || ((PsiArrayType)type1).getComponentType().equalsToText(CommonClassNames.JAVA_LANG_OBJECT) || ((PsiArrayType)type2).getComponentType().equalsToText(CommonClassNames.JAVA_LANG_OBJECT))) { + class1 != null && (!JavaVersionService.getInstance().isAtLeast(class1, JavaSdkVersion.JDK_1_7) || ((PsiArrayType)type1).getComponentType().equalsToText(CommonClassNames.JAVA_LANG_OBJECT) || ((PsiArrayType)type2).getComponentType().equalsToText(CommonClassNames.JAVA_LANG_OBJECT))) { type1 = ((PsiEllipsisType)type1).toArrayType(); type2 = ((PsiEllipsisType)type2).toArrayType(); } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/ResolveConflictDiamonds.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/ResolveConflictDiamonds.java new file mode 100644 index 000000000000..a4949425dbd3 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/ResolveConflictDiamonds.java @@ -0,0 +1,19 @@ +class Test { + enum FooBar {Foo, Bar} + + void someMethod() { + new Infer<>((FooBar) null, FooBar.class); + new Infer( (FooBar) null, FooBar.class ); + } + + + public class Infer> { + @SafeVarargs + public Infer(T inst, Class tClass, T... excludes) { + } + + @SafeVarargs + public Infer(String inst, Class tClass, T... excludes) { + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/PropertiesInsteadOfSiteSubstitutorIfAny.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/PropertiesInsteadOfSiteSubstitutorIfAny.java new file mode 100644 index 000000000000..ddc4008f666a --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/PropertiesInsteadOfSiteSubstitutorIfAny.java @@ -0,0 +1,51 @@ + +import java.util.List; +import java.util.Optional; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Stream; + +class Test { + public static class Thing { + public Integer toPresenter() { + return 1; + } + } + + public void map1(Function mapper) {} + + private void getPresentersFailure( final Stream stream) { + map1((roles) -> { + return stream.map(Thing::toPresenter); + }); + } + +} + +class Test1 { + public interface Convertable { + ThingPresenter toPresenter(); + } + + public static class Thing implements Convertable { + @Override + public ThingPresenter toPresenter() { + return new ThingPresenter("thing"); + } + } + + public static class ThingPresenter { + public String value; + public ThingPresenter(String value) { this.value = value; } + } + + private static Stream getPresentersFailure(Supplier>> thingSupplier) { + Optional> personRoles = thingSupplier.get(); + return personRoles.map(roles -> roles.stream().map(Thing::toPresenter)).get(); + } + + private static Stream getPresentersWorking(Supplier>> thingSupplier) { + Optional> personRoles = thingSupplier.get(); + return personRoles.map(roles -> roles.stream().map(t -> t.toPresenter())).get(); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/TypeParametersInitOrder.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/TypeParametersInitOrder.java new file mode 100644 index 000000000000..966b0137f7b6 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/TypeParametersInitOrder.java @@ -0,0 +1,21 @@ +import java.util.function.Function; + +interface Repository { + S save(S s); +} + +interface Builder { + + T build(); + + default Builder map(Function fx) { + return () -> fx.apply(this.build()); + } +} + +class Usage { + void test(Repository repository, Builder sample) { + sample.map(repository::save).build(); + sample.map((s) -> repository.save(s)).build(); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/defaultFileTemplateUsage/Range.java b/java/java-tests/testData/inspection/defaultFileTemplateUsage/Range.java new file mode 100644 index 000000000000..2a36f0341190 --- /dev/null +++ b/java/java-tests/testData/inspection/defaultFileTemplateUsage/Range.java @@ -0,0 +1,10 @@ +package mylibs.aspectjlibs.lib2; + +/** + * Created by irina on 11/6/2014. + */ +class Range { + /** + * for all public methods with name == foo* and String type + */ +} diff --git a/java/java-tests/testData/inspection/defaultFileTemplateUsage/defaultFile/src/x/X.java b/java/java-tests/testData/inspection/defaultFileTemplateUsage/X.java similarity index 95% rename from java/java-tests/testData/inspection/defaultFileTemplateUsage/defaultFile/src/x/X.java rename to java/java-tests/testData/inspection/defaultFileTemplateUsage/X.java index c77b8f372e74..a9e7bf01f025 100644 --- a/java/java-tests/testData/inspection/defaultFileTemplateUsage/defaultFile/src/x/X.java +++ b/java/java-tests/testData/inspection/defaultFileTemplateUsage/X.java @@ -1,9 +1,9 @@ package x; import java.io.*; -/** +/** * Created by Alexey on 02.12.2005. - */ + */ public class X implements Runnable{ File f; //kkj lkkl jjkuufdffffjkkjjh kjh kjhj kkjh kjh i k kj kj klj lkj lkj lkjl kj klkl kl { @@ -60,4 +60,3 @@ public class X implements Runnable{ } } } - diff --git a/java/java-tests/testData/inspection/defaultFileTemplateUsage/defaultFile/src/x/X2.java b/java/java-tests/testData/inspection/defaultFileTemplateUsage/X2.java similarity index 60% rename from java/java-tests/testData/inspection/defaultFileTemplateUsage/defaultFile/src/x/X2.java rename to java/java-tests/testData/inspection/defaultFileTemplateUsage/X2.java index 89efeb89d00b..545b6c0de29a 100644 --- a/java/java-tests/testData/inspection/defaultFileTemplateUsage/defaultFile/src/x/X2.java +++ b/java/java-tests/testData/inspection/defaultFileTemplateUsage/X2.java @@ -1,8 +1,8 @@ package x; import java.io.*; -/** +/** * Created by Alexey on 02.12.2005. - */ + */ public class X2 { } diff --git a/java/java-tests/testData/inspection/defaultFileTemplateUsage/defaultFile/src/x/X3.java b/java/java-tests/testData/inspection/defaultFileTemplateUsage/X3.java similarity index 87% rename from java/java-tests/testData/inspection/defaultFileTemplateUsage/defaultFile/src/x/X3.java rename to java/java-tests/testData/inspection/defaultFileTemplateUsage/X3.java index c50dafa29576..a9f45957e068 100644 --- a/java/java-tests/testData/inspection/defaultFileTemplateUsage/defaultFile/src/x/X3.java +++ b/java/java-tests/testData/inspection/defaultFileTemplateUsage/X3.java @@ -5,5 +5,5 @@ import java.io.*; * Created by Alexey on 02.12.2005. * This class represents something important. */ -public class X2 { +public class X3 { } diff --git a/java/java-tests/testData/inspection/defaultFileTemplateUsage/defaultFile/expected.xml b/java/java-tests/testData/inspection/defaultFileTemplateUsage/defaultFile/expected.xml deleted file mode 100644 index 46addf64a834..000000000000 --- a/java/java-tests/testData/inspection/defaultFileTemplateUsage/defaultFile/expected.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - X.java - 4 - Default File Template Usage - Default File template - - - - X2.java - 4 - Default File Template Usage - Default File template - - \ No newline at end of file diff --git a/java/java-tests/testData/inspection/redundantArrayForVarargs/polymorphicSignature/expected.xml b/java/java-tests/testData/inspection/redundantArrayForVarargs/polymorphicSignature/expected.xml new file mode 100644 index 000000000000..5e933496b9cf --- /dev/null +++ b/java/java-tests/testData/inspection/redundantArrayForVarargs/polymorphicSignature/expected.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/java/java-tests/testData/inspection/redundantArrayForVarargs/polymorphicSignature/src/Test.java b/java/java-tests/testData/inspection/redundantArrayForVarargs/polymorphicSignature/src/Test.java new file mode 100644 index 000000000000..b6cd9f28da7f --- /dev/null +++ b/java/java-tests/testData/inspection/redundantArrayForVarargs/polymorphicSignature/src/Test.java @@ -0,0 +1,9 @@ +import java.lang.invoke.MethodHandle; + +public class Test { + + public static void main(String[] args) { + MethodHandle meh = null; + meh.invokeExact(new Object[] {}); + } +} \ 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 e7e236999426..36861062d1a0 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java @@ -107,6 +107,7 @@ public class LightAdvHighlightingJdk7Test extends LightDaemonAnalyzerTestCase { public void testInnerInTypeArguments() { doTest(false, false); } public void testRawSubstitutor() { doTest(false, false); } public void testIncompleteDiamonds() { doTest(false, false); } + public void testResolveConflictDiamonds() { doTest(false, false); } public void testDynamicallyAddIgnoredAnnotations() { ExtensionPoint point = Extensions.getRootArea().getExtensionPoint(ToolExtensionPoints.DEAD_CODE_TOOL); diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewLambdaHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewLambdaHighlightingTest.java index 5f606082970e..416f07e77b22 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewLambdaHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewLambdaHighlightingTest.java @@ -156,6 +156,10 @@ public class NewLambdaHighlightingTest extends LightDaemonAnalyzerTestCase { doTest(); } + public void testPropertiesInsteadOfSiteSubstitutorIfAny() throws Exception { + doTest(); + } + private void doTest() { doTest(false); } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewMethodRefHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewMethodRefHighlightingTest.java index 281cefa64109..57629d86b601 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewMethodRefHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewMethodRefHighlightingTest.java @@ -318,6 +318,10 @@ public class NewMethodRefHighlightingTest extends LightDaemonAnalyzerTestCase { doTest(); } + public void testTypeParametersInitOrder() throws Exception { + doTest(); + } + private void doTest() { doTest(false); } diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/DefaultFileTemplateInspectionTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/DefaultFileTemplateInspectionTest.java deleted file mode 100644 index 0bfd7e0021d5..000000000000 --- a/java/java-tests/testSrc/com/intellij/codeInspection/DefaultFileTemplateInspectionTest.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.intellij.codeInspection; - -import com.intellij.JavaTestUtil; -import com.intellij.codeInspection.defaultFileTemplateUsage.DefaultFileTemplateUsageInspection; -import com.intellij.openapi.projectRoots.Sdk; -import com.intellij.openapi.roots.LanguageLevelProjectExtension; -import com.intellij.pom.java.LanguageLevel; -import com.intellij.testFramework.InspectionTestCase; - -public class DefaultFileTemplateInspectionTest extends InspectionTestCase { - @Override - protected Sdk getTestProjectSdk() { - final Sdk sdk = super.getTestProjectSdk(); - LanguageLevelProjectExtension.getInstance(getProject()).setLanguageLevel(LanguageLevel.JDK_1_7); - return sdk; - } - - @Override - protected String getTestDataPath() { - return JavaTestUtil.getJavaTestDataPath() + "/inspection"; - } - - private void doTest() throws Exception { - doTest("defaultFileTemplateUsage/" + getTestName(true), new DefaultFileTemplateUsageInspection()); - } - - public void testDefaultFile() throws Exception{ - doTest(); - } -} diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/DefaultFileTemplateUsageInspectionTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/DefaultFileTemplateUsageInspectionTest.java new file mode 100644 index 000000000000..3230fa6f1483 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/codeInspection/DefaultFileTemplateUsageInspectionTest.java @@ -0,0 +1,37 @@ +/* + * Copyright 2000-2014 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.codeInspection; + +import com.intellij.JavaTestUtil; +import com.intellij.codeInspection.defaultFileTemplateUsage.DefaultFileTemplateUsageInspection; +import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; + +public class DefaultFileTemplateUsageInspectionTest extends LightCodeInsightFixtureTestCase { + @Override + protected String getTestDataPath() { + return JavaTestUtil.getJavaTestDataPath() + "/inspection/defaultFileTemplateUsage"; + } + + public void testX() { doTest(); } + public void testX2() { doTest(); } + public void testX3() { doTest(); } + public void testRange() { doTest(); } + + public void doTest() { + myFixture.enableInspections(new DefaultFileTemplateUsageInspection()); + myFixture.testHighlighting(true, false, true, getTestName(false) + ".java"); + } +} diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/RedundantArrayForVarargsCallInspectionTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/RedundantArrayForVarargsCallInspectionTest.java index 2b961772e74a..38ceeff5bab3 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/RedundantArrayForVarargsCallInspectionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/RedundantArrayForVarargsCallInspectionTest.java @@ -24,4 +24,5 @@ public class RedundantArrayForVarargsCallInspectionTest extends InspectionTestCa public void testCheckEnumConstant() throws Exception { doTest(); } public void testGeneric() throws Exception { doTest(); } public void testRawArray() throws Exception { doTest(); } + public void testPolymorphicSignature() throws Exception { doTest(); } } diff --git a/jps/model-serialization/src/org/jetbrains/jps/model/serialization/runConfigurations/JpsRunConfigurationSerializer.java b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/runConfigurations/JpsRunConfigurationSerializer.java index b20ddf0ff9ae..796ad663129a 100644 --- a/jps/model-serialization/src/org/jetbrains/jps/model/serialization/runConfigurations/JpsRunConfigurationSerializer.java +++ b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/runConfigurations/JpsRunConfigurationSerializer.java @@ -15,6 +15,7 @@ */ package org.jetbrains.jps.model.serialization.runConfigurations; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.JDOMUtil; import com.intellij.util.containers.hash.HashMap; import org.jdom.Element; @@ -31,6 +32,8 @@ import java.util.Map; * @author nik */ public class JpsRunConfigurationSerializer { + private static final Logger LOG = Logger.getInstance(JpsRunConfigurationSerializer.class); + public static void loadRunConfigurations(@NotNull JpsProject project, @Nullable Element runManagerTag) { Map> serializers = new HashMap>(); for (JpsModelSerializerExtension extension : JpsModelSerializerExtension.getExtensions()) { @@ -50,9 +53,12 @@ public class JpsRunConfigurationSerializer { if (serializer != null) { loadRunConfiguration(name, configurationTag, serializer, project); } - else { + else if (typeId != null) { project.addRunConfiguration(name, new JpsUnknownRunConfigurationType(typeId), JpsElementFactory.getInstance().createDummyElement()); } + else { + LOG.info("Run configuration '" + name + "' wasn't loaded because 'type' attribute is missing"); + } } } diff --git a/jps/model-serialization/testData/run-configurations-dir/.idea/runConfigurations/invalid.xml b/jps/model-serialization/testData/run-configurations-dir/.idea/runConfigurations/invalid.xml new file mode 100644 index 000000000000..7e0f311245cf --- /dev/null +++ b/jps/model-serialization/testData/run-configurations-dir/.idea/runConfigurations/invalid.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/jps/model-serialization/testData/run-configurations/run-configurations.ipr b/jps/model-serialization/testData/run-configurations/run-configurations.ipr index 93c6bd97232b..e20908c8a349 100644 --- a/jps/model-serialization/testData/run-configurations/run-configurations.ipr +++ b/jps/model-serialization/testData/run-configurations/run-configurations.ipr @@ -45,6 +45,8 @@ + + diff --git a/json/src/com/intellij/json/codeinsight/JsonStandardComplianceInspection.java b/json/src/com/intellij/json/codeinsight/JsonStandardComplianceInspection.java index 8c17715d696c..d1c83ec03952 100644 --- a/json/src/com/intellij/json/codeinsight/JsonStandardComplianceInspection.java +++ b/json/src/com/intellij/json/codeinsight/JsonStandardComplianceInspection.java @@ -54,7 +54,9 @@ public class JsonStandardComplianceInspection extends LocalInspectionTool { @Override public void visitComment(PsiComment comment) { if (myWarnAboutComments) { - holder.registerProblem(comment, JsonBundle.message("msg.compliance.problem.comments"), ProblemHighlightType.WEAK_WARNING); + if (JsonStandardComplianceProvider.shouldWarnAboutComment(comment)) { + holder.registerProblem(comment, JsonBundle.message("msg.compliance.problem.comments"), ProblemHighlightType.WEAK_WARNING); + } } } diff --git a/json/src/com/intellij/json/codeinsight/JsonStandardComplianceProvider.java b/json/src/com/intellij/json/codeinsight/JsonStandardComplianceProvider.java new file mode 100644 index 000000000000..996cc82a6867 --- /dev/null +++ b/json/src/com/intellij/json/codeinsight/JsonStandardComplianceProvider.java @@ -0,0 +1,44 @@ +/* + * Copyright 2000-2014 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.json.codeinsight; + +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.psi.PsiComment; +import org.jetbrains.annotations.NotNull; + +/** + * Allows to configure a compliance level for JSON. + * For example, some tools ignore comments in JSON silently when parsing, so there is no need to warn users about it. + */ +public abstract class JsonStandardComplianceProvider { + public static final ExtensionPointName EP_NAME = + ExtensionPointName.create("com.intellij.json.jsonStandardComplianceProvider"); + + public abstract boolean isCommentAllowed(@NotNull PsiComment comment); + + public static boolean shouldWarnAboutComment(@NotNull PsiComment comment) { + JsonStandardComplianceProvider[] providers = EP_NAME.getExtensions(); + if (providers.length == 0) { + return true; + } + for (JsonStandardComplianceProvider provider : providers) { + if (provider.isCommentAllowed(comment)) { + return false; + } + } + return true; + } +} diff --git a/json/src/com/intellij/json/navigation/JsonQualifiedNameProvider.java b/json/src/com/intellij/json/navigation/JsonQualifiedNameProvider.java new file mode 100644 index 000000000000..75d5a3888033 --- /dev/null +++ b/json/src/com/intellij/json/navigation/JsonQualifiedNameProvider.java @@ -0,0 +1,50 @@ +package com.intellij.json.navigation; + +import com.intellij.ide.actions.QualifiedNameProvider; +import com.intellij.json.psi.JsonElement; +import com.intellij.json.psi.JsonProperty; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.EditorModificationUtil; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.PsiElement; +import com.intellij.psi.util.PsiTreeUtil; +import org.jetbrains.annotations.Nullable; + +import java.util.LinkedList; + +/** + * @author Mikhail Golubev + */ +public class JsonQualifiedNameProvider implements QualifiedNameProvider { + @Nullable + @Override + public PsiElement adjustElementToCopy(PsiElement element) { + return element; + } + + @Nullable + @Override + public String getQualifiedName(PsiElement element) { + if (!(element instanceof JsonElement)) { + return null; + } + final LinkedList qualifiers = new LinkedList(); + JsonProperty parentProperty = PsiTreeUtil.getNonStrictParentOfType(element, JsonProperty.class); + while (parentProperty != null) { + qualifiers.addFirst(parentProperty.getName()); + parentProperty = PsiTreeUtil.getParentOfType(parentProperty, JsonProperty.class); + } + return qualifiers.isEmpty() ? null : StringUtil.join(qualifiers, "."); + } + + @Override + public PsiElement qualifiedNameToElement(String fqn, Project project) { + return null; + } + + @Override + public void insertQualifiedName(String fqn, PsiElement element, Editor editor, Project project) { + EditorModificationUtil.insertStringAtCaret(editor, fqn); + } +} diff --git a/json/tests/test/com/intellij/json/JsonNavigationTest.java b/json/tests/test/com/intellij/json/JsonNavigationTest.java new file mode 100644 index 000000000000..1ca4acf83f8d --- /dev/null +++ b/json/tests/test/com/intellij/json/JsonNavigationTest.java @@ -0,0 +1,20 @@ +package com.intellij.json; + +import com.intellij.ide.actions.CopyReferenceAction; +import com.intellij.json.psi.JsonProperty; +import com.intellij.psi.PsiElement; + +/** + * @author Mikhail Golubev + */ +public class JsonNavigationTest extends JsonTestCase { + + // WEB-14048 + public void testCopyReference() { + myFixture.configureByFile("navigation/" + getTestName(false) + ".json"); + final PsiElement element = myFixture.getElementAtCaret(); + assertInstanceOf(element, JsonProperty.class); + final String qualifiedName = CopyReferenceAction.elementToFqn(element); + assertEquals("foo.bar.baz", qualifiedName); + } +} diff --git a/json/tests/testData/navigation/CopyReference.json b/json/tests/testData/navigation/CopyReference.json new file mode 100644 index 000000000000..c5f889219193 --- /dev/null +++ b/json/tests/testData/navigation/CopyReference.json @@ -0,0 +1,11 @@ +{ + "foo": { + "bar": [ + [ + { + "baz": null + } + ] + ] + } +} \ No newline at end of file diff --git a/platform/core-api/src/com/intellij/openapi/util/SimpleModificationTracker.java b/platform/core-api/src/com/intellij/openapi/util/SimpleModificationTracker.java index 9b74576176fb..832ce58167a2 100644 --- a/platform/core-api/src/com/intellij/openapi/util/SimpleModificationTracker.java +++ b/platform/core-api/src/com/intellij/openapi/util/SimpleModificationTracker.java @@ -23,14 +23,14 @@ import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; /** * Created by Max Medvedev on 28/03/14 */ +@Transient public class SimpleModificationTracker implements ModificationTracker { static { // field made public to workaround bug in JDK7 when AtomicIntegerFieldUpdater can't be created for private field, even from within its own class // fixed in JDK8 assert Patches.JDK_BUG_ID_7103570; } - - @Transient + public volatile int myCounter; @Override diff --git a/platform/core-impl/src/com/intellij/psi/impl/source/text/BlockSupportImpl.java b/platform/core-impl/src/com/intellij/psi/impl/source/text/BlockSupportImpl.java index 80d62f72d72b..708a4e2ac1d4 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/source/text/BlockSupportImpl.java +++ b/platform/core-impl/src/com/intellij/psi/impl/source/text/BlockSupportImpl.java @@ -27,6 +27,7 @@ import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.PlainTextLanguage; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Couple; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; @@ -58,7 +59,7 @@ public class BlockSupportImpl extends BlockSupport { project.getMessageBus().connect().subscribe(DocumentBulkUpdateListener.TOPIC, new DocumentBulkUpdateListener.Adapter() { @Override public void updateStarted(@NotNull final Document doc) { - doc.putUserData(DO_NOT_REPARSE_INCREMENTALLY, Boolean.TRUE); + doc.putUserData(DO_NOT_REPARSE_INCREMENTALLY, Boolean.TRUE); } }); } @@ -80,22 +81,34 @@ public class BlockSupportImpl extends BlockSupport { @NotNull final CharSequence newFileText, @NotNull final ProgressIndicator indicator) { final PsiFileImpl fileImpl = (PsiFileImpl)file; - Project project = fileImpl.getProject(); - final FileElement treeFileElement = fileImpl.getTreeElement(); - final CharTable charTable = treeFileElement.getCharTable(); + + final Couple reparseableRoots = findReparseableRoots(fileImpl, changedPsiRange, newFileText); + return reparseableRoots != null + ? mergeTrees(fileImpl, reparseableRoots.first, reparseableRoots.second, indicator) + : makeFullParse(fileImpl.getTreeElement(), newFileText, newFileText.length(), fileImpl, indicator); + } + /** + * This method searches ast node that could be reparsed incrementally and returns pair of target reparseable node and new replacement node. + * Returns null if there is no any chance to make incremental parsing. + */ + @Nullable + public Couple findReparseableRoots(@NotNull PsiFileImpl file, + @NotNull TextRange changedPsiRange, + @NotNull CharSequence newFileText) { + Project project = file.getProject(); + final FileElement fileElement = file.getTreeElement(); + final CharTable charTable = fileElement.getCharTable(); + int lengthShift = newFileText.length() - fileElement.getTextLength(); - final int textLength = newFileText.length(); - int lengthShift = textLength - treeFileElement.getTextLength(); - - if (treeFileElement.getElementType() instanceof ITemplateDataElementType || isTooDeep(file)) { + if (fileElement.getElementType() instanceof ITemplateDataElementType || isTooDeep(file)) { // unable to perform incremental reparse for template data in JSP, or in exceptionally deep trees - return makeFullParse(treeFileElement, newFileText, textLength, fileImpl, indicator); + return null; } - final ASTNode leafAtStart = treeFileElement.findLeafElementAt(Math.max(0, changedPsiRange.getStartOffset() - 1)); - final ASTNode leafAtEnd = treeFileElement.findLeafElementAt(changedPsiRange.getEndOffset()); - ASTNode node = leafAtStart != null && leafAtEnd != null ? TreeUtil.findCommonParent(leafAtStart, leafAtEnd) : treeFileElement; + final ASTNode leafAtStart = fileElement.findLeafElementAt(Math.max(0, changedPsiRange.getStartOffset() - 1)); + final ASTNode leafAtEnd = fileElement.findLeafElementAt(Math.min(changedPsiRange.getEndOffset(), fileElement.getTextLength() - 1)); + ASTNode node = leafAtStart != null && leafAtEnd != null ? TreeUtil.findCommonParent(leafAtStart, leafAtEnd) : fileElement; Language baseLanguage = file.getViewProvider().getBaseLanguage(); while (node != null && !(node instanceof FileElement)) { @@ -117,25 +130,24 @@ public class BlockSupportImpl extends BlockSupport { if (reparseable.isParsable(node.getTreeParent(), newTextStr, baseLanguage, project)) { ASTNode chameleon = reparseable.createNode(newTextStr); if (chameleon != null) { - DummyHolder holder = DummyHolderFactory.createHolder(fileImpl.getManager(), null, node.getPsi(), charTable); + DummyHolder holder = DummyHolderFactory.createHolder(file.getManager(), null, node.getPsi(), charTable); holder.getTreeElement().rawAddChildren((TreeElement)chameleon); if (holder.getTextLength() != newTextStr.length()) { String details = ApplicationManager.getApplication().isInternal() - ? "text=" + newTextStr + "; treeText=" + holder.getText() + ";" - : ""; + ? "text=" + newTextStr + "; treeText=" + holder.getText() + ";" + : ""; LOG.error("Inconsistent reparse: " + details + " type=" + elementType); } - return mergeTrees(fileImpl, node, chameleon, indicator); + return Couple.of(node, chameleon); } } } } node = node.getTreeParent(); } - - return makeFullParse(node, newFileText, textLength, fileImpl, indicator); + return null; } private static void reportInconsistentLength(PsiFile file, CharSequence newFileText, ASTNode node, int start, int end) { @@ -288,7 +300,7 @@ public class BlockSupportImpl extends BlockSupport { }; } - private static boolean isReplaceWholeNode(@NotNull PsiFileImpl fileImpl, @NotNull ASTNode newRoot) throws ReparsedSuccessfullyException{ + private static boolean isReplaceWholeNode(@NotNull PsiFileImpl fileImpl, @NotNull ASTNode newRoot) throws ReparsedSuccessfullyException { final Boolean data = fileImpl.getUserData(DO_NOT_REPARSE_INCREMENTALLY); if (data != null) fileImpl.putUserData(DO_NOT_REPARSE_INCREMENTALLY, null); @@ -308,7 +320,7 @@ public class BlockSupportImpl extends BlockSupport { } public static void sendBeforeChildrenChangeEvent(@NotNull PsiManagerImpl manager, @NotNull PsiElement scope, boolean isGenericChange) { - if(!scope.isPhysical()) { + if (!scope.isPhysical()) { manager.beforeChange(false); return; } @@ -318,7 +330,7 @@ public class BlockSupportImpl extends BlockSupport { TextRange range = scope.getTextRange(); event.setOffset(range == null ? 0 : range.getStartOffset()); event.setOldLength(scope.getTextLength()); - // the "generic" event is being sent on every PSI change. It does not carry any specific info except the fact that "something has changed" + // the "generic" event is being sent on every PSI change. It does not carry any specific info except the fact that "something has changed" event.setGenericChange(isGenericChange); manager.beforeChildrenChange(event); } @@ -327,7 +339,7 @@ public class BlockSupportImpl extends BlockSupport { @NotNull PsiFile scope, int oldLength, boolean isGenericChange) { - if(!scope.isPhysical()) { + if (!scope.isPhysical()) { manager.afterChange(false); return; } diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushLog.java b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushLog.java index b91aa17e04d5..2e1713e05c89 100644 --- a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushLog.java +++ b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushLog.java @@ -127,7 +127,15 @@ public class PushLog extends JPanel implements TypeSafeDataProvider { public void editingStopped(ChangeEvent e) { DefaultMutableTreeNode node = (DefaultMutableTreeNode)myTree.getLastSelectedPathComponent(); if (node != null && node instanceof EditableTreeNode) { - ((EditableTreeNode)node).fireOnChange(); + JComponent editedComponent = (JComponent)node.getUserObject(); + InputVerifier verifier = editedComponent.getInputVerifier(); + if (verifier != null && !verifier.verify(editedComponent)) { + // if invalid and interrupted, then revert + ((EditableTreeNode)node).fireOnCancel(); + } + else { + ((EditableTreeNode)node).fireOnChange(); + } } myTree.firePropertyChange(PushLogTreeUtil.EDIT_MODE_PROP, true, false); } @@ -141,6 +149,8 @@ public class PushLog extends JPanel implements TypeSafeDataProvider { myTree.firePropertyChange(PushLogTreeUtil.EDIT_MODE_PROP, true, false); } }); + // complete editing when interrupt + myTree.setInvokesStopCellEditing(true); myTree.setRootVisible(false); TreeUtil.collapseAll(myTree, 1); final VcsBranchEditorListener linkMouseListener = new VcsBranchEditorListener(myTreeCellRenderer); diff --git a/platform/editor-ui-api/src/com/intellij/ide/ui/UISettings.java b/platform/editor-ui-api/src/com/intellij/ide/ui/UISettings.java index 4a390bc1383b..a366c5bff330 100644 --- a/platform/editor-ui-api/src/com/intellij/ide/ui/UISettings.java +++ b/platform/editor-ui-api/src/com/intellij/ide/ui/UISettings.java @@ -186,7 +186,7 @@ public class UISettings extends SimpleModificationTracker implements PersistentS public static class FontFilter implements SerializationFilter { @Override - public boolean accepts(Accessor accessor, Object bean) { + public boolean accepts(@NotNull Accessor accessor, Object bean) { UISettings settings = (UISettings)bean; return !hasDefaultFontSetting(settings); } diff --git a/platform/editor-ui-api/src/com/intellij/openapi/editor/colors/EditorColors.java b/platform/editor-ui-api/src/com/intellij/openapi/editor/colors/EditorColors.java index ff563a51b97e..17a4ea41eb30 100644 --- a/platform/editor-ui-api/src/com/intellij/openapi/editor/colors/EditorColors.java +++ b/platform/editor-ui-api/src/com/intellij/openapi/editor/colors/EditorColors.java @@ -61,5 +61,7 @@ public interface EditorColors { ColorKey MODIFIED_LINES_COLOR = ColorKey.createColorKey("MODIFIED_LINES_COLOR"); ColorKey DELETED_LINES_COLOR = ColorKey.createColorKey("DELETED_LINES_COLOR"); ColorKey WHITESPACES_MODIFIED_LINES_COLOR = ColorKey.createColorKey("WHITESPACES_MODIFIED_LINES_COLOR"); + ColorKey BORDER_LINES_COLOR = ColorKey.createColorKey("BORDER_LINES_COLOR"); + TextAttributesKey INJECTED_LANGUAGE_FRAGMENT = TextAttributesKey.createTextAttributesKey("INJECTED_LANGUAGE_FRAGMENT"); } diff --git a/platform/icons/src/Logo_welcomeScreen.png b/platform/icons/src/Logo_welcomeScreen.png index 9023c4285eba..c5dbabdd5f63 100644 Binary files a/platform/icons/src/Logo_welcomeScreen.png and b/platform/icons/src/Logo_welcomeScreen.png differ diff --git a/platform/icons/src/Logo_welcomeScreen@2x.png b/platform/icons/src/Logo_welcomeScreen@2x.png index 2ef76b6c829c..4b3b1d6e7eb3 100644 Binary files a/platform/icons/src/Logo_welcomeScreen@2x.png and b/platform/icons/src/Logo_welcomeScreen@2x.png differ diff --git a/platform/icons/src/icons/ide/nextStep@2x.png b/platform/icons/src/icons/ide/nextStep@2x.png index 8968229a6f58..d5be0c3ce6a4 100644 Binary files a/platform/icons/src/icons/ide/nextStep@2x.png and b/platform/icons/src/icons/ide/nextStep@2x.png differ diff --git a/platform/icons/src/icons/ide/nextStepGrayed@2x.png b/platform/icons/src/icons/ide/nextStepGrayed@2x.png index 12f3ee9480c0..ff3d7277ed6b 100644 Binary files a/platform/icons/src/icons/ide/nextStepGrayed@2x.png and b/platform/icons/src/icons/ide/nextStepGrayed@2x.png differ diff --git a/platform/icons/src/icons/ide/nextStepInverted@2x.png b/platform/icons/src/icons/ide/nextStepInverted@2x.png index ca8155765ee7..1ca60fc1f979 100644 Binary files a/platform/icons/src/icons/ide/nextStepInverted@2x.png and b/platform/icons/src/icons/ide/nextStepInverted@2x.png differ diff --git a/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/id/IdIndex.java b/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/id/IdIndex.java index af193348c71b..aed1ccf7277f 100644 --- a/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/id/IdIndex.java +++ b/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/id/IdIndex.java @@ -91,7 +91,7 @@ public class IdIndex extends FileBasedIndexExtension { @Override public int getVersion() { - return 13 + (ourSnapshotMappingsEnabled ? 0xFF:0); // TODO: version should enumerate all word scanner versions and build version upon that set + return 14 + (ourSnapshotMappingsEnabled ? 0xFF:0); // TODO: version should enumerate all word scanner versions and build version upon that set } @Override diff --git a/platform/lang-api/src/com/intellij/execution/configurations/ModuleBasedConfiguration.java b/platform/lang-api/src/com/intellij/execution/configurations/ModuleBasedConfiguration.java index 16b4d3a18c9b..9f640fb6a5b3 100644 --- a/platform/lang-api/src/com/intellij/execution/configurations/ModuleBasedConfiguration.java +++ b/platform/lang-api/src/com/intellij/execution/configurations/ModuleBasedConfiguration.java @@ -24,6 +24,7 @@ import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.WriteExternalException; +import com.intellij.util.xmlb.annotations.Property; import org.jdom.Element; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -39,7 +40,10 @@ import java.util.Set; */ public abstract class ModuleBasedConfiguration extends LocatableConfigurationBase implements Cloneable, ModuleRunConfiguration { private static final Logger LOG = Logger.getInstance("#com.intellij.execution.configurations.ModuleBasedConfiguration"); + + @Property(surroundWithTag = false) private final ConfigurationModule myModule; + @NonNls protected static final String TO_CLONE_ELEMENT_NAME = "toClone"; diff --git a/platform/lang-api/src/com/intellij/execution/configurations/RunConfigurationModule.java b/platform/lang-api/src/com/intellij/execution/configurations/RunConfigurationModule.java index 189696892b66..21292428f11d 100644 --- a/platform/lang-api/src/com/intellij/execution/configurations/RunConfigurationModule.java +++ b/platform/lang-api/src/com/intellij/execution/configurations/RunConfigurationModule.java @@ -26,6 +26,9 @@ import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.JDOMExternalizable; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.xmlb.annotations.Attribute; +import com.intellij.util.xmlb.annotations.Tag; +import com.intellij.util.xmlb.annotations.Transient; import org.jdom.Element; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -33,6 +36,7 @@ import org.jetbrains.annotations.Nullable; import java.util.List; +@Tag("module") public class RunConfigurationModule implements JDOMExternalizable { private static final Logger LOG = Logger.getInstance(RunConfigurationModule.class); @@ -40,7 +44,10 @@ public class RunConfigurationModule implements JDOMExternalizable { @NonNls private static final String ATTRIBUTE = "name"; private Module myModule = null; + + @Attribute("name") private String myModuleName; + private final Project myProject; public RunConfigurationModule(@NotNull Project project) { @@ -81,6 +88,7 @@ public class RunConfigurationModule implements JDOMExternalizable { } @Nullable + @Transient public Module getModule() { if (myModuleName != null) { //caching myModule = findModule(myModuleName); diff --git a/platform/lang-api/src/com/intellij/lang/folding/CustomFoldingSurroundDescriptor.java b/platform/lang-api/src/com/intellij/lang/folding/CustomFoldingSurroundDescriptor.java index 17da710c06c5..41a6cbe66074 100644 --- a/platform/lang-api/src/com/intellij/lang/folding/CustomFoldingSurroundDescriptor.java +++ b/platform/lang-api/src/com/intellij/lang/folding/CustomFoldingSurroundDescriptor.java @@ -26,10 +26,7 @@ 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.PsiDocumentManager; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiWhiteSpace; +import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.psi.codeStyle.CommonCodeStyleSettings; @@ -62,7 +59,7 @@ public class CustomFoldingSurroundDescriptor implements SurroundDescriptor { @NotNull @Override public PsiElement[] getElementsToSurround(PsiFile file, int startOffset, int endOffset) { - if (startOffset >= endOffset - 1) return PsiElement.EMPTY_ARRAY; + if (startOffset >= endOffset) return PsiElement.EMPTY_ARRAY; Commenter commenter = LanguageCommenters.INSTANCE.forLanguage(file.getLanguage()); if (commenter == null || commenter.getLineCommentPrefix() == null) return PsiElement.EMPTY_ARRAY; PsiElement startElement = file.findElementAt(startOffset); @@ -70,18 +67,11 @@ public class CustomFoldingSurroundDescriptor implements SurroundDescriptor { PsiElement endElement = file.findElementAt(endOffset - 1); if (endElement instanceof PsiWhiteSpace) endElement = endElement.getPrevSibling(); if (startElement != null && endElement != null) { - if (startElement.getTextRange().getStartOffset() > endElement.getTextRange().getStartOffset()) return PsiElement.EMPTY_ARRAY; startElement = findClosestParentAfterLineBreak(startElement); if (startElement != null) { endElement = findClosestParentBeforeLineBreak(endElement); if (endElement != null) { - startElement = adjustStartElementIfEndAbsorbed(startElement, endElement); - endElement = adjustEndElementIfStartAbsorbed(startElement, endElement); - final PsiElement commonParent = startElement.getParent(); - if (endElement.getParent() == commonParent) { - if (startElement == endElement) return new PsiElement[]{startElement}; - return new PsiElement[]{startElement, endElement}; - } + return adjustRange(startElement, endElement); } } } @@ -89,46 +79,116 @@ public class CustomFoldingSurroundDescriptor implements SurroundDescriptor { } @NotNull - private static PsiElement adjustEndElementIfStartAbsorbed(@NotNull PsiElement start, @NotNull PsiElement end) { - if (PsiTreeUtil.isAncestor(end, start, false) && start.getTextRange().getEndOffset() == end.getTextRange().getEndOffset()) { - return start; + private static PsiElement[] adjustRange(@NotNull PsiElement start, @NotNull PsiElement end) { + PsiElement newStart = lowerStartElementIfNeeded(start, end); + PsiElement newEnd = lowerEndElementIfNeeded(start, end); + if (newStart == null || newEnd == null) { + return PsiElement.EMPTY_ARRAY; + } + final PsiElement commonParent = findCommonAncestorForWholeRange(newStart, newEnd); + if (commonParent != null) { + return new PsiElement[] {commonParent}; + } + // If either start or end element is the first/last leaf element in its parent, use the parent itself instead + // to prevent selection of clearly illegal ranges like the following: + // [ + // 1 + // ] + // E.g. in case shown, because of that adjustment, closing bracket and number literal won't have the same parent + // and next test will fail. + if (newStart.getParent().getFirstChild() == newStart && newStart.getFirstChild() == null) { + newStart = newStart.getParent(); + } + if (newEnd.getParent().getLastChild() == newEnd && newEnd.getFirstChild() == null) { + newEnd = newEnd.getParent(); + } + if (newStart.getParent() == newEnd.getParent()) { + return new PsiElement[] {newStart, newEnd}; + } + return PsiElement.EMPTY_ARRAY; + } + + @Nullable + private static PsiElement lowerEndElementIfNeeded(@NotNull PsiElement start, @NotNull PsiElement end) { + if (PsiTreeUtil.isAncestor(end, start, true)) { + PsiElement lastChild = end.getLastChild(); + while (lastChild != null && lastChild.getParent() != start.getParent()) { + lastChild = lastChild.getLastChild(); + } + return lastChild; } return end; } - @NotNull - private static PsiElement adjustStartElementIfEndAbsorbed(@NotNull PsiElement start, @NotNull PsiElement end) { - if (PsiTreeUtil.isAncestor(start, end, false) && start.getTextRange().getStartOffset() == end.getTextRange().getStartOffset()) { - return end; + @Nullable + private static PsiElement lowerStartElementIfNeeded(@NotNull PsiElement start, @NotNull PsiElement end) { + if (PsiTreeUtil.isAncestor(start, end, true)) { + PsiElement firstChild = start.getFirstChild(); + while (firstChild != null && firstChild.getParent() != end.getParent()) { + firstChild = firstChild.getFirstChild(); + } + return firstChild; } return start; } @Nullable - private static PsiElement findClosestParentAfterLineBreak(PsiElement element) { - PsiElement parent = element; - while (parent != null) { - PsiElement prev = parent.getPrevSibling(); - while (prev != null && prev.getTextLength() <= 0) { - prev = prev.getPrevSibling(); - } - if (isWhiteSpaceWithLineFeed(prev)) return parent; - parent = parent.getParent(); + private static PsiElement findCommonAncestorForWholeRange(@NotNull PsiElement start, @NotNull PsiElement end) { + final PsiElement parent = PsiTreeUtil.findCommonParent(start, end); + if (parent == null) { + return null; + } + final TextRange parentRange = parent.getTextRange(); + if (parentRange.getStartOffset() == start.getTextRange().getStartOffset() && + parentRange.getEndOffset() == end.getTextRange().getEndOffset()) { + return parent; } return null; } @Nullable - private static PsiElement findClosestParentBeforeLineBreak(PsiElement element) { + private static PsiElement findClosestParentAfterLineBreak(PsiElement element) { PsiElement parent = element; - while (parent != null) { - PsiElement next = parent.getNextSibling(); - if (isWhiteSpaceWithLineFeed(next)) return parent; + while (parent != null && !(parent instanceof PsiFileSystemItem)) { + PsiElement prev = parent.getPrevSibling(); + while (prev != null && prev.getTextLength() <= 0) { + prev = prev.getPrevSibling(); + } + if (firstElementInFile(parent)) { + return parent.getContainingFile(); + } + else if (isWhiteSpaceWithLineFeed(prev)) { + return parent; + } parent = parent.getParent(); } return null; } + private static boolean firstElementInFile(@NotNull PsiElement element) { + return element.getTextOffset() == 0; + } + + @Nullable + private static PsiElement findClosestParentBeforeLineBreak(PsiElement element) { + PsiElement parent = element; + while (parent != null && !(parent instanceof PsiFileSystemItem)) { + final PsiElement next = parent.getNextSibling(); + if (lastElementInFile(parent)) { + return parent.getContainingFile(); + } + else if (isWhiteSpaceWithLineFeed(next)) { + return parent; + } + parent = parent.getParent(); + } + return null; + } + + private static boolean lastElementInFile(@NotNull PsiElement element) { + return element.getTextRange().getEndOffset() == element.getContainingFile().getTextRange().getEndOffset(); + } + private static boolean isWhiteSpaceWithLineFeed(@Nullable PsiElement element) { if (element == null) { return false; diff --git a/platform/lang-impl/src/com/intellij/application/options/colors/FontEditorPreview.java b/platform/lang-impl/src/com/intellij/application/options/colors/FontEditorPreview.java index ddd24150b395..c0587f1fea0a 100644 --- a/platform/lang-impl/src/com/intellij/application/options/colors/FontEditorPreview.java +++ b/platform/lang-impl/src/com/intellij/application/options/colors/FontEditorPreview.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -66,8 +66,9 @@ public class FontEditorPreview implements PreviewPanel{ static void installTrafficLights(@NotNull EditorEx editor) { TrafficLightRenderer renderer = new TrafficLightRenderer(null, null,null){ + @NotNull @Override - protected DaemonCodeAnalyzerStatus getDaemonCodeAnalyzerStatus(boolean fillErrorsCount, SeverityRegistrar severityRegistrar) { + protected DaemonCodeAnalyzerStatus getDaemonCodeAnalyzerStatus(@NotNull SeverityRegistrar severityRegistrar) { DaemonCodeAnalyzerStatus status = new DaemonCodeAnalyzerStatus(); status.errorAnalyzingFinished = true; status.errorCount = new int[]{1, 2}; diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/TrafficLightRenderer.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/TrafficLightRenderer.java index c67af24d8cdc..84255a5e8729 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/TrafficLightRenderer.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/TrafficLightRenderer.java @@ -18,9 +18,12 @@ package com.intellij.codeInsight.daemon.impl; import com.intellij.codeHighlighting.HighlightDisplayLevel; import com.intellij.codeHighlighting.TextEditorHighlightingPass; +import com.intellij.codeInsight.daemon.DaemonBundle; import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer; -import com.intellij.codeInsight.daemon.impl.analysis.HighlightingLevelManager; +import com.intellij.codeInsight.daemon.impl.analysis.FileHighlightingSetting; +import com.intellij.codeInsight.daemon.impl.analysis.HighlightingSettingsPerFile; import com.intellij.icons.AllIcons; +import com.intellij.ide.PowerSaveMode; import com.intellij.lang.Language; import com.intellij.lang.annotation.HighlightSeverity; import com.intellij.openapi.Disposable; @@ -35,14 +38,22 @@ import com.intellij.openapi.editor.impl.EditorMarkupModelImpl; import com.intellij.openapi.editor.impl.event.MarkupModelListener; import com.intellij.openapi.editor.markup.ErrorStripeRenderer; import com.intellij.openapi.editor.markup.RangeHighlighter; +import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.FileViewProvider; +import com.intellij.psi.PsiCompiledElement; import com.intellij.psi.PsiFile; import com.intellij.ui.LayeredIcon; import com.intellij.util.ArrayUtil; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.HashMap; +import com.intellij.util.io.storage.HeavyProcessLatch; import com.intellij.util.ui.UIUtil; +import com.intellij.xml.util.XmlStringUtil; import gnu.trove.TIntArrayList; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -50,20 +61,27 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; -import java.util.ArrayList; -import java.util.Collections; +import java.util.*; import java.util.List; -import java.util.Set; public class TrafficLightRenderer implements ErrorStripeRenderer, Disposable { private static final Icon NO_ANALYSIS_ICON = AllIcons.General.NoAnalysis; - private static final Icon STARING_EYE_ICON = AllIcons.General.InspectionInProgress; private final Project myProject; private final Document myDocument; private final PsiFile myFile; private final DaemonCodeAnalyzerImpl myDaemonCodeAnalyzer; private final SeverityRegistrar mySeverityRegistrar; + Icon icon; + String statistics; + String statusLabel; + String statusExtraLine; + boolean passStatusesVisible; + final Map> passes = ContainerUtil.newLinkedHashMap(); + final Map myProgressToText = new HashMap(); + static final int MAX = 100; + boolean progressBarsEnabled; + Boolean progressBarsCompleted; /** * array filled with number of highlighters with a given severity. @@ -131,8 +149,12 @@ public class TrafficLightRenderer implements ErrorStripeRenderer, Disposable { Disposer.dispose(tlr); } renderer = new TrafficLightRenderer(project, document, file); - Disposer.register(((EditorImpl)editorMarkupModel.getEditor()).getDisposable(), (Disposable)renderer); - editorMarkupModel.setErrorStripeRenderer(renderer); + EditorImpl editor = (EditorImpl)editorMarkupModel.getEditor(); + + if (!editor.isDisposed()) { + Disposer.register(editor.getDisposable(), (Disposable)renderer); + editorMarkupModel.setErrorStripeRenderer(renderer); + } } @Override @@ -153,10 +175,9 @@ public class TrafficLightRenderer implements ErrorStripeRenderer, Disposable { public static class DaemonCodeAnalyzerStatus { public boolean errorAnalyzingFinished; // all passes done public List passStati = Collections.emptyList(); - public String[/*rootsNumber*/] noHighlightingRoots; - public String[/*rootsNumber*/] noInspectionRoots; public int[] errorCount = ArrayUtil.EMPTY_INT_ARRAY; - public boolean enabled = true; + public String reasonWhyDisabled; + public String reasonWhySuspended; public int rootsNumber; @Override @@ -171,30 +192,65 @@ public class TrafficLightRenderer implements ErrorStripeRenderer, Disposable { } } - @Nullable - protected DaemonCodeAnalyzerStatus getDaemonCodeAnalyzerStatus(boolean fillErrorsCount, SeverityRegistrar severityRegistrar) { - if (myFile == null || myProject != null && myProject.isDisposed() || !myDaemonCodeAnalyzer.isHighlightingAvailable(myFile)) return null; + @NotNull + protected DaemonCodeAnalyzerStatus getDaemonCodeAnalyzerStatus(@NotNull SeverityRegistrar severityRegistrar) { + DaemonCodeAnalyzerStatus status = new DaemonCodeAnalyzerStatus(); + if (myFile == null) { + status.reasonWhyDisabled = "No file"; + status.errorAnalyzingFinished = true; + return status; + } + if (myProject != null && myProject.isDisposed()) { + status.reasonWhyDisabled = "Project is disposed"; + status.errorAnalyzingFinished = true; + return status; + } + if (!myDaemonCodeAnalyzer.isHighlightingAvailable(myFile)) { + if (!myFile.isPhysical()) { + status.reasonWhyDisabled = "File is generated"; + status.errorAnalyzingFinished = true; + return status; + } + else if (myFile instanceof PsiCompiledElement) { + status.reasonWhyDisabled = "File is decompiled"; + status.errorAnalyzingFinished = true; + return status; + } + final FileType fileType = myFile.getFileType(); + if (fileType.isBinary()) { + status.reasonWhyDisabled = "File is binary"; + status.errorAnalyzingFinished = true; + return status; + } + status.reasonWhyDisabled = "Highlighting is disabled for this file"; + status.errorAnalyzingFinished = true; + return status; + } - List noInspectionRoots = new ArrayList(); - List noHighlightingRoots = new ArrayList(); FileViewProvider provider = myFile.getViewProvider(); Set languages = provider.getLanguages(); + HighlightingSettingsPerFile levelSettings = HighlightingSettingsPerFile.getInstance(myProject); + boolean shouldHighlight = languages.isEmpty(); for (Language language : languages) { PsiFile root = provider.getPsi(language); - if (!HighlightingLevelManager.getInstance(myProject).shouldHighlight(root)) { - noHighlightingRoots.add(language.getID()); - } - else if (!HighlightingLevelManager.getInstance(myProject).shouldInspect(root)) { - noInspectionRoots.add(language.getID()); - } + FileHighlightingSetting level = levelSettings.getHighlightingSettingForRoot(root); + shouldHighlight |= level != FileHighlightingSetting.SKIP_HIGHLIGHTING; + } + if (!shouldHighlight) { + status.reasonWhyDisabled = "Highlighting level is None"; + status.errorAnalyzingFinished = true; + return status; + } + + if (HeavyProcessLatch.INSTANCE.isRunning()) { + status.reasonWhySuspended = StringUtil.defaultIfEmpty(HeavyProcessLatch.INSTANCE.getRunningOperationName(), "Heavy operation is running"); + status.errorAnalyzingFinished = true; + return status; } - DaemonCodeAnalyzerStatus status = new DaemonCodeAnalyzerStatus(); - status.noInspectionRoots = noInspectionRoots.isEmpty() ? null : ArrayUtil.toStringArray(noInspectionRoots); - status.noHighlightingRoots = noHighlightingRoots.isEmpty() ? null : ArrayUtil.toStringArray(noHighlightingRoots); status.errorCount = errorCount.clone(); status.rootsNumber = languages.size(); - fillDaemonCodeAnalyzerErrorsStatus(status, fillErrorsCount, severityRegistrar); + fillDaemonCodeAnalyzerErrorsStatus(status, severityRegistrar); List passes = myDaemonCodeAnalyzer.getPassesToShowProgressFor(myDocument); status.passStati = passes.isEmpty() ? Collections.emptyList() : new ArrayList(passes.size()); @@ -208,14 +264,13 @@ public class TrafficLightRenderer implements ErrorStripeRenderer, Disposable { status.passStati.add(pass); } status.errorAnalyzingFinished = myDaemonCodeAnalyzer.isAllAnalysisFinished(myFile); - status.enabled = myDaemonCodeAnalyzer.isUpdateByTimerEnabled(); + status.reasonWhySuspended = myDaemonCodeAnalyzer.isUpdateByTimerEnabled() ? null : "Highlighting is paused temporarily"; return status; } - protected void fillDaemonCodeAnalyzerErrorsStatus(final DaemonCodeAnalyzerStatus status, - final boolean fillErrorsCount, - final SeverityRegistrar severityRegistrar) { + protected void fillDaemonCodeAnalyzerErrorsStatus(@NotNull DaemonCodeAnalyzerStatus status, + @NotNull SeverityRegistrar severityRegistrar) { } public final Project getProject() { @@ -230,7 +285,7 @@ public class TrafficLightRenderer implements ErrorStripeRenderer, Disposable { @Override public void paint(Component c, Graphics g, Rectangle r) { - DaemonCodeAnalyzerStatus status = getDaemonCodeAnalyzerStatus(false, mySeverityRegistrar); + DaemonCodeAnalyzerStatus status = getDaemonCodeAnalyzerStatus(mySeverityRegistrar); Icon icon = getIcon(status); int height = icon.getIconHeight(); @@ -240,32 +295,17 @@ public class TrafficLightRenderer implements ErrorStripeRenderer, Disposable { icon.paintIcon(c, g, x, y); } + @NotNull private Icon getIcon(DaemonCodeAnalyzerStatus status) { - if (status == null || status.noHighlightingRoots != null && status.noHighlightingRoots.length == status.rootsNumber) { - return NO_ANALYSIS_ICON; - } - - Icon icon = HighlightDisplayLevel.DO_NOT_SHOW.getIcon(); - for (int i = status.errorCount.length - 1; i >= 0; i--) { - if (status.errorCount[i] != 0) { - icon = mySeverityRegistrar.getRendererIconByIndex(i); - break; - } - } - - if (status.errorAnalyzingFinished) { - if (myProject != null && DumbService.isDumb(myProject)) { - return new LayeredIcon(NO_ANALYSIS_ICON, icon, STARING_EYE_ICON); - } - + updatePanel(status, getProject()); + Icon icon = this.icon; + if (PowerSaveMode.isEnabled() || status.reasonWhySuspended != null || status.reasonWhyDisabled != null) { return icon; } - if (!status.enabled) return NO_ANALYSIS_ICON; - double progress = getOverallProgress(status); TruncatingIcon trunc = new TruncatingIcon(icon, icon.getIconWidth(), (int)(icon.getIconHeight() * progress)); - return new LayeredIcon(NO_ANALYSIS_ICON, trunc, STARING_EYE_ICON); + return new LayeredIcon(NO_ANALYSIS_ICON, trunc); } private static double getOverallProgress(DaemonCodeAnalyzerStatus status) { @@ -277,4 +317,108 @@ public class TrafficLightRenderer implements ErrorStripeRenderer, Disposable { } return limit == 0 ? status.errorAnalyzingFinished ? 1 : 0 : advancement * 1.0 / limit; } + + // return true if panel needs to be rebuilt + boolean updatePanel(@NotNull DaemonCodeAnalyzerStatus status, Project project) { + progressBarsEnabled = false; + progressBarsCompleted = null; + statistics = ""; + passStatusesVisible = (false); + statusLabel = null; + statusExtraLine = null; + + boolean result = false; + if (!status.passStati.equals(new ArrayList(passes.keySet()))) { + // passes set has changed + rebuildPassesMap(status); + result = true; + } + + if (PowerSaveMode.isEnabled()) { + statusLabel = "Code analysis is disabled in power save mode"; + status.errorAnalyzingFinished = true; + icon = AllIcons.Nodes.Plugin; + return result; + } + if (status.reasonWhyDisabled != null) { + statusLabel = "No analysis has been performed"; + statusExtraLine = "(" + status.reasonWhyDisabled + ")"; + passStatusesVisible = (true); + progressBarsCompleted = Boolean.FALSE; + icon = AllIcons.General.NoAnalysis; + return result; + } + if (status.reasonWhySuspended != null) { + statusLabel = "Code analysis has been suspended"; + statusExtraLine = "(" + status.reasonWhySuspended + ")"; + passStatusesVisible = (true); + progressBarsCompleted = Boolean.FALSE; + icon = AllIcons.Actions.Pause; + return result; + } + + Icon icon = HighlightDisplayLevel.DO_NOT_SHOW.getIcon(); + for (int i = status.errorCount.length - 1; i >= 0; i--) { + if (status.errorCount[i] != 0) { + icon = SeverityRegistrar.getSeverityRegistrar(project).getRendererIconByIndex(i); + break; + } + } + + if (status.errorAnalyzingFinished) { + boolean isDumb = DumbService.isDumb(project); + if (isDumb) { + statusLabel = "Shallow analysis completed"; + statusExtraLine = "Complete results will be available after indexing"; + } + else { + statusLabel = DaemonBundle.message("analysis.completed"); + } + progressBarsCompleted = Boolean.TRUE; + } + else { + statusLabel = DaemonBundle.message("performing.code.analysis"); + passStatusesVisible = true; + progressBarsEnabled = true; + progressBarsCompleted = null; + } + + int currentSeverityErrors = 0; + @org.intellij.lang.annotations.Language("HTML") + String text = ""; + for (int i = status.errorCount.length - 1; i >= 0; i--) { + if (status.errorCount[i] > 0) { + final HighlightSeverity severity = SeverityRegistrar.getSeverityRegistrar(project).getSeverityByIndex(i); + String name = + status.errorCount[i] > 1 ? StringUtil.pluralize(severity.getName().toLowerCase()) : severity.getName().toLowerCase(); + text += status.errorAnalyzingFinished + ? DaemonBundle.message("errors.found", status.errorCount[i], name) + : DaemonBundle.message("errors.found.so.far", status.errorCount[i], name); + text += "
"; + currentSeverityErrors += status.errorCount[i]; + } + } + if (currentSeverityErrors == 0) { + text += status.errorAnalyzingFinished + ? DaemonBundle.message("no.errors.or.warnings.found") + : DaemonBundle.message("no.errors.or.warnings.found.so.far") + "
"; + } + statistics = XmlStringUtil.wrapInHtml(text); + + this.icon = icon; + return result; + } + + private void rebuildPassesMap(@NotNull DaemonCodeAnalyzerStatus status) { + passes.clear(); + for (ProgressableTextEditorHighlightingPass pass : status.passStati) { + JProgressBar progressBar = new JProgressBar(0, MAX); + progressBar.setMaximum(TrafficLightRenderer.MAX); + progressBar.putClientProperty("JComponent.sizeVariant", "mini"); + JLabel percLabel = new JLabel(); + percLabel.setText(TrafficProgressPanel.MAX_TEXT); + passes.put(pass, Pair.create(progressBar, percLabel)); + myProgressToText.put(progressBar, percLabel); + } + } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/TrafficProgressPanel.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/TrafficProgressPanel.java index 74cfdd9f434e..aec39b1fb83e 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/TrafficProgressPanel.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/TrafficProgressPanel.java @@ -16,11 +16,8 @@ package com.intellij.codeInsight.daemon.impl; import com.intellij.codeInsight.daemon.DaemonBundle; -import com.intellij.ide.PowerSaveMode; -import com.intellij.lang.annotation.HighlightSeverity; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.TextRange; @@ -32,10 +29,7 @@ import com.intellij.ui.components.panels.NonOpaquePanel; import com.intellij.ui.components.panels.VerticalBox; import com.intellij.ui.components.panels.Wrapper; import com.intellij.util.containers.HashMap; -import com.intellij.util.containers.hash.LinkedHashMap; import com.intellij.util.ui.AwtVisitor; -import com.intellij.xml.util.XmlStringUtil; -import org.intellij.lang.annotations.Language; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -48,16 +42,14 @@ import java.util.Map; * User: cdr */ public class TrafficProgressPanel extends JPanel { - private static final int MAX = 100; - private static final String MAX_TEXT = "100%"; + static final String MAX_TEXT = "100%"; private static final String MIN_TEXT = "0%"; private final JLabel statistics = new JLabel(); - private final Map> passes = new LinkedHashMap>(); private final Map myProgressToText = new HashMap(); private final JLabel statusLabel = new JLabel(); - private final JLabel dumbLabel = new JLabel("Complete results will be available after indexing"); + private final JLabel statusExtraLineLabel = new JLabel(); @NotNull private final TrafficLightRenderer myTrafficLightRenderer; private final JPanel myPassStatuses = new JPanel(); @@ -73,10 +65,10 @@ public class TrafficProgressPanel extends JPanel { setLayout(new BorderLayout()); VerticalBox center = new VerticalBox(); - add(center, BorderLayout.NORTH); + add(center, BorderLayout.NORTH); center.add(statusLabel); - center.add(dumbLabel); + center.add(statusExtraLineLabel); center.add(new Separator()); center.add(Box.createVerticalStrut(6)); @@ -98,19 +90,46 @@ public class TrafficProgressPanel extends JPanel { } }); } - rebuildPassesPanel(fakeStatusLargeEnough); - for (Pair pair : passes.values()) { - JProgressBar bar = pair.first; - bar.setMaximum(MAX); - JLabel label = pair.second; - label.setText(MAX_TEXT); - } center.add(myPassStatusesContainer); add(statistics, BorderLayout.SOUTH); updatePanel(fakeStatusLargeEnough, true); hintHint.initStyle(this, true); + statusLabel.setFont(statusLabel.getFont().deriveFont(Font.BOLD)); + } + + public int getMinWidth() { + return Math.max(Math.max(Math.max(getLabelMinWidth(statistics), getLabelMinWidth(statusExtraLineLabel)), getLabelMinWidth(statusLabel)), getLabelMinWidth(new JLabel("Slow inspections progress report long line"))); + } + + private int getLabelMinWidth(@NotNull JLabel label) { + String text = label.getText(); + Icon icon = label.isEnabled() ? label.getIcon() : label.getDisabledIcon(); + + if ((icon == null) && (StringUtil.isEmpty(text))) { + return 0; + } + + Rectangle paintIconR = new Rectangle(); + Rectangle paintTextR = new Rectangle(); + Rectangle paintViewR = new Rectangle(10000, 10000); + + SwingUtilities.layoutCompoundLabel( + label, + getFontMetrics(getFont()), + text, + icon, + label.getVerticalAlignment(), + label.getHorizontalAlignment(), + label.getVerticalTextPosition(), + label.getHorizontalTextPosition(), + paintViewR, + paintIconR, + paintTextR, + label.getIconTextGap()); + + return paintTextR.width; } private class Separator extends NonOpaquePanel { @@ -137,115 +156,34 @@ public class TrafficProgressPanel extends JPanel { } } - private void rebuildPassesPanel(@Nullable TrafficLightRenderer.DaemonCodeAnalyzerStatus status) { - myPassStatuses.removeAll(); - myPassStatuses.setLayout(new GridBagLayout()); - passes.clear(); - GridBagConstraints c = new GridBagConstraints(); - c.gridy = 0; - c.fill = GridBagConstraints.HORIZONTAL; - if (status != null) { - for (ProgressableTextEditorHighlightingPass pass : status.passStati) { - JLabel label = new JLabel(pass.getPresentableName() + ": "); - label.setHorizontalTextPosition(SwingConstants.RIGHT); - - JProgressBar progressBar = new JProgressBar(0, MAX); - progressBar.putClientProperty("JComponent.sizeVariant", "mini"); - JLabel percLabel = new JLabel(); - passes.put(pass, Pair.create(progressBar, percLabel)); - myProgressToText.put(progressBar, percLabel); - c.gridx = 0; - myPassStatuses.add(label, c); - c.gridx = 1; - myPassStatuses.add(progressBar, c); - c.gridx = 2; - c.weightx = 1; - myPassStatuses.add(percLabel, c); - - c.gridy++; - } - } - - myHintHint.initStyle(myPassStatuses, true); - statusLabel.setFont(statusLabel.getFont().deriveFont(Font.BOLD)); - } - - public void updatePanel(@Nullable TrafficLightRenderer.DaemonCodeAnalyzerStatus status, boolean isFake) { - boolean isDumb = DumbService.isDumb(myTrafficLightRenderer.getProject()); - dumbLabel.setVisible(isDumb); + public void updatePanel(@NotNull TrafficLightRenderer.DaemonCodeAnalyzerStatus status, boolean isFake) { try { - if (PowerSaveMode.isEnabled()) { - statusLabel.setText("Code analysis is disabled in power save mode"); - myPassStatuses.setVisible(false); - statistics.setText(""); - } - else if (status == null || status.noHighlightingRoots != null && status.noHighlightingRoots.length == status.rootsNumber) { - statusLabel.setText(DaemonBundle.message("analysis.hasnot.been.run")); - myPassStatuses.setVisible(true); - setPassesEnabled(false, Boolean.FALSE); - statistics.setText(""); - } - else if (status.errorAnalyzingFinished) { - if (isDumb) { - statusLabel.setText("Shallow analysis completed"); - } - else { - statusLabel.setText(DaemonBundle.message("analysis.completed")); - } - myPassStatuses.setVisible(true); - setPassesEnabled(false, Boolean.TRUE); - } - else if (!status.enabled) { - statusLabel.setText("Code analysis has been suspended"); - myPassStatuses.setVisible(true); - setPassesEnabled(false, Boolean.FALSE); - statistics.setText(""); + boolean needRebuild = myTrafficLightRenderer.updatePanel(status, myTrafficLightRenderer.getProject()); + statusLabel.setText(myTrafficLightRenderer.statusLabel); + if (myTrafficLightRenderer.statusExtraLine == null) { + statusExtraLineLabel.setVisible(false); } else { - statusLabel.setText(DaemonBundle.message("performing.code.analysis")); - myPassStatuses.setVisible(true); - setPassesEnabled(true, null); + statusExtraLineLabel.setText(myTrafficLightRenderer.statusExtraLine); + statusExtraLineLabel.setVisible(true); } + myPassStatuses.setVisible(myTrafficLightRenderer.passStatusesVisible); + statistics.setText(myTrafficLightRenderer.statistics); + resetProgressBars(myTrafficLightRenderer.progressBarsEnabled, myTrafficLightRenderer.progressBarsCompleted); - - if (status == null || - !status.passStati.equals(new ArrayList(passes.keySet()))) { + if (needRebuild) { // passes set has changed - rebuildPassesPanel(status); + rebuildPassesProgress(status); } - if (status != null) { - for (ProgressableTextEditorHighlightingPass pass : status.passStati) { - double progress = pass.getProgress(); - Pair pair = passes.get(pass); - JProgressBar progressBar = pair.first; - int percent = (int)Math.round(progress * MAX); - progressBar.setValue(percent); - JLabel percentage = pair.second; - percentage.setText(percent + "%"); - } - - int currentSeverityErrors = 0; - @Language("HTML") - String text = ""; - for (int i = status.errorCount.length - 1; i >= 0; i--) { - if (status.errorCount[i] > 0) { - final HighlightSeverity severity = SeverityRegistrar.getSeverityRegistrar(myTrafficLightRenderer.getProject()).getSeverityByIndex(i); - String name = - status.errorCount[i] > 1 ? StringUtil.pluralize(severity.getName().toLowerCase()) : severity.getName().toLowerCase(); - text += status.errorAnalyzingFinished - ? DaemonBundle.message("errors.found", status.errorCount[i], name) - : DaemonBundle.message("errors.found.so.far", status.errorCount[i], name); - text += "
"; - currentSeverityErrors += status.errorCount[i]; - } - } - if (currentSeverityErrors == 0) { - text += status.errorAnalyzingFinished - ? DaemonBundle.message("no.errors.or.warnings.found") - : DaemonBundle.message("no.errors.or.warnings.found.so.far") + "
"; - } - statistics.setText(XmlStringUtil.wrapInHtml(text)); + for (ProgressableTextEditorHighlightingPass pass : status.passStati) { + double progress = pass.getProgress(); + Pair pair = myTrafficLightRenderer.passes.get(pass); + JProgressBar progressBar = pair.first; + int percent = (int)Math.round(progress * TrafficLightRenderer.MAX); + progressBar.setValue(percent); + JLabel percentage = pair.second; + percentage.setText(percent + "%"); } } finally { @@ -259,7 +197,7 @@ public class TrafficProgressPanel extends JPanel { } } - private void setPassesEnabled(final boolean enabled, @Nullable final Boolean completed) { + private void resetProgressBars(final boolean enabled, @Nullable final Boolean completed) { new AwtVisitor(myPassStatuses) { @Override public boolean visit(Component component) { @@ -268,7 +206,7 @@ public class TrafficProgressPanel extends JPanel { progress.setEnabled(enabled); if (completed != null) { if (completed) { - progress.setValue(MAX); + progress.setValue(TrafficLightRenderer.MAX); myProgressToText.get(progress).setText(MAX_TEXT); } else { @@ -281,4 +219,33 @@ public class TrafficProgressPanel extends JPanel { } }; } + + private void rebuildPassesProgress(@NotNull TrafficLightRenderer.DaemonCodeAnalyzerStatus status) { + myPassStatuses.removeAll(); + myPassStatuses.setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.gridy = 0; + c.fill = GridBagConstraints.HORIZONTAL; + for (ProgressableTextEditorHighlightingPass pass : status.passStati) { + JLabel label = new JLabel(pass.getPresentableName() + ": "); + label.setHorizontalTextPosition(SwingConstants.RIGHT); + + Pair pair = myTrafficLightRenderer.passes.get(pass); + JProgressBar progressBar = pair.getFirst(); + progressBar.putClientProperty("JComponent.sizeVariant", "mini"); + JLabel percLabel = pair.getSecond(); + myProgressToText.put(progressBar, percLabel); + c.gridx = 0; + myPassStatuses.add(label, c); + c.gridx = 1; + myPassStatuses.add(progressBar, c); + c.gridx = 2; + c.weightx = 1; + myPassStatuses.add(percLabel, c); + + c.gridy++; + } + + myHintHint.initStyle(myPassStatuses, true); + } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/TrafficTooltipRendererImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/TrafficTooltipRendererImpl.java index 22eebb5e880d..55bf221973df 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/TrafficTooltipRendererImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/TrafficTooltipRendererImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -48,7 +48,7 @@ public class TrafficTooltipRendererImpl extends ComparableObject.Impl implements public void repaintTooltipWindow() { if (myPanel != null) { SeverityRegistrar severityRegistrar = SeverityRegistrar.getSeverityRegistrar(myTrafficLightRenderer.getProject()); - TrafficLightRenderer.DaemonCodeAnalyzerStatus status = myTrafficLightRenderer.getDaemonCodeAnalyzerStatus(true, severityRegistrar); + TrafficLightRenderer.DaemonCodeAnalyzerStatus status = myTrafficLightRenderer.getDaemonCodeAnalyzerStatus(severityRegistrar); myPanel.updatePanel(status, false); } } @@ -57,7 +57,8 @@ public class TrafficTooltipRendererImpl extends ComparableObject.Impl implements public LightweightHint show(@NotNull Editor editor, @NotNull Point p, boolean alignToRight, @NotNull TooltipGroup group, @NotNull HintHint hintHint) { myTrafficLightRenderer = (TrafficLightRenderer)((EditorMarkupModelImpl)editor.getMarkupModel()).getErrorStripeRenderer(); myPanel = new TrafficProgressPanel(myTrafficLightRenderer, editor, hintHint); - LineTooltipRenderer.correctLocation(editor, myPanel, p, alignToRight, false, -1); + repaintTooltipWindow(); + LineTooltipRenderer.correctLocation(editor, myPanel, p, alignToRight, true, myPanel.getMinWidth()); LightweightHint hint = new LightweightHint(myPanel); HintManagerImpl hintManager = (HintManagerImpl)HintManager.getInstance(); @@ -72,7 +73,6 @@ public class TrafficTooltipRendererImpl extends ComparableObject.Impl implements onHide.run(); } }); - repaintTooltipWindow(); return hint; } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/hint/ImplementationViewComponent.java b/platform/lang-impl/src/com/intellij/codeInsight/hint/ImplementationViewComponent.java index b83d832f8348..38063e097f0d 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/hint/ImplementationViewComponent.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/hint/ImplementationViewComponent.java @@ -39,6 +39,7 @@ import com.intellij.openapi.util.Comparing; import com.intellij.openapi.vcs.FileStatusManager; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtilCore; import com.intellij.ui.IdeBorderFactory; import com.intellij.ui.ListCellRendererWrapper; @@ -329,12 +330,26 @@ public class ImplementationViewComponent extends JPanel { if (element instanceof PsiNamedElement) { names.add(((PsiNamedElement)element).getName()); } + if (names.size() > 1) { + break; + } } + for (PsiElement element : elements) { PsiFile file = getContainingFile(element); if (file == null) continue; - final PsiElement parent = element.getParent(); - files.add(new FileDescriptor(file, names.size() > 1 || parent == file ? element : parent)); + if (names.size() > 1) { + files.add(new FileDescriptor(file, element)); + } + else { + final PsiElement parent = PsiTreeUtil.getStubOrPsiParent(element); + if (parent == file) { + files.add(new FileDescriptor(file, element)); + } + else { + files.add(new FileDescriptor(file, parent)); + } + } candidates.add(element); } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupTypedHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupTypedHandler.java index b13bbb4be33e..dd370f6dfe7f 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupTypedHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupTypedHandler.java @@ -59,18 +59,19 @@ public class LookupTypedHandler extends TypedActionHandlerBase { @Override public void execute(@NotNull Editor originalEditor, char charTyped, @NotNull DataContext dataContext) { final Project project = CommonDataKeys.PROJECT.getData(dataContext); - PsiFile file; + PsiFile file = project == null ? null : PsiUtilBase.getPsiFileInEditor(originalEditor, project); - if (project == null - || (file = PsiUtilBase.getPsiFileInEditor(originalEditor, project)) == null - || !CodeInsightUtilBase.prepareEditorForWrite(originalEditor) - || !FileDocumentManager.getInstance().requestWriting(originalEditor.getDocument(), project)) { + if (file == null) { if (myOriginalHandler != null){ myOriginalHandler.execute(originalEditor, charTyped, dataContext); } return; } + if (!CodeInsightUtilBase.prepareEditorForWrite(originalEditor) || !FileDocumentManager.getInstance().requestWriting(originalEditor.getDocument(), project)) { + return; + } + CompletionPhase oldPhase = CompletionServiceImpl.getCompletionPhase(); if (oldPhase instanceof CompletionPhase.CommittingDocuments && ((CompletionPhase.CommittingDocuments)oldPhase).isRestartingCompletion()) { assert oldPhase.indicator != null; diff --git a/platform/lang-impl/src/com/intellij/formatting/AbstractBlockAlignmentProcessor.java b/platform/lang-impl/src/com/intellij/formatting/AbstractBlockAlignmentProcessor.java index 4cea2ab53d74..a66eceb51618 100644 --- a/platform/lang-impl/src/com/intellij/formatting/AbstractBlockAlignmentProcessor.java +++ b/platform/lang-impl/src/com/intellij/formatting/AbstractBlockAlignmentProcessor.java @@ -16,8 +16,9 @@ package com.intellij.formatting; import com.intellij.diagnostic.LogMessageEx; +import com.intellij.lang.ASTNode; +import com.intellij.lang.Language; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.util.TextRange; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -50,10 +51,16 @@ public abstract class AbstractBlockAlignmentProcessor implements BlockAlignmentP } if (diff > 0) { - whiteSpace.setSpaces(whiteSpace.getSpaces() + diff, whiteSpace.getIndentSpaces()); + int alignmentSpaces = whiteSpace.getSpaces() + diff; + if (alignmentSpaces > context.maxAlignmentSpaces) { + whiteSpace.setSpaces(1, whiteSpace.getIndentSpaces()); + reportAlignmentProcessingError(context); + return Result.RECURSION_DETECTED; + } + whiteSpace.setSpaces(alignmentSpaces, whiteSpace.getIndentSpaces()); - // Avoid tabulations usage for aligning blocks that are not the first blocks on a line. if (!whiteSpace.containsLineFeeds()) { + // Avoid tabulations usage for aligning blocks that are not the first blocks on a line. whiteSpace.setForceSkipTabulationsUsage(true); } return Result.TARGET_BLOCK_ALIGNED; @@ -127,4 +134,12 @@ public abstract class AbstractBlockAlignmentProcessor implements BlockAlignmentP * @return alignment anchor indent minus current target block indent */ protected abstract int getAlignmentIndentDiff(@NotNull IndentData alignmentAnchorIndent, @NotNull Context context); + + private static void reportAlignmentProcessingError(Context context) { + ASTNode node = context.targetBlock.getNode(); + Language language = node != null ? node.getPsi().getLanguage() : null; + LogMessageEx.error(LOG, + (language != null ? language.getDisplayName() + ": " : "") + + "Can't align block " + context.targetBlock, context.document.getText()); + } } diff --git a/platform/lang-impl/src/com/intellij/formatting/BlockAlignmentProcessor.java b/platform/lang-impl/src/com/intellij/formatting/BlockAlignmentProcessor.java index c1debaab6909..8ac3700f8b08 100644 --- a/platform/lang-impl/src/com/intellij/formatting/BlockAlignmentProcessor.java +++ b/platform/lang-impl/src/com/intellij/formatting/BlockAlignmentProcessor.java @@ -71,13 +71,15 @@ public interface BlockAlignmentProcessor { @NotNull public final Map> alignmentMappings; @NotNull public final Map> backwardShiftedAlignedBlocks; @NotNull public final CommonCodeStyleSettings.IndentOptions indentOptions; + public int maxAlignmentSpaces; public Context(@NotNull Document document, @NotNull AlignmentImpl alignment, @NotNull LeafBlockWrapper targetBlock, @NotNull Map> alignmentMappings, @NotNull Map> backwardShiftedAlignedBlocks, - @NotNull CommonCodeStyleSettings.IndentOptions indentOptions) + @NotNull CommonCodeStyleSettings.IndentOptions indentOptions, + int maxAlignmentSpaces) { this.document = document; this.alignment = alignment; @@ -85,6 +87,7 @@ public interface BlockAlignmentProcessor { this.alignmentMappings = alignmentMappings; this.backwardShiftedAlignedBlocks = backwardShiftedAlignedBlocks; this.indentOptions = indentOptions; + this.maxAlignmentSpaces = maxAlignmentSpaces; } } } diff --git a/platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java b/platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java index 73358455bdcd..d94fabf83baf 100644 --- a/platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java +++ b/platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java @@ -683,7 +683,7 @@ class FormatProcessor { BlockAlignmentProcessor.Context context = new BlockAlignmentProcessor.Context( myDocument, alignment, myCurrentBlock, myAlignmentMappings, myBackwardShiftedAlignedBlocks, - getIndentOptionsToUse(myCurrentBlock, myDefaultIndentOption) + getIndentOptionsToUse(myCurrentBlock, myDefaultIndentOption), myRightMargin ); BlockAlignmentProcessor.Result result = alignmentProcessor.applyAlignment(context); final LeafBlockWrapper offsetResponsibleBlock = alignment.getOffsetRespBlockBefore(myCurrentBlock); diff --git a/platform/lang-impl/src/com/intellij/ide/actions/GoToLinkTargetAction.java b/platform/lang-impl/src/com/intellij/ide/actions/GoToLinkTargetAction.java index 951ff97fb40b..138a102e2dad 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/GoToLinkTargetAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/GoToLinkTargetAction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -24,17 +24,18 @@ import com.intellij.openapi.vfs.VFileProperty; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiFileSystemItem; import com.intellij.psi.PsiManager; +import org.jetbrains.annotations.NotNull; public class GoToLinkTargetAction extends DumbAwareAction { @Override - public void update(AnActionEvent e) { + public void update(@NotNull AnActionEvent e) { Project project = getEventProject(e); VirtualFile file = CommonDataKeys.VIRTUAL_FILE.getData(e.getDataContext()); e.getPresentation().setEnabledAndVisible(project != null && file != null && file.is(VFileProperty.SYMLINK)); } @Override - public void actionPerformed(AnActionEvent e) { + public void actionPerformed(@NotNull AnActionEvent e) { Project project = getEventProject(e); VirtualFile file = CommonDataKeys.VIRTUAL_FILE.getData(e.getDataContext()); if (project != null && file != null && file.is(VFileProperty.SYMLINK)) { diff --git a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java index c5a1db15c2e4..0e595a8d9027 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java @@ -443,7 +443,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA private ActionCallback onFocusLost() { final ActionCallback result = new ActionCallback(); //noinspection SSBasedInspection - SwingUtilities.invokeLater(new Runnable() { + UIUtil.invokeLaterIfNeeded(new Runnable() { @Override public void run() { try { diff --git a/platform/lang-impl/src/com/intellij/ide/hierarchy/HierarchyBrowserManager.java b/platform/lang-impl/src/com/intellij/ide/hierarchy/HierarchyBrowserManager.java index 595907aa5720..905e8a96ceb9 100644 --- a/platform/lang-impl/src/com/intellij/ide/hierarchy/HierarchyBrowserManager.java +++ b/platform/lang-impl/src/com/intellij/ide/hierarchy/HierarchyBrowserManager.java @@ -17,11 +17,11 @@ package com.intellij.ide.hierarchy; import com.intellij.icons.AllIcons; +import com.intellij.ide.actions.ToggleToolbarAction; import com.intellij.ide.impl.ContentManagerWatcher; import com.intellij.openapi.actionSystem.DefaultActionGroup; import com.intellij.openapi.components.*; import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.SimpleToolWindowPanel; import com.intellij.openapi.wm.ToolWindow; import com.intellij.openapi.wm.ToolWindowAnchor; import com.intellij.openapi.wm.ToolWindowId; @@ -52,7 +52,7 @@ public final class HierarchyBrowserManager implements PersistentStateComponent ref = new Ref(); + accessChanges(new Runnable() { + @Override + public void run() { + try { + out.writeInt(myChanges.size()); + for (Change c : myChanges) { + StreamUtil.writeChange(out, c); + } + } + catch (IOException e) { + ref.set(e); + } + } + }); + if (ref.get() != null) throw ref.get(); } public void setName(@Nullable String name) { diff --git a/platform/platform-api/src/com/intellij/openapi/actionSystem/ActionPlaces.java b/platform/platform-api/src/com/intellij/openapi/actionSystem/ActionPlaces.java index aa1248775a21..7c0006c9a3e7 100644 --- a/platform/platform-api/src/com/intellij/openapi/actionSystem/ActionPlaces.java +++ b/platform/platform-api/src/com/intellij/openapi/actionSystem/ActionPlaces.java @@ -38,6 +38,7 @@ public abstract class ActionPlaces { public static final String COMMANDER_POPUP = "CommanderPopup"; public static final String COMMANDER_TOOLBAR = "CommanderToolbar"; public static final String CONTEXT_TOOLBAR = "ContextToolbar"; + public static final String TOOLWINDOW_TITLE = "ToolwindowTitle"; public static final String PROJECT_VIEW_POPUP = "ProjectViewPopup"; public static final String PROJECT_VIEW_TOOLBAR = "ProjectViewToolbar"; diff --git a/platform/platform-api/src/com/intellij/openapi/ui/SimpleToolWindowPanel.java b/platform/platform-api/src/com/intellij/openapi/ui/SimpleToolWindowPanel.java index 7c3e91f78394..6e5af8a92fb2 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/SimpleToolWindowPanel.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/SimpleToolWindowPanel.java @@ -15,23 +15,14 @@ */ package com.intellij.openapi.ui; -import com.intellij.ide.util.PropertiesComponent; -import com.intellij.openapi.actionSystem.*; -import com.intellij.openapi.project.DumbAware; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Conditions; +import com.intellij.openapi.actionSystem.ActionToolbar; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.DataProvider; import com.intellij.openapi.util.Ref; -import com.intellij.openapi.wm.ToolWindow; -import com.intellij.ui.content.Content; -import com.intellij.ui.content.ContentManager; -import com.intellij.ui.content.ContentManagerAdapter; -import com.intellij.ui.content.ContentManagerEvent; import com.intellij.ui.switcher.QuickActionProvider; import com.intellij.util.ui.AwtVisitor; -import com.intellij.util.ui.JBSwingUtilities; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; @@ -172,61 +163,4 @@ public class SimpleToolWindowPanel extends JPanel implements QuickActionProvider } } } - - @NotNull - public static AnAction createToggleToolbarAction(Project project, @NotNull ToolWindow toolWindow) { - return new ToggleToolbarAction(toolWindow, PropertiesComponent.getInstance(project)); - } - - private static class ToggleToolbarAction extends ToggleAction implements DumbAware { - - private final PropertiesComponent myPropertiesComponent; - private final ToolWindow myToolWindow; - - private ToggleToolbarAction(@NotNull ToolWindow toolWindow, @NotNull PropertiesComponent propertiesComponent) { - super("Show Toolbar"); - myPropertiesComponent = propertiesComponent; - myToolWindow = toolWindow; - myToolWindow.getContentManager().addContentManagerListener(new ContentManagerAdapter() { - @Override - public void contentAdded(ContentManagerEvent event) { - JComponent component = event.getContent().getComponent(); - setContentToolbarVisible(component, getVisibilityValue()); - - // support nested content managers, e.g. RunnerLayoutUi as content component - ContentManager contentManager = - component instanceof DataProvider ? PlatformDataKeys.CONTENT_MANAGER.getData((DataProvider)component) : null; - if (contentManager != null) contentManager.addContentManagerListener(this); - } - }); - } - - @Override - public boolean isSelected(AnActionEvent e) { - return getVisibilityValue(); - } - - @Override - public void setSelected(AnActionEvent e, boolean state) { - myPropertiesComponent.setValue(getProperty(), String.valueOf(state), String.valueOf(true)); - for (Content content : myToolWindow.getContentManager().getContents()) { - setContentToolbarVisible(content.getComponent(), state); - } - } - - @NotNull - private String getProperty() { - return myToolWindow.getStripeTitle() + ".ShowToolbar"; - } - - private boolean getVisibilityValue() { - return myPropertiesComponent.getBoolean(getProperty(), true); - } - - private static void setContentToolbarVisible(@NotNull JComponent root, boolean state) { - for (Component c : JBSwingUtilities.uiTraverser().preOrderTraversal(root).filter(Conditions.instanceOf(ActionToolbar.class))) { - c.setVisible(state); - } - } - } } \ No newline at end of file diff --git a/platform/platform-api/src/com/intellij/ui/popup/HintUpdateSupply.java b/platform/platform-api/src/com/intellij/ui/popup/HintUpdateSupply.java index 54b071ab0b94..9f64f809af96 100644 --- a/platform/platform-api/src/com/intellij/ui/popup/HintUpdateSupply.java +++ b/platform/platform-api/src/com/intellij/ui/popup/HintUpdateSupply.java @@ -15,6 +15,8 @@ */ package com.intellij.ui.popup; +import com.intellij.ide.DataManager; +import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.ui.popup.JBPopup; import com.intellij.openapi.util.Key; import com.intellij.psi.PsiElement; @@ -55,12 +57,40 @@ public abstract class HintUpdateSupply { if (supply != null) supply.hideHint(); } + public static void installSimpleHintUpdateSupply(@NotNull final JComponent component) { + HintUpdateSupply supply = new HintUpdateSupply(component) { + @Nullable + @Override + protected PsiElement getPsiElementForHint(@Nullable Object selectedValue) { + return selectedValue instanceof PsiElement ? (PsiElement)selectedValue : + CommonDataKeys.PSI_ELEMENT.getData(DataManager.getInstance().getDataContext(component)); + } + }; + if (component instanceof JList) supply.installListListener((JList)component); + if (component instanceof JTree) supply.installTreeListener((JTree)component); + if (component instanceof JTable) supply.installTableListener((JTable)component); + } + protected HintUpdateSupply(@NotNull JComponent component) { installSupply(component); } - public HintUpdateSupply(@NotNull final JBTable table) { + public HintUpdateSupply(@NotNull JBTable table) { installSupply(table); + installTableListener(table); + } + + public HintUpdateSupply(@NotNull Tree tree) { + installSupply(tree); + installTreeListener(tree); + } + + public HintUpdateSupply(@NotNull JBList list) { + installSupply(list); + installListListener(list); + } + + protected void installTableListener(@NotNull final JTable table) { ListSelectionListener listener = new ListSelectionListener() { @Override public void valueChanged(final ListSelectionEvent e) { @@ -80,8 +110,7 @@ public abstract class HintUpdateSupply { table.getColumnModel().getSelectionModel().addListSelectionListener(listener); } - public HintUpdateSupply(@NotNull final Tree tree) { - installSupply(tree); + protected void installTreeListener(@NotNull final JTree tree) { tree.addTreeSelectionListener(new TreeSelectionListener() { @Override public void valueChanged(final TreeSelectionEvent e) { @@ -98,8 +127,7 @@ public abstract class HintUpdateSupply { }); } - public HintUpdateSupply(@NotNull final JBList list) { - installSupply(list); + protected void installListListener(@NotNull final JList list) { list.addListSelectionListener(new ListSelectionListener() { @Override public void valueChanged(final ListSelectionEvent e) { diff --git a/platform/platform-api/src/com/intellij/util/ui/ButtonlessScrollBarUI.java b/platform/platform-api/src/com/intellij/util/ui/ButtonlessScrollBarUI.java index a816efde21c5..a8d7bb981ab4 100644 --- a/platform/platform-api/src/com/intellij/util/ui/ButtonlessScrollBarUI.java +++ b/platform/platform-api/src/com/intellij/util/ui/ButtonlessScrollBarUI.java @@ -275,14 +275,8 @@ public class ButtonlessScrollBarUI extends BasicScrollBarUI { super.setThumbBounds(x, y, width, height); } else { - /* If the thumbs bounds haven't changed, we're done. - */ - if ((thumbRect.x == x) && - (thumbRect.y == y) && - (thumbRect.width == width) && - (thumbRect.height == height)) { - return; - } + // We want to repaint whole scrollbar even if thumb wasn't moved (on small scroll of a big panel) + // Even if scrollbar wasn't changed itself, myRepaintCallback could need repaint /* Update thumbRect, and repaint the union of x,y,w,h and * the old thumbRect. diff --git a/platform/platform-impl/src/com/intellij/ide/actions/OpenProjectFileChooserDescriptor.java b/platform/platform-impl/src/com/intellij/ide/actions/OpenProjectFileChooserDescriptor.java index b462fcbc11ad..b5cecc222169 100644 --- a/platform/platform-impl/src/com/intellij/ide/actions/OpenProjectFileChooserDescriptor.java +++ b/platform/platform-impl/src/com/intellij/ide/actions/OpenProjectFileChooserDescriptor.java @@ -24,6 +24,7 @@ import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.projectImport.ProjectOpenProcessor; +import com.intellij.util.SystemProperties; import org.jetbrains.annotations.NotNull; import javax.swing.*; @@ -34,6 +35,7 @@ import javax.swing.*; */ public class OpenProjectFileChooserDescriptor extends FileChooserDescriptor { private static final Icon ourProjectIcon = IconLoader.getIcon(ApplicationInfoEx.getInstanceEx().getSmallIconUrl()); + private static final boolean ourCanInspectDirs = SystemProperties.getBooleanProperty("idea.chooser.lookup.for.project.dirs", true); public OpenProjectFileChooserDescriptor(boolean chooseFiles) { super(chooseFiles, true, chooseFiles, chooseFiles, false, false); @@ -64,15 +66,14 @@ public class OpenProjectFileChooserDescriptor extends FileChooserDescriptor { } private static boolean canInspectDirectory(VirtualFile file) { - if (file.getParent() == null) return false; - VirtualFile home = VfsUtil.getUserHomeDir(); - if (home == null) return false; // unnatural situation - VirtualFile homes = home.getParent(); - if (homes == null) return false; // another one - if (homes.equals(file.getParent()) || VfsUtilCore.isAncestor(file, homes, false)) return false; - - return true; + if (home == null || VfsUtilCore.isAncestor(file, home, false)) { + return false; + } + if (ourCanInspectDirs || VfsUtilCore.isAncestor(home, file, true)) { + return true; + } + return false; } private static Icon getImporterIcon(VirtualFile file) { diff --git a/platform/platform-impl/src/com/intellij/ide/actions/SwitcherToolWindowsListRenderer.java b/platform/platform-impl/src/com/intellij/ide/actions/SwitcherToolWindowsListRenderer.java index 52aada754cba..7aed887c254b 100644 --- a/platform/platform-impl/src/com/intellij/ide/actions/SwitcherToolWindowsListRenderer.java +++ b/platform/platform-impl/src/com/intellij/ide/actions/SwitcherToolWindowsListRenderer.java @@ -53,11 +53,11 @@ class SwitcherToolWindowsListRenderer extends ColoredListCellRenderer { final String name; String stripeTitle = tw.getStripeTitle(); - if (myPinned) { + String shortcut = shortcuts.get(tw); + if (myPinned || shortcut == null) { name = stripeTitle; - } - else { - append(shortcuts.get(tw), new SimpleTextAttributes(SimpleTextAttributes.STYLE_UNDERLINE, null)); + } else { + append(shortcut, new SimpleTextAttributes(SimpleTextAttributes.STYLE_UNDERLINE, null)); name = ": " + stripeTitle; } diff --git a/platform/platform-impl/src/com/intellij/ide/actions/ToggleToolbarAction.java b/platform/platform-impl/src/com/intellij/ide/actions/ToggleToolbarAction.java new file mode 100644 index 000000000000..f2ca56055989 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/ide/actions/ToggleToolbarAction.java @@ -0,0 +1,151 @@ +/* + * Copyright 2000-2014 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.ide.actions; + +import com.intellij.ide.util.PropertiesComponent; +import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.project.DumbAware; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.wm.ToolWindow; +import com.intellij.ui.content.Content; +import com.intellij.ui.content.ContentManager; +import com.intellij.ui.content.ContentManagerAdapter; +import com.intellij.ui.content.ContentManagerEvent; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.ui.JBSwingUtilities; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.util.List; + +/** +* @author gregsh +*/ +public class ToggleToolbarAction extends ToggleAction implements DumbAware { + + @NotNull + public static ActionGroup createToggleToolbarGroup(@NotNull Project project, @NotNull ToolWindow toolWindow) { + return new DefaultActionGroup(new OptionsGroup(toolWindow), + new ToggleToolbarAction(toolWindow, PropertiesComponent.getInstance(project))); + } + + private final PropertiesComponent myPropertiesComponent; + private final ToolWindow myToolWindow; + + ToggleToolbarAction(@NotNull ToolWindow toolWindow, @NotNull PropertiesComponent propertiesComponent) { + super("Show Toolbar"); + myPropertiesComponent = propertiesComponent; + myToolWindow = toolWindow; + myToolWindow.getContentManager().addContentManagerListener(new ContentManagerAdapter() { + @Override + public void contentAdded(ContentManagerEvent event) { + JComponent component = event.getContent().getComponent(); + setContentToolbarVisible(component, getVisibilityValue()); + + // support nested content managers, e.g. RunnerLayoutUi as content component + ContentManager contentManager = + component instanceof DataProvider ? PlatformDataKeys.CONTENT_MANAGER.getData((DataProvider)component) : null; + if (contentManager != null) contentManager.addContentManagerListener(this); + } + }); + } + + @Override + public boolean isSelected(AnActionEvent e) { + return getVisibilityValue(); + } + + @Override + public void setSelected(AnActionEvent e, boolean state) { + myPropertiesComponent.setValue(getProperty(), String.valueOf(state), String.valueOf(true)); + for (Content content : myToolWindow.getContentManager().getContents()) { + setContentToolbarVisible(content.getComponent(), state); + } + } + + @NotNull + private String getProperty() { + return getShowToolbarProperty(myToolWindow); + } + + private boolean getVisibilityValue() { + return myPropertiesComponent.getBoolean(getProperty(), true); + } + + private static void setContentToolbarVisible(@NotNull JComponent root, boolean state) { + for (ActionToolbar toolbar : iterateToolbars(root)) { + toolbar.getComponent().setVisible(state); + } + } + + @NotNull + public static String getShowToolbarProperty(@NotNull ToolWindow window) { + return window.getStripeTitle() + ".ShowToolbar"; + } + + @NotNull + private static Iterable iterateToolbars(JComponent root) { + return JBSwingUtilities.uiTraverser().preOrderTraversal(root).filter(ActionToolbar.class); + } + + private static class OptionsGroup extends ActionGroup { + + private final ToolWindow myToolWindow; + + public OptionsGroup(ToolWindow toolWindow) { + super("View Options", true); + myToolWindow = toolWindow; + } + + @Override + public boolean isPopup() { + // configured in getChildren() + return super.isPopup(); + } + + @Override + public void update(AnActionEvent e) { + e.getPresentation().setVisible(!ActionGroupUtil.isGroupEmpty(this, e)); + } + + @NotNull + @Override + public AnAction[] getChildren(@Nullable AnActionEvent e) { + ContentManager contentManager = myToolWindow.getContentManager(); + Content selectedContent = contentManager.getSelectedContent(); + JComponent contentComponent = selectedContent != null ? selectedContent.getComponent() : null; + if (contentComponent == null) return EMPTY_ARRAY; + List result = ContainerUtil.newSmartList(); + boolean addSeparator = false; + for (final ActionToolbar toolbar : iterateToolbars(contentComponent)) { + JComponent c = toolbar.getComponent(); + if (c.isVisible() || !c.isValid()) continue; + List actions = toolbar.getActions(false); + for (AnAction action : actions) { + if (action instanceof Separator && (addSeparator = true) || !(action instanceof ToggleAction)) continue; + if (addSeparator && !result.isEmpty()) result.add(Separator.getInstance()); + result.add(action); + addSeparator = false; + } + } + boolean popup = result.size() > 3; + setPopup(popup); + if (!popup && !result.isEmpty()) result.add(Separator.getInstance()); + return result.toArray(new AnAction[result.size()]); + } + } +} diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaTextFieldUI.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaTextFieldUI.java index 7cffd25ae46c..9b522b676377 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaTextFieldUI.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaTextFieldUI.java @@ -97,7 +97,7 @@ public class DarculaTextFieldUI extends BasicTextFieldUI { } protected void showSearchPopup() { - final Object value = getComponent().getClientProperty("JTextField.Search.FindPopup"); + final Object value = myTextField.getClientProperty("JTextField.Search.FindPopup"); if (value instanceof JPopupMenu) { final JPopupMenu popup = (JPopupMenu)value; popup.show(getComponent(), getSearchIconCoord().x, getComponent().getHeight()); @@ -168,7 +168,7 @@ public class DarculaTextFieldUI extends BasicTextFieldUI { } } Point p = getSearchIconCoord(); - Icon searchIcon = getComponent().getClientProperty("JTextField.Search.FindPopup") instanceof JPopupMenu ? UIManager.getIcon("TextField.darcula.searchWithHistory.icon") : UIManager.getIcon("TextField.darcula.search.icon"); + Icon searchIcon = myTextField.getClientProperty("JTextField.Search.FindPopup") instanceof JPopupMenu ? UIManager.getIcon("TextField.darcula.searchWithHistory.icon") : UIManager.getIcon("TextField.darcula.search.icon"); if (searchIcon == null) { searchIcon = IconLoader.findIcon("/com/intellij/ide/ui/laf/icons/search.png", DarculaTextFieldUI.class, true); } diff --git a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionToolbarImpl.java b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionToolbarImpl.java index 529d5ba1c62f..e65c6dd0cfe5 100644 --- a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionToolbarImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionToolbarImpl.java @@ -24,31 +24,26 @@ import com.intellij.openapi.actionSystem.ex.ActionButtonLook; import com.intellij.openapi.actionSystem.ex.ActionManagerEx; import com.intellij.openapi.actionSystem.ex.AnActionListener; import com.intellij.openapi.actionSystem.ex.CustomComponentAction; -import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.keymap.Keymap; -import com.intellij.openapi.keymap.KeymapManagerListener; import com.intellij.openapi.keymap.ex.KeymapManagerEx; import com.intellij.openapi.project.DumbAwareRunnable; import com.intellij.openapi.ui.popup.*; import com.intellij.openapi.util.ActionCallback; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Disposer; -import com.intellij.openapi.util.IdRunnable; import com.intellij.openapi.wm.IdeFocusManager; import com.intellij.openapi.wm.WindowManager; import com.intellij.openapi.wm.ex.WindowManagerEx; import com.intellij.ui.ColorUtil; import com.intellij.ui.Gray; import com.intellij.ui.JBColor; -import com.intellij.ui.ScreenUtil; import com.intellij.ui.awt.RelativePoint; import com.intellij.ui.awt.RelativeRectangle; import com.intellij.ui.switcher.SwitchTarget; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.UIUtil; -import com.intellij.util.ui.update.UiNotifyConnector; import org.jetbrains.annotations.NotNull; import javax.swing.*; @@ -96,11 +91,12 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar { private int myOrientation; private final ActionGroup myActionGroup; private final String myPlace; - private final MyKeymapManagerListener myKeymapManagerListener; - private List myNewVisibleActions; protected List myVisibleActions; - private final PresentationFactory myPresentationFactory; + private final PresentationFactory myPresentationFactory = new PresentationFactory(); private final boolean myDecorateButtons; + + private final ToolbarUpdater myUpdater; + /** * @see ActionToolbar#adjustTheSameSize(boolean) */ @@ -109,7 +105,7 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar { private final ActionButtonLook myButtonLook = null; private final ActionButtonLook myMinimalButtonLook = new InplaceActionButtonLook(); private final DataManager myDataManager; - @NotNull protected final ActionManagerEx myActionManager; + protected final ActionManagerEx myActionManager; private Rectangle myAutoPopupRec; @@ -122,7 +118,6 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar { } private ActionButton mySecondaryActionsButton; - private final KeymapManagerEx myKeymapManager; private int myFirstOutsideIndex = -1; private JBPopup myPopup; @@ -131,45 +126,46 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar { private boolean myReservePlaceAutoPopupIcon = true; private boolean myAddSeparatorFirst; - private final WeakTimerListener myWeakTimerListener; - @SuppressWarnings({"FieldCanBeLocal"}) private final ActionToolbarImpl.MyTimerListener myTimerListener; - public ActionToolbarImpl(final String place, + public ActionToolbarImpl(String place, @NotNull final ActionGroup actionGroup, - final boolean horizontal, - DataManager dataManager, + boolean horizontal, + @NotNull DataManager dataManager, @NotNull ActionManagerEx actionManager, - KeymapManagerEx keymapManager) { + @NotNull KeymapManagerEx keymapManager) { this(place, actionGroup, horizontal, false, dataManager, actionManager, keymapManager, false); } - public ActionToolbarImpl(final String place, - @NotNull final ActionGroup actionGroup, - final boolean horizontal, - final boolean decorateButtons, - DataManager dataManager, + + public ActionToolbarImpl(String place, + @NotNull ActionGroup actionGroup, + boolean horizontal, + boolean decorateButtons, + @NotNull DataManager dataManager, @NotNull ActionManagerEx actionManager, - KeymapManagerEx keymapManager) { + @NotNull KeymapManagerEx keymapManager) { this(place, actionGroup, horizontal, decorateButtons, dataManager, actionManager, keymapManager, false); } - public ActionToolbarImpl(final String place, - @NotNull final ActionGroup actionGroup, + public ActionToolbarImpl(String place, + @NotNull ActionGroup actionGroup, final boolean horizontal, final boolean decorateButtons, - DataManager dataManager, + @NotNull DataManager dataManager, @NotNull ActionManagerEx actionManager, - KeymapManagerEx keymapManager, + @NotNull KeymapManagerEx keymapManager, boolean updateActionsNow) { super(null); myActionManager = actionManager; - myKeymapManager = keymapManager; myPlace = place; myActionGroup = actionGroup; - myPresentationFactory = new PresentationFactory(); - myKeymapManagerListener = new MyKeymapManagerListener(); myVisibleActions = new ArrayList(); - myNewVisibleActions = new ArrayList(); myDataManager = dataManager; myDecorateButtons = decorateButtons; + myUpdater = new ToolbarUpdater(actionManager, keymapManager, this) { + @Override + protected void updateActionsImpl(boolean transparentOnly, boolean forced) { + ActionToolbarImpl.this.updateActionsImpl(transparentOnly, forced); + } + }; setLayout(new BorderLayout()); setOrientation(horizontal ? SwingConstants.HORIZONTAL : SwingConstants.VERTICAL); @@ -177,12 +173,8 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar { mySecondaryActions.getTemplatePresentation().setIcon(AllIcons.General.SecondaryGroup); mySecondaryActions.setPopup(true); - updateActions(updateActionsNow, false, false); + myUpdater.updateActions(updateActionsNow, false); - // - keymapManager.addWeakListener(myKeymapManagerListener); - myTimerListener = new MyTimerListener(); - myWeakTimerListener = new WeakTimerListener(actionManager, myTimerListener); // If the panel doesn't handle mouse event then it will be passed to its parent. // It means that if the panel is in sliding mode then the focus goes to the editor // and panel will be automatically hidden. @@ -202,9 +194,7 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar { public void addNotify() { super.addNotify(); ourToolbars.add(this); - myActionManager.addTimerListener(500, myWeakTimerListener); - myActionManager.addTransparentTimerListener(500, myWeakTimerListener); - + // should update action right on the showing, otherwise toolbar may not be displayed at all, // since by default all updates are postponed until frame gets focused. updateActionsImmediately(); @@ -226,10 +216,6 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar { public void removeNotify() { super.removeNotify(); ourToolbars.remove(this); - myActionManager.removeTimerListener(myWeakTimerListener); - myActionManager.removeTransparentTimerListener(myWeakTimerListener); - if (ScreenUtil.isStandardAddRemoveNotify(this)) - myKeymapManager.removeWeakListener(myKeymapManagerListener); } @Override @@ -373,7 +359,11 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar { } private ActionButton createToolbarButton(final AnAction action) { - return createToolbarButton(action, myMinimalMode ? myMinimalButtonLook : myDecorateButtons ? new MacToolbarDecoratorButtonLook() : myButtonLook, myPlace, myPresentationFactory.getPresentation(action), myMinimumButtonSize); + return createToolbarButton( + action, + myMinimalMode ? myMinimalButtonLook : myDecorateButtons ? new MacToolbarDecoratorButtonLook() : myButtonLook, + myPlace, myPresentationFactory.getPresentation(action), + myMinimumButtonSize); } @Override @@ -847,53 +837,6 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar { } } - private final class MyKeymapManagerListener implements KeymapManagerListener { - @Override - public void activeKeymapChanged(final Keymap keymap) { - final int componentCount = getComponentCount(); - for (int i = 0; i < componentCount; i++) { - final Component component = getComponent(i); - if (component instanceof ActionButton) { - ((ActionButton)component).updateToolTipText(); - } - } - } - } - - private final class MyTimerListener implements TimerListener { - - @Override - public ModalityState getModalityState() { - return ModalityState.stateForComponent(ActionToolbarImpl.this); - } - - @Override - public void run() { - if (!isShowing()) { - return; - } - - // do not update when a popup menu is shown (if popup menu contains action which is also in the toolbar, it should not be enabled/disabled) - final MenuSelectionManager menuSelectionManager = MenuSelectionManager.defaultManager(); - final MenuElement[] selectedPath = menuSelectionManager.getSelectedPath(); - if (selectedPath.length > 0) { - return; - } - - // don't update toolbar if there is currently active modal dialog - - final Window window = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusedWindow(); - if (window instanceof Dialog) { - final Dialog dialog = (Dialog)window; - if (dialog.isModal() && !SwingUtilities.isDescendingFrom(ActionToolbarImpl.this, dialog)) { - return; - } - } - - updateActions(false, myActionManager.isTransparentOnlyActionsUpdateNow(), false); - } - } - @Override public void adjustTheSameSize(final boolean value) { if (myAdjustTheSameSize == value) { @@ -927,79 +870,47 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar { @Override public void updateActionsImmediately() { ApplicationManager.getApplication().assertIsDispatchThread(); - updateActions(true, false, false); + myUpdater.updateActions(true, false); } - private void updateActions(boolean now, final boolean transparentOnly, final boolean forced) { - final IdRunnable updateRunnable = new IdRunnable(this) { - @Override - public void run() { - if (!isVisible()) { - return; - } + private void updateActionsImpl(boolean transparentOnly, boolean forced) { + List newVisibleActions = ContainerUtil.newArrayListWithCapacity(myVisibleActions.size()); + DataContext dataContext = getDataContext(); - myNewVisibleActions.clear(); - final DataContext dataContext = getDataContext(); + Utils.expandActionGroup(myActionGroup, newVisibleActions, myPresentationFactory, dataContext, + myPlace, myActionManager, transparentOnly); - Utils.expandActionGroup(myActionGroup, myNewVisibleActions, myPresentationFactory, dataContext, myPlace, myActionManager, transparentOnly); + if (forced || !newVisibleActions.equals(myVisibleActions)) { + boolean shouldRebuildUI = newVisibleActions.isEmpty() || myVisibleActions.isEmpty(); + myVisibleActions = newVisibleActions; - if (forced || !myNewVisibleActions.equals(myVisibleActions)) { - // should rebuild UI + Dimension oldSize = getPreferredSize(); - final boolean changeBarVisibility = myNewVisibleActions.isEmpty() || myVisibleActions.isEmpty(); + removeAll(); + mySecondaryActions.removeAll(); + mySecondaryActionsButton = null; + fillToolBar(myVisibleActions, getLayoutPolicy() == AUTO_LAYOUT_POLICY && myOrientation == SwingConstants.HORIZONTAL); - final List temp = myVisibleActions; - myVisibleActions = myNewVisibleActions; - myNewVisibleActions = temp; + Dimension newSize = getPreferredSize(); - Dimension oldSize = getPreferredSize(); + ((WindowManagerEx)WindowManager.getInstance()).adjustContainerWindow(this, oldSize, newSize); - removeAll(); - mySecondaryActions.removeAll(); - mySecondaryActionsButton = null; - fillToolBar(myVisibleActions, getLayoutPolicy() == AUTO_LAYOUT_POLICY && myOrientation == SwingConstants.HORIZONTAL); - - Dimension newSize = getPreferredSize(); - - if (changeBarVisibility) { - revalidate(); - } - else { - final Container parent = getParent(); - if (parent != null) { - parent.invalidate(); - parent.validate(); - } - } - - ((WindowManagerEx)WindowManager.getInstance()).adjustContainerWindow(ActionToolbarImpl.this, oldSize, newSize); - - repaint(); + if (shouldRebuildUI) { + revalidate(); + } + else { + Container parent = getParent(); + if (parent != null) { + parent.invalidate(); + parent.validate(); } } - }; - if (now) { - updateRunnable.run(); - } else { - final Application app = ApplicationManager.getApplication(); - final IdeFocusManager fm = IdeFocusManager.getInstance(null); - - if (!app.isUnitTestMode() && !app.isHeadlessEnvironment()) { - if (app.isDispatchThread()) { - fm.doWhenFocusSettlesDown(updateRunnable); - } else { - UiNotifyConnector.doWhenFirstShown(this, new Runnable() { - @Override - public void run() { - fm.doWhenFocusSettlesDown(updateRunnable); - } - }); - } - } + repaint(); } } + @Override public boolean hasVisibleActions() { return !myVisibleActions.isEmpty(); @@ -1013,7 +924,7 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar { ApplicationManager.getApplication().invokeLater(new DumbAwareRunnable() { @Override public void run() { - updateActions(false, false, false); + myUpdater.updateActions(false, false); } }, ModalityState.stateForComponent(myTargetComponent)); } @@ -1060,7 +971,7 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar { group = outside; } - PopupToolbar popupToolbar = new PopupToolbar(myPlace, group, true, myDataManager, myActionManager, myKeymapManager, this) { + PopupToolbar popupToolbar = new PopupToolbar(myPlace, group, true, myDataManager, myActionManager, myUpdater.getKeymapManager(), this) { @Override protected void onOtherActionPerformed() { hidePopup(); @@ -1094,7 +1005,7 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar { public Boolean compute() { final boolean toClose = myActionManager.isActionPopupStackEmpty(); if (toClose) { - updateActions(false, false, true); + myUpdater.updateActions(false, true); } return toClose; } @@ -1191,7 +1102,7 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar { Disposer.dispose(myPopup); myPopup = null; - updateActions(false, false, false); + myUpdater.updateActions(false, false); } abstract static class PopupToolbar extends ActionToolbarImpl implements AnActionListener, Disposable { @@ -1264,7 +1175,7 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar { return result; } - private class ActionTarget implements SwitchTarget { + private static class ActionTarget implements SwitchTarget { private final ActionButton myButton; private ActionTarget(ActionButton button) { @@ -1350,11 +1261,11 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar { setLayoutPolicy(AUTO_LAYOUT_POLICY); } - updateActions(false, false, true); + myUpdater.updateActions(false, true); } public void setAddSeparatorFirst(boolean addSeparatorFirst) { myAddSeparatorFirst = addSeparatorFirst; - updateActions(false, false, true); + myUpdater.updateActions(false, true); } } diff --git a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ToolbarUpdater.java b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ToolbarUpdater.java new file mode 100644 index 000000000000..2d219251d549 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ToolbarUpdater.java @@ -0,0 +1,174 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.actionSystem.impl; + +import com.intellij.openapi.actionSystem.TimerListener; +import com.intellij.openapi.actionSystem.ex.ActionManagerEx; +import com.intellij.openapi.application.Application; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; +import com.intellij.openapi.keymap.Keymap; +import com.intellij.openapi.keymap.KeymapManagerListener; +import com.intellij.openapi.keymap.ex.KeymapManagerEx; +import com.intellij.openapi.util.IdRunnable; +import com.intellij.openapi.wm.IdeFocusManager; +import com.intellij.ui.ScreenUtil; +import com.intellij.util.ui.JBSwingUtilities; +import com.intellij.util.ui.update.Activatable; +import com.intellij.util.ui.update.UiNotifyConnector; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.awt.*; + +/** + * @author Konstantin Bulenkov + */ +public abstract class ToolbarUpdater implements Activatable { + private final KeymapManagerListener myKeymapManagerListener; + private final WeakTimerListener myWeakTimerListener; + /** @noinspection FieldCanBeLocal*/ + private final TimerListener myTimerListener; + private final ActionManagerEx myActionManager; + private final KeymapManagerEx myKeymapManager; + private final JComponent myComponent; + + public ToolbarUpdater(@NotNull JComponent component) { + this(ActionManagerEx.getInstanceEx(), KeymapManagerEx.getInstanceEx(), component); + } + + public ToolbarUpdater(@NotNull ActionManagerEx actionManager, @NotNull KeymapManagerEx keymapManager, @NotNull JComponent component) { + new UiNotifyConnector(component, this); + myActionManager = actionManager; + myKeymapManager = keymapManager; + myComponent = component; + myKeymapManagerListener = new MyKeymapManagerListener(); + keymapManager.addWeakListener(myKeymapManagerListener); + myTimerListener = new MyTimerListener(); + myWeakTimerListener = new WeakTimerListener(actionManager, myTimerListener); + } + + @Override + public void showNotify() { + myActionManager.addTimerListener(500, myWeakTimerListener); + myActionManager.addTransparentTimerListener(500, myWeakTimerListener); + } + + @Override + public void hideNotify() { + //noinspection ConstantConditions + if (myActionManager == null) return; // not yet initialized + myActionManager.removeTimerListener(myWeakTimerListener); + myActionManager.removeTransparentTimerListener(myWeakTimerListener); + if (ScreenUtil.isStandardAddRemoveNotify(myComponent)) { + myKeymapManager.removeWeakListener(myKeymapManagerListener); + } + } + + @NotNull + public KeymapManagerEx getKeymapManager() { + return myKeymapManager; + } + + @NotNull + public ActionManagerEx getActionManager() { + return myActionManager; + } + + public void updateActions(boolean now, boolean forced) { + updateActions(now, false, forced); + } + + private void updateActions(boolean now, final boolean transparentOnly, final boolean forced) { + final IdRunnable updateRunnable = new IdRunnable(this) { + @Override + public void run() { + if (!myComponent.isVisible()) { + return; + } + + updateActionsImpl(transparentOnly, forced); + } + }; + + if (now) { + updateRunnable.run(); + } + else { + final Application app = ApplicationManager.getApplication(); + final IdeFocusManager fm = IdeFocusManager.getInstance(null); + + if (!app.isUnitTestMode() && !app.isHeadlessEnvironment()) { + if (app.isDispatchThread()) { + fm.doWhenFocusSettlesDown(updateRunnable); + } + else { + UiNotifyConnector.doWhenFirstShown(myComponent, new Runnable() { + @Override + public void run() { + fm.doWhenFocusSettlesDown(updateRunnable); + } + }); + } + } + } + } + + protected abstract void updateActionsImpl(boolean transparentOnly, boolean forced); + + protected void updateActionTooltips() { + for (ActionButton actionButton : JBSwingUtilities.uiTraverser().preOrderTraversal(myComponent).filter(ActionButton.class)) { + actionButton.updateToolTipText(); + } + } + + private final class MyKeymapManagerListener implements KeymapManagerListener { + @Override + public void activeKeymapChanged(Keymap keymap) { + updateActionTooltips(); + } + } + + private final class MyTimerListener implements TimerListener { + + @Override + public ModalityState getModalityState() { + return ModalityState.stateForComponent(myComponent); + } + + @Override + public void run() { + if (!myComponent.isShowing()) { + return; + } + + // do not update when a popup menu is shown (if popup menu contains action which is also in the toolbar, it should not be enabled/disabled) + MenuSelectionManager menuSelectionManager = MenuSelectionManager.defaultManager(); + MenuElement[] selectedPath = menuSelectionManager.getSelectedPath(); + if (selectedPath.length > 0) { + return; + } + + // don't update toolbar if there is currently active modal dialog + Window window = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusedWindow(); + if (window instanceof Dialog && ((Dialog)window).isModal() && !SwingUtilities.isDescendingFrom(myComponent, window)) { + return; + } + + updateActions(false, myActionManager.isTransparentOnlyActionsUpdateNow(), false); + } + } +} diff --git a/platform/platform-impl/src/com/intellij/openapi/command/impl/DocumentReferenceByNonlocalVirtualFile.java b/platform/platform-impl/src/com/intellij/openapi/command/impl/DocumentReferenceByNonlocalVirtualFile.java new file mode 100644 index 000000000000..101801ee3440 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/openapi/command/impl/DocumentReferenceByNonlocalVirtualFile.java @@ -0,0 +1,48 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.command.impl; + +import com.intellij.openapi.command.undo.DocumentReference; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +class DocumentReferenceByNonlocalVirtualFile implements DocumentReference { + private final VirtualFile myFile; + + DocumentReferenceByNonlocalVirtualFile(@NotNull VirtualFile file) { + myFile = file; + } + + @Override + @Nullable + public Document getDocument() { + return FileDocumentManager.getInstance().getDocument(myFile); + } + + @Override + @NotNull + public VirtualFile getFile() { + return myFile; + } + + @Override + public String toString() { + return myFile.toString(); + } +} diff --git a/platform/platform-impl/src/com/intellij/openapi/command/impl/DocumentReferenceByVirtualFile.java b/platform/platform-impl/src/com/intellij/openapi/command/impl/DocumentReferenceByVirtualFile.java index db56ab7a8fdb..271bf8f84c12 100644 --- a/platform/platform-impl/src/com/intellij/openapi/command/impl/DocumentReferenceByVirtualFile.java +++ b/platform/platform-impl/src/com/intellij/openapi/command/impl/DocumentReferenceByVirtualFile.java @@ -19,7 +19,6 @@ import com.intellij.openapi.command.undo.DocumentReference; import com.intellij.openapi.editor.Document; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.testFramework.LightVirtualFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -33,7 +32,7 @@ public class DocumentReferenceByVirtualFile implements DocumentReference { @Override @Nullable public Document getDocument() { - assert myFile.isValid() || myFile instanceof LightVirtualFile : "should not be called on references to deleted file: " + myFile; + assert myFile.isValid() : "should not be called on references to deleted file: " + myFile; return FileDocumentManager.getInstance().getDocument(myFile); } diff --git a/platform/platform-impl/src/com/intellij/openapi/command/impl/DocumentReferenceManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/command/impl/DocumentReferenceManagerImpl.java index 5f226ed07608..7b98099aebcf 100644 --- a/platform/platform-impl/src/com/intellij/openapi/command/impl/DocumentReferenceManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/command/impl/DocumentReferenceManagerImpl.java @@ -28,7 +28,6 @@ import com.intellij.openapi.vfs.VirtualFileEvent; import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.openapi.vfs.newvfs.NewVirtualFile; import com.intellij.reference.SoftReference; -import com.intellij.testFramework.LightVirtualFile; import com.intellij.util.containers.WeakKeyWeakValueHashMap; import com.intellij.util.containers.WeakValueHashMap; import com.intellij.util.io.fs.FilePath; @@ -46,6 +45,7 @@ public class DocumentReferenceManagerImpl extends DocumentReferenceManager imple private final Map myDocToRef = new WeakKeyWeakValueHashMap(); private static final Key> FILE_TO_REF_KEY = Key.create("FILE_TO_REF_KEY"); + private static final Key FILE_TO_STRONG_REF_KEY = Key.create("FILE_TO_STRONG_REF_KEY"); private final Map myDeletedFilePathToRef = new WeakValueHashMap(); @Override @@ -132,7 +132,16 @@ public class DocumentReferenceManagerImpl extends DocumentReferenceManager imple @Override public DocumentReference create(@NotNull VirtualFile file) { assertInDispatchThread(); - assert file.isValid() || file instanceof LightVirtualFile : "file is invalid: " + file; + + if (!file.isInLocalFileSystem()) { // we treat local files differently from non local because we can undo their deletion + DocumentReference reference = file.getUserData(FILE_TO_STRONG_REF_KEY); + if (reference == null) { + file.putUserData(FILE_TO_STRONG_REF_KEY, reference = new DocumentReferenceByNonlocalVirtualFile(file)); + } + return reference; + } + + assert file.isValid() : "file is invalid: " + file; DocumentReference result = SoftReference.dereference(file.getUserData(FILE_TO_REF_KEY)); if (result == null) { diff --git a/platform/platform-impl/src/com/intellij/openapi/command/impl/UndoRedoStacksHolder.java b/platform/platform-impl/src/com/intellij/openapi/command/impl/UndoRedoStacksHolder.java index 529fddd24a5d..41f49774bcf5 100644 --- a/platform/platform-impl/src/com/intellij/openapi/command/impl/UndoRedoStacksHolder.java +++ b/platform/platform-impl/src/com/intellij/openapi/command/impl/UndoRedoStacksHolder.java @@ -19,8 +19,8 @@ import com.intellij.openapi.command.undo.DocumentReference; import com.intellij.openapi.command.undo.DocumentReferenceManager; import com.intellij.openapi.editor.Document; import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.UserDataHolder; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.testFramework.LightVirtualFile; import com.intellij.util.containers.HashMap; import com.intellij.util.containers.WeakList; import gnu.trove.THashSet; @@ -34,8 +34,11 @@ class UndoRedoStacksHolder { private final boolean myUndo; private final LinkedList myGlobalStack = new LinkedList(); + // strongly reference local files for which we can undo file removal + // document without files and nonlocal files are stored without strong reference private final Map> myDocumentStacks = new HashMap>(); - private final List myDocumentsWithStacks = new WeakList(); + private final WeakList myDocumentsWithStacks = new WeakList(); + private final WeakList myNonlocalVirtualFilesWithStacks = new WeakList(); public UndoRedoStacksHolder(boolean isUndo) { myUndo = isUndo; @@ -43,17 +46,25 @@ class UndoRedoStacksHolder { @NotNull LinkedList getStack(@NotNull DocumentReference r) { - VirtualFile file = r.getFile(); - return file != null && !(file instanceof LightVirtualFile) ? doGetStackForFile(r) : doGetStackForDocument(r); + return r.getFile() != null ? doGetStackForFile(r) : doGetStackForDocument(r); } @NotNull private LinkedList doGetStackForFile(@NotNull DocumentReference r) { - LinkedList result = myDocumentStacks.get(r); - if (result == null) { - result = new LinkedList(); - myDocumentStacks.put(r, result); + LinkedList result; + VirtualFile file = r.getFile(); + + if (!file.isInLocalFileSystem()) { + result = addWeaklyTrackedEmptyStack(file, myNonlocalVirtualFilesWithStacks); } + else { + result = myDocumentStacks.get(r); + if (result == null) { + result = new LinkedList(); + myDocumentStacks.put(r, result); + } + } + return result; } @@ -63,12 +74,15 @@ class UndoRedoStacksHolder { // itself to avoid memory leaks caused by holding stacks of all documents, ever created, here. // And to know, what documents do exist now, we have to maintain weak reference list of them. - Document d = r.getDocument(); - LinkedList result = d.getUserData(STACK_IN_DOCUMENT_KEY); + return addWeaklyTrackedEmptyStack(r.getDocument(), myDocumentsWithStacks); + } + + private LinkedList addWeaklyTrackedEmptyStack(T holder, WeakList allHolders) { + LinkedList result; + result = holder.getUserData(STACK_IN_DOCUMENT_KEY); if (result == null) { - result = new LinkedList(); - d.putUserData(STACK_IN_DOCUMENT_KEY, result); - myDocumentsWithStacks.add(d); + holder.putUserData(STACK_IN_DOCUMENT_KEY, result = new LinkedList()); + allHolders.add(holder); } return result; } @@ -164,15 +178,20 @@ class UndoRedoStacksHolder { } - Set docsToDrop = new THashSet(); - for (Document each : myDocumentsWithStacks) { - LinkedList stack = each.getUserData(STACK_IN_DOCUMENT_KEY); + cleanWeaklyTrackedEmptyStacks(myDocumentsWithStacks); + cleanWeaklyTrackedEmptyStacks(myNonlocalVirtualFilesWithStacks); + } + + private void cleanWeaklyTrackedEmptyStacks(WeakList stackHolders) { + Set holdersToDrop = new THashSet(); + for (T holder : stackHolders) { + LinkedList stack = holder.getUserData(STACK_IN_DOCUMENT_KEY); if (stack != null && stack.isEmpty()) { - each.putUserData(STACK_IN_DOCUMENT_KEY, null); - docsToDrop.add(each); + holder.putUserData(STACK_IN_DOCUMENT_KEY, null); + holdersToDrop.add(holder); } } - myDocumentsWithStacks.removeAll(docsToDrop); + stackHolders.removeAll(holdersToDrop); } private void clearStacksFrom(@NotNull UndoableGroup from) { @@ -217,8 +236,13 @@ class UndoRedoStacksHolder { private void collectLocalAffectedDocuments(@NotNull Collection result) { result.addAll(myDocumentStacks.keySet()); + DocumentReferenceManager documentReferenceManager = DocumentReferenceManager.getInstance(); + for (Document each : myDocumentsWithStacks) { - result.add(DocumentReferenceManager.getInstance().create(each)); + result.add(documentReferenceManager.create(each)); + } + for (VirtualFile each : myNonlocalVirtualFilesWithStacks) { + result.add(documentReferenceManager.create(each)); } } diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/AbstractUpdateDialog.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/AbstractUpdateDialog.java index 7d5456dd53b3..fb3f69fc9c77 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/AbstractUpdateDialog.java +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/AbstractUpdateDialog.java @@ -102,7 +102,7 @@ public abstract class AbstractUpdateDialog extends DialogWrapper { protected void configureMessageArea(@NotNull JEditorPane area) { - configureMessageArea(area, IdeBundle.message("updates.configure.label", ShowSettingsUtil.getSettingsMenuName()), null, null); + configureMessageArea(area, myEnableLink ? IdeBundle.message("updates.configure.label", ShowSettingsUtil.getSettingsMenuName()) : "", null, null); } protected void configureMessageArea(final @NotNull JEditorPane area, @@ -113,7 +113,7 @@ public abstract class AbstractUpdateDialog extends DialogWrapper { UIUtil.getCssFontDeclaration(UIUtil.getLabelFont(), fontColor, null, null) + "" + "" + - (myEnableLink ? messageBody : "") + + messageBody + ""; area.setBackground(UIUtil.getPanelBackground()); diff --git a/platform/platform-impl/src/com/intellij/openapi/vcs/readOnlyHandler/ReadOnlyStatusDialog.java b/platform/platform-impl/src/com/intellij/openapi/vcs/readOnlyHandler/ReadOnlyStatusDialog.java index 84c5d462b803..e5ad2a53fee7 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vcs/readOnlyHandler/ReadOnlyStatusDialog.java +++ b/platform/platform-impl/src/com/intellij/openapi/vcs/readOnlyHandler/ReadOnlyStatusDialog.java @@ -18,6 +18,7 @@ package com.intellij.openapi.vcs.readOnlyHandler; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.registry.Registry; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.VcsBundle; import com.intellij.openapi.vfs.ReadonlyStatusHandler; import com.intellij.ui.CollectionComboBoxModel; @@ -107,11 +108,12 @@ public class ReadOnlyStatusDialog extends OptionsDialog { @Override protected void doCustomize(JList list, String value, int index, boolean selected, boolean hasFocus) { if (value == null) return; + String trimmed = StringUtil.first(value, 50, true); if (value.equals(defaultChangelist)) { - append(value, selected ? SELECTED_BOLD_ATTRIBUTES : BOLD_ATTRIBUTES); + append(trimmed, selected ? SELECTED_BOLD_ATTRIBUTES : BOLD_ATTRIBUTES); } else { - append(value, selected ? SimpleTextAttributes.SELECTED_SIMPLE_CELL_ATTRIBUTES : SimpleTextAttributes.SIMPLE_CELL_ATTRIBUTES); + append(trimmed, selected ? SimpleTextAttributes.SELECTED_SIMPLE_CELL_ATTRIBUTES : SimpleTextAttributes.SIMPLE_CELL_ATTRIBUTES); } } }); diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/InternalDecorator.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/InternalDecorator.java index dbee99dd8035..29f9b96aeb28 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/InternalDecorator.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/InternalDecorator.java @@ -19,9 +19,6 @@ import com.intellij.ide.actions.ResizeToolWindowAction; import com.intellij.idea.ActionsBundle; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.*; -import com.intellij.openapi.keymap.Keymap; -import com.intellij.openapi.keymap.KeymapManagerListener; -import com.intellij.openapi.keymap.ex.KeymapManagerEx; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Queryable; @@ -54,7 +51,7 @@ import java.util.Map; * @author Eugene Belyaev * @author Vladimir Kondratyev */ -public final class InternalDecorator extends JPanel implements Queryable, TypeSafeDataProvider { +public final class InternalDecorator extends JPanel implements Queryable, DataProvider { private Project myProject; private WindowInfoImpl myInfo; @@ -74,7 +71,6 @@ public final class InternalDecorator extends JPanel implements Queryable, TypeSa /** * Catches all event from tool window and modifies decorator's appearance. */ - private final MyKeymapManagerListener myWeakKeymapManagerListener; @NonNls private static final String HIDE_ACTIVE_WINDOW_ACTION_ID = "HideActiveWindow"; @NonNls public static final String TOGGLE_PINNED_MODE_ACTION_ID = "TogglePinnedMode"; @NonNls public static final String TOGGLE_DOCK_MODE_ACTION_ID = "ToggleDockMode"; @@ -124,11 +120,6 @@ public final class InternalDecorator extends JPanel implements Queryable, TypeSa } }; - MyKeymapManagerListener keymapManagerListener = new MyKeymapManagerListener(); - final KeymapManagerEx keymapManager = KeymapManagerEx.getInstanceEx(); - myWeakKeymapManagerListener = keymapManagerListener; - keymapManager.addWeakListener(keymapManagerListener); - init(); apply(info); @@ -192,11 +183,13 @@ public final class InternalDecorator extends JPanel implements Queryable, TypeSa setBorder(new InnerPanelBorder(myToolWindow)); } + @Nullable @Override - public void calcData(DataKey key, DataSink sink) { - if (PlatformDataKeys.TOOL_WINDOW.equals(key)) { - sink.put(PlatformDataKeys.TOOL_WINDOW, myToolWindow); + public Object getData(@NonNls String dataId) { + if (PlatformDataKeys.TOOL_WINDOW.is(dataId)) { + return myToolWindow; } + return null; } final void addInternalDecoratorListener(InternalDecoratorListener l) { @@ -209,7 +202,6 @@ public final class InternalDecorator extends JPanel implements Queryable, TypeSa final void dispose() { removeAll(); - KeymapManagerEx.getInstanceEx().removeWeakListener(myWeakKeymapManagerListener); Disposer.dispose(myHeader); myHeader = null; @@ -502,7 +494,7 @@ public final class InternalDecorator extends JPanel implements Queryable, TypeSa } @Override - public final void actionPerformed(final AnActionEvent e) { + public final void actionPerformed(@NotNull final AnActionEvent e) { fireAnchorChanged(myAnchor); } } @@ -581,7 +573,7 @@ public final class InternalDecorator extends JPanel implements Queryable, TypeSa } @Override - public void update(final AnActionEvent e) { + public void update(@NotNull final AnActionEvent e) { super.update(e); } } @@ -595,12 +587,12 @@ public final class InternalDecorator extends JPanel implements Queryable, TypeSa } @Override - public final void actionPerformed(final AnActionEvent e) { + public final void actionPerformed(@NotNull final AnActionEvent e) { fireHidden(); } @Override - public final void update(final AnActionEvent event) { + public final void update(@NotNull final AnActionEvent event) { final Presentation presentation = event.getPresentation(); presentation.setEnabled(myInfo.isVisible()); } @@ -714,6 +706,7 @@ public final class InternalDecorator extends JPanel implements Queryable, TypeSa } } + @NotNull @Override public Cursor getCursor() { final boolean isVerticalCursor = myInfo.isDocked() ? myInfo.getAnchor().isSplitVertically() : myInfo.getAnchor().isHorizontal(); @@ -721,18 +714,6 @@ public final class InternalDecorator extends JPanel implements Queryable, TypeSa } } - /** - * Updates tooltips. - */ - private final class MyKeymapManagerListener implements KeymapManagerListener { - @Override - public final void activeKeymapChanged(final Keymap keymap) { - if (myHeader != null) { - myHeader.updateTooltips(); - } - } - } - @Override public void putInfo(@NotNull Map info) { info.put("toolWindowTitle", myToolWindow.getTitle()); diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowHeader.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowHeader.java index e84028ead618..101d3ab2762b 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowHeader.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowHeader.java @@ -22,8 +22,7 @@ import com.intellij.ide.ui.UISettingsListener; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.actionSystem.ex.ActionManagerEx; -import com.intellij.openapi.actionSystem.impl.ActionManagerImpl; -import com.intellij.openapi.actionSystem.impl.MenuItemPresentationFactory; +import com.intellij.openapi.actionSystem.impl.*; import com.intellij.openapi.keymap.KeymapUtil; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.util.SystemInfo; @@ -37,7 +36,9 @@ import com.intellij.ui.UIBundle; import com.intellij.ui.components.panels.Wrapper; import com.intellij.ui.tabs.TabsUtil; import com.intellij.util.Producer; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.EmptyIcon; +import com.intellij.util.ui.JBSwingUtilities; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -49,6 +50,7 @@ import java.awt.event.*; import java.awt.image.BufferedImage; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import java.util.List; /** * @author pegov @@ -66,6 +68,11 @@ public abstract class ToolWindowHeader extends JPanel implements Disposable, UIS private final JPanel myButtonPanel; private final ToolWindowHeader.ActionButton myGearButton; + private final PresentationFactory myPresentationFactory = new PresentationFactory(); + private final ToolbarUpdater myUpdater; + private final DefaultActionGroup myActionGroup = new DefaultActionGroup(); + private List myVisibleActions = ContainerUtil.newArrayListWithCapacity(2); + public ToolWindowHeader(final ToolWindowImpl toolWindow, @NotNull WindowInfoImpl info, @NotNull final Producer gearProducer) { setLayout(new BorderLayout()); @@ -103,7 +110,7 @@ public abstract class ToolWindowHeader extends JPanel implements Disposable, UIS myGearButton = new ActionButton(new AnAction() { @Override - public void actionPerformed(AnActionEvent e) { + public void actionPerformed(@NotNull AnActionEvent e) { final InputEvent inputEvent = e.getInputEvent(); final ActionPopupMenu popupMenu = ((ActionManagerImpl)ActionManager.getInstance()) @@ -127,17 +134,15 @@ public abstract class ToolWindowHeader extends JPanel implements Disposable, UIS myHideButton = new ActionButton(new HideAction() { @Override - public void actionPerformed(AnActionEvent e) { + public void actionPerformed(@NotNull AnActionEvent e) { hideToolWindow(); } }, new HideSideAction() { @Override - public void actionPerformed(AnActionEvent e) { + public void actionPerformed(@NotNull AnActionEvent e) { sideHidden(); } - }, - AllIcons.General.HideLeft, null, null - ) { + }, AllIcons.General.HideLeft, null, null) { @Override protected Icon getActiveIcon() { return getHideToolWindowIcon(myToolWindow); @@ -190,6 +195,19 @@ public abstract class ToolWindowHeader extends JPanel implements Disposable, UIS setBorder(BorderFactory.createEmptyBorder(TabsUtil.TABS_BORDER, 1, TabsUtil.TABS_BORDER, 1)); UISettings.getInstance().addUISettingsListener(this, toolWindow.getContentUI()); + myUpdater = new ToolbarUpdater(this) { + @Override + protected void updateActionsImpl(boolean transparentOnly, boolean forced) { + ToolWindowHeader.this.updateActionsImpl(transparentOnly, forced); + } + + @Override + protected void updateActionTooltips() { + for (ActionButton actionButton : JBSwingUtilities.uiTraverser().preOrderTraversal(myButtonPanel).filter(ActionButton.class)) { + actionButton.updateTooltip(); + } + } + }; } @Override @@ -211,32 +229,46 @@ public abstract class ToolWindowHeader extends JPanel implements Disposable, UIS myInfo = null; } - public void updateTooltips() { - if (myHideButton != null) { - myHideButton.updateTooltip(); - } + public void setAdditionalTitleActions(AnAction[] actions) { + myActionGroup.removeAll(); + myActionGroup.addAll(actions); + myUpdater.updateActions(false, true); } - public void setAdditionalTitleActions(AnAction[] actions) { - myButtonPanel.removeAll(); - boolean actionAdded = false; - for (final AnAction action : actions) { - if (action == null) continue; - myButtonPanel.add(new ActionButton(action, action.getTemplatePresentation().getIcon()) { - @Override - protected Icon getActiveHoveredIcon() { - final Icon icon = action.getTemplatePresentation().getHoveredIcon(); - return icon != null ? icon : super.getActiveHoveredIcon(); - } - }); - myButtonPanel.add(Box.createHorizontalStrut(9)); - actionAdded = true; + private void updateActionsImpl(boolean transparentOnly, boolean forced) { + List newVisibleActions = ContainerUtil.newArrayListWithCapacity(myVisibleActions.size()); + DataContext dataContext = DataManager.getInstance().getDataContext(this); + + Utils.expandActionGroup(myActionGroup, newVisibleActions, myPresentationFactory, dataContext, + ActionPlaces.TOOLWINDOW_TITLE, myUpdater.getActionManager(), transparentOnly); + + if (forced || !newVisibleActions.equals(myVisibleActions)) { + myVisibleActions = newVisibleActions; + + myButtonPanel.removeAll(); + boolean actionAdded = false; + for (final AnAction action : newVisibleActions) { + if (action == null) continue; + final Presentation presentation = myPresentationFactory.getPresentation(action); + myButtonPanel.add(new ActionButton(action, presentation.getIcon()) { + @Override + protected Icon getActiveHoveredIcon() { + Icon icon = presentation.getHoveredIcon(); + return icon != null ? icon : super.getActiveHoveredIcon(); + } + }); + myButtonPanel.add(Box.createHorizontalStrut(9)); + actionAdded = true; + } + if (actionAdded) { + myButtonPanel.add(new JLabel(AllIcons.General.Divider)); + myButtonPanel.add(Box.createHorizontalStrut(6)); + } + addDefaultActions(myButtonPanel); + + revalidate(); + repaint(); } - if (actionAdded) { - myButtonPanel.add(new JLabel(AllIcons.General.Divider)); - myButtonPanel.add(Box.createHorizontalStrut(6)); - } - addDefaultActions(myButtonPanel); } private static Icon getHideToolWindowIcon(ToolWindow toolWindow) { @@ -484,7 +516,7 @@ public abstract class ToolWindowHeader extends JPanel implements Disposable, UIS final ActionManagerEx actionManager = ActionManagerEx.getInstanceEx(); InputEvent inputEvent = e.getSource() instanceof InputEvent ? (InputEvent) e.getSource() : null; final AnActionEvent event = - new AnActionEvent(inputEvent, dataContext, ActionPlaces.UNKNOWN, action.getTemplatePresentation(), + new AnActionEvent(inputEvent, dataContext, ActionPlaces.TOOLWINDOW_TITLE, action.getTemplatePresentation(), ActionManager.getInstance(), 0); actionManager.fireBeforeActionPerformed(action, dataContext, event); @@ -542,9 +574,9 @@ public abstract class ToolWindowHeader extends JPanel implements Disposable, UIS getTemplatePresentation().setText(UIBundle.message("tool.window.hideSide.action.name")); } - public abstract void actionPerformed(final AnActionEvent e); + public abstract void actionPerformed(@NotNull final AnActionEvent e); - public final void update(final AnActionEvent event) { + public final void update(@NotNull final AnActionEvent event) { final Presentation presentation = event.getPresentation(); presentation.setEnabled(myInfo.isVisible()); } @@ -558,7 +590,7 @@ public abstract class ToolWindowHeader extends JPanel implements Disposable, UIS getTemplatePresentation().setText(UIBundle.message("tool.window.hide.action.name")); } - public final void update(final AnActionEvent event) { + public final void update(@NotNull final AnActionEvent event) { final Presentation presentation = event.getPresentation(); presentation.setEnabled(myInfo.isVisible()); } diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/InfoAndProgressPanel.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/InfoAndProgressPanel.java index 0aa196baedef..383b74acb4f2 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/InfoAndProgressPanel.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/InfoAndProgressPanel.java @@ -40,6 +40,7 @@ import com.intellij.openapi.wm.StatusBar; import com.intellij.openapi.wm.StatusBarWidget; import com.intellij.openapi.wm.ex.ProgressIndicatorEx; import com.intellij.ui.Gray; +import com.intellij.ui.TabbedPaneWrapper; import com.intellij.ui.awt.RelativePoint; import com.intellij.ui.components.labels.LinkLabel; import com.intellij.ui.components.labels.LinkListener; @@ -414,6 +415,8 @@ public class InfoAndProgressPanel extends JPanel implements CustomStatusBarWidge @NotNull private static Component getAnchor(@NotNull JRootPane pane) { + Component tabWrapper = UIUtil.findComponentOfType(pane, TabbedPaneWrapper.TabWrapper.class); + if (tabWrapper != null) return tabWrapper; Component splitters = UIUtil.findComponentOfType(pane, EditorsSplitters.class); if (splitters != null) return splitters; FileEditorManagerEx ex = FileEditorManagerEx.getInstanceEx(ProjectUtil.guessCurrentProject(pane)); diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/PresentationModeProgressPanel.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/PresentationModeProgressPanel.java index f62910ffd556..d5cf0885b77d 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/PresentationModeProgressPanel.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/PresentationModeProgressPanel.java @@ -23,6 +23,8 @@ import com.intellij.ui.InplaceButton; import com.intellij.ui.TransparentPanel; import com.intellij.util.ui.EmptyIcon; import com.intellij.util.ui.UIUtil; +import com.intellij.util.ui.update.MergingUpdateQueue; +import com.intellij.util.ui.update.Update; import org.jetbrains.annotations.NotNull; import javax.swing.*; @@ -40,6 +42,8 @@ public class PresentationModeProgressPanel { private InplaceButton myCancelButton; private JLabel myText2; private JPanel myRootPanel; + private MergingUpdateQueue myUpdateQueue; + private Update myUpdate; public PresentationModeProgressPanel(InlineProgressIndicator progress) { myProgress = progress; @@ -48,15 +52,17 @@ public class PresentationModeProgressPanel { myText2.setFont(font); myText.setIcon(EmptyIcon.create(1, 16)); myText2.setIcon(EmptyIcon.create(1, 16)); - } - - public void update() { - UIUtil.invokeLaterIfNeeded(new Runnable() { + myUpdateQueue = new MergingUpdateQueue("Presentation Mode Progress", 100, true, null); + myUpdate = new Update("Update UI") { @Override public void run() { updateImpl(); } - }); + }; + } + + public void update() { + myUpdateQueue.queue(myUpdate); } @NotNull diff --git a/platform/platform-impl/src/com/intellij/ui/popup/PopupComponent.java b/platform/platform-impl/src/com/intellij/ui/popup/PopupComponent.java index 1670491b91bf..aa2f1745b03b 100644 --- a/platform/platform-impl/src/com/intellij/ui/popup/PopupComponent.java +++ b/platform/platform-impl/src/com/intellij/ui/popup/PopupComponent.java @@ -140,23 +140,10 @@ public interface PopupComponent { myDialog.setFocusableWindowState(false); } - try { - if (UIUtil.isUnderDarcula()) { - AWTUtilities.setWindowOpaque(myDialog, false); - } - } - catch (Exception ignore) { - } - + AwtPopupWrapper.fixFlickering(myDialog, false); myDialog.setVisible(true); + AwtPopupWrapper.fixFlickering(myDialog, true); - try { - if (UIUtil.isUnderDarcula()) { - AWTUtilities.setWindowOpaque(myDialog, true); - } - } - catch (Exception ignore) { - } SwingUtilities.invokeLater(new Runnable() { public void run() { myDialog.setFocusableWindowState(true); diff --git a/platform/platform-resources-en/src/messages/ActionsBundle.properties b/platform/platform-resources-en/src/messages/ActionsBundle.properties index ad2a2098d8f7..1125e69f3b16 100644 --- a/platform/platform-resources-en/src/messages/ActionsBundle.properties +++ b/platform/platform-resources-en/src/messages/ActionsBundle.properties @@ -1401,7 +1401,7 @@ action.Console.History.Browse.text=Browse History action.Console.History.Browse.description=Browse console history action.RevealIn.description=Highlights the file in platform's file manager action.GoToLinkTarget.text=Go to Link Target -action.GoToLinkTarget.description=Opens a target ot this symlink in the Project View +action.GoToLinkTarget.description=Opens a target of this symlink in the Project View action.Images.EditExternally.text=Jump to External Editor action.Images.EditExternally.description=Open image in external editor diff --git a/platform/platform-resources-en/src/messages/OptionsBundle.properties b/platform/platform-resources-en/src/messages/OptionsBundle.properties index 1906440c7ecc..e2475e4e5b8b 100644 --- a/platform/platform-resources-en/src/messages/OptionsBundle.properties +++ b/platform/platform-resources-en/src/messages/OptionsBundle.properties @@ -126,10 +126,11 @@ options.general.color.descriptor.vcs.annotations=VCS annotations options.general.color.descriptor.vcs.annotations.merged=VCS annotations (merged from) options.general.color.descriptor.tearline=Tear line options.general.color.descriptor.tearline.selected=Selected tear line -options.general.color.descriptor.added.lines=Added lines -options.general.color.descriptor.modified.lines=Modified lines -options.general.color.descriptor.deleted.lines=Deleted lines -options.general.color.descriptor.whitespaces.modified.lines=Minor modified lines +options.general.color.descriptor.added.lines=Added lines in gutter +options.general.color.descriptor.modified.lines=Modified lines in gutter +options.general.color.descriptor.deleted.lines=Deleted lines in gutter +options.general.color.descriptor.whitespaces.modified.lines=Minor modified lines in gutter +options.general.color.descriptor.border.lines=Border for changed lines in gutter options.general.color.descriptor.console.background=Console background options.general.color.descriptor.console.stdout=Console standard output options.general.color.descriptor.console.stderr=Console error output diff --git a/platform/platform-resources/src/META-INF/JsonPlugin.xml b/platform/platform-resources/src/META-INF/JsonPlugin.xml index deeec3ad3fa2..4dd4b11b044a 100644 --- a/platform/platform-resources/src/META-INF/JsonPlugin.xml +++ b/platform/platform-resources/src/META-INF/JsonPlugin.xml @@ -31,6 +31,7 @@ + @@ -58,4 +59,10 @@ implementationClass="com.intellij.json.psi.JsonStringLiteralManipulator"/> + + + + + \ No newline at end of file diff --git a/platform/projectModel-api/src/com/intellij/openapi/roots/FileIndex.java b/platform/projectModel-api/src/com/intellij/openapi/roots/FileIndex.java index 64558ddc5889..99eec952f1d9 100644 --- a/platform/projectModel-api/src/com/intellij/openapi/roots/FileIndex.java +++ b/platform/projectModel-api/src/com/intellij/openapi/roots/FileIndex.java @@ -57,6 +57,7 @@ public interface FileIndex { /** * Returns true if file is a source file which belongs to sources of the content. + * (Returns true for both source and test source).

* Note that sometimes a file can belong to the content and be a source file but not belong to sources of the content. * This happens if sources of some library are located under the content (so they belong to the project content but not as sources). * diff --git a/platform/projectModel-api/src/com/intellij/openapi/roots/ProjectFileIndex.java b/platform/projectModel-api/src/com/intellij/openapi/roots/ProjectFileIndex.java index fdae3317e74e..d47f640926d5 100644 --- a/platform/projectModel-api/src/com/intellij/openapi/roots/ProjectFileIndex.java +++ b/platform/projectModel-api/src/com/intellij/openapi/roots/ProjectFileIndex.java @@ -125,7 +125,7 @@ public interface ProjectFileIndex extends FileIndex { boolean isLibraryClassFile(@NotNull VirtualFile file); /** - * Returns true if fileOrDir is a file or directory from the content source or library sources. + * Returns true if fileOrDir is a file or directory from the content production/test source or library source. * * @param fileOrDir the file or directory to check. * @return true if the file or directory belongs to project or library sources, false otherwise. diff --git a/platform/util/src/com/intellij/ui/JBColor.java b/platform/util/src/com/intellij/ui/JBColor.java index cd204b3c00d8..3669e725610d 100644 --- a/platform/util/src/com/intellij/ui/JBColor.java +++ b/platform/util/src/com/intellij/ui/JBColor.java @@ -250,11 +250,23 @@ public class JBColor extends Color { public static final Color CYAN = cyan; public static Color foreground() { - return UIUtil.getLabelForeground(); + return new JBColor(new NotNullProducer() { + @NotNull + @Override + public Color produce() { + return UIUtil.getLabelForeground(); + } + }); } public static Color background() { - return UIUtil.getListBackground(); + return new JBColor(new NotNullProducer() { + @NotNull + @Override + public Color produce() { + return UIUtil.getListBackground(); + } + }); } public static Color border() { diff --git a/platform/util/src/com/intellij/util/containers/LinkedMultiMap.java b/platform/util/src/com/intellij/util/containers/LinkedMultiMap.java index 9c780bc804fc..b778e4c63f2b 100644 --- a/platform/util/src/com/intellij/util/containers/LinkedMultiMap.java +++ b/platform/util/src/com/intellij/util/containers/LinkedMultiMap.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.intellij.util.containers; import com.intellij.util.containers.hash.LinkedHashMap; @@ -26,15 +25,15 @@ import java.util.Map; * @author Evgeny Gerashchenko */ public class LinkedMultiMap extends MultiMap { - @NotNull - @Override - protected Map> createMap() { - return new LinkedHashMap>(); - } + @NotNull + @Override + protected Map> createMap() { + return new LinkedHashMap>(); + } - @NotNull - @Override - protected Map> createMap(int initialCapacity, float loadFactor) { - return new LinkedHashMap>(initialCapacity, loadFactor); - } + @NotNull + @Override + protected Map> createMap(int initialCapacity, float loadFactor) { + return new LinkedHashMap>(initialCapacity, loadFactor); + } } diff --git a/platform/util/src/com/intellij/util/containers/MultiMap.java b/platform/util/src/com/intellij/util/containers/MultiMap.java index acd97a51268a..f14303607c26 100644 --- a/platform/util/src/com/intellij/util/containers/MultiMap.java +++ b/platform/util/src/com/intellij/util/containers/MultiMap.java @@ -63,7 +63,7 @@ public class MultiMap implements Serializable { @NotNull protected Collection createCollection() { - return new ArrayList(); + return new SmartList(); } @NotNull @@ -261,12 +261,6 @@ public class MultiMap implements Serializable { protected Map> createMap() { return new THashMap>(strategy); } - - @NotNull - @Override - protected Collection createCollection() { - return new SmartList(); - } }; } @@ -289,12 +283,6 @@ public class MultiMap implements Serializable { @NotNull public static MultiMap createSmartList() { return new MultiMap() { - @NotNull - @Override - protected Collection createCollection() { - return new SmartList(); - } - @NotNull @Override protected Map> createMap() { diff --git a/platform/util/src/com/intellij/util/ui/UIUtil.java b/platform/util/src/com/intellij/util/ui/UIUtil.java index 893eb1d636b3..97352ca3ef1a 100644 --- a/platform/util/src/com/intellij/util/ui/UIUtil.java +++ b/platform/util/src/com/intellij/util/ui/UIUtil.java @@ -25,7 +25,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.CharsetToolkit; import com.intellij.ui.*; import com.intellij.util.*; -import com.intellij.util.containers.*; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.WeakHashMap; import org.intellij.lang.annotations.Language; import org.jetbrains.annotations.NonNls; @@ -75,7 +75,6 @@ import java.lang.reflect.Method; import java.net.URL; import java.text.NumberFormat; import java.util.*; -import java.util.HashMap; import java.util.List; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; @@ -680,11 +679,11 @@ public class UIUtil { } public static Color getLabelBackground() { - return getColor("Label.background"); + return UIManager.getColor("Label.background"); } public static Color getLabelForeground() { - return getColor("Label.foreground"); + return UIManager.getColor("Label.foreground"); } public static Color getLabelDisabledForeground() { @@ -734,11 +733,11 @@ public class UIUtil { } public static Color getTableHeaderBackground() { - return getColor("TableHeader.background"); + return UIManager.getColor("TableHeader.background"); } public static Color getTreeTextForeground() { - return getColor("Tree.textForeground"); + return UIManager.getColor("Tree.textForeground"); } public static Color getTreeSelectionBackground() { @@ -748,22 +747,23 @@ public class UIUtil { color = UIManager.getColor("nimbusSelectionBackground"); if (color != null) return color; } - return getColor("Tree.selectionBackground"); + return UIManager.getColor("Tree.selectionBackground"); } public static Color getTreeTextBackground() { - return getColor("Tree.textBackground"); + return UIManager.getColor("Tree.textBackground"); } public static Color getListSelectionForeground() { - if (isUnderNimbusLookAndFeel()) { + final Color color = UIManager.getColor("List.selectionForeground"); + if (color == null) { return UIManager.getColor("List[Selected].textForeground"); // Nimbus } - return getColor("List.selectionForeground"); + return color; } public static Color getFieldForegroundColor() { - return getColor("field.foreground"); + return UIManager.getColor("field.foreground"); } public static Color getTableSelectionBackground() { @@ -773,23 +773,11 @@ public class UIUtil { color = UIManager.getColor("nimbusSelectionBackground"); if (color != null) return color; } - return getColor("Table.selectionBackground"); + return UIManager.getColor("Table.selectionBackground"); } public static Color getActiveTextColor() { - return getColor("textActiveText"); - } - - @NotNull - private static Color getColor(final String property) { - return new JBColor(new NotNullProducer() { - @NotNull - @Override - public Color produce() { - final Color color = UIManager.getColor(property); - return color == null ? Gray.TRANSPARENT : color; - } - }); + return UIManager.getColor("textActiveText"); } public static Color getInactiveTextColor() { @@ -809,7 +797,7 @@ public class UIUtil { } public static Color getInactiveTextFieldBackgroundColor() { - return getColor("TextField.inactiveBackground"); + return UIManager.getColor("TextField.inactiveBackground"); } public static Font getTreeFont() { @@ -821,7 +809,7 @@ public class UIUtil { } public static Color getTreeSelectionForeground() { - return getColor("Tree.selectionForeground"); + return UIManager.getColor("Tree.selectionForeground"); } /** @@ -840,7 +828,7 @@ public class UIUtil { } public static Color getTreeSelectionBorderColor() { - return getColor("Tree.selectionBorderColor"); + return UIManager.getColor("Tree.selectionBorderColor"); } public static int getTreeRightChildIndent() { @@ -852,23 +840,23 @@ public class UIUtil { } public static Color getToolTipBackground() { - return getColor("ToolTip.background"); + return UIManager.getColor("ToolTip.background"); } public static Color getToolTipForeground() { - return getColor("ToolTip.foreground"); + return UIManager.getColor("ToolTip.foreground"); } public static Color getComboBoxDisabledForeground() { - return getColor("ComboBox.disabledForeground"); + return UIManager.getColor("ComboBox.disabledForeground"); } public static Color getComboBoxDisabledBackground() { - return getColor("ComboBox.disabledBackground"); + return UIManager.getColor("ComboBox.disabledBackground"); } public static Color getButtonSelectColor() { - return getColor("Button.select"); + return UIManager.getColor("Button.select"); } public static Integer getPropertyMaxGutterIconWidth(final String propertyPrefix) { @@ -876,7 +864,7 @@ public class UIUtil { } public static Color getMenuItemDisabledForeground() { - return getColor("MenuItem.disabledForeground"); + return UIManager.getColor("MenuItem.disabledForeground"); } public static Object getMenuItemDisabledForegroundObject() { @@ -893,7 +881,7 @@ public class UIUtil { public static Color getTableBackground() { // Under GTK+ L&F "Table.background" often has main panel color, which looks ugly - return isUnderGTKLookAndFeel() ? getTreeTextBackground() : getColor("Table.background"); + return isUnderGTKLookAndFeel() ? getTreeTextBackground() : UIManager.getColor("Table.background"); } public static Color getTableBackground(final boolean isSelected) { @@ -904,11 +892,11 @@ public class UIUtil { if (isUnderNimbusLookAndFeel()) { return UIManager.getColor("Table[Enabled+Selected].textForeground"); } - return getColor("Table.selectionForeground"); + return UIManager.getColor("Table.selectionForeground"); } public static Color getTableForeground() { - return getColor("Table.foreground"); + return UIManager.getColor("Table.foreground"); } public static Color getTableForeground(final boolean isSelected) { @@ -916,7 +904,7 @@ public class UIUtil { } public static Color getTableGridColor() { - return getColor("Table.gridColor"); + return UIManager.getColor("Table.gridColor"); } public static Color getListBackground() { @@ -926,7 +914,7 @@ public class UIUtil { return new Color(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha()); } // Under GTK+ L&F "Table.background" often has main panel color, which looks ugly - return isUnderGTKLookAndFeel() ? getTreeTextBackground() : getColor("List.background"); + return isUnderGTKLookAndFeel() ? getTreeTextBackground() : UIManager.getColor("List.background"); } public static Color getListBackground(boolean isSelected) { @@ -934,7 +922,7 @@ public class UIUtil { } public static Color getListForeground() { - return getColor("List.foreground"); + return UIManager.getColor("List.foreground"); } public static Color getListForeground(boolean isSelected) { @@ -942,26 +930,26 @@ public class UIUtil { } public static Color getPanelBackground() { - return getColor("Panel.background"); + return UIManager.getColor("Panel.background"); } public static Color getTreeBackground() { - return getColor("Tree.background"); + return UIManager.getColor("Tree.background"); } public static Color getTreeForeground() { - return getColor("Tree.foreground"); + return UIManager.getColor("Tree.foreground"); } public static Color getTableFocusCellBackground() { - return getColor(TABLE_FOCUS_CELL_BACKGROUND_PROPERTY); + return UIManager.getColor(TABLE_FOCUS_CELL_BACKGROUND_PROPERTY); } public static Color getListSelectionBackground() { if (isUnderNimbusLookAndFeel()) { return UIManager.getColor("List[Selected].textBackground"); // Nimbus } - return getColor("List.selectionBackground"); + return UIManager.getColor("List.selectionBackground"); } public static Color getListUnfocusedSelectionBackground() { @@ -978,11 +966,11 @@ public class UIUtil { } public static Color getTextFieldForeground() { - return getColor("TextField.foreground"); + return UIManager.getColor("TextField.foreground"); } public static Color getTextFieldBackground() { - return isUnderGTKLookAndFeel() ? UIManager.getColor("EditorPane.background") : getColor("TextField.background"); + return isUnderGTKLookAndFeel() ? UIManager.getColor("EditorPane.background") : UIManager.getColor("TextField.background"); } public static Font getButtonFont() { @@ -994,7 +982,7 @@ public class UIUtil { } public static Color getTabbedPaneBackground() { - return getColor("TabbedPane.background"); + return UIManager.getColor("TabbedPane.background"); } public static void setSliderIsFilled(final JSlider slider, final boolean value) { @@ -1002,11 +990,11 @@ public class UIUtil { } public static Color getLabelTextForeground() { - return getColor("Label.textForeground"); + return UIManager.getColor("Label.textForeground"); } public static Color getControlColor() { - return getColor("control"); + return UIManager.getColor("control"); } public static Font getOptionPaneMessageFont() { @@ -1018,19 +1006,19 @@ public class UIUtil { } public static Color getSeparatorForeground() { - return getColor("Separator.foreground"); + return UIManager.getColor("Separator.foreground"); } public static Color getSeparatorBackground() { - return getColor("Separator.background"); + return UIManager.getColor("Separator.background"); } public static Color getSeparatorShadow() { - return getColor("Separator.shadow"); + return UIManager.getColor("Separator.shadow"); } public static Color getSeparatorHighlight() { - return getColor("Separator.highlight"); + return UIManager.getColor("Separator.highlight"); } public static Color getSeparatorColorUnderNimbus() { @@ -1065,7 +1053,7 @@ public class UIUtil { } public static Color getTableFocusCellForeground() { - return getColor("Table.focusCellForeground"); + return UIManager.getColor("Table.focusCellForeground"); } /** @@ -1160,15 +1148,15 @@ public class UIUtil { } public static Color getWindowColor() { - return getColor("window"); + return UIManager.getColor("window"); } public static Color getTextAreaForeground() { - return getColor("TextArea.foreground"); + return UIManager.getColor("TextArea.foreground"); } public static Color getOptionPaneBackground() { - return getColor("OptionPane.background"); + return UIManager.getColor("OptionPane.background"); } @SuppressWarnings({"HardCodedStringLiteral"}) diff --git a/platform/util/src/com/intellij/util/ui/tree/WideSelectionTreeUI.java b/platform/util/src/com/intellij/util/ui/tree/WideSelectionTreeUI.java index 9775ddb01be1..93cdf6a01822 100644 --- a/platform/util/src/com/intellij/util/ui/tree/WideSelectionTreeUI.java +++ b/platform/util/src/com/intellij/util/ui/tree/WideSelectionTreeUI.java @@ -122,11 +122,6 @@ public class WideSelectionTreeUI extends BasicTreeUI { private void handle(MouseEvent e) { final JTree tree = (JTree)e.getSource(); if (SwingUtilities.isLeftMouseButton(e) && !e.isPopupTrigger()) { - // if we can't stop any ongoing editing, do nothing - if (isEditing(tree) && tree.getInvokesStopCellEditing() && !stopEditing(tree)) { - return; - } - final TreePath pressedPath = getClosestPathForLocation(tree, e.getX(), e.getY()); if (pressedPath != null) { Rectangle bounds = getPathBounds(tree, pressedPath); diff --git a/platform/util/src/com/intellij/util/xmlb/AbstractCollectionBinding.java b/platform/util/src/com/intellij/util/xmlb/AbstractCollectionBinding.java index 77d39314073e..1252a271a34a 100644 --- a/platform/util/src/com/intellij/util/xmlb/AbstractCollectionBinding.java +++ b/platform/util/src/com/intellij/util/xmlb/AbstractCollectionBinding.java @@ -29,18 +29,18 @@ import java.util.Collection; import java.util.List; import java.util.Map; -abstract class AbstractCollectionBinding implements Binding { +abstract class AbstractCollectionBinding extends Binding { private Map myElementBindings; private final Class myElementType; private final String myTagName; - @Nullable protected final Accessor myAccessor; private final AbstractCollection myAnnotation; public AbstractCollectionBinding(Class elementType, String tagName, @Nullable Accessor accessor) { + super(accessor); + myElementType = elementType; myTagName = tagName; - myAccessor = accessor; myAnnotation = accessor == null ? null : accessor.getAnnotation(AbstractCollection.class); } diff --git a/platform/util/src/com/intellij/util/xmlb/Accessor.java b/platform/util/src/com/intellij/util/xmlb/Accessor.java index 02c007ffb85a..7e364b9b6105 100644 --- a/platform/util/src/com/intellij/util/xmlb/Accessor.java +++ b/platform/util/src/com/intellij/util/xmlb/Accessor.java @@ -39,4 +39,6 @@ public interface Accessor { Class getValueClass(); Type getGenericType(); + + boolean isFinal(); } diff --git a/platform/util/src/com/intellij/util/xmlb/AccessorBindingWrapper.java b/platform/util/src/com/intellij/util/xmlb/AccessorBindingWrapper.java index e071b6b915ec..266fdf8f926a 100644 --- a/platform/util/src/com/intellij/util/xmlb/AccessorBindingWrapper.java +++ b/platform/util/src/com/intellij/util/xmlb/AccessorBindingWrapper.java @@ -15,15 +15,16 @@ */ package com.intellij.util.xmlb; +import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -class AccessorBindingWrapper implements Binding { - private final Accessor myAccessor; +class AccessorBindingWrapper extends Binding { private final Binding myBinding; public AccessorBindingWrapper(@NotNull Accessor accessor, @NotNull Binding binding) { - myAccessor = accessor; + super(accessor); + myBinding = binding; } @@ -41,9 +42,14 @@ class AccessorBindingWrapper implements Binding { @Nullable public Object deserialize(Object context, @NotNull Object... nodes) { Object currentValue = myAccessor.read(context); - Object deserializedValue = myBinding.deserialize(currentValue, nodes); - if (currentValue != deserializedValue) { - myAccessor.write(context, deserializedValue); + if (myBinding instanceof BeanBinding && myAccessor.isFinal()) { + ((BeanBinding)myBinding).deserializeInto(currentValue, (Element)nodes[0], null); + } + else { + Object deserializedValue = myBinding.deserialize(currentValue, nodes); + if (currentValue != deserializedValue) { + myAccessor.write(context, deserializedValue); + } } return context; } diff --git a/platform/util/src/com/intellij/util/xmlb/AttributeBinding.java b/platform/util/src/com/intellij/util/xmlb/AttributeBinding.java index 578b9e12eb7b..c3cbeae595f3 100644 --- a/platform/util/src/com/intellij/util/xmlb/AttributeBinding.java +++ b/platform/util/src/com/intellij/util/xmlb/AttributeBinding.java @@ -86,4 +86,8 @@ public class AttributeBinding extends BasePrimitiveBinding { throw new XmlSerializationException("Can't use attribute binding for non-text content: " + myAccessor); } } + + public String toString() { + return "AttributeBinding[" + myName + ", binding=" + myBinding + "]"; + } } diff --git a/platform/util/src/com/intellij/util/xmlb/BasePrimitiveBinding.java b/platform/util/src/com/intellij/util/xmlb/BasePrimitiveBinding.java index 68c5e626a3ea..936c367f4404 100644 --- a/platform/util/src/com/intellij/util/xmlb/BasePrimitiveBinding.java +++ b/platform/util/src/com/intellij/util/xmlb/BasePrimitiveBinding.java @@ -20,15 +20,15 @@ import com.intellij.util.ReflectionUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -abstract class BasePrimitiveBinding implements Binding { - protected final Accessor myAccessor; +abstract class BasePrimitiveBinding extends Binding { protected final String myName; protected final @Nullable Converter myConverter; @Nullable protected Binding myBinding; protected BasePrimitiveBinding(@NotNull Accessor accessor, @Nullable String suggestedName, @Nullable Class converterClass) { - myAccessor = accessor; + super(accessor); + myName = StringUtil.isEmpty(suggestedName) ? myAccessor.getName() : suggestedName; if (converterClass == null || converterClass == Converter.class) { myConverter = null; diff --git a/platform/util/src/com/intellij/util/xmlb/BeanBinding.java b/platform/util/src/com/intellij/util/xmlb/BeanBinding.java index c9078e63b009..78725e85378e 100644 --- a/platform/util/src/com/intellij/util/xmlb/BeanBinding.java +++ b/platform/util/src/com/intellij/util/xmlb/BeanBinding.java @@ -26,8 +26,8 @@ import com.intellij.util.containers.ConcurrentSoftValueHashMap; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.ContainerUtilRt; import com.intellij.util.containers.MultiMap; -import com.intellij.util.containers.hash.LinkedHashMap; import com.intellij.util.xmlb.annotations.*; +import gnu.trove.TObjectDoubleHashMap; import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -37,20 +37,23 @@ import java.beans.Introspector; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.util.*; import java.util.List; -import java.util.Map; -import java.util.Set; -class BeanBinding implements Binding { +class BeanBinding extends Binding { private static final Logger LOG = Logger.getInstance(BeanBinding.class); private static final Map> ourAccessorCache = new ConcurrentSoftValueHashMap>(); private final String myTagName; - private final LinkedHashMap myPropertyBindings = new LinkedHashMap(); + @SuppressWarnings("FieldAccessedSynchronizedAndUnsynchronized") + private Binding[] myBindings; + private final Class myBeanClass; - public BeanBinding(Class beanClass) { + public BeanBinding(@NotNull Class beanClass, @Nullable Accessor accessor) { + super(accessor); + assert !beanClass.isArray() : "Bean is an array: " + beanClass; assert !beanClass.isPrimitive() : "Bean is primitive type: " + beanClass; myBeanClass = beanClass; @@ -59,13 +62,15 @@ class BeanBinding implements Binding { } @Override - public void init() { - initPropertyBindings(myBeanClass); - } + public synchronized void init() { + assert myBindings == null; - private synchronized void initPropertyBindings(Class beanClass) { - for (Accessor accessor : getAccessors(beanClass)) { - myPropertyBindings.put(createBindingByAccessor(accessor), accessor); + List accessors = getAccessors(myBeanClass); + myBindings = new Binding[accessors.size()]; + for (int i = 0, size = accessors.size(); i < size; i++) { + Binding binding = createBinding(accessors.get(i)); + binding.init(); + myBindings[i] = binding; } } @@ -81,23 +86,22 @@ class BeanBinding implements Binding { @Nullable public Element serializeInto(@NotNull Object o, @Nullable Element element, @NotNull SerializationFilter filter) { - for (Binding binding : myPropertyBindings.keySet()) { - Accessor accessor = myPropertyBindings.get(binding); + return serializeInto(o, element, filter, myBindings); + } + + @Nullable + public Element serializeInto(@NotNull Object o, @Nullable Element element, @NotNull SerializationFilter filter, @Nullable Binding[] bindings) { + for (Binding binding : bindings == null ? myBindings : bindings) { + Accessor accessor = binding.getAccessor(); if (!filter.accepts(accessor, o)) { continue; } //todo: optimize. Cache it. Property property = accessor.getAnnotation(Property.class); - if (property != null && property.filter() != SerializationFilter.class) { - try { - if (!ReflectionUtil.newInstance(property.filter()).accepts(accessor, o)) { - continue; - } - } - catch (RuntimeException e) { - throw new XmlSerializationException(e); - } + if (property != null && property.filter() != SerializationFilter.class && + !ReflectionUtil.newInstance(property.filter()).accepts(accessor, o)) { + continue; } if (element == null) { @@ -130,21 +134,54 @@ class BeanBinding implements Binding { if (element == null) { return o; } - Object instance = XmlSerializerImpl.newInstance(myBeanClass); + Object instance = ReflectionUtil.newInstance(myBeanClass); deserializeInto(instance, element, null); return instance; } + @NotNull + public Binding[] computeOrderedBindings(@NotNull LinkedHashSet accessorNameTracker) { + final TObjectDoubleHashMap weights = new TObjectDoubleHashMap(accessorNameTracker.size()); + double weight = 0; + double step = (double)myBindings.length / (double)accessorNameTracker.size(); + for (String name : accessorNameTracker) { + weights.put(name, weight); + weight += step; + } + + weight = 0; + for (Binding binding : myBindings) { + String name = binding.getAccessor().getName(); + if (!weights.containsKey(name)) { + weights.put(name, weight); + } + + weight++; + } + + Binding[] result = Arrays.copyOf(myBindings, myBindings.length); + Arrays.sort(result, new Comparator() { + @Override + public int compare(@NotNull Binding o1, @NotNull Binding o2) { + String n1 = o1.getAccessor().getName(); + String n2 = o2.getAccessor().getName(); + double w1 = weights.get(n1); + double w2 = weights.get(n2); + return (int)(w1 - w2); + } + }); + return result; + } + public void deserializeInto(@NotNull Object result, @NotNull Element element, @Nullable Set accessorNameTracker) { - Set bindings = myPropertyBindings.keySet(); - MultiMap data = MultiMap.createSmartList(); + MultiMap data = MultiMap.createLinked(); nextNode: for (Object child : ContainerUtil.concat(element.getContent(), element.getAttributes())) { if (XmlSerializerImpl.isIgnoredNode(child)) { continue; } - for (Binding binding : bindings) { + for (Binding binding : myBindings) { if (binding.isBoundTo(child)) { data.putValue(binding, child); continue nextNode; @@ -159,7 +196,7 @@ class BeanBinding implements Binding { for (Binding binding : data.keySet()) { if (accessorNameTracker != null) { - accessorNameTracker.add(myPropertyBindings.get(binding).getName()); + accessorNameTracker.add(binding.getAccessor().getName()); } binding.deserialize(result, ArrayUtil.toObjectArray(data.get(binding))); } @@ -244,15 +281,25 @@ class BeanBinding implements Binding { } } - private static void collectFieldAccessors(Class aClass, List accessors) { - for (Field field : aClass.getFields()) { - final int modifiers = field.getModifiers(); - if (Modifier.isPublic(modifiers) && !Modifier.isStatic(modifiers) && - !Modifier.isFinal(modifiers) && !Modifier.isTransient(modifiers) && - field.getAnnotation(Transient.class) == null) { - accessors.add(new FieldAccessor(field)); + private static void collectFieldAccessors(@NotNull Class aClass, @NotNull List accessors) { + Class currentClass = aClass; + do { + for (Field field : currentClass.getDeclaredFields()) { + int modifiers = field.getModifiers(); + if (!Modifier.isStatic(modifiers) && + (field.getAnnotation(OptionTag.class) != null || + field.getAnnotation(Tag.class) != null || + field.getAnnotation(Attribute.class) != null || + field.getAnnotation(Property.class) != null || + (Modifier.isPublic(modifiers) && + !Modifier.isFinal(modifiers) && + !Modifier.isTransient(modifiers) && + field.getAnnotation(Transient.class) == null))) { + accessors.add(new FieldAccessor(field)); + } } } + while ((currentClass = currentClass.getSuperclass()) != null && currentClass.getAnnotation(Transient.class) == null); } @Nullable @@ -276,13 +323,8 @@ class BeanBinding implements Binding { return "BeanBinding[" + myBeanClass.getName() + ", tagName=" + myTagName + "]"; } - private static Binding createBindingByAccessor(@NotNull Accessor accessor) { - final Binding binding = _createBinding(accessor); - binding.init(); - return binding; - } - - private static Binding _createBinding(@NotNull Accessor accessor) { + @NotNull + private static Binding createBinding(@NotNull Accessor accessor) { Binding binding = XmlSerializerImpl.getTypeBinding(accessor.getGenericType(), accessor); if (binding instanceof JDOMElementBinding) { return binding; diff --git a/platform/util/src/com/intellij/util/xmlb/Binding.java b/platform/util/src/com/intellij/util/xmlb/Binding.java index cc6cc168b43d..6bf6a4c6feb8 100644 --- a/platform/util/src/com/intellij/util/xmlb/Binding.java +++ b/platform/util/src/com/intellij/util/xmlb/Binding.java @@ -18,16 +18,28 @@ package com.intellij.util.xmlb; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -interface Binding { - @Nullable - Object serialize(Object o, @Nullable Object context, SerializationFilter filter); +abstract class Binding { + protected final Accessor myAccessor; + + protected Binding(Accessor accessor) { + myAccessor = accessor; + } + + @NotNull + public Accessor getAccessor() { + return myAccessor; + } @Nullable - Object deserialize(Object context, @NotNull Object... nodes); + public abstract Object serialize(Object o, @Nullable Object context, SerializationFilter filter); - boolean isBoundTo(Object node); + @Nullable + public abstract Object deserialize(Object context, @NotNull Object... nodes); - Class getBoundNodeType(); + public abstract boolean isBoundTo(Object node); - void init(); + public abstract Class getBoundNodeType(); + + public void init() { + } } diff --git a/platform/util/src/com/intellij/util/xmlb/DateBinding.java b/platform/util/src/com/intellij/util/xmlb/DateBinding.java index b3ae2634c03e..da3292932868 100644 --- a/platform/util/src/com/intellij/util/xmlb/DateBinding.java +++ b/platform/util/src/com/intellij/util/xmlb/DateBinding.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.intellij.util.xmlb; import org.jdom.Text; @@ -25,9 +24,8 @@ import java.util.Date; * @author Dmitry Avdeev */ public class DateBinding extends PrimitiveValueBinding { - - public DateBinding() { - super(Date.class); + public DateBinding(@Nullable Accessor accessor) { + super(Date.class, accessor); } @Nullable diff --git a/platform/util/src/com/intellij/util/xmlb/FieldAccessor.java b/platform/util/src/com/intellij/util/xmlb/FieldAccessor.java index 172b5e364825..c7fd18abad65 100644 --- a/platform/util/src/com/intellij/util/xmlb/FieldAccessor.java +++ b/platform/util/src/com/intellij/util/xmlb/FieldAccessor.java @@ -21,6 +21,7 @@ import org.jetbrains.annotations.NotNull; import java.lang.annotation.Annotation; import java.lang.reflect.Field; +import java.lang.reflect.Modifier; import java.lang.reflect.Type; class FieldAccessor implements Accessor { @@ -81,6 +82,11 @@ class FieldAccessor implements Accessor { return myField.getGenericType(); } + @Override + public boolean isFinal() { + return Modifier.isFinal(myField.getModifiers()); + } + @NonNls public String toString() { return "FieldAccessor[" + myField.getDeclaringClass() + "." + myField.getName() + "]"; diff --git a/platform/util/src/com/intellij/util/xmlb/JDOMElementBinding.java b/platform/util/src/com/intellij/util/xmlb/JDOMElementBinding.java index 227f0fd4757c..8541b48eced3 100644 --- a/platform/util/src/com/intellij/util/xmlb/JDOMElementBinding.java +++ b/platform/util/src/com/intellij/util/xmlb/JDOMElementBinding.java @@ -23,12 +23,12 @@ import org.jetbrains.annotations.Nullable; import java.util.ArrayList; -class JDOMElementBinding implements Binding { - private final Accessor myAccessor; +class JDOMElementBinding extends Binding { private final String myTagName; public JDOMElementBinding(@NotNull Accessor accessor) { - myAccessor = accessor; + super(accessor); + Tag tag = myAccessor.getAnnotation(Tag.class); assert tag != null : "jdom.Element property without @Tag annotation: " + accessor; diff --git a/platform/util/src/com/intellij/util/xmlb/MapBinding.java b/platform/util/src/com/intellij/util/xmlb/MapBinding.java index a2490e39fdb2..144c71e1204b 100644 --- a/platform/util/src/com/intellij/util/xmlb/MapBinding.java +++ b/platform/util/src/com/intellij/util/xmlb/MapBinding.java @@ -34,7 +34,7 @@ import java.util.Map; import static com.intellij.util.xmlb.Constants.*; -class MapBinding implements Binding { +class MapBinding extends Binding { private static final Logger LOG = Logger.getInstance(MapBinding.class); private static final Comparator KEY_COMPARATOR = new Comparator() { @@ -54,7 +54,9 @@ class MapBinding implements Binding { private final Binding myValueBinding; private final MapAnnotation myMapAnnotation; - public MapBinding(ParameterizedType type, Accessor accessor) { + public MapBinding(ParameterizedType type, @NotNull Accessor accessor) { + super(accessor); + Type[] arguments = type.getActualTypeArguments(); Type keyType = arguments[0]; Type valueType = arguments[1]; @@ -64,6 +66,10 @@ class MapBinding implements Binding { myMapAnnotation = accessor.getAnnotation(MapAnnotation.class); } + @Override + public void init() { + } + @Nullable @Override public Object serialize(Object o, @Nullable Object context, SerializationFilter filter) { @@ -218,8 +224,4 @@ class MapBinding implements Binding { public Class getBoundNodeType() { return Element.class; } - - @Override - public void init() { - } } diff --git a/platform/util/src/com/intellij/util/xmlb/PrimitiveValueBinding.java b/platform/util/src/com/intellij/util/xmlb/PrimitiveValueBinding.java index 3c303b07b410..22b5cb80549d 100644 --- a/platform/util/src/com/intellij/util/xmlb/PrimitiveValueBinding.java +++ b/platform/util/src/com/intellij/util/xmlb/PrimitiveValueBinding.java @@ -16,14 +16,18 @@ package com.intellij.util.xmlb; import com.intellij.openapi.util.JDOMUtil; +import org.jdom.Attribute; +import org.jdom.Content; import org.jdom.Text; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -class PrimitiveValueBinding implements Binding { +class PrimitiveValueBinding extends Binding { private final Class myType; - public PrimitiveValueBinding(@NotNull Class myType) { + public PrimitiveValueBinding(@NotNull Class myType, @Nullable Accessor accessor) { + super(accessor); + this.myType = myType; } @@ -44,8 +48,8 @@ class PrimitiveValueBinding implements Binding { value = JDOMUtil.concatTextNodesValues(nodes); } else { - assert nodes[0] != null; - value = JDOMUtil.getValue(nodes[0]); + Object node = nodes[0]; + value = node instanceof Attribute ? ((Attribute)node).getValue() : ((Content)node).getValue(); } return convertString(value); } diff --git a/platform/util/src/com/intellij/util/xmlb/PropertyAccessor.java b/platform/util/src/com/intellij/util/xmlb/PropertyAccessor.java index 9bef1ab7bf8a..9780e683154d 100644 --- a/platform/util/src/com/intellij/util/xmlb/PropertyAccessor.java +++ b/platform/util/src/com/intellij/util/xmlb/PropertyAccessor.java @@ -110,6 +110,11 @@ class PropertyAccessor implements Accessor { return myGenericType; } + @Override + public boolean isFinal() { + return false; + } + @NonNls public String toString() { return "PropertyAccessor[" + myReadMethod.getDeclaringClass().getName() + "." + getName() +"]"; diff --git a/platform/util/src/com/intellij/util/xmlb/SerializationFilter.java b/platform/util/src/com/intellij/util/xmlb/SerializationFilter.java index 4c0d2a81ff62..01f6f68f4fd1 100644 --- a/platform/util/src/com/intellij/util/xmlb/SerializationFilter.java +++ b/platform/util/src/com/intellij/util/xmlb/SerializationFilter.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -13,9 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.intellij.util.xmlb; +import org.jetbrains.annotations.NotNull; + public interface SerializationFilter { - boolean accepts(Accessor accessor, Object bean); + boolean accepts(@NotNull Accessor accessor, Object bean); } diff --git a/platform/util/src/com/intellij/util/xmlb/SerializationFilterBase.java b/platform/util/src/com/intellij/util/xmlb/SerializationFilterBase.java index 3fab01c85af6..7c1cb2b51795 100644 --- a/platform/util/src/com/intellij/util/xmlb/SerializationFilterBase.java +++ b/platform/util/src/com/intellij/util/xmlb/SerializationFilterBase.java @@ -20,7 +20,7 @@ import org.jetbrains.annotations.Nullable; public abstract class SerializationFilterBase implements SerializationFilter { @Override - public final boolean accepts(Accessor accessor, Object bean) { + public final boolean accepts(@NotNull Accessor accessor, Object bean) { if (bean == null) { return true; } diff --git a/platform/util/src/com/intellij/util/xmlb/SkipEmptySerializationFilter.java b/platform/util/src/com/intellij/util/xmlb/SkipEmptySerializationFilter.java index 4a98cf7a5cb8..aec1ab68e74a 100644 --- a/platform/util/src/com/intellij/util/xmlb/SkipEmptySerializationFilter.java +++ b/platform/util/src/com/intellij/util/xmlb/SkipEmptySerializationFilter.java @@ -36,8 +36,8 @@ public class SkipEmptySerializationFilter extends SerializationFilterBase { if (Boolean.FALSE.equals(beanValue) || (beanValue instanceof String && ((String)beanValue).isEmpty()) || - (beanValue instanceof Map && ((Map)beanValue).isEmpty()) || - (beanValue instanceof Collection && ((Collection)beanValue).isEmpty())) { + beanValue instanceof Collection && ((Collection)beanValue).isEmpty() || + (beanValue instanceof Map && ((Map)beanValue).isEmpty())) { return false; } diff --git a/platform/util/src/com/intellij/util/xmlb/SmartSerializer.java b/platform/util/src/com/intellij/util/xmlb/SmartSerializer.java index dd6a7cb916d3..3a9ef3dc9ec2 100644 --- a/platform/util/src/com/intellij/util/xmlb/SmartSerializer.java +++ b/platform/util/src/com/intellij/util/xmlb/SmartSerializer.java @@ -16,19 +16,19 @@ package com.intellij.util.xmlb; import com.intellij.util.ThreeState; -import gnu.trove.THashSet; import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Set; +import java.util.LinkedHashSet; public final class SmartSerializer { - private final Set mySerializedAccessorNameTracker; + private final LinkedHashSet mySerializedAccessorNameTracker; + private Binding[] myOrderedBindings; private final SerializationFilter mySerializationFilter; public SmartSerializer(boolean trackSerializedNames, boolean useSkipEmptySerializationFilter) { - mySerializedAccessorNameTracker = trackSerializedNames ? new THashSet() : null; + mySerializedAccessorNameTracker = trackSerializedNames ? new LinkedHashSet() : null; mySerializationFilter = useSkipEmptySerializationFilter ? new SkipEmptySerializationFilter() { @@ -55,11 +55,18 @@ public final class SmartSerializer { public void readExternal(@NotNull Object bean, @NotNull Element element) { if (mySerializedAccessorNameTracker != null) { mySerializedAccessorNameTracker.clear(); + myOrderedBindings = null; + } + + BeanBinding beanBinding = (BeanBinding)XmlSerializerImpl.getBinding(bean.getClass()); + beanBinding.deserializeInto(bean, element, mySerializedAccessorNameTracker); + + if (mySerializedAccessorNameTracker != null) { + myOrderedBindings = beanBinding.computeOrderedBindings(mySerializedAccessorNameTracker); } - XmlSerializer.deserializeInto(bean, element, mySerializedAccessorNameTracker); } public void writeExternal(@NotNull Object bean, @NotNull Element element) { - XmlSerializer.serializeInto(bean, element, mySerializationFilter); + ((BeanBinding)XmlSerializerImpl.getBinding(bean.getClass())).serializeInto(bean, element, mySerializationFilter, myOrderedBindings); } } \ No newline at end of file diff --git a/platform/util/src/com/intellij/util/xmlb/TagBinding.java b/platform/util/src/com/intellij/util/xmlb/TagBinding.java index 78336be646fe..37b013b5333d 100644 --- a/platform/util/src/com/intellij/util/xmlb/TagBinding.java +++ b/platform/util/src/com/intellij/util/xmlb/TagBinding.java @@ -16,6 +16,7 @@ package com.intellij.util.xmlb; import com.intellij.openapi.util.JDOMUtil; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.SmartList; import com.intellij.util.xmlb.annotations.Tag; @@ -25,6 +26,7 @@ import org.jdom.Text; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Collections; import java.util.List; class TagBinding extends BasePrimitiveBinding { @@ -33,7 +35,7 @@ class TagBinding extends BasePrimitiveBinding { public TagBinding(@NotNull Accessor accessor, @NotNull Tag tagAnnotation) { super(accessor, tagAnnotation.value(), null); - myTextIfEmpty = tagAnnotation.textIfEmpty(); + myTextIfEmpty = StringUtil.nullize(tagAnnotation.textIfEmpty()); } @Nullable @@ -57,28 +59,35 @@ class TagBinding extends BasePrimitiveBinding { @Nullable public Object deserialize(Object o, @NotNull Object... nodes) { assert nodes.length > 0; - Object[] children; + List children; + boolean isBeanBinding = myBinding instanceof BeanBinding; if (nodes.length == 1) { - children = JDOMUtil.getContent((Element)nodes[0]); + Element node = (Element)nodes[0]; + children = isBeanBinding ? node.getChildren() : node.getContent(); } else { String name = ((Element)nodes[0]).getName(); - List childrenList = new SmartList(); + children = new SmartList(); for (Object node : nodes) { - assert ((Element)node).getName().equals(name); - childrenList.addAll(((Element)node).getContent()); + Element element = (Element)node; + assert element.getName().equals(name); + //noinspection unchecked + children.addAll(((List)(isBeanBinding ? element.getChildren() : element.getContent()))); } - children = ArrayUtil.toObjectArray(childrenList); - } - - if (children.length == 0) { - children = new Object[] {new Text(myTextIfEmpty)}; } assert myBinding != null; - Object v = myBinding.deserialize(myAccessor.read(o), children); - Object value = XmlSerializerImpl.convert(v, myAccessor.getValueClass()); - myAccessor.write(o, value); + if (isBeanBinding && myAccessor.isFinal()) { + ((BeanBinding)myBinding).deserializeInto(o, (Element)children.get(0), null); + } + else { + if (children.isEmpty() && myTextIfEmpty != null) { + children = Collections.singletonList(new Text(myTextIfEmpty)); + } + + Object v = myBinding.deserialize(myAccessor.read(o), ArrayUtil.toObjectArray(children)); + myAccessor.write(o, XmlSerializerImpl.convert(v, myAccessor.getValueClass())); + } return o; } diff --git a/platform/util/src/com/intellij/util/xmlb/TagBindingWrapper.java b/platform/util/src/com/intellij/util/xmlb/TagBindingWrapper.java index 389adca9cd18..59568dd60858 100644 --- a/platform/util/src/com/intellij/util/xmlb/TagBindingWrapper.java +++ b/platform/util/src/com/intellij/util/xmlb/TagBindingWrapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.intellij.util.xmlb; import com.intellij.openapi.util.JDOMUtil; @@ -24,14 +23,17 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; //todo: merge with option tag binding -class TagBindingWrapper implements Binding { +class TagBindingWrapper extends Binding { private final Binding binding; private final String myTagName; private final String myAttributeName; - public TagBindingWrapper(Binding binding, final String tagName, final String attributeName) { + public TagBindingWrapper(@NotNull Binding binding, final String tagName, final String attributeName) { + super(binding.myAccessor); + this.binding = binding; + //noinspection unchecked assert binding.getBoundNodeType().isAssignableFrom(Text.class); myTagName = tagName; myAttributeName = attributeName; @@ -81,8 +83,4 @@ class TagBindingWrapper implements Binding { public Class getBoundNodeType() { return Element.class; } - - @Override - public void init() { - } } diff --git a/platform/util/src/com/intellij/util/xmlb/TextBinding.java b/platform/util/src/com/intellij/util/xmlb/TextBinding.java index 5cfaad76594d..ae9192bb3a0c 100644 --- a/platform/util/src/com/intellij/util/xmlb/TextBinding.java +++ b/platform/util/src/com/intellij/util/xmlb/TextBinding.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.intellij.util.xmlb; import org.jdom.Content; @@ -21,12 +20,11 @@ import org.jdom.Text; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class TextBinding implements Binding { - private final Accessor myAccessor; +public class TextBinding extends Binding { private volatile Binding myBinding; - public TextBinding(final Accessor accessor) { - myAccessor = accessor; + public TextBinding(@NotNull Accessor accessor) { + super(accessor); } @Nullable diff --git a/platform/util/src/com/intellij/util/xmlb/XmlSerializer.java b/platform/util/src/com/intellij/util/xmlb/XmlSerializer.java index 76fa9d08c0e1..97e4a35276a5 100644 --- a/platform/util/src/com/intellij/util/xmlb/XmlSerializer.java +++ b/platform/util/src/com/intellij/util/xmlb/XmlSerializer.java @@ -31,7 +31,7 @@ import java.util.Set; public class XmlSerializer { private static final SerializationFilter TRUE_FILTER = new SerializationFilter() { @Override - public boolean accepts(Accessor accessor, Object bean) { + public boolean accepts(@NotNull Accessor accessor, Object bean) { return true; } }; diff --git a/platform/util/src/com/intellij/util/xmlb/XmlSerializerImpl.java b/platform/util/src/com/intellij/util/xmlb/XmlSerializerImpl.java index ee16d1270500..0f7c1fc2ba4b 100644 --- a/platform/util/src/com/intellij/util/xmlb/XmlSerializerImpl.java +++ b/platform/util/src/com/intellij/util/xmlb/XmlSerializerImpl.java @@ -26,6 +26,7 @@ import java.lang.annotation.Annotation; import java.lang.ref.SoftReference; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; import java.util.*; import java.util.concurrent.ConcurrentHashMap; @@ -72,9 +73,21 @@ class XmlSerializerImpl { } static Binding getTypeBinding(@NotNull Type type, @Nullable Accessor accessor) { - return _getClassBinding(type instanceof Class ? (Class)type : (Class)((ParameterizedType)type).getRawType(), type, accessor); + Class aClass; + if (type instanceof Class) { + aClass = (Class)type; + } + else if (type instanceof TypeVariable) { + Type bound = ((TypeVariable)type).getBounds()[0]; + aClass = bound instanceof Class ? (Class)bound : (Class)((ParameterizedType)bound).getRawType(); + } + else { + aClass = (Class)((ParameterizedType)type).getRawType(); + } + return _getClassBinding(aClass, type, accessor); } + @NotNull private static synchronized Binding _getClassBinding(@NotNull Class aClass, @NotNull Type originalType, @Nullable Accessor accessor) { Pair key = Pair.create(originalType, accessor); Map, Binding> map = getBindingCacheMap(); @@ -97,26 +110,42 @@ class XmlSerializerImpl { return map; } + @NotNull private static Binding _getNonCachedClassBinding(@NotNull Class aClass, @Nullable Accessor accessor, @NotNull Type originalType) { - if (aClass.isPrimitive()) return new PrimitiveValueBinding(aClass); + if (aClass.isPrimitive()) { + return new PrimitiveValueBinding(aClass, accessor); + } if (aClass.isArray()) { return Element.class.isAssignableFrom(aClass.getComponentType()) ? new JDOMElementBinding(accessor) : new ArrayBinding(aClass, accessor); } - if (Number.class.isAssignableFrom(aClass)) return new PrimitiveValueBinding(aClass); - if (Boolean.class.isAssignableFrom(aClass)) return new PrimitiveValueBinding(aClass); - if (String.class.isAssignableFrom(aClass)) return new PrimitiveValueBinding(aClass); + if (Number.class.isAssignableFrom(aClass)) { + return new PrimitiveValueBinding(aClass, accessor); + } + if (Boolean.class.isAssignableFrom(aClass)) { + return new PrimitiveValueBinding(aClass, accessor); + } + if (String.class.isAssignableFrom(aClass)) { + return new PrimitiveValueBinding(aClass, accessor); + } if (Collection.class.isAssignableFrom(aClass) && originalType instanceof ParameterizedType) { return new CollectionBinding((ParameterizedType)originalType, accessor); } - if (Map.class.isAssignableFrom(aClass) && originalType instanceof ParameterizedType) { - return new MapBinding((ParameterizedType)originalType, accessor); + if (accessor != null) { + if (Map.class.isAssignableFrom(aClass) && originalType instanceof ParameterizedType) { + return new MapBinding((ParameterizedType)originalType, accessor); + } + if (Element.class.isAssignableFrom(aClass)) { + return new JDOMElementBinding(accessor); + } } - if (Element.class.isAssignableFrom(aClass)) return new JDOMElementBinding(accessor); - if (Date.class.isAssignableFrom(aClass)) return new DateBinding(); - if (aClass.isEnum()) return new PrimitiveValueBinding(aClass); - - return new BeanBinding(aClass); + if (Date.class.isAssignableFrom(aClass)) { + return new DateBinding(accessor); + } + if (aClass.isEnum()) { + return new PrimitiveValueBinding(aClass, accessor); + } + return new BeanBinding(aClass, accessor); } @Nullable diff --git a/platform/util/testSrc/com/intellij/util/xmlb/XmlSerializerTest.java b/platform/util/testSrc/com/intellij/util/xmlb/XmlSerializerTest.java index 0f7217c5241e..69cc37512462 100644 --- a/platform/util/testSrc/com/intellij/util/xmlb/XmlSerializerTest.java +++ b/platform/util/testSrc/com/intellij/util/xmlb/XmlSerializerTest.java @@ -24,9 +24,11 @@ import junit.framework.AssertionFailedError; import junit.framework.TestCase; import org.intellij.lang.annotations.Language; import org.jdom.Element; +import org.jdom.JDOMException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.io.IOException; import java.util.*; import java.util.concurrent.atomic.AtomicReference; @@ -535,7 +537,7 @@ public class XmlSerializerTest extends TestCase { "", new SerializationFilter() { @Override - public boolean accepts(Accessor accessor, Object bean) { + public boolean accepts(@NotNull Accessor accessor, Object bean) { return accessor.getName().startsWith("I"); } }); @@ -848,7 +850,7 @@ public class XmlSerializerTest extends TestCase { } public static class PropertyFilterTest implements SerializationFilter { @Override - public boolean accepts(Accessor accessor, Object bean) { + public boolean accepts(@NotNull Accessor accessor, Object bean) { return !accessor.read(bean).equals("skip"); } } @@ -1219,6 +1221,37 @@ public class XmlSerializerTest extends TestCase { doSerializerTest("", bean); } + static class Bean2 { + @Attribute + public String ab; + + @Attribute + public String module; + + @Attribute + public String ac; + } + + public void testOrdered() throws IOException, JDOMException { + Bean2 bean = new Bean2(); + bean.module = "module"; + bean.ab = "ab"; + doSerializerTest("", bean); + + checkSmartSerialization(new Bean2(), ""); + checkSmartSerialization(new Bean2(), ""); + checkSmartSerialization(new Bean2(), ""); + checkSmartSerialization(new Bean2(), ""); + } + + private static void checkSmartSerialization(@NotNull Bean2 bean, @NotNull String serialized) throws IOException, JDOMException { + SmartSerializer serializer = new SmartSerializer(); + serializer.readExternal(bean, JDOMUtil.loadDocument(serialized).getRootElement()); + Element serializedState = new Element("Bean2"); + serializer.writeExternal(bean, serializedState); + assertEquals(serialized, JDOMUtil.writeElement(serializedState)); + } + //--------------------------------------------------------------------------------------------------- private static Element assertSerializer(Object bean, String expected, SerializationFilter filter) { return assertSerializer(bean, expected, "Serialization failure", filter); @@ -1232,6 +1265,7 @@ public class XmlSerializerTest extends TestCase { Element element = assertSerializer(bean, expectedText, filter); //test deserializer + @SuppressWarnings("unchecked") Class aClass = (Class)bean.getClass(); T o = XmlSerializer.deserialize(element, aClass); assertSerializer(o, expectedText, "Deserialization failure", filter); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesViewContentManager.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesViewContentManager.java index 7801b7f80b45..2fc08b1d2f8a 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesViewContentManager.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesViewContentManager.java @@ -17,6 +17,7 @@ package com.intellij.openapi.vcs.changes.ui; import com.intellij.icons.AllIcons; +import com.intellij.ide.actions.ToggleToolbarAction; import com.intellij.lifecycle.PeriodicalTasksCloser; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.DefaultActionGroup; @@ -27,7 +28,6 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.DumbAwareRunnable; import com.intellij.openapi.project.Project; import com.intellij.openapi.startup.StartupManager; -import com.intellij.openapi.ui.SimpleToolWindowPanel; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.Key; @@ -87,7 +87,7 @@ public class ChangesViewContentManager extends AbstractProjectComponent implemen myToolWindow = toolWindowManager.registerToolWindow(TOOLWINDOW_ID, true, ToolWindowAnchor.BOTTOM, myProject, true); myToolWindow.setIcon(AllIcons.Toolwindows.ToolWindowChanges); DefaultActionGroup gearActions = new DefaultActionGroup(); - gearActions.addAction(SimpleToolWindowPanel.createToggleToolbarAction(myProject, myToolWindow)).setAsSecondary(true); + gearActions.addAction(ToggleToolbarAction.createToggleToolbarGroup(myProject, myToolWindow)).setAsSecondary(true); ((ToolWindowEx)myToolWindow).setAdditionalGearActions(gearActions); updateToolWindowAvailability(); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTrackerDrawing.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTrackerDrawing.java index ccf0a1560c8c..af016745218b 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTrackerDrawing.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTrackerDrawing.java @@ -46,6 +46,7 @@ import com.intellij.ui.HintListener; import com.intellij.ui.LightweightHint; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; @@ -70,43 +71,27 @@ public class LineStatusTrackerDrawing { private static void paintGutterFragment(final Editor editor, final Graphics g, final Rectangle r, final Range range) { final EditorGutterComponentEx gutter = ((EditorEx)editor).getGutterComponentEx(); - Color stripeColor = getDiffGutterColor(range); + Color gutterColor = getDiffGutterColor(range); + Color borderColor = getDiffGutterBorderColor(); + + final int x = r.x + r.width - 3; + final int endX = gutter.getWhitespaceSeparatorOffset(); - int triangle = 4; if (range.getInnerRanges() == null) { // actual painter - g.setColor(stripeColor); - - final int endX = gutter.getWhitespaceSeparatorOffset(); - final int x = r.x + r.width - 3; - final int width = endX - x; if (r.height > 0) { - g.fillRect(x, r.y, width, r.height); + paintRect(g, gutterColor, borderColor, x, r.y, endX, r.y + r.height); } else { - final int[] xPoints = new int[]{x, x, endX}; - final int[] yPoints = new int[]{r.y - triangle, r.y + triangle, r.y}; - g.fillPolygon(xPoints, yPoints, 3); + paintTriangle(g, gutterColor, borderColor, x, endX, r.y); } } else { // registry: diff.status.tracker.smart - final int x = gutter.getLineMarkerAreaOffset() + gutter.getIconsAreaWidth() + 1; - final int endX = gutter.getWhitespaceSeparatorOffset(); - final int width = endX - x; - if (range.getType() == Range.DELETED) { final int y = lineToY(editor, range.getLine1()); - - final int[] xPoints = new int[]{x, x, endX + 1}; - final int[] yPoints = new int[]{y - triangle, y + triangle, y}; - - g.setColor(stripeColor); - g.fillPolygon(xPoints, yPoints, 3); - - g.setColor(gutter.getOutlineColor(false)); - g.drawPolygon(xPoints, yPoints, 3); + paintTriangle(g, gutterColor, borderColor, x, endX, y); } else { - int y = lineToY(editor, range.getLine1()); + final int y = lineToY(editor, range.getLine1()); int endY = lineToY(editor, range.getLine2()); List innerRanges = range.getInnerRanges(); @@ -116,8 +101,7 @@ public class LineStatusTrackerDrawing { int start = lineToY(editor, innerRange.getLine1()); int end = lineToY(editor, innerRange.getLine2()); - g.setColor(getDiffColor(innerRange)); - g.fillRect(x, start, width, end - start); + paintRect(g, getDiffColor(innerRange), null, x, start, endX, end); } for (int i = 0; i < innerRanges.size(); i++) { @@ -140,14 +124,10 @@ public class LineStatusTrackerDrawing { end = lineToY(editor, innerRange.getLine2()) + 3; } - g.setColor(getDiffColor(innerRange)); - g.fillRect(x, start, width, end - start); + paintRect(g, getDiffColor(innerRange), null, x, start, endX, end); } - g.setColor(gutter.getOutlineColor(false)); - UIUtil.drawLine(g, x, y, endX - 1, y); - UIUtil.drawLine(g, x, y, x, endY - 1); - UIUtil.drawLine(g, x, endY - 1, endX - 1, endY - 1); + paintRect(g, null, borderColor, x, y, endX, endY); } } } @@ -161,6 +141,35 @@ public class LineStatusTrackerDrawing { return editor.logicalPositionToXY(editor.offsetToLogicalPosition(document.getLineStartOffset(line))).y; } + private static void paintRect(@NotNull Graphics g, @Nullable Color color, @Nullable Color borderColor, int x1, int y1, int x2, int y2) { + if (color != null) { + g.setColor(color); + g.fillRect(x1, y1, x2 - x1, y2 - y1); + } + if (borderColor != null) { + g.setColor(borderColor); + UIUtil.drawLine(g, x1, y1, x2 - 1, y1); + UIUtil.drawLine(g, x1, y1, x1, y2 - 1); + UIUtil.drawLine(g, x1, y2 - 1, x2 - 1, y2 - 1); + } + } + + private static void paintTriangle(@NotNull Graphics g, @Nullable Color color, @Nullable Color borderColor, int x1, int x2, int y) { + int size = 4; + + final int[] xPoints = new int[]{x1, x1, x2}; + final int[] yPoints = new int[]{y - size, y + size, y}; + + if (color != null) { + g.setColor(color); + g.fillPolygon(xPoints, yPoints, xPoints.length); + } + if (borderColor != null) { + g.setColor(borderColor); + g.drawPolygon(xPoints, yPoints, xPoints.length); + } + } + public static LineMarkerRenderer createRenderer(final Range range, final LineStatusTracker tracker) { return new ActiveGutterRenderer() { public void paint(final Editor editor, final Graphics g, final Rectangle r) { @@ -307,8 +316,9 @@ public class LineStatusTrackerDrawing { }); } - @NotNull + @Nullable private static Color getDiffColor(@NotNull Range.InnerRange range) { + // TODO: we should move color settings from Colors-General to Colors-Diff final EditorColorsScheme globalScheme = EditorColorsManager.getInstance().getGlobalScheme(); switch (range.getType()) { case Range.INSERTED: @@ -341,7 +351,7 @@ public class LineStatusTrackerDrawing { } } - @NotNull + @Nullable private static Color getDiffGutterColor(@NotNull Range range) { final EditorColorsScheme globalScheme = EditorColorsManager.getInstance().getGlobalScheme(); switch (range.getType()) { @@ -356,4 +366,10 @@ public class LineStatusTrackerDrawing { return null; } } + + @Nullable + private static Color getDiffGutterBorderColor() { + final EditorColorsScheme globalScheme = EditorColorsManager.getInstance().getGlobalScheme(); + return globalScheme.getColor(EditorColors.BORDER_LINES_COLOR); + } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/ProjectLevelVcsManagerImpl.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/ProjectLevelVcsManagerImpl.java index 6886dd5098d8..1e0ab57f5c52 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/ProjectLevelVcsManagerImpl.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/ProjectLevelVcsManagerImpl.java @@ -16,6 +16,7 @@ package com.intellij.openapi.vcs.impl; import com.intellij.icons.AllIcons; +import com.intellij.ide.actions.ToggleToolbarAction; import com.intellij.openapi.actionSystem.DefaultActionGroup; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; @@ -34,7 +35,6 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ex.ProjectEx; import com.intellij.openapi.roots.FileIndexFacade; import com.intellij.openapi.startup.StartupManager; -import com.intellij.openapi.ui.SimpleToolWindowPanel; import com.intellij.openapi.util.*; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.registry.Registry; @@ -242,7 +242,7 @@ public class ProjectLevelVcsManagerImpl extends ProjectLevelVcsManagerEx impleme myContentManager = toolWindow.getContentManager(); toolWindow.setIcon(AllIcons.Toolwindows.VcsSmallTab); DefaultActionGroup gearActions = new DefaultActionGroup(); - gearActions.addAction(SimpleToolWindowPanel.createToggleToolbarAction(myProject, toolWindow)).setAsSecondary(true); + gearActions.addAction(ToggleToolbarAction.createToggleToolbarGroup(myProject, toolWindow)).setAsSecondary(true); ((ToolWindowEx)toolWindow).setAdditionalGearActions(gearActions); toolWindow.installWatcher(myContentManager); } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogDataHolder.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogDataHolder.java index f076e1325b4b..83638e2aa70e 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogDataHolder.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogDataHolder.java @@ -19,6 +19,7 @@ import com.intellij.openapi.Disposable; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.BackgroundTaskQueue; +import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; @@ -111,7 +112,9 @@ public class VcsLogDataHolder implements Disposable, VcsLogDataProvider { myDataPackUpdateHandler, new Consumer() { @Override public void consume(Exception e) { - LOG.error(e); + if (!(e instanceof ProcessCanceledException)) { + LOG.error(e); + } } }, mySettings.getRecentCommitsCount()); } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/PrimitiveArrayArgumentToVariableArgMethodInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/PrimitiveArrayArgumentToVariableArgMethodInspection.java index 90921cdb2cc1..f168f9d1f57c 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/PrimitiveArrayArgumentToVariableArgMethodInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/PrimitiveArrayArgumentToVariableArgMethodInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2006-2013 Dave Griffith, Bas Leijdekkers + * Copyright 2006-2014 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,6 +15,7 @@ */ package com.siyeh.ig.bugs; +import com.intellij.codeInsight.AnnotationUtil; import com.intellij.psi.*; import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.TypeConversionUtil; @@ -23,6 +24,8 @@ import com.siyeh.ig.BaseInspection; import com.siyeh.ig.BaseInspectionVisitor; import org.jetbrains.annotations.NotNull; +import java.util.Arrays; + public class PrimitiveArrayArgumentToVariableArgMethodInspection extends BaseInspection { @Override @@ -67,7 +70,7 @@ public class PrimitiveArrayArgumentToVariableArgMethodInspection extends BaseIns } final JavaResolveResult result = call.resolveMethodGenerics(); final PsiMethod method = (PsiMethod)result.getElement(); - if (method == null) { + if (method == null || AnnotationUtil.isAnnotated(method, Arrays.asList("java.lang.invoke.MethodHandle.PolymorphicSignature"))) { return; } final PsiParameterList parameterList = method.getParameterList(); diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/var_arg/PrimitiveArrayArgumentToVariableArgMethod.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/var_arg/PrimitiveArrayArgumentToVariableArgMethod.java index aa8620ac34c1..b6dcd68939dd 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/var_arg/PrimitiveArrayArgumentToVariableArgMethod.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/var_arg/PrimitiveArrayArgumentToVariableArgMethod.java @@ -1,11 +1,15 @@ package com.siyeh.igtest.bugs.var_arg; +import java.lang.invoke.MethodHandle; + public class PrimitiveArrayArgumentToVariableArgMethod { - public static void main(String[] arg) + public static void main(String[] arg) throws Throwable { - methodVarArgObject(new byte[3]); + methodVarArgObject(new byte[3]); methodVarArgByteArray(new byte[3]); + MethodHandle meh = null; + meh.invokeExact(new int[] { }); } private static void methodVarArgObject(Object... bytes) diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/var_arg/expected.xml b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/var_arg/expected.xml deleted file mode 100644 index cee36b29eb4e..000000000000 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/var_arg/expected.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - PrimitiveArrayArgumentToVariableArgMethod.java - 7 - Confusing primitive array argument to var-arg method - Confusing primitive array argument to var-arg method #loc - - \ No newline at end of file diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/bugs/PrimitiveArrayArgumentToVariableArgMethodInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/bugs/PrimitiveArrayArgumentToVariableArgMethodInspectionTest.java index 505385d32ca2..c88e008d377b 100644 --- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/bugs/PrimitiveArrayArgumentToVariableArgMethodInspectionTest.java +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/bugs/PrimitiveArrayArgumentToVariableArgMethodInspectionTest.java @@ -1,10 +1,23 @@ package com.siyeh.ig.bugs; -import com.siyeh.ig.IGInspectionTestCase; +import com.intellij.codeInspection.InspectionProfileEntry; +import com.siyeh.ig.LightInspectionTestCase; +import org.jetbrains.annotations.Nullable; -public class PrimitiveArrayArgumentToVariableArgMethodInspectionTest extends IGInspectionTestCase { +public class PrimitiveArrayArgumentToVariableArgMethodInspectionTest extends LightInspectionTestCase { - public void test() throws Exception { - doTest("com/siyeh/igtest/bugs/var_arg", new PrimitiveArrayArgumentToVariableArgMethodInspection()); + public void testPrimitiveArrayArgumentToVariableArgMethod() throws Exception { + doTest(); + } + + @Nullable + @Override + protected InspectionProfileEntry getInspection() { + return new PrimitiveArrayArgumentToVariableArgMethodInspection(); + } + + @Override + protected String getBasePath() { + return "/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/var_arg"; } } \ No newline at end of file diff --git a/plugins/git4idea/src/git4idea/GitBranch.java b/plugins/git4idea/src/git4idea/GitBranch.java index 0c7d394befda..acdd45a7f050 100644 --- a/plugins/git4idea/src/git4idea/GitBranch.java +++ b/plugins/git4idea/src/git4idea/GitBranch.java @@ -66,8 +66,8 @@ public abstract class GitBranch extends GitReference { * if this information wasn't supplied to the GitBranch constructor.

*/ @NotNull - public String getHash() { - return myHash.asString(); + public Hash getHash() { + return myHash; } /** diff --git a/plugins/git4idea/src/git4idea/GitUtil.java b/plugins/git4idea/src/git4idea/GitUtil.java index ffa394211faf..c0790eb6496b 100644 --- a/plugins/git4idea/src/git4idea/GitUtil.java +++ b/plugins/git4idea/src/git4idea/GitUtil.java @@ -15,7 +15,6 @@ */ package git4idea; -import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.collect.Collections2; import com.intellij.openapi.components.ServiceManager; @@ -26,7 +25,6 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogBuilder; import com.intellij.openapi.ui.ex.MultiLineLabel; import com.intellij.openapi.util.Condition; -import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.AbstractVcsHelper; @@ -99,14 +97,9 @@ public class GitUtil { public static final Charset UTF8_CHARSET = Charset.forName(UTF8_ENCODING); public static final String DOT_GIT = ".git"; - private final static Logger LOG = Logger.getInstance(GitUtil.class); + public static final String ORIGIN_HEAD = "origin/HEAD"; - public static final Predicate NOT_NULL_PREDICATE = new Predicate() { - @Override - public boolean apply(@Nullable GitBranchTrackInfo input) { - return input != null; - } - }; + private final static Logger LOG = Logger.getInstance(GitUtil.class); /** * A private constructor to suppress instance creation @@ -226,22 +219,6 @@ public class GitUtil { return sortFilePathsByGitRoot(files, false); } - /** - * Sort files by vcs root - * - * @param files files to sort. - * @return the map from root to the files under the root - */ - public static Map> sortGitFilePathsByGitRoot(Collection files) { - try { - return sortFilePathsByGitRoot(files, true); - } - catch (VcsException e) { - throw new RuntimeException("Unexpected exception:", e); - } - } - - /** * Sort files by vcs root * @@ -687,8 +664,13 @@ public class GitUtil { @Nullable - public static GitRemote findRemoteByName(@NotNull GitRepository repository, @Nullable final String name) { - return ContainerUtil.find(repository.getRemotes(), new Condition() { + public static GitRemote findRemoteByName(@NotNull GitRepository repository, @NotNull final String name) { + return findRemoteByName(repository.getRemotes(), name); + } + + @Nullable + public static GitRemote findRemoteByName(Collection remotes, @NotNull final String name) { + return ContainerUtil.find(remotes, new Condition() { @Override public boolean value(GitRemote remote) { return remote.getName().equals(name); @@ -709,39 +691,6 @@ public class GitUtil { }); } - /** - * @deprecated Calls Git for tracked info, use {@link GitRepository#getBranchTrackInfos()} instead. - */ - @Nullable - @Deprecated - public static Pair findMatchingRemoteBranch(GitRepository repository, GitLocalBranch branch) - throws VcsException { - /* - from man git-push: - git push - Works like git push , where is the current branch's remote (or origin, if no - remote is configured for the current branch). - - */ - String remoteName = GitBranchUtil.getTrackedRemoteName(repository.getProject(), repository.getRoot(), branch.getName()); - GitRemote remote; - if (remoteName == null) { - remote = findOrigin(repository.getRemotes()); - } else { - remote = findRemoteByName(repository, remoteName); - } - if (remote == null) { - return null; - } - - for (GitRemoteBranch remoteBranch : repository.getBranches().getRemoteBranches()) { - if (remoteBranch.getName().equals(remote.getName() + "/" + branch.getName())) { - return Pair.create(remote, remoteBranch); - } - } - return null; - } - @Nullable private static GitRemote findOrigin(Collection remotes) { for (GitRemote remote : remotes) { @@ -752,10 +701,6 @@ public class GitUtil { return null; } - public static boolean repoContainsRemoteBranch(@NotNull GitRepository repository, @NotNull GitRemoteBranch dest) { - return repository.getBranches().getRemoteBranches().contains(dest); - } - @NotNull public static Collection getRootsFromRepositories(@NotNull Collection repositories) { Collection roots = new ArrayList(repositories.size()); diff --git a/plugins/git4idea/src/git4idea/actions/GitRepositoryAction.java b/plugins/git4idea/src/git4idea/actions/GitRepositoryAction.java index 7ee419e6ae9d..042b651c6840 100644 --- a/plugins/git4idea/src/git4idea/actions/GitRepositoryAction.java +++ b/plugins/git4idea/src/git4idea/actions/GitRepositoryAction.java @@ -18,9 +18,6 @@ package git4idea.actions; import com.intellij.openapi.actionSystem.ActionPlaces; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; -import com.intellij.openapi.actionSystem.DataContext; -import com.intellij.openapi.actionSystem.PlatformDataKeys; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; @@ -53,21 +50,10 @@ public abstract class GitRepositoryAction extends DumbAwareAction { */ final List myDelayedTasks = new ArrayList(); - /** - * {@inheritDoc} - */ - public void actionPerformed(final AnActionEvent e) { + public void actionPerformed(@NotNull final AnActionEvent e) { myDelayedTasks.clear(); - ApplicationManager.getApplication().runWriteAction(new Runnable() { - public void run() { - FileDocumentManager.getInstance().saveAllDocuments(); - } - }); - DataContext dataContext = e.getDataContext(); - final Project project = CommonDataKeys.PROJECT.getData(dataContext); - if (project == null) { - return; - } + FileDocumentManager.getInstance().saveAllDocuments(); + final Project project = e.getRequiredData(CommonDataKeys.PROJECT); GitVcs vcs = GitVcs.getInstance(project); final List roots = getGitRoots(project, vcs); if (roots == null) return; @@ -196,9 +182,6 @@ public abstract class GitRepositoryAction extends DumbAwareAction { final Set affectedRoots, List exceptions) throws VcsException; - /** - * {@inheritDoc} - */ @Override public void update(final AnActionEvent e) { super.update(e); diff --git a/plugins/git4idea/src/git4idea/branch/GitBranchUtil.java b/plugins/git4idea/src/git4idea/branch/GitBranchUtil.java index 4cc356e27df8..b996dea69e5f 100644 --- a/plugins/git4idea/src/git4idea/branch/GitBranchUtil.java +++ b/plugins/git4idea/src/git4idea/branch/GitBranchUtil.java @@ -16,10 +16,8 @@ package git4idea.branch; import com.google.common.base.Function; -import com.google.common.base.Optional; import com.google.common.base.Predicate; import com.google.common.collect.Collections2; -import com.google.common.collect.Iterables; import com.intellij.dvcs.DvcsUtil; import com.intellij.dvcs.repo.RepositoryUtil; import com.intellij.openapi.diagnostic.Logger; @@ -32,7 +30,6 @@ import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.containers.ContainerUtil; -import com.intellij.vcs.log.Hash; import com.intellij.vcsUtil.VcsUtil; import git4idea.*; import git4idea.commands.GitCommand; @@ -47,7 +44,10 @@ import org.jetbrains.annotations.Nullable; import java.io.File; import java.io.IOException; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; /** * @author Kirill Likhodedov @@ -208,46 +208,6 @@ public class GitBranchUtil { return remote; } - /** - * - * @return {@link git4idea.GitStandardRemoteBranch} or {@link GitSvnRemoteBranch}, or null in case of an error. The error is logged in this method. - * @deprecated Should be used only in the GitRepositoryReader, i. e. moved there once all other usages are removed. - */ - @Deprecated - @Nullable - public static GitRemoteBranch parseRemoteBranch(@NotNull String fullBranchName, @NotNull Hash hash, - @NotNull Collection remotes) { - String stdName = stripRefsPrefix(fullBranchName); - - int slash = stdName.indexOf('/'); - if (slash == -1) { // .git/refs/remotes/my_branch => git-svn - return new GitSvnRemoteBranch(fullBranchName, hash); - } - else { - String remoteName = stdName.substring(0, slash); - String branchName = stdName.substring(slash + 1); - GitRemote remote = findRemoteByName(remoteName, remotes); - if (remote == null) { - // user may remove the remote section from .git/config, but leave remote refs untouched in .git/refs/remotes - LOG.info(String.format("No remote found with the name [%s]. All remotes: %s", remoteName, remotes)); - GitRemote fakeRemote = new GitRemote(remoteName, ContainerUtil.emptyList(), Collections.emptyList(), - Collections.emptyList(), Collections.emptyList()); - return new GitStandardRemoteBranch(fakeRemote, branchName, hash); - } - return new GitStandardRemoteBranch(remote, branchName, hash); - } - } - - @Nullable - private static GitRemote findRemoteByName(@NotNull String remoteName, @NotNull Collection remotes) { - for (GitRemote remote : remotes) { - if (remote.getName().equals(remoteName)) { - return remote; - } - } - return null; - } - /** * Convert {@link git4idea.GitRemoteBranch GitRemoteBranches} to their names, and remove remote HEAD pointers: origin/HEAD. */ @@ -262,50 +222,6 @@ public class GitBranchUtil { }); } - /** - * @deprecated Don't use names, use {@link GitLocalBranch} objects. - */ - @Deprecated - @Nullable - public static GitLocalBranch findLocalBranchByName(@NotNull GitRepository repository, @NotNull final String branchName) { - Optional optional = Iterables.tryFind(repository.getBranches().getLocalBranches(), new Predicate() { - @Override - public boolean apply(@Nullable GitLocalBranch input) { - assert input != null; - return input.getName().equals(branchName); - } - }); - if (optional.isPresent()) { - return optional.get(); - } - LOG.info(String.format("Couldn't find branch with name %s in %s", branchName, repository)); - return null; - - } - - /** - * Looks through the remote branches in the given repository and tries to find the one from the given remote, - * which the given name. - * @return remote branch or null if such branch couldn't be found. - */ - @Nullable - public static GitRemoteBranch findRemoteBranchByName(@NotNull String remoteBranchName, @NotNull final String remoteName, - @NotNull final Collection remoteBranches) { - final String branchName = stripRefsPrefix(remoteBranchName); - Optional optional = Iterables.tryFind(remoteBranches, new Predicate() { - @Override - public boolean apply(@Nullable GitRemoteBranch input) { - assert input != null; - return input.getNameForRemoteOperations().equals(branchName) && input.getRemote().getName().equals(remoteName); - } - }); - if (optional.isPresent()) { - return optional.get(); - } - LOG.info(String.format("Couldn't find branch with name %s", branchName)); - return null; - } - @NotNull public static String stripRefsPrefix(@NotNull String branchName) { if (branchName.startsWith(GitBranch.REFS_HEADS_PREFIX)) { diff --git a/plugins/git4idea/src/git4idea/history/GitHistoryUtils.java b/plugins/git4idea/src/git4idea/history/GitHistoryUtils.java index 1c310492059d..f50604bcf6d3 100644 --- a/plugins/git4idea/src/git4idea/history/GitHistoryUtils.java +++ b/plugins/git4idea/src/git4idea/history/GitHistoryUtils.java @@ -585,7 +585,7 @@ public class GitHistoryUtils { public VcsRef fun(String refName) { VcsRefType type = GitRefManager.getRefType(refName); refName = GitBranchUtil.stripRefsPrefix(refName); - return factory.createRef(hash, refName, type, root); + return refName.equals(GitUtil.ORIGIN_HEAD) ? null : factory.createRef(hash, refName, type, root); } }); } diff --git a/plugins/git4idea/src/git4idea/log/GitLogProvider.java b/plugins/git4idea/src/git4idea/log/GitLogProvider.java index 0b50a55c5e1a..d89d2540592a 100644 --- a/plugins/git4idea/src/git4idea/log/GitLogProvider.java +++ b/plugins/git4idea/src/git4idea/log/GitLogProvider.java @@ -39,6 +39,7 @@ import git4idea.history.GitHistoryUtils; import git4idea.repo.GitRepository; import git4idea.repo.GitRepositoryChangeListener; import git4idea.repo.GitRepositoryManager; +import gnu.trove.THashSet; import gnu.trove.TObjectHashingStrategy; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -121,10 +122,10 @@ public class GitLogProvider implements VcsLogProvider { currentTagNames = readCurrentTagNames(root); addOldStillExistingTags(allRefs, currentTagNames, rex.getPreviousRefs()); - allDetails = ContainerUtil.newHashSet(data.getCommits()); + allDetails = newHashSet(data.getCommits()); - Set previousTags = new HashSet(ContainerUtil.mapNotNull(rex.getPreviousRefs(), GET_TAG_NAME)); - Set safeTags = new HashSet(ContainerUtil.mapNotNull(safeRefs, GET_TAG_NAME)); + Set previousTags = newHashSet(ContainerUtil.mapNotNull(rex.getPreviousRefs(), GET_TAG_NAME)); + Set safeTags = newHashSet(ContainerUtil.mapNotNull(safeRefs, GET_TAG_NAME)); Set newUnmatchedTags = remove(currentTagNames, previousTags, safeTags); if (!newUnmatchedTags.isEmpty()) { @@ -263,14 +264,14 @@ public class GitLogProvider implements VcsLogProvider { @NotNull private Set readCurrentTagNames(@NotNull VirtualFile root) throws VcsException { - Set tags = ContainerUtil.newHashSet(); + Set tags = newHashSet(); GitTag.listAsStrings(myProject, root, tags, null); return tags; } @NotNull private static Set remove(@NotNull Set original, @NotNull Set... toRemove) { - Set result = ContainerUtil.newHashSet(original); + Set result = newHashSet(original); for (Set set : toRemove) { result.removeAll(set); } @@ -305,8 +306,8 @@ public class GitLogProvider implements VcsLogProvider { parameters.add("--sparse"); final GitBekParentFixer parentFixer = GitBekParentFixer.prepare(root, this); - Set userRegistry = ContainerUtil.newHashSet(); - Set refs = ContainerUtil.newHashSet(); + Set userRegistry = newHashSet(); + Set refs = newHashSet(); GitHistoryUtils.readCommits(myProject, root, parameters, new CollectConsumer(userRegistry), new CollectConsumer(refs), new Consumer() { @Override @@ -339,13 +340,13 @@ public class GitLogProvider implements VcsLogProvider { VirtualFile root = repository.getRoot(); Collection localBranches = repository.getBranches().getLocalBranches(); Collection remoteBranches = repository.getBranches().getRemoteBranches(); - Set refs = new HashSet(localBranches.size() + remoteBranches.size()); + Set refs = new THashSet(localBranches.size() + remoteBranches.size()); for (GitLocalBranch localBranch : localBranches) { refs.add( - myVcsObjectsFactory.createRef(HashImpl.build(localBranch.getHash()), localBranch.getName(), GitRefManager.LOCAL_BRANCH, root)); + myVcsObjectsFactory.createRef(localBranch.getHash(), localBranch.getName(), GitRefManager.LOCAL_BRANCH, root)); } for (GitRemoteBranch remoteBranch : remoteBranches) { - refs.add(myVcsObjectsFactory.createRef(HashImpl.build(remoteBranch.getHash()), remoteBranch.getNameForLocalOperations(), + refs.add(myVcsObjectsFactory.createRef(remoteBranch.getHash(), remoteBranch.getNameForLocalOperations(), GitRefManager.REMOTE_BRANCH, root)); } String currentRevision = repository.getCurrentRevision(); @@ -495,4 +496,15 @@ public class GitLogProvider implements VcsLogProvider { } return true; } + + @NotNull + private static Set newHashSet() { + return new THashSet(); + } + + @NotNull + private static Set newHashSet(@NotNull Collection initialCollection) { + return new THashSet(initialCollection); + } + } \ No newline at end of file diff --git a/plugins/git4idea/src/git4idea/merge/GitPullDialog.java b/plugins/git4idea/src/git4idea/merge/GitPullDialog.java index ee8ddf33e582..eaf372e5f4f7 100644 --- a/plugins/git4idea/src/git4idea/merge/GitPullDialog.java +++ b/plugins/git4idea/src/git4idea/merge/GitPullDialog.java @@ -22,6 +22,8 @@ import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.ListCellRendererWrapper; +import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; import git4idea.GitBranch; import git4idea.GitRemoteBranch; import git4idea.GitUtil; @@ -170,11 +172,13 @@ public class GitPullDialog extends DialogWrapper { String currentRemoteBranch = trackInfo == null ? null : trackInfo.getRemoteBranch().getNameForLocalOperations(); List remoteBranches = new ArrayList(repository.getBranches().getRemoteBranches()); Collections.sort(remoteBranches); - for (GitBranch remoteBranch : remoteBranches) { - if (belongsToRemote(remoteBranch, selectedRemote)) { - myBranchChooser.addElement(remoteBranch.getName(), remoteBranch.getName().equals(currentRemoteBranch)); + myBranchChooser.setElements(ContainerUtil.map(remoteBranches, new Function() { + @Override + public String fun(GitRemoteBranch branch) { + return branch.getName(); } - } + }), false); + myBranchChooser.setElementMarked(currentRemoteBranch, true); validateDialog(); } diff --git a/plugins/git4idea/src/git4idea/repo/GitConfig.java b/plugins/git4idea/src/git4idea/repo/GitConfig.java index 4b0bdeadc8f9..aeb0bf8eb55c 100644 --- a/plugins/git4idea/src/git4idea/repo/GitConfig.java +++ b/plugins/git4idea/src/git4idea/repo/GitConfig.java @@ -158,7 +158,7 @@ public class GitConfig { Pair, Collection> remotesAndUrls = parseRemotes(ini, classLoader); Collection trackedInfos = parseTrackedInfos(ini, classLoader); - + return new GitConfig(remotesAndUrls.getFirst(), remotesAndUrls.getSecond(), trackedInfos); } @@ -201,12 +201,12 @@ public class GitConfig { boolean merge = mergeName != null; final String remoteBranchName = (merge ? mergeName : rebaseName); - assert remoteName != null; - assert remoteBranchName != null; GitLocalBranch localBranch = findLocalBranch(branchName, localBranches); - GitRemoteBranch remoteBranch = GitBranchUtil.findRemoteBranchByName(remoteBranchName, remoteName, remoteBranches); + GitRemoteBranch remoteBranch = findRemoteBranch(remoteBranchName, remoteName, remoteBranches); if (localBranch == null || remoteBranch == null) { + // obsolete record in .git/config: local or remote branch doesn't exist, but the tracking information wasn't removed + LOG.debug("localBranch: " + localBranch + ", remoteBranch: " + remoteBranch); return null; } return new GitBranchTrackInfo(localBranch, remoteBranch, merge); @@ -215,19 +215,25 @@ public class GitConfig { @Nullable private static GitLocalBranch findLocalBranch(@NotNull String branchName, @NotNull Collection localBranches) { final String name = GitBranchUtil.stripRefsPrefix(branchName); - try { - return ContainerUtil.find(localBranches, new Condition() { - @Override - public boolean value(@Nullable GitLocalBranch input) { - assert input != null; - return input.getName().equals(name); - } - }); - } - catch (NoSuchElementException e) { - LOG.info("Couldn't find branch with name " + name); - return null; - } + return ContainerUtil.find(localBranches, new Condition() { + @Override + public boolean value(@Nullable GitLocalBranch input) { + assert input != null; + return input.getName().equals(name); + } + }); + } + + @Nullable + public static GitRemoteBranch findRemoteBranch(@NotNull String remoteBranchName, @NotNull final String remoteName, + @NotNull final Collection remoteBranches) { + final String branchName = GitBranchUtil.stripRefsPrefix(remoteBranchName); + return ContainerUtil.find(remoteBranches, new Condition() { + @Override + public boolean value(GitRemoteBranch branch) { + return branch.getNameForRemoteOperations().equals(branchName) && branch.getRemote().getName().equals(remoteName); + } + }); } @Nullable diff --git a/plugins/git4idea/src/git4idea/repo/GitRepositoryImpl.java b/plugins/git4idea/src/git4idea/repo/GitRepositoryImpl.java index 3f6f25f1dc46..30951670e079 100644 --- a/plugins/git4idea/src/git4idea/repo/GitRepositoryImpl.java +++ b/plugins/git4idea/src/git4idea/repo/GitRepositoryImpl.java @@ -217,7 +217,7 @@ public class GitRepositoryImpl extends RepositoryImpl implements GitRepository { if (Disposer.isDisposed(repository.getProject())) { return; } - if (previousInfo != null && !info.equals(previousInfo)) { + if (!info.equals(previousInfo)) { repository.getProject().getMessageBus().syncPublisher(GIT_REPO_CHANGE).repositoryChanged(repository); } } diff --git a/plugins/git4idea/src/git4idea/repo/GitRepositoryReader.java b/plugins/git4idea/src/git4idea/repo/GitRepositoryReader.java index 576f326a8ea3..66ce94172794 100644 --- a/plugins/git4idea/src/git4idea/repo/GitRepositoryReader.java +++ b/plugins/git4idea/src/git4idea/repo/GitRepositoryReader.java @@ -25,9 +25,7 @@ import com.intellij.util.Processor; import com.intellij.util.containers.ContainerUtil; import com.intellij.vcs.log.Hash; import com.intellij.vcs.log.impl.HashImpl; -import git4idea.GitBranch; -import git4idea.GitLocalBranch; -import git4idea.GitRemoteBranch; +import git4idea.*; import git4idea.branch.GitBranchUtil; import git4idea.branch.GitBranchesCollection; import org.jetbrains.annotations.NonNls; @@ -349,7 +347,7 @@ class GitRepositoryReader { String hash = loadHashFromBranchFile(file); Hash h = createHash(hash); if (h != null) { - GitRemoteBranch remoteBranch = GitBranchUtil.parseRemoteBranch(branchName, h, remotes); + GitRemoteBranch remoteBranch = parseRemoteBranch(branchName, h, remotes); if (remoteBranch != null) { branches.add(remoteBranch); } @@ -386,7 +384,7 @@ class GitRepositoryReader { localBranches.add(new GitLocalBranch(branchName, hash)); } else if (branchName.startsWith(REFS_REMOTES_PREFIX)) { - GitRemoteBranch remoteBranch = GitBranchUtil.parseRemoteBranch(branchName, hash, remotes); + GitRemoteBranch remoteBranch = parseRemoteBranch(branchName, hash, remotes); if (remoteBranch != null) { remoteBranches.add(remoteBranch); } @@ -395,6 +393,31 @@ class GitRepositoryReader { return new GitBranchesCollection(localBranches, remoteBranches); } + @Nullable + private static GitRemoteBranch parseRemoteBranch(@NotNull String fullBranchName, + @NotNull Hash hash, + @NotNull Collection remotes) { + String stdName = GitBranchUtil.stripRefsPrefix(fullBranchName); + + int slash = stdName.indexOf('/'); + if (slash == -1) { // .git/refs/remotes/my_branch => git-svn + return new GitSvnRemoteBranch(fullBranchName, hash); + } + else { + String remoteName = stdName.substring(0, slash); + String branchName = stdName.substring(slash + 1); + GitRemote remote = GitUtil.findRemoteByName(remotes, remoteName); + if (remote == null) { + // user may remove the remote section from .git/config, but leave remote refs untouched in .git/refs/remotes + LOG.debug(String.format("No remote found with the name [%s]. All remotes: %s", remoteName, remotes)); + GitRemote fakeRemote = new GitRemote(remoteName, ContainerUtil.emptyList(), Collections.emptyList(), + Collections.emptyList(), Collections.emptyList()); + return new GitStandardRemoteBranch(fakeRemote, branchName, hash); + } + return new GitStandardRemoteBranch(remote, branchName, hash); + } + } + @NotNull private static String readBranchFile(@NotNull File branchFile) { return RepositoryUtil.tryLoadFile(branchFile); diff --git a/plugins/git4idea/src/git4idea/ui/branch/GitMultiRootBranchConfig.java b/plugins/git4idea/src/git4idea/ui/branch/GitMultiRootBranchConfig.java index 18076a1b9a61..360cf56fe505 100644 --- a/plugins/git4idea/src/git4idea/ui/branch/GitMultiRootBranchConfig.java +++ b/plugins/git4idea/src/git4idea/ui/branch/GitMultiRootBranchConfig.java @@ -103,7 +103,7 @@ public class GitMultiRootBranchConfig extends DvcsMultiRootBranchConfigemptySet())); + assertFalse("origin/HEAD should be ignored", ContainerUtil.exists(block.getRefs(), new Condition() { + @Override + public boolean value(VcsRef ref) { + return ref.getName().equals("origin/HEAD"); + } + })); + } + private static void prepareSomeHistory() { tac("a.txt"); git("tag ATAG"); diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/surroundWith/SurrounderOrderTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/surroundWith/SurrounderOrderTest.groovy index b038c11de80f..aca3fa8ea5be 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/surroundWith/SurrounderOrderTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/surroundWith/SurrounderOrderTest.groovy @@ -39,7 +39,9 @@ class SurrounderOrderTest extends LightCodeInsightFixtureTestCase { "(expr)", "!(expr)", "((Type) expr)", - "with () {...}" + "with () {...}", + " Comments", + "region...endregion Comments" } public void testStatementWithSemicolon() throws Exception { @@ -50,7 +52,9 @@ class SurrounderOrderTest extends LightCodeInsightFixtureTestCase { "{}", "for", "try / catch", "try / finally", "try / catch / finally", "shouldFail () {...}", - "with () {...}" + "with () {...}", + " Comments", + "region...endregion Comments" } public void testStatementsWithComments() throws Exception { @@ -64,7 +68,9 @@ println c /*also important */ "{}", "for", "try / catch", "try / finally", "try / catch / finally", "shouldFail () {...}", - "with () {...}" + "with () {...}", + " Comments", + "region...endregion Comments" } public void testInnerExpressionSurrounders() { diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/GotoTaskAction.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/GotoTaskAction.java index 6174054be32f..40a9cf04afbc 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/GotoTaskAction.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/GotoTaskAction.java @@ -54,7 +54,6 @@ public class GotoTaskAction extends GotoActionBase implements DumbAware { popup.setShowListForEmptyPattern(true); popup.setSearchInAnyPlace(true); - popup.setFixLostTyping(false); popup.setAlwaysHasMore(true); popup.setAdText("Press SHIFT to merge with current context
" + "Pressing " + diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/TaskItemProvider.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/TaskItemProvider.java index 63bff938a26f..0bd5835cd1a6 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/TaskItemProvider.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/TaskItemProvider.java @@ -26,7 +26,7 @@ import java.util.concurrent.atomic.AtomicReference; class TaskItemProvider implements ChooseByNameItemProvider, Disposable { private static final Logger LOG = Logger.getInstance(TaskItemProvider.class); - private static final int DELAY_PERIOD = 1000; // ms + private static final int DELAY_PERIOD = 200; // ms private final Project myProject; @@ -76,19 +76,31 @@ class TaskItemProvider implements ChooseByNameItemProvider, Disposable { }); // Newer request always wins - Future> oldFeature = myFutureReference.getAndSet(future); - if (oldFeature != null) { + Future> oldFuture = myFutureReference.getAndSet(future); + if (oldFuture != null) { LOG.debug("Cancelling existing task"); - oldFeature.cancel(true); + oldFuture.cancel(true); } if (myAlarm.isDisposed()) { return false; } - myAlarm.addRequest(future, DELAY_PERIOD); + myAlarm.addRequest(future, oldFuture == null && pattern.length() > 5 ? 0 : DELAY_PERIOD); try { - List tasks = future.get(); + List tasks; + while (true) { + try { + tasks = future.get(10, TimeUnit.MILLISECONDS); + break; + } + catch (TimeoutException ignore) { + } + if (base.hasPostponedAction()) { + future.cancel(true); + return true; + } + } myFutureReference.compareAndSet(future, null); // Exclude *all* cached and local issues, not only those returned by TaskSearchSupport.getLocalAndCachedTasks(). diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/config/TaskRepositoriesConfigurable.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/config/TaskRepositoriesConfigurable.java index 2ab1079ac56c..02b599ed1340 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/config/TaskRepositoriesConfigurable.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/config/TaskRepositoriesConfigurable.java @@ -8,6 +8,7 @@ import com.intellij.openapi.actionSystem.Separator; import com.intellij.openapi.options.BaseConfigurable; import com.intellij.openapi.options.Configurable; import com.intellij.openapi.options.ConfigurationException; +import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ui.configuration.actions.IconWithTextAction; import com.intellij.openapi.ui.Splitter; @@ -27,6 +28,7 @@ import com.intellij.util.containers.ConcurrentFactoryMap; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.FactoryMap; import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; @@ -86,12 +88,10 @@ public class TaskRepositoriesConfigurable extends BaseConfigurable implements Co final List createActions = new ArrayList(); for (final TaskRepositoryType repositoryType : groups) { for (final TaskRepositorySubtype subtype : (List)repositoryType.getAvailableSubtypes()) { - String description = "New " + subtype.getName() + " server"; - createActions.add(new IconWithTextAction(subtype.getName(), description, subtype.getIcon()) { + createActions.add(new AddServerAction(subtype) { @Override - public void actionPerformed(AnActionEvent e) { - TaskRepository repository = repositoryType.createRepository(subtype); - addRepository(repository); + protected TaskRepository getRepository() { + return repositoryType.createRepository(subtype); } }); } @@ -111,10 +111,10 @@ public class TaskRepositoriesConfigurable extends BaseConfigurable implements Co if (!repositories.isEmpty()) { group.add(Separator.getInstance()); for (final TaskRepository repository : repositories) { - group.add(new IconWithTextAction(repository.getUrl(), repository.getUrl(), repository.getIcon()) { + group.add(new AddServerAction(repository) { @Override - public void actionPerformed(AnActionEvent e) { - addRepository(repository); + protected TaskRepository getRepository() { + return repository; } }); } @@ -122,7 +122,7 @@ public class TaskRepositoriesConfigurable extends BaseConfigurable implements Co JBPopupFactory.getInstance() .createActionGroupPopup("Add server", group, DataManager.getInstance().getDataContext(anActionButton.getContextComponent()), - JBPopupFactory.ActionSelectionAid.SPEEDSEARCH, false).show( + JBPopupFactory.ActionSelectionAid.SPEEDSEARCH, true).show( anActionButton.getPreferredPopupPoint()); } }); @@ -151,7 +151,7 @@ public class TaskRepositoriesConfigurable extends BaseConfigurable implements Co myServersPanel.add(toolbarDecorator.createPanel(), BorderLayout.CENTER); myRepositoriesList.getSelectionModel().addListSelectionListener(new ListSelectionListener() { - public void valueChanged(ListSelectionEvent e) { + public void valueChanged(@NotNull ListSelectionEvent e) { TaskRepository repository = getSelectedRepository(); if (repository != null) { String name = myRepoNames.get(repository); @@ -182,21 +182,17 @@ public class TaskRepositoriesConfigurable extends BaseConfigurable implements Co private void addRepository(TaskRepository repository) { myRepositories.add(repository); ((CollectionListModel)myRepositoriesList.getModel()).add(repository); - addRepositoryEditor(repository, true); + addRepositoryEditor(repository); myRepositoriesList.setSelectedIndex(myRepositoriesList.getModel().getSize() - 1); } - private void addRepositoryEditor(TaskRepository repository, boolean requestFocus) { + private void addRepositoryEditor(TaskRepository repository) { TaskRepositoryEditor editor = repository.getRepositoryType().createEditor(repository, myProject, myChangeListener); myEditors.add(editor); JComponent component = editor.createComponent(); String name = myRepoNames.get(repository); myRepositoryEditor.add(component, name); myRepositoryEditor.doLayout(); - JComponent preferred = editor.getPreferredFocusedComponent(); - if (preferred != null && requestFocus) { -// IdeFocusManager.getInstance(myProject).requestFocus(preferred, false); - } } @Nullable @@ -255,7 +251,7 @@ public class TaskRepositoriesConfigurable extends BaseConfigurable implements Co myRepositoriesList.setModel(listModel); for (TaskRepository clone : myRepositories) { - addRepositoryEditor(clone, false); + addRepositoryEditor(clone); } if (!myRepositories.isEmpty()) { @@ -272,4 +268,22 @@ public class TaskRepositoriesConfigurable extends BaseConfigurable implements Co Disposer.dispose(editor); } } + + private abstract class AddServerAction extends IconWithTextAction implements DumbAware { + + public AddServerAction(TaskRepositorySubtype subtype) { + super(subtype.getName(), "New " + subtype.getName() + " server", subtype.getIcon()); + } + + public AddServerAction(TaskRepository repository) { + super(repository.getUrl(), repository.getUrl(), repository.getIcon()); + } + + protected abstract TaskRepository getRepository(); + + @Override + public void actionPerformed(@NotNull AnActionEvent e) { + addRepository(getRepository()); + } + } } diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/context/XDebuggerBreakpointsContextProvider.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/context/XDebuggerBreakpointsContextProvider.java index 2e8d5df8c823..ec4d81f86d2c 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/context/XDebuggerBreakpointsContextProvider.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/context/XDebuggerBreakpointsContextProvider.java @@ -56,7 +56,7 @@ public class XDebuggerBreakpointsContextProvider extends WorkingContextProvider XBreakpointManagerImpl.BreakpointManagerState state = myBreakpointManager.getState(); Element serialize = XmlSerializer.serialize(state, new SerializationFilter() { @Override - public boolean accepts(Accessor accessor, Object bean) { + public boolean accepts(@NotNull Accessor accessor, Object bean) { return accessor.read(bean) != null; } }); diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/context/XDebuggerWatchesProvider.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/context/XDebuggerWatchesProvider.java index 62b26995daf2..2b39f86d30b8 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/context/XDebuggerWatchesProvider.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/context/XDebuggerWatchesProvider.java @@ -54,7 +54,7 @@ public class XDebuggerWatchesProvider extends WorkingContextProvider { XDebuggerWatchesManager.WatchesManagerState state = myWatchesManager.getState(); Element serialize = XmlSerializer.serialize(state, new SerializationFilter() { @Override - public boolean accepts(Accessor accessor, Object bean) { + public boolean accepts(@NotNull Accessor accessor, Object bean) { return accessor.read(bean) != null; } }); diff --git a/python/edu/build/pycharm_edu_build.gant b/python/edu/build/pycharm_edu_build.gant index 356df8c7d4c7..85889184ab09 100644 --- a/python/edu/build/pycharm_edu_build.gant +++ b/python/edu/build/pycharm_edu_build.gant @@ -144,8 +144,11 @@ target('default': "Build artifacts") { layoutEducational("${paths.sandbox}/classes/production", usedJars) - def extraArgs = ["build.code": "pycharm${buildName}", "build.number": "PE-$buildNumber", "artifacts.path": "${paths.artifacts}"] + signMacZip("pycharm", extraArgs) + notifyArtifactBuilt("${paths.artifacts}/pycharm${buildName}.sit") + buildDmg("pycharm", "${pythonEduHome}/build/DMG_background.png", extraArgs) + signMacZip("pycharm", extraArgs + ["sitFileName": "pycharm${buildName}-jdk-bundled", "jdk_archive_name": "jdk_mac_redist_for_${buildNumber}.tar"]) buildDmg("pycharm", "${pythonEduHome}/build/DMG_background.png", extraArgs + ["sitFileName": "pycharm${buildName}-jdk-bundled", "jdk_archive_name": "jdk_mac_redist_for_${buildNumber}.tar"]) @@ -206,7 +209,7 @@ public layoutEducational(String classesPath, Set usedJars) { String macAppRoot = isEap() ? "PyCharm Educational ${p("component.version.major")}.${p("component.version.minor")} EAP.app/Contents" : "PyCharm Educational.app/Contents" buildMacZip(macAppRoot, "${paths.artifacts}/pycharm${buildName}.sit", [paths.distAll], paths.distMac) ant.copy(file: "${paths.artifacts}/pycharm${buildName}.sit", tofile: "${paths.artifacts}/pycharm${buildName}-jdk-bundled.sit") - ant.delete(file: "${paths.artifacts}/pycharm${buildName}.sit") + //ant.delete(file: "${paths.artifacts}/pycharm${buildName}.sit") } private layoutPlugins(layouts) { diff --git a/python/helpers/pydev/pydevd_vars.py b/python/helpers/pydev/pydevd_vars.py index d9e1d28c37c5..db297f991928 100644 --- a/python/helpers/pydev/pydevd_vars.py +++ b/python/helpers/pydev/pydevd_vars.py @@ -399,16 +399,17 @@ def array_to_xml(array, roffset, coffset, rows, cols, format): cols = 1 elif rows == 1 or cols == 1: is_row = True if (rows == 1) else False - pure_1d = False if (len(array) == 1) else True + if is_row: + array = array[roffset:] + else: + array = array[coffset:] - if not pure_1d: + if len(array) == 1: array = array[0] if is_row: - array = array[coffset:] cols = min(cols, len(array)) else: - array = array[roffset:] rows = min(rows, len(array)) else: array = array[roffset:, coffset:] diff --git a/python/src/com/jetbrains/python/debugger/array/ArrayTableForm.java b/python/src/com/jetbrains/python/debugger/array/ArrayTableForm.java index 90b6d1c1b75c..f50f0161034f 100644 --- a/python/src/com/jetbrains/python/debugger/array/ArrayTableForm.java +++ b/python/src/com/jetbrains/python/debugger/array/ArrayTableForm.java @@ -15,6 +15,8 @@ */ package com.jetbrains.python.debugger.array; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.ex.EditorEx; import com.intellij.openapi.project.Project; import com.intellij.ui.EditorTextField; import com.intellij.ui.components.JBScrollPane; @@ -31,6 +33,7 @@ import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.DefaultTableModel; import javax.swing.table.JTableHeader; import java.awt.*; +import java.awt.event.KeyListener; /** * @author amarch @@ -46,23 +49,41 @@ public class ArrayTableForm { private JTable myTable; private JBTable myBusyTable; private final Project myProject; + private KeyListener myResliceCallback; + private KeyListener myReformatCallback; private static final String DATA_LOADING_IN_PROCESS = "Please wait, load array data."; private static final String NOT_APPLICABLE = "View not applicable for "; - public ArrayTableForm(@NotNull Project project) { + public ArrayTableForm(@NotNull Project project, KeyListener resliceCallback, KeyListener reformatCallback) { myProject = project; + myResliceCallback = resliceCallback; + myReformatCallback = reformatCallback; } private void createUIComponents() { - mySliceTextField = new EditorTextField("", myProject, PythonFileType.INSTANCE); + mySliceTextField = new EditorTextField("", myProject, PythonFileType.INSTANCE) { + @Override + protected EditorEx createEditor() { + EditorEx editor = super.createEditor(); + editor.getContentComponent().addKeyListener(myResliceCallback); + return editor; + } + }; myTable = new JBTableWithRowHeaders(); myScrollPane = ((JBTableWithRowHeaders)myTable).getScrollPane(); - myFormatTextField = new EditorTextField("", myProject, PythonFileType.INSTANCE); + myFormatTextField = new EditorTextField("", myProject, PythonFileType.INSTANCE) { + @Override + protected EditorEx createEditor() { + EditorEx editor = super.createEditor(); + editor.getContentComponent().addKeyListener(myReformatCallback); + return editor; + } + }; myBusyTable = new JBTable(new DefaultTableModel()); myBusyTable.getEmptyText().setText(""); diff --git a/python/src/com/jetbrains/python/debugger/array/NumpyArrayTable.java b/python/src/com/jetbrains/python/debugger/array/NumpyArrayTable.java index 230e8c058974..dacf3d51a770 100644 --- a/python/src/com/jetbrains/python/debugger/array/NumpyArrayTable.java +++ b/python/src/com/jetbrains/python/debugger/array/NumpyArrayTable.java @@ -19,6 +19,7 @@ import com.intellij.codeInsight.hint.HintManager; import com.intellij.openapi.application.Result; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.RangeMarker; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; @@ -76,7 +77,21 @@ public class NumpyArrayTable { @NotNull PyViewArrayAction.ViewArrayDialog dialog, @NotNull PyDebugValue value) { myValue = value; myDialog = dialog; - myComponent = new ArrayTableForm(project); + myComponent = new ArrayTableForm(project, new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_ENTER) { + doReslice(getSliceText(), null); + } + } + }, new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_ENTER) { + doApplyFormat(); + } + } + }); myTable = myComponent.getTable(); myProject = project; myEvaluator = new PyDebuggerEvaluator(project, getDebugValue().getFrameAccessor()); @@ -127,9 +142,6 @@ public class NumpyArrayTable { }); } - // add slice actions - initSliceFieldActions(); - //make value name read-only myComponent.getSliceTextField().addFocusListener(new FocusListener() { @Override @@ -145,9 +157,6 @@ public class NumpyArrayTable { } } }); - - //add format actions - initFormatFieldActions(); } public void disableColor() { @@ -166,28 +175,6 @@ public class NumpyArrayTable { }); } - private void initSliceFieldActions() { - myComponent.getSliceTextField().addKeyListener(new KeyAdapter() { - @Override - public void keyPressed(KeyEvent e) { - if (e.getKeyCode() == KeyEvent.VK_ENTER) { - doReslice(getSliceText(), null); - } - } - }); - } - - private void initFormatFieldActions() { - myComponent.getFormatTextField().addKeyListener(new KeyAdapter() { - @Override - public void keyPressed(KeyEvent e) { - if (e.getKeyCode() == KeyEvent.VK_ENTER) { - doApplyFormat(); - } - } - }); - } - public PyDebugValue getDebugValue() { return myValue; } diff --git a/python/src/com/jetbrains/python/inspections/PyPropertyDefinitionInspection.java b/python/src/com/jetbrains/python/inspections/PyPropertyDefinitionInspection.java index e808a0d1dbdb..e52134dbfad9 100644 --- a/python/src/com/jetbrains/python/inspections/PyPropertyDefinitionInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyPropertyDefinitionInspection.java @@ -82,20 +82,20 @@ public class PyPropertyDefinitionInspection extends PyInspection { // save us continuous checks for level, module, stc myLevel = LanguageLevel.forElement(psiFile); // string classes - final List string_classes = new ArrayList(2); + final List stringClasses = new ArrayList(2); final PyBuiltinCache builtins = PyBuiltinCache.getInstance(psiFile); PyClass cls = builtins.getClass("str"); - if (cls != null) string_classes.add(cls); + if (cls != null) stringClasses.add(cls); cls = builtins.getClass("unicode"); - if (cls != null) string_classes.add(cls); - myStringClasses = string_classes; + if (cls != null) stringClasses.add(cls); + myStringClasses = stringClasses; // reference signatures - PyClass object_class = builtins.getClass("object"); - if (object_class != null) { - final PyFunction method_repr = object_class.findMethodByName("__repr__", false); - if (method_repr != null) myOneParamFunction = method_repr; - final PyFunction method_delattr = object_class.findMethodByName("__delattr__", false); - if (method_delattr != null) myTwoParamFunction = method_delattr; + PyClass objectClass = builtins.getClass("object"); + if (objectClass != null) { + final PyFunction methodRepr = objectClass.findMethodByName("__repr__", false); + if (methodRepr != null) myOneParamFunction = methodRepr; + final PyFunction methodDelattr = objectClass.findMethodByName("__delattr__", false); + if (methodDelattr != null) myTwoParamFunction = methodDelattr; } } @@ -121,10 +121,10 @@ public class PyPropertyDefinitionInspection extends PyInspection { assert arglist != null : "Property call has null arglist"; CallArgumentsMapping analysis = arglist.analyzeCall(getResolveContext()); // we assume fget, fset, fdel, doc names - for (Map.Entry entry: analysis.getPlainMappedParams().entrySet()) { - final String param_name = entry.getValue().getName(); + for (Map.Entry entry : analysis.getPlainMappedParams().entrySet()) { + final String paramName = entry.getValue().getName(); PyExpression argument = PyUtil.peelArgument(entry.getKey()); - checkPropertyCallArgument(param_name, argument, node.getContainingFile()); + checkPropertyCallArgument(paramName, argument, node.getContainingFile()); } } else { @@ -137,40 +137,45 @@ public class PyPropertyDefinitionInspection extends PyInspection { } return false; // always want more } - }, false); } - private void checkPropertyCallArgument(String param_name, PyExpression argument, PsiFile containingFile) { + private void checkPropertyCallArgument(String paramName, PyExpression argument, PsiFile containingFile) { assert argument != null : "Parameter mapped to null argument"; Callable callable = null; if (argument instanceof PyReferenceExpression) { final PsiPolyVariantReference reference = ((PyReferenceExpression)argument).getReference(getResolveContext()); - if (reference != null) { - PsiElement resolved = reference.resolve(); - if (resolved instanceof Callable) { - callable = (Callable)resolved; - } - else { - reportNonCallableArg(resolved, argument); - return; - } + PsiElement resolved = reference.resolve(); + if (resolved instanceof Callable) { + callable = (Callable)resolved; + } + else { + reportNonCallableArg(resolved, argument); + return; } } - else if (argument instanceof PyLambdaExpression) callable = (PyLambdaExpression)argument; - else if (! "doc".equals(param_name)) { + else if (argument instanceof PyLambdaExpression) { + callable = (PyLambdaExpression)argument; + } + else if (!"doc".equals(paramName)) { reportNonCallableArg(argument, argument); return; } if (callable != null && callable.getContainingFile() != containingFile) { return; } - if ("fget".equals(param_name)) checkGetter(callable, argument); - else if ("fset".equals(param_name)) checkSetter(callable, argument); - else if ("fdel".equals(param_name)) checkDeleter(callable, argument); - else if ("doc".equals(param_name)) { + if ("fget".equals(paramName)) { + checkGetter(callable, argument); + } + else if ("fset".equals(paramName)) { + checkSetter(callable, argument); + } + else if ("fdel".equals(paramName)) { + checkDeleter(callable, argument); + } + else if ("doc".equals(paramName)) { PyType type = myTypeEvalContext.getType(argument); - if (! (type instanceof PyClassType && myStringClasses.contains(((PyClassType)type).getPyClass()))) { + if (!(type instanceof PyClassType && myStringClasses.contains(((PyClassType)type).getPyClass()))) { registerProblem(argument, PyBundle.message("INSP.doc.param.should.be.str")); } } @@ -203,17 +208,21 @@ public class PyPropertyDefinitionInspection extends PyInspection { if (decos != null) { String name = node.getName(); for (PyDecorator deco : decos.getDecorators()) { - final QualifiedName q_name = deco.getQualifiedName(); - if (q_name != null) { - List name_parts = q_name.getComponents(); - if (name_parts.size() == 2) { - final int suffix_index = SUFFIXES.indexOf(name_parts.get(1)); - if (suffix_index >= 0) { - if (Comparing.equal(name, name_parts.get(0))) { + final QualifiedName qName = deco.getQualifiedName(); + if (qName != null) { + List nameParts = qName.getComponents(); + if (nameParts.size() == 2) { + final int suffixIndex = SUFFIXES.indexOf(nameParts.get(1)); + if (suffixIndex >= 0) { + if (Comparing.equal(name, nameParts.get(0))) { // names are ok, what about signatures? PsiElement markable = getFunctionMarkingElement(node); - if (suffix_index == 0) checkSetter(node, markable); - else checkDeleter(node, markable); + if (suffixIndex == 0) { + checkSetter(node, markable); + } + else { + checkDeleter(node, markable); + } } else { registerProblem(deco, PyBundle.message("INSP.func.property.name.mismatch")); @@ -230,37 +239,37 @@ public class PyPropertyDefinitionInspection extends PyInspection { @Nullable private static PsiElement getFunctionMarkingElement(PyFunction node) { if (node == null) return null; - final ASTNode name_node = node.getNameNode(); + final ASTNode nameNode = node.getNameNode(); PsiElement markable = node; - if (name_node != null) markable = name_node.getPsi(); + if (nameNode != null) markable = nameNode.getPsi(); return markable; } - private void checkGetter(Callable callable, PsiElement being_checked) { + private void checkGetter(Callable callable, PsiElement beingChecked) { if (callable != null) { - checkOneParameter(callable, being_checked, true); - checkReturnValueAllowed(callable, being_checked, true, PyBundle.message("INSP.getter.return.smth")); + checkOneParameter(callable, beingChecked, true); + checkReturnValueAllowed(callable, beingChecked, true, PyBundle.message("INSP.getter.return.smth")); } } - private void checkSetter(Callable callable, PsiElement being_checked) { + private void checkSetter(Callable callable, PsiElement beingChecked) { if (callable != null) { // signature: at least two params, more optionals ok; first arg 'self' - final PyParameterList param_list = callable.getParameterList(); + final PyParameterList paramList = callable.getParameterList(); if (myTwoParamFunction != null && !PyUtil.isSignatureCompatibleTo(callable, myTwoParamFunction, myTypeEvalContext)) { - registerProblem(being_checked, PyBundle.message("INSP.setter.signature.advice"), new PyUpdatePropertySignatureQuickFix(true)); + registerProblem(beingChecked, PyBundle.message("INSP.setter.signature.advice"), new PyUpdatePropertySignatureQuickFix(true)); } - checkForSelf(param_list); + checkForSelf(paramList); // no explicit return type - checkReturnValueAllowed(callable, being_checked, false, PyBundle.message("INSP.setter.should.not.return")); + checkReturnValueAllowed(callable, beingChecked, false, PyBundle.message("INSP.setter.should.not.return")); } } - private void checkDeleter(Callable callable, PsiElement being_checked) { + private void checkDeleter(Callable callable, PsiElement beingChecked) { if (callable != null) { - checkOneParameter(callable, being_checked, false); - checkReturnValueAllowed(callable, being_checked, false, PyBundle.message("INSP.deleter.should.not.return")); + checkOneParameter(callable, beingChecked, false); + checkReturnValueAllowed(callable, beingChecked, false, PyBundle.message("INSP.deleter.should.not.return")); } } @@ -278,25 +287,26 @@ public class PyPropertyDefinitionInspection extends PyInspection { checkForSelf(parameterList); } - private void checkForSelf(PyParameterList param_list) { - PyParameter[] parameters = param_list.getParameters(); - final PyClass cls = PsiTreeUtil.getParentOfType(param_list, PyClass.class); + private void checkForSelf(PyParameterList paramList) { + PyParameter[] parameters = paramList.getParameters(); + final PyClass cls = PsiTreeUtil.getParentOfType(paramList, PyClass.class); if (cls != null && cls.isSubclass("type")) return; - if (parameters.length > 0 && ! PyNames.CANONICAL_SELF.equals(parameters[0].getName())) { + if (parameters.length > 0 && !PyNames.CANONICAL_SELF.equals(parameters[0].getName())) { registerProblem( - parameters[0], PyBundle.message("INSP.accessor.first.param.is.$0", PyNames.CANONICAL_SELF), ProblemHighlightType.WEAK_WARNING, null, + parameters[0], PyBundle.message("INSP.accessor.first.param.is.$0", PyNames.CANONICAL_SELF), ProblemHighlightType.WEAK_WARNING, + null, new RenameParameterQuickFix(PyNames.CANONICAL_SELF)); } } - private void checkReturnValueAllowed(Callable callable, PsiElement being_checked, boolean allowed, String message) { + private void checkReturnValueAllowed(Callable callable, PsiElement beingChecked, boolean allowed, String message) { // TODO: use a real flow analysis to check all exit points boolean hasReturns; if (callable instanceof PyFunction) { final PsiElement[] returnStatements = PsiTreeUtil.collectElements(callable, new PsiElementFilter() { @Override public boolean isAccepted(PsiElement element) { - return (element instanceof PyReturnStatement && ((PyReturnStatement) element).getExpression() != null) || + return (element instanceof PyReturnStatement && ((PyReturnStatement)element).getExpression() != null) || (element instanceof PyYieldExpression); } }); @@ -308,6 +318,9 @@ public class PyPropertyDefinitionInspection extends PyInspection { } if (allowed ^ hasReturns) { if (allowed && callable instanceof PyFunction) { + if (PyUtil.isDecoratedAsAbstract(((PyFunction)callable))) { + return; + } // one last chance: maybe there's no return but a 'raise' statement, see PY-4043, PY-5048 PyStatementList statementList = ((PyFunction)callable).getStatementList(); for (PyStatement stmt : statementList.getStatements()) { @@ -316,9 +329,8 @@ public class PyPropertyDefinitionInspection extends PyInspection { } } } - registerProblem(being_checked, message); + registerProblem(beingChecked, message); } } } - } diff --git a/python/src/com/jetbrains/python/inspections/unresolvedReference/PyUnresolvedReferencesInspection.java b/python/src/com/jetbrains/python/inspections/unresolvedReference/PyUnresolvedReferencesInspection.java index daa1fd8fc19a..d737467ba0f6 100644 --- a/python/src/com/jetbrains/python/inspections/unresolvedReference/PyUnresolvedReferencesInspection.java +++ b/python/src/com/jetbrains/python/inspections/unresolvedReference/PyUnresolvedReferencesInspection.java @@ -32,6 +32,8 @@ import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.QualifiedName; import com.intellij.util.Consumer; import com.intellij.util.PlatformUtils; +import com.intellij.util.SmartList; +import com.intellij.util.containers.ContainerUtil; import com.jetbrains.python.PyBundle; import com.jetbrains.python.PyCustomMembersType; import com.jetbrains.python.PyNames; @@ -436,9 +438,9 @@ public class PyUnresolvedReferencesInspection extends PyInspection { return; } - final QualifiedName canonicalQName = getCanonicalName(reference, myTypeEvalContext); - final String canonicalName = canonicalQName != null ? canonicalQName.toString() : null; - if (canonicalName != null) { + final List qualifiedNames = getCanonicalNames(reference, myTypeEvalContext); + for (QualifiedName name: qualifiedNames) { + final String canonicalName = name.toString(); for (String ignored : myIgnoredIdentifiers) { if (ignored.endsWith(END_WILDCARD)) { final String prefix = ignored.substring(0, ignored.length() - END_WILDCARD.length()); @@ -582,10 +584,11 @@ public class PyUnresolvedReferencesInspection extends PyInspection { actions.addAll(GenerateBinaryStubsFix.generateFixes(importStatementBase)); } } - if (canonicalQName != null) { - actions.add(new AddIgnoredIdentifierQuickFix(canonicalQName, false)); - if (canonicalQName.getComponentCount() > 1) { - actions.add(new AddIgnoredIdentifierQuickFix(canonicalQName.removeLastComponent(), true)); + if (qualifiedNames.size() == 1) { + final QualifiedName qualifiedName = qualifiedNames.get(0); + actions.add(new AddIgnoredIdentifierQuickFix(qualifiedName, false)); + if (qualifiedName.getComponentCount() > 1) { + actions.add(new AddIgnoredIdentifierQuickFix(qualifiedName.removeLastComponent(), true)); } } addPluginQuickFixes(reference, actions); @@ -621,20 +624,20 @@ public class PyUnresolvedReferencesInspection extends PyInspection { } /** - * Return the canonical qualified name for a reference (even for an unresolved one). + * Return the canonical qualified names for a reference (even for an unresolved one). + * If reference is qualified and its qualifier has union type, all possible canonical names will be returned. */ - @Nullable - private static QualifiedName getCanonicalName(@NotNull PsiReference reference, @NotNull TypeEvalContext context) { + @NotNull + private static List getCanonicalNames(@NotNull PsiReference reference, @NotNull TypeEvalContext context) { final PsiElement element = reference.getElement(); + final List result = new SmartList(); if (reference instanceof PyOperatorReference && element instanceof PyQualifiedExpression) { final PyExpression receiver = ((PyOperatorReference)reference).getReceiver(); if (receiver != null) { final PyType type = context.getType(receiver); if (type instanceof PyClassType) { - final String name = ((PyClassType)type).getClassQName(); - if (name != null) { - return QualifiedName.fromDottedString(name).append(((PyQualifiedExpression)element).getReferencedName()); - } + final String methodName = ((PyQualifiedExpression)element).getReferencedName(); + ContainerUtil.addIfNotNull(result, extractAttributeQNameFromClassType(methodName, (PyClassType)type)); } } } @@ -646,16 +649,20 @@ public class PyUnresolvedReferencesInspection extends PyInspection { if (qualifier != null) { final PyType type = context.getType(qualifier); if (type instanceof PyClassType) { - final String name = ((PyClassType)type).getClassQName(); - if (name != null) { - return QualifiedName.fromDottedString(name).append(exprName); - } + ContainerUtil.addIfNotNull(result, extractAttributeQNameFromClassType(exprName, (PyClassType)type)); } else if (type instanceof PyModuleType) { final PyFile file = ((PyModuleType)type).getModule(); final QualifiedName name = QualifiedNameFinder.findCanonicalImportPath(file, element); if (name != null) { - return name.append(exprName); + ContainerUtil.addIfNotNull(result, name.append(exprName)); + } + } + else if (type instanceof PyUnionType) { + for (PyType memberType : ((PyUnionType)type).getMembers()) { + if (memberType instanceof PyClassType) { + ContainerUtil.addIfNotNull(result, extractAttributeQNameFromClassType(exprName, (PyClassType)memberType)); + } } } } @@ -664,14 +671,14 @@ public class PyUnresolvedReferencesInspection extends PyInspection { if (parent instanceof PyImportElement) { final PyImportStatementBase importStmt = PsiTreeUtil.getParentOfType(parent, PyImportStatementBase.class); if (importStmt instanceof PyImportStatement) { - return QualifiedName.fromComponents(exprName); + ContainerUtil.addIfNotNull(result, QualifiedName.fromComponents(exprName)); } else if (importStmt instanceof PyFromImportStatement) { final PsiElement resolved = ((PyFromImportStatement)importStmt).resolveImportSource(); if (resolved != null) { final QualifiedName path = QualifiedNameFinder.findCanonicalImportPath(resolved, element); if (path != null) { - return path.append(exprName); + ContainerUtil.addIfNotNull(result, path.append(exprName)); } } } @@ -679,14 +686,22 @@ public class PyUnresolvedReferencesInspection extends PyInspection { else { final QualifiedName path = QualifiedNameFinder.findCanonicalImportPath(element, element); if (path != null) { - return path.append(exprName); + ContainerUtil.addIfNotNull(result, path.append(exprName)); } } } } } else if (reference instanceof DocStringParameterReference) { - return QualifiedName.fromDottedString(reference.getCanonicalText()); + ContainerUtil.addIfNotNull(result, QualifiedName.fromDottedString(reference.getCanonicalText())); + } + return result; + } + + private static QualifiedName extractAttributeQNameFromClassType(String exprName, PyClassType type) { + final String name = type.getClassQName(); + if (name != null) { + return QualifiedName.fromDottedString(name).append(exprName); } return null; } diff --git a/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java index 1fc91e0334ec..fd1126e64a2f 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java @@ -374,10 +374,19 @@ public class PyReferenceExpressionImpl extends PyElementImpl implements PyRefere return context.getType((PyTypedElement)target); } if (target instanceof PsiDirectory) { - PsiFile file = ((PsiDirectory)target).findFile(PyNames.INIT_DOT_PY); + final PsiDirectory dir = (PsiDirectory)target; + PsiFile file = dir.findFile(PyNames.INIT_DOT_PY); if (file != null) { return getTypeFromTarget(file, context, anchor); } + if (PyUtil.isPackage(dir, anchor)) { + final PsiFile containingFile = anchor.getContainingFile(); + if (containingFile instanceof PyFile) { + final QualifiedName qualifiedName = QualifiedName.fromComponents(dir.getName()); + final PyImportedModule module = new PyImportedModule(null, (PyFile)containingFile, qualifiedName); + return new PyImportedModuleType(module); + } + } } return null; } diff --git a/python/src/com/jetbrains/python/psi/impl/references/PyImportReference.java b/python/src/com/jetbrains/python/psi/impl/references/PyImportReference.java index 69eb8a6dd0da..be7921bd6b22 100644 --- a/python/src/com/jetbrains/python/psi/impl/references/PyImportReference.java +++ b/python/src/com/jetbrains/python/psi/impl/references/PyImportReference.java @@ -157,8 +157,8 @@ public class PyImportReference extends PyReferenceImpl { } ASTNode node = myElement.getNode(); while (node != null) { - final IElementType node_type = node.getElementType(); - if (node_type == PyTokenTypes.IMPORT_KEYWORD) { + final IElementType nodeType = node.getElementType(); + if (nodeType == PyTokenTypes.IMPORT_KEYWORD) { return true; } node = node.getTreeNext(); @@ -175,7 +175,7 @@ public class PyImportReference extends PyReferenceImpl { public ImportVariantCollector(@NotNull TypeEvalContext context) { myContext = context; PsiFile currentFile = myElement.getContainingFile(); - if (currentFile != null) currentFile = currentFile.getOriginalFile(); + currentFile = currentFile.getOriginalFile(); myCurrentFile = currentFile; myNamesAlready = new HashSet(); myObjects = new ArrayList(); @@ -187,15 +187,15 @@ public class PyImportReference extends PyReferenceImpl { // NOTE: could use getPointInImport() // are we in "import _" or "from foo import _"? - PyFromImportStatement from_import = PsiTreeUtil.getParentOfType(myElement, PyFromImportStatement.class); - if (from_import != null && myElement.getParent() != from_import) { // in "from foo import _" - PyReferenceExpression src = from_import.getImportSource(); + PyFromImportStatement fromImport = PsiTreeUtil.getParentOfType(myElement, PyFromImportStatement.class); + if (fromImport != null && myElement.getParent() != fromImport) { // in "from foo import _" + PyReferenceExpression src = fromImport.getImportSource(); if (src != null) { - PsiElement mod_candidate = src.getReference().resolve(); - if (mod_candidate instanceof PyExpression) { - addImportedNames(from_import.getImportElements()); // don't propose already imported items + PsiElement modCandidate = src.getReference().resolve(); + if (modCandidate instanceof PyExpression) { + addImportedNames(fromImport.getImportElements()); // don't propose already imported items // try to collect submodules - PyExpression module = (PyExpression)mod_candidate; + PyExpression module = (PyExpression)modCandidate; PyType qualifierType = myContext.getType(module); if (qualifierType != null) { ProcessingContext ctx = new ProcessingContext(); @@ -204,18 +204,18 @@ public class PyImportReference extends PyReferenceImpl { } return myObjects.toArray(); } - else if (mod_candidate instanceof PsiDirectory) { - fillFromDir((PsiDirectory)mod_candidate, ImportKeywordHandler.INSTANCE); + else if (modCandidate instanceof PsiDirectory) { + fillFromDir((PsiDirectory)modCandidate, ImportKeywordHandler.INSTANCE); return myObjects.toArray(); } } else { // null source, must be a "from ... import" - relativeLevel = from_import.getRelativeLevel(); + relativeLevel = fromImport.getRelativeLevel(); if (relativeLevel > 0) { - PsiDirectory relative_dir = ResolveImportUtil.stepBackFrom(myCurrentFile, relativeLevel); - if (relative_dir != null) { - addImportedNames(from_import.getImportElements()); - fillFromDir(relative_dir, null); + PsiDirectory relativeDir = ResolveImportUtil.stepBackFrom(myCurrentFile, relativeLevel); + if (relativeDir != null) { + addImportedNames(fromImport.getImportElements()); + fillFromDir(relativeDir, null); } } } @@ -226,21 +226,21 @@ public class PyImportReference extends PyReferenceImpl { relativeLevel += 1; n = n.getTreePrev(); } - if (from_import != null) { - addImportedNames(from_import.getImportElements()); + if (fromImport != null) { + addImportedNames(fromImport.getImportElements()); if (!alreadyHasImportKeyword()) { insertHandler = ImportKeywordHandler.INSTANCE; } } else { myNamesAlready.add(PyNames.FUTURE_MODULE); // never add it to "import ..." - PyImportStatement import_stmt = PsiTreeUtil.getParentOfType(myElement, PyImportStatement.class); - if (import_stmt != null) { - addImportedNames(import_stmt.getImportElements()); + PyImportStatement importStatement = PsiTreeUtil.getParentOfType(myElement, PyImportStatement.class); + if (importStatement != null) { + addImportedNames(importStatement.getImportElements()); } } // look at dir by level - if (myCurrentFile != null && (relativeLevel >= 0 || !ResolveImportUtil.isAbsoluteImportEnabledFor(myCurrentFile))) { + if ((relativeLevel >= 0 || !ResolveImportUtil.isAbsoluteImportEnabledFor(myCurrentFile))) { final PsiDirectory containingDirectory = myCurrentFile.getContainingDirectory(); if (containingDirectory != null) { QualifiedName thisQName = QualifiedNameFinder.findShortestImportableQName(containingDirectory); @@ -268,9 +268,9 @@ public class PyImportReference extends PyReferenceImpl { } } - private void addImportedNames(@NotNull PyImportElement[] import_elts) { - for (PyImportElement ielt : import_elts) { - PyReferenceExpression ref = ielt.getImportReferenceExpression(); + private void addImportedNames(@NotNull PyImportElement[] importElements) { + for (PyImportElement element : importElements) { + PyReferenceExpression ref = element.getImportReferenceExpression(); if (ref != null) { String s = ref.getReferencedName(); if (s != null) myNamesAlready.add(s); @@ -278,22 +278,24 @@ public class PyImportReference extends PyReferenceImpl { } } - // adds variants found under given dir - private void fillFromDir(PsiDirectory target_dir, @Nullable InsertHandler insertHandler) { - if (target_dir != null) { - PsiFile initPy = target_dir.findFile(PyNames.INIT_DOT_PY); + /** + * Adds variants found under given dir. + */ + private void fillFromDir(PsiDirectory targetDir, @Nullable InsertHandler insertHandler) { + if (targetDir != null) { + PsiFile initPy = targetDir.findFile(PyNames.INIT_DOT_PY); if (initPy instanceof PyFile) { PyModuleType moduleType = new PyModuleType((PyFile)initPy); ProcessingContext context = new ProcessingContext(); context.put(PyType.CTX_NAMES, myNamesAlready); - Object[] completionVariants = moduleType.getCompletionVariants("", (PyExpression)getElement(), context); + Object[] completionVariants = moduleType.getCompletionVariants("", getElement(), context); if (insertHandler != null) { replaceInsertHandler(completionVariants, insertHandler); } myObjects.addAll(Arrays.asList(completionVariants)); } else { - myObjects.addAll(PyModuleType.getSubModuleVariants(target_dir, myElement, myNamesAlready)); + myObjects.addAll(PyModuleType.getSubModuleVariants(targetDir, myElement, myNamesAlready)); } } } diff --git a/python/src/com/jetbrains/python/psi/types/PyImportedModuleType.java b/python/src/com/jetbrains/python/psi/types/PyImportedModuleType.java index 9fcbe52ed8d0..bc26a1a87ba2 100644 --- a/python/src/com/jetbrains/python/psi/types/PyImportedModuleType.java +++ b/python/src/com/jetbrains/python/psi/types/PyImportedModuleType.java @@ -19,15 +19,13 @@ import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.LookupElementBuilder; import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiElement; +import com.intellij.psi.util.QualifiedName; +import com.intellij.util.ArrayUtil; import com.intellij.util.ProcessingContext; import com.jetbrains.python.codeInsight.controlflow.ScopeOwner; import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil; -import com.jetbrains.python.psi.AccessDirection; -import com.jetbrains.python.psi.PyExpression; -import com.jetbrains.python.psi.PyFile; -import com.jetbrains.python.psi.PyImportElement; +import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.impl.PyImportedModule; -import com.intellij.psi.util.QualifiedName; import com.jetbrains.python.psi.resolve.PyResolveContext; import com.jetbrains.python.psi.resolve.RatedResolveResult; import com.jetbrains.python.psi.resolve.ResolveImportUtil; @@ -82,7 +80,14 @@ public class PyImportedModuleType implements PyType { } } } - return result.toArray(new Object[result.size()]); + final PsiElement resolved = myImportedModule.resolve(); + if (resolved instanceof PsiDirectory) { + final PsiDirectory dir = (PsiDirectory)resolved; + if (PyUtil.isPackage(dir, location)) { + result.addAll(PyModuleType.getSubModuleVariants(dir, location, null)); + } + } + return ArrayUtil.toObjectArray(result); } public String getName() { diff --git a/python/src/com/jetbrains/python/psi/types/PyModuleType.java b/python/src/com/jetbrains/python/psi/types/PyModuleType.java index 0aec8612c989..8db0b716194f 100644 --- a/python/src/com/jetbrains/python/psi/types/PyModuleType.java +++ b/python/src/com/jetbrains/python/psi/types/PyModuleType.java @@ -245,7 +245,7 @@ public class PyModuleType implements PyType { // Modules don't descend from obje * not suitable for import. */ @NotNull - private static List getSubmodulesList(final PsiDirectory directory) { + private static List getSubmodulesList(final PsiDirectory directory, @Nullable PsiElement anchor) { List result = new ArrayList(); if (directory != null) { // just in case @@ -259,7 +259,9 @@ public class PyModuleType implements PyType { // Modules don't descend from obje } // dir modules for (PsiDirectory dir : directory.getSubdirectories()) { - if (dir.findFile(PyNames.INIT_DOT_PY) instanceof PyFile) result.add(dir); + if (PyUtil.isPackage(dir, anchor)) { + result.add(dir); + } } } return result; @@ -365,7 +367,7 @@ public class PyModuleType implements PyType { // Modules don't descend from obje PsiElement location, Set namesAlready) { List result = new ArrayList(); - for (PsiFileSystemItem item : getSubmodulesList(directory)) { + for (PsiFileSystemItem item : getSubmodulesList(directory, location)) { if (item != location.getContainingFile().getOriginalFile()) { LookupElement lookupElement = buildFileLookupElement(item, namesAlready); if (lookupElement != null) { diff --git a/python/testData/completion/fromQualifiedNamespacePackageImport/a.after.py b/python/testData/completion/fromQualifiedNamespacePackageImport/a.after.py new file mode 100644 index 000000000000..08b9946188ab --- /dev/null +++ b/python/testData/completion/fromQualifiedNamespacePackageImport/a.after.py @@ -0,0 +1 @@ +from nspkg1.foo import diff --git a/python/testData/completion/fromQualifiedNamespacePackageImport/a.py b/python/testData/completion/fromQualifiedNamespacePackageImport/a.py new file mode 100644 index 000000000000..dc6e9e115236 --- /dev/null +++ b/python/testData/completion/fromQualifiedNamespacePackageImport/a.py @@ -0,0 +1 @@ +from nspkg1.f diff --git a/python/testData/completion/fromQualifiedNamespacePackageImport/nspkg1/bar.py b/python/testData/completion/fromQualifiedNamespacePackageImport/nspkg1/bar.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/completion/fromQualifiedNamespacePackageImport/nspkg1/foo.py b/python/testData/completion/fromQualifiedNamespacePackageImport/nspkg1/foo.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/completion/importNamespacePackage/a.after.py b/python/testData/completion/importNamespacePackage/a.after.py new file mode 100644 index 000000000000..3a900b8dcab9 --- /dev/null +++ b/python/testData/completion/importNamespacePackage/a.after.py @@ -0,0 +1 @@ +import nspkg1 diff --git a/python/testData/completion/importNamespacePackage/a.py b/python/testData/completion/importNamespacePackage/a.py new file mode 100644 index 000000000000..bbb3f11374c9 --- /dev/null +++ b/python/testData/completion/importNamespacePackage/a.py @@ -0,0 +1 @@ +import nspk diff --git a/python/testData/completion/importQualifiedNamespacePackage/a.after.py b/python/testData/completion/importQualifiedNamespacePackage/a.after.py new file mode 100644 index 000000000000..c0b0b049717a --- /dev/null +++ b/python/testData/completion/importQualifiedNamespacePackage/a.after.py @@ -0,0 +1 @@ +import nspkg1.foo diff --git a/python/testData/completion/importQualifiedNamespacePackage/a.py b/python/testData/completion/importQualifiedNamespacePackage/a.py new file mode 100644 index 000000000000..737dcb8bad5d --- /dev/null +++ b/python/testData/completion/importQualifiedNamespacePackage/a.py @@ -0,0 +1 @@ +import nspkg1.f diff --git a/python/testData/completion/importQualifiedNamespacePackage/nspkg1/bar.py b/python/testData/completion/importQualifiedNamespacePackage/nspkg1/bar.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/completion/importQualifiedNamespacePackage/nspkg1/foo.py b/python/testData/completion/importQualifiedNamespacePackage/nspkg1/foo.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/inspections/PyPropertyDefinitionInspection26/src/prop_test.py b/python/testData/inspections/PyPropertyDefinitionInspection26/src/prop_test.py index 5823e797f197..f7b7d2065e45 100644 --- a/python/testData/inspections/PyPropertyDefinitionInspection26/src/prop_test.py +++ b/python/testData/inspections/PyPropertyDefinitionInspection26/src/prop_test.py @@ -63,3 +63,8 @@ class A(object): get_foo2 = lambda self: 'foo2' foo2 = property(get_foo2) + + @property + @abstractproperty + def abstract_property(self): + pass diff --git a/python/testData/inspections/PyPropertyDefinitionInspection33/expected.xml b/python/testData/inspections/PyPropertyDefinitionInspection33/expected.xml new file mode 100644 index 000000000000..d12754a111d5 --- /dev/null +++ b/python/testData/inspections/PyPropertyDefinitionInspection33/expected.xml @@ -0,0 +1,9 @@ + + + + prop_test.py + 3 + Getter should return or yield something + + + diff --git a/python/testData/inspections/PyPropertyDefinitionInspection33/src/prop_test.py b/python/testData/inspections/PyPropertyDefinitionInspection33/src/prop_test.py new file mode 100644 index 000000000000..516047992b8e --- /dev/null +++ b/python/testData/inspections/PyPropertyDefinitionInspection33/src/prop_test.py @@ -0,0 +1,14 @@ +class A: + @property + def normal_property(self): + pass + + @property + @abstractproperty + def abstract_property1(self): + pass + + @property + @abstractmethod + def abstract_property2(self): + pass diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/ignoredUnresolvedReferenceInUnionType.py b/python/testData/inspections/PyUnresolvedReferencesInspection/ignoredUnresolvedReferenceInUnionType.py new file mode 100644 index 000000000000..49000449847d --- /dev/null +++ b/python/testData/inspections/PyUnresolvedReferencesInspection/ignoredUnresolvedReferenceInUnionType.py @@ -0,0 +1,8 @@ +class A: + pass + +a = A() +print(a.foo) + +x = A() or None +print(x.foo) \ No newline at end of file diff --git a/python/testData/surround/SurroundFirstMethodWithCustomFoldingRegion.py b/python/testData/surround/CustomFoldingRegionFirstMethod.py similarity index 100% rename from python/testData/surround/SurroundFirstMethodWithCustomFoldingRegion.py rename to python/testData/surround/CustomFoldingRegionFirstMethod.py diff --git a/python/testData/surround/CustomFoldingRegionFirstMethod_after.py b/python/testData/surround/CustomFoldingRegionFirstMethod_after.py new file mode 100644 index 000000000000..222424499910 --- /dev/null +++ b/python/testData/surround/CustomFoldingRegionFirstMethod_after.py @@ -0,0 +1,17 @@ +class ThisIsATest(): + # + def __init__(self): + self.test = 1 + # + + def another_one(self): + print "Hello, world!" + + def another_two(self): + print "Hello, world!" + + def another_three(self): + print "Hello, world!" + + def another_four(self): + print "Hello, world!" \ No newline at end of file diff --git a/python/testData/surround/CustomFoldingRegionIllegalSelection.py b/python/testData/surround/CustomFoldingRegionIllegalSelection.py new file mode 100644 index 000000000000..bfb208e40e7f --- /dev/null +++ b/python/testData/surround/CustomFoldingRegionIllegalSelection.py @@ -0,0 +1,4 @@ +[ + 1, + 2 +] \ No newline at end of file diff --git a/python/testData/surround/CustomFoldingRegionIllegalSelection_after.py b/python/testData/surround/CustomFoldingRegionIllegalSelection_after.py new file mode 100644 index 000000000000..63964002bf9f --- /dev/null +++ b/python/testData/surround/CustomFoldingRegionIllegalSelection_after.py @@ -0,0 +1,4 @@ +[ + 1, + 2 +] \ No newline at end of file diff --git a/python/testData/surround/SurroundLastMethodWithCustomFoldingRegion.py b/python/testData/surround/CustomFoldingRegionLastMethod.py similarity index 87% rename from python/testData/surround/SurroundLastMethodWithCustomFoldingRegion.py rename to python/testData/surround/CustomFoldingRegionLastMethod.py index 2dbc0cb2d23d..fb75998201cd 100644 --- a/python/testData/surround/SurroundLastMethodWithCustomFoldingRegion.py +++ b/python/testData/surround/CustomFoldingRegionLastMethod.py @@ -12,4 +12,4 @@ class ThisIsATest(): print "Hello, world!" def another_four(self): - print "Hello, world!" + print "Hello, world!" \ No newline at end of file diff --git a/python/testData/surround/CustomFoldingRegionLastMethod_after.py b/python/testData/surround/CustomFoldingRegionLastMethod_after.py new file mode 100644 index 000000000000..c283100ac33b --- /dev/null +++ b/python/testData/surround/CustomFoldingRegionLastMethod_after.py @@ -0,0 +1,17 @@ +class ThisIsATest(): + def __init__(self): + self.test = 1 + + def another_one(self): + print "Hello, world!" + + def another_two(self): + print "Hello, world!" + + def another_three(self): + print "Hello, world!" + + # + def another_four(self): + print "Hello, world!" + # \ No newline at end of file diff --git a/python/testData/surround/SurroundWithCustomFoldingRegion.py b/python/testData/surround/CustomFoldingRegionPreservesIndentation.py similarity index 100% rename from python/testData/surround/SurroundWithCustomFoldingRegion.py rename to python/testData/surround/CustomFoldingRegionPreservesIndentation.py diff --git a/python/testData/surround/SurroundWithCustomFoldingRegion_after.py b/python/testData/surround/CustomFoldingRegionPreservesIndentation_after.py similarity index 100% rename from python/testData/surround/SurroundWithCustomFoldingRegion_after.py rename to python/testData/surround/CustomFoldingRegionPreservesIndentation_after.py diff --git a/python/testData/surround/CustomFoldingRegionSeveralMethods.py b/python/testData/surround/CustomFoldingRegionSeveralMethods.py new file mode 100644 index 000000000000..867f0898db15 --- /dev/null +++ b/python/testData/surround/CustomFoldingRegionSeveralMethods.py @@ -0,0 +1,9 @@ +class C: + def m1(self): + pass + + def m2(self): + pass + + def m3(self): + pass \ No newline at end of file diff --git a/python/testData/surround/CustomFoldingRegionSeveralMethods_after.py b/python/testData/surround/CustomFoldingRegionSeveralMethods_after.py new file mode 100644 index 000000000000..a1f58e5f63b2 --- /dev/null +++ b/python/testData/surround/CustomFoldingRegionSeveralMethods_after.py @@ -0,0 +1,11 @@ +class C: + def m1(self): + pass + + # + def m2(self): + pass + + def m3(self): + pass + # \ No newline at end of file diff --git a/python/testData/surround/CustomFoldingRegionSingleCharacter.py b/python/testData/surround/CustomFoldingRegionSingleCharacter.py new file mode 100644 index 000000000000..d6558960207f --- /dev/null +++ b/python/testData/surround/CustomFoldingRegionSingleCharacter.py @@ -0,0 +1 @@ +x = 'foo' + 'bar' \ No newline at end of file diff --git a/python/testData/surround/CustomFoldingRegionSingleCharacter_after.py b/python/testData/surround/CustomFoldingRegionSingleCharacter_after.py new file mode 100644 index 000000000000..3efae30ebce7 --- /dev/null +++ b/python/testData/surround/CustomFoldingRegionSingleCharacter_after.py @@ -0,0 +1,3 @@ +# +x = 'foo' + 'bar' +# \ No newline at end of file diff --git a/python/testData/surround/CustomFoldingRegionSingleStatementInFile.py b/python/testData/surround/CustomFoldingRegionSingleStatementInFile.py new file mode 100644 index 000000000000..6f8ff0d5f034 --- /dev/null +++ b/python/testData/surround/CustomFoldingRegionSingleStatementInFile.py @@ -0,0 +1,2 @@ +print('foo') + \ No newline at end of file diff --git a/python/testData/surround/CustomFoldingRegionSingleStatementInFile_after.py b/python/testData/surround/CustomFoldingRegionSingleStatementInFile_after.py new file mode 100644 index 000000000000..5991df264bf7 --- /dev/null +++ b/python/testData/surround/CustomFoldingRegionSingleStatementInFile_after.py @@ -0,0 +1,3 @@ +# +print('foo') +# diff --git a/python/testSrc/com/jetbrains/python/Py3CompletionTest.java b/python/testSrc/com/jetbrains/python/Py3CompletionTest.java index ca7c3c2649f3..9c87e473dd56 100644 --- a/python/testSrc/com/jetbrains/python/Py3CompletionTest.java +++ b/python/testSrc/com/jetbrains/python/Py3CompletionTest.java @@ -69,6 +69,13 @@ public class Py3CompletionTest extends PyTestCase { myFixture.checkResultByFile(testName + ".after.py"); } + private void doMultiFileTest() { + myFixture.copyDirectoryToProject("completion/" + getTestName(true), ""); + myFixture.configureByFile("a.py"); + myFixture.completeBasic(); + myFixture.checkResultByFile("completion/" + getTestName(true) + "/a.after.py"); + } + private List doTestByText(String text) { myFixture.configureByText(PythonFileType.INSTANCE, text); myFixture.completeBasic(); @@ -93,4 +100,19 @@ public class Py3CompletionTest extends PyTestCase { setLanguageLevel(null); } } + + // PY-7375 + public void testImportNamespacePackage() { + doMultiFileTest(); + } + + // PY-5422 + public void testImportQualifiedNamespacePackage() { + doMultiFileTest(); + } + + // PY-6477 + public void testFromQualifiedNamespacePackageImport() { + doMultiFileTest(); + } } diff --git a/python/testSrc/com/jetbrains/python/PySurroundWithTest.java b/python/testSrc/com/jetbrains/python/PySurroundWithTest.java index 9abfa6313669..2af16ff92edc 100644 --- a/python/testSrc/com/jetbrains/python/PySurroundWithTest.java +++ b/python/testSrc/com/jetbrains/python/PySurroundWithTest.java @@ -19,11 +19,9 @@ import com.intellij.codeInsight.generation.surroundWith.SurroundWithHandler; import com.intellij.lang.folding.CustomFoldingSurroundDescriptor; import com.intellij.lang.surroundWith.Surrounder; import com.intellij.openapi.command.WriteCommandAction; -import com.intellij.openapi.editor.SelectionModel; -import com.intellij.psi.PsiElement; +import com.intellij.openapi.util.Condition; +import com.intellij.util.containers.ContainerUtil; import com.jetbrains.python.fixtures.PyTestCase; -import com.jetbrains.python.psi.PyElement; -import com.jetbrains.python.psi.PyFunction; import com.jetbrains.python.refactoring.surround.surrounders.statements.PyWithIfSurrounder; import com.jetbrains.python.refactoring.surround.surrounders.statements.PyWithTryExceptSurrounder; import com.jetbrains.python.refactoring.surround.surrounders.statements.PyWithWhileSurrounder; @@ -45,32 +43,45 @@ public class PySurroundWithTest extends PyTestCase { } // PY-11357 - public void testSurroundFirstMethodWithCustomFoldingRegion() { - checkCustomFoldingRegionRange(PyFunction.class); + public void testCustomFoldingRegionFirstMethod() throws Exception { + doTestSurroundWithCustomFoldingRegion(); } // PY-11357 - public void testSurroundLastMethodWithCustomFoldingRegion() { - checkCustomFoldingRegionRange(PyFunction.class); + public void testCustomFoldingRegionLastMethod() throws Exception { + doTestSurroundWithCustomFoldingRegion(); } // PY-14261 - public void testSurroundWithCustomFoldingRegion() throws Exception { - doTest(CustomFoldingSurroundDescriptor.SURROUNDERS[0]); + public void testCustomFoldingRegionPreservesIndentation() throws Exception { + doTestSurroundWithCustomFoldingRegion(); } + public void testCustomFoldingRegionSingleCharacter() throws Exception { + doTestSurroundWithCustomFoldingRegion(); + } - private PsiElement[] checkCustomFoldingRegionRange(Class... elementTypes) { - myFixture.configureByFile("/surround/" + getTestName(false) + ".py"); - final SelectionModel selection = myFixture.getEditor().getSelectionModel(); - final PsiElement[] range = CustomFoldingSurroundDescriptor.INSTANCE.getElementsToSurround(myFixture.getFile(), - selection.getSelectionStart(), - selection.getSelectionEnd()); - assertEquals(elementTypes.length, range.length); - for (int i = 0; i < elementTypes.length; i++) { - assertInstanceOf(range[i], elementTypes[i]); - } - return range; + public void testCustomFoldingRegionSingleStatementInFile() throws Exception { + doTestSurroundWithCustomFoldingRegion(); + } + + public void testCustomFoldingRegionIllegalSelection() throws Exception { + doTestSurroundWithCustomFoldingRegion(); + } + + public void testCustomFoldingRegionSeveralMethods() throws Exception { + doTestSurroundWithCustomFoldingRegion(); + } + + private void doTestSurroundWithCustomFoldingRegion() throws Exception { + final Surrounder surrounder = ContainerUtil.find(CustomFoldingSurroundDescriptor.SURROUNDERS, new Condition() { + @Override + public boolean value(Surrounder surrounder) { + return surrounder.getTemplateDescription().contains(" getInspectionClass() { diff --git a/resources/src/META-INF/IdeaPlugin.xml b/resources/src/META-INF/IdeaPlugin.xml index 4a9f2b5fe5cb..bae70d18ab02 100644 --- a/resources/src/META-INF/IdeaPlugin.xml +++ b/resources/src/META-INF/IdeaPlugin.xml @@ -1375,7 +1375,6 @@ - diff --git a/xml/dom-impl/src/com/intellij/util/xml/highlighting/DomElementsErrorPanel.java b/xml/dom-impl/src/com/intellij/util/xml/highlighting/DomElementsErrorPanel.java index b4a3502f223a..c147324e75c6 100644 --- a/xml/dom-impl/src/com/intellij/util/xml/highlighting/DomElementsErrorPanel.java +++ b/xml/dom-impl/src/com/intellij/util/xml/highlighting/DomElementsErrorPanel.java @@ -25,7 +25,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Disposer; import com.intellij.psi.PsiDocumentManager; -import com.intellij.psi.PsiFile; +import com.intellij.psi.xml.XmlFile; import com.intellij.util.Alarm; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.xml.DomChangeAdapter; @@ -34,6 +34,7 @@ import com.intellij.util.xml.DomManager; import com.intellij.util.xml.DomUtil; import com.intellij.util.xml.ui.CommittablePanel; import com.intellij.util.xml.ui.Highlightable; +import org.jetbrains.annotations.NotNull; import javax.swing.*; import java.awt.*; @@ -152,25 +153,24 @@ public class DomElementsErrorPanel extends JPanel implements CommittablePanel, H } private class DomElementsTrafficLightRenderer extends TrafficLightRenderer { - - public DomElementsTrafficLightRenderer(final PsiFile xmlFile) { + public DomElementsTrafficLightRenderer(@NotNull XmlFile xmlFile) { super(xmlFile.getProject(), PsiDocumentManager.getInstance(xmlFile.getProject()).getDocument(xmlFile), xmlFile); } + @NotNull @Override - protected DaemonCodeAnalyzerStatus getDaemonCodeAnalyzerStatus(boolean fillErrorsCount, SeverityRegistrar severityRegistrar) { - final DaemonCodeAnalyzerStatus status = super.getDaemonCodeAnalyzerStatus(fillErrorsCount, severityRegistrar); - if (status != null && isInspectionCompleted()) { + protected DaemonCodeAnalyzerStatus getDaemonCodeAnalyzerStatus(@NotNull SeverityRegistrar severityRegistrar) { + final DaemonCodeAnalyzerStatus status = super.getDaemonCodeAnalyzerStatus(severityRegistrar); + if (isInspectionCompleted()) { status.errorAnalyzingFinished = true; } return status; } @Override - protected void fillDaemonCodeAnalyzerErrorsStatus(DaemonCodeAnalyzerStatus status, - boolean fillErrorsCount, - SeverityRegistrar severityRegistrar) { + protected void fillDaemonCodeAnalyzerErrorsStatus(@NotNull DaemonCodeAnalyzerStatus status, + @NotNull SeverityRegistrar severityRegistrar) { for (int i = 0; i < status.errorCount.length; i++) { final HighlightSeverity minSeverity = severityRegistrar.getSeverityByIndex(i); if (minSeverity == null) { diff --git a/xml/impl/src/com/intellij/refactoring/XmlImportOptimizer.java b/xml/impl/src/com/intellij/refactoring/XmlImportOptimizer.java index fe78e55df189..2e02abcd071f 100644 --- a/xml/impl/src/com/intellij/refactoring/XmlImportOptimizer.java +++ b/xml/impl/src/com/intellij/refactoring/XmlImportOptimizer.java @@ -15,6 +15,7 @@ */ package com.intellij.refactoring; +import com.intellij.codeInsight.daemon.HighlightDisplayKey; import com.intellij.codeInsight.daemon.impl.analysis.XmlUnusedNamespaceInspection; import com.intellij.codeInspection.InspectionManager; import com.intellij.codeInspection.ProblemDescriptor; @@ -23,6 +24,7 @@ import com.intellij.codeInspection.QuickFix; import com.intellij.lang.ImportOptimizer; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Condition; +import com.intellij.profile.codeInspection.InspectionProjectProfileManager; import com.intellij.psi.*; import com.intellij.psi.xml.XmlAttribute; import com.intellij.psi.xml.XmlFile; @@ -64,6 +66,8 @@ public class XmlImportOptimizer implements ImportOptimizer { public void run() { XmlFile xmlFile = (XmlFile)file; Project project = xmlFile.getProject(); + HighlightDisplayKey key = HighlightDisplayKey.find(myInspection.getShortName()); + if (!InspectionProjectProfileManager.getInstance(project).getInspectionProfile().isToolEnabled(key, xmlFile)) return; ProblemsHolder holder = new ProblemsHolder(InspectionManager.getInstance(project), xmlFile, false); final XmlElementVisitor visitor = (XmlElementVisitor)myInspection.buildVisitor(holder, false); new PsiRecursiveElementVisitor() { diff --git a/xml/tests/src/com/intellij/xml/XmlNamespacesTest.java b/xml/tests/src/com/intellij/xml/XmlNamespacesTest.java index c38ce07bc1e2..90e1cdd3310d 100644 --- a/xml/tests/src/com/intellij/xml/XmlNamespacesTest.java +++ b/xml/tests/src/com/intellij/xml/XmlNamespacesTest.java @@ -19,11 +19,13 @@ import com.intellij.codeInsight.actions.OptimizeImportsProcessor; import com.intellij.codeInsight.daemon.impl.analysis.XmlUnusedNamespaceInspection; import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.codeInspection.htmlInspections.XmlInspectionToolProvider; +import com.intellij.ide.highlighter.XmlFileType; import com.intellij.javaee.ExternalResourceManagerExImpl; import com.intellij.openapi.application.Result; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.testFramework.IdeaTestCase; import com.intellij.testFramework.fixtures.CodeInsightFixtureTestCase; +import org.jetbrains.annotations.NotNull; /** * @author Dmitry Avdeev @@ -235,6 +237,13 @@ public class XmlNamespacesTest extends CodeInsightFixtureTestCase { myFixture.testHighlighting("import.xml", "import.xsd"); } + public void testDoNotOptimizeWhenInspectionDisabled() throws Exception { + myFixture.disableInspections(new XmlUnusedNamespaceInspection()); + String text = ""; + myFixture.configureByText(XmlFileType.INSTANCE, text); + doOptimizeImportsTest(text); + } + private void doUnusedDeclarationTest(String text, String after, String name) throws Exception { doUnusedDeclarationTest(text, after, name, true); } @@ -257,7 +266,7 @@ public class XmlNamespacesTest extends CodeInsightFixtureTestCase { myFixture.testHighlighting(); new WriteCommandAction(getProject(), getFile()) { @Override - protected void run(Result result) throws Throwable { + protected void run(@NotNull Result result) throws Throwable { new OptimizeImportsProcessor(getProject(), getFile()).runWithoutProgress(); } }.execute();