diff --git a/java/execution/impl/src/com/intellij/execution/remote/RemoteConfiguration.java b/java/execution/impl/src/com/intellij/execution/remote/RemoteConfiguration.java index 57c84c9fa929..92a9c9ad7ad6 100644 --- a/java/execution/impl/src/com/intellij/execution/remote/RemoteConfiguration.java +++ b/java/execution/impl/src/com/intellij/execution/remote/RemoteConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -41,8 +41,8 @@ import org.jetbrains.annotations.NotNull; import java.util.Collection; -public class RemoteConfiguration extends ModuleBasedConfiguration implements - RunConfigurationWithSuppressedDefaultRunAction { +public class RemoteConfiguration extends ModuleBasedConfiguration + implements RunConfigurationWithSuppressedDefaultRunAction, RemoteRunProfile { @Override public void writeExternal(final Element element) throws WriteExternalException { diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/InferredAnnotationsManagerImpl.java b/java/java-analysis-impl/src/com/intellij/codeInsight/InferredAnnotationsManagerImpl.java index 77a227d49847..0de6c43cc178 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/InferredAnnotationsManagerImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/InferredAnnotationsManagerImpl.java @@ -65,9 +65,9 @@ public class InferredAnnotationsManagerImpl extends InferredAnnotationsManager { return null; } - private PsiAnnotation getHardcodedContractAnnotation(PsiMethod listOwner) { - List contracts = HardcodedContracts.getHardcodedContracts(listOwner, null); - return contracts.isEmpty() ? null : createContractAnnotation(contracts, true); + private PsiAnnotation getHardcodedContractAnnotation(PsiMethod method) { + List contracts = HardcodedContracts.getHardcodedContracts(method, null); + return contracts.isEmpty() ? null : createContractAnnotation(contracts, !"java.lang.System.exit".equals(PsiUtil.getMemberQualifiedName(method))); } private static boolean ignoreBytecodeInference(PsiModifierListOwner owner, String annotationFQN) { @@ -95,7 +95,7 @@ public class InferredAnnotationsManagerImpl extends InferredAnnotationsManager { private PsiAnnotation createContractAnnotation(List contracts, boolean pure) { final String attrs; if (!contracts.isEmpty() && pure) { - attrs = "value = " + "\"" + StringUtil.join(contracts, "; ") + "\"; pure = true"; + attrs = "value = " + "\"" + StringUtil.join(contracts, "; ") + "\", pure = true"; } else if (pure) { attrs = "pure = true"; } else if (!contracts.isEmpty()) { diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractInference.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractInference.java index f919ac5f8796..3af865b19bde 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractInference.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractInference.java @@ -17,13 +17,16 @@ package com.intellij.codeInspection.dataFlow; import com.intellij.codeInsight.NullableNotNullManager; import com.intellij.codeInspection.dataFlow.MethodContract.ValueConstraint; +import com.intellij.openapi.roots.FileIndexFacade; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.RecursionManager; +import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.CachedValueProvider; import com.intellij.psi.util.CachedValuesManager; +import com.intellij.psi.util.PsiUtilCore; import com.intellij.util.Function; import com.intellij.util.NullableFunction; import com.intellij.util.containers.ContainerUtil; @@ -44,7 +47,7 @@ public class ContractInference { @NotNull public static List inferContracts(@NotNull final PsiMethod method) { - if (method instanceof PsiCompiledElement) { + if (isLibraryCode(method)) { return Collections.emptyList(); } @@ -56,6 +59,12 @@ public class ContractInference { } }); } + + static boolean isLibraryCode(@NotNull PsiMethod method) { + if (method instanceof PsiCompiledElement) return true; + VirtualFile virtualFile = PsiUtilCore.getVirtualFile(method); + return virtualFile != null && FileIndexFacade.getInstance(method.getProject()).isInLibrarySource(virtualFile); + } } class ContractInferenceInterpreter { diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowRunner.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowRunner.java index 10e0a0f4acd3..834bf53b675a 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowRunner.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowRunner.java @@ -124,7 +124,7 @@ public class DataFlowRunner { joinInstructions.add(myInstructions[((GotoInstruction)instruction).getOffset()]); } else if (instruction instanceof ConditionalGotoInstruction) { joinInstructions.add(myInstructions[((ConditionalGotoInstruction)instruction).getOffset()]); - } else if (instruction instanceof MethodCallInstruction) { + } else if (instruction instanceof MethodCallInstruction && !((MethodCallInstruction)instruction).getContracts().isEmpty()) { joinInstructions.add(myInstructions[index + 1]); } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/PurityInference.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/PurityInference.java index 7686cf21855c..6550cd60d270 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/PurityInference.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/PurityInference.java @@ -34,7 +34,7 @@ import java.util.List; public class PurityInference { public static boolean inferPurity(@NotNull final PsiMethod method) { - if (method instanceof PsiCompiledElement || method.getReturnType() == PsiType.VOID || method.getBody() == null || method.isConstructor()) { + if (ContractInference.isLibraryCode(method) || method.getReturnType() == PsiType.VOID || method.getBody() == null || method.isConstructor()) { return false; } diff --git a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/TabPostFormatProcessor.java b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/TabPostFormatProcessor.java index 495155145a5e..31358cdc045f 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/TabPostFormatProcessor.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/TabPostFormatProcessor.java @@ -72,7 +72,7 @@ public class TabPostFormatProcessor implements PostFormatProcessor { if (!source.isValid()) return range; PsiFile file = source.getContainingFile(); - CommonCodeStyleSettings.IndentOptions indentOptions = settings.getIndentOptionsByFile(file); + CommonCodeStyleSettings.IndentOptions indentOptions = settings.getIndentOptionsByFile(file, range); boolean useTabs = indentOptions.USE_TAB_CHARACTER; boolean smartTabs = indentOptions.SMART_TABS; diff --git a/java/java-psi-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java b/java/java-psi-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java index 67b1ef813de8..7d7d697d724e 100644 --- a/java/java-psi-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java +++ b/java/java-psi-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java @@ -746,7 +746,7 @@ public class JavaDocInfoGenerator { buffer.append("("); boolean first = true; for (PsiNameValuePair pair : attributes) { - if (!first) buffer.append(" "); + if (!first) buffer.append(", "); first = false; final String name = pair.getName(); if (name != null) { diff --git a/java/java-tests/testData/codeInsight/indentProvider/reformatFileSupported_after.java b/java/java-tests/testData/codeInsight/indentProvider/reformatFileSupported_after.java new file mode 100644 index 000000000000..2c4a5a27aa56 --- /dev/null +++ b/java/java-tests/testData/codeInsight/indentProvider/reformatFileSupported_after.java @@ -0,0 +1,8 @@ +class A { + private void foo(boolean b) { + int x; + if (b) { + System.out.println(x); + } + } +} diff --git a/java/java-tests/testData/codeInsight/indentProvider/reformatFileSupported_before.java b/java/java-tests/testData/codeInsight/indentProvider/reformatFileSupported_before.java new file mode 100644 index 000000000000..288ed2b2cc3e --- /dev/null +++ b/java/java-tests/testData/codeInsight/indentProvider/reformatFileSupported_before.java @@ -0,0 +1,8 @@ +class A { + private void foo(boolean b) { + int x; + if (b) { + System.out.println(x); + } + } +} diff --git a/java/java-tests/testData/codeInsight/indentProvider/reformatFile_after.java b/java/java-tests/testData/codeInsight/indentProvider/reformatFile_after.java index 2c4a5a27aa56..4dca5f373a24 100644 --- a/java/java-tests/testData/codeInsight/indentProvider/reformatFile_after.java +++ b/java/java-tests/testData/codeInsight/indentProvider/reformatFile_after.java @@ -1,8 +1,8 @@ class A { - private void foo(boolean b) { - int x; - if (b) { - System.out.println(x); - } - } + private void foo(boolean b) { + int x; + if (b) { + System.out.println(x); + } + } } diff --git a/java/java-tests/testData/codeInsight/indentProvider/reformatTextFullSupported_after.java b/java/java-tests/testData/codeInsight/indentProvider/reformatTextFullSupported_after.java new file mode 100644 index 000000000000..2c4a5a27aa56 --- /dev/null +++ b/java/java-tests/testData/codeInsight/indentProvider/reformatTextFullSupported_after.java @@ -0,0 +1,8 @@ +class A { + private void foo(boolean b) { + int x; + if (b) { + System.out.println(x); + } + } +} diff --git a/java/java-tests/testData/codeInsight/indentProvider/reformatTextFullSupported_before.java b/java/java-tests/testData/codeInsight/indentProvider/reformatTextFullSupported_before.java new file mode 100644 index 000000000000..288ed2b2cc3e --- /dev/null +++ b/java/java-tests/testData/codeInsight/indentProvider/reformatTextFullSupported_before.java @@ -0,0 +1,8 @@ +class A { + private void foo(boolean b) { + int x; + if (b) { + System.out.println(x); + } + } +} diff --git a/java/java-tests/testData/codeInsight/indentProvider/reformatTextRange_after.java b/java/java-tests/testData/codeInsight/indentProvider/reformatTextRange_after.java new file mode 100644 index 000000000000..2c4a5a27aa56 --- /dev/null +++ b/java/java-tests/testData/codeInsight/indentProvider/reformatTextRange_after.java @@ -0,0 +1,8 @@ +class A { + private void foo(boolean b) { + int x; + if (b) { + System.out.println(x); + } + } +} diff --git a/java/java-tests/testData/codeInsight/indentProvider/reformatTextRange_before.java b/java/java-tests/testData/codeInsight/indentProvider/reformatTextRange_before.java new file mode 100644 index 000000000000..288ed2b2cc3e --- /dev/null +++ b/java/java-tests/testData/codeInsight/indentProvider/reformatTextRange_before.java @@ -0,0 +1,8 @@ +class A { + private void foo(boolean b) { + int x; + if (b) { + System.out.println(x); + } + } +} diff --git a/java/java-tests/testData/codeInsight/indentProvider/reformatText_after.java b/java/java-tests/testData/codeInsight/indentProvider/reformatText_after.java index 2c4a5a27aa56..4dca5f373a24 100644 --- a/java/java-tests/testData/codeInsight/indentProvider/reformatText_after.java +++ b/java/java-tests/testData/codeInsight/indentProvider/reformatText_after.java @@ -1,8 +1,8 @@ class A { - private void foo(boolean b) { - int x; - if (b) { - System.out.println(x); - } - } + private void foo(boolean b) { + int x; + if (b) { + System.out.println(x); + } + } } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/folding/JavaFoldingTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/folding/JavaFoldingTest.groovy index 0baf4d8510ee..f87cd5bc331e 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/folding/JavaFoldingTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/folding/JavaFoldingTest.groovy @@ -920,4 +920,81 @@ public class Test { myFixture.performEditorAction(IdeActions.ACTION_EDITOR_UNSELECT_WORD_AT_CARET) assert 'return field;' == myFixture.editor.selectionModel.selectedText } + + public void "test expand and collapse regions in selection"() { + def text = """ +class Foo { + public static void main() { + new Runnable(){ + public void run() { + } + }.run(); + } +} +""" + configure text + assertEquals 3, foldRegionsCount + myFixture.performEditorAction(IdeActions.ACTION_EXPAND_ALL_REGIONS) + assertEquals 3, expandedFoldRegionsCount + + + myFixture.editor.selectionModel.setSelection(text.indexOf("new"), text.indexOf("run();")) + myFixture.performEditorAction(IdeActions.ACTION_COLLAPSE_ALL_REGIONS) + assertEquals 1, expandedFoldRegionsCount + myFixture.performEditorAction(IdeActions.ACTION_EXPAND_ALL_REGIONS) + assertEquals 3, expandedFoldRegionsCount + } + + public void "test expand and collapse recursively"() { + def text = """ +class Foo { + public static void main() { + new Runnable(){ + public void run() { + } + }.run(); + } +} +""" + configure text + assertEquals 3, foldRegionsCount + myFixture.performEditorAction(IdeActions.ACTION_EXPAND_ALL_REGIONS) + assertEquals 3, expandedFoldRegionsCount + + + myFixture.editor.caretModel.moveToOffset(text.indexOf("new")) + myFixture.performEditorAction(IdeActions.ACTION_COLLAPSE_REGION_RECURSIVELY) + assertEquals 1, expandedFoldRegionsCount + myFixture.performEditorAction(IdeActions.ACTION_EXPAND_REGION_RECURSIVELY) + assertEquals 3, expandedFoldRegionsCount + } + + public void "test expand to level"() { + def text = """ +class Foo { + public static void main() { + new Runnable(){ + public void run() { + } + }.run(); + } +} +""" + configure text + assertEquals 3, foldRegionsCount + + myFixture.editor.caretModel.moveToOffset(text.indexOf("new")) + myFixture.performEditorAction(IdeActions.ACTION_EXPAND_TO_LEVEL_1) + assertEquals 2, expandedFoldRegionsCount + myFixture.performEditorAction(IdeActions.ACTION_EXPAND_ALL_TO_LEVEL_1) + assertEquals 1, expandedFoldRegionsCount + } + + private int getFoldRegionsCount() { + return myFixture.editor.foldingModel.allFoldRegions.length + } + + private int getExpandedFoldRegionsCount() { + return myFixture.editor.foldingModel.allFoldRegions.count { it.isExpanded() ? 1 : 0} + } } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/indentOptionsProvider/FileIndentProviderTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/indentOptionsProvider/FileIndentProviderTest.java index c542f1a5a4e0..9ba42b9aaaa8 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/indentOptionsProvider/FileIndentProviderTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/indentOptionsProvider/FileIndentProviderTest.java @@ -38,6 +38,7 @@ public class FileIndentProviderTest extends LightPlatformCodeInsightFixtureTestC private final static FileIndentOptionsProvider TEST_FILE_INDENT_OPTIONS_PROVIDER = new TestIndentOptionsProvider(); private static CommonCodeStyleSettings.IndentOptions myTestIndentOptions; + private static boolean myUseOnFullReformat; @Override protected void setUp() throws Exception { @@ -54,6 +55,7 @@ public class FileIndentProviderTest extends LightPlatformCodeInsightFixtureTestC Extensions.getRootArea().getExtensionPoint(FileIndentOptionsProvider.EP_NAME); extensionPoint.unregisterExtension(TEST_FILE_INDENT_OPTIONS_PROVIDER); myTestIndentOptions = null; + myUseOnFullReformat = false; super.tearDown(); } @@ -80,6 +82,11 @@ public class FileIndentProviderTest extends LightPlatformCodeInsightFixtureTestC public CommonCodeStyleSettings.IndentOptions getIndentOptions(@NotNull PsiFile file) { return myTestIndentOptions; } + + @Override + public boolean useOnFullReformat() { + return myUseOnFullReformat; + } } public void testTypeEnter() { @@ -111,6 +118,16 @@ public class FileIndentProviderTest extends LightPlatformCodeInsightFixtureTestC myFixture.checkResultByFile(getTestName(true) + "_after.java"); } + public void testReformatFileSupported() { + myUseOnFullReformat = true; + myTestIndentOptions.INDENT_SIZE = 3; + myTestIndentOptions.TAB_SIZE = 2; + myTestIndentOptions.USE_TAB_CHARACTER = true; + PsiFile file = myFixture.configureByFile(getTestName(true) + "_before.java"); + CodeStyleManager.getInstance(getProject()).reformat(file); + myFixture.checkResultByFile(getTestName(true) + "_after.java"); + } + public void testReformatText() { myTestIndentOptions.INDENT_SIZE = 3; myTestIndentOptions.TAB_SIZE = 2; @@ -119,4 +136,27 @@ public class FileIndentProviderTest extends LightPlatformCodeInsightFixtureTestC CodeStyleManager.getInstance(getProject()).reformatText(file, 0, file.getTextRange().getEndOffset()); myFixture.checkResultByFile(getTestName(true) + "_after.java"); } + + /** + * Reformat using indent provider if a part of the file is selected. + */ + public void testReformatTextRange() { + myTestIndentOptions.INDENT_SIZE = 3; + myTestIndentOptions.TAB_SIZE = 2; + myTestIndentOptions.USE_TAB_CHARACTER = true; + PsiFile file = myFixture.configureByFile(getTestName(true) + "_before.java"); + // Just any range smaller than the file + CodeStyleManager.getInstance(getProject()).reformatText(file, 6, file.getTextRange().getEndOffset() - 1); + myFixture.checkResultByFile(getTestName(true) + "_after.java"); + } + + public void testReformatTextFullSupported() { + myUseOnFullReformat = true; + myTestIndentOptions.INDENT_SIZE = 3; + myTestIndentOptions.TAB_SIZE = 2; + myTestIndentOptions.USE_TAB_CHARACTER = true; + PsiFile file = myFixture.configureByFile(getTestName(true) + "_before.java"); + CodeStyleManager.getInstance(getProject()).reformatText(file, 0, file.getTextRange().getEndOffset()); + myFixture.checkResultByFile(getTestName(true) + "_after.java"); + } } diff --git a/platform/lang-api/src/com/intellij/execution/configurations/RemoteRunProfile.java b/platform/lang-api/src/com/intellij/execution/configurations/RemoteRunProfile.java new file mode 100644 index 000000000000..4ba1a8f8e976 --- /dev/null +++ b/platform/lang-api/src/com/intellij/execution/configurations/RemoteRunProfile.java @@ -0,0 +1,25 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.execution.configurations; + +/** + * Special interface for remote debug processes + * + * @author Konstantin Bulenkov + * @since 14 + */ +public interface RemoteRunProfile extends RunProfile { +} diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettings.java b/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettings.java index ae9f2f960640..eecdc4b6e937 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettings.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettings.java @@ -663,26 +663,65 @@ public class CodeStyleSettings extends CommonCodeStyleSettings implements Clonea @NotNull public IndentOptions getIndentOptionsByFile(@Nullable PsiFile file) { - return getIndentOptionsByFile(file, false); + return getIndentOptionsByFile(file, null); } @NotNull - public IndentOptions getIndentOptionsByFile(@Nullable PsiFile file, boolean ignoreDocOptions) { + public IndentOptions getIndentOptionsByFile(@Nullable PsiFile file, @Nullable TextRange formatRange) { + return getIndentOptionsByFile(file, formatRange, false); + } + + /** + * Retrieves indent options for PSI file from an associated document or (if not defined in the document) from file indent options + * providers. + * @param file The PSI file to retrieve options for. + * @param formatRange The text range within the file for formatting purposes or null if there is either no specific range or multiple + * ranges. If the range covers the entire file (full reformat), options stored in the document are ignored and + * indent options are taken from file indent options providers. + * @param ignoreDocOptions Ignore options stored in the document and use file indent options providers even if there is no text range + * or the text range doesn't cover the entire file. + * @return Indent options from the associated document or file indent options providers. + * @see com.intellij.psi.codeStyle.FileIndentOptionsProvider + */ + @NotNull + public IndentOptions getIndentOptionsByFile(@Nullable PsiFile file, @Nullable TextRange formatRange, boolean ignoreDocOptions) { if (file != null && file.isValid()) { - if (!ignoreDocOptions) { + boolean isFullReformat = isFileFullyCoveredByRange(file, formatRange); + if (!ignoreDocOptions && !isFullReformat) { IndentOptions docOptions = IndentOptions.retrieveFromAssociatedDocument(file); if (docOptions != null) return docOptions; } FileIndentOptionsProvider[] providers = Extensions.getExtensions(FileIndentOptionsProvider.EP_NAME); for (FileIndentOptionsProvider provider : providers) { - IndentOptions indentOptions = provider.getIndentOptions(file); - if (indentOptions != null) return indentOptions; + if (!isFullReformat || provider.useOnFullReformat()) { + IndentOptions indentOptions = provider.getIndentOptions(file); + if (indentOptions != null) { + logIndentOptions(file, provider, indentOptions); + return indentOptions; + } + } } return getIndentOptions(file.getFileType()); } else return OTHER_INDENT_OPTIONS; } + + private static boolean isFileFullyCoveredByRange(@NotNull PsiFile file, @Nullable TextRange formatRange) { + return + formatRange != null && + file.getTextRange().equals(formatRange); + } + + private static void logIndentOptions(@NotNull PsiFile file, + @NotNull FileIndentOptionsProvider provider, + @NotNull IndentOptions options) { + LOG.info("Indent options returned by " + provider.getClass().getName() + + " for " + file.getName() + + ": indent size=" + options.INDENT_SIZE + + ", use tabs=" + options.USE_TAB_CHARACTER + + ", tab size=" + options.TAB_SIZE); + } @Nullable private IndentOptions getLanguageIndentOptions(@Nullable FileType fileType) { diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettingsManager.java b/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettingsManager.java index 9dd266a0b3aa..08b742beea04 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettingsManager.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettingsManager.java @@ -139,7 +139,7 @@ public class CodeStyleSettingsManager implements PersistentStateComponent scopeToAverageSeverityMap = + final LinkedHashMap scopeToAverageSeverityMap = ((MultiScopeSeverityIcon)maybeIcon).getScopeToAverageSeverityMap(); final JComponent component; if (scopeToAverageSeverityMap.size() == 1) { - final HighlightSeverity severity = ContainerUtil.getFirstItem(scopeToAverageSeverityMap.values()); + final HighlightDisplayLevel level = ContainerUtil.getFirstItem(scopeToAverageSeverityMap.values()); final JLabel label = new JLabel(); - label.setIcon(HighlightDisplayLevel.find(severity).getIcon()); - label.setText(SingleInspectionProfilePanel.renderSeverity(severity)); + label.setIcon(level.getIcon()); + label.setText(SingleInspectionProfilePanel.renderSeverity(level.getSeverity())); component = label; } else { component = new ScopesAndSeveritiesHintTable(scopeToAverageSeverityMap); diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/inspectionsTree/MultiScopeSeverityIcon.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/inspectionsTree/MultiScopeSeverityIcon.java index 099dbb622261..3d5bbd6d6db5 100644 --- a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/inspectionsTree/MultiScopeSeverityIcon.java +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/inspectionsTree/MultiScopeSeverityIcon.java @@ -19,6 +19,7 @@ package com.intellij.profile.codeInspection.ui.inspectionsTree; import com.intellij.codeHighlighting.HighlightDisplayLevel; import com.intellij.codeInspection.ex.InspectionProfileImpl; import com.intellij.lang.annotation.HighlightSeverity; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.profile.codeInspection.ui.ScopeOrderComparator; import com.intellij.ui.JBColor; @@ -31,26 +32,36 @@ import java.util.List; * @author Dmitry Batkovich */ public class MultiScopeSeverityIcon implements Icon { + private final static Logger LOG = Logger.getInstance(MultiScopeSeverityIcon.class); + private final static JBColor MIXED_SEVERITY_COLOR = JBColor.DARK_GRAY; private final static int SIZE = 12; - private final LinkedHashMap myScopeToAverageSeverityMap; + private final LinkedHashMap myScopeToAverageSeverityMap; public MultiScopeSeverityIcon(final Map scopeToAverageSeverityMap, final String defaultScopeName, final InspectionProfileImpl inspectionProfile) { final List sortedScopeNames = new ArrayList(scopeToAverageSeverityMap.keySet()); - myScopeToAverageSeverityMap = new LinkedHashMap(); + myScopeToAverageSeverityMap = new LinkedHashMap(); Collections.sort(sortedScopeNames, new ScopeOrderComparator(inspectionProfile)); sortedScopeNames.remove(defaultScopeName); sortedScopeNames.add(defaultScopeName); for (final String scopeName : sortedScopeNames) { - myScopeToAverageSeverityMap.put(scopeName, scopeToAverageSeverityMap.get(scopeName)); + final HighlightSeverity severity = scopeToAverageSeverityMap.get(scopeName); + if (severity == null) { + continue; + } + final HighlightDisplayLevel level = HighlightDisplayLevel.find(severity); + if (level == null) { + continue; + } + myScopeToAverageSeverityMap.put(scopeName, level); } } - public LinkedHashMap getScopeToAverageSeverityMap() { + public LinkedHashMap getScopeToAverageSeverityMap() { return myScopeToAverageSeverityMap; } @@ -60,10 +71,10 @@ public class MultiScopeSeverityIcon implements Icon { final int partWidth = iconWidth / myScopeToAverageSeverityMap.size(); - final Collection values = myScopeToAverageSeverityMap.values(); + final Collection values = myScopeToAverageSeverityMap.values(); int idx = 0; - for (final HighlightSeverity severity : values) { - final Icon icon = HighlightDisplayLevel.find(severity).getIcon(); + for (final HighlightDisplayLevel level : values) { + final Icon icon = level.getIcon(); g.setColor(icon instanceof HighlightDisplayLevel.SingleColorIconWithMask ? ((HighlightDisplayLevel.SingleColorIconWithMask)icon).getColor() : MIXED_SEVERITY_COLOR); final int x = i + partWidth * idx; diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/inspectionsTree/ScopesAndSeveritiesHintTable.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/inspectionsTree/ScopesAndSeveritiesHintTable.java index 5d619ce6a0ed..9ff70c59a0cf 100644 --- a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/inspectionsTree/ScopesAndSeveritiesHintTable.java +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/inspectionsTree/ScopesAndSeveritiesHintTable.java @@ -16,7 +16,6 @@ package com.intellij.profile.codeInspection.ui.inspectionsTree; import com.intellij.codeHighlighting.HighlightDisplayLevel; -import com.intellij.lang.annotation.HighlightSeverity; import com.intellij.profile.codeInspection.ui.SingleInspectionProfilePanel; import com.intellij.ui.table.JBTable; import com.intellij.util.ui.UIUtil; @@ -37,7 +36,7 @@ public class ScopesAndSeveritiesHintTable extends JBTable { private final static int SCOPE_COLUMN = 0; private final static int SEVERITY_COLUMN = 1; - public ScopesAndSeveritiesHintTable(final LinkedHashMap scopeToAverageSeverityMap) { + public ScopesAndSeveritiesHintTable(final LinkedHashMap scopeToAverageSeverityMap) { super(new MyModel(scopeToAverageSeverityMap)); getColumnModel().getColumn(SCOPE_COLUMN).setCellRenderer(new DefaultTableCellRenderer() { @@ -64,9 +63,9 @@ public class ScopesAndSeveritiesHintTable extends JBTable { final int row, final int column) { super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); - final HighlightSeverity severity = (HighlightSeverity)value; - setIcon(HighlightDisplayLevel.find(severity).getIcon()); - setText(SingleInspectionProfilePanel.renderSeverity(severity)); + final HighlightDisplayLevel level = (HighlightDisplayLevel)value; + setIcon(level.getIcon()); + setText(SingleInspectionProfilePanel.renderSeverity(level.getSeverity())); setOpaque(false); UIUtil.applyStyle(UIUtil.ComponentStyle.SMALL, this); return this; @@ -90,10 +89,10 @@ public class ScopesAndSeveritiesHintTable extends JBTable { private final static class MyModel extends AbstractTableModel { - private final LinkedHashMap myScopeToAverageSeverityMap; + private final LinkedHashMap myScopeToAverageSeverityMap; private final List myScopes; - public MyModel(final LinkedHashMap scopeToAverageSeverityMap) { + public MyModel(final LinkedHashMap scopeToAverageSeverityMap) { myScopeToAverageSeverityMap = scopeToAverageSeverityMap; myScopes = new ArrayList(myScopeToAverageSeverityMap.keySet()); } @@ -102,7 +101,7 @@ public class ScopesAndSeveritiesHintTable extends JBTable { public Class getColumnClass(final int columnIndex) { switch (columnIndex) { case SCOPE_COLUMN: return String.class; - case SEVERITY_COLUMN: return HighlightSeverity.class; + case SEVERITY_COLUMN: return HighlightDisplayLevel.class; default: throw new IllegalArgumentException(); } } diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeFormatterFacade.java b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeFormatterFacade.java index ff3976a6f118..dc24b2b1d583 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeFormatterFacade.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeFormatterFacade.java @@ -129,7 +129,7 @@ public class CodeFormatterFacade { if (file.getTextLength() > 0) { try { FormatterEx.getInstanceEx().format( - model, mySettings,mySettings.getIndentOptionsByFile(fileToFormat), new FormatTextRanges(range, true) + model, mySettings,mySettings.getIndentOptionsByFile(fileToFormat, range), new FormatTextRanges(range, true) ); wrapLongLinesIfNecessary(file, document, startOffset, endOffset); @@ -242,7 +242,7 @@ public class CodeFormatterFacade { indentOptions = ((FormattingModelBuilderEx)builder).getIndentOptionsToUse(file, ranges, mySettings); } if (indentOptions == null) { - indentOptions = mySettings.getIndentOptionsByFile(file); + indentOptions = mySettings.getIndentOptionsByFile(file, textRanges.size() == 1 ? textRanges.get(0).getTextRange() : null); } formatter.format(model, mySettings, indentOptions, ranges); diff --git a/platform/platform-api/src/com/intellij/openapi/actionSystem/IdeActions.java b/platform/platform-api/src/com/intellij/openapi/actionSystem/IdeActions.java index b6b15047aa24..e43fe3ffa31b 100644 --- a/platform/platform-api/src/com/intellij/openapi/actionSystem/IdeActions.java +++ b/platform/platform-api/src/com/intellij/openapi/actionSystem/IdeActions.java @@ -150,6 +150,13 @@ public interface IdeActions { @NonNls String ACTION_COLLAPSE_ALL = "CollapseAll"; @NonNls String ACTION_EXPORT_TO_TEXT_FILE = "ExportToTextFile"; + @NonNls String ACTION_EXPAND_ALL_REGIONS = "ExpandAllRegions"; + @NonNls String ACTION_COLLAPSE_ALL_REGIONS = "CollapseAllRegions"; + @NonNls String ACTION_EXPAND_REGION_RECURSIVELY = "ExpandRegionRecursively"; + @NonNls String ACTION_COLLAPSE_REGION_RECURSIVELY = "CollapseRegionRecursively"; + @NonNls String ACTION_EXPAND_TO_LEVEL_1 = "ExpandToLevel1"; + @NonNls String ACTION_EXPAND_ALL_TO_LEVEL_1 = "ExpandAllToLevel1"; + @NonNls String ACTION_NEW_HORIZONTAL_TAB_GROUP = "NewHorizontalTabGroup"; @NonNls String ACTION_NEW_VERTICAL_TAB_GROUP = "NewVerticalTabGroup"; @NonNls String ACTION_MOVE_EDITOR_TO_OPPOSITE_TAB_GROUP = "MoveEditorToOppositeTabGroup"; diff --git a/platform/platform-api/src/com/intellij/openapi/options/OptionsBundle.java b/platform/platform-api/src/com/intellij/openapi/options/OptionsBundle.java index faaa5629a21c..20f2561ce50c 100644 --- a/platform/platform-api/src/com/intellij/openapi/options/OptionsBundle.java +++ b/platform/platform-api/src/com/intellij/openapi/options/OptionsBundle.java @@ -34,7 +34,7 @@ public class OptionsBundle { } private static Reference ourBundle; - @NonNls protected static final String PATH_TO_BUNDLE = "messages.OptionsBundle"; + @NonNls public static final String PATH_TO_BUNDLE = "messages.OptionsBundle"; private OptionsBundle() { } diff --git a/platform/platform-api/src/com/intellij/util/net/HttpConfigurable.java b/platform/platform-api/src/com/intellij/util/net/HttpConfigurable.java index 757706127a38..1edcdc4015ca 100644 --- a/platform/platform-api/src/com/intellij/util/net/HttpConfigurable.java +++ b/platform/platform-api/src/com/intellij/util/net/HttpConfigurable.java @@ -43,6 +43,11 @@ import com.intellij.util.xmlb.annotations.Transient; import gnu.trove.THashMap; import gnu.trove.THashSet; import gnu.trove.TObjectObjectProcedure; +import org.apache.http.HttpHost; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.CredentialsProvider; +import org.apache.http.client.config.RequestConfig; import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -52,7 +57,10 @@ import java.io.File; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.net.*; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; @State( name = "HttpConfigurable", @@ -426,6 +434,34 @@ public class HttpConfigurable implements PersistentStateComponent> getJvmPropertiesList(final boolean withAutodetection, @Nullable final URI uri) { final HttpConfigurable me = getInstance(); if (! me.USE_HTTP_PROXY && ! me.USE_PROXY_PAC) { diff --git a/platform/platform-api/src/com/intellij/util/net/ssl/CertificateManager.java b/platform/platform-api/src/com/intellij/util/net/ssl/CertificateManager.java index ac20c3ece2d4..7af12fca2bf7 100644 --- a/platform/platform-api/src/com/intellij/util/net/ssl/CertificateManager.java +++ b/platform/platform-api/src/com/intellij/util/net/ssl/CertificateManager.java @@ -168,7 +168,7 @@ public class CertificateManager implements PersistentStateComponent() { + boolean accepted = askUser && CertificateManager.showAcceptDialog(new Callable() { @Override public DialogWrapper call() throws Exception { // TODO may be another kind of warning, if default trust store is missing @@ -137,7 +144,9 @@ public class ConfirmingTrustManager extends ClientOnlyTrustManager { }); if (accepted) { LOG.info("Certificate was accepted by user"); - myCustomManager.addCertificate(endPoint); + if (addToKeyStore) { + myCustomManager.addCertificate(endPoint); + } } return accepted; } diff --git a/platform/platform-impl/src/com/intellij/codeInsight/hint/HintManagerImpl.java b/platform/platform-impl/src/com/intellij/codeInsight/hint/HintManagerImpl.java index 6c7a28854914..3d2a61020be4 100644 --- a/platform/platform-impl/src/com/intellij/codeInsight/hint/HintManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/codeInsight/hint/HintManagerImpl.java @@ -626,26 +626,34 @@ public class HintManagerImpl extends HintManager implements Disposable { int col2 = pos2.column; Point location; - JLayeredPane layeredPane = editor.getComponent().getRootPane().getLayeredPane(); + @NotNull JComponent externalComponent = editor.getComponent(); + JRootPane rootPane = externalComponent.getRootPane(); + if (rootPane != null) { + externalComponent = rootPane; + JLayeredPane layeredPane = rootPane.getLayeredPane(); + if (layeredPane != null) { + externalComponent = layeredPane; + } + } JComponent internalComponent = editor.getContentComponent(); if (constraint == RIGHT_UNDER) { Point p = editor.logicalPositionToXY(new LogicalPosition(line2, col2)); if (!showByBalloon) { p.y += editor.getLineHeight(); } - location = SwingUtilities.convertPoint(internalComponent, p, layeredPane); + location = SwingUtilities.convertPoint(internalComponent, p, externalComponent); } else { Point p = editor.logicalPositionToXY(new LogicalPosition(line1, col1)); if (constraint == UNDER) { p.y += editor.getLineHeight(); } - location = SwingUtilities.convertPoint(internalComponent, p, layeredPane); + location = SwingUtilities.convertPoint(internalComponent, p, externalComponent); } if (constraint == ABOVE && !showByBalloon) { location.y -= hintSize.height; - int diff = location.x + hintSize.width - layeredPane.getWidth(); + int diff = location.x + hintSize.width - externalComponent.getWidth(); if (diff > 0) { location.x = Math.max(location.x - diff, 0); } diff --git a/platform/platform-impl/src/com/intellij/ide/actions/ExportSettingsAction.java b/platform/platform-impl/src/com/intellij/ide/actions/ExportSettingsAction.java index 0d54096c56e8..e115a9825faa 100644 --- a/platform/platform-impl/src/com/intellij/ide/actions/ExportSettingsAction.java +++ b/platform/platform-impl/src/com/intellij/ide/actions/ExportSettingsAction.java @@ -19,6 +19,8 @@ */ package com.intellij.ide.actions; +import com.intellij.AbstractBundle; +import com.intellij.CommonBundle; import com.intellij.ide.IdeBundle; import com.intellij.ide.plugins.IdeaPluginDescriptor; import com.intellij.ide.plugins.PluginManager; @@ -31,10 +33,13 @@ import com.intellij.openapi.application.impl.ApplicationImpl; import com.intellij.openapi.components.*; import com.intellij.openapi.components.impl.ServiceManagerImpl; import com.intellij.openapi.components.impl.stores.StateStorageManager; +import com.intellij.openapi.extensions.PluginDescriptor; +import com.intellij.openapi.options.OptionsBundle; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.PairProcessor; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.MultiMap; import com.intellij.util.io.ZipUtil; @@ -128,10 +133,10 @@ public class ExportSettingsAction extends AnAction implements DumbAware { } @NotNull - public static MultiMap getExportableComponentsMap(boolean onlyExisting) { + public static MultiMap getExportableComponentsMap(final boolean onlyExisting) { ExportableApplicationComponent[] components1 = ApplicationManager.getApplication().getComponents(ExportableApplicationComponent.class); List components2 = ServiceBean.loadServicesFromBeans(ExportableComponent.EXTENSION_POINT, ExportableComponent.class); - MultiMap result = MultiMap.createSet(); + final MultiMap result = MultiMap.createSet(); for (ExportableComponent component : ContainerUtil.concat(Arrays.asList(components1), components2)) { for (File exportFile : component.getExportFiles()) { result.putValue(exportFile, component); @@ -147,42 +152,79 @@ public class ExportSettingsAction extends AnAction implements DumbAware { } ApplicationImpl application = (ApplicationImpl)ApplicationManager.getApplication(); - StateStorageManager storageManager = application.getStateStore().getStateStorageManager(); - List> classes = ServiceManagerImpl.getAllImplementationClasses(application); - for (Class aClass : classes) { - final State stateAnnotation = aClass.getAnnotation(State.class); - if (stateAnnotation != null && stateAnnotation.storages().length == 1 && !StringUtil.isEmpty(stateAnnotation.name())) { - if (ExportableComponent.class.isAssignableFrom(aClass)) { - continue; - } + final StateStorageManager storageManager = application.getStateStore().getStateStorageManager(); + ServiceManagerImpl.processAllImplementationClasses(application, new PairProcessor, PluginDescriptor>() { + @Override + public boolean process(@NotNull Class aClass, @Nullable PluginDescriptor pluginDescriptor) { + State stateAnnotation = aClass.getAnnotation(State.class); + if (stateAnnotation != null && stateAnnotation.storages().length == 1 && !StringUtil.isEmpty(stateAnnotation.name())) { + if (ExportableComponent.class.isAssignableFrom(aClass)) { + return true; + } - Storage storage = stateAnnotation.storages()[0]; - if (storage.roamingType() != RoamingType.DISABLED && - storage.storageClass().equals(StateStorage.class) && - storage.scheme() == StorageScheme.DEFAULT && - !StringUtil.isEmpty(storage.file()) && - storage.file().startsWith(StoragePathMacros.APP_CONFIG)) { - final File file = new File(storageManager.expandMacros(storage.file())); - if (!onlyExisting || file.exists()) { - result.putValue(file, new ExportableComponent() { - @NotNull - @Override - public File[] getExportFiles() { - return new File[]{file}; - } - - @NotNull - @Override - public String getPresentableName() { - return stateAnnotation.name(); - } - }); + Storage storage = stateAnnotation.storages()[0]; + if (storage.roamingType() != RoamingType.DISABLED && + storage.storageClass().equals(StateStorage.class) && + storage.scheme() == StorageScheme.DEFAULT && + !StringUtil.isEmpty(storage.file()) && + storage.file().startsWith(StoragePathMacros.APP_CONFIG)) { + File file = new File(storageManager.expandMacros(storage.file())); + if (!onlyExisting || file.exists()) { + result.putValue(file, new MyExportableComponent(file, getExportableComponentPresentableName(stateAnnotation.name(), aClass, pluginDescriptor))); + } } } + return true; } + }); + return result; + } + + @NotNull + private static String getExportableComponentPresentableName(@NotNull String defaultName, @NotNull Class aClass, @Nullable PluginDescriptor pluginDescriptor) { + String resourceBundleName; + if (pluginDescriptor != null && pluginDescriptor instanceof IdeaPluginDescriptor && !"com.intellij".equals(pluginDescriptor.getPluginId().getIdString())) { + resourceBundleName = ((IdeaPluginDescriptor)pluginDescriptor).getResourceBundleBaseName(); + } + else { + resourceBundleName = OptionsBundle.PATH_TO_BUNDLE; } - return result; + if (resourceBundleName == null) { + return defaultName; + } + + ClassLoader classLoader = pluginDescriptor == null ? null : pluginDescriptor.getPluginClassLoader(); + classLoader = classLoader == null ? aClass.getClassLoader() : classLoader; + if (classLoader != null) { + ResourceBundle bundle = AbstractBundle.getResourceBundle(resourceBundleName, classLoader); + if (bundle != null) { + return CommonBundle.messageOrDefault(bundle, "exportable." + defaultName + ".presentable.name", defaultName); + } + } + return defaultName; + } + + private static final class MyExportableComponent implements ExportableComponent { + private final File file; + private final String name; + + public MyExportableComponent(@NotNull File file, @NotNull String name) { + this.file = file; + this.name = name; + } + + @NotNull + @Override + public File[] getExportFiles() { + return new File[]{file}; + } + + @NotNull + @Override + public String getPresentableName() { + return name; + } } } diff --git a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/AbbreviationManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/AbbreviationManagerImpl.java index fd96e54fc98e..0016d909ede8 100644 --- a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/AbbreviationManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/AbbreviationManagerImpl.java @@ -16,14 +16,11 @@ package com.intellij.openapi.actionSystem.impl; import com.intellij.openapi.actionSystem.AbbreviationManager; -import com.intellij.openapi.application.PathManager; import com.intellij.openapi.components.*; import gnu.trove.THashMap; import org.jdom.Element; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.io.File; import java.util.*; /** @@ -33,8 +30,7 @@ import java.util.*; name = "AbbreviationManager", storages = {@Storage(file = StoragePathMacros.APP_CONFIG + "/abbreviations.xml", roamingType = RoamingType.PER_PLATFORM)} ) -public class AbbreviationManagerImpl extends AbbreviationManager implements - ExportableComponent, PersistentStateComponent { +public class AbbreviationManagerImpl extends AbbreviationManager implements PersistentStateComponent { private final Map> myAbbreviation2ActionId = new THashMap>(); private final Map> myActionId2Abbreviations = new THashMap>(); private final Map> myPluginsActionId2Abbreviations = new THashMap>(); @@ -109,18 +105,6 @@ public class AbbreviationManagerImpl extends AbbreviationManager implements } } - @NotNull - @Override - public File[] getExportFiles() { - return new File[]{PathManager.getOptionsFile("abbreviations")}; - } - - @NotNull - @Override - public String getPresentableName() { - return "Actions"; - } - @Override public Set getAbbreviations() { final Set result = new HashSet(); diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/ServiceManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/ServiceManagerImpl.java index 9c95d681967f..68e536284274 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/ServiceManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/ServiceManagerImpl.java @@ -25,6 +25,7 @@ import com.intellij.openapi.extensions.*; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Disposer; +import com.intellij.util.PairProcessor; import com.intellij.util.io.storage.HeavyProcessLatch; import com.intellij.util.pico.AssignableToComponentAdapter; import com.intellij.util.pico.ConstructorInjectionComponentAdapter; @@ -32,7 +33,9 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.picocontainer.*; -import java.util.*; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; public class ServiceManagerImpl implements BaseComponent { private static final ExtensionPointName APP_SERVICES = new ExtensionPointName("com.intellij.applicationService"); @@ -83,31 +86,34 @@ public class ServiceManagerImpl implements BaseComponent { return Arrays.asList(extensions); } - @NotNull - public static List> getAllImplementationClasses(@NotNull ComponentManager componentManager) { + public static void processAllImplementationClasses(@NotNull ComponentManager componentManager, @NotNull PairProcessor, PluginDescriptor> processor) { Collection adapters = componentManager.getPicoContainer().getComponentAdapters(); if (adapters.isEmpty()) { - return Collections.emptyList(); + return; } - List> classes = new ArrayList>(512); for (Object o : adapters) { if (o instanceof MyComponentAdapter) { MyComponentAdapter adapter = (MyComponentAdapter)o; ComponentAdapter delegate = adapter.myDelegate; - // we cannot use getDelegate - not all components are instantiable (JobSchedulerImpl, for example, causes such error) + Class aClass; try { - classes.add(delegate == null ? adapter.loadClass(adapter.myDescriptor.getImplementation()) : delegate.getComponentImplementation()); + // we cannot use getDelegate - not all components are instantiable (JobSchedulerImpl, for example, causes such error) + aClass = delegate == null ? adapter.loadClass(adapter.myDescriptor.getImplementation()) : delegate.getComponentImplementation(); } catch (RuntimeException e) { // ignore ClassNotFoundException - invalid entry (GithubSslSupport, for example) if (!(e.getCause() instanceof ClassNotFoundException)) { throw e; } + continue; + } + + if (!processor.process(aClass, adapter.myPluginDescriptor)) { + break; } } } - return classes; } @Override diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/ex/EditorSettingsExternalizable.java b/platform/platform-impl/src/com/intellij/openapi/editor/ex/EditorSettingsExternalizable.java index 7ab5edb57334..9ed804f92265 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/ex/EditorSettingsExternalizable.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/ex/EditorSettingsExternalizable.java @@ -16,10 +16,8 @@ package com.intellij.openapi.editor.ex; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.application.PathManager; import com.intellij.openapi.components.*; import com.intellij.openapi.editor.impl.softwrap.SoftWrapAppliancePlaces; -import com.intellij.openapi.options.OptionsBundle; import com.intellij.openapi.util.text.StringUtil; import org.intellij.lang.annotations.MagicConstant; import org.jetbrains.annotations.NonNls; @@ -28,7 +26,6 @@ import org.jetbrains.annotations.Nullable; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; -import java.io.File; import java.util.EnumSet; import java.util.Set; @@ -36,7 +33,7 @@ import java.util.Set; name = "EditorSettings", storages = {@Storage(file = StoragePathMacros.APP_CONFIG + "/editor.xml")} ) -public class EditorSettingsExternalizable implements PersistentStateComponent, ExportableComponent { +public class EditorSettingsExternalizable implements PersistentStateComponent { //Q: make it interface? public static final class OptionSet { public String LINE_SEPARATOR; @@ -389,18 +386,6 @@ public class EditorSettingsExternalizable implements PersistentStateComponent OVERRIDE_STRIP_TRAILING_SPACES_KEY = + com.intellij.openapi.editor.impl.TrailingSpacesStripper.OVERRIDE_STRIP_TRAILING_SPACES_KEY; + + public static final Key OVERRIDE_ENSURE_NEWLINE_KEY = + com.intellij.openapi.editor.impl.TrailingSpacesStripper.OVERRIDE_ENSURE_NEWLINE_KEY; + +} diff --git a/platform/platform-resources-en/src/messages/OptionsBundle.properties b/platform/platform-resources-en/src/messages/OptionsBundle.properties index 029a8fc0bc21..881d3182fc4c 100644 --- a/platform/platform-resources-en/src/messages/OptionsBundle.properties +++ b/platform/platform-resources-en/src/messages/OptionsBundle.properties @@ -247,7 +247,6 @@ project.settings.display.name=Project Settings [{0}] template.project.settings.short.name=Template Project project.settings.short.name=Project options.color.schemes.presentable.name=Color schemes -options.editor.settings.presentable.name=Editor settings options.java.attribute.descriptor.weak.warning=Weak Warning options.java.attribute.descriptor.server.problems=Problem from server options.java.attribute.descriptor.server.duplicate=Duplicate from server @@ -277,4 +276,7 @@ color.settings.console.magentaBright=ANSI Bright Magenta color.settings.console.cyanBright=ANSI Bright Cyan color.settings.console.white=ANSI White -options.general.attribute.descriptor.live.template=Live Template \ No newline at end of file +options.general.attribute.descriptor.live.template=Live Template + +exportable.EditorSettings.presentable.name=Editor +exportable.AbbreviationManager.presentable.name=Actions \ No newline at end of file diff --git a/platform/platform-resources/src/META-INF/PlatformExtensions.xml b/platform/platform-resources/src/META-INF/PlatformExtensions.xml index 9911ceb80b34..610dca2e6144 100644 --- a/platform/platform-resources/src/META-INF/PlatformExtensions.xml +++ b/platform/platform-resources/src/META-INF/PlatformExtensions.xml @@ -245,11 +245,8 @@ - - - + diff --git a/platform/platform-resources/src/brokenPlugins.txt b/platform/platform-resources/src/brokenPlugins.txt index 60191981cc8a..9b347f110eff 100644 --- a/platform/platform-resources/src/brokenPlugins.txt +++ b/platform/platform-resources/src/brokenPlugins.txt @@ -16,4 +16,4 @@ SBT 1.0.0 1.1.0 1.2.0 1.3.0 1.3.1 1.4.0 1.5.0 AngularJS 134.1094 0.1.8 0.1.9 org.jetbrains.plugins.vagrant 0.1 0.2 org.intellij.clojure 0.2.1.178 -net.nicoulaj.idea.markdown 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 +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 diff --git a/platform/platform-resources/src/idea/Keymap_EclipseMac.xml b/platform/platform-resources/src/idea/Keymap_EclipseMac.xml index d267f18f7649..69086f9f9b2b 100644 --- a/platform/platform-resources/src/idea/Keymap_EclipseMac.xml +++ b/platform/platform-resources/src/idea/Keymap_EclipseMac.xml @@ -91,6 +91,16 @@ + + + + + + + + + + diff --git a/platform/platform-resources/src/idea/Keymap_Mac.xml b/platform/platform-resources/src/idea/Keymap_Mac.xml index 2ad9c7f7e2c6..0cbcef8c36e0 100644 --- a/platform/platform-resources/src/idea/Keymap_Mac.xml +++ b/platform/platform-resources/src/idea/Keymap_Mac.xml @@ -555,5 +555,25 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/platform/platform-resources/src/idea/Keymap_MacClassic.xml b/platform/platform-resources/src/idea/Keymap_MacClassic.xml index 730477d2af8a..bd4e97e6d743 100644 --- a/platform/platform-resources/src/idea/Keymap_MacClassic.xml +++ b/platform/platform-resources/src/idea/Keymap_MacClassic.xml @@ -353,5 +353,25 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/StripTrailingSpacesTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/StripTrailingSpacesTest.java index 7ac5f7bb2a7f..5189252e3530 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/StripTrailingSpacesTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/StripTrailingSpacesTest.java @@ -40,6 +40,7 @@ public class StripTrailingSpacesTest extends LightPlatformCodeInsightTestCase { super.setUp(); EditorSettingsExternalizable settings = EditorSettingsExternalizable.getInstance(); oldSettings = settings.getState(); + settings.loadState(new EditorSettingsExternalizable.OptionSet()); settings.setStripTrailingSpaces(EditorSettingsExternalizable.STRIP_TRAILING_SPACES_CHANGED); settings.setVirtualSpace(false); } diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/fileEditor/FileDocumentManagerImplTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/fileEditor/FileDocumentManagerImplTest.java index a5cdcbef8439..4acf5edb5892 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/fileEditor/FileDocumentManagerImplTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/fileEditor/FileDocumentManagerImplTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,6 +34,7 @@ import com.intellij.psi.PsiFile; import com.intellij.testFramework.PlatformLangTestCase; import com.intellij.util.IncorrectOperationException; import com.intellij.util.LocalTimeCounter; +import com.intellij.util.ObjectUtils; import com.intellij.util.PairProcessor; import org.jetbrains.annotations.NotNull; @@ -41,12 +42,13 @@ import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.OutputStream; -import java.util.Arrays; + +import static org.junit.Assert.assertNotEquals; public class FileDocumentManagerImplTest extends PlatformLangTestCase { private FileDocumentManagerImpl myDocumentManager; + private Boolean myReloadFromDisk; - public Boolean myReloadFromDisk; @Override protected void setUp() throws Exception { super.setUp(); @@ -148,7 +150,7 @@ public class FileDocumentManagerImplTest extends PlatformLangTestCase { final Document[] unsavedDocuments = myDocumentManager.getUnsavedDocuments(); assertEquals(1, unsavedDocuments.length); assertSame(document, unsavedDocuments[0]); - assertTrue(Arrays.equals("test".getBytes("UTF-8"), file.contentsToByteArray())); + assertEquals("test", new String(file.contentsToByteArray(), "UTF-8")); } public void testGetUnsavedDocuments_afterSaveAllDocuments() throws Exception { @@ -216,7 +218,7 @@ public class FileDocumentManagerImplTest extends PlatformLangTestCase { final Document[] unsavedDocuments = myDocumentManager.getUnsavedDocuments(); assertEquals(1, unsavedDocuments.length); assertSame(document, unsavedDocuments[0]); - assertTrue(Arrays.equals("test".getBytes("UTF-8"), file.contentsToByteArray())); + assertEquals("test", new String(file.contentsToByteArray(), "UTF-8")); } finally { myDocumentManager.dropAllUnsavedDocuments(); @@ -231,7 +233,7 @@ public class FileDocumentManagerImplTest extends PlatformLangTestCase { WriteCommandAction.runWriteCommandAction(myProject, new Runnable() { @Override public void run() { - myDocumentManager.getDocument(file).insertString(0, "xxx"); + ObjectUtils.assertNotNull(myDocumentManager.getDocument(file)).insertString(0, "xxx"); } }); @@ -252,7 +254,7 @@ public class FileDocumentManagerImplTest extends PlatformLangTestCase { WriteCommandAction.runWriteCommandAction(myProject, new Runnable() { @Override public void run() { - myDocumentManager.getDocument(file).insertString(0, "xxx"); + ObjectUtils.assertNotNull(myDocumentManager.getDocument(file)).insertString(0, "xxx"); } }); @@ -294,7 +296,7 @@ public class FileDocumentManagerImplTest extends PlatformLangTestCase { myDocumentManager.saveDocument(document); assertTrue(stamp != file.getModificationStamp()); assertEquals(document.getModificationStamp(), file.getModificationStamp()); - assertTrue(Arrays.equals("xxx test".getBytes("UTF-8"), file.contentsToByteArray())); + assertEquals("xxx test", new String(file.contentsToByteArray(), "UTF-8")); } public void testSaveAllDocuments_DocumentWasChanged() throws Exception { @@ -309,10 +311,9 @@ public class FileDocumentManagerImplTest extends PlatformLangTestCase { } }); - myDocumentManager.saveAllDocuments(); - assertTrue(stamp != file.getModificationStamp()); - assertTrue(Arrays.equals("xxx test".getBytes("UTF-8"), file.contentsToByteArray())); + assertNotEquals(stamp, file.getModificationStamp()); + assertEquals("xxx test", new String(file.contentsToByteArray(), "UTF-8")); } public void testGetFile() throws Exception { @@ -341,7 +342,7 @@ public class FileDocumentManagerImplTest extends PlatformLangTestCase { }); myDocumentManager.saveAllDocuments(); - assertTrue(Arrays.equals("xxx test\rtest".getBytes("UTF-8"), file.contentsToByteArray())); + assertEquals("xxx test\rtest", new String(file.contentsToByteArray(), "UTF-8")); } public void testContentChanged_noDocument() throws Exception { @@ -531,7 +532,7 @@ public class FileDocumentManagerImplTest extends PlatformLangTestCase { assertEquals("old test", document.getText()); assertEquals(file.getModificationStamp(), document.getModificationStamp()); - assertTrue(Arrays.equals("old test".getBytes("UTF-8"), file.contentsToByteArray())); + assertEquals("old test", new String(file.contentsToByteArray(), "UTF-8")); assertEquals(documentStamp, document.getModificationStamp()); } @@ -631,6 +632,7 @@ public class FileDocumentManagerImplTest extends PlatformLangTestCase { assertNotNull(virtualFile.getPath(), original); final PsiFile file = getPsiFile(original); + assertNotNull(file); FileDocumentManagerListener saveListener = new FileDocumentManagerAdapter() { @Override public void beforeDocumentSaving(@NotNull Document document) { @@ -650,6 +652,7 @@ public class FileDocumentManagerImplTest extends PlatformLangTestCase { }; getProject().getMessageBus().connect(getTestRootDisposable()).subscribe(AppTopics.FILE_DOCUMENT_SYNC, saveListener); final Document document = PsiDocumentManager.getInstance(getProject()).getDocument(file); + assertNotNull(document); WriteCommandAction.runWriteCommandAction(getProject(), new Runnable() { @Override public void run() { diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/SMTestProxy.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/SMTestProxy.java index d0850c9eef85..6e24904e1d33 100644 --- a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/SMTestProxy.java +++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/SMTestProxy.java @@ -42,6 +42,9 @@ import java.util.Collections; import java.util.List; /** + * Represents a test result tree node. + * Not thread-safe. All methods should be called in EDT only. + * * @author: Roman Chernyatchik */ public class SMTestProxy extends AbstractTestProxy { @@ -296,6 +299,7 @@ public class SMTestProxy extends AbstractTestProxy { } public List getChildren() { + ApplicationManager.getApplication().assertIsDispatchThread(); return myChildren != null ? myChildren : Collections.emptyList(); } diff --git a/platform/testFramework/testSrc/com/intellij/openapi/keymap/KeymapsTestCase.java b/platform/testFramework/testSrc/com/intellij/openapi/keymap/KeymapsTestCase.java index da59c1fb5460..e722fcd1a72e 100644 --- a/platform/testFramework/testSrc/com/intellij/openapi/keymap/KeymapsTestCase.java +++ b/platform/testFramework/testSrc/com/intellij/openapi/keymap/KeymapsTestCase.java @@ -213,7 +213,8 @@ public abstract class KeymapsTestCase extends PlatformTestCase { { "shift F2", "GotoPreviousError", "GotoDeclaration"}, { "shift control F7", "FindUsagesInFile", "HighlightUsagesInFile"}, { "shift control I", "ImplementMethods", "QuickImplementations"}, - { "alt F9", "ViewBreakpoints", "EditBreakpoint"}, + { "alt F9", "ViewBreakpoints", "EditBreakpoint"}, + { "alt MULTIPLY", "ShowExecutionPoint", "Images.Thumbnails.ToggleRecursive"}, }); put("Default for XWin", new String[][] { }); @@ -277,7 +278,7 @@ public abstract class KeymapsTestCase extends PlatformTestCase { { "control 2", "ActivateProjectToolWindow", "FileChooser.GotoProject", "DuplicatesForm.SendToRight"}, { "control 3", "ActivateProjectToolWindow", "FileChooser.GotoModule"}, { "control BACK_SPACE", "EditorDeleteToWordStart", "ToggleDockMode"}, - { "control DIVIDE", "CommentByLineComment", "Images.Editor.ActualSize"}, + { "control DIVIDE", "CollapseRegionRecursively", "Images.Editor.ActualSize"}, { "control D", "EditorDuplicate", "CompareDirs", "CompareTwoFiles", "SendEOF", "FileChooser.GotoDesktop"}, { "control M", "Vcs.ShowMessageHistory", "Move"}, { "control R", "RenameElement", "Console.TableResult.Reload", "org.jetbrains.plugins.ruby.rails.console.ReloadSources"}, diff --git a/platform/testRunner/src/com/intellij/execution/testframework/ui/TestsOutputConsolePrinter.java b/platform/testRunner/src/com/intellij/execution/testframework/ui/TestsOutputConsolePrinter.java index b69636bd643e..535f2d454999 100644 --- a/platform/testRunner/src/com/intellij/execution/testframework/ui/TestsOutputConsolePrinter.java +++ b/platform/testRunner/src/com/intellij/execution/testframework/ui/TestsOutputConsolePrinter.java @@ -42,15 +42,7 @@ public class TestsOutputConsolePrinter implements Printer, Disposable { }; public TestsOutputConsolePrinter(@NotNull BaseTestsOutputConsoleView testsOutputConsoleView, final TestConsoleProperties properties, final AbstractTestProxy unboundOutputRoot) { - this(testsOutputConsoleView.getConsole(), properties, unboundOutputRoot); - } - - /** - * @deprecated left for JSTestDriver compatibility - */ - @Deprecated - public TestsOutputConsolePrinter(final ConsoleView console, final TestConsoleProperties properties, final AbstractTestProxy unboundOutputRoot) { - myConsole = console; + myConsole = testsOutputConsoleView.getConsole(); myProperties = properties; myUnboundOutputRoot = unboundOutputRoot; myProperties.addListener(TestConsoleProperties.SCROLL_TO_STACK_TRACE, myPropertyListener); @@ -148,7 +140,7 @@ public class TestsOutputConsolePrinter implements Printer, Disposable { } public boolean canPause() { - return myCurrentTest != null ? myCurrentTest.isInProgress() : false; + return myCurrentTest != null && myCurrentTest.isInProgress(); } protected void scrollToBeginning() { diff --git a/platform/util/resources/misc/registry.properties b/platform/util/resources/misc/registry.properties index 563ff2522d06..53628fcec0ce 100644 --- a/platform/util/resources/misc/registry.properties +++ b/platform/util/resources/misc/registry.properties @@ -341,6 +341,7 @@ svn.use.terminal=false svn.use.incoming.optimization=false svn.executable.locale=C.UTF-8 svn.lowest.supported.format.for.command.line=1.7.0 +svn.use.svnkit.for.https.server.certificate.check=true completion.enable.relevant.method.chain.suggestions=false ide.mac.message.sheets.java.emulation=false @@ -439,4 +440,4 @@ spy.js.realtime.evaluation.description=Enables spy-js autocomplete and realtime new.css.schema.enabled=true editor.disable.rtl=false -editor.disable.rtl.description=Disables RTL support in editor (which is broken now anyway) \ No newline at end of file +editor.disable.rtl.description=Disables RTL support in editor (which is broken now anyway) diff --git a/platform/util/src/com/intellij/util/containers/FList.java b/platform/util/src/com/intellij/util/containers/FList.java index 12f5fad9a0e6..dde6dcf3fcba 100644 --- a/platform/util/src/com/intellij/util/containers/FList.java +++ b/platform/util/src/com/intellij/util/containers/FList.java @@ -15,9 +15,12 @@ */ package com.intellij.util.containers; +import com.intellij.openapi.util.Comparing; import org.jetbrains.annotations.NotNull; -import java.util.*; +import java.util.AbstractList; +import java.util.Iterator; +import java.util.NoSuchElementException; /** * Immutable list in functional style @@ -25,18 +28,15 @@ import java.util.*; * @author nik */ public class FList extends AbstractList { - private static final FList EMPTY_LIST = new FList(); - private E myHead; - private FList myTail; - private int mySize; + @SuppressWarnings("unchecked") private static final FList EMPTY_LIST = new FList(null, null, 0); + private final E myHead; + private final FList myTail; + private final int mySize; - private FList() { - } - - private FList(E head, FList tail) { + private FList(E head, FList tail, int size) { myHead = head; myTail = tail; - mySize = tail.size()+1; + mySize = size; } @Override @@ -58,7 +58,7 @@ public class FList extends AbstractList { } public FList prepend(E elem) { - return new FList(elem, this); + return new FList(elem, this, mySize + 1); } public FList without(E elem) { @@ -120,7 +120,37 @@ public class FList extends AbstractList { return mySize; } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o instanceof FList) { + FList list1 = this; + FList list2 = (FList)o; + if (mySize != list2.mySize) return false; + while (list1 != null) { + if (!Comparing.equal(list1.myHead, list2.myHead)) return false; + list1 = list1.getTail(); + list2 = list2.getTail(); + if (list1 == list2) return true; + } + return true; + } + return super.equals(o); + } + + @Override + public int hashCode() { + int result = 1; + FList each = this; + while (each != null) { + result = result * 31 + (each.myHead != null ? each.myHead.hashCode() : 0); + each = each.getTail(); + } + return result; + } + public static FList emptyList() { + //noinspection unchecked return (FList)EMPTY_LIST; } } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java index ddc28745934a..a28c2cc2b42b 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java @@ -61,6 +61,7 @@ import com.intellij.xdebugger.frame.XStackFrame; import com.intellij.xdebugger.frame.XSuspendContext; import com.intellij.xdebugger.frame.XValueMarkerProvider; import com.intellij.xdebugger.impl.breakpoints.*; +import com.intellij.xdebugger.impl.evaluate.XDebuggerEditorLinePainter; import com.intellij.xdebugger.impl.evaluate.quick.common.ValueLookupManager; import com.intellij.xdebugger.impl.frame.XValueMarkers; import com.intellij.xdebugger.impl.settings.XDebuggerSettingsManager; @@ -891,6 +892,7 @@ public class XDebugSessionImpl implements XDebugSession { myStopped = true; myDebuggerManager.removeSession(this); myDispatcher.getMulticaster().sessionStopped(); + myProject.putUserData(XDebuggerEditorLinePainter.CACHE, null); } public boolean isInactiveSlaveBreakpoint(final XBreakpoint breakpoint) { diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/quick/XValueHint.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/quick/XValueHint.java index e1435be03d2b..589c8aed2abf 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/quick/XValueHint.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/quick/XValueHint.java @@ -28,6 +28,7 @@ import com.intellij.openapi.actionSystem.ShortcutSet; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.impl.EditorImpl; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.keymap.KeymapUtil; import com.intellij.openapi.project.DumbAwareAction; @@ -115,6 +116,7 @@ public class XValueHint extends AbstractValueHint { boolean result = super.showHint(component); if (result && getType() == ValueHintType.MOUSE_OVER_HINT) { myDisposable = Disposer.newDisposable(); + Disposer.register(((EditorImpl)getEditor()).getDisposable(), myDisposable); ShortcutSet shortcut = ActionManager.getInstance().getAction("ShowErrorDescription").getShortcutSet(); new DumbAwareAction() { @Override @@ -133,7 +135,6 @@ public class XValueHint extends AbstractValueHint { super.hideHint(); if (myDisposable != null) { Disposer.dispose(myDisposable); - } } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/XValueContainerNode.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/XValueContainerNode.java index 0bbe12da965a..787a2cb5bb54 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/XValueContainerNode.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/XValueContainerNode.java @@ -15,6 +15,11 @@ */ package com.intellij.xdebugger.impl.ui.tree.nodes; +import com.intellij.execution.configurations.RemoteRunProfile; +import com.intellij.execution.runners.ExecutionEnvironment; +import com.intellij.ide.DataManager; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.actionSystem.LangDataKeys; import com.intellij.openapi.util.registry.Registry; import com.intellij.ui.SimpleTextAttributes; import com.intellij.util.ObjectUtils; @@ -92,7 +97,7 @@ public abstract class XValueContainerNode createGroupNodes(List groups, @Nullable List prevNodes, diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/XValueNodeImpl.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/XValueNodeImpl.java index 292cca541699..595322d761f1 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/XValueNodeImpl.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/XValueNodeImpl.java @@ -149,13 +149,14 @@ public class XValueNodeImpl extends XValueContainerNode implements XValu if (doc == null) return; int line = sourcePosition.getLine(); Pair key = Pair.create(file, line); - Set presentations = map.get(key); - if (presentations == null) { - presentations = new LinkedHashSet(); - map.put(key, presentations); - timestamps.put(file, doc.getModificationStamp()); - } + Set presentations = new LinkedHashSet(); + Set old = map.get(key); + map.put(key, presentations); + timestamps.put(file, doc.getModificationStamp()); presentations.add(XValueNodeImpl.this); + if (old != null) { + presentations.addAll(old); + } } }); } diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java index 07ed51bfca7d..972c240db1d0 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java @@ -7,7 +7,6 @@ import com.intellij.openapi.progress.EmptyProgressIndicator; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Couple; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.ThrowableComputable; @@ -488,12 +487,12 @@ public class GithubCreatePullRequestWorker { String localBranchName = "'" + myCurrentBranch + "'"; String targetBranchName = "'" + fork.getRemoteName() + "/" + branch.getRemoteName() + "'"; if (info.getInfo().getBranchToHeadCommits(myGitRepository).isEmpty()) { - return Messages.YES == GithubNotifications + return GithubNotifications .showYesNoDialog(myProject, "Do you want to proceed anyway?", "Empty pull request: the branch " + localBranchName + " is fully merged to the branch " + targetBranchName); } if (!info.getInfo().getHeadToBranchCommits(myGitRepository).isEmpty()) { - return Messages.YES == GithubNotifications + return GithubNotifications .showYesNoDialog(myProject, "Do you want to proceed anyway?", "The branch " + targetBranchName + " is not fully merged to the branch " + localBranchName); } diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubShareAction.java b/plugins/github/src/org/jetbrains/plugins/github/GithubShareAction.java index c372b09805a1..537a580775c8 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubShareAction.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubShareAction.java @@ -49,14 +49,16 @@ import git4idea.repo.GitRepositoryManager; import git4idea.util.GitFileUtils; import git4idea.util.GitUIUtil; import icons.GithubIcons; +import org.apache.http.HttpStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.plugins.github.api.GithubApiUtil; -import org.jetbrains.plugins.github.api.GithubConnection; -import org.jetbrains.plugins.github.api.GithubRepo; -import org.jetbrains.plugins.github.api.GithubUserDetailed; +import org.jetbrains.plugins.github.api.*; +import org.jetbrains.plugins.github.exceptions.GithubStatusCodeException; import org.jetbrains.plugins.github.ui.GithubShareDialog; -import org.jetbrains.plugins.github.util.*; +import org.jetbrains.plugins.github.util.GithubAuthDataHolder; +import org.jetbrains.plugins.github.util.GithubNotifications; +import org.jetbrains.plugins.github.util.GithubUrlUtil; +import org.jetbrains.plugins.github.util.GithubUtil; import javax.swing.*; import java.io.IOException; @@ -114,19 +116,18 @@ public class GithubShareAction extends DumbAwareAction { final boolean gitDetected = gitRepository != null; final VirtualFile root = gitDetected ? gitRepository.getRoot() : project.getBaseDir(); + final GithubAuthDataHolder authHolder = GithubAuthDataHolder.createFromSettings(); + // check for existing git repo boolean externalRemoteDetected = false; if (gitDetected) { final String githubRemote = GithubUtil.findGithubRemoteUrl(gitRepository); if (githubRemote != null) { - GithubNotifications.showInfoURL(project, "Project is already on GitHub", "GitHub", githubRemote); - return; + if (!checkExistingRemote(project, authHolder, githubRemote)) return; } externalRemoteDetected = !gitRepository.getRemotes().isEmpty(); } - final GithubAuthDataHolder authHolder = GithubAuthDataHolder.createFromSettings(); - // get available GitHub repos with modal progress final GithubInfo githubInfo = loadGithubInfoWithModal(authHolder, project); if (githubInfo == null) { @@ -203,6 +204,53 @@ public class GithubShareAction extends DumbAwareAction { }.queue(); } + private static boolean checkExistingRemote(@NotNull final Project project, + @NotNull final GithubAuthDataHolder authHolder, + @NotNull String remote) { + final GithubFullPath path = GithubUrlUtil.getUserAndRepositoryFromRemoteUrl(remote); + if (path == null) { + return GithubNotifications.showYesNoDialog(project, + "Project is already on GitHub", + "Can't connect to repository from configured remote. You could want to check .git config.\n" + + "Do you want to proceed anyway?"); + } + + try { + GithubRepo repo = + GithubUtil.computeValueInModal(project, "Access to GitHub", new ThrowableConvertor() { + @NotNull + @Override + public GithubRepo convert(ProgressIndicator indicator) throws IOException { + return GithubUtil + .runTask(project, authHolder, indicator, new ThrowableConvertor() { + @NotNull + @Override + public GithubRepo convert(@NotNull GithubConnection connection) throws IOException { + return GithubApiUtil.getDetailedRepoInfo(connection, path.getUser(), path.getRepository()); + } + }); + } + }); + GithubNotifications.showInfoURL(project, "Project is already on GitHub", "GitHub", repo.getHtmlUrl()); + return false; + } + catch (GithubStatusCodeException e) { + if (e.getStatusCode() == HttpStatus.SC_NOT_FOUND) { + return GithubNotifications.showYesNoDialog(project, + "Project is already on GitHub", + "Can't connect to repository from configured remote. You could want to check .git config.\n" + + "Do you want to proceed anyway?"); + } + + GithubNotifications.showErrorDialog(project, "Failed to connect to GitHub", e); + return false; + } + catch (IOException e) { + GithubNotifications.showErrorDialog(project, "Failed to connect to GitHub", e); + return false; + } + } + @Nullable private static GithubInfo loadGithubInfoWithModal(@NotNull final GithubAuthDataHolder authHolder, @NotNull final Project project) { try { diff --git a/plugins/github/src/org/jetbrains/plugins/github/api/GithubConnection.java b/plugins/github/src/org/jetbrains/plugins/github/api/GithubConnection.java index 6358b79e38ee..35b4a50c7a7b 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/api/GithubConnection.java +++ b/plugins/github/src/org/jetbrains/plugins/github/api/GithubConnection.java @@ -144,10 +144,8 @@ public class GithubConnection { .setConnectTimeout(timeout) .setSocketTimeout(timeout); - final HttpConfigurable proxySettings = HttpConfigurable.getInstance(); - if (auth.isUseProxy() && proxySettings.USE_HTTP_PROXY && !StringUtil.isEmptyOrSpaces(proxySettings.PROXY_HOST)) { - builder - .setProxy(new HttpHost(proxySettings.PROXY_HOST, proxySettings.PROXY_PORT)); + if (auth.isUseProxy()) { + HttpConfigurable.getInstance().setProxy(builder); } return builder.build(); @@ -170,14 +168,10 @@ public class GithubConnection { provider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(basicAuth.getLogin(), basicAuth.getPassword())); } - final HttpConfigurable proxySettings = HttpConfigurable.getInstance(); - //proxySettings.USE_HTTP_PROXY - if (auth.isUseProxy() && proxySettings.USE_HTTP_PROXY && !StringUtil.isEmptyOrSpaces(proxySettings.PROXY_HOST)) { - if (proxySettings.PROXY_AUTHENTICATION) { - provider.setCredentials(new AuthScope(proxySettings.PROXY_HOST, proxySettings.PROXY_PORT), - new UsernamePasswordCredentials(proxySettings.PROXY_LOGIN, proxySettings.getPlainProxyPassword())); - } + if (auth.isUseProxy()) { + HttpConfigurable.getInstance().setProxyCredentials(provider); } + return provider; } diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java index 482ef9492fdc..c9b213db4358 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java @@ -103,7 +103,7 @@ public class GithubCreatePullRequestDialog extends DialogWrapper { createRemote = GithubNotifications.showYesNoDialog(project, "Can't Find Remote", "Configure remote for '" + fork.getPath().getUser() + "'?", - ourDoNotAskOption) == Messages.YES; + ourDoNotAskOption); break; } diff --git a/plugins/github/src/org/jetbrains/plugins/github/util/GithubNotifications.java b/plugins/github/src/org/jetbrains/plugins/github/util/GithubNotifications.java index d34441bf1ba3..1b8d7920f4b8 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/util/GithubNotifications.java +++ b/plugins/github/src/org/jetbrains/plugins/github/util/GithubNotifications.java @@ -136,15 +136,15 @@ public class GithubNotifications { } @Messages.YesNoResult - public static int showYesNoDialog(@Nullable Project project, @NotNull String title, @NotNull String message) { - return Messages.showYesNoDialog(project, message, title, Messages.getQuestionIcon()); + public static boolean showYesNoDialog(@Nullable Project project, @NotNull String title, @NotNull String message) { + return Messages.YES == Messages.showYesNoDialog(project, message, title, Messages.getQuestionIcon()); } @Messages.YesNoResult - public static int showYesNoDialog(@Nullable Project project, - @NotNull String title, - @NotNull String message, - @NotNull DialogWrapper.DoNotAskOption doNotAskOption) { - return Messages.showYesNoDialog(project, message, title, Messages.getQuestionIcon(), doNotAskOption); + public static boolean showYesNoDialog(@Nullable Project project, + @NotNull String title, + @NotNull String message, + @NotNull DialogWrapper.DoNotAskOption doNotAskOption) { + return Messages.YES == Messages.showYesNoDialog(project, message, title, Messages.getQuestionIcon(), doNotAskOption); } } diff --git a/plugins/google-app-engine/testData/sdk/1.3.7/bin/appcfg.bat b/plugins/google-app-engine/testData/sdk/1.3.7/bin/appcfg.cmd similarity index 100% rename from plugins/google-app-engine/testData/sdk/1.3.7/bin/appcfg.bat rename to plugins/google-app-engine/testData/sdk/1.3.7/bin/appcfg.cmd diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/AuthenticationService.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/AuthenticationService.java index 076fd59611f3..a8a0d7ccdc60 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/AuthenticationService.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/AuthenticationService.java @@ -22,23 +22,39 @@ import com.intellij.openapi.ui.popup.util.PopupUtil; import com.intellij.openapi.util.Getter; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.registry.Registry; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.ArrayUtil; import com.intellij.util.WaitForProgressToShow; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.net.HttpConfigurable; +import com.intellij.util.net.ssl.CertificateManager; import com.intellij.util.proxy.CommonProxy; +import org.apache.http.client.HttpClient; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.config.SocketConfig; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.impl.client.BasicCredentialsProvider; +import org.apache.http.impl.client.HttpClients; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.SvnBundle; import org.jetbrains.idea.svn.SvnConfiguration; import org.jetbrains.idea.svn.SvnVcs; +import org.jetbrains.idea.svn.commandLine.SvnBindException; import org.jetbrains.idea.svn.dialogs.SimpleCredentialsDialog; import org.tmatesoft.svn.core.SVNURL; import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager; import org.tmatesoft.svn.core.auth.SVNAuthentication; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLHandshakeException; +import javax.net.ssl.TrustManager; import java.io.File; import java.io.IOException; import java.net.*; +import java.security.KeyManagementException; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -165,12 +181,106 @@ public class AuthenticationService { }); } - public boolean acceptSSLServerCertificate(final SVNURL repositoryUrl, final String realm) { + public boolean acceptSSLServerCertificate(@Nullable SVNURL repositoryUrl, final String realm) throws SvnBindException { if (repositoryUrl == null) { return false; } - return new SSLServerCertificateAuthenticator(this, repositoryUrl, realm).tryAuthenticate(); + boolean result; + + if (Registry.is("svn.use.svnkit.for.https.server.certificate.check")) { + result = new SSLServerCertificateAuthenticator(this, repositoryUrl, realm).tryAuthenticate(); + } + else { + HttpClient client = getClient(repositoryUrl); + + try { + client.execute(new HttpGet(repositoryUrl.toDecodedString())); + result = true; + } + catch (IOException e) { + throw new SvnBindException(fixMessage(e), e); + } + } + + return result; + } + + @Nullable + private static String fixMessage(@NotNull IOException e) { + String message = null; + + if (e instanceof SSLHandshakeException) { + if (StringUtil.containsIgnoreCase(e.getMessage(), "received fatal alert: handshake_failure")) { + message = e.getMessage() + ". Please try to specify SSL protocol manually - SSLv3 or TLSv1"; + } + else if (e.getCause() != null) { + // SSLHandshakeException.getMessage() could contain full type name of cause exception - for instance when cause is + // CertificateException. We just use cause exception message not to show exception type to the user. + message = e.getCause().getMessage(); + } + } + + return message; + } + + @NotNull + private HttpClient getClient(@NotNull SVNURL repositoryUrl) { + // TODO: Implement algorithm of resolving necessary enabled protocols (TLSv1 vs SSLv3) instead of just using values from Settings. + SSLContext sslContext = createSslContext(repositoryUrl); + List supportedProtocols = getSupportedSslProtocols(); + SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext, ArrayUtil.toStringArray(supportedProtocols), null, + SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); + HttpConfigurable httpSettings = HttpConfigurable.getInstance(); + + // TODO: Seems more suitable here to read timeout values directly from config file - without utilizing SvnAuthenticationManager. + return HttpClients.custom() + .setSSLSocketFactory(socketFactory) + .setDefaultSocketConfig(SocketConfig.custom().setSoTimeout(getAuthenticationManager().getReadTimeout(repositoryUrl)).build()) + .setDefaultRequestConfig( + httpSettings.setProxy(RequestConfig.custom(), haveDataForTmpConfig()) + .setConnectTimeout(getAuthenticationManager().getConnectTimeout(repositoryUrl)) + .build()) + .setDefaultCredentialsProvider(httpSettings.setProxyCredentials(new BasicCredentialsProvider(), haveDataForTmpConfig())) + .build(); + } + + @NotNull + private List getSupportedSslProtocols() { + List result = ContainerUtil.newArrayList(); + + switch (myConfiguration.getSslProtocols()) { + case sslv3: + result.add("SSLv3"); + break; + case tlsv1: + result.add("TLSv1"); + break; + case all: + break; + } + + return result; + } + + @NotNull + private SSLContext createSslContext(@NotNull SVNURL url) { + SSLContext result = CertificateManager.getSystemSslContext(); + TrustManager trustManager = new CertificateTrustManager(this, url); + + try { + result.init(CertificateManager.getDefaultKeyManagers(), new TrustManager[]{trustManager}, null); + } + catch (KeyManagementException e) { + LOG.error(e); + } + + return result; + } + + @NotNull + public SvnAuthenticationManager getAuthenticationManager() { + return isActive() ? myConfiguration.getInteractiveManager(myVcs) : myConfiguration.getPassiveAuthenticationManager(myVcs.getProject()); } public void clearPassiveCredentials(String realm, SVNURL repositoryUrl, boolean password) { @@ -186,6 +296,7 @@ public class AuthenticationService { } } + // TODO: rename public boolean haveDataForTmpConfig() { final HttpConfigurable instance = HttpConfigurable.getInstance(); return SvnConfiguration.getInstance(myVcs.getProject()).isIsUseDefaultProxy() && diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/CertificateTrustManager.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/CertificateTrustManager.java new file mode 100644 index 000000000000..c5bd5a54182b --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/CertificateTrustManager.java @@ -0,0 +1,123 @@ +/* + * 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 org.jetbrains.idea.svn.auth; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.util.net.ssl.CertificateManager; +import com.intellij.util.net.ssl.ClientOnlyTrustManager; +import org.apache.http.client.utils.URIBuilder; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.idea.svn.SvnConfiguration; +import org.tmatesoft.svn.core.SVNURL; +import org.tmatesoft.svn.core.auth.ISVNAuthenticationProvider; + +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +/** + * We assume that this trust manager is only used when server certificate is valid but untrusted. So we do not perform any additional + * validation here - just checking if certificate is trusted in several ways: + * - runtime cache + * - java trust store + * - "Server Certificates" settings + * - ask user + * + * @author Konstantin Kolosovsky. + */ +public class CertificateTrustManager extends ClientOnlyTrustManager { + + private static final Logger LOG = Logger.getInstance(CertificateTrustManager.class); + + @NotNull private final AuthenticationService myAuthenticationService; + @NotNull private final SVNURL myRepositoryUrl; + @NotNull private final String myRealm; + + public CertificateTrustManager(@NotNull AuthenticationService authenticationService, @NotNull SVNURL repositoryUrl) { + myAuthenticationService = authenticationService; + myRepositoryUrl = repositoryUrl; + myRealm = new URIBuilder() + .setScheme(repositoryUrl.getProtocol()) + .setHost(repositoryUrl.getHost()) + .setPort(repositoryUrl.getPort()) + .toString(); + } + + @Override + public void checkServerTrusted(@Nullable X509Certificate[] chain, String authType) throws CertificateException { + if (chain != null && chain.length > 0 && chain[0] != null) { + X509Certificate certificate = chain[0]; + + if (!checkPassive(certificate)) { + if (!isAcceptedByIdea(chain, authType)) { + checkActive(certificate); + } + + // no exceptions - so certificate is trusted - save to runtime cache + acknowledge(certificate); + } + } + } + + private boolean checkPassive(@NotNull X509Certificate certificate) throws CertificateEncodingException { + Object cachedData = SvnConfiguration.RUNTIME_AUTH_CACHE.getDataWithLowerCheck("svn.ssl.server", myRealm); + + return certificate.equals(cachedData); + } + + private static boolean isAcceptedByIdea(@NotNull X509Certificate[] chain, String authType) { + boolean result; + + try { + CertificateManager.getInstance().getTrustManager().checkServerTrusted(chain, authType, false, false); + result = true; + } + catch (CertificateException e) { + LOG.debug(e); + result = false; + } + + return result; + } + + private void checkActive(@NotNull X509Certificate certificate) throws CertificateException { + boolean isStorageEnabled = + myAuthenticationService.getAuthenticationManager().getHostOptionsProvider().getHostOptions(myRepositoryUrl).isAuthStorageEnabled(); + int result = myAuthenticationService.getAuthenticationManager().getInnerProvider() + .acceptServerAuthentication(myRepositoryUrl, myRealm, certificate, isStorageEnabled); + + switch (result) { + case ISVNAuthenticationProvider.ACCEPTED: + // TODO: --trust-server-cert command line key does not allow caching credentials permanently - so permanent caching should be + // TODO: separately implemented. Try utilizing "Server Certificates" settings for this. + case ISVNAuthenticationProvider.ACCEPTED_TEMPORARY: + // acknowledge() is called in checkServerTrusted() + break; + case ISVNAuthenticationProvider.REJECTED: + throw new CertificateException("Server SSL certificate rejected"); + } + } + + private void acknowledge(@NotNull X509Certificate certificate) throws CertificateEncodingException { + myAuthenticationService.getVcs().getSvnConfiguration().acknowledge("svn.ssl.server", myRealm, certificate); + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + return CertificateManager.getInstance().getTrustManager().getAcceptedIssuers(); + } +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/SvnAuthenticationManager.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/SvnAuthenticationManager.java index e844374cf341..88f7f65502aa 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/SvnAuthenticationManager.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/SvnAuthenticationManager.java @@ -41,6 +41,7 @@ import com.intellij.util.proxy.CommonProxy; import com.intellij.util.ui.UIUtil; import com.trilead.ssh2.auth.AgentProxy; import org.intellij.lang.annotations.MagicConstant; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.*; import org.jetbrains.idea.svn.config.ProxyGroup; @@ -722,20 +723,20 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im // 30 seconds private final static int DEFAULT_READ_TIMEOUT = 30 * 1000; - @Override - public int getReadTimeout(final SVNRepository repository) { - String protocol = repository.getLocation().getProtocol(); + public int getReadTimeout(@NotNull SVNURL url) { + String protocol = url.getProtocol(); if (HTTP.equals(protocol) || HTTPS.equals(protocol)) { - String host = repository.getLocation().getHost(); - String timeout = getServersPropertyIdea(host, "http-timeout"); - if (timeout != null) { - try { - return Integer.parseInt(timeout)*1000; - } catch (NumberFormatException nfe) { - // use default - } + String host = url.getHost(); + String timeout = getServersPropertyIdea(host, "http-timeout"); + if (timeout != null) { + try { + return Integer.parseInt(timeout) * 1000; } - return DEFAULT_READ_TIMEOUT; + catch (NumberFormatException nfe) { + // use default + } + } + return DEFAULT_READ_TIMEOUT; } if (SVN_SSH.equals(protocol)) { return (int)getConfig().getSshReadTimeout(); @@ -743,19 +744,28 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im return 0; } - @Override - public int getConnectTimeout(SVNRepository repository) { - String protocol = repository.getLocation().getProtocol(); + public int getConnectTimeout(@NotNull SVNURL url) { + String protocol = url.getProtocol(); if (SVN_SSH.equals(protocol)) { return (int)getConfig().getSshConnectionTimeout(); } - final int connectTimeout = super.getConnectTimeout(repository); + final int connectTimeout = getHostOptionsProvider().getHostOptions(url).getConnectTimeout(); if ((HTTP.equals(protocol) || HTTPS.equals(protocol)) && (connectTimeout <= 0)) { return DEFAULT_READ_TIMEOUT; } return connectTimeout; } + @Override + public int getReadTimeout(@NotNull SVNRepository repository) { + return getReadTimeout(repository.getLocation()); + } + + @Override + public int getConnectTimeout(@NotNull SVNRepository repository) { + return getConnectTimeout(repository.getLocation()); + } + // taken from default manager as is private String getServersPropertyIdea(String host, final String name) { final SVNCompositeConfigFile serversFile = getHostOptionsProvider().getServersFile(); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/AuthCallbackCase.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/AuthCallbackCase.java index 77cca02a04fb..7edfaa491935 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/AuthCallbackCase.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/AuthCallbackCase.java @@ -25,7 +25,6 @@ import org.tmatesoft.svn.core.SVNURL; */ public abstract class AuthCallbackCase { protected final SVNURL myUrl; - protected boolean myTried = false; @NotNull protected final AuthenticationService myAuthenticationService; AuthCallbackCase(@NotNull AuthenticationService authenticationService, SVNURL url) { diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CertificateCallbackCase.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CertificateCallbackCase.java index f58a775079ed..79d7a7ac3055 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CertificateCallbackCase.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CertificateCallbackCase.java @@ -15,6 +15,7 @@ */ package org.jetbrains.idea.svn.commandLine; +import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.idea.svn.auth.AuthenticationService; @@ -29,6 +30,7 @@ public class CertificateCallbackCase extends AuthCallbackCase { private static final String CERTIFICATE_ERROR = "Error validating server certificate for"; private static final String UNTRUSTED_SERVER_CERTIFICATE = "Server SSL certificate untrusted"; private static final String CERTIFICATE_VERIFICATION_FAILED = "certificate verification failed"; + private static final String CERTIFICATE_VERIFICATION_FAILED_ISSUER_NOT_TRUSTED = "certificate verification failed: issuer is not trusted"; private boolean accepted; @@ -38,11 +40,22 @@ public class CertificateCallbackCase extends AuthCallbackCase { @Override public boolean canHandle(String error) { + boolean useSvnKit = Registry.is("svn.use.svnkit.for.https.server.certificate.check"); + return error.startsWith(CERTIFICATE_ERROR) || // https one-way protocol untrusted server certificate error.contains(UNTRUSTED_SERVER_CERTIFICATE) || - // for instance, certificate issued for a different hostname, issuer is not trusted - for both 1.7 and 1.8 - error.contains(CERTIFICATE_VERIFICATION_FAILED); + // any certificate verification failure - for instance, "certificate issued for a different hostname" and/or + // "issuer is not trusted" - for both 1.7 and 1.8. + // SVNKit-based implementation persists credentials (by utilizing SVNKit api) emulating situation as if credentials were cached + // by Subversion. That is why we could process both untrusted and invalid certificate errors. + useSvnKit && isCertificateVerificationFailed(error) || + // valid but untrusted certificates - "issuer is not trusted" error - for both 1.7 and 1.8. + // Implementation not based on SVNKit does not persist credentials to emulate situation as if credentials were cached by + // Subversion. And in "--non-interactive" mode we could only make Subversion accept untrusted, but not invalid certificate. + // So we explicitly check that verification failure is only "issuer is not trusted". If certificate has some other failures, + // command will end with error. + !useSvnKit && isValidButUntrustedCertificate(error); } @Override @@ -56,9 +69,8 @@ public class CertificateCallbackCase extends AuthCallbackCase { realm = serverUrl != null ? serverUrl.toString() : realm; } - if (!myTried && myAuthenticationService.acceptSSLServerCertificate(myUrl, realm)) { + if (myAuthenticationService.acceptSSLServerCertificate(myUrl, realm)) { accepted = true; - myTried = true; return true; } throw new SvnBindException("Server SSL certificate rejected"); @@ -87,6 +99,14 @@ public class CertificateCallbackCase extends AuthCallbackCase { } } + public static boolean isValidButUntrustedCertificate(@NotNull String error) { + return error.contains(CERTIFICATE_VERIFICATION_FAILED_ISSUER_NOT_TRUSTED); + } + + public static boolean isCertificateVerificationFailed(@NotNull String error) { + return error.contains(CERTIFICATE_VERIFICATION_FAILED); + } + private SVNURL getServerUrl(String realm) { SVNURL result = parseUrl(realm); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/UsernamePasswordCallback.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/UsernamePasswordCallback.java index ad908b213ab3..63930418e327 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/UsernamePasswordCallback.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/UsernamePasswordCallback.java @@ -15,6 +15,7 @@ */ package org.jetbrains.idea.svn.commandLine; +import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.idea.svn.auth.AuthenticationService; @@ -49,13 +50,17 @@ public class UsernamePasswordCallback extends AuthCallbackCase { @Override public boolean canHandle(String error) { + boolean useSvnKit = Registry.is("svn.use.svnkit.for.https.server.certificate.check"); + return // http/https protocol invalid credentials error.contains(AUTHENTICATION_FAILED_MESSAGE) || // svn protocol invalid credentials - messages could be "Can't get password", "Can't get username or password" error.contains(INVALID_CREDENTIALS_FOR_SVN_PROTOCOL) && error.contains(PASSWORD_STRING) || // http/https protocol, svn 1.7, non-interactive - error.contains(UNABLE_TO_CONNECT_MESSAGE) || + // we additionally check that error is not related to certificate verification - as CertificateCallbackCase could only handle + // untrusted certificates, but not invalid when useSvnKit = false + (error.contains(UNABLE_TO_CONNECT_MESSAGE) && (useSvnKit || !CertificateCallbackCase.isCertificateVerificationFailed(error))) || // http, svn 1.6, non-interactive StringUtil.containsIgnoreCase(error, COULD_NOT_AUTHENTICATE_TO_SERVER_MESSAGE); } diff --git a/plugins/svn4idea/svn4idea.iml b/plugins/svn4idea/svn4idea.iml index 20482fa75610..f88970ebf676 100644 --- a/plugins/svn4idea/svn4idea.iml +++ b/plugins/svn4idea/svn4idea.iml @@ -91,6 +91,7 @@ + diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/httpclient/NewBaseRepositoryImpl.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/httpclient/NewBaseRepositoryImpl.java index 082d49812d5b..5f71422c1ec1 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/httpclient/NewBaseRepositoryImpl.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/httpclient/NewBaseRepositoryImpl.java @@ -89,24 +89,19 @@ public abstract class NewBaseRepositoryImpl extends BaseRepository { provider.setCredentials(BASIC_AUTH_SCOPE, new UsernamePasswordCredentials(getUsername(), getPassword())); } // Proxy authentication - HttpConfigurable proxySettings = HttpConfigurable.getInstance(); - if (isUseProxy() && proxySettings.PROXY_AUTHENTICATION) { - provider.setCredentials(new AuthScope(proxySettings.PROXY_HOST, proxySettings.PROXY_PORT), - new UsernamePasswordCredentials(proxySettings.PROXY_LOGIN, proxySettings.getPlainProxyPassword())); - } + HttpConfigurable.getInstance().setProxyCredentials(provider, isUseProxy()); + return provider; } @NotNull protected RequestConfig createRequestConfig() { TaskSettings tasksSettings = TaskSettings.getInstance(); - HttpConfigurable proxySettings = HttpConfigurable.getInstance(); RequestConfig.Builder builder = RequestConfig.custom() .setConnectTimeout(3000) .setSocketTimeout(tasksSettings.CONNECTION_TIMEOUT); - if (isUseProxy()) { - builder.setProxy(new HttpHost(proxySettings.PROXY_HOST, proxySettings.PROXY_PORT)); - } + HttpConfigurable.getInstance().setProxy(builder, isUseProxy()); + return builder.build(); } diff --git a/xml/impl/src/org/jetbrains/builtInWebServer/ConsoleManager.java b/xml/impl/src/org/jetbrains/builtInWebServer/ConsoleManager.java index 854ae09923fc..1857c7f17f6c 100644 --- a/xml/impl/src/org/jetbrains/builtInWebServer/ConsoleManager.java +++ b/xml/impl/src/org/jetbrains/builtInWebServer/ConsoleManager.java @@ -3,10 +3,17 @@ package org.jetbrains.builtInWebServer; import com.intellij.execution.filters.TextConsoleBuilder; import com.intellij.execution.filters.TextConsoleBuilderFactory; import com.intellij.execution.ui.ConsoleView; +import com.intellij.openapi.actionSystem.ActionGroup; +import com.intellij.openapi.actionSystem.ActionManager; +import com.intellij.openapi.actionSystem.ActionPlaces; +import com.intellij.openapi.actionSystem.ActionToolbar; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.ui.SimpleToolWindowPanel; +import com.intellij.openapi.util.Disposer; import com.intellij.openapi.wm.ToolWindow; import com.intellij.openapi.wm.ToolWindowAnchor; import com.intellij.openapi.wm.ToolWindowManager; +import com.intellij.ui.content.Content; import com.intellij.ui.content.ContentFactory; import org.jetbrains.annotations.NotNull; @@ -29,9 +36,21 @@ public final class ConsoleManager { ApplicationManager.getApplication().invokeLater(new Runnable() { @Override public void run() { - ToolWindow toolWindow = ToolWindowManager.getInstance(netService.project).registerToolWindow(netService.getConsoleToolWindowId(), false, ToolWindowAnchor.BOTTOM, netService.project, true); + ActionGroup actionGroup = netService.getConsoleToolWindowActions(); + ActionToolbar toolbar = ActionManager.getInstance().createActionToolbar(ActionPlaces.UNKNOWN, actionGroup, false); + + SimpleToolWindowPanel toolWindowPanel = new SimpleToolWindowPanel(false, true); + toolWindowPanel.setContent(console.getComponent()); + toolWindowPanel.setToolbar(toolbar.getComponent()); + + ToolWindow toolWindow = ToolWindowManager.getInstance(netService.project) + .registerToolWindow(netService.getConsoleToolWindowId(), false, ToolWindowAnchor.BOTTOM, netService.project, true); toolWindow.setIcon(netService.getConsoleToolWindowIcon()); - toolWindow.getContentManager().addContent(ContentFactory.SERVICE.getInstance().createContent(console.getComponent(), "", false)); + + Content content = ContentFactory.SERVICE.getInstance().createContent(toolWindowPanel, "", false); + Disposer.register(content, console); + + toolWindow.getContentManager().addContent(content); } }, netService.project.getDisposed()); } diff --git a/xml/impl/src/org/jetbrains/builtInWebServer/NetService.java b/xml/impl/src/org/jetbrains/builtInWebServer/NetService.java index a218d2af218a..fcbbd8045125 100644 --- a/xml/impl/src/org/jetbrains/builtInWebServer/NetService.java +++ b/xml/impl/src/org/jetbrains/builtInWebServer/NetService.java @@ -8,6 +8,8 @@ import com.intellij.execution.process.ProcessAdapter; import com.intellij.execution.process.ProcessEvent; import com.intellij.execution.ui.ConsoleViewContentType; import com.intellij.openapi.Disposable; +import com.intellij.openapi.actionSystem.ActionGroup; +import com.intellij.openapi.actionSystem.DefaultActionGroup; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; @@ -119,7 +121,10 @@ public abstract class NetService implements Disposable { @Nullable protected abstract OSProcessHandler createProcessHandler(@NotNull Project project, int port) throws ExecutionException; - protected void connectToProcess(@NotNull AsyncResult asyncResult, int port, @NotNull OSProcessHandler processHandler, @NotNull Consumer errorOutputConsumer) { + protected void connectToProcess(@NotNull AsyncResult asyncResult, + int port, + @NotNull OSProcessHandler processHandler, + @NotNull Consumer errorOutputConsumer) { asyncResult.setDone(processHandler); } @@ -139,6 +144,11 @@ public abstract class NetService implements Disposable { @NotNull protected abstract Icon getConsoleToolWindowIcon(); + @NotNull + public ActionGroup getConsoleToolWindowActions() { + return new DefaultActionGroup(); + } + private final class MyProcessAdapter extends ProcessAdapter implements Consumer { @Override public void onTextAvailable(ProcessEvent event, Key outputType) {