mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -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<JavaRunConfigurationModule> implements
|
||||
RunConfigurationWithSuppressedDefaultRunAction {
|
||||
public class RemoteConfiguration extends ModuleBasedConfiguration<JavaRunConfigurationModule>
|
||||
implements RunConfigurationWithSuppressedDefaultRunAction, RemoteRunProfile {
|
||||
|
||||
@Override
|
||||
public void writeExternal(final Element element) throws WriteExternalException {
|
||||
|
||||
+4
-4
@@ -65,9 +65,9 @@ public class InferredAnnotationsManagerImpl extends InferredAnnotationsManager {
|
||||
return null;
|
||||
}
|
||||
|
||||
private PsiAnnotation getHardcodedContractAnnotation(PsiMethod listOwner) {
|
||||
List<MethodContract> contracts = HardcodedContracts.getHardcodedContracts(listOwner, null);
|
||||
return contracts.isEmpty() ? null : createContractAnnotation(contracts, true);
|
||||
private PsiAnnotation getHardcodedContractAnnotation(PsiMethod method) {
|
||||
List<MethodContract> 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<MethodContract> 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()) {
|
||||
|
||||
+10
-1
@@ -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<MethodContract> 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 {
|
||||
|
||||
+1
-1
@@ -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]);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
class A {
|
||||
private void foo(boolean b) {
|
||||
int x;
|
||||
if (b) {
|
||||
System.out.println(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
class A {
|
||||
private void foo(boolean b) {
|
||||
int x;
|
||||
if (b) {
|
||||
System.out.println(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
class A {
|
||||
private void foo(boolean b) {
|
||||
int x;
|
||||
if (b) {
|
||||
System.out.println(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
class A {
|
||||
private void foo(boolean b) {
|
||||
int x;
|
||||
if (b) {
|
||||
System.out.println(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
class A {
|
||||
private void foo(boolean b) {
|
||||
int x;
|
||||
if (b) {
|
||||
System.out.println(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
class A {
|
||||
private void foo(boolean b) {
|
||||
int x;
|
||||
if (b) {
|
||||
System.out.println(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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}
|
||||
}
|
||||
}
|
||||
|
||||
+40
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -139,7 +139,7 @@ public class CodeStyleSettingsManager implements PersistentStateComponent<Elemen
|
||||
if (documentManager != null) {
|
||||
PsiFile file = documentManager.getPsiFile(document);
|
||||
if (file != null) {
|
||||
CommonCodeStyleSettings.IndentOptions indentOptions = getSettings(project).getIndentOptionsByFile(file, true);
|
||||
CommonCodeStyleSettings.IndentOptions indentOptions = getSettings(project).getIndentOptionsByFile(file, null, true);
|
||||
indentOptions.associateWithDocument(document);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,4 +33,12 @@ public abstract class FileIndentOptionsProvider {
|
||||
*/
|
||||
@Nullable
|
||||
public abstract CommonCodeStyleSettings.IndentOptions getIndentOptions(@NotNull PsiFile file);
|
||||
|
||||
/**
|
||||
* Tells if the provider can be used when a complete file is reformatted.
|
||||
* @return True by default
|
||||
*/
|
||||
public boolean useOnFullReformat() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
+8
-1
@@ -22,6 +22,7 @@ import com.intellij.icons.AllIcons;
|
||||
import com.intellij.lang.annotation.HighlightSeverity;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.DefaultActionGroup;
|
||||
import com.intellij.openapi.actionSystem.Toggleable;
|
||||
import com.intellij.openapi.actionSystem.ex.CheckboxAction;
|
||||
import com.intellij.profile.codeInspection.SeverityProvider;
|
||||
import com.intellij.profile.codeInspection.ui.LevelChooserAction;
|
||||
@@ -33,7 +34,7 @@ import java.util.SortedSet;
|
||||
/**
|
||||
* @author Dmitry Batkovich
|
||||
*/
|
||||
public class InspectionFilterAction extends DefaultActionGroup {
|
||||
public class InspectionFilterAction extends DefaultActionGroup implements Toggleable {
|
||||
|
||||
private final SeverityRegistrar mySeverityRegistrar;
|
||||
private final InspectionsFilter myInspectionsFilter;
|
||||
@@ -46,6 +47,12 @@ public class InspectionFilterAction extends DefaultActionGroup {
|
||||
tune();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(AnActionEvent e) {
|
||||
super.update(e);
|
||||
e.getPresentation().putClientProperty(Toggleable.SELECTED_PROPERTY, !myInspectionsFilter.isEmptyFilter());
|
||||
}
|
||||
|
||||
private void tune() {
|
||||
addAction(new ShowEnabledOrDisabledInspectionsAction(null));
|
||||
addAction(new ShowEnabledOrDisabledInspectionsAction(true));
|
||||
|
||||
+4
-4
@@ -84,14 +84,14 @@ public class InspectionsConfigTreeTable extends TreeTable {
|
||||
final int row = rowAtPoint(point);
|
||||
final Object maybeIcon = getModel().getValueAt(row, column);
|
||||
if (maybeIcon instanceof MultiScopeSeverityIcon) {
|
||||
final LinkedHashMap<String, HighlightSeverity> scopeToAverageSeverityMap =
|
||||
final LinkedHashMap<String, HighlightDisplayLevel> 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);
|
||||
|
||||
+18
-7
@@ -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<String, HighlightSeverity> myScopeToAverageSeverityMap;
|
||||
private final LinkedHashMap<String, HighlightDisplayLevel> myScopeToAverageSeverityMap;
|
||||
|
||||
public MultiScopeSeverityIcon(final Map<String, HighlightSeverity> scopeToAverageSeverityMap,
|
||||
final String defaultScopeName,
|
||||
final InspectionProfileImpl inspectionProfile) {
|
||||
final List<String> sortedScopeNames = new ArrayList<String>(scopeToAverageSeverityMap.keySet());
|
||||
myScopeToAverageSeverityMap = new LinkedHashMap<String, HighlightSeverity>();
|
||||
myScopeToAverageSeverityMap = new LinkedHashMap<String, HighlightDisplayLevel>();
|
||||
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<String, HighlightSeverity> getScopeToAverageSeverityMap() {
|
||||
public LinkedHashMap<String, HighlightDisplayLevel> getScopeToAverageSeverityMap() {
|
||||
return myScopeToAverageSeverityMap;
|
||||
}
|
||||
|
||||
@@ -60,10 +71,10 @@ public class MultiScopeSeverityIcon implements Icon {
|
||||
|
||||
final int partWidth = iconWidth / myScopeToAverageSeverityMap.size();
|
||||
|
||||
final Collection<HighlightSeverity> values = myScopeToAverageSeverityMap.values();
|
||||
final Collection<HighlightDisplayLevel> 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;
|
||||
|
||||
+7
-8
@@ -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<String, HighlightSeverity> scopeToAverageSeverityMap) {
|
||||
public ScopesAndSeveritiesHintTable(final LinkedHashMap<String, HighlightDisplayLevel> 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<String, HighlightSeverity> myScopeToAverageSeverityMap;
|
||||
private final LinkedHashMap<String, HighlightDisplayLevel> myScopeToAverageSeverityMap;
|
||||
private final List<String> myScopes;
|
||||
|
||||
public MyModel(final LinkedHashMap<String, HighlightSeverity> scopeToAverageSeverityMap) {
|
||||
public MyModel(final LinkedHashMap<String, HighlightDisplayLevel> scopeToAverageSeverityMap) {
|
||||
myScopeToAverageSeverityMap = scopeToAverageSeverityMap;
|
||||
myScopes = new ArrayList<String>(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();
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -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);
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -34,7 +34,7 @@ public class OptionsBundle {
|
||||
}
|
||||
|
||||
private static Reference<ResourceBundle> ourBundle;
|
||||
@NonNls protected static final String PATH_TO_BUNDLE = "messages.OptionsBundle";
|
||||
@NonNls public static final String PATH_TO_BUNDLE = "messages.OptionsBundle";
|
||||
|
||||
private OptionsBundle() {
|
||||
}
|
||||
|
||||
@@ -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<HttpConfigurab
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public RequestConfig.Builder setProxy(@NotNull RequestConfig.Builder builder) {
|
||||
return setProxy(builder, USE_HTTP_PROXY);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public CredentialsProvider setProxyCredentials(@NotNull CredentialsProvider provider) {
|
||||
return setProxyCredentials(provider, USE_HTTP_PROXY);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public RequestConfig.Builder setProxy(@NotNull RequestConfig.Builder builder, boolean useProxy) {
|
||||
if (useProxy) {
|
||||
builder.setProxy(new HttpHost(PROXY_HOST, PROXY_PORT));
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public CredentialsProvider setProxyCredentials(@NotNull CredentialsProvider provider, boolean useProxy) {
|
||||
if (useProxy && PROXY_AUTHENTICATION) {
|
||||
provider.setCredentials(new AuthScope(PROXY_HOST, PROXY_PORT), new UsernamePasswordCredentials(PROXY_LOGIN, getPlainProxyPassword()));
|
||||
}
|
||||
|
||||
return provider;
|
||||
}
|
||||
|
||||
public static List<KeyValue<String, String>> getJvmPropertiesList(final boolean withAutodetection, @Nullable final URI uri) {
|
||||
final HttpConfigurable me = getInstance();
|
||||
if (! me.USE_HTTP_PROXY && ! me.USE_PROXY_PAC) {
|
||||
|
||||
@@ -168,7 +168,7 @@ public class CertificateManager implements PersistentStateComponent<CertificateM
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static SSLContext getSystemSslContext() {
|
||||
public static SSLContext getSystemSslContext() {
|
||||
// NOTE: SSLContext.getDefault() should not be called because it automatically creates
|
||||
// default context which can't be initialized twice
|
||||
try {
|
||||
|
||||
@@ -95,6 +95,11 @@ public class ConfirmingTrustManager extends ClientOnlyTrustManager {
|
||||
|
||||
@Override
|
||||
public void checkServerTrusted(final X509Certificate[] certificates, String s) throws CertificateException {
|
||||
checkServerTrusted(certificates, s, true, true);
|
||||
}
|
||||
|
||||
public void checkServerTrusted(final X509Certificate[] certificates, String s, boolean addToKeyStore, boolean askUser)
|
||||
throws CertificateException {
|
||||
try {
|
||||
mySystemManager.checkServerTrusted(certificates, s);
|
||||
}
|
||||
@@ -105,7 +110,7 @@ public class ConfirmingTrustManager extends ClientOnlyTrustManager {
|
||||
myCustomManager.checkServerTrusted(certificates, s);
|
||||
}
|
||||
catch (CertificateException e2) {
|
||||
if (myCustomManager.isBroken() || !confirmAndUpdate(certificates)) {
|
||||
if (myCustomManager.isBroken() || !confirmAndUpdate(certificates, addToKeyStore, askUser)) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
@@ -113,7 +118,7 @@ public class ConfirmingTrustManager extends ClientOnlyTrustManager {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean confirmAndUpdate(final X509Certificate[] chain) {
|
||||
private boolean confirmAndUpdate(final X509Certificate[] chain, boolean addToKeyStore, boolean askUser) {
|
||||
Application app = ApplicationManager.getApplication();
|
||||
final X509Certificate endPoint = chain[0];
|
||||
// IDEA-123467 and IDEA-123335 workaround
|
||||
@@ -125,10 +130,12 @@ public class ConfirmingTrustManager extends ClientOnlyTrustManager {
|
||||
CertificateManager.Config config = CertificateManager.getInstance().getState();
|
||||
if (app.isUnitTestMode() || app.isHeadlessEnvironment() || config.ACCEPT_AUTOMATICALLY) {
|
||||
LOG.debug("Certificate will be accepted automatically");
|
||||
myCustomManager.addCertificate(endPoint);
|
||||
if (addToKeyStore) {
|
||||
myCustomManager.addCertificate(endPoint);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
boolean accepted = CertificateManager.showAcceptDialog(new Callable<DialogWrapper>() {
|
||||
boolean accepted = askUser && CertificateManager.showAcceptDialog(new Callable<DialogWrapper>() {
|
||||
@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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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<File, ExportableComponent> getExportableComponentsMap(boolean onlyExisting) {
|
||||
public static MultiMap<File, ExportableComponent> getExportableComponentsMap(final boolean onlyExisting) {
|
||||
ExportableApplicationComponent[] components1 = ApplicationManager.getApplication().getComponents(ExportableApplicationComponent.class);
|
||||
List<ExportableComponent> components2 = ServiceBean.loadServicesFromBeans(ExportableComponent.EXTENSION_POINT, ExportableComponent.class);
|
||||
MultiMap<File, ExportableComponent> result = MultiMap.createSet();
|
||||
final MultiMap<File, ExportableComponent> 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<Class<?>> 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<Class<?>, 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-17
@@ -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<Element> {
|
||||
public class AbbreviationManagerImpl extends AbbreviationManager implements PersistentStateComponent<Element> {
|
||||
private final Map<String, List<String>> myAbbreviation2ActionId = new THashMap<String, List<String>>();
|
||||
private final Map<String, LinkedHashSet<String>> myActionId2Abbreviations = new THashMap<String, LinkedHashSet<String>>();
|
||||
private final Map<String, LinkedHashSet<String>> myPluginsActionId2Abbreviations = new THashMap<String, LinkedHashSet<String>>();
|
||||
@@ -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<String> getAbbreviations() {
|
||||
final Set<String> result = new HashSet<String>();
|
||||
|
||||
+14
-8
@@ -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<ServiceDescriptor> APP_SERVICES = new ExtensionPointName<ServiceDescriptor>("com.intellij.applicationService");
|
||||
@@ -83,31 +86,34 @@ public class ServiceManagerImpl implements BaseComponent {
|
||||
return Arrays.asList(extensions);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static List<Class<?>> getAllImplementationClasses(@NotNull ComponentManager componentManager) {
|
||||
public static void processAllImplementationClasses(@NotNull ComponentManager componentManager, @NotNull PairProcessor<Class<?>, PluginDescriptor> processor) {
|
||||
Collection adapters = componentManager.getPicoContainer().getComponentAdapters();
|
||||
if (adapters.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
return;
|
||||
}
|
||||
|
||||
List<Class<?>> classes = new ArrayList<Class<?>>(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
|
||||
|
||||
+1
-16
@@ -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<EditorSettingsExternalizable.OptionSet>, ExportableComponent {
|
||||
public class EditorSettingsExternalizable implements PersistentStateComponent<EditorSettingsExternalizable.OptionSet> {
|
||||
//Q: make it interface?
|
||||
public static final class OptionSet {
|
||||
public String LINE_SEPARATOR;
|
||||
@@ -389,18 +386,6 @@ public class EditorSettingsExternalizable implements PersistentStateComponent<Ed
|
||||
myOptions.REFRAIN_FROM_SCROLLING = b;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public File[] getExportFiles() {
|
||||
return new File[]{PathManager.getOptionsFile("editor")};
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getPresentableName() {
|
||||
return OptionsBundle.message("options.editor.settings.presentable.name");
|
||||
}
|
||||
|
||||
public boolean isWhitespacesShown() {
|
||||
return myOptions.IS_WHITESPACES_SHOWN;
|
||||
}
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.openapi.fileEditor.impl;
|
||||
|
||||
import com.intellij.openapi.util.Key;
|
||||
|
||||
/** @deprecated use {@link com.intellij.openapi.editor.impl.TrailingSpacesStripper} (to be removed in IDEA 15) */
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
public class TrailingSpacesStripper {
|
||||
|
||||
public static final Key<String> OVERRIDE_STRIP_TRAILING_SPACES_KEY =
|
||||
com.intellij.openapi.editor.impl.TrailingSpacesStripper.OVERRIDE_STRIP_TRAILING_SPACES_KEY;
|
||||
|
||||
public static final Key<Boolean> OVERRIDE_ENSURE_NEWLINE_KEY =
|
||||
com.intellij.openapi.editor.impl.TrailingSpacesStripper.OVERRIDE_ENSURE_NEWLINE_KEY;
|
||||
|
||||
}
|
||||
@@ -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
|
||||
options.general.attribute.descriptor.live.template=Live Template
|
||||
|
||||
exportable.EditorSettings.presentable.name=Editor
|
||||
exportable.AbbreviationManager.presentable.name=Actions
|
||||
@@ -245,11 +245,8 @@
|
||||
|
||||
<applicationService serviceInterface="com.intellij.openapi.actionSystem.AbbreviationManager"
|
||||
serviceImplementation="com.intellij.openapi.actionSystem.impl.AbbreviationManagerImpl"/>
|
||||
<exportable serviceInterface="com.intellij.openapi.actionSystem.AbbreviationManager"/>
|
||||
|
||||
<applicationService serviceInterface="com.intellij.openapi.editor.ex.EditorSettingsExternalizable"
|
||||
serviceImplementation="com.intellij.openapi.editor.ex.EditorSettingsExternalizable"/>
|
||||
<exportable serviceInterface="com.intellij.openapi.editor.ex.EditorSettingsExternalizable"/>
|
||||
<applicationService serviceImplementation="com.intellij.openapi.editor.ex.EditorSettingsExternalizable"/>
|
||||
|
||||
<scopeParserExtension implementation="com.intellij.psi.search.scope.packageSet.FilePackageSetParserExtension"/>
|
||||
<applicationService serviceInterface="com.intellij.openapi.ui.popup.StackingPopupDispatcher" serviceImplementation="com.intellij.ui.popup.StackingPopupDispatcherImpl"/>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -91,6 +91,16 @@
|
||||
<action id="ExpandAllRegions">
|
||||
<keyboard-shortcut first-keystroke="meta MULTIPLY" />
|
||||
</action>
|
||||
<action id="ExpandAllToLevel1"/>
|
||||
<action id="ExpandAllToLevel2"/>
|
||||
<action id="ExpandAllToLevel3"/>
|
||||
<action id="ExpandAllToLevel4"/>
|
||||
<action id="ExpandAllToLevel5"/>
|
||||
<action id="ExpandToLevel1"/>
|
||||
<action id="ExpandToLevel2"/>
|
||||
<action id="ExpandToLevel3"/>
|
||||
<action id="ExpandToLevel4"/>
|
||||
<action id="ExpandToLevel5"/>
|
||||
<action id="ExternalJavaDoc">
|
||||
<keyboard-shortcut first-keystroke="shift F2" />
|
||||
</action>
|
||||
|
||||
@@ -555,5 +555,25 @@
|
||||
<action id="NewScratchFile">
|
||||
<keyboard-shortcut first-keystroke="meta shift N"/>
|
||||
</action>
|
||||
<action id="ExpandAllToLevel1">
|
||||
<keyboard-shortcut first-keystroke="meta alt MULTIPLY" second-keystroke="1"/>
|
||||
<keyboard-shortcut first-keystroke="meta alt MULTIPLY" second-keystroke="NUMPAD1"/>
|
||||
</action>
|
||||
<action id="ExpandAllToLevel2">
|
||||
<keyboard-shortcut first-keystroke="meta alt MULTIPLY" second-keystroke="2"/>
|
||||
<keyboard-shortcut first-keystroke="meta alt MULTIPLY" second-keystroke="NUMPAD2"/>
|
||||
</action>
|
||||
<action id="ExpandAllToLevel3">
|
||||
<keyboard-shortcut first-keystroke="meta alt MULTIPLY" second-keystroke="3"/>
|
||||
<keyboard-shortcut first-keystroke="meta alt MULTIPLY" second-keystroke="NUMPAD3"/>
|
||||
</action>
|
||||
<action id="ExpandAllToLevel4">
|
||||
<keyboard-shortcut first-keystroke="meta alt MULTIPLY" second-keystroke="4"/>
|
||||
<keyboard-shortcut first-keystroke="meta alt MULTIPLY" second-keystroke="NUMPAD4"/>
|
||||
</action>
|
||||
<action id="ExpandAllToLevel5">
|
||||
<keyboard-shortcut first-keystroke="meta alt MULTIPLY" second-keystroke="5"/>
|
||||
<keyboard-shortcut first-keystroke="meta alt MULTIPLY" second-keystroke="NUMPAD5"/>
|
||||
</action>
|
||||
</keymap>
|
||||
</component>
|
||||
|
||||
@@ -353,5 +353,25 @@
|
||||
<action id="NewScratchFile">
|
||||
<keyboard-shortcut first-keystroke="control shift N"/>
|
||||
</action>
|
||||
<action id="ExpandAllToLevel1">
|
||||
<keyboard-shortcut first-keystroke="meta alt MULTIPLY" second-keystroke="1"/>
|
||||
<keyboard-shortcut first-keystroke="meta alt MULTIPLY" second-keystroke="NUMPAD1"/>
|
||||
</action>
|
||||
<action id="ExpandAllToLevel2">
|
||||
<keyboard-shortcut first-keystroke="meta alt MULTIPLY" second-keystroke="2"/>
|
||||
<keyboard-shortcut first-keystroke="meta alt MULTIPLY" second-keystroke="NUMPAD2"/>
|
||||
</action>
|
||||
<action id="ExpandAllToLevel3">
|
||||
<keyboard-shortcut first-keystroke="meta alt MULTIPLY" second-keystroke="3"/>
|
||||
<keyboard-shortcut first-keystroke="meta alt MULTIPLY" second-keystroke="NUMPAD3"/>
|
||||
</action>
|
||||
<action id="ExpandAllToLevel4">
|
||||
<keyboard-shortcut first-keystroke="meta alt MULTIPLY" second-keystroke="4"/>
|
||||
<keyboard-shortcut first-keystroke="meta alt MULTIPLY" second-keystroke="NUMPAD4"/>
|
||||
</action>
|
||||
<action id="ExpandAllToLevel5">
|
||||
<keyboard-shortcut first-keystroke="meta alt MULTIPLY" second-keystroke="5"/>
|
||||
<keyboard-shortcut first-keystroke="meta alt MULTIPLY" second-keystroke="NUMPAD5"/>
|
||||
</action>
|
||||
</keymap>
|
||||
</component>
|
||||
|
||||
+1
@@ -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);
|
||||
}
|
||||
|
||||
+16
-13
@@ -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() {
|
||||
|
||||
@@ -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<? extends SMTestProxy> getChildren() {
|
||||
ApplicationManager.getApplication().assertIsDispatchThread();
|
||||
return myChildren != null ? myChildren : Collections.<SMTestProxy>emptyList();
|
||||
}
|
||||
|
||||
|
||||
@@ -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"},
|
||||
|
||||
+2
-10
@@ -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() {
|
||||
|
||||
@@ -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)
|
||||
editor.disable.rtl.description=Disables RTL support in editor (which is broken now anyway)
|
||||
|
||||
@@ -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<E> extends AbstractList<E> {
|
||||
private static final FList<?> EMPTY_LIST = new FList();
|
||||
private E myHead;
|
||||
private FList<E> myTail;
|
||||
private int mySize;
|
||||
@SuppressWarnings("unchecked") private static final FList<?> EMPTY_LIST = new FList(null, null, 0);
|
||||
private final E myHead;
|
||||
private final FList<E> myTail;
|
||||
private final int mySize;
|
||||
|
||||
private FList() {
|
||||
}
|
||||
|
||||
private FList(E head, FList<E> tail) {
|
||||
private FList(E head, FList<E> tail, int size) {
|
||||
myHead = head;
|
||||
myTail = tail;
|
||||
mySize = tail.size()+1;
|
||||
mySize = size;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -58,7 +58,7 @@ public class FList<E> extends AbstractList<E> {
|
||||
}
|
||||
|
||||
public FList<E> prepend(E elem) {
|
||||
return new FList<E>(elem, this);
|
||||
return new FList<E>(elem, this, mySize + 1);
|
||||
}
|
||||
|
||||
public FList<E> without(E elem) {
|
||||
@@ -120,7 +120,37 @@ public class FList<E> extends AbstractList<E> {
|
||||
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 <E> FList<E> emptyList() {
|
||||
//noinspection unchecked
|
||||
return (FList<E>)EMPTY_LIST;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
+2
-1
@@ -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);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+12
-1
@@ -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<ValueContainer extends XValueContainer
|
||||
myValueChildren.add(node);
|
||||
newChildren.add(node);
|
||||
|
||||
if (Registry.is("ide.debugger.inline") && "this".equals(node.getName())) { //todo[kb]: try to generify this dirty hack
|
||||
if (Registry.is("ide.debugger.inline") && "this".equals(node.getName()) && !isRemoteConfiguration(myTree)) { //todo[kb]: try to generify this dirty hack
|
||||
//initialize "this" fields to display in inline view
|
||||
node.getChildren();
|
||||
}
|
||||
@@ -113,6 +118,12 @@ public abstract class XValueContainerNode<ValueContainer extends XValueContainer
|
||||
});
|
||||
}
|
||||
|
||||
private static boolean isRemoteConfiguration(XDebuggerTree tree) {
|
||||
DataContext context = DataManager.getInstance().getDataContext(tree);
|
||||
ExecutionEnvironment env = LangDataKeys.EXECUTION_ENVIRONMENT.getData(context);
|
||||
return env != null && env.getRunProfile() instanceof RemoteRunProfile;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private List<XValueGroupNodeImpl> createGroupNodes(List<XValueGroup> groups,
|
||||
@Nullable List<XValueGroupNodeImpl> prevNodes,
|
||||
|
||||
+7
-6
@@ -149,13 +149,14 @@ public class XValueNodeImpl extends XValueContainerNode<XValue> implements XValu
|
||||
if (doc == null) return;
|
||||
int line = sourcePosition.getLine();
|
||||
Pair<VirtualFile, Integer> key = Pair.create(file, line);
|
||||
Set<XValueNodeImpl> presentations = map.get(key);
|
||||
if (presentations == null) {
|
||||
presentations = new LinkedHashSet<XValueNodeImpl>();
|
||||
map.put(key, presentations);
|
||||
timestamps.put(file, doc.getModificationStamp());
|
||||
}
|
||||
Set<XValueNodeImpl> presentations = new LinkedHashSet<XValueNodeImpl>();
|
||||
Set<XValueNodeImpl> old = map.get(key);
|
||||
map.put(key, presentations);
|
||||
timestamps.put(file, doc.getModificationStamp());
|
||||
presentations.add(XValueNodeImpl.this);
|
||||
if (old != null) {
|
||||
presentations.addAll(old);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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<ProgressIndicator, GithubRepo, IOException>() {
|
||||
@NotNull
|
||||
@Override
|
||||
public GithubRepo convert(ProgressIndicator indicator) throws IOException {
|
||||
return GithubUtil
|
||||
.runTask(project, authHolder, indicator, new ThrowableConvertor<GithubConnection, GithubRepo, IOException>() {
|
||||
@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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<String> 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<String> getSupportedSslProtocols() {
|
||||
List<String> 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() &&
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -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) {
|
||||
|
||||
+24
-4
@@ -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);
|
||||
|
||||
|
||||
+6
-1
@@ -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);
|
||||
}
|
||||
|
||||
@@ -91,6 +91,7 @@
|
||||
<SOURCES />
|
||||
</library>
|
||||
</orderEntry>
|
||||
<orderEntry type="library" name="http-client" level="project" />
|
||||
</component>
|
||||
</module>
|
||||
|
||||
|
||||
+4
-9
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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<OSProcessHandler> asyncResult, int port, @NotNull OSProcessHandler processHandler, @NotNull Consumer<String> errorOutputConsumer) {
|
||||
protected void connectToProcess(@NotNull AsyncResult<OSProcessHandler> asyncResult,
|
||||
int port,
|
||||
@NotNull OSProcessHandler processHandler,
|
||||
@NotNull Consumer<String> 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<String> {
|
||||
@Override
|
||||
public void onTextAvailable(ProcessEvent event, Key outputType) {
|
||||
|
||||
Reference in New Issue
Block a user