diff --git a/.idea/modules.xml b/.idea/modules.xml index 864fbcb945dc..5fbe4581a919 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -159,6 +159,7 @@ + diff --git a/build/scripts/dist.gant b/build/scripts/dist.gant index 6e2f28edb0b4..bda315e41d48 100644 --- a/build/scripts/dist.gant +++ b/build/scripts/dist.gant @@ -29,14 +29,14 @@ String out = new File(out).getCanonicalPath() target(compile: "Compile project") { def options = new BuildOptions() options.outputRootPath = out - new IdeaCommunityBuilder(home, out, binding, options).compileModules() + new IdeaCommunityBuilder(home, binding, options).compileModules() } target('default': 'The default target') { def options = new BuildOptions() options.outputRootPath = out options.buildNumber = null //we cannot provide consistent build number for IDEA Community if it's built separately so use *.SNAPSHOT number to avoid confusion - new IdeaCommunityBuilder(home, out, binding, options).buildDistributions() + new IdeaCommunityBuilder(home, binding, options).buildDistributions() } //todo[nik] do we really need this target? update.xml calls layout.gant directly @@ -44,5 +44,5 @@ target('build-dist-jars' : 'Target to build jars from locally compiled classes') def options = new BuildOptions() options.outputRootPath = out options.useCompiledClassesFromProjectOutput = true - new IdeaCommunityBuilder(home, out, binding, options).buildDistJars() + new IdeaCommunityBuilder(home, binding, options).buildDistJars() } diff --git a/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java b/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java index ebd9794df560..5c04960c2647 100644 --- a/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java +++ b/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java @@ -101,7 +101,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.io.BuiltInServer; import org.jetbrains.io.ChannelRegistrar; -import org.jetbrains.io.NettyKt; import org.jetbrains.jps.api.*; import org.jetbrains.jps.cmdline.BuildMain; import org.jetbrains.jps.cmdline.ClasspathBootstrap; @@ -110,8 +109,7 @@ import org.jetbrains.jps.model.java.JpsJavaSdkType; import org.jetbrains.jps.model.java.compiler.JavaCompilers; import org.jetbrains.jps.model.serialization.JpsGlobalLoader; -import javax.tools.JavaCompiler; -import javax.tools.ToolProvider; +import javax.tools.*; import java.awt.*; import java.io.File; import java.io.IOException; @@ -126,6 +124,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Collectors; import java.util.stream.Stream; +import static com.intellij.util.io.NettyKt.serverBootstrap; import static org.jetbrains.jps.api.CmdlineRemoteProto.Message.ControllerMessage.ParametersMessage.TargetTypeBuildScope; /** @@ -1316,7 +1315,7 @@ public class BuildManager implements Disposable { else { group = mainServer.getEventLoopGroup(); } - final ServerBootstrap bootstrap = NettyKt.serverBootstrap(group); + final ServerBootstrap bootstrap = serverBootstrap(group); bootstrap.childHandler(new ChannelInitializer() { @Override protected void initChannel(@NotNull Channel channel) throws Exception { diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java index 654642cc687e..8f391be57743 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java @@ -53,7 +53,7 @@ import com.intellij.openapi.application.ApplicationNamesInfo; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.project.Project; -import com.intellij.openapi.projectRoots.JavaSdk; +import com.intellij.openapi.projectRoots.JavaSdkType; import com.intellij.openapi.projectRoots.ProjectJdkTable; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.roots.ProjectRootManager; @@ -614,10 +614,12 @@ public abstract class DebugProcessImpl extends UserDataHolderBase implements Deb DebuggerBundle.message("warning.jdk140.unstable"), DebuggerBundle.message("title.jdk140.unstable"), Messages.getWarningIcon() )); } - Sdk projectSdk = ProjectRootManager.getInstance(myProject).getProjectSdk(); - if (getSession().getAlternativeJre() == null && !versionMatch(projectSdk, version)) { - for (Sdk sdk : ProjectJdkTable.getInstance().getAllJdks()) { - if (versionMatch(sdk, version)) { + if (getSession().getAlternativeJre() == null) { + Sdk projectSdk = ProjectRootManager.getInstance(myProject).getProjectSdk(); + if ((projectSdk == null || projectSdk.getSdkType() instanceof JavaSdkType) && !versionMatch(projectSdk, version)) { + Arrays.stream(ProjectJdkTable.getInstance().getAllJdks()) + .filter(sdk -> versionMatch(sdk, version)) + .findFirst().ifPresent(sdk -> { XDebugSessionImpl.NOTIFICATION_GROUP.createNotification( DebuggerBundle.message("message.remote.jre.version.mismatch", version, @@ -625,14 +627,13 @@ public abstract class DebugProcessImpl extends UserDataHolderBase implements Deb sdk.getName()) , MessageType.INFO).notify(myProject); getSession().setAlternativeJre(sdk); - break; - } + }); } } } private static boolean versionMatch(@Nullable Sdk sdk, String version) { - if (sdk != null && sdk.getSdkType() instanceof JavaSdk) { + if (sdk != null && sdk.getSdkType() instanceof JavaSdkType) { String versionString = sdk.getVersionString(); return versionString != null && versionString.contains(version); } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ByteArrayAsStringRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ByteArrayAsStringRenderer.java new file mode 100644 index 000000000000..89d5f0372412 --- /dev/null +++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ByteArrayAsStringRenderer.java @@ -0,0 +1,33 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://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.debugger.ui.tree.render; + +import com.intellij.debugger.engine.evaluation.CodeFragmentKind; +import com.intellij.debugger.engine.evaluation.TextWithImportsImpl; +import com.intellij.debugger.settings.NodeRendererSettings; + +/** + * @author egor + */ +public class ByteArrayAsStringRenderer extends CompoundReferenceRenderer { + public ByteArrayAsStringRenderer(final NodeRendererSettings rendererSettings) { + super(rendererSettings, "String", null, null); + setClassName("byte[]"); + LabelRenderer labelRenderer = new LabelRenderer(); + labelRenderer.setLabelExpression(new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, "new String(this)")); + setLabelRenderer(labelRenderer); + } +} diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/deprecation/DeprecationInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/deprecation/DeprecationInspection.java index 081053a6ed53..6c3a1a4600f1 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/deprecation/DeprecationInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/deprecation/DeprecationInspection.java @@ -104,11 +104,11 @@ public class DeprecationInspection extends BaseJavaBatchLocalInspectionTool { private final boolean myIgnoreImportStatements; private final boolean myIgnoreMethodsOfDeprecated; - public DeprecationElementVisitor(final ProblemsHolder holder, - boolean ignoreInsideDeprecated, - boolean ignoreAbstractDeprecatedOverrides, - boolean ignoreImportStatements, - boolean ignoreMethodsOfDeprecated) { + DeprecationElementVisitor(@NotNull ProblemsHolder holder, + boolean ignoreInsideDeprecated, + boolean ignoreAbstractDeprecatedOverrides, + boolean ignoreImportStatements, + boolean ignoreMethodsOfDeprecated) { myHolder = holder; myIgnoreInsideDeprecated = ignoreInsideDeprecated; myIgnoreAbstractDeprecatedOverrides = ignoreAbstractDeprecatedOverrides; @@ -254,13 +254,13 @@ public class DeprecationInspection extends BaseJavaBatchLocalInspectionTool { checkDeprecated(refElement, elementToHighlight, rangeInElement, false, false, true, holder); } - public static void checkDeprecated(PsiElement refElement, - PsiElement elementToHighlight, - @Nullable TextRange rangeInElement, - boolean ignoreInsideDeprecated, - boolean ignoreImportStatements, - boolean ignoreMethodsOfDeprecated, - ProblemsHolder holder) { + static void checkDeprecated(PsiElement refElement, + PsiElement elementToHighlight, + @Nullable TextRange rangeInElement, + boolean ignoreInsideDeprecated, + boolean ignoreImportStatements, + boolean ignoreMethodsOfDeprecated, + ProblemsHolder holder) { if (!(refElement instanceof PsiDocCommentOwner)) return; if (!((PsiDocCommentOwner)refElement).isDeprecated()) { if (!ignoreMethodsOfDeprecated) { diff --git a/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationInspection.java b/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationInspection.java index 0f564b79a8dd..658ba21f5290 100644 --- a/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationInspection.java @@ -28,6 +28,7 @@ import com.intellij.codeInspection.unusedSymbol.UnusedSymbolLocalInspectionBase; import com.intellij.openapi.ui.VerticalFlowLayout; import com.intellij.psi.*; import com.intellij.psi.controlFlow.DefUseUtil; +import com.intellij.ui.ScrollPaneFactory; import com.intellij.ui.TitledSeparator; import com.intellij.ui.components.JBLabel; import com.intellij.ui.components.JBRadioButton; @@ -123,8 +124,8 @@ public class UnusedDeclarationInspection extends UnusedDeclarationInspectionBase @Override public JComponent createOptionsPanel() { JTabbedPane tabs = new JBTabbedPane(SwingConstants.TOP); - tabs.add("Members to report", myLocalInspectionBase.createOptionsPanel()); - tabs.add("Entry points", new OptionsPanel()); + tabs.add("Members to report", ScrollPaneFactory.createScrollPane(myLocalInspectionBase.createOptionsPanel(), true)); + tabs.add("Entry points", ScrollPaneFactory.createScrollPane(new OptionsPanel(), true)); return tabs; } diff --git a/java/java-impl/src/com/intellij/codeInspection/intermediaryVariable/ReturnSeparatedFromComputationInspection.java b/java/java-impl/src/com/intellij/codeInspection/intermediaryVariable/ReturnSeparatedFromComputationInspection.java index af3d772815e4..e2e006aa72af 100644 --- a/java/java-impl/src/com/intellij/codeInspection/intermediaryVariable/ReturnSeparatedFromComputationInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/intermediaryVariable/ReturnSeparatedFromComputationInspection.java @@ -186,22 +186,20 @@ public class ReturnSeparatedFromComputationInspection extends BaseJavaBatchLocal } private static boolean isApplicable(@NotNull ControlFlow flow, @NotNull ReturnContext context) { - final int flowStart = flow.getStartOffset(context.returnScope); - final int flowEnd = flow.getEndOffset(context.returnScope); - if (flowStart < 0 || flowEnd < 0) return false; - - final int returnStartOffset = flow.getStartOffset(context.returnStatement); - final int returnEndOffset = flow.getEndOffset(context.returnStatement); - if (returnStartOffset < 0 || returnEndOffset < 0) return false; - if (hasChainedAssignmentsInScope(flow, context.returnedVariable, context.returnStatement)) { return false; } - - if (context.returnScope != context.variableScope && - ControlFlowUtil.hasObservableThrowExitPoints(flow, flowStart, flowEnd, - new PsiElement[]{context.refactoredStatement}, context.variableScope)) { - return false; + if (context.returnScope != context.variableScope) { + if (ControlFlowUtil.isVariableReadInFinally(flow, context.returnScope, context.variableScope, context.returnedVariable)) { + return false; + } + final int flowStart = flow.getStartOffset(context.returnScope); + final int flowEnd = flow.getEndOffset(context.returnScope); + if (flowStart < 0 || flowEnd < 0) return false; + if (ControlFlowUtil.hasObservableThrowExitPoints(flow, flowStart, flowEnd, + new PsiElement[]{context.refactoredStatement}, context.variableScope)) { + return false; + } } Mover mover = new Mover(flow, context.refactoredStatement, context.returnedVariable, context.returnType, true); @@ -383,8 +381,7 @@ public class ReturnSeparatedFromComputationInspection extends BaseJavaBatchLocal PsiJavaToken rBrace = codeBlock.getRBrace(); if (rBrace != null) { PsiStatement lastNonEmptyStatement = getPrevNonEmptyStatement(rBrace, removeCompletely); - if (lastNonEmptyStatement == null || - isIfBranch(codeBlock) && hasChainedAssignmentsInScope(flow, resultVariable, lastNonEmptyStatement)) { + if (lastNonEmptyStatement == null) { return false; } if (moveTo(lastNonEmptyStatement, returnAtTheEnd)) { @@ -508,11 +505,6 @@ public class ReturnSeparatedFromComputationInspection extends BaseJavaBatchLocal return ExpressionUtils.computeConstantExpression(condition) == Boolean.TRUE; } - private static boolean isIfBranch(@NotNull PsiCodeBlock codeBlock) { - final PsiElement parent = codeBlock.getParent(); - return parent instanceof PsiBlockStatement && parent.getParent() instanceof PsiIfStatement; - } - private Set getBreaks(@NotNull PsiStatement targetStatement) { if (breakStatements == null) { breakStatements = new THashMap<>(); diff --git a/java/java-psi-impl/src/com/intellij/psi/controlFlow/ControlFlowUtil.java b/java/java-psi-impl/src/com/intellij/psi/controlFlow/ControlFlowUtil.java index 032d2e143a28..4b08e3e094a6 100644 --- a/java/java-psi-impl/src/com/intellij/psi/controlFlow/ControlFlowUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/controlFlow/ControlFlowUtil.java @@ -258,6 +258,37 @@ public class ControlFlowUtil { return false; } + public static boolean isVariableReadInFinally(@NotNull ControlFlow flow, + @Nullable PsiElement startElement, + @NotNull PsiElement enclosingCodeFragment, + @NotNull PsiVariable variable) { + for (PsiElement element = startElement; element != null && element != enclosingCodeFragment; element = element.getParent()) { + if (element instanceof PsiCodeBlock) { + final PsiElement parent = element.getParent(); + if (parent instanceof PsiTryStatement) { + final PsiTryStatement tryStatement = (PsiTryStatement)parent; + if (tryStatement.getTryBlock() == element) { + final PsiCodeBlock finallyBlock = tryStatement.getFinallyBlock(); + if (finallyBlock != null) { + final List instructions = flow.getInstructions(); + final int startOffset = flow.getStartOffset(finallyBlock); + final int endOffset = flow.getEndOffset(finallyBlock); + LOG.assertTrue(startOffset >= 0, "flow start"); + LOG.assertTrue(endOffset <= instructions.size(), "flow end"); + for (int i = startOffset; i < endOffset; i++) { + final Instruction instruction = instructions.get(i); + if (instruction instanceof ReadVariableInstruction && ((ReadVariableInstruction)instruction).variable == variable) { + return true; + } + } + } + } + } + } + } + return false; + } + public static List getInputVariables(ControlFlow flow, int start, int end) { List usedVariables = getUsedVariables(flow, start, end); ArrayList array = new ArrayList(usedVariables.size()); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/returnSeparatedFromComputation/afterAssignmentChainUnderIf.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/returnSeparatedFromComputation/afterAssignmentChainUnderIf.java new file mode 100644 index 000000000000..2166acd42d90 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/returnSeparatedFromComputation/afterAssignmentChainUnderIf.java @@ -0,0 +1,15 @@ +// "Move 'return' closer to computation of the value of 'n'" "true" +class T { + int x; + int y; + + int f(int a) { + int n = -1; + if (a != 0) { + n = a; + n = 31 * x + n; + return 31 * y + n; + } + return n; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/returnSeparatedFromComputation/beforeAssignmentChainUnderIf.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/returnSeparatedFromComputation/beforeAssignmentChainUnderIf.java index c0ccfdbfa1c0..8ed6b4e96bc8 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/returnSeparatedFromComputation/beforeAssignmentChainUnderIf.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/returnSeparatedFromComputation/beforeAssignmentChainUnderIf.java @@ -1,15 +1,15 @@ -// "Move 'return' closer to computation of the value of 'n'" "false" +// "Move 'return' closer to computation of the value of 'n'" "true" class T { - int x; - int y; + int x; + int y; - int f(int a) { - int n = -1; - if (a != 0) { - n = a; - n = 31 * x + n; - n = 31 * y + n; + int f(int a) { + int n = -1; + if (a != 0) { + n = a; + n = 31 * x + n; + n = 31 * y + n; + } + return n; } - return n; - } } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/returnSeparatedFromComputation/beforeReadInFinally.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/returnSeparatedFromComputation/beforeReadInFinally.java new file mode 100644 index 000000000000..f77fe792c84d --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/returnSeparatedFromComputation/beforeReadInFinally.java @@ -0,0 +1,14 @@ +// "Move 'return' closer to computation of the value of 'n'" "false" +class T { + int f(boolean b) { + int n = -1; + try { + if (b) throw new RuntimeException(); + n = 1; + return n; + } + finally { + System.out.println(n); + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/returnSeparatedFromComputation8/afterIfInLambda.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/returnSeparatedFromComputation8/afterIfInLambda.java new file mode 100644 index 000000000000..a3000a616d11 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/returnSeparatedFromComputation8/afterIfInLambda.java @@ -0,0 +1,17 @@ +// "Move 'return' closer to computation of the value of 'n'" "true" +class T { + interface I { + int call(); + } + void f(boolean b) { + g(() -> { + int n = -1; + if (b) return 1; + return n; + }); + } + + void g(I i) { + i.call(); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/returnSeparatedFromComputation8/afterWhileInLambda.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/returnSeparatedFromComputation8/afterWhileInLambda.java new file mode 100644 index 000000000000..9de9ab16d54b --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/returnSeparatedFromComputation8/afterWhileInLambda.java @@ -0,0 +1,24 @@ +// "Move 'return' closer to computation of the value of 'n'" "true" +class T { + interface I { + int call(); + } + void f(boolean b) { + g(() -> { + int n = -1; + while (true) { + if (h()) { + return 1; + } + } + }); + } + + void g(I i) { + i.call(); + } + + boolean h() { + return true; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/returnSeparatedFromComputation8/beforeIfInLambda.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/returnSeparatedFromComputation8/beforeIfInLambda.java new file mode 100644 index 000000000000..e78ffa19f3a6 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/returnSeparatedFromComputation8/beforeIfInLambda.java @@ -0,0 +1,17 @@ +// "Move 'return' closer to computation of the value of 'n'" "true" +class T { + interface I { + int call(); + } + void f(boolean b) { + g(() -> { + int n = -1; + if (b) n = 1; + return n; + }); + } + + void g(I i) { + i.call(); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/returnSeparatedFromComputation8/beforeWhileInLambda.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/returnSeparatedFromComputation8/beforeWhileInLambda.java new file mode 100644 index 000000000000..279ff1b87762 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/returnSeparatedFromComputation8/beforeWhileInLambda.java @@ -0,0 +1,26 @@ +// "Move 'return' closer to computation of the value of 'n'" "true" +class T { + interface I { + int call(); + } + void f(boolean b) { + g(() -> { + int n = -1; + while (true) { + if (h()) { + n = 1; + break; + } + } + return n; + }); + } + + void g(I i) { + i.call(); + } + + boolean h() { + return true; + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/ReturnSeparatedFromComputationFix8Test.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/ReturnSeparatedFromComputationFix8Test.java new file mode 100644 index 000000000000..b18edfdc9043 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/ReturnSeparatedFromComputationFix8Test.java @@ -0,0 +1,47 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInsight.daemon.quickFix; + +import com.intellij.codeInspection.LocalInspectionTool; +import com.intellij.codeInspection.intermediaryVariable.ReturnSeparatedFromComputationInspection; +import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.testFramework.IdeaTestUtil; +import org.jetbrains.annotations.NotNull; + +/** + * @author Pavel.Dolgov + */ +public class ReturnSeparatedFromComputationFix8Test extends LightQuickFixParameterizedTestCase { + @NotNull + @Override + protected LocalInspectionTool[] configureLocalInspectionTools() { + return new LocalInspectionTool[]{new ReturnSeparatedFromComputationInspection()}; + } + + public void test() throws Exception { + doAllTests(); + } + + @Override + protected String getBasePath() { + return "/codeInsight/daemonCodeAnalyzer/quickFix/returnSeparatedFromComputation8"; + } + + @Override + protected Sdk getProjectJDK() { + return IdeaTestUtil.getMockJdk18(); + } +} diff --git a/platform/bootstrap/src/com/intellij/ide/actions/ImportSettingsFilenameFilter.java b/platform/bootstrap/src/com/intellij/ide/actions/ImportSettingsFilenameFilter.java index 0431bb02026c..7458c7f28f7c 100644 --- a/platform/bootstrap/src/com/intellij/ide/actions/ImportSettingsFilenameFilter.java +++ b/platform/bootstrap/src/com/intellij/ide/actions/ImportSettingsFilenameFilter.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,7 +17,6 @@ package com.intellij.ide.actions; import com.intellij.openapi.application.PathManager; import com.intellij.openapi.util.io.FileUtil; -import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import java.io.File; @@ -31,7 +30,7 @@ import java.util.Set; * @author mike */ public class ImportSettingsFilenameFilter implements FilenameFilter, Serializable { - @NonNls static final String SETTINGS_JAR_MARKER = "IntelliJ IDEA Global Settings"; + public static final String SETTINGS_JAR_MARKER = "IntelliJ IDEA Global Settings"; private final Set myRelativeNamesToExtract; diff --git a/platform/built-in-server/src/org/jetbrains/builtInWebServer/DefaultWebServerPathHandler.kt b/platform/built-in-server/src/org/jetbrains/builtInWebServer/DefaultWebServerPathHandler.kt index 591553e37413..1ff618f41732 100644 --- a/platform/built-in-server/src/org/jetbrains/builtInWebServer/DefaultWebServerPathHandler.kt +++ b/platform/built-in-server/src/org/jetbrains/builtInWebServer/DefaultWebServerPathHandler.kt @@ -25,13 +25,14 @@ import com.intellij.openapi.util.text.StringUtil import com.intellij.openapi.vfs.VFileProperty import com.intellij.openapi.vfs.VirtualFile import com.intellij.util.PathUtilRt -import com.intellij.util.io.isDirectory +import com.intellij.util.io.* import io.netty.channel.Channel import io.netty.channel.ChannelHandlerContext import io.netty.handler.codec.http.FullHttpRequest import io.netty.handler.codec.http.HttpRequest import io.netty.handler.codec.http.HttpResponseStatus -import org.jetbrains.io.* +import org.jetbrains.io.orInSafeMode +import org.jetbrains.io.send import java.nio.file.Path import java.nio.file.Paths import java.util.regex.Pattern diff --git a/platform/built-in-server/src/org/jetbrains/builtInWebServer/SingleConnectionNetService.kt b/platform/built-in-server/src/org/jetbrains/builtInWebServer/SingleConnectionNetService.kt index 44ad82e744a4..d058d23ab853 100644 --- a/platform/built-in-server/src/org/jetbrains/builtInWebServer/SingleConnectionNetService.kt +++ b/platform/built-in-server/src/org/jetbrains/builtInWebServer/SingleConnectionNetService.kt @@ -3,6 +3,10 @@ package org.jetbrains.builtInWebServer import com.intellij.execution.process.OSProcessHandler import com.intellij.openapi.project.Project import com.intellij.util.Consumer +import com.intellij.util.io.addChannelListener +import com.intellij.util.io.closeAndShutdownEventLoop +import com.intellij.util.io.connect +import com.intellij.util.io.shutdownIfOio import com.intellij.util.net.loopbackSocketAddress import io.netty.bootstrap.Bootstrap import io.netty.channel.Channel @@ -10,7 +14,7 @@ import org.jetbrains.concurrency.AsyncPromise import org.jetbrains.concurrency.Promise import org.jetbrains.concurrency.catchError import org.jetbrains.concurrency.resolvedPromise -import org.jetbrains.io.* +import org.jetbrains.io.oioClientBootstrap import java.util.concurrent.atomic.AtomicReference abstract class SingleConnectionNetService(project: Project) : NetService(project) { diff --git a/platform/built-in-server/src/org/jetbrains/builtInWebServer/WebServerPathHandler.kt b/platform/built-in-server/src/org/jetbrains/builtInWebServer/WebServerPathHandler.kt index 772c9c35a6a1..97189cb23630 100644 --- a/platform/built-in-server/src/org/jetbrains/builtInWebServer/WebServerPathHandler.kt +++ b/platform/built-in-server/src/org/jetbrains/builtInWebServer/WebServerPathHandler.kt @@ -18,13 +18,13 @@ package org.jetbrains.builtInWebServer import com.intellij.openapi.extensions.ExtensionPointName import com.intellij.openapi.project.Project import com.intellij.openapi.vfs.VfsUtil +import com.intellij.util.io.host +import com.intellij.util.io.uriScheme import io.netty.channel.Channel import io.netty.channel.ChannelHandlerContext import io.netty.handler.codec.http.* -import org.jetbrains.io.host import org.jetbrains.io.response import org.jetbrains.io.send -import org.jetbrains.io.uriScheme /** * By default [WebServerPathToFileManager] will be used to map request to file. diff --git a/platform/built-in-server/src/org/jetbrains/ide/RestService.java b/platform/built-in-server/src/org/jetbrains/ide/RestService.java index 1afdbc1bacd7..ba0ff07fe7af 100644 --- a/platform/built-in-server/src/org/jetbrains/ide/RestService.java +++ b/platform/built-in-server/src/org/jetbrains/ide/RestService.java @@ -41,6 +41,7 @@ import com.intellij.openapi.wm.IdeFrame; import com.intellij.util.ExceptionUtil; import com.intellij.util.ObjectUtils; import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.io.NettyKt; import com.intellij.util.net.NetUtils; import io.netty.buffer.ByteBufInputStream; import io.netty.buffer.Unpooled; @@ -50,7 +51,6 @@ import io.netty.handler.codec.http.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.builtInWebServer.BuiltInWebServerKt; -import org.jetbrains.io.NettyKt; import org.jetbrains.io.Responses; import javax.swing.*; diff --git a/platform/built-in-server/src/org/jetbrains/io/SubServer.java b/platform/built-in-server/src/org/jetbrains/io/SubServer.java index 5fdf36683de5..432082cfefc7 100644 --- a/platform/built-in-server/src/org/jetbrains/io/SubServer.java +++ b/platform/built-in-server/src/org/jetbrains/io/SubServer.java @@ -34,6 +34,8 @@ import org.jetbrains.ide.CustomPortServerManager; import java.net.InetSocketAddress; import java.util.Map; +import static com.intellij.util.io.NettyKt.serverBootstrap; + public final class SubServer implements CustomPortServerManager.CustomPortService, Disposable { private ChannelRegistrar channelRegistrar; @@ -57,7 +59,7 @@ public final class SubServer implements CustomPortServerManager.CustomPortServic channelRegistrar = new ChannelRegistrar(); } - ServerBootstrap bootstrap = NettyKt.serverBootstrap(server.getEventLoopGroup()); + ServerBootstrap bootstrap = serverBootstrap(server.getEventLoopGroup()); Map xmlRpcHandlers = user.createXmlRpcHandlers(); if (xmlRpcHandlers == null) { BuiltInServer.configureChildHandler(bootstrap, channelRegistrar, null); diff --git a/platform/built-in-server/src/org/jetbrains/io/fastCgi/FastCgiRequest.kt b/platform/built-in-server/src/org/jetbrains/io/fastCgi/FastCgiRequest.kt index 35161ea62ed6..1fe1f0f294f0 100644 --- a/platform/built-in-server/src/org/jetbrains/io/fastCgi/FastCgiRequest.kt +++ b/platform/built-in-server/src/org/jetbrains/io/fastCgi/FastCgiRequest.kt @@ -1,6 +1,7 @@ package org.jetbrains.io.fastCgi import com.intellij.openapi.util.io.FileUtil +import com.intellij.util.io.writeUtf8 import io.netty.buffer.ByteBuf import io.netty.buffer.ByteBufAllocator import io.netty.buffer.ByteBufUtil @@ -8,7 +9,6 @@ import io.netty.channel.Channel import io.netty.handler.codec.http.FullHttpRequest import org.jetbrains.builtInWebServer.PathInfo import org.jetbrains.io.serverHeaderValue -import org.jetbrains.io.writeUtf8 import java.net.InetSocketAddress import java.util.* diff --git a/platform/built-in-server/src/org/jetbrains/io/fastCgi/FastCgiService.kt b/platform/built-in-server/src/org/jetbrains/io/fastCgi/FastCgiService.kt index a295c1ca12fa..a8116ffa5a29 100644 --- a/platform/built-in-server/src/org/jetbrains/io/fastCgi/FastCgiService.kt +++ b/platform/built-in-server/src/org/jetbrains/io/fastCgi/FastCgiService.kt @@ -19,6 +19,8 @@ import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.project.Project import com.intellij.util.Consumer import com.intellij.util.containers.ContainerUtil +import com.intellij.util.io.addChannelListener +import com.intellij.util.io.handler import io.netty.bootstrap.Bootstrap import io.netty.buffer.ByteBuf import io.netty.channel.Channel diff --git a/platform/built-in-server/src/org/jetbrains/io/jsonRpc/JsonRpcServer.kt b/platform/built-in-server/src/org/jetbrains/io/jsonRpc/JsonRpcServer.kt index fd48276dbf1d..e59efb3bbe3d 100644 --- a/platform/built-in-server/src/org/jetbrains/io/jsonRpc/JsonRpcServer.kt +++ b/platform/built-in-server/src/org/jetbrains/io/jsonRpc/JsonRpcServer.kt @@ -15,14 +15,14 @@ import com.intellij.util.ArrayUtil import com.intellij.util.ArrayUtilRt import com.intellij.util.Consumer import com.intellij.util.SmartList +import com.intellij.util.io.releaseIfError +import com.intellij.util.io.writeUtf8 import gnu.trove.THashMap import gnu.trove.TIntArrayList import io.netty.buffer.* import org.jetbrains.concurrency.Promise import org.jetbrains.io.JsonReaderEx import org.jetbrains.io.JsonUtil -import org.jetbrains.io.releaseIfError -import org.jetbrains.io.writeUtf8 import java.io.IOException import java.lang.reflect.Method import java.util.concurrent.atomic.AtomicInteger @@ -40,7 +40,7 @@ private val INT_LIST_TYPE_ADAPTER_FACTORY = object : TypeAdapterFactory { if (typeAdapter == null) { typeAdapter = IntArrayListTypeAdapter() } - @Suppress("CAST_NEVER_SUCCEEDS") + @Suppress("UNCHECKED_CAST") return typeAdapter as TypeAdapter? } } diff --git a/platform/built-in-server/src/org/jetbrains/io/webSocket/MessageChannelHandler.java b/platform/built-in-server/src/org/jetbrains/io/webSocket/MessageChannelHandler.java index fe482bc618f1..dc691b1e019e 100644 --- a/platform/built-in-server/src/org/jetbrains/io/webSocket/MessageChannelHandler.java +++ b/platform/built-in-server/src/org/jetbrains/io/webSocket/MessageChannelHandler.java @@ -6,12 +6,13 @@ import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame; import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; import org.jetbrains.annotations.NotNull; -import org.jetbrains.io.NettyKt; import org.jetbrains.io.jsonRpc.Client; import org.jetbrains.io.jsonRpc.ClientManager; import org.jetbrains.io.jsonRpc.ClientManagerKt; import org.jetbrains.io.jsonRpc.MessageServer; +import static com.intellij.util.io.NettyKt.readUtf8; + @ChannelHandler.Sharable final class MessageChannelHandler extends WebSocketProtocolHandler { private final ClientManager clientManager; @@ -43,7 +44,7 @@ final class MessageChannelHandler extends WebSocketProtocolHandler { WebSocketClient client = (WebSocketClient)channel.attr(ClientManagerKt.getCLIENT()).get(); CharSequence chars; try { - chars = NettyKt.readUtf8(message.content()); + chars = readUtf8(message.content()); } catch (Throwable e) { try { diff --git a/platform/built-in-server/testSrc/ChannelBufferToStringTest.kt b/platform/built-in-server/testSrc/com/intellij/util/io/ChannelBufferToStringTest.kt similarity index 92% rename from platform/built-in-server/testSrc/ChannelBufferToStringTest.kt rename to platform/built-in-server/testSrc/com/intellij/util/io/ChannelBufferToStringTest.kt index 6948eaab879e..4e5406cb7349 100644 --- a/platform/built-in-server/testSrc/ChannelBufferToStringTest.kt +++ b/platform/built-in-server/testSrc/com/intellij/util/io/ChannelBufferToStringTest.kt @@ -1,4 +1,4 @@ -package org.jetbrains.io +package com.intellij.util.io import io.netty.buffer.Unpooled import org.assertj.core.api.Assertions.assertThat diff --git a/platform/built-in-server/testSrc/IsLocalHostTest.kt b/platform/built-in-server/testSrc/com/intellij/util/io/IsLocalHostTest.kt similarity index 97% rename from platform/built-in-server/testSrc/IsLocalHostTest.kt rename to platform/built-in-server/testSrc/com/intellij/util/io/IsLocalHostTest.kt index 722138936003..bf6c2521df84 100644 --- a/platform/built-in-server/testSrc/IsLocalHostTest.kt +++ b/platform/built-in-server/testSrc/com/intellij/util/io/IsLocalHostTest.kt @@ -1,4 +1,4 @@ -package org.jetbrains.io +package com.intellij.util.io import org.assertj.core.api.Assertions.assertThat import org.junit.Test diff --git a/platform/built-in-server/testSrc/BinaryRequestHandlerTest.kt b/platform/built-in-server/testSrc/org/jetbrains/ide/BinaryRequestHandlerTest.kt similarity index 94% rename from platform/built-in-server/testSrc/BinaryRequestHandlerTest.kt rename to platform/built-in-server/testSrc/org/jetbrains/ide/BinaryRequestHandlerTest.kt index c077f10afa80..cd190b21b7c7 100644 --- a/platform/built-in-server/testSrc/BinaryRequestHandlerTest.kt +++ b/platform/built-in-server/testSrc/org/jetbrains/ide/BinaryRequestHandlerTest.kt @@ -2,6 +2,7 @@ package org.jetbrains.ide import com.intellij.testFramework.ProjectRule import com.intellij.util.concurrency.Semaphore +import com.intellij.util.io.handler import com.intellij.util.net.loopbackSocketAddress import io.netty.buffer.ByteBuf import io.netty.buffer.Unpooled @@ -11,7 +12,10 @@ import io.netty.util.CharsetUtil import junit.framework.TestCase import org.jetbrains.concurrency.AsyncPromise import org.jetbrains.concurrency.Promise -import org.jetbrains.io.* +import org.jetbrains.io.ChannelExceptionHandler +import org.jetbrains.io.Decoder +import org.jetbrains.io.MessageDecoder +import org.jetbrains.io.oioClientBootstrap import org.junit.ClassRule import org.junit.Test import java.util.* diff --git a/platform/built-in-server/testSrc/BuiltInServerTestCase.kt b/platform/built-in-server/testSrc/org/jetbrains/ide/BuiltInServerTestCase.kt similarity index 94% rename from platform/built-in-server/testSrc/BuiltInServerTestCase.kt rename to platform/built-in-server/testSrc/org/jetbrains/ide/BuiltInServerTestCase.kt index 1e84816f1801..af561527be10 100644 --- a/platform/built-in-server/testSrc/BuiltInServerTestCase.kt +++ b/platform/built-in-server/testSrc/org/jetbrains/ide/BuiltInServerTestCase.kt @@ -23,10 +23,10 @@ internal abstract class BuiltInServerTestCase { protected val manager = TestManager(projectRule, tempDirManager) private val ruleChain = RuleChain( - tempDirManager, - Timeout(60, TimeUnit.SECONDS), - manager, - DisposeModulesRule(projectRule)) + tempDirManager, + Timeout(60, TimeUnit.SECONDS), + manager, + DisposeModulesRule(projectRule)) @Rule fun getChain() = ruleChain protected open val urlPathPrefix = "" diff --git a/platform/built-in-server/testSrc/BuiltInWebServerTest.kt b/platform/built-in-server/testSrc/org/jetbrains/ide/BuiltInWebServerTest.kt similarity index 100% rename from platform/built-in-server/testSrc/BuiltInWebServerTest.kt rename to platform/built-in-server/testSrc/org/jetbrains/ide/BuiltInWebServerTest.kt diff --git a/platform/built-in-server/testSrc/RestApiTest.kt b/platform/built-in-server/testSrc/org/jetbrains/ide/RestApiTest.kt similarity index 100% rename from platform/built-in-server/testSrc/RestApiTest.kt rename to platform/built-in-server/testSrc/org/jetbrains/ide/RestApiTest.kt diff --git a/platform/built-in-server/testSrc/TestManager.kt b/platform/built-in-server/testSrc/org/jetbrains/ide/TestManager.kt similarity index 100% rename from platform/built-in-server/testSrc/TestManager.kt rename to platform/built-in-server/testSrc/org/jetbrains/ide/TestManager.kt diff --git a/platform/configuration-store-impl/configuration-store-impl.iml b/platform/configuration-store-impl/configuration-store-impl.iml index 11f77f156540..89c1e10f6df4 100644 --- a/platform/configuration-store-impl/configuration-store-impl.iml +++ b/platform/configuration-store-impl/configuration-store-impl.iml @@ -3,7 +3,7 @@ - + diff --git a/platform/configuration-store-impl/src/com/intellij/ide/actions/ChooseComponentsToExportDialog.java b/platform/configuration-store-impl/src/ChooseComponentsToExportDialog.java similarity index 99% rename from platform/configuration-store-impl/src/com/intellij/ide/actions/ChooseComponentsToExportDialog.java rename to platform/configuration-store-impl/src/ChooseComponentsToExportDialog.java index d6776aaaf72f..b043d9fcaf35 100644 --- a/platform/configuration-store-impl/src/com/intellij/ide/actions/ChooseComponentsToExportDialog.java +++ b/platform/configuration-store-impl/src/ChooseComponentsToExportDialog.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.ide.actions; +package com.intellij.configurationStore; import com.intellij.ide.IdeBundle; import com.intellij.ide.util.ElementsChooser; diff --git a/platform/configuration-store-impl/src/ExportSettingsAction.kt b/platform/configuration-store-impl/src/ExportSettingsAction.kt index 2e116abdb261..25908e561072 100644 --- a/platform/configuration-store-impl/src/ExportSettingsAction.kt +++ b/platform/configuration-store-impl/src/ExportSettingsAction.kt @@ -13,15 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.ide.actions +package com.intellij.configurationStore import com.intellij.AbstractBundle import com.intellij.CommonBundle -import com.intellij.configurationStore.ROOT_CONFIG -import com.intellij.configurationStore.SchemeManagerFactoryBase -import com.intellij.configurationStore.path -import com.intellij.configurationStore.sortByDeprecated import com.intellij.ide.IdeBundle +import com.intellij.ide.actions.ImportSettingsFilenameFilter +import com.intellij.ide.actions.ShowFilePathAction import com.intellij.ide.plugins.IdeaPluginDescriptor import com.intellij.ide.plugins.PluginManager import com.intellij.ide.plugins.PluginManagerCore @@ -34,7 +32,6 @@ import com.intellij.openapi.components.* import com.intellij.openapi.components.impl.ServiceManagerImpl import com.intellij.openapi.components.impl.stores.StateStorageManager import com.intellij.openapi.components.impl.stores.StoreUtil -import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.extensions.PluginDescriptor import com.intellij.openapi.options.OptionsBundle import com.intellij.openapi.options.SchemeManagerFactory @@ -63,9 +60,9 @@ private class ExportSettingsAction : AnAction(), DumbAware { ApplicationManager.getApplication().saveSettings() val dialog = ChooseComponentsToExportDialog(getExportableComponentsMap(true, true), true, - IdeBundle.message("title.select.components.to.export"), - IdeBundle.message( - "prompt.please.check.all.components.to.export")) + IdeBundle.message("title.select.components.to.export"), + IdeBundle.message( + "prompt.please.check.all.components.to.export")) if (!dialog.showAndGet()) { return } @@ -83,14 +80,14 @@ private class ExportSettingsAction : AnAction(), DumbAware { val saveFile = dialog.exportFile try { if (saveFile.exists() && Messages.showOkCancelDialog( - IdeBundle.message("prompt.overwrite.settings.file", saveFile.toString()), - IdeBundle.message("title.file.already.exists"), Messages.getWarningIcon()) != Messages.OK) { + IdeBundle.message("prompt.overwrite.settings.file", saveFile.toString()), + IdeBundle.message("title.file.already.exists"), Messages.getWarningIcon()) != Messages.OK) { return } exportSettings(exportFiles, saveFile.outputStream(), FileUtilRt.toSystemIndependentName(PathManager.getConfigPath())) - ShowFilePathAction.showDialog(AnAction.getEventProject(e), IdeBundle.message("message.settings.exported.successfully"), - IdeBundle.message("title.export.successful"), saveFile.toFile(), null) + ShowFilePathAction.showDialog(getEventProject(e), IdeBundle.message("message.settings.exported.successfully"), + IdeBundle.message("title.export.successful"), saveFile.toFile(), null) } catch (e1: IOException) { Messages.showErrorDialog(IdeBundle.message("error.writing.settings", e1.toString()), IdeBundle.message("title.error.writing.file")) @@ -132,8 +129,6 @@ private class MyZipOutputStream(out: OutputStream) : ZipOutputStream(out) { data class ExportableItem(val files: List, val presentableName: String, val roamingType: RoamingType = RoamingType.DEFAULT) -private val LOG = Logger.getInstance(ExportSettingsAction::class.java) - private fun exportInstalledPlugins(zipOut: MyZipOutputStream) { val plugins = ArrayList() for (descriptor in PluginManagerCore.getPlugins()) { diff --git a/platform/configuration-store-impl/src/com/intellij/configurationStore/FileStorageAnnotation.java b/platform/configuration-store-impl/src/FileStorageAnnotation.java similarity index 100% rename from platform/configuration-store-impl/src/com/intellij/configurationStore/FileStorageAnnotation.java rename to platform/configuration-store-impl/src/FileStorageAnnotation.java diff --git a/platform/configuration-store-impl/src/ImportSettingsAction.kt b/platform/configuration-store-impl/src/ImportSettingsAction.kt index a486c643d892..0be56e2257b7 100644 --- a/platform/configuration-store-impl/src/ImportSettingsAction.kt +++ b/platform/configuration-store-impl/src/ImportSettingsAction.kt @@ -13,9 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.ide.actions +package com.intellij.configurationStore import com.intellij.ide.IdeBundle +import com.intellij.ide.actions.ImportSettingsFilenameFilter import com.intellij.ide.plugins.PluginManager import com.intellij.ide.startup.StartupActionScriptManager import com.intellij.openapi.actionSystem.AnAction @@ -51,12 +52,12 @@ private class ImportSettingsAction : AnAction(), DumbAware { } catch (e1: ZipException) { Messages.showErrorDialog( - IdeBundle.message("error.reading.settings.file", presentableFileName(saveFile), e1.message, promptLocationMessage()), - IdeBundle.message("title.invalid.file")) + IdeBundle.message("error.reading.settings.file", presentableFileName(saveFile), e1.message, promptLocationMessage()), + IdeBundle.message("title.invalid.file")) } catch (e1: IOException) { Messages.showErrorDialog(IdeBundle.message("error.reading.settings.file.2", presentableFileName(saveFile), e1.message), - IdeBundle.message("title.error.reading.file")) + IdeBundle.message("title.error.reading.file")) } } } @@ -64,22 +65,23 @@ private class ImportSettingsAction : AnAction(), DumbAware { private fun doImport(saveFile: File) { if (!saveFile.exists()) { Messages.showErrorDialog(IdeBundle.message("error.cannot.find.file", presentableFileName(saveFile)), - IdeBundle.message("title.file.not.found")) + IdeBundle.message("title.file.not.found")) return } val relativePaths = getPaths(saveFile.inputStream()) if (!relativePaths.contains(ImportSettingsFilenameFilter.SETTINGS_JAR_MARKER)) { Messages.showErrorDialog( - IdeBundle.message("error.file.contains.no.settings.to.import", presentableFileName(saveFile), promptLocationMessage()), - IdeBundle.message("title.invalid.file")) + IdeBundle.message("error.file.contains.no.settings.to.import", presentableFileName(saveFile), promptLocationMessage()), + IdeBundle.message("title.invalid.file")) return } val configPath = FileUtil.toSystemIndependentName(PathManager.getConfigPath()) - val dialog = ChooseComponentsToExportDialog(getExportableComponentsMap(false, true, onlyPaths = relativePaths), false, - IdeBundle.message("title.select.components.to.import"), - IdeBundle.message("prompt.check.components.to.import")) + val dialog = ChooseComponentsToExportDialog( + getExportableComponentsMap(false, true, onlyPaths = relativePaths), false, + IdeBundle.message("title.select.components.to.import"), + IdeBundle.message("prompt.check.components.to.import")) if (!dialog.showAndGet()) { return } @@ -98,9 +100,9 @@ private class ImportSettingsAction : AnAction(), DumbAware { else "message.settings.imported.successfully" if (Messages.showOkCancelDialog(IdeBundle.message(key, - ApplicationNamesInfo.getInstance().productName, - ApplicationNamesInfo.getInstance().fullProductName), - IdeBundle.message("title.restart.needed"), Messages.getQuestionIcon()) == Messages.OK) { + ApplicationNamesInfo.getInstance().productName, + ApplicationNamesInfo.getInstance().fullProductName), + IdeBundle.message("title.restart.needed"), Messages.getQuestionIcon()) == Messages.OK) { (ApplicationManager.getApplication() as ApplicationEx).restart(true) } } diff --git a/platform/configuration-store-impl/src/StorageBaseEx.kt b/platform/configuration-store-impl/src/StorageBaseEx.kt index 7b2d0c726e56..68c0a3708424 100644 --- a/platform/configuration-store-impl/src/StorageBaseEx.kt +++ b/platform/configuration-store-impl/src/StorageBaseEx.kt @@ -48,13 +48,12 @@ class StateGetter(private val component: PersistentStateCompon return } - val stateAfterLoad: S? - try { - stateAfterLoad = component.state + val stateAfterLoad = try { + component.state } catch (e: Throwable) { LOG.error("Cannot get state after load", e) - stateAfterLoad = null + null } val serializedStateAfterLoad = if (stateAfterLoad == null) { diff --git a/platform/configuration-store-impl/src/com/intellij/configurationStore/StreamProviderWrapper.java b/platform/configuration-store-impl/src/StreamProviderWrapper.java similarity index 100% rename from platform/configuration-store-impl/src/com/intellij/configurationStore/StreamProviderWrapper.java rename to platform/configuration-store-impl/src/StreamProviderWrapper.java diff --git a/platform/configuration-store-impl/src/XmlElementStorage.kt b/platform/configuration-store-impl/src/XmlElementStorage.kt index f39b0fc9289e..ab3cfffef2d0 100644 --- a/platform/configuration-store-impl/src/XmlElementStorage.kt +++ b/platform/configuration-store-impl/src/XmlElementStorage.kt @@ -49,13 +49,12 @@ abstract class XmlElementStorage protected constructor(protected val fileSpec: S val element: Element? // we don't use local data if has stream provider if (provider != null && provider.isApplicable(fileSpec, roamingType)) { - try { - element = loadDataFromProvider() - dataLoadedFromProvider(element) + element = try { + loadDataFromProvider().apply { dataLoadedFromProvider(this) } } catch (e: Exception) { LOG.error(e) - element = null + null } } else { diff --git a/platform/configuration-store-impl/testSrc/ApplicationStoreTest.kt b/platform/configuration-store-impl/testSrc/ApplicationStoreTest.kt index 5af1ebe8470c..0393dc16938a 100644 --- a/platform/configuration-store-impl/testSrc/ApplicationStoreTest.kt +++ b/platform/configuration-store-impl/testSrc/ApplicationStoreTest.kt @@ -15,10 +15,6 @@ */ package com.intellij.configurationStore -import com.intellij.ide.actions.ExportableItem -import com.intellij.ide.actions.exportSettings -import com.intellij.ide.actions.getExportableComponentsMap -import com.intellij.ide.actions.getPaths import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.components.* import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream diff --git a/platform/configuration-store-impl/testSrc/SchemeManagerTest.kt b/platform/configuration-store-impl/testSrc/SchemeManagerTest.kt index b20528523524..1eec16373260 100644 --- a/platform/configuration-store-impl/testSrc/SchemeManagerTest.kt +++ b/platform/configuration-store-impl/testSrc/SchemeManagerTest.kt @@ -220,7 +220,7 @@ internal class SchemeManagerTest { val dir = tempDirManager.newPath() var schemeManager = createSchemeManager(dir) val converter: (Element) -> TestScheme = { XmlSerializer.deserialize(it, TestScheme::class.java)!! } - val bundledPath = "/bundledSchemes/default" + val bundledPath = "/com/intellij/configurationStore/bundledSchemes/default" schemeManager.loadBundledScheme(bundledPath, this, converter) val customScheme = TestScheme("default") assertThat(schemeManager.allSchemes).containsOnly(customScheme) diff --git a/platform/configuration-store-impl/testSrc/configuration-store-tests.iml b/platform/configuration-store-impl/testSrc/configuration-store-tests.iml index e8b910b9c896..445de1bb4649 100644 --- a/platform/configuration-store-impl/testSrc/configuration-store-tests.iml +++ b/platform/configuration-store-impl/testSrc/configuration-store-tests.iml @@ -3,7 +3,7 @@ - + diff --git a/platform/core-api/src/com/intellij/openapi/progress/ProgressIndicatorProvider.java b/platform/core-api/src/com/intellij/openapi/progress/ProgressIndicatorProvider.java index 0fd4e889c20d..4f168fd0aa5d 100644 --- a/platform/core-api/src/com/intellij/openapi/progress/ProgressIndicatorProvider.java +++ b/platform/core-api/src/com/intellij/openapi/progress/ProgressIndicatorProvider.java @@ -40,6 +40,7 @@ public abstract class ProgressIndicatorProvider { public abstract NonCancelableSection startNonCancelableSection(); @NotNull + @Deprecated // use ProgressManager.executeNonCancelableSection() instead public static NonCancelableSection startNonCancelableSectionIfSupported() { return getInstance().startNonCancelableSection(); } diff --git a/platform/credential-store/credential-store.iml b/platform/credential-store/credential-store.iml index 302c953e7481..3194c7f2d648 100644 --- a/platform/credential-store/credential-store.iml +++ b/platform/credential-store/credential-store.iml @@ -3,8 +3,8 @@ - - + + diff --git a/platform/credential-store/src/com/intellij/credentialStore/CredentialStoreFactory.java b/platform/credential-store/src/CredentialStoreFactory.java similarity index 100% rename from platform/credential-store/src/com/intellij/credentialStore/CredentialStoreFactory.java rename to platform/credential-store/src/CredentialStoreFactory.java diff --git a/platform/credential-store/src/nativeCredentialStore.kt b/platform/credential-store/src/CredentialStoreWrapper.kt similarity index 96% rename from platform/credential-store/src/nativeCredentialStore.kt rename to platform/credential-store/src/CredentialStoreWrapper.kt index 9953f45f04f2..53971934f053 100644 --- a/platform/credential-store/src/nativeCredentialStore.kt +++ b/platform/credential-store/src/CredentialStoreWrapper.kt @@ -15,9 +15,6 @@ */ package com.intellij.credentialStore -import com.intellij.credentialStore.linux.SecretCredentialStore -import com.intellij.credentialStore.macOs.KeyChainCredentialStore -import com.intellij.credentialStore.macOs.isMacOsCredentialStoreSupported import com.intellij.ide.passwordSafe.PasswordStorage import com.intellij.notification.NotificationGroup import com.intellij.notification.NotificationType diff --git a/platform/credential-store/src/com/intellij/credentialStore/EnterPasswordComponent.java b/platform/credential-store/src/EnterPasswordComponent.java similarity index 96% rename from platform/credential-store/src/com/intellij/credentialStore/EnterPasswordComponent.java rename to platform/credential-store/src/EnterPasswordComponent.java index 5fb91e63e7ac..7be5b8faaa7d 100644 --- a/platform/credential-store/src/com/intellij/credentialStore/EnterPasswordComponent.java +++ b/platform/credential-store/src/EnterPasswordComponent.java @@ -15,13 +15,11 @@ */ package com.intellij.credentialStore; -import com.intellij.credentialStore.macOs.MacOsKeychainLibraryKt; import com.intellij.icons.AllIcons; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.ui.ValidationInfo; import com.intellij.openapi.util.SystemInfo; import com.intellij.ui.ComponentsKt; -import com.intellij.ui.layout.LayoutKt; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; diff --git a/platform/credential-store/src/KeePassCredentialStore.kt b/platform/credential-store/src/KeePassCredentialStore.kt index 6f095913ab7c..c278688adb15 100644 --- a/platform/credential-store/src/KeePassCredentialStore.kt +++ b/platform/credential-store/src/KeePassCredentialStore.kt @@ -18,8 +18,8 @@ package com.intellij.credentialStore import com.intellij.credentialStore.kdbx.KdbxPassword import com.intellij.credentialStore.kdbx.KeePassDatabase import com.intellij.credentialStore.kdbx.loadKdbx +import com.intellij.credentialStore.windows.WindowsCryptUtils import com.intellij.ide.passwordSafe.PasswordStorage -import com.intellij.ide.passwordSafe.impl.providers.masterKey.windows.WindowsCryptUtils import com.intellij.openapi.application.PathManager import com.intellij.openapi.util.SystemInfo import com.intellij.openapi.util.io.setOwnerPermissions diff --git a/platform/credential-store/src/com/intellij/credentialStore/MasterPasswordDialog.java b/platform/credential-store/src/MasterPasswordDialog.java similarity index 100% rename from platform/credential-store/src/com/intellij/credentialStore/MasterPasswordDialog.java rename to platform/credential-store/src/MasterPasswordDialog.java diff --git a/platform/credential-store/src/com/intellij/credentialStore/PasswordComponentBase.form b/platform/credential-store/src/PasswordComponentBase.form similarity index 100% rename from platform/credential-store/src/com/intellij/credentialStore/PasswordComponentBase.form rename to platform/credential-store/src/PasswordComponentBase.form diff --git a/platform/credential-store/src/com/intellij/credentialStore/PasswordDatabase.java b/platform/credential-store/src/PasswordDatabase.java similarity index 100% rename from platform/credential-store/src/com/intellij/credentialStore/PasswordDatabase.java rename to platform/credential-store/src/PasswordDatabase.java diff --git a/platform/credential-store/src/PasswordSafeImpl.kt b/platform/credential-store/src/PasswordSafeImpl.kt index 7acaa69c65b5..229a7c99d5e7 100644 --- a/platform/credential-store/src/PasswordSafeImpl.kt +++ b/platform/credential-store/src/PasswordSafeImpl.kt @@ -13,6 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +@file:Suppress("PackageDirectoryMismatch") + package com.intellij.ide.passwordSafe.impl import com.intellij.credentialStore.* diff --git a/platform/credential-store/src/com/intellij/credentialStore/PasswordSafeSettings.java b/platform/credential-store/src/PasswordSafeSettings.java similarity index 100% rename from platform/credential-store/src/com/intellij/credentialStore/PasswordSafeSettings.java rename to platform/credential-store/src/PasswordSafeSettings.java diff --git a/platform/credential-store/src/com/intellij/credentialStore/PasswordSafeSettingsListener.java b/platform/credential-store/src/PasswordSafeSettingsListener.java similarity index 100% rename from platform/credential-store/src/com/intellij/credentialStore/PasswordSafeSettingsListener.java rename to platform/credential-store/src/PasswordSafeSettingsListener.java diff --git a/platform/credential-store/src/dbV1Convertor.kt b/platform/credential-store/src/dbV1Convertor.kt index 135520cac8d1..517e4aadff1e 100644 --- a/platform/credential-store/src/dbV1Convertor.kt +++ b/platform/credential-store/src/dbV1Convertor.kt @@ -15,10 +15,10 @@ */ package com.intellij.credentialStore +import com.intellij.credentialStore.windows.WindowsCryptUtils import com.intellij.ide.ApplicationLoadListener import com.intellij.ide.passwordSafe.impl.providers.ByteArrayWrapper import com.intellij.ide.passwordSafe.impl.providers.EncryptionUtil -import com.intellij.ide.passwordSafe.impl.providers.masterKey.windows.WindowsCryptUtils import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.PathManager import com.intellij.openapi.components.ServiceManager diff --git a/platform/credential-store/src/org/linguafranca/hashedblock/HashedBlockInputStream.java b/platform/credential-store/src/kdbx/HashedBlockInputStream.java similarity index 98% rename from platform/credential-store/src/org/linguafranca/hashedblock/HashedBlockInputStream.java rename to platform/credential-store/src/kdbx/HashedBlockInputStream.java index 9fa2d8be0972..b961bc01428d 100644 --- a/platform/credential-store/src/org/linguafranca/hashedblock/HashedBlockInputStream.java +++ b/platform/credential-store/src/kdbx/HashedBlockInputStream.java @@ -14,9 +14,8 @@ * limitations under the License. */ -package org.linguafranca.hashedblock; +package com.intellij.credentialStore.kdbx; -import com.intellij.credentialStore.kdbx.KdbxHeaderKt; import org.jetbrains.annotations.NotNull; import java.io.ByteArrayInputStream; diff --git a/platform/credential-store/src/org/linguafranca/hashedblock/HashedBlockOutputStream.java b/platform/credential-store/src/kdbx/HashedBlockOutputStream.java similarity index 97% rename from platform/credential-store/src/org/linguafranca/hashedblock/HashedBlockOutputStream.java rename to platform/credential-store/src/kdbx/HashedBlockOutputStream.java index 012bae3a82e0..2d42743903cd 100644 --- a/platform/credential-store/src/org/linguafranca/hashedblock/HashedBlockOutputStream.java +++ b/platform/credential-store/src/kdbx/HashedBlockOutputStream.java @@ -14,9 +14,8 @@ * limitations under the License. */ -package org.linguafranca.hashedblock; +package com.intellij.credentialStore.kdbx; -import com.intellij.credentialStore.kdbx.KdbxHeaderKt; import org.jetbrains.annotations.NotNull; import java.io.ByteArrayOutputStream; diff --git a/platform/credential-store/src/kdbx/KdbxSerializer.kt b/platform/credential-store/src/kdbx/KdbxSerializer.kt new file mode 100644 index 000000000000..7dd5741fb0f0 --- /dev/null +++ b/platform/credential-store/src/kdbx/KdbxSerializer.kt @@ -0,0 +1,266 @@ +/* + * Copyright 2015 Jo Rabin + * + * 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.credentialStore.kdbx + +import com.google.common.io.LittleEndianDataInputStream +import com.google.common.io.LittleEndianDataOutputStream +import java.io.InputStream +import java.io.OutputStream +import java.nio.ByteBuffer +import java.security.DigestInputStream +import java.security.DigestOutputStream +import java.util.* +import java.util.zip.GZIPInputStream +import java.util.zip.GZIPOutputStream + +/** + * A KDBX file is little-endian and consists of the following: + * + * 1. An unencrypted portion + * + * 1. 8 bytes Magic number + * 1. 4 bytes version + * 1. A header containing details of the encryption of the remainder of the file + * + * The header fields are encoded using a TLV style. The Type is an enumeration encoded in 1 byte. + * The length is encoded in 2 bytes and the value according to the length denoted. The sequence is + * terminated by a zero type with 0 length. + * + * 1. An encrypted portion + * + * 1. A sequence of bytes contained in the header. If they don't match, decryption has not worked. + * 1. A payload serialized in Hashed Block format. + * + * The methods in this class provide support for serializing and deserializing plain text payload content + * to and from the above format. + * @author jo + */ +internal object KdbxSerializer { + /** + * Provides the payload of a KDBX file as an unencrypted [InputStream]. + + * @param credentials credentials for decryption of the stream + * @param kdbxHeader a header instance to be populated with values from the stream + * @param inputStream a KDBX formatted input stream + * @return an unencrypted input stream, to be read and closed by the caller + */ + fun createUnencryptedInputStream(credentials: KeePassCredentials, kdbxHeader: KdbxHeader, inputStream: InputStream): InputStream { + readKdbxHeader(kdbxHeader, inputStream) + + val decryptedInputStream = kdbxHeader.createDecryptedStream(credentials.key, inputStream) + checkStartBytes(kdbxHeader, decryptedInputStream) + val blockInputStream = HashedBlockInputStream(decryptedInputStream) + if (kdbxHeader.compressionFlags == KdbxHeader.CompressionFlags.NONE) { + return blockInputStream + } + return GZIPInputStream(blockInputStream) + } + + /** + * Provides an [OutputStream] to be encoded and encrypted in KDBX format + + * @param credentials credentials for encryption of the stream + * @param kdbxHeader a KDBX header to control the formatting and encryption operation + * @param outputStream output stream to contain the KDBX formatted output + * @return an unencrypted output stream, to be written to, flushed and closed by the caller + */ + fun createEncryptedOutputStream(credentials: KeePassCredentials, kdbxHeader: KdbxHeader, outputStream: OutputStream): OutputStream { + writeKdbxHeader(kdbxHeader, outputStream) + + val encryptedOutputStream = kdbxHeader.createEncryptedStream(credentials.key, outputStream) + LittleEndianDataOutputStream(encryptedOutputStream).write(kdbxHeader.streamStartBytes) + + val blockOutputStream = HashedBlockOutputStream(encryptedOutputStream) + if (kdbxHeader.compressionFlags == KdbxHeader.CompressionFlags.NONE) { + return blockOutputStream + } + return GZIPOutputStream(blockOutputStream) + } +} + +private fun checkStartBytes(kdbxHeader: KdbxHeader, decryptedInputStream: InputStream) { + val startBytes = ByteArray(32) + LittleEndianDataInputStream(decryptedInputStream).readFully(startBytes) + if (!Arrays.equals(startBytes, kdbxHeader.streamStartBytes)) { + throw IllegalStateException("Inconsistent stream bytes") + } +} + +private val SIG1 = 0x9AA2D903.toInt() +private val SIG2 = 0xB54BFB67.toInt() +private val FILE_VERSION_CRITICAL_MASK = 0xFFFF0000.toInt() +private val FILE_VERSION_32 = 0x00030001 + +private object HeaderType { + internal val END: Byte = 0 + internal val COMMENT: Byte = 1 + internal val CIPHER_ID: Byte = 2 + internal val COMPRESSION_FLAGS: Byte = 3 + internal val MASTER_SEED: Byte = 4 + internal val TRANSFORM_SEED: Byte = 5 + internal val TRANSFORM_ROUNDS: Byte = 6 + internal val ENCRYPTION_IV: Byte = 7 + internal val PROTECTED_STREAM_KEY: Byte = 8 + internal val STREAM_START_BYTES: Byte = 9 + internal val INNER_RANDOM_STREAM_ID: Byte = 10 +} + +private fun verifyMagicNumber(input: LittleEndianDataInputStream): Boolean { + val sig1 = input.readInt() + val sig2 = input.readInt() + return sig1 == SIG1 && sig2 == SIG2 +} + +private fun verifyFileVersion(input: LittleEndianDataInputStream): Boolean { + return input.readInt() and FILE_VERSION_CRITICAL_MASK <= FILE_VERSION_32 and FILE_VERSION_CRITICAL_MASK +} + +/** + * Populate a KdbxHeader from the input stream supplied + + * @param kdbxHeader a header to be populated + * @param inputStream an input stream + * @return the populated KdbxHeader + */ +internal fun readKdbxHeader(kdbxHeader: KdbxHeader, inputStream: InputStream): KdbxHeader { + val digest = sha256MessageDigest() + // we do not close this stream, otherwise we lose our place in the underlying stream + val digestInputStream = DigestInputStream(inputStream, digest) + // we do not close this stream, otherwise we lose our place in the underlying stream + val input = LittleEndianDataInputStream(digestInputStream) + + if (!verifyMagicNumber(input)) { + throw IllegalStateException("Magic number did not match") + } + + if (!verifyFileVersion(input)) { + throw IllegalStateException("File version did not match") + } + + while (true) { + val headerType = input.readByte() + if (headerType == HeaderType.END) { + break + } + + when (headerType) { + HeaderType.COMMENT -> getByteArray(input) + HeaderType.CIPHER_ID -> kdbxHeader.setCipherUuid(getByteArray(input)) + HeaderType.COMPRESSION_FLAGS -> kdbxHeader.setCompressionFlags(getInt(input)) + HeaderType.MASTER_SEED -> kdbxHeader.masterSeed = getByteArray(input) + HeaderType.TRANSFORM_SEED -> kdbxHeader.transformSeed = getByteArray(input) + HeaderType.TRANSFORM_ROUNDS -> kdbxHeader.transformRounds = getLong(input) + HeaderType.ENCRYPTION_IV -> kdbxHeader.encryptionIv = getByteArray(input) + HeaderType.PROTECTED_STREAM_KEY -> kdbxHeader.protectedStreamKey = getByteArray(input) + HeaderType.STREAM_START_BYTES -> kdbxHeader.streamStartBytes = getByteArray(input) + HeaderType.INNER_RANDOM_STREAM_ID -> kdbxHeader.setInnerRandomStreamId(getInt(input)) + + else -> throw IllegalStateException("Unknown File Header") + } + } + + // consume length etc. following END flag + getByteArray(input) + + kdbxHeader.headerHash = digest.digest() + return kdbxHeader +} + +/** + * Write a KdbxHeader to the output stream supplied. The header is updated with the + * message digest of the written stream. + + * @param kdbxHeader the header to write and update + * @param outputStream the output stream + */ +internal fun writeKdbxHeader(kdbxHeader: KdbxHeader, outputStream: OutputStream) { + val messageDigest = sha256MessageDigest() + val digestOutputStream = DigestOutputStream(outputStream, messageDigest) + val output = LittleEndianDataOutputStream(digestOutputStream) + + // write the magic number + output.writeInt(SIG1) + output.writeInt(SIG2) + // write a file version + output.writeInt(FILE_VERSION_32) + + output.writeByte(HeaderType.CIPHER_ID.toInt()) + output.writeShort(16) + val b = ByteArray(16) + val bb = ByteBuffer.wrap(b) + bb.putLong(kdbxHeader.cipherUuid.mostSignificantBits) + bb.putLong(8, kdbxHeader.cipherUuid.leastSignificantBits) + output.write(b) + + output.writeByte(HeaderType.COMPRESSION_FLAGS.toInt()) + output.writeShort(4) + output.writeInt(kdbxHeader.compressionFlags.ordinal) + + output.writeByte(HeaderType.MASTER_SEED.toInt()) + output.writeShort(kdbxHeader.masterSeed.size) + output.write(kdbxHeader.masterSeed) + + output.writeByte(HeaderType.TRANSFORM_SEED.toInt()) + output.writeShort(kdbxHeader.transformSeed.size) + output.write(kdbxHeader.transformSeed) + + output.writeByte(HeaderType.TRANSFORM_ROUNDS.toInt()) + output.writeShort(8) + output.writeLong(kdbxHeader.transformRounds) + + output.writeByte(HeaderType.ENCRYPTION_IV.toInt()) + output.writeShort(kdbxHeader.encryptionIv.size) + output.write(kdbxHeader.encryptionIv) + + output.writeByte(HeaderType.PROTECTED_STREAM_KEY.toInt()) + output.writeShort(kdbxHeader.protectedStreamKey.size) + output.write(kdbxHeader.protectedStreamKey) + + output.writeByte(HeaderType.STREAM_START_BYTES.toInt()) + output.writeShort(kdbxHeader.streamStartBytes.size) + output.write(kdbxHeader.streamStartBytes) + + output.writeByte(HeaderType.INNER_RANDOM_STREAM_ID.toInt()) + output.writeShort(4) + output.writeInt(kdbxHeader.protectedStreamAlgorithm.ordinal) + + output.writeByte(HeaderType.END.toInt()) + output.writeShort(0) + + kdbxHeader.headerHash = digestOutputStream.messageDigest.digest() +} + +private fun getInt(input: LittleEndianDataInputStream): Int { + val fieldLength = input.readShort() + if (fieldLength.toInt() != 4) { + throw IllegalStateException("Int required but length was $fieldLength") + } + return input.readInt() +} + +private fun getLong(input: LittleEndianDataInputStream): Long { + val fieldLength = input.readShort() + if (fieldLength.toInt() != 8) { + throw IllegalStateException("Long required but length was $fieldLength") + } + return input.readLong() +} + +private fun getByteArray(input: LittleEndianDataInputStream): ByteArray { + val value = ByteArray(input.readShort().toInt()) + input.readFully(value) + return value +} diff --git a/platform/credential-store/src/kdbx/KeePassDatabase.kt b/platform/credential-store/src/kdbx/KeePassDatabase.kt index 074361896671..3718b25b985f 100644 --- a/platform/credential-store/src/kdbx/KeePassDatabase.kt +++ b/platform/credential-store/src/kdbx/KeePassDatabase.kt @@ -4,7 +4,6 @@ import com.intellij.util.get import com.intellij.util.getOrCreate import org.jdom.Element import org.jdom.xpath.XPath -import org.linguafranca.pwdb.kdbx.KdbxSerializer import java.io.OutputStream import java.nio.ByteBuffer import java.time.LocalDateTime diff --git a/platform/credential-store/src/kdbx/kdbx.kt b/platform/credential-store/src/kdbx/kdbx.kt index f2a3958dfc24..ecc98cdb41aa 100644 --- a/platform/credential-store/src/kdbx/kdbx.kt +++ b/platform/credential-store/src/kdbx/kdbx.kt @@ -23,7 +23,6 @@ import org.bouncycastle.crypto.engines.Salsa20Engine import org.bouncycastle.crypto.params.KeyParameter import org.bouncycastle.crypto.params.ParametersWithIV import org.jdom.Element -import org.linguafranca.pwdb.kdbx.KdbxSerializer import java.io.InputStream import java.io.OutputStream import java.nio.file.Path diff --git a/platform/credential-store/src/libraries/linuxSecretLibrary.kt b/platform/credential-store/src/linuxSecretLibrary.kt similarity index 97% rename from platform/credential-store/src/libraries/linuxSecretLibrary.kt rename to platform/credential-store/src/linuxSecretLibrary.kt index 475e7252e732..397a728137a1 100644 --- a/platform/credential-store/src/libraries/linuxSecretLibrary.kt +++ b/platform/credential-store/src/linuxSecretLibrary.kt @@ -1,6 +1,5 @@ -package com.intellij.credentialStore.linux +package com.intellij.credentialStore -import com.intellij.credentialStore.* import com.intellij.util.io.jna.DisposableMemory import com.sun.jna.Library import com.sun.jna.Native @@ -121,7 +120,7 @@ private interface SecretLibrary : Library { } @Suppress("unused") -class GErrorStruct : Structure() { +internal class GErrorStruct : Structure() { @JvmField var domain = 0 @JvmField diff --git a/platform/credential-store/src/libraries/macOsKeychainLibrary.kt b/platform/credential-store/src/macOsKeychainLibrary.kt similarity index 99% rename from platform/credential-store/src/libraries/macOsKeychainLibrary.kt rename to platform/credential-store/src/macOsKeychainLibrary.kt index f9ba554f49a2..fcaf49cdfda9 100644 --- a/platform/credential-store/src/libraries/macOsKeychainLibrary.kt +++ b/platform/credential-store/src/macOsKeychainLibrary.kt @@ -13,9 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.credentialStore.macOs +package com.intellij.credentialStore -import com.intellij.credentialStore.* import com.intellij.openapi.util.SystemInfo import com.sun.jna.* import com.sun.jna.ptr.IntByReference diff --git a/platform/credential-store/src/org/linguafranca/pwdb/kdbx/KdbxSerializer.java b/platform/credential-store/src/org/linguafranca/pwdb/kdbx/KdbxSerializer.java deleted file mode 100644 index 03b4b1e87a04..000000000000 --- a/platform/credential-store/src/org/linguafranca/pwdb/kdbx/KdbxSerializer.java +++ /dev/null @@ -1,337 +0,0 @@ -/* - * Copyright 2015 Jo Rabin - * - * 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.linguafranca.pwdb.kdbx; - -import com.google.common.io.LittleEndianDataInputStream; -import com.google.common.io.LittleEndianDataOutputStream; -import com.intellij.credentialStore.kdbx.KdbxHeader; -import com.intellij.credentialStore.kdbx.KdbxHeaderKt; -import com.intellij.credentialStore.kdbx.KeePassCredentials; -import org.linguafranca.hashedblock.HashedBlockInputStream; -import org.linguafranca.hashedblock.HashedBlockOutputStream; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.ByteBuffer; -import java.security.DigestInputStream; -import java.security.DigestOutputStream; -import java.security.MessageDigest; -import java.util.Arrays; -import java.util.zip.GZIPInputStream; -import java.util.zip.GZIPOutputStream; - -/** - * This class provides static methods for the encryption and decryption of Keepass KDBX files. - *

- * A KDBX file is little-endian and consists of the following: - *

    - *
  1. An unencrypted portion
  2. - *
      - *
    1. 8 bytes Magic number
    2. - *
    3. 4 bytes version
    4. - *
    5. A header containing details of the encryption of the remainder of the file
    6. - *

      The header fields are encoded using a TLV style. The Type is an enumeratrion encoded in 1 byte. - * The length is encoded in 2 bytes and the value according to the length denoted. The sequence is - * terminated by a zero type with 0 length.

      - *
    - *
  3. An encrypted portion
  4. - *
      - *
    1. A sequence of bytes contained in the header. If they don't match, decryption has not worked.
    2. - *
    3. A payload serialized in Hashed Block format.
    4. - *

      The content of this payload is expected to be a Keepass Database in XML format.

      - *
    - *
- *

- * The methods in this class provide support for serializing and deserializing plain text payload content - * to and from the above format. - *

- * - * @author jo - */ -public class KdbxSerializer { - private KdbxSerializer() { - } - - /** - * Provides the payload of a KDBX file as an unencrypted {@link InputStream}. - * - * @param credentials credentials for decryption of the stream - * @param kdbxHeader a header instance to be populated with values from the stream - * @param inputStream a KDBX formatted input stream - * @return an unencrypted input stream, to be read and closed by the caller - */ - public static InputStream createUnencryptedInputStream(KeePassCredentials credentials, KdbxHeader kdbxHeader, InputStream inputStream) throws IOException { - - readKdbxHeader(kdbxHeader, inputStream); - - InputStream decryptedInputStream = kdbxHeader.createDecryptedStream(credentials.getKey(), inputStream); - - checkStartBytes(kdbxHeader, decryptedInputStream); - - HashedBlockInputStream blockInputStream = new HashedBlockInputStream(decryptedInputStream); - if (kdbxHeader.getCompressionFlags().equals(KdbxHeader.CompressionFlags.NONE)) { - return blockInputStream; - } - return new GZIPInputStream(blockInputStream); - } - - /** - * Provides an {@link OutputStream} to be encoded and encrypted in KDBX format - * - * @param credentials credentials for encryption of the stream - * @param kdbxHeader a KDBX header to control the formatting and encryption operation - * @param outputStream output stream to contain the KDBX formatted output - * @return an unencrypted output stream, to be written to, flushed and closed by the caller - * @throws IOException - */ - public static OutputStream createEncryptedOutputStream(KeePassCredentials credentials, KdbxHeader kdbxHeader, OutputStream outputStream) - throws IOException { - writeKdbxHeader(kdbxHeader, outputStream); - - OutputStream encryptedOutputStream = kdbxHeader.createEncryptedStream(credentials.getKey(), outputStream); - - new LittleEndianDataOutputStream(encryptedOutputStream).write(kdbxHeader.getStreamStartBytes()); - - HashedBlockOutputStream blockOutputStream = new HashedBlockOutputStream(encryptedOutputStream); - if (kdbxHeader.getCompressionFlags().equals(KdbxHeader.CompressionFlags.NONE)) { - return blockOutputStream; - } - return new GZIPOutputStream(blockOutputStream); - } - - private static void checkStartBytes(KdbxHeader kdbxHeader, InputStream decryptedInputStream) throws IOException { - byte[] startBytes = new byte[32]; - new LittleEndianDataInputStream(decryptedInputStream).readFully(startBytes); - if (!Arrays.equals(startBytes, kdbxHeader.getStreamStartBytes())) { - throw new IllegalStateException("Inconsistent stream bytes"); - } - } - - private static final int SIG1 = 0x9AA2D903; - private static final int SIG2 = 0xB54BFB67; - private static final int FILE_VERSION_CRITICAL_MASK = 0xFFFF0000; - private static final int FILE_VERSION_32 = 0x00030001; - - private static class HeaderType { - static final byte END = 0; - static final byte COMMENT = 1; - static final byte CIPHER_ID = 2; - static final byte COMPRESSION_FLAGS = 3; - static final byte MASTER_SEED = 4; - static final byte TRANSFORM_SEED = 5; - static final byte TRANSFORM_ROUNDS = 6; - static final byte ENCRYPTION_IV = 7; - static final byte PROTECTED_STREAM_KEY = 8; - static final byte STREAM_START_BYTES = 9; - static final byte INNER_RANDOM_STREAM_ID = 10; - } - - /** - * Read two lots of 4 bytes and verify that they satisfy the signature of a - * kdbx file; - * - * @param ledis an input stream - * @return true if it looks like this is a kdbx file - * @throws IOException - */ - private static boolean verifyMagicNumber(LittleEndianDataInputStream ledis) throws IOException { - int sig1 = ledis.readInt(); - int sig2 = ledis.readInt(); - return sig1 == SIG1 && sig2 == SIG2; - } - - /** - * Read 4 bytes and make sure they conform to expectations of file version - * - * @param ledis an input stream - * @return true if it looks like we understand this file version - * @throws IOException - */ - private static boolean verifyFileVersion(LittleEndianDataInputStream ledis) throws IOException { - return ((ledis.readInt() & FILE_VERSION_CRITICAL_MASK) <= (FILE_VERSION_32 & FILE_VERSION_CRITICAL_MASK)); - } - - /** - * Populate a KdbxHeader from the input stream supplied - * - * @param kdbxHeader a header to be populated - * @param inputStream an input stream - * @return the populated KdbxHeader - * @throws IOException - */ - public static KdbxHeader readKdbxHeader(KdbxHeader kdbxHeader, InputStream inputStream) throws IOException { - - MessageDigest digest = KdbxHeaderKt.sha256MessageDigest(); - // we do not close this stream, otherwise we lose our place in the underlying stream - DigestInputStream digestInputStream = new DigestInputStream(inputStream, digest); - // we do not close this stream, otherwise we lose our place in the underlying stream - LittleEndianDataInputStream ledis = new LittleEndianDataInputStream(digestInputStream); - - if (!verifyMagicNumber(ledis)) { - throw new IllegalStateException("Magic number did not match"); - } - - if (!verifyFileVersion(ledis)) { - throw new IllegalStateException("File version did not match"); - } - - byte headerType; - while ((headerType = ledis.readByte()) != HeaderType.END) { - switch (headerType) { - - case HeaderType.COMMENT: - getByteArray(ledis); - break; - - case HeaderType.CIPHER_ID: - kdbxHeader.setCipherUuid(getByteArray(ledis)); - break; - - case HeaderType.COMPRESSION_FLAGS: - kdbxHeader.setCompressionFlags(getInt(ledis)); - break; - - case HeaderType.MASTER_SEED: - kdbxHeader.setMasterSeed(getByteArray(ledis)); - break; - - case HeaderType.TRANSFORM_SEED: - kdbxHeader.setTransformSeed(getByteArray(ledis)); - break; - - case HeaderType.TRANSFORM_ROUNDS: - kdbxHeader.setTransformRounds(getLong(ledis)); - break; - - case HeaderType.ENCRYPTION_IV: - kdbxHeader.setEncryptionIv(getByteArray(ledis)); - break; - - case HeaderType.PROTECTED_STREAM_KEY: - kdbxHeader.setProtectedStreamKey(getByteArray(ledis)); - break; - - case HeaderType.STREAM_START_BYTES: - kdbxHeader.setStreamStartBytes(getByteArray(ledis)); - break; - - case HeaderType.INNER_RANDOM_STREAM_ID: - kdbxHeader.setInnerRandomStreamId(getInt(ledis)); - break; - - default: - throw new IllegalStateException("Unknown File Header"); - } - } - - // consume length etc. following END flag - getByteArray(ledis); - - kdbxHeader.setHeaderHash(digest.digest()); - return kdbxHeader; - } - - /** - * Write a KdbxHeader to the output stream supplied. The header is updated with the - * message digest of the written stream. - * - * @param kdbxHeader the header to write and update - * @param outputStream the output stream - * @throws IOException - */ - public static void writeKdbxHeader(KdbxHeader kdbxHeader, OutputStream outputStream) throws IOException { - MessageDigest messageDigest = KdbxHeaderKt.sha256MessageDigest(); - DigestOutputStream digestOutputStream = new DigestOutputStream(outputStream, messageDigest); - LittleEndianDataOutputStream ledos = new LittleEndianDataOutputStream(digestOutputStream); - - // write the magic number - ledos.writeInt(SIG1); - ledos.writeInt(SIG2); - // write a file version - ledos.writeInt(FILE_VERSION_32); - - ledos.writeByte(HeaderType.CIPHER_ID); - ledos.writeShort(16); - byte[] b = new byte[16]; - ByteBuffer bb = ByteBuffer.wrap(b); - bb.putLong(kdbxHeader.getCipherUuid().getMostSignificantBits()); - bb.putLong(8, kdbxHeader.getCipherUuid().getLeastSignificantBits()); - ledos.write(b); - - ledos.writeByte(HeaderType.COMPRESSION_FLAGS); - ledos.writeShort(4); - ledos.writeInt(kdbxHeader.getCompressionFlags().ordinal()); - - ledos.writeByte(HeaderType.MASTER_SEED); - ledos.writeShort(kdbxHeader.getMasterSeed().length); - ledos.write(kdbxHeader.getMasterSeed()); - - ledos.writeByte(HeaderType.TRANSFORM_SEED); - ledos.writeShort(kdbxHeader.getTransformSeed().length); - ledos.write(kdbxHeader.getTransformSeed()); - - ledos.writeByte(HeaderType.TRANSFORM_ROUNDS); - ledos.writeShort(8); - ledos.writeLong(kdbxHeader.getTransformRounds()); - - ledos.writeByte(HeaderType.ENCRYPTION_IV); - ledos.writeShort(kdbxHeader.getEncryptionIv().length); - ledos.write(kdbxHeader.getEncryptionIv()); - - ledos.writeByte(HeaderType.PROTECTED_STREAM_KEY); - ledos.writeShort(kdbxHeader.getProtectedStreamKey().length); - ledos.write(kdbxHeader.getProtectedStreamKey()); - - ledos.writeByte(HeaderType.STREAM_START_BYTES); - ledos.writeShort(kdbxHeader.getStreamStartBytes().length); - ledos.write(kdbxHeader.getStreamStartBytes()); - - ledos.writeByte(HeaderType.INNER_RANDOM_STREAM_ID); - ledos.writeShort(4); - ledos.writeInt(kdbxHeader.getProtectedStreamAlgorithm().ordinal()); - - ledos.writeByte(HeaderType.END); - ledos.writeShort(0); - - MessageDigest digest = digestOutputStream.getMessageDigest(); - kdbxHeader.setHeaderHash(digest.digest()); - } - - private static int getInt(LittleEndianDataInputStream ledis) throws IOException { - short fieldLength = ledis.readShort(); - if (fieldLength != 4) { - throw new IllegalStateException("Int required but length was " + fieldLength); - } - return ledis.readInt(); - } - - private static long getLong(LittleEndianDataInputStream ledis) throws IOException { - short fieldLength = ledis.readShort(); - if (fieldLength != 8) { - throw new IllegalStateException("Long required but length was " + fieldLength); - } - return ledis.readLong(); - } - - private static byte[] getByteArray(LittleEndianDataInputStream ledis) throws IOException { - short fieldLength = ledis.readShort(); - byte[] value = new byte[fieldLength]; - ledis.readFully(value); - return value; - } -} \ No newline at end of file diff --git a/platform/credential-store/src/com/intellij/ide/passwordSafe/impl/providers/masterKey/windows/W32API.java b/platform/credential-store/src/windows/W32API.java similarity index 98% rename from platform/credential-store/src/com/intellij/ide/passwordSafe/impl/providers/masterKey/windows/W32API.java rename to platform/credential-store/src/windows/W32API.java index dd93ea1fe4ab..55810c9c3099 100644 --- a/platform/credential-store/src/com/intellij/ide/passwordSafe/impl/providers/masterKey/windows/W32API.java +++ b/platform/credential-store/src/windows/W32API.java @@ -10,7 +10,7 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ -package com.intellij.ide.passwordSafe.impl.providers.masterKey.windows; +package com.intellij.credentialStore.windows; import com.sun.jna.*; import com.sun.jna.ptr.ByReference; diff --git a/platform/credential-store/src/com/intellij/ide/passwordSafe/impl/providers/masterKey/windows/WindowsCryptUtils.java b/platform/credential-store/src/windows/WindowsCryptUtils.java similarity index 98% rename from platform/credential-store/src/com/intellij/ide/passwordSafe/impl/providers/masterKey/windows/WindowsCryptUtils.java rename to platform/credential-store/src/windows/WindowsCryptUtils.java index c04b13129217..eddd136d5f97 100644 --- a/platform/credential-store/src/com/intellij/ide/passwordSafe/impl/providers/masterKey/windows/WindowsCryptUtils.java +++ b/platform/credential-store/src/windows/WindowsCryptUtils.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.ide.passwordSafe.impl.providers.masterKey.windows; +package com.intellij.credentialStore.windows; import com.intellij.util.containers.ContainerUtil; import com.sun.jna.*; diff --git a/platform/credential-store/test/NativeKeychainTest.kt b/platform/credential-store/test/CredentialStoreTest.kt similarity index 94% rename from platform/credential-store/test/NativeKeychainTest.kt rename to platform/credential-store/test/CredentialStoreTest.kt index a0dbefd35e57..4a107232abec 100644 --- a/platform/credential-store/test/NativeKeychainTest.kt +++ b/platform/credential-store/test/CredentialStoreTest.kt @@ -1,7 +1,5 @@ -package com.intellij.credentialStore.linux +package com.intellij.credentialStore -import com.intellij.credentialStore.* -import com.intellij.credentialStore.macOs.KeyChainCredentialStore import com.intellij.openapi.util.SystemInfo import com.intellij.testFramework.UsefulTestCase import org.assertj.core.api.Assertions.assertThat @@ -10,7 +8,7 @@ import java.util.* private const val TEST_SERVICE_NAME = "IntelliJ Platform Test" -internal class NativeKeychainTest { +internal class CredentialStoreTest { @Test fun linux() { if (!SystemInfo.isLinux || UsefulTestCase.IS_UNDER_TEAMCITY) { diff --git a/platform/credential-store/test/CsTestSuite.kt b/platform/credential-store/test/CredentialStoreTestSuite.kt similarity index 65% rename from platform/credential-store/test/CsTestSuite.kt rename to platform/credential-store/test/CredentialStoreTestSuite.kt index e73518d9e713..de9e4ac090f7 100644 --- a/platform/credential-store/test/CsTestSuite.kt +++ b/platform/credential-store/test/CredentialStoreTestSuite.kt @@ -13,15 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jetbrains.settingsRepository.test +package com.intellij.credentialStore -import com.intellij.credentialStore.CredentialSerializeTest -import com.intellij.credentialStore.FileCredentialStoreTest -import com.intellij.credentialStore.MasterPasswordMigrationTest -import com.intellij.credentialStore.linux.NativeKeychainTest import org.junit.runner.RunWith import org.junit.runners.Suite @RunWith(Suite::class) -@Suite.SuiteClasses(FileCredentialStoreTest::class, CredentialSerializeTest::class, NativeKeychainTest::class, MasterPasswordMigrationTest::class) -internal class CsTestSuite \ No newline at end of file +@Suite.SuiteClasses(FileCredentialStoreTest::class, CredentialSerializeTest::class, CredentialStoreTest::class, MasterPasswordMigrationTest::class) +internal class CredentialStoreTestSuite \ No newline at end of file diff --git a/platform/credential-store/test/testClass.kt b/platform/credential-store/test/testClass.kt index b2a1caabfa69..9939d1d2c608 100644 --- a/platform/credential-store/test/testClass.kt +++ b/platform/credential-store/test/testClass.kt @@ -1,3 +1,5 @@ +@file:Suppress("PackageDirectoryMismatch") + package com.intellij.ide.passwordSafe.impl.providers.masterKey class MasterKeyPasswordSafeTest { diff --git a/platform/credential-store/test/com/intellij/ide/passwordSafe/impl/providers/masterKey/windows/WindowsCryptUtilTest.java b/platform/credential-store/test/windows/WindowsCryptUtilTest.java similarity index 94% rename from platform/credential-store/test/com/intellij/ide/passwordSafe/impl/providers/masterKey/windows/WindowsCryptUtilTest.java rename to platform/credential-store/test/windows/WindowsCryptUtilTest.java index c428b8bb0416..0a4ef2d71b6f 100644 --- a/platform/credential-store/test/com/intellij/ide/passwordSafe/impl/providers/masterKey/windows/WindowsCryptUtilTest.java +++ b/platform/credential-store/test/windows/WindowsCryptUtilTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.ide.passwordSafe.impl.providers.masterKey.windows; +package com.intellij.credentialStore.windows; import com.intellij.openapi.util.SystemInfo; import org.junit.Assert; diff --git a/platform/editor-ui-api/src/com/intellij/openapi/editor/markup/GutterIconRenderer.java b/platform/editor-ui-api/src/com/intellij/openapi/editor/markup/GutterIconRenderer.java index 159fae17babe..09c340cff4de 100644 --- a/platform/editor-ui-api/src/com/intellij/openapi/editor/markup/GutterIconRenderer.java +++ b/platform/editor-ui-api/src/com/intellij/openapi/editor/markup/GutterIconRenderer.java @@ -23,8 +23,6 @@ import com.intellij.openapi.project.PossiblyDumbAware; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import javax.swing.*; - /** * Interface which should be implemented in order to draw icons in the gutter area and handle events * for them. Gutter icons are drawn to the left of the folding area and can be used, for example, @@ -33,23 +31,12 @@ import javax.swing.*; * Daemon code analyzer checks newly arrived gutter icon renderer against the old one and if they are equal, does not redraw the icon. * So it is highly advisable to override hashCode()/equals() methods to avoid icon flickering when old gutter renderer gets replaced with the new.

* - * During indexing, methods are only invoked for renderers implementing {@link com.intellij.openapi.project.DumbAware}. + * During indexing, methods are only invoked for renderers implementing {@link DumbAware}. * * @author max * @see RangeHighlighter#setGutterIconRenderer(GutterIconRenderer) */ public abstract class GutterIconRenderer implements GutterMark, PossiblyDumbAware { - - - /** - * Returns the icon drawn in the gutter. - * - * @return the gutter icon. - */ - @Override - @NotNull - public abstract Icon getIcon(); - /** * Returns the action group actions from which are used to fill the context menu * displayed when the icon is right-clicked. diff --git a/platform/icons/src/vcs/silentShelve.png b/platform/icons/src/vcs/silentShelve.png new file mode 100644 index 000000000000..c9e482fae550 Binary files /dev/null and b/platform/icons/src/vcs/silentShelve.png differ diff --git a/platform/icons/src/vcs/silentShelve@2x.png b/platform/icons/src/vcs/silentShelve@2x.png new file mode 100644 index 000000000000..edeb02cf858c Binary files /dev/null and b/platform/icons/src/vcs/silentShelve@2x.png differ diff --git a/platform/icons/src/vcs/silentUnshelve.png b/platform/icons/src/vcs/silentUnshelve.png new file mode 100644 index 000000000000..f3df00c2f294 Binary files /dev/null and b/platform/icons/src/vcs/silentUnshelve.png differ diff --git a/platform/icons/src/vcs/silentUnshelve@2x.png b/platform/icons/src/vcs/silentUnshelve@2x.png new file mode 100644 index 000000000000..15344f636d42 Binary files /dev/null and b/platform/icons/src/vcs/silentUnshelve@2x.png differ diff --git a/platform/lang-impl/src/com/intellij/application/options/GeneralCodeStylePanel.java b/platform/lang-impl/src/com/intellij/application/options/GeneralCodeStylePanel.java index 4a47ebd7869e..fd410d0dbf1e 100644 --- a/platform/lang-impl/src/com/intellij/application/options/GeneralCodeStylePanel.java +++ b/platform/lang-impl/src/com/intellij/application/options/GeneralCodeStylePanel.java @@ -133,7 +133,6 @@ public class GeneralCodeStylePanel extends CodeStyleAbstractPanel { myPanel.setBorder(JBUI.Borders.empty(10, 10)); myScrollPane = ScrollPaneFactory.createScrollPane(null, true); myScrollPane.setViewport(new GradientViewport(myPanel, JBUI.insetsTop(5), true)); - myScrollPane.getVerticalScrollBar().setUnitIncrement(JBUI.scale(10)); myAdditionalSettingsPanel.setLayout(new VerticalFlowLayout(true, true)); myAdditionalSettingsPanel.removeAll(); diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/CodeStyleBlankLinesPanel.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/CodeStyleBlankLinesPanel.java index 0a57cd2e9914..9726daaf879d 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/CodeStyleBlankLinesPanel.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/CodeStyleBlankLinesPanel.java @@ -90,7 +90,6 @@ public class CodeStyleBlankLinesPanel extends CustomizableLanguageCodeStylePanel optionsPanel.setBorder(JBUI.Borders.empty(0, 10)); JScrollPane scroll = ScrollPaneFactory.createScrollPane(optionsPanel, true); - scroll.getVerticalScrollBar().setUnitIncrement(10); scroll.setMinimumSize(new Dimension(optionsPanel.getPreferredSize().width + scroll.getVerticalScrollBar().getPreferredSize().width + 5, -1)); scroll.setPreferredSize(scroll.getMinimumSize()); diff --git a/platform/lang-impl/src/com/intellij/find/actions/ShowUsagesTableCellRenderer.java b/platform/lang-impl/src/com/intellij/find/actions/ShowUsagesTableCellRenderer.java index e82b858bfa7d..a9df5d8f103b 100644 --- a/platform/lang-impl/src/com/intellij/find/actions/ShowUsagesTableCellRenderer.java +++ b/platform/lang-impl/src/com/intellij/find/actions/ShowUsagesTableCellRenderer.java @@ -105,7 +105,8 @@ class ShowUsagesTableCellRenderer implements TableCellRenderer { panel.setBackground(panelBackground); panel.setForeground(panelForeground); - boolean isEnabled = !myUsageView.isOriginUsage(usage); + // greying the current usage you originated your "find usages" from is turned off by @nik orders + boolean isEnabled = true;//!myUsageView.isOriginUsage(usage); if (!isEnabled) { fg = UIUtil.getLabelDisabledForeground(); } diff --git a/platform/platform-api/src/com/intellij/openapi/ui/MessageDialogBuilder.java b/platform/platform-api/src/com/intellij/openapi/ui/MessageDialogBuilder.java index 445027fec026..9bf9ab6ad79e 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/MessageDialogBuilder.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/MessageDialogBuilder.java @@ -58,10 +58,10 @@ public abstract class MessageDialogBuilder { } /** - * @see {@link com.intellij.openapi.ui.Messages#getInformationIcon()} - * @see {@link com.intellij.openapi.ui.Messages#getWarningIcon()} - * @see {@link com.intellij.openapi.ui.Messages#getErrorIcon()} - * @see {@link com.intellij.openapi.ui.Messages#getQuestionIcon()} + * @see Messages#getInformationIcon() + * @see Messages#getWarningIcon() + * @see Messages#getErrorIcon() + * @see Messages#getQuestionIcon() */ public T icon(@Nullable Icon icon) { myIcon = icon; @@ -109,7 +109,7 @@ public abstract class MessageDialogBuilder { return Messages.showDialog(myProject, myMessage, myTitle, new String[]{yesText, noText}, 0, myIcon, myDoNotAskOption) == 0 ? Messages.YES : Messages.NO; } - public boolean is() { + public boolean isYes() { return show() == Messages.YES; } } diff --git a/platform/platform-api/src/com/intellij/ui/components/JBScrollPane.java b/platform/platform-api/src/com/intellij/ui/components/JBScrollPane.java index b5e767233fb7..e74c3bcf9797 100644 --- a/platform/platform-api/src/com/intellij/ui/components/JBScrollPane.java +++ b/platform/platform-api/src/com/intellij/ui/components/JBScrollPane.java @@ -364,6 +364,33 @@ public class JBScrollPane extends JScrollPane { public boolean canBePreprocessed(MouseEvent e) { return JBScrollPane.canBePreprocessed(e, this); } + + @Override + public int getUnitIncrement() { + return fixUnitIncrement(super.getUnitIncrement()); + } + + @Override + public int getUnitIncrement(int direction) { + return fixUnitIncrement(super.getUnitIncrement(direction)); + } + + // increases default unit increment for non-scrollable components to provide fast scrolling + private int fixUnitIncrement(int increment) { + if (increment != 1) return increment; + + JViewport viewport = getViewport(); + if (viewport == null) return increment; + + Component view = viewport.getView(); + if (view == null) return increment; + if (view instanceof Scrollable) { + if (Adjustable.VERTICAL == getOrientation()) return increment; + if (view instanceof JTable) return increment; + } + Font font = view.getFont(); + return font == null ? increment : font.getSize(); + } } diff --git a/platform/platform-impl/src/com/intellij/diagnostic/ITNReporter.kt b/platform/platform-impl/src/com/intellij/diagnostic/ITNReporter.kt index 55a5459fbd10..e02ab619f833 100644 --- a/platform/platform-impl/src/com/intellij/diagnostic/ITNReporter.kt +++ b/platform/platform-impl/src/com/intellij/diagnostic/ITNReporter.kt @@ -34,6 +34,7 @@ import com.intellij.openapi.diagnostic.IdeaLoggingEvent import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.diagnostic.SubmittedReportInfo import com.intellij.openapi.project.Project +import com.intellij.openapi.ui.MessageDialogBuilder import com.intellij.openapi.ui.Messages import com.intellij.util.Consumer import com.intellij.xml.util.XmlStringUtil @@ -85,16 +86,6 @@ private fun showMessageDialog(parentComponent: Component, project: Project?, mes } } -@Messages.YesNoResult -private fun showYesNoDialog(parentComponent: Component, project: Project?, message: String, title: String, icon: Icon): Int { - if (parentComponent.isShowing) { - return Messages.showYesNoDialog(parentComponent, message, title, icon) - } - else { - return Messages.showYesNoDialog(project, message, title, icon) - } -} - private fun submit(event: IdeaLoggingEvent, parentComponent: Component, callback: Consumer, errorBean: ErrorBean, description: String?): Boolean { var credentials = ErrorReportConfigurable.getCredentials() // ask password only if user name was specified @@ -131,9 +122,8 @@ private fun submit(event: IdeaLoggingEvent, parentComponent: Component, callback val project = CommonDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext(parentComponent)) ITNProxy.sendError(project, login, password, errorBean, { threadId -> updatePreviousThreadId(threadId) - val url = ITNProxy.getBrowseUrl(threadId!!) val linkText = threadId.toString() - val reportInfo = SubmittedReportInfo(url, linkText, SubmittedReportInfo.SubmissionStatus.NEW_ISSUE) + val reportInfo = SubmittedReportInfo(ITNProxy.getBrowseUrl(threadId), linkText, SubmittedReportInfo.SubmissionStatus.NEW_ISSUE) callback.consume(reportInfo) ApplicationManager.getApplication().invokeLater { val text = StringBuilder() @@ -156,14 +146,18 @@ private fun submit(event: IdeaLoggingEvent, parentComponent: Component, callback val message = DiagnosticBundle.message("error.report.new.eap.build.message", e.message) showMessageDialog(parentComponent, project, message, CommonBundle.getWarningTitle(), Messages.getWarningIcon()) callback.consume(SubmittedReportInfo(SubmittedReportInfo.SubmissionStatus.FAILED)) + return@invokeLater } - else if (showYesNoDialog(parentComponent, project, msg, ReportMessages.ERROR_REPORT, Messages.getErrorIcon()) != Messages.YES) { + + if (!MessageDialogBuilder.yesNo(ReportMessages.ERROR_REPORT, msg).project(project).isYes) { callback.consume(SubmittedReportInfo(SubmittedReportInfo.SubmissionStatus.FAILED)) } - else if (e is NoSuchEAPUserException) { - showJetBrainsAccountDialog(parentComponent, project).show() + else { + if (e is NoSuchEAPUserException) { + showJetBrainsAccountDialog(parentComponent, project).show() + } + ApplicationManager.getApplication().invokeLater { submit(event, parentComponent, callback, errorBean, description) } } - ApplicationManager.getApplication().invokeLater { submit(event, parentComponent, callback, errorBean, description) } } } return true diff --git a/platform/platform-impl/src/com/intellij/errorreport/itn/ITNProxy.java b/platform/platform-impl/src/com/intellij/errorreport/itn/ITNProxy.java index 6f793eca30b3..2bdd8aeb1273 100644 --- a/platform/platform-impl/src/com/intellij/errorreport/itn/ITNProxy.java +++ b/platform/platform-impl/src/com/intellij/errorreport/itn/ITNProxy.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -60,6 +60,9 @@ import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.util.Calendar; import java.util.Map; +import java.util.function.IntConsumer; + +import static javax.xml.transform.OutputKeys.ENCODING; /** * @author stathik @@ -68,14 +71,13 @@ import java.util.Map; public class ITNProxy { private static final String NEW_THREAD_VIEW_URL = "https://ea.jetbrains.com/browser/ea_reports/"; private static final String NEW_THREAD_POST_URL = "https://ea-report.jetbrains.com/trackerRpc/idea/createScr"; - private static final String ENCODING = "UTF8"; public static void sendError(@Nullable Project project, final String login, final String password, @NotNull final ErrorBean error, - @NotNull final Consumer callback, - @NotNull final Consumer errback) { + @NotNull final IntConsumer callback, + @NotNull final Consumer errorCallback) { if (StringUtil.isEmpty(login)) { return; } @@ -84,11 +86,10 @@ public class ITNProxy { @Override public void run(@NotNull ProgressIndicator indicator) { try { - int threadId = postNewThread(login, password, error); - callback.consume(threadId); + callback.accept(postNewThread(login, password, error)); } catch (Exception ex) { - errback.consume(ex); + errorCallback.consume(ex); } } }; @@ -123,8 +124,7 @@ public class ITNProxy { String response; InputStream is = connection.getInputStream(); try { - byte[] bytes = FileUtil.loadBytes(is); - response = new String(bytes, ENCODING); + response = FileUtil.loadTextAndClose(is); } finally { is.close(); diff --git a/platform/platform-impl/src/com/intellij/ide/customize/CustomizePluginsStepPanel.java b/platform/platform-impl/src/com/intellij/ide/customize/CustomizePluginsStepPanel.java index 651ba079bd72..785be9e58a74 100644 --- a/platform/platform-impl/src/com/intellij/ide/customize/CustomizePluginsStepPanel.java +++ b/platform/platform-impl/src/com/intellij/ide/customize/CustomizePluginsStepPanel.java @@ -146,7 +146,6 @@ public class CustomizePluginsStepPanel extends AbstractCustomizeWizardStep imple static JBScrollPane createScrollPane(JPanel gridPanel) { JBScrollPane scrollPane = new JBScrollPane(gridPanel, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); - scrollPane.getVerticalScrollBar().setUnitIncrement(10); scrollPane.setBorder(JBUI.Borders.empty()); // to disallow resetting border on LaF change return scrollPane; } diff --git a/platform/platform-impl/src/com/intellij/notification/impl/actions/NotificationTestAction.java b/platform/platform-impl/src/com/intellij/notification/impl/actions/NotificationTestAction.java index 62eae969c125..5ac2489828aa 100644 --- a/platform/platform-impl/src/com/intellij/notification/impl/actions/NotificationTestAction.java +++ b/platform/platform-impl/src/com/intellij/notification/impl/actions/NotificationTestAction.java @@ -292,7 +292,7 @@ public class NotificationTestAction extends AnAction implements DumbAware { @Override public void hyperlinkUpdate(@NotNull Notification notification, @NotNull HyperlinkEvent event) { - if (MessageDialogBuilder.yesNo("Notification Listener", event.getDescription() + " Expire?").is()) { + if (MessageDialogBuilder.yesNo("Notification Listener", event.getDescription() + " Expire?").isYes()) { myNotification.expire(); myNotification = null; } @@ -314,7 +314,7 @@ public class NotificationTestAction extends AnAction implements DumbAware { @Override public void actionPerformed(AnActionEvent e) { - if (MessageDialogBuilder.yesNo("AnAction", getTemplatePresentation().getText() + " Expire?").is()) { + if (MessageDialogBuilder.yesNo("AnAction", getTemplatePresentation().getText() + " Expire?").isYes()) { myNotification.expire(); myNotification = null; } diff --git a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/IdeMouseEventDispatcher.java b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/IdeMouseEventDispatcher.java index 2597914c08fc..70bc19a69870 100644 --- a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/IdeMouseEventDispatcher.java +++ b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/IdeMouseEventDispatcher.java @@ -26,7 +26,6 @@ import com.intellij.openapi.keymap.Keymap; import com.intellij.openapi.keymap.KeymapManager; import com.intellij.openapi.keymap.impl.ui.MouseShortcutPanel; import com.intellij.openapi.util.SystemInfo; -import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.wm.IdeFocusManager; import com.intellij.openapi.wm.IdeFrame; import com.intellij.openapi.wm.impl.FocusManagerImpl; @@ -313,16 +312,13 @@ public final class IdeMouseEventDispatcher { } private static int getScrollAmount(Component c, MouseWheelEvent me, JScrollBar scrollBar) { - final int scrollBarWidth = scrollBar.getWidth(); - final int ratio = Registry.is("ide.smart.horizontal.scrolling") && scrollBarWidth > 0 - ? Math.max((int)Math.pow(c.getWidth() / scrollBarWidth, 2), 10) : 10; // do annoying scrolling faster if smart scrolling is on - return me.getUnitsToScroll() * scrollBar.getUnitIncrement() * ratio; + return me.getUnitsToScroll() * scrollBar.getUnitIncrement(); } private static boolean isHorizontalScrolling(Component c, MouseEvent e) { if ( c != null && e instanceof MouseWheelEvent - && (!SystemInfo.isMac || isDiagramViewComponent(c.getParent()))) { + && isDiagramViewComponent(c.getParent())) { final MouseWheelEvent mwe = (MouseWheelEvent)e; return mwe.isShiftDown() && mwe.getScrollType() == MouseWheelEvent.WHEEL_UNIT_SCROLL diff --git a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ShortcutDialog.java b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ShortcutDialog.java index c9ef408ba5a3..6b8c088aa8b5 100644 --- a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ShortcutDialog.java +++ b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ShortcutDialog.java @@ -163,7 +163,6 @@ abstract class ShortcutDialog extends DialogWrapper { if (!Registry.is("ide.scroll.new.layout")) { scroll.getVerticalScrollBar().setUI(ButtonlessScrollBarUI.createTransparent()); } - scroll.getVerticalScrollBar().setUnitIncrement(JBUI.scale(10)); scroll.getVerticalScrollBar().setOpaque(false); scroll.getViewport().setOpaque(false); scroll.setOpaque(false); diff --git a/platform/platform-impl/src/com/intellij/openapi/options/ex/ConfigurableCardPanel.java b/platform/platform-impl/src/com/intellij/openapi/options/ex/ConfigurableCardPanel.java index 2d3f02f170ae..ced804d9b010 100644 --- a/platform/platform-impl/src/com/intellij/openapi/options/ex/ConfigurableCardPanel.java +++ b/platform/platform-impl/src/com/intellij/openapi/options/ex/ConfigurableCardPanel.java @@ -91,7 +91,6 @@ public class ConfigurableCardPanel extends CardLayoutPanel Unit): Bootstrap { + handler(object : ChannelInitializer() { + override fun initChannel(channel: Channel) { + task(channel) + } + }) + return this +} + +fun serverBootstrap(group: EventLoopGroup): ServerBootstrap { + val bootstrap = ServerBootstrap() + .group(group) + .channel(if (group is NioEventLoopGroup) NioServerSocketChannel::class.java else OioServerSocketChannel::class.java) + bootstrap.childOption(ChannelOption.TCP_NODELAY, true).childOption(ChannelOption.SO_KEEPALIVE, true) + return bootstrap +} + +inline fun ChannelFuture.addChannelListener(crossinline listener: (future: ChannelFuture) -> Unit) { + addListener(GenericFutureListener { listener(it) }) +} + +// if NIO, so, it is shared and we must not shutdown it +fun EventLoop.shutdownIfOio() { + if (this is OioEventLoopGroup) { + @Suppress("USELESS_CAST") + (this as OioEventLoopGroup).shutdownGracefully(1L, 2L, TimeUnit.NANOSECONDS) + } +} + +// Event loop will be shut downed only if OIO +fun Channel.closeAndShutdownEventLoop() { + val eventLoop = eventLoop() + try { + close().awaitUninterruptibly() + } + finally { + eventLoop.shutdownIfOio() + } +} + +@JvmOverloads +fun Bootstrap.connect(remoteAddress: InetSocketAddress, promise: AsyncPromise<*>? = null, maxAttemptCount: Int = NettyUtil.DEFAULT_CONNECT_ATTEMPT_COUNT, stopCondition: Condition? = null): Channel? { + try { + return doConnect(this, remoteAddress, promise, maxAttemptCount, stopCondition ?: Conditions.alwaysFalse()) + } + catch (e: Throwable) { + promise?.setError(e) + return null + } +} + +private fun doConnect(bootstrap: Bootstrap, + remoteAddress: InetSocketAddress, + promise: AsyncPromise<*>?, + maxAttemptCount: Int, + stopCondition: Condition): Channel? { + var attemptCount = 0 + if (bootstrap.config().group() is NioEventLoopGroup) { + return connectNio(bootstrap, remoteAddress, promise, maxAttemptCount, stopCondition, attemptCount) + } + + bootstrap.validate() + + val socket: Socket + while (true) { + try { + //noinspection IOResourceOpenedButNotSafelyClosed,SocketOpenedButNotSafelyClosed + socket = Socket(remoteAddress.address, remoteAddress.port) + break + } + catch (e: IOException) { + if (stopCondition.value(null) || promise != null && promise.state != Promise.State.PENDING) { + return null + } + else if (maxAttemptCount == -1) { + if (sleep(promise, 300)) { + return null + } + attemptCount++ + } + else if (++attemptCount < maxAttemptCount) { + if (sleep(promise, attemptCount * NettyUtil.MIN_START_TIME)) { + return null + } + } + else { + promise?.setError(e) + return null + } + } + + } + + val channel = OioSocketChannel(socket) + BootstrapUtil.initAndRegister(channel, bootstrap).sync() + return channel +} + +private fun connectNio(bootstrap: Bootstrap, + remoteAddress: InetSocketAddress, + promise: AsyncPromise<*>?, + maxAttemptCount: Int, + stopCondition: Condition, + _attemptCount: Int): Channel? { + var attemptCount = _attemptCount + while (true) { + val future = bootstrap.connect(remoteAddress).awaitUninterruptibly() + if (future.isSuccess) { + if (!future.channel().isOpen) { + continue + } + return future.channel() + } + else if (stopCondition.value(null) || promise != null && promise.state == Promise.State.REJECTED) { + return null + } + else if (maxAttemptCount == -1) { + if (sleep(promise, 300)) { + return null + } + attemptCount++ + } + else if (++attemptCount < maxAttemptCount) { + if (sleep(promise, attemptCount * NettyUtil.MIN_START_TIME)) { + return null + } + } + else { + @SuppressWarnings("ThrowableResultOfMethodCallIgnored") + val cause = future.cause() + if (promise != null) { + if (cause == null) { + promise.setError("Cannot connect: unknown error") + } + else { + promise.setError(cause) + } + } + return null + } + } +} + +private fun sleep(promise: AsyncPromise<*>?, time: Int): Boolean { + try { + //noinspection BusyWait + Thread.sleep(time.toLong()) + } + catch (ignored: InterruptedException) { + promise?.setError("Interrupted") + return true + } + + return false +} + +val Channel.uriScheme: String + get() = if (pipeline().get(SslHandler::class.java) == null) "http" else "https" + +val HttpRequest.host: String? + get() = headers().getAsString(HttpHeaderNames.HOST) + +val HttpRequest.origin: String? + get() = headers().getAsString(HttpHeaderNames.ORIGIN) + +val HttpRequest.referrer: String? + get() = headers().getAsString(HttpHeaderNames.REFERER) + +val HttpRequest.userAgent: String? + get() = headers().getAsString(HttpHeaderNames.USER_AGENT) + +inline fun ByteBuf.releaseIfError(task: () -> T): T { + try { + return task() + } + catch (e: Exception) { + try { + release() + } + finally { + throw e + } + } +} + +fun isLocalHost(host: String, onlyAnyOrLoopback: Boolean, hostsOnly: Boolean = false): Boolean { + if (NetUtils.isLocalhost(host)) { + return true + } + + // if IP address, it is safe to use getByName (not affected by DNS rebinding) + if (onlyAnyOrLoopback && !InetAddresses.isInetAddress(host)) { + return false + } + + fun InetAddress.isLocal() = isAnyLocalAddress || isLoopbackAddress || NetworkInterface.getByInetAddress(this) != null + + try { + val address = InetAddress.getByName(host) + if (!address.isLocal()) { + return false + } + // be aware - on windows hosts file doesn't contain localhost + // hosts can contain remote addresses, so, we check it + if (hostsOnly && !InetAddresses.isInetAddress(host)) { + return io.netty.resolver.HostsFileEntriesResolver.DEFAULT.address(host).let { it != null && it.isLocal() } + } + else { + return true + } + } + catch (ignored: IOException) { + return false + } +} + +@JvmOverloads +fun HttpRequest.isLocalOrigin(onlyAnyOrLoopback: Boolean = true, hostsOnly: Boolean = false) = parseAndCheckIsLocalHost(origin, onlyAnyOrLoopback, hostsOnly) && parseAndCheckIsLocalHost(referrer, onlyAnyOrLoopback, hostsOnly) + +private fun isTrustedChromeExtension(url: Url): Boolean { + return url.scheme == "chrome-extension" && (url.authority == "hmhgeddbohgjknpmjagkdomcpobmllji" || url.authority == "offnedcbhjldheanlbojaefbfbllddna") +} + +private val Url.host: String? + get() = authority?.let { + val portIndex = it.indexOf(':') + if (portIndex > 0) it.substring(0, portIndex) else it + } + +@JvmOverloads +fun parseAndCheckIsLocalHost(uri: String?, onlyAnyOrLoopback: Boolean = true, hostsOnly: Boolean = false): Boolean { + if (uri == null || uri == "about:blank") { + return true + } + + try { + val parsedUri = Urls.parse(uri, false) ?: return false + val host = parsedUri.host + return host != null && (isTrustedChromeExtension(parsedUri) || isLocalHost(host, onlyAnyOrLoopback, hostsOnly)) + } + catch (ignored: Exception) { + } + return false +} + +fun HttpRequest.isRegularBrowser() = userAgent?.startsWith("Mozilla/5.0") ?: false + +// forbid POST requests from browser without Origin +fun HttpRequest.isWriteFromBrowserWithoutOrigin(): Boolean { + val method = method() + return origin.isNullOrEmpty() && isRegularBrowser() && (method == HttpMethod.POST || method == HttpMethod.PATCH || method == HttpMethod.PUT || method == HttpMethod.DELETE) +} + +fun ByteBuf.readUtf8() = toString(Charsets.UTF_8) + +fun ByteBuf.writeUtf8(data: CharSequence) = writeCharSequence(data, Charsets.UTF_8) \ No newline at end of file diff --git a/platform/platform-impl/src/io/netty/buffer/ByteBufUtf8Writer.java b/platform/platform-impl/src/io/netty/buffer/ByteBufUtf8Writer.java deleted file mode 100644 index a6eaab4ad5eb..000000000000 --- a/platform/platform-impl/src/io/netty/buffer/ByteBufUtf8Writer.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2000-2016 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://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 io.netty.buffer; - -import com.intellij.util.text.CharArrayCharSequence; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.io.NettyKt; - -import java.io.IOException; -import java.io.InputStream; -import java.io.Writer; - -public final class ByteBufUtf8Writer extends Writer { - private final ByteBuf buffer; - - public ByteBufUtf8Writer(@NotNull ByteBuf buffer) { - this.buffer = buffer; - } - - public void write(@NotNull InputStream inputStream, int length) throws IOException { - buffer.writeBytes(inputStream, length); - } - - public void ensureWritable(int minWritableBytes) { - buffer.ensureWritable(minWritableBytes); - } - - @Override - public void write(char[] chars, int off, int len) { - NettyKt.writeUtf8(buffer, new CharArrayCharSequence(chars, off, off + len)); - } - - @Override - public void write(String str) { - NettyKt.writeUtf8(buffer, str); - } - - @Override - public void write(String str, int off, int len) { - ByteBufUtilEx.writeUtf8(buffer, str, off, off + len); - } - - @Override - public Writer append(CharSequence csq) { - if (csq == null) { - ByteBufUtil.writeAscii(buffer, "null"); - } - else { - NettyKt.writeUtf8(buffer, csq); - } - return this; - } - - @Override - public Writer append(CharSequence csq, int start, int end) { - ByteBufUtilEx.writeUtf8(buffer, csq, start, end); - return this; - } - - @Override - public void flush() { - } - - @Override - public void close() { - } -} diff --git a/platform/platform-impl/src/io/netty/buffer/ByteBufUtf8Writer.kt b/platform/platform-impl/src/io/netty/buffer/ByteBufUtf8Writer.kt new file mode 100644 index 000000000000..d8baec212e8b --- /dev/null +++ b/platform/platform-impl/src/io/netty/buffer/ByteBufUtf8Writer.kt @@ -0,0 +1,64 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://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 io.netty.buffer + +import com.intellij.util.io.writeUtf8 +import com.intellij.util.text.CharArrayCharSequence +import java.io.InputStream +import java.io.Writer + +class ByteBufUtf8Writer(private val buffer: ByteBuf) : Writer() { + fun write(inputStream: InputStream, length: Int) { + buffer.writeBytes(inputStream, length) + } + + fun ensureWritable(minWritableBytes: Int) { + buffer.ensureWritable(minWritableBytes) + } + + override fun write(chars: CharArray, off: Int, len: Int) { + buffer.writeUtf8(CharArrayCharSequence(chars, off, off + len)) + } + + override fun write(str: String) { + buffer.writeUtf8(str) + } + + override fun write(str: String, off: Int, len: Int) { + ByteBufUtilEx.writeUtf8(buffer, str, off, off + len) + } + + override fun append(csq: CharSequence?): Writer { + if (csq == null) { + ByteBufUtil.writeAscii(buffer, "null") + } + else { + buffer.writeUtf8(csq) + } + return this + } + + override fun append(csq: CharSequence?, start: Int, end: Int): Writer { + ByteBufUtilEx.writeUtf8(buffer, csq, start, end) + return this + } + + override fun flush() { + } + + override fun close() { + } +} diff --git a/platform/platform-impl/src/org/jetbrains/ide/HttpRequestHandler.java b/platform/platform-impl/src/org/jetbrains/ide/HttpRequestHandler.java deleted file mode 100644 index 075898fd0f47..000000000000 --- a/platform/platform-impl/src/org/jetbrains/ide/HttpRequestHandler.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2000-2016 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://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.ide; - -import com.intellij.openapi.extensions.ExtensionPointName; -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.http.FullHttpRequest; -import io.netty.handler.codec.http.HttpMethod; -import io.netty.handler.codec.http.HttpRequest; -import io.netty.handler.codec.http.QueryStringDecoder; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.io.NettyKt; - -import java.io.IOException; - -public abstract class HttpRequestHandler { - // Your handler will be instantiated on first user request - public static final ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.httpRequestHandler"); - - protected static boolean checkPrefix(@NotNull String uri, @NotNull String prefix) { - if (uri.length() > prefix.length() && uri.charAt(0) == '/' && uri.regionMatches(true, 1, prefix, 0, prefix.length())) { - if ((uri.length() - prefix.length()) == 1) { - return true; - } - else { - char c = uri.charAt(prefix.length() + 1); - return c == '/' || c == '?'; - } - } - return false; - } - - /** - * Write request from browser without Origin will be always blocked regardles of your implementation. - */ - @SuppressWarnings("SpellCheckingInspection") - public boolean isAccessible(@NotNull HttpRequest request) { - String host = NettyKt.getHost(request); - // If attacker.com DNS rebound to 127.0.0.1 and user open site directly — no Origin or Referer headers. - // So we should check Host header. - return host != null && NettyKt.isLocalOrigin(request) && NettyKt.parseAndCheckIsLocalHost("http://" + host); - } - - public boolean isSupported(@NotNull FullHttpRequest request) { - return request.method() == HttpMethod.GET || request.method() == HttpMethod.HEAD; - } - - /** - * @return true if processed successfully, false to pass processing to other handlers. - */ - public abstract boolean process(@NotNull QueryStringDecoder urlDecoder, @NotNull FullHttpRequest request, @NotNull ChannelHandlerContext context) - throws IOException; -} \ No newline at end of file diff --git a/platform/platform-impl/src/org/jetbrains/ide/HttpRequestHandler.kt b/platform/platform-impl/src/org/jetbrains/ide/HttpRequestHandler.kt new file mode 100644 index 000000000000..8312293c5a65 --- /dev/null +++ b/platform/platform-impl/src/org/jetbrains/ide/HttpRequestHandler.kt @@ -0,0 +1,69 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://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.ide + +import com.intellij.openapi.extensions.ExtensionPointName +import com.intellij.util.io.host +import com.intellij.util.io.isLocalOrigin +import com.intellij.util.io.parseAndCheckIsLocalHost +import io.netty.channel.ChannelHandlerContext +import io.netty.handler.codec.http.FullHttpRequest +import io.netty.handler.codec.http.HttpMethod +import io.netty.handler.codec.http.HttpRequest +import io.netty.handler.codec.http.QueryStringDecoder +import java.io.IOException + +abstract class HttpRequestHandler { + companion object { + // Your handler will be instantiated on first user request + val EP_NAME = ExtensionPointName.create("com.intellij.httpRequestHandler")!! + + @JvmStatic + protected fun checkPrefix(uri: String, prefix: String): Boolean { + if (uri.length > prefix.length && uri[0] == '/' && uri.regionMatches(1, prefix, 0, prefix.length, ignoreCase = true)) { + if (uri.length - prefix.length == 1) { + return true + } + else { + val c = uri.get(prefix.length + 1) + return c == '/' || c == '?' + } + } + return false + } + } + + /** + * Write request from browser without Origin will be always blocked regardless of your implementation. + */ + @SuppressWarnings("SpellCheckingInspection") + open fun isAccessible(request: HttpRequest): Boolean { + val host = request.host + // If attacker.com DNS rebound to 127.0.0.1 and user open site directly — no Origin or Referrer headers. + // So we should check Host header. + return host != null && request.isLocalOrigin() && parseAndCheckIsLocalHost("http://$host") + } + + open fun isSupported(request: FullHttpRequest): Boolean { + return request.method() === HttpMethod.GET || request.method() === HttpMethod.HEAD + } + + /** + * @return true if processed successfully, false to pass processing to other handlers. + */ + @Throws(IOException::class) + abstract fun process(urlDecoder: QueryStringDecoder, request: FullHttpRequest, context: ChannelHandlerContext): Boolean +} \ No newline at end of file diff --git a/platform/platform-impl/src/org/jetbrains/io/BuiltInServer.java b/platform/platform-impl/src/org/jetbrains/io/BuiltInServer.java index 550e7446ac55..13f6cee0576c 100644 --- a/platform/platform-impl/src/org/jetbrains/io/BuiltInServer.java +++ b/platform/platform-impl/src/org/jetbrains/io/BuiltInServer.java @@ -34,6 +34,8 @@ import java.util.Random; import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicInteger; +import static com.intellij.util.io.NettyKt.serverBootstrap; + public class BuiltInServer implements Disposable { // Some antiviral software detect viruses by the fact of accessing these ports so we should not touch them to appear innocent. private static final int[] FORBIDDEN_PORTS = {6953, 6969, 6970}; @@ -113,7 +115,7 @@ public class BuiltInServer implements Disposable { boolean tryAnyPort, @Nullable NotNullProducer handler) throws Exception { ChannelRegistrar channelRegistrar = new ChannelRegistrar(); - ServerBootstrap bootstrap = NettyKt.serverBootstrap(eventLoopGroup); + ServerBootstrap bootstrap = serverBootstrap(eventLoopGroup); configureChildHandler(bootstrap, channelRegistrar, handler); int port = bind(firstPort, portsCount, tryAnyPort, bootstrap, channelRegistrar, isEventLoopGroupOwner); return new BuiltInServer(eventLoopGroup, port, channelRegistrar); diff --git a/platform/platform-impl/src/org/jetbrains/io/ChannelBufferToString.java b/platform/platform-impl/src/org/jetbrains/io/ChannelBufferToString.java index bb2878d332fd..83da1f70f73b 100644 --- a/platform/platform-impl/src/org/jetbrains/io/ChannelBufferToString.java +++ b/platform/platform-impl/src/org/jetbrains/io/ChannelBufferToString.java @@ -20,11 +20,13 @@ import org.jetbrains.annotations.NotNull; import java.io.IOException; +import static com.intellij.util.io.NettyKt.readUtf8; + @SuppressWarnings("unused") @Deprecated public final class ChannelBufferToString { @NotNull public static CharSequence readChars(@NotNull ByteBuf buffer) throws IOException { - return NettyKt.readUtf8(buffer); + return readUtf8(buffer); } } diff --git a/platform/platform-impl/src/org/jetbrains/io/DelegatingHttpRequestHandler.kt b/platform/platform-impl/src/org/jetbrains/io/DelegatingHttpRequestHandler.kt index ee17b364b0d7..1ef83fc23726 100644 --- a/platform/platform-impl/src/org/jetbrains/io/DelegatingHttpRequestHandler.kt +++ b/platform/platform-impl/src/org/jetbrains/io/DelegatingHttpRequestHandler.kt @@ -18,6 +18,7 @@ package org.jetbrains.io import com.intellij.openapi.application.ex.ApplicationInfoEx import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.util.IconLoader +import com.intellij.util.io.isWriteFromBrowserWithoutOrigin import com.intellij.util.ui.UIUtil import io.netty.buffer.Unpooled import io.netty.channel.ChannelHandler @@ -82,7 +83,7 @@ internal class DelegatingHttpRequestHandler : DelegatingHttpRequestHandlerBase() @Suppress("OverridingDeprecatedMember") override fun exceptionCaught(context: ChannelHandlerContext, cause: Throwable) { try { - context.channel().attr(PREV_HANDLER).remove() + context.channel().attr(PREV_HANDLER).set(null) } finally { @Suppress("DEPRECATION") diff --git a/platform/platform-impl/src/org/jetbrains/io/NettyUtil.java b/platform/platform-impl/src/org/jetbrains/io/NettyUtil.java index 7b779dfbc95a..9c9ba6fb96a9 100644 --- a/platform/platform-impl/src/org/jetbrains/io/NettyUtil.java +++ b/platform/platform-impl/src/org/jetbrains/io/NettyUtil.java @@ -16,13 +16,10 @@ package org.jetbrains.io; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.util.Condition; import io.netty.bootstrap.Bootstrap; -import io.netty.bootstrap.BootstrapUtil; import io.netty.channel.*; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioSocketChannel; -import io.netty.channel.socket.oio.OioSocketChannel; import io.netty.handler.codec.http.HttpMethod; import io.netty.handler.codec.http.HttpObjectAggregator; import io.netty.handler.codec.http.HttpRequestDecoder; @@ -33,17 +30,12 @@ import io.netty.handler.codec.http.cors.CorsHandler; import io.netty.handler.stream.ChunkedWriteHandler; import io.netty.util.concurrent.GlobalEventExecutor; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; -import org.jetbrains.concurrency.AsyncPromise; -import org.jetbrains.concurrency.Promise; import org.jetbrains.ide.PooledThreadExecutor; import java.io.IOException; import java.net.BindException; import java.net.ConnectException; -import java.net.InetSocketAddress; -import java.net.Socket; import java.util.concurrent.TimeUnit; public final class NettyUtil { @@ -78,114 +70,6 @@ public final class NettyUtil { } } - @Nullable - static Channel doConnect(@NotNull Bootstrap bootstrap, - @NotNull InetSocketAddress remoteAddress, - @Nullable AsyncPromise promise, - int maxAttemptCount, - @NotNull Condition stopCondition) throws Throwable { - int attemptCount = 0; - if (bootstrap.config().group() instanceof NioEventLoopGroup) { - return connectNio(bootstrap, remoteAddress, promise, maxAttemptCount, stopCondition, attemptCount); - } - - bootstrap.validate(); - - Socket socket; - while (true) { - try { - //noinspection IOResourceOpenedButNotSafelyClosed,SocketOpenedButNotSafelyClosed - socket = new Socket(remoteAddress.getAddress(), remoteAddress.getPort()); - break; - } - catch (IOException e) { - if (stopCondition.value(null) || (promise != null && promise.getState() != Promise.State.PENDING)) { - return null; - } - else if (maxAttemptCount == -1) { - if (sleep(promise, 300)) { - return null; - } - attemptCount++; - } - else if (++attemptCount < maxAttemptCount) { - if (sleep(promise, attemptCount * MIN_START_TIME)) { - return null; - } - } - else { - if (promise != null) { - promise.setError(e); - } - return null; - } - } - } - - OioSocketChannel channel = new OioSocketChannel(socket); - BootstrapUtil.initAndRegister(channel, bootstrap).sync(); - return channel; - } - - @Nullable - private static Channel connectNio(@NotNull Bootstrap bootstrap, - @NotNull InetSocketAddress remoteAddress, - @Nullable AsyncPromise promise, - int maxAttemptCount, - @NotNull Condition stopCondition, - int attemptCount) { - while (true) { - ChannelFuture future = bootstrap.connect(remoteAddress).awaitUninterruptibly(); - if (future.isSuccess()) { - if (!future.channel().isOpen()) { - continue; - } - return future.channel(); - } - else if (stopCondition.value(null) || (promise != null && promise.getState() == Promise.State.REJECTED)) { - return null; - } - else if (maxAttemptCount == -1) { - if (sleep(promise, 300)) { - return null; - } - attemptCount++; - } - else if (++attemptCount < maxAttemptCount) { - if (sleep(promise, attemptCount * MIN_START_TIME)) { - return null; - } - } - else { - @SuppressWarnings("ThrowableResultOfMethodCallIgnored") - Throwable cause = future.cause(); - if (promise != null) { - if (cause == null) { - promise.setError("Cannot connect: unknown error"); - } - else { - promise.setError(cause); - } - } - return null; - } - } - } - - private static boolean sleep(@Nullable AsyncPromise promise, int time) { - try { - //noinspection BusyWait - Thread.sleep(time); - } - catch (InterruptedException ignored) { - if (promise != null) { - promise.setError("Interrupted"); - } - return true; - } - return false; - } - private static boolean isAsWarning(@NotNull Throwable throwable) { String message = throwable.getMessage(); if (message == null) { diff --git a/platform/platform-impl/src/org/jetbrains/io/netty.kt b/platform/platform-impl/src/org/jetbrains/io/netty.kt index 4642a40a243f..352995aa9cc9 100644 --- a/platform/platform-impl/src/org/jetbrains/io/netty.kt +++ b/platform/platform-impl/src/org/jetbrains/io/netty.kt @@ -15,189 +15,5 @@ */ package org.jetbrains.io -import com.google.common.net.InetAddresses -import com.intellij.openapi.util.Condition -import com.intellij.openapi.util.Conditions -import com.intellij.util.Url -import com.intellij.util.Urls -import com.intellij.util.net.NetUtils -import io.netty.bootstrap.Bootstrap -import io.netty.bootstrap.ServerBootstrap -import io.netty.buffer.ByteBuf -import io.netty.channel.* -import io.netty.channel.nio.NioEventLoopGroup -import io.netty.channel.oio.OioEventLoopGroup -import io.netty.channel.socket.nio.NioServerSocketChannel -import io.netty.channel.socket.oio.OioServerSocketChannel -import io.netty.channel.socket.oio.OioSocketChannel -import io.netty.handler.codec.http.HttpHeaderNames -import io.netty.handler.codec.http.HttpMethod -import io.netty.handler.codec.http.HttpRequest -import io.netty.handler.ssl.SslHandler -import io.netty.resolver.HostsFileEntriesResolver -import io.netty.util.concurrent.GenericFutureListener -import org.jetbrains.concurrency.AsyncPromise -import org.jetbrains.ide.PooledThreadExecutor -import java.io.IOException -import java.net.InetAddress -import java.net.InetSocketAddress -import java.net.NetworkInterface -import java.util.concurrent.TimeUnit - -inline fun Bootstrap.handler(crossinline task: (Channel) -> Unit): Bootstrap { - handler(object : ChannelInitializer() { - override fun initChannel(channel: Channel) { - task(channel) - } - }) - return this -} - -fun serverBootstrap(group: EventLoopGroup): ServerBootstrap { - val bootstrap = ServerBootstrap() - .group(group) - .channel(if (group is NioEventLoopGroup) NioServerSocketChannel::class.java else OioServerSocketChannel::class.java) - bootstrap.childOption(ChannelOption.TCP_NODELAY, true).childOption(ChannelOption.SO_KEEPALIVE, true) - return bootstrap -} - -fun oioClientBootstrap(): Bootstrap { - val bootstrap = Bootstrap().group(OioEventLoopGroup(1, PooledThreadExecutor.INSTANCE)).channel(OioSocketChannel::class.java) - bootstrap.option(ChannelOption.TCP_NODELAY, true).option(ChannelOption.SO_KEEPALIVE, true) - return bootstrap -} - -inline fun ChannelFuture.addChannelListener(crossinline listener: (future: ChannelFuture) -> Unit) { - addListener(GenericFutureListener { listener(it) }) -} - -// if NIO, so, it is shared and we must not shutdown it -fun EventLoop.shutdownIfOio() { - if (this is OioEventLoopGroup) { - @Suppress("USELESS_CAST") - (this as OioEventLoopGroup).shutdownGracefully(1L, 2L, TimeUnit.NANOSECONDS) - } -} - -// Event loop will be shut downed only if OIO -fun Channel.closeAndShutdownEventLoop() { - val eventLoop = eventLoop() - try { - close().awaitUninterruptibly() - } - finally { - eventLoop.shutdownIfOio() - } -} - -@JvmOverloads -fun Bootstrap.connect(remoteAddress: InetSocketAddress, promise: AsyncPromise<*>? = null, maxAttemptCount: Int = NettyUtil.DEFAULT_CONNECT_ATTEMPT_COUNT, stopCondition: Condition? = null): Channel? { - try { - return NettyUtil.doConnect(this, remoteAddress, promise, maxAttemptCount, stopCondition ?: Conditions.alwaysFalse()) - } - catch (e: Throwable) { - promise?.setError(e) - return null - } -} - -val Channel.uriScheme: String - get() = if (pipeline().get(SslHandler::class.java) == null) "http" else "https" - -val HttpRequest.host: String? - get() = headers().getAsString(HttpHeaderNames.HOST) - -val HttpRequest.origin: String? - get() = headers().getAsString(HttpHeaderNames.ORIGIN) - -val HttpRequest.referrer: String? - get() = headers().getAsString(HttpHeaderNames.REFERER) - -val HttpRequest.userAgent: String? - get() = headers().getAsString(HttpHeaderNames.USER_AGENT) - -inline fun ByteBuf.releaseIfError(task: () -> T): T { - try { - return task() - } - catch (e: Exception) { - try { - release() - } - finally { - throw e - } - } -} - -fun isLocalHost(host: String, onlyAnyOrLoopback: Boolean, hostsOnly: Boolean = false): Boolean { - if (NetUtils.isLocalhost(host)) { - return true - } - - // if IP address, it is safe to use getByName (not affected by DNS rebinding) - if (onlyAnyOrLoopback && !InetAddresses.isInetAddress(host)) { - return false - } - - fun InetAddress.isLocal() = isAnyLocalAddress || isLoopbackAddress || NetworkInterface.getByInetAddress(this) != null - - try { - val address = InetAddress.getByName(host) - if (!address.isLocal()) { - return false - } - // be aware - on windows hosts file doesn't contain localhost - // hosts can contain remote addresses, so, we check it - if (hostsOnly && !InetAddresses.isInetAddress(host)) { - return HostsFileEntriesResolver.DEFAULT.address(host).let { it != null && it.isLocal() } - } - else { - return true - } - } - catch (ignored: IOException) { - return false - } -} - -@JvmOverloads -fun HttpRequest.isLocalOrigin(onlyAnyOrLoopback: Boolean = true, hostsOnly: Boolean = false) = parseAndCheckIsLocalHost(origin, onlyAnyOrLoopback, hostsOnly) && parseAndCheckIsLocalHost(referrer, onlyAnyOrLoopback, hostsOnly) - -private fun isTrustedChromeExtension(url: Url): Boolean { - return url.scheme == "chrome-extension" && (url.authority == "hmhgeddbohgjknpmjagkdomcpobmllji" || url.authority == "offnedcbhjldheanlbojaefbfbllddna") -} - -private val Url.host: String? - get() = authority?.let { - val portIndex = it.indexOf(':') - if (portIndex > 0) it.substring(0, portIndex) else it - } - -@JvmOverloads -fun parseAndCheckIsLocalHost(uri: String?, onlyAnyOrLoopback: Boolean = true, hostsOnly: Boolean = false): Boolean { - if (uri == null || uri == "about:blank") { - return true - } - - try { - val parsedUri = Urls.parse(uri, false) ?: return false - val host = parsedUri.host - return host != null && (isTrustedChromeExtension(parsedUri) || isLocalHost(host, onlyAnyOrLoopback, hostsOnly)) - } - catch (ignored: Exception) { - } - return false -} - -fun HttpRequest.isRegularBrowser() = userAgent?.startsWith("Mozilla/5.0") ?: false - -// forbid POST requests from browser without Origin -fun HttpRequest.isWriteFromBrowserWithoutOrigin(): Boolean { - val method = method() - return origin.isNullOrEmpty() && isRegularBrowser() && (method == HttpMethod.POST || method == HttpMethod.PATCH || method == HttpMethod.PUT || method == HttpMethod.DELETE) -} - -fun ByteBuf.readUtf8() = toString(Charsets.UTF_8) - -fun ByteBuf.writeUtf8(data: CharSequence) = writeCharSequence(data, Charsets.UTF_8) \ No newline at end of file +// used in Go +fun oioClientBootstrap() = com.intellij.util.io.oioClientBootstrap() \ No newline at end of file diff --git a/platform/platform-resources-en/src/messages/VcsBundle.properties b/platform/platform-resources-en/src/messages/VcsBundle.properties index 1abdb4ced983..1028a7613899 100644 --- a/platform/platform-resources-en/src/messages/VcsBundle.properties +++ b/platform/platform-resources-en/src/messages/VcsBundle.properties @@ -506,6 +506,7 @@ progress.loading.diff.revisions=Getting revisions content show.diff.with.local.action.text=Show Diff with Local show.diff.with.local.action.description=Compare selected revision with the local version of the file unshelve.changes.dialog.title=Unshelve Changes +unshelve.changes.progress.title=Unshelving Changes... ignored.edit.multiple.directories=Selected {0} directories close.tab.action.name=Close revert.changes.title=Revert Changes diff --git a/platform/platform-resources/src/idea/PlatformActions.xml b/platform/platform-resources/src/idea/PlatformActions.xml index 09ffd11804b1..d317320e533c 100644 --- a/platform/platform-resources/src/idea/PlatformActions.xml +++ b/platform/platform-resources/src/idea/PlatformActions.xml @@ -249,8 +249,8 @@ - - + + @@ -615,8 +615,8 @@ - - + + diff --git a/platform/platform-resources/src/idea/PlatformLangActionManager.xml b/platform/platform-resources/src/idea/PlatformLangActionManager.xml index b4fb5c71ac4d..ad5e80316343 100644 --- a/platform/platform-resources/src/idea/PlatformLangActionManager.xml +++ b/platform/platform-resources/src/idea/PlatformLangActionManager.xml @@ -4,7 +4,8 @@ - + diff --git a/platform/platform-resources/src/idea/VcsActions.xml b/platform/platform-resources/src/idea/VcsActions.xml index 3c4258ffba85..e67a8f987486 100644 --- a/platform/platform-resources/src/idea/VcsActions.xml +++ b/platform/platform-resources/src/idea/VcsActions.xml @@ -93,6 +93,10 @@ icon="AllIcons.Actions.Submit1"/> + + + @@ -159,6 +163,10 @@ + + + diff --git a/platform/projectModel-impl/src/com/intellij/configurationStore/ExternalizableSchemeAdapter.kt b/platform/projectModel-impl/src/com/intellij/openapi/options/ExternalizableSchemeAdapter.kt similarity index 100% rename from platform/projectModel-impl/src/com/intellij/configurationStore/ExternalizableSchemeAdapter.kt rename to platform/projectModel-impl/src/com/intellij/openapi/options/ExternalizableSchemeAdapter.kt diff --git a/platform/script-debugger/backend/src/StandaloneVmHelper.kt b/platform/script-debugger/backend/src/StandaloneVmHelper.kt index 782e6ab8c0c4..c3814cce6230 100644 --- a/platform/script-debugger/backend/src/StandaloneVmHelper.kt +++ b/platform/script-debugger/backend/src/StandaloneVmHelper.kt @@ -15,12 +15,12 @@ */ package org.jetbrains.debugger +import com.intellij.util.io.addChannelListener +import com.intellij.util.io.shutdownIfOio import io.netty.channel.Channel import org.jetbrains.concurrency.AsyncPromise import org.jetbrains.concurrency.Promise import org.jetbrains.concurrency.resolvedPromise -import org.jetbrains.io.addChannelListener -import org.jetbrains.io.shutdownIfOio import org.jetbrains.jsonProtocol.Request import org.jetbrains.rpc.CONNECTION_CLOSED_MESSAGE import org.jetbrains.rpc.LOG diff --git a/platform/script-debugger/backend/src/util.kt b/platform/script-debugger/backend/src/util.kt index cdc69cdf5bd2..0918579830b9 100644 --- a/platform/script-debugger/backend/src/util.kt +++ b/platform/script-debugger/backend/src/util.kt @@ -19,10 +19,10 @@ import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.util.io.FileUtil import com.intellij.openapi.util.registry.Registry import com.intellij.util.io.CharSequenceBackedByChars +import com.intellij.util.io.addChannelListener import io.netty.buffer.ByteBuf import io.netty.channel.Channel import org.jetbrains.annotations.PropertyKey -import org.jetbrains.io.addChannelListener import java.io.File import java.io.FileOutputStream import java.nio.CharBuffer diff --git a/platform/script-debugger/debugger-ui/script-debugger-ui.iml b/platform/script-debugger/debugger-ui/script-debugger-ui.iml index f77248634d16..8e155859df27 100644 --- a/platform/script-debugger/debugger-ui/script-debugger-ui.iml +++ b/platform/script-debugger/debugger-ui/script-debugger-ui.iml @@ -4,7 +4,7 @@ - + diff --git a/platform/script-debugger/debugger-ui/src/RemoteVmConnection.kt b/platform/script-debugger/debugger-ui/src/RemoteVmConnection.kt index 8b2581628371..3ff09b773f61 100644 --- a/platform/script-debugger/debugger-ui/src/RemoteVmConnection.kt +++ b/platform/script-debugger/debugger-ui/src/RemoteVmConnection.kt @@ -21,6 +21,7 @@ import com.intellij.openapi.ui.popup.JBPopupFactory import com.intellij.openapi.util.Condition import com.intellij.ui.ColoredListCellRenderer import com.intellij.ui.components.JBList +import com.intellij.util.io.connect import com.intellij.util.io.socketConnection.ConnectionStatus import io.netty.bootstrap.Bootstrap import io.netty.channel.ChannelFuture @@ -31,7 +32,6 @@ import org.jetbrains.concurrency.rejectedPromise import org.jetbrains.concurrency.resolvedPromise import org.jetbrains.debugger.Vm import org.jetbrains.io.NettyUtil -import org.jetbrains.io.connect import org.jetbrains.rpc.LOG import java.net.ConnectException import java.net.InetSocketAddress diff --git a/platform/script-debugger/debugger-ui/testSrc/Content.java b/platform/script-debugger/debugger-ui/testSrc/Content.java new file mode 100644 index 000000000000..ff53d141f4aa --- /dev/null +++ b/platform/script-debugger/debugger-ui/testSrc/Content.java @@ -0,0 +1,26 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://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.debugger; + +import com.intellij.util.SmartList; + +import java.util.List; + +public final class Content { + public final List topGroups = new SmartList<>(); + public final List values = new SmartList<>(); + public final List bottomGroups = new SmartList<>(); +} \ No newline at end of file diff --git a/platform/script-debugger/debugger-ui/testSrc/org/jetbrains/debugger/TestCompositeNode.java b/platform/script-debugger/debugger-ui/testSrc/TestCompositeNode.java similarity index 100% rename from platform/script-debugger/debugger-ui/testSrc/org/jetbrains/debugger/TestCompositeNode.java rename to platform/script-debugger/debugger-ui/testSrc/TestCompositeNode.java diff --git a/platform/script-debugger/debugger-ui/testSrc/org/jetbrains/debugger/TestValueNode.java b/platform/script-debugger/debugger-ui/testSrc/TestValueNode.java similarity index 100% rename from platform/script-debugger/debugger-ui/testSrc/org/jetbrains/debugger/TestValueNode.java rename to platform/script-debugger/debugger-ui/testSrc/TestValueNode.java diff --git a/platform/script-debugger/debugger-ui/testSrc/org/jetbrains/debugger/Content.java b/platform/script-debugger/debugger-ui/testSrc/org/jetbrains/debugger/Content.java deleted file mode 100644 index 55fd5dbd91d5..000000000000 --- a/platform/script-debugger/debugger-ui/testSrc/org/jetbrains/debugger/Content.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.jetbrains.debugger; - -import com.intellij.util.SmartList; - -import java.util.List; - -public final class Content { - public final List topGroups = new SmartList<>(); - public final List values = new SmartList<>(); - public final List bottomGroups = new SmartList<>(); -} \ No newline at end of file diff --git a/platform/script-debugger/protocol/protocol-reader-runtime/src/org/jetbrains/jsonProtocol/OutMessage.kt b/platform/script-debugger/protocol/protocol-reader-runtime/src/org/jetbrains/jsonProtocol/OutMessage.kt index 31f8c204d278..318bf2743481 100644 --- a/platform/script-debugger/protocol/protocol-reader-runtime/src/org/jetbrains/jsonProtocol/OutMessage.kt +++ b/platform/script-debugger/protocol/protocol-reader-runtime/src/org/jetbrains/jsonProtocol/OutMessage.kt @@ -18,14 +18,13 @@ package org.jetbrains.jsonProtocol import com.google.gson.stream.JsonWriter import com.intellij.openapi.vfs.CharsetToolkit import com.intellij.util.containers.isNullOrEmpty +import com.intellij.util.io.writeUtf8 import gnu.trove.TIntArrayList import gnu.trove.TIntHashSet import io.netty.buffer.ByteBuf import io.netty.buffer.ByteBufAllocator import io.netty.buffer.ByteBufUtf8Writer import org.jetbrains.io.JsonUtil -import org.jetbrains.io.writeUtf8 -import java.io.IOException open class OutMessage() { val buffer: ByteBuf = ByteBufAllocator.DEFAULT.heapBuffer() @@ -204,19 +203,16 @@ open class OutMessage() { beginArguments() writer.name(name).value(value?.toString() ?: null) } +} - companion object { - @Throws(IOException::class) - fun prepareWriteRaw(message: OutMessage, name: String) { - message.writer.name(name).nullValue() - val itemBuffer = message.buffer - itemBuffer.writerIndex(itemBuffer.writerIndex() - "null".length) - } +fun prepareWriteRaw(message: OutMessage, name: String) { + message.writer.name(name).nullValue() + val itemBuffer = message.buffer + itemBuffer.writerIndex(itemBuffer.writerIndex() - "null".length) +} - fun doWriteRaw(message: OutMessage, rawValue: String) { - message.buffer.writeUtf8(rawValue) - } - } +fun doWriteRaw(message: OutMessage, rawValue: String) { + message.buffer.writeUtf8(rawValue) } fun OutMessage.writeEnum(name: String, value: Enum<*>?, defaultValue: Enum<*>?) { @@ -238,7 +234,7 @@ fun OutMessage.writeString(name: String, value: CharSequence?, defaultValue: Cha fun OutMessage.writeString(name: String, value: CharSequence) { beginArguments() - OutMessage.prepareWriteRaw(this, name) + prepareWriteRaw(this, name) JsonUtil.escape(value, buffer) } diff --git a/platform/testFramework/testSrc/com/intellij/openapi/keymap/KeymapsTestCase.java b/platform/testFramework/testSrc/com/intellij/openapi/keymap/KeymapsTestCase.java index 8b50bb5ef688..5c6aa34f9d86 100644 --- a/platform/testFramework/testSrc/com/intellij/openapi/keymap/KeymapsTestCase.java +++ b/platform/testFramework/testSrc/com/intellij/openapi/keymap/KeymapsTestCase.java @@ -107,6 +107,8 @@ public abstract class KeymapsTestCase extends PlatformTestCase { { "control alt R", "org.jetbrains.plugins.ruby.tasks.rake.actions.RakeTasksPopupAction", "Django.RunManageTaskAction"}, { "control alt UP", "PreviousOccurence", "Console.TableResult.PreviousPage"}, { "control alt N", "Inline", "Console.TableResult.SetNull"}, + { "ctrl alt H", "CallHierarchy", "ChangesView.ShelveSilently"}, + { "ctrl alt U", "ShowUmlDiagramPopup", "ChangesView.UnshelveSilently"}, { "control MINUS", "CollapseAll", "CollapseRegion"}, { "control PERIOD", "EditorChooseLookupItemDot", "CollapseSelection"}, { "shift DELETE", "$Cut", "Maven.Uml.Exclude"}, @@ -118,7 +120,7 @@ public abstract class KeymapsTestCase extends PlatformTestCase { { "shift alt T", "tasks.switch", "tasks.switch.toolbar"}, { "shift control D", "TagDocumentationNavigation", "Diff.ShowSettingsPopup", "Uml.ShowDiff"}, { "shift control DOWN", "ResizeToolWindowDown", "MoveStatementDown"}, - { "shift control ENTER", "EditorChooseLookupItemCompleteStatement", "EditorCompleteStatement", "Console.Jpa.GenerateSql"}, + { "shift control ENTER", "EditorCompleteStatement", "Console.Jpa.GenerateSql"}, { "shift control F10", "Console.Open", "RunClass", "RunTargetAction"}, { "shift control F8", "ViewBreakpoints", "EditBreakpoint"}, { "shift control G", "ClassTemplateNavigation", "GoToClass"}, @@ -318,7 +320,7 @@ public abstract class KeymapsTestCase extends PlatformTestCase { { "shift alt F9", "ChooseDebugConfiguration", "ValidateXml", "ValidateJsp"}, { "shift alt D", "ToggleFloatingMode", "hg4idea.QFold"}, { "shift control DOWN", "EditorDuplicate", "ResizeToolWindowDown", }, - { "shift control ENTER", "EditorChooseLookupItemCompleteStatement", "EditorCompleteStatement", "Console.Jpa.GenerateSql"}, + { "shift control ENTER", "EditorCompleteStatement", "Console.Jpa.GenerateSql"}, { "shift control F7", "HighlightUsagesInFile", "XDebugger.NewWatch"}, { "shift control UP", "EditorDuplicate", "ResizeToolWindowUp", }, { "shift control alt P", "Print", "Graph.Print"}, @@ -338,7 +340,7 @@ public abstract class KeymapsTestCase extends PlatformTestCase { { "control P", "FileChooser.TogglePathShowing", "FindInPath"}, { "shift control A", "SaveAll", "GotoAction"}, { "shift control E", "RecentChangedFiles", "ExtractMethod"}, - { "shift control ENTER", "EditorChooseLookupItemCompleteStatement", "FindUsages", "Console.Jpa.GenerateSql"}, + { "shift control ENTER", "FindUsages", "Console.Jpa.GenerateSql"}, { "shift control F6", "NextTab", "ChangeTypeSignature"}, { "shift control G", "GotoSymbol", "ClassTemplateNavigation", "GoToClass"}, { "control SUBTRACT", "CollapseAll", "CollapseRegion"}, diff --git a/platform/util/resources/misc/registry.properties b/platform/util/resources/misc/registry.properties index d8d38f8a4a09..00712e1432d9 100644 --- a/platform/util/resources/misc/registry.properties +++ b/platform/util/resources/misc/registry.properties @@ -107,7 +107,6 @@ ide.tree.uiLockAttempt=250 ide.tree.deferred.icon.invalidates.cache=true ide.splitter.mouseZone=6 -ide.smart.horizontal.scrolling=false ide.scroll.new.layout=true ide.scroll.align.component=true ide.scroll.background.auto=true @@ -806,3 +805,6 @@ ide.remote.interpreters.use.rsync.description=Use rsync utility to synchronize r spring.initializr.new.ui=false spring.initializr.new.ui.description=Use new UI for dependencies panel + +javafx.fxml.controller.from.loader=false +javafx.fxml.controller.from.loader.description=Resolve FXML controllers specified with FXMLLoader.setController() diff --git a/platform/util/src/com/intellij/icons/AllIcons.java b/platform/util/src/com/intellij/icons/AllIcons.java index d139c7d991bc..d08e2f297f6d 100644 --- a/platform/util/src/com/intellij/icons/AllIcons.java +++ b/platform/util/src/com/intellij/icons/AllIcons.java @@ -1240,6 +1240,8 @@ public class AllIcons { public static final Icon Not_equal = IconLoader.getIcon("/vcs/not_equal.png"); // 16x16 public static final Icon Remove = IconLoader.getIcon("/vcs/remove.png"); // 16x16 public static final Icon ResetStrip = IconLoader.getIcon("/vcs/resetStrip.png"); // 16x16 + public static final Icon SilentShelve = IconLoader.getIcon("/vcs/silentShelve.png"); // 16x16 + public static final Icon SilentUnshelve = IconLoader.getIcon("/vcs/silentUnshelve.png"); // 16x16 public static final Icon StripDown = IconLoader.getIcon("/vcs/stripDown.png"); // 16x16 public static final Icon StripNull = IconLoader.getIcon("/vcs/stripNull.png"); // 16x16 public static final Icon StripUp = IconLoader.getIcon("/vcs/stripUp.png"); // 16x16 diff --git a/platform/util/src/com/intellij/util/ui/UIUtil.java b/platform/util/src/com/intellij/util/ui/UIUtil.java index 1094deacb77a..ad08dac48a50 100644 --- a/platform/util/src/com/intellij/util/ui/UIUtil.java +++ b/platform/util/src/com/intellij/util/ui/UIUtil.java @@ -1780,32 +1780,17 @@ public class UIUtil { } /** - * Creates a HiDPI-aware BufferedImage + * Creates a HiDPI-aware BufferedImage in device scale. * * @param width the width in user coordinate space * @param height the height in user coordinate space * @param type the type of the image * - * @return a HiDPI-aware image + * @return a HiDPI-aware BufferedImage in device scale */ @NotNull public static BufferedImage createImage(int width, int height, int type) { - return createImage(width, height, type, true); - } - - /** - * Creates a HiDPI-aware or plain BufferedImage - * - * @param width the width in user or device coordinate space - * @param height the height in user or device coordinate space - * @param type the type of the image - * @param hidpiAware whether the image should be HiDPI-aware - * - * @return a HiDPI-aware or plain image - */ - @NotNull - public static BufferedImage createImage(int width, int height, int type, boolean hidpiAware) { - if (hidpiAware && isRetina()) { + if (isRetina()) { return RetinaImage.create(width, height, type); } //noinspection UndesirableClassUsage @@ -1813,14 +1798,14 @@ public class UIUtil { } /** - * Creates a BufferedImage with HiDPI-awareness matching the graphics. + * Creates a HiDPI-aware BufferedImage in the graphics scale. * - * @param g the graphics to match + * @param g the graphics of the referent scale * @param width the width in user coordinate space * @param height the height in user coordinate space * @param type the type of the image * - * @return an image matching the graphics + * @return a HiDPI-aware BufferedImage in the graphics scale */ @NotNull public static BufferedImage createImageForGraphics(Graphics2D g, int width, int height, int type) { diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/FilePathImpl.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/FilePathImpl.java index bb1adb67f74d..d40c255c5118 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/FilePathImpl.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/FilePathImpl.java @@ -36,7 +36,7 @@ import java.nio.charset.Charset; /** * It is kept for compatibility reasons: some plugins still refer this obsolete class. * - * @deprecated Use {@link LocalFilePath} instead. To remove in IDEA 16. + * @deprecated Use {@link LocalFilePath} instead. */ @Deprecated public class FilePathImpl implements FilePath { @@ -47,6 +47,11 @@ public class FilePathImpl implements FilePath { myPath = FileUtil.toCanonicalPath(path); myIsDirectory = isDirectory; } + + /** + * @deprecated Use {@link LocalFilePath}. + */ + @Deprecated public FilePathImpl(@NotNull VirtualFile file) { this(file.getPath(), file.isDirectory()); } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateToggleAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateToggleAction.java index 3c4a87319999..3e224d012141 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateToggleAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateToggleAction.java @@ -104,7 +104,7 @@ public class AnnotateToggleAction extends ToggleAction implements DumbAware { fileAnnotation.setReloader(newFileAnnotation -> { if (editor.getGutter().isAnnotationsShown()) { - assert Comparing.equal(currentFile, newFileAnnotation.getFile()); + assert Comparing.equal(fileAnnotation.getFile(), newFileAnnotation.getFile()); doAnnotate(editor, project, currentFile, newFileAnnotation, vcs, upToDateLineNumberProvider); } }); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/VcsPreviewPanel.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/VcsPreviewPanel.java index 3cbab72e353a..616615faaedd 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/VcsPreviewPanel.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/VcsPreviewPanel.java @@ -52,6 +52,8 @@ class VcsPreviewPanel implements PreviewPanel { public VcsPreviewPanel() { DocumentImpl document = new DocumentImpl("", true); myEditor = (EditorEx)EditorFactory.getInstance().createViewer(document); + myEditor.getGutterComponentEx().setForceShowRightFreePaintersArea(true); + myEditor.getSettings().setFoldingOutlineShown(true); } @Override diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangesViewManager.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangesViewManager.java index 2ff7491a491b..ec4409176f40 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangesViewManager.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangesViewManager.java @@ -22,6 +22,7 @@ import com.intellij.icons.AllIcons; import com.intellij.ide.CommonActionsManager; import com.intellij.ide.TreeExpander; import com.intellij.ide.actions.ContextHelpAction; +import com.intellij.ide.dnd.DnDEvent; import com.intellij.lifecycle.PeriodicalTasksCloser; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.*; @@ -29,6 +30,7 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.components.*; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.SimpleToolWindowPanel; @@ -41,15 +43,12 @@ import com.intellij.openapi.vcs.VcsBundle; import com.intellij.openapi.vcs.VcsConfiguration; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.changes.actions.IgnoredSettingsAction; -import com.intellij.openapi.vcs.changes.ui.ChangesDnDSupport; -import com.intellij.openapi.vcs.changes.ui.ChangesListView; -import com.intellij.openapi.vcs.changes.ui.ChangesViewContentManager; -import com.intellij.openapi.vcs.changes.ui.TreeModelBuilder; +import com.intellij.openapi.vcs.changes.shelf.ShelveChangesManager; +import com.intellij.openapi.vcs.changes.ui.*; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.impl.DebugUtil; import com.intellij.ui.*; import com.intellij.ui.content.Content; -import com.intellij.ui.content.ContentFactory; import com.intellij.util.Alarm; import com.intellij.util.FunctionUtil; import com.intellij.util.ui.JBUI; @@ -148,7 +147,7 @@ public class ChangesViewManager implements ChangesViewI, ProjectComponent, Persi } }); if (ApplicationManager.getApplication().isHeadlessEnvironment()) return; - myContent = ContentFactory.SERVICE.getInstance().createContent(createChangeViewComponent(), ChangesViewContentManager.LOCAL_CHANGES, false); + myContent = new MyChangeViewContent(createChangeViewComponent(), ChangesViewContentManager.LOCAL_CHANGES, false); myContent.setCloseable(false); myContentManager.addContent(myContent); @@ -560,4 +559,33 @@ public class ChangesViewManager implements ChangesViewI, ProjectComponent, Persi } } } + + private class MyChangeViewContent extends DnDTargetContentAdapter { + private MyChangeViewContent(JComponent component, String displayName, boolean isLockable) { + super(component, displayName, isLockable); + } + + @Override + public void drop(DnDEvent event) { + Object attachedObject = event.getAttachedObject(); + if (attachedObject instanceof ShelvedChangeListDragBean) { + FileDocumentManager.getInstance().saveAllDocuments(); + ShelvedChangeListDragBean shelvedBean = (ShelvedChangeListDragBean)attachedObject; + ShelveChangesManager.getInstance(myProject) + .unshelveSilentlyAsynchronously(myProject, shelvedBean.getShelvedChangelists(), shelvedBean.getChanges(), + shelvedBean.getBinaryFiles(), null); + } + } + + @Override + public boolean update(DnDEvent event) { + Object attachedObject = event.getAttachedObject(); + if (attachedObject instanceof ShelvedChangeListDragBean) { + ShelvedChangeListDragBean shelveBean = (ShelvedChangeListDragBean)attachedObject; + event.setDropPossible(!shelveBean.getShelvedChangelists().isEmpty()); + return false; + } + return true; + } + } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/DnDTargetContentAdapter.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/DnDTargetContentAdapter.java new file mode 100644 index 000000000000..54521a438633 --- /dev/null +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/DnDTargetContentAdapter.java @@ -0,0 +1,36 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://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.vcs.changes; + +import com.intellij.ide.dnd.DnDTarget; +import com.intellij.ui.content.impl.ContentImpl; + +import javax.swing.*; +import java.awt.*; + +public abstract class DnDTargetContentAdapter extends ContentImpl implements DnDTarget { + protected DnDTargetContentAdapter(JComponent component, String displayName, boolean isLockable) { + super(component, displayName, isLockable); + } + + @Override + public void cleanUpOnLeave() { + } + + @Override + public void updateDraggedImage(Image image, Point dropPoint, Point imageOffset) { + } +} \ No newline at end of file diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/CreatePatchFromChangesAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/CreatePatchFromChangesAction.java index 04855bf49385..43afabbd39fb 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/CreatePatchFromChangesAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/CreatePatchFromChangesAction.java @@ -52,9 +52,9 @@ public class CreatePatchFromChangesAction extends AnAction implements DumbAware final Change[] changes = e.getData(VcsDataKeys.CHANGES); if ((changes == null) || (changes.length == 0)) return; String commitMessage = null; - ShelvedChangeList[] shelvedChangeLists = e.getData(ShelvedChangesViewManager.SHELVED_CHANGELIST_KEY); - if (shelvedChangeLists != null && shelvedChangeLists.length > 0) { - commitMessage = shelvedChangeLists [0].DESCRIPTION; + List shelvedChangeLists = ShelvedChangesViewManager.getShelvedLists(e.getDataContext()); + if (!shelvedChangeLists.isEmpty()) { + commitMessage = shelvedChangeLists.get(0).DESCRIPTION; } else { ChangeList[] changeLists = e.getData(VcsDataKeys.CHANGE_LISTS); @@ -120,15 +120,12 @@ public class CreatePatchFromChangesAction extends AnAction implements DumbAware public void update(final AnActionEvent e) { final Boolean haveSelectedChanges = e.getData(VcsDataKeys.HAVE_SELECTED_CHANGES); Change[] changes; - ChangeList[] data1 = e.getData(VcsDataKeys.CHANGE_LISTS); - ShelvedChangeList[] data2 = e.getData(ShelvedChangesViewManager.SHELVED_CHANGELIST_KEY); - ShelvedChangeList[] data3 = e.getData(ShelvedChangesViewManager.SHELVED_RECYCLED_CHANGELIST_KEY); + ChangeList[] changeLists = e.getData(VcsDataKeys.CHANGE_LISTS); + List shelveChangelists = ShelvedChangesViewManager.getShelvedLists(e.getDataContext()); + int changelistNum = changeLists == null ? 0 : changeLists.length; + changelistNum += shelveChangelists.size(); - int sum = data1 == null ? 0 : data1.length; - sum += data2 == null ? 0 : data2.length; - sum += data3 == null ? 0 : data3.length; - - e.getPresentation().setEnabled(Boolean.TRUE.equals(haveSelectedChanges) && (sum == 1) && + e.getPresentation().setEnabled(Boolean.TRUE.equals(haveSelectedChanges) && (changelistNum == 1) && ((changes = e.getData(VcsDataKeys.CHANGES)) != null && changes.length > 0)); } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/ShelveSilentlyAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/ShelveSilentlyAction.java new file mode 100644 index 000000000000..f75e0a9e308c --- /dev/null +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/ShelveSilentlyAction.java @@ -0,0 +1,45 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://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.vcs.changes.actions; + +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.project.DumbAware; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vcs.VcsDataKeys; +import com.intellij.openapi.vcs.changes.Change; +import com.intellij.openapi.vcs.changes.shelf.ShelveChangesManager; +import com.intellij.util.ObjectUtils; + +import java.util.Arrays; + +public class ShelveSilentlyAction extends AnAction implements DumbAware { + + @Override + public void actionPerformed(AnActionEvent e) { + final Project project = ObjectUtils.assertNotNull(getEventProject(e)); + FileDocumentManager.getInstance().saveAllDocuments(); + Change[] changes = ObjectUtils.assertNotNull(e.getData(VcsDataKeys.CHANGES)); + ShelveChangesManager.getInstance(project).shelveSilentlyUnderProgress(Arrays.asList(changes)); + } + + @Override + public void update(AnActionEvent e) { + Change[] changes = e.getData(VcsDataKeys.CHANGES); + e.getPresentation().setEnabled(getEventProject(e) != null && changes != null && changes.length > 0); + } +} \ No newline at end of file diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/UnshelveSilentlyAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/UnshelveSilentlyAction.java new file mode 100644 index 000000000000..02d87aa9e6a8 --- /dev/null +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/UnshelveSilentlyAction.java @@ -0,0 +1,45 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://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.vcs.changes.actions; + +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.project.DumbAware; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vcs.changes.shelf.ShelveChangesManager; +import com.intellij.util.ObjectUtils; + +import static com.intellij.openapi.vcs.changes.shelf.ShelvedChangesViewManager.*; + +public class UnshelveSilentlyAction extends AnAction implements DumbAware { + + @Override + public void actionPerformed(AnActionEvent e) { + final Project project = ObjectUtils.assertNotNull(getEventProject(e)); + FileDocumentManager.getInstance().saveAllDocuments(); + DataContext dataContext = e.getDataContext(); + ShelveChangesManager.getInstance(project). + unshelveSilentlyAsynchronously(project, getShelvedLists(dataContext), getShelveChanges(dataContext), + getBinaryShelveChanges(dataContext), null); + } + + @Override + public void update(AnActionEvent e) { + e.getPresentation().setEnabled(getEventProject(e) != null && !getShelvedLists(e.getDataContext()).isEmpty()); + } +} \ No newline at end of file diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/DiffShelvedChangesAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/DiffShelvedChangesAction.java index 9f81a1d41bed..c525f45d49fd 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/DiffShelvedChangesAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/DiffShelvedChangesAction.java @@ -51,6 +51,7 @@ import com.intellij.openapi.vcs.changes.patch.ApplyPatchForBaseRevisionTexts; import com.intellij.openapi.vcs.changes.patch.PatchDiffRequestFactory; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.Consumer; +import com.intellij.util.ObjectUtils; import com.intellij.util.containers.ContainerUtil; import com.intellij.vcsUtil.VcsUtil; import org.jetbrains.annotations.NotNull; @@ -73,12 +74,8 @@ public class DiffShelvedChangesAction extends AnAction implements DumbAware { public static boolean isEnabled(final DataContext dc) { final Project project = CommonDataKeys.PROJECT.getData(dc); if (project == null) return false; - - ShelvedChangeList[] changeLists = ShelvedChangesViewManager.SHELVED_CHANGELIST_KEY.getData(dc); - if (changeLists == null) changeLists = ShelvedChangesViewManager.SHELVED_RECYCLED_CHANGELIST_KEY.getData(dc); - if (changeLists == null || changeLists.length != 1) return false; - - return true; + List changeLists = ShelvedChangesViewManager.getShelvedLists(dc); + return changeLists.size() == 1; } public static void showShelvedChangesDiff(final DataContext dc) { @@ -86,12 +83,11 @@ public class DiffShelvedChangesAction extends AnAction implements DumbAware { if (project == null) return; if (ChangeListManager.getInstance(project).isFreezedWithNotification(null)) return; - ShelvedChangeList[] changeLists = ShelvedChangesViewManager.SHELVED_CHANGELIST_KEY.getData(dc); - if (changeLists == null) changeLists = ShelvedChangesViewManager.SHELVED_RECYCLED_CHANGELIST_KEY.getData(dc); - if (changeLists == null || changeLists.length != 1) return; + List changeLists = ShelvedChangesViewManager.getShelvedLists(dc); + ShelvedChangeList changeList = ObjectUtils.assertNotNull(ContainerUtil.getFirstItem(changeLists)); - final List textChanges = changeLists[0].getChanges(project); - final List binaryChanges = changeLists[0].getBinaryFiles(); + final List textChanges = changeList.getChanges(project); + final List binaryChanges = changeList.getBinaryFiles(); final List diffRequestProducers = new ArrayList<>(); @@ -102,8 +98,8 @@ public class DiffShelvedChangesAction extends AnAction implements DumbAware { // selected changes inside lists final Set selectedChanges = new HashSet<>(); - selectedChanges.addAll(ContainerUtil.notNullize(ShelvedChangesViewManager.SHELVED_CHANGE_KEY.getData(dc))); - selectedChanges.addAll(ContainerUtil.notNullize(ShelvedChangesViewManager.SHELVED_BINARY_FILE_KEY.getData(dc))); + selectedChanges.addAll(ShelvedChangesViewManager.getShelveChanges(dc)); + selectedChanges.addAll(ShelvedChangesViewManager.getBinaryShelveChanges(dc)); int index = 0; for (int i = 0; i < diffRequestProducers.size(); i++) { diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/RenameShelvedChangeListAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/RenameShelvedChangeListAction.java index 242473dc1409..8d6f2b839f23 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/RenameShelvedChangeListAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/RenameShelvedChangeListAction.java @@ -18,11 +18,12 @@ package com.intellij.openapi.vcs.changes.shelf; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; -import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.InputValidator; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.vcs.VcsBundle; +import com.intellij.util.ObjectUtils; +import com.intellij.util.containers.ContainerUtil; import java.util.List; @@ -31,11 +32,9 @@ import java.util.List; */ public class RenameShelvedChangeListAction extends AnAction { public void actionPerformed(AnActionEvent e) { - final Project project = e.getData(CommonDataKeys.PROJECT); - final ShelvedChangeList[] changes = e.getData(ShelvedChangesViewManager.SHELVED_CHANGELIST_KEY); - final ShelvedChangeList[] recycledChanges = e.getData(ShelvedChangesViewManager.SHELVED_RECYCLED_CHANGELIST_KEY); - assert (changes != null) || (recycledChanges != null); - final ShelvedChangeList changeList = (changes != null && changes.length == 1) ? changes [0] : recycledChanges[0]; + final Project project = e.getRequiredData(CommonDataKeys.PROJECT); + final List changelists = ShelvedChangesViewManager.getShelvedLists(e.getDataContext()); + final ShelvedChangeList changeList = ObjectUtils.assertNotNull(ContainerUtil.getFirstItem(changelists)); String newName = Messages.showInputDialog(project, VcsBundle.message("shelve.changes.rename.prompt"), VcsBundle.message("shelve.changes.rename.title"), Messages.getQuestionIcon(), changeList.DESCRIPTION, @@ -46,7 +45,7 @@ public class RenameShelvedChangeListAction extends AnAction { } final List list = ShelveChangesManager.getInstance(project).getShelvedChangeLists(); - for(ShelvedChangeList oldList: list) { + for (ShelvedChangeList oldList : list) { if (oldList != changeList && oldList.DESCRIPTION.equals(inputString)) { return false; } @@ -64,10 +63,6 @@ public class RenameShelvedChangeListAction extends AnAction { } public void update(final AnActionEvent e) { - final Project project = e.getData(CommonDataKeys.PROJECT); - final ShelvedChangeList[] changes = e.getData(ShelvedChangesViewManager.SHELVED_CHANGELIST_KEY); - final ShelvedChangeList[] recycledChanges = e.getData(ShelvedChangesViewManager.SHELVED_RECYCLED_CHANGELIST_KEY); - e.getPresentation().setEnabled((project != null) && ((changes != null && changes.length == 1) || - ((recycledChanges != null) && (recycledChanges.length == 1)))); + e.getPresentation().setEnabled(getEventProject(e) != null && ShelvedChangesViewManager.getShelvedLists(e.getDataContext()).size() == 1); } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/ShelveChangesManager.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/ShelveChangesManager.java index 177bb296fd48..ae934596149f 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/ShelveChangesManager.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/ShelveChangesManager.java @@ -34,6 +34,9 @@ import com.intellij.openapi.options.SchemeManager; import com.intellij.openapi.options.SchemeManagerFactory; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.progress.Task; +import com.intellij.openapi.project.DumbModePermission; +import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.*; import com.intellij.openapi.util.io.FileUtil; @@ -49,7 +52,6 @@ import com.intellij.openapi.vfs.CharsetToolkit; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.Consumer; import com.intellij.util.PathUtil; -import com.intellij.util.Processor; import com.intellij.util.SmartList; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.messages.MessageBus; @@ -61,9 +63,8 @@ import com.intellij.vcsUtil.FilesProgress; import org.jdom.Element; import org.jdom.Parent; import org.jetbrains.annotations.CalledInAny; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.CalledInAwt; +import org.jetbrains.annotations.*; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; @@ -72,6 +73,8 @@ import java.util.*; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; +import static com.intellij.openapi.vcs.changes.ChangeListUtil.getPredefinedChangeList; + public class ShelveChangesManager extends AbstractProjectComponent implements JDOMExternalizable { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vcs.changes.shelf.ShelveChangesManager"); @NonNls private static final String ELEMENT_CHANGELIST = "changelist"; @@ -119,12 +122,7 @@ public class ShelveChangesManager extends AbstractProjectComponent implements JD } }); - myCleaningFuture = JobScheduler.getScheduler().scheduleWithFixedDelay(new Runnable() { - @Override - public void run() { - cleanSystemUnshelvedOlderOneWeek(); - } - }, 1, 1, TimeUnit.DAYS); + myCleaningFuture = JobScheduler.getScheduler().scheduleWithFixedDelay(() -> cleanSystemUnshelvedOlderOneWeek(), 1, 1, TimeUnit.DAYS); Disposer.register(project, new Disposable() { @Override public void dispose() { @@ -163,15 +161,11 @@ public class ShelveChangesManager extends AbstractProjectComponent implements JD private void filterNonValidShelvedChangeLists() { final List allSchemes = ContainerUtil.newArrayList(mySchemeManager.getAllSchemes()); - ContainerUtil.process(allSchemes, new Processor() { - - @Override - public boolean process(ShelvedChangeList shelvedChangeList) { - if (!shelvedChangeList.isValid()) { - mySchemeManager.removeScheme(shelvedChangeList); - } - return true; + ContainerUtil.process(allSchemes, shelvedChangeList -> { + if (!shelvedChangeList.isValid()) { + mySchemeManager.removeScheme(shelvedChangeList); } + return true; }); } @@ -283,12 +277,7 @@ public class ShelveChangesManager extends AbstractProjectComponent implements JD @NotNull private List getRecycled(final boolean recycled) { - return ContainerUtil.newUnmodifiableList(ContainerUtil.filter(mySchemeManager.getAllSchemes(), new Condition() { - @Override - public boolean value(ShelvedChangeList list) { - return recycled == list.isRecycled(); - } - })); + return ContainerUtil.newUnmodifiableList(ContainerUtil.filter(mySchemeManager.getAllSchemes(), list -> recycled == list.isRecycled())); } public ShelvedChangeList shelveChanges(final Collection changes, final String commitMessage, final boolean rollback) @@ -586,24 +575,21 @@ public class ShelveChangesManager extends AbstractProjectComponent implements JD patches.add(new ShelvedBinaryFilePatch(shelvedBinaryFile)); } - ApplicationManager.getApplication().invokeAndWait(new Runnable() { - @Override - public void run() { - final BinaryPatchApplier binaryPatchApplier = new BinaryPatchApplier(); - final PatchApplier patchApplier = - new PatchApplier<>(myProject, myProject.getBaseDir(), - patches, targetChangeList, binaryPatchApplier, commitContext, reverse, leftConflictTitle, - rightConflictTitle); - patchApplier.setIsSystemOperation(systemOperation); - patchApplier.execute(showSuccessNotification, systemOperation); - if (isRemoveFilesFromShelf() || systemOperation) { - remainingPatches.addAll(patchApplier.getRemainingPatches()); - if (remainingPatches.isEmpty() && remainingBinaries.isEmpty()) { - recycleChangeList(changeList); - } - else { - saveRemainingPatches(changeList, remainingPatches, remainingBinaries, commitContext); - } + ApplicationManager.getApplication().invokeAndWait(() -> { + final BinaryPatchApplier binaryPatchApplier = new BinaryPatchApplier(); + final PatchApplier patchApplier = + new PatchApplier<>(myProject, myProject.getBaseDir(), + patches, targetChangeList, binaryPatchApplier, commitContext, reverse, leftConflictTitle, + rightConflictTitle); + patchApplier.setIsSystemOperation(systemOperation); + patchApplier.execute(showSuccessNotification, systemOperation); + if (isRemoveFilesFromShelf() || systemOperation) { + remainingPatches.addAll(patchApplier.getRemainingPatches()); + if (remainingPatches.isEmpty() && remainingBinaries.isEmpty()) { + recycleChangeList(changeList); + } + else { + saveRemainingPatches(changeList, remainingPatches, remainingBinaries, commitContext); } } }); @@ -646,13 +632,79 @@ public class ShelveChangesManager extends AbstractProjectComponent implements JD public void cleanUnshelved(final boolean onlyMarkedToDelete, long timeBefore) { final Date limitDate = new Date(timeBefore); - final List toDelete = ContainerUtil.filter(mySchemeManager.getAllSchemes(), new Condition() { + final List toDelete = ContainerUtil.filter(mySchemeManager.getAllSchemes(), list -> (list.isRecycled()) && + list.DATE.before(limitDate) && + (!onlyMarkedToDelete || + list.isMarkedToDelete())); + clearShelvedLists(toDelete); + } + + @CalledInAwt + public void shelveSilentlyUnderProgress(@NotNull List changes) { + final boolean completed = ProgressManager.getInstance().runProcessWithProgressSynchronously( + () -> DumbService.allowStartingDumbModeInside(DumbModePermission.MAY_START_BACKGROUND, () -> shelveChangesInSeparatedLists(changes)), + VcsBundle.getString("shelve.changes.progress.title"), true, myProject); + + if (completed) { + VcsNotifier.getInstance(myProject).notifySuccess("Changes shelved successfully"); + } + } + + public void shelveChangesInSeparatedLists(@NotNull Collection changes) { + List failedChangeLists = ContainerUtil.newArrayList(); + List changeListsCopy = ChangeListManager.getInstance(myProject).getChangeListsCopy(); + for (LocalChangeList list : changeListsCopy) { + Collection changesForChangelist = ContainerUtil.intersection(list.getChanges(), changes); + if (changesForChangelist.isEmpty()) continue; + try { + shelveChanges(changesForChangelist, list.getName(), true); + } + catch (Exception e) { + LOG.warn(e); + failedChangeLists.add(list.getName()); + } + } + if (!failedChangeLists.isEmpty()) { + VcsNotifier.getInstance(myProject).notifyError("Shelf Failed", String + .format("Shelving changes for %s [%s] failed", StringUtil.pluralize("changelist", failedChangeLists.size()), + StringUtil.join(failedChangeLists, ","))); + } + } + + + public void unshelveSilentlyAsynchronously(@NotNull final Project project, + @NotNull final List selectedChangeLists, + @NotNull final List selectedChanges, + @NotNull final List selectedBinaryChanges, + @Nullable final LocalChangeList forcePredefinedOneChangelist) { + ProgressManager.getInstance().run(new Task.Backgroundable(project, VcsBundle.getString("unshelve.changes.progress.title"), true) { @Override - public boolean value(ShelvedChangeList list) { - return (list.isRecycled()) && list.DATE.before(limitDate) && (!onlyMarkedToDelete || list.isMarkedToDelete()); + public void run(@NotNull ProgressIndicator indicator) { + for (ShelvedChangeList changeList : selectedChangeLists) { + List changesForChangelist = + ContainerUtil.newArrayList(ContainerUtil.intersection(changeList.getChanges(myProject), selectedChanges)); + List binariesForChangelist = + ContainerUtil.newArrayList(ContainerUtil.intersection(changeList.getBinaryFiles(), selectedBinaryChanges)); + boolean shouldUnshelveAllList = changesForChangelist.isEmpty() && binariesForChangelist.isEmpty(); + unshelveChangeList(changeList, shouldUnshelveAllList ? null : changesForChangelist, + shouldUnshelveAllList ? null : binariesForChangelist, + forcePredefinedOneChangelist != null ? forcePredefinedOneChangelist : getChangeListUnshelveTo(changeList), + true); + } } }); - clearShelvedLists(toDelete); + } + + @NotNull + private LocalChangeList getChangeListUnshelveTo(@NotNull ShelvedChangeList list) { + String changeListName = list.DESCRIPTION; + ChangeListManager manager = ChangeListManager.getInstance(myProject); + LocalChangeList localChangeList = manager.findChangeList(changeListName); + if (localChangeList != null) return localChangeList; + if (list.isMarkedToDelete()) { + localChangeList = getPredefinedChangeList(changeListName, manager); + } + return localChangeList != null ? localChangeList : manager.addChangeList(changeListName, ""); } private class BinaryPatchApplier implements CustomBinaryPatchApplier { diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/ShelvedChangesViewManager.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/ShelvedChangesViewManager.java index 3fe0a1502d09..77788ae53bc0 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/ShelvedChangesViewManager.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/ShelvedChangesViewManager.java @@ -21,6 +21,8 @@ import com.intellij.icons.AllIcons; import com.intellij.ide.DataManager; import com.intellij.ide.DeleteProvider; import com.intellij.ide.actions.EditSourceAction; +import com.intellij.ide.dnd.*; +import com.intellij.ide.dnd.aware.DnDAwareTree; import com.intellij.ide.util.treeView.TreeState; import com.intellij.lifecycle.PeriodicalTasksCloser; import com.intellij.openapi.actionSystem.*; @@ -30,6 +32,7 @@ import com.intellij.openapi.components.ProjectComponent; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.diff.impl.patch.FilePatch; import com.intellij.openapi.diff.impl.patch.PatchSyntaxException; +import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.project.Project; @@ -40,10 +43,13 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.*; import com.intellij.openapi.vcs.changes.Change; import com.intellij.openapi.vcs.changes.CommitContext; +import com.intellij.openapi.vcs.changes.DnDTargetContentAdapter; import com.intellij.openapi.vcs.changes.issueLinks.IssueLinkRenderer; import com.intellij.openapi.vcs.changes.issueLinks.TreeLinkMouseListener; import com.intellij.openapi.vcs.changes.patch.RelativePathCalculator; +import com.intellij.openapi.vcs.changes.ui.ChangeListDragBean; import com.intellij.openapi.vcs.changes.ui.ChangesViewContentManager; +import com.intellij.openapi.vcs.changes.ui.ShelvedChangeListDragBean; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.wm.ToolWindow; import com.intellij.openapi.wm.ToolWindowManager; @@ -51,7 +57,6 @@ import com.intellij.pom.Navigatable; import com.intellij.pom.NavigatableAdapter; import com.intellij.ui.*; import com.intellij.ui.content.Content; -import com.intellij.ui.content.ContentFactory; import com.intellij.ui.treeStructure.Tree; import com.intellij.util.IconUtil; import com.intellij.util.containers.ContainerUtil; @@ -124,6 +129,8 @@ public class ShelvedChangesViewManager implements ProjectComponent { myTree.setShowsRootHandles(true); myTree.setCellRenderer(new ShelfTreeCellRenderer(project, myMoveRenameInfo)); new TreeLinkMouseListener(new ShelfTreeCellRenderer(project, myMoveRenameInfo)).installOn(myTree); + DnDSupport.createBuilder(myTree).disableAsTarget().setImageProvider(this::createDraggedImage).setBeanProvider(this::createDragStartBean) + .install(); final AnAction showDiffAction = ActionManager.getInstance().getAction("ShelvedChanges.Diff"); showDiffAction.registerCustomShortcutSet(showDiffAction.getShortcutSet(), myTree); @@ -198,7 +205,7 @@ public class ShelvedChangesViewManager implements ProjectComponent { else { if (myContent == null) { JPanel rootPanel = createRootPanel(); - myContent = ContentFactory.SERVICE.getInstance().createContent(rootPanel, VcsBundle.message("shelf.tab"), false); + myContent = new MyShelfContent(rootPanel, VcsBundle.message("shelf.tab"), false); myContent.setCloseable(false); myContentManager.addContent(myContent); } @@ -412,6 +419,31 @@ public class ShelvedChangesViewManager implements ProjectComponent { } } + @NotNull + public static List getShelvedLists(@NotNull final DataContext dataContext) { + final ShelvedChangeList[] shelved = SHELVED_CHANGELIST_KEY.getData(dataContext); + final ShelvedChangeList[] recycled = SHELVED_RECYCLED_CHANGELIST_KEY.getData(dataContext); + if (shelved == null && recycled == null) return Collections.emptyList(); + List shelvedChangeLists = ContainerUtil.newArrayList(); + if (shelved != null) { + ContainerUtil.addAll(shelvedChangeLists, shelved); + } + if (recycled != null) { + ContainerUtil.addAll(shelvedChangeLists, recycled); + } + return shelvedChangeLists; + } + + @NotNull + public static List getShelveChanges(@NotNull final DataContext dataContext) { + return notNullize(dataContext.getData(SHELVED_CHANGE_KEY)); + } + + @NotNull + public static List getBinaryShelveChanges(@NotNull final DataContext dataContext) { + return notNullize(dataContext.getData(SHELVED_BINARY_FILE_KEY)); + } + private final static class ShelvedFilePatchComparator implements Comparator { private final static ShelvedFilePatchComparator ourInstance = new ShelvedFilePatchComparator(); @@ -523,13 +555,11 @@ public class ShelvedChangesViewManager implements ProjectComponent { if (project == null) return; List shelvedListsToDelete = TreeUtil.collectSelectedObjectsOfType(myTree, ShelvedChangeList.class); - ArrayList shelvedListsFromChanges = ContainerUtil.newArrayList(getLists(dataContext)); + ArrayList shelvedListsFromChanges = ContainerUtil.newArrayList(getShelvedLists(dataContext)); // filter changes shelvedListsFromChanges.removeAll(shelvedListsToDelete); - List changesToDelete = - getChangesNotInLists(shelvedListsToDelete, notNullize(SHELVED_CHANGE_KEY.getData(dataContext))); - List binariesToDelete = - getBinariesNotInLists(shelvedListsToDelete, notNullize(SHELVED_BINARY_FILE_KEY.getData(dataContext))); + List changesToDelete = getChangesNotInLists(shelvedListsToDelete, getShelveChanges(dataContext)); + List binariesToDelete = getBinariesNotInLists(shelvedListsToDelete, getBinaryShelveChanges(dataContext)); int changeListSize = shelvedListsToDelete.size(); int fileListSize = binariesToDelete.size() + changesToDelete.size(); @@ -623,22 +653,49 @@ public class ShelvedChangesViewManager implements ProjectComponent { } public boolean canDeleteElement(@NotNull DataContext dataContext) { - return !getLists(dataContext).isEmpty(); - } - - @NotNull - private List getLists(@NotNull final DataContext dataContext) { - final ShelvedChangeList[] shelved = SHELVED_CHANGELIST_KEY.getData(dataContext); - final ShelvedChangeList[] recycled = SHELVED_RECYCLED_CHANGELIST_KEY.getData(dataContext); - if (shelved == null && recycled == null) return Collections.emptyList(); - List shelvedChangeLists = ContainerUtil.newArrayList(); - if (shelved != null) { - ContainerUtil.addAll(shelvedChangeLists, shelved); - } - if (recycled != null) { - ContainerUtil.addAll(shelvedChangeLists, recycled); - } - return shelvedChangeLists; + return !getShelvedLists(dataContext).isEmpty(); } } + + public class MyShelfContent extends DnDTargetContentAdapter { + private MyShelfContent(JPanel panel, String displayName, boolean isLockable) { + super(panel, displayName, isLockable); + } + + @Override + public void drop(DnDEvent event) { + Object attachedObject = event.getAttachedObject(); + if (attachedObject instanceof ChangeListDragBean) { + FileDocumentManager.getInstance().saveAllDocuments(); + List changes = Arrays.asList(((ChangeListDragBean)attachedObject).getChanges()); + myShelveChangesManager.shelveSilentlyUnderProgress(changes); + } + } + + @Override + public boolean update(DnDEvent event) { + Object attachedObject = event.getAttachedObject(); + if (attachedObject instanceof ChangeListDragBean) { + event.setDropPossible(((ChangeListDragBean)attachedObject).getChanges().length > 0); + return false; + } + return true; + } + } + + @Nullable + private DnDDragStartBean createDragStartBean(@NotNull DnDActionInfo info) { + if (info.isMove()) { + DataContext dc = DataManager.getInstance().getDataContext(myTree); + return new DnDDragStartBean(new ShelvedChangeListDragBean(getShelveChanges(dc), getBinaryShelveChanges(dc), getShelvedLists(dc))); + } + return null; + } + + @NotNull + private DnDImage createDraggedImage(@NotNull DnDActionInfo info) { + String imageText = "Unshelve changes"; + Image image = DnDAwareTree.getDragImage(myTree, imageText, null).getFirst(); + return new DnDImage(image, new Point(-image.getWidth(null), -image.getHeight(null))); + } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/UnshelveWithDialogAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/UnshelveWithDialogAction.java index 3a7a9397a94e..f0684baf9a0b 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/UnshelveWithDialogAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/UnshelveWithDialogAction.java @@ -16,11 +16,8 @@ package com.intellij.openapi.vcs.changes.shelf; import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.CommonDataKeys; +import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.fileEditor.FileDocumentManager; -import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.progress.ProgressManager; -import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.MessageType; @@ -49,23 +46,25 @@ import java.util.Collections; import java.util.List; import static com.intellij.openapi.vcs.changes.ChangeListUtil.getPredefinedChangeList; +import static com.intellij.openapi.vcs.changes.shelf.ShelvedChangesViewManager.getBinaryShelveChanges; +import static com.intellij.openapi.vcs.changes.shelf.ShelvedChangesViewManager.getShelveChanges; import static com.intellij.util.containers.ContainerUtil.newArrayList; public class UnshelveWithDialogAction extends DumbAwareAction { @Override public void actionPerformed(AnActionEvent e) { - final Project project = e.getData(CommonDataKeys.PROJECT); - final ShelvedChangeList[] changeLists = e.getData(ShelvedChangesViewManager.SHELVED_CHANGELIST_KEY); - if (project == null || changeLists == null || changeLists.length == 0) return; + final Project project = ObjectUtils.assertNotNull(getEventProject(e)); + DataContext dataContext = e.getDataContext(); + final List changeLists = ShelvedChangesViewManager.getShelvedLists(dataContext); + if (changeLists.isEmpty()) return; FileDocumentManager.getInstance().saveAllDocuments(); - if (changeLists.length > 1) { - unshelveMultipleShelveChangeLists(e.getData(ShelvedChangesViewManager.SHELVED_CHANGE_KEY), project, changeLists, - e.getData(ShelvedChangesViewManager.SHELVED_BINARY_FILE_KEY)); + if (changeLists.size() > 1) { + unshelveMultipleShelveChangeLists(project, changeLists, getBinaryShelveChanges(dataContext), getShelveChanges(dataContext)); } else { - ShelvedChangeList changeList = changeLists[0]; + ShelvedChangeList changeList = changeLists.get(0); final VirtualFile virtualFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(new File(changeList.PATH)); if (virtualFile == null) { VcsBalloonProblemNotifier.showOverChangesView(project, "Can not find path file", MessageType.ERROR); @@ -80,11 +79,11 @@ public class UnshelveWithDialogAction extends DumbAwareAction { } } - private static void unshelveMultipleShelveChangeLists(@Nullable List changes, - @NotNull final Project project, - @NotNull final ShelvedChangeList[] changeLists, - @Nullable List binaryFiles) { - String suggestedName = changeLists[0].DESCRIPTION; + private static void unshelveMultipleShelveChangeLists(@NotNull final Project project, + @NotNull final List changeLists, + @NotNull List binaryFiles, + @NotNull List changes) { + String suggestedName = changeLists.get(0).DESCRIPTION; final ChangeListManager changeListManager = ChangeListManager.getInstance(project); final ChangeListChooser chooser = new ChangeListChooser(project, changeListManager.getChangeListsCopy(), changeListManager.getDefaultChangeList(), @@ -97,19 +96,8 @@ public class UnshelveWithDialogAction extends DumbAwareAction { }; if (!chooser.showAndGet()) return; - - //todo accept empty collections as a nullable to avoid ugly checks and reassignments - final List finalBinaryFiles = binaryFiles == null || binaryFiles.isEmpty() ? null : binaryFiles; - final List finalChanges = changes == null || changes.isEmpty() ? null : changes; - final ShelveChangesManager shelveChangesManager = ShelveChangesManager.getInstance(project); - ProgressManager.getInstance().run(new Task.Backgroundable(project, "Unshelve Changes", true) { - @Override - public void run(@NotNull ProgressIndicator indicator) { - for (ShelvedChangeList changeList : changeLists) { - shelveChangesManager.unshelveChangeList(changeList, finalChanges, finalBinaryFiles, chooser.getSelectedList(), true); - } - } - }); + ShelveChangesManager.getInstance(project).unshelveSilentlyAsynchronously(project, changeLists, changes, binaryFiles, + chooser.getSelectedList()); } private static boolean hasNotAllSelectedChanges(@NotNull Project project, @NotNull ShelvedChangeList list, @Nullable Change[] changes) { @@ -118,9 +106,7 @@ public class UnshelveWithDialogAction extends DumbAwareAction { @Override public void update(AnActionEvent e) { - final Project project = e.getData(CommonDataKeys.PROJECT); - final ShelvedChangeList[] changes = e.getData(ShelvedChangesViewManager.SHELVED_CHANGELIST_KEY); - e.getPresentation().setEnabled(project != null && changes != null); + e.getPresentation().setEnabled(getEventProject(e) != null && !ShelvedChangesViewManager.getShelvedLists(e.getDataContext()).isEmpty()); } private static class MyUnshelveDialog extends ApplyPatchDifferentiatedDialog { diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangeListDragBean.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangeListDragBean.java index 2fd530558dc7..aca1b0015ddc 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangeListDragBean.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangeListDragBean.java @@ -25,7 +25,7 @@ import java.util.List; /** * @author yole */ -class ChangeListDragBean { +public class ChangeListDragBean { private final JComponent mySourceComponent; private final Change[] myChanges; private final List myUnversionedFiles; diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/CommitChangeListDialog.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/CommitChangeListDialog.java index 73686ddf1f3e..58a77fdca669 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/CommitChangeListDialog.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/CommitChangeListDialog.java @@ -1009,7 +1009,6 @@ public class CommitChangeListDialog extends DialogWrapper implements CheckinProj JPanel mainPanel; if (myAdditionalOptionsPanel != null) { JScrollPane optionsPane = ScrollPaneFactory.createScrollPane(myAdditionalOptionsPanel, true); - optionsPane.getVerticalScrollBar().setUnitIncrement(10); if (!Registry.is("ide.scroll.new.layout")) { optionsPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); optionsPane.getVerticalScrollBar().setUI(ButtonlessScrollBarUI.createTransparent()); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ShelvedChangeListDragBean.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ShelvedChangeListDragBean.java new file mode 100644 index 000000000000..2d959a9002c0 --- /dev/null +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ShelvedChangeListDragBean.java @@ -0,0 +1,52 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://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.vcs.changes.ui; + +import com.intellij.openapi.vcs.changes.shelf.ShelvedBinaryFile; +import com.intellij.openapi.vcs.changes.shelf.ShelvedChange; +import com.intellij.openapi.vcs.changes.shelf.ShelvedChangeList; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +public class ShelvedChangeListDragBean { + @NotNull private List myShelvedChanges; + @NotNull private List myBinaries; + @NotNull private List myShelvedChangelists; + + public ShelvedChangeListDragBean(@NotNull List shelvedChanges, + @NotNull List binaries, + @NotNull List shelvedChangelists) { + myShelvedChanges = shelvedChanges; + myBinaries = binaries; + myShelvedChangelists = shelvedChangelists; + } + + @NotNull + public List getChanges() { + return myShelvedChanges; + } + + @NotNull + public List getBinaryFiles() { + return myBinaries; + } + + @NotNull + public List getShelvedChangelists() { + return myShelvedChangelists; + } +} diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java index 5e03b226c547..4374f034763e 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java @@ -71,8 +71,6 @@ class DetailsPanel extends JPanel implements EditorColorsListener { myColorManager = colorManager; myScrollPane = new JBScrollPane(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); - myScrollPane.getVerticalScrollBar().setUnitIncrement(JBUI.scale(10)); - myScrollPane.getHorizontalScrollBar().setUnitIncrement(JBUI.scale(10)); myMainContentPanel = new ScrollablePanel() { @Override public boolean getScrollableTracksViewportWidth() { diff --git a/plugins/git4idea/src/git4idea/annotate/GitAnnotationProvider.java b/plugins/git4idea/src/git4idea/annotate/GitAnnotationProvider.java index 2e1f073ec883..e849b8db15cc 100644 --- a/plugins/git4idea/src/git4idea/annotate/GitAnnotationProvider.java +++ b/plugins/git4idea/src/git4idea/annotate/GitAnnotationProvider.java @@ -198,7 +198,7 @@ public class GitAnnotationProvider implements AnnotationProviderEx { if (revisions == null) return; ApplicationManager.getApplication().invokeLater(() -> { GitFileAnnotation newFileAnnotation = new GitFileAnnotation(fileAnnotation); - fileAnnotation.setRevisions(revisions); + newFileAnnotation.setRevisions(revisions); fileAnnotation.reload(newFileAnnotation); }); }, diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleToolWindowPanel.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleToolWindowPanel.java index 9db445ce7313..61384ab33601 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleToolWindowPanel.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleToolWindowPanel.java @@ -91,7 +91,6 @@ public abstract class GradleToolWindowPanel extends SimpleToolWindowPanel { final JComponent payloadControl = buildContent(); JScrollPane scrollPane = ScrollPaneFactory.createScrollPane(payloadControl); JScrollBar scrollBar = scrollPane.getVerticalScrollBar(); - scrollBar.setUnitIncrement(scrollBar.getUnitIncrement() * 7); myContent.add(scrollPane, CONTENT_CARD_NAME); RichTextControlBuilder builder = new RichTextControlBuilder(); builder.setBackgroundColor(payloadControl.getBackground()); diff --git a/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFXHighlightingTest.java b/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFXHighlightingTest.java index f87e362250ed..2e77d3f94017 100644 --- a/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFXHighlightingTest.java +++ b/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFXHighlightingTest.java @@ -19,6 +19,8 @@ import com.intellij.codeInsight.daemon.impl.analysis.XmlPathReferenceInspection; import com.intellij.codeInspection.deadCode.UnusedDeclarationInspectionBase; import com.intellij.codeInspection.htmlInspections.RequiredAttributesInspection; import com.intellij.openapi.application.PluginPathManager; +import com.intellij.openapi.util.registry.Registry; +import com.intellij.openapi.util.registry.RegistryValue; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.util.ArrayUtil; @@ -133,7 +135,16 @@ public class JavaFXHighlightingTest extends AbstractJavaFXTestCase { public void testInjectedController() throws Exception { myFixture.copyFileToProject("injected/MyController.java"); myFixture.copyFileToProject("injected/FooVBox.java"); - doTestNavigation("injected.MyController", "label", "injected/" + getTestName(true) + ".fxml"); + + final RegistryValue registryValue = Registry.get("javafx.fxml.controller.from.loader"); + final boolean injectionAllowed = registryValue.asBoolean(); + try { + registryValue.setValue(true); + doTestNavigation("injected.MyController", "label", "injected/" + getTestName(true) + ".fxml"); + } + finally { + registryValue.setValue(injectionAllowed); + } } public void testControllerInExpression() throws Exception{ diff --git a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/JavaFxPsiUtil.java b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/JavaFxPsiUtil.java index 290a395fcdfc..ec690bc93ddb 100644 --- a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/JavaFxPsiUtil.java +++ b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/JavaFxPsiUtil.java @@ -25,6 +25,7 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.*; +import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; @@ -291,11 +292,13 @@ public class JavaFxPsiUtil { } } } - final CachedValuesManager manager = CachedValuesManager.getManager(containingFile.getProject()); - final PsiClass injectedControllerClass = manager.getCachedValue( - containingFile, INJECTED_CONTROLLER, () -> computeInjectedControllerClass(containingFile), true); - if (injectedControllerClass != null) { - return injectedControllerClass; + if (Registry.is("javafx.fxml.controller.from.loader", false)) { + final CachedValuesManager manager = CachedValuesManager.getManager(containingFile.getProject()); + final PsiClass injectedControllerClass = manager.getCachedValue( + containingFile, INJECTED_CONTROLLER, () -> computeInjectedControllerClass(containingFile), true); + if (injectedControllerClass != null) { + return injectedControllerClass; + } } if (rootTag != null && FxmlConstants.FX_ROOT.equals(rootTag.getName())) { diff --git a/plugins/junit5_rt/junit5_rt.iml b/plugins/junit5_rt/junit5_rt.iml index 7a8b49687cd5..ec639f339e82 100644 --- a/plugins/junit5_rt/junit5_rt.iml +++ b/plugins/junit5_rt/junit5_rt.iml @@ -4,7 +4,6 @@ - @@ -12,14 +11,5 @@ - - - - - - - - - \ No newline at end of file diff --git a/plugins/junit5_rt/src/com/intellij/junit5/JUnit5TestRunnerUtil.java b/plugins/junit5_rt/src/com/intellij/junit5/JUnit5TestRunnerUtil.java index b2247b57ef0a..23180c7f187d 100644 --- a/plugins/junit5_rt/src/com/intellij/junit5/JUnit5TestRunnerUtil.java +++ b/plugins/junit5_rt/src/com/intellij/junit5/JUnit5TestRunnerUtil.java @@ -15,26 +15,29 @@ */ package com.intellij.junit5; +import org.junit.platform.commons.util.AnnotationUtils; import org.junit.platform.engine.DiscoverySelector; import org.junit.platform.engine.discovery.DiscoverySelectors; -import org.junit.platform.engine.discovery.MethodSelector; import org.junit.platform.launcher.LauncherDiscoveryRequest; import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; +import java.lang.annotation.Annotation; import java.util.ArrayList; import java.util.List; public class JUnit5TestRunnerUtil { + public static final String DISABLED_ANNO = "org.junit.jupiter.api.Disabled"; + public static LauncherDiscoveryRequest buildRequest(String[] suiteClassNames, String[] packageNameRef) { if (suiteClassNames.length == 0) { return null; } - final LauncherDiscoveryRequestBuilder builder = LauncherDiscoveryRequestBuilder.request(); + LauncherDiscoveryRequestBuilder builder = LauncherDiscoveryRequestBuilder.request(); if (suiteClassNames.length == 1 && suiteClassNames[0].charAt(0) == '@') { @@ -46,7 +49,7 @@ public class JUnit5TestRunnerUtil { if (packageName == null) return null; //todo category? - final String categoryName = reader.readLine(); + reader.readLine(); String line; List selectors = new ArrayList<>(); @@ -66,12 +69,33 @@ public class JUnit5TestRunnerUtil { } } else { - return builder.selectors(createSelector(suiteClassNames[0])).build(); + boolean disableDisabledCondition = isDisabledConditionDisabled(suiteClassNames[0]); + if (disableDisabledCondition) { + builder = builder.configurationParameter("junit.conditions.deactivate", "org.junit.*DisabledCondition"); + } + return builder.selectors(createSelector(suiteClassNames[0])).build(); } return null; } + public static boolean isDisabledConditionDisabled(String name) { + int commaIdx = name.indexOf(","); + boolean disableDisabledCondition = true; + if (commaIdx < 0) { + try { + ClassLoader loader = JUnit5TestRunnerUtil.class.getClassLoader(); + Class aClass = Class.forName(name, false, loader); + Class disabledAnnotation = (Class)Class.forName(DISABLED_ANNO, false, loader); + disableDisabledCondition = AnnotationUtils.findAnnotation(aClass, disabledAnnotation).isPresent(); + } + catch (ClassNotFoundException e) { + disableDisabledCondition = false; + } + } + return disableDisabledCondition; + } + protected static DiscoverySelector createSelector(String line) { if (line.contains(",")) { return DiscoverySelectors.selectMethod(line.replaceFirst(",", "#")); diff --git a/plugins/junit5_rt_tests/junit5_rt_tests.iml b/plugins/junit5_rt_tests/junit5_rt_tests.iml new file mode 100644 index 000000000000..ef9de995f5de --- /dev/null +++ b/plugins/junit5_rt_tests/junit5_rt_tests.iml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/junit5_rt_tests/test/com/intellij/junit5/JUnit5ConditionsTest.java b/plugins/junit5_rt_tests/test/com/intellij/junit5/JUnit5ConditionsTest.java new file mode 100644 index 000000000000..6486f61cbad9 --- /dev/null +++ b/plugins/junit5_rt_tests/test/com/intellij/junit5/JUnit5ConditionsTest.java @@ -0,0 +1,63 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://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.junit5; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.Arrays; + +class JUnit5ConditionsTest { + @Test + void disabledConditions() throws Exception { + String[] disabledClasses = {DisabledClass.class.getName(), MetaDisabledClass.class.getName()}; + Arrays.stream(disabledClasses) + .flatMap(klass -> Arrays.stream(new String[]{klass, klass + ",test1"})) + .forEach(member -> Assertions.assertTrue(JUnit5TestRunnerUtil.isDisabledConditionDisabled(member), member)); + + String withDisabledMethodName = WithDisabledMethod.class.getName(); + Assertions.assertAll(() -> Assertions.assertFalse(JUnit5TestRunnerUtil.isDisabledConditionDisabled(withDisabledMethodName), withDisabledMethodName), + () -> Assertions.assertTrue(JUnit5TestRunnerUtil.isDisabledConditionDisabled(withDisabledMethodName + ",test1"), withDisabledMethodName)); + } + + class WithDisabledMethod { + @Disabled + @Test + void test1() {} + } + + @Disabled + class DisabledClass { + @Test + void test1() {} + } + + @Target({ElementType.TYPE, ElementType.METHOD}) + @Retention(RetentionPolicy.RUNTIME) + @Disabled + @interface MetaDisabled {} + + @MetaDisabled + class MetaDisabledClass { + @Test + void test1() {} + } +} diff --git a/plugins/junit5_rt/test/com/intellij/junit5/JUnit5EventsTest.java b/plugins/junit5_rt_tests/test/com/intellij/junit5/JUnit5EventsTest.java similarity index 100% rename from plugins/junit5_rt/test/com/intellij/junit5/JUnit5EventsTest.java rename to plugins/junit5_rt_tests/test/com/intellij/junit5/JUnit5EventsTest.java diff --git a/plugins/junit5_rt/test/com/intellij/junit5/JUnit5NavigationTest.java b/plugins/junit5_rt_tests/test/com/intellij/junit5/JUnit5NavigationTest.java similarity index 100% rename from plugins/junit5_rt/test/com/intellij/junit5/JUnit5NavigationTest.java rename to plugins/junit5_rt_tests/test/com/intellij/junit5/JUnit5NavigationTest.java diff --git a/plugins/properties/properties-psi-impl/src/com/intellij/codeInspection/unused/UnusedPropertyInspection.java b/plugins/properties/properties-psi-impl/src/com/intellij/codeInspection/unused/UnusedPropertyInspection.java index eb0a4b34ded5..5bc2fac93db9 100644 --- a/plugins/properties/properties-psi-impl/src/com/intellij/codeInspection/unused/UnusedPropertyInspection.java +++ b/plugins/properties/properties-psi-impl/src/com/intellij/codeInspection/unused/UnusedPropertyInspection.java @@ -50,7 +50,7 @@ import java.util.function.Function; * @author cdr */ public class UnusedPropertyInspection extends PropertySuppressableInspectionBase implements ResourceBundleEditorInspection { - private final static Logger LOG = Logger.getInstance(UnusedPropertyInspection.class); + private static final Logger LOG = Logger.getInstance(UnusedPropertyInspection.class); @Override @NotNull @@ -147,20 +147,21 @@ public class UnusedPropertyInspection extends PropertySuppressableInspectionBase if (name == null) return true; } - if (mayHaveUsages(property, original, name, helper.getOwnUseScope(), helper, isOnTheFly)) return true; + PsiSearchHelper searchHelper = helper.getSearchHelper(); + if (mayHaveUsages(property, name, searchHelper, helper.getOwnUseScope(), isOnTheFly, original)) return true; final GlobalSearchScope widerScope = getWidestUseScope(property.getKey(), property.getProject(), helper.getModule()); - if (widerScope != null && mayHaveUsages(property, original, name, widerScope, helper, isOnTheFly)) return true; + if (widerScope != null && mayHaveUsages(property, name, searchHelper, widerScope, isOnTheFly, original)) return true; return false; } - private static boolean mayHaveUsages(Property property, - ProgressIndicator original, - String name, - GlobalSearchScope searchScope, - @NotNull UnusedPropertiesSearchHelper helper, - boolean onTheFly) { - PsiSearchHelper.SearchCostResult cheapEnough = helper.getSearchHelper().isCheapEnoughToSearch(name, searchScope, null, original); + private static boolean mayHaveUsages(@NotNull PsiElement property, + @NotNull String name, + @NotNull PsiSearchHelper psiSearchHelper, + @NotNull GlobalSearchScope searchScope, + boolean onTheFly, + @Nullable ProgressIndicator indicator) { + PsiSearchHelper.SearchCostResult cheapEnough = psiSearchHelper.isCheapEnoughToSearch(name, searchScope, null, indicator); if (cheapEnough == PsiSearchHelper.SearchCostResult.ZERO_OCCURRENCES) return false; if (onTheFly && cheapEnough == PsiSearchHelper.SearchCostResult.TOO_MANY_OCCURRENCES) return true; @@ -168,17 +169,16 @@ public class UnusedPropertyInspection extends PropertySuppressableInspectionBase } private static class UnusedPropertiesSearchHelper { - private final GlobalSearchScope myOwnUseScope; private final Module myModule; private final PropertySearcher mySearcher; private final PsiSearchHelper mySearchHelper; - public UnusedPropertiesSearchHelper(Module module) { + UnusedPropertiesSearchHelper(Module module) { myOwnUseScope = GlobalSearchScope.moduleWithDependentsScope(module); myModule = module; mySearcher = (PropertySearcher)ContainerUtil.find(Extensions.getExtensions("com.intellij.referencesSearch"), - new FilteringIterator.InstanceOf(PropertySearcher.class)); + new FilteringIterator.InstanceOf<>(PropertySearcher.class)); mySearchHelper = PsiSearchHelper.SERVICE.getInstance(module.getProject()); } @@ -186,7 +186,7 @@ public class UnusedPropertyInspection extends PropertySuppressableInspectionBase return myModule; } - public GlobalSearchScope getOwnUseScope() { + GlobalSearchScope getOwnUseScope() { return myOwnUseScope; } @@ -194,7 +194,7 @@ public class UnusedPropertyInspection extends PropertySuppressableInspectionBase return mySearcher; } - public PsiSearchHelper getSearchHelper() { + PsiSearchHelper getSearchHelper() { return mySearchHelper; } } diff --git a/plugins/settings-repository/settings-repository-tests.iml b/plugins/settings-repository/settings-repository-tests.iml index 8379717cd86d..ee22d71d8f62 100644 --- a/plugins/settings-repository/settings-repository-tests.iml +++ b/plugins/settings-repository/settings-repository-tests.iml @@ -3,7 +3,7 @@ - + diff --git a/plugins/settings-repository/settings-repository.iml b/plugins/settings-repository/settings-repository.iml index 480c5a0ae562..5415701f7a1e 100644 --- a/plugins/settings-repository/settings-repository.iml +++ b/plugins/settings-repository/settings-repository.iml @@ -4,7 +4,7 @@ - + diff --git a/plugins/settings-repository/src/org/jetbrains/settingsRepository/CommitToIcsDialog.java b/plugins/settings-repository/src/CommitToIcsDialog.java similarity index 100% rename from plugins/settings-repository/src/org/jetbrains/settingsRepository/CommitToIcsDialog.java rename to plugins/settings-repository/src/CommitToIcsDialog.java diff --git a/plugins/settings-repository/src/settings/IcsConfigurable.kt b/plugins/settings-repository/src/IcsConfigurable.kt similarity index 100% rename from plugins/settings-repository/src/settings/IcsConfigurable.kt rename to plugins/settings-repository/src/IcsConfigurable.kt diff --git a/plugins/settings-repository/src/IcsManager.kt b/plugins/settings-repository/src/IcsManager.kt index 20cd11a2727c..90d78fa12981 100644 --- a/plugins/settings-repository/src/IcsManager.kt +++ b/plugins/settings-repository/src/IcsManager.kt @@ -56,12 +56,12 @@ class IcsManager(dir: Path) { val repositoryManager: RepositoryManager = GitRepositoryManager(credentialsStore, dir.resolve("repository")) init { - try { - settings = loadSettings(settingsFile) + settings = try { + loadSettings(settingsFile) } catch (e: Exception) { - settings = IcsSettings() LOG.error(e) + IcsSettings() } } diff --git a/plugins/settings-repository/src/settings/IcsSettings.kt b/plugins/settings-repository/src/IcsSettings.kt similarity index 100% rename from plugins/settings-repository/src/settings/IcsSettings.kt rename to plugins/settings-repository/src/IcsSettings.kt diff --git a/plugins/settings-repository/src/org/jetbrains/settingsRepository/IcsSettingsPanel.form b/plugins/settings-repository/src/IcsSettingsPanel.form similarity index 100% rename from plugins/settings-repository/src/org/jetbrains/settingsRepository/IcsSettingsPanel.form rename to plugins/settings-repository/src/IcsSettingsPanel.form diff --git a/plugins/settings-repository/src/org/jetbrains/settingsRepository/IcsSettingsPanel.java b/plugins/settings-repository/src/IcsSettingsPanel.java similarity index 98% rename from plugins/settings-repository/src/org/jetbrains/settingsRepository/IcsSettingsPanel.java rename to plugins/settings-repository/src/IcsSettingsPanel.java index 34f4e2862440..aa8a94c3fb58 100644 --- a/plugins/settings-repository/src/org/jetbrains/settingsRepository/IcsSettingsPanel.java +++ b/plugins/settings-repository/src/IcsSettingsPanel.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/plugins/settings-repository/src/RepositoryService.kt b/plugins/settings-repository/src/RepositoryService.kt index abf760f059f7..cd6d978c4657 100644 --- a/plugins/settings-repository/src/RepositoryService.kt +++ b/plugins/settings-repository/src/RepositoryService.kt @@ -67,7 +67,7 @@ interface RepositoryService { .yesNo(icsMessage("init.dialog.title"), icsMessage("init.dialog.message", file)) .yesText("Create") .project(project) - .`is`()) { + .isYes) { try { createBareRepository(file) return true diff --git a/plugins/settings-repository/src/copyAppSettingsToRepository.kt b/plugins/settings-repository/src/copyAppSettingsToRepository.kt index be4d4b1333b9..5b72e0bf273f 100644 --- a/plugins/settings-repository/src/copyAppSettingsToRepository.kt +++ b/plugins/settings-repository/src/copyAppSettingsToRepository.kt @@ -15,12 +15,7 @@ */ package org.jetbrains.settingsRepository -import com.intellij.configurationStore.ROOT_CONFIG -import com.intellij.configurationStore.StateStorageManagerImpl -import com.intellij.configurationStore.StreamProviderWrapper -import com.intellij.configurationStore.removeMacroIfStartsWith -import com.intellij.ide.actions.ExportableItem -import com.intellij.ide.actions.getExportableComponentsMap +import com.intellij.configurationStore.* import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.components.RoamingType import com.intellij.openapi.components.stateStore diff --git a/plugins/settings-repository/src/git/GitRepositoryManager.kt b/plugins/settings-repository/src/git/GitRepositoryManager.kt index d2205afa8948..02660790c9e6 100644 --- a/plugins/settings-repository/src/git/GitRepositoryManager.kt +++ b/plugins/settings-repository/src/git/GitRepositoryManager.kt @@ -34,10 +34,6 @@ import org.eclipse.jgit.lib.Repository import org.eclipse.jgit.lib.RepositoryState import org.eclipse.jgit.storage.file.FileRepositoryBuilder import org.eclipse.jgit.transport.* -import org.jetbrains.jgit.dirCache.AddLoadedFile -import org.jetbrains.jgit.dirCache.DeleteDirectory -import org.jetbrains.jgit.dirCache.deletePath -import org.jetbrains.jgit.dirCache.edit import org.jetbrains.settingsRepository.* import org.jetbrains.settingsRepository.RepositoryManager.Updater import java.io.IOException diff --git a/plugins/settings-repository/src/git/JGitCredentialsProvider.kt b/plugins/settings-repository/src/git/JGitCredentialsProvider.kt index 3397313bde52..68fd383d2033 100644 --- a/plugins/settings-repository/src/git/JGitCredentialsProvider.kt +++ b/plugins/settings-repository/src/git/JGitCredentialsProvider.kt @@ -19,7 +19,7 @@ import com.google.common.cache.CacheBuilder import com.google.common.cache.CacheLoader import com.intellij.credentialStore.Credentials import com.intellij.credentialStore.isFulfilled -import com.intellij.credentialStore.macOs.isMacOsCredentialStoreSupported +import com.intellij.credentialStore.isMacOsCredentialStoreSupported import com.intellij.openapi.ui.MessageDialogBuilder import com.intellij.openapi.ui.Messages import com.intellij.util.text.nullize diff --git a/plugins/settings-repository/src/git/JGitMergeProvider.kt b/plugins/settings-repository/src/git/JGitMergeProvider.kt index 16c6f9ca49a2..9a07b57ccbee 100644 --- a/plugins/settings-repository/src/git/JGitMergeProvider.kt +++ b/plugins/settings-repository/src/git/JGitMergeProvider.kt @@ -23,8 +23,6 @@ import com.intellij.openapi.vfs.VirtualFile import com.intellij.util.ArrayUtil import com.intellij.util.ui.ColumnInfo import org.eclipse.jgit.lib.Repository -import org.jetbrains.jgit.dirCache.deletePath -import org.jetbrains.jgit.dirCache.writePath import org.jetbrains.settingsRepository.RepositoryVirtualFile import java.nio.CharBuffer import java.util.* diff --git a/plugins/settings-repository/src/git/commit.kt b/plugins/settings-repository/src/git/commit.kt index 281edddba5f2..fd312a07f1cc 100644 --- a/plugins/settings-repository/src/git/commit.kt +++ b/plugins/settings-repository/src/git/commit.kt @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,9 +22,6 @@ import com.intellij.util.SmartList import org.eclipse.jgit.lib.IndexDiff import org.eclipse.jgit.lib.ProgressMonitor import org.eclipse.jgit.lib.Repository -import org.jetbrains.jgit.dirCache.AddFile -import org.jetbrains.jgit.dirCache.PathEdit -import org.jetbrains.jgit.dirCache.edit import org.jetbrains.settingsRepository.LOG import org.jetbrains.settingsRepository.PROJECTS_DIR_NAME diff --git a/plugins/settings-repository/src/git/dirCacheEditor.kt b/plugins/settings-repository/src/git/dirCacheEditor.kt index 73d2120b7033..8fe63871eb22 100644 --- a/plugins/settings-repository/src/git/dirCacheEditor.kt +++ b/plugins/settings-repository/src/git/dirCacheEditor.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jetbrains.jgit.dirCache +package org.jetbrains.settingsRepository.git import com.intellij.openapi.util.SystemInfo import com.intellij.openapi.util.io.FileUtil @@ -32,7 +32,7 @@ import java.io.FileInputStream import java.text.MessageFormat import java.util.* -private val EDIT_CMP = Comparator { o1, o2 -> +private val EDIT_CMP = Comparator { o1, o2 -> val a = o1.path val b = o2.path DirCache.cmp(a, a.size, b, b.size) @@ -166,7 +166,8 @@ class AddFile(private val pathString: String) : PathEditBase(encodePath(pathStri } } -class AddLoadedFile(path: String, private val content: ByteArray, private val size: Int = content.size, private val lastModified: Long = System.currentTimeMillis()) : PathEditBase(encodePath(path)) { +class AddLoadedFile(path: String, private val content: ByteArray, private val size: Int = content.size, private val lastModified: Long = System.currentTimeMillis()) : PathEditBase( + encodePath(path)) { override fun apply(entry: DirCacheEntry, repository: Repository) { entry.fileMode = FileMode.REGULAR_FILE entry.length = size @@ -189,7 +190,8 @@ class DeleteFile(path: ByteArray) : PathEditBase(path) { override fun apply(entry: DirCacheEntry, repository: Repository) = throw UnsupportedOperationException(JGitText.get().noApplyInDelete) } -class DeleteDirectory(entryPath: String) : PathEditBase(encodePath(if (entryPath.endsWith('/') || entryPath.isEmpty()) entryPath else "$entryPath/")) { +class DeleteDirectory(entryPath: String) : PathEditBase( + encodePath(if (entryPath.endsWith('/') || entryPath.isEmpty()) entryPath else "$entryPath/")) { override fun apply(entry: DirCacheEntry, repository: Repository) = throw UnsupportedOperationException(JGitText.get().noApplyInDelete) } diff --git a/plugins/settings-repository/src/git/reset.kt b/plugins/settings-repository/src/git/reset.kt index e7158f9f1ff3..30c1f99741b4 100644 --- a/plugins/settings-repository/src/git/reset.kt +++ b/plugins/settings-repository/src/git/reset.kt @@ -19,7 +19,6 @@ import com.intellij.openapi.diagnostic.debug import com.intellij.openapi.progress.ProgressIndicator import org.eclipse.jgit.api.MergeResult import org.eclipse.jgit.merge.MergeStrategy -import org.jetbrains.jgit.dirCache.deleteAllFiles import org.jetbrains.settingsRepository.LOG import org.jetbrains.settingsRepository.MutableUpdateResult import org.jetbrains.settingsRepository.UpdateResult diff --git a/plugins/settings-repository/src/settings/readOnlySourcesEditor.kt b/plugins/settings-repository/src/readOnlySourcesEditor.kt similarity index 100% rename from plugins/settings-repository/src/settings/readOnlySourcesEditor.kt rename to plugins/settings-repository/src/readOnlySourcesEditor.kt diff --git a/plugins/settings-repository/src/settings/repositoryListEditor.kt b/plugins/settings-repository/src/repositoryListEditor.kt similarity index 100% rename from plugins/settings-repository/src/settings/repositoryListEditor.kt rename to plugins/settings-repository/src/repositoryListEditor.kt diff --git a/plugins/settings-repository/src/settings/upstreamEditor.kt b/plugins/settings-repository/src/upstreamEditor.kt similarity index 100% rename from plugins/settings-repository/src/settings/upstreamEditor.kt rename to plugins/settings-repository/src/upstreamEditor.kt diff --git a/plugins/settings-repository/testSrc/GitTest.kt b/plugins/settings-repository/testSrc/GitTest.kt index 50eaa948a7d6..15bb7b4ce687 100644 --- a/plugins/settings-repository/testSrc/GitTest.kt +++ b/plugins/settings-repository/testSrc/GitTest.kt @@ -23,14 +23,14 @@ import com.intellij.testFramework.file import com.intellij.util.PathUtilRt import com.intellij.util.io.writeChild import org.assertj.core.api.Assertions.assertThat -import org.jetbrains.jgit.dirCache.deletePath -import org.jetbrains.jgit.dirCache.writePath import org.jetbrains.settingsRepository.CannotResolveConflictInTestMode import org.jetbrains.settingsRepository.SyncType import org.jetbrains.settingsRepository.conflictResolver import org.jetbrains.settingsRepository.copyLocalConfig import org.jetbrains.settingsRepository.git.commit import org.jetbrains.settingsRepository.git.computeIndexDiff +import org.jetbrains.settingsRepository.git.deletePath +import org.jetbrains.settingsRepository.git.writePath import org.junit.Test import java.nio.charset.StandardCharsets import java.util.* diff --git a/plugins/settings-repository/testSrc/IcsCredentialTest.kt b/plugins/settings-repository/testSrc/IcsCredentialTest.kt index 8e7121275517..464c03608eb9 100644 --- a/plugins/settings-repository/testSrc/IcsCredentialTest.kt +++ b/plugins/settings-repository/testSrc/IcsCredentialTest.kt @@ -1,4 +1,4 @@ -package org.jetbrains.settingsRepository +package org.jetbrains.settingsRepository.test import com.intellij.credentialStore.Credentials import com.intellij.credentialStore.OneTimeString @@ -7,6 +7,7 @@ import org.assertj.core.api.Assertions.assertThat import org.eclipse.jgit.storage.file.FileRepositoryBuilder import org.eclipse.jgit.transport.CredentialItem import org.eclipse.jgit.transport.URIish +import org.jetbrains.settingsRepository.IcsCredentialsStore import org.jetbrains.settingsRepository.git.JGitCredentialsProvider import org.junit.ClassRule import org.junit.Test diff --git a/plugins/settings-repository/testSrc/IcsTestCase.kt b/plugins/settings-repository/testSrc/IcsTestCase.kt index 1646c533a652..89a9c7b5b6b8 100644 --- a/plugins/settings-repository/testSrc/IcsTestCase.kt +++ b/plugins/settings-repository/testSrc/IcsTestCase.kt @@ -19,10 +19,10 @@ import com.intellij.testFramework.InMemoryFsRule import com.intellij.testFramework.TemporaryDirectory import com.intellij.util.io.writeChild import org.eclipse.jgit.lib.Repository -import org.jetbrains.jgit.dirCache.AddLoadedFile -import org.jetbrains.jgit.dirCache.edit import org.jetbrains.settingsRepository.IcsManager +import org.jetbrains.settingsRepository.git.AddLoadedFile import org.jetbrains.settingsRepository.git.createGitRepository +import org.jetbrains.settingsRepository.git.edit import org.junit.Rule import java.nio.file.FileSystem import java.nio.file.Path diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/CopiesPanel.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/CopiesPanel.java index 5cec52163510..e53136fe2c85 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/CopiesPanel.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/CopiesPanel.java @@ -186,9 +186,6 @@ public class CopiesPanel { final JScrollPane pane = ScrollPaneFactory.createScrollPane(holderPanel); registerHelp(pane); myHolder = pane; - final JScrollBar vBar = pane.getVerticalScrollBar(); - vBar.setBlockIncrement(vBar.getBlockIncrement() * 5); - vBar.setUnitIncrement(vBar.getUnitIncrement() * 5); myHolder.setBorder(null); setFocusableForLinks(myRefreshLabel); refreshOnPooled.consume(true); diff --git a/resources/src/META-INF/IdeaPlugin.xml b/resources/src/META-INF/IdeaPlugin.xml index ea6c97b61240..84713f65de70 100644 --- a/resources/src/META-INF/IdeaPlugin.xml +++ b/resources/src/META-INF/IdeaPlugin.xml @@ -1649,6 +1649,7 @@ + diff --git a/resources/src/idea/RichPlatformActions.xml b/resources/src/idea/RichPlatformActions.xml index c08541820d0a..8b01f1bc4930 100644 --- a/resources/src/idea/RichPlatformActions.xml +++ b/resources/src/idea/RichPlatformActions.xml @@ -4,7 +4,8 @@ - +