diff --git a/java/java-analysis-impl/src/com/intellij/refactoring/util/duplicates/DuplicatesFinder.java b/java/java-analysis-impl/src/com/intellij/refactoring/util/duplicates/DuplicatesFinder.java index 1da4eb7fd6b8..2a7b7963145b 100644 --- a/java/java-analysis-impl/src/com/intellij/refactoring/util/duplicates/DuplicatesFinder.java +++ b/java/java-analysis-impl/src/com/intellij/refactoring/util/duplicates/DuplicatesFinder.java @@ -30,6 +30,7 @@ import com.intellij.refactoring.extractMethod.InputVariables; import com.intellij.refactoring.util.RefactoringChangeUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.IntArrayList; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -518,6 +519,8 @@ public class DuplicatesFinder { final PsiJavaCodeReferenceElement candidateQualifier = ((PsiSuperExpression)candidate).getQualifier(); return contextClass == (candidateQualifier != null ? candidateQualifier.resolve() : PsiTreeUtil.getContextOfType(candidate, PsiClass.class)); } + } else if (pattern instanceof PsiModifierList) { + return candidate instanceof PsiModifierList && matchModifierList((PsiModifierList)pattern, (PsiModifierList)candidate); } PsiElement[] children1 = getFilteredChildren(pattern); @@ -541,6 +544,40 @@ public class DuplicatesFinder { return true; } + private static boolean matchModifierList(PsiModifierList modifierList1, PsiModifierList modifierList2) { + if (!(modifierList1.getParent() instanceof PsiLocalVariable)) { + // local variables can only have a final modifier, and are considered equivalent with or without it. + for (String modifier : PsiModifier.MODIFIERS) { + if (modifierList1.hasModifierProperty(modifier)) { + if (!modifierList2.hasModifierProperty(modifier)) { + return false; + } + } + else if (modifierList2.hasModifierProperty(modifier)) { + return false; + } + } + } + final List annotations1 = ContainerUtil.newArrayList(modifierList1.getAnnotations()); + final List annotations2 = ContainerUtil.newArrayList(modifierList2.getAnnotations()); + annotations1.removeIf(a -> CommonClassNames.JAVA_LANG_OVERRIDE.equals(a.getQualifiedName())); + annotations2.removeIf(a -> CommonClassNames.JAVA_LANG_OVERRIDE.equals(a.getQualifiedName())); + if (annotations1.size() != annotations2.size()) { + return false; + } + for (final Iterator iterator = annotations1.iterator(); iterator.hasNext(); ) { + final PsiAnnotation annotation1 = iterator.next(); + for (final Iterator iterator2 = annotations2.iterator(); iterator2.hasNext(); ) { + final PsiAnnotation annotation2 = iterator2.next(); + if (PsiEquivalenceUtil.areElementsEquivalent(annotation1, annotation2)) { + iterator.remove(); + iterator2.remove(); + } + } + } + return true; + } + private static boolean checkParameterModification(PsiExpression expression, final IElementType sign, PsiExpression candidate) { diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/ConstructorInsertHandler.java b/java/java-impl/src/com/intellij/codeInsight/completion/ConstructorInsertHandler.java index 88d14aa13d77..c2ce494ab957 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/ConstructorInsertHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/ConstructorInsertHandler.java @@ -58,7 +58,7 @@ public class ConstructorInsertHandler implements InsertHandler= 0 && plEnd >= 0) { diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/DefineParamsDefaultValueAction.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/DefineParamsDefaultValueAction.java index 7440f6feb0e8..8374967361d3 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/DefineParamsDefaultValueAction.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/DefineParamsDefaultValueAction.java @@ -15,24 +15,62 @@ */ package com.intellij.codeInsight.daemon.impl.quickfix; +import com.intellij.codeInsight.FileModificationService; +import com.intellij.codeInsight.generation.ClassMember; +import com.intellij.codeInsight.hint.HintManager; +import com.intellij.codeInsight.intention.LowPriorityAction; +import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction; import com.intellij.codeInsight.intention.impl.ParameterClassMember; +import com.intellij.codeInsight.template.Template; +import com.intellij.codeInsight.template.TemplateBuilderImpl; +import com.intellij.codeInsight.template.impl.TextExpression; +import com.intellij.icons.AllIcons; import com.intellij.ide.util.MemberChooser; import com.intellij.lang.java.JavaLanguage; +import com.intellij.openapi.application.ApplicationManager; +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.Iconable; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; +import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; +import com.intellij.refactoring.util.RefactoringUtil; +import com.intellij.util.ArrayUtil; +import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import javax.swing.*; +import java.util.Arrays; +import java.util.HashSet; import java.util.List; /** * User: anna * Date: 8/2/12 */ -public class DefineParamsDefaultValueAction extends DelegateWithDefaultParamValueIntentionAction { +public class DefineParamsDefaultValueAction extends PsiElementBaseIntentionAction implements Iconable, LowPriorityAction { + private static final Logger LOG = Logger.getInstance(DefineParamsDefaultValueAction.class); + + @Override + public boolean startInWriteAction() { + return false; + } + + @NotNull + @Override + public String getFamilyName() { + return "Generate overloaded method with default parameter values"; + } + + @Override + public Icon getIcon(int flags) { + return AllIcons.Actions.RefactoringBulb; + } @Override public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) { @@ -56,20 +94,106 @@ public class DefineParamsDefaultValueAction extends DelegateWithDefaultParamValu return true; } - @Nullable @Override + public void invoke(@NotNull final Project project, final Editor editor, @NotNull PsiElement element) throws IncorrectOperationException { + final PsiParameter[] parameters = getParams(element); + if (parameters == null || parameters.length == 0) return; + final PsiMethod method = (PsiMethod)parameters[0].getDeclarationScope(); + final PsiMethod methodPrototype = generateMethodPrototype(method, parameters); + final PsiClass containingClass = method.getContainingClass(); + if (containingClass == null) return; + final PsiMethod existingMethod = containingClass.findMethodBySignature(methodPrototype, false); + if (existingMethod != null) { + editor.getCaretModel().moveToOffset(existingMethod.getTextOffset()); + HintManager.getInstance().showErrorHint(editor, (existingMethod.isConstructor() ? "Constructor" : "Method") + + " with the chosen signature already exists"); + return; + } + + if (!FileModificationService.getInstance().preparePsiElementForWrite(element)) return; + + Runnable runnable = () -> { + final PsiMethod prototype = (PsiMethod)containingClass.addBefore(methodPrototype, method); + RefactoringUtil.fixJavadocsForParams(prototype, new HashSet(Arrays.asList(prototype.getParameterList().getParameters()))); + TemplateBuilderImpl builder = new TemplateBuilderImpl(prototype); + + PsiCodeBlock body = prototype.getBody(); + final String callArgs = + "(" + StringUtil.join(method.getParameterList().getParameters(), psiParameter -> { + if (ArrayUtil.find(parameters, psiParameter) > -1) return "IntelliJIDEARulezzz"; + return psiParameter.getName(); + }, ",") + ");"; + final String methodCall; + if (method.getReturnType() == null) { + methodCall = "this"; + } else if (!PsiType.VOID.equals(method.getReturnType())) { + methodCall = "return " + method.getName(); + } else { + methodCall = method.getName(); + } + LOG.assertTrue(body != null); + body.add(JavaPsiFacade.getElementFactory(project).createStatementFromText(methodCall + callArgs, method)); + body = (PsiCodeBlock)CodeStyleManager.getInstance(project).reformat(body); + final PsiStatement stmt = body.getStatements()[0]; + PsiExpression expr = null; + if (stmt instanceof PsiReturnStatement) { + expr = ((PsiReturnStatement)stmt).getReturnValue(); + } else if (stmt instanceof PsiExpressionStatement) { + expr = ((PsiExpressionStatement)stmt).getExpression(); + } + if (expr instanceof PsiMethodCallExpression) { + PsiMethodCallExpression methodCallExp = (PsiMethodCallExpression)expr; + RangeMarker rangeMarker = editor.getDocument().createRangeMarker(prototype.getTextRange()); + for (PsiParameter parameter : parameters) { + final PsiExpression exprToBeDefault = + methodCallExp.getArgumentList().getExpressions()[method.getParameterList().getParameterIndex(parameter)]; + builder.replaceElement(exprToBeDefault, new TextExpression("")); + } + Template template = builder.buildTemplate(); + editor.getCaretModel().moveToOffset(rangeMarker.getStartOffset()); + + PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.getDocument()); + editor.getDocument().deleteString(rangeMarker.getStartOffset(), rangeMarker.getEndOffset()); + + rangeMarker.dispose(); + + CreateFromUsageBaseFix.startTemplate(editor, template, project); + } + }; + if (startInWriteAction()) { + runnable.run(); + } else { + ApplicationManager.getApplication().runWriteAction(runnable); + } + } + + @Nullable protected PsiParameter[] getParams(PsiElement element) { final PsiMethod method = PsiTreeUtil.getParentOfType(element, PsiMethod.class); assert method != null; final PsiParameter[] parameters = method.getParameterList().getParameters(); + if (parameters.length == 1) { + return parameters; + } final ParameterClassMember[] members = new ParameterClassMember[parameters.length]; for (int i = 0; i < members.length; i++) { members[i] = new ParameterClassMember(parameters[i]); } + final PsiParameter selectedParam = PsiTreeUtil.getParentOfType(element, PsiParameter.class); + final int idx = selectedParam != null ? ArrayUtil.find(parameters, selectedParam) : -1; + if (ApplicationManager.getApplication().isUnitTestMode()) { + return idx >= 0 ? new PsiParameter[] {selectedParam} : null; + } final MemberChooser chooser = new MemberChooser(members, false, true, element.getProject()); - chooser.selectElements(members); + if (idx >= 0) { + chooser.selectElements(new ClassMember[] {members[idx]}); + } + else { + chooser.selectElements(members); + } chooser.setTitle("Choose Default Value Parameters"); + chooser.setCopyJavadocVisible(false); if (chooser.showAndGet()) { final List elements = chooser.getSelectedElements(); if (elements != null) { @@ -83,14 +207,34 @@ public class DefineParamsDefaultValueAction extends DelegateWithDefaultParamValu return null; } - @Override - public boolean startInWriteAction() { - return false; - } + private static PsiMethod generateMethodPrototype(PsiMethod method, PsiParameter... params) { + final PsiMethod prototype = (PsiMethod)method.copy(); + final PsiCodeBlock body = prototype.getBody(); + final PsiCodeBlock emptyBody = JavaPsiFacade.getElementFactory(method.getProject()).createMethodFromText("void foo(){}", prototype).getBody(); + assert emptyBody != null; + if (body != null) { + body.replace(emptyBody); + } else { + prototype.getModifierList().setModifierProperty(PsiModifier.ABSTRACT, false); + prototype.addBefore(emptyBody, null); + } - @NotNull - @Override - public String getFamilyName() { - return "Generate overloaded method with default parameter values"; + final PsiClass aClass = method.getContainingClass(); + if (aClass != null && aClass.isInterface() && !method.hasModifierProperty(PsiModifier.STATIC)) { + prototype.getModifierList().setModifierProperty(PsiModifier.DEFAULT, true); + } + + final PsiParameterList parameterList = method.getParameterList(); + Arrays.sort(params, (p1, p2) -> { + final int parameterIndex1 = parameterList.getParameterIndex(p1); + final int parameterIndex2 = parameterList.getParameterIndex(p2); + return parameterIndex1 > parameterIndex2 ? -1 : 1; + }); + + for (PsiParameter param : params) { + final int parameterIndex = parameterList.getParameterIndex(param); + prototype.getParameterList().getParameters()[parameterIndex].delete(); + } + return prototype; } } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/DelegateWithDefaultParamValueIntentionAction.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/DelegateWithDefaultParamValueIntentionAction.java deleted file mode 100644 index d3bbc2bed94d..000000000000 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/DelegateWithDefaultParamValueIntentionAction.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright 2000-2015 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.codeInsight.daemon.impl.quickfix; - -import com.intellij.codeInsight.FileModificationService; -import com.intellij.codeInsight.hint.HintManager; -import com.intellij.codeInsight.intention.LowPriorityAction; -import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction; -import com.intellij.codeInsight.template.Template; -import com.intellij.codeInsight.template.TemplateBuilderImpl; -import com.intellij.codeInsight.template.impl.TextExpression; -import com.intellij.icons.AllIcons; -import com.intellij.lang.StdLanguages; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.RangeMarker; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Iconable; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.psi.*; -import com.intellij.psi.codeStyle.CodeStyleManager; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.psi.util.PsiUtil; -import com.intellij.refactoring.util.RefactoringUtil; -import com.intellij.util.ArrayUtil; -import com.intellij.util.Function; -import com.intellij.util.IncorrectOperationException; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javax.swing.*; -import java.util.Arrays; -import java.util.Comparator; -import java.util.HashSet; - -/** - * User: anna - */ -public class DelegateWithDefaultParamValueIntentionAction extends PsiElementBaseIntentionAction implements Iconable, LowPriorityAction { - @Override - public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) { - final PsiParameter parameter = PsiTreeUtil.getParentOfType(element, PsiParameter.class); - if (parameter != null) { - if (!parameter.getLanguage().isKindOf(StdLanguages.JAVA)) return false; - final PsiElement declarationScope = parameter.getDeclarationScope(); - if (declarationScope instanceof PsiMethod) { - final PsiMethod method = (PsiMethod)declarationScope; - final PsiClass containingClass = method.getContainingClass(); - if (containingClass != null && (!containingClass.isInterface() || PsiUtil.isLanguageLevel8OrHigher(method))) { - if (containingClass.findMethodBySignature(generateMethodPrototype(method, parameter), false) != null) { - return false; - } - setText("Generate overloaded " + (method.isConstructor() ? "constructor" : "method") + " with default parameter value"); - return true; - } - } - } - return false; - } - - @Override - public Icon getIcon(int flags) { - return AllIcons.Actions.RefactoringBulb; - } - - private static PsiMethod generateMethodPrototype(PsiMethod method, PsiParameter... params) { - final PsiMethod prototype = (PsiMethod)method.copy(); - final PsiCodeBlock body = prototype.getBody(); - final PsiCodeBlock emptyBody = JavaPsiFacade.getElementFactory(method.getProject()).createMethodFromText("void foo(){}", prototype).getBody(); - assert emptyBody != null; - if (body != null) { - body.replace(emptyBody); - } else { - prototype.getModifierList().setModifierProperty(PsiModifier.ABSTRACT, false); - prototype.addBefore(emptyBody, null); - } - - final PsiClass aClass = method.getContainingClass(); - if (aClass != null && aClass.isInterface() && !method.hasModifierProperty(PsiModifier.STATIC)) { - prototype.getModifierList().setModifierProperty(PsiModifier.DEFAULT, true); - } - - final PsiParameterList parameterList = method.getParameterList(); - Arrays.sort(params, (p1, p2) -> { - final int parameterIndex1 = parameterList.getParameterIndex(p1); - final int parameterIndex2 = parameterList.getParameterIndex(p2); - return parameterIndex1 > parameterIndex2 ? -1 : 1; - }); - - for (PsiParameter param : params) { - final int parameterIndex = parameterList.getParameterIndex(param); - prototype.getParameterList().getParameters()[parameterIndex].delete(); - } - return prototype; - } - - @Override - public void invoke(@NotNull final Project project, final Editor editor, @NotNull PsiElement element) throws IncorrectOperationException { - final PsiParameter[] parameters = getParams(element); - if (parameters == null || parameters.length == 0) return; - final PsiMethod method = (PsiMethod)parameters[0].getDeclarationScope(); - final PsiMethod methodPrototype = generateMethodPrototype(method, parameters); - final PsiMethod existingMethod = method.getContainingClass().findMethodBySignature(methodPrototype, false); - if (existingMethod != null) { - editor.getCaretModel().moveToOffset(existingMethod.getTextOffset()); - HintManager.getInstance().showErrorHint(editor, (existingMethod.isConstructor() ? "Constructor" : "Method") + - " with the chosen signature already exists"); - return; - } - - if (!FileModificationService.getInstance().preparePsiElementForWrite(element)) return; - - Runnable runnable = () -> { - - final PsiMethod prototype = (PsiMethod)method.getContainingClass().addBefore(methodPrototype, method); - RefactoringUtil.fixJavadocsForParams(prototype, new HashSet(Arrays.asList(prototype.getParameterList().getParameters()))); - TemplateBuilderImpl builder = new TemplateBuilderImpl(prototype); - - PsiCodeBlock body = prototype.getBody(); - final String callArgs = - "(" + StringUtil.join(method.getParameterList().getParameters(), psiParameter -> { - if (ArrayUtil.find(parameters, psiParameter) > -1) return "IntelliJIDEARulezzz"; - return psiParameter.getName(); - }, ",") + ");"; - final String methodCall; - if (method.getReturnType() == null) { - methodCall = "this"; - } else if (!PsiType.VOID.equals(method.getReturnType())) { - methodCall = "return " + method.getName(); - } else { - methodCall = method.getName(); - } - body.add(JavaPsiFacade.getElementFactory(project).createStatementFromText(methodCall + callArgs, method)); - body = (PsiCodeBlock)CodeStyleManager.getInstance(project).reformat(body); - final PsiStatement stmt = body.getStatements()[0]; - PsiExpression expr = null; - if (stmt instanceof PsiReturnStatement) { - expr = ((PsiReturnStatement)stmt).getReturnValue(); - } else if (stmt instanceof PsiExpressionStatement) { - expr = ((PsiExpressionStatement)stmt).getExpression(); - } - if (expr instanceof PsiMethodCallExpression) { - PsiMethodCallExpression methodCallExp = (PsiMethodCallExpression)expr; - RangeMarker rangeMarker = editor.getDocument().createRangeMarker(prototype.getTextRange()); - for (PsiParameter parameter : parameters) { - final PsiExpression exprToBeDefault = - methodCallExp.getArgumentList().getExpressions()[method.getParameterList().getParameterIndex(parameter)]; - builder.replaceElement(exprToBeDefault, new TextExpression("")); - } - Template template = builder.buildTemplate(); - editor.getCaretModel().moveToOffset(rangeMarker.getStartOffset()); - - PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.getDocument()); - editor.getDocument().deleteString(rangeMarker.getStartOffset(), rangeMarker.getEndOffset()); - - rangeMarker.dispose(); - - CreateFromUsageBaseFix.startTemplate(editor, template, project); - } - }; - if (startInWriteAction()) { - runnable.run(); - } else { - ApplicationManager.getApplication().runWriteAction(runnable); - } - } - - @Nullable - protected PsiParameter[] getParams(PsiElement element) { - return new PsiParameter[]{PsiTreeUtil.getParentOfType(element, PsiParameter.class)}; - } - - @NotNull - @Override - public String getFamilyName() { - return "Generate overloaded method with default parameter value"; - } -} diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/RemoveRedundantElseAction.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/RemoveRedundantElseAction.java deleted file mode 100644 index 28db235e1e1b..000000000000 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/RemoveRedundantElseAction.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.codeInsight.daemon.impl.quickfix; - -import com.intellij.codeInsight.FileModificationService; -import com.intellij.codeInsight.daemon.QuickFixBundle; -import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.project.Project; -import com.intellij.psi.*; -import com.intellij.psi.controlFlow.*; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.util.BitUtil; -import com.intellij.util.IncorrectOperationException; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * @author ven - */ -public class RemoveRedundantElseAction extends PsiElementBaseIntentionAction { - private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.daemon.impl.quickfix.RemoveRedundantElseAction"); - - @Override - @NotNull - public String getText() { - return QuickFixBundle.message("remove.redundant.else.fix"); - } - - @Override - @NotNull - public String getFamilyName() { - return QuickFixBundle.message("remove.redundant.else.fix"); - } - - @Override - public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) { - if (element instanceof PsiKeyword && - element.getParent() instanceof PsiIfStatement && - PsiKeyword.ELSE.equals(element.getText())) { - PsiIfStatement ifStatement = (PsiIfStatement)element.getParent(); - if (ifStatement.getElseBranch() == null) return false; - PsiStatement thenBranch = ifStatement.getThenBranch(); - if (thenBranch == null) return false; - PsiElement block = PsiTreeUtil.getParentOfType(ifStatement, PsiCodeBlock.class); - if (block != null) { - while (cantCompleteNormally(thenBranch, block)) { - thenBranch = getPrevThenBranch(thenBranch); - if (thenBranch == null) return true; - } - return false; - } - } - return false; - } - - @Nullable - private static PsiStatement getPrevThenBranch(@NotNull PsiElement thenBranch) { - final PsiElement ifStatement = thenBranch.getParent(); - final PsiElement parent = ifStatement.getParent(); - if (parent instanceof PsiIfStatement && ((PsiIfStatement)parent).getElseBranch() == ifStatement) { - return ((PsiIfStatement)parent).getThenBranch(); - } - return null; - } - - private static boolean cantCompleteNormally(@NotNull PsiStatement thenBranch, PsiElement block) { - try { - ControlFlow controlFlow = ControlFlowFactory.getInstance(thenBranch.getProject()).getControlFlow(block, LocalsOrMyInstanceFieldsControlFlowPolicy.getInstance()); - int startOffset = controlFlow.getStartOffset(thenBranch); - int endOffset = controlFlow.getEndOffset(thenBranch); - return startOffset != -1 && endOffset != -1 && !BitUtil.isSet(ControlFlowUtil.getCompletionReasons(controlFlow, startOffset, endOffset), ControlFlowUtil.NORMAL_COMPLETION_REASON); - } - catch (AnalysisCanceledException e) { - return false; - } - } - - @Override - public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element) throws IncorrectOperationException { - if (!FileModificationService.getInstance().preparePsiElementForWrite(element)) return; - PsiIfStatement ifStatement = (PsiIfStatement)element.getParent(); - LOG.assertTrue(ifStatement != null && ifStatement.getElseBranch() != null); - PsiStatement elseBranch = ifStatement.getElseBranch(); - if (elseBranch instanceof PsiBlockStatement) { - PsiElement[] statements = ((PsiBlockStatement)elseBranch).getCodeBlock().getStatements(); - if (statements.length > 0) { - ifStatement.getParent().addRangeAfter(statements[0], statements[statements.length-1], ifStatement); - } - } else { - ifStatement.getParent().addAfter(elseBranch, ifStatement); - } - ifStatement.getElseBranch().delete(); - } -} diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/quickFix/RedundantLambdaParameterTypeIntention.java b/java/java-impl/src/com/intellij/codeInspection/lambda/RedundantLambdaParameterTypeInspection.java similarity index 73% rename from java/java-impl/src/com/intellij/codeInsight/daemon/quickFix/RedundantLambdaParameterTypeIntention.java rename to java/java-impl/src/com/intellij/codeInspection/lambda/RedundantLambdaParameterTypeInspection.java index 38eacc30395a..4e2445fbaee9 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/quickFix/RedundantLambdaParameterTypeIntention.java +++ b/java/java-impl/src/com/intellij/codeInspection/lambda/RedundantLambdaParameterTypeInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2016 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,44 +13,43 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.codeInsight.daemon.quickFix; +package com.intellij.codeInspection.lambda; -import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction; +import com.intellij.codeInspection.BaseJavaBatchLocalInspectionTool; +import com.intellij.codeInspection.LocalQuickFix; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.codeInspection.ProblemsHolder; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.impl.source.resolve.DefaultParameterTypeInferencePolicy; import com.intellij.psi.infos.MethodCandidateInfo; -import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; -import com.intellij.util.Function; -import com.intellij.util.IncorrectOperationException; +import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; /** * User: anna */ -public class RedundantLambdaParameterTypeIntention extends PsiElementBaseIntentionAction { - public static final Logger LOG = Logger.getInstance("#" + RedundantLambdaParameterTypeIntention.class.getName()); +public class RedundantLambdaParameterTypeInspection extends BaseJavaBatchLocalInspectionTool { + public static final Logger LOG = Logger.getInstance("#" + RedundantLambdaParameterTypeInspection.class.getName()); @NotNull @Override - public String getFamilyName() { - return "Remove redundant types"; + public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) { + return new JavaElementVisitor() { + @Override + public void visitParameterList(PsiParameterList parameterList) { + super.visitParameterList(parameterList); + if (isApplicable(parameterList)) { + holder.registerProblem(parameterList, "Remove redundant types", new LambdaParametersFix()); + } + } + }; } - @NotNull - @Override - public String getText() { - return getFamilyName(); - } - - @Override - public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) { - final PsiParameterList parameterList = PsiTreeUtil.getParentOfType(element, PsiParameterList.class); - if (parameterList == null) return false; + private static boolean isApplicable(@NotNull PsiParameterList parameterList) { final PsiElement parent = parameterList.getParent(); if (!(parent instanceof PsiLambdaExpression)) return false; final PsiLambdaExpression expression = (PsiLambdaExpression)parent; @@ -73,9 +72,9 @@ public class RedundantLambdaParameterTypeIntention extends PsiElementBaseIntenti final PsiTypeParameter[] typeParameters = method.getTypeParameters(); final PsiExpression[] arguments = ((PsiExpressionList)lambdaParent).getExpressions(); - final JavaPsiFacade javaPsiFacade = JavaPsiFacade.getInstance(project); + final JavaPsiFacade javaPsiFacade = JavaPsiFacade.getInstance(parameterList.getProject()); arguments[idx] = javaPsiFacade.getElementFactory().createExpressionFromText( - "(" + StringUtil.join(expression.getParameterList().getParameters(), parameter -> parameter.getName(), ", ") + ") -> {}", expression); + "(" + StringUtil.join(expression.getParameterList().getParameters(), PsiParameter::getName, ", ") + ") -> {}", expression); final PsiParameter[] methodParams = method.getParameterList().getParameters(); final PsiSubstitutor substitutor = javaPsiFacade.getResolveHelper() .inferTypeArguments(typeParameters, methodParams, arguments, ((MethodCandidateInfo)resolveResult).getSiteSubstitutor(), @@ -85,8 +84,7 @@ public class RedundantLambdaParameterTypeIntention extends PsiElementBaseIntenti final PsiType psiType = substitutor.substitute(parameter); if (psiType == null || dependsOnTypeParams(psiType, expression, parameter)) return false; } - - + final PsiType paramType; if (idx < methodParams.length) { paramType = methodParams[idx].getType(); @@ -107,12 +105,6 @@ public class RedundantLambdaParameterTypeIntention extends PsiElementBaseIntenti return false; } - @Override - public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element) throws IncorrectOperationException { - final PsiLambdaExpression lambdaExpression = PsiTreeUtil.getParentOfType(element, PsiLambdaExpression.class); - removeTypes(lambdaExpression); - } - private static void removeTypes(PsiLambdaExpression lambdaExpression) { if (lambdaExpression != null) { final PsiParameter[] parameters = lambdaExpression.getParameterList().getParameters(); @@ -121,7 +113,7 @@ public class RedundantLambdaParameterTypeIntention extends PsiElementBaseIntenti text = parameters[0].getName(); } else { - text = "(" + StringUtil.join(parameters, parameter -> parameter.getName(), ", ") + ")"; + text = "(" + StringUtil.join(parameters, PsiParameter::getName, ", ") + ")"; } final PsiLambdaExpression expression = (PsiLambdaExpression)JavaPsiFacade.getElementFactory(lambdaExpression.getProject()) .createExpressionFromText(text + "->{}", lambdaExpression); @@ -135,4 +127,29 @@ public class RedundantLambdaParameterTypeIntention extends PsiElementBaseIntenti return LambdaUtil.depends(type, new LambdaUtil.TypeParamsChecker(expr, PsiUtil .resolveGenericsClassInType(LambdaUtil.getFunctionalInterfaceType(expr, false)).getElement()), param2Check); } + + private static class LambdaParametersFix implements LocalQuickFix { + @Nls + @NotNull + @Override + public String getName() { + return getFamilyName(); + } + + @Nls + @NotNull + @Override + public String getFamilyName() { + return "Remove redundant types"; + } + + @Override + public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { + final PsiElement element = descriptor.getPsiElement(); + final PsiElement parent = element.getParent(); + if (parent instanceof PsiLambdaExpression) { + removeTypes((PsiLambdaExpression)parent); + } + } + } } diff --git a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/HierarchyServiceImpl.java b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/HierarchyServiceImpl.java index 31fa42faa53a..2583ea48770b 100644 --- a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/HierarchyServiceImpl.java +++ b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/HierarchyServiceImpl.java @@ -19,13 +19,10 @@ import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressIndicatorProvider; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ProjectFileIndex; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.roots.ProjectRootManager; +import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.openapi.vfs.VirtualFileWithId; import com.intellij.psi.impl.java.stubs.hierarchy.IndexTree; -import com.intellij.psi.search.DelegatingGlobalSearchScope; -import com.intellij.psi.search.EverythingGlobalScope; -import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.stubsHierarchy.HierarchyService; import com.intellij.psi.util.CachedValue; import com.intellij.psi.util.CachedValueProvider; @@ -33,17 +30,18 @@ import com.intellij.psi.util.CachedValuesManager; import com.intellij.psi.util.PsiModificationTracker; import com.intellij.util.CachedValueBase; import com.intellij.util.indexing.FileBasedIndex; +import com.intellij.util.indexing.FileBasedIndexImpl; import org.jetbrains.annotations.NotNull; +import java.util.BitSet; + public class HierarchyServiceImpl extends HierarchyService { private static final SingleClassHierarchy EMPTY_HIERARCHY = new SingleClassHierarchy(Symbol.ClassSymbol.EMPTY_ARRAY); private final Project myProject; - private final ProjectFileIndex myFileIndex; private final CachedValue myHierarchy; public HierarchyServiceImpl(Project project) { myProject = project; - myFileIndex = ProjectFileIndex.SERVICE.getInstance(project); myHierarchy = CachedValuesManager.getManager(project).createCachedValue( () -> CachedValueProvider.Result.create(buildHierarchy(), PsiModificationTracker.MODIFICATION_COUNT), false); @@ -69,38 +67,56 @@ public class HierarchyServiceImpl extends HierarchyService { private SingleClassHierarchy buildHierarchy() { Symbols symbols = new Symbols(); StubEnter stubEnter = new StubEnter(symbols); + IdSets idSets = IdSets.getIdSets(myProject); - loadUnits(false, symbols.myNameEnvironment, stubEnter); + loadUnits(idSets.libraryFiles, StubHierarchyIndex.BINARY_FILES, symbols.myNameEnvironment, stubEnter); stubEnter.connect1(); - loadUnits(true, symbols.myNameEnvironment, stubEnter); + loadUnits(idSets.sourceFiles, StubHierarchyIndex.SOURCE_FILES, symbols.myNameEnvironment, stubEnter); stubEnter.connect2(); return symbols.createHierarchy(); } - private void loadUnits(boolean sourceMode, NameEnvironment names, StubEnter stubEnter) { - GlobalSearchScope scope = new DelegatingGlobalSearchScope(new EverythingGlobalScope(myProject)) { - @Override - public boolean contains(@NotNull VirtualFile file) { - return sourceMode ? myFileIndex.isInSourceContent(file) : myFileIndex.isInLibraryClasses(file); - } - }; + private void loadUnits(BitSet files, int indexKey, NameEnvironment names, StubEnter stubEnter) { ProgressIndicator indicator = ProgressIndicatorProvider.getGlobalProgressIndicator(); - FileBasedIndex index = FileBasedIndex.getInstance(); - for (String packageName : index.getAllKeys(StubHierarchyIndex.INDEX_ID, myProject)) { - QualifiedName pkg = StringUtil.isEmpty(packageName) ? null : names.fromString(packageName, true); - index.processValues(StubHierarchyIndex.INDEX_ID, packageName, null, new FileBasedIndex.ValueProcessor() { - int count = 0; - @Override - public boolean process(VirtualFile file, IndexTree.Unit unit) { - if (indicator != null && ++count % 128 == 0) indicator.checkCanceled(); - stubEnter.unitEnter(Translator.internNames(names, unit, ((VirtualFileWithId)file).getId(), pkg)); - return true; + FileBasedIndexImpl index = (FileBasedIndexImpl)FileBasedIndex.getInstance(); + index.processAllValues(StubHierarchyIndex.INDEX_ID, indexKey, myProject, new FileBasedIndexImpl.IdValueProcessor() { + int count = 0; + @Override + public boolean process(int fileId, IndexTree.Unit unit) { + if (indicator != null && ++count % 128 == 0) indicator.checkCanceled(); + if (files.get(fileId)) { + QualifiedName pkg = unit.myPackageName.length == 0 ? null : names.myNamesEnumerator.getFullName(unit.myPackageName, true); + stubEnter.unitEnter(Translator.internNames(names, unit, fileId, pkg)); } - }, scope); - } + return true; + } + }); } + private static class IdSets { + final BitSet sourceFiles = new BitSet(); + final BitSet libraryFiles = new BitSet(); + + static IdSets getIdSets(@NotNull Project project) { + return CachedValuesManager.getManager(project).getCachedValue(project, () -> { + IdSets answer = new IdSets(); + ProjectFileIndex index = ProjectFileIndex.SERVICE.getInstance(project); + FileBasedIndex.getInstance().iterateIndexableFiles(file -> { + if (!file.isDirectory() && file instanceof VirtualFileWithId) { + if (index.isInSourceContent(file)) { + answer.sourceFiles.set(((VirtualFileWithId) file).getId()); + } + else if (index.isInLibraryClasses(file)) { + answer.libraryFiles.set(((VirtualFileWithId) file).getId()); + } + } + return true; + }, project, ProgressIndicatorProvider.getGlobalProgressIndicator()); + return CachedValueProvider.Result.create(answer, ProjectRootManager.getInstance(project), VirtualFileManager.VFS_STRUCTURE_MODIFICATIONS); + }); + } + } } diff --git a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/JavaStubIndexer.java b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/JavaStubIndexer.java index 550c33b9c74e..616ea7213f3c 100644 --- a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/JavaStubIndexer.java +++ b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/JavaStubIndexer.java @@ -18,7 +18,6 @@ package com.intellij.psi.stubsHierarchy.impl; import com.intellij.ide.highlighter.JavaClassFileType; import com.intellij.ide.highlighter.JavaFileType; import com.intellij.openapi.fileTypes.FileType; -import com.intellij.openapi.util.Pair; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiModifier; import com.intellij.psi.PsiNameHelper; @@ -39,7 +38,10 @@ import com.intellij.util.indexing.FileContent; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.*; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; public class JavaStubIndexer extends StubHierarchyIndexer { @@ -61,7 +63,7 @@ public class JavaStubIndexer extends StubHierarchyIndexer { @Nullable @Override - public List> indexFile(@NotNull FileContent content) { + public Unit indexFile(@NotNull FileContent content) { Stub stubTree = StubTreeBuilder.buildStubTree(content); if (!(stubTree instanceof PsiJavaFileStub)) return null; @@ -87,7 +89,7 @@ public class JavaStubIndexer extends StubHierarchyIndexer { ClassDecl[] classes = classList.isEmpty() ? ClassDecl.EMPTY_ARRAY : classList.toArray(new ClassDecl[classList.size()]); Import[] imports = importList.isEmpty() ? Import.EMPTY_ARRAY : importList.toArray(new Import[importList.size()]); byte type = javaFileStub.isCompiled() ? IndexTree.BYTECODE : IndexTree.JAVA; - return Collections.singletonList(Pair.create(javaFileStub.getPackageName(), new Unit(type, imports, classes))); + return new Unit(javaFileStub.getPackageName(), type, imports, classes); } @Nullable diff --git a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/NameEnvironment.java b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/NameEnvironment.java index 4dd87cff7630..e97f18ff7bd4 100644 --- a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/NameEnvironment.java +++ b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/NameEnvironment.java @@ -16,14 +16,12 @@ package com.intellij.psi.stubsHierarchy.impl; import com.intellij.openapi.util.UserDataHolderBase; -import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.impl.java.stubs.hierarchy.IndexTree; import org.jetbrains.annotations.Nullable; import java.util.Arrays; -import java.util.List; public class NameEnvironment extends UserDataHolderBase { - public final QualifiedName empty; public final QualifiedName java_lang_Object; public final QualifiedName java_lang_Enum; @@ -40,22 +38,7 @@ public class NameEnvironment extends UserDataHolderBase { @Nullable public QualifiedName fromString(String s, boolean create) { - List comps = StringUtil.split(s, "."); - int[] ids = new int[comps.size()]; - for (int i = 0; i < comps.size(); i++) { - int name = simpleName(comps.get(i), create); - if (name == NamesEnumerator.NO_NAME) { - return null; - } - ids[i] = name; - } - return myNamesEnumerator.getFullName(ids, create); - } - - public int simpleName(String s, boolean create) { - if (s == null) - return NamesEnumerator.NO_NAME; - return myNamesEnumerator.getSimpleName(s, create); + return myNamesEnumerator.getFullName(IndexTree.hashQualifiedName(s), create); } public QualifiedName prefix(QualifiedName name) { diff --git a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/NamesEnumerator.java b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/NamesEnumerator.java index 02ee1143574e..cde21cf6ca45 100644 --- a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/NamesEnumerator.java +++ b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/NamesEnumerator.java @@ -15,31 +15,15 @@ */ package com.intellij.psi.stubsHierarchy.impl; -import com.intellij.util.ArrayUtil; import gnu.trove.TObjectHashingStrategy; import gnu.trove.TObjectIntHashMap; -import org.jetbrains.annotations.Nullable; import java.util.Arrays; public class NamesEnumerator { final static int NO_NAME = 0; - private TObjectIntHashMap myAsciiMap = new TObjectIntHashMap(new TObjectHashingStrategy() { - @Override - public int computeHashCode(byte[] object) { - return Arrays.hashCode(object); - } - - @Override - public boolean equals(byte[] o1, byte[] o2) { - return Arrays.equals(o1, o2); - } - }); - - private TObjectIntHashMap myNonAsciiMap = new TObjectIntHashMap(); - - TObjectIntHashMap fullNameMap = new TObjectIntHashMap(new TObjectHashingStrategy() { + private final TObjectIntHashMap myFullNameMap = new TObjectIntHashMap(new TObjectHashingStrategy() { @Override public int computeHashCode(int[] object) { return Arrays.hashCode(object); @@ -50,38 +34,17 @@ public class NamesEnumerator { return Arrays.equals(o1, o2); } }); - private QualifiedName[] myQualifiedNames = new QualifiedName[0x8000]; QualifiedName qualifiedName(int id) { return myQualifiedNames[id]; } - public int getSimpleName(String s, boolean create) { - byte[] bytes = convertToBytesIfAsciiString(s); - if (bytes != null) { - int id = myAsciiMap.get(bytes); - if (id == 0 && create) { - id = myAsciiMap.size() + myNonAsciiMap.size() + 1; - myAsciiMap.put(bytes, id); - } - return id; - } - else { - int id = myNonAsciiMap.get(s); - if (id == 0 && create) { - id = myAsciiMap.size() + myNonAsciiMap.size() + 1; - myNonAsciiMap.put(s, id); - } - return id; - } - } - public QualifiedName getFullName(int[] ids, boolean create) { - int id = fullNameMap.get(ids); + int id = myFullNameMap.get(ids); if (id == 0 && create) { - id = fullNameMap.size() + 1; - fullNameMap.put(ids, id); + id = myFullNameMap.size() + 1; + myFullNameMap.put(ids, id); ensureFullCapacity(id); myQualifiedNames[id] = new QualifiedName(id, ids); } @@ -104,20 +67,4 @@ public class NamesEnumerator { return currentLength; } - @Nullable - public static byte[] convertToBytesIfAsciiString(CharSequence name) { - int length = name.length(); - if (length == 0) return ArrayUtil.EMPTY_BYTE_ARRAY; - - byte[] bytes = new byte[length]; - for (int i = 0; i < length; i++) { - char c = name.charAt(i); - if (c >= 128) { - return null; - } - bytes[i] = (byte)c; - } - return bytes; - } - } diff --git a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/StubEnter.java b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/StubEnter.java index 728a39f29c21..77dab13e8492 100644 --- a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/StubEnter.java +++ b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/StubEnter.java @@ -88,7 +88,7 @@ public class StubEnter { supers = myNameEnvironment.annotation; } - ClassSymbol classSymbol = mySymbols.enterClass(tree.myClassAnchor, flags, tree.myName, owner, info, supers, myStubHierarchyConnector); + ClassSymbol classSymbol = mySymbols.enterClass(tree.myClassAnchor, flags, tree.myName, owner, info, supers); if (uncompleted != null) { uncompleted.add(classSymbol); @@ -100,14 +100,14 @@ public class StubEnter { public void connect1() { for (ClassSymbol classSymbol : uncompleted) { - classSymbol.connect(); + classSymbol.connect(myStubHierarchyConnector); } uncompleted = new ArrayList(); } public void connect2() { for (ClassSymbol classSymbol : uncompleted) { - classSymbol.connect(); + classSymbol.connect(myStubHierarchyConnector); } uncompleted = null; } diff --git a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/StubHierarchyConnector.java b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/StubHierarchyConnector.java index 31b84f114fd0..f1c3e41117ce 100644 --- a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/StubHierarchyConnector.java +++ b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/StubHierarchyConnector.java @@ -26,14 +26,14 @@ public class StubHierarchyConnector { protected StubHierarchyConnector(NameEnvironment nameEnvironment, Symbols symbols) { this.myNameEnvironment = nameEnvironment; - myResolve = new StubResolver(symbols); + myResolve = new StubResolver(symbols, this); } void connect(Symbol sym) { Symbol.ClassSymbol c = (Symbol.ClassSymbol) sym; if (c.myOwner instanceof Symbol.ClassSymbol) { - ((Symbol.ClassSymbol)c.myOwner).connect(); + ((Symbol.ClassSymbol)c.myOwner).connect(this); } // Determine supertype. @@ -67,6 +67,7 @@ public class StubHierarchyConnector { c.mySuperClasses = Symbol.ClassSymbol.EMPTY_ARRAY; } else { + //noinspection SuspiciousToArrayCall c.mySuperClasses = supertypes.toArray(new Symbol.ClassSymbol[supertypes.size()]); } } diff --git a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/StubHierarchyIndex.java b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/StubHierarchyIndex.java index 2550e2fb528a..e695897cfe8b 100644 --- a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/StubHierarchyIndex.java +++ b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/StubHierarchyIndex.java @@ -18,47 +18,42 @@ package com.intellij.psi.stubsHierarchy.impl; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.roots.ProjectFileIndex; -import com.intellij.openapi.util.Pair; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.impl.java.stubs.hierarchy.IndexTree; import com.intellij.psi.impl.java.stubs.index.JavaUnitDescriptor; import com.intellij.psi.stubsHierarchy.StubHierarchyIndexer; import com.intellij.util.indexing.*; import com.intellij.util.io.DataExternalizer; -import com.intellij.util.io.EnumeratorStringDescriptor; +import com.intellij.util.io.EnumeratorIntegerDescriptor; import com.intellij.util.io.KeyDescriptor; import org.jetbrains.annotations.NotNull; -import java.util.*; +import java.util.Arrays; +import java.util.Collections; /** * @author peter */ -public class StubHierarchyIndex extends FileBasedIndexExtension implements PsiDependentIndex { - static final ID INDEX_ID = ID.create("jvm.hierarchy"); +public class StubHierarchyIndex extends FileBasedIndexExtension implements PsiDependentIndex { + public static final int BINARY_FILES = 0; + public static final int SOURCE_FILES = 1; + static final ID INDEX_ID = ID.create("jvm.hierarchy"); private static final StubHierarchyIndexer[] ourIndexers = StubHierarchyIndexer.EP_NAME.getExtensions(); @NotNull @Override - public ID getName() { + public ID getName() { return INDEX_ID; } @NotNull @Override - public DataIndexer getIndexer() { + public DataIndexer getIndexer() { return inputData -> { for (StubHierarchyIndexer indexer : ourIndexers) { - List> pairs = indexer.handlesFile(inputData.getFile()) ? indexer.indexFile(inputData) : null; - if (pairs != null && !pairs.isEmpty()) { - Map answer = new HashMap<>(); - for (Pair entry : pairs) { - if (entry.second.myDecls.length > 0) { - answer.put(StringUtil.notNullize(entry.first), entry.second); - } - } - return answer; + IndexTree.Unit unit = indexer.handlesFile(inputData.getFile()) ? indexer.indexFile(inputData) : null; + if (unit != null && unit.myDecls.length > 0) { + return Collections.singletonMap(inputData.getFile().getFileType().isBinary() ? BINARY_FILES : SOURCE_FILES, unit); } } return Collections.emptyMap(); @@ -67,8 +62,8 @@ public class StubHierarchyIndex extends FileBasedIndexExtension getKeyDescriptor() { - return EnumeratorStringDescriptor.INSTANCE; + public KeyDescriptor getKeyDescriptor() { + return EnumeratorIntegerDescriptor.INSTANCE; } @NotNull @@ -79,7 +74,7 @@ public class StubHierarchyIndex extends FileBasedIndexExtension symbols, Set processed) throws IncompleteHierarchyException { + private void findMemberType(Symbol s, int name, Set symbols, Set processed) throws IncompleteHierarchyException { if (!processed.add(s)) { return; } @@ -130,9 +132,9 @@ public class StubResolver { } } - private static void findInheritedMemberType(Symbol.ClassSymbol c, int name, Set symbols, Set processed) + private void findInheritedMemberType(Symbol.ClassSymbol c, int name, Set symbols, Set processed) throws IncompleteHierarchyException { - for (Symbol.ClassSymbol st : c.getSuperClasses()) + for (Symbol.ClassSymbol st : c.getSuperClasses(myConnector)) findMemberType(st, name, symbols, processed); } @@ -194,13 +196,13 @@ public class StubResolver { } // handling of import static `tsym.name` as - private static void importNamedStatic(final Symbol.ClassSymbol tsym, final int name, final Set symbols) throws IncompleteHierarchyException { + private void importNamedStatic(final Symbol.ClassSymbol tsym, final int name, final Set symbols) throws IncompleteHierarchyException { new Object() { Set processed = new HashSet(); void importFrom(Symbol.ClassSymbol cs) throws IncompleteHierarchyException { if (cs == null || !processed.add(cs)) return; - for (Symbol.ClassSymbol c : cs.getSuperClasses()) + for (Symbol.ClassSymbol c : cs.getSuperClasses(myConnector)) importFrom(c); importMember(cs.members(), name, symbols, true); } diff --git a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/Symbol.java b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/Symbol.java index bb1505d342ec..4ffcbed374fe 100644 --- a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/Symbol.java +++ b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/Symbol.java @@ -86,28 +86,27 @@ public abstract class Symbol { /** A class for class symbols */ public static class ClassSymbol extends Symbol { + private static final int HIERARCHY_INCOMPLETE = 1 << 20; + private static final int CONNECT_STARTED = 1 << 21; public static final ClassSymbol[] EMPTY_ARRAY = new ClassSymbol[0]; - public final StubClassAnchor myClassAnchor; - public ClassSymbol[] mySuperClasses; - public UnitInfo myUnitInfo; - public QualifiedName[] mySuperNames; - private ClassSymbol[] myMembers; - private StubHierarchyConnector myConnector; - private boolean myHierarchyIncomplete; - public ClassSymbol(StubClassAnchor classAnchor, + final StubClassAnchor myClassAnchor; + ClassSymbol[] mySuperClasses; + UnitInfo myUnitInfo; + QualifiedName[] mySuperNames; + private ClassSymbol[] myMembers; + + ClassSymbol(StubClassAnchor classAnchor, int flags, Symbol owner, QualifiedName fullname, int name, UnitInfo unitInfo, - QualifiedName[] supers, - StubHierarchyConnector connector) { + QualifiedName[] supers) { super(flags | IndexTree.CLASS, owner, fullname, name); this.myClassAnchor = classAnchor; this.mySuperNames = supers; this.myUnitInfo = unitInfo; - this.myConnector = connector; } @Override @@ -115,18 +114,21 @@ public abstract class Symbol { return myClassAnchor.toString(); } - public void connect() { - if (myConnector != null) { - StubHierarchyConnector c = myConnector; - myConnector = null; - c.connect(this); + void connect(StubHierarchyConnector connector) { + if (!isConnectStarted()) { + myFlags = BitUtil.set(myFlags, CONNECT_STARTED, true); + connector.connect(this); } } + private boolean isConnectStarted() { + return BitUtil.isSet(myFlags, CONNECT_STARTED); + } + @NotNull - public ClassSymbol[] getSuperClasses() throws IncompleteHierarchyException { - connect(); - if (myHierarchyIncomplete) { + ClassSymbol[] getSuperClasses(StubHierarchyConnector connector) throws IncompleteHierarchyException { + connect(connector); + if (isHierarchyIncomplete()) { throw IncompleteHierarchyException.INSTANCE; } return rawSuperClasses(); @@ -134,11 +136,11 @@ public abstract class Symbol { @NotNull ClassSymbol[] rawSuperClasses() { - assert myConnector == null; + assert isConnectStarted(); return mySuperClasses == null ? EMPTY_ARRAY : mySuperClasses; } - public boolean isCompiled() { + boolean isCompiled() { return BitUtil.isSet(myFlags, IndexTree.COMPILED); } @@ -154,11 +156,11 @@ public abstract class Symbol { mySuperClasses = EMPTY_ARRAY; mySuperNames = null; myUnitInfo = null; - myHierarchyIncomplete = true; + myFlags = BitUtil.set(myFlags, HIERARCHY_INCOMPLETE, true); } boolean isHierarchyIncomplete() { - return myHierarchyIncomplete; + return BitUtil.isSet(myFlags, HIERARCHY_INCOMPLETE); } boolean hasAmbiguousSupers() { diff --git a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/Symbols.java b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/Symbols.java index 42feaf324509..13017b18ab46 100644 --- a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/Symbols.java +++ b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/Symbols.java @@ -63,10 +63,10 @@ public class Symbols { return (ClassSymbol[])cs; } - public ClassSymbol enterClass(ClassAnchor classAnchor, int flags, int shortName, Symbol owner, UnitInfo info, QualifiedName[] supers, StubHierarchyConnector connector) { + public ClassSymbol enterClass(ClassAnchor classAnchor, int flags, int shortName, Symbol owner, UnitInfo info, QualifiedName[] supers) { QualifiedName qualifiedName = myNameEnvironment.qualifiedName(owner, shortName); StubClassAnchor stubClassAnchor = new StubClassAnchor(myClassSymbols.size(), classAnchor); - ClassSymbol c = new ClassSymbol(stubClassAnchor, flags, owner, qualifiedName, shortName, info, supers, connector); + ClassSymbol c = new ClassSymbol(stubClassAnchor, flags, owner, qualifiedName, shortName, info, supers); myClassSymbols.add(c); putClassByName(c); return c; diff --git a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/Translator.java b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/Translator.java index 0ad3c8b8d831..1367d003dd4e 100644 --- a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/Translator.java +++ b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/Translator.java @@ -16,15 +16,12 @@ package com.intellij.psi.stubsHierarchy.impl; import com.intellij.openapi.util.Key; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.psi.PsiNameHelper; import com.intellij.psi.impl.java.stubs.hierarchy.IndexTree; import com.intellij.psi.stubsHierarchy.stubs.*; import com.intellij.util.BitUtil; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; -import java.util.List; public class Translator { private static final Key DEFAULT_JAVA_IMPORTS_KEY = Key.create("java_imports"); @@ -91,11 +88,10 @@ public class Translator { } private static ClassDeclaration processClassDecl(NameEnvironment nameEnvironment, int fileId, IndexTree.ClassDecl def) { - String stubName = def.myName; - int name = stubName == null ? 0 : nameEnvironment.simpleName(stubName, true); + int name = def.myName; ArrayList superList = new ArrayList(); - for (String aSuper : def.mySupers) { - superList.add(id(nameEnvironment, aSuper)); + for (int[] aSuper : def.mySupers) { + superList.add(nameEnvironment.concat(aSuper, true)); } if (BitUtil.isSet(def.myMods, IndexTree.ENUM)) { superList.add(nameEnvironment.java_lang_Enum); @@ -130,21 +126,8 @@ public class Translator { } private static long processImport(NameEnvironment nameEnvironment, IndexTree.Import anImport) { - QualifiedName fullname = nameEnvironment.fromString(anImport.myFullname, true); - int aliasName = anImport.myAlias == null ? 0 : nameEnvironment.simpleName(anImport.myAlias, true); - return Import.mkImport(fullname, anImport.myStaticImport, anImport.myOnDemand, aliasName); + QualifiedName fullname = nameEnvironment.myNamesEnumerator.getFullName(anImport.myFullname, true); + return Import.mkImport(fullname, anImport.myStaticImport, anImport.myOnDemand, anImport.myAlias); } - private static QualifiedName id(NameEnvironment nameEnvironment, String s) { - s = PsiNameHelper.getQualifiedClassName(s, true); - List ids = StringUtil.split(s, "."); - int[] comps = new int[ids.size()]; - int i = 0; - for (String id : ids) { - int name = nameEnvironment.simpleName(id, true); - comps[i] = name; - i++; - } - return nameEnvironment.concat(comps, true); - } } diff --git a/java/java-impl/src/com/intellij/refactoring/extractclass/ExtractClassHandler.java b/java/java-impl/src/com/intellij/refactoring/extractclass/ExtractClassHandler.java index b263d49ddfdc..6a6146434d54 100644 --- a/java/java-impl/src/com/intellij/refactoring/extractclass/ExtractClassHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/extractclass/ExtractClassHandler.java @@ -63,7 +63,7 @@ public class ExtractClassHandler implements ElementsHandler { if (cannotRefactorMessage != null) { CommonRefactoringUtil.showErrorHint(project, editor, RefactorJBundle.message("cannot.perform.the.refactoring") + cannotRefactorMessage, - null, getHelpID()); + ExtractClassProcessor.REFACTORING_NAME, getHelpID()); return; } new ExtractClassDialog(containingClass, selectedMember).show(); diff --git a/java/java-impl/src/com/intellij/refactoring/extractclass/ExtractClassProcessor.java b/java/java-impl/src/com/intellij/refactoring/extractclass/ExtractClassProcessor.java index 1e92218a183e..b0f0236075f0 100644 --- a/java/java-impl/src/com/intellij/refactoring/extractclass/ExtractClassProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/extractclass/ExtractClassProcessor.java @@ -66,6 +66,7 @@ import java.util.*; public class ExtractClassProcessor extends FixableUsagesRefactoringProcessor { private static final Logger logger = Logger.getInstance("com.siyeh.rpp.extractclass.ExtractClassProcessor"); + @NonNls public static final String REFACTORING_NAME = "Extract Delegate"; private final PsiClass sourceClass; private final List fields; diff --git a/java/java-indexing-impl/src/com/intellij/psi/impl/java/stubs/index/JavaUnitDescriptor.java b/java/java-indexing-impl/src/com/intellij/psi/impl/java/stubs/index/JavaUnitDescriptor.java index bc8d742039b6..ad2fddadbe36 100644 --- a/java/java-indexing-impl/src/com/intellij/psi/impl/java/stubs/index/JavaUnitDescriptor.java +++ b/java/java-indexing-impl/src/com/intellij/psi/impl/java/stubs/index/JavaUnitDescriptor.java @@ -16,6 +16,7 @@ package com.intellij.psi.impl.java.stubs.index; import com.intellij.psi.impl.java.stubs.hierarchy.IndexTree; +import com.intellij.util.BitUtil; import com.intellij.util.io.DataExternalizer; import com.intellij.util.io.DataInputOutputUtil; import org.jetbrains.annotations.NotNull; @@ -24,18 +25,34 @@ import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; +import static com.intellij.psi.impl.java.stubs.index.JavaUnitDescriptor.ImportFlags.*; + public class JavaUnitDescriptor implements DataExternalizer { public static final JavaUnitDescriptor INSTANCE = new JavaUnitDescriptor(); + private static void writeIntArray(DataOutput out, int[] array) throws IOException { + DataInputOutputUtil.writeINT(out, array.length); + for (int i : array) { + out.writeInt(i); + } + } + private static int[] readIntArray(DataInput in) throws IOException { + int length = DataInputOutputUtil.readINT(in); + int[] result = new int[length]; + for (int i = 0; i < length; i++) { + result[i] = in.readInt(); + } + return result; + } + @Override public void save(@NotNull DataOutput out, IndexTree.Unit value) throws IOException { + writeIntArray(out, value.myPackageName); out.writeByte(value.myUnitType); if (value.myUnitType != IndexTree.BYTECODE) { DataInputOutputUtil.writeINT(out, value.imports.length); for (IndexTree.Import anImport : value.imports) { - out.writeUTF(anImport.myFullname); - out.writeBoolean(anImport.myStaticImport); - out.writeBoolean(anImport.myOnDemand); + writeImport(out, anImport); } } // class Declaration @@ -46,12 +63,12 @@ public class JavaUnitDescriptor implements DataExternalizer { } private void saveClassDecl(@NotNull DataOutput out, IndexTree.ClassDecl value) throws IOException { - out.writeInt(value.myStubId); + DataInputOutputUtil.writeINT(out, value.myStubId); DataInputOutputUtil.writeINT(out, value.myMods); - out.writeUTF(value.myName == null ? "" : value.myName); + out.writeInt(value.myName); DataInputOutputUtil.writeINT(out, value.mySupers.length); - for (String aSuper : value.mySupers) { - out.writeUTF(aSuper); + for (int[] aSuper : value.mySupers) { + writeIntArray(out, aSuper); } DataInputOutputUtil.writeINT(out, value.myDecls.length); for (IndexTree.Decl def : value.myDecls) { @@ -75,31 +92,29 @@ public class JavaUnitDescriptor implements DataExternalizer { @Override public IndexTree.Unit read(@NotNull DataInput in) throws IOException { + int[] pid = readIntArray(in); byte type = in.readByte(); IndexTree.Import[] imports = IndexTree.Import.EMPTY_ARRAY; if (type != IndexTree.BYTECODE) { imports = new IndexTree.Import[DataInputOutputUtil.readINT(in)]; for (int i = 0; i < imports.length; i++) { - imports[i] = new IndexTree.Import(in.readUTF(), in.readBoolean(), in.readBoolean(), null); + imports[i] = readImport(in); } } IndexTree.ClassDecl[] classes = new IndexTree.ClassDecl[DataInputOutputUtil.readINT(in)]; for (int i = 0; i < classes.length; i++) { classes[i] = readClassDecl(in); } - return new IndexTree.Unit(type, imports, classes); + return new IndexTree.Unit(pid, type, imports, classes); } private IndexTree.ClassDecl readClassDecl(DataInput in) throws IOException { - int stubId = in.readInt(); + int stubId = DataInputOutputUtil.readINT(in); int mods = DataInputOutputUtil.readINT(in); - String name = in.readUTF(); - if (name.isEmpty()) { - name = null; - } - String[] supers = new String[DataInputOutputUtil.readINT(in)]; + int name = in.readInt(); + int[][] supers = new int[DataInputOutputUtil.readINT(in)][]; for (int i = 0; i < supers.length; i++) { - supers[i] = in.readUTF(); + supers[i] = readIntArray(in); } IndexTree.Decl[] decls = new IndexTree.Decl[DataInputOutputUtil.readINT(in)]; for (int i = 0; i < decls.length; i++) { @@ -122,4 +137,32 @@ public class JavaUnitDescriptor implements DataExternalizer { } } + interface ImportFlags { + int IS_STATIC = 1; + int IS_ON_DEMAND = 2; + int HAS_ALIAS = 4; + } + + private static void writeImport(@NotNull DataOutput out, IndexTree.Import anImport) throws IOException { + writeIntArray(out, anImport.myFullname); + boolean hasAlias = anImport.myAlias != 0; + int flags = 0; + flags = BitUtil.set(flags, IS_STATIC, anImport.myStaticImport); + flags = BitUtil.set(flags, IS_ON_DEMAND, anImport.myOnDemand); + flags = BitUtil.set(flags, HAS_ALIAS, hasAlias); + out.writeByte(flags); + if (hasAlias) { + out.writeInt(anImport.myAlias); + } + } + + @NotNull + private static IndexTree.Import readImport(@NotNull DataInput in) throws IOException { + int[] fullname = readIntArray(in); + int flags = in.readByte(); + return new IndexTree.Import(fullname, + BitUtil.isSet(flags, IS_STATIC), BitUtil.isSet(flags, IS_ON_DEMAND), + BitUtil.isSet(flags, HAS_ALIAS) ? in.readInt() : 0); + } + } diff --git a/java/java-indexing-impl/src/com/intellij/psi/stubsHierarchy/StubHierarchyIndexer.java b/java/java-indexing-impl/src/com/intellij/psi/stubsHierarchy/StubHierarchyIndexer.java index ce9d16602224..4e0e8ac260fc 100644 --- a/java/java-indexing-impl/src/com/intellij/psi/stubsHierarchy/StubHierarchyIndexer.java +++ b/java/java-indexing-impl/src/com/intellij/psi/stubsHierarchy/StubHierarchyIndexer.java @@ -16,15 +16,12 @@ package com.intellij.psi.stubsHierarchy; import com.intellij.openapi.extensions.ExtensionPointName; -import com.intellij.openapi.util.Pair; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.impl.java.stubs.hierarchy.IndexTree; import com.intellij.util.indexing.FileContent; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.List; - /** * @author peter */ @@ -37,7 +34,7 @@ public abstract class StubHierarchyIndexer { * @return a list of pairs for a specified file content */ @Nullable - public abstract List> indexFile(@NotNull FileContent content); + public abstract IndexTree.Unit indexFile(@NotNull FileContent content); public abstract boolean handlesFile(@NotNull VirtualFile file); diff --git a/java/java-psi-api/src/com/intellij/psi/util/PsiSuperMethodUtil.java b/java/java-psi-api/src/com/intellij/psi/util/PsiSuperMethodUtil.java index 2148bd45b3cb..ef0e11156650 100644 --- a/java/java-psi-api/src/com/intellij/psi/util/PsiSuperMethodUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/util/PsiSuperMethodUtil.java @@ -15,11 +15,15 @@ */ package com.intellij.psi.util; +import com.intellij.openapi.roots.FileIndexFacade; +import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; +import com.intellij.psi.search.GlobalSearchScope; import com.intellij.util.containers.HashSet; import gnu.trove.THashMap; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.LinkedHashSet; import java.util.List; @@ -111,6 +115,7 @@ public class PsiSuperMethodUtil { public static Map> collectOverrideEquivalents(@NotNull PsiClass aClass) { final Map> overrideEquivalent = new THashMap>(MethodSignatureUtil.METHOD_PARAMETERS_ERASURE_EQUALITY); + final GlobalSearchScope resolveScope = aClass.getResolveScope(); PsiClass[] supers = aClass.getSupers(); for (int i = 0; i < supers.length; i++) { PsiClass superClass = supers[i]; @@ -122,10 +127,12 @@ public class PsiSuperMethodUtil { if (subType) continue; final PsiSubstitutor superClassSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(superClass, aClass, PsiSubstitutor.EMPTY); for (HierarchicalMethodSignature hms : superClass.getVisibleSignatures()) { - final PsiMethod method = hms.getMethod(); + PsiMethod method = hms.getMethod(); if (MethodSignatureUtil.findMethodBySignature(aClass, method.getSignature(superClassSubstitutor), false) != null) continue; - final PsiClass containingClass = method.getContainingClass(); + final PsiClass containingClass = correctClassByScope(method.getContainingClass(), resolveScope); if (containingClass == null) continue; + method = containingClass.findMethodBySignature(method, false); + if (method == null) continue; final PsiSubstitutor containingClassSubstitutor = TypeConversionUtil.getClassSubstitutor(containingClass, aClass, PsiSubstitutor.EMPTY); if (containingClassSubstitutor == null) continue; final PsiSubstitutor finalSubstitutor = @@ -141,4 +148,30 @@ public class PsiSuperMethodUtil { } return overrideEquivalent; } + + @Nullable + public static PsiClass correctClassByScope(PsiClass psiClass, final GlobalSearchScope resolveScope) { + if (psiClass == null) return null; + String qualifiedName = psiClass.getQualifiedName(); + if (qualifiedName == null) { + return psiClass; + } + + PsiFile file = psiClass.getContainingFile(); + if (file == null || !file.getViewProvider().isPhysical()) { + return psiClass; + } + + final VirtualFile vFile = file.getVirtualFile(); + if (vFile == null) { + return psiClass; + } + + final FileIndexFacade index = FileIndexFacade.getInstance(file.getProject()); + if (!index.isInSource(vFile) && !index.isInLibrarySource(vFile) && !index.isInLibraryClasses(vFile)) { + return psiClass; + } + + return JavaPsiFacade.getInstance(psiClass.getProject()).findClass(qualifiedName, resolveScope); + } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/TypeCorrector.java b/java/java-psi-impl/src/com/intellij/psi/impl/TypeCorrector.java index f6521658c6dc..c6063e0b05bd 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/TypeCorrector.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/TypeCorrector.java @@ -15,11 +15,10 @@ */ package com.intellij.psi.impl; -import com.intellij.openapi.roots.FileIndexFacade; -import com.intellij.openapi.vfs.VirtualFile; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.util.PsiSuperMethodUtil; import com.intellij.psi.util.PsiUtilCore; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; @@ -56,7 +55,7 @@ class TypeCorrector extends PsiTypeMapper { final PsiClassType.ClassResolveResult classResolveResult = classType.resolveGenerics(); final PsiClass psiClass = classResolveResult.getElement(); if (psiClass != null && classResolveResult.getSubstitutor() == PsiSubstitutor.EMPTY) { - final PsiClass mappedClass = mapClass(psiClass); + final PsiClass mappedClass = PsiSuperMethodUtil.correctClassByScope(psiClass, myResolveScope); if (mappedClass == null || mappedClass == psiClass) return (T) classType; } } @@ -79,7 +78,7 @@ class TypeCorrector extends PsiTypeMapper { PsiUtilCore.ensureValid(psiClass); - final PsiClass mappedClass = mapClass(psiClass); + final PsiClass mappedClass = PsiSuperMethodUtil.correctClassByScope(psiClass, myResolveScope); if (mappedClass == null) return classType; PsiClassType mappedType = new PsiCorrectedClassType(classType.getLanguageLevel(), @@ -89,31 +88,6 @@ class TypeCorrector extends PsiTypeMapper { return mappedType; } - @Nullable - private PsiClass mapClass(@NotNull PsiClass psiClass) { - String qualifiedName = psiClass.getQualifiedName(); - if (qualifiedName == null) { - return psiClass; - } - - PsiFile file = psiClass.getContainingFile(); - if (file == null || !file.getViewProvider().isPhysical()) { - return psiClass; - } - - final VirtualFile vFile = file.getVirtualFile(); - if (vFile == null) { - return psiClass; - } - - final FileIndexFacade index = FileIndexFacade.getInstance(file.getProject()); - if (!index.isInSource(vFile) && !index.isInLibrarySource(vFile) && !index.isInLibraryClasses(vFile)) { - return psiClass; - } - - return JavaPsiFacade.getInstance(psiClass.getProject()).findClass(qualifiedName, myResolveScope); - } - @NotNull private PsiSubstitutor mapSubstitutor(PsiClass originalClass, PsiClass mappedClass, PsiSubstitutor substitutor) { PsiTypeParameter[] typeParameters = mappedClass.getTypeParameters(); diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/hierarchy/IndexTree.java b/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/hierarchy/IndexTree.java index faf27c3a2d7b..b7a148b21be1 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/hierarchy/IndexTree.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/hierarchy/IndexTree.java @@ -17,12 +17,19 @@ package com.intellij.psi.impl.java.stubs.hierarchy; import com.intellij.openapi.util.registry.Registry; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.PsiNameHelper; +import com.intellij.util.ArrayUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.Arrays; +import java.util.List; public class IndexTree { public static final boolean STUB_HIERARCHY_ENABLED = Registry.is("java.hierarchy.service"); + @SuppressWarnings("PointlessBitwiseExpression") public final static int PACKAGE = 1 << 0; public final static int CLASS = 1 << 1; public static final int STATIC = 1 << 3; @@ -36,15 +43,52 @@ public class IndexTree { public static final byte JAVA = 1; public static final byte GROOVY = 2; + private static int hashIdentifier(@Nullable String s) { + if (s == null) return 0; + + // not using String.hashCode because this way there's less collisions for short package names like 'com' + int hash = 0; + for (int i = 0; i < s.length(); i++) { + hash = hash * 239 + s.charAt(i); + } + return hash; + } + + public static int[] hashQualifiedName(@NotNull String qName) { + qName = PsiNameHelper.getQualifiedClassName(qName, true); + if (qName.isEmpty()) return ArrayUtil.EMPTY_INT_ARRAY; + + List components = StringUtil.split(qName, "."); + int[] result = new int[components.size()]; + for (int i = 0; i < components.size(); i++) { + result[i] = hashIdentifier(components.get(i)); + } + return result; + } + + private static int[][] hashQualifiedNameArray(String[] supers) { + int[][] superHashes = new int[supers.length][]; + for (int i = 0; i < supers.length; i++) { + superHashes[i] = hashQualifiedName(supers[i]); + } + return superHashes; + } + public static class Unit { + @NotNull public final int[] myPackageName; public final byte myUnitType; public final Import[] imports; public final ClassDecl[] myDecls; - public Unit(byte unitType, Import[] imports, ClassDecl[] decls) { - this.myUnitType = unitType; + public Unit(@Nullable String packageName, byte unitType, Import[] imports, ClassDecl[] decls) { + this(hashQualifiedName(StringUtil.notNullize(packageName)), unitType, imports, decls); + } + + public Unit(@NotNull int[] packageName, byte unitType, Import[] imports, ClassDecl[] decls) { + myPackageName = packageName; + myUnitType = unitType; this.imports = imports; - this.myDecls = decls; + myDecls = decls; } @Override @@ -54,6 +98,8 @@ public class IndexTree { Unit unit = (Unit)o; + if (myUnitType != unit.myUnitType) return false; + if (!Arrays.equals(myPackageName, unit.myPackageName)) return false; if (!Arrays.equals(imports, unit.imports)) return false; if (!Arrays.equals(myDecls, unit.myDecls)) return false; @@ -62,22 +108,33 @@ public class IndexTree { @Override public int hashCode() { - return Arrays.hashCode(myDecls); + int hash = myUnitType * 31 + Arrays.hashCode(myPackageName); + for (ClassDecl decl : myDecls) { + int name = decl.myName; + if (name != 0) { + return hash * 31 + name; + } + } + return hash; } } public static class Import { public static final Import[] EMPTY_ARRAY = new Import[0]; - public final String myFullname; + public final int[] myFullname; public final boolean myStaticImport; public final boolean myOnDemand; - public final String myAlias; + public final int myAlias; - public Import(String fullname, boolean staticImport, boolean onDemand, String alias) { - this.myFullname = fullname; - this.myStaticImport = staticImport; - this.myOnDemand = onDemand; - this.myAlias = alias; + public Import(String fullname, boolean staticImport, boolean onDemand, @Nullable String alias) { + this(hashQualifiedName(fullname), staticImport, onDemand, hashIdentifier(alias)); + } + + public Import(int[] fullname, boolean staticImport, boolean onDemand, int alias) { + myFullname = fullname; + myStaticImport = staticImport; + myOnDemand = onDemand; + myAlias = alias; } @Override @@ -89,18 +146,18 @@ public class IndexTree { if (myStaticImport != anImport.myStaticImport) return false; if (myOnDemand != anImport.myOnDemand) return false; - if (!myFullname.equals(anImport.myFullname)) return false; - if (myAlias != null ? !myAlias.equals(anImport.myAlias) : anImport.myAlias != null) return false; + if (!Arrays.equals(myFullname, anImport.myFullname)) return false; + if (myAlias != anImport.myAlias) return false; return true; } @Override public int hashCode() { - int result = myFullname.hashCode(); + int result = Arrays.hashCode(myFullname); result = 31 * result + (myStaticImport ? 1 : 0); result = 31 * result + (myOnDemand ? 1 : 0); - result = 31 * result + (myAlias != null ? myAlias.hashCode() : 0); + result = 31 * result + myAlias; return result; } } @@ -118,16 +175,20 @@ public class IndexTree { public static final ClassDecl[] EMPTY_ARRAY = new ClassDecl[0]; public final int myStubId; public final int myMods; - public final String myName; - public final String[] mySupers; + public final int myName; + public final int[][] mySupers; - public ClassDecl(int stubId, int mods, String name, String[] supers, Decl[] decls) { + public ClassDecl(int stubId, int mods, @Nullable String name, String[] supers, Decl[] decls) { + this(stubId, mods, hashIdentifier(name), hashQualifiedNameArray(supers), decls); + } + + public ClassDecl(int stubId, int mods, int name, int[][] supers, Decl[] decls) { super(decls); assert stubId > 0; - this.myStubId = stubId; - this.myMods = mods; - this.myName = name; - this.mySupers = supers; + myStubId = stubId; + myMods = mods; + myName = name; + mySupers = supers; } @Override @@ -138,8 +199,8 @@ public class IndexTree { ClassDecl classDecl = (ClassDecl)o; if (myStubId != classDecl.myStubId) return false; if (myMods != classDecl.myMods) return false; - if (myName != null ? !myName.equals(classDecl.myName) : classDecl.myName != null) return false; - if (!Arrays.equals(mySupers, classDecl.mySupers)) return false; + if (myName != classDecl.myName) return false; + if (!Arrays.deepEquals(mySupers, classDecl.mySupers)) return false; if (!Arrays.equals(myDecls, classDecl.myDecls)) return false; return true; } @@ -148,7 +209,7 @@ public class IndexTree { public int hashCode() { int result = myStubId; result = 31 * result + myMods; - result = 31 * result + (myName != null ? myName.hashCode() : 0); + result = 31 * result + myName; return result; } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodCallExpressionImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodCallExpressionImpl.java index 50b49e3b29b1..18ed26bd5e43 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodCallExpressionImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodCallExpressionImpl.java @@ -237,9 +237,7 @@ public class PsiMethodCallExpressionImpl extends ExpressionPsiElement implements PsiType ret, JavaResolveResult result, LanguageLevel languageLevel) { - PsiSubstitutor substitutor = result instanceof MethodCandidateInfo && !PsiPolyExpressionUtil.isMethodCallTypeDependsOnInference(call, method) - ? ((MethodCandidateInfo)result).getSiteSubstitutor() - : result.getSubstitutor(); + PsiSubstitutor substitutor = result.getSubstitutor(); PsiType substitutedReturnType = substitutor.substitute(ret); if (substitutedReturnType == null) { return TypeConversionUtil.erasure(ret); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/after1.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/after1.java index 89683098fc6b..d785f80ad35f 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/after1.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/after1.java @@ -1,4 +1,4 @@ -// "Generate overloaded method with default parameter value" "true" +// "Generate overloaded method with default parameter values" "true" class Test { void foo() { foo(); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/afterAbstractMethod.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/afterAbstractMethod.java index e72764fff0dc..768f01176512 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/afterAbstractMethod.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/afterAbstractMethod.java @@ -1,4 +1,4 @@ -// "Generate overloaded method with default parameter value" "true" +// "Generate overloaded method with default parameter values" "true" abstract class Test { int foo(boolean... args) { return foo(, args); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/afterCommentsInBody.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/afterCommentsInBody.java index 4844902fdf14..0bd44690c430 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/afterCommentsInBody.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/afterCommentsInBody.java @@ -1,4 +1,4 @@ -// "Generate overloaded method with default parameter value" "true" +// "Generate overloaded method with default parameter values" "true" class Test { int foo() { return foo(); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/afterConstructor.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/afterConstructor.java index b73c48ebd2df..1f3d305ec5b1 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/afterConstructor.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/afterConstructor.java @@ -1,4 +1,4 @@ -// "Generate overloaded constructor with default parameter value" "true" +// "Generate overloaded constructor with default parameter values" "true" class Test { Test() { this(); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/afterExistinMethod.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/afterExistinMethod.java new file mode 100644 index 000000000000..d1e063f7955a --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/afterExistinMethod.java @@ -0,0 +1,6 @@ +// "Generate overloaded method with default parameter values" "true" +class Test { + void foo(){} + void foo(int ii){ + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/afterInterface.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/afterInterface.java index decd3f141818..7a3ddc85e93d 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/afterInterface.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/afterInterface.java @@ -1,4 +1,4 @@ -// "Generate overloaded method with default parameter value" "true" +// "Generate overloaded method with default parameter values" "true" interface Test { default void foo() { foo(); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/afterJavadoc.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/afterJavadoc.java index 3f15183133d7..697c0e305b6a 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/afterJavadoc.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/afterJavadoc.java @@ -1,4 +1,4 @@ -// "Generate overloaded method with default parameter value" "true" +// "Generate overloaded method with default parameter values" "true" class Test { /** */ diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/afterReturnValue.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/afterReturnValue.java index 1e89e83a3cb7..971da0d8e6da 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/afterReturnValue.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/afterReturnValue.java @@ -1,4 +1,4 @@ -// "Generate overloaded method with default parameter value" "true" +// "Generate overloaded method with default parameter values" "true" class Test { int foo() { return foo(); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/afterStaticMethodInInterface.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/afterStaticMethodInInterface.java index 01e1bdab551b..eb84d0998b75 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/afterStaticMethodInInterface.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/afterStaticMethodInInterface.java @@ -1,4 +1,4 @@ -// "Generate overloaded method with default parameter value" "true" +// "Generate overloaded method with default parameter values" "true" interface Test { static void foo() { foo(); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/afterTypeParams.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/afterTypeParams.java index 57fb3563e0ac..c392c5a86323 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/afterTypeParams.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/afterTypeParams.java @@ -1,4 +1,4 @@ -// "Generate overloaded method with default parameter value" "true" +// "Generate overloaded method with default parameter values" "true" class Test { int foo(boolean... args) { return foo(, args); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/afterVarargs.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/afterVarargs.java index 68e2eaeec564..d9878cc69b41 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/afterVarargs.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/afterVarargs.java @@ -1,4 +1,4 @@ -// "Generate overloaded method with default parameter value" "true" +// "Generate overloaded method with default parameter values" "true" class Test { int foo(boolean... args) { return foo(, args); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/before1.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/before1.java index 48895a8251b2..558e6e4c68f6 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/before1.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/before1.java @@ -1,4 +1,4 @@ -// "Generate overloaded method with default parameter value" "true" +// "Generate overloaded method with default parameter values" "true" class Test { void foo(int ii){ } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/beforeAbstractMethod.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/beforeAbstractMethod.java index 320debae10f2..9080288f6fa8 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/beforeAbstractMethod.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/beforeAbstractMethod.java @@ -1,4 +1,4 @@ -// "Generate overloaded method with default parameter value" "true" +// "Generate overloaded method with default parameter values" "true" abstract class Test { abstract int foo(int ii, boolean... args); } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/beforeCommentsInBody.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/beforeCommentsInBody.java index 9a6ad6184854..97357c6b3e0e 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/beforeCommentsInBody.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/beforeCommentsInBody.java @@ -1,4 +1,4 @@ -// "Generate overloaded method with default parameter value" "true" +// "Generate overloaded method with default parameter values" "true" class Test { int foo(int ii){ //comment1 diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/beforeConstructor.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/beforeConstructor.java index 7fe236b65cf4..a8b8be8ba4b8 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/beforeConstructor.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/beforeConstructor.java @@ -1,4 +1,4 @@ -// "Generate overloaded constructor with default parameter value" "true" +// "Generate overloaded constructor with default parameter values" "true" class Test { Test(int ii){} } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/beforeExistinMethod.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/beforeExistinMethod.java index 52fa17401c5d..f8dbe503ccc7 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/beforeExistinMethod.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/beforeExistinMethod.java @@ -1,4 +1,4 @@ -// "Generate overloaded method with default parameter value" "false" +// "Generate overloaded method with default parameter values" "true" class Test { void foo(){} void foo(int ii){ diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/beforeInterface.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/beforeInterface.java index 1f960d28b21d..8217a2c642fe 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/beforeInterface.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/beforeInterface.java @@ -1,4 +1,4 @@ -// "Generate overloaded method with default parameter value" "true" +// "Generate overloaded method with default parameter values" "true" interface Test { void foo(int ii); } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/beforeJavadoc.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/beforeJavadoc.java index 267cdf9f901a..c4906ebcfafb 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/beforeJavadoc.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/beforeJavadoc.java @@ -1,4 +1,4 @@ -// "Generate overloaded method with default parameter value" "true" +// "Generate overloaded method with default parameter values" "true" class Test { /** * @param i diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/beforeReturnValue.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/beforeReturnValue.java index 4df7057f4e31..056d8badf78b 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/beforeReturnValue.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/beforeReturnValue.java @@ -1,4 +1,4 @@ -// "Generate overloaded method with default parameter value" "true" +// "Generate overloaded method with default parameter values" "true" class Test { int foo(int ii){ return 1; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/beforeStaticMethodInInterface.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/beforeStaticMethodInInterface.java index 5ea839e503a6..f2026953d9f3 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/beforeStaticMethodInInterface.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/beforeStaticMethodInInterface.java @@ -1,4 +1,4 @@ -// "Generate overloaded method with default parameter value" "true" +// "Generate overloaded method with default parameter values" "true" interface Test { static void foo(int ii) {} } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/beforeTypeParams.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/beforeTypeParams.java index e55000a24f37..4ab9ec7459fd 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/beforeTypeParams.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/beforeTypeParams.java @@ -1,4 +1,4 @@ -// "Generate overloaded method with default parameter value" "true" +// "Generate overloaded method with default parameter values" "true" class Test { int foo(T ii, boolean... args){ return 1; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/beforeVarargs.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/beforeVarargs.java index 6ddbc5a9069c..7f6628882710 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/beforeVarargs.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/delegateWithDefaultValue/beforeVarargs.java @@ -1,4 +1,4 @@ -// "Generate overloaded method with default parameter value" "true" +// "Generate overloaded method with default parameter values" "true" class Test { int foo(int ii, boolean... args){ return 1; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/removeRedundantElse/after1.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/removeRedundantElse/after1.java deleted file mode 100644 index d0d55761f11b..000000000000 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/removeRedundantElse/after1.java +++ /dev/null @@ -1,13 +0,0 @@ -// "Remove redundant 'else'" "true" -class a { - void foo() { - int a = 0; - int b = 0; - if (a != b) { - return; - } - a = b; - a++; - } -} - diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/removeRedundantElse/before1.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/removeRedundantElse/before1.java deleted file mode 100644 index ea4609835464..000000000000 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/removeRedundantElse/before1.java +++ /dev/null @@ -1,14 +0,0 @@ -// "Remove redundant 'else'" "true" -class a { - void foo() { - int a = 0; - int b = 0; - if (a != b) { - return; - } else { - a = b; - } - a++; - } -} - diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/removeRedundantElse/beforeCanThrowException.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/removeRedundantElse/beforeCanThrowException.java deleted file mode 100644 index 8fd59ef094f3..000000000000 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/removeRedundantElse/beforeCanThrowException.java +++ /dev/null @@ -1,15 +0,0 @@ -// "Remove redundant 'else'" "false" -import java.io.IOException; -class a { - void foo(boolean condition) throws IOException{ - if (condition) { - tMethod(); - } - else { - System.out.println("else"); - } - } - - void tMethod() throws IOException {} -} - diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/removeRedundantElse/beforeIfElseChain.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/removeRedundantElse/beforeIfElseChain.java deleted file mode 100644 index f702178d781f..000000000000 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/removeRedundantElse/beforeIfElseChain.java +++ /dev/null @@ -1,17 +0,0 @@ -// "Remove redundant 'else'" "false" -class a { - void foo() { - int a = 0; - int b = 0; - if (a != b) { - a = 10; - } else if (a + 1 == b) { - return; - } - else { - a = b; - } - a++; - } -} - diff --git a/java/java-tests/testData/codeInsight/multipleJdks/java7/p/I.java b/java/java-tests/testData/codeInsight/multipleJdks/java7/p/I.java new file mode 100644 index 000000000000..30e62b5249e6 --- /dev/null +++ b/java/java-tests/testData/codeInsight/multipleJdks/java7/p/I.java @@ -0,0 +1,4 @@ +package p; +interface I { + default void foo(); +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/multipleJdks/java7/p/UnrelatedDefaultsFromDifferentJdkVersions.java b/java/java-tests/testData/codeInsight/multipleJdks/java7/p/UnrelatedDefaultsFromDifferentJdkVersions.java new file mode 100644 index 000000000000..52e05186d644 --- /dev/null +++ b/java/java-tests/testData/codeInsight/multipleJdks/java7/p/UnrelatedDefaultsFromDifferentJdkVersions.java @@ -0,0 +1,3 @@ +package p; + +public abstract class A implements I {} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/multipleJdks/java8/p/I.java b/java/java-tests/testData/codeInsight/multipleJdks/java8/p/I.java new file mode 100644 index 000000000000..30e62b5249e6 --- /dev/null +++ b/java/java-tests/testData/codeInsight/multipleJdks/java8/p/I.java @@ -0,0 +1,4 @@ +package p; +interface I { + default void foo(); +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/multipleJdks/java8/p/UnrelatedDefaultsFromDifferentJdkVersions.java b/java/java-tests/testData/codeInsight/multipleJdks/java8/p/UnrelatedDefaultsFromDifferentJdkVersions.java new file mode 100644 index 000000000000..ab93746c9c7d --- /dev/null +++ b/java/java-tests/testData/codeInsight/multipleJdks/java8/p/UnrelatedDefaultsFromDifferentJdkVersions.java @@ -0,0 +1,8 @@ +package p; + +class EmptyValueIterator extends A implements ValueIterator { + +} + +interface ValueIterator extends I {} + diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantLambdaParameterType/beforeAssignment.java b/java/java-tests/testData/codeInspection/redundantLambdaParameterType/Assignment.java similarity index 100% rename from java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantLambdaParameterType/beforeAssignment.java rename to java/java-tests/testData/codeInspection/redundantLambdaParameterType/Assignment.java diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantLambdaParameterType/beforeAssignmentNoParams.java b/java/java-tests/testData/codeInspection/redundantLambdaParameterType/AssignmentNoParams.java similarity index 100% rename from java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantLambdaParameterType/beforeAssignmentNoParams.java rename to java/java-tests/testData/codeInspection/redundantLambdaParameterType/AssignmentNoParams.java diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantLambdaParameterType/beforeAssignmentNoTypes.java b/java/java-tests/testData/codeInspection/redundantLambdaParameterType/AssignmentNoTypes.java similarity index 100% rename from java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantLambdaParameterType/beforeAssignmentNoTypes.java rename to java/java-tests/testData/codeInspection/redundantLambdaParameterType/AssignmentNoTypes.java diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantLambdaParameterType/afterAssignment.java b/java/java-tests/testData/codeInspection/redundantLambdaParameterType/Assignment_after.java similarity index 100% rename from java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantLambdaParameterType/afterAssignment.java rename to java/java-tests/testData/codeInspection/redundantLambdaParameterType/Assignment_after.java diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantLambdaParameterType/beforeAtVarargPlace.java b/java/java-tests/testData/codeInspection/redundantLambdaParameterType/AtVarargPlace.java similarity index 100% rename from java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantLambdaParameterType/beforeAtVarargPlace.java rename to java/java-tests/testData/codeInspection/redundantLambdaParameterType/AtVarargPlace.java diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantLambdaParameterType/beforeCallNoTypeArgs.java b/java/java-tests/testData/codeInspection/redundantLambdaParameterType/CallNoTypeArgs.java similarity index 100% rename from java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantLambdaParameterType/beforeCallNoTypeArgs.java rename to java/java-tests/testData/codeInspection/redundantLambdaParameterType/CallNoTypeArgs.java diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantLambdaParameterType/beforeCallNoTypeArgs1.java b/java/java-tests/testData/codeInspection/redundantLambdaParameterType/CallNoTypeArgs1.java similarity index 100% rename from java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantLambdaParameterType/beforeCallNoTypeArgs1.java rename to java/java-tests/testData/codeInspection/redundantLambdaParameterType/CallNoTypeArgs1.java diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantLambdaParameterType/beforeCallWithTypeArgs.java b/java/java-tests/testData/codeInspection/redundantLambdaParameterType/CallWithTypeArgs.java similarity index 100% rename from java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantLambdaParameterType/beforeCallWithTypeArgs.java rename to java/java-tests/testData/codeInspection/redundantLambdaParameterType/CallWithTypeArgs.java diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantLambdaParameterType/afterCallWithTypeArgs.java b/java/java-tests/testData/codeInspection/redundantLambdaParameterType/CallWithTypeArgs_after.java similarity index 100% rename from java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantLambdaParameterType/afterCallWithTypeArgs.java rename to java/java-tests/testData/codeInspection/redundantLambdaParameterType/CallWithTypeArgs_after.java diff --git a/java/java-tests/testData/codeInspection/redundantLambdaParameterType/InChain.java b/java/java-tests/testData/codeInspection/redundantLambdaParameterType/InChain.java new file mode 100644 index 000000000000..7262e3bbca40 --- /dev/null +++ b/java/java-tests/testData/codeInspection/redundantLambdaParameterType/InChain.java @@ -0,0 +1,7 @@ +import java.util.stream.Stream; + +class InChain { + public static void main(String[] args) { + Stream.of("a").map((String s) -> s + "1").forEach(System.out::println); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInspection/redundantLambdaParameterType/InChain_after.java b/java/java-tests/testData/codeInspection/redundantLambdaParameterType/InChain_after.java new file mode 100644 index 000000000000..857e423db1eb --- /dev/null +++ b/java/java-tests/testData/codeInspection/redundantLambdaParameterType/InChain_after.java @@ -0,0 +1,7 @@ +import java.util.stream.Stream; + +class InChain { + public static void main(String[] args) { + Stream.of("a").map(s -> s + "1").forEach(System.out::println); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantLambdaParameterType/beforeInferredFromOtherArgs.java b/java/java-tests/testData/codeInspection/redundantLambdaParameterType/InferredFromOtherArgs.java similarity index 100% rename from java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantLambdaParameterType/beforeInferredFromOtherArgs.java rename to java/java-tests/testData/codeInspection/redundantLambdaParameterType/InferredFromOtherArgs.java diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantLambdaParameterType/afterInferredFromOtherArgs.java b/java/java-tests/testData/codeInspection/redundantLambdaParameterType/InferredFromOtherArgs_after.java similarity index 100% rename from java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantLambdaParameterType/afterInferredFromOtherArgs.java rename to java/java-tests/testData/codeInspection/redundantLambdaParameterType/InferredFromOtherArgs_after.java diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantLambdaParameterType/beforeNoSelfTypeParam.java b/java/java-tests/testData/codeInspection/redundantLambdaParameterType/NoSelfTypeParam.java similarity index 100% rename from java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantLambdaParameterType/beforeNoSelfTypeParam.java rename to java/java-tests/testData/codeInspection/redundantLambdaParameterType/NoSelfTypeParam.java diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantLambdaParameterType/afterNoSelfTypeParam.java b/java/java-tests/testData/codeInspection/redundantLambdaParameterType/NoSelfTypeParam_after.java similarity index 100% rename from java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantLambdaParameterType/afterNoSelfTypeParam.java rename to java/java-tests/testData/codeInspection/redundantLambdaParameterType/NoSelfTypeParam_after.java diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantLambdaParameterType/beforeTypeParam.java b/java/java-tests/testData/codeInspection/redundantLambdaParameterType/TypeParam.java similarity index 100% rename from java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantLambdaParameterType/beforeTypeParam.java rename to java/java-tests/testData/codeInspection/redundantLambdaParameterType/TypeParam.java diff --git a/java/java-tests/testData/refactoring/extractMethod/LocalVariableAnnotationsOrder.java b/java/java-tests/testData/refactoring/extractMethod/LocalVariableAnnotationsOrder.java new file mode 100644 index 000000000000..7fa69c17de76 --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethod/LocalVariableAnnotationsOrder.java @@ -0,0 +1,13 @@ +class C { + { + @B @A int i = 0; + System.out.println(i); + } + + void f() { + @A @B int j = 0; + System.out.println(j); + } +} +@interface A {} +@interface B {} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/extractMethod/LocalVariableAnnotationsOrder_after.java b/java/java-tests/testData/refactoring/extractMethod/LocalVariableAnnotationsOrder_after.java new file mode 100644 index 000000000000..54630c858b1d --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethod/LocalVariableAnnotationsOrder_after.java @@ -0,0 +1,16 @@ +class C { + { + newMethod(); + } + + void f() { + newMethod(); + } + + private void newMethod() { + @A @B int j = 0; + System.out.println(j); + } +} +@interface A {} +@interface B {} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/extractMethod/LocalVariableModifierList.java b/java/java-tests/testData/refactoring/extractMethod/LocalVariableModifierList.java new file mode 100644 index 000000000000..d9d2f99e4e0b --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethod/LocalVariableModifierList.java @@ -0,0 +1,11 @@ +class C { + { + int i = 0; + System.out.println(i); + } + + void f() { + final int j = 0; + System.out.println(j); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/extractMethod/LocalVariableModifierList_after.java b/java/java-tests/testData/refactoring/extractMethod/LocalVariableModifierList_after.java new file mode 100644 index 000000000000..e6792368059f --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethod/LocalVariableModifierList_after.java @@ -0,0 +1,14 @@ +class C { + { + newMethod(); + } + + void f() { + newMethod(); + } + + private void newMethod() { + final int j = 0; + System.out.println(j); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/extractMethod/MethodAnnotations.java b/java/java-tests/testData/refactoring/extractMethod/MethodAnnotations.java new file mode 100644 index 000000000000..a21035126650 --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethod/MethodAnnotations.java @@ -0,0 +1,21 @@ +class Test10 { + void test() { + new Super() { + int get() { + return 0; + } + }; + + new Super() { + @Override + int get() { + return 0; + } + }; + } +} +class Super { + int get() { + return 1; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/extractMethod/MethodAnnotations_after.java b/java/java-tests/testData/refactoring/extractMethod/MethodAnnotations_after.java new file mode 100644 index 000000000000..1c7baecdfe26 --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethod/MethodAnnotations_after.java @@ -0,0 +1,20 @@ +class Test10 { + void test() { + newMethod(); + + newMethod(); + } + + private void newMethod() { + new Super() { + int get() { + return 0; + } + }; + } +} +class Super { + int get() { + return 1; + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/MultipleJdksHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/MultipleJdksHighlightingTest.java index 874522ec38f7..4c6c21761f55 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/MultipleJdksHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/MultipleJdksHighlightingTest.java @@ -18,7 +18,6 @@ package com.intellij.codeInsight; import com.intellij.openapi.application.ex.PathManagerEx; import com.intellij.openapi.module.Module; -import com.intellij.openapi.roots.ModifiableRootModel; import com.intellij.openapi.roots.ModuleRootModificationUtil; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.pom.java.LanguageLevel; @@ -26,7 +25,6 @@ import com.intellij.testFramework.IdeaTestUtil; import com.intellij.testFramework.UsefulTestCase; import com.intellij.testFramework.builders.JavaModuleFixtureBuilder; import com.intellij.testFramework.fixtures.*; -import com.intellij.util.Consumer; public class MultipleJdksHighlightingTest extends UsefulTestCase { @@ -197,6 +195,16 @@ public class MultipleJdksHighlightingTest extends UsefulTestCase { myFixture.checkHighlighting(); } + public void testUnrelatedDefaultsFromDifferentJdkVersions() throws Exception { + ModuleRootModificationUtil.addDependency(myJava8Module, myJava7Module); + myFixture.copyFileToProject("java7/p/I.java"); + myFixture.copyFileToProject("java8/p/I.java"); + + final String testName = getTestName(false); + myFixture.configureByFiles("java8/p/" + testName + ".java", "java7/p/" + testName + ".java"); + myFixture.checkHighlighting(); + } + private void doTestWithoutLibrary() { final String name = getTestName(false); myFixture.configureByFiles("java7/p/" + name + ".java", "java8/p/" + name + ".java"); diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/DelegateWithDefaultParamValueTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/DelegateWithDefaultParamValueTest.java index c53bb0085d87..eb9825dd8c70 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/DelegateWithDefaultParamValueTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/DelegateWithDefaultParamValueTest.java @@ -30,8 +30,9 @@ public class DelegateWithDefaultParamValueTest extends LightQuickFixParameterize if (actionShouldBeAvailable) { TemplateState state = TemplateManagerImpl.getTemplateState(getEditor()); - assert state != null; - state.gotoEnd(false); + if (state != null) { + state.gotoEnd(false); + } } } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/RedundantLambdaParameterTypeIntentionTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/RedundantLambdaParameterTypeIntentionTest.java deleted file mode 100644 index 4f85962f0a62..000000000000 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/RedundantLambdaParameterTypeIntentionTest.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2000-2012 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.codeInsight.daemon.quickFix; - -import com.intellij.openapi.projectRoots.Sdk; -import com.intellij.testFramework.IdeaTestUtil; - -public class RedundantLambdaParameterTypeIntentionTest extends LightQuickFixParameterizedTestCase { - public void test() throws Exception { doAllTests(); } - - @Override - protected String getBasePath() { - return "/codeInsight/daemonCodeAnalyzer/quickFix/redundantLambdaParameterType"; - } - - @Override - protected Sdk getProjectJDK() { - return IdeaTestUtil.getMockJdk18(); - } -} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/RedundantLambdaParameterTypeInspectionTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/RedundantLambdaParameterTypeInspectionTest.java new file mode 100644 index 000000000000..3e610fcbcf04 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/codeInspection/RedundantLambdaParameterTypeInspectionTest.java @@ -0,0 +1,112 @@ +/* + * Copyright 2000-2016 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:public void testwww() {}.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.codeInsight.intention.IntentionAction; +import com.intellij.codeInspection.lambda.RedundantLambdaParameterTypeInspection; +import com.intellij.idea.Bombed; +import com.intellij.openapi.roots.ModuleRootModificationUtil; +import com.intellij.testFramework.IdeaTestUtil; +import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; + +import java.util.Calendar; +import java.util.List; + +public class RedundantLambdaParameterTypeInspectionTest extends LightCodeInsightFixtureTestCase { + private RedundantLambdaParameterTypeInspection myInspection = new RedundantLambdaParameterTypeInspection(); + private String myIntentionName = "Remove redundant types"; + + @Override + protected String getBasePath() { + return JavaTestUtil.getRelativeJavaTestDataPath() + "/codeInspection/redundantLambdaParameterType"; + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + ModuleRootModificationUtil.setModuleSdk(myModule, IdeaTestUtil.getMockJdk18()); + myFixture.enableInspections(myInspection); + } + + @Override + protected void tearDown() throws Exception { + try { + myFixture.disableInspections(myInspection); + } + finally { + super.tearDown(); + } + } + + public void testAssignment() { + doTest(); + } + + public void testAssignmentNoParams() { + assertIntentionNotAvailable(); + } + + public void testAssignmentNoTypes() { + assertIntentionNotAvailable(); + } + + public void testAtVarargPlace() { + assertIntentionNotAvailable(); + } + + public void testCallNoTypeArgs() { + assertIntentionNotAvailable(); + } + + public void testCallNoTypeArgs1() { + assertIntentionNotAvailable(); + } + + public void testCallWithTypeArgs() { + doTest(); + } + + public void testInferredFromOtherArgs() { + doTest(); + } + + public void testNoSelfTypeParam() { + doTest(); + } + + public void testTypeParam() { + assertIntentionNotAvailable(); + } + + @Bombed(month = Calendar.AUGUST, day = 1, user = "Pavel Dolgov") + public void testInChain() { + doTest(); + } + + private void doTest() { + myFixture.configureByFiles(getTestName(false) + ".java"); + final IntentionAction singleIntention = myFixture.findSingleIntention(myIntentionName); + myFixture.launchAction(singleIntention); + myFixture.checkResultByFile(getTestName(false) + ".java", getTestName(false) + "_after.java", true); + } + + private void assertIntentionNotAvailable() { + myFixture.configureByFiles(getTestName(false) + ".java"); + final List intentionActions = myFixture.filterAvailableIntentions(myIntentionName); + assertEmpty(myIntentionName + " is not expected", intentionActions); + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/psi/impl/smartPointers/SmartPsiElementPointersTest.java b/java/java-tests/testSrc/com/intellij/psi/impl/smartPointers/SmartPsiElementPointersTest.java index 37ea37f6c233..b9d84f386d96 100644 --- a/java/java-tests/testSrc/com/intellij/psi/impl/smartPointers/SmartPsiElementPointersTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/impl/smartPointers/SmartPsiElementPointersTest.java @@ -58,10 +58,7 @@ import org.junit.Assert; import java.io.IOException; import java.lang.ref.SoftReference; -import java.util.Collections; -import java.util.List; -import java.util.Random; -import java.util.Set; +import java.util.*; import java.util.stream.Collectors; @PlatformTestCase.WrapInCommand @@ -915,4 +912,20 @@ public class SmartPsiElementPointersTest extends CodeInsightTestCase { assertEquals(psiClass.getNameIdentifier().getTextRange(), TextRange.create(range)); } + public void testManySmartPointersCreationDeletionPerformance() throws Exception { + String text = StringUtil.repeatSymbol(' ', 100000); + PsiFile file = createFile("a.txt", text); + + PlatformTestUtil.startPerformanceTest("", 2000, () -> { + List pointers = new ArrayList<>(); + for (int i = 0; i < text.length() - 1; i++) { + pointers.add(getPointerManager().createSmartPsiFileRangePointer(file, new TextRange(i, i + 1))); + } + Collections.shuffle(pointers); + for (SmartPsiFileRange pointer : pointers) { + getPointerManager().removePointer(pointer); + } + }).cpuBound().assertTiming(); + } + } diff --git a/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodTest.java b/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodTest.java index bfe820f7197f..a84f0d143dab 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodTest.java @@ -805,6 +805,18 @@ public class ExtractMethodTest extends LightCodeInsightTestCase { doTest(); } + public void testLocalVariableModifierList() throws Exception { + doTest(); + } + + public void testLocalVariableAnnotationsOrder() throws Exception { + doTest(); + } + + public void testMethodAnnotations() throws Exception { + doTest(); + } + public void testQualifyWhenConflictingNamePresent() throws Exception { final CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(getProject()); settings.ELSE_ON_NEW_LINE = true; diff --git a/platform/core-api/src/com/intellij/psi/tree/CustomParsingType.java b/platform/core-api/src/com/intellij/psi/tree/CustomParsingType.java index 45fb4110211b..d369c892d2ef 100644 --- a/platform/core-api/src/com/intellij/psi/tree/CustomParsingType.java +++ b/platform/core-api/src/com/intellij/psi/tree/CustomParsingType.java @@ -19,17 +19,13 @@ */ package com.intellij.psi.tree; -import com.intellij.lang.ASTNode; import com.intellij.lang.Language; -import com.intellij.util.CharTable; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public abstract class CustomParsingType extends IElementType { +public abstract class CustomParsingType extends IElementType implements ICustomParsingType { public CustomParsingType(@NotNull @NonNls String debugName, @Nullable Language language) { super(debugName, language); } - - public abstract ASTNode parse(CharSequence text, CharTable table); } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/RemoveRedundantElseActionTest.java b/platform/core-api/src/com/intellij/psi/tree/ICustomParsingType.java similarity index 58% rename from java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/RemoveRedundantElseActionTest.java rename to platform/core-api/src/com/intellij/psi/tree/ICustomParsingType.java index 0a33ada748f8..659f24e4c169 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/RemoveRedundantElseActionTest.java +++ b/platform/core-api/src/com/intellij/psi/tree/ICustomParsingType.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 JetBrains s.r.o. + * Copyright 2000-2016 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,20 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.codeInsight.daemon.quickFix; +package com.intellij.psi.tree; + +import com.intellij.lang.ASTNode; +import com.intellij.util.CharTable; +import org.jetbrains.annotations.NotNull; /** - * User: anna - * Date: Aug 30, 2010 + * A token which is more convenient to parse separately. Parsing is done when leaf elements are created. */ -public class RemoveRedundantElseActionTest extends LightQuickFixParameterizedTestCase { - - public void test() throws Exception { doAllTests(); } - - @Override - protected String getBasePath() { - return "/codeInsight/daemonCodeAnalyzer/quickFix/removeRedundantElse"; - } +public interface ICustomParsingType { + @NotNull + ASTNode parse(@NotNull CharSequence text, @NotNull CharTable table); } - diff --git a/platform/core-impl/src/com/intellij/lang/impl/PsiBuilderImpl.java b/platform/core-impl/src/com/intellij/lang/impl/PsiBuilderImpl.java index a07f110329e3..0563e613ea61 100644 --- a/platform/core-impl/src/com/intellij/lang/impl/PsiBuilderImpl.java +++ b/platform/core-impl/src/com/intellij/lang/impl/PsiBuilderImpl.java @@ -1562,7 +1562,7 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder { } if (oldNode.getElementType() instanceof ILazyParseableElementType && type instanceof ILazyParseableElementType || - oldNode.getElementType() instanceof CustomParsingType && type instanceof CustomParsingType) { + oldNode.getElementType() instanceof ICustomParsingType && type instanceof ICustomParsingType) { return ((TreeElement)oldNode).textMatches(token.getText()) ? ThreeState.YES : ThreeState.NO; @@ -1853,8 +1853,8 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder { return new PsiWhiteSpaceImpl(text); } - if (type instanceof CustomParsingType) { - return (TreeElement)((CustomParsingType)type).parse(text, myCharTable); + if (type instanceof ICustomParsingType) { + return (TreeElement)((ICustomParsingType)type).parse(text, myCharTable); } if (type instanceof ILazyParseableElementType) { diff --git a/platform/core-impl/src/com/intellij/psi/impl/smartPointers/SmartPointerManagerImpl.java b/platform/core-impl/src/com/intellij/psi/impl/smartPointers/SmartPointerManagerImpl.java index d18fb3ed192c..28a99999203e 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/smartPointers/SmartPointerManagerImpl.java +++ b/platform/core-impl/src/com/intellij/psi/impl/smartPointers/SmartPointerManagerImpl.java @@ -29,7 +29,7 @@ import com.intellij.psi.*; import com.intellij.psi.impl.PsiDocumentManagerBase; import com.intellij.psi.util.PsiUtilCore; import com.intellij.reference.SoftReference; -import com.intellij.util.ArrayUtil; +import com.intellij.util.CommonProcessors; import com.intellij.util.Processor; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; @@ -68,7 +68,7 @@ public class SmartPointerManagerImpl extends SmartPointerManager { FilePointersList pointers = reference.file.getUserData(reference.key); if (pointers != null) { - pointers.remove(reference); + pointers.removeReference(reference); } } } @@ -160,12 +160,13 @@ public class SmartPointerManagerImpl extends SmartPointerManager { SmartPointerElementInfo info = pointer.getElementInfo(); if (!(info instanceof SelfElementInfo)) return; + PointerReference reference = new PointerReference(pointer, containingFile, POINTERS_KEY); while (true) { FilePointersList pointers = getPointers(containingFile); if (pointers == null) { pointers = containingFile.putUserDataIfAbsent(POINTERS_KEY, new FilePointersList()); } - if (pointers.add(new PointerReference(pointer, containingFile, ourQueue, POINTERS_KEY))) { + if (pointers.add(reference)) { if (((SelfElementInfo)info).hasRange()) { pointers.markerCache.rangeChanged(); } @@ -193,8 +194,10 @@ public class SmartPointerManagerImpl extends SmartPointerManager { if (containingFile == null) return; VirtualFile vFile = containingFile.getViewProvider().getVirtualFile(); FilePointersList pointers = getPointers(vFile); - if (pointers == null) return; - pointers.remove(pointer); + PointerReference reference = ((SmartPsiElementPointerImpl)pointer).pointerReference; + if (pointers != null && reference != null) { + pointers.removeReference(reference); + } } } @@ -264,17 +267,18 @@ public class SmartPointerManagerImpl extends SmartPointerManager { return myPsiDocManager; } - private static class PointerReference extends WeakReference { + static class PointerReference extends WeakReference { @NotNull private final VirtualFile file; @NotNull private final Key key; + private int index = -2; private PointerReference(@NotNull SmartPsiElementPointerImpl pointer, @NotNull VirtualFile containingFile, - @NotNull ReferenceQueue queue, @NotNull Key key) { - super(pointer, queue); + super(pointer, ourQueue); file = containingFile; this.key = key; + pointer.pointerReference = this; } } @@ -292,104 +296,98 @@ public class SmartPointerManagerImpl extends SmartPointerManager { } if (nextAvailableIndex >= references.length || nextAvailableIndex > size*2) { // overflow or too many dead refs - int newCapacity = nextAvailableIndex >= references.length ? references.length * 3/2 +1 : size * 3/2+1; - PointerReference[] newReferences = new PointerReference[newCapacity]; + int newCapacity = (nextAvailableIndex >= references.length ? references.length : size) * 3 / 2 + 1; + final PointerReference[] newReferences = new PointerReference[newCapacity]; - int o = 0; - for (PointerReference oldRef : references) { - if (SoftReference.dereference(oldRef) != null) { - newReferences[o++] = oldRef; + final int[] o = {0}; + processAlivePointers(new Processor() { + @Override + public boolean process(SmartPsiElementPointerImpl pointer) { + storePointerReference(newReferences, o[0]++, pointer.pointerReference); + return true; } - } + }); references = newReferences; - size = nextAvailableIndex = o; + size = nextAvailableIndex = o[0]; } - references[nextAvailableIndex++] = reference; + assert references[nextAvailableIndex] == null : references[nextAvailableIndex]; + storePointerReference(references, nextAvailableIndex++, reference); size++; mySorted = false; return true; } - private synchronized void remove(@NotNull PointerReference reference) { - int index = ArrayUtil.indexOf(references, reference, 0, nextAvailableIndex); - if (index != -1) { - removeReference(reference, index); - } - } + private synchronized void removeReference(@NotNull PointerReference reference) { + int index = reference.index; + if (index < 0) return; - private synchronized void remove(@NotNull SmartPsiElementPointer smartPointer) { - for (int i = 0; i < nextAvailableIndex; i++) { - PointerReference reference = references[i]; - if (reference != null && reference.get() == smartPointer) { - removeReference(reference, i); - return; - } - } - } - - private void removeReference(@NotNull PointerReference reference, int index) { + assert references[index] == reference : "At " + index + " expected " + reference + ", found " + references[index]; + references[index].index = -1; references[index] = null; if (--size == 0) { reference.file.replace(reference.key, this, null); } } - boolean processAlivePointers(@NotNull Processor processor) { + synchronized boolean processAlivePointers(@NotNull Processor processor) { for (int i = 0; i < nextAvailableIndex; i++) { - SmartPsiElementPointerImpl pointer = SoftReference.dereference(references[i]); - if (pointer != null && !processor.process(pointer)) { + PointerReference ref = references[i]; + if (ref == null) continue; + + SmartPsiElementPointerImpl pointer = ref.get(); + if (pointer == null) { + removeReference(ref); + continue; + } + + if (!processor.process(pointer)) { return false; } } return true; } - synchronized List getSortedInfos() { + private void ensureSorted() { if (!mySorted) { - List hardRefs = ContainerUtil.newArrayListWithCapacity(size); - for (int i = 0; i < nextAvailableIndex; i++) { - PointerReference reference = references[i]; - if (reference == null) continue; + List pointers = new ArrayList(); + processAlivePointers(new CommonProcessors.CollectProcessor(pointers)); + assert size == pointers.size(); - SmartPsiElementPointerImpl pointer = reference.get(); - if (pointer != null) { - hardRefs.add(pointer); - } - else { - removeReference(reference, i); - if (size == 0) { - return Collections.emptyList(); - } - } - } - assert size == hardRefs.size(); - - Arrays.sort(references, 0, nextAvailableIndex, new Comparator() { + Collections.sort(pointers, new Comparator() { @Override - public int compare(PointerReference o1, PointerReference o2) { - SmartPsiElementPointerImpl p1 = SoftReference.dereference(o1); - SmartPsiElementPointerImpl p2 = SoftReference.dereference(o2); - if (p1 == null || p2 == null) { - return p1 != null ? -1 : p2 != null ? 1 : 0; // null references to the end - } + public int compare(SmartPsiElementPointerImpl p1, SmartPsiElementPointerImpl p2) { return MarkerCache.INFO_COMPARATOR.compare((SelfElementInfo)p1.getElementInfo(), (SelfElementInfo)p2.getElementInfo()); } }); - nextAvailableIndex = hardRefs.size(); + + for (int i = 0; i < pointers.size(); i++) { + storePointerReference(references, i, pointers.get(i).pointerReference); + } + Arrays.fill(references, pointers.size(), nextAvailableIndex, null); + nextAvailableIndex = pointers.size(); mySorted = true; } + } - List infos = ContainerUtil.newArrayListWithCapacity(size); - for (int i = 0; i < nextAvailableIndex; i++) { - Reference reference = references[i]; - SmartPsiElementPointerImpl pointer = SoftReference.dereference(reference); - if (pointer != null) { + private static void storePointerReference(PointerReference[] references, int index, PointerReference ref) { + references[index] = ref; + ref.index = index; + } + + synchronized List getSortedInfos() { + ensureSorted(); + + final List infos = ContainerUtil.newArrayListWithCapacity(size); + processAlivePointers(new Processor() { + @Override + public boolean process(SmartPsiElementPointerImpl pointer) { SelfElementInfo info = (SelfElementInfo)pointer.getElementInfo(); - if (!info.hasRange()) break; + if (!info.hasRange()) return false; infos.add(info); + return true; } - } + }); return infos; } diff --git a/platform/core-impl/src/com/intellij/psi/impl/smartPointers/SmartPsiElementPointerImpl.java b/platform/core-impl/src/com/intellij/psi/impl/smartPointers/SmartPsiElementPointerImpl.java index ee7c4c9c249a..01e43e3b8d35 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/smartPointers/SmartPsiElementPointerImpl.java +++ b/platform/core-impl/src/com/intellij/psi/impl/smartPointers/SmartPsiElementPointerImpl.java @@ -46,6 +46,7 @@ class SmartPsiElementPointerImpl implements SmartPointerEx private final SmartPointerElementInfo myElementInfo; private final Class myElementClass; private byte myReferenceCount = 1; + @Nullable SmartPointerManagerImpl.PointerReference pointerReference; SmartPsiElementPointerImpl(@NotNull Project project, @NotNull E element, @Nullable PsiFile containingFile, boolean forInjected) { this(element, createElementInfo(project, element, containingFile, forInjected), element.getClass()); diff --git a/platform/diff-api/src/com/intellij/diff/comparison/ComparisonManager.java b/platform/diff-api/src/com/intellij/diff/comparison/ComparisonManager.java index cd0915a0d435..30f8a8f7d35e 100644 --- a/platform/diff-api/src/com/intellij/diff/comparison/ComparisonManager.java +++ b/platform/diff-api/src/com/intellij/diff/comparison/ComparisonManager.java @@ -17,6 +17,7 @@ package com.intellij.diff.comparison; import com.intellij.diff.fragments.DiffFragment; import com.intellij.diff.fragments.LineFragment; +import com.intellij.diff.fragments.MergeLineFragment; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.progress.ProgressIndicator; import org.jetbrains.annotations.NotNull; @@ -61,6 +62,16 @@ public abstract class ComparisonManager { @NotNull ComparisonPolicy policy, @NotNull ProgressIndicator indicator) throws DiffTooBigException; + /** + * Compare three texts by-line (LEFT - BASE - RIGHT) + */ + @NotNull + public abstract List compareLines(@NotNull CharSequence text1, + @NotNull CharSequence text2, + @NotNull CharSequence text3, + @NotNull ComparisonPolicy policy, + @NotNull ProgressIndicator indicator) throws DiffTooBigException; + /** * Compare two texts by-word */ diff --git a/platform/diff-impl/src/com/intellij/diff/fragments/MergeLineFragment.java b/platform/diff-api/src/com/intellij/diff/fragments/MergeLineFragment.java similarity index 100% rename from platform/diff-impl/src/com/intellij/diff/fragments/MergeLineFragment.java rename to platform/diff-api/src/com/intellij/diff/fragments/MergeLineFragment.java diff --git a/platform/diff-impl/src/com/intellij/diff/fragments/MergeWordFragment.java b/platform/diff-api/src/com/intellij/diff/fragments/MergeWordFragment.java similarity index 100% rename from platform/diff-impl/src/com/intellij/diff/fragments/MergeWordFragment.java rename to platform/diff-api/src/com/intellij/diff/fragments/MergeWordFragment.java diff --git a/platform/diff-impl/src/com/intellij/diff/comparison/ByLine.java b/platform/diff-impl/src/com/intellij/diff/comparison/ByLine.java index f204eafde823..ae75bbaf8f33 100644 --- a/platform/diff-impl/src/com/intellij/diff/comparison/ByLine.java +++ b/platform/diff-impl/src/com/intellij/diff/comparison/ByLine.java @@ -15,13 +15,8 @@ */ package com.intellij.diff.comparison; -import com.intellij.diff.comparison.iterables.DiffIterableUtil.*; +import com.intellij.diff.comparison.iterables.DiffIterableUtil.ExpandChangeBuilder; import com.intellij.diff.comparison.iterables.FairDiffIterable; -import com.intellij.diff.fragments.LineFragment; -import com.intellij.diff.fragments.LineFragmentImpl; -import com.intellij.diff.fragments.MergeLineFragment; -import com.intellij.diff.fragments.MergeLineFragmentImpl; -import com.intellij.diff.util.IntPair; import com.intellij.diff.util.MergeRange; import com.intellij.diff.util.Range; import com.intellij.openapi.progress.ProgressIndicator; @@ -29,68 +24,77 @@ import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.containers.ContainerUtil; +import gnu.trove.Equality; import gnu.trove.TIntArrayList; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.List; +import static com.intellij.diff.comparison.ComparisonPolicy.IGNORE_WHITESPACES; import static com.intellij.diff.comparison.TrimUtil.trimEnd; import static com.intellij.diff.comparison.TrimUtil.trimStart; -import static com.intellij.diff.comparison.iterables.DiffIterableUtil.*; +import static com.intellij.diff.comparison.iterables.DiffIterableUtil.diff; +import static com.intellij.diff.comparison.iterables.DiffIterableUtil.fair; import static com.intellij.openapi.util.text.StringUtil.isWhiteSpace; public class ByLine { @NotNull - public static List compare(@NotNull CharSequence text1, - @NotNull CharSequence text2, - @NotNull ComparisonPolicy policy, - @NotNull ProgressIndicator indicator) { + public static FairDiffIterable compare(@NotNull List lines1, + @NotNull List lines2, + @NotNull ComparisonPolicy policy, + @NotNull ProgressIndicator indicator) { indicator.checkCanceled(); - - List lines1 = getLines(text1, policy); - List lines2 = getLines(text2, policy); - - FairDiffIterable changes = compareSmart(lines1, lines2, indicator); - changes = optimizeLineChunks(lines1, lines2, changes, indicator); - changes = expandRanges(lines1, lines2, changes, indicator); - return convertIntoFragments(lines1, lines2, changes); + return doCompare(getLines(lines1, policy), getLines(lines2, policy), policy, indicator); } @NotNull - public static List compareTwoStep(@NotNull CharSequence text1, - @NotNull CharSequence text2, - @NotNull ComparisonPolicy policy, - @NotNull ProgressIndicator indicator) { + public static List compare(@NotNull List lines1, + @NotNull List lines2, + @NotNull List lines3, + @NotNull ComparisonPolicy policy, + @NotNull ProgressIndicator indicator) { + indicator.checkCanceled(); + return doCompare(getLines(lines1, policy), getLines(lines2, policy), getLines(lines3, policy), policy, indicator); + } + + // + // Impl + // + + @NotNull + static FairDiffIterable doCompare(@NotNull List lines1, + @NotNull List lines2, + @NotNull ComparisonPolicy policy, + @NotNull ProgressIndicator indicator) { indicator.checkCanceled(); - List lines1 = getLines(text1, policy); - List lines2 = getLines(text2, policy); + if (policy == IGNORE_WHITESPACES) { + FairDiffIterable changes = compareSmart(lines1, lines2, indicator); + changes = optimizeLineChunks(lines1, lines2, changes, indicator); + return correctChangesSecondStepIW(lines1, lines2, changes); + } + else { + List iwLines1 = convertMode(lines1, IGNORE_WHITESPACES); + List iwLines2 = convertMode(lines2, IGNORE_WHITESPACES); - List iwLines1 = convertToIgnoreWhitespace(lines1); - List iwLines2 = convertToIgnoreWhitespace(lines2); - - FairDiffIterable iwChanges = compareSmart(iwLines1, iwLines2, indicator); - iwChanges = optimizeLineChunks(lines1, lines2, iwChanges, indicator); - FairDiffIterable changes = correctChangesSecondStep(lines1, lines2, iwChanges); - return convertIntoFragments(lines1, lines2, changes); + FairDiffIterable iwChanges = compareSmart(iwLines1, iwLines2, indicator); + iwChanges = optimizeLineChunks(lines1, lines2, iwChanges, indicator); + return correctChangesSecondStep(lines1, lines2, iwChanges); + } } @NotNull - public static List compareTwoStep(@NotNull CharSequence text1, - @NotNull CharSequence text2, - @NotNull CharSequence text3, - @NotNull ComparisonPolicy policy, - @NotNull ProgressIndicator indicator) { + static List doCompare(@NotNull List lines1, + @NotNull List lines2, + @NotNull List lines3, + @NotNull ComparisonPolicy policy, + @NotNull ProgressIndicator indicator) { indicator.checkCanceled(); - List lines1 = getLines(text1, policy); - List lines2 = getLines(text2, policy); - List lines3 = getLines(text3, policy); - - List iwLines1 = convertToIgnoreWhitespace(lines1); - List iwLines2 = convertToIgnoreWhitespace(lines2); - List iwLines3 = convertToIgnoreWhitespace(lines3); + List iwLines1 = convertMode(lines1, IGNORE_WHITESPACES); + List iwLines2 = convertMode(lines2, IGNORE_WHITESPACES); + List iwLines3 = convertMode(lines3, IGNORE_WHITESPACES); FairDiffIterable iwChanges1 = compareSmart(iwLines2, iwLines1, indicator); iwChanges1 = optimizeLineChunks(lines2, lines1, iwChanges1, indicator); @@ -100,18 +104,30 @@ public class ByLine { iwChanges2 = optimizeLineChunks(lines2, lines3, iwChanges2, indicator); FairDiffIterable iterable2 = correctChangesSecondStep(lines2, lines3, iwChanges2); - List conflicts = ComparisonMergeUtil.buildFair(iterable1, iterable2, indicator); - return convertIntoFragments(conflicts); + return ComparisonMergeUtil.buildFair(iterable1, iterable2, indicator); } - // - // Impl - // - @NotNull private static FairDiffIterable correctChangesSecondStep(@NotNull final List lines1, @NotNull final List lines2, @NotNull final FairDiffIterable changes) { + return doCorrectChangesSecondStep(lines1, lines2, changes, + Equality.CANONICAL); + } + + @NotNull + private static FairDiffIterable correctChangesSecondStepIW(@NotNull final List lines1, + @NotNull final List lines2, + @NotNull final FairDiffIterable changes) { + return doCorrectChangesSecondStep(lines1, lines2, changes, + (l1, l2) -> StringUtil.equals(l1.getContent(), l2.getContent())); + } + + @NotNull + private static FairDiffIterable doCorrectChangesSecondStep(@NotNull final List lines1, + @NotNull final List lines2, + @NotNull final FairDiffIterable changes, + @NotNull final Equality maximisingEquality) { /* * We want to fix invalid matching here: * @@ -156,7 +172,7 @@ public class ByLine { Line line2 = lines2.get(index2); if (!StringUtil.equalsIgnoreWhitespaces(sample, line1.getContent())) { - if (line1.equals(line2)) { + if (maximisingEquality.equals(line1, line2)) { flush(index1, index2); builder.markEqual(index1, index2); } @@ -197,13 +213,24 @@ public class ByLine { } private void alignExactMatching(TIntArrayList subLines1, TIntArrayList subLines2) { - if (subLines1.size() == subLines2.size()) return; - int n = Math.max(subLines1.size(), subLines2.size()); - if (n > 10) return; // we use brute-force algorithm (C_n_k). This will limit search space by ~250 cases. + boolean skipAligning = n > 10 || // we use brute-force algorithm (C_n_k). This will limit search space by ~250 cases. + subLines1.size() == subLines2.size(); // nothing to do + + if (skipAligning) { + int count = Math.min(subLines1.size(), subLines2.size()); + for (int i = 0; i < count; i++) { + int index1 = subLines1.get(i); + int index2 = subLines2.get(i); + if (lines1.get(index1).equals(lines2.get(index2))) { + builder.markEqual(index1, index2); + } + } + return; + } if (subLines1.size() < subLines2.size()) { - int[] matching = getBestMatchingAlignment(subLines1, subLines2, lines1, lines2); + int[] matching = getBestMatchingAlignment(subLines1, subLines2, lines1, lines2, maximisingEquality); for (int i = 0; i < subLines1.size(); i++) { int index1 = subLines1.get(i); int index2 = subLines2.get(matching[i]); @@ -213,7 +240,7 @@ public class ByLine { } } else { - int[] matching = getBestMatchingAlignment(subLines2, subLines1, lines2, lines1); + int[] matching = getBestMatchingAlignment(subLines2, subLines1, lines2, lines1, maximisingEquality); for (int i = 0; i < subLines2.size(); i++) { int index1 = subLines1.get(matching[i]); int index2 = subLines2.get(i); @@ -232,7 +259,8 @@ public class ByLine { private static int[] getBestMatchingAlignment(@NotNull final TIntArrayList subLines1, @NotNull final TIntArrayList subLines2, @NotNull final List lines1, - @NotNull final List lines2) { + @NotNull final List lines2, + @NotNull final Equality maximisingEquality) { assert subLines1.size() < subLines2.size(); final int size = subLines1.size(); @@ -267,7 +295,7 @@ public class ByLine { for (int i = 0; i < size; i++) { int index1 = subLines1.get(i); int index2 = subLines2.get(comb[i]); - if (lines1.get(index1).equals(lines2.get(index2))) weight++; + if (maximisingEquality.equals(lines1.get(index1), lines2.get(index2))) weight++; } if (weight > bestWeight) { @@ -288,45 +316,6 @@ public class ByLine { return new ChunkOptimizer.LineChunkOptimizer(lines1, lines2, iterable, indicator).build(); } - @NotNull - private static List convertIntoFragments(@NotNull List lines1, - @NotNull List lines2, - @NotNull FairDiffIterable changes) { - List fragments = new ArrayList<>(); - for (Range ch : changes.iterateChanges()) { - IntPair offsets1 = getOffsets(lines1, ch.start1, ch.end1); - IntPair offsets2 = getOffsets(lines2, ch.start2, ch.end2); - - fragments.add(new LineFragmentImpl(ch.start1, ch.end1, ch.start2, ch.end2, - offsets1.val1, offsets1.val2, offsets2.val1, offsets2.val2)); - } - return fragments; - } - - @NotNull - private static List convertIntoFragments(@NotNull List conflicts) { - return ContainerUtil.map(conflicts, ch -> new MergeLineFragmentImpl(ch)); - } - - @NotNull - private static IntPair getOffsets(@NotNull List lines, int startIndex, int endIndex) { - if (startIndex == endIndex) { - int offset; - if (startIndex < lines.size()) { - offset = lines.get(startIndex).getOffset1(); - } - else { - offset = lines.get(lines.size() - 1).getOffset2(); - } - return new IntPair(offset, offset); - } - else { - int offset1 = lines.get(startIndex).getOffset1(); - int offset2 = lines.get(endIndex - 1).getOffset2(); - return new IntPair(offset1, offset2); - } - } - /* * Compare lines in two steps: * - compare ignoring "unimportant" lines @@ -361,90 +350,44 @@ public class ByLine { return Pair.create(bigLines, indexes); } - @NotNull - private static FairDiffIterable expandRanges(@NotNull List lines1, - @NotNull List lines2, - @NotNull FairDiffIterable iterable, - @NotNull ProgressIndicator indicator) { - List changes = new ArrayList<>(); - - for (Range ch : iterable.iterateChanges()) { - Range expanded = TrimUtil.expand(lines1, lines2, ch.start1, ch.start2, ch.end1, ch.end2); - if (!expanded.isEmpty()) changes.add(expanded); - } - - return fair(create(changes, lines1.size(), lines2.size())); - } - // // Lines // @NotNull - private static List getLines(@NotNull CharSequence text, @NotNull ComparisonPolicy policy) { - List lines = new ArrayList<>(); - - int offset = 0; - while (true) { - Line line = createLine(text, offset, policy); - lines.add(line); - offset = line.getOffset2(); - if (!line.hasNewline()) break; - } - - return lines; + private static List getLines(@NotNull List text, @NotNull ComparisonPolicy policy) { + return ContainerUtil.map(text, (line) -> new Line(line, policy)); } @NotNull - private static Line createLine(@NotNull CharSequence text, int offset, @NotNull ComparisonPolicy policy) { - switch (policy) { - case DEFAULT: - return Line.createDefault(text, offset); - case IGNORE_WHITESPACES: - return Line.createIgnore(text, offset); - case TRIM_WHITESPACES: - return Line.createTrim(text, offset); - default: - throw new IllegalArgumentException(policy.name()); - } - } - - @NotNull - private static List convertToIgnoreWhitespace(@NotNull List original) { + private static List convertMode(@NotNull List original, @NotNull ComparisonPolicy policy) { List result = new ArrayList<>(original.size()); - for (Line line : original) { - result.add(Line.createIgnore(line.getOriginalText(), line.getOffset1())); + result.add(new Line(line.getContent(), policy)); } - return result; } - static class Line extends TextChunk { - enum Mode {DEFAULT, TRIM, IGNORE} - - @NotNull private final Mode myMode; + static class Line { + @NotNull private final CharSequence myText; + @NotNull private final ComparisonPolicy myPolicy; private final int myHash; private final int myNonSpaceChars; - private final boolean myNewline; - public Line(@NotNull CharSequence text, int offset1, int offset2, - @NotNull Mode mode, int hash, int nonSpaceChars, boolean newline) { - super(text, offset1, offset2); - myMode = mode; - myHash = hash; - myNonSpaceChars = nonSpaceChars; - myNewline = newline; - } - - public boolean hasNewline() { - return myNewline; + public Line(@NotNull CharSequence text, @NotNull ComparisonPolicy policy) { + myText = text; + myPolicy = policy; + myHash = hashCode(text, policy); + myNonSpaceChars = countNonSpaceChars(text); } @NotNull - @Override public CharSequence getContent() { - return getOriginalText().subSequence(getOffset1(), getOffset2() - (myNewline ? 1 : 0)); + return myText; + } + + public int getNonSpaceChars() { + return myNonSpaceChars; } @Override @@ -453,20 +396,11 @@ public class ByLine { if (o == null || getClass() != o.getClass()) return false; Line line = (Line)o; - assert myMode == line.myMode; + assert myPolicy == line.myPolicy; if (hashCode() != line.hashCode()) return false; - switch (myMode) { - case DEFAULT: - return StringUtil.equals(getContent(), line.getContent()); - case TRIM: - return StringUtil.equalsTrimWhitespaces(getContent(), line.getContent()); - case IGNORE: - return StringUtil.equalsIgnoreWhitespaces(getContent(), line.getContent()); - default: - throw new IllegalArgumentException(myMode.toString()); - } + return equals(getContent(), line.getContent(), myPolicy); } @Override @@ -474,87 +408,47 @@ public class ByLine { return myHash; } - public int getNonSpaceChars() { - return myNonSpaceChars; - } - - public static Line createDefault(@NotNull CharSequence text, int startOffset) { - int len = text.length(); - - int h = 0; + private static int countNonSpaceChars(@NotNull CharSequence text) { int nonSpace = 0; - boolean newline = false; - int offset = startOffset; + int len = text.length(); + int offset = 0; + while (offset < len) { char c = text.charAt(offset); - if (c == '\n') { - offset++; - newline = true; - break; - } - if (!isWhiteSpace(c)) nonSpace++; - h = 31 * h + c; - offset++; - } - - return new Line(text, startOffset, offset, Mode.DEFAULT, h, nonSpace, newline); - } - - public static Line createIgnore(@NotNull CharSequence text, int startOffset) { - int len = text.length(); - - int h = 0; - int nonSpace = 0; - boolean newline = false; - - int offset = startOffset; - while (offset < len) { - char c = text.charAt(offset); - if (c == '\n') { - offset++; - newline = true; - break; - } - if (!isWhiteSpace(c)) { - nonSpace++; - h = 31 * h + c; - } - offset++; - } - - return new Line(text, startOffset, offset, Mode.IGNORE, h, nonSpace, newline); - } - - public static Line createTrim(@NotNull CharSequence text, int startOffset) { - int len = text.length(); - - int nonSpace = 0; - boolean newline = false; - - int offset = startOffset; - while (offset < len) { - char c = text.charAt(offset); - if (c == '\n') { - offset++; - newline = true; - break; - } if (!isWhiteSpace(c)) nonSpace++; offset++; } - int h = calcTrimHash(text, startOffset, offset); - - return new Line(text, startOffset, offset, Mode.TRIM, h, nonSpace, newline); + return nonSpace; } + private static boolean equals(@NotNull CharSequence text1, @NotNull CharSequence text2, @NotNull ComparisonPolicy policy) { + switch (policy) { + case DEFAULT: + return StringUtil.equals(text1, text2); + case TRIM_WHITESPACES: + return StringUtil.equalsTrimWhitespaces(text1, text2); + case IGNORE_WHITESPACES: + return StringUtil.equalsIgnoreWhitespaces(text1, text2); + default: + throw new IllegalArgumentException(policy.toString()); + } + } - private static int calcTrimHash(@NotNull CharSequence text, int offset1, int offset2) { - offset1 = trimStart(text, offset1, offset2); - offset2 = trimEnd(text, offset1, offset2); - - return StringUtil.stringHashCode(text, offset1, offset2); + private static int hashCode(@NotNull CharSequence text, @NotNull ComparisonPolicy policy) { + switch (policy) { + case DEFAULT: + return StringUtil.stringHashCode(text); + case TRIM_WHITESPACES: + int offset1 = trimStart(text, 0, text.length()); + int offset2 = trimEnd(text, offset1, text.length()); + return StringUtil.stringHashCode(text, offset1, offset2); + case IGNORE_WHITESPACES: + return StringUtil.stringHashCodeIgnoreWhitespaces(text); + default: + throw new IllegalArgumentException(policy.name()); + } } } } diff --git a/platform/diff-impl/src/com/intellij/diff/comparison/ByWord.java b/platform/diff-impl/src/com/intellij/diff/comparison/ByWord.java index 7e97f0de823a..eec26d3f1e25 100644 --- a/platform/diff-impl/src/com/intellij/diff/comparison/ByWord.java +++ b/platform/diff-impl/src/com/intellij/diff/comparison/ByWord.java @@ -17,24 +17,23 @@ package com.intellij.diff.comparison; import com.intellij.diff.comparison.LineFragmentSplitter.WordBlock; import com.intellij.diff.comparison.iterables.DiffIterable; -import com.intellij.diff.comparison.iterables.DiffIterableUtil; import com.intellij.diff.comparison.iterables.DiffIterableUtil.*; import com.intellij.diff.comparison.iterables.FairDiffIterable; import com.intellij.diff.fragments.DiffFragment; import com.intellij.diff.fragments.MergeWordFragment; -import com.intellij.diff.fragments.MergeWordFragmentImpl; import com.intellij.diff.util.MergeRange; import com.intellij.diff.util.Range; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.util.Couple; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.util.containers.ContainerUtil; import com.intellij.util.text.MergingCharSequence; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.List; +import static com.intellij.diff.comparison.ComparisonManagerImpl.convertIntoDiffFragments; +import static com.intellij.diff.comparison.ComparisonManagerImpl.convertIntoMergeWordFragments; import static com.intellij.diff.comparison.TrimUtil.*; import static com.intellij.diff.comparison.TrimUtil.trim; import static com.intellij.diff.comparison.iterables.DiffIterableUtil.*; @@ -66,7 +65,7 @@ public class ByWord { FairDiffIterable delimitersIterable = matchAdjustmentDelimiters(text1, text2, words1, words2, wordChanges, indicator); DiffIterable iterable = matchAdjustmentWhitespaces(text1, text2, delimitersIterable, policy, indicator); - return convertIntoFragments(iterable); + return convertIntoDiffFragments(iterable); } @NotNull @@ -92,7 +91,7 @@ public class ByWord { List wordConflicts = ComparisonMergeUtil.buildFair(iterable1, iterable2, indicator); List result = matchAdjustmentWhitespaces(text1, text2, text3, wordConflicts, policy, indicator); - return convertIntoFragments(result); + return convertIntoMergeWordFragments(result); } @NotNull @@ -144,7 +143,7 @@ public class ByWord { offsets.start1, offsets.start2, indicator); DiffIterable iterable = matchAdjustmentWhitespaces(subtext1, subtext2, delimitersIterable, policy, indicator); - List fragments = convertIntoFragments(iterable); + List fragments = convertIntoDiffFragments(iterable); int newlines1 = countNewlines(subwords1); int newlines2 = countNewlines(subwords2); @@ -159,16 +158,6 @@ public class ByWord { // Impl // - @NotNull - private static List convertIntoFragments(@NotNull List conflicts) { - return ContainerUtil.map(conflicts, ch -> new MergeWordFragmentImpl(ch)); - } - - @NotNull - private static List convertIntoFragments(@NotNull DiffIterable iterable) { - return DiffIterableUtil.convertIntoFragments(iterable); - } - @NotNull private static FairDiffIterable optimizeWordChunks(@NotNull CharSequence text1, @NotNull CharSequence text2, @@ -863,14 +852,32 @@ public class ByWord { int getOffset2(); } - static class WordChunk extends TextChunk implements InlineChunk { + static class WordChunk implements InlineChunk { + @NotNull private final CharSequence myText; + private final int myOffset1; + private final int myOffset2; private final int myHash; public WordChunk(@NotNull CharSequence text, int offset1, int offset2, int hash) { - super(text, offset1, offset2); + myText = text; + myOffset1 = offset1; + myOffset2 = offset2; myHash = hash; } + @NotNull + public CharSequence getContent() { + return myText.subSequence(myOffset1, myOffset2); + } + + public int getOffset1() { + return myOffset1; + } + + public int getOffset2() { + return myOffset2; + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/platform/diff-impl/src/com/intellij/diff/comparison/ComparisonManagerImpl.java b/platform/diff-impl/src/com/intellij/diff/comparison/ComparisonManagerImpl.java index 26aa3fa4ed20..31f67d866a6f 100644 --- a/platform/diff-impl/src/com/intellij/diff/comparison/ComparisonManagerImpl.java +++ b/platform/diff-impl/src/com/intellij/diff/comparison/ComparisonManagerImpl.java @@ -15,10 +15,11 @@ */ package com.intellij.diff.comparison; -import com.intellij.diff.fragments.DiffFragment; -import com.intellij.diff.fragments.DiffFragmentImpl; -import com.intellij.diff.fragments.LineFragment; -import com.intellij.diff.fragments.LineFragmentImpl; +import com.intellij.diff.comparison.iterables.DiffIterable; +import com.intellij.diff.comparison.iterables.FairDiffIterable; +import com.intellij.diff.fragments.*; +import com.intellij.diff.util.IntPair; +import com.intellij.diff.util.MergeRange; import com.intellij.diff.util.Range; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressIndicator; @@ -33,8 +34,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -import static com.intellij.diff.comparison.iterables.DiffIterableUtil.convertIntoFragments; - public class ComparisonManagerImpl extends ComparisonManager { public static final Logger LOG = Logger.getInstance(ComparisonManagerImpl.class); @@ -44,12 +43,24 @@ public class ComparisonManagerImpl extends ComparisonManager { @NotNull CharSequence text2, @NotNull ComparisonPolicy policy, @NotNull ProgressIndicator indicator) throws DiffTooBigException { - if (policy == ComparisonPolicy.IGNORE_WHITESPACES) { - return ByLine.compare(text1, text2, policy, indicator); - } - else { - return ByLine.compareTwoStep(text1, text2, policy, indicator); - } + List lines1 = getLines(text1); + List lines2 = getLines(text2); + FairDiffIterable iterable = ByLine.compare(lines1, lines2, policy, indicator); + return convertIntoLineFragments(lines1, lines2, iterable); + } + + @NotNull + @Override + public List compareLines(@NotNull CharSequence text1, + @NotNull CharSequence text2, + @NotNull CharSequence text3, + @NotNull ComparisonPolicy policy, + @NotNull ProgressIndicator indicator) throws DiffTooBigException { + List lines1 = getLines(text1); + List lines2 = getLines(text2); + List lines3 = getLines(text3); + List ranges = ByLine.compare(lines1, lines2, lines3, policy, indicator); + return convertIntoMergeLineFragments(ranges); } @NotNull @@ -145,13 +156,13 @@ public class ComparisonManagerImpl extends ComparisonManager { @NotNull ComparisonPolicy policy, @NotNull ProgressIndicator indicator) throws DiffTooBigException { if (policy == ComparisonPolicy.IGNORE_WHITESPACES) { - return convertIntoFragments(ByChar.compareIgnoreWhitespaces(text1, text2, indicator)); + return convertIntoDiffFragments(ByChar.compareIgnoreWhitespaces(text1, text2, indicator)); } if (policy == ComparisonPolicy.DEFAULT) { - return convertIntoFragments(ByChar.compareTwoStep(text1, text2, indicator)); + return convertIntoDiffFragments(ByChar.compareTwoStep(text1, text2, indicator)); } LOG.warn(policy.toString() + " is not supported by ByChar comparison"); - return convertIntoFragments(ByChar.compareTwoStep(text1, text2, indicator)); + return convertIntoDiffFragments(ByChar.compareTwoStep(text1, text2, indicator)); } @Override @@ -159,6 +170,63 @@ public class ComparisonManagerImpl extends ComparisonManager { return ComparisonUtil.isEquals(text1, text2, policy); } + // + // Fragments + // + + @NotNull + public static List convertIntoDiffFragments(@NotNull DiffIterable changes) { + final List fragments = new ArrayList<>(); + for (Range ch : changes.iterateChanges()) { + fragments.add(new DiffFragmentImpl(ch.start1, ch.end1, ch.start2, ch.end2)); + } + return fragments; + } + + @NotNull + public static List convertIntoLineFragments(@NotNull List lines1, + @NotNull List lines2, + @NotNull FairDiffIterable changes) { + List fragments = new ArrayList<>(); + for (Range ch : changes.iterateChanges()) { + IntPair offsets1 = getOffsets(lines1, ch.start1, ch.end1); + IntPair offsets2 = getOffsets(lines2, ch.start2, ch.end2); + + fragments.add(new LineFragmentImpl(ch.start1, ch.end1, ch.start2, ch.end2, + offsets1.val1, offsets1.val2, offsets2.val1, offsets2.val2)); + } + return fragments; + } + + @NotNull + private static IntPair getOffsets(@NotNull List lines, int startIndex, int endIndex) { + if (startIndex == endIndex) { + int offset; + if (startIndex < lines.size()) { + offset = lines.get(startIndex).getOffset1(); + } + else { + offset = lines.get(lines.size() - 1).getOffset2(); + } + return new IntPair(offset, offset); + } + else { + int offset1 = lines.get(startIndex).getOffset1(); + int offset2 = lines.get(endIndex - 1).getOffset2(); + return new IntPair(offset1, offset2); + } + } + + @NotNull + public static List convertIntoMergeLineFragments(@NotNull List conflicts) { + return ContainerUtil.map(conflicts, ch -> new MergeLineFragmentImpl(ch.start1, ch.end1, ch.start2, ch.end2, ch.start3, ch.end3)); + } + + @NotNull + public static List convertIntoMergeWordFragments(@NotNull List conflicts) { + return ContainerUtil.map(conflicts, ch -> new MergeWordFragmentImpl(ch.start1, ch.end1, ch.start2, ch.end2, ch.start3, ch.end3)); + } + // // Post process line fragments // @@ -304,4 +372,45 @@ public class ComparisonManagerImpl extends ComparisonManager { int length2 = lineFragment.getEndOffset2() - lineFragment.getStartOffset2(); return Collections.singletonList(new DiffFragmentImpl(0, length1, 0, length2)); } + + @NotNull + private static List getLines(@NotNull CharSequence text) { + List lines = new ArrayList<>(); + + int offset = 0; + while (true) { + int lineEnd = StringUtil.indexOf(text, '\n', offset); + if (lineEnd != -1) { + lines.add(new Line(text, offset, lineEnd, true)); + offset = lineEnd + 1; + } + else { + lines.add(new Line(text, offset, text.length(), false)); + break; + } + } + + return lines; + } + + private static class Line extends CharSequenceSubSequence { + private final int myOffset1; + private final int myOffset2; + private final boolean myNewline; + + public Line(@NotNull CharSequence chars, int offset1, int offset2, boolean newline) { + super(chars, offset1, offset2); + myOffset1 = offset1; + myOffset2 = offset2; + myNewline = newline; + } + + public int getOffset1() { + return myOffset1; + } + + public int getOffset2() { + return myOffset2 + (myNewline ? 1 : 0); + } + } } diff --git a/platform/diff-impl/src/com/intellij/diff/comparison/TextChunk.java b/platform/diff-impl/src/com/intellij/diff/comparison/TextChunk.java deleted file mode 100644 index 8a163f39b653..000000000000 --- a/platform/diff-impl/src/com/intellij/diff/comparison/TextChunk.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2000-2015 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.diff.comparison; - -import org.jetbrains.annotations.NotNull; - -abstract class TextChunk { - @NotNull private final CharSequence myText; - private final int myOffset1; - private final int myOffset2; - - public TextChunk(@NotNull CharSequence text, int offset1, int offset2) { - myText = text; - myOffset1 = offset1; - myOffset2 = offset2; - } - - @Override - public abstract int hashCode(); - - @Override - public abstract boolean equals(Object obj); - - @NotNull - public CharSequence getContent() { - return myText.subSequence(myOffset1, myOffset2); - } - - @NotNull - public CharSequence getOriginalText() { - return myText; - } - - public int getOffset1() { - return myOffset1; - } - - public int getOffset2() { - return myOffset2; - } - - @Override - public String toString() { - return getContent().toString(); - } -} diff --git a/platform/diff-impl/src/com/intellij/diff/comparison/iterables/DiffIterableUtil.java b/platform/diff-impl/src/com/intellij/diff/comparison/iterables/DiffIterableUtil.java index 10a4fc0de250..346e1402e489 100644 --- a/platform/diff-impl/src/com/intellij/diff/comparison/iterables/DiffIterableUtil.java +++ b/platform/diff-impl/src/com/intellij/diff/comparison/iterables/DiffIterableUtil.java @@ -18,7 +18,6 @@ package com.intellij.diff.comparison.iterables; import com.intellij.diff.comparison.DiffTooBigException; import com.intellij.diff.comparison.TrimUtil; import com.intellij.diff.fragments.DiffFragment; -import com.intellij.diff.fragments.DiffFragmentImpl; import com.intellij.diff.util.Range; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.util.Comparing; @@ -88,20 +87,6 @@ public class DiffIterableUtil { return diff(data1, data2, indicator); } - /* - * Compare two arrays, basing on equals() and hashCode() of it's elements - * - * If the input arrays are too big, "everything is changed" can be returned. - */ - @NotNull - public static FairDiffIterable diffSomehow(@NotNull T[] data1, @NotNull T[] data2, @NotNull ProgressIndicator indicator) { - indicator.checkCanceled(); - - // TODO: use ProgressIndicator inside - Diff.Change change = Diff.buildChangesSomehow(data1, data2); - return fair(create(change, data1.length, data2.length)); - } - // // Iterable // @@ -158,15 +143,6 @@ public class DiffIterableUtil { // Misc // - @NotNull - public static List convertIntoFragments(@NotNull DiffIterable changes) { - final List fragments = new ArrayList<>(); - for (Range ch : changes.iterateChanges()) { - fragments.add(new DiffFragmentImpl(ch.start1, ch.end1, ch.start2, ch.end2)); - } - return fragments; - } - @NotNull public static Iterable> iterateAll(@NotNull final DiffIterable iterable) { return () -> new Iterator>() { diff --git a/platform/diff-impl/src/com/intellij/diff/fragments/MergeLineFragmentImpl.java b/platform/diff-impl/src/com/intellij/diff/fragments/MergeLineFragmentImpl.java index eea8b6a2d590..a9d7b118fc3c 100644 --- a/platform/diff-impl/src/com/intellij/diff/fragments/MergeLineFragmentImpl.java +++ b/platform/diff-impl/src/com/intellij/diff/fragments/MergeLineFragmentImpl.java @@ -15,7 +15,6 @@ */ package com.intellij.diff.fragments; -import com.intellij.diff.util.MergeRange; import com.intellij.diff.util.ThreeSide; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -57,14 +56,6 @@ public class MergeLineFragmentImpl implements MergeLineFragment { myInnerFragments = innerFragments; } - public MergeLineFragmentImpl(@NotNull MergeRange range) { - this(range, null); - } - - public MergeLineFragmentImpl(@NotNull MergeRange range, @Nullable List innerFragments) { - this(range.start1, range.end1, range.start2, range.end2, range.start3, range.end3, innerFragments); - } - public MergeLineFragmentImpl(@NotNull MergeLineFragment fragment, @Nullable List fragments) { this(fragment.getStartLine(ThreeSide.LEFT), fragment.getEndLine(ThreeSide.LEFT), fragment.getStartLine(ThreeSide.BASE), fragment.getEndLine(ThreeSide.BASE), diff --git a/platform/diff-impl/src/com/intellij/diff/fragments/MergeWordFragmentImpl.java b/platform/diff-impl/src/com/intellij/diff/fragments/MergeWordFragmentImpl.java index b95a3e316493..b7abb9c333ed 100644 --- a/platform/diff-impl/src/com/intellij/diff/fragments/MergeWordFragmentImpl.java +++ b/platform/diff-impl/src/com/intellij/diff/fragments/MergeWordFragmentImpl.java @@ -41,10 +41,6 @@ public class MergeWordFragmentImpl implements MergeWordFragment { myEndOffset3 = endOffset3; } - public MergeWordFragmentImpl(@NotNull MergeRange range) { - this(range.start1, range.end1, range.start2, range.end2, range.start3, range.end3); - } - @Override public int getStartOffset(@NotNull ThreeSide side) { return side.select(myStartOffset1, myStartOffset2, myStartOffset3); diff --git a/platform/diff-impl/src/com/intellij/diff/merge/TextMergeViewer.java b/platform/diff-impl/src/com/intellij/diff/merge/TextMergeViewer.java index dd6e166e4a16..e5de1b18f040 100644 --- a/platform/diff-impl/src/com/intellij/diff/merge/TextMergeViewer.java +++ b/platform/diff-impl/src/com/intellij/diff/merge/TextMergeViewer.java @@ -18,7 +18,7 @@ package com.intellij.diff.merge; import com.intellij.diff.DiffContext; import com.intellij.diff.FrameDiffTool; import com.intellij.diff.actions.ProxyUndoRedoAction; -import com.intellij.diff.comparison.ByLine; +import com.intellij.diff.comparison.ComparisonManager; import com.intellij.diff.comparison.ComparisonMergeUtil; import com.intellij.diff.comparison.ComparisonPolicy; import com.intellij.diff.comparison.DiffTooBigException; @@ -363,8 +363,9 @@ public class TextMergeViewer implements MergeTool.MergeViewer { return ContainerUtil.map(documents, Document::getImmutableCharSequence); }); - List lineFragments = ByLine.compareTwoStep(sequences.get(0), sequences.get(1), sequences.get(2), - ComparisonPolicy.DEFAULT, indicator); + ComparisonManager manager = ComparisonManager.getInstance(); + List lineFragments = manager.compareLines(sequences.get(0), sequences.get(1), sequences.get(2), + ComparisonPolicy.DEFAULT, indicator); List conflictTypes = ReadAction.compute(() -> { indicator.checkCanceled(); diff --git a/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleThreesideDiffViewer.java b/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleThreesideDiffViewer.java index 3d2325550148..c67f66adcf11 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleThreesideDiffViewer.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleThreesideDiffViewer.java @@ -16,7 +16,7 @@ package com.intellij.diff.tools.simple; import com.intellij.diff.DiffContext; -import com.intellij.diff.comparison.ByLine; +import com.intellij.diff.comparison.ComparisonManager; import com.intellij.diff.comparison.ComparisonPolicy; import com.intellij.diff.comparison.DiffTooBigException; import com.intellij.diff.contents.DiffContent; @@ -125,8 +125,10 @@ public class SimpleThreesideDiffViewer extends ThreesideTextDiffViewerEx { }); final ComparisonPolicy comparisonPolicy = getIgnorePolicy().getComparisonPolicy(); - List lineFragments = ByLine.compareTwoStep(sequences.get(0), sequences.get(1), sequences.get(2), - comparisonPolicy, indicator); + + ComparisonManager manager = ComparisonManager.getInstance(); + List lineFragments = manager.compareLines(sequences.get(0), sequences.get(1), sequences.get(2), + comparisonPolicy, indicator); List conflictTypes = ReadAction.compute(() -> { indicator.checkCanceled(); diff --git a/platform/diff-impl/tests/com/intellij/diff/comparison/ComparisonUtilAutoTest.kt b/platform/diff-impl/tests/com/intellij/diff/comparison/ComparisonUtilAutoTest.kt index 36431c682616..4de112cd371b 100644 --- a/platform/diff-impl/tests/com/intellij/diff/comparison/ComparisonUtilAutoTest.kt +++ b/platform/diff-impl/tests/com/intellij/diff/comparison/ComparisonUtilAutoTest.kt @@ -134,7 +134,7 @@ class ComparisonUtilAutoTest : DiffTestCase() { val sequence2 = text2.charsSequence val sequence3 = text3.charsSequence - val fragments = ByLine.compareTwoStep(sequence1, sequence2, sequence3, policy, INDICATOR) + val fragments = MANAGER.compareLines(sequence1, sequence2, sequence3, policy, INDICATOR) val fineFragments = fragments.map { f -> val chunk1 = DiffUtil.getLinesContent(text1, f.startLine1, f.endLine1) diff --git a/platform/diff-impl/tests/com/intellij/diff/comparison/LineComparisonUtilTest.kt b/platform/diff-impl/tests/com/intellij/diff/comparison/LineComparisonUtilTest.kt index 9144618851d3..2eab93eccb42 100644 --- a/platform/diff-impl/tests/com/intellij/diff/comparison/LineComparisonUtilTest.kt +++ b/platform/diff-impl/tests/com/intellij/diff/comparison/LineComparisonUtilTest.kt @@ -401,6 +401,7 @@ class LineComparisonUtilTest : ComparisonUtilTestBase() { // TODO (" _-------_ _ _ " - " _ _ _ ").trim() (" _-------_ _ _ " - " _ _ _ ").default() (" _ _--_-_------" - " _--_-_ ").trim() + (" _-------_ _ _ " - " _ _ _ ").ignore() testAll() } @@ -416,7 +417,6 @@ class LineComparisonUtilTest : ComparisonUtilTestBase() { lines() { ("====}_==== }_Y_====}" - "====}_Y_====}") (" _------_ _ " - " _ _ ").default() // result after second step correction - (" _ _-_-----" - " _-_ ").ignore() // result looks strange because of 'diff.unimportant.line.char.count' testAll() } } @@ -428,4 +428,59 @@ class LineComparisonUtilTest : ComparisonUtilTestBase() { testDefault() } } + + fun `test ignore whitespace policy applies two-step correction`() { + lines() { + ("1_ _ 1" - " 1") + ("-_-_ " - " ").default() + (" _-_---" - " ").trim() + ("-_-_ " - " ").ignore() + testAll() + } + + lines() { + (" 1_ _1" - " 1") + (" _-_-" - " ").default() + testAll() + } + + lines() { + ("X_ Y_X" - "Y ") + ("-_--_-" - "--").default() + ("-_ _-" - " ").trim() + testAll() + } + } + + fun `test regression - second step correction should be performed if there are no ambigous matchings`() { + lines { + ("}_ }" - " }_}") + ("-_--" - "--_-").default() + (" _ " - " _ ").trim() + testAll() + } + + lines { + (" }_}_ }" - "}_}_}") + ("--_ _--" - "-_ _-").default() + (" _ _ " - " _ _ ").trim() + testAll() + } + + lines() { + ("X_X __Y" - "X__Z") + (" _--__-" - " __-").default() + ("-_ __-" - " __-").trim() + testAll() + } + } + + fun `test regression - second step with too many possible matchings`() { + lines { + (" X_X_X_X_X_X_X_X_X_X_X_X_X_X_X_X_X_X_X_X_X_X_X_ X" - "X_X_X_X_X_X_X_X_X_X_X_X_X_X_X_X_X_X_X ") + ("--_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _-_-_-_-_-_--" - "-_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _--").default() + (" _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _-_-_-_-_--" - " _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ").trim() + testAll() + } + } } diff --git a/platform/icons/src/icon.png b/platform/icons/src/icon.png index 5af892c1ec5f..78b2f6c13262 100644 Binary files a/platform/icons/src/icon.png and b/platform/icons/src/icon.png differ diff --git a/platform/icons/src/windows/close.png b/platform/icons/src/windows/close.png deleted file mode 100644 index 4c593adde24b..000000000000 Binary files a/platform/icons/src/windows/close.png and /dev/null differ diff --git a/platform/icons/src/windows/closeActive.png b/platform/icons/src/windows/closeActive.png new file mode 100644 index 000000000000..9399d0a75cb8 Binary files /dev/null and b/platform/icons/src/windows/closeActive.png differ diff --git a/platform/icons/src/windows/closeActive@2x.png b/platform/icons/src/windows/closeActive@2x.png new file mode 100644 index 000000000000..0d27cde74cd9 Binary files /dev/null and b/platform/icons/src/windows/closeActive@2x.png differ diff --git a/platform/icons/src/windows/closeActive@2x_dark.png b/platform/icons/src/windows/closeActive@2x_dark.png new file mode 100644 index 000000000000..bfad5bb3d0c4 Binary files /dev/null and b/platform/icons/src/windows/closeActive@2x_dark.png differ diff --git a/platform/icons/src/windows/closeActive_dark.png b/platform/icons/src/windows/closeActive_dark.png new file mode 100644 index 000000000000..c7b47d6b1e26 Binary files /dev/null and b/platform/icons/src/windows/closeActive_dark.png differ diff --git a/platform/icons/src/windows/closeHover.png b/platform/icons/src/windows/closeHover.png new file mode 100644 index 000000000000..6b0095161034 Binary files /dev/null and b/platform/icons/src/windows/closeHover.png differ diff --git a/platform/icons/src/windows/closeHover@2x.png b/platform/icons/src/windows/closeHover@2x.png new file mode 100644 index 000000000000..33cb80c35b65 Binary files /dev/null and b/platform/icons/src/windows/closeHover@2x.png differ diff --git a/platform/icons/src/windows/closeInactive.png b/platform/icons/src/windows/closeInactive.png new file mode 100644 index 000000000000..a24938407f83 Binary files /dev/null and b/platform/icons/src/windows/closeInactive.png differ diff --git a/platform/icons/src/windows/closeInactive@2x.png b/platform/icons/src/windows/closeInactive@2x.png new file mode 100644 index 000000000000..4d232434c41b Binary files /dev/null and b/platform/icons/src/windows/closeInactive@2x.png differ diff --git a/platform/icons/src/windows/closeInactive@2x_dark.png b/platform/icons/src/windows/closeInactive@2x_dark.png new file mode 100644 index 000000000000..e5d8f6671fab Binary files /dev/null and b/platform/icons/src/windows/closeInactive@2x_dark.png differ diff --git a/platform/icons/src/windows/closeInactive_dark.png b/platform/icons/src/windows/closeInactive_dark.png new file mode 100644 index 000000000000..0be3f457eba8 Binary files /dev/null and b/platform/icons/src/windows/closeInactive_dark.png differ diff --git a/platform/icons/src/windows/iconify.png b/platform/icons/src/windows/iconify.png deleted file mode 100644 index b2dd7458495e..000000000000 Binary files a/platform/icons/src/windows/iconify.png and /dev/null differ diff --git a/platform/icons/src/windows/maximize.png b/platform/icons/src/windows/maximize.png deleted file mode 100644 index 4dfcc65f4f88..000000000000 Binary files a/platform/icons/src/windows/maximize.png and /dev/null differ diff --git a/platform/icons/src/windows/maximize@2x.png b/platform/icons/src/windows/maximize@2x.png new file mode 100644 index 000000000000..a9dc5c1eaeb3 Binary files /dev/null and b/platform/icons/src/windows/maximize@2x.png differ diff --git a/platform/icons/src/windows/maximize@2x_dark.png b/platform/icons/src/windows/maximize@2x_dark.png new file mode 100644 index 000000000000..c12370c18563 Binary files /dev/null and b/platform/icons/src/windows/maximize@2x_dark.png differ diff --git a/platform/icons/src/windows/maximizeInactive.png b/platform/icons/src/windows/maximizeInactive.png new file mode 100644 index 000000000000..688e4e3fc0b6 Binary files /dev/null and b/platform/icons/src/windows/maximizeInactive.png differ diff --git a/platform/icons/src/windows/maximizeInactive@2x.png b/platform/icons/src/windows/maximizeInactive@2x.png new file mode 100644 index 000000000000..1b8ba51e0556 Binary files /dev/null and b/platform/icons/src/windows/maximizeInactive@2x.png differ diff --git a/platform/icons/src/windows/maximizeInactive@2x_dark.png b/platform/icons/src/windows/maximizeInactive@2x_dark.png new file mode 100644 index 000000000000..a335b14ef756 Binary files /dev/null and b/platform/icons/src/windows/maximizeInactive@2x_dark.png differ diff --git a/platform/icons/src/windows/maximizeInactive_dark.png b/platform/icons/src/windows/maximizeInactive_dark.png new file mode 100644 index 000000000000..23d7af2614e5 Binary files /dev/null and b/platform/icons/src/windows/maximizeInactive_dark.png differ diff --git a/platform/icons/src/windows/maximize_dark.png b/platform/icons/src/windows/maximize_dark.png new file mode 100644 index 000000000000..ff9b20695970 Binary files /dev/null and b/platform/icons/src/windows/maximize_dark.png differ diff --git a/platform/icons/src/windows/minimize.png b/platform/icons/src/windows/minimize.png index dc6b39109161..f21aafd5314b 100644 Binary files a/platform/icons/src/windows/minimize.png and b/platform/icons/src/windows/minimize.png differ diff --git a/platform/icons/src/windows/minimize@2x.png b/platform/icons/src/windows/minimize@2x.png new file mode 100644 index 000000000000..fa32e78f8176 Binary files /dev/null and b/platform/icons/src/windows/minimize@2x.png differ diff --git a/platform/icons/src/windows/minimize@2x_dark.png b/platform/icons/src/windows/minimize@2x_dark.png new file mode 100644 index 000000000000..f463d2d83d41 Binary files /dev/null and b/platform/icons/src/windows/minimize@2x_dark.png differ diff --git a/platform/icons/src/windows/minimizeInactive.png b/platform/icons/src/windows/minimizeInactive.png new file mode 100644 index 000000000000..49be621e23a8 Binary files /dev/null and b/platform/icons/src/windows/minimizeInactive.png differ diff --git a/platform/icons/src/windows/minimizeInactive@2x.png b/platform/icons/src/windows/minimizeInactive@2x.png new file mode 100644 index 000000000000..afe98f8b3a40 Binary files /dev/null and b/platform/icons/src/windows/minimizeInactive@2x.png differ diff --git a/platform/icons/src/windows/minimizeInactive@2x_dark.png b/platform/icons/src/windows/minimizeInactive@2x_dark.png new file mode 100644 index 000000000000..a4fd6cebfdd0 Binary files /dev/null and b/platform/icons/src/windows/minimizeInactive@2x_dark.png differ diff --git a/platform/icons/src/windows/minimizeInactive_dark.png b/platform/icons/src/windows/minimizeInactive_dark.png new file mode 100644 index 000000000000..c5ff31352b07 Binary files /dev/null and b/platform/icons/src/windows/minimizeInactive_dark.png differ diff --git a/platform/icons/src/windows/minimize_dark.png b/platform/icons/src/windows/minimize_dark.png new file mode 100644 index 000000000000..01275e1af39b Binary files /dev/null and b/platform/icons/src/windows/minimize_dark.png differ diff --git a/platform/icons/src/windows/restore.png b/platform/icons/src/windows/restore.png new file mode 100644 index 000000000000..9dcafef6a1a7 Binary files /dev/null and b/platform/icons/src/windows/restore.png differ diff --git a/platform/icons/src/windows/restore@2x.png b/platform/icons/src/windows/restore@2x.png new file mode 100644 index 000000000000..2d1fc2b55664 Binary files /dev/null and b/platform/icons/src/windows/restore@2x.png differ diff --git a/platform/icons/src/windows/restore@2x_dark.png b/platform/icons/src/windows/restore@2x_dark.png new file mode 100644 index 000000000000..0fa65cd5b7c1 Binary files /dev/null and b/platform/icons/src/windows/restore@2x_dark.png differ diff --git a/platform/icons/src/windows/restoreInactive.png b/platform/icons/src/windows/restoreInactive.png new file mode 100644 index 000000000000..6e25f284583d Binary files /dev/null and b/platform/icons/src/windows/restoreInactive.png differ diff --git a/platform/icons/src/windows/restoreInactive@2x.png b/platform/icons/src/windows/restoreInactive@2x.png new file mode 100644 index 000000000000..2faaa2b60268 Binary files /dev/null and b/platform/icons/src/windows/restoreInactive@2x.png differ diff --git a/platform/icons/src/windows/restoreInactive@2x_dark.png b/platform/icons/src/windows/restoreInactive@2x_dark.png new file mode 100644 index 000000000000..056a3a5aebc8 Binary files /dev/null and b/platform/icons/src/windows/restoreInactive@2x_dark.png differ diff --git a/platform/icons/src/windows/restoreInactive_dark.png b/platform/icons/src/windows/restoreInactive_dark.png new file mode 100644 index 000000000000..718897b7bdea Binary files /dev/null and b/platform/icons/src/windows/restoreInactive_dark.png differ diff --git a/platform/icons/src/windows/restore_dark.png b/platform/icons/src/windows/restore_dark.png new file mode 100644 index 000000000000..ae6ffc89101b Binary files /dev/null and b/platform/icons/src/windows/restore_dark.png differ diff --git a/platform/lang-api/src/com/intellij/codeInsight/completion/CompletionContributor.java b/platform/lang-api/src/com/intellij/codeInsight/completion/CompletionContributor.java index b6485d6c5432..ac368eae64bd 100644 --- a/platform/lang-api/src/com/intellij/codeInsight/completion/CompletionContributor.java +++ b/platform/lang-api/src/com/intellij/codeInsight/completion/CompletionContributor.java @@ -54,9 +54,7 @@ import java.util.Set; * A: There are two ways. The easier and preferred one is to provide constructor in your contributor and register completion providers there: * {@link #extend(CompletionType, ElementPattern, CompletionProvider)}.
* A more generic way is to override default {@link #fillCompletionVariants(CompletionParameters, CompletionResultSet)} implementation - * and provide your own. It's easier to debug, but harder to write. Remember, that completion variant collection is done in a dedicated thread - * WITHOUT read action, so you'll have to manually invoke {@link com.intellij.openapi.application.Application#runReadAction(Runnable)} each time - * you access PSI. Don't spend long time inside read action, since this will prevent user from selecting lookup element or cancelling completion.

+ * and provide your own. It's easier to debug, but harder to write.

* * Q: What does the {@link CompletionParameters#getPosition()} return?
* A: When completion is invoked, the file being edited is first copied (the original file can be accessed from {@link com.intellij.psi.PsiFile#getOriginalFile()} diff --git a/platform/lang-api/src/com/intellij/codeInsight/completion/OffsetMap.java b/platform/lang-api/src/com/intellij/codeInsight/completion/OffsetMap.java index 90a9b12292e9..8f28dffa0dcb 100644 --- a/platform/lang-api/src/com/intellij/codeInsight/completion/OffsetMap.java +++ b/platform/lang-api/src/com/intellij/codeInsight/completion/OffsetMap.java @@ -19,10 +19,10 @@ import com.intellij.openapi.Disposable; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.RangeMarker; import com.intellij.openapi.progress.ProgressManager; +import com.intellij.util.containers.ContainerUtil; import gnu.trove.THashMap; import gnu.trove.THashSet; -import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; @@ -48,10 +48,10 @@ public class OffsetMap implements Disposable { public int getOffset(OffsetKey key) { synchronized (myMap) { final RangeMarker marker = myMap.get(key); - if (marker == null) return -1; + if (marker == null) throw new IllegalArgumentException("Offset " + key + " is not registered"); if (!marker.isValid()) { removeOffset(key); - return -1; + throw new IllegalStateException("Offset " + key + " is invalid: " + marker); } final int endOffset = marker.getEndOffset(); @@ -62,6 +62,11 @@ public class OffsetMap implements Disposable { } } + public boolean containsOffset(OffsetKey key) { + final RangeMarker marker = myMap.get(key); + return marker != null && marker.isValid(); + } + /** * Register key-offset binding. Offset will change together with {@link Document} editing operations * unless an operation replaces completely the offset vicinity. @@ -108,7 +113,7 @@ public class OffsetMap implements Disposable { synchronized (myMap) { ProgressManager.checkCanceled(); assert !myDisposed; - return new ArrayList(myMap.keySet()); + return ContainerUtil.filter(myMap.keySet(), this::containsOffset); } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java index 34a67a149b82..bb8e159880e0 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java @@ -566,10 +566,9 @@ public class CodeCompletionHandlerBase { final Editor editor = indicator.getEditor(); final int caretOffset = indicator.getCaret().getOffset(); - int idEndOffset = indicator.getIdentifierEndOffset(); - if (idEndOffset < 0) { - idEndOffset = CompletionInitializationContext.calcDefaultIdentifierEnd(editor, caretOffset); - } + final int idEndOffset = indicator.getOffsetMap().containsOffset(CompletionInitializationContext.IDENTIFIER_END_OFFSET) ? + indicator.getIdentifierEndOffset() : + CompletionInitializationContext.calcDefaultIdentifierEnd(editor, caretOffset); final int idEndOffsetDelta = idEndOffset - caretOffset; CompletionAssertions.WatchingInsertionContext context; diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/ComboEditorCompletionContributor.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/ComboEditorCompletionContributor.java index 59159a84a440..10994f07e85b 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/ComboEditorCompletionContributor.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/ComboEditorCompletionContributor.java @@ -18,6 +18,8 @@ package com.intellij.codeInsight.completion; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.LookupElementBuilder; import com.intellij.openapi.editor.Document; +import com.intellij.openapi.project.DumbAware; +import com.intellij.openapi.util.Key; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiFile; import com.intellij.ui.StringComboboxEditor; @@ -28,7 +30,9 @@ import javax.swing.*; /** * @author peter */ -public class ComboEditorCompletionContributor extends CompletionContributor{ +public class ComboEditorCompletionContributor extends CompletionContributor implements DumbAware { + + public static final Key CONTINUE_RUN_COMPLETION = Key.create("CONTINUE_RUN_COMPLETION"); @Override public void fillCompletionVariants(@NotNull final CompletionParameters parameters, @NotNull final CompletionResultSet result) { @@ -60,7 +64,9 @@ public class ComboEditorCompletionContributor extends CompletionContributor{ }), count-i)); } } - result.stopHere(); + if (!Boolean.TRUE.equals(document.getUserData(CONTINUE_RUN_COMPLETION))) { + result.stopHere(); + } } } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionLookupArranger.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionLookupArranger.java index 1a4be6bf4c56..20a099c0dfb9 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionLookupArranger.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionLookupArranger.java @@ -462,6 +462,10 @@ public class CompletionLookupArranger extends LookupArranger { return; } + if (!context.getOffsetMap().containsOffset(CompletionInitializationContext.START_OFFSET)) { + return; + } + final Document document = context.getDocument(); int startOffset = context.getStartOffset(); int tailOffset = context.getEditor().getCaretModel().getOffset(); @@ -550,7 +554,9 @@ public class CompletionLookupArranger extends LookupArranger { public void addSparedChars(CompletionProgressIndicator indicator, LookupElement item, InsertionContext context, char completionChar) { String textInserted; - if (context.getStartOffset() >= 0 && context.getTailOffset() >= context.getStartOffset()) { + if (context.getOffsetMap().containsOffset(CompletionInitializationContext.START_OFFSET) && + context.getOffsetMap().containsOffset(InsertionContext.TAIL_OFFSET) && + context.getTailOffset() >= context.getStartOffset()) { textInserted = context.getDocument().getImmutableCharSequence().subSequence(context.getStartOffset(), context.getTailOffset()).toString(); } else { textInserted = item.getLookupString(); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PassExecutorService.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PassExecutorService.java index 534ec24f9e19..87c490400fec 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PassExecutorService.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PassExecutorService.java @@ -35,18 +35,17 @@ import com.intellij.openapi.fileEditor.FileEditor; import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.fileEditor.TextEditor; import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx; +import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.DumbAwareRunnable; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.util.Consumer; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.MultiMap; import gnu.trove.THashMap; @@ -57,7 +56,10 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.TestOnly; import java.util.*; -import java.util.concurrent.*; +import java.util.concurrent.CancellationException; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -506,10 +508,18 @@ class PassExecutorService implements Disposable { pass.applyInformationToEditor(); } } - catch (RuntimeException e) { + catch (ProcessCanceledException e) { log(updateProgress, pass, "Error " + e); throw e; } + catch (RuntimeException e) { + Document document = pass.getDocument(); + VirtualFile file = document == null ? null : FileDocumentManager.getInstance().getFile(document); + FileType fileType = file == null ? null : file.getFileType(); + String message = "Exception while applying information to " + fileEditor + "("+fileType+")"; + log(updateProgress, pass, message + e); + throw new RuntimeException(message, e); + } if (threadsToStartCountdown.decrementAndGet() == 0) { log(updateProgress, pass, "Stopping "); updateProgress.stopIfRunning(); diff --git a/platform/lang-impl/src/com/intellij/codeInspection/InspectionApplication.java b/platform/lang-impl/src/com/intellij/codeInspection/InspectionApplication.java index 50b7d0a414e4..03a5ecc59e3b 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/InspectionApplication.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/InspectionApplication.java @@ -17,6 +17,7 @@ package com.intellij.codeInspection; import com.intellij.analysis.AnalysisScope; +import com.intellij.codeInsight.daemon.HighlightDisplayKey; import com.intellij.codeInspection.ex.*; import com.intellij.conversion.ConversionListener; import com.intellij.conversion.ConversionService; @@ -257,7 +258,8 @@ public class InspectionApplication { }); final String descriptionsFile = resultsDataPath + File.separatorChar + DESCRIPTIONS + XML_EXTENSION; describeInspections(descriptionsFile, - myRunWithEditorSettings ? null : inspectionProfile.getName()); + myRunWithEditorSettings ? null : inspectionProfile.getName(), + (InspectionProfile)inspectionProfile); inspectionsResults.add(new File(descriptionsFile)); // convert report if (reportConverter != null) { @@ -448,8 +450,8 @@ public class InspectionApplication { } } - private static void describeInspections(@NonNls String myOutputPath, final String name) throws IOException { - final InspectionToolWrapper[] toolWrappers = InspectionProfileImpl.getDefaultProfile().getInspectionTools(null); + private static void describeInspections(@NonNls String myOutputPath, final String name, final InspectionProfile profile) throws IOException { + final InspectionToolWrapper[] toolWrappers = profile.getInspectionTools(null); final Map> map = new HashMap>(); for (InspectionToolWrapper toolWrapper : toolWrappers) { final String groupName = toolWrapper.getGroupDisplayName(); @@ -474,14 +476,17 @@ public class InspectionApplication { final Set entries = map.get(groupName); for (InspectionToolWrapper toolWrapper : entries) { xmlWriter.startNode("inspection"); - xmlWriter.addAttribute("shortName", toolWrapper.getShortName()); + final String shortName = toolWrapper.getShortName(); + xmlWriter.addAttribute("shortName", shortName); xmlWriter.addAttribute("displayName", toolWrapper.getDisplayName()); + final boolean toolEnabled = profile.isToolEnabled(HighlightDisplayKey.find(shortName)); + xmlWriter.addAttribute("enabled", Boolean.toString(toolEnabled)); final String description = toolWrapper.loadDescription(); if (description != null) { xmlWriter.setValue(description); } else { - LOG.error(toolWrapper.getShortName() + " descriptionUrl==" + toolWrapper); + LOG.error(shortName + " descriptionUrl==" + toolWrapper); } xmlWriter.endNode(); } diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/SeverityEditorDialog.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/SeverityEditorDialog.java index 43a7e4df55e7..443b9e60fa3a 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ex/SeverityEditorDialog.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ex/SeverityEditorDialog.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -42,6 +42,7 @@ import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.InputValidator; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.ui.*; import com.intellij.ui.components.JBList; import org.jdom.Element; @@ -91,7 +92,8 @@ public class SeverityEditorDialog extends DialogWrapper { public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { final Component rendererComponent = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); if (value instanceof SeverityBasedTextAttributes) { - setText(((SeverityBasedTextAttributes)value).getSeverity().getName()); + final HighlightSeverity severity = ((SeverityBasedTextAttributes)value).getSeverity(); + setText(StringUtil.capitalizeWords(severity.getName().toLowerCase(), true)); } return rendererComponent; } @@ -124,7 +126,7 @@ public class SeverityEditorDialog extends DialogWrapper { final ListModel listModel = myOptionsList.getModel(); for (int i = 0; i < listModel.getSize(); i++) { final String severityName = ((SeverityBasedTextAttributes)listModel.getElementAt(i)).getSeverity().myName; - if (Comparing.strEqual(severityName, inputString)) return false; + if (Comparing.strEqual(severityName, inputString, false)) return false; } return true; } diff --git a/platform/lang-impl/src/com/intellij/formatting/FormatterTagHandler.java b/platform/lang-impl/src/com/intellij/formatting/FormatterTagHandler.java index 1bfca618803e..51e607a2acfd 100644 --- a/platform/lang-impl/src/com/intellij/formatting/FormatterTagHandler.java +++ b/platform/lang-impl/src/com/intellij/formatting/FormatterTagHandler.java @@ -58,7 +58,7 @@ public class FormatterTagHandler { return FormatterTag.NONE; } - private FormatterTag getFormatterTag(@NotNull PsiComment comment) { + protected FormatterTag getFormatterTag(@NotNull PsiComment comment) { CharSequence nodeChars = comment.getNode().getChars(); if (mySettings.FORMATTER_TAGS_ACCEPT_REGEXP) { Pattern onPattern = mySettings.getFormatterOnPattern(); diff --git a/platform/lang-impl/src/com/intellij/ide/scopeView/ScopePaneSelectInTarget.java b/platform/lang-impl/src/com/intellij/ide/scopeView/ScopePaneSelectInTarget.java index 78d612f36939..99d00a895cd4 100644 --- a/platform/lang-impl/src/com/intellij/ide/scopeView/ScopePaneSelectInTarget.java +++ b/platform/lang-impl/src/com/intellij/ide/scopeView/ScopePaneSelectInTarget.java @@ -51,7 +51,8 @@ public class ScopePaneSelectInTarget extends ProjectViewSelectInTarget { } @Nullable - private NamedScope getContainingScope(PsiFile file) { + private NamedScope getContainingScope(@Nullable PsiFile file) { + if (file == null) return null; NamedScopesHolder scopesHolder = DependencyValidationManager.getInstance(myProject); for (NamedScope scope : ScopeViewPane.getShownScopes(myProject)) { PackageSet packageSet = scope.getValue(); diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/LevelChooserAction.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/LevelChooserAction.java index 660d7b4fb1b2..0920f870d296 100644 --- a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/LevelChooserAction.java +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/LevelChooserAction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -19,7 +19,6 @@ import com.intellij.codeHighlighting.HighlightDisplayLevel; import com.intellij.codeInsight.daemon.impl.HighlightInfoType; import com.intellij.codeInsight.daemon.impl.SeverityRegistrar; import com.intellij.codeInsight.daemon.impl.SeverityUtil; -import com.intellij.codeInspection.ex.InspectionProfileImpl; import com.intellij.codeInspection.ex.SeverityEditorDialog; import com.intellij.lang.annotation.HighlightSeverity; import com.intellij.openapi.actionSystem.AnActionEvent; @@ -28,13 +27,13 @@ import com.intellij.openapi.actionSystem.Presentation; import com.intellij.openapi.actionSystem.ex.ComboBoxAction; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.DumbAwareAction; -import com.intellij.profile.codeInspection.SeverityProvider; import com.intellij.profile.codeInspection.ui.table.SeverityRenderer; import org.jetbrains.annotations.NotNull; import javax.swing.*; -import java.util.SortedSet; -import java.util.TreeSet; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; /** * @author Dmitry Batkovich @@ -83,23 +82,20 @@ public abstract class LevelChooserAction extends ComboBoxAction implements DumbA return group; } - public static SortedSet getSeverities(final SeverityRegistrar severityRegistrar) { + public static List getSeverities(final SeverityRegistrar severityRegistrar) { return getSeverities(severityRegistrar, true); } - public static SortedSet getSeverities(final SeverityRegistrar severityRegistrar, - boolean includeDoNotShow) { - final SortedSet severities = new TreeSet(severityRegistrar); + public static List getSeverities(final SeverityRegistrar severityRegistrar, + boolean includeDoNotShow) { + final List severities = new ArrayList(); for (final SeverityRegistrar.SeverityBasedTextAttributes type : SeverityUtil.getRegisteredHighlightingInfoTypes(severityRegistrar)) { severities.add(type.getSeverity()); } - severities.add(HighlightSeverity.ERROR); - severities.add(HighlightSeverity.WARNING); - severities.add(HighlightSeverity.WEAK_WARNING); - severities.add(HighlightSeverity.GENERIC_SERVER_ERROR_OR_WARNING); if (includeDoNotShow) { severities.add(HighlightSeverity.INFORMATION); } + Collections.sort(severities, (a, b) -> -severityRegistrar.compare(a, b)); return severities; } diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/filter/InspectionFilterAction.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/filter/InspectionFilterAction.java index 9db40ed9ea99..d17160502620 100644 --- a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/filter/InspectionFilterAction.java +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/filter/InspectionFilterAction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -82,8 +82,7 @@ public class InspectionFilterAction extends DefaultActionGroup implements Toggle addAction(new ShowOnlyModifiedInspectionsAction()); addSeparator(); - final SortedSet severities = LevelChooserAction.getSeverities(mySeverityRegistrar); - for (final HighlightSeverity severity : severities) { + for (final HighlightSeverity severity : LevelChooserAction.getSeverities(mySeverityRegistrar)) { add(new ShowWithSpecifiedSeverityInspectionsAction(severity)); } addSeparator(); diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/table/SeverityRenderer.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/table/SeverityRenderer.java index 5db2970d8d9f..b8fea3dec0f6 100644 --- a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/table/SeverityRenderer.java +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/table/SeverityRenderer.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -23,7 +23,6 @@ import com.intellij.openapi.ui.popup.LightweightWindowEvent; import com.intellij.profile.codeInspection.SeverityProvider; import com.intellij.profile.codeInspection.ui.LevelChooserAction; import com.intellij.profile.codeInspection.ui.SingleInspectionProfilePanel; -import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.ColorIcon; import com.intellij.util.ui.UIUtil; @@ -33,7 +32,7 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.event.MouseEvent; import java.util.EventObject; -import java.util.SortedSet; +import java.util.List; /** * @author Dmitry Batkovich @@ -49,7 +48,7 @@ public class SeverityRenderer extends ComboBoxTableRenderer { } public static SeverityRenderer create(final InspectionProfileImpl inspectionProfile, @Nullable final Runnable onClose) { - final SortedSet severities = + final List severities = LevelChooserAction.getSeverities(((SeverityProvider)inspectionProfile.getProfileManager()).getOwnSeverityRegistrar()); return new SeverityRenderer(ContainerUtil.map2Array(severities, new SeverityState[severities.size()], severity -> new SeverityState(severity, true, false)), onClose); } diff --git a/platform/lang-impl/src/com/intellij/util/indexing/ChangeTrackingValueContainer.java b/platform/lang-impl/src/com/intellij/util/indexing/ChangeTrackingValueContainer.java index 096e77b84ceb..b2a358ebbcf4 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/ChangeTrackingValueContainer.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/ChangeTrackingValueContainer.java @@ -127,7 +127,9 @@ class ChangeTrackingValueContainer extends UpdatableValueContainer newMerged = ((ChangeTrackingValueContainer)fromDisk).getMergedData().copy(); } - if ((myAdded != null || myInvalidated != null) && newMerged.size() > ValueContainerImpl.NUMBER_OF_VALUES_THRESHOLD) { + if ((myAdded != null || myInvalidated != null) && + (newMerged.size() > ValueContainerImpl.NUMBER_OF_VALUES_THRESHOLD || + (myAdded != null && myAdded.size() > ValueContainerImpl.NUMBER_OF_VALUES_THRESHOLD))) { // Calculate file ids that have Value mapped to avoid O(NumberOfValuesInMerged) during removal fileId2ValueMapping = new FileId2ValueMapping(newMerged); } diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java index 3ff4aa000ccd..fe96142f26cf 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java @@ -767,13 +767,15 @@ public class FileBasedIndexImpl extends FileBasedIndex { } } - processValuesImpl(indexId, dataKey, true, restrictToFile, new ValueProcessor() { - @Override - public boolean process(final VirtualFile file, final V value) { - values.add(value); - return true; - } - }, filter, null); + ValueProcessor processor = (file, value) -> { + values.add(value); + return true; + }; + if (restrictToFile != null) { + processValuesInOneFile(indexId, dataKey, restrictToFile, processor, filter); + } else { + processValuesInScope(indexId, dataKey, true, filter, null, processor); + } return values; } @@ -783,13 +785,10 @@ public class FileBasedIndexImpl extends FileBasedIndex { @NotNull K dataKey, @NotNull final GlobalSearchScope filter) { final Set files = new THashSet(); - processValuesImpl(indexId, dataKey, false, null, new ValueProcessor() { - @Override - public boolean process(final VirtualFile file, final V value) { - files.add(file); - return true; - } - }, filter, null); + processValuesInScope(indexId, dataKey, false, filter, null, (file, value) -> { + files.add(file); + return true; + }); return files; } @@ -807,7 +806,40 @@ public class FileBasedIndexImpl extends FileBasedIndex { @NotNull ValueProcessor processor, @NotNull GlobalSearchScope filter, @Nullable IdFilter idFilter) { - return processValuesImpl(indexId, dataKey, false, inFile, processor, filter, idFilter); + return inFile != null + ? processValuesInOneFile(indexId, dataKey, inFile, processor, filter) + : processValuesInScope(indexId, dataKey, false, filter, idFilter, processor); + } + + public interface IdValueProcessor { + /** + * @param fileId the id of the file that the value came from + * @param value a value to process + * @return false if no further processing is needed, true otherwise + */ + boolean process(int fileId, V value); + } + + /** + * Process values for a given index key together with their containing file ids. Note that project is supplied + * only to ensure that all the indices in that project are up to date; there's no guarantee that the processed file ids belong + * to this project. + */ + public boolean processAllValues(@NotNull ID indexId, + @NotNull K key, + @NotNull Project project, + @NotNull IdValueProcessor processor) { + return processValueIterator(indexId, key, null, GlobalSearchScope.allScope(project), valueIt -> { + while (valueIt.hasNext()) { + V value = valueIt.next(); + for (ValueContainer.IntIterator inputIdsIterator = valueIt.getInputIdsIterator(); inputIdsIterator.hasNext(); ) { + if (!processor.process(inputIdsIterator.next(), value)) { + return false; + } + } + } + return true; + }); } @Nullable @@ -854,54 +886,61 @@ public class FileBasedIndexImpl extends FileBasedIndex { return null; } - private boolean processValuesImpl(@NotNull final ID indexId, @NotNull final K dataKey, final boolean ensureValueProcessedOnce, - @Nullable final VirtualFile restrictToFile, @NotNull final ValueProcessor processor, - @NotNull final GlobalSearchScope scope, @Nullable final IdFilter idFilter) { - ThrowableConvertor, Boolean, StorageException> keyProcessor = - index -> { - final ValueContainer container = index.getData(dataKey); + private boolean processValuesInOneFile(@NotNull ID indexId, + @NotNull K dataKey, + @NotNull VirtualFile restrictToFile, + @NotNull ValueProcessor processor, @NotNull GlobalSearchScope scope) { + if (!(restrictToFile instanceof VirtualFileWithId)) return true; - boolean shouldContinue = true; + int restrictedFileId = getFileId(restrictToFile); + return processValueIterator(indexId, dataKey, restrictToFile, scope, valueIt -> { + while (valueIt.hasNext()) { + V value = valueIt.next(); + if (valueIt.getValueAssociationPredicate().contains(restrictedFileId) && !processor.process(restrictToFile, value)) { + return false; + } + } + return true; + }); + } - if (restrictToFile != null) { - if (restrictToFile instanceof VirtualFileWithId) { - final int restrictedFileId = getFileId(restrictToFile); - for (final ValueContainer.ValueIterator valueIt = container.getValueIterator(); valueIt.hasNext(); ) { - final V value = valueIt.next(); - if (valueIt.getValueAssociationPredicate().contains(restrictedFileId)) { - shouldContinue = processor.process(restrictToFile, value); - if (!shouldContinue) { - break; - } - } + private boolean processValuesInScope(@NotNull ID indexId, + @NotNull K dataKey, + boolean ensureValueProcessedOnce, + @NotNull GlobalSearchScope scope, + @Nullable IdFilter idFilter, + @NotNull ValueProcessor processor) { + PersistentFS fs = (PersistentFS)ManagingFS.getInstance(); + IdFilter filter = idFilter != null ? idFilter : projectIndexableFiles(scope.getProject()); + + return processValueIterator(indexId, dataKey, null, scope, valueIt -> { + while (valueIt.hasNext()) { + final V value = valueIt.next(); + for (final ValueContainer.IntIterator inputIdsIterator = valueIt.getInputIdsIterator(); inputIdsIterator.hasNext(); ) { + final int id = inputIdsIterator.next(); + if (filter != null && !filter.containsFileId(id)) continue; + VirtualFile file = IndexInfrastructure.findFileByIdIfCached(fs, id); + if (file != null && scope.accept(file)) { + if (!processor.process(file, value)) { + return false; + } + if (ensureValueProcessedOnce) { + break; // continue with the next value } } } - else { - final PersistentFS fs = (PersistentFS)ManagingFS.getInstance(); - final IdFilter filter = idFilter != null ? idFilter : projectIndexableFiles(scope.getProject()); - VALUES_LOOP: - for (final ValueContainer.ValueIterator valueIt = container.getValueIterator(); valueIt.hasNext(); ) { - final V value = valueIt.next(); - for (final ValueContainer.IntIterator inputIdsIterator = valueIt.getInputIdsIterator(); inputIdsIterator.hasNext(); ) { - final int id = inputIdsIterator.next(); - if (filter != null && !filter.containsFileId(id)) continue; - VirtualFile file = IndexInfrastructure.findFileByIdIfCached(fs, id); - if (file != null && scope.accept(file)) { - shouldContinue = processor.process(file, value); - if (!shouldContinue) { - break VALUES_LOOP; - } - if (ensureValueProcessedOnce) { - break; // continue with the next value - } - } - } - } - } - return shouldContinue; - }; - final Boolean result = processExceptions(indexId, restrictToFile, scope, keyProcessor); + } + return true; + }); + } + + private boolean processValueIterator(@NotNull ID indexId, + @NotNull K dataKey, + @Nullable VirtualFile restrictToFile, + @NotNull GlobalSearchScope scope, + @NotNull Processor> valueProcessor) { + final Boolean result = processExceptions(indexId, restrictToFile, scope, + index -> valueProcessor.process(index.getData(dataKey).getValueIterator())); return result == null || result.booleanValue(); } diff --git a/platform/lang-impl/src/com/intellij/util/indexing/ValueContainerImpl.java b/platform/lang-impl/src/com/intellij/util/indexing/ValueContainerImpl.java index beda46464af9..8e779cb70315 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/ValueContainerImpl.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/ValueContainerImpl.java @@ -21,7 +21,6 @@ import com.intellij.util.SmartList; import com.intellij.util.containers.EmptyIterator; import com.intellij.util.indexing.containers.ChangeBufferingList; import com.intellij.util.indexing.containers.IdSet; -import com.intellij.util.indexing.containers.SortedFileIdSetIterator; import com.intellij.util.io.DataExternalizer; import com.intellij.util.io.DataInputOutputUtil; import gnu.trove.THashMap; @@ -447,11 +446,8 @@ class ValueContainerImpl extends UpdatableValueContainer implement } else { // serialize positive file ids with delta encoding ChangeBufferingList originalInput = (ChangeBufferingList)fileSetObject; - IntIterator intIterator = originalInput.rawIntIterator(); - if (!intIterator.hasAscendingOrder()) { - // remove possible dupes - intIterator = SortedFileIdSetIterator.getTransientIterator(intIterator); - } + IntIterator intIterator = originalInput.sortedIntIterator(); + if (DebugAssertions.DEBUG) DebugAssertions.assertTrue(intIterator.hasAscendingOrder()); if (intIterator.size() == 1) { DataInputOutputUtil.writeINT(out, intIterator.next()); diff --git a/platform/lang-impl/src/com/intellij/util/indexing/containers/ChangeBufferingList.java b/platform/lang-impl/src/com/intellij/util/indexing/containers/ChangeBufferingList.java index d1a7b6734fdd..57512fb4fd4d 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/containers/ChangeBufferingList.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/containers/ChangeBufferingList.java @@ -19,6 +19,8 @@ import com.intellij.util.indexing.DebugAssertions; import com.intellij.util.indexing.ValueContainer; import gnu.trove.TIntProcedure; +import java.util.Arrays; + import static com.intellij.util.indexing.DebugAssertions.EXTRA_SANITY_CHECKS; /** @@ -122,7 +124,6 @@ public class ChangeBufferingList implements Cloneable { if (randomAccessContainer == null) { int someElementsNumberEstimation = length; - int[] minMax = calcMinMax(changes, length); // todo we can check these lengths instead of only relying upon reaching MAX_FILES //int lengthOfBitSet = IdBitSet.sizeInBytes(minMax[1], minMax[0]); @@ -131,7 +132,7 @@ public class ChangeBufferingList implements Cloneable { if (someElementsNumberEstimation < MAX_FILES) { if (!hasRemovals) { if (mayHaveDupes) { - mergeChangesRemovingDupes(); + removingDupesAndSort(); } idSet = new SortedIdSet(currentChanges, length); @@ -144,7 +145,7 @@ public class ChangeBufferingList implements Cloneable { idSet = new IdBitSet(changes, length, 0); copyChanges = false; } else { - idSet = new IdBitSet(minMax, 0); + idSet = new IdBitSet(calcMinMax(changes, length), 0); } } else if (checkSet != null) { idSet = (RandomAccessIntContainer)randomAccessContainer.clone(); @@ -186,15 +187,40 @@ public class ChangeBufferingList implements Cloneable { } } - private void mergeChangesRemovingDupes() { // duplicated ids can be present for some index due to cancellation of indexing for next index - int[] currentChanges = changes; - ValueContainer.IntIterator sorted = SortedFileIdSetIterator.getTransientIterator(new ChangesIterator(currentChanges, length)); - int lastIndex = 0; - while(sorted.hasNext()) { - currentChanges[lastIndex++] = sorted.next(); - } + private void removingDupesAndSort() { // duplicated ids can be present for some index due to cancellation of indexing for next index + final int[] currentChanges = changes; + final int intLength = length; - length = (short)lastIndex; + if (intLength < 250) { // Plain sorting in Arrays works without allocations for small number of elements (see DualPivotQuicksort.QUICKSORT_THRESHOLD) + Arrays.sort(currentChanges, 0, intLength); + boolean hasDupes = false; + + for(int i = 0, max = intLength - 1; i < max; ++i) { + if (currentChanges[i] == currentChanges[i + 1]) { + hasDupes = true; + break; + } + } + + if (hasDupes) { + int ptr = 0; + for(int i = 1; i < intLength; ++i) { + if (currentChanges[i] != currentChanges[ptr]) { + currentChanges[++ptr] = currentChanges[i]; + } + } + length = (short)(ptr + 1); + } + } else { + ValueContainer.IntIterator sorted = + SortedFileIdSetIterator.getTransientIterator(new ChangesIterator(currentChanges, length, false)); + int lastIndex = 0; + while (sorted.hasNext()) { + currentChanges[lastIndex++] = sorted.next(); + } + + length = (short)lastIndex; + } mayHaveDupes = false; } @@ -262,21 +288,22 @@ public class ChangeBufferingList implements Cloneable { if (currentChanges != null) { if (mayHaveDupes) { synchronized (currentChanges) { - if (mayHaveDupes) mergeChangesRemovingDupes(); + if (mayHaveDupes) removingDupesAndSort(); } } - return new ChangesIterator(currentChanges, length); + return new ChangesIterator(currentChanges, length, true); } } return getRandomAccessContainer().intIterator(); } - public ValueContainer.IntIterator rawIntIterator() { - RandomAccessIntContainer intContainer = randomAccessContainer; - if (intContainer == null && !hasRemovals) { - return new ChangesIterator(changes, length); // dupes are possible + public ValueContainer.IntIterator sortedIntIterator() { + ValueContainer.IntIterator intIterator = intIterator(); + + if (!intIterator.hasAscendingOrder()) { + intIterator = SortedFileIdSetIterator.getTransientIterator(intIterator); } - return getRandomAccessContainer().intIterator(); + return intIterator; } public IdSet getCheckSet() { @@ -287,10 +314,12 @@ public class ChangeBufferingList implements Cloneable { private int cursor; private final int length; private final int[] changes; + private final boolean sorted; - ChangesIterator(int[] _changes, int _length) { + ChangesIterator(int[] _changes, int _length, boolean _sorted) { changes = _changes; length = _length; + sorted = _sorted; } @Override @@ -312,12 +341,12 @@ public class ChangeBufferingList implements Cloneable { @Override public boolean hasAscendingOrder() { - return false; + return sorted; } @Override public ValueContainer.IntIterator createCopyInInitialState() { - return new ChangesIterator(changes, length); + return new ChangesIterator(changes, length, sorted); } } } diff --git a/platform/platform-api/src/com/intellij/openapi/fileEditor/TextEditorLocation.java b/platform/platform-api/src/com/intellij/openapi/fileEditor/TextEditorLocation.java index 9477beb04a11..ef1c4ed6dd23 100644 --- a/platform/platform-api/src/com/intellij/openapi/fileEditor/TextEditorLocation.java +++ b/platform/platform-api/src/com/intellij/openapi/fileEditor/TextEditorLocation.java @@ -50,7 +50,7 @@ public class TextEditorLocation implements FileEditorLocation { } @Override - public int compareTo(FileEditorLocation fileEditorLocation) { + public int compareTo(@NotNull FileEditorLocation fileEditorLocation) { TextEditorLocation otherLocation = (TextEditorLocation)fileEditorLocation; if (myEditor != otherLocation.myEditor) { LOG.error("Different editors: " + myEditor + "; and " + otherLocation.myEditor); diff --git a/platform/platform-api/src/com/intellij/openapi/wm/ToolWindow.java b/platform/platform-api/src/com/intellij/openapi/wm/ToolWindow.java index 841b46bf6148..9460fd2c3f36 100644 --- a/platform/platform-api/src/com/intellij/openapi/wm/ToolWindow.java +++ b/platform/platform-api/src/com/intellij/openapi/wm/ToolWindow.java @@ -29,7 +29,7 @@ import java.awt.event.InputEvent; public interface ToolWindow extends BusyObject { - Key SHOW_CONTENT_ICON = new Key("ContentIcon"); + Key SHOW_CONTENT_ICON = new Key<>("ContentIcon"); /** * @exception IllegalStateException if tool window isn't installed. @@ -74,7 +74,7 @@ public interface ToolWindow extends BusyObject { /** * @exception IllegalStateException if tool window isn't installed. */ - void setAnchor(ToolWindowAnchor anchor, @Nullable Runnable runnable); + void setAnchor(@NotNull ToolWindowAnchor anchor, @Nullable Runnable runnable); /** * @exception IllegalStateException if tool window isn't installed. @@ -104,7 +104,7 @@ public interface ToolWindow extends BusyObject { /** * @exception IllegalStateException if tool window isn't installed. */ - void setType(ToolWindowType type, @Nullable Runnable runnable); + void setType(@NotNull ToolWindowType type, @Nullable Runnable runnable); /** * @return window icon. Returns null if window has no icon. diff --git a/platform/platform-api/src/com/intellij/openapi/wm/ToolWindowAnchor.java b/platform/platform-api/src/com/intellij/openapi/wm/ToolWindowAnchor.java index 1628a6f679bf..88f544d237de 100644 --- a/platform/platform-api/src/com/intellij/openapi/wm/ToolWindowAnchor.java +++ b/platform/platform-api/src/com/intellij/openapi/wm/ToolWindowAnchor.java @@ -17,6 +17,7 @@ package com.intellij.openapi.wm; import com.intellij.ide.ui.UISettings; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; import javax.swing.*; @@ -26,9 +27,10 @@ public final class ToolWindowAnchor { public static final ToolWindowAnchor BOTTOM = new ToolWindowAnchor("bottom"); public static final ToolWindowAnchor RIGHT = new ToolWindowAnchor("right"); + @NotNull private final String myText; - private ToolWindowAnchor(@NonNls String text){ + private ToolWindowAnchor(@NonNls @NotNull String text){ myText = text; } @@ -40,6 +42,7 @@ public final class ToolWindowAnchor { return this == TOP || this == BOTTOM; } + @NotNull public static ToolWindowAnchor get(int swingOrientationConstant) { switch(swingOrientationConstant) { case SwingConstants.TOP: @@ -56,12 +59,16 @@ public final class ToolWindowAnchor { } public boolean isSplitVertically() { - return (this == LEFT && !UISettings.getInstance().LEFT_HORIZONTAL_SPLIT) || (this == RIGHT && !UISettings.getInstance().RIGHT_HORIZONTAL_SPLIT); + return this == LEFT && !UISettings.getInstance().LEFT_HORIZONTAL_SPLIT + || this == RIGHT && !UISettings.getInstance().RIGHT_HORIZONTAL_SPLIT; } + @NotNull public static ToolWindowAnchor fromText(String anchor) { for (ToolWindowAnchor a : new ToolWindowAnchor[]{TOP, LEFT, BOTTOM, RIGHT}) { - if (a.myText.equals(anchor)) return a; + if (a.myText.equals(anchor)) { + return a; + } } throw new IllegalArgumentException("Unknown anchor constant: " + anchor); } diff --git a/platform/platform-api/src/com/intellij/openapi/wm/ToolWindowManager.java b/platform/platform-api/src/com/intellij/openapi/wm/ToolWindowManager.java index 8baa090b2af2..96fbb41189ad 100644 --- a/platform/platform-api/src/com/intellij/openapi/wm/ToolWindowManager.java +++ b/platform/platform-api/src/com/intellij/openapi/wm/ToolWindowManager.java @@ -73,7 +73,7 @@ public abstract class ToolWindowManager { public abstract ToolWindow registerToolWindow(@NotNull String id, @NotNull JComponent component, @NotNull ToolWindowAnchor anchor, - Disposable parentDisposable, + @NotNull Disposable parentDisposable, boolean canWorkInDumbMode); /** * @deprecated {@link ToolWindowManager#registerToolWindow(String, boolean, ToolWindowAnchor)} @@ -83,7 +83,7 @@ public abstract class ToolWindowManager { public abstract ToolWindow registerToolWindow(@NotNull String id, @NotNull JComponent component, @NotNull ToolWindowAnchor anchor, - Disposable parentDisposable, + @NotNull Disposable parentDisposable, boolean canWorkInDumbMode, boolean canCloseContents); @@ -91,19 +91,31 @@ public abstract class ToolWindowManager { public abstract ToolWindow registerToolWindow(@NotNull String id, boolean canCloseContent, @NotNull ToolWindowAnchor anchor); @NotNull - public abstract ToolWindow registerToolWindow(@NotNull String id, boolean canCloseContent, @NotNull ToolWindowAnchor anchor, boolean secondary); + public abstract ToolWindow registerToolWindow(@NotNull String id, + boolean canCloseContent, + @NotNull ToolWindowAnchor anchor, + boolean secondary); @NotNull - public abstract ToolWindow registerToolWindow(@NotNull String id, boolean canCloseContent, @NotNull ToolWindowAnchor anchor, Disposable parentDisposable, boolean canWorkInDumbMode); + public abstract ToolWindow registerToolWindow(@NotNull String id, + boolean canCloseContent, + @NotNull ToolWindowAnchor anchor, + @NotNull Disposable parentDisposable, + boolean canWorkInDumbMode); @NotNull - public abstract ToolWindow registerToolWindow(@NotNull String id, boolean canCloseContent, @NotNull ToolWindowAnchor anchor, Disposable parentDisposable, boolean canWorkInDumbMode, boolean secondary); + public abstract ToolWindow registerToolWindow(@NotNull String id, + boolean canCloseContent, + @NotNull ToolWindowAnchor anchor, + @NotNull Disposable parentDisposable, + boolean canWorkInDumbMode, + boolean secondary); @NotNull public ToolWindow registerToolWindow(@NotNull final String id, final boolean canCloseContent, @NotNull final ToolWindowAnchor anchor, - final Disposable parentDisposable) { + @NotNull Disposable parentDisposable) { return registerToolWindow(id, canCloseContent, anchor, parentDisposable, false); } diff --git a/platform/platform-impl/src/com/intellij/designer/LightToolWindow.java b/platform/platform-impl/src/com/intellij/designer/LightToolWindow.java index 7bdb59ea19e2..b1b8a84de370 100644 --- a/platform/platform-impl/src/com/intellij/designer/LightToolWindow.java +++ b/platform/platform-impl/src/com/intellij/designer/LightToolWindow.java @@ -46,9 +46,9 @@ import java.awt.event.*; * @author Alexander Lobas */ public class LightToolWindow extends JPanel { - public static final String LEFT_MIN_KEY = "left"; - public static final String RIGHT_MIN_KEY = "right"; - public static final int MINIMIZE_WIDTH = 25; + static final String LEFT_MIN_KEY = "left"; + static final String RIGHT_MIN_KEY = "right"; + static final int MINIMIZE_WIDTH = 25; private static final String IGNORE_WIDTH_KEY = "ignore_width"; private final LightToolWindowContent myContent; @@ -139,12 +139,14 @@ public class LightToolWindow extends JPanel { add(contentWrapper, BorderLayout.CENTER); addMouseListener(new MouseAdapter() { + @Override public void mouseReleased(final MouseEvent e) { IdeFocusManager.getInstance(myProject).requestFocus(myFocusedComponent, true); } }); addMouseListener(new PopupHandler() { + @Override public void invokePopup(Component component, int x, int y) { showGearPopup(component, x, y); } @@ -167,12 +169,9 @@ public class LightToolWindow extends JPanel { return myAnchor; } }; - myMinimizeButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - myMinimizeButton.setSelected(false); - updateContent(true, true); - } + myMinimizeButton.addActionListener(e -> { + myMinimizeButton.setSelected(false); + updateContent(true, true); }); myMinimizeButton.setBorder(BorderFactory.createEmptyBorder(5, 5, 0, 5)); myMinimizeButton.setFocusable(false); @@ -233,7 +232,7 @@ public class LightToolWindow extends JPanel { } } - public void updateAnchor(ToolWindowAnchor newAnchor) { + void updateAnchor(ToolWindowAnchor newAnchor) { JComponent minimizeParent = myContentSplitter.getInnerComponent(); minimizeParent.putClientProperty(IGNORE_WIDTH_KEY, Boolean.TRUE); @@ -374,7 +373,7 @@ public class LightToolWindow extends JPanel { } private class GearAction extends AnAction { - public GearAction() { + GearAction() { Presentation presentation = getTemplatePresentation(); presentation.setIcon(AllIcons.General.Gear); presentation.setHoveredIcon(AllIcons.General.GearHover); @@ -462,7 +461,7 @@ public class LightToolWindow extends JPanel { } private class ToggleWindowedModeAction extends ToggleTypeModeAction { - public ToggleWindowedModeAction() { + ToggleWindowedModeAction() { super(ToolWindowType.WINDOWED, InternalDecorator.TOGGLE_WINDOWED_MODE_ACTION_ID); } @@ -475,7 +474,7 @@ public class LightToolWindow extends JPanel { private class ToggleTypeModeAction extends ToggleAction { private final ToolWindowType myType; - public ToggleTypeModeAction(ToolWindowType type, String id) { + ToggleTypeModeAction(@NotNull ToolWindowType type, @NotNull String id) { myType = type; copyFrom(ActionManager.getInstance().getAction(id)); } diff --git a/platform/platform-impl/src/com/intellij/ide/actions/SaveDocumentAction.java b/platform/platform-impl/src/com/intellij/ide/actions/SaveDocumentAction.java index 5ad331ae5a67..d63683f09f28 100644 --- a/platform/platform-impl/src/com/intellij/ide/actions/SaveDocumentAction.java +++ b/platform/platform-impl/src/com/intellij/ide/actions/SaveDocumentAction.java @@ -1,17 +1,16 @@ package com.intellij.ide.actions; -import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; -import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.project.DumbAwareAction; /** * @author yole */ -public class SaveDocumentAction extends AnAction { +public class SaveDocumentAction extends DumbAwareAction { @Override public void actionPerformed(AnActionEvent e) { Document doc = getDocument(e); diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/darcula_windows.properties b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/darcula_windows.properties index e633a34e62ee..e28788497193 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/darcula_windows.properties +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/darcula_windows.properties @@ -9,7 +9,7 @@ InternalFrameUI=com.intellij.ide.ui.laf.darcula.ui.DarculaInternalFrameUI InternalFrame.border=com.intellij.ide.ui.laf.darcula.ui.DarculaInternalBorder RootPaneUI=com.intellij.ide.ui.laf.darcula.ui.DarculaRootPaneUI -InternalFrame.closeIcon=AllIcons.Windows.Close -InternalFrame.iconifyIcon=AllIcons.Windows.Iconify -InternalFrame.maximizeIcon=AllIcons.Windows.Maximize -InternalFrame.minimizeIcon=AllIcons.Windows.Minimize +InternalFrame.closeIcon=AllIcons.Windows.CloseInactive +InternalFrame.iconifyIcon=AllIcons.Windows.MinimizeInactive +InternalFrame.maximizeIcon=AllIcons.Windows.MaximizeInactive +InternalFrame.minimizeIcon=AllIcons.Windows.RestoreInactive diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaTitlePane.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaTitlePane.java index 7b86a9c29738..2c91e3b7e546 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaTitlePane.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaTitlePane.java @@ -15,14 +15,18 @@ */ package com.intellij.ide.ui.laf.darcula.ui; +import com.intellij.icons.AllIcons; import com.intellij.ide.DataManager; import com.intellij.openapi.actionSystem.ex.ActionManagerEx; -import com.intellij.openapi.ui.GraphicsConfig; import com.intellij.openapi.wm.impl.IdeMenuBar; import com.intellij.openapi.wm.impl.IdeRootPane; import com.intellij.ui.Gray; import com.intellij.ui.JBColor; -import com.intellij.util.ui.*; +import com.intellij.util.IconUtil; +import com.intellij.util.ui.ImageUtil; +import com.intellij.util.ui.JBDimension; +import com.intellij.util.ui.JBUI; +import com.intellij.util.ui.UIUtil; import org.imgscalr.Scalr; import sun.swing.SwingUtilities2; @@ -293,7 +297,7 @@ public class DarculaTitlePane extends JComponent { menu.add(myCloseAction); } - private static JButton createButton(String accessibleName, Icon icon, Action action) { + private static JButton createButton(String accessibleName, Icon icon, Icon hoverIcon, Action action, Color hoverBg) { JButton button = new JButton() { boolean mouseOverButton = false; { @@ -314,11 +318,11 @@ public class DarculaTitlePane extends JComponent { } @Override protected void paintComponent(Graphics g) { - final Window window = SwingUtilities.windowForComponent(this); - float alpha = window.isActive() && mouseOverButton ? 1f : 0.5f; - final GraphicsConfig config = GraphicsUtil.paintWithAlpha(g, alpha); - getIcon().paintIcon(this, g, 0, 0); - config.restore(); + if (mouseOverButton) { + g.setColor(hoverBg); + g.fillRect(0, 0, getWidth(), getHeight()); + } + IconUtil.paintInCenterOf(this, g, mouseOverButton ? hoverIcon : icon); } }; button.setFocusPainted(false); @@ -334,14 +338,14 @@ public class DarculaTitlePane extends JComponent { } private void createButtons() { - myCloseButton = createButton("Close", UIManager.getIcon("InternalFrame.closeIcon"), myCloseAction); + myCloseButton = createButton("Close", AllIcons.Windows.CloseActive, AllIcons.Windows.CloseHover, myCloseAction, Color.red); if (getWindowDecorationStyle() == JRootPane.FRAME) { myMaximizeIcon = UIManager.getIcon("InternalFrame.maximizeIcon"); myMinimizeIcon = UIManager.getIcon("InternalFrame.minimizeIcon"); - myIconifyButton = createButton("Iconify", UIManager.getIcon("InternalFrame.iconifyIcon"), myIconifyAction); - myToggleButton = createButton("Maximize", myMaximizeIcon, myRestoreAction); + myIconifyButton = createButton("Iconify", AllIcons.Windows.MinimizeInactive, AllIcons.Windows.Minimize, myIconifyAction, new Color(0x55585A)); + myToggleButton = createButton("Maximize", AllIcons.Windows.MaximizeInactive, AllIcons.Windows.MaximizeInactive, myRestoreAction, new Color(0x55585A)); } } @@ -541,14 +545,14 @@ public class DarculaTitlePane extends JComponent { } - int w = width; - int h = height; - h--; + //int w = width; + //int h = height; + //h--; g.setColor(UIManager.getColor("MenuBar.darcula.borderColor")); - g.drawLine(0, h, w, h); - h--; - g.setColor(UIManager.getColor("MenuBar.darcula.borderShadowColor")); - g.drawLine(0, h, w, h); + //g.drawLine(0, h, w, h); + //h--; + //g.setColor(UIManager.getColor("MenuBar.darcula.borderShadowColor")); + g.drawLine(0, getHeight()-1, getWidth(), getHeight()-1); } private class CloseAction extends AbstractAction { @@ -604,7 +608,8 @@ public class DarculaTitlePane extends JComponent { } if (mySystemIcon != null) { - g.drawImage(mySystemIcon, 0, 0, IMAGE_WIDTH, IMAGE_HEIGHT, null); + final int offset = (getHeight() - mySystemIcon.getHeight(null)) / 2; + g.drawImage(mySystemIcon, offset, offset, null); } else { Icon icon = UIManager.getIcon("InternalFrame.icon"); @@ -653,7 +658,7 @@ public class DarculaTitlePane extends JComponent { iconHeight = IMAGE_HEIGHT; } - return Math.max(Math.max(fontHeight, iconHeight), JBUI.scale(myIdeMenu == null ? 28 : 36)); + return Math.max(Math.max(fontHeight, iconHeight), JBUI.scale(31)); } public void layoutContainer(Container c) { @@ -661,17 +666,17 @@ public class DarculaTitlePane extends JComponent { int h = getHeight(); int x; int spacing; - int buttonHeight; - int buttonWidth; + int buttonHeight = JBUI.scale(29); + int buttonWidth = JBUI.scale(45); - if (myCloseButton != null && myCloseButton.getIcon() != null) { - buttonHeight = myCloseButton.getIcon().getIconHeight(); - buttonWidth = myCloseButton.getIcon().getIconWidth(); - } - else { - buttonHeight = IMAGE_HEIGHT; - buttonWidth = IMAGE_WIDTH; - } + //if (myCloseButton != null && myCloseButton.getIcon() != null) { + // buttonHeight = myCloseButton.getIcon().getIconHeight(); + // buttonWidth = myCloseButton.getIcon().getIconWidth(); + //} + //else { + // buttonHeight = IMAGE_HEIGHT; + // buttonWidth = IMAGE_WIDTH; + //} spacing = 5; x = spacing; @@ -679,33 +684,33 @@ public class DarculaTitlePane extends JComponent { myMenuBar.setBounds(x, (h - buttonHeight) / 2, buttonWidth, buttonHeight); } + int systemIconSize = mySystemIcon == null ? JBUI.scale(16) : mySystemIcon.getWidth(null); + + x = buttonHeight - systemIconSize + systemIconSize + systemIconSize/2; // offset + width + offset, where offset is (H - iconHeight) / 2 if (myIdeMenu != null) { final Dimension size = myIdeMenu.getPreferredSize(); - x += spacing + (myMenuBar != null ? buttonWidth : 0); - myIdeMenu.setBounds(x, (h - size.height) / 2, size.width, size.height); } x = w; - spacing = 8; - x += -spacing - buttonWidth; + spacing = 0; + x -= spacing + buttonWidth; if (myCloseButton != null) { myCloseButton.setBounds(x, (h - buttonHeight) / 2, buttonWidth, buttonHeight); } - if (getWindowDecorationStyle() == JRootPane.FRAME) { if (Toolkit.getDefaultToolkit().isFrameStateSupported( Frame.MAXIMIZED_BOTH)) { if (myToggleButton.getParent() != null) { //spacing = 10; - x += -spacing - buttonWidth; + x -= spacing + buttonWidth; myToggleButton.setBounds(x, (h - buttonHeight) / 2, buttonWidth, buttonHeight); } } if (myIconifyButton != null && myIconifyButton.getParent() != null) { - x += -spacing - buttonWidth; + x -= spacing + buttonWidth; myIconifyButton.setBounds(x, (h - buttonHeight) / 2, buttonWidth, buttonHeight); } } @@ -757,7 +762,7 @@ public class DarculaTitlePane extends JComponent { } else if (icons.size() == 1) { mySystemIcon = icons.get(0); } else { - final JBDimension size = JBUI.size(32); + final JBDimension size = JBUI.size(16); final Image image = icons.get(0); mySystemIcon = Scalr.resize(ImageUtil.toBufferedImage(image), Scalr.Method.ULTRA_QUALITY, size.width, size.height); } diff --git a/platform/platform-impl/src/com/intellij/openapi/project/FileContentQueue.java b/platform/platform-impl/src/com/intellij/openapi/project/FileContentQueue.java index d8a822ec3bcc..2ca27bfd6f9c 100644 --- a/platform/platform-impl/src/com/intellij/openapi/project/FileContentQueue.java +++ b/platform/platform-impl/src/com/intellij/openapi/project/FileContentQueue.java @@ -29,6 +29,7 @@ import com.intellij.util.concurrency.AppExecutorUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.io.FileNotFoundException; import java.io.IOException; import java.util.Collection; import java.util.Deque; @@ -156,7 +157,11 @@ public class FileContentQueue { throw (InterruptedException)e; } else if (e instanceof IOException || e instanceof InvalidVirtualFileAccessException) { - LOG.info(e); + if (e instanceof FileNotFoundException) { + LOG.debug(e); // it is possible to not observe file system change until refresh finish, we handle missed file properly anyway + } else { + LOG.info(e); + } } else if (ApplicationManager.getApplication().isUnitTestMode()) { //noinspection CallToPrintStackTrace diff --git a/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectManagerImpl.java index 1899bb294b43..1ec346b95475 100644 --- a/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectManagerImpl.java @@ -314,6 +314,13 @@ public class ProjectManagerImpl extends ProjectManagerEx implements Disposable { } } + for (Project p : myOpenProjects) { + if (ProjectUtil.isSameProject(project.getBasePath(), p)) { + ProjectUtil.focusProjectWindow(p, false); + return false; + } + } + if (!addToOpened(project)) { return false; } @@ -384,19 +391,31 @@ public class ProjectManagerImpl extends ProjectManagerEx implements Disposable { } @Override - public Project loadAndOpenProject(@NotNull final String filePath) throws IOException { - Project project = myProgressManager.run(new Task.WithResult(null, ProjectBundle.message("project.load.progress"), true) { - @Override - protected Project compute(@NotNull ProgressIndicator indicator) throws IOException { - final Project project = convertAndLoadProject(filePath); - if (project == null) { - return null; + public Project loadAndOpenProject(@NotNull final String originalFilePath) throws IOException { + final String filePath = toCanonicalName(originalFilePath); + final ConversionResult conversionResult = ConversionService.getInstance().convert(filePath); + Project project; + if (conversionResult.openingIsCanceled()) { + project = null; + } + else { + project = myProgressManager.run(new Task.WithResult(null, ProjectBundle.message("project.load.progress"), true) { + @Override + protected Project compute(@NotNull ProgressIndicator indicator) throws IOException { + final Project project = loadProjectWithProgress(filePath); + if (project == null) { + return null; + } + + if (!conversionResult.conversionNotNeeded()) { + StartupManager.getInstance(project).registerPostStartupActivity(() -> conversionResult.postStartupActivity(project)); + } + openProject(project); + return project; } + }); + } - openProject(project); - return project; - } - }); if (project == null) { WelcomeFrame.showIfNoProjectOpened(); return null; @@ -423,20 +442,9 @@ public class ProjectManagerImpl extends ProjectManagerEx implements Disposable { return null; } - final Project project; - try { - project = loadProjectWithProgress(filePath); - if (project == null) return null; - } - catch (ProcessCanceledException e) { - return null; - } - catch (Throwable t) { - LOG.info(t); - throw new IOException(t); - } + final Project project = loadProjectWithProgress(filePath); - if (!conversionResult.conversionNotNeeded()) { + if (project != null && !conversionResult.conversionNotNeeded()) { StartupManager.getInstance(project).registerPostStartupActivity(() -> conversionResult.postStartupActivity(project)); } return project; @@ -449,23 +457,26 @@ public class ProjectManagerImpl extends ProjectManagerEx implements Disposable { * @return the project, or null if the user has cancelled opening the project. */ @Nullable - private Project loadProjectWithProgress(@NotNull final String filePath) { - final ProjectImpl project = createProject(null, toCanonicalName(filePath), false); - if (myProgressManager.getProgressIndicator() != null) { - initProject(project, null); - return project; - } + private Project loadProjectWithProgress(@NotNull String filePath) throws IOException { try { + final ProjectImpl project = createProject(null, toCanonicalName(filePath), false); + if (myProgressManager.getProgressIndicator() != null) { + initProject(project, null); + return project; + } myProgressManager.runProcessWithProgressSynchronously((ThrowableComputable)() -> { initProject(project, null); return project; }, ProjectBundle.message("project.load.progress"), canCancelProjectLoading(), project); + return project; } - catch (ProcessCanceledException ignore) { + catch (ProcessCanceledException e) { return null; } - - return project; + catch (Throwable t) { + LOG.info(t); + throw new IOException(t); + } } private static void notifyProjectOpenFailed() { diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/ex/DefaultFrameEditorComponentProvider.java b/platform/platform-impl/src/com/intellij/openapi/wm/ex/DefaultFrameEditorComponentProvider.java index efab9e503b62..96346063e4a4 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/ex/DefaultFrameEditorComponentProvider.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/ex/DefaultFrameEditorComponentProvider.java @@ -2,6 +2,7 @@ package com.intellij.openapi.wm.ex; import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx; import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.NotNull; import javax.swing.*; @@ -10,8 +11,8 @@ import javax.swing.*; */ public class DefaultFrameEditorComponentProvider implements FrameEditorComponentProvider { @Override - public JComponent createEditorComponent(Project project) { + public JComponent createEditorComponent(@NotNull Project project) { FileEditorManagerEx editorManager = FileEditorManagerEx.getInstanceEx(project); - return editorManager.getComponent(); + return editorManager.getComponent(); } } diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/ex/FrameEditorComponentProvider.java b/platform/platform-impl/src/com/intellij/openapi/wm/ex/FrameEditorComponentProvider.java index f6fce90c56ab..5f012185e89e 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/ex/FrameEditorComponentProvider.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/ex/FrameEditorComponentProvider.java @@ -2,14 +2,16 @@ package com.intellij.openapi.wm.ex; import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.NotNull; import javax.swing.*; /** * @author Konstantin Bulenkov */ +@FunctionalInterface public interface FrameEditorComponentProvider { ExtensionPointName EP = ExtensionPointName.create("com.intellij.frameEditorComponentProvider"); - JComponent createEditorComponent(Project project); + JComponent createEditorComponent(@NotNull Project project); } diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/ex/ToolWindowManagerEx.java b/platform/platform-impl/src/com/intellij/openapi/wm/ex/ToolWindowManagerEx.java index d8414ddc37ed..f38d3bab16b2 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/ex/ToolWindowManagerEx.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/ex/ToolWindowManagerEx.java @@ -35,9 +35,9 @@ public abstract class ToolWindowManagerEx extends ToolWindowManager { return (ToolWindowManagerEx)getInstance(project); } - public abstract void addToolWindowManagerListener(@NotNull ToolWindowManagerListener l); - public abstract void addToolWindowManagerListener(@NotNull ToolWindowManagerListener l, @NotNull Disposable parentDisposable); - public abstract void removeToolWindowManagerListener(@NotNull ToolWindowManagerListener l); + public abstract void addToolWindowManagerListener(@NotNull ToolWindowManagerListener listener); + public abstract void addToolWindowManagerListener(@NotNull ToolWindowManagerListener listener, @NotNull Disposable parentDisposable); + public abstract void removeToolWindowManagerListener(@NotNull ToolWindowManagerListener listener); /** * @return ID of tool window that was activated last time. @@ -69,5 +69,6 @@ public abstract class ToolWindowManagerEx extends ToolWindowManager { public abstract void hideToolWindow(@NotNull String id, boolean hideSide); + @NotNull public abstract List getIdsOn(@NotNull ToolWindowAnchor anchor); } diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ActiveStack.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ActiveStack.java index ef8cdf338406..f99d3e221238 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ActiveStack.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ActiveStack.java @@ -15,8 +15,10 @@ */ package com.intellij.openapi.wm.impl; +import com.intellij.util.containers.Stack; +import org.jetbrains.annotations.NotNull; + import java.util.Iterator; -import java.util.Stack; /** * Actually this class represent two stacks. @@ -43,8 +45,8 @@ final class ActiveStack { * Creates enabled window stack. */ ActiveStack() { - myStack = new Stack(); - myPersistentStack = new Stack(); + myStack = new Stack<>(); + myPersistentStack = new Stack<>(); } /** @@ -61,10 +63,12 @@ final class ActiveStack { return myStack.isEmpty(); } + @NotNull String pop() { return myStack.pop(); } + @NotNull String peek() { return myStack.peek(); } @@ -73,10 +77,12 @@ final class ActiveStack { return myStack.size(); } - String peek(int i) { + @NotNull + private String peek(int i) { return myStack.get(getSize() - i - 1); } + @NotNull String[] getStack() { String[] result = new String[getSize()]; for (int i = 0; i < getSize(); i++) { @@ -85,6 +91,7 @@ final class ActiveStack { return result; } + @NotNull String[] getPersistentStack() { String[] result = new String[getPersistentSize()]; for (int i = 0; i < getPersistentSize(); i++) { @@ -93,7 +100,7 @@ final class ActiveStack { return result; } - void push(final String id) { + void push(@NotNull String id) { remove(id, true); myStack.push(id); myPersistentStack.push(id); @@ -106,6 +113,7 @@ final class ActiveStack { /** * Peeks element at the persistent stack. 0 means the top of the stack. */ + @NotNull String peekPersistent(final int index) { return myPersistentStack.get(myPersistentStack.size() - index - 1); } @@ -117,7 +125,7 @@ final class ActiveStack { * @param removePersistentAlso if true then clears last active ID * if it's the last active ID. */ - void remove(final String id, final boolean removePersistentAlso) { + void remove(@NotNull String id, final boolean removePersistentAlso) { for (Iterator i = myStack.iterator(); i.hasNext();) { if (id.equals(i.next())) { i.remove(); diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/DesktopLayout.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/DesktopLayout.java index 62c77fcb1357..a3cc0dea6e31 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/DesktopLayout.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/DesktopLayout.java @@ -36,11 +36,11 @@ public final class DesktopLayout implements JDOMExternalizable { /** * Map between ids and registered WindowInfos. */ - private final Map myRegisteredId2Info; + private final Map myRegisteredId2Info = new HashMap<>(); /** * Map between ids and unregistered WindowInfos. */ - private final Map myUnregisteredId2Info; + private final Map myUnregisteredId2Info = new HashMap<>(); /** * */ @@ -63,19 +63,15 @@ public final class DesktopLayout implements JDOMExternalizable { * if the cached data is invalid. */ private WindowInfoImpl[] myAllInfos; - @NonNls public static final String ID_ATTR = "id"; + @NonNls private static final String ID_ATTR = "id"; - public DesktopLayout() { - myRegisteredId2Info = new HashMap(); - myUnregisteredId2Info = new HashMap(); - } /** * Copies itself from the passed * * @param layout to be copied. */ - public final void copyFrom(final DesktopLayout layout) { + public final void copyFrom(@NotNull DesktopLayout layout) { final WindowInfoImpl[] infos = layout.getAllInfos(); for (WindowInfoImpl info1 : infos) { WindowInfoImpl info = myRegisteredId2Info.get(info1.getId()); @@ -128,7 +124,7 @@ public final class DesktopLayout implements JDOMExternalizable { return info; } - final void unregister(final String id) { + final void unregister(@NotNull String id) { final WindowInfoImpl info = myRegisteredId2Info.remove(id).copy(); myUnregisteredId2Info.put(id, info); // invalidate caches @@ -142,14 +138,12 @@ public final class DesktopLayout implements JDOMExternalizable { * If onlyRegistered is true then returns not null * value if and only if window with id is registered one. */ - final WindowInfoImpl getInfo(final String id, final boolean onlyRegistered) { + final WindowInfoImpl getInfo(String id, final boolean onlyRegistered) { final WindowInfoImpl info = myRegisteredId2Info.get(id); if (onlyRegistered || info != null) { return info; } - else { - return myUnregisteredId2Info.get(id); - } + return myUnregisteredId2Info.get(id); } @Nullable @@ -166,6 +160,7 @@ public final class DesktopLayout implements JDOMExternalizable { /** * @return WindowInfos for all registered tool windows. */ + @NotNull final WindowInfoImpl[] getInfos() { if (myRegisteredInfos == null) { myRegisteredInfos = myRegisteredId2Info.values().toArray(new WindowInfoImpl[myRegisteredId2Info.size()]); @@ -176,6 +171,7 @@ public final class DesktopLayout implements JDOMExternalizable { /** * @return WindowInfoss for all windows that are currently unregistered. */ + @NotNull private WindowInfoImpl[] getUnregisteredInfos() { if (myUnregisteredInfos == null) { myUnregisteredInfos = myUnregisteredId2Info.values().toArray(new WindowInfoImpl[myUnregisteredId2Info.size()]); @@ -186,7 +182,8 @@ public final class DesktopLayout implements JDOMExternalizable { /** * @return WindowInfos of all (registered and unregistered) tool windows. */ - WindowInfoImpl[] getAllInfos() { + @NotNull + private WindowInfoImpl[] getAllInfos() { final WindowInfoImpl[] registeredInfos = getInfos(); final WindowInfoImpl[] unregisteredInfos = getUnregisteredInfos(); myAllInfos = ArrayUtil.mergeArrays(registeredInfos, unregisteredInfos); @@ -197,9 +194,10 @@ public final class DesktopLayout implements JDOMExternalizable { * @return all (registered and not unregistered) WindowInfos for the specified anchor. * Returned infos are sorted by order. */ - private WindowInfoImpl[] getAllInfos(final ToolWindowAnchor anchor) { + @NotNull + private WindowInfoImpl[] getAllInfos(@NotNull ToolWindowAnchor anchor) { WindowInfoImpl[] infos = getAllInfos(); - final ArrayList list = new ArrayList(infos.length); + final ArrayList list = new ArrayList<>(infos.length); for (WindowInfoImpl info : infos) { if (anchor == info.getAnchor()) { list.add(info); @@ -214,7 +212,7 @@ public final class DesktopLayout implements JDOMExternalizable { * Normalizes order of windows in the passed array. Note, that array should be * sorted by order (by ascending). Order of first window will be 0. */ - private static void normalizeOrder(final WindowInfoImpl[] infos) { + private static void normalizeOrder(@NotNull WindowInfoImpl[] infos) { for (int i = 0; i < infos.length; i++) { infos[i].setOrder(i); } @@ -228,7 +226,8 @@ public final class DesktopLayout implements JDOMExternalizable { * @return comparator which compares StripeButtons in the stripe with * specified anchor. */ - final Comparator comparator(final ToolWindowAnchor anchor) { + @NotNull + final Comparator comparator(@NotNull ToolWindowAnchor anchor) { return new MyStripeButtonComparator(anchor); } @@ -237,7 +236,7 @@ public final class DesktopLayout implements JDOMExternalizable { * @return maximum ordinal number in the specified stripe. Returns -1 * if there is no any tool window with the specified anchor. */ - private int getMaxOrder(final ToolWindowAnchor anchor) { + private int getMaxOrder(@NotNull ToolWindowAnchor anchor) { int res = -1; final WindowInfoImpl[] infos = getAllInfos(); for (final WindowInfoImpl info : infos) { @@ -255,7 +254,7 @@ public final class DesktopLayout implements JDOMExternalizable { * @param newAnchor new anchor * @param newOrder new order */ - final void setAnchor(final String id, final ToolWindowAnchor newAnchor, int newOrder) { + final void setAnchor(@NotNull String id, @NotNull ToolWindowAnchor newAnchor, int newOrder) { if (newOrder == -1) { // if order isn't defined then the window will the last in the stripe newOrder = getMaxOrder(newAnchor) + 1; } @@ -279,11 +278,12 @@ public final class DesktopLayout implements JDOMExternalizable { } } - final void setSplitMode(final String id, boolean split) { + final void setSplitMode(@NotNull String id, boolean split) { final WindowInfoImpl info = getInfo(id, true); info.setSplit(split); } + @Override public final void readExternal(final Element layoutElement) { myUnregisteredInfos = null; for (Object o : layoutElement.getChildren()) { @@ -301,6 +301,7 @@ public final class DesktopLayout implements JDOMExternalizable { } } + @Override public final void writeExternal(final Element layoutElement) { final WindowInfoImpl[] infos = getAllInfos(); for (WindowInfoImpl info : infos) { @@ -310,30 +311,30 @@ public final class DesktopLayout implements JDOMExternalizable { } } - public List getVisibleIdsOn(final ToolWindowAnchor anchor, ToolWindowManagerImpl manager) { - ArrayList ids = new ArrayList(); + @NotNull + List getVisibleIdsOn(@NotNull ToolWindowAnchor anchor, @NotNull ToolWindowManagerImpl manager) { + List ids = new ArrayList<>(); for (WindowInfoImpl each : getAllInfos(anchor)) { - if (manager == null) break; - final ToolWindow window = manager.getToolWindow(each.getId()); - if (window == null) continue; - if (window.isAvailable() || UISettings.getInstance().ALWAYS_SHOW_WINDOW_BUTTONS) { - ids.add(each.getId()); - } + final ToolWindow window = manager.getToolWindow(each.getId()); + if (window == null) continue; + if (window.isAvailable() || UISettings.getInstance().ALWAYS_SHOW_WINDOW_BUTTONS) { + ids.add(each.getId()); + } } return ids; } private static final class MyWindowInfoComparator implements Comparator { + @Override public int compare(final WindowInfoImpl info1, final WindowInfoImpl info2) { return info1.getOrder() - info2.getOrder(); } } private final class MyStripeButtonComparator implements Comparator { - private final HashMap myId2Info; + private final HashMap myId2Info = new HashMap<>(); - public MyStripeButtonComparator(final ToolWindowAnchor anchor) { - myId2Info = new HashMap(); + public MyStripeButtonComparator(@NotNull ToolWindowAnchor anchor) { final WindowInfoImpl[] infos = getInfos(); for (final WindowInfoImpl info : infos) { if (anchor == info.getAnchor()) { @@ -342,6 +343,7 @@ public final class DesktopLayout implements JDOMExternalizable { } } + @Override public final int compare(final StripeButton obj1, final StripeButton obj2) { final WindowInfoImpl info1 = myId2Info.get(obj1.getWindowInfo().getId()); final int order1 = info1 != null ? info1.getOrder() : 0; diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/FloatingDecorator.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/FloatingDecorator.java index dabd6ada57f2..c3d0bc2f54fb 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/FloatingDecorator.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/FloatingDecorator.java @@ -28,6 +28,7 @@ import com.intellij.ui.JBColor; import com.intellij.ui.ScreenUtil; import com.intellij.util.Alarm; import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.NotNull; import javax.swing.*; import java.awt.*; @@ -66,7 +67,7 @@ public final class FloatingDecorator extends JDialog { private float myEndRatio; // start and end alpha ratio for transparency animation - FloatingDecorator(final IdeFrameImpl owner,final WindowInfoImpl info,final InternalDecorator internalDecorator){ + FloatingDecorator(final IdeFrameImpl owner, @NotNull WindowInfoImpl info, @NotNull InternalDecorator internalDecorator){ super(owner,internalDecorator.getToolWindow().getId()); MnemonicHelper.init(getContentPane()); myInternalDecorator=internalDecorator; @@ -154,7 +155,7 @@ public final class FloatingDecorator extends JDialog { super.dispose(); } - final void apply(final WindowInfoImpl info){ + final void apply(@NotNull WindowInfoImpl info){ LOG.assertTrue(info.isFloating()); myInfo=info; // Set alpha mode 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 2dcec6aed305..a214765244fa 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 @@ -116,7 +116,7 @@ public final class InternalDecorator extends JPanel implements Queryable, DataPr } @Override - protected void toolWindowTypeChanged(ToolWindowType type) { + protected void toolWindowTypeChanged(@NotNull ToolWindowType type) { fireTypeChanged(type); } @@ -214,7 +214,7 @@ public final class InternalDecorator extends JPanel implements Queryable, DataPr myProject = null; } - private void fireAnchorChanged(ToolWindowAnchor anchor) { + private void fireAnchorChanged(@NotNull ToolWindowAnchor anchor) { myDispatcher.getMulticaster().anchorChanged(this, anchor); } @@ -243,7 +243,7 @@ public final class InternalDecorator extends JPanel implements Queryable, DataPr myDispatcher.getMulticaster().activated(this); } - private void fireTypeChanged(ToolWindowType type) { + private void fireTypeChanged(@NotNull ToolWindowType type) { myDispatcher.getMulticaster().typeChanged(this, type); } @@ -255,7 +255,7 @@ public final class InternalDecorator extends JPanel implements Queryable, DataPr myDispatcher.getMulticaster().sideStatusChanged(this, isSide); } - private void fireContentUiTypeChanges(ToolWindowContentUiType type) { + private void fireContentUiTypeChanges(@NotNull ToolWindowContentUiType type) { myDispatcher.getMulticaster().contentUiTypeChanges(this, type); } @@ -512,9 +512,9 @@ public final class InternalDecorator extends JPanel implements Queryable, DataPr } private final class ChangeAnchorAction extends AnAction implements DumbAware { - private final ToolWindowAnchor myAnchor; + @NotNull private final ToolWindowAnchor myAnchor; - public ChangeAnchorAction(final String title, final ToolWindowAnchor anchor) { + public ChangeAnchorAction(@NotNull String title, @NotNull ToolWindowAnchor anchor) { super(title); myAnchor = anchor; } diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/InternalDecoratorListener.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/InternalDecoratorListener.java index b59657225a06..38bba5916e71 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/InternalDecoratorListener.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/InternalDecoratorListener.java @@ -27,23 +27,23 @@ import java.util.EventListener; */ interface InternalDecoratorListener extends EventListener{ - public void anchorChanged(InternalDecorator source,ToolWindowAnchor anchor); + void anchorChanged(@NotNull InternalDecorator source, @NotNull ToolWindowAnchor anchor); - public void autoHideChanged(InternalDecorator source,boolean autoHide); + void autoHideChanged(@NotNull InternalDecorator source, boolean autoHide); - public void hidden(InternalDecorator source); + void hidden(@NotNull InternalDecorator source); - public void hiddenSide(InternalDecorator source); + void hiddenSide(@NotNull InternalDecorator source); - public void resized(InternalDecorator source); + void resized(@NotNull InternalDecorator source); - public void activated(InternalDecorator source); + void activated(@NotNull InternalDecorator source); - public void typeChanged(InternalDecorator source,ToolWindowType type); + void typeChanged(@NotNull InternalDecorator source, @NotNull ToolWindowType type); - public void sideStatusChanged(InternalDecorator source,boolean isSideTool); + void sideStatusChanged(@NotNull InternalDecorator source, boolean isSideTool); - public void contentUiTypeChanges(InternalDecorator sources, @NotNull ToolWindowContentUiType type); + void contentUiTypeChanges(@NotNull InternalDecorator sources, @NotNull ToolWindowContentUiType type); - public void visibleStripeButtonChanged(InternalDecorator source, boolean visible); + void visibleStripeButtonChanged(@NotNull InternalDecorator source, boolean visible); } diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/Stripe.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/Stripe.java index 53124343ae01..a381b93e5168 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/Stripe.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/Stripe.java @@ -28,6 +28,7 @@ import com.intellij.ui.ColorUtil; import com.intellij.ui.Gray; import com.intellij.ui.ScreenUtil; import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.NotNull; import javax.swing.*; import javax.swing.border.Border; @@ -166,7 +167,7 @@ final class Stripe extends JPanel implements UISettingsListener { super.removeNotify(); } - void addButton(final StripeButton button, final Comparator comparator) { + void addButton(@NotNull StripeButton button, final Comparator comparator) { myPrefSize = null; myButtons.add(button); Collections.sort(myButtons, comparator); @@ -174,7 +175,7 @@ final class Stripe extends JPanel implements UISettingsListener { revalidate(); } - void removeButton(final StripeButton button) { + void removeButton(@NotNull StripeButton button) { myPrefSize = null; myButtons.remove(button); remove(button); @@ -475,7 +476,7 @@ final class Stripe extends JPanel implements UISettingsListener { } } - public boolean containsScreen(final Rectangle screenRec) { + public boolean containsScreen(@NotNull Rectangle screenRec) { final Point point = screenRec.getLocation(); SwingUtilities.convertPointFromScreen(point, this); return new Rectangle(point, screenRec.getSize()).intersects( 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 66633a9f6d83..dc3c222572be 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 @@ -49,7 +49,6 @@ import javax.swing.plaf.PanelUI; import java.awt.*; import java.awt.event.*; import java.awt.image.BufferedImage; -import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.List; @@ -74,7 +73,7 @@ public abstract class ToolWindowHeader extends JPanel implements Disposable, UIS private final DefaultActionGroup myActionGroup = new DefaultActionGroup(); private List myVisibleActions = ContainerUtil.newArrayListWithCapacity(2); - public ToolWindowHeader(final ToolWindowImpl toolWindow, @NotNull WindowInfoImpl info, @NotNull final Producer gearProducer) { + ToolWindowHeader(final ToolWindowImpl toolWindow, @NotNull WindowInfoImpl info, @NotNull final Producer gearProducer) { setLayout(new BorderLayout()); myToolWindow = toolWindow; @@ -89,7 +88,7 @@ public abstract class ToolWindowHeader extends JPanel implements Disposable, UIS Component c = getComponent(0); Dimension size = c.getPreferredSize(); - if (size.width < (r.width - insets.left - insets.right)) { + if (size.width < r.width - insets.left - insets.right) { c.setBounds(insets.left, insets.top, size.width, r.height - insets.top - insets.bottom); } else { c.setBounds(insets.left, insets.top, r.width - insets.left - insets.right, r.height - insets.top - insets.bottom); @@ -170,6 +169,7 @@ public abstract class ToolWindowHeader extends JPanel implements Disposable, UIS myButtonPanel = eastPanel; westPanel.addMouseListener(new PopupHandler() { + @Override public void invokePopup(final Component comp, final int x, final int y) { toolWindow.getContentUI().showContextMenu(comp, x, y, toolWindow.getPopupGroup(), toolWindow.getContentManager().getSelectedContent()); } @@ -182,6 +182,7 @@ public abstract class ToolWindowHeader extends JPanel implements Disposable, UIS }); addMouseListener(new MouseAdapter() { + @Override public void mouseReleased(final MouseEvent e) { if (!e.isPopupTrigger()) { if (UIUtil.isCloseClick(e, MouseEvent.MOUSE_RELEASED)) { @@ -227,7 +228,7 @@ public abstract class ToolWindowHeader extends JPanel implements Disposable, UIS @Override public void mouseReleased(final MouseEvent e) { Runnable runnable = - () -> ToolWindowHeader.this.dispatchEvent(SwingUtilities.convertMouseEvent(e.getComponent(), e, ToolWindowHeader.this)); + () -> dispatchEvent(SwingUtilities.convertMouseEvent(e.getComponent(), e, ToolWindowHeader.this)); //noinspection SSBasedInspection SwingUtilities.invokeLater(runnable); } @@ -253,7 +254,7 @@ public abstract class ToolWindowHeader extends JPanel implements Disposable, UIS myInfo = null; } - public void setAdditionalTitleActions(AnAction[] actions) { + void setAdditionalTitleActions(AnAction[] actions) { myActionGroup.removeAll(); myActionGroup.addAll(actions); myUpdater.updateActions(false, true); @@ -300,7 +301,7 @@ public abstract class ToolWindowHeader extends JPanel implements Disposable, UIS if (anchor == ToolWindowAnchor.BOTTOM) { return AllIcons.General.HideDownPart; } - else if (anchor == ToolWindowAnchor.RIGHT) { + if (anchor == ToolWindowAnchor.RIGHT) { return AllIcons.General.HideRightPart; } @@ -312,7 +313,7 @@ public abstract class ToolWindowHeader extends JPanel implements Disposable, UIS if (anchor == ToolWindowAnchor.BOTTOM) { return AllIcons.General.HideDown; } - else if (anchor == ToolWindowAnchor.RIGHT) { + if (anchor == ToolWindowAnchor.RIGHT) { return AllIcons.General.HideRight; } @@ -324,7 +325,7 @@ public abstract class ToolWindowHeader extends JPanel implements Disposable, UIS if (anchor == ToolWindowAnchor.BOTTOM) { return AllIcons.General.HideDownPartHover; } - else if (anchor == ToolWindowAnchor.RIGHT) { + if (anchor == ToolWindowAnchor.RIGHT) { return AllIcons.General.HideRightPartHover; } @@ -336,7 +337,7 @@ public abstract class ToolWindowHeader extends JPanel implements Disposable, UIS if (anchor == ToolWindowAnchor.BOTTOM) { return AllIcons.General.HideDownHover; } - else if (anchor == ToolWindowAnchor.RIGHT) { + if (anchor == ToolWindowAnchor.RIGHT) { return AllIcons.General.HideRightHover; } @@ -419,7 +420,7 @@ public abstract class ToolWindowHeader extends JPanel implements Disposable, UIS protected abstract void sideHidden(); - protected abstract void toolWindowTypeChanged(ToolWindowType type); + protected abstract void toolWindowTypeChanged(@NotNull ToolWindowType type); @Override public Dimension getPreferredSize() { @@ -468,18 +469,15 @@ public abstract class ToolWindowHeader extends JPanel implements Disposable, UIS setIcon(getActiveIcon(), getInactiveIcon() == null ? getActiveIcon() : getInactiveIcon(), getActiveHoveredIcon()); - PropertyChangeListener listener = new PropertyChangeListener() { - @Override - public void propertyChange(PropertyChangeEvent evt) { - if (myAlternativeAction == null) return; - if ("ancestor".equals(evt.getPropertyName())) { - if (evt.getNewValue() == null) { - AltStateManager.getInstance().removeListener(ActionButton.this); - switchAlternativeAction(false); - } - else { - AltStateManager.getInstance().addListener(ActionButton.this); - } + PropertyChangeListener listener = evt -> { + if (myAlternativeAction == null) return; + if ("ancestor".equals(evt.getPropertyName())) { + if (evt.getNewValue() == null) { + AltStateManager.getInstance().removeListener(this); + switchAlternativeAction(false); + } + else { + AltStateManager.getInstance().addListener(this); } } }; @@ -487,7 +485,7 @@ public abstract class ToolWindowHeader extends JPanel implements Disposable, UIS addPropertyChangeListener(listener); } - public void updateTooltip() { + void updateTooltip() { myButton.setToolTipText(getToolTipTextByAction(myCurrentAction)); } @@ -533,6 +531,7 @@ public abstract class ToolWindowHeader extends JPanel implements Disposable, UIS this(action, activeIcon, activeIcon); } + @Override public void actionPerformed(final ActionEvent e) { AnAction action = myAlternativeAction != null && BitUtil.isSet(e.getModifiers(), InputEvent.ALT_MASK) ? myAlternativeAction : myAction; @@ -557,6 +556,7 @@ public abstract class ToolWindowHeader extends JPanel implements Disposable, UIS myButton.setIcons(active, inactive, hovered); } + @Override public void setToolTipText(final String text) { myButton.setToolTipText(text); } @@ -588,15 +588,17 @@ public abstract class ToolWindowHeader extends JPanel implements Disposable, UIS } private abstract class HideSideAction extends AnAction implements DumbAware { - @NonNls public static final String HIDE_ACTIVE_SIDE_WINDOW_ACTION_ID = ToolWindowHeader.HIDE_ACTIVE_SIDE_WINDOW_ACTION_ID; + @NonNls static final String HIDE_ACTIVE_SIDE_WINDOW_ACTION_ID = ToolWindowHeader.HIDE_ACTIVE_SIDE_WINDOW_ACTION_ID; public HideSideAction() { copyFrom(ActionManager.getInstance().getAction(HIDE_ACTIVE_SIDE_WINDOW_ACTION_ID)); getTemplatePresentation().setText(UIBundle.message("tool.window.hideSide.action.name")); } + @Override public abstract void actionPerformed(@NotNull final AnActionEvent e); + @Override public final void update(@NotNull final AnActionEvent event) { final Presentation presentation = event.getPresentation(); presentation.setEnabled(myInfo.isVisible()); @@ -604,13 +606,14 @@ public abstract class ToolWindowHeader extends JPanel implements Disposable, UIS } private abstract class HideAction extends AnAction implements DumbAware { - @NonNls public static final String HIDE_ACTIVE_WINDOW_ACTION_ID = ToolWindowHeader.HIDE_ACTIVE_WINDOW_ACTION_ID; + @NonNls static final String HIDE_ACTIVE_WINDOW_ACTION_ID = ToolWindowHeader.HIDE_ACTIVE_WINDOW_ACTION_ID; public HideAction() { copyFrom(ActionManager.getInstance().getAction(HIDE_ACTIVE_WINDOW_ACTION_ID)); getTemplatePresentation().setText(UIBundle.message("tool.window.hide.action.name")); } + @Override 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/ToolWindowHeadlessManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowHeadlessManagerImpl.java index 3c89e2642939..29f8cbeae9ca 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowHeadlessManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowHeadlessManagerImpl.java @@ -53,9 +53,9 @@ import java.beans.PropertyChangeListener; import java.util.*; import java.util.List; -@SuppressWarnings({"ConstantConditions"}) +@SuppressWarnings("ConstantConditions") public class ToolWindowHeadlessManagerImpl extends ToolWindowManagerEx { - private final Map myToolWindows = new HashMap(); + private final Map myToolWindows = new HashMap<>(); private final Project myProject; public ToolWindowHeadlessManagerImpl(Project project) { @@ -75,12 +75,7 @@ public class ToolWindowHeadlessManagerImpl extends ToolWindowManagerEx { MockToolWindow tw = new MockToolWindow(myProject); myToolWindows.put(id, tw); if (parentDisposable != null) { - Disposer.register(parentDisposable, new Disposable() { - @Override - public void dispose() { - unregisterToolWindow(id); - } - }); + Disposer.register(parentDisposable, () -> unregisterToolWindow(id)); } return tw; } @@ -90,7 +85,7 @@ public class ToolWindowHeadlessManagerImpl extends ToolWindowManagerEx { public ToolWindow registerToolWindow(@NotNull String id, @NotNull JComponent component, @NotNull ToolWindowAnchor anchor, - Disposable parentDisposable, + @NotNull Disposable parentDisposable, boolean canWorkInDumbMode) { return doRegisterToolWindow(id, parentDisposable); } @@ -106,7 +101,7 @@ public class ToolWindowHeadlessManagerImpl extends ToolWindowManagerEx { public ToolWindow registerToolWindow(@NotNull String id, @NotNull JComponent component, @NotNull ToolWindowAnchor anchor, - Disposable parentDisposable, + @NotNull Disposable parentDisposable, boolean canWorkInDumbMode, boolean canCloseContents) { return doRegisterToolWindow(id, parentDisposable); @@ -139,7 +134,7 @@ public class ToolWindowHeadlessManagerImpl extends ToolWindowManagerEx { @NotNull @Override public ToolWindow registerToolWindow(@NotNull final String id, final boolean canCloseContent, @NotNull final ToolWindowAnchor anchor, - final Disposable parentDisposable, final boolean dumbAware) { + @NotNull final Disposable parentDisposable, final boolean dumbAware) { return doRegisterToolWindow(id, parentDisposable); } @@ -148,7 +143,7 @@ public class ToolWindowHeadlessManagerImpl extends ToolWindowManagerEx { public ToolWindow registerToolWindow(@NotNull String id, boolean canCloseContent, @NotNull ToolWindowAnchor anchor, - Disposable parentDisposable, + @NotNull Disposable parentDisposable, boolean canWorkInDumbMode, boolean secondary) { return doRegisterToolWindow(id, parentDisposable); @@ -222,16 +217,16 @@ public class ToolWindowHeadlessManagerImpl extends ToolWindowManagerEx { } @Override - public void addToolWindowManagerListener(@NotNull ToolWindowManagerListener l) { + public void addToolWindowManagerListener(@NotNull ToolWindowManagerListener listener) { } @Override - public void addToolWindowManagerListener(@NotNull ToolWindowManagerListener l, @NotNull Disposable parentDisposable) { + public void addToolWindowManagerListener(@NotNull ToolWindowManagerListener listener, @NotNull Disposable parentDisposable) { } @Override - public void removeToolWindowManagerListener(@NotNull ToolWindowManagerListener l) { + public void removeToolWindowManagerListener(@NotNull ToolWindowManagerListener listener) { } @Override @@ -270,9 +265,10 @@ public class ToolWindowHeadlessManagerImpl extends ToolWindowManagerEx { public void hideToolWindow(@NotNull final String id, final boolean hideSide) { } + @NotNull @Override public List getIdsOn(@NotNull final ToolWindowAnchor anchor) { - return new ArrayList(); + return new ArrayList<>(); } public static class MockToolWindow implements ToolWindowEx { @@ -330,7 +326,7 @@ public class ToolWindowHeadlessManagerImpl extends ToolWindowManagerEx { } @Override - public void setAnchor(ToolWindowAnchor anchor, @Nullable Runnable runnable) { + public void setAnchor(@NotNull ToolWindowAnchor anchor, @Nullable Runnable runnable) { } @Override @@ -367,7 +363,7 @@ public class ToolWindowHeadlessManagerImpl extends ToolWindowManagerEx { } @Override - public void setType(ToolWindowType type, @Nullable Runnable runnable) { + public void setType(@NotNull ToolWindowType type, @Nullable Runnable runnable) { } @Override @@ -500,7 +496,7 @@ public class ToolWindowHeadlessManagerImpl extends ToolWindowManagerEx { private static class MockContentManager implements ContentManager { private final EventDispatcher myDispatcher = EventDispatcher.create(ContentManagerListener.class); - private final List myContents = new ArrayList(); + private final List myContents = new ArrayList<>(); private Content mySelected; @NotNull diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowImpl.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowImpl.java index d58f6ce9a646..c97831818eec 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowImpl.java @@ -60,11 +60,11 @@ import java.util.Set; * @author Vladimir Kondratyev */ public final class ToolWindowImpl implements ToolWindowEx { - private final PropertyChangeSupport myChangeSupport; + private final PropertyChangeSupport myChangeSupport = new PropertyChangeSupport(this); private final ToolWindowManagerImpl myToolWindowManager; private final String myId; private final JComponent myComponent; - private boolean myAvailable; + private boolean myAvailable = true; private final ContentManager myContentManager; private Icon myIcon; private String myStripeTitle; @@ -74,18 +74,18 @@ public final class ToolWindowImpl implements ToolWindowEx { private InternalDecorator myDecorator; - private boolean myHideOnEmptyContent = false; + private boolean myHideOnEmptyContent; private boolean myPlaceholderMode; private ToolWindowFactory myContentFactory; - private static Set FORWARD_TRAVERSAL_KEYSTROKES = new HashSet(Arrays.asList( - new KeyStroke[] { + private static final Set FORWARD_TRAVERSAL_KEYSTROKES = new HashSet<>(Arrays.asList( + new KeyStroke[]{ KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0) } )); - private static Set BACKWARD_TRAVERSAL_KEYSTROKES = new HashSet(Arrays.asList( - new KeyStroke[] { + private static final Set BACKWARD_TRAVERSAL_KEYSTROKES = new HashSet<>(Arrays.asList( + new KeyStroke[]{ KeyStroke.getKeyStroke(KeyEvent.VK_TAB, InputEvent.SHIFT_DOWN_MASK) } )); @@ -102,16 +102,13 @@ public final class ToolWindowImpl implements ToolWindowEx { private static final Logger LOG = Logger.getInstance(ToolWindowImpl.class); - ToolWindowImpl(final ToolWindowManagerImpl toolWindowManager, final String id, boolean canCloseContent, @Nullable final JComponent component) { + ToolWindowImpl(@NotNull ToolWindowManagerImpl toolWindowManager, @NotNull String id, boolean canCloseContent, @Nullable final JComponent component) { myToolWindowManager = toolWindowManager; - myChangeSupport = new PropertyChangeSupport(this); myId = id; - myAvailable = true; final ContentFactory contentFactory = ServiceManager.getService(ContentFactory.class); myContentUI = new ToolWindowContentUi(this); - myContentManager = - contentFactory.createContentManager(myContentUI, canCloseContent, toolWindowManager.getProject()); + myContentManager = contentFactory.createContentManager(myContentUI, canCloseContent, toolWindowManager.getProject()); if (component != null) { final Content content = contentFactory.createContent(component, "", false); @@ -224,7 +221,7 @@ public final class ToolWindowImpl implements ToolWindowEx { public ActionCallback getReady(@NotNull final Object requestor) { final ActionCallback result = new ActionCallback(); myShowing.getReady(this).doWhenDone(() -> { - ArrayList cmd = new ArrayList(); + ArrayList cmd = new ArrayList<>(); cmd.add(new FinalizableCommand(null) { @Override public void run() { @@ -268,7 +265,7 @@ public final class ToolWindowImpl implements ToolWindowEx { } @Override - public final void setAnchor(final ToolWindowAnchor anchor, @Nullable final Runnable runnable) { + public final void setAnchor(@NotNull final ToolWindowAnchor anchor, @Nullable final Runnable runnable) { ApplicationManager.getApplication().assertIsDispatchThread(); myToolWindowManager.setToolWindowAnchor(myId, anchor); if (runnable != null) { @@ -330,7 +327,7 @@ public final class ToolWindowImpl implements ToolWindowEx { } @Override - public final void setType(final ToolWindowType type, @Nullable final Runnable runnable) { + public final void setType(@NotNull final ToolWindowType type, @Nullable final Runnable runnable) { ApplicationManager.getApplication().assertIsDispatchThread(); myToolWindowManager.setToolWindowType(myId, type); if (runnable != null) { @@ -416,6 +413,7 @@ public final class ToolWindowImpl implements ToolWindowEx { //return getSelectedContent().getIcon(); } + @NotNull public final String getId() { return myId; } @@ -531,11 +529,11 @@ public final class ToolWindowImpl implements ToolWindowEx { return myContentManager.isDisposed(); } - public boolean isPlaceholderMode() { + boolean isPlaceholderMode() { return myPlaceholderMode; } - public void setPlaceholderMode(final boolean placeholderMode) { + void setPlaceholderMode(final boolean placeholderMode) { myPlaceholderMode = placeholderMode; } @@ -546,7 +544,7 @@ public final class ToolWindowImpl implements ToolWindowEx { } @NotNull - public ActionCallback setActivation(@NotNull ActionCallback activation) { + ActionCallback setActivation(@NotNull ActionCallback activation) { if (!myActivation.isProcessed() && !myActivation.equals(activation)) { myActivation.setRejected(); } diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java index 977407222522..1fcbb33e3af1 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java @@ -95,26 +95,26 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements private final Project myProject; private final WindowManagerEx myWindowManager; private final EventDispatcher myDispatcher = EventDispatcher.create(ToolWindowManagerListener.class); - private final DesktopLayout myLayout; - private final Map myId2InternalDecorator; - private final Map myId2FloatingDecorator; - private final Map myId2WindowedDecorator; - private final Map myId2StripeButton; - private final Map myId2FocusWatcher; + private final DesktopLayout myLayout = new DesktopLayout(); + private final Map myId2InternalDecorator = new HashMap<>(); + private final Map myId2FloatingDecorator = new HashMap<>(); + private final Map myId2WindowedDecorator = new HashMap<>(); + private final Map myId2StripeButton = new HashMap<>(); + private final Map myId2FocusWatcher = new HashMap<>(); private final Set myDumbAwareIds = Collections.synchronizedSet(ContainerUtil.newTroveSet()); - private final EditorComponentFocusWatcher myEditorComponentFocusWatcher; - private final MyToolWindowPropertyChangeListener myToolWindowPropertyChangeListener; - private final InternalDecoratorListener myInternalDecoratorListener; + private final EditorComponentFocusWatcher myEditorComponentFocusWatcher = new EditorComponentFocusWatcher(); + private final MyToolWindowPropertyChangeListener myToolWindowPropertyChangeListener = new MyToolWindowPropertyChangeListener(); + private final InternalDecoratorListener myInternalDecoratorListener = new MyInternalDecoratorListener(); private boolean myEditorWasActive; - private final ActiveStack myActiveStack; - private final SideStack mySideStack; + private final ActiveStack myActiveStack = new ActiveStack(); + private final SideStack mySideStack = new SideStack(); private ToolWindowsPane myToolWindowsPane; private IdeFrameImpl myFrame; - private DesktopLayout myLayoutToRestoreLater = null; + private DesktopLayout myLayoutToRestoreLater; @NonNls private static final String EDITOR_ELEMENT = "editor"; @NonNls private static final String ACTIVE_ATTR_VALUE = "active"; @NonNls private static final String FRAME_ELEMENT = "frame"; @@ -127,8 +127,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements private final FileEditorManager myFileEditorManager; private final LafManager myLafManager; - private final Map myWindow2Balloon = new HashMap(); - private Pair myMaximizedToolwindowSize = null; + private final Map myWindow2Balloon = new HashMap<>(); private KeyState myCurrentState = KeyState.waiting; private final Alarm myWaiterForSecondPress = new Alarm(); @@ -139,7 +138,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements }; private final PropertyChangeListener myFocusListener; - public boolean isToolWindowRegistered(String id) { + boolean isToolWindowRegistered(@NotNull String id) { return myLayout.isToolWindowRegistered(id); } @@ -148,7 +147,6 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements } private final Alarm myUpdateHeadersAlarm = new Alarm(); - private final Runnable myUpdateHeadersRunnable = () -> updateToolWindowHeaders(); /** * invoked by reflection @@ -182,22 +180,8 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements }, project); } - myLayout = new DesktopLayout(); myLayout.copyFrom(windowManagerEx.getLayout()); - myId2InternalDecorator = new HashMap(); - myId2FloatingDecorator = new HashMap(); - myId2WindowedDecorator = new HashMap(); - myId2StripeButton = new HashMap(); - myId2FocusWatcher = new HashMap(); - - myEditorComponentFocusWatcher = new EditorComponentFocusWatcher(); - myToolWindowPropertyChangeListener = new MyToolWindowPropertyChangeListener(); - myInternalDecoratorListener = new MyInternalDecoratorListener(); - - myActiveStack = new ActiveStack(); - mySideStack = new SideStack(); - project.getMessageBus().connect().subscribe(FileEditorManagerListener.FILE_EDITOR_MANAGER, new FileEditorManagerListener() { @Override public void fileOpened(@NotNull FileEditorManager source, @NotNull VirtualFile file) { @@ -220,13 +204,10 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements } }); - myFocusListener = new PropertyChangeListener() { - @Override - public void propertyChange(PropertyChangeEvent evt) { - if ("focusOwner".equals(evt.getPropertyName())) { - myUpdateHeadersAlarm.cancelAllRequests(); - myUpdateHeadersAlarm.addRequest(myUpdateHeadersRunnable, 50); - } + myFocusListener = evt -> { + if ("focusOwner".equals(evt.getPropertyName())) { + myUpdateHeadersAlarm.cancelAllRequests(); + myUpdateHeadersAlarm.addRequest(this::updateToolWindowHeaders, 50); } }; KeyboardFocusManager.getCurrentKeyboardFocusManager().addPropertyChangeListener(myFocusListener); @@ -253,7 +234,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements }); } - public boolean dispatchKeyEvent(KeyEvent e) { + public boolean dispatchKeyEvent(@NotNull KeyEvent e) { if (e.getKeyCode() != KeyEvent.VK_CONTROL && e.getKeyCode() != KeyEvent.VK_ALT && e.getKeyCode() != KeyEvent.VK_SHIFT && @@ -299,8 +280,9 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements return false; } - public static Set getActivateToolWindowVKs() { - if (ApplicationManager.getApplication() == null) return new HashSet(); + @NotNull + private static Set getActivateToolWindowVKs() { + if (ApplicationManager.getApplication() == null) return new HashSet<>(); Keymap keymap = KeymapManager.getInstance().getActiveKeymap(); Shortcut[] baseShortcut = keymap.getShortcuts("ActivateProjectToolWindow"); @@ -373,7 +355,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements @Override public void disposeComponent() { - for (String id : new ArrayList(myId2StripeButton.keySet())) { + for (String id : new ArrayList<>(myId2StripeButton.keySet())) { unregisterToolWindow(id); } @@ -390,21 +372,17 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements UIManager.addPropertyChangeListener(uiManagerPropertyListener); myLafManager.addLafManagerListener(lafManagerListener); - Disposer.register(myProject, new Disposable() { - @Override - public void dispose() { - UIManager.removePropertyChangeListener(uiManagerPropertyListener); - myLafManager.removeLafManagerListener(lafManagerListener); - } + Disposer.register(myProject, () -> { + UIManager.removePropertyChangeListener(uiManagerPropertyListener); + myLafManager.removeLafManagerListener(lafManagerListener); }); myFrame = myWindowManager.allocateFrame(myProject); LOG.assertTrue(myFrame != null); - final ArrayList commandsList = new ArrayList(); - myToolWindowsPane = new ToolWindowsPane(myFrame, this); Disposer.register(myProject, myToolWindowsPane); ((IdeRootPane)myFrame.getRootPane()).setToolWindowsPane(myToolWindowsPane); + List commandsList = new ArrayList<>(); appendUpdateToolWindowsPaneCmd(commandsList); myFrame.setTitle(FrameTitleBuilder.getInstance().getProjectTitle(myProject)); @@ -432,13 +410,10 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements }; myProject.getMessageBus().connect().subscribe(DumbService.DUMB_MODE, dumbModeListener); - StartupManager.getInstance(myProject).registerPostStartupActivity(new DumbAwareRunnable() { - @Override - public void run() { - registerToolWindowsFromBeans(); - if (DumbService.getInstance(myProject).isDumb()) { - disableStripeButtons(); - } + StartupManager.getInstance(myProject).registerPostStartupActivity((DumbAwareRunnable)() -> { + registerToolWindowsFromBeans(); + if (DumbService.getInstance(myProject).isDumb()) { + disableStripeButtons(); } }); @@ -446,7 +421,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements if (e instanceof KeyEvent) { dispatchKeyEvent((KeyEvent)e); } - if (e instanceof WindowEvent && (e.getID() == WindowEvent.WINDOW_LOST_FOCUS) && e.getSource() == myFrame) { + if (e instanceof WindowEvent && e.getID() == WindowEvent.WINDOW_LOST_FOCUS && e.getSource() == myFrame) { resetHoldState(); } return false; @@ -467,7 +442,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements } } - private JComponent createEditorComponent(Project project) { + private static JComponent createEditorComponent(@NotNull Project project) { return FrameEditorComponentProvider.EP.getExtensions()[0].createEditorComponent(project); } @@ -542,19 +517,16 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements WindowInfoImpl info = getInfo(bean.id); if (!info.isSplit() && bean.secondary && !info.wasRead()) { - toolWindow.setSplitMode(bean.secondary, null); + toolWindow.setSplitMode(true, null); } final ActionCallback activation = toolWindow.setActivation(new ActionCallback()); - final DumbAwareRunnable runnable = new DumbAwareRunnable() { - @Override - public void run() { - if (toolWindow.isDisposed()) return; + final DumbAwareRunnable runnable = () -> { + if (toolWindow.isDisposed()) return; - toolWindow.ensureContentInitialized(); - activation.setDone(); - } + toolWindow.ensureContentInitialized(); + activation.setDone(); }; if (ApplicationManager.getApplication().isUnitTestMode()) { runnable.run(); @@ -566,7 +538,6 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements @Override public void projectClosed() { - final ArrayList commandsList = new ArrayList(); final String[] ids = getToolWindowIds(); // Remove ToolWindowsPane @@ -574,6 +545,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements ((IdeRootPane)myFrame.getRootPane()).setToolWindowsPane(null); myWindowManager.releaseFrame(myFrame); } + List commandsList = new ArrayList<>(); appendUpdateToolWindowsPaneCmd(commandsList); // Hide all tool windows @@ -591,18 +563,18 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements } @Override - public void addToolWindowManagerListener(@NotNull ToolWindowManagerListener l) { - myDispatcher.addListener(l); + public void addToolWindowManagerListener(@NotNull ToolWindowManagerListener listener) { + myDispatcher.addListener(listener); } @Override - public void addToolWindowManagerListener(@NotNull ToolWindowManagerListener l, @NotNull Disposable parentDisposable) { - myDispatcher.addListener(l, parentDisposable); + public void addToolWindowManagerListener(@NotNull ToolWindowManagerListener listener, @NotNull Disposable parentDisposable) { + myDispatcher.addListener(listener, parentDisposable); } @Override - public void removeToolWindowManagerListener(@NotNull ToolWindowManagerListener l) { - myDispatcher.removeListener(l); + public void removeToolWindowManagerListener(@NotNull ToolWindowManagerListener listener) { + myDispatcher.removeListener(listener); } /** @@ -641,7 +613,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements final ExpirableRunnable runnable = new ExpirableRunnable.ForProject(myProject) { @Override public void run() { - final ArrayList commandList = new ArrayList(); + List commandList = new ArrayList<>(); activateEditorComponentImpl(commandList, forced); execute(commandList); } @@ -669,15 +641,14 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements } } - private void activateEditorComponentImpl(List commandList, final boolean forced) { + private void activateEditorComponentImpl(@NotNull List commandList, final boolean forced) { final String active = getActiveToolWindowId(); // Now we have to request focus into most recent focused editor appendRequestFocusInEditorComponentCmd(commandList, forced).doWhenDone(() -> { - final ArrayList commandList12 = new ArrayList(); - if (LOG.isDebugEnabled()) { LOG.debug("editor activated"); } + List commandList12 = new ArrayList<>(); deactivateWindows(null, commandList12); myActiveStack.clear(); @@ -688,9 +659,9 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements @NotNull @Override public ActionCallback run() { - final ArrayList commandList1 = new ArrayList(); + List commandList1 = new ArrayList<>(); - final WindowInfoImpl toReactivate = getInfo(active); + final WindowInfoImpl toReactivate = active == null ? null : getInfo(active); final boolean reactivateLastActive = toReactivate != null && !isToHideOnDeactivation(toReactivate); deactivateWindows(reactivateLastActive ? active : null, commandList1); execute(commandList1); @@ -714,7 +685,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements }); } - private void deactivateWindows( @Nullable String idToIgnore, final List commandList) { + private void deactivateWindows(@Nullable String idToIgnore, @NotNull List commandList) { final WindowInfoImpl[] infos = myLayout.getInfos(); for (final WindowInfoImpl info : infos) { if (idToIgnore != null && idToIgnore.equals(info.getId())) { @@ -736,11 +707,10 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements * * @param dirtyMode if true then all UI operations are performed in "dirty" mode. * It means that UI isn't validated and repainted just after each add/remove operation. - * @see ToolWindowManagerImpl#prepareForActivation */ - private void showAndActivate(final String id, + private void showAndActivate(@NotNull String id, final boolean dirtyMode, - List commandsList, + @NotNull List commandsList, boolean autoFocusContents, boolean forcedFocusRequest) { if (!getToolWindow(id).isAvailable()) { @@ -766,7 +736,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements } } - void activateToolWindow(final String id, boolean forced, boolean autoFocusContents) { + void activateToolWindow(@NotNull String id, boolean forced, boolean autoFocusContents) { if (LOG.isDebugEnabled()) { LOG.debug("enter: activateToolWindow(" + id + ")"); } @@ -776,13 +746,13 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements return; } - final ArrayList commandList = new ArrayList(); + List commandList = new ArrayList<>(); activateToolWindowImpl(id, commandList, forced, autoFocusContents); execute(commandList); } - private void activateToolWindowImpl(final String id, - List commandList, + private void activateToolWindowImpl(@NotNull String id, + @NotNull List commandList, boolean forced, boolean autoFocusContents) { if (!FocusManagerImpl.getInstance().isUnforcedRequestAllowed() && !forced) return; @@ -810,7 +780,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements * * @throws IllegalStateException if tool window isn't installed. */ - private void checkId(final String id) { + private void checkId(@NotNull String id) { if (!myLayout.isToolWindowRegistered(id)) { throw new IllegalStateException("window with id=\"" + id + "\" isn't registered"); } @@ -822,7 +792,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements * @param id id of the tool window to be deactivated. * @param shouldHide if true then also hides specified tool window. */ - private void deactivateToolWindowImpl(final String id, final boolean shouldHide, final List commandsList) { + private void deactivateToolWindowImpl(@NotNull String id, final boolean shouldHide, @NotNull List commandsList) { if (LOG.isDebugEnabled()) { LOG.debug("enter: deactivateToolWindowImpl(" + id + "," + shouldHide + ")"); } @@ -887,37 +857,38 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements /** * @return floating decorator for the tool window with specified ID. */ - private FloatingDecorator getFloatingDecorator(final String id) { + private FloatingDecorator getFloatingDecorator(@NotNull String id) { return myId2FloatingDecorator.get(id); } /** * @return windowed decorator for the tool window with specified ID. */ - private WindowedDecorator getWindowedDecorator(String id) { + private WindowedDecorator getWindowedDecorator(@NotNull String id) { return myId2WindowedDecorator.get(id); } /** * @return internal decorator for the tool window with specified ID. */ - private InternalDecorator getInternalDecorator(final String id) { + private InternalDecorator getInternalDecorator(@NotNull String id) { return myId2InternalDecorator.get(id); } /** * @return tool button for the window with specified ID. */ - private StripeButton getStripeButton(final String id) { + private StripeButton getStripeButton(@NotNull String id) { return myId2StripeButton.get(id); } /** * @return info for the tool window with specified ID. */ - private WindowInfoImpl getInfo(final String id) { + private WindowInfoImpl getInfo(@NotNull String id) { return myLayout.getInfo(id, true); } @Override + @NotNull public List getIdsOn(@NotNull final ToolWindowAnchor anchor) { return myLayout.getVisibleIdsOn(anchor, this); } @@ -931,12 +902,12 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements return decorator != null ? decorator.getToolWindow() : null; } - void showToolWindow(final String id) { + void showToolWindow(@NotNull String id) { if (LOG.isDebugEnabled()) { LOG.debug("enter: showToolWindow(" + id + ")"); } ApplicationManager.getApplication().assertIsDispatchThread(); - final ArrayList commandList = new ArrayList(); + List commandList = new ArrayList<>(); showToolWindowImpl(id, false, commandList); execute(commandList); } @@ -946,12 +917,12 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements hideToolWindow(id, hideSide, true); } - public void hideToolWindow(final String id, final boolean hideSide, final boolean moveFocus) { + public void hideToolWindow(@NotNull String id, final boolean hideSide, final boolean moveFocus) { ApplicationManager.getApplication().assertIsDispatchThread(); checkId(id); final WindowInfoImpl info = getInfo(id); if (!info.isVisible()) return; - final ArrayList commandList = new ArrayList(); + List commandList = new ArrayList<>(); final boolean wasActive = info.isActive(); // hide and deactivate @@ -1024,7 +995,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements } else { final String toBeActivatedId = myActiveStack.pop(); - if (toBeActivatedId != null && (getInfo(toBeActivatedId).isVisible() || isStackEnabled())) { + if (getInfo(toBeActivatedId).isVisible() || isStackEnabled()) { activateToolWindowImpl(toBeActivatedId, commandList, false, true); } else { @@ -1044,7 +1015,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements /** * @param dirtyMode if true then all UI operations are performed in dirty mode. */ - private void showToolWindowImpl(final String id, final boolean dirtyMode, final List commandsList) { + private void showToolWindowImpl(@NotNull String id, final boolean dirtyMode, @NotNull List commandsList) { final WindowInfoImpl toBeShownInfo = getInfo(id); if (toBeShownInfo.isVisible() || !getToolWindow(id).isAvailable()) { return; @@ -1184,7 +1155,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements public ToolWindow registerToolWindow(@NotNull String id, boolean canCloseContent, @NotNull ToolWindowAnchor anchor, - Disposable parentDisposable, + @NotNull Disposable parentDisposable, boolean canWorkInDumbMode, boolean secondary) { ToolWindow window = registerToolWindow(id, null, anchor, secondary, canCloseContent, canWorkInDumbMode); @@ -1226,7 +1197,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements final StripeButton button = new StripeButton(decorator, myToolWindowsPane); myId2StripeButton.put(id, button); - List commandsList = new ArrayList(); + List commandsList = new ArrayList<>(); appendAddButtonCmd(button, info, commandsList); if (canWorkInDumbMode) { @@ -1260,12 +1231,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements @NotNull private ToolWindow registerDisposable(@NotNull final String id, @NotNull final Disposable parentDisposable, @NotNull ToolWindow window) { - Disposer.register(parentDisposable, new Disposable() { - @Override - public void dispose() { - unregisterToolWindow(id); - } - }); + Disposer.register(parentDisposable, () -> unregisterToolWindow(id)); return window; } @@ -1284,7 +1250,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements // Save recent appearance of tool window myLayout.unregister(id); // Remove decorator and tool button from the screen - final ArrayList commandsList = new ArrayList(); + List commandsList = new ArrayList<>(); if (info.isVisible()) { info.setVisible(false); if (info.isFloating()) { @@ -1338,7 +1304,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements @Override public void setLayout(@NotNull final DesktopLayout layout) { ApplicationManager.getApplication().assertIsDispatchThread(); - final ArrayList commandList = new ArrayList(); + List commandList = new ArrayList<>(); // hide tool window that are invisible in new layout final WindowInfoImpl[] currentInfos = myLayout.getInfos(); for (final WindowInfoImpl currentInfo : currentInfos) { @@ -1400,7 +1366,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements @Override public void invokeLater(@NotNull final Runnable runnable) { - List commandList = new ArrayList(); + List commandList = new ArrayList<>(); commandList.add(new InvokeLaterCmd(runnable, myWindowManager.getCommandProcessor())); execute(commandList); } @@ -1480,19 +1446,16 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements }); listenerWrapper.myBalloon = balloon; myWindow2Balloon.put(toolWindowId, balloon); - Disposer.register(balloon, new Disposable() { - @Override - public void dispose() { - window.setPlaceholderMode(false); - stripe.updatePresentation(); - stripe.revalidate(); - stripe.repaint(); - myWindow2Balloon.remove(toolWindowId); - } + Disposer.register(balloon, () -> { + window.setPlaceholderMode(false); + stripe.updatePresentation(); + stripe.revalidate(); + stripe.repaint(); + myWindow2Balloon.remove(toolWindowId); }); Disposer.register(getProject(), balloon); - execute(new ArrayList(Arrays.asList(new FinalizableCommand(null) { + execute(new ArrayList<>(Collections.singletonList(new FinalizableCommand(null) { @Override public void run() { final StripeButton button = stripe.getButtonFor(toolWindowId); @@ -1550,7 +1513,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements }; if (!button.isValid()) { - SwingUtilities.invokeLater(() -> show.run()); + SwingUtilities.invokeLater(show); } else { show.run(); @@ -1573,27 +1536,28 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements return splitters != null; } - ToolWindowAnchor getToolWindowAnchor(final String id) { + @NotNull + ToolWindowAnchor getToolWindowAnchor(@NotNull String id) { checkId(id); return getInfo(id).getAnchor(); } - void setToolWindowAnchor(final String id, final ToolWindowAnchor anchor) { + void setToolWindowAnchor(@NotNull String id, @NotNull ToolWindowAnchor anchor) { ApplicationManager.getApplication().assertIsDispatchThread(); setToolWindowAnchor(id, anchor, -1); } - void setToolWindowAnchor(final String id, final ToolWindowAnchor anchor, final int order) { + private void setToolWindowAnchor(@NotNull String id, @NotNull ToolWindowAnchor anchor, final int order) { ApplicationManager.getApplication().assertIsDispatchThread(); - final ArrayList commandList = new ArrayList(); + List commandList = new ArrayList<>(); setToolWindowAnchorImpl(id, anchor, order, commandList); execute(commandList); } - private void setToolWindowAnchorImpl(final String id, - final ToolWindowAnchor anchor, + private void setToolWindowAnchorImpl(@NotNull String id, + @NotNull ToolWindowAnchor anchor, final int order, - final ArrayList commandsList) { + @NotNull List commandsList) { checkId(id); final WindowInfoImpl info = getInfo(id); if (anchor == info.getAnchor() && order == info.getOrder()) { @@ -1630,42 +1594,42 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements } } - boolean isSplitMode(String id) { + boolean isSplitMode(@NotNull String id) { ApplicationManager.getApplication().assertIsDispatchThread(); checkId(id); return getInfo(id).isSplit(); } @NotNull - ToolWindowContentUiType getContentUiType(String id) { + ToolWindowContentUiType getContentUiType(@NotNull String id) { ApplicationManager.getApplication().assertIsDispatchThread(); checkId(id); return getInfo(id).getContentUiType(); } - void setSideTool(String id, boolean isSide) { - final ArrayList commandList = new ArrayList(); + void setSideTool(@NotNull String id, boolean isSide) { + List commandList = new ArrayList<>(); setSplitModeImpl(id, isSide, commandList); execute(commandList); } - public void setContentUiType(String id, @NotNull ToolWindowContentUiType type) { - final ArrayList commandList = new ArrayList(); + void setContentUiType(@NotNull String id, @NotNull ToolWindowContentUiType type) { checkId(id); WindowInfoImpl info = getInfo(id); info.setContentUiType(type); + List commandList = new ArrayList<>(); appendApplyWindowInfoCmd(info, commandList); execute(commandList); } - void setSideToolAndAnchor(String id, ToolWindowAnchor anchor, int order, boolean isSide) { - final ArrayList commandList = new ArrayList(); + void setSideToolAndAnchor(@NotNull String id, @NotNull ToolWindowAnchor anchor, int order, boolean isSide) { setToolWindowAnchor(id, anchor, order); + List commandList = new ArrayList<>(); setSplitModeImpl(id, isSide, commandList); execute(commandList); } - private void setSplitModeImpl(final String id, final boolean isSplit, final ArrayList commandList) { + private void setSplitModeImpl(@NotNull String id, final boolean isSplit, @NotNull List commandList) { checkId(id); final WindowInfoImpl info = getInfo(id); if (isSplit == info.isSplit()) { @@ -1688,18 +1652,18 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements commandList.add(myToolWindowsPane.createUpdateButtonPositionCmd(id, myWindowManager.getCommandProcessor())); } - ToolWindowType getToolWindowInternalType(final String id) { + ToolWindowType getToolWindowInternalType(@NotNull String id) { ApplicationManager.getApplication().assertIsDispatchThread(); checkId(id); return getInfo(id).getInternalType(); } - ToolWindowType getToolWindowType(final String id) { + ToolWindowType getToolWindowType(@NotNull String id) { checkId(id); return getInfo(id).getType(); } - private void fireToolWindowRegistered(final String id) { + private void fireToolWindowRegistered(@NotNull String id) { myDispatcher.getMulticaster().toolWindowRegistered(id); } @@ -1707,31 +1671,31 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements myDispatcher.getMulticaster().stateChanged(); } - boolean isToolWindowActive(final String id) { + boolean isToolWindowActive(@NotNull String id) { ApplicationManager.getApplication().assertIsDispatchThread(); checkId(id); return getInfo(id).isActive(); } - boolean isToolWindowAutoHide(final String id) { + boolean isToolWindowAutoHide(@NotNull String id) { ApplicationManager.getApplication().assertIsDispatchThread(); checkId(id); return getInfo(id).isAutoHide(); } - boolean isToolWindowVisible(final String id) { + boolean isToolWindowVisible(@NotNull String id) { checkId(id); return getInfo(id).isVisible(); } - void setToolWindowAutoHide(final String id, final boolean autoHide) { + void setToolWindowAutoHide(@NotNull String id, final boolean autoHide) { ApplicationManager.getApplication().assertIsDispatchThread(); - final ArrayList commandList = new ArrayList(); + List commandList = new ArrayList<>(); setToolWindowAutoHideImpl(id, autoHide, commandList); execute(commandList); } - private void setToolWindowAutoHideImpl(final String id, final boolean autoHide, final ArrayList commandsList) { + private void setToolWindowAutoHideImpl(@NotNull String id, final boolean autoHide, @NotNull List commandsList) { checkId(id); final WindowInfoImpl info = getInfo(id); if (info.isAutoHide() == autoHide) { @@ -1745,14 +1709,14 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements } } - void setToolWindowType(final String id, final ToolWindowType type) { + void setToolWindowType(@NotNull String id, @NotNull ToolWindowType type) { ApplicationManager.getApplication().assertIsDispatchThread(); - final ArrayList commandList = new ArrayList(); + List commandList = new ArrayList<>(); setToolWindowTypeImpl(id, type, commandList); execute(commandList); } - private void setToolWindowTypeImpl(final String id, final ToolWindowType type, final ArrayList commandsList) { + private void setToolWindowTypeImpl(@NotNull String id, @NotNull ToolWindowType type, @NotNull List commandsList) { checkId(id); final WindowInfoImpl info = getInfo(id); if (info.getType() == type) { @@ -1782,7 +1746,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements } } - private void appendApplyWindowInfoCmd(final WindowInfoImpl info, final List commandsList) { + private void appendApplyWindowInfoCmd(@NotNull WindowInfoImpl info, @NotNull List commandsList) { final StripeButton button = getStripeButton(info.getId()); final InternalDecorator decorator = getInternalDecorator(info.getId()); commandsList.add(new ApplyWindowInfoCmd(info, button, decorator, myWindowManager.getCommandProcessor())); @@ -1791,10 +1755,10 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements /** * @see ToolWindowsPane#createAddDecoratorCmd */ - private void appendAddDecoratorCmd(final InternalDecorator decorator, - final WindowInfoImpl info, + private void appendAddDecoratorCmd(@NotNull InternalDecorator decorator, + @NotNull WindowInfoImpl info, final boolean dirtyMode, - final List commandsList) { + @NotNull List commandsList) { final CommandProcessor commandProcessor = myWindowManager.getCommandProcessor(); final FinalizableCommand command = myToolWindowsPane.createAddDecoratorCmd(decorator, info, dirtyMode, commandProcessor); commandsList.add(command); @@ -1803,17 +1767,17 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements /** * @see ToolWindowsPane#createRemoveDecoratorCmd */ - private void appendRemoveDecoratorCmd(final String id, final boolean dirtyMode, final List commandsList) { + private void appendRemoveDecoratorCmd(@NotNull String id, final boolean dirtyMode, @NotNull List commandsList) { final FinalizableCommand command = myToolWindowsPane.createRemoveDecoratorCmd(id, dirtyMode, myWindowManager.getCommandProcessor()); commandsList.add(command); } - private void appendRemoveFloatingDecoratorCmd(final WindowInfoImpl info, final List commandsList) { + private void appendRemoveFloatingDecoratorCmd(@NotNull WindowInfoImpl info, @NotNull List commandsList) { final RemoveFloatingDecoratorCmd command = new RemoveFloatingDecoratorCmd(info); commandsList.add(command); } - private void appendRemoveWindowedDecoratorCmd(final WindowInfoImpl info, final List commandsList) { + private void appendRemoveWindowedDecoratorCmd(@NotNull WindowInfoImpl info, @NotNull List commandsList) { final RemoveWindowedDecoratorCmd command = new RemoveWindowedDecoratorCmd(info); commandsList.add(command); } @@ -1821,7 +1785,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements /** * @see ToolWindowsPane#createAddButtonCmd */ - private void appendAddButtonCmd(final StripeButton button, final WindowInfoImpl info, final List commandsList) { + private void appendAddButtonCmd(final StripeButton button, @NotNull WindowInfoImpl info, @NotNull List commandsList) { final Comparator comparator = myLayout.comparator(info.getAnchor()); final CommandProcessor commandProcessor = myWindowManager.getCommandProcessor(); final FinalizableCommand command = myToolWindowsPane.createAddButtonCmd(button, info, comparator, commandProcessor); @@ -1831,7 +1795,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements /** * @see ToolWindowsPane#createAddButtonCmd */ - private void appendRemoveButtonCmd(final String id, final List commandsList) { + private void appendRemoveButtonCmd(@NotNull String id, @NotNull List commandsList) { final FinalizableCommand command = myToolWindowsPane.createRemoveButtonCmd(id, myWindowManager.getCommandProcessor()); commandsList.add(command); } @@ -1855,7 +1819,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements /** * @see ToolWindowsPane#createSetEditorComponentCmd */ - public void appendSetEditorComponentCmd(@Nullable final JComponent component, final List commandsList) { + private void appendSetEditorComponentCmd(@Nullable final JComponent component, @NotNull List commandsList) { final CommandProcessor commandProcessor = myWindowManager.getCommandProcessor(); final FinalizableCommand command = myToolWindowsPane.createSetEditorComponentCmd(component, commandProcessor); commandsList.add(command); @@ -1885,36 +1849,6 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements return splitters != null ? splitters : fem.getSplitters(); } - /** - * @return true if tool window with the specified id - * is floating and has modal showing child dialog. Such windows should not be closed - * when auto-hide windows are gone. - */ - private boolean hasModalChild(final WindowInfoImpl info) { - if (!info.isVisible() || !info.isFloating()) { - return false; - } - final FloatingDecorator decorator = getFloatingDecorator(info.getId()); - LOG.assertTrue(decorator != null); - return isModalOrHasModalChild(decorator); - } - - private static boolean isModalOrHasModalChild(final Window window) { - if (window instanceof Dialog) { - final Dialog dialog = (Dialog)window; - if (dialog.isModal() && dialog.isShowing()) { - return true; - } - final Window[] ownedWindows = dialog.getOwnedWindows(); - for (int i = ownedWindows.length - 1; i >= 0; i--) { - if (isModalOrHasModalChild(ownedWindows[i])) { - return true; - } - } - } - return false; - } - @Override public void clearSideStack() { mySideStack.clear(); @@ -2000,14 +1934,14 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements } } - public void setDefaultContentUiType(ToolWindowImpl toolWindow, @NotNull ToolWindowContentUiType type) { + void setDefaultContentUiType(@NotNull ToolWindowImpl toolWindow, @NotNull ToolWindowContentUiType type) { final WindowInfoImpl info = getInfo(toolWindow.getId()); if (info.wasRead()) return; toolWindow.setContentUiType(type, null); } - public void stretchWidth(ToolWindowImpl toolWindow, int value) { + void stretchWidth(@NotNull ToolWindowImpl toolWindow, int value) { myToolWindowsPane.stretchWidth(toolWindow, value); } @@ -2021,7 +1955,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements myToolWindowsPane.setMaximized(wnd, maximized); } - public void stretchHeight(ToolWindowImpl toolWindow, int value) { + void stretchHeight(ToolWindowImpl toolWindow, int value) { myToolWindowsPane.stretchHeight(toolWindow, value); } @@ -2029,7 +1963,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements private Balloon myBalloon; private final HyperlinkListener myListener; - public BalloonHyperlinkListener(HyperlinkListener listener) { + BalloonHyperlinkListener(HyperlinkListener listener) { myListener = listener; } @@ -2054,7 +1988,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements /** * Creates floating decorator for specified internal decorator. */ - private AddFloatingDecoratorCmd(final InternalDecorator decorator, final WindowInfoImpl info) { + private AddFloatingDecoratorCmd(@NotNull InternalDecorator decorator, @NotNull WindowInfoImpl info) { super(myWindowManager.getCommandProcessor()); myFloatingDecorator = new FloatingDecorator(myFrame, info.copy(), decorator); myId2FloatingDecorator.put(info.getId(), myFloatingDecorator); @@ -2093,7 +2027,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements private final class RemoveFloatingDecoratorCmd extends FinalizableCommand { private final FloatingDecorator myFloatingDecorator; - private RemoveFloatingDecoratorCmd(final WindowInfoImpl info) { + private RemoveFloatingDecoratorCmd(@NotNull WindowInfoImpl info) { super(myWindowManager.getCommandProcessor()); myFloatingDecorator = getFloatingDecorator(info.getId()); myId2FloatingDecorator.remove(info.getId()); @@ -2126,7 +2060,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements /** * Creates windowed decorator for specified internal decorator. */ - private AddWindowedDecoratorCmd(final InternalDecorator decorator, final WindowInfoImpl info) { + private AddWindowedDecoratorCmd(@NotNull InternalDecorator decorator, @NotNull WindowInfoImpl info) { super(myWindowManager.getCommandProcessor()); myWindowedDecorator = new WindowedDecorator(myProject, info.copy(), decorator); Window window = myWindowedDecorator.getFrame(); @@ -2146,12 +2080,9 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements window.setLocationRelativeTo(myFrame); } myId2WindowedDecorator.put(info.getId(), myWindowedDecorator); - myWindowedDecorator.addDisposable(new Disposable() { - @Override - public void dispose() { - if (myId2WindowedDecorator.get(info.getId()) != null) { - hideToolWindow(info.getId(), false); - } + myWindowedDecorator.addDisposable(() -> { + if (myId2WindowedDecorator.get(info.getId()) != null) { + hideToolWindow(info.getId(), false); } }); } @@ -2183,7 +2114,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements private final class RemoveWindowedDecoratorCmd extends FinalizableCommand { private final WindowedDecorator myWindowedDecorator; - private RemoveWindowedDecoratorCmd(final WindowInfoImpl info) { + private RemoveWindowedDecoratorCmd(@NotNull WindowInfoImpl info) { super(myWindowManager.getCommandProcessor()); myWindowedDecorator = getWindowedDecorator(info.getId()); myId2WindowedDecorator.remove(info.getId()); @@ -2255,8 +2186,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements private final String myId; private final ToolWindowImpl myToolWindow; - - private ToolWindowFocusWatcher(final ToolWindowImpl toolWindow) { + private ToolWindowFocusWatcher(@NotNull ToolWindowImpl toolWindow) { myId = toolWindow.getId(); install(toolWindow.getComponent()); myToolWindow = toolWindow; @@ -2317,27 +2247,27 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements */ private final class MyInternalDecoratorListener implements InternalDecoratorListener { @Override - public void anchorChanged(final InternalDecorator source, final ToolWindowAnchor anchor) { + public void anchorChanged(@NotNull final InternalDecorator source, @NotNull final ToolWindowAnchor anchor) { setToolWindowAnchor(source.getToolWindow().getId(), anchor); } @Override - public void autoHideChanged(final InternalDecorator source, final boolean autoHide) { + public void autoHideChanged(@NotNull final InternalDecorator source, final boolean autoHide) { setToolWindowAutoHide(source.getToolWindow().getId(), autoHide); } @Override - public void hidden(final InternalDecorator source) { + public void hidden(@NotNull final InternalDecorator source) { hideToolWindow(source.getToolWindow().getId(), false); } @Override - public void hiddenSide(final InternalDecorator source) { + public void hiddenSide(@NotNull final InternalDecorator source) { hideToolWindow(source.getToolWindow().getId(), true); } @Override - public void contentUiTypeChanges(InternalDecorator source, @NotNull ToolWindowContentUiType type) { + public void contentUiTypeChanges(@NotNull InternalDecorator source, @NotNull ToolWindowContentUiType type) { setContentUiType(source.getToolWindow().getId(), type); } @@ -2346,13 +2276,12 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements * tool window depending on decoration type. */ @Override - public void resized(final InternalDecorator source) { + public void resized(@NotNull final InternalDecorator source) { if (!source.isShowing()) { return; // do not recalculate the tool window size if it is not yet shown (and, therefore, has 0,0,0,0 bounds) } final WindowInfoImpl info = getInfo(source.getToolWindow().getId()); - InternalDecorator another = null; if (info.isFloating()) { final Window owner = SwingUtilities.getWindowAncestor(source); if (owner != null) { @@ -2367,6 +2296,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements } else { // docked and sliding windows ToolWindowAnchor anchor = info.getAnchor(); + InternalDecorator another = null; if (source.getParent() instanceof Splitter) { float sizeInSplit = anchor.isSplitVertically() ? source.getHeight() : source.getWidth(); Splitter splitter = (Splitter)source.getParent(); @@ -2399,21 +2329,22 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements } @Override - public void activated(final InternalDecorator source) { + public void activated(@NotNull final InternalDecorator source) { activateToolWindow(source.getToolWindow().getId(), true, true); } @Override - public void typeChanged(final InternalDecorator source, final ToolWindowType type) { + public void typeChanged(@NotNull final InternalDecorator source, @NotNull final ToolWindowType type) { setToolWindowType(source.getToolWindow().getId(), type); } @Override - public void sideStatusChanged(final InternalDecorator source, final boolean isSideTool) { + public void sideStatusChanged(@NotNull final InternalDecorator source, final boolean isSideTool) { setSideTool(source.getToolWindow().getId(), isSideTool); } - public void visibleStripeButtonChanged(InternalDecorator source, boolean visible) { + @Override + public void visibleStripeButtonChanged(@NotNull InternalDecorator source, boolean visible) { setShowStripeButton(source.getToolWindow().getId(), visible); } } @@ -2546,11 +2477,12 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements return IdeFocusManager.getInstance(myProject).dispatch(e); } + @NotNull public Expirable getTimestamp(boolean trackOnlyForcedCommands) { return IdeFocusManager.getInstance(myProject).getTimestamp(trackOnlyForcedCommands); } - public void setShowStripeButton(String id, boolean visibleOnPanel) { + void setShowStripeButton(@NotNull String id, boolean visibleOnPanel) { checkId(id); WindowInfoImpl info = getInfo(id); if (visibleOnPanel == info.isShowStripeButton()) { @@ -2559,12 +2491,12 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements info.setShowStripeButton(visibleOnPanel); UsageTrigger.trigger("StripeButton[" + id + "]." + (visibleOnPanel ? "shown" : "hidden")); - final ArrayList commandList = new ArrayList(); + List commandList = new ArrayList<>(); appendApplyWindowInfoCmd(info, commandList); execute(commandList); } - public boolean isShowStripeButton(String id) { + boolean isShowStripeButton(@NotNull String id) { WindowInfoImpl info = getInfo(id); return info == null || info.isShowStripeButton(); } diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowsPane.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowsPane.java index 2f626df5477e..86a45f418e26 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowsPane.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowsPane.java @@ -42,10 +42,10 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; import java.awt.image.BufferedImage; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; +import java.lang.ref.Reference; import java.util.ArrayList; import java.util.Comparator; +import java.util.List; /** * This panel contains all tool stripes and JLayeredPanle at the center area. All tool windows are @@ -59,12 +59,12 @@ public final class ToolWindowsPane extends JBLayeredPane implements UISettingsLi private final IdeFrameImpl myFrame; - private final HashMap myId2Button; - private final HashMap myId2Decorator; - private final HashMap myButton2Info; - private final HashMap myDecorator2Info; - private final HashMap myId2SplitProportion; - private Pair myMaximizedProportion = null; + private final HashMap myId2Button = new HashMap<>(); + private final HashMap myId2Decorator = new HashMap<>(); + private final HashMap myButton2Info = new HashMap<>(); + private final HashMap myDecorator2Info = new HashMap<>(); + private final HashMap myId2SplitProportion = new HashMap<>(); + private Pair myMaximizedProportion; /** * This panel is the layered pane where all sliding tool windows are located. The DEFAULT * layer contains splitters. The PALETTE layer contains all sliding tool windows. @@ -84,29 +84,23 @@ public final class ToolWindowsPane extends JBLayeredPane implements UISettingsLi private final Stripe myBottomStripe; private final Stripe myTopStripe; - private final ArrayList myStripes = new ArrayList(); + private final List myStripes = new ArrayList<>(); private final ToolWindowManagerImpl myManager; private boolean myStripesOverlayed; private final Disposable myDisposable = Disposer.newDisposable(); - private boolean myWidescreen = false; - private boolean myLeftHorizontalSplit = false; - private boolean myRightHorizontalSplit = false; + private boolean myWidescreen; + private boolean myLeftHorizontalSplit; + private boolean myRightHorizontalSplit; - ToolWindowsPane(final IdeFrameImpl frame, ToolWindowManagerImpl manager) { + ToolWindowsPane(@NotNull IdeFrameImpl frame, @NotNull ToolWindowManagerImpl manager) { myManager = manager; setOpaque(false); myFrame = frame; - myId2Button = new HashMap(); - myId2Decorator = new HashMap(); - myButton2Info = new HashMap(); - myDecorator2Info = new HashMap(); - myId2SplitProportion = new HashMap(); // Splitters - myVerticalSplitter = new ThreeComponentsSplitter(true); Disposer.register(this, myVerticalSplitter); myVerticalSplitter.setDividerWidth(0); @@ -193,6 +187,7 @@ public final class ToolWindowsPane extends JBLayeredPane implements UISettingsLi /** * Invoked when enclosed frame is being shown. */ + @Override public final void addNotify() { super.addNotify(); } @@ -200,6 +195,7 @@ public final class ToolWindowsPane extends JBLayeredPane implements UISettingsLi /** * Invoked when enclosed frame is being disposed. */ + @Override public final void removeNotify() { if (ScreenUtil.isStandardAddRemoveNotify(this)) { Disposer.dispose(myDisposable); @@ -211,6 +207,7 @@ public final class ToolWindowsPane extends JBLayeredPane implements UISettingsLi return myFrame.getProject(); } + @Override public final void uiSettingsChanged(final UISettings source) { updateToolStripesVisibility(); updateLayout(); @@ -225,10 +222,11 @@ public final class ToolWindowsPane extends JBLayeredPane implements UISettingsLi * @param comparator which is used to sort buttons within the stripe. * @param finishCallBack invoked when the command is completed. */ + @NotNull final FinalizableCommand createAddButtonCmd(final StripeButton button, - final WindowInfoImpl info, - final Comparator comparator, - final Runnable finishCallBack) { + @NotNull WindowInfoImpl info, + @NotNull Comparator comparator, + @NotNull Runnable finishCallBack) { final WindowInfoImpl copiedInfo = info.copy(); myId2Button.put(copiedInfo.getId(), button); myButton2Info.put(button, copiedInfo); @@ -242,12 +240,11 @@ public final class ToolWindowsPane extends JBLayeredPane implements UISettingsLi * @param dirtyMode if true then JRootPane will not be validated and repainted after adding * the decorator. Moreover in this (dirty) mode animation doesn't work. */ - final FinalizableCommand createAddDecoratorCmd( - final InternalDecorator decorator, - final WindowInfoImpl info, - final boolean dirtyMode, - final Runnable finishCallBack - ) { + @NotNull + final FinalizableCommand createAddDecoratorCmd(@NotNull InternalDecorator decorator, + @NotNull WindowInfoImpl info, + final boolean dirtyMode, + @NotNull Runnable finishCallBack) { final WindowInfoImpl copiedInfo = info.copy(); final String id = copiedInfo.getId(); @@ -276,10 +273,11 @@ public final class ToolWindowsPane extends JBLayeredPane implements UISettingsLi * * @param id ID of the button to be removed. */ - final FinalizableCommand createRemoveButtonCmd(final String id, final Runnable finishCallBack) { + @NotNull + final FinalizableCommand createRemoveButtonCmd(@NotNull String id, @NotNull Runnable finishCallBack) { final StripeButton button = getButtonById(id); final WindowInfoImpl info = getButtonInfoById(id); - // + myButton2Info.remove(button); myId2Button.remove(id); return new RemoveToolStripeButtonCmd(button, info, finishCallBack); @@ -291,7 +289,8 @@ public final class ToolWindowsPane extends JBLayeredPane implements UISettingsLi * @param dirtyMode if true then JRootPane will not be validated and repainted after removing * the decorator. Moreover in this (dirty) mode animation doesn't work. */ - final FinalizableCommand createRemoveDecoratorCmd(final String id, final boolean dirtyMode, final Runnable finishCallBack) { + @NotNull + final FinalizableCommand createRemoveDecoratorCmd(@NotNull String id, final boolean dirtyMode, @NotNull Runnable finishCallBack) { final Component decorator = getDecoratorById(id); final WindowInfoImpl info = getDecoratorInfoById(id); @@ -321,14 +320,17 @@ public final class ToolWindowsPane extends JBLayeredPane implements UISettingsLi * * @param component component to be set. */ - final FinalizableCommand createSetEditorComponentCmd(final JComponent component, final Runnable finishCallBack) { + @NotNull + final FinalizableCommand createSetEditorComponentCmd(final JComponent component, @NotNull Runnable finishCallBack) { return new SetEditorComponentCmd(component, finishCallBack); } - final FinalizableCommand createUpdateButtonPositionCmd(String id, final Runnable finishCallback) { + @NotNull + final FinalizableCommand createUpdateButtonPositionCmd(@NotNull String id, @NotNull Runnable finishCallback) { return new UpdateButtonPositionCmd(id, finishCallback); } + @NotNull public final JComponent getMyLayeredPane() { return myLayeredPane; } @@ -361,7 +363,7 @@ public final class ToolWindowsPane extends JBLayeredPane implements UISettingsLi /** * Sets (docks) specified component to the specified anchor. */ - private void setComponent(final JComponent component, final ToolWindowAnchor anchor, final float weight) { + private void setComponent(final JComponent component, @NotNull ToolWindowAnchor anchor, final float weight) { if (ToolWindowAnchor.TOP == anchor) { myVerticalSplitter.setFirstComponent(component); myVerticalSplitter.setFirstSize((int)(myLayeredPane.getHeight() * weight)); @@ -383,7 +385,7 @@ public final class ToolWindowsPane extends JBLayeredPane implements UISettingsLi } } - private JComponent getComponentAt(ToolWindowAnchor anchor) { + private JComponent getComponentAt(@NotNull ToolWindowAnchor anchor) { if (ToolWindowAnchor.TOP == anchor) { return myVerticalSplitter.getFirstComponent(); } @@ -402,12 +404,12 @@ public final class ToolWindowsPane extends JBLayeredPane implements UISettingsLi } } - private float getPreferredSplitProportion(String id, float defaultValue) { + private float getPreferredSplitProportion(@NotNull String id, float defaultValue) { Float f = myId2SplitProportion.get(id); - return (f == null ? defaultValue : f); + return f == null ? defaultValue : f; } - private WindowInfoImpl getDockedInfoAt(ToolWindowAnchor anchor, boolean side) { + private WindowInfoImpl getDockedInfoAt(@NotNull ToolWindowAnchor anchor, boolean side) { for (WindowInfoImpl info : myDecorator2Info.values()) { if (info.isVisible() && info.isDocked() && info.getAnchor() == anchor && side == info.isSplit()) { return info; @@ -417,7 +419,7 @@ public final class ToolWindowsPane extends JBLayeredPane implements UISettingsLi return null; } - public void setDocumentComponent(final JComponent component) { + private void setDocumentComponent(final JComponent component) { (myWidescreen ? myVerticalSplitter : myHorizontalSplitter).setInnerComponent(component); } @@ -464,13 +466,13 @@ public final class ToolWindowsPane extends JBLayeredPane implements UISettingsLi if (ToolWindowAnchor.TOP == anchor) { return myTopStripe; } - else if (ToolWindowAnchor.BOTTOM == anchor) { + if (ToolWindowAnchor.BOTTOM == anchor) { return myBottomStripe; } - else if (ToolWindowAnchor.LEFT == anchor) { + if (ToolWindowAnchor.LEFT == anchor) { return myLeftStripe; } - else if (ToolWindowAnchor.RIGHT == anchor) { + if (ToolWindowAnchor.RIGHT == anchor) { return myRightStripe; } @@ -478,7 +480,7 @@ public final class ToolWindowsPane extends JBLayeredPane implements UISettingsLi } @Nullable - Stripe getStripeFor(final Rectangle screenRec, Stripe preferred) { + Stripe getStripeFor(@NotNull Rectangle screenRec, @NotNull Stripe preferred) { if (preferred.containsScreen(screenRec)) { return myStripes.get(myStripes.indexOf(preferred)); } @@ -504,15 +506,15 @@ public final class ToolWindowsPane extends JBLayeredPane implements UISettingsLi } } - public void stretchWidth(ToolWindow wnd, int value) { + void stretchWidth(@NotNull ToolWindow wnd, int value) { stretch(wnd, value); } - public void stretchHeight(ToolWindow wnd, int value) { + void stretchHeight(@NotNull ToolWindow wnd, int value) { stretch(wnd, value); } - private void stretch(ToolWindow wnd, int value) { + private void stretch(@NotNull ToolWindow wnd, int value) { Pair pair = findResizerAndComponent(wnd); if (pair == null) return; @@ -520,13 +522,13 @@ public final class ToolWindowsPane extends JBLayeredPane implements UISettingsLi int actualSize = (vertical ? pair.second.getHeight() : pair.second.getWidth()) + value; boolean first = wnd.getAnchor() == ToolWindowAnchor.LEFT || wnd.getAnchor() == ToolWindowAnchor.TOP; int maxValue = vertical ? myVerticalSplitter.getMaxSize(first) : myHorizontalSplitter.getMaxSize(first); - int minValue = vertical ? myVerticalSplitter.getMinSize(first) : myHorizontalSplitter.getMinSize(first);; + int minValue = vertical ? myVerticalSplitter.getMinSize(first) : myHorizontalSplitter.getMinSize(first); pair.first.setSize(Math.max(minValue, Math.min(maxValue, actualSize))); } @Nullable - private Pair findResizerAndComponent(ToolWindow wnd) { + private Pair findResizerAndComponent(@NotNull ToolWindow wnd) { if (!wnd.isVisible()) return null; Resizer resizer = null; @@ -620,7 +622,7 @@ public final class ToolWindowsPane extends JBLayeredPane implements UISettingsLi return myMaximizedProportion != null && myMaximizedProportion.first == wnd; } - public void setMaximized(@NotNull ToolWindow wnd, boolean maximized) { + void setMaximized(@NotNull ToolWindow wnd, boolean maximized) { Pair resizerAndComponent = findResizerAndComponent(wnd); if (resizerAndComponent == null) return; @@ -638,6 +640,7 @@ public final class ToolWindowsPane extends JBLayeredPane implements UISettingsLi } + @FunctionalInterface interface Resizer { void setSize(int size); @@ -645,25 +648,27 @@ public final class ToolWindowsPane extends JBLayeredPane implements UISettingsLi abstract class Splitter implements Resizer { ThreeComponentsSplitter mySplitter; - Splitter(ThreeComponentsSplitter splitter) { + Splitter(@NotNull ThreeComponentsSplitter splitter) { mySplitter = splitter; } static class FirstComponent extends Splitter { - FirstComponent(ThreeComponentsSplitter splitter) { + FirstComponent(@NotNull ThreeComponentsSplitter splitter) { super(splitter); } + @Override public void setSize(int size) { mySplitter.setFirstSize(size); } } static class LastComponent extends Splitter { - LastComponent(ThreeComponentsSplitter splitter) { + LastComponent(@NotNull ThreeComponentsSplitter splitter) { super(splitter); } + @Override public void setSize(int size) { mySplitter.setLastSize(size); } @@ -673,10 +678,11 @@ public final class ToolWindowsPane extends JBLayeredPane implements UISettingsLi abstract class LayeredPane implements Resizer { Component myComponent; - protected LayeredPane(Component component) { + LayeredPane(@NotNull Component component) { myComponent = component; } + @Override public final void setSize(int size) { _setSize(size); if (myComponent.getParent() instanceof JComponent) { @@ -690,20 +696,22 @@ public final class ToolWindowsPane extends JBLayeredPane implements UISettingsLi static class Left extends LayeredPane { - Left(Component component) { + Left(@NotNull Component component) { super(component); } + @Override public void _setSize(int size) { myComponent.setSize(size, myComponent.getHeight()); } } static class Right extends LayeredPane { - Right(Component component) { + Right(@NotNull Component component) { super(component); } + @Override public void _setSize(int size) { Rectangle bounds = myComponent.getBounds(); int delta = size - bounds.width; @@ -714,20 +722,22 @@ public final class ToolWindowsPane extends JBLayeredPane implements UISettingsLi } static class Top extends LayeredPane { - Top(Component component) { + Top(@NotNull Component component) { super(component); } + @Override public void _setSize(int size) { myComponent.setSize(myComponent.getWidth(), size); } } static class Bottom extends LayeredPane { - Bottom(Component component) { + Bottom(@NotNull Component component) { super(component); } + @Override public void _setSize(int size) { Rectangle bounds = myComponent.getBounds(); int delta = size - bounds.height; @@ -744,16 +754,17 @@ public final class ToolWindowsPane extends JBLayeredPane implements UISettingsLi private final WindowInfoImpl myInfo; private final boolean myDirtyMode; - public AddDockedComponentCmd(final JComponent component, - final WindowInfoImpl info, + public AddDockedComponentCmd(@NotNull JComponent component, + @NotNull WindowInfoImpl info, final boolean dirtyMode, - final Runnable finishCallBack) { + @NotNull Runnable finishCallBack) { super(finishCallBack); myComponent = component; myInfo = info; myDirtyMode = dirtyMode; } + @Override public final void run() { try { final ToolWindowAnchor anchor = myInfo.getAnchor(); @@ -774,17 +785,19 @@ public final class ToolWindowsPane extends JBLayeredPane implements UISettingsLi private final WindowInfoImpl myInfo; private final boolean myDirtyMode; - private AddAndSplitDockedComponentCmd(final JComponent newComponent, - final WindowInfoImpl info, final boolean dirtyMode, final Runnable finishCallBack) { + private AddAndSplitDockedComponentCmd(@NotNull JComponent newComponent, + @NotNull WindowInfoImpl info, + final boolean dirtyMode, + @NotNull Runnable finishCallBack) { super(finishCallBack); myNewComponent = newComponent; myInfo = info; myDirtyMode = dirtyMode; } + @Override public void run() { try { - float newWeight; final ToolWindowAnchor anchor = myInfo.getAnchor(); class MySplitter extends Splitter implements UISettingsListener { @Override @@ -801,28 +814,26 @@ public final class ToolWindowsPane extends JBLayeredPane implements UISettingsLi splitter.setOrientation(anchor.isSplitVertically()); if (!anchor.isHorizontal()) { splitter.setAllowSwitchOrientationByMouseClick(true); - splitter.addPropertyChangeListener(new PropertyChangeListener() { - @Override - public void propertyChange(PropertyChangeEvent evt) { - if (!Splitter.PROP_ORIENTATION.equals(evt.getPropertyName())) return; - boolean isSplitterHorizontalNow = !splitter.isVertical(); - UISettings settings = UISettings.getInstance(); - if (anchor == ToolWindowAnchor.LEFT) { - if (settings.LEFT_HORIZONTAL_SPLIT != isSplitterHorizontalNow) { - settings.LEFT_HORIZONTAL_SPLIT = isSplitterHorizontalNow; - settings.fireUISettingsChanged(); - } + splitter.addPropertyChangeListener(evt -> { + if (!Splitter.PROP_ORIENTATION.equals(evt.getPropertyName())) return; + boolean isSplitterHorizontalNow = !splitter.isVertical(); + UISettings settings = UISettings.getInstance(); + if (anchor == ToolWindowAnchor.LEFT) { + if (settings.LEFT_HORIZONTAL_SPLIT != isSplitterHorizontalNow) { + settings.LEFT_HORIZONTAL_SPLIT = isSplitterHorizontalNow; + settings.fireUISettingsChanged(); } - if (anchor == ToolWindowAnchor.RIGHT) { - if (settings.RIGHT_HORIZONTAL_SPLIT != isSplitterHorizontalNow) { - settings.RIGHT_HORIZONTAL_SPLIT = isSplitterHorizontalNow; - settings.fireUISettingsChanged(); - } + } + if (anchor == ToolWindowAnchor.RIGHT) { + if (settings.RIGHT_HORIZONTAL_SPLIT != isSplitterHorizontalNow) { + settings.RIGHT_HORIZONTAL_SPLIT = isSplitterHorizontalNow; + settings.fireUISettingsChanged(); } } }); } JComponent c = getComponentAt(anchor); + float newWeight; if (c instanceof InternalDecorator) { InternalDecorator oldComponent = (InternalDecorator)c; if (myInfo.isSplit()) { @@ -872,15 +883,16 @@ public final class ToolWindowsPane extends JBLayeredPane implements UISettingsLi private final WindowInfoImpl myInfo; private final boolean myDirtyMode; - public AddSlidingComponentCmd(final Component component, - final WindowInfoImpl info, + public AddSlidingComponentCmd(@NotNull Component component, + @NotNull WindowInfoImpl info, final boolean dirtyMode, - final Runnable finishCallBack) { + @NotNull Runnable finishCallBack) { super(finishCallBack); myComponent = component; myInfo = info; myDirtyMode = dirtyMode; } + @Override public final void run() { try { // Show component. @@ -946,15 +958,16 @@ public final class ToolWindowsPane extends JBLayeredPane implements UISettingsLi private final Comparator myComparator; public AddToolStripeButtonCmd(final StripeButton button, - final WindowInfoImpl info, - final Comparator comparator, - final Runnable finishCallBack) { + @NotNull WindowInfoImpl info, + @NotNull Comparator comparator, + @NotNull Runnable finishCallBack) { super(finishCallBack); myButton = button; myInfo = info; myComparator = comparator; } + @Override public final void run() { try { final ToolWindowAnchor anchor = myInfo.getAnchor(); @@ -986,12 +999,13 @@ public final class ToolWindowsPane extends JBLayeredPane implements UISettingsLi private final StripeButton myButton; private final WindowInfoImpl myInfo; - public RemoveToolStripeButtonCmd(final StripeButton button, final WindowInfoImpl info, final Runnable finishCallBack) { + public RemoveToolStripeButtonCmd(@NotNull StripeButton button, @NotNull WindowInfoImpl info, @NotNull Runnable finishCallBack) { super(finishCallBack); myButton = button; myInfo = info; } + @Override public final void run() { try { final ToolWindowAnchor anchor = myInfo.getAnchor(); @@ -1023,12 +1037,13 @@ public final class ToolWindowsPane extends JBLayeredPane implements UISettingsLi private final WindowInfoImpl myInfo; private final boolean myDirtyMode; - public RemoveDockedComponentCmd(final WindowInfoImpl info, final boolean dirtyMode, final Runnable finishCallBack) { + public RemoveDockedComponentCmd(@NotNull WindowInfoImpl info, final boolean dirtyMode, @NotNull Runnable finishCallBack) { super(finishCallBack); myInfo = info; myDirtyMode = dirtyMode; } + @Override public final void run() { try { setComponent(null, myInfo.getAnchor(), 0); @@ -1047,14 +1062,15 @@ public final class ToolWindowsPane extends JBLayeredPane implements UISettingsLi private final WindowInfoImpl myInfo; private final boolean myDirtyMode; - private RemoveSplitAndDockedComponentCmd(final WindowInfoImpl info, + private RemoveSplitAndDockedComponentCmd(@NotNull WindowInfoImpl info, boolean dirtyMode, - final Runnable finishCallBack) { + @NotNull Runnable finishCallBack) { super(finishCallBack); myInfo = info; myDirtyMode = dirtyMode; } + @Override public void run() { try { ToolWindowAnchor anchor = myInfo.getAnchor(); @@ -1086,12 +1102,13 @@ public final class ToolWindowsPane extends JBLayeredPane implements UISettingsLi private final WindowInfoImpl myInfo; private final boolean myDirtyMode; - public RemoveSlidingComponentCmd(Component component, WindowInfoImpl info, boolean dirtyMode, Runnable finishCallBack) { + public RemoveSlidingComponentCmd(Component component, @NotNull WindowInfoImpl info, boolean dirtyMode, @NotNull Runnable finishCallBack) { super(finishCallBack); myComponent = component; myInfo = info; myDirtyMode = dirtyMode; } + @Override public final void run() { try { final UISettings uiSettings = UISettings.getInstance(); @@ -1147,11 +1164,12 @@ public final class ToolWindowsPane extends JBLayeredPane implements UISettingsLi private final class SetEditorComponentCmd extends FinalizableCommand { private final JComponent myComponent; - public SetEditorComponentCmd(final JComponent component, final Runnable finishCallBack) { + public SetEditorComponentCmd(final JComponent component, @NotNull Runnable finishCallBack) { super(finishCallBack); myComponent = component; } + @Override public void run() { try { setDocumentComponent(myComponent); @@ -1167,11 +1185,12 @@ public final class ToolWindowsPane extends JBLayeredPane implements UISettingsLi private final class UpdateButtonPositionCmd extends FinalizableCommand { private final String myId; - private UpdateButtonPositionCmd(String id, final Runnable finishCallBack) { + private UpdateButtonPositionCmd(@NotNull String id, @NotNull Runnable finishCallBack) { super(finishCallBack); myId = id; } + @Override public void run() { try { StripeButton stripeButton = getButtonById(myId); @@ -1209,35 +1228,31 @@ public final class ToolWindowsPane extends JBLayeredPane implements UISettingsLi * These images are used to perform animated showing and hiding of components. * They are the member for performance reason. */ - private SoftReference myBottomImageRef; - private SoftReference myTopImageRef; + private Reference myBottomImageRef; + private Reference myTopImageRef; - public MyLayeredPane(final JComponent splitter) { - myBottomImageRef = new SoftReference(null); - myTopImageRef = new SoftReference(null); + public MyLayeredPane(@NotNull JComponent splitter) { setOpaque(false); add(splitter, JLayeredPane.DEFAULT_LAYER); } - public final Image getBottomImage() { - Pair> result = getImage(myBottomImageRef); + final Image getBottomImage() { + Pair> result = getImage(myBottomImageRef); myBottomImageRef = result.second; return result.first; } - public final Image getTopImage() { - Pair> result = getImage(myTopImageRef); + final Image getTopImage() { + Pair> result = getImage(myTopImageRef); myTopImageRef = result.second; return result.first; } - private Pair> getImage(SoftReference imageRef) { + @NotNull + private Pair> getImage(@Nullable Reference imageRef) { LOG.assertTrue(UISettings.getInstance().ANIMATE_WINDOWS); - BufferedImage image = imageRef.get(); - if ( - image == null || - image.getWidth(null) < getWidth() || image.getHeight(null) < getHeight() - ) { + BufferedImage image = SoftReference.dereference(imageRef); + if (image == null || image.getWidth(null) < getWidth() || image.getHeight(null) < getHeight()) { final int width = Math.max(Math.max(1, getWidth()), myFrame.getWidth()); final int height = Math.max(Math.max(1, getHeight()), myFrame.getHeight()); if (SystemInfo.isWindows) { @@ -1251,7 +1266,7 @@ public final class ToolWindowsPane extends JBLayeredPane implements UISettingsLi image = UIUtil.createImage(width, height, BufferedImage.TYPE_INT_RGB); } - imageRef = new SoftReference(image); + imageRef = new SoftReference<>(image); } return Pair.create(image, imageRef); } @@ -1259,6 +1274,7 @@ public final class ToolWindowsPane extends JBLayeredPane implements UISettingsLi /** * When component size becomes larger then bottom and top images should be enlarged. */ + @Override public void doLayout() { final int width = getWidth(); final int height = getHeight(); @@ -1295,7 +1311,7 @@ public final class ToolWindowsPane extends JBLayeredPane implements UISettingsLi } } - public final void setBoundsInPaletteLayer(final Component component, final ToolWindowAnchor anchor, float weight) { + final void setBoundsInPaletteLayer(@NotNull Component component, @NotNull ToolWindowAnchor anchor, float weight) { if (weight < .0f) { weight = WindowInfoImpl.DEFAULT_WEIGHT; } @@ -1322,7 +1338,7 @@ public final class ToolWindowsPane extends JBLayeredPane implements UISettingsLi } } - public void setStripesOverlayed(boolean stripesOverlayed) { + void setStripesOverlayed(boolean stripesOverlayed) { myStripesOverlayed = stripesOverlayed; updateToolStripesVisibility(); } diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/WindowInfoImpl.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/WindowInfoImpl.java index 22558914ce43..ff006a1156e2 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/WindowInfoImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/WindowInfoImpl.java @@ -32,16 +32,16 @@ public final class WindowInfoImpl implements Cloneable,JDOMExternalizable, Windo /** * XML tag. */ - @NonNls static final String TAG="window_info"; + @NonNls static final String TAG = "window_info"; /** * Default window weight. */ - static final float DEFAULT_WEIGHT= 0.33f; - static final float DEFAULT_SIDE_WEIGHT = 0.5f; + static final float DEFAULT_WEIGHT = 0.33f; + private static final float DEFAULT_SIDE_WEIGHT = 0.5f; private boolean myActive; @NotNull - private ToolWindowAnchor myAnchor; + private ToolWindowAnchor myAnchor = ToolWindowAnchor.LEFT; private boolean myAutoHide; /** * Bounds of window in "floating" mode. It equals to null if @@ -52,9 +52,9 @@ public final class WindowInfoImpl implements Cloneable,JDOMExternalizable, Windo private ToolWindowType myInternalType; private ToolWindowType myType; private boolean myVisible; - private boolean myShowStripeButton; - private float myWeight; - private float mySideWeight; + private boolean myShowStripeButton = true; + private float myWeight = DEFAULT_WEIGHT; + private float mySideWeight = DEFAULT_SIDE_WEIGHT; private boolean mySplitMode; @NotNull private ToolWindowContentUiType myContentUiType = ToolWindowContentUiType.TABBED; @@ -62,24 +62,24 @@ public final class WindowInfoImpl implements Cloneable,JDOMExternalizable, Windo * Defines order of tool window button inside the stripe. * The default value is -1. */ - private int myOrder; - @NonNls static final String ID_ATTR = "id"; - @NonNls static final String ACTIVE_ATTR = "active"; - @NonNls static final String ANCHOR_ATTR = "anchor"; - @NonNls static final String AUTOHIDE_ATTR = "auto_hide"; - @NonNls static final String INTERNAL_TYPE_ATTR = "internal_type"; - @NonNls static final String TYPE_ATTR = "type"; - @NonNls static final String VISIBLE_ATTR = "visible"; - @NonNls static final String WEIGHT_ATTR = "weight"; - @NonNls static final String SIDE_WEIGHT_ATTR = "sideWeight"; - @NonNls static final String ORDER_ATTR = "order"; - @NonNls static final String X_ATTR = "x"; - @NonNls static final String Y_ATTR = "y"; - @NonNls static final String WIDTH_ATTR = "width"; - @NonNls static final String HEIGHT_ATTR = "height"; - @NonNls static final String SIDE_TOOL_ATTR = "side_tool"; - @NonNls static final String CONTENT_UI_ATTR = "content_ui"; - @NonNls static final String SHOW_STRIPE_BUTTON = "show_stripe_button"; + private int myOrder = -1; + @NonNls private static final String ID_ATTR = "id"; + @NonNls private static final String ACTIVE_ATTR = "active"; + @NonNls private static final String ANCHOR_ATTR = "anchor"; + @NonNls private static final String AUTOHIDE_ATTR = "auto_hide"; + @NonNls private static final String INTERNAL_TYPE_ATTR = "internal_type"; + @NonNls private static final String TYPE_ATTR = "type"; + @NonNls private static final String VISIBLE_ATTR = "visible"; + @NonNls private static final String WEIGHT_ATTR = "weight"; + @NonNls private static final String SIDE_WEIGHT_ATTR = "sideWeight"; + @NonNls private static final String ORDER_ATTR = "order"; + @NonNls private static final String X_ATTR = "x"; + @NonNls private static final String Y_ATTR = "y"; + @NonNls private static final String WIDTH_ATTR = "width"; + @NonNls private static final String HEIGHT_ATTR = "height"; + @NonNls private static final String SIDE_TOOL_ATTR = "side_tool"; + @NonNls private static final String CONTENT_UI_ATTR = "content_ui"; + @NonNls private static final String SHOW_STRIPE_BUTTON = "show_stripe_button"; private boolean myWasRead; @@ -88,18 +88,8 @@ public final class WindowInfoImpl implements Cloneable,JDOMExternalizable, Windo * Creates WindowInfo for tool window with specified ID. */ WindowInfoImpl(@NotNull String id) { - myActive = false; - myAnchor = ToolWindowAnchor.LEFT; - myAutoHide = false; - myFloatingBounds = null; myId = id; setType(ToolWindowType.DOCKED); - myVisible = false; - myShowStripeButton = true; - myWeight = DEFAULT_WEIGHT; - mySideWeight = DEFAULT_SIDE_WEIGHT; - myOrder = -1; - mySplitMode = false; } /** @@ -122,7 +112,7 @@ public final class WindowInfoImpl implements Cloneable,JDOMExternalizable, Windo /** * Copies all data from the passed WindowInfo into itself. */ - void copyFrom(final WindowInfoImpl info){ + void copyFrom(@NotNull WindowInfoImpl info){ myActive = info.myActive; myAnchor = info.myAnchor; myAutoHide = info.myAutoHide; @@ -178,15 +168,16 @@ public final class WindowInfoImpl implements Cloneable,JDOMExternalizable, Windo * window can be in floating mode, but this method has sense if you want to know what type * tool window had when it was internal one. The method never returns null. */ + @NotNull ToolWindowType getInternalType(){ return myInternalType; } /** * @return current type of tool window. - * @see com.intellij.openapi.wm.ToolWindowType#DOCKED - * @see com.intellij.openapi.wm.ToolWindowType#FLOATING - * @see com.intellij.openapi.wm.ToolWindowType#SLIDING + * @see ToolWindowType#DOCKED + * @see ToolWindowType#FLOATING + * @see ToolWindowType#SLIDING */ @Override public ToolWindowType getType(){ @@ -248,11 +239,12 @@ public final class WindowInfoImpl implements Cloneable,JDOMExternalizable, Windo return myVisible; } + @Override public boolean isShowStripeButton() { return myShowStripeButton; } - public void setShowStripeButton(boolean showStripeButton) { + void setShowStripeButton(boolean showStripeButton) { myShowStripeButton = showStripeButton; } @@ -266,7 +258,7 @@ public final class WindowInfoImpl implements Cloneable,JDOMExternalizable, Windo } @Override - @SuppressWarnings({"EmptyCatchBlock"}) + @SuppressWarnings("EmptyCatchBlock") public void readExternal(final Element element) { myId = element.getAttributeValue(ID_ATTR); myWasRead = true; @@ -353,7 +345,7 @@ public final class WindowInfoImpl implements Cloneable,JDOMExternalizable, Windo setTypeAndCheck(type); } //Hardcoded to avoid single-usage-API - private void setTypeAndCheck(ToolWindowType type) { + private void setTypeAndCheck(@NotNull ToolWindowType type) { myType = ToolWindowId.PREVIEW == myId && type == ToolWindowType.DOCKED ? ToolWindowType.SLIDING : type; } @@ -420,7 +412,7 @@ public final class WindowInfoImpl implements Cloneable,JDOMExternalizable, Windo return myAnchor.hashCode()+myId.hashCode()+myType.hashCode()+myOrder; } - @SuppressWarnings({"HardCodedStringLiteral"}) + @SuppressWarnings("HardCodedStringLiteral") public String toString(){ return getClass().getName() + "[myId=" + myId + "; myVisible=" + myVisible @@ -439,7 +431,7 @@ public final class WindowInfoImpl implements Cloneable,JDOMExternalizable, Windo ']'; } - public boolean wasRead() { + boolean wasRead() { return myWasRead; } } diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/WindowedDecorator.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/WindowedDecorator.java index 53e29a1a8749..0d1b997aff80 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/WindowedDecorator.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/WindowedDecorator.java @@ -15,14 +15,11 @@ */ package com.intellij.openapi.wm.impl; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.FrameWrapper; import org.jetbrains.annotations.NotNull; -public final class WindowedDecorator extends FrameWrapper { - private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.wm.impl.WindowedDecorator"); - +final class WindowedDecorator extends FrameWrapper { private final Project myProject; WindowedDecorator(@NotNull Project project, @NotNull WindowInfoImpl info, @NotNull InternalDecorator internalDecorator) { diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/commands/FinalizableCommand.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/commands/FinalizableCommand.java index 249391cc253f..b11387bdb1dd 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/commands/FinalizableCommand.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/commands/FinalizableCommand.java @@ -17,6 +17,7 @@ package com.intellij.openapi.wm.impl.commands; import com.intellij.openapi.util.Condition; import com.intellij.openapi.wm.ToolWindowManager; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** @@ -27,15 +28,15 @@ public abstract class FinalizableCommand implements Runnable{ protected ToolWindowManager myManager; - public FinalizableCommand(final Runnable finishCallBack){ - myFinishCallBack=finishCallBack; + public FinalizableCommand(Runnable finishCallBack){ + myFinishCallBack = finishCallBack; } public final void finish(){ myFinishCallBack.run(); } - public void beforeExecute(final ToolWindowManager toolWindowManager) { + public void beforeExecute(@NotNull ToolWindowManager toolWindowManager) { myManager = toolWindowManager; } diff --git a/platform/platform-resources/src/brokenPlugins.txt b/platform/platform-resources/src/brokenPlugins.txt index b0df3bcebde1..1d2302211944 100644 --- a/platform/platform-resources/src/brokenPlugins.txt +++ b/platform/platform-resources/src/brokenPlugins.txt @@ -28,7 +28,7 @@ com.jetbrains.plugins.ini4idea 0.3 0.2 0.4 0.5 0.6 0.7 0.8 0.8.1 0.9 0.9.1 1.0 org.jetbrains.plugins.vagrant 0.6.143.80 0.6.143.71 0.6.143.1 0.1 0.2 0.3 0.4 0.5 0.6.143.3 com.intellij.apacheConfig 143.381.48 142.5266 141.388 139.789 138.2502 org.intellij.clojure 0.2.1.178 -net.nicoulaj.idea.markdown 0.9.5 0.9.4 0.9.3 0.9.2 0.9.1 0.8.3 0.8.2 0.8.1 0.8 0.7 0.6.1 0.6 0.5.1 0.5 0.4 0.3 0.2 0.1 +net.nicoulaj.idea.markdown 0.9.7 0.9.6 0.9.5 0.9.4 0.9.3 0.9.2 0.9.1 0.8.3 0.8.2 0.8.1 0.8 0.7 0.6.1 0.6 0.5.1 0.5 0.4 0.3 0.2 0.1 zielu.gittoolbox 13.1.0 13.5.2 mobi.hsz.idea.gitignore 1.2 1.3 com.vladsch.idea.multimarkdown 1.4.2 1.4.7 @@ -56,3 +56,4 @@ com.phpuaca 1.3.1 1.2.1 coffeescript-idea 0.1-1-gae5a RESTClient 1.2 krasa.nonProjectFilesUnlocker 1.0 1.1 +com.chrisrm.idea.MaterialThemeUI 0.1.9 diff --git a/platform/testFramework/src/com/intellij/mock/Mock.java b/platform/testFramework/src/com/intellij/mock/Mock.java index d6d960f5bd17..89a0106fff6a 100644 --- a/platform/testFramework/src/com/intellij/mock/Mock.java +++ b/platform/testFramework/src/com/intellij/mock/Mock.java @@ -562,7 +562,7 @@ public class Mock { public ToolWindow registerToolWindow(@NotNull String id, @NotNull JComponent component, @NotNull ToolWindowAnchor anchor, - Disposable parentDisposable, + @NotNull Disposable parentDisposable, boolean canWorkInDumbMode, boolean canCloseContents) { throw new RuntimeException(); } @@ -572,7 +572,7 @@ public class Mock { public ToolWindow registerToolWindow(@NotNull String id, @NotNull JComponent component, @NotNull ToolWindowAnchor anchor, - Disposable parentDisposable, + @NotNull Disposable parentDisposable, boolean canWorkInDumbMode) { throw new RuntimeException(); } @@ -592,7 +592,7 @@ public class Mock { @NotNull @Override public ToolWindow registerToolWindow(@NotNull final String id, final boolean canCloseContent, @NotNull final ToolWindowAnchor anchor, - final Disposable parentDisposable, final boolean dumbAware) { + @NotNull final Disposable parentDisposable, final boolean dumbAware) { throw new RuntimeException(); } @@ -601,7 +601,7 @@ public class Mock { public ToolWindow registerToolWindow(@NotNull String id, boolean canCloseContent, @NotNull ToolWindowAnchor anchor, - Disposable parentDisposable, + @NotNull Disposable parentDisposable, boolean canWorkInDumbMode, boolean secondary) { throw new RuntimeException(); diff --git a/platform/usageView/src/com/intellij/usages/UsageViewPresentation.java b/platform/usageView/src/com/intellij/usages/UsageViewPresentation.java index 0fca039bd150..41a47484531a 100644 --- a/platform/usageView/src/com/intellij/usages/UsageViewPresentation.java +++ b/platform/usageView/src/com/intellij/usages/UsageViewPresentation.java @@ -49,6 +49,7 @@ public class UsageViewPresentation { private boolean myDetachedMode; // no UI will be shown private String myDynamicCodeUsagesString; private boolean myMergeDupLinesAvailable = true; + private boolean myExcludeAvailable = true; public String getTabText() { return myTabText; @@ -218,6 +219,14 @@ public class UsageViewPresentation { myUsageTypeFilteringAvailable = usageTypeFilteringAvailable; } + public boolean isExcludeAvailable() { + return myExcludeAvailable; + } + + public void setExcludeAvailable(boolean excludeAvailable) { + myExcludeAvailable = excludeAvailable; + } + @Override public boolean equals(Object o) { if (this == o) return true; @@ -232,6 +241,7 @@ public class UsageViewPresentation { if (myShowCancelButton != that.myShowCancelButton) return false; if (myShowReadOnlyStatusAsRed != that.myShowReadOnlyStatusAsRed) return false; if (myUsageTypeFilteringAvailable != that.myUsageTypeFilteringAvailable) return false; + if (myExcludeAvailable != that.myExcludeAvailable) return false; if (myCodeUsagesString != null ? !myCodeUsagesString.equals(that.myCodeUsagesString) : that.myCodeUsagesString != null) return false; if (myDynamicCodeUsagesString != null ? !myDynamicCodeUsagesString.equals(that.myDynamicCodeUsagesString) @@ -272,6 +282,7 @@ public class UsageViewPresentation { result = 31 * result + (myOpenInNewTab ? 1 : 0); result = 31 * result + (myCodeUsages ? 1 : 0); result = 31 * result + (myUsageTypeFilteringAvailable ? 1 : 0); + result = 31 * result + (myExcludeAvailable ? 1 : 0); result = 31 * result + (myUsagesWord != null ? myUsagesWord.hashCode() : 0); result = 31 * result + (myTabName != null ? myTabName.hashCode() : 0); result = 31 * result + (myToolwindowTitle != null ? myToolwindowTitle.hashCode() : 0); diff --git a/platform/usageView/src/com/intellij/usages/impl/UsageViewImpl.java b/platform/usageView/src/com/intellij/usages/impl/UsageViewImpl.java index 5fb1e51df688..0c279e77df35 100644 --- a/platform/usageView/src/com/intellij/usages/impl/UsageViewImpl.java +++ b/platform/usageView/src/com/intellij/usages/impl/UsageViewImpl.java @@ -37,7 +37,10 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.ui.SimpleToolWindowPanel; import com.intellij.openapi.ui.Splitter; -import com.intellij.openapi.util.*; +import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.Factory; +import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.vfs.ReadonlyStatusHandler; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; @@ -272,7 +275,7 @@ public class UsageViewImpl implements UsageView, UsageModelTracker.UsageModelTra @Override public boolean isActionEnabled(boolean isExcludeAction) { - return true; + return getPresentation().isExcludeAvailable(); } @Override diff --git a/platform/util/src/com/intellij/icons/AllIcons.java b/platform/util/src/com/intellij/icons/AllIcons.java index 17f75185e7b5..06e71b0bc314 100644 --- a/platform/util/src/com/intellij/icons/AllIcons.java +++ b/platform/util/src/com/intellij/icons/AllIcons.java @@ -1267,10 +1267,14 @@ public class AllIcons { } public static class Windows { - public static final Icon Close = IconLoader.getIcon("/windows/close.png"); // 16x16 - public static final Icon Iconify = IconLoader.getIcon("/windows/iconify.png"); // 16x16 - public static final Icon Maximize = IconLoader.getIcon("/windows/maximize.png"); // 16x16 + public static final Icon CloseActive = IconLoader.getIcon("/windows/closeActive.png"); // 16x16 + public static final Icon CloseHover = IconLoader.getIcon("/windows/closeHover.png"); // 16x16 + public static final Icon CloseInactive = IconLoader.getIcon("/windows/closeInactive.png"); // 16x16 + public static final Icon MaximizeInactive = IconLoader.getIcon("/windows/maximizeInactive.png"); // 16x16 public static final Icon Minimize = IconLoader.getIcon("/windows/minimize.png"); // 16x16 + public static final Icon MinimizeInactive = IconLoader.getIcon("/windows/minimizeInactive.png"); // 16x16 + public static final Icon Restore = IconLoader.getIcon("/windows/restore.png"); // 16x16 + public static final Icon RestoreInactive = IconLoader.getIcon("/windows/restoreInactive.png"); // 16x16 public static class Shadow { public static final Icon Bottom = IconLoader.getIcon("/windows/shadow/bottom.png"); // 1x8 diff --git a/platform/util/src/com/intellij/util/RetinaImage.java b/platform/util/src/com/intellij/util/RetinaImage.java index c9e0eda32c19..590b78241a4d 100644 --- a/platform/util/src/com/intellij/util/RetinaImage.java +++ b/platform/util/src/com/intellij/util/RetinaImage.java @@ -17,6 +17,7 @@ package com.intellij.util; import com.intellij.openapi.util.SystemInfo; import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.NotNull; import java.awt.*; import java.awt.image.BufferedImage; @@ -50,6 +51,7 @@ public class RetinaImage { * @param observer the raw image observer * @return the Retina-aware wrapper */ + @NotNull public static Image createFrom(Image image, final int scale, ImageObserver observer) { int w = image.getWidth(observer); int h = image.getHeight(observer); @@ -65,11 +67,13 @@ public class RetinaImage { return hidpi; } + @NotNull public static BufferedImage create(final int width, int height, int type) { return create(null, width, height, type); } + @NotNull private static BufferedImage create(Image image, final int width, int height, int type) { if (SystemInfo.isAppleJvm) { return AppleHiDPIScaledImage.create(width, height, type); diff --git a/platform/util/src/com/intellij/util/concurrency/SchedulingWrapper.java b/platform/util/src/com/intellij/util/concurrency/SchedulingWrapper.java index 52aad13bc246..bdf89a41ddd6 100644 --- a/platform/util/src/com/intellij/util/concurrency/SchedulingWrapper.java +++ b/platform/util/src/com/intellij/util/concurrency/SchedulingWrapper.java @@ -183,8 +183,7 @@ class SchedulingWrapper implements ScheduledExecutorService { @Override public int compareTo(@NotNull Delayed other) { - if (other == this) // compare zero if same object - { + if (other == this) { return 0; } if (other instanceof MyScheduledFutureTask) { diff --git a/platform/util/src/com/intellij/util/diff/Diff.java b/platform/util/src/com/intellij/util/diff/Diff.java index 7cf36e31e5e3..627fc2db358c 100644 --- a/platform/util/src/com/intellij/util/diff/Diff.java +++ b/platform/util/src/com/intellij/util/diff/Diff.java @@ -35,22 +35,6 @@ import java.util.BitSet; public class Diff { private static final Logger LOG = Logger.getInstance("#com.intellij.util.diff.Diff"); - @Nullable - public static Change buildChangesSomehow(@NotNull T[] objects1, @NotNull T[] objects2) { - try { - return buildChanges(objects1, objects2); - } - catch (FilesTooBigForDiffException e) { - final int startShift = getStartShift(objects1, objects2); - final int endCut = getEndCut(objects1, objects2, startShift); - - int trimmedLength1 = objects1.length - startShift - endCut; - int trimmedLength2 = objects2.length - startShift - endCut; - - return new Change(startShift, startShift, trimmedLength1, trimmedLength2, null); - } - } - @Nullable public static Change buildChanges(@NotNull CharSequence before, @NotNull CharSequence after) throws FilesTooBigForDiffException { final String[] strings1 = LineTokenizer.tokenize(before, false); diff --git a/platform/util/src/com/intellij/util/ui/UIUtil.java b/platform/util/src/com/intellij/util/ui/UIUtil.java index a5ef76f881ef..ec24c55d3434 100644 --- a/platform/util/src/com/intellij/util/ui/UIUtil.java +++ b/platform/util/src/com/intellij/util/ui/UIUtil.java @@ -1779,6 +1779,7 @@ public class UIUtil { } } + @NotNull public static BufferedImage createImage(int width, int height, int type) { if (isRetina()) { return RetinaImage.create(width, height, type); @@ -1787,6 +1788,7 @@ public class UIUtil { return new BufferedImage(width, height, type); } + @NotNull public static BufferedImage createImageForGraphics(Graphics2D g, int width, int height, int type) { if (isRetina(g)) { return RetinaImage.create(width, height, type); diff --git a/platform/vcs-impl/src/com/intellij/diff/Block.java b/platform/vcs-impl/src/com/intellij/diff/Block.java index 5bff2d3acbf0..1e333cf119a4 100644 --- a/platform/vcs-impl/src/com/intellij/diff/Block.java +++ b/platform/vcs-impl/src/com/intellij/diff/Block.java @@ -15,6 +15,9 @@ */ package com.intellij.diff; +import com.intellij.diff.comparison.ByLine; +import com.intellij.diff.comparison.ComparisonPolicy; +import com.intellij.diff.comparison.DiffTooBigException; import com.intellij.diff.comparison.iterables.DiffIterableUtil; import com.intellij.diff.comparison.iterables.FairDiffIterable; import com.intellij.diff.util.Range; @@ -64,39 +67,50 @@ public class Block { int end = -1; int shift = 0; - FairDiffIterable iterable = DiffIterableUtil.diffSomehow(prevContent, mySource, DumbProgressIndicator.INSTANCE); - for (Pair pair : DiffIterableUtil.iterateAll(iterable)) { - Boolean equals = pair.second; - Range range = pair.first; - if (!equals) { - if (Math.max(myStart, range.start2) < Math.min(myEnd, range.end2)) { - // ranges intersect - if (range.start2 <= myStart) start = range.start1; - if (range.end2 > myEnd) end = range.end1; - } - if (range.start2 > myStart) { - if (start == -1) start = myStart - shift; - if (end == -1 && range.start2 >= myEnd) end = myEnd - shift; - } + try { + FairDiffIterable iterable = ByLine.compare(Arrays.asList(prevContent), Arrays.asList(mySource), + ComparisonPolicy.IGNORE_WHITESPACES, DumbProgressIndicator.INSTANCE); - shift += (range.end2 - range.start2) - (range.end1 - range.start1); - } - else { - // intern strings, reducing memory usage - int count = range.end1 - range.start1; - for (int i = 0; i < count; i++) { - prevContent[range.start1 + i] = mySource[range.start2 + i]; + for (Pair pair : DiffIterableUtil.iterateAll(iterable)) { + Boolean equals = pair.second; + Range range = pair.first; + if (!equals) { + if (Math.max(myStart, range.start2) < Math.min(myEnd, range.end2)) { + // ranges intersect + if (range.start2 <= myStart) start = range.start1; + if (range.end2 > myEnd) end = range.end1; + } + if (range.start2 > myStart) { + if (start == -1) start = myStart - shift; + if (end == -1 && range.start2 >= myEnd) end = myEnd - shift; + } + + shift += (range.end2 - range.start2) - (range.end1 - range.start1); + } + else { + // intern strings, reducing memory usage + int count = range.end1 - range.start1; + for (int i = 0; i < count; i++) { + int prevIndex = range.start1 + i; + int sourceIndex = range.start2 + i; + if (prevContent[prevIndex].equals(mySource[sourceIndex])) { + prevContent[prevIndex] = mySource[sourceIndex]; + } + } } } - } - if (start == -1) start = myStart - shift; - if (end == -1) end = myEnd - shift; + if (start == -1) start = myStart - shift; + if (end == -1) end = myEnd - shift; - if (start < 0 || end > prevContent.length || end < start) { - LOG.error("Invalid block range: [" + start + ", " + end + "); length - " + prevContent.length); - } + if (start < 0 || end > prevContent.length || end < start) { + LOG.error("Invalid block range: [" + start + ", " + end + "); length - " + prevContent.length); + } - return new Block(prevContent, start, end); + return new Block(prevContent, start, end); + } + catch (DiffTooBigException e) { + return new Block(prevContent, 0, 0); + } } @NotNull diff --git a/platform/vcs-impl/src/com/intellij/openapi/diff/impl/patch/formove/PatchApplier.java b/platform/vcs-impl/src/com/intellij/openapi/diff/impl/patch/formove/PatchApplier.java index b1d7de38617a..58c34c7a2a0a 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/diff/impl/patch/formove/PatchApplier.java +++ b/platform/vcs-impl/src/com/intellij/openapi/diff/impl/patch/formove/PatchApplier.java @@ -182,8 +182,11 @@ public class PatchApplier { // listeners finished, all 'legal' file additions/deletions with VCS are done trigger.processIt(); LocalHistory.getInstance().putSystemLabel(myProject, "After patch"); // insert a label to be visible in local history dialog - if (myStatus == ApplyPatchStatus.FAILURE || myStatus == ApplyPatchStatus.ABORT) { - suggestRollback(myProject, Collections.singletonList(PatchApplier.this), beforeLabel); + if (myStatus == ApplyPatchStatus.FAILURE) { + suggestRollback(myProject, Collections.singletonList(PatchApplier.this), beforeLabel); + } + else if (myStatus == ApplyPatchStatus.ABORT) { + rollbackUnderProgress(myProject, myProject.getBaseDir(), beforeLabel); } if(myShowNotification || !ApplyPatchStatus.SUCCESS.equals(myStatus)) { showApplyStatus(myProject, myStatus); @@ -303,9 +306,12 @@ public class PatchApplier { directlyAffected.addAll(trigger.getAffected()); final Consumer> mover = localChangeList == null ? null : createMover(project, localChangeList); refreshPassedFilesAndMoveToChangelist(project, directlyAffected, indirectlyAffected, mover); - if (result == ApplyPatchStatus.FAILURE || result == ApplyPatchStatus.ABORT) { + if (result == ApplyPatchStatus.FAILURE) { suggestRollback(project, group, beforeLabel); } + else if (result == ApplyPatchStatus.ABORT) { + rollbackUnderProgress(project, project.getBaseDir(), beforeLabel); + } showApplyStatus(project, result); return result; } @@ -343,17 +349,16 @@ public class PatchApplier { private static void rollbackUnderProgress(@NotNull final Project project, @NotNull final VirtualFile virtualFile, @NotNull final Label labelToRevert) { - ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() { - @Override - public void run() { - try { - labelToRevert.revert(project, virtualFile); - } - catch (LocalHistoryException e) { - VcsNotifier.getInstance(project) - .notifyImportantWarning("Rollback Failed", String.format("Try using local history dialog for %s and perform revert manually.", - virtualFile.getName())); - } + ProgressManager.getInstance().runProcessWithProgressSynchronously(() -> { + try { + labelToRevert.revert(project, virtualFile); + VcsNotifier.getInstance(project) + .notifyImportantWarning("Apply Patch Aborted", "All files changed during apply patch action were rolled back"); + } + catch (LocalHistoryException e) { + VcsNotifier.getInstance(project) + .notifyImportantWarning("Rollback Failed", String.format("Try using local history dialog for %s and perform revert manually.", + virtualFile.getName())); } }, "Rollback Applied Changes...", true, project); } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/ApplyPatchAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/ApplyPatchAction.java index dea34c26131a..ca9f03df7694 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/ApplyPatchAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/ApplyPatchAction.java @@ -241,9 +241,9 @@ public class ApplyPatchAction extends DumbAwareAction { @Override public boolean value(MergeTool.MergeViewer viewer) { int result = Messages.showYesNoCancelDialog(viewer.getComponent().getRootPane(), - "Would you like to abort applying patch action?", + "Would you like to (A)bort&Rollback applying patch action or (S)kip this file?", "Close Merge", - "Abort", "Skip File", "Cancel", Messages.getQuestionIcon()); + "_Abort", "_Skip", "Cancel", Messages.getQuestionIcon()); if (result == Messages.YES) { applyPatchStatusReference.set(ApplyPatchStatus.ABORT); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/ApplyPatchDifferentiatedDialog.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/ApplyPatchDifferentiatedDialog.java index 3a4f74e753e6..6d234ea67fd7 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/ApplyPatchDifferentiatedDialog.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/ApplyPatchDifferentiatedDialog.java @@ -60,7 +60,6 @@ import com.intellij.ui.*; import com.intellij.util.Alarm; import com.intellij.util.Consumer; import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.containers.Convertor; import com.intellij.util.containers.MultiMap; import com.intellij.util.ui.JBUI; import com.intellij.util.ui.UIUtil; @@ -196,7 +195,7 @@ public class ApplyPatchDifferentiatedDialog extends DialogWrapper { myReset = myCanChangePatchFile ? this::reset : EmptyRunnable.getInstance(); myChangeListChooser = new ChangeListChooserPanel(project, errorMessage -> { - setOKActionEnabled(errorMessage == null); + setOKActionEnabled(errorMessage == null && isChangeTreeEnabled()); setErrorText(errorMessage); }); ChangeListManager changeListManager = ChangeListManager.getInstance(project); @@ -244,7 +243,15 @@ public class ApplyPatchDifferentiatedDialog extends DialogWrapper { } private void updateOkActions() { - setOKActionEnabled(!myChangesTreeList.getIncludedChanges().isEmpty()); + boolean changeTreeEnabled = isChangeTreeEnabled(); + setOKActionEnabled(changeTreeEnabled); + if (changeTreeEnabled) { + myChangeListChooser.updateEnabled(); + } + } + + private boolean isChangeTreeEnabled() { + return !myChangesTreeList.getIncludedChanges().isEmpty(); } private void queueRequest() { @@ -371,6 +378,7 @@ public class ApplyPatchDifferentiatedDialog extends DialogWrapper { myReader = patchReader; updateTree(true); paintBusy(false); + updateOkActions(); }, ModalityState.stateForComponent(myCenterPanel)); } } @@ -519,8 +527,7 @@ public class ApplyPatchDifferentiatedDialog extends DialogWrapper { protected DefaultTreeModel buildTreeModel(List changes, ChangeNodeDecorator changeNodeDecorator) { TreeModelBuilder builder = new TreeModelBuilder(myProject, isShowFlatten()); - return builder.buildModel(ObjectsConvertor.convert(changes, - (Convertor)o -> o), changeNodeDecorator); + return builder.buildModel(ObjectsConvertor.convert(changes, o -> o), changeNodeDecorator); } @Override diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangeListChooserPanel.form b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangeListChooserPanel.form deleted file mode 100644 index 7228db028df1..000000000000 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangeListChooserPanel.form +++ /dev/null @@ -1,50 +0,0 @@ - -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangeListChooserPanel.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangeListChooserPanel.java index 363d5f1e319f..1c93f351669a 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangeListChooserPanel.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangeListChooserPanel.java @@ -15,20 +15,23 @@ */ package com.intellij.openapi.vcs.changes.ui; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; +import com.intellij.openapi.editor.ex.EditorEx; +import com.intellij.openapi.fileTypes.FileTypes; import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.ui.ComboBox; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.vcs.VcsBundle; import com.intellij.openapi.vcs.VcsConfiguration; import com.intellij.openapi.vcs.changes.ChangeList; import com.intellij.openapi.vcs.changes.ChangeListManager; import com.intellij.openapi.vcs.changes.LocalChangeList; import com.intellij.openapi.vcs.changes.committed.CommittedChangeListRenderer; -import com.intellij.openapi.vcs.changes.issueLinks.IssueLinkRenderer; -import com.intellij.openapi.wm.IdeFocusManager; import com.intellij.ui.*; import com.intellij.util.NullableConsumer; -import com.intellij.util.ui.UIUtil; +import com.intellij.util.ObjectUtils; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.CalledInAwt; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -36,140 +39,144 @@ import javax.swing.*; import java.awt.*; import java.awt.event.FocusAdapter; import java.awt.event.FocusEvent; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; -import java.util.*; +import java.util.Collection; +import java.util.Collections; import java.util.List; -/** - * @author yole - */ -public class ChangeListChooserPanel extends JPanel { - private static final Comparator CHANGE_LIST_COMPARATOR = new Comparator() { - @Override - public int compare(ChangeList o1, ChangeList o2) { - return o1.getName().compareToIgnoreCase(o2.getName()); - } - }; +import static com.intellij.codeInsight.completion.ComboEditorCompletionContributor.CONTINUE_RUN_COMPLETION; - private JPanel myPanel; - private JRadioButton myRbExisting; - private JRadioButton myRbNew; - private JComboBox myExistingListsCombo; - private NewEditChangelistPanel myNewListPanel; +public class ChangeListChooserPanel extends JPanel { + + private final MyEditorComboBox myExistingListsCombo; + private final NewEditChangelistPanel myListPanel; private final NullableConsumer myOkEnabledListener; - private Project myProject; + private final Project myProject; + private String myLastTypedDescription; public ChangeListChooserPanel(final Project project, @NotNull final NullableConsumer okEnabledListener) { super(new BorderLayout()); myProject = project; - myOkEnabledListener = okEnabledListener; - add(myPanel, BorderLayout.CENTER); - - myRbExisting.addItemListener(new ItemListener() { - public void itemStateChanged(ItemEvent e) { - updateEnabledItems(); - } - }); - } - - public void init() { - myExistingListsCombo.setRenderer(new ColoredListCellRendererWrapper() { - private final IssueLinkRenderer myLinkRenderer = new IssueLinkRenderer(myProject, this); - + myExistingListsCombo = new MyEditorComboBox(project); + myExistingListsCombo.setEditable(true); + myExistingListsCombo.setRenderer(new ColoredListCellRenderer() { @Override - protected void doCustomize(JList list, Object value, int index, boolean selected, boolean hasFocus) { - if (value instanceof LocalChangeList) { - String name = ((LocalChangeList) value).getName(); - - if (myExistingListsCombo.getWidth() == 0) { + protected void customizeCellRenderer(@NotNull JList list, + String value, + int index, + boolean selected, + boolean hasFocus) { + if (value != null) { + String name = value; + LocalChangeList changeList = ChangeListManager.getInstance(myProject).findChangeList(name); + int visibleWidth = myExistingListsCombo.getEditorTextField().getVisibleRect().width; + if (visibleWidth == 0) { name = name.length() > 10 ? name.substring(0, 7) + " .." : name; } else { final FontMetrics fm = list.getFontMetrics(list.getFont()); final int width = fm.stringWidth(name); - final int listWidth = myExistingListsCombo.getWidth(); - if ((listWidth > 0) && (width > listWidth)) { - final String truncated = CommittedChangeListRenderer.truncateDescription(name, fm, listWidth - fm.stringWidth(" ..") - 7); + if ((visibleWidth > 0) && (width > visibleWidth)) { + final String truncated = CommittedChangeListRenderer + .truncateDescription(name, fm, visibleWidth - fm.stringWidth(" ..") - 7); if (truncated.length() > 5) { name = truncated + " .."; } } } - myLinkRenderer.appendTextWithLinks(name, ((LocalChangeList)value).isDefault() - ? SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES : SimpleTextAttributes.REGULAR_ATTRIBUTES); + append(name, changeList != null && changeList.isDefault() + ? SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES + : SimpleTextAttributes.REGULAR_ATTRIBUTES); } } }); - myNewListPanel.init(null); - myRbNew.addFocusListener(new FocusAdapter() { + myListPanel = new NewEditChangelistPanel(myProject) { + @Override - public void focusGained(FocusEvent e) { - if (myRbNew.isSelected()) { - IdeFocusManager.getInstance(myProject).requestFocus(myNewListPanel.getPreferredFocusedComponent(), true); - } + protected NewEditChangelistPanel.ComponentWithTextFieldWrapper createComponentWithTextField(Project project) { + return new ComponentWithTextFieldWrapper(myExistingListsCombo) { + @NotNull + @Override + public EditorTextField getEditorTextField() { + return myExistingListsCombo.getEditorTextField(); + } + }; } - }); - final ComboboxSpeedSearch search = new ComboboxSpeedSearch(myExistingListsCombo); - search.setComparator(new SpeedSearchComparator(true, false)); + + @Override + @CalledInAwt + protected void nameChanged(String errorMessage) { + //invoke later because of undo manager problem: when you try to undo changelist after description was already changed manually + ApplicationManager.getApplication().invokeLater(() -> updateDescription(), ModalityState.current()); + myOkEnabledListener.consume(errorMessage); + } + + @Override + public void init(LocalChangeList initial) { + super.init(initial); + myDescriptionTextArea.addFocusListener(new FocusAdapter() { + @Override + public void focusLost(FocusEvent e) { + super.focusLost(e); + if (getExistingChangelist() == null) { + myLastTypedDescription = myListPanel.getDescription(); + } + } + }); + } + + @Override + protected void nameChangedImpl(Project project, LocalChangeList initial) { + nameChanged(StringUtil.isEmptyOrSpaces(getChangeListName()) ? "Cannot create new changelist with empty name." : null); + } + }; + myOkEnabledListener = okEnabledListener; + add(myListPanel, BorderLayout.CENTER); + } + + public void init() { + myListPanel.init(null); } public void setChangeLists(Collection changeLists) { - List list = new ArrayList(changeLists); - Collections.sort(list, CHANGE_LIST_COMPARATOR); - myExistingListsCombo.setModel(new CollectionComboBoxModel(list, null)); + List changelistNames = ContainerUtil.map(changeLists, ChangeList::getName); + Collections.sort(changelistNames); + myExistingListsCombo.setModel(new CollectionComboBoxModel(changelistNames)); } public void setDefaultName(String name) { - if (! StringUtil.isEmptyOrSpaces(name)) { - myNewListPanel.setChangeListName(name); + if (!StringUtil.isEmptyOrSpaces(name)) { + myListPanel.setChangeListName(name); } } - private void updateEnabledItems() { - if (myRbExisting.isSelected()) { - myExistingListsCombo.setEnabled(true); - UIUtil.setEnabled(myNewListPanel, false, true); - myExistingListsCombo.requestFocus(); - } - else { - myExistingListsCombo.setEnabled(false); - UIUtil.setEnabled(myNewListPanel, true, true); - myNewListPanel.requestFocus(); - } + public void updateEnabled() { if (myProject != null) { - myNewListPanel.nameChangedImpl(myProject, null); + myListPanel.nameChangedImpl(myProject, null); } } + /** + * Method used as getResult, usually invoked inside doOkAction + */ @Nullable public LocalChangeList getSelectedList(Project project) { ChangeListManager manager = ChangeListManager.getInstance(project); - if (myRbNew.isSelected()) { - String newText = myNewListPanel.getChangeListName(); - if (manager.findChangeList(newText) != null) { - Messages.showErrorDialog(project, - VcsBundle.message("changes.newchangelist.warning.already.exists.text", newText), - VcsBundle.message("changes.newchangelist.warning.already.exists.title")); - return null; - } - } - final boolean existingSelected = myRbExisting.isSelected(); - VcsConfiguration.getInstance(myProject).PRESELECT_EXISTING_CHANGELIST = existingSelected; + String changeListName = myListPanel.getChangeListName(); + LocalChangeList localChangeList = manager.findChangeList(changeListName); - if (existingSelected) { - return (LocalChangeList)myExistingListsCombo.getSelectedItem(); + if (localChangeList == null) { + localChangeList = manager.addChangeList(changeListName, myListPanel.getDescription()); + myListPanel.changelistCreatedOrChanged(localChangeList); } else { - LocalChangeList changeList = manager.addChangeList(myNewListPanel.getChangeListName(), myNewListPanel.getDescription()); - myNewListPanel.changelistCreatedOrChanged(changeList); - if (myNewListPanel.getMakeActiveCheckBox().isSelected()) { - manager.setDefaultChangeList(changeList); - } - VcsConfiguration.getInstance(project).MAKE_NEW_CHANGELIST_ACTIVE = myNewListPanel.getMakeActiveCheckBox().isSelected(); - - return changeList; + //update description if changed + localChangeList.setComment(myListPanel.getDescription()); } + if (myListPanel.getMakeActiveCheckBox().isSelected()) { + manager.setDefaultChangeList(localChangeList); + } + VcsConfiguration.getInstance(project).MAKE_NEW_CHANGELIST_ACTIVE = myListPanel.getMakeActiveCheckBox().isSelected(); + return localChangeList; } public void setDefaultSelection(final ChangeList defaultSelection) { @@ -177,34 +184,46 @@ public class ChangeListChooserPanel extends JPanel { myExistingListsCombo.setSelectedIndex(0); } else { - myExistingListsCombo.setSelectedItem(defaultSelection); - } - //if defaultSelection was predefined as null then it means we could not use existing is this context - if (defaultSelection != null && VcsConfiguration.getInstance(myProject).PRESELECT_EXISTING_CHANGELIST) { - myRbExisting.setSelected(true); - } - else { - myRbNew.setSelected(true); + myExistingListsCombo.setSelectedItem(defaultSelection.getName()); } + updateDescription(); + updateEnabled(); + } - updateEnabledItems(); + private void updateDescription() { + LocalChangeList list = getExistingChangelist(); + String newText = list != null ? list.getComment() : myLastTypedDescription; + if (!StringUtil.equals(myListPanel.getDescription(), newText)) { + myListPanel.setDescription(newText); + } + } + + private LocalChangeList getExistingChangelist() { + ChangeListManager manager = ChangeListManager.getInstance(myProject); + String changeListName = myListPanel.getChangeListName(); + return manager.findChangeList(changeListName); } public JComponent getPreferredFocusedComponent() { - return myRbExisting.isSelected() ? myExistingListsCombo : myNewListPanel.getPreferredFocusedComponent(); + return myExistingListsCombo; } - private void createUIComponents() { - myNewListPanel = new NewEditChangelistPanel(myProject) { + private static class MyEditorComboBox extends ComboBox { - @Override - protected void nameChanged(String errorMessage) { - if (myRbExisting.isSelected()) { - myOkEnabledListener.consume(null); - } else { - myOkEnabledListener.consume(errorMessage); + public MyEditorComboBox(Project project) { + super(); + setEditor(new StringComboboxEditor(project, FileTypes.PLAIN_TEXT, this) { + @Override + protected void onEditorCreate(EditorEx editor) { + super.onEditorCreate(editor); + getDocument().putUserData(CONTINUE_RUN_COMPLETION, true); } - } - }; + }); + } + + @NotNull + private EditorTextField getEditorTextField() { + return ObjectUtils.assertNotNull((EditorTextField)getEditor().getEditorComponent()); + } } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/NewEditChangelistPanel.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/NewEditChangelistPanel.java index e9a1fa117556..98260d3f6a08 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/NewEditChangelistPanel.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/NewEditChangelistPanel.java @@ -17,8 +17,8 @@ package com.intellij.openapi.vcs.changes.ui; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.editor.SpellCheckingEditorCustomizationProvider; +import com.intellij.openapi.editor.event.DocumentAdapter; import com.intellij.openapi.editor.event.DocumentEvent; -import com.intellij.openapi.editor.event.DocumentListener; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.fileTypes.FileTypes; import com.intellij.openapi.project.Project; @@ -30,19 +30,20 @@ import com.intellij.ui.*; import com.intellij.util.Consumer; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.JBUI; +import org.jetbrains.annotations.NotNull; import javax.swing.*; import java.awt.*; import java.util.Set; public abstract class NewEditChangelistPanel extends JPanel { - private EditorTextField myNameTextField; - private EditorTextField myDescriptionTextArea; - private JPanel myAdditionalControlsPanel; - private JCheckBox myMakeActiveCheckBox; + protected final EditorTextField myNameTextField; + protected final EditorTextField myDescriptionTextArea; + private final JPanel myAdditionalControlsPanel; + private final JCheckBox myMakeActiveCheckBox; private Consumer myConsumer; - private final Project myProject; + protected final Project myProject; public NewEditChangelistPanel(final Project project) { super(new GridBagLayout()); @@ -52,14 +53,15 @@ public abstract class NewEditChangelistPanel extends JPanel { final JLabel nameLabel = new JLabel(VcsBundle.message("edit.changelist.name")); add(nameLabel, gb); - ++ gb.gridx; + ++gb.gridx; gb.fill = GridBagConstraints.HORIZONTAL; gb.weightx = 1; - myNameTextField = createEditorField(project, 1); + ComponentWithTextFieldWrapper componentWithTextField = createComponentWithTextField(project); + myNameTextField = componentWithTextField.getEditorTextField(); myNameTextField.setOneLineMode(true); myNameTextField.setText("New changelist"); myNameTextField.selectAll(); - add(myNameTextField, gb); + add(componentWithTextField.myComponent, gb); nameLabel.setLabelFor(myNameTextField); ++ gb.gridy; @@ -100,11 +102,7 @@ public abstract class NewEditChangelistPanel extends JPanel { support.installSearch(myNameTextField, myDescriptionTextArea); myConsumer = support.addControls(myAdditionalControlsPanel, initial); } - myNameTextField.getDocument().addDocumentListener(new DocumentListener() { - @Override - public void beforeDocumentChange(DocumentEvent event) { - } - + myNameTextField.getDocument().addDocumentListener(new DocumentAdapter() { @Override public void documentChanged(DocumentEvent event) { nameChangedImpl(myProject, initial); @@ -160,6 +158,17 @@ public abstract class NewEditChangelistPanel extends JPanel { protected abstract void nameChanged(String errorMessage); + protected ComponentWithTextFieldWrapper createComponentWithTextField(Project project) { + final EditorTextField editorTextField = createEditorField(project, 1); + return new ComponentWithTextFieldWrapper(editorTextField) { + @NotNull + @Override + public EditorTextField getEditorTextField() { + return editorTextField; + } + }; + } + private static EditorTextField createEditorField(final Project project, final int defaultLines) { final EditorTextFieldProvider service = ServiceManager.getService(project, EditorTextFieldProvider.class); final EditorTextField editorField; @@ -178,4 +187,15 @@ public abstract class NewEditChangelistPanel extends JPanel { editorField.getComponent().setMinimumSize(new Dimension(100, (int)(height * 1.3))); return editorField; } + + protected abstract static class ComponentWithTextFieldWrapper { + @NotNull private final Component myComponent; + + public ComponentWithTextFieldWrapper(@NotNull Component component) { + myComponent = component; + } + + @NotNull + abstract EditorTextField getEditorTextField(); + } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/RangesBuilder.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/RangesBuilder.java index 56d7ca2449ee..3f12ec58f470 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/RangesBuilder.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/RangesBuilder.java @@ -15,17 +15,22 @@ */ package com.intellij.openapi.vcs.ex; +import com.intellij.diff.comparison.ByLine; +import com.intellij.diff.comparison.ComparisonPolicy; +import com.intellij.diff.comparison.TrimUtil; +import com.intellij.diff.comparison.iterables.DiffIterableUtil; +import com.intellij.diff.comparison.iterables.FairDiffIterable; import com.intellij.diff.util.DiffUtil; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.util.ArrayUtil; -import com.intellij.util.diff.Diff; +import com.intellij.openapi.progress.DumbProgressIndicator; +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.vcs.ex.Range.InnerRange; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.diff.FilesTooBigForDiffException; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; -import java.util.Collections; import java.util.List; public class RangesBuilder { @@ -45,131 +50,166 @@ public class RangesBuilder { @NotNull public static List createRanges(@NotNull List current, @NotNull List vcs, - int shift, + int currentShift, int vcsShift, boolean innerWhitespaceChanges) throws FilesTooBigForDiffException { - Diff.Change ch = Diff.buildChanges(ArrayUtil.toStringArray(vcs), ArrayUtil.toStringArray(current)); + if (innerWhitespaceChanges) { + return createRangesSmart(current, vcs, currentShift, vcsShift); + } + else { + return createRangesSimple(current, vcs, currentShift, vcsShift); + } + } + + @NotNull + private static List createRangesSimple(@NotNull List current, + @NotNull List vcs, + int currentShift, + int vcsShift) throws FilesTooBigForDiffException { + FairDiffIterable iterable = ByLine.compare(vcs, current, ComparisonPolicy.DEFAULT, DumbProgressIndicator.INSTANCE); List result = new ArrayList(); - while (ch != null) { - if (innerWhitespaceChanges) { - result.add(createOnSmart(ch, shift, vcsShift, current, vcs)); - } - else { - result.add(createOn(ch, shift, vcsShift)); - } - ch = ch.link; + for (com.intellij.diff.util.Range range : iterable.iterateChanges()) { + int vcsLine1 = vcsShift + range.start1; + int vcsLine2 = vcsShift + range.end1; + int currentLine1 = currentShift + range.start2; + int currentLine2 = currentShift + range.end2; + + result.add(new Range(currentLine1, currentLine2, vcsLine1, vcsLine2)); } return result; } - private static Range createOn(@NotNull Diff.Change change, int shift, int vcsShift) { - int offset1 = shift + change.line1; - int offset2 = offset1 + change.inserted; + @NotNull + private static List createRangesSmart(@NotNull List current, + @NotNull List vcs, + int shift, + int vcsShift) throws FilesTooBigForDiffException { + FairDiffIterable iwIterable = ByLine.compare(vcs, current, ComparisonPolicy.IGNORE_WHITESPACES, DumbProgressIndicator.INSTANCE); - int uOffset1 = vcsShift + change.line0; - int uOffset2 = uOffset1 + change.deleted; + RangeBuilder rangeBuilder = new RangeBuilder(current, vcs, shift, vcsShift); - return new Range(offset1, offset2, uOffset1, uOffset2); - } + for (Pair pair : DiffIterableUtil.iterateAll(iwIterable)) { + com.intellij.diff.util.Range range = pair.first; + Boolean equals = pair.second; - private static Range createOnSmart(@NotNull Diff.Change change, - int shift, - int vcsShift, - @NotNull List current, - @NotNull List vcs) throws FilesTooBigForDiffException { - byte type = getChangeType(change); + if (equals) { + int count = range.end1 - range.start1; + for (int i = 0; i < count; i++) { + int vcsIndex = range.start1 + i; + int currentIndex = range.start2 + i; + String vcsLine = vcs.get(vcsIndex); + String currentLine = current.get(currentIndex); - int offset1 = shift + change.line1; - int offset2 = offset1 + change.inserted; - - int uOffset1 = vcsShift + change.line0; - int uOffset2 = uOffset1 + change.deleted; - - if (type != Range.MODIFIED) { - return new Range(offset1, offset2, uOffset1, uOffset2, Collections.singletonList(new Range.InnerRange(offset1, offset2, type))); - } - - LineWrapper[] lines1 = new LineWrapper[change.deleted]; - LineWrapper[] lines2 = new LineWrapper[change.inserted]; - for (int i = 0; i < change.deleted; i++) { - lines1[i] = new LineWrapper(vcs.get(i + change.line0)); - } - for (int i = 0; i < change.inserted; i++) { - lines2[i] = new LineWrapper(current.get(i + change.line1)); - } - - Diff.Change ch = Diff.buildChanges(lines1, lines2); - - List inner = new ArrayList(); - - int last0 = 0; - int last1 = 0; - while (ch != null) { - if (ch.line0 != last0 && ch.line1 != last1) { - byte innerType = Range.EQUAL; - int innerStart = shift + change.line1 + last1; - int innerEnd = shift + change.line1 + ch.line1; - inner.add(new Range.InnerRange(innerStart, innerEnd, innerType)); + if (vcsLine.equals(currentLine)) { + rangeBuilder.flushChange(); + } + else { + rangeBuilder.markChangedWhitespaces(vcsIndex, currentIndex); + } + } + } + else { + rangeBuilder.markChanged(range.start1, range.end1, range.start2, range.end2); } - - byte innerType = getChangeType(ch); - int innerStart = shift + change.line1 + ch.line1; - int innerEnd = innerStart + ch.inserted; - inner.add(new Range.InnerRange(innerStart, innerEnd, innerType)); - - last0 = ch.line0 + ch.deleted; - last1 = ch.line1 + ch.inserted; - - ch = ch.link; - } - if (change.deleted != last0 && change.inserted != last1) { - byte innerType = Range.EQUAL; - int innerStart = shift + change.line1 + last1; - int innerEnd = shift + change.line1 + change.inserted; - inner.add(new Range.InnerRange(innerStart, innerEnd, innerType)); } - return new Range(offset1, offset2, uOffset1, uOffset2, inner); + return rangeBuilder.finish(); } - private static byte getChangeType(@NotNull Diff.Change change) { - if ((change.deleted > 0) && (change.inserted > 0)) return Range.MODIFIED; - if ((change.deleted > 0)) return Range.DELETED; - if ((change.inserted > 0)) return Range.INSERTED; - LOG.error("Unknown change type"); - return Range.EQUAL; - } + private static class RangeBuilder { + @NotNull private final List myCurrent; + @NotNull private final List myVcs; + private final int myCurrentShift; + private final int myVcsShift; - private static class LineWrapper { - @NotNull private final String myLine; - private final int myHash; + @NotNull private final List myRanges = new ArrayList<>(); - public LineWrapper(@NotNull String line) { - myLine = line; - myHash = StringUtil.stringHashCodeIgnoreWhitespaces(line); + private com.intellij.diff.util.Range change; + private ArrayList innerRanges; + + public RangeBuilder(@NotNull List current, + @NotNull List vcs, + int currentShift, + int vcsShift) { + myCurrent = current; + myVcs = vcs; + myCurrentShift = currentShift; + myVcsShift = vcsShift; + } + + public void flushChange() { + if (change == null) return; + + for (InnerRange range : innerRanges) { + range.shift(myCurrentShift); + } + innerRanges.trimToSize(); + + change = TrimUtil.expand(myVcs, myCurrent, change.start1, change.start2, change.end1, change.end2); + + int currentLine1 = myCurrentShift + change.start2; + int currentLine2 = myCurrentShift + change.end2; + int vcsLine1 = myVcsShift + change.start1; + int vcsLine2 = myVcsShift + change.end1; + myRanges.add(new Range(currentLine1, currentLine2, vcsLine1, vcsLine2, innerRanges)); + + change = null; + innerRanges = null; + } + + public void markChangedWhitespaces(int vcsIndex, int currentIndex) { + appendChangedLine(vcsIndex, vcsIndex + 1, currentIndex, currentIndex + 1); + appendInnerEquals(vcsIndex, vcsIndex + 1, currentIndex, currentIndex + 1); + } + + public void markChanged(int vcsStart, int vcsEnd, int currentStart, int currentEnd) { + appendChangedLine(vcsStart, vcsEnd, currentStart, currentEnd); + appendInnerChange(vcsStart, vcsEnd, currentStart, currentEnd); } @NotNull - public String getLine() { - return myLine; + public List finish() { + flushChange(); + return myRanges; } - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - LineWrapper wrapper = (LineWrapper)o; - - if (myHash != wrapper.myHash) return false; - - return StringUtil.equalsIgnoreWhitespaces(myLine, wrapper.myLine); + private void appendChangedLine(int vcsStart, int vcsEnd, int currentStart, int currentEnd) { + if (change == null) { + change = new com.intellij.diff.util.Range(vcsStart, vcsEnd, currentStart, currentEnd); + innerRanges = new ArrayList<>(); + } + else { + assert vcsStart == change.end1; + assert currentStart == change.end2; + change = new com.intellij.diff.util.Range(change.start1, vcsEnd, change.start2, currentEnd); + } } - @Override - public int hashCode() { - return myHash; + private void appendInnerChange(int vcsStart, int vcsEnd, int currentStart, int currentEnd) { + byte type = getChangeType(vcsStart, vcsEnd, currentStart, currentEnd); + innerRanges.add(new InnerRange(currentStart, currentEnd, type)); + } + + private void appendInnerEquals(int vcsStart, int vcsEnd, int currentStart, int currentEnd) { + InnerRange last = ContainerUtil.getLastItem(innerRanges); + if (last == null || last.getType() != Range.EQUAL) { + innerRanges.add(new InnerRange(currentStart, currentEnd, Range.EQUAL)); + } + else { + assert currentStart == last.getLine2(); + innerRanges.set(innerRanges.size() - 1, new InnerRange(last.getLine1(), currentEnd, Range.EQUAL)); + } } } + + private static byte getChangeType(int vcsStart, int vcsEnd, int currentStart, int currentEnd) { + int deleted = vcsEnd - vcsStart; + int inserted = currentEnd - currentStart; + if (deleted > 0 && inserted > 0) return Range.MODIFIED; + if (deleted > 0) return Range.DELETED; + if (inserted > 0) return Range.INSERTED; + LOG.error("Unknown change type"); + return Range.EQUAL; + } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/history/impl/VcsSelectionHistoryDialog.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/history/impl/VcsSelectionHistoryDialog.java index 6f9cb5d3c0f8..891108da0b8e 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/history/impl/VcsSelectionHistoryDialog.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/history/impl/VcsSelectionHistoryDialog.java @@ -228,7 +228,8 @@ public class VcsSelectionHistoryDialog extends FrameWrapper implements DataProvi @Override protected void notifyError(@NotNull VcsException e) { SwingUtilities.invokeLater(() -> { - if (!VcsSelectionHistoryDialog.this.getFrame().isShowing()) return; + VcsSelectionHistoryDialog dialog = VcsSelectionHistoryDialog.this; + if (dialog.isDisposed() || !dialog.getFrame().isShowing()) return; PopupUtil.showBalloonForComponent(mySplitter, canNoLoadMessage(e), MessageType.ERROR, true, myProject); }); } 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 b158bf52d26e..fc1252f72e40 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 @@ -33,6 +33,8 @@ import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; +import com.intellij.openapi.project.ProjectManager; +import com.intellij.openapi.project.ProjectManagerAdapter; import com.intellij.openapi.roots.FileIndexFacade; import com.intellij.openapi.util.*; import com.intellij.openapi.util.io.FileUtil; @@ -128,24 +130,35 @@ public class ProjectLevelVcsManagerImpl extends ProjectLevelVcsManagerEx impleme private final VcsFileListenerContextHelper myVcsFileListenerContextHelper; private final VcsAnnotationLocalChangesListenerImpl myAnnotationLocalChangesListener; - public ProjectLevelVcsManagerImpl(Project project, final FileStatusManager manager, MessageBus messageBus, - final FileIndexFacade excludedFileIndex) { + public ProjectLevelVcsManagerImpl(Project project, + final FileStatusManager manager, + MessageBus messageBus, + final FileIndexFacade excludedFileIndex, + ProjectManager projectManager, + DefaultVcsRootPolicy defaultVcsRootPolicy, + VcsFileListenerContextHelper vcsFileListenerContextHelper) { myProject = project; myMessageBus = messageBus; mySerialization = new ProjectLevelVcsManagerSerialization(); myOptionsAndConfirmations = new OptionsAndConfirmations(); - myDefaultVcsRootPolicy = DefaultVcsRootPolicy.getInstance(project); + myDefaultVcsRootPolicy = defaultVcsRootPolicy; myInitialization = new VcsInitialization(myProject); Disposer.register(project, myInitialization); // wait for the thread spawned in VcsInitialization to terminate + projectManager.addProjectManagerListener(project, new ProjectManagerAdapter() { + @Override + public void projectClosing(Project project) { + Disposer.dispose(myInitialization); + } + }); myMappings = new NewMappings(myProject, myMessageBus, this, manager); myMappingsToRoots = new MappingsToRoots(myMappings, myProject); myVcsHistoryCache = new VcsHistoryCache(); myContentRevisionCache = new ContentRevisionCache(); myConnect = myMessageBus.connect(); - myVcsFileListenerContextHelper = VcsFileListenerContextHelper.getInstance(myProject); + myVcsFileListenerContextHelper = vcsFileListenerContextHelper; VcsListener vcsListener = new VcsListener() { @Override public void directoryMappingChanged() { diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/VcsInitialization.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/VcsInitialization.java index 83498737c18b..b6ee4ff05886 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/VcsInitialization.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/VcsInitialization.java @@ -76,7 +76,7 @@ public class VcsInitialization implements Disposable { } } - public void execute() { + private void execute() { final List> list; synchronized (myLock) { list = myList; @@ -103,6 +103,11 @@ public class VcsInitialization implements Disposable { @Override public void dispose() { myIndicator.cancel(); + cancelBackgroundInitialization(); + } + + private void cancelBackgroundInitialization() { + // do not leave VCS initialization run in background when the project is closed Future future = myFuture; if (future != null) { future.cancel(false); diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/statistics/VcsLogRepoSizeCollector.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/statistics/VcsLogRepoSizeCollector.java index 5fb354443773..37c41b6033d4 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/statistics/VcsLogRepoSizeCollector.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/statistics/VcsLogRepoSizeCollector.java @@ -59,7 +59,7 @@ public class VcsLogRepoSizeCollector extends AbstractApplicationUsagesCollector asList(0, 1, 100, 1000, 10 * 1000, 100 * 1000, 500 * 1000))); for (VcsKey vcs : groupedRoots.keySet()) { usages.add(StatisticsUtilKt.getCountingUsage("data." + vcs.getName().toLowerCase() + ".root.count", groupedRoots.get(vcs).size(), - asList(0, 1, 2, 5, 8, 15, 30, 50, 100))); + asList(0, 1, 2, 5, 8, 15, 30, 50, 100, 500, 1000))); } return usages; } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/controlflow/IfStatementWithIdenticalBranchesInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/controlflow/IfStatementWithIdenticalBranchesInspection.java index 132d88cfd5e8..814fee1e2edb 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/controlflow/IfStatementWithIdenticalBranchesInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/controlflow/IfStatementWithIdenticalBranchesInspection.java @@ -174,8 +174,8 @@ public class IfStatementWithIdenticalBranchesInspection @Override public void visitIfStatement(@NotNull PsiIfStatement ifStatement) { super.visitIfStatement(ifStatement); - final PsiStatement elseBranch = unwrap(ifStatement.getElseBranch()); - final PsiStatement thenBranch = unwrap(ifStatement.getThenBranch()); + final PsiStatement elseBranch = ifStatement.getElseBranch(); + final PsiStatement thenBranch = ifStatement.getThenBranch(); if (thenBranch == null) { return; } @@ -194,7 +194,9 @@ public class IfStatementWithIdenticalBranchesInspection } } - private boolean isDuplicate(@NotNull PsiElement element1, @NotNull PsiElement element2) { + private boolean isDuplicate(@NotNull PsiStatement element1, @NotNull PsiStatement element2) { + element1 = unwrap(element1); + element2 = unwrap(element2); final InputVariables inputVariables = new InputVariables(Collections.emptyList(), element1.getProject(), new LocalSearchScope(element1), false); final DuplicatesFinder finder = new DuplicatesFinder(new PsiElement[]{element1}, inputVariables, null, Collections.emptyList()); diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/controlflow/if_statement_with_identical_branches/IfStatementWithIdenticalBranches.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/controlflow/if_statement_with_identical_branches/IfStatementWithIdenticalBranches.java index 4c57ca5c142d..89b141cfdf73 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/controlflow/if_statement_with_identical_branches/IfStatementWithIdenticalBranches.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/controlflow/if_statement_with_identical_branches/IfStatementWithIdenticalBranches.java @@ -214,4 +214,14 @@ class NotADup { private Object bar(Object x) { return null; } + + void nesting(int i, int j) { + if (i == 2) { + System.out.println("2"); + } else { + if (j == 2) { + System.out.println("2"); + } + } + } } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/GrTraitMethod.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/GrTraitMethod.java index 19f30aab7a27..af4225639c66 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/GrTraitMethod.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/GrTraitMethod.java @@ -25,6 +25,7 @@ public class GrTraitMethod extends LightMethod implements PsiMirrorElement { @NotNull PsiMethod method, @NotNull PsiSubstitutor substitutor) { super(containingClass, method, substitutor); + setNavigationElement(method); } @Override diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/stubs/hierarchy/GrStubIndexer.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/stubs/hierarchy/GrStubIndexer.java index 2a9303c09d62..c124aae6cc20 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/stubs/hierarchy/GrStubIndexer.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/stubs/hierarchy/GrStubIndexer.java @@ -15,7 +15,6 @@ */ package org.jetbrains.plugins.groovy.lang.psi.stubs.hierarchy; -import com.intellij.openapi.util.Pair; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiNameHelper; import com.intellij.psi.impl.java.stubs.hierarchy.IndexTree; @@ -33,7 +32,10 @@ import org.jetbrains.plugins.groovy.GroovyFileType; import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes; import org.jetbrains.plugins.groovy.lang.psi.stubs.*; -import java.util.*; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; public class GrStubIndexer extends StubHierarchyIndexer { @Override @@ -48,14 +50,14 @@ public class GrStubIndexer extends StubHierarchyIndexer { @Nullable @Override - public List> indexFile(@NotNull FileContent content) { + public Unit indexFile(@NotNull FileContent content) { Stub stubTree = StubTreeBuilder.buildStubTree(content); if (!(stubTree instanceof GrFileStub)) return null; GrFileStub grFileStub = (GrFileStub)stubTree; new StubTree(grFileStub, false); - String pid = null; + String pid = ""; ArrayList classList = new ArrayList(); Set usedNames = new HashSet(); for (StubElement el : grFileStub.getChildrenStubs()) { @@ -82,7 +84,7 @@ public class GrStubIndexer extends StubHierarchyIndexer { } ClassDecl[] classes = classList.isEmpty() ? ClassDecl.EMPTY_ARRAY : classList.toArray(new ClassDecl[classList.size()]); Import[] imports = importList.isEmpty() ? Import.EMPTY_ARRAY : importList.toArray(new Import[importList.size()]); - return Collections.singletonList(Pair.create(pid, new Unit(IndexTree.GROOVY, imports, classes))); + return new Unit(pid, IndexTree.GROOVY, imports, classes); } @Nullable diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/Gr23HighlightingTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/Gr23HighlightingTest.groovy index c0e2bc27e838..64d5b720afac 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/Gr23HighlightingTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/Gr23HighlightingTest.groovy @@ -19,6 +19,7 @@ import com.intellij.codeInspection.InspectionProfileEntry import com.intellij.ide.highlighter.JavaFileType import com.intellij.testFramework.LightProjectDescriptor import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.codeInspection.GroovyUnusedDeclarationInspection import org.jetbrains.plugins.groovy.codeInspection.assignment.GroovyAssignabilityCheckInspection import org.jetbrains.plugins.groovy.codeInspection.untypedUnresolvedAccess.GrUnresolvedAccessInspection @@ -460,4 +461,16 @@ class C implements T { ''' myFixture.testHighlighting false, false, false } + + void 'test trait method usages'() { + testHighlighting '''\ +trait T { + def getFoo() {} +} + +class A implements T {} + +new A().foo +''', GroovyUnusedDeclarationInspection + } } diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCUtils.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCUtils.java index 5ab441fd84bf..edd3a7f240ac 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCUtils.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCUtils.java @@ -18,7 +18,6 @@ import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.vfs.VirtualFileEvent; import com.intellij.psi.PsiDirectory; import com.intellij.util.DocumentUtil; import com.intellij.util.Function; @@ -31,7 +30,10 @@ import org.jetbrains.annotations.Nullable; import java.io.File; import java.io.IOException; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Map; public class CCUtils { public static final String ANSWER_EXTENSION_DOTTED = ".answer."; @@ -144,11 +146,8 @@ public class CCUtils { return generatedRoot.get(); } - /** - * @param requestor {@link VirtualFileEvent#getRequestor} - */ @Nullable - public static VirtualFile generateFolder(@NotNull Project project, @NotNull Module module, @Nullable Object requestor, String name) { + public static VirtualFile generateFolder(@NotNull Project project, @NotNull Module module, String name) { VirtualFile generatedRoot = getGeneratedFilesFolder(project, module); if (generatedRoot == null) { return null; @@ -159,9 +158,9 @@ public class CCUtils { ApplicationManager.getApplication().runWriteAction(() -> { try { if (folder.get() != null) { - folder.get().delete(requestor); + folder.get().delete(null); } - folder.set(generatedRoot.createChildDirectory(requestor, name)); + folder.set(generatedRoot.createChildDirectory(null, name)); } catch (IOException e) { LOG.info("Failed to generate folder " + name, e); diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAddAnswerPlaceholder.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAddAnswerPlaceholder.java index 41275862f6f0..0643eaa8cf0c 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAddAnswerPlaceholder.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAddAnswerPlaceholder.java @@ -26,7 +26,7 @@ import java.util.List; public class CCAddAnswerPlaceholder extends CCAnswerPlaceholderAction { public CCAddAnswerPlaceholder() { - super("Add/Delete Answer Placeholder", "Add/Delete answer placeholder", null); + super("Add/Delete Answer Placeholder", "Add/Delete answer placeholder"); } diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAnswerPlaceholderAction.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAnswerPlaceholderAction.java index 4a0479403094..ba3db4d16fb1 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAnswerPlaceholderAction.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAnswerPlaceholderAction.java @@ -14,12 +14,10 @@ import com.jetbrains.edu.learning.courseFormat.TaskFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import javax.swing.*; - abstract public class CCAnswerPlaceholderAction extends DumbAwareAction { - protected CCAnswerPlaceholderAction(@Nullable String text, @Nullable String description, @Nullable Icon icon) { - super(text, description, icon); + protected CCAnswerPlaceholderAction(@Nullable String text, @Nullable String description) { + super(text, description, null); } @Nullable diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCChangeCourseInfo.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCChangeCourseInfo.java index 3423c822aae8..9b0839dacaa6 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCChangeCourseInfo.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCChangeCourseInfo.java @@ -9,7 +9,6 @@ import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogBuilder; import com.intellij.psi.PsiDirectory; -import com.intellij.util.ui.JBUI; import com.jetbrains.edu.coursecreator.CCUtils; import com.jetbrains.edu.coursecreator.ui.CCNewProjectPanel; import com.jetbrains.edu.learning.StudyTaskManager; @@ -17,6 +16,7 @@ import com.jetbrains.edu.learning.courseFormat.Course; import org.jetbrains.annotations.NotNull; import javax.swing.*; +import java.awt.*; public class CCChangeCourseInfo extends DumbAwareAction { @@ -75,7 +75,8 @@ public class CCChangeCourseInfo extends DumbAwareAction { builder.setTitle(ACTION_TEXT); JPanel changeInfoPanel = panel.getMainPanel(); - changeInfoPanel.setMinimumSize(JBUI.size(400, 300)); + changeInfoPanel.setPreferredSize(new Dimension(450, 300)); + changeInfoPanel.setMinimumSize(new Dimension(450, 300)); builder.setCenterPanel(changeInfoPanel); return builder; diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCCreateCourseArchive.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCCreateCourseArchive.java index 8425c71b0483..50e2336444f5 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCCreateCourseArchive.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCCreateCourseArchive.java @@ -77,7 +77,7 @@ public class CCCreateCourseArchive extends DumbAwareAction { final Course course = StudyTaskManager.getInstance(project).getCourse(); if (course == null) return; final VirtualFile baseDir = project.getBaseDir(); - VirtualFile archiveFolder = CCUtils.generateFolder(project, module, null, zipName); + VirtualFile archiveFolder = CCUtils.generateFolder(project, module, zipName); if (archiveFolder == null) { return; } diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCDeleteAllAnswerPlaceholdersAction.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCDeleteAllAnswerPlaceholdersAction.java index 0916e1b678f4..7c10fba712b4 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCDeleteAllAnswerPlaceholdersAction.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCDeleteAllAnswerPlaceholdersAction.java @@ -107,7 +107,7 @@ public class CCDeleteAllAnswerPlaceholdersAction extends DumbAwareAction { private static class ClearPlaceholders implements UndoableAction { private final List myPlaceholders; private final Editor myEditor; - TaskFile myTaskFile; + private final TaskFile myTaskFile; public ClearPlaceholders(TaskFile taskFile, List placeholders, Editor editor) { myTaskFile = taskFile; diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCEditAnswerPlaceholder.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCEditAnswerPlaceholder.java index 622ddacf1cac..72a33a1e0261 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCEditAnswerPlaceholder.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCEditAnswerPlaceholder.java @@ -12,7 +12,7 @@ import org.jetbrains.annotations.NotNull; public class CCEditAnswerPlaceholder extends CCAnswerPlaceholderAction { public CCEditAnswerPlaceholder() { - super("Edit Answer Placeholder", "Edit answer placeholder", null); + super("Edit Answer Placeholder", "Edit answer placeholder"); } @Override diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/handlers/CCLessonMoveHandlerDelegate.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/handlers/CCLessonMoveHandlerDelegate.java index d9d6f5adc3df..15da6057e0c7 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/handlers/CCLessonMoveHandlerDelegate.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/handlers/CCLessonMoveHandlerDelegate.java @@ -21,7 +21,6 @@ import com.intellij.util.Function; import com.jetbrains.edu.coursecreator.CCUtils; import com.jetbrains.edu.coursecreator.ui.CCMoveStudyItemDialog; import com.jetbrains.edu.learning.StudyTaskManager; -import com.jetbrains.edu.coursecreator.CCUtils; import com.jetbrains.edu.learning.core.EduNames; import com.jetbrains.edu.learning.core.EduUtils; import com.jetbrains.edu.learning.courseFormat.Course; diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/handlers/CCTaskMoveHandlerDelegate.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/handlers/CCTaskMoveHandlerDelegate.java index e69a1eeb8523..b37e0093c0b4 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/handlers/CCTaskMoveHandlerDelegate.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/handlers/CCTaskMoveHandlerDelegate.java @@ -17,7 +17,6 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiReference; import com.intellij.refactoring.move.MoveCallback; import com.intellij.refactoring.move.MoveHandlerDelegate; -import com.intellij.util.Function; import com.jetbrains.edu.coursecreator.CCUtils; import com.jetbrains.edu.coursecreator.ui.CCMoveStudyItemDialog; import com.jetbrains.edu.learning.StudyTaskManager; @@ -25,7 +24,6 @@ import com.jetbrains.edu.learning.core.EduNames; import com.jetbrains.edu.learning.core.EduUtils; import com.jetbrains.edu.learning.courseFormat.Course; import com.jetbrains.edu.learning.courseFormat.Lesson; -import com.jetbrains.edu.learning.courseFormat.StudyItem; import com.jetbrains.edu.learning.courseFormat.Task; import org.jetbrains.annotations.Nullable; @@ -91,6 +89,9 @@ public class CCTaskMoveHandlerDelegate extends MoveHandlerDelegate { final Course course = StudyTaskManager.getInstance(project).getCourse(); final PsiDirectory sourceDirectory = (PsiDirectory)elements[0]; + if (course == null) { + return; + } final Task taskToMove = EduUtils.getTask(sourceDirectory, course); if (taskToMove == null) { return; diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/projectView/CCTreeStructureProvider.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/projectView/CCTreeStructureProvider.java index 3ba35d688992..39d0ab89145b 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/projectView/CCTreeStructureProvider.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/projectView/CCTreeStructureProvider.java @@ -12,7 +12,6 @@ import com.jetbrains.edu.learning.StudyUtils; import com.jetbrains.edu.learning.projectView.StudyTreeStructureProvider; import org.jetbrains.annotations.NotNull; -import java.util.ArrayList; import java.util.Collection; public class CCTreeStructureProvider extends StudyTreeStructureProvider { @@ -24,7 +23,7 @@ public class CCTreeStructureProvider extends StudyTreeStructureProvider { if (!needModify(parent)) { return children; } - Collection modifiedChildren = new ArrayList(super.modify(parent, children, settings)); + Collection modifiedChildren = super.modify(parent, children, settings); for (AbstractTreeNode node : children) { Project project = node.getProject(); @@ -41,7 +40,8 @@ public class CCTreeStructureProvider extends StudyTreeStructureProvider { if (virtualFile == null) { continue; } - if (StudyUtils.getTaskFile(project, virtualFile) == null && !StudyUtils.isTaskDescriptionFile(virtualFile.getName())) { + if (project != null && StudyUtils.getTaskFile(project, virtualFile) == null + && !StudyUtils.isTaskDescriptionFile(virtualFile.getName())) { modifiedChildren.add(new CCStudentInvisibleFileNode(project, ((PsiFileNode)node).getValue(), settings)); } } diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/ui/CCCreateAnswerPlaceholderPanel.form b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/ui/CCCreateAnswerPlaceholderPanel.form index 5e4b17d84c04..e5ff6da604d1 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/ui/CCCreateAnswerPlaceholderPanel.form +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/ui/CCCreateAnswerPlaceholderPanel.form @@ -1,6 +1,6 @@
- + @@ -10,64 +10,41 @@ - + + - - + - - - + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/ui/CCCreateAnswerPlaceholderPanel.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/ui/CCCreateAnswerPlaceholderPanel.java index 28cd014d3288..09a6012c5ca7 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/ui/CCCreateAnswerPlaceholderPanel.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/ui/CCCreateAnswerPlaceholderPanel.java @@ -1,5 +1,7 @@ package com.jetbrains.edu.coursecreator.ui; +import com.intellij.ui.JBColor; + import javax.swing.*; import java.awt.*; @@ -14,6 +16,7 @@ public class CCCreateAnswerPlaceholderPanel extends JPanel { add(myPanel, BorderLayout.CENTER); myHintText.setLineWrap(true); myHintText.setWrapStyleWord(true); + myHintText.setBorder(BorderFactory.createLineBorder(JBColor.border())); myAnswerPlaceholderText.grabFocus(); } diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/ui/CCCreateStudyItemPanel.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/ui/CCCreateStudyItemPanel.java index fd4854ffb359..572ba0806508 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/ui/CCCreateStudyItemPanel.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/ui/CCCreateStudyItemPanel.java @@ -8,7 +8,7 @@ public class CCCreateStudyItemPanel extends JPanel { private JPanel myPanel; private JTextField myNameField; private CCItemPositionPanel myPositionalPanel; - private String myThresholdName; + private final String myThresholdName; public CCCreateStudyItemPanel(String itemName, String thresholdName, int thresholdIndex) { myThresholdName = thresholdName; diff --git a/python/educational-core/student/resources/META-INF/plugin.xml b/python/educational-core/student/resources/META-INF/plugin.xml index d950bc814f9b..aafd06787e4e 100644 --- a/python/educational-core/student/resources/META-INF/plugin.xml +++ b/python/educational-core/student/resources/META-INF/plugin.xml @@ -89,7 +89,6 @@ displayName="Education"/> - diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyBasePluginConfigurator.java b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyBasePluginConfigurator.java index 99163eea7916..35ecc643f5bf 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyBasePluginConfigurator.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyBasePluginConfigurator.java @@ -56,6 +56,11 @@ public abstract class StudyBasePluginConfigurator implements StudyPluginConfigur @Override public void fileClosed(@NotNull FileEditorManager source, @NotNull VirtualFile file) { + for (VirtualFile openedFile : source.getOpenFiles()) { + if (StudyUtils.getTaskFile(project, openedFile) != null) { + return; + } + } toolWindow.setEmptyText(project); } diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyProjectComponent.java b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyProjectComponent.java index 44cf72f11f58..5a505d0bb7f3 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyProjectComponent.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyProjectComponent.java @@ -25,15 +25,16 @@ import com.intellij.openapi.wm.ToolWindow; import com.intellij.openapi.wm.ToolWindowAnchor; import com.intellij.openapi.wm.ToolWindowManager; import com.intellij.util.containers.hash.HashMap; +import com.jetbrains.edu.learning.actions.StudyActionWithShortcut; +import com.jetbrains.edu.learning.actions.StudyNextWindowAction; +import com.jetbrains.edu.learning.actions.StudyPrevWindowAction; import com.jetbrains.edu.learning.core.EduNames; import com.jetbrains.edu.learning.core.EduUtils; import com.jetbrains.edu.learning.courseFormat.Course; import com.jetbrains.edu.learning.courseFormat.Lesson; import com.jetbrains.edu.learning.courseFormat.Task; import com.jetbrains.edu.learning.courseFormat.TaskFile; -import com.jetbrains.edu.learning.actions.*; import com.jetbrains.edu.learning.editor.StudyEditorFactoryListener; -import com.jetbrains.edu.learning.ui.StudyProgressToolWindowFactory; import com.jetbrains.edu.learning.ui.StudyToolWindow; import com.jetbrains.edu.learning.ui.StudyToolWindowFactory; import javafx.application.Platform; @@ -93,13 +94,9 @@ public class StudyProjectComponent implements ProjectComponent { final ToolWindowManager toolWindowManager = ToolWindowManager.getInstance(myProject); registerToolWindows(toolWindowManager); final ToolWindow studyToolWindow = toolWindowManager.getToolWindow(StudyToolWindowFactory.STUDY_TOOL_WINDOW); - final ToolWindow progressToolWindow = toolWindowManager.getToolWindow(StudyProgressToolWindowFactory.ID); if (studyToolWindow != null) { studyToolWindow.show(null); - } - if (progressToolWindow != null) { StudyUtils.initToolWindows(myProject); - progressToolWindow.show(null); } } } @@ -118,6 +115,8 @@ public class StudyProjectComponent implements ProjectComponent { } } } + addShortcut(StudyNextWindowAction.ACTION_ID, new String[]{StudyNextWindowAction.SHORTCUT, StudyNextWindowAction.SHORTCUT2}); + addShortcut(StudyPrevWindowAction.ACTION_ID, new String[]{StudyPrevWindowAction.SHORTCUT}); } else { LOG.warn("Actions on toolbar are nulls"); @@ -130,10 +129,6 @@ public class StudyProjectComponent implements ProjectComponent { if (toolWindow == null) { toolWindowManager.registerToolWindow(StudyToolWindowFactory.STUDY_TOOL_WINDOW, true, ToolWindowAnchor.RIGHT, myProject, true); } - ToolWindow progressToolWindow = toolWindowManager.getToolWindow(StudyProgressToolWindowFactory.ID); - if (progressToolWindow == null) { - toolWindowManager.registerToolWindow(StudyProgressToolWindowFactory.ID, true, ToolWindowAnchor.LEFT, myProject, true, true); - } } private void updateCourse() { @@ -221,10 +216,6 @@ public class StudyProjectComponent implements ProjectComponent { if (toolWindow != null) { toolWindow.getContentManager().removeAllContents(false); } - final ToolWindow progressToolWindow = ToolWindowManager.getInstance(myProject).getToolWindow(StudyProgressToolWindowFactory.ID); - if (progressToolWindow != null) { - progressToolWindow.getContentManager().removeAllContents(false); - } KeymapManagerEx keymapManager = KeymapManagerEx.getInstanceEx(); for (Keymap keymap : keymapManager.getAllKeymaps()) { List> pairs = myDeletedShortcuts.get(keymap); diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java index b85cad3d58bf..69542b448629 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java @@ -42,8 +42,8 @@ import com.intellij.psi.PsiFile; import com.intellij.ui.JBColor; import com.intellij.ui.awt.RelativePoint; import com.intellij.ui.content.Content; -import com.intellij.util.TimeoutUtil; import com.intellij.util.ObjectUtils; +import com.intellij.util.TimeoutUtil; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.text.MarkdownUtil; import com.intellij.util.ui.UIUtil; @@ -56,7 +56,6 @@ import com.jetbrains.edu.learning.core.EduUtils; import com.jetbrains.edu.learning.courseFormat.*; import com.jetbrains.edu.learning.courseGeneration.StudyProjectGenerator; import com.jetbrains.edu.learning.editor.StudyEditor; -import com.jetbrains.edu.learning.ui.StudyProgressToolWindowFactory; import com.jetbrains.edu.learning.ui.StudyToolWindow; import com.jetbrains.edu.learning.ui.StudyToolWindowFactory; import com.petebevin.markdown.MarkdownProcessor; @@ -165,10 +164,17 @@ public class StudyUtils { } public static void updateToolWindows(@NotNull final Project project) { - updateStudyToolWindow(project); - - final ToolWindowManager windowManager = ToolWindowManager.getInstance(project); - createProgressToolWindowContent(project, windowManager); + final StudyToolWindow studyToolWindow = getStudyToolWindow(project); + if (studyToolWindow != null) { + String taskText = getTaskText(project); + if (taskText != null) { + studyToolWindow.setTaskText(taskText, null, project); + } + else { + LOG.warn("Task text is null"); + } + studyToolWindow.updateCourseProgress(project); + } } public static void initToolWindows(@NotNull final Project project) { @@ -177,15 +183,8 @@ public class StudyUtils { StudyToolWindowFactory factory = new StudyToolWindowFactory(); factory.createToolWindowContent(project, windowManager.getToolWindow(StudyToolWindowFactory.STUDY_TOOL_WINDOW)); - createProgressToolWindowContent(project, windowManager); } - private static void createProgressToolWindowContent(@NotNull Project project, ToolWindowManager windowManager) { - windowManager.getToolWindow(StudyProgressToolWindowFactory.ID).getContentManager().removeAllContents(false); - StudyProgressToolWindowFactory windowFactory = new StudyProgressToolWindowFactory(); - windowFactory.createToolWindowContent(project, windowManager.getToolWindow(StudyProgressToolWindowFactory.ID)); - } - @Nullable public static StudyToolWindow getStudyToolWindow(@NotNull final Project project) { ToolWindow toolWindow = ToolWindowManager.getInstance(project).getToolWindow(StudyToolWindowFactory.STUDY_TOOL_WINDOW); @@ -558,19 +557,6 @@ public class StudyUtils { return taskFile != null ? taskFile.getTask() : null; } - public static void updateStudyToolWindow(Project project) { - final StudyToolWindow studyToolWindow = getStudyToolWindow(project); - if (studyToolWindow != null) { - String taskText = getTaskText(project); - if (taskText != null) { - studyToolWindow.setTaskText(taskText, null, project); - } - else { - LOG.warn("Task text is null"); - } - } - } - public static boolean isStudyProject(@NotNull Project project) { return StudyTaskManager.getInstance(project).getCourse() != null; } diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyCheckAction.java b/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyCheckAction.java index 04d692333e01..39ef983b5800 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyCheckAction.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyCheckAction.java @@ -21,7 +21,7 @@ import javax.swing.*; public abstract class StudyCheckAction extends StudyActionWithShortcut { public static final String SHORTCUT = "ctrl alt pressed ENTER"; - protected Ref myCheckInProgress = new Ref<>(false); + protected final Ref myCheckInProgress = new Ref<>(false); public StudyCheckAction() { super("Check Task (" + KeymapUtil.getShortcutText(new KeyboardShortcut(KeyStroke.getKeyStroke(SHORTCUT), null)) + ")", "Check current task", InteractiveLearningIcons.CheckTask); diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyNextWindowAction.java b/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyNextWindowAction.java index 01fd8dcbceec..17769a988282 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyNextWindowAction.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyNextWindowAction.java @@ -26,7 +26,7 @@ public class StudyNextWindowAction extends StudyWindowNavigationAction { List windows = window.getTaskFile().getAnswerPlaceholders(); if (StudyUtils.indexIsValid(index, windows)) { int newIndex = index + 1; - return newIndex == windows.size() ? windows.get(0) : windows.get(newIndex); + return windows.get(newIndex == windows.size() ? 0 : newIndex); } return null; } diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyTaskNavigationAction.java b/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyTaskNavigationAction.java index 363e73e37018..614d78671fab 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyTaskNavigationAction.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyTaskNavigationAction.java @@ -20,6 +20,8 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.tree.TreePath; +import java.util.ArrayList; +import java.util.List; import java.util.Map; @@ -44,9 +46,6 @@ abstract public class StudyTaskNavigationAction extends StudyActionWithShortcut int nextTaskIndex = nextTask.getIndex(); int lessonIndex = nextTask.getLesson().getIndex(); Map nextTaskFiles = nextTask.getTaskFiles(); - if (nextTaskFiles.isEmpty()) { - return; - } VirtualFile projectDir = project.getBaseDir(); String lessonDirName = EduNames.LESSON + String.valueOf(lessonIndex); if (projectDir == null) { @@ -61,32 +60,69 @@ abstract public class StudyTaskNavigationAction extends StudyActionWithShortcut if (taskDir == null) { return; } + if (nextTaskFiles.isEmpty()) { + ProjectView.getInstance(project).select(taskDir, taskDir, false); + return; + } VirtualFile shouldBeActive = getFileToActivate(project, nextTaskFiles, taskDir); - JTree tree = ProjectView.getInstance(project).getCurrentProjectViewPane().getTree(); - TreePath path = TreeUtil.getFirstNodePath(tree); - tree.collapsePath(path); - if (shouldBeActive != null) { - ProjectView.getInstance(project).select(shouldBeActive, shouldBeActive, false); - FileEditorManager.getInstance(project).openFile(shouldBeActive, true); - } + + updateProjectView(project, shouldBeActive); + ToolWindow runToolWindow = ToolWindowManager.getInstance(project).getToolWindow(ToolWindowId.RUN); if (runToolWindow != null) { runToolWindow.hide(null); } } + private static void updateProjectView(@NotNull Project project, VirtualFile shouldBeActive) { + JTree tree = ProjectView.getInstance(project).getCurrentProjectViewPane().getTree(); + if (shouldBeActive != null) { + ProjectView.getInstance(project).selectCB(shouldBeActive, shouldBeActive, false).doWhenDone(() -> { + List paths = TreeUtil.collectExpandedPaths(tree); + List toCollapse = new ArrayList(); + TreePath selectedPath = tree.getSelectionPath(); + for (TreePath treePath : paths) { + if (treePath.isDescendant(selectedPath)) { + continue; + } + if (toCollapse.isEmpty()) { + toCollapse.add(treePath); + continue; + } + for (int i = 0; i < toCollapse.size(); i++) { + TreePath path = toCollapse.get(i); + if (treePath.isDescendant(path)) { + toCollapse.set(i, treePath); + } else { + if (!path.isDescendant(treePath)) { + toCollapse.add(treePath); + } + } + } + } + for (TreePath path : toCollapse) { + tree.collapsePath(path); + tree.fireTreeCollapsed(path); + } + }); + FileEditorManager.getInstance(project).openFile(shouldBeActive, true); + } + } + @Nullable protected VirtualFile getFileToActivate(@NotNull Project project, Map nextTaskFiles, VirtualFile taskDir) { VirtualFile shouldBeActive = null; for (Map.Entry entry : nextTaskFiles.entrySet()) { String name = entry.getKey(); TaskFile taskFile = entry.getValue(); - VirtualFile srcDir = taskDir.findChild("src"); + VirtualFile srcDir = taskDir.findChild(EduNames.SRC); VirtualFile vf = srcDir == null ? taskDir.findChild(name) : srcDir.findChild(name); if (vf != null) { - FileEditorManager.getInstance(project).openFile(vf, true); - if (!taskFile.getAnswerPlaceholders().isEmpty()) { + if (shouldBeActive != null) { + FileEditorManager.getInstance(project).openFile(vf, true); + } + if (shouldBeActive == null && !taskFile.getAnswerPlaceholders().isEmpty()) { shouldBeActive = vf; } } diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/checker/StudyCheckTask.java b/python/educational-core/student/src/com/jetbrains/edu/learning/checker/StudyCheckTask.java index fd98e1690139..0a9d5ca85394 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/checker/StudyCheckTask.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/checker/StudyCheckTask.java @@ -24,6 +24,7 @@ import com.jetbrains.edu.learning.courseFormat.StudyStatus; import com.jetbrains.edu.learning.courseFormat.Task; import com.jetbrains.edu.learning.stepic.EduAdaptiveStepicConnector; import com.jetbrains.edu.learning.stepic.EduStepicConnector; +import com.jetbrains.edu.learning.stepic.StepicUser; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -36,9 +37,10 @@ public class StudyCheckTask extends com.intellij.openapi.progress.Task.Backgroun protected final VirtualFile myTaskDir; protected final StudyTaskManager myTaskManger; private final StudyStatus myStatusBeforeCheck; - private Ref myCheckInProcess; + private final Ref myCheckInProcess; private final Process myTestProcess; private final String myCommandLine; + private final String FAILED_CHECK_LAUNCH = "Failed to launch checking"; public StudyCheckTask(Project project, StudyState studyState, Ref checkInProcess, Process testProcess, String commandLine) { super(project, "Checking Task"); @@ -118,7 +120,7 @@ public class StudyCheckTask extends com.intellij.openapi.progress.Task.Backgroun String stderr = output.getStderr(); if (!stderr.isEmpty()) { ApplicationManager.getApplication().invokeLater(() -> - StudyCheckUtils.showTestResultPopUp("Failed to launch checking", + StudyCheckUtils.showTestResultPopUp(FAILED_CHECK_LAUNCH, MessageType.WARNING.getPopupBackground(), myProject)); //log error output of tests @@ -149,7 +151,7 @@ public class StudyCheckTask extends com.intellij.openapi.progress.Task.Backgroun runAfterTaskCheckedActions(); } else { - ApplicationManager.getApplication().invokeLater(() -> StudyCheckUtils.showTestResultPopUp("Failed to launch checking", + ApplicationManager.getApplication().invokeLater(() -> StudyCheckUtils.showTestResultPopUp(FAILED_CHECK_LAUNCH, MessageType.WARNING .getPopupBackground(), myProject)); @@ -214,8 +216,10 @@ public class StudyCheckTask extends com.intellij.openapi.progress.Task.Backgroun protected void postAttemptToStepic(@NotNull StudyTestsOutputParser.TestsOutput testsOutput) { final StudyTaskManager studySettings = StudyTaskManager.getInstance(myProject); - final String login = studySettings.getUser().getEmail(); - final String password = StringUtil.isEmptyOrSpaces(login) ? "" : studySettings.getUser().getPassword(); + final StepicUser user = studySettings.getUser(); + if (user == null) return; + final String login = user.getEmail(); + final String password = StringUtil.isEmptyOrSpaces(login) ? "" : user.getPassword(); EduStepicConnector.postAttempt(myTask, testsOutput.isSuccess(), login, password); } } diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/checker/StudyCheckUtils.java b/python/educational-core/student/src/com/jetbrains/edu/learning/checker/StudyCheckUtils.java index a14e89fa6c73..73812b9be5bc 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/checker/StudyCheckUtils.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/checker/StudyCheckUtils.java @@ -185,7 +185,7 @@ public class StudyCheckUtils { if (virtualFile == null) { continue; } - EduUtils.flushWindows(taskFile, virtualFile, true); + EduUtils.flushWindows(taskFile, virtualFile); } } diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/checker/StudySmartChecker.java b/python/educational-core/student/src/com/jetbrains/edu/learning/checker/StudySmartChecker.java index 9621efbd7d39..e67c2b62b227 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/checker/StudySmartChecker.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/checker/StudySmartChecker.java @@ -62,7 +62,7 @@ public class StudySmartChecker { String text = usersDocument.getText(new TextRange(userStart, userEnd)); windowDocument.replaceString(start, end, text); ApplicationManager.getApplication().runWriteAction(() -> documentManager.saveDocument(windowDocument)); - VirtualFile fileWindows = EduUtils.flushWindows(windowTaskFile, windowCopy, true); + VirtualFile fileWindows = EduUtils.flushWindows(windowTaskFile, windowCopy); Process smartTestProcess = testRunner.createCheckProcess(project, windowCopy.getPath()); final CapturingProcessHandler handler = new CapturingProcessHandler(smartTestProcess, null, windowCopy.getPath()); final ProcessOutput output = handler.runProcess(); diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduNames.java b/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduNames.java index a9537e24d6c5..cf6d4fd21c2e 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduNames.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduNames.java @@ -41,11 +41,11 @@ public class EduNames { public static final String SANDBOX_DIR = "Sandbox"; public static final String COURSE_META_FILE = "course.json"; public static final String STUDY = "Study"; - public static String PYCHARM_ADDITIONAL = "PyCharm additional materials"; + public static final String PYCHARM_ADDITIONAL = "PyCharm additional materials"; public static final String PYCHARM = "PyCharm"; - public static String PLACEHOLDER = "Answer Placeholder"; - public static String SRC = "src"; + public static final String PLACEHOLDER = "Answer Placeholder"; + public static final String SRC = "src"; private EduNames() { } diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduUtils.java b/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduUtils.java index e6e520fca01c..edad8e41cacd 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduUtils.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduUtils.java @@ -31,7 +31,7 @@ public class EduUtils { } private static final Logger LOG = Logger.getInstance(EduUtils.class.getName()); - public static Comparator INDEX_COMPARATOR = (o1, o2) -> o1.getIndex() - o2.getIndex(); + public static final Comparator INDEX_COMPARATOR = (o1, o2) -> o1.getIndex() - o2.getIndex(); public static void enableAction(@NotNull final AnActionEvent event, boolean isEnable) { final Presentation presentation = event.getPresentation(); @@ -64,8 +64,7 @@ public class EduUtils { @SuppressWarnings("IOResourceOpenedButNotSafelyClosed") @Nullable - public static VirtualFile flushWindows(@NotNull final TaskFile taskFile, @NotNull final VirtualFile file, - boolean useLength) { + public static VirtualFile flushWindows(@NotNull final TaskFile taskFile, @NotNull final VirtualFile file) { final VirtualFile taskDir = file.getParent(); VirtualFile fileWindows = null; final Document document = FileDocumentManager.getInstance().getDocument(file); diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/courseFormat/Course.java b/python/educational-core/student/src/com/jetbrains/edu/learning/courseFormat/Course.java index 6b60f47f6faa..a5b88246230c 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/courseFormat/Course.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/courseFormat/Course.java @@ -75,7 +75,7 @@ public class Course { } public static String getAuthorsString(@NotNull List authors) { - return StringUtil.join(authors, author -> author.getName(), ", "); + return StringUtil.join(authors, StepicUser::getName, ", "); } public void setAuthors(String[] authors) { diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/courseFormat/TaskFile.java b/python/educational-core/student/src/com/jetbrains/edu/learning/courseFormat/TaskFile.java index 88037f08679c..1223f43f3d10 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/courseFormat/TaskFile.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/courseFormat/TaskFile.java @@ -98,6 +98,8 @@ public class TaskFile { answerPlaceholderCopy.setPossibleAnswer(answerPlaceholder.getPossibleAnswer()); answerPlaceholderCopy.setIndex(answerPlaceholder.getIndex()); answerPlaceholderCopy.setHint(answerPlaceholder.getHint()); + final AnswerPlaceholder.MyInitialState state = answerPlaceholder.getInitialState(); + answerPlaceholderCopy.setInitialState(new AnswerPlaceholder.MyInitialState(state.getOffset(), state.getLength())); answerPlaceholdersCopy.add(answerPlaceholderCopy); } target.name = source.name; diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/courseGeneration/StudyGenerator.java b/python/educational-core/student/src/com/jetbrains/edu/learning/courseGeneration/StudyGenerator.java index 6e031380977b..58687fc2391e 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/courseGeneration/StudyGenerator.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/courseGeneration/StudyGenerator.java @@ -116,15 +116,15 @@ public class StudyGenerator { baseDir.createChildDirectory(project, EduNames.SANDBOX_DIR); File[] files = resourceRoot.listFiles( (dir, name) -> !name.contains(EduNames.LESSON) && !name.equals(EduNames.COURSE_META_FILE) && !name.equals(EduNames.HINTS)); - for (File file : files) { - File dir = new File(baseDir.getPath(), file.getName()); - if (file.isDirectory()) { - FileUtil.copyDir(file, dir); - continue; + if (files != null) { + for (File file : files) { + File dir = new File(baseDir.getPath(), file.getName()); + if (file.isDirectory()) { + FileUtil.copyDir(file, dir); + continue; + } + FileUtil.copy(file, dir); } - - FileUtil.copy(file, dir); - } } catch (IOException e) { diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/projectView/StudyDirectoryNode.java b/python/educational-core/student/src/com/jetbrains/edu/learning/projectView/StudyDirectoryNode.java index c9821a704112..5439bce17d2e 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/projectView/StudyDirectoryNode.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/projectView/StudyDirectoryNode.java @@ -142,7 +142,7 @@ public class StudyDirectoryNode extends PsiDirectoryNode { @Override public void navigate(boolean requestFocus) { final String myValueName = myValue.getName(); - if (myValueName != null && myValueName.contains(EduNames.TASK)) { + if (myValueName.contains(EduNames.TASK)) { TaskFile taskFile = null; VirtualFile virtualFile = null; for (PsiElement child : myValue.getChildren()) { @@ -186,7 +186,7 @@ public class StudyDirectoryNode extends PsiDirectoryNode { @Override public boolean expandOnDoubleClick() { final String myValueName = myValue.getName(); - if (myValueName!= null && myValueName.contains(EduNames.TASK)) { + if (myValueName.contains(EduNames.TASK)) { return false; } return super.expandOnDoubleClick(); diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/settings/StudyConfigurable.java b/python/educational-core/student/src/com/jetbrains/edu/learning/settings/StudyConfigurable.java index ba47bee2c62a..7b45780e26f8 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/settings/StudyConfigurable.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/settings/StudyConfigurable.java @@ -27,7 +27,7 @@ import java.util.List; public class StudyConfigurable extends CompositeConfigurable { public static final String ID = "com.jetbrains.edu.learning.stepic.EduConfigurable"; - private JPanel myMainPanel; + private final JPanel myMainPanel; public StudyConfigurable() { myMainPanel = new JPanel(new VerticalFlowLayout()); @@ -59,11 +59,6 @@ public class StudyConfigurable extends CompositeConfigurable createConfigurables() { return ConfigurableWrapper.createConfigurables(StudyOptionsProviderEP.EP_NAME); diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/stepic/CourseInfo.java b/python/educational-core/student/src/com/jetbrains/edu/learning/stepic/CourseInfo.java index 004b313054a1..b29140ba494c 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/stepic/CourseInfo.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/stepic/CourseInfo.java @@ -12,7 +12,7 @@ import java.util.List; * and when project is being created */ public class CourseInfo { - public static CourseInfo INVALID_COURSE = new CourseInfo(); + public static final CourseInfo INVALID_COURSE = new CourseInfo(); @SerializedName("title") private String myName; int id; diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/stepic/EduAdaptiveStepicConnector.java b/python/educational-core/student/src/com/jetbrains/edu/learning/stepic/EduAdaptiveStepicConnector.java index 18225c548598..d867774a22c3 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/stepic/EduAdaptiveStepicConnector.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/stepic/EduAdaptiveStepicConnector.java @@ -403,7 +403,7 @@ public class EduAdaptiveStepicConnector { public static Pair checkTask(@NotNull final Project project, @NotNull final Task task) { int attemptId = -1; try { - attemptId = getAttemptId(project, task, EduStepicNames.ATTEMPTS); + attemptId = getAttemptId(project, task); } catch (IOException e) { LOG.warn(e.getMessage()); @@ -519,10 +519,10 @@ public class EduAdaptiveStepicConnector { return null; } - private static int getAttemptId(@NotNull final Project project, @NotNull Task task, @NotNull final String attempts) throws IOException { + private static int getAttemptId(@NotNull final Project project, @NotNull Task task) throws IOException { final StepicWrappers.AttemptToPostWrapper attemptWrapper = new StepicWrappers.AttemptToPostWrapper(task.getStepicId()); - final HttpPost post = new HttpPost(EduStepicNames.STEPIC_API_URL + attempts); + final HttpPost post = new HttpPost(EduStepicNames.STEPIC_API_URL + EduStepicNames.ATTEMPTS); post.setEntity(new StringEntity(new Gson().toJson(attemptWrapper))); final CloseableHttpClient client = getHttpClient(project); diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/stepic/EduStepicNames.java b/python/educational-core/student/src/com/jetbrains/edu/learning/stepic/EduStepicNames.java index 5ece7fe02284..7710f5e392c5 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/stepic/EduStepicNames.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/stepic/EduStepicNames.java @@ -22,5 +22,5 @@ public class EduStepicNames { public static final String STEPS = "/steps"; public static final String SECTIONS = "/sections/"; public static final String ENROLLMENTS = "/enrollments"; - public static String STEPIC_SIGN_IN_LINK = "https://stepic.org/accounts/signup/?next=/users/16516293/learn"; + public static final String STEPIC_SIGN_IN_LINK = "https://stepic.org/accounts/signup/?next=/users/16516293/learn"; } diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/stepic/StepicAdaptiveReactionsPanel.java b/python/educational-core/student/src/com/jetbrains/edu/learning/stepic/StepicAdaptiveReactionsPanel.java index 04a52dec8e7d..24db1b1575aa 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/stepic/StepicAdaptiveReactionsPanel.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/stepic/StepicAdaptiveReactionsPanel.java @@ -38,8 +38,8 @@ public class StepicAdaptiveReactionsPanel extends JPanel { setLayout(new GridBagLayout()); setBackground(UIUtil.getTextFieldBackground()); - myHardPanel = new ReactionButtonPanel(HARD_REACTION, HARD_LABEL_TOOLTIP, SOLVED_TASK_TOOLTIP, TOO_HARD_REACTION); - myBoringPanel = new ReactionButtonPanel(BORING_REACTION, BORING_LABEL_TOOLTIP, SOLVED_TASK_TOOLTIP, TOO_BORING_REACTION); + myHardPanel = new ReactionButtonPanel(HARD_REACTION, HARD_LABEL_TOOLTIP, TOO_HARD_REACTION); + myBoringPanel = new ReactionButtonPanel(BORING_REACTION, BORING_LABEL_TOOLTIP, TOO_BORING_REACTION); addFileListener(); final GridBagConstraints c = new GridBagConstraints(); @@ -99,7 +99,6 @@ public class StepicAdaptiveReactionsPanel extends JPanel { public ReactionButtonPanel(@NotNull final String text, @NotNull final String enabledTooltip, - @NotNull final String disabledTooltip, int reaction) { com.jetbrains.edu.learning.courseFormat.Task task = StudyUtils.getTaskFromSelectedEditor(myProject); final boolean isEnabled = task != null && task.getStatus() != StudyStatus.Solved; @@ -108,7 +107,7 @@ public class StepicAdaptiveReactionsPanel extends JPanel { myButtonPanel = new JPanel(); myButtonPanel.setLayout(new BoxLayout(myButtonPanel, BoxLayout.PAGE_AXIS)); - myButtonPanel.setToolTipText(isEnabled ? enabledTooltip : disabledTooltip); + myButtonPanel.setToolTipText(isEnabled ? enabledTooltip : SOLVED_TASK_TOOLTIP); myButtonPanel.add(Box.createVerticalStrut(5)); myButtonPanel.add(myLabel); myButtonPanel.add(Box.createVerticalStrut(5)); diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/stepic/StepicStudyOptions.java b/python/educational-core/student/src/com/jetbrains/edu/learning/stepic/StepicStudyOptions.java index ae823206ddf4..9b48578db82a 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/stepic/StepicStudyOptions.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/stepic/StepicStudyOptions.java @@ -108,9 +108,10 @@ public class StepicStudyOptions implements StudyOptionsProvider { Project project = StudyUtils.getStudyProject(); if (project != null) { final StepicUser user = StudyTaskManager.getInstance(project).getUser(); - setLogin(user.getEmail()); - setPassword(DEFAULT_PASSWORD_TEXT); - + if (user != null) { + setLogin(user.getEmail()); + setPassword(DEFAULT_PASSWORD_TEXT); + } resetCredentialsModification(); } else { diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/stepic/StepicWrappers.java b/python/educational-core/student/src/com/jetbrains/edu/learning/stepic/StepicWrappers.java index 83363d59b082..c5820eaf95cf 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/stepic/StepicWrappers.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/stepic/StepicWrappers.java @@ -61,15 +61,12 @@ public class StepicWrappers { for (final Map.Entry entry : task.getTaskFiles().entrySet()) { final TaskFile taskFile = new TaskFile(); TaskFile.copy(entry.getValue(), taskFile); - ApplicationManager.getApplication().runWriteAction(new Runnable() { - @Override - public void run() { - final VirtualFile taskDir = task.getTaskDir(project); - assert taskDir != null; - VirtualFile ideaDir = project.getBaseDir().findChild(".idea"); - assert ideaDir != null; - EduUtils.createStudentFileFromAnswer(project, ideaDir, taskDir, entry.getKey(), taskFile); - } + ApplicationManager.getApplication().runWriteAction(() -> { + final VirtualFile taskDir = task.getTaskDir(project); + assert taskDir != null; + VirtualFile ideaDir = project.getBaseDir().findChild(".idea"); + assert ideaDir != null; + EduUtils.createStudentFileFromAnswer(project, ideaDir, taskDir, entry.getKey(), taskFile); }); taskFile.name = entry.getKey(); @@ -98,11 +95,8 @@ public class StepicWrappers { private static void setTests(@NotNull final Task task, @NotNull final StepOptions source, @NotNull final Project project) { final Map testsText = task.getTestsText(); if (testsText.isEmpty()) { - ApplicationManager.getApplication().runReadAction(new Runnable() { - @Override - public void run() { - source.test = Collections.singletonList(new TestFileWrapper(EduNames.TESTS_FILE, task.getTestsText(project))); - } + ApplicationManager.getApplication().runReadAction(() -> { + source.test = Collections.singletonList(new TestFileWrapper(EduNames.TESTS_FILE, task.getTestsText(project))); }); } else { diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/twitter/StudyTwitterUtils.java b/python/educational-core/student/src/com/jetbrains/edu/learning/twitter/StudyTwitterUtils.java index 1192e7bea612..8c6d8668066d 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/twitter/StudyTwitterUtils.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/twitter/StudyTwitterUtils.java @@ -242,7 +242,7 @@ public class StudyTwitterUtils { * Dialog wrapper class with DoNotAsl option for asking user to tweet. * */ private static class TwitterDialogWrapper extends DialogWrapper { - private StudyTwitterUtils.TwitterDialogPanel myPanel; + private final StudyTwitterUtils.TwitterDialogPanel myPanel; TwitterDialogWrapper(@Nullable Project project, @NotNull StudyTwitterUtils.TwitterDialogPanel panel, DoNotAskOption doNotAskOption) { super(project); diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyProgressBar.java b/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyProgressBar.java index c21aef13acb7..6effcc2df65c 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyProgressBar.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyProgressBar.java @@ -20,7 +20,7 @@ public class StudyProgressBar extends JComponent implements DumbAware { private final int myHeight; private final int myIndent; private double myFraction = 0.0; - private static Color myColor = JBColor.GREEN; + private static final Color myColor = JBColor.GREEN; public StudyProgressBar(double fraction, int height, int indent) { myFraction = fraction; @@ -100,4 +100,8 @@ public class StudyProgressBar extends JComponent implements DumbAware { dimension.height = myHeight + 10; return dimension; } + + public void setFraction(double fraction) { + myFraction = fraction; + } } diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyProgressToolWindowFactory.java b/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyProgressToolWindowFactory.java deleted file mode 100644 index d57ad24c70f8..000000000000 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyProgressToolWindowFactory.java +++ /dev/null @@ -1,80 +0,0 @@ -package com.jetbrains.edu.learning.ui; - -import com.intellij.openapi.project.DumbAware; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.wm.ToolWindow; -import com.intellij.openapi.wm.ToolWindowFactory; -import com.intellij.ui.content.Content; -import com.intellij.ui.content.ContentFactory; -import com.intellij.util.ui.UIUtil; -import com.jetbrains.edu.learning.core.EduNames; -import com.jetbrains.edu.learning.courseFormat.Course; -import com.jetbrains.edu.learning.courseFormat.Lesson; -import com.jetbrains.edu.learning.courseFormat.StudyStatus; -import com.jetbrains.edu.learning.courseFormat.Task; -import com.jetbrains.edu.learning.StudyTaskManager; -import icons.InteractiveLearningIcons; -import org.jetbrains.annotations.NotNull; - -import javax.swing.*; -import java.awt.*; -import java.util.List; - -public class StudyProgressToolWindowFactory implements ToolWindowFactory, DumbAware { - public static final String ID = "Course Progress"; - - - @Override - public void createToolWindowContent(@NotNull final Project project, @NotNull final ToolWindow toolWindow) { - toolWindow.setIcon(InteractiveLearningIcons.CourseProgress); - JPanel contentPanel = new JPanel(); - StudyTaskManager taskManager = StudyTaskManager.getInstance(project); - if (taskManager.getCourse() != null) { - contentPanel.setLayout(new BoxLayout(contentPanel, BoxLayout.PAGE_AXIS)); - contentPanel.add(Box.createRigidArea(new Dimension(10, 0))); - - Course course = taskManager.getCourse(); - if (course == null) { - return; - } - int taskNum = 0; - int taskSolved = 0; - List lessons = course.getLessons(); - for (Lesson lesson : lessons) { - if (lesson.getName().equals(EduNames.PYCHARM_ADDITIONAL)) continue; - taskNum += lesson.getTaskList().size(); - taskSolved += getSolvedTasks(lesson); - } - String completedTasks = String.format("%d of %d tasks completed", taskSolved, taskNum); - - double percent = (taskSolved * 100.0) / taskNum; - contentPanel.add(Box.createRigidArea(new Dimension(0, 10))); - StudyProgressBar studyProgressBar = new StudyProgressBar(percent / 100, 40, 10); - contentPanel.add(studyProgressBar); - contentPanel.add(Box.createRigidArea(new Dimension(0, 10))); - addStatistics(completedTasks, contentPanel); - contentPanel.setPreferredSize(new Dimension(100, 50)); - ContentFactory contentFactory = ContentFactory.SERVICE.getInstance(); - Content content = contentFactory.createContent(contentPanel, "", false); - contentPanel.setMinimumSize(new Dimension(300, 100)); - toolWindow.getContentManager().addContent(content); - } - } - - private static void addStatistics(String statistics, JPanel contentPanel) { - String labelText = UIUtil.toHtml(statistics, 5); - contentPanel.add(Box.createRigidArea(new Dimension(0, 10))); - JLabel statisticLabel = new JLabel(labelText); - contentPanel.add(statisticLabel); - } - - private static int getSolvedTasks(@NotNull final Lesson lesson) { - int solved = 0; - for (Task task : lesson.getTaskList()) { - if (task.getStatus() == StudyStatus.Solved) { - solved += 1; - } - } - return solved; - } -} diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyToolWindow.java b/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyToolWindow.java index d47ef138d308..98d0e1cb343d 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyToolWindow.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyToolWindow.java @@ -30,16 +30,18 @@ import com.intellij.openapi.ui.SimpleToolWindowPanel; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.JBCardLayout; +import com.intellij.ui.JBColor; import com.intellij.ui.OnePixelSplitter; import com.intellij.util.ui.JBUI; import com.jetbrains.edu.learning.*; -import com.jetbrains.edu.learning.courseFormat.Course; -import com.jetbrains.edu.learning.courseFormat.TaskFile; +import com.jetbrains.edu.learning.core.EduNames; +import com.jetbrains.edu.learning.courseFormat.*; import com.jetbrains.edu.learning.stepic.StepicAdaptiveReactionsPanel; import org.jetbrains.annotations.NotNull; import javax.swing.*; import java.awt.*; +import java.util.List; import java.util.Map; public abstract class StudyToolWindow extends SimpleToolWindowPanel implements DataProvider, Disposable { @@ -50,6 +52,8 @@ public abstract class StudyToolWindow extends SimpleToolWindowPanel implements D private final JBCardLayout myCardLayout; private final JPanel myContentPanel; private final OnePixelSplitter mySplitPane; + private JLabel myStatisticLabel; + private StudyProgressBar myStudyProgressBar; public StudyToolWindow() { super(true, true); @@ -72,6 +76,11 @@ public abstract class StudyToolWindow extends SimpleToolWindowPanel implements D } JComponent taskInfoPanel = createTaskInfoPanel(project); panel.add(taskInfoPanel, BorderLayout.CENTER); + final JPanel courseProgress = createCourseProgress(project); + if (course != null && !course.isAdaptive() && EduNames.STUDY.equals(course.getCourseMode())) { + panel.add(courseProgress, BorderLayout.SOUTH); + } + myContentPanel.add(TASK_INFO_ID, panel); mySplitPane.setFirstComponent(myContentPanel); addAdditionalPanels(project); @@ -231,6 +240,53 @@ public abstract class StudyToolWindow extends SimpleToolWindowPanel implements D WebBrowserManager.getInstance().setShowBrowserHover(true); mySplitPane.setFirstComponent(myContentPanel); StudyTaskManager.getInstance(project).setToolWindowMode(StudyToolWindowMode.TEXT); - StudyUtils.updateStudyToolWindow(project); + StudyUtils.updateToolWindows(project); + } + + private JPanel createCourseProgress(@NotNull final Project project) { + JPanel contentPanel = new JPanel(); + contentPanel.setBackground(JBColor.WHITE); + contentPanel.setLayout(new BoxLayout(contentPanel, BoxLayout.PAGE_AXIS)); + contentPanel.add(Box.createRigidArea(new Dimension(10, 0))); + contentPanel.add(Box.createRigidArea(new Dimension(0, 10))); + myStudyProgressBar = new StudyProgressBar(0, 20, 10); + + myStatisticLabel = new JLabel("", SwingConstants.LEFT); + contentPanel.add(myStatisticLabel); + contentPanel.add(myStudyProgressBar); + + contentPanel.setPreferredSize(new Dimension(100, 60)); + contentPanel.setMinimumSize(new Dimension(300, 40)); + updateCourseProgress(project); + return contentPanel; + } + + public void updateCourseProgress(@NotNull final Project project) { + final Course course = StudyTaskManager.getInstance(project).getCourse(); + if (course != null) { + int taskNum = 0; + int taskSolved = 0; + List lessons = course.getLessons(); + for (Lesson lesson : lessons) { + if (lesson.getName().equals(EduNames.PYCHARM_ADDITIONAL)) continue; + taskNum += lesson.getTaskList().size(); + taskSolved += getSolvedTasks(lesson); + } + String completedTasks = String.format("%d of %d tasks completed", taskSolved, taskNum); + double percent = (taskSolved * 100.0) / taskNum; + + myStatisticLabel.setText(completedTasks); + myStudyProgressBar.setFraction(percent / 100); + } + } + + private static int getSolvedTasks(@NotNull final Lesson lesson) { + int solved = 0; + for (Task task : lesson.getTaskList()) { + if (task.getStatus() == StudyStatus.Solved) { + solved += 1; + } + } + return solved; } } diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyToolWindowFactory.java b/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyToolWindowFactory.java index 4530e004504d..2cbb4cff7f99 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyToolWindowFactory.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyToolWindowFactory.java @@ -7,7 +7,6 @@ import com.intellij.openapi.wm.ToolWindow; import com.intellij.openapi.wm.ToolWindowFactory; import com.intellij.ui.content.Content; import com.intellij.ui.content.ContentManager; -import com.jetbrains.edu.learning.StudyProjectComponent; import com.jetbrains.edu.learning.StudyTaskManager; import com.jetbrains.edu.learning.StudyUtils; import com.jetbrains.edu.learning.courseFormat.Course; diff --git a/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCRunTestsConfigurationProducer.java b/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCRunTestsConfigurationProducer.java index 617345600d30..80f40044bca7 100644 --- a/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCRunTestsConfigurationProducer.java +++ b/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCRunTestsConfigurationProducer.java @@ -81,7 +81,8 @@ public class PyCCRunTestsConfigurationProducer extends RunConfigurationProducer< String testsPath = taskDir.findChild(EduNames.SRC) != null ? FileUtil.join(taskDirPath, EduNames.SRC, EduNames.TESTS_FILE) : FileUtil.join(taskDirPath, EduNames.TESTS_FILE); - return file.getPath().equals(testsPath) ? testsPath : null; + String filePath = FileUtil.toSystemDependentName(file.getPath()); + return filePath.equals(testsPath) ? testsPath : null; } @Override diff --git a/python/educational-python/src/com/jetbrains/python/edu/PyCharmEduInitialConfigurator.java b/python/educational-python/src/com/jetbrains/python/edu/PyCharmEduInitialConfigurator.java index 49d301b1c327..d479b31c6893 100644 --- a/python/educational-python/src/com/jetbrains/python/edu/PyCharmEduInitialConfigurator.java +++ b/python/educational-python/src/com/jetbrains/python/edu/PyCharmEduInitialConfigurator.java @@ -56,10 +56,15 @@ import com.intellij.openapi.project.ProjectManagerAdapter; import com.intellij.openapi.project.ex.ProjectManagerEx; import com.intellij.openapi.startup.StartupManager; import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.Key; import com.intellij.openapi.vfs.VfsUtil; +import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.wm.*; import com.intellij.platform.DirectoryProjectConfigurator; import com.intellij.platform.PlatformProjectViewOpener; +import com.intellij.profile.codeInspection.InspectionProjectProfileManager; +import com.intellij.psi.PsiDirectory; +import com.intellij.psi.PsiManager; import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.ui.treeStructure.Tree; @@ -68,6 +73,7 @@ import com.intellij.util.messages.MessageBus; import com.intellij.util.ui.tree.TreeUtil; import com.jetbrains.python.PythonLanguage; import com.jetbrains.python.codeInsight.PyCodeInsightSettings; +import com.jetbrains.python.inspections.PyPep8Inspection; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -77,6 +83,7 @@ import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreeNode; import javax.swing.tree.TreePath; +import java.util.Collections; import java.util.HashSet; import java.util.Set; @@ -201,7 +208,11 @@ public class PyCharmEduInitialConfigurator { @Override public void run() { if (project.isDisposed()) return; + updateInspectionsProfile(); + openProjectStructure(); + } + private void openProjectStructure() { ToolWindowManager.getInstance(project).invokeLater(new Runnable() { int count = 0; @@ -212,12 +223,24 @@ public class PyCharmEduInitialConfigurator { return; } ToolWindow toolWindow = ToolWindowManager.getInstance(project).getToolWindow("Project"); - if (toolWindow !=null && toolWindow.getType() != ToolWindowType.SLIDING) { + if (toolWindow != null && toolWindow.getType() != ToolWindowType.SLIDING) { toolWindow.activate(null); } } }); } + + private void updateInspectionsProfile() { + final String[] codes = new String[]{"W29", "E501"}; + final VirtualFile baseDir = project.getBaseDir(); + final PsiDirectory directory = PsiManager.getInstance(project).findDirectory(baseDir); + if (directory != null) { + InspectionProjectProfileManager.getInstance(project).getInspectionProfile().modifyToolSettings( + Key.create(PyPep8Inspection.INSPECTION_SHORT_NAME), directory, + inspection -> Collections.addAll(inspection.ignoredErrors, codes) + ); + } + } }); } }); diff --git a/python/educational-python/student-python/src/com/jetbrains/edu/learning/PyStudyDirectoryProjectGenerator.java b/python/educational-python/student-python/src/com/jetbrains/edu/learning/PyStudyDirectoryProjectGenerator.java index 20d11cb4bc97..1e63ad532000 100644 --- a/python/educational-python/student-python/src/com/jetbrains/edu/learning/PyStudyDirectoryProjectGenerator.java +++ b/python/educational-python/student-python/src/com/jetbrains/edu/learning/PyStudyDirectoryProjectGenerator.java @@ -165,6 +165,7 @@ public class PyStudyDirectoryProjectGenerator extends PythonProjectGenerator imp return generator -> { final List enrolledCoursesIds = myGenerator.getEnrolledCoursesIds(); final CourseInfo course = (CourseInfo)mySettingsPanel.getCoursesComboBox().getSelectedItem(); + if (course == null) return true; if (course.isAdaptive() && !enrolledCoursesIds.contains(course.getId())) { ProgressManager.getInstance().runProcessWithProgressSynchronously(() -> { ProgressManager.getInstance().getProgressIndicator().setIndeterminate(true); diff --git a/python/educational-python/student-python/src/com/jetbrains/edu/learning/PyStudyInstructionPainter.java b/python/educational-python/student-python/src/com/jetbrains/edu/learning/PyStudyInstructionPainter.java index c8dc443d26f6..0496db550dbb 100644 --- a/python/educational-python/student-python/src/com/jetbrains/edu/learning/PyStudyInstructionPainter.java +++ b/python/educational-python/student-python/src/com/jetbrains/edu/learning/PyStudyInstructionPainter.java @@ -5,7 +5,6 @@ import com.intellij.openapi.fileEditor.impl.EditorEmptyTextPainter; import com.intellij.openapi.keymap.KeymapUtil; import com.intellij.util.ui.UIUtil; import com.jetbrains.edu.learning.actions.*; -import com.jetbrains.edu.learning.ui.StudyProgressToolWindowFactory; import org.jetbrains.annotations.NotNull; import javax.swing.*; @@ -23,6 +22,5 @@ public class PyStudyInstructionPainter extends EditorEmptyTextPainter { appendAction(painter, "Reset current task file", getActionShortcutText(StudyRefreshTaskFileAction.ACTION_ID)); appendAction(painter, "Check task", getActionShortcutText(PyStudyCheckAction.ACTION_ID)); appendAction(painter, "Get hint for the answer placeholder", getActionShortcutText(StudyShowHintAction.ACTION_ID)); - appendLine(painter, "To see your progress open the '" + StudyProgressToolWindowFactory.ID + "' panel"); } } \ No newline at end of file diff --git a/python/helpers/pycharm/tcunittest.py b/python/helpers/pycharm/tcunittest.py index 185c12898a1e..1418bfa487ed 100644 --- a/python/helpers/pycharm/tcunittest.py +++ b/python/helpers/pycharm/tcunittest.py @@ -211,6 +211,8 @@ class TeamcityTestResult(TestResult): def __getDuration(self, test): start = getattr(test, "startTime", datetime.datetime.now()) + assert isinstance(start, datetime.datetime), \ + "You testcase has property named 'startTime' (value {0}). Please, rename it".format(start) d = datetime.datetime.now() - start duration = d.microseconds / 1000 + d.seconds * 1000 + d.days * 86400000 return duration diff --git a/python/helpers/pycharm_generator_utils/module_redeclarator.py b/python/helpers/pycharm_generator_utils/module_redeclarator.py index a79a91ed4dd3..fd34c3ad7c37 100644 --- a/python/helpers/pycharm_generator_utils/module_redeclarator.py +++ b/python/helpers/pycharm_generator_utils/module_redeclarator.py @@ -684,7 +684,9 @@ class ModuleRedeclarator(object): try: item = getattr(p_class, item_name) # let getters do the magic except AttributeError: - item = field_source[item_name] # have it raw + item = field_source.get(item_name) # have it raw + if item is None: + continue except Exception: continue if is_callable(item) and not isinstance(item, type): diff --git a/python/helpers/pydev/_pydev_bundle/pydev_console_utils.py b/python/helpers/pydev/_pydev_bundle/pydev_console_utils.py index 19be9971bda1..c9078e14457d 100644 --- a/python/helpers/pydev/_pydev_bundle/pydev_console_utils.py +++ b/python/helpers/pydev/_pydev_bundle/pydev_console_utils.py @@ -114,6 +114,31 @@ class StdIn(BaseStdIn): return '\n' +#======================================================================================================================= +# DebugConsoleStdIn +#======================================================================================================================= +class DebugConsoleStdIn(BaseStdIn): + ''' + Object to be added to stdin (to emulate it as non-blocking while the next line arrives) + ''' + + def __init__(self, dbg, original_stdin): + BaseStdIn.__init__(self) + self.debugger = dbg + self.original_stdin = original_stdin + + def readline(self, *args, **kwargs): + # Notify Java side about input and call original function + try: + cmd = self.debugger.cmd_factory.make_input_requested_message() + self.debugger.writer.add_command(cmd) + except Exception: + import traceback + traceback.print_exc() + return '\n' + return self.original_stdin.readline(*args, **kwargs) + + class CodeFragment: def __init__(self, text, is_single_line=True): self.text = text diff --git a/python/helpers/pydev/_pydevd_bundle/pydevd_comm.py b/python/helpers/pydev/_pydevd_bundle/pydevd_comm.py index babdc3571d0a..ec0c13d692b5 100644 --- a/python/helpers/pydev/_pydevd_bundle/pydevd_comm.py +++ b/python/helpers/pydev/_pydevd_bundle/pydevd_comm.py @@ -138,6 +138,7 @@ CMD_GET_ARRAY = 143 CMD_STEP_INTO_MY_CODE = 144 CMD_GET_CONCURRENCY_EVENT = 145 CMD_SHOW_RETURN_VALUES = 146 +CMD_INPUT_REQUESTED = 147 CMD_VERSION = 501 CMD_RETURN = 502 @@ -191,6 +192,7 @@ ID_TO_MEANING = { '144': 'CMD_STEP_INTO_MY_CODE', '145': 'CMD_GET_CONCURRENCY_EVENT', '146': 'CMD_SHOW_RETURN_VALUES', + '147': 'CMD_INPUT_REQUESTED', '501': 'CMD_VERSION', '502': 'CMD_RETURN', @@ -779,6 +781,13 @@ class NetCommandFactory: except: return self.make_error_message(0, get_exception_traceback_str()) + def make_input_requested_message(self): + try: + return NetCommand(CMD_INPUT_REQUESTED, 0, '') + except: + return self.make_error_message(0, get_exception_traceback_str()) + + def make_exit_message(self): try: net = NetCommand(CMD_EXIT, 0, '') diff --git a/python/helpers/pydev/pydevd.py b/python/helpers/pydev/pydevd.py index b27daef92c57..e333f90df1c7 100644 --- a/python/helpers/pydev/pydevd.py +++ b/python/helpers/pydev/pydevd.py @@ -1180,6 +1180,7 @@ def _locked_settrace( if bufferStdErrToServer: init_stderr_redirect() + patch_stdin(debugger) debugger.set_trace_for_frame_and_parents(get_frame(), False, overwrite_prev_trace=overwrite_prev_trace) @@ -1382,6 +1383,12 @@ def apply_debugger_options(setup_options): enable_qt_support() +def patch_stdin(debugger): + from _pydev_bundle.pydev_console_utils import DebugConsoleStdIn + orig_stdin = sys.stdin + sys.stdin = DebugConsoleStdIn(debugger, orig_stdin) + + #======================================================================================================================= # main #======================================================================================================================= @@ -1512,6 +1519,7 @@ if __name__ == '__main__': pass # It's ok not having stackless there... is_module = setup['module'] + patch_stdin(debugger) if fix_app_engine_debug: sys.stderr.write("pydev debugger: google app engine integration enabled\n") diff --git a/python/ide/src/com/jetbrains/python/PythonSdkChooserCombo.java b/python/ide/src/com/jetbrains/python/PythonSdkChooserCombo.java index 7c9335ba62bd..032bda6b3741 100644 --- a/python/ide/src/com/jetbrains/python/PythonSdkChooserCombo.java +++ b/python/ide/src/com/jetbrains/python/PythonSdkChooserCombo.java @@ -20,16 +20,15 @@ import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectSdksModel; +import com.intellij.openapi.ui.ComboBox; import com.intellij.openapi.util.Condition; import com.intellij.ui.CollectionComboBoxModel; import com.intellij.ui.ComboboxWithBrowseButton; -import com.intellij.util.NullableConsumer; import com.intellij.util.containers.ContainerUtil; import com.jetbrains.python.configuration.PyConfigurableInterpreterList; import com.jetbrains.python.sdk.PySdkListCellRenderer; import com.jetbrains.python.sdk.PySdkService; import com.jetbrains.python.sdk.PythonSdkDetailsStep; -import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.event.ActionEvent; @@ -41,17 +40,12 @@ import java.util.List; */ public class PythonSdkChooserCombo extends ComboboxWithBrowseButton { private final List myChangedListeners = ContainerUtil.createLockFreeCopyOnWriteList(); - private static final Logger LOG = Logger.getInstance("#com.jetbrains.python.PythonSdkChooserCombo"); + private static final Logger LOG = Logger.getInstance(PythonSdkChooserCombo.class); @SuppressWarnings("unchecked") public PythonSdkChooserCombo(final Project project, List sdks, final Condition acceptableSdkCondition) { - Sdk initialSelection = null; - for (Sdk sdk : sdks) { - if (acceptableSdkCondition.value(sdk)) { - initialSelection = sdk; - break; - } - } + super(new ComboBox<>()); + final Sdk initialSelection = ContainerUtil.find(sdks, acceptableSdkCondition); final JComboBox comboBox = getComboBox(); comboBox.setModel(new CollectionComboBoxModel(sdks, initialSelection)); comboBox.setRenderer(new PySdkListCellRenderer(true)); @@ -78,6 +72,9 @@ public class PythonSdkChooserCombo extends ComboboxWithBrowseButton { private void showOptions(final Project project) { final PyConfigurableInterpreterList interpreterList = PyConfigurableInterpreterList.getInstance(project); final Sdk[] sdks = interpreterList.getModel().getSdks(); + //noinspection unchecked + final JComboBox comboBox = getComboBox(); + final Sdk oldSelectedSdk = (Sdk)comboBox.getSelectedItem(); PythonSdkDetailsStep.show(project, sdks, null, this, getButton().getLocationOnScreen(), sdk -> { if (sdk == null) return; final PySdkService sdkService = PySdkService.getInstance(); @@ -93,8 +90,10 @@ public class PythonSdkChooserCombo extends ComboboxWithBrowseButton { LOG.error("Error adding new python interpreter " + e.getMessage()); } } - //noinspection unchecked - getComboBox().setModel(new CollectionComboBoxModel(interpreterList.getAllPythonSdks(), sdk)); + final List committedSdks = interpreterList.getAllPythonSdks(); + final Sdk copiedSdk = interpreterList.getModel().findSdk(sdk.getName()); + comboBox.setModel(new CollectionComboBoxModel<>(committedSdks, oldSelectedSdk)); + comboBox.setSelectedItem(copiedSdk); }, true); } diff --git a/python/ide/src/com/jetbrains/python/newProject/actions/ProjectSpecificSettingsStep.java b/python/ide/src/com/jetbrains/python/newProject/actions/ProjectSpecificSettingsStep.java index 5a34a82f377b..6952315028b8 100644 --- a/python/ide/src/com/jetbrains/python/newProject/actions/ProjectSpecificSettingsStep.java +++ b/python/ide/src/com/jetbrains/python/newProject/actions/ProjectSpecificSettingsStep.java @@ -15,7 +15,6 @@ */ package com.jetbrains.python.newProject.actions; -import com.intellij.execution.ExecutionException; import com.intellij.facet.ui.ValidationResult; import com.intellij.ide.util.projectWizard.ProjectSettingsStepBase; import com.intellij.ide.util.projectWizard.WebProjectTemplate; @@ -29,15 +28,16 @@ import com.intellij.platform.DirectoryProjectGenerator; import com.intellij.ui.DocumentAdapter; import com.intellij.ui.HideableDecorator; import com.intellij.util.NullableConsumer; +import com.intellij.util.PathUtil; import com.intellij.util.ui.UIUtil; +import com.intellij.util.ui.update.UiNotifyConnector; import com.jetbrains.python.PythonSdkChooserCombo; import com.jetbrains.python.configuration.PyConfigurableInterpreterList; import com.jetbrains.python.configuration.VirtualEnvProjectFilter; import com.jetbrains.python.newProject.PyFrameworkProjectGenerator; import com.jetbrains.python.newProject.PythonProjectGenerator; -import com.jetbrains.python.packaging.PyPackageManager; +import com.jetbrains.python.packaging.PyPackage; import com.jetbrains.python.packaging.PyPackageUtil; -import com.jetbrains.python.sdk.PySdkUtil; import com.jetbrains.python.sdk.PythonSdkType; import icons.PythonIcons; import org.jetbrains.annotations.NotNull; @@ -48,9 +48,7 @@ import javax.swing.event.DocumentEvent; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -import java.io.File; +import java.awt.event.ItemEvent; import java.util.ArrayList; import java.util.List; @@ -119,20 +117,29 @@ public class ProjectSpecificSettingsStep extends ProjectSettingsStepBase impleme protected void registerValidators() { super.registerValidators(); if (myProjectGenerator instanceof PythonProjectGenerator && !((PythonProjectGenerator)myProjectGenerator).hideInterpreter()) { - mySdkCombo.getComboBox().addPropertyChangeListener(new PropertyChangeListener() { + myLocationField.getTextField().getDocument().addDocumentListener(new DocumentAdapter() { @Override - public void propertyChange(PropertyChangeEvent event) { + protected void textChanged(DocumentEvent e) { + final String path = myLocationField.getText().trim(); + ((PythonProjectGenerator)myProjectGenerator).locationChanged(PathUtil.getFileName(path)); + } + }); + + mySdkCombo.getComboBox().addItemListener(e -> { + if (e.getStateChange() == ItemEvent.SELECTED) { checkValid(); } }); - final ActionListener listener = new ActionListener() { - @Override - public void actionPerformed(ActionEvent event) { - checkValid(); - } - }; - mySdkCombo.getComboBox().addActionListener(listener); - mySdkCombo.addActionListener(listener); + UiNotifyConnector.doWhenFirstShown(mySdkCombo, this::checkValid); + } + } + + @Override + protected void initGeneratorListeners() { + super.initGeneratorListeners(); + if (myProjectGenerator instanceof PythonProjectGenerator) { + ((PythonProjectGenerator)myProjectGenerator).addSettingsStateListener(this::checkValid); + myErrorLabel.addMouseListener(((PythonProjectGenerator)myProjectGenerator).getErrorLabelMouseListener()); } } @@ -169,14 +176,11 @@ public class ProjectSpecificSettingsStep extends ProjectSettingsStepBase impleme if (PyPackageUtil.packageManagementEnabled(sdk)) { warningList.add(frameworkName + " will be installed on the selected interpreter"); myInstallFramework = true; - final PyPackageManager packageManager = PyPackageManager.getInstance(sdk); - boolean hasManagement = false; - try { - hasManagement = packageManager.hasManagement(PySdkUtil.isRemote(sdk)); + final List packages = PyPackageUtil.refreshAndGetPackagesModally(sdk); + if (packages == null) { + return false; } - catch (ExecutionException ignored) { - } - if (!hasManagement) { + if (!PyPackageUtil.hasManagement(packages)) { warningList.add("Python packaging tools and " + warningList); } } else { @@ -282,33 +286,4 @@ public class ProjectSpecificSettingsStep extends ProjectSettingsStepBase impleme return LabeledComponent.create(mySdkCombo, "Interpreter", BorderLayout.WEST); } - - @Override - protected void initGeneratorListeners() { - super.initGeneratorListeners(); - if (myProjectGenerator instanceof PythonProjectGenerator) { - ((PythonProjectGenerator)myProjectGenerator).addSettingsStateListener(new PythonProjectGenerator.SettingsListener() { - @Override - public void stateChanged() { - checkValid(); - } - }); - - myErrorLabel.addMouseListener(((PythonProjectGenerator)myProjectGenerator).getErrorLabelMouseListener()); - } - myLocationField.getTextField().getDocument().addDocumentListener(new DocumentAdapter() { - @Override - protected void textChanged(DocumentEvent e) { - if (myProjectGenerator instanceof PythonProjectGenerator) { - String path = myLocationField.getText().trim(); - path = StringUtil.trimEnd(path, File.separator); - int ind = path.lastIndexOf(File.separator); - if (ind != -1) { - String projectName = path.substring(ind + 1, path.length()); - ((PythonProjectGenerator)myProjectGenerator).locationChanged(projectName); - } - } - } - }); - } } diff --git a/python/ipnb/src/org/jetbrains/plugins/ipnb/configuration/IpnbConnectionManager.java b/python/ipnb/src/org/jetbrains/plugins/ipnb/configuration/IpnbConnectionManager.java index 27be6ff10510..7bba8e8e03a8 100644 --- a/python/ipnb/src/org/jetbrains/plugins/ipnb/configuration/IpnbConnectionManager.java +++ b/python/ipnb/src/org/jetbrains/plugins/ipnb/configuration/IpnbConnectionManager.java @@ -33,6 +33,7 @@ import com.intellij.util.ui.UIUtil; import com.jetbrains.python.PythonHelper; import com.jetbrains.python.packaging.PyPackage; import com.jetbrains.python.packaging.PyPackageManager; +import com.jetbrains.python.packaging.PyPackageUtil; import com.jetbrains.python.sdk.PythonSdkType; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -269,15 +270,12 @@ public final class IpnbConnectionManager implements ProjectComponent { showWarning(fileEditor, "Please check Python Interpreter in Settings->Python Interpreter", null); return false; } - try { - final PyPackage ipythonPackage = PyPackageManager.getInstance(sdk).findPackage("ipython", false); - final PyPackage jupyterPackage = PyPackageManager.getInstance(sdk).findPackage("jupyter", false); - if (ipythonPackage == null && jupyterPackage == null) { - showWarning(fileEditor, "Add Jupyter to the interpreter of the current project.", null); - return false; - } - } - catch (ExecutionException ignored) { + final List packages = PyPackageManager.getInstance(sdk).getPackages(); + final PyPackage ipythonPackage = packages != null ? PyPackageUtil.findPackage(packages, "ipython") : null; + final PyPackage jupyterPackage = packages != null ? PyPackageUtil.findPackage(packages, "jupyter") : null; + if (ipythonPackage == null && jupyterPackage == null) { + showWarning(fileEditor, "Add Jupyter to the interpreter of the current project.", null); + return false; } String url = showDialogUrl(initUrl); diff --git a/python/ipnb/src/org/jetbrains/plugins/ipnb/format/IpnbParser.java b/python/ipnb/src/org/jetbrains/plugins/ipnb/format/IpnbParser.java index e9bc33718e75..4d19bea816a4 100644 --- a/python/ipnb/src/org/jetbrains/plugins/ipnb/format/IpnbParser.java +++ b/python/ipnb/src/org/jetbrains/plugins/ipnb/format/IpnbParser.java @@ -4,7 +4,6 @@ import com.google.common.collect.Lists; import com.google.gson.*; import com.google.gson.annotations.SerializedName; import com.google.gson.stream.JsonWriter; -import com.intellij.execution.ExecutionException; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.module.Module; @@ -16,7 +15,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.text.VersionComparatorUtil; import com.jetbrains.python.packaging.PyPackage; -import com.jetbrains.python.packaging.PyPackageManager; +import com.jetbrains.python.packaging.PyPackageUtil; import com.jetbrains.python.sdk.PythonSdkType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -79,14 +78,12 @@ public class IpnbParser { if (module != null) { final Sdk sdk = PythonSdkType.findPythonSdk(module); if (sdk != null) { - try { - final PyPackage ipython = PyPackageManager.getInstance(sdk).findPackage("ipython", true); - final PyPackage jupyter = PyPackageManager.getInstance(sdk).findPackage("jupyter", true); - if (jupyter == null && ipython != null && VersionComparatorUtil.compare(ipython.getVersion(), "3.0") <= 0) { - return false; - } - } - catch (ExecutionException ignored) { + // It should be called first before IpnbConnectionManager#startIpythonServer() + final List packages = PyPackageUtil.refreshAndGetPackagesModally(sdk); + final PyPackage ipython = packages != null ? PyPackageUtil.findPackage(packages, "ipython") : null; + final PyPackage jupyter = packages != null ? PyPackageUtil.findPackage(packages, "jupyter") : null; + if (jupyter == null && ipython != null && VersionComparatorUtil.compare(ipython.getVersion(), "3.0") <= 0) { + return false; } } } diff --git a/python/openapi/src/com/jetbrains/python/packaging/PyPackageManager.java b/python/openapi/src/com/jetbrains/python/packaging/PyPackageManager.java index c8b8dd4ab633..a500532496eb 100644 --- a/python/openapi/src/com/jetbrains/python/packaging/PyPackageManager.java +++ b/python/openapi/src/com/jetbrains/python/packaging/PyPackageManager.java @@ -31,19 +31,16 @@ import java.util.Set; public abstract class PyPackageManager { public static final Key RUNNING_PACKAGING_TASKS = Key.create("PyPackageRequirementsInspection.RunningPackagingTasks"); - public static final String SETUPTOOLS = "setuptools"; - public static final String PIP = "pip"; - public static final String DISTRIBUTE = "distribute"; - public static final String USE_USER_SITE = "--user"; - public static PyPackageManager getInstance(Sdk sdk) { + @NotNull + public static PyPackageManager getInstance(@NotNull Sdk sdk) { return PyPackageManagers.getInstance().forSdk(sdk); } public abstract void installManagement() throws ExecutionException; - public abstract boolean hasManagement(boolean cachedOnly) throws ExecutionException; + public abstract boolean hasManagement() throws ExecutionException; public abstract void install(@NotNull String requirementString) throws ExecutionException; @@ -57,26 +54,14 @@ public abstract class PyPackageManager { public abstract String createVirtualEnv(@NotNull String destinationDir, boolean useGlobalSite) throws ExecutionException; @Nullable - public abstract List getPackages(boolean cachedOnly) throws ExecutionException; + public abstract List getPackages(); - /** - * @param cachedOnly only search through cached packages. Cache may be empty just after project opened. - * warning: non-cache access may be slow on remote interpreters. - * Use {@link #findPackage(String)}: this method uses cache on remote interpreters and skips - * in local - */ - @Nullable - public abstract PyPackage findPackage(@NotNull String name, boolean cachedOnly) throws ExecutionException; - - /** - * Like {@link #findPackage(String, boolean)} but controls cache access based on intepreter remote/local type - */ - @Nullable - public abstract PyPackage findPackage(@NotNull String name) throws ExecutionException; + @NotNull + public abstract List refreshAndGetPackages(boolean alwaysRefresh) throws ExecutionException; @Nullable public abstract List getRequirements(@NotNull Module module); - @Nullable + @NotNull public abstract Set getDependents(@NotNull PyPackage pkg) throws ExecutionException; } diff --git a/python/openapi/src/com/jetbrains/python/packaging/PyPackageManagers.java b/python/openapi/src/com/jetbrains/python/packaging/PyPackageManagers.java index 83fccdcea6cf..6729ff51ffd4 100644 --- a/python/openapi/src/com/jetbrains/python/packaging/PyPackageManagers.java +++ b/python/openapi/src/com/jetbrains/python/packaging/PyPackageManagers.java @@ -32,7 +32,7 @@ public abstract class PyPackageManagers { } @NotNull - public abstract PyPackageManager forSdk(Sdk sdk); + public abstract PyPackageManager forSdk(@NotNull Sdk sdk); public abstract PackageManagementService getManagementService(Project project, Sdk sdk); diff --git a/python/openapi/src/com/jetbrains/python/templateLanguages/PyTemplatesUtil.java b/python/openapi/src/com/jetbrains/python/templateLanguages/PyTemplatesUtil.java deleted file mode 100644 index ce08ddfd80dc..000000000000 --- a/python/openapi/src/com/jetbrains/python/templateLanguages/PyTemplatesUtil.java +++ /dev/null @@ -1,101 +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. - */ -package com.jetbrains.python.templateLanguages; - -import com.intellij.execution.ExecutionException; -import com.intellij.facet.ui.ValidationResult; -import com.intellij.lang.Language; -import com.intellij.openapi.projectRoots.Sdk; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.psi.FileViewProvider; -import com.intellij.psi.PsiElement; -import com.intellij.psi.templateLanguages.TemplateLanguageFileViewProvider; -import com.jetbrains.python.packaging.PyPackage; -import com.jetbrains.python.packaging.PyPackageManager; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public class PyTemplatesUtil { - private PyTemplatesUtil() { - } - - public static ValidationResult checkInstalled(@Nullable final Sdk sdk, @NotNull final TemplateLanguagePanel templatesPanel, - @NotNull final String prefix) { - if (sdk == null) return ValidationResult.OK; - String templateBinding = null; - @NonNls String language = templatesPanel.getTemplateLanguage(); - if (language != null) { - String framework = StringUtil.trimEnd(prefix, '_'); - framework = StringUtil.trimEnd(framework, '-'); - String postfix = language.toLowerCase(); - if (framework.equals(postfix)) return ValidationResult.OK; - if (language.equals(TemplatesService.JINJA2)) { - postfix = "jinja"; - } - templateBinding = prefix + postfix; - } - final PyPackageManager packageManager = PyPackageManager.getInstance(sdk); - if (templateBinding != null) { - if (TemplatesService.ALL_TEMPLATE_BINDINGS.contains(templateBinding)) { - try { - final PyPackage installedPackage = packageManager.findPackage(templateBinding, false); - if (installedPackage == null) { - return new ValidationResult(templateBinding + " will be installed on the selected interpreter"); - } - } - catch (ExecutionException ignored) { - } - } - } - if (language != null) { - try { - final PyPackage installedPackage = packageManager.findPackage(language, false); - if (installedPackage == null) { - return new ValidationResult(language + " will be installed on the selected interpreter"); - } - } - catch (ExecutionException ignored) { - } - } - return null; - } - - /** - * Fetches template data language if file has {@link TemplateLanguageFileViewProvider} - * - * @param psiElement element to get lang for - * @param expectedProvider only fetch language if provider has certain type. Pass null for any type. - * @return template data language - */ - @Nullable - public static Language getTemplateDataLanguage(@Nullable final PsiElement psiElement, - @Nullable final Class expectedProvider) { - if (psiElement == null) { - return null; - } - - final FileViewProvider provider = psiElement.getContainingFile().getViewProvider(); - if (provider instanceof TemplateLanguageFileViewProvider) { - if (expectedProvider == null || expectedProvider.isInstance(provider)) { - return (((TemplateLanguageFileViewProvider)provider).getTemplateDataLanguage()); - } - } - - return psiElement.getLanguage(); - } -} - diff --git a/python/openapi/src/com/jetbrains/python/templateLanguages/PythonTemplateIndentOptionsProvider.java b/python/openapi/src/com/jetbrains/python/templateLanguages/PythonTemplateIndentOptionsProvider.java deleted file mode 100644 index cb8663544b77..000000000000 --- a/python/openapi/src/com/jetbrains/python/templateLanguages/PythonTemplateIndentOptionsProvider.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2000-2015 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.jetbrains.python.templateLanguages; - -import com.intellij.lang.Language; -import com.intellij.psi.PsiFile; -import com.intellij.psi.codeStyle.CodeStyleSettings; -import com.intellij.psi.codeStyle.CommonCodeStyleSettings.IndentOptions; -import com.intellij.psi.codeStyle.FileIndentOptionsProvider; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * Injects indents for Python templates. - * In Python we have template langs, but we should use indent from underlying language (like html) - * because templ. language never works standalone: it is always emebedded in some language - * - * @author Ilya.Kazakevich - */ -public class PythonTemplateIndentOptionsProvider extends FileIndentOptionsProvider { - @Nullable - @Override - public final IndentOptions getIndentOptions(@NotNull final CodeStyleSettings settings, - @NotNull final PsiFile file) { - final Language language = file.getLanguage(); - if (!(language instanceof PythonTemplateLanguage)) { - return null; // We only care about python template files - } - - // This template language has no settings, lets use parent language then - final Language templateDataLanguage = PyTemplatesUtil.getTemplateDataLanguage(file, null); - if (templateDataLanguage == null) { - return null; // No template data language - } - return settings.getIndentOptions(templateDataLanguage.getAssociatedFileType()); - } -} diff --git a/python/openapi/src/com/jetbrains/python/templateLanguages/TemplatesService.java b/python/openapi/src/com/jetbrains/python/templateLanguages/TemplatesService.java index b8eb026b8674..a0be24a26434 100644 --- a/python/openapi/src/com/jetbrains/python/templateLanguages/TemplatesService.java +++ b/python/openapi/src/com/jetbrains/python/templateLanguages/TemplatesService.java @@ -19,9 +19,9 @@ import com.intellij.lang.Language; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleServiceManager; import com.intellij.openapi.project.Project; +import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.containers.ContainerUtil; -import com.jetbrains.python.packaging.PyPackageManager; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -111,7 +111,7 @@ public abstract class TemplatesService { public abstract void setTemplateFileTypes(List fileTypes); public abstract void generateTemplates(@NotNull final TemplateSettingsHolder settings, VirtualFile baseDir); - public abstract void installTemplateEngine(@NotNull final TemplateSettingsHolder settings, @NotNull final PyPackageManager packageManager, + public abstract void installTemplateEngine(@NotNull final TemplateSettingsHolder settings, @NotNull final Sdk sdk, @NotNull final Project project, @NotNull final String prefix); public abstract void addLanguageSelectedListener(Runnable listener); diff --git a/python/pluginJava/com/jetbrains/python/psi/impl/PyJavaImportCandidateProvider.java b/python/pluginJava/com/jetbrains/python/psi/impl/PyJavaImportCandidateProvider.java index a8673fb642c4..90a667299d84 100644 --- a/python/pluginJava/com/jetbrains/python/psi/impl/PyJavaImportCandidateProvider.java +++ b/python/pluginJava/com/jetbrains/python/psi/impl/PyJavaImportCandidateProvider.java @@ -41,7 +41,11 @@ public class PyJavaImportCandidateProvider implements PyImportCandidateProvider PsiShortNamesCache cache = PsiShortNamesCache.getInstance(project); final PsiClass[] classesByName = cache.getClassesByName(name, scope); for (PsiClass psiClass : classesByName) { - final QualifiedName packageQName = QualifiedName.fromDottedString(psiClass.getQualifiedName()).removeLastComponent(); + final String qualifiedName = psiClass.getQualifiedName(); + if (qualifiedName == null) { + continue; + } + final QualifiedName packageQName = QualifiedName.fromDottedString(qualifiedName).removeLastComponent(); quickFix.addImport(psiClass, psiClass.getContainingFile(), packageQName); } } diff --git a/python/pydevSrc/com/jetbrains/python/debugger/IPyDebugProcess.java b/python/pydevSrc/com/jetbrains/python/debugger/IPyDebugProcess.java index 82155bacd88f..ce55d8e87e83 100644 --- a/python/pydevSrc/com/jetbrains/python/debugger/IPyDebugProcess.java +++ b/python/pydevSrc/com/jetbrains/python/debugger/IPyDebugProcess.java @@ -37,5 +37,7 @@ public interface IPyDebugProcess extends PyFrameAccessor { boolean isSuspendedOnAllThreadsPolicy(); + void consoleInputRequested(); + XDebugSession getSession(); } diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/AbstractCommand.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/AbstractCommand.java index 4ed466cacbc6..941e39343ba4 100644 --- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/AbstractCommand.java +++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/AbstractCommand.java @@ -50,6 +50,7 @@ public abstract class AbstractCommand { public static final int STEP_INTO_MY_CODE = 144; public static final int LOG_CONCURRENCY_EVENT = 145; public static final int SHOW_RETURN_VALUES = 146; + public static final int INPUT_REQUESTED = 147; public static final int ERROR = 901; @@ -197,6 +198,10 @@ public abstract class AbstractCommand { return command == WRITE_TO_CONSOLE; } + public static boolean isInputRequested(final int command) { + return command == INPUT_REQUESTED; + } + public static boolean isExitEvent(final int command) { return command == EXIT; } diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java index 7b15821aef8b..08b93e8fbfa1 100644 --- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java +++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java @@ -547,6 +547,9 @@ public class RemoteDebugger implements ProcessDebugger { else if (AbstractCommand.isConcurrencyEvent(frame.getCommand())) { recordConcurrencyEvent(ProtocolParser.parseConcurrencyEvent(frame.getPayload(), myDebugProcess.getPositionConverter())); } + else if (AbstractCommand.isInputRequested(frame.getCommand())) { + myDebugProcess.consoleInputRequested(); + } else { placeResponse(frame.getSequence(), frame); } diff --git a/python/python-community-configure/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java b/python/python-community-configure/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java index d15ae055eaec..41be0e419608 100644 --- a/python/python-community-configure/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java +++ b/python/python-community-configure/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java @@ -51,8 +51,7 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; import java.util.ArrayList; import java.util.List; import java.util.Set; @@ -195,24 +194,16 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { myInitialSdkSet = myProjectSdksModel.getProjectSdks().keySet(); myProjectSdksModel.addListener(mySdkModelListener); - mySdkCombo.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { + mySdkCombo.addItemListener(e -> { + if (e.getStateChange() == ItemEvent.SELECTED) { final Sdk selectedSdk = (Sdk)mySdkCombo.getSelectedItem(); - myPackagesPanel.updatePackages(selectedSdk != null ? - PyPackageManagers.getInstance().getManagementService(myProject, selectedSdk) : null); + final PyPackageManagers packageManagers = PyPackageManagers.getInstance(); + myPackagesPanel.updatePackages(selectedSdk != null ? packageManagers.getManagementService(myProject, selectedSdk) : null); myPackagesPanel.updateNotifications(selectedSdk); } }); myAddSdkCallback = new SdkAddedCallback(); - myDetailsButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - showDetails(); - } - } - ); - + myDetailsButton.addActionListener(e -> showDetails()); } private void showDetails() { @@ -295,8 +286,6 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { else { mySdkCombo.getModel().setSelectedItem(selectedSdk == null ? null : myProjectSdksModel.findSdk(selectedSdk.getName())); } - myPackagesPanel.updatePackages(selectedSdk != null ? PyPackageManagers.getInstance().getManagementService(myProject, selectedSdk) : null); - myPackagesPanel.updateNotifications(selectedSdk); } private void rehighlightVersionSpecific(@Nullable final Sdk newSdk, @Nullable final Sdk prevSdk) { diff --git a/python/python-rest/src/com/jetbrains/rest/RestPythonUtil.java b/python/python-rest/src/com/jetbrains/rest/RestPythonUtil.java index e7e2eae2b928..b3353c6ab7e2 100644 --- a/python/python-rest/src/com/jetbrains/rest/RestPythonUtil.java +++ b/python/python-rest/src/com/jetbrains/rest/RestPythonUtil.java @@ -15,7 +15,6 @@ */ package com.jetbrains.rest; -import com.intellij.execution.ExecutionException; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.actionSystem.LangDataKeys; @@ -26,8 +25,11 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.Sdk; import com.jetbrains.python.packaging.PyPackage; import com.jetbrains.python.packaging.PyPackageManager; +import com.jetbrains.python.packaging.PyPackageUtil; import com.jetbrains.python.sdk.PythonSdkType; +import java.util.List; + /** * User : catherine */ @@ -45,15 +47,11 @@ public class RestPythonUtil { module = modules.length == 0 ? null : modules [0]; } if (module != null) { - Sdk sdk = PythonSdkType.findPythonSdk(module); + final Sdk sdk = PythonSdkType.findPythonSdk(module); if (sdk != null) { - PyPackageManager manager = PyPackageManager.getInstance(sdk); - try { - final PyPackage sphinx = manager.findPackage("Sphinx", false); - presentation.setEnabled(sphinx != null); - } - catch (ExecutionException ignored) { - } + final List packages = PyPackageManager.getInstance(sdk).getPackages(); + final PyPackage sphinx = packages != null ? PyPackageUtil.findPackage(packages, "Sphinx") : null; + presentation.setEnabled(sphinx != null); } } } diff --git a/python/python-rest/src/com/jetbrains/rest/run/sphinx/SphinxRunConfiguration.java b/python/python-rest/src/com/jetbrains/rest/run/sphinx/SphinxRunConfiguration.java index f2e90d02079e..26311708c5ce 100644 --- a/python/python-rest/src/com/jetbrains/rest/run/sphinx/SphinxRunConfiguration.java +++ b/python/python-rest/src/com/jetbrains/rest/run/sphinx/SphinxRunConfiguration.java @@ -25,10 +25,13 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; import com.jetbrains.python.packaging.PyPackage; import com.jetbrains.python.packaging.PyPackageManager; +import com.jetbrains.python.packaging.PyPackageUtil; import com.jetbrains.rest.run.RestConfigurationEditor; import com.jetbrains.rest.run.RestRunConfiguration; import org.jetbrains.annotations.NotNull; +import java.util.List; + /** * User : catherine */ @@ -42,14 +45,13 @@ public class SphinxRunConfiguration extends RestRunConfiguration { protected SettingsEditor createConfigurationEditor() { final SphinxTasksModel model = new SphinxTasksModel(); if (!model.contains("pdf") && getSdk() != null) { - try { - final PyPackage rst2pdf = PyPackageManager.getInstance(getSdk()).findPackage("rst2pdf"); + final List packages = PyPackageManager.getInstance(getSdk()).getPackages(); + if (packages != null) { + final PyPackage rst2pdf = PyPackageUtil.findPackage(packages,"rst2pdf"); if (rst2pdf != null) { model.add(13, "pdf"); } } - catch (ExecutionException ignored) { - } } RestConfigurationEditor editor = new RestConfigurationEditor(getProject(), this, model); diff --git a/python/src/com/jetbrains/python/PyBundle.properties b/python/src/com/jetbrains/python/PyBundle.properties index ee67f7d0e69a..d1e327049b9a 100644 --- a/python/src/com/jetbrains/python/PyBundle.properties +++ b/python/src/com/jetbrains/python/PyBundle.properties @@ -889,7 +889,8 @@ sdk.gen.reloading=Reloading generated skeletons... sdk.gen.reading.versions.file=Reading versions file... sdk.gen.notify.converting.old.skels=Converting old skeletons sdk.gen.notify.converting.text=Skeletons of binary modules seem to be from an older version.
These will be fully re-generated, which will take some time, but will happen only once.
Next time you open the project, only skeletons of new or updated binary modules will be re-generated. -sdk.gen.updating.skeletons=Updating Skeletons +sdk.gen.updating.interpreter=Updating Python Interpreter +sdk.scanning.installed.packages=Scanning Installed Packages sdk.gen.stubs.for.binary.modules=Generate stubs for binary module {0} # Active SDK configurable and related dialogs @@ -1009,4 +1010,4 @@ formatter.dictionary.literals=Dictionary literals smartKeys.insert.backslash.in.statement.on.enter=Insert backslash when pressing Enter inside a statement smartKeys.insert.self.in.method=Insert 'self' when defining a method -smartKeys.insert.type.placeholder.in.docstring.stub=Insert type placeholders in the documentation comment stub \ No newline at end of file +smartKeys.insert.type.placeholder.in.docstring.stub=Insert type placeholders in the documentation comment stub diff --git a/python/src/com/jetbrains/python/console/PydevConsoleExecuteActionHandler.java b/python/src/com/jetbrains/python/console/PydevConsoleExecuteActionHandler.java index 4f1b10b78692..67f52844bfe9 100644 --- a/python/src/com/jetbrains/python/console/PydevConsoleExecuteActionHandler.java +++ b/python/src/com/jetbrains/python/console/PydevConsoleExecuteActionHandler.java @@ -100,6 +100,10 @@ public class PydevConsoleExecuteActionHandler extends ProcessBackedConsoleExecut sendLineToConsole(new ConsoleCommunication.ConsoleCodeFragment(myInputBuffer.toString(), false)); } + public void clearInputBuffer() { + myInputBuffer = null; + } + private void processOneLine(String line) { int indentSize = IndentHelperImpl.getIndent(getProject(), PythonFileType.INSTANCE, line, false); line = StringUtil.trimTrailing(line); diff --git a/python/src/com/jetbrains/python/console/PythonConsoleView.java b/python/src/com/jetbrains/python/console/PythonConsoleView.java index e3e17b295f02..98a25946f70b 100644 --- a/python/src/com/jetbrains/python/console/PythonConsoleView.java +++ b/python/src/com/jetbrains/python/console/PythonConsoleView.java @@ -95,6 +95,18 @@ public class PythonConsoleView extends LanguageConsoleImpl implements Observable myExecuteActionHandler = consoleExecuteActionHandler; } + public void inputRequested() { + if (myExecuteActionHandler != null) { + final ConsoleCommunication consoleCommunication = myExecuteActionHandler.getConsoleCommunication(); + if (consoleCommunication instanceof PythonDebugConsoleCommunication) { + ((PythonDebugConsoleCommunication)consoleCommunication).waitingForInput = true; + myExecuteActionHandler.inputRequested(); + myExecuteActionHandler.setEnabled(true); + myExecuteActionHandler.clearInputBuffer(); + } + } + } + @Override public void requestFocus() { IdeFocusManager.findInstance().requestFocus(getConsoleEditor().getContentComponent(), true); diff --git a/python/src/com/jetbrains/python/console/PythonDebugConsoleCommunication.java b/python/src/com/jetbrains/python/console/PythonDebugConsoleCommunication.java index 25eb30cc0552..78ecbf99578b 100644 --- a/python/src/com/jetbrains/python/console/PythonDebugConsoleCommunication.java +++ b/python/src/com/jetbrains/python/console/PythonDebugConsoleCommunication.java @@ -15,8 +15,10 @@ */ package com.jetbrains.python.console; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; +import com.intellij.openapi.vfs.encoding.EncodingProjectManager; import com.intellij.util.Function; import com.jetbrains.python.console.pydev.AbstractConsoleCommunication; import com.jetbrains.python.console.pydev.InterpreterResponse; @@ -26,12 +28,16 @@ import com.jetbrains.python.debugger.PyDebuggerException; import com.jetbrains.python.debugger.pydev.PyDebugCallback; import org.jetbrains.annotations.NotNull; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.charset.Charset; import java.util.List; /** * @author traff */ public class PythonDebugConsoleCommunication extends AbstractConsoleCommunication { + private static final Logger LOG = Logger.getInstance("#com.jetbrains.python.console.pydev.PythonDebugConsoleCommunication"); private final PyDebugProcess myDebugProcess; private final StringBuilder myExpression = new StringBuilder(); @@ -55,7 +61,7 @@ public class PythonDebugConsoleCommunication extends AbstractConsoleCommunicatio @Override public boolean isWaitingForInput() { - return false; + return waitingForInput; } @Override @@ -78,24 +84,41 @@ public class PythonDebugConsoleCommunication extends AbstractConsoleCommunicatio } public void execInterpreter(ConsoleCodeFragment code, final Function callback) { - myExpression.append(code.getText()); - exec(new ConsoleCodeFragment(myExpression.toString(), false), new PyDebugCallback>() { - @Override - public void ok(Pair executed) { - boolean more = executed.second; - - if (!more) { - myExpression.setLength(0); + if (waitingForInput) { + final OutputStream processInput = myDebugProcess.getProcessHandler().getProcessInput(); + if (processInput != null) { + try { + final Charset defaultCharset = EncodingProjectManager.getInstance(myDebugProcess.getProject()).getDefaultCharset(); + processInput.write((code.getText()).getBytes(defaultCharset)); + processInput.flush(); + } + catch (IOException e) { + LOG.error(e.getMessage()); } - callback.fun(new InterpreterResponse(more, isWaitingForInput())); } + waitingForInput = false; + } + else { - @Override - public void error(PyDebuggerException exception) { - myExpression.setLength(0); - callback.fun(new InterpreterResponse(false, isWaitingForInput())); - } - }); + myExpression.append(code.getText()); + exec(new ConsoleCodeFragment(myExpression.toString(), false), new PyDebugCallback>() { + @Override + public void ok(Pair executed) { + boolean more = executed.second; + + if (!more) { + myExpression.setLength(0); + } + callback.fun(new InterpreterResponse(more, isWaitingForInput())); + } + + @Override + public void error(PyDebuggerException exception) { + myExpression.setLength(0); + callback.fun(new InterpreterResponse(false, isWaitingForInput())); + } + }); + } } @Override diff --git a/python/src/com/jetbrains/python/debugger/PyDebugProcess.java b/python/src/com/jetbrains/python/debugger/PyDebugProcess.java index ea7c3afccd9c..3570746593d0 100644 --- a/python/src/com/jetbrains/python/debugger/PyDebugProcess.java +++ b/python/src/com/jetbrains/python/debugger/PyDebugProcess.java @@ -346,6 +346,13 @@ public class PyDebugProcess extends XDebugProcess implements IPyDebugProcess, Pr } } + @Override + public void consoleInputRequested() { + if (myExecutionConsole instanceof PythonDebugLanguageConsoleView) { + ((PythonDebugLanguageConsoleView)myExecutionConsole).getPydevConsoleView().inputRequested(); + } + } + protected void afterConnect() { } @@ -526,7 +533,8 @@ public class PyDebugProcess extends XDebugProcess implements IPyDebugProcess, Pr breakpoint = myRegisteredExceptionBreakpoints.get(exceptionName); } } - if ((breakpoint != null) && (breakpoint.getSuspendPolicy() == SuspendPolicy.ALL)) { + if ((breakpoint != null) && (breakpoint.getType().isSuspendThreadSupported()) && + (breakpoint.getSuspendPolicy() == SuspendPolicy.ALL)) { return true; } } @@ -848,7 +856,7 @@ public class PyDebugProcess extends XDebugProcess implements IPyDebugProcess, Pr } } if (breakpoint != null) { - if (breakpoint.getSuspendPolicy() == SuspendPolicy.ALL) { + if ((breakpoint.getType().isSuspendThreadSupported()) && (breakpoint.getSuspendPolicy() == SuspendPolicy.ALL)) { suspendAllOtherThreads(threadInfo); } } diff --git a/python/src/com/jetbrains/python/inspections/PyPackageRequirementsInspection.java b/python/src/com/jetbrains/python/inspections/PyPackageRequirementsInspection.java index 31bd6d7cbf50..2ae69d0dd897 100644 --- a/python/src/com/jetbrains/python/inspections/PyPackageRequirementsInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyPackageRequirementsInspection.java @@ -39,7 +39,6 @@ import com.jetbrains.python.packaging.*; import com.jetbrains.python.packaging.ui.PyChooseRequirementsDialog; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.impl.PyPsiUtils; -import com.jetbrains.python.sdk.PySdkUtil; import com.jetbrains.python.sdk.PythonSdkType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -158,7 +157,7 @@ public class PyPackageRequirementsInspection extends PyInspection { return; } } - if (PyPackageManager.SETUPTOOLS.equals(packageName)) { + if (PyPackageUtil.SETUPTOOLS.equals(packageName)) { return; } final Module module = ModuleUtilCore.findModuleForPsiElement(packageReferenceExpression); @@ -211,13 +210,7 @@ public class PyPackageRequirementsInspection extends PyInspection { return Collections.emptySet(); } final Set results = new HashSet(requirements); - final List packages; - try { - packages = PyPackageManager.getInstance(sdk).getPackages(PySdkUtil.isRemote(sdk)); - } - catch (ExecutionException e) { - return null; - } + final List packages = PyPackageManager.getInstance(sdk).getPackages(); if (packages == null) return null; for (PyRequirement req : requirements) { final PyPackage pkg = req.match(packages); @@ -237,15 +230,10 @@ public class PyPackageRequirementsInspection extends PyInspection { final PyPackageManager manager = PyPackageManager.getInstance(sdk); List requirements = manager.getRequirements(module); if (requirements != null) { - final List packages; - try { - packages = manager.getPackages(PySdkUtil.isRemote(sdk)); - } - catch (ExecutionException e) { - LOG.warn(e); + final List packages = manager.getPackages(); + if (packages == null) { return null; } - if (packages == null) return null; final List unsatisfied = new ArrayList(); for (PyRequirement req : requirements) { if (!ignoredPackages.contains(req.getName()) && req.match(packages) == null) { @@ -297,13 +285,11 @@ public class PyPackageRequirementsInspection extends PyInspection { public void applyFix(@NotNull final Project project, @NotNull ProblemDescriptor descriptor) { boolean installManagement = false; final PyPackageManager manager = PyPackageManager.getInstance(mySdk); - boolean hasManagement = false; - try { - hasManagement = manager.hasManagement(false); + final List packages = manager.getPackages(); + if (packages == null) { + return; } - catch (ExecutionException ignored) { - } - if (!hasManagement) { + if (PyPackageUtil.hasManagement(packages)) { final int result = Messages.showYesNoDialog(project, "Python packaging tools are required for installing packages. Do you want to " + "install 'pip' and 'setuptools' for your interpreter?", diff --git a/python/src/com/jetbrains/python/packaging/PyCondaPackageManagerImpl.java b/python/src/com/jetbrains/python/packaging/PyCondaPackageManagerImpl.java index ac6135ac7135..12b0f622468b 100644 --- a/python/src/com/jetbrains/python/packaging/PyCondaPackageManagerImpl.java +++ b/python/src/com/jetbrains/python/packaging/PyCondaPackageManagerImpl.java @@ -49,9 +49,8 @@ public class PyCondaPackageManagerImpl extends PyPackageManagerImpl { public void installManagement() throws ExecutionException { } - @Override - public boolean hasManagement(boolean cachedOnly) throws ExecutionException { + public boolean hasManagement() throws ExecutionException { final Sdk sdk = getSdk(); return isCondaVEnv(sdk); } @@ -126,10 +125,10 @@ public class PyCondaPackageManagerImpl extends PyPackageManagerImpl { @NotNull @Override - protected List getPackages() throws ExecutionException { + protected List collectPackages() throws ExecutionException { final ProcessOutput output = getCondaOutput("list", Lists.newArrayList("-e")); final Set packages = Sets.newConcurrentHashSet(parseCondaToolOutput(output.getStdout())); - packages.addAll(super.getPackages()); + packages.addAll(super.collectPackages()); return Lists.newArrayList(packages); } diff --git a/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java b/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java index f504c905450e..fce9cffa7961 100644 --- a/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java +++ b/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java @@ -41,7 +41,6 @@ import com.intellij.util.messages.MessageBusConnection; import com.intellij.util.net.HttpConfigurable; import com.jetbrains.python.PythonHelpersLocator; import com.jetbrains.python.psi.LanguageLevel; -import com.jetbrains.python.sdk.PySdkUtil; import com.jetbrains.python.sdk.PythonEnvUtil; import com.jetbrains.python.sdk.PythonSdkType; import org.jetbrains.annotations.NotNull; @@ -50,22 +49,22 @@ import org.jetbrains.annotations.Nullable; import java.io.File; import java.io.IOException; import java.util.*; +import java.util.concurrent.atomic.AtomicBoolean; /** * @author vlan */ public class PyPackageManagerImpl extends PyPackageManager { // Python 2.4-2.5 compatible versions - public static final String SETUPTOOLS_PRE_26_VERSION = "1.4.2"; - public static final String PIP_PRE_26_VERSION = "1.1"; - public static final String VIRTUALENV_PRE_26_VERSION = "1.7.2"; + private static final String SETUPTOOLS_PRE_26_VERSION = "1.4.2"; + private static final String PIP_PRE_26_VERSION = "1.1"; + private static final String VIRTUALENV_PRE_26_VERSION = "1.7.2"; - public static final String SETUPTOOLS_VERSION = "18.1"; - public static final String PIP_VERSION = "7.1.0"; - public static final String VIRTUALENV_VERSION = "13.1.0"; + private static final String SETUPTOOLS_VERSION = "18.1"; + private static final String PIP_VERSION = "7.1.0"; + private static final String VIRTUALENV_VERSION = "13.1.0"; - public static final int OK = 0; - public static final int ERROR_NO_SETUPTOOLS = 3; + private static final int ERROR_NO_SETUPTOOLS = 3; private static final Logger LOG = Logger.getInstance(PyPackageManagerImpl.class); @@ -74,13 +73,12 @@ public class PyPackageManagerImpl extends PyPackageManager { private static final String BUILD_DIR_OPTION = "--build-dir"; - public static final String INSTALL = "install"; - public static final String UNINSTALL = "uninstall"; - public static final String UNTAR = "untar"; + private static final String INSTALL = "install"; + private static final String UNINSTALL = "uninstall"; + private static final String UNTAR = "untar"; - private final Object myCacheLock = new Object(); - private List myPackagesCache = null; - private ExecutionException myExceptionCache = null; + @Nullable private volatile List myPackagesCache = null; + private final AtomicBoolean myUpdatingCache = new AtomicBoolean(false); @NotNull final private Sdk mySdk; @@ -95,7 +93,6 @@ public class PyPackageManagerImpl extends PyPackageManager { VfsUtil.markDirtyAndRefresh(true, true, true, files); }); PythonSdkType.getInstance().setupSdkPaths(sdk); - clearCaches(); }); } @@ -103,24 +100,26 @@ public class PyPackageManagerImpl extends PyPackageManager { public void installManagement() throws ExecutionException { final Sdk sdk = getSdk(); final boolean pre26 = PythonSdkType.getLanguageLevelForSdk(sdk).isOlderThan(LanguageLevel.PYTHON26); - if (!hasSetuptools(false)) { - final String name = SETUPTOOLS + "-" + (pre26 ? SETUPTOOLS_PRE_26_VERSION : SETUPTOOLS_VERSION); + if (!refreshAndCheckForSetuptools()) { + final String name = PyPackageUtil.SETUPTOOLS + "-" + (pre26 ? SETUPTOOLS_PRE_26_VERSION : SETUPTOOLS_VERSION); installManagement(name); } - if (!hasPackage(PIP, false)) { - final String name = PIP + "-" + (pre26 ? PIP_PRE_26_VERSION : PIP_VERSION); + if (PyPackageUtil.findPackage(refreshAndGetPackages(false), PyPackageUtil.PIP) == null) { + final String name = PyPackageUtil.PIP + "-" + (pre26 ? PIP_PRE_26_VERSION : PIP_VERSION); installManagement(name); } } @Override - public boolean hasManagement(boolean cachedOnly) throws ExecutionException { - return hasSetuptools(cachedOnly) && hasPackage(PIP, cachedOnly); + public boolean hasManagement() throws ExecutionException { + return refreshAndCheckForSetuptools() && PyPackageUtil.findPackage(refreshAndGetPackages(false), PyPackageUtil.PIP) != null; } - private boolean hasSetuptools(boolean cachedOnly) throws ExecutionException { + private boolean refreshAndCheckForSetuptools() throws ExecutionException { try { - return hasPackage(SETUPTOOLS, cachedOnly) || hasPackage(DISTRIBUTE, cachedOnly); + final List packages = refreshAndGetPackages(false); + return PyPackageUtil.findPackage(packages, PyPackageUtil.SETUPTOOLS) != null || + PyPackageUtil.findPackage(packages, PyPackageUtil.DISTRIBUTE) != null; } catch (PyExecutionException e) { if (e.getExitCode() == ERROR_NO_SETUPTOOLS) { @@ -137,7 +136,6 @@ public class PyPackageManagerImpl extends PyPackageManager { getPythonProcessResult(fileName, Collections.singletonList(INSTALL), true, true, dirName + name); } finally { - clearCaches(); FileUtil.delete(new File(dirName)); } } @@ -154,10 +152,6 @@ public class PyPackageManagerImpl extends PyPackageManager { return dirName; } - private boolean hasPackage(@NotNull String name, boolean cachedOnly) throws ExecutionException { - return findPackage(name, cachedOnly) != null; - } - PyPackageManagerImpl(@NotNull final Sdk sdk) { mySdk = sdk; subscribeToLocalChanges(); @@ -177,12 +171,12 @@ public class PyPackageManagerImpl extends PyPackageManager { @Override public void install(@NotNull String requirementString) throws ExecutionException { installManagement(); - install(Collections.singletonList(PyRequirement.fromLine(requirementString)), Collections.emptyList()); + install(Collections.singletonList(PyRequirement.fromLine(requirementString)), Collections.emptyList()); } @Override public void install(@NotNull List requirements, @NotNull List extraArgs) throws ExecutionException { - final List args = new ArrayList(); + final List args = new ArrayList<>(); args.add(INSTALL); final File buildDir; try { @@ -195,7 +189,7 @@ public class PyPackageManagerImpl extends PyPackageManager { args.addAll(Arrays.asList(BUILD_DIR_OPTION, buildDir.getAbsolutePath())); } - boolean useUserSite = extraArgs.contains(USE_USER_SITE); + final boolean useUserSite = extraArgs.contains(USE_USER_SITE); final String proxyString = getProxyString(); if (proxyString != null) { @@ -210,7 +204,7 @@ public class PyPackageManagerImpl extends PyPackageManager { getHelperResult(PACKAGING_TOOL, args, !useUserSite, true, null); } catch (PyExecutionException e) { - final List simplifiedArgs = new ArrayList(); + final List simplifiedArgs = new ArrayList<>(); simplifiedArgs.add("install"); if (proxyString != null) { simplifiedArgs.add("--proxy"); @@ -223,14 +217,15 @@ public class PyPackageManagerImpl extends PyPackageManager { throw new PyExecutionException(e.getMessage(), "pip", simplifiedArgs, e.getStdout(), e.getStderr(), e.getExitCode(), e.getFixes()); } finally { - LOG.debug("Packages cache is about to be cleared because these requirements were installed: " + requirements); - clearCaches(); + LOG.debug("Packages cache is about to be refreshed because these requirements were installed: " + requirements); + refreshPackagesSynchronously(); FileUtil.delete(buildDir); } } + @Override public void uninstall(@NotNull List packages) throws ExecutionException { - final List args = new ArrayList(); + final List args = new ArrayList<>(); try { args.add(UNINSTALL); boolean canModify = true; @@ -249,60 +244,31 @@ public class PyPackageManagerImpl extends PyPackageManager { throw new PyExecutionException(e.getMessage(), "pip", args, e.getStdout(), e.getStderr(), e.getExitCode(), e.getFixes()); } finally { - LOG.debug("Packages cache is about to be cleared because these packages were uninstalled: " + packages); - clearCaches(); + LOG.debug("Packages cache is about to be refreshed because these packages were uninstalled: " + packages); + refreshPackagesSynchronously(); } } + @Nullable - public List getPackages(boolean cachedOnly) throws ExecutionException { - synchronized (myCacheLock) { - if (myPackagesCache != null) { - return new ArrayList(myPackagesCache); - } - if (myExceptionCache != null) { - throw myExceptionCache; - } - if (cachedOnly) { - return null; - } - } - try { - final List packages = getPackages(); - if (LOG.isDebugEnabled()) { - LOG.debug("Packages installed in " + mySdk.getName() + ": " + packages); - } - synchronized (myCacheLock) { - myPackagesCache = packages; - return new ArrayList(myPackagesCache); - } - } - catch (ExecutionException e) { - synchronized (myCacheLock) { - myExceptionCache = e; - } - throw e; - } + @Override + public List getPackages() { + final List packages = myPackagesCache; + return packages != null ? Collections.unmodifiableList(packages) : null; } - //@NotNull - //public String fetchLatestVersion(InstalledPackage pkg) throws ExecutionException { - // final ArrayList arguments = Lists.newArrayList("latestVersion", pkg.getName()); - // arguments.addAll(PyPackageService.getInstance().additionalRepositories); - // return getHelperResult(PACKAGING_TOOL, arguments, false, false, null); - //} - @NotNull - protected List getPackages() throws ExecutionException { + protected List collectPackages() throws ExecutionException { final String output; try { + LOG.debug("Collecting installed packages for the SDK " + mySdk.getName(), new Throwable()); output = getHelperResult(PACKAGING_TOOL, Collections.singletonList("list"), false, false, null); } catch (final ProcessNotCreatedException ex) { if (ApplicationManager.getApplication().isUnitTestMode()) { LOG.info("Not-env unit test mode, will return mock packages"); - return Lists.newArrayList(new PyPackage(PIP, PIP_VERSION, null, Collections.emptyList()), - new PyPackage(SETUPTOOLS, SETUPTOOLS_VERSION, null, Collections.emptyList())); + return Lists.newArrayList(new PyPackage(PyPackageUtil.PIP, PIP_VERSION, null, Collections.emptyList()), + new PyPackage(PyPackageUtil.SETUPTOOLS, SETUPTOOLS_VERSION, null, Collections.emptyList())); } else { throw ex; @@ -312,47 +278,26 @@ public class PyPackageManagerImpl extends PyPackageManager { return parsePackagingToolOutput(output); } - @Nullable + @Override + @NotNull public Set getDependents(@NotNull PyPackage pkg) throws ExecutionException { - final List packages = getPackages(false); - if (packages != null) { - final Set dependents = new HashSet(); - for (PyPackage p : packages) { - final List requirements = p.getRequirements(); - for (PyRequirement requirement : requirements) { - if (requirement.getName().equals(pkg.getName())) { - dependents.add(p); - } - } - } - return dependents; - } - return null; - } - - @Override - @Nullable - public PyPackage findPackage(@NotNull String name, boolean cachedOnly) throws ExecutionException { - final List packages = getPackages(cachedOnly); - if (packages != null) { - for (PyPackage pkg : packages) { - if (name.equalsIgnoreCase(pkg.getName())) { - return pkg; + final List packages = refreshAndGetPackages(false); + final Set dependents = new HashSet<>(); + for (PyPackage p : packages) { + final List requirements = p.getRequirements(); + for (PyRequirement requirement : requirements) { + if (requirement.getName().equals(pkg.getName())) { + dependents.add(p); } } } - return null; + return dependents; } - @Nullable @Override - public final PyPackage findPackage(@NotNull final String name) throws ExecutionException { - return findPackage(name, PySdkUtil.isRemote(mySdk)); - } - @NotNull public String createVirtualEnv(@NotNull String destinationDir, boolean useGlobalSite) throws ExecutionException { - final List args = new ArrayList(); + final List args = new ArrayList<>(); final Sdk sdk = getSdk(); final LanguageLevel languageLevel = PythonSdkType.getLanguageLevelForSdk(sdk); final boolean usePyVenv = languageLevel.isAtLeast(LanguageLevel.PYTHON33); @@ -398,6 +343,7 @@ public class PyPackageManagerImpl extends PyPackageManager { return path; } + @Override @Nullable public List getRequirements(@NotNull Module module) { return Optional @@ -405,12 +351,30 @@ public class PyPackageManagerImpl extends PyPackageManager { .orElseGet(() -> PyPackageUtil.findSetupPyRequires(module)); } - protected void clearCaches() { - synchronized (myCacheLock) { - myPackagesCache = null; - myExceptionCache = null; - LOG.debug("Packages cache is cleared"); + + // public List refreshAndGetPackagesIfNotInProgress(boolean alwaysRefresh) throws ExecutionException + + @Override + @NotNull + public List refreshAndGetPackages(boolean alwaysRefresh) throws ExecutionException { + final List currentPackages = myPackagesCache; + if (alwaysRefresh || currentPackages == null) { + try { + final List packages = collectPackages(); + LOG.debug("Packages installed in " + mySdk.getName() + ": " + packages); + myPackagesCache = packages; + return Collections.unmodifiableList(packages); + } + catch (ExecutionException e) { + myPackagesCache = Collections.emptyList(); + throw e; + } } + return Collections.unmodifiableList(currentPackages); + } + + private void refreshPackagesSynchronously() { + PyPackageUtil.updatePackagesSynchronouslyWithGuard(this, myUpdatingCache); } @Nullable @@ -468,7 +432,7 @@ public class PyPackageManagerImpl extends PyPackageManager { if (workingDir == null) { workingDir = new File(homePath).getParent(); } - final List cmdline = new ArrayList(); + final List cmdline = new ArrayList<>(); cmdline.add(homePath); cmdline.add(helperPath); cmdline.addAll(args); @@ -478,11 +442,11 @@ public class PyPackageManagerImpl extends PyPackageManager { final boolean useSudo = !canCreate && !SystemInfo.isWindows && askForSudo; try { - final Map environment = new HashMap(System.getenv()); + final Map environment = new HashMap<>(System.getenv()); PythonEnvUtil.setPythonUnbuffered(environment); PythonEnvUtil.setPythonDontWriteBytecode(environment); - GeneralCommandLine commandLine = new GeneralCommandLine(cmdline).withWorkDirectory(workingDir).withEnvironment(environment); - Process process; + final GeneralCommandLine commandLine = new GeneralCommandLine(cmdline).withWorkDirectory(workingDir).withEnvironment(environment); + final Process process; if (useSudo) { process = ExecUtil.sudo(commandLine, "Please enter your password to make changes in system packages: "); } @@ -535,16 +499,16 @@ public class PyPackageManagerImpl extends PyPackageManager { @NotNull private static List parsePackagingToolOutput(@NotNull String s) throws ExecutionException { final String[] lines = StringUtil.splitByLines(s); - final List packages = new ArrayList(); + final List packages = new ArrayList<>(); for (String line : lines) { final List fields = StringUtil.split(line, "\t"); if (fields.size() < 3) { - throw new PyExecutionException("Invalid output format", PACKAGING_TOOL, Collections.emptyList()); + throw new PyExecutionException("Invalid output format", PACKAGING_TOOL, Collections.emptyList()); } final String name = fields.get(0); final String version = fields.get(1); final String location = fields.get(2); - final List requirements = new ArrayList(); + final List requirements = new ArrayList<>(); if (fields.size() >= 4) { final String requiresLine = fields.get(3); final String requiresSpec = StringUtil.join(StringUtil.split(requiresLine, ":"), "\n"); @@ -567,8 +531,8 @@ public class PyPackageManagerImpl extends PyPackageManager { if (file != null) { for (VirtualFile root : roots) { if (VfsUtilCore.isAncestor(root, file, false)) { - LOG.debug("Clearing packages cache on SDK change"); - clearCaches(); + LOG.debug("Refreshing packages cache on SDK change"); + ApplicationManager.getApplication().executeOnPooledThread(PyPackageManagerImpl.this::refreshPackagesSynchronously); return; } } diff --git a/python/src/com/jetbrains/python/packaging/PyPackageManagersImpl.java b/python/src/com/jetbrains/python/packaging/PyPackageManagersImpl.java index 11d61778f85a..6f0a8cee52c2 100644 --- a/python/src/com/jetbrains/python/packaging/PyPackageManagersImpl.java +++ b/python/src/com/jetbrains/python/packaging/PyPackageManagersImpl.java @@ -29,10 +29,7 @@ import com.jetbrains.python.sdk.flavors.PythonSdkFlavor; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; /** * @author yole @@ -98,16 +95,16 @@ public class PyPackageManagersImpl extends PyPackageManagers { throw new ExecutionException(getErrorMessage()); } + @Override + public boolean hasManagement() throws ExecutionException { + return false; + } + @NotNull private String getErrorMessage() { return "Invalid interpreter \"" + myName + "\" version: " + myLanguageLevel.toString() + " type: " + myFlavor.getName(); } - @Override - public boolean hasManagement(boolean cachedOnly) throws ExecutionException { - throw new ExecutionException(getErrorMessage()); - } - @Override public void install(@NotNull String requirementString) throws ExecutionException { throw new ExecutionException(getErrorMessage()); @@ -135,19 +132,13 @@ public class PyPackageManagersImpl extends PyPackageManagers { @Nullable @Override - public List getPackages(boolean cachedOnly) throws ExecutionException { - throw new ExecutionException(getErrorMessage()); + public List getPackages() { + return null; } - @Nullable + @NotNull @Override - public PyPackage findPackage(@NotNull String name, boolean cachedOnly) throws ExecutionException { - throw new ExecutionException(getErrorMessage()); - } - - @Nullable - @Override - public PyPackage findPackage(@NotNull String name) throws ExecutionException { + public List refreshAndGetPackages(boolean alwaysRefresh) throws ExecutionException { throw new ExecutionException(getErrorMessage()); } @@ -157,7 +148,7 @@ public class PyPackageManagersImpl extends PyPackageManagers { return null; } - @Nullable + @NotNull @Override public Set getDependents(@NotNull PyPackage pkg) throws ExecutionException { throw new ExecutionException(getErrorMessage()); diff --git a/python/src/com/jetbrains/python/packaging/PyPackageUtil.java b/python/src/com/jetbrains/python/packaging/PyPackageUtil.java index 6ce2c625d814..b1e2ffe071d5 100644 --- a/python/src/com/jetbrains/python/packaging/PyPackageUtil.java +++ b/python/src/com/jetbrains/python/packaging/PyPackageUtil.java @@ -17,6 +17,9 @@ package com.jetbrains.python.packaging; import com.intellij.openapi.editor.Document; import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.execution.ExecutionException; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.Sdk; @@ -32,6 +35,7 @@ import com.intellij.openapi.vfs.VirtualFileVisitor; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiManager; +import com.jetbrains.python.PyBundle; import com.jetbrains.python.PyNames; import com.jetbrains.python.codeInsight.controlflow.ScopeOwner; import com.jetbrains.python.packaging.setupPy.SetupTaskIntrospector; @@ -48,11 +52,16 @@ import org.jetbrains.annotations.Nullable; import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; +import java.util.concurrent.atomic.AtomicBoolean; /** * @author vlan */ public class PyPackageUtil { + public static final String SETUPTOOLS = "setuptools"; + public static final String PIP = "pip"; + public static final String DISTRIBUTE = "distribute"; + private static final Logger LOG = Logger.getInstance(PyPackageUtil.class); @NotNull private static final String REQUIRES = "requires"; @@ -270,6 +279,66 @@ public class PyPackageUtil { }.withSshContribution(true).withVagrantContribution(true).withWebDeploymentContribution(true).check(sdk); } + @Nullable + public static List refreshAndGetPackagesModally(@NotNull Sdk sdk) { + final Ref> packagesRef = Ref.create(); + LOG.debug("Showing modal progress for collecting installed packages", new Throwable()); + PyUtil.runWithProgress(null, PyBundle.message("sdk.scanning.installed.packages"), true, false, indicator -> { + indicator.setIndeterminate(true); + try { + packagesRef.set(PyPackageManager.getInstance(sdk).refreshAndGetPackages(false)); + } + catch (ExecutionException e) { + LOG.warn(e); + } + }); + return packagesRef.get(); + } + + /** + * Run unconditional update of the list of packages installed in SDK. Normally only one such of updates should run at time. + * This behavior in enforced by the parameter isUpdating. + * + * @param manager package manager for SDK + * @param isUpdating flag indicating whether another refresh is already running + * @return whether packages were refreshed successfully, e.g. this update wasn't cancelled because of another refresh in progress + */ + public static boolean updatePackagesSynchronouslyWithGuard(@NotNull PyPackageManager manager, @NotNull AtomicBoolean isUpdating) { + assert !ApplicationManager.getApplication().isDispatchThread(); + if (!isUpdating.compareAndSet(false, true)) { + return false; + } + try { + if (manager instanceof PyPackageManagerImpl) { + LOG.info("Refreshing installed packages for SDK " + ((PyPackageManagerImpl)manager).getSdk().getHomePath()); + } + manager.refreshAndGetPackages(true); + } + catch (ExecutionException e) { + LOG.warn(e); + } + finally { + isUpdating.set(false); + } + return true; + } + + + @Nullable + public static PyPackage findPackage(@NotNull List packages, @NotNull String name) { + for (PyPackage pkg : packages) { + if (name.equalsIgnoreCase(pkg.getName())) { + return pkg; + } + } + return null; + } + + public static boolean hasManagement(@NotNull List packages) { + return (findPackage(packages, SETUPTOOLS) != null || findPackage(packages, DISTRIBUTE) != null) || + findPackage(packages, PIP) != null; + } + @Nullable public static List getRequirementsFromTxt(@NotNull Module module) { final VirtualFile requirementsTxt = findRequirementsTxt(module); diff --git a/python/src/com/jetbrains/python/packaging/PyRemotePackageManagerImpl.java b/python/src/com/jetbrains/python/packaging/PyRemotePackageManagerImpl.java index 2fe8f70bfead..158dcfceed99 100644 --- a/python/src/com/jetbrains/python/packaging/PyRemotePackageManagerImpl.java +++ b/python/src/com/jetbrains/python/packaging/PyRemotePackageManagerImpl.java @@ -214,7 +214,6 @@ public class PyRemotePackageManagerImpl extends PyPackageManagerImpl { try { manager.runVagrant(myVagrantFolder, myMachineName); PythonSdkType.getInstance().setupSdkPaths(sdk); - clearCaches(); } catch (ExecutionException e) { throw new RuntimeException(e); diff --git a/python/src/com/jetbrains/python/packaging/ui/PyInstalledPackagesPanel.java b/python/src/com/jetbrains/python/packaging/ui/PyInstalledPackagesPanel.java index f0a5a850751a..f84a7eb24b51 100644 --- a/python/src/com/jetbrains/python/packaging/ui/PyInstalledPackagesPanel.java +++ b/python/src/com/jetbrains/python/packaging/ui/PyInstalledPackagesPanel.java @@ -93,7 +93,7 @@ public class PyInstalledPackagesPanel extends InstalledPackagesPanel { application.executeOnPooledThread(() -> { PyExecutionException exception = null; try { - myHasManagement = PyPackageManager.getInstance(selectedSdk).hasManagement(false); + myHasManagement = PyPackageManager.getInstance(selectedSdk).hasManagement(); if (!myHasManagement) { throw new PyExecutionException("Python packaging tools not found", "pip", Collections.emptyList(), "", "", 0, ImmutableList.of(new PyInstallPackageManagementFix())); @@ -156,9 +156,9 @@ public class PyInstalledPackagesPanel extends InstalledPackagesPanel { } } final String name = pkg.getName(); - if (PyPackageManager.PIP.equals(name) || - PyPackageManager.SETUPTOOLS.equals(name) || - PyPackageManager.DISTRIBUTE.equals(name) || + if (PyPackageUtil.PIP.equals(name) || + PyPackageUtil.SETUPTOOLS.equals(name) || + PyPackageUtil.DISTRIBUTE.equals(name) || PyCondaPackageManagerImpl.PYTHON.equals(name)) { return false; } diff --git a/python/src/com/jetbrains/python/packaging/ui/PyPackageManagementService.java b/python/src/com/jetbrains/python/packaging/ui/PyPackageManagementService.java index 4096539aef49..78332f1fdba4 100644 --- a/python/src/com/jetbrains/python/packaging/ui/PyPackageManagementService.java +++ b/python/src/com/jetbrains/python/packaging/ui/PyPackageManagementService.java @@ -15,6 +15,7 @@ */ package com.jetbrains.python.packaging.ui; +import com.google.common.collect.Lists; import com.intellij.execution.ExecutionException; import com.intellij.execution.RunCanceledByUserException; import com.intellij.openapi.project.Project; @@ -139,17 +140,17 @@ public class PyPackageManagementService extends PackageManagementServiceEx { @Override public Collection getInstalledPackages() throws IOException { - List packages; + + final PyPackageManager manager = PyPackageManager.getInstance(mySdk); + final List packages; try { - packages = PyPackageManager.getInstance(mySdk).getPackages(false); - if (packages != null) { - Collections.sort(packages, (pkg1, pkg2) -> pkg1.getName().compareTo(pkg2.getName())); - } + packages = Lists.newArrayList(manager.refreshAndGetPackages(true)); } catch (ExecutionException e) { throw new IOException(e); } - return packages != null ? new ArrayList(packages) : new ArrayList(); + Collections.sort(packages, (pkg1, pkg2) -> pkg1.getName().compareTo(pkg2.getName())); + return new ArrayList(packages); } @Override diff --git a/python/src/com/jetbrains/python/psi/PyUtil.java b/python/src/com/jetbrains/python/psi/PyUtil.java index 9fdc17b2ebb1..bdf133eed108 100644 --- a/python/src/com/jetbrains/python/psi/PyUtil.java +++ b/python/src/com/jetbrains/python/psi/PyUtil.java @@ -28,6 +28,7 @@ import com.intellij.injected.editor.VirtualFileWindow; import com.intellij.lang.ASTFactory; import com.intellij.lang.ASTNode; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.EditorFactory; @@ -38,6 +39,9 @@ import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.module.ModuleUtilCore; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.roots.ModuleRootManager; @@ -81,15 +85,11 @@ import com.jetbrains.python.refactoring.classes.PyDependenciesComparator; import com.jetbrains.python.refactoring.classes.extractSuperclass.PyExtractSuperclassHelper; import com.jetbrains.python.refactoring.classes.membersManager.PyMemberInfo; import com.jetbrains.python.sdk.PythonSdkType; -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.*; import javax.swing.*; import java.awt.*; import java.io.File; -import java.io.FileFilter; import java.io.IOException; import java.util.*; import java.util.List; @@ -858,6 +858,28 @@ public class PyUtil { return result; } + public static void runWithProgress(@Nullable Project project, @Nls(capitalization = Nls.Capitalization.Title) @NotNull String title, + boolean modal, boolean canBeCancelled, @NotNull final Consumer function) { + ApplicationManager.getApplication().invokeAndWait(() -> { + if (modal) { + ProgressManager.getInstance().run(new Task.Modal(project, title, canBeCancelled) { + @Override + public void run(@NotNull ProgressIndicator indicator) { + function.consume(indicator); + } + }); + } + else { + ProgressManager.getInstance().run(new Task.Backgroundable(project, title, canBeCancelled) { + @Override + public void run(@NotNull ProgressIndicator indicator) { + function.consume(indicator); + } + }); + } + }, ModalityState.current()); + } + /** * Executes code only if
_PYCHARM_VERBOSE_MODE
is set in env (which should be done for debug purposes only) * @param runnable code to call diff --git a/python/src/com/jetbrains/python/sdk/PythonSdkType.java b/python/src/com/jetbrains/python/sdk/PythonSdkType.java index f45a1331e6b7..f4e78a80c7c8 100644 --- a/python/src/com/jetbrains/python/sdk/PythonSdkType.java +++ b/python/src/com/jetbrains/python/sdk/PythonSdkType.java @@ -59,7 +59,6 @@ import com.intellij.remote.ext.LanguageCaseCollector; import com.intellij.util.ArrayUtil; import com.intellij.util.Consumer; import com.intellij.util.ExceptionUtil; -import com.intellij.util.NullableConsumer; import com.intellij.util.containers.ContainerUtil; import com.jetbrains.python.PyBundle; import com.jetbrains.python.PyNames; @@ -322,9 +321,11 @@ public final class PythonSdkType extends SdkType { final String version = getVersionString(sdk); if (flavor != null && version != null) { for (Sdk baseSdk : getAllSdks()) { - final PythonSdkFlavor baseFlavor = PythonSdkFlavor.getFlavor(baseSdk); - if (!isVirtualEnv(baseSdk) && flavor.equals(baseFlavor) && version.equals(getVersionString(baseSdk))) { - return baseSdk; + if (!isRemote(baseSdk)) { + final PythonSdkFlavor baseFlavor = PythonSdkFlavor.getFlavor(baseSdk); + if (!isVirtualEnv(baseSdk) && flavor.equals(baseFlavor) && version.equals(getVersionString(baseSdk))) { + return baseSdk; + } } } } diff --git a/python/src/com/jetbrains/python/sdk/PythonSdkUpdater.java b/python/src/com/jetbrains/python/sdk/PythonSdkUpdater.java index 7baf341b46de..7e38682fcf4f 100644 --- a/python/src/com/jetbrains/python/sdk/PythonSdkUpdater.java +++ b/python/src/com/jetbrains/python/sdk/PythonSdkUpdater.java @@ -18,6 +18,7 @@ package com.jetbrains.python.sdk; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import com.google.common.collect.Sets; +import com.intellij.execution.ExecutionException; import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; @@ -44,6 +45,7 @@ import com.intellij.util.concurrency.BlockingSet; import com.intellij.util.concurrency.EdtExecutorService; import com.jetbrains.python.PyBundle; import com.jetbrains.python.codeInsight.userSkeletons.PyUserSkeletonsUtil; +import com.jetbrains.python.packaging.PyPackageManager; import com.jetbrains.python.psi.PyUtil; import com.jetbrains.python.remote.PyCredentialsContribution; import com.jetbrains.python.remote.PyRemoteSdkAdditionalDataBase; @@ -138,7 +140,7 @@ public class PythonSdkUpdater implements StartupActivity { } ourScheduledToRefresh.remove(homePath); } - ProgressManager.getInstance().run(new Task.Backgroundable(project, PyBundle.message("sdk.gen.updating.skeletons"), false) { + ProgressManager.getInstance().run(new Task.Backgroundable(project, PyBundle.message("sdk.gen.updating.interpreter"), false) { @Override public void run(@NotNull ProgressIndicator indicator) { final Project project1 = getProject(); @@ -152,8 +154,19 @@ public class PythonSdkUpdater implements StartupActivity { LOG.error("For refreshing skeletons of remote SDK, either project or owner component must be specified"); } LOG.info("Performing background update of skeletons for SDK " + sdk12.getHomePath()); + indicator.setText("Updating skeletons..."); PySkeletonRefresher.refreshSkeletonsOfSdk(project1, ownerComponent, skeletonsPath, sdk12); updateRemoteSdkPaths(sdk12); + indicator.setIndeterminate(true); + indicator.setText("Scanning installed packages..."); + indicator.setText2(""); + LOG.info("Performing background scan of packages for SDK " + sdk12.getHomePath()); + try { + PyPackageManager.getInstance(sdk12).refreshAndGetPackages(true); + } + catch (ExecutionException e) { + LOG.error(e); + } } catch (InvalidSdkException e) { if (PythonSdkType.isVagrant(sdk12) diff --git a/python/src/com/jetbrains/python/sdk/skeletons/PySkeletonRefresher.java b/python/src/com/jetbrains/python/sdk/skeletons/PySkeletonRefresher.java index a3600e260b3b..bc5cd1f8f936 100644 --- a/python/src/com/jetbrains/python/sdk/skeletons/PySkeletonRefresher.java +++ b/python/src/com/jetbrains/python/sdk/skeletons/PySkeletonRefresher.java @@ -43,7 +43,6 @@ import com.jetbrains.python.PyBundle; import com.jetbrains.python.PyNames; import com.jetbrains.python.buildout.BuildoutFacet; import com.jetbrains.python.codeInsight.userSkeletons.PyUserSkeletonsUtil; -import com.jetbrains.python.packaging.PyPackageManager; import com.jetbrains.python.psi.resolve.PythonSdkPathCache; import com.jetbrains.python.remote.PythonRemoteInterpreterManager; import com.jetbrains.python.sdk.InvalidSdkException; @@ -345,15 +344,6 @@ public class PySkeletonRefresher { indicate(PyBundle.message("sdk.gen.cleaning.$0", readablePath)); cleanUpSkeletons(skeletonsDir); } - if (PySdkUtil.isRemote(mySdk)) { - try { - // Force loading packages - PyPackageManager.getInstance(mySdk).getPackages(false); - } - catch (ExecutionException e) { - // ignore - already logged - } - } if ((builtinsUpdated || PySdkUtil.isRemote(mySdk)) && myProject != null) { ApplicationManager.getApplication().invokeLater(() -> DaemonCodeAnalyzer.getInstance(myProject).restart(), myProject.getDisposed()); diff --git a/python/src/com/jetbrains/python/testing/PyIntegratedToolsProjectConfigurator.java b/python/src/com/jetbrains/python/testing/PyIntegratedToolsProjectConfigurator.java index 3ad43f6d6c86..8cf525865f0f 100644 --- a/python/src/com/jetbrains/python/testing/PyIntegratedToolsProjectConfigurator.java +++ b/python/src/com/jetbrains/python/testing/PyIntegratedToolsProjectConfigurator.java @@ -38,6 +38,7 @@ import com.jetbrains.python.PythonModuleTypeBase; import com.jetbrains.python.documentation.PyDocumentationSettings; import com.jetbrains.python.documentation.docstrings.DocStringFormat; import com.jetbrains.python.documentation.docstrings.DocStringUtil; +import com.jetbrains.python.packaging.PyPackage; import com.jetbrains.python.packaging.PyPackageUtil; import com.jetbrains.python.psi.*; import com.jetbrains.python.sdk.PythonSdkType; @@ -114,17 +115,20 @@ public class PyIntegratedToolsProjectConfigurator implements DirectoryProjectCon //check if installed in sdk final Sdk sdk = PythonSdkType.findPythonSdk(module); if (sdk != null && sdk.getSdkType() instanceof PythonSdkType) { - final Boolean nose = VFSTestFrameworkListener.isTestFrameworkInstalled(sdk, PyNames.NOSE_TEST); - final Boolean pytest = VFSTestFrameworkListener.isTestFrameworkInstalled(sdk, PyNames.PY_TEST); - final Boolean attest = VFSTestFrameworkListener.isTestFrameworkInstalled(sdk, PyNames.AT_TEST); - if (nose != null && nose) - testRunner = PythonTestConfigurationsModel.PYTHONS_NOSETEST_NAME; - else if (pytest != null && pytest) - testRunner = PythonTestConfigurationsModel.PY_TEST_NAME; - else if (attest != null && attest) - testRunner = PythonTestConfigurationsModel.PYTHONS_ATTEST_NAME; - if (!testRunner.isEmpty()) { - LOG.debug("Test runner '" + testRunner + "' was detected from SDK " + sdk); + final List packages = PyPackageUtil.refreshAndGetPackagesModally(sdk); + if (packages != null) { + final boolean nose = PyPackageUtil.findPackage(packages, PyNames.NOSE_TEST) != null; + final boolean pytest = PyPackageUtil.findPackage(packages, PyNames.PY_TEST) != null; + final boolean attest = PyPackageUtil.findPackage(packages, PyNames.AT_TEST) != null; + if (nose) + testRunner = PythonTestConfigurationsModel.PYTHONS_NOSETEST_NAME; + else if (pytest) + testRunner = PythonTestConfigurationsModel.PY_TEST_NAME; + else if (attest) + testRunner = PythonTestConfigurationsModel.PYTHONS_ATTEST_NAME; + if (!testRunner.isEmpty()) { + LOG.debug("Test runner '" + testRunner + "' was detected from SDK " + sdk); + } } } } diff --git a/python/src/com/jetbrains/python/testing/VFSTestFrameworkListener.java b/python/src/com/jetbrains/python/testing/VFSTestFrameworkListener.java index 6dd8eb7b839a..d193dc2aabc9 100644 --- a/python/src/com/jetbrains/python/testing/VFSTestFrameworkListener.java +++ b/python/src/com/jetbrains/python/testing/VFSTestFrameworkListener.java @@ -15,7 +15,6 @@ */ package com.jetbrains.python.testing; -import com.intellij.execution.ExecutionException; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.projectRoots.Sdk; @@ -30,22 +29,25 @@ import com.intellij.openapi.vfs.newvfs.events.VFileContentChangeEvent; import com.intellij.openapi.vfs.newvfs.events.VFileEvent; import com.intellij.util.Alarm; import com.intellij.util.messages.MessageBus; -import com.intellij.util.ui.UIUtil; import com.intellij.util.ui.update.MergingUpdateQueue; import com.intellij.util.ui.update.Update; import com.jetbrains.python.PyNames; +import com.jetbrains.python.packaging.PyPackage; import com.jetbrains.python.packaging.PyPackageManager; +import com.jetbrains.python.packaging.PyPackageUtil; import com.jetbrains.python.sdk.PySdkUtil; import com.jetbrains.python.sdk.PythonSdkType; import org.jetbrains.annotations.NotNull; import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; /** * User: catherine */ public class VFSTestFrameworkListener { private static final Logger LOG = Logger.getInstance("#com.jetbrains.python.testing.VFSTestFrameworkListener"); + private final AtomicBoolean myIsUpdating = new AtomicBoolean(false); private final MergingUpdateQueue myQueue; private final PyTestFrameworkService myService; @@ -112,17 +114,18 @@ public class VFSTestFrameworkListener { /** * @return null if we can't be sure */ - public static Boolean isTestFrameworkInstalled(Sdk sdk, String testPackageName) { + public Boolean isTestFrameworkInstalled(Sdk sdk, String testPackageName) { if (sdk == null || StringUtil.isEmptyOrSpaces(sdk.getHomePath())) { LOG.info("Searching test runner in empty sdk"); return null; } - final PyPackageManager packageManager = PyPackageManager.getInstance(sdk); - try { - return packageManager.findPackage(testPackageName, false) != null; - } - catch (ExecutionException e) { - LOG.info("Can't load package list " + e.getMessage()); + final PyPackageManager manager = PyPackageManager.getInstance(sdk); + final boolean refreshed = PyPackageUtil.updatePackagesSynchronouslyWithGuard(manager, myIsUpdating); + if (refreshed) { + final List packages = manager.getPackages(); + if (packages != null) { + return PyPackageUtil.findPackage(packages, testPackageName) != null; + } } return null; } diff --git a/python/src/com/jetbrains/python/testing/pytest/PyTestConfigurationProducer.java b/python/src/com/jetbrains/python/testing/pytest/PyTestConfigurationProducer.java index 2249516da492..69fa292538c8 100644 --- a/python/src/com/jetbrains/python/testing/pytest/PyTestConfigurationProducer.java +++ b/python/src/com/jetbrains/python/testing/pytest/PyTestConfigurationProducer.java @@ -15,7 +15,6 @@ */ package com.jetbrains.python.testing.pytest; -import com.intellij.execution.ExecutionException; import com.intellij.execution.Location; import com.intellij.execution.actions.ConfigurationContext; import com.intellij.openapi.module.Module; @@ -31,6 +30,7 @@ import com.intellij.psi.util.PsiTreeUtil; import com.intellij.webcore.packaging.PackageVersionComparator; import com.jetbrains.python.packaging.PyPackage; import com.jetbrains.python.packaging.PyPackageManager; +import com.jetbrains.python.packaging.PyPackageUtil; import com.jetbrains.python.psi.PyClass; import com.jetbrains.python.psi.PyFile; import com.jetbrains.python.psi.PyFunction; @@ -115,17 +115,12 @@ public class PyTestConfigurationProducer extends PythonTestConfigurationProducer if (pyFunction != null) { keywords = pyFunction.getName(); if (pyClass != null) { - final PyPackageManager packageManager = PyPackageManager.getInstance(sdk); - try { - final PyPackage pytestPackage = packageManager.findPackage("pytest", false); - if (pytestPackage != null && PackageVersionComparator.VERSION_COMPARATOR.compare(pytestPackage.getVersion(), "2.3.3") >= 0) { - keywords = pyClass.getName() + " and " + keywords; - } - else { - keywords = pyClass.getName() + "." + keywords; - } + final List packages = PyPackageManager.getInstance(sdk).getPackages(); + final PyPackage pytestPackage = packages != null ? PyPackageUtil.findPackage(packages, "pytest") : null; + if (pytestPackage != null && PackageVersionComparator.VERSION_COMPARATOR.compare(pytestPackage.getVersion(), "2.3.3") >= 0) { + keywords = pyClass.getName() + " and " + keywords; } - catch (ExecutionException e) { + else { keywords = pyClass.getName() + "." + keywords; } } diff --git a/python/testSrc/com/jetbrains/env/PyEnvTestCase.java b/python/testSrc/com/jetbrains/env/PyEnvTestCase.java index 3e0d55d15fb4..01587acba9c2 100644 --- a/python/testSrc/com/jetbrains/env/PyEnvTestCase.java +++ b/python/testSrc/com/jetbrains/env/PyEnvTestCase.java @@ -19,6 +19,7 @@ import com.intellij.util.ui.UIUtil; import com.jetbrains.TestEnv; import com.jetbrains.python.packaging.PyPackage; import com.jetbrains.python.packaging.PyPackageManager; +import com.jetbrains.python.packaging.PyPackageUtil; import org.hamcrest.Matchers; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -113,7 +114,7 @@ public abstract class PyEnvTestCase { @Nullable public static PyPackage getInstalledDjango(@NotNull final Sdk sdk) throws ExecutionException { - return PyPackageManager.getInstance(sdk).findPackage("django", false); + return PyPackageUtil.findPackage(PyPackageManager.getInstance(sdk).refreshAndGetPackages(false), "django"); } public static String norm(String testDataPath) { diff --git a/python/testSrc/com/jetbrains/env/python/PyPackagingTest.java b/python/testSrc/com/jetbrains/env/python/PyPackagingTest.java index e89d9033bf8e..a7d127c5a325 100644 --- a/python/testSrc/com/jetbrains/env/python/PyPackagingTest.java +++ b/python/testSrc/com/jetbrains/env/python/PyPackagingTest.java @@ -52,7 +52,7 @@ public class PyPackagingTest extends PyEnvTestCase { final Sdk sdk = createTempSdk(sdkHome, SdkCreationType.EMPTY_SDK); List packages = null; try { - packages = PyPackageManager.getInstance(sdk).getPackages(false); + packages = PyPackageManager.getInstance(sdk).refreshAndGetPackages(false); } catch (ExecutionException ignored) { } @@ -82,7 +82,7 @@ public class PyPackagingTest extends PyEnvTestCase { assertNotNull(venvSdk); assertTrue(PythonSdkType.isVirtualEnv(venvSdk)); assertInstanceOf(PythonSdkFlavor.getPlatformIndependentFlavor(venvSdk.getHomePath()), VirtualEnvSdkFlavor.class); - final List packages = PyPackageManager.getInstance(venvSdk).getPackages(false); + final List packages = PyPackageManager.getInstance(venvSdk).refreshAndGetPackages(false); final PyPackage setuptools = findPackage("setuptools", packages); assertNotNull(setuptools); assertEquals("setuptools", setuptools.getName()); @@ -114,11 +114,11 @@ public class PyPackagingTest extends PyEnvTestCase { final Sdk venvSdk = createTempSdk(venvSdkHome, SdkCreationType.EMPTY_SDK); assertNotNull(venvSdk); final PyPackageManager manager = PyPackageManager.getInstance(venvSdk); - final List packages1 = manager.getPackages(false); + final List packages1 = manager.refreshAndGetPackages(false); // TODO: Install Markdown from a local file manager.install(list(PyRequirement.fromLine("Markdown<2.2"), new PyRequirement("httplib2")), Collections.emptyList()); - final List packages2 = manager.getPackages(false); + final List packages2 = manager.refreshAndGetPackages(false); final PyPackage markdown2 = findPackage("Markdown", packages2); assertNotNull(markdown2); assertTrue(markdown2.isInstalled()); @@ -126,7 +126,7 @@ public class PyPackagingTest extends PyEnvTestCase { assertNotNull(pip1); assertEquals("pip", pip1.getName()); manager.uninstall(list(pip1)); - final List packages3 = manager.getPackages(false); + final List packages3 = manager.refreshAndGetPackages(false); final PyPackage pip2 = findPackage("pip", packages3); assertNull(pip2); } diff --git a/python/testSrc/com/jetbrains/python/inspections/PyPackageRequirementsInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyPackageRequirementsInspectionTest.java index 00d5eee2330e..554c34a904cf 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyPackageRequirementsInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyPackageRequirementsInspectionTest.java @@ -15,14 +15,25 @@ */ package com.jetbrains.python.inspections; +import com.intellij.openapi.projectRoots.Sdk; import com.jetbrains.python.fixtures.PyTestCase; +import com.jetbrains.python.packaging.PyPackageManager; import com.jetbrains.python.psi.LanguageLevel; +import com.jetbrains.python.sdk.PythonSdkType; import org.jetbrains.annotations.NotNull; /** * @author vlan */ public class PyPackageRequirementsInspectionTest extends PyTestCase { + @Override + public void setUp() throws Exception { + super.setUp(); + final Sdk sdk = PythonSdkType.findPythonSdk(myFixture.getModule()); + assertNotNull(sdk); + PyPackageManager.getInstance(sdk).refreshAndGetPackages(true); + } + public void testPartiallySatisfiedRequirementsTxt() { doTest("test1.py"); } diff --git a/resources-en/src/inspectionDescriptions/RedundantLambdaParameterType.html b/resources-en/src/inspectionDescriptions/RedundantLambdaParameterType.html new file mode 100644 index 000000000000..ea49461e2613 --- /dev/null +++ b/resources-en/src/inspectionDescriptions/RedundantLambdaParameterType.html @@ -0,0 +1,5 @@ + + +This inspection removes lambda formal parameter types when they can be inferred from context. + + \ No newline at end of file diff --git a/resources-en/src/intentionDescriptions/DelegateWithDefaultParamValueIntentionAction/after.java.template b/resources-en/src/intentionDescriptions/DelegateWithDefaultParamValueIntentionAction/after.java.template deleted file mode 100644 index 8b1a0e1d4fe8..000000000000 --- a/resources-en/src/intentionDescriptions/DelegateWithDefaultParamValueIntentionAction/after.java.template +++ /dev/null @@ -1,9 +0,0 @@ -class Test { - void foo(int a) { - foo(a, |); - } - - void foo(int a, int b) { - //do smth - } -} \ No newline at end of file diff --git a/resources-en/src/intentionDescriptions/DelegateWithDefaultParamValueIntentionAction/before.java.template b/resources-en/src/intentionDescriptions/DelegateWithDefaultParamValueIntentionAction/before.java.template deleted file mode 100644 index 0ecad2088cdf..000000000000 --- a/resources-en/src/intentionDescriptions/DelegateWithDefaultParamValueIntentionAction/before.java.template +++ /dev/null @@ -1,5 +0,0 @@ -class Test { - void foo(int a, int b) { - //do smth - } -} \ No newline at end of file diff --git a/resources-en/src/intentionDescriptions/DelegateWithDefaultParamValueIntentionAction/description.html b/resources-en/src/intentionDescriptions/DelegateWithDefaultParamValueIntentionAction/description.html deleted file mode 100644 index 821c26642038..000000000000 --- a/resources-en/src/intentionDescriptions/DelegateWithDefaultParamValueIntentionAction/description.html +++ /dev/null @@ -1,5 +0,0 @@ - - -Generates an overloaded method which delegates to the current one setting the selected parameter to the specified default value. - - diff --git a/resources-en/src/intentionDescriptions/RedundantLambdaParameterTypeIntention/after.java.template b/resources-en/src/intentionDescriptions/RedundantLambdaParameterTypeIntention/after.java.template deleted file mode 100644 index 925e26bf3039..000000000000 --- a/resources-en/src/intentionDescriptions/RedundantLambdaParameterTypeIntention/after.java.template +++ /dev/null @@ -1,5 +0,0 @@ -class X { - { - Comparable c = o -> 0; - } -} \ No newline at end of file diff --git a/resources-en/src/intentionDescriptions/RedundantLambdaParameterTypeIntention/before.java.template b/resources-en/src/intentionDescriptions/RedundantLambdaParameterTypeIntention/before.java.template deleted file mode 100644 index 84da2abb9213..000000000000 --- a/resources-en/src/intentionDescriptions/RedundantLambdaParameterTypeIntention/before.java.template +++ /dev/null @@ -1,5 +0,0 @@ -class X { - { - Comparable c = (String o) -> 0; - } -} \ No newline at end of file diff --git a/resources-en/src/intentionDescriptions/RedundantLambdaParameterTypeIntention/description.html b/resources-en/src/intentionDescriptions/RedundantLambdaParameterTypeIntention/description.html deleted file mode 100644 index 7e47e9314b11..000000000000 --- a/resources-en/src/intentionDescriptions/RedundantLambdaParameterTypeIntention/description.html +++ /dev/null @@ -1,5 +0,0 @@ - - -This intention removes lambda formal parameter types when they can be inferred from context. - - \ No newline at end of file diff --git a/resources-en/src/intentionDescriptions/RemoveRedundantElseAction/after.java.template b/resources-en/src/intentionDescriptions/RemoveRedundantElseAction/after.java.template deleted file mode 100644 index 6bbd9d56135a..000000000000 --- a/resources-en/src/intentionDescriptions/RemoveRedundantElseAction/after.java.template +++ /dev/null @@ -1,8 +0,0 @@ -public class X { - void f(int i) { - if (i==0) { - return; - } - int j = 0; - } -} \ No newline at end of file diff --git a/resources-en/src/intentionDescriptions/RemoveRedundantElseAction/before.java.template b/resources-en/src/intentionDescriptions/RemoveRedundantElseAction/before.java.template deleted file mode 100644 index edad99d14f45..000000000000 --- a/resources-en/src/intentionDescriptions/RemoveRedundantElseAction/before.java.template +++ /dev/null @@ -1,10 +0,0 @@ -public class X { - void f(int i) { - if (i==0) { - return; - } - else { - int j = 0; - } - } -} \ No newline at end of file diff --git a/resources-en/src/intentionDescriptions/RemoveRedundantElseAction/description.html b/resources-en/src/intentionDescriptions/RemoveRedundantElseAction/description.html deleted file mode 100644 index 8992a7b29b2c..000000000000 --- a/resources-en/src/intentionDescriptions/RemoveRedundantElseAction/description.html +++ /dev/null @@ -1,7 +0,0 @@ - - -This intention detaches else clause from the if statement, -if corresponding then clause never completes normally. - - - diff --git a/resources/src/META-INF/IdeaPlugin.xml b/resources/src/META-INF/IdeaPlugin.xml index 241fb3149571..ca43d4c44eda 100644 --- a/resources/src/META-INF/IdeaPlugin.xml +++ b/resources/src/META-INF/IdeaPlugin.xml @@ -800,11 +800,12 @@ groupKey="group.names.declaration.redundancy" enabledByDefault="true" level="WARNING" implementationClass="com.intellij.codeInspection.SimplifyStreamApiCallChainsInspection" displayName="Simplify stream API call chains"/> + - - com.intellij.codeInsight.daemon.quickFix.RedundantLambdaParameterTypeIntention - Java/Declaration - com.intellij.codeInsight.intention.impl.SplitIfAction Java/Control Flow @@ -825,10 +826,6 @@ com.intellij.codeInsight.intention.impl.ExtractIfConditionAction Java/Control Flow - - com.intellij.codeInsight.daemon.impl.quickfix.RemoveRedundantElseAction - Java/Control Flow - com.intellij.codeInsight.intention.impl.AddNotNullAnnotationIntention Java/Annotations @@ -960,10 +957,6 @@ com.intellij.codeInsight.intention.impl.AddOverrideAnnotationAction Java/Annotations - - com.intellij.codeInsight.daemon.impl.quickfix.DelegateWithDefaultParamValueIntentionAction - Java/Declaration - com.intellij.codeInsight.daemon.impl.quickfix.DefineParamsDefaultValueAction Java/Declaration diff --git a/xml/relaxng/src/resources/html5-schema/html5/block.rnc b/xml/relaxng/src/resources/html5-schema/html5/block.rnc index 6d0eb0d80df1..6f06902115f5 100644 --- a/xml/relaxng/src/resources/html5-schema/html5/block.rnc +++ b/xml/relaxng/src/resources/html5-schema/html5/block.rnc @@ -242,9 +242,6 @@ datatypes w = "http://whattf.org/datatype-draft" element legend { legend.inner & legend.attrs } legend.attrs = ( common.attrs - & ( common.attrs.aria.role.presentation - | common.attrs.aria.role.menuitem - )? ) legend.inner = ( common.inner.phrasing ) diff --git a/xml/relaxng/src/resources/html5-schema/html5/common.rnc b/xml/relaxng/src/resources/html5-schema/html5/common.rnc index 68d9acc5f28f..0800048f2e38 100644 --- a/xml/relaxng/src/resources/html5-schema/html5/common.rnc +++ b/xml/relaxng/src/resources/html5-schema/html5/common.rnc @@ -93,10 +93,8 @@ datatypes w = "http://whattf.org/datatype-draft" ( text & common.elem.flow* ) common.inner.flow = - ( style.elem.scoped*, - ( text - & common.elem.flow* - ) + ( text + & common.elem.flow* ) # ##################################################################### @@ -414,6 +412,11 @@ common.attrs.other = common.data.functionbody = w:functionbody +## autocomplete + + common.data.autocomplete.any = + w:autocomplete-any + # ##################################################################### ## WF2 Module Hook # # ##################################################################### diff --git a/xml/relaxng/src/resources/html5-schema/html5/data.rnc b/xml/relaxng/src/resources/html5-schema/html5/data.rnc index 991f6987dfc3..24c2b110ca31 100644 --- a/xml/relaxng/src/resources/html5-schema/html5/data.rnc +++ b/xml/relaxng/src/resources/html5-schema/html5/data.rnc @@ -10,25 +10,30 @@ datatypes w = "http://whattf.org/datatype-draft" element time { time.inner & time.attrs } time.attrs = ( common.attrs - & time.attrs.datetime? + & common.attrs.aria? + ) + time.inner = + ( text ) #Cannot enforce textContent format here + + common.elem.phrasing |= time.elem + +## Time with datetime attribute: