diff --git a/.idea/modules.xml b/.idea/modules.xml
index 7e7c54b009a4..430c128405c2 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -12,7 +12,7 @@
-
+
diff --git a/build/scripts/common_tests.gant b/build/scripts/common_tests.gant
index 42a5e6b76ac7..898b8938f613 100644
--- a/build/scripts/common_tests.gant
+++ b/build/scripts/common_tests.gant
@@ -16,7 +16,6 @@
import static org.jetbrains.jps.idea.IdeaProjectLoader.guessHome
includeTargets << new File("${guessHome(this)}/build/scripts/utils.gant")
-includeTargets << new File("${guessHome(this)}/build/scripts/cucumber-tests.gant")
requireProperty("out", "$home/out")
@@ -108,5 +107,5 @@ target('run_tests': 'Run java tests') {
}
target('default' : "Run all tests") {
- depends([compile, run_tests, run_cucumber_tests])
+ depends([compile, run_tests])
}
\ No newline at end of file
diff --git a/build/scripts/cucumber-tests.gant b/build/scripts/cucumber-tests.gant
deleted file mode 100644
index 7eb4e4bf40b8..000000000000
--- a/build/scripts/cucumber-tests.gant
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright 2000-2013 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.
- */
-target('run_cucumber_tests': "Run cucumber tests") {
- if (!isDefined("cucumber_test_dirs")) {
- return
- }
-
- cucumber_test_dirs.each {
- def m = findModule(it[0])
- def platformPrefix = it[1]
- def testsDir = it[2]
- def stepDefsPackage = it[3]
-
-
- ant.java(failonerror: "true", classname: "com.intellij.cucumber.CucumberMain", fork: "true", dir: testsDir) {
- jvmarg(line: "-Xmx512m")
- jvmarg(line: "-XX:MaxPermSize=350m")
- jvmarg(line: "-XX:+HeapDumpOnOutOfMemoryError")
- jvmarg(line: "-ea")
- jvmarg(line: "-Didea.platform.prefix=$platformPrefix")
-
- System.getProperties().entrySet().each {
- if (it.key.startsWith("pass.")) {
- def trimmed = it.key.substring("pass.".length());
- jvmarg(value: "-D${trimmed}=${it.value}");
- };
- }
-
- arg(value: "--format")
- arg(value: "org.jetbrains.plugins.cucumber.java.run.CucumberJvmSMFormatter")
- arg(value: "--glue")
- arg(value: stepDefsPackage)
- arg(value: ".")
-
- classpath() {
- projectBuilder.moduleRuntimeClasspath(findModule("cucumber-test-runner"), false).each {
- pathelement(location: it)
- }
- projectBuilder.moduleRuntimeClasspath(m, true).each {
- pathelement(location: it)
- }
- }
- }
-
- }
-
-}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/MethodBreakpoint.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/MethodBreakpoint.java
index 1a7da7eda2fe..da776d39b2bf 100644
--- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/MethodBreakpoint.java
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/MethodBreakpoint.java
@@ -48,7 +48,9 @@ import com.intellij.psi.*;
import com.intellij.util.StringBuilderSpinAllocator;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.MultiMap;
+import com.intellij.xdebugger.XDebuggerManager;
import com.intellij.xdebugger.breakpoints.XBreakpoint;
+import com.intellij.xdebugger.breakpoints.XBreakpointListener;
import com.sun.jdi.*;
import com.sun.jdi.event.LocatableEvent;
import com.sun.jdi.event.MethodEntryEvent;
@@ -69,6 +71,7 @@ import org.jetbrains.org.objectweb.asm.Opcodes;
import javax.swing.*;
import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import java.util.stream.Stream;
@@ -132,7 +135,7 @@ public class MethodBreakpoint extends BreakpointWithHighlighter indicatorRef = new AtomicReference<>();
+ AtomicReference indicatorRef = new AtomicReference<>();
ApplicationManager.getApplication().invokeAndWait(
() -> {
ProgressWindowWithNotification progress =
@@ -140,13 +143,35 @@ public class MethodBreakpoint extends BreakpointWithHighlighter> listener = new XBreakpointListener>() {
+ void changed(@NotNull XBreakpoint b) {
+ if (b == breakpoint.getXBreakpoint()) {
+ changed.set(true);
+ indicator.cancel();
+ }
+ }
+
+ @Override
+ public void breakpointRemoved(@NotNull XBreakpoint b) {
+ changed(b);
+ }
+
+ @Override
+ public void breakpointChanged(@NotNull XBreakpoint b) {
+ changed(b);
+ }
+ };
+
+ XDebuggerManager.getInstance(debugProcess.getProject()).getBreakpointManager().addBreakpointListener(listener, indicator);
ProgressManager.getInstance().executeProcessUnderProgress(
() -> processPreparedSubTypes(baseType,
subType -> createRequestForPreparedClassEmulated(breakpoint, debugProcess, subType, false),
indicator),
indicator);
- if (indicator.isCanceled()) {
+ if (indicator.isCanceled() && !changed.get()) {
breakpoint.disableEmulation();
}
}
diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/ModuleHighlightUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/ModuleHighlightUtil.java
index 85badb241cb9..26ff9d8148ce 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/ModuleHighlightUtil.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/ModuleHighlightUtil.java
@@ -197,6 +197,7 @@ public class ModuleHighlightUtil {
String message = JavaErrorMessages.message(key, refText);
HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(statement).descriptionAndTooltip(message).create();
QuickFixAction.registerQuickFixAction(info, factory().createDeleteFix(statement));
+ QuickFixAction.registerQuickFixAction(info, MergeModuleStatementsFix.createFix(statement));
results.add(info);
}
}
diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/MergeModuleStatementsFix.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/MergeModuleStatementsFix.java
new file mode 100644
index 000000000000..aab24b6ded6d
--- /dev/null
+++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/MergeModuleStatementsFix.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2000-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.codeInsight.daemon.impl.quickfix;
+
+import com.intellij.codeInspection.LocalQuickFixAndIntentionActionOnPsiElement;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.*;
+import com.intellij.psi.codeStyle.CodeStyleManager;
+import com.intellij.psi.util.PsiUtil;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.StringJoiner;
+
+/**
+ * @author Pavel.Dolgov
+ */
+public abstract class MergeModuleStatementsFix extends LocalQuickFixAndIntentionActionOnPsiElement {
+ protected final SmartPsiElementPointer myOtherStatement;
+
+ protected MergeModuleStatementsFix(@NotNull T thisStatement, @NotNull T otherStatement) {
+ super(thisStatement);
+ final PsiFile file = otherStatement.getContainingFile();
+ myOtherStatement = SmartPointerManager.getInstance(otherStatement.getProject()).createSmartPsiElementPointer(otherStatement, file);
+ }
+
+ @Override
+ public boolean isAvailable(@NotNull Project project,
+ @NotNull PsiFile file,
+ @NotNull PsiElement startElement,
+ @NotNull PsiElement endElement) {
+ final T otherStatement = myOtherStatement.getElement();
+ return otherStatement != null && otherStatement.isValid() && PsiUtil.isLanguageLevel9OrHigher(file);
+ }
+
+ @Override
+ public void invoke(@NotNull Project project,
+ @NotNull PsiFile file,
+ @Nullable Editor editor,
+ @NotNull PsiElement thisStatement,
+ @NotNull PsiElement endElement) {
+ final T otherStatement = myOtherStatement.getElement();
+
+ if (otherStatement != null) {
+ final PsiElement parent = otherStatement.getParent();
+ if (parent instanceof PsiJavaModule) {
+ final String moduleName = ((PsiJavaModule)parent).getName();
+ final String moduleText = PsiKeyword.MODULE + " " + moduleName + " {" + getReplacementText(otherStatement) + "}";
+ final PsiElementFactory factory = JavaPsiFacade.getInstance(project).getElementFactory();
+ final PsiJavaModule tempModule = factory.createModuleFromText(moduleText);
+
+ final Iterator statementIterator = getStatements(tempModule).iterator();
+ LOG.assertTrue(statementIterator.hasNext());
+ final T replacement = statementIterator.next();
+
+ final CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project);
+ codeStyleManager.reformat(otherStatement.replace(replacement));
+ thisStatement.delete();
+ }
+ }
+ }
+
+ @NotNull
+ protected abstract String getReplacementText(@NotNull T otherStatement);
+
+ @NotNull
+ protected abstract Iterable getStatements(@NotNull PsiJavaModule javaModule);
+
+ @NotNull
+ protected static String joinNames(@NotNull List oldNames, @NotNull List newNames) {
+ final StringJoiner joiner = new StringJoiner(",");
+ oldNames.forEach(joiner::add);
+ newNames.stream().filter(name -> !oldNames.contains(name)).forEach(joiner::add);
+ return joiner.toString();
+ }
+
+ @Nullable
+ public static MergeModuleStatementsFix createFix(@Nullable PsiElement statement) {
+ if (statement instanceof PsiPackageAccessibilityStatement) {
+ return MergePackageAccessibilityStatementsFix.createFix((PsiPackageAccessibilityStatement)statement);
+ }
+ else if (statement instanceof PsiProvidesStatement) {
+ return MergeProvidesStatementsFix.createFix((PsiProvidesStatement)statement);
+ }
+ return null;
+ }
+}
diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/MergePackageAccessibilityStatementsFix.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/MergePackageAccessibilityStatementsFix.java
new file mode 100644
index 000000000000..0f771dce97b2
--- /dev/null
+++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/MergePackageAccessibilityStatementsFix.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2000-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.codeInsight.daemon.impl.quickfix;
+
+import com.intellij.codeInsight.daemon.QuickFixBundle;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiJavaModule;
+import com.intellij.psi.PsiKeyword;
+import com.intellij.psi.PsiPackageAccessibilityStatement;
+import com.intellij.psi.PsiPackageAccessibilityStatement.Role;
+import org.jetbrains.annotations.Nls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * @author Pavel.Dolgov
+ */
+public class MergePackageAccessibilityStatementsFix
+ extends MergeModuleStatementsFix {
+
+ private static final Logger LOG = Logger.getInstance(MergePackageAccessibilityStatementsFix.class);
+ private final String myPackageName;
+ private final List myModuleNames;
+ private final Role myRole;
+
+ protected MergePackageAccessibilityStatementsFix(@NotNull PsiPackageAccessibilityStatement thisStatement,
+ @NotNull String packageName,
+ @NotNull List moduleNames,
+ @NotNull PsiPackageAccessibilityStatement otherStatement) {
+ super(thisStatement, otherStatement);
+ myPackageName = packageName;
+ myModuleNames = moduleNames;
+ myRole = thisStatement.getRole();
+ }
+
+ @Nls
+ @NotNull
+ @Override
+ public String getText() {
+ return QuickFixBundle.message("java.9.merge.module.statements.fix.name", getKeyword(), myPackageName);
+ }
+
+ @Nls
+ @NotNull
+ @Override
+ public String getFamilyName() {
+ return QuickFixBundle.message("java.9.merge.module.statements.fix.family.name", getKeyword());
+ }
+
+ @NotNull
+ @Override
+ protected String getReplacementText(@NotNull PsiPackageAccessibilityStatement otherStatement) {
+ return getKeyword() + " " + myPackageName + " " + PsiKeyword.TO + " " +
+ joinNames(otherStatement.getModuleNames(), myModuleNames) + ";";
+ }
+
+ @NotNull
+ @Override
+ protected Iterable getStatements(@NotNull PsiJavaModule javaModule) {
+ return getStatements(javaModule, myRole);
+ }
+
+ @Nullable
+ public static MergeModuleStatementsFix createFix(@Nullable PsiPackageAccessibilityStatement statement) {
+ if (statement != null) {
+ final PsiElement parent = statement.getParent();
+ if (parent instanceof PsiJavaModule) {
+ final PsiJavaModule javaModule = (PsiJavaModule)parent;
+
+ final String packageName = statement.getPackageName();
+ if (packageName != null) {
+ final List moduleNames = statement.getModuleNames();
+ if (!moduleNames.isEmpty()) {
+ for (PsiPackageAccessibilityStatement candidate : getStatements(javaModule, statement.getRole())) {
+ if (candidate != statement &&
+ packageName.equals(candidate.getPackageName()) &&
+ candidate.getModuleNames().iterator().hasNext()) {
+ return new MergePackageAccessibilityStatementsFix(statement, packageName, moduleNames, candidate);
+ }
+ }
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ @NotNull
+ private static Iterable getStatements(@NotNull PsiJavaModule javaModule, @NotNull Role role) {
+ switch (role) {
+ case OPENS:
+ return javaModule.getOpens();
+ case EXPORTS:
+ return javaModule.getExports();
+ }
+ LOG.error("Unexpected role " + role);
+ return Collections.emptyList();
+ }
+
+ @NotNull
+ private String getKeyword() {
+ switch (myRole) {
+ case OPENS:
+ return PsiKeyword.OPENS;
+ case EXPORTS:
+ return PsiKeyword.EXPORTS;
+ }
+ LOG.error("Unexpected role " + myRole);
+ return "";
+ }
+}
diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/MergeProvidesStatementsFix.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/MergeProvidesStatementsFix.java
new file mode 100644
index 000000000000..d5ef41fbde47
--- /dev/null
+++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/MergeProvidesStatementsFix.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2000-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.codeInsight.daemon.impl.quickfix;
+
+import com.intellij.codeInsight.daemon.QuickFixBundle;
+import com.intellij.psi.*;
+import org.jetbrains.annotations.Nls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+/**
+ * @author Pavel.Dolgov
+ */
+public class MergeProvidesStatementsFix extends MergeModuleStatementsFix {
+ private final String myInterfaceName;
+ private final List myImplementationNames;
+
+ MergeProvidesStatementsFix(@NotNull PsiProvidesStatement thisStatement,
+ @NotNull String interfaceName,
+ @NotNull List implementationNames,
+ @NotNull PsiProvidesStatement otherStatement) {
+ super(thisStatement, otherStatement);
+ myInterfaceName = interfaceName;
+ myImplementationNames = implementationNames;
+ }
+
+ @NotNull
+ @Override
+ public String getText() {
+ return QuickFixBundle.message("java.9.merge.module.statements.fix.name", PsiKeyword.PROVIDES, myInterfaceName);
+ }
+
+ @Nls
+ @NotNull
+ @Override
+ public String getFamilyName() {
+ return QuickFixBundle.message("java.9.merge.module.statements.fix.family.name", PsiKeyword.PROVIDES);
+ }
+
+ @NotNull
+ @Override
+ protected String getReplacementText(@NotNull PsiProvidesStatement otherStatement) {
+ return PsiKeyword.PROVIDES + " " + myInterfaceName + " " + PsiKeyword.WITH + " " +
+ joinNames(getImplementationNames(otherStatement), myImplementationNames) + ";";
+ }
+
+ @NotNull
+ @Override
+ protected Iterable getStatements(@NotNull PsiJavaModule javaModule) {
+ return javaModule.getProvides();
+ }
+
+ @NotNull
+ private static List getImplementationNames(@Nullable PsiProvidesStatement statement) {
+ if (statement != null) {
+ final PsiReferenceList implementationList = statement.getImplementationList();
+ if (implementationList != null) {
+ return Arrays.stream(implementationList.getReferenceElements())
+ .map(PsiJavaCodeReferenceElement::getQualifiedName)
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+ }
+ }
+ return Collections.emptyList();
+ }
+
+ @Nullable
+ public static MergeModuleStatementsFix createFix(@Nullable PsiProvidesStatement statement) {
+ if (statement != null) {
+ final PsiElement parent = statement.getParent();
+ if (parent instanceof PsiJavaModule) {
+ final PsiJavaModule javaModule = (PsiJavaModule)parent;
+
+ final PsiJavaCodeReferenceElement interfaceReference = statement.getInterfaceReference();
+ if (interfaceReference != null) {
+ final String interfaceName = interfaceReference.getQualifiedName();
+ if (interfaceName != null) {
+ final List implementationNames = getImplementationNames(statement);
+ if (!implementationNames.isEmpty()) {
+ for (PsiProvidesStatement candidate : javaModule.getProvides()) {
+ final PsiJavaCodeReferenceElement candidateInterfaceReference = candidate.getInterfaceReference();
+ if (candidateInterfaceReference != null && interfaceName.equals(candidateInterfaceReference.getQualifiedName())) {
+ return new MergeProvidesStatementsFix(statement, interfaceName, implementationNames, candidate);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return null;
+ }
+}
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix/Exports1.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix/Exports1.java
new file mode 100644
index 000000000000..f6177533a7db
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix/Exports1.java
@@ -0,0 +1,4 @@
+module M {
+ exports my.api to M4;
+ exports my.api to M6;
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix/Exports1_after.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix/Exports1_after.java
new file mode 100644
index 000000000000..7429e15dd796
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix/Exports1_after.java
@@ -0,0 +1,3 @@
+module M {
+ exports my.api to M4, M6;
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix/Exports2.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix/Exports2.java
new file mode 100644
index 000000000000..fe9b8f588763
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix/Exports2.java
@@ -0,0 +1,5 @@
+module M {
+ exports my.api;
+ exports my.api to M2, M4;
+ exports my.api to M6;
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix/Exports2_after.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix/Exports2_after.java
new file mode 100644
index 000000000000..a773247df415
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix/Exports2_after.java
@@ -0,0 +1,4 @@
+module M {
+ exports my.api;
+ exports my.api to M6, M2, M4;
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix/Opens1.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix/Opens1.java
new file mode 100644
index 000000000000..748f667a110d
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix/Opens1.java
@@ -0,0 +1,4 @@
+module M {
+ opens my.api to M4;
+ opens my.api to M6;
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix/Opens1_after.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix/Opens1_after.java
new file mode 100644
index 000000000000..d0ebef07939e
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix/Opens1_after.java
@@ -0,0 +1,3 @@
+module M {
+ opens my.api to M4, M6;
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix/Opens2.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix/Opens2.java
new file mode 100644
index 000000000000..8ef463a4e2ee
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix/Opens2.java
@@ -0,0 +1,5 @@
+module M {
+ opens my.api;
+ opens my.api to M2, M4;
+ opens my.api to M6;
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix/Opens2_after.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix/Opens2_after.java
new file mode 100644
index 000000000000..321668b41336
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix/Opens2_after.java
@@ -0,0 +1,4 @@
+module M {
+ opens my.api;
+ opens my.api to M6, M2, M4;
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix/Provides1.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix/Provides1.java
new file mode 100644
index 000000000000..85f06ee632b0
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix/Provides1.java
@@ -0,0 +1,4 @@
+module M {
+ provides my.api.MyService with my.impl.MyServiceImpl;
+ provides my.api.MyService with my.impl.MyServiceImpl1;
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix/Provides1_after.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix/Provides1_after.java
new file mode 100644
index 000000000000..910b1b3a4d33
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix/Provides1_after.java
@@ -0,0 +1,3 @@
+module M {
+ provides my.api.MyService with my.impl.MyServiceImpl,my.impl.MyServiceImpl1;
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix/Provides2.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix/Provides2.java
new file mode 100644
index 000000000000..1f239ec09995
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix/Provides2.java
@@ -0,0 +1,8 @@
+import my.impl.MyServiceImpl;
+import my.impl.MyServiceImpl1;
+import my.impl.MyServiceImpl2;
+
+module M {
+ provides my.api.MyService with MyServiceImpl, MyServiceImpl2;
+ provides my.api.MyService with MyServiceImpl1;
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix/Provides2_after.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix/Provides2_after.java
new file mode 100644
index 000000000000..939d69b108c2
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix/Provides2_after.java
@@ -0,0 +1,7 @@
+import my.impl.MyServiceImpl;
+import my.impl.MyServiceImpl1;
+import my.impl.MyServiceImpl2;
+
+module M {
+ provides my.api.MyService with MyServiceImpl,MyServiceImpl2,MyServiceImpl1;
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix/Provides3.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix/Provides3.java
new file mode 100644
index 000000000000..2ee7ea1d1383
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix/Provides3.java
@@ -0,0 +1,8 @@
+import my.impl.MyServiceImpl;
+import my.impl.MyServiceImpl1;
+import my.impl.MyServiceImpl2;
+
+module M {
+ provides my.api.MyService with MyServiceImpl;
+ provides my.api.MyService with MyServiceImpl1, MyServiceImpl2;
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix/Provides3_after.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix/Provides3_after.java
new file mode 100644
index 000000000000..f7ad4557f838
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix/Provides3_after.java
@@ -0,0 +1,7 @@
+import my.impl.MyServiceImpl;
+import my.impl.MyServiceImpl1;
+import my.impl.MyServiceImpl2;
+
+module M {
+ provides my.api.MyService with MyServiceImpl,MyServiceImpl1,MyServiceImpl2;
+}
\ No newline at end of file
diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/MergeModuleStatementsFixTest.kt b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/MergeModuleStatementsFixTest.kt
new file mode 100644
index 000000000000..6bc714d33279
--- /dev/null
+++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/MergeModuleStatementsFixTest.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2000-2017 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.JavaTestUtil.getRelativeJavaTestDataPath
+import com.intellij.codeInsight.daemon.QuickFixBundle
+import com.intellij.codeInsight.intention.IntentionAction
+import com.intellij.testFramework.fixtures.LightJava9ModulesCodeInsightFixtureTestCase
+import com.intellij.testFramework.fixtures.MultiModuleJava9ProjectDescriptor.ModuleDescriptor.*
+
+/**
+ * @author Pavel.Dolgov
+ */
+class MergeModuleStatementsFixTest : LightJava9ModulesCodeInsightFixtureTestCase() {
+
+ override fun getBasePath() = getRelativeJavaTestDataPath() + "/codeInsight/daemonCodeAnalyzer/quickFix/mergeModuleStatementsFix"
+
+ fun testExports1() = doTest("exports", "my.api")
+ fun testExports2() = doTest("exports", "my.api")
+
+ fun testProvides1() = doTest("provides", "my.api.MyService")
+ fun testProvides2() = doTest("provides", "my.api.MyService")
+ fun testProvides3() = doTest("provides", "my.api.MyService")
+
+ fun testOpens1() = doTest("opens", "my.api")
+ fun testOpens2() = doTest("opens", "my.api")
+
+
+ override fun setUp() {
+ super.setUp()
+ addFile("module-info.java", "module M2 { }", M2)
+ addFile("module-info.java", "module M4 { }", M4)
+ addFile("module-info.java", "module M6 { }", M6)
+
+ addFile("my/api/MyService.java", "package my.api; public class MyService {}")
+ addFile("my/impl/MyServiceImpl.java", "package my.impl; public class MyServiceImpl extends my.api.MyService {}")
+ addFile("my/impl/MyServiceImpl1.java", "package my.impl; public class MyServiceImpl1 extends my.api.MyService {}")
+ addFile("my/impl/MyServiceImpl2.java", "package my.impl; public class MyServiceImpl2 extends my.api.MyService {}")
+ }
+
+ private fun doTest(type: String, name: String) {
+ val testName = getTestName(false)
+ val virtualFile = myFixture.copyFileToProject("${testName}.java", "module-info.java")
+ myFixture.configureFromExistingVirtualFile(virtualFile)
+
+ val action = findActionWithText(QuickFixBundle.message("java.9.merge.module.statements.fix.name", type, name))
+ myFixture.launchAction(action)
+ myFixture.checkResultByFile("${testName}_after.java")
+ }
+
+ private fun findActionWithText(actionText: String): IntentionAction {
+ myFixture.doHighlighting()
+
+ val actions = LightQuickFixTestCase.getAvailableActions(editor, file)
+ val action = LightQuickFixTestCase.findActionWithText(actions, actionText)
+ assertNotNull("No action [$actionText] in ${actions.map { it.text }}", action)
+ return action
+ }
+}
\ No newline at end of file
diff --git a/platform/platform-impl/src/com/intellij/credentialStore/credentialPromt.kt b/platform/platform-impl/src/com/intellij/credentialStore/credentialPromt.kt
index daf18871d55d..4c9809f088dc 100644
--- a/platform/platform-impl/src/com/intellij/credentialStore/credentialPromt.kt
+++ b/platform/platform-impl/src/com/intellij/credentialStore/credentialPromt.kt
@@ -21,6 +21,7 @@ import com.intellij.ide.passwordSafe.PasswordSafe
import com.intellij.openapi.application.ModalityState
import com.intellij.openapi.application.invokeAndWaitIfNeed
import com.intellij.openapi.project.Project
+import com.intellij.ui.AppIcon
import com.intellij.ui.components.CheckBox
import com.intellij.ui.components.dialog
import com.intellij.ui.layout.*
@@ -83,6 +84,7 @@ fun askCredentials(project: Project?,
}
}
+ AppIcon.getInstance().requestAttention(project, true)
if (dialog(dialogTitle, project = project, panel = panel, focusedComponent = passwordField, errorText = error).showAndGet()) {
val isMemoryOnly = store.isMemoryOnly || !rememberCheckBox!!.isSelected
val credentials = Credentials(attributes.userName, passwordField.password.nullize())
diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/DarculaUIUtil.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/DarculaUIUtil.java
index 317bddc5741a..fb8092c8812d 100644
--- a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/DarculaUIUtil.java
+++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/DarculaUIUtil.java
@@ -28,7 +28,6 @@ import javax.swing.text.Position;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.geom.Path2D;
-import java.awt.geom.RoundRectangle2D;
import static javax.swing.SwingConstants.EAST;
import static javax.swing.SwingConstants.WEST;
@@ -116,28 +115,52 @@ public class DarculaUIUtil {
}
public static void paintErrorBorder(Graphics2D g, int width, int height, int arc, boolean hasFocus) {
- int lw = JBUI.scale(UIUtil.isUnderDefaultMacTheme() ? 4 : 3);
-
- g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
- g.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, MacUIUtil.USE_QUARTZ ? RenderingHints.VALUE_STROKE_PURE : RenderingHints.VALUE_STROKE_NORMALIZE);
g.setPaint(hasFocus ? ACTIVE_ERROR_COLOR : INACTIVE_ERROR_COLOR);
-
- Path2D path = new Path2D.Double(Path2D.WIND_EVEN_ODD);
- path.append(new RoundRectangle2D.Double(0, 0, width, height, arc + lw * 2, arc + lw * 2), false);
- path.append(new RoundRectangle2D.Double(lw, lw, width - lw * 2, height - lw * 2, arc, arc), false);
-
- g.fill(path);
+ doPaint(g, width, height, arc);
}
- public static void paintFocusBorder(Graphics2D g, int width, int height, int lw, int arc) {
+ public static void paintFocusBorder(Graphics2D g, int width, int height, int arc) {
+ g.setPaint(IntelliJLaf.isGraphite() ? MAC_GRAPHITE_COLOR : MAC_REGULAR_COLOR);
+ doPaint(g, width, height, arc);
+ }
+
+ @SuppressWarnings("SuspiciousNameCombination")
+ private static void doPaint(Graphics2D g, int width, int height, int arc) {
+ double bw = UIUtil.isRetina(g) ? 0.5 : 1.0;
+ double lw = JBUI.scale(UIUtil.isUnderDefaultMacTheme() ? 3 : 2);
+
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, MacUIUtil.USE_QUARTZ ? RenderingHints.VALUE_STROKE_PURE : RenderingHints.VALUE_STROKE_NORMALIZE);
- g.setPaint(IntelliJLaf.isGraphite() ? MAC_GRAPHITE_COLOR : MAC_REGULAR_COLOR);
+
+ double outerArc = arc > 0 ? arc + lw - JBUI.scale(2) : lw;
+ double rightOuterArc = JBUI.scale(6);
+ Path2D outerRect = new Path2D.Double(Path2D.WIND_EVEN_ODD);
+ outerRect.moveTo(width - rightOuterArc, 0);
+ outerRect.quadTo(width, 0, width, rightOuterArc);
+ outerRect.lineTo(width, height - rightOuterArc);
+ outerRect.quadTo(width, height, width - rightOuterArc, height);
+ outerRect.lineTo(outerArc, height);
+ outerRect.quadTo(0, height, 0, height - outerArc);
+ outerRect.lineTo(0, outerArc);
+ outerRect.quadTo(0, 0, outerArc, 0);
+ outerRect.closePath();
+
+ lw += bw;
+ double rightInnerArc = JBUI.scale(7);
+ Path2D innerRect = new Path2D.Double(Path2D.WIND_EVEN_ODD);
+ innerRect.moveTo(width - rightInnerArc, lw);
+ innerRect.quadTo(width - lw, lw , width - lw, rightInnerArc);
+ innerRect.lineTo(width - lw, height - rightInnerArc);
+ innerRect.quadTo(width - lw, height - lw, width - rightInnerArc, height - lw);
+ innerRect.lineTo(outerArc, height - lw);
+ innerRect.quadTo(lw, height - lw, lw, height - outerArc);
+ innerRect.lineTo(lw, outerArc);
+ innerRect.quadTo(lw, lw, outerArc, lw);
+ innerRect.closePath();
Path2D path = new Path2D.Double(Path2D.WIND_EVEN_ODD);
- path.append(new RoundRectangle2D.Double(0, 0, width, height, arc + lw * 2, arc + lw * 2), false);
- path.append(new RoundRectangle2D.Double(lw, lw, width - lw * 2, height - lw * 2, arc, arc), false);
-
+ path.append(outerRect, false);
+ path.append(innerRect, false);
g.fill(path);
}
diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaSpinnerUI.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaSpinnerUI.java
index 2902e47a24f1..d41200bd0164 100644
--- a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaSpinnerUI.java
+++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaSpinnerUI.java
@@ -137,10 +137,8 @@ public class DarculaSpinnerUI extends BasicSpinnerUI {
}
protected void layoutEditor(@NotNull JComponent editor) {
- if (editor != null) {
- final Rectangle bounds = editor.getBounds();
+ Rectangle bounds = editor.getBounds();
editor.setBounds(bounds.x, bounds.y, bounds.width - 6, bounds.height);
- }
}
protected void paintArrowButton(Graphics g,
diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/MacComboBoxBorder.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/MacComboBoxBorder.java
index af450b4ea0a7..3e3944643617 100644
--- a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/MacComboBoxBorder.java
+++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/MacComboBoxBorder.java
@@ -16,9 +16,10 @@
package com.intellij.ide.ui.laf.intellij;
import com.intellij.ui.Gray;
-import com.intellij.ui.paint.RectanglePainter;
import com.intellij.util.ui.JBInsets;
import com.intellij.util.ui.JBUI;
+import com.intellij.util.ui.MacUIUtil;
+import com.intellij.util.ui.UIUtil;
import javax.swing.*;
import java.awt.*;
@@ -27,6 +28,8 @@ import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
+import static com.intellij.ide.ui.laf.intellij.MacIntelliJComboBoxUI.VALUE_OFFSET;
+
/**
* @author Konstantin Bulenkov
*/
@@ -34,11 +37,13 @@ public class MacComboBoxBorder extends MacIntelliJTextBorder {
@Override
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
- Graphics2D g2 = (Graphics2D)g.create();
+ if (!(c instanceof JComponent)) return;
+ Graphics2D g2 = (Graphics2D)g.create();
try {
g2.translate(x, y);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+ g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, MacUIUtil.USE_QUARTZ ? RenderingHints.VALUE_STROKE_PURE : RenderingHints.VALUE_STROKE_NORMALIZE);
Shape clip = g2.getClip();
Area area = new Area(new Rectangle2D.Double(0, 0, width, height));
@@ -46,26 +51,43 @@ public class MacComboBoxBorder extends MacIntelliJTextBorder {
area.intersect(new Area(clip));
g2.setClip(area);
- int arc = isRound(c) ? JBUI.scale(8) : 0;
+ int arc = isRound(c) ? JBUI.scale(6) : 0;
+ Insets i = ((JComponent)c).getInsets();
if (c instanceof JComboBox) {
JComboBox comboBox = (JComboBox)c;
g2.setColor(UIManager.getColor(comboBox.isEnabled() ? "ComboBox.background" : "ComboBox.disabledBackground"));
- Path2D path = new Path2D.Double(Path2D.WIND_EVEN_ODD);
- path.moveTo(JBUI.scale(8), JBUI.scale(3));
- path.lineTo(JBUI.scale(8), c.getHeight() - JBUI.scale(3));
- path.lineTo(JBUI.scale(3) + arc, c.getHeight() - JBUI.scale(3));
- path.quadTo(JBUI.scale(3), c.getHeight() - JBUI.scale(3), JBUI.scale(3), c.getHeight() - JBUI.scale(3) - arc);
- path.lineTo(JBUI.scale(3), JBUI.scale(3) + arc);
- path.quadTo(JBUI.scale(3), JBUI.scale(3), JBUI.scale(3) + arc, JBUI.scale(3));
- path.lineTo(JBUI.scale(8), JBUI.scale(3));
- g2.fill(path);
+ if (comboBox.isEditable()) {
+ Shape shape = new Rectangle2D.Double(i.left, i.top,
+ width - (i.left + i.right),
+ height - (i.top + i.bottom));
+ g2.fill(shape);
+ } else {
+ Path2D path = new Path2D.Double(Path2D.WIND_EVEN_ODD);
+ path.moveTo(i.left + VALUE_OFFSET, i.top);
+ path.lineTo(i.left + VALUE_OFFSET, c.getHeight() - i.bottom);
+ path.lineTo(i.left + arc, c.getHeight() - i.bottom);
+ path.quadTo(i.left, c.getHeight() - i.bottom, i.left, c.getHeight() - arc - i.bottom);
+ path.lineTo(i.left, arc + i.top);
+ path.quadTo(i.left, i.top, arc + i.left, i.top);
+ path.closePath();
+ g2.fill(path);
+ }
}
- RectanglePainter.paint(g2, JBUI.scale(3), JBUI.scale(3),
- c.getWidth() - JBUI.scale(6),
- c.getHeight() - JBUI.scale(6),
- arc, null, Gray.xBC);
+ Path2D border = new Path2D.Double(Path2D.WIND_EVEN_ODD);
+ double lw = UIUtil.isRetina(g2) ? 0.5 : 1.0;
+ border.append(new RoundRectangle2D.Double(JBUI.scale(3), JBUI.scale(3),
+ c.getWidth() - JBUI.scale(6),
+ c.getHeight() - JBUI.scale(6),
+ arc, arc), false);
+ double innerArc = arc > 0 ? arc - lw : 0.0;
+ border.append(new RoundRectangle2D.Double(JBUI.scale(3) + lw, JBUI.scale(3) + lw,
+ c.getWidth() - JBUI.scale(6) - lw * 2,
+ c.getHeight() - JBUI.scale(6) - lw * 2,
+ innerArc, innerArc), false);
+ g2.setColor(Gray.xBC);
+ g2.fill(border);
g2.setClip(clip); // Reset clip
paint(c, g2, width, height, arc);
@@ -109,14 +131,15 @@ public class MacComboBoxBorder extends MacIntelliJTextBorder {
@Override void clipForBorder(Component c, Graphics2D g2, int width, int height) {
Area area = new Area(new Rectangle2D.Double(0, 0, width, height));
+ double lw = UIUtil.isRetina(g2) ? 0.5 : 1.0;
Shape innerShape = isRound(c) ?
- new RoundRectangle2D.Double(JBUI.scale(4), JBUI.scale(4),
- width - JBUI.scale(8),
- height - JBUI.scale(8),
- JBUI.scale(10), JBUI.scale(10)) :
- new Rectangle2D.Double(JBUI.scale(4), JBUI.scale(4),
- width - JBUI.scale(8),
- height - JBUI.scale(8));
+ new RoundRectangle2D.Double(JBUI.scale(3) + lw, JBUI.scale(3) + lw,
+ width - JBUI.scale(6) - lw * 2,
+ height - JBUI.scale(6) - lw * 2,
+ JBUI.scale(3) + lw, JBUI.scale(3) + lw) :
+ new Rectangle2D.Double(JBUI.scale(3) + lw, JBUI.scale(3) + lw,
+ width - JBUI.scale(6) - lw * 2,
+ height - JBUI.scale(6) - lw * 2);
area.subtract(new Area(innerShape));
area.add(getButtonBounds(c));
diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/MacIntelliJComboBoxUI.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/MacIntelliJComboBoxUI.java
index 9a595f2eb977..5233d70ccfaf 100644
--- a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/MacIntelliJComboBoxUI.java
+++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/MacIntelliJComboBoxUI.java
@@ -40,6 +40,7 @@ import java.beans.PropertyChangeListener;
public class MacIntelliJComboBoxUI extends BasicComboBoxUI {
private static final Border ourDefaultEditorBorder = JBUI.Borders.empty(1, 0);
+ static final int VALUE_OFFSET = JBUI.scale(5);
private Icon DEFAULT_ICON;
private PropertyChangeListener myEditorChangeListener;
@@ -243,8 +244,8 @@ public class MacIntelliJComboBoxUI extends BasicComboBoxUI {
@Override
protected Rectangle rectangleForCurrentValue() {
Rectangle rect = super.rectangleForCurrentValue();
- rect.x += JBUI.scale(5);
- rect.width -= JBUI.scale(5);
+ rect.x += VALUE_OFFSET;
+ rect.width -= VALUE_OFFSET;
return rect;
}
diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/MacIntelliJSpinnerUI.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/MacIntelliJSpinnerUI.java
index f19d6760765b..7d3f4c612ca8 100644
--- a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/MacIntelliJSpinnerUI.java
+++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/MacIntelliJSpinnerUI.java
@@ -25,6 +25,8 @@ import javax.swing.*;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicArrowButton;
import java.awt.*;
+import java.awt.geom.Path2D;
+
/**
* @author Konstantin Bulenkov
@@ -42,21 +44,31 @@ public class MacIntelliJSpinnerUI extends DarculaSpinnerUI {
Container parent = c.getParent();
if (c.isOpaque() && parent != null) {
g.setColor(parent.getBackground());
- g.fillRect(0,0,c.getWidth(),c.getHeight());
+ g.fillRect(0, 0, c.getWidth(), c.getHeight());
}
Insets i = c.getInsets();
-
int x = c.getWidth() - DEFAULT_ICON.getIconWidth() - i.right;
- Icon icon = MacIntelliJIconCache.getIcon("spinnerRight", false, false, c.isEnabled());
- icon.paintIcon(c, g, x, i.top);
if (c instanceof JSpinner) {
- JComponent editor = ((JSpinner)c).getEditor();
- Rectangle editorBounds = editor.getBounds();
- g.setColor(UIManager.getColor("FormattedTextField.background"));
- g.fillRect(i.left + JBUI.scale(1), i.top + JBUI.scale(1), x - JBUI.scale(1) - i.left, editorBounds.height + JBUI.scale(2));
+ Graphics2D g2 = (Graphics2D)g;
+ g2.setColor(UIManager.getColor("FormattedTextField.background"));
+
+ double arc = JBUI.scale(6);
+ Path2D rect = new Path2D.Double(Path2D.WIND_EVEN_ODD);
+ rect.moveTo(x, i.top);
+ rect.lineTo(x, c.getHeight() - i.bottom);
+ rect.lineTo(i.left + arc, c.getHeight() - i.bottom);
+ rect.quadTo(i.left, c.getHeight() - i.bottom, i.left, c.getHeight() - i.bottom - arc);
+ rect.lineTo(i.left, i.top + arc);
+ rect.quadTo(i.left, i.top, i.left + arc, i.top);
+ rect.closePath();
+
+ g2.fill(rect);
}
+
+ Icon icon = MacIntelliJIconCache.getIcon("spinnerRight", false, false, c.isEnabled());
+ icon.paintIcon(c, g, x, i.top);
}
@Override protected void paintArrowButton(Graphics g, BasicArrowButton button, int direction) {}
diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/MacIntelliJTextBorder.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/MacIntelliJTextBorder.java
index 0facdf1c9621..198afeaf25f0 100644
--- a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/MacIntelliJTextBorder.java
+++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/MacIntelliJTextBorder.java
@@ -20,12 +20,13 @@ import com.intellij.ide.ui.laf.darcula.ui.DarculaTextBorder;
import com.intellij.ide.ui.laf.darcula.ui.TextFieldWithPopupHandlerUI;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.ui.Gray;
-import com.intellij.ui.paint.RectanglePainter;
import com.intellij.util.ui.JBUI;
+import com.intellij.util.ui.UIUtil;
import javax.swing.*;
import java.awt.*;
import java.awt.geom.Area;
+import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;
/**
@@ -51,9 +52,17 @@ public class MacIntelliJTextBorder extends DarculaTextBorder {
Graphics2D g2 = (Graphics2D)g.create();
try {
g2.translate(x, y);
- RectanglePainter.paint(g2, JBUI.scale(3), JBUI.scale(3),
- c.getWidth() - JBUI.scale(6),
- c.getHeight() - JBUI.scale(6), 0, null, Gray.xBC);
+
+ Path2D border = new Path2D.Double(Path2D.WIND_EVEN_ODD);
+ double lw = UIUtil.isRetina(g2) ? 0.5 : 1.0;
+ border.append(new Rectangle2D.Double(JBUI.scale(3), JBUI.scale(3),
+ c.getWidth() - JBUI.scale(6),
+ c.getHeight() - JBUI.scale(6)), false);
+ border.append(new Rectangle2D.Double(JBUI.scale(3) + lw, JBUI.scale(3) + lw,
+ c.getWidth() - JBUI.scale(6) - lw * 2,
+ c.getHeight() - JBUI.scale(6) - lw * 2), false);
+ g2.setColor(Gray.xBC);
+ g2.fill(border);
if (c.getParent() instanceof JComboBox) return;
@@ -70,7 +79,7 @@ public class MacIntelliJTextBorder extends DarculaTextBorder {
if (Registry.is("ide.inplace.errors.outline") && Boolean.parseBoolean(String.valueOf(eop))) {
DarculaUIUtil.paintErrorBorder(g2, width, height, arc, isFocused(c));
} else if (isFocused(c)) {
- DarculaUIUtil.paintFocusBorder(g2, width, height, JBUI.scale(4), arc);
+ DarculaUIUtil.paintFocusBorder(g2, width, height, arc);
}
}
@@ -80,9 +89,10 @@ public class MacIntelliJTextBorder extends DarculaTextBorder {
void clipForBorder(Component c, Graphics2D g2, int width, int height) {
Area area = new Area(new Rectangle2D.Double(0, 0, width, height));
- area.subtract(new Area(new Rectangle2D.Double(JBUI.scale(4), JBUI.scale(4),
- width - JBUI.scale(8),
- height - JBUI.scale(8))));
+ double lw = UIUtil.isRetina(g2) ? 0.5 : 1.0;
+ area.subtract(new Area(new Rectangle2D.Double(JBUI.scale(3) + lw, JBUI.scale(3) + lw,
+ width - JBUI.scale(6) - lw * 2,
+ height - JBUI.scale(6) - lw * 2)));
area.intersect(new Area(g2.getClip()));
g2.setClip(area);
}
diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/MacIntelliJTextFieldUI.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/MacIntelliJTextFieldUI.java
index 1dad871bd85d..4b1c6205f67d 100644
--- a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/MacIntelliJTextFieldUI.java
+++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/MacIntelliJTextFieldUI.java
@@ -19,8 +19,9 @@ import com.intellij.ide.ui.laf.darcula.DarculaUIUtil;
import com.intellij.ide.ui.laf.darcula.ui.TextFieldWithPopupHandlerUI;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.ui.Gray;
-import com.intellij.ui.paint.RectanglePainter;
import com.intellij.util.ui.JBUI;
+import com.intellij.util.ui.MacUIUtil;
+import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
@@ -28,7 +29,9 @@ import javax.swing.plaf.ComponentUI;
import javax.swing.text.JTextComponent;
import java.awt.*;
import java.awt.geom.Area;
+import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;
+import java.awt.geom.RoundRectangle2D;
/**
* @author Konstantin Bulenkov
@@ -160,16 +163,35 @@ public class MacIntelliJTextFieldUI extends TextFieldWithPopupHandlerUI {
protected void paintSearchField(Graphics2D g, JTextComponent c, Rectangle r) {
Graphics2D g2 = (Graphics2D)g.create();
try {
- RectanglePainter.paint(g2, r.x + JBUI.scale(3), r.y + JBUI.scale(3),
- r.width - JBUI.scale(6), r.height - JBUI.scale(6),
- JBUI.scale(8), c.getBackground(), Gray.xBC);
+ g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+ g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, MacUIUtil.USE_QUARTZ ? RenderingHints.VALUE_STROKE_PURE : RenderingHints.VALUE_STROKE_NORMALIZE);
+ g2.translate(r.x, r.y);
+
+ int arc = JBUI.scale(6);
+ double lw = UIUtil.isRetina(g2) ? 0.5 : 1.0;
+ Shape outerShape = new RoundRectangle2D.Double(JBUI.scale(3), JBUI.scale(3),
+ r.width - JBUI.scale(6),
+ r.height - JBUI.scale(6),
+ arc, arc);
+ g2.setColor(c.getBackground());
+ g2.fill(outerShape);
+
+ Path2D path = new Path2D.Double(Path2D.WIND_EVEN_ODD);
+ path.append(outerShape, false);
+ path.append(new RoundRectangle2D.Double(JBUI.scale(3) + lw, JBUI.scale(3) + lw,
+ r.width - JBUI.scale(6) - lw*2,
+ r.height - JBUI.scale(6) - lw*2,
+ arc-lw, arc-lw), false);
+
+ g2.setColor(Gray.xBC);
+ g2.fill(path);
if (c.hasFocus() && c.getClientProperty("JTextField.Search.noBorderRing") != Boolean.TRUE) {
- g2.translate(r.x, r.y);
- DarculaUIUtil.paintFocusBorder(g2, r.width, r.height, JBUI.scale(4), JBUI.scale(6));
- g2.translate(-r.x, -r.y);
+ DarculaUIUtil.paintFocusBorder(g2, r.width, r.height, arc);
}
+ g2.translate(-r.x, -r.y);
+
boolean withHistoryPopup = isSearchFieldWithHistoryPopup(c);
Icon label = getSearchIcon(c);
boolean isEmpty = !hasText();
@@ -234,12 +256,31 @@ public class MacIntelliJTextFieldUI extends TextFieldWithPopupHandlerUI {
public static void paintAquaSearchFocusRing(Graphics2D g, Rectangle r, Component c) {
Graphics2D g2 = (Graphics2D)g.create();
try {
- RectanglePainter.paint(g, r.x + JBUI.scale(3), r.y + JBUI.scale(3),
- r.width - JBUI.scale(6), r.height - JBUI.scale(6),
- JBUI.scale(8), c.getBackground(), Gray.xBC);
+ g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+ g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, MacUIUtil.USE_QUARTZ ? RenderingHints.VALUE_STROKE_PURE : RenderingHints.VALUE_STROKE_NORMALIZE);
+ g2.translate(r.x, r.y);
+
+ int arc = JBUI.scale(6);
+ double lw = UIUtil.isRetina(g2) ? 0.5 : 1.0;
+ Shape outerShape = new RoundRectangle2D.Double(JBUI.scale(3), JBUI.scale(3),
+ r.width - JBUI.scale(6),
+ r.height - JBUI.scale(6),
+ arc, arc);
+ g2.setColor(c.getBackground());
+ g2.fill(outerShape);
+
+ Path2D path = new Path2D.Double(Path2D.WIND_EVEN_ODD);
+ path.append(outerShape, false);
+ path.append(new RoundRectangle2D.Double(JBUI.scale(3) + lw, JBUI.scale(3) + lw,
+ r.width - JBUI.scale(6) - lw*2,
+ r.height - JBUI.scale(6) - lw*2,
+ arc-lw, arc-lw), false);
+
+ g2.setColor(Gray.xBC);
+ g2.fill(path);
+
if (c.hasFocus()) {
- g.translate(r.x, r.y);
- DarculaUIUtil.paintFocusBorder(g, r.width, r.height, JBUI.scale(4), JBUI.scale(6));
+ DarculaUIUtil.paintFocusBorder(g2, r.width, r.height, arc);
}
}
finally {
diff --git a/platform/platform-impl/src/com/intellij/ui/FinderRecursivePanel.java b/platform/platform-impl/src/com/intellij/ui/FinderRecursivePanel.java
index a6997b918a5a..a775244f5f4f 100644
--- a/platform/platform-impl/src/com/intellij/ui/FinderRecursivePanel.java
+++ b/platform/platform-impl/src/com/intellij/ui/FinderRecursivePanel.java
@@ -156,6 +156,22 @@ public abstract class FinderRecursivePanel extends OnePixelSplitter implement
return null;
}
+ /**
+ * Returns tooltip text for the given list item or null if no tooltip is available.
+ *
+ *
This method is invoked by panel's list cell render in order to set a tooltip text for the list cell render component.
+ * It is invoked before {@link #doCustomizeCellRenderer(SimpleColoredComponent, JList, Object, int, boolean, boolean)},
+ * thus the tooltip may still be reset in {@code doCustomizeCellRenderer}.
+ *
+ * @param t the list item
+ * @return the text to display in a tooltip for the given list item
+ * @since 2017.2
+ */
+ @Nullable
+ protected String getItemTooltipText(T t) {
+ return null;
+ }
+
protected abstract boolean hasChildren(T t);
/**
@@ -190,7 +206,7 @@ public abstract class FinderRecursivePanel extends OnePixelSplitter implement
ScrollPaneFactory.createScrollPane(myList,
ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
- return ListWithFilter.wrap(myList, pane, (Function)o -> getItemText(o));
+ return ListWithFilter.wrap(myList, pane, o -> getItemText(o));
}
protected JBList createList() {
@@ -298,13 +314,8 @@ public abstract class FinderRecursivePanel extends OnePixelSplitter implement
}
private void installSpeedSearch(JBList list) {
- final ListSpeedSearch search = new ListSpeedSearch(list, new Function