From 51c6b779fec8e2320c3e8b9ac53a4cf7aadc69d9 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Mon, 6 Oct 2014 08:00:34 +0200 Subject: [PATCH 01/28] use Collections.singletonList --- .../intellij/codeInsight/daemon/impl/PsiChangeHandler.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PsiChangeHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PsiChangeHandler.java index 661e9bed82da..2eda0331b7b5 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PsiChangeHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PsiChangeHandler.java @@ -40,12 +40,12 @@ import com.intellij.psi.impl.PsiDocumentManagerImpl; import com.intellij.psi.impl.PsiDocumentTransactionListener; import com.intellij.psi.impl.PsiTreeChangeEventImpl; import com.intellij.util.SmartList; -import com.intellij.util.containers.ContainerUtil; import com.intellij.util.messages.MessageBusConnection; import gnu.trove.THashMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Collections; import java.util.List; import java.util.Map; @@ -111,7 +111,7 @@ public class PsiChangeHandler extends PsiTreeChangeAdapter implements Disposable PsiElement file = PsiDocumentManager.getInstance(myProject).getCachedPsiFile(document); if (file == null) return; - toUpdate = ContainerUtil.newArrayList(Pair.create(file, true)); + toUpdate = Collections.singletonList(Pair.create(file, true)); } Application application = ApplicationManager.getApplication(); final Editor editor = FileEditorManager.getInstance(myProject).getSelectedTextEditor(); From 4e2badc13c1c4178524c7fbdda8e967e25162175 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Mon, 6 Oct 2014 08:02:33 +0200 Subject: [PATCH 02/28] fix Already disposed: Project (Disposed) --- .../com/intellij/codeInsight/daemon/impl/PsiChangeHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PsiChangeHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PsiChangeHandler.java index 2eda0331b7b5..f5f698e4a40a 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PsiChangeHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PsiChangeHandler.java @@ -100,7 +100,7 @@ public class PsiChangeHandler extends PsiTreeChangeAdapter implements Disposable } private void updateChangesForDocument(@NotNull final Document document) { - if (DaemonListeners.isUnderIgnoredAction(null)) return; + if (DaemonListeners.isUnderIgnoredAction(null) || myProject.isDisposed()) return; List> toUpdate = changedElements.get(document); if (toUpdate == null) { // The document has been changed, but psi hasn't From a481b867c7e46060090beb9d5768579c5d9faeaa Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Mon, 6 Oct 2014 08:59:55 +0200 Subject: [PATCH 03/28] EA-61303 - IAE: EffectiveLanguageLevelUtil.getEffectiveLanguageLevel --- .../java15api/Java15APIUsageInspectionBase.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/java15api/Java15APIUsageInspectionBase.java b/java/java-analysis-impl/src/com/intellij/codeInspection/java15api/Java15APIUsageInspectionBase.java index fdeb517f5a1d..8ade742af3d6 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/java15api/Java15APIUsageInspectionBase.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/java15api/Java15APIUsageInspectionBase.java @@ -203,8 +203,10 @@ public class Java15APIUsageInspectionBase extends BaseJavaBatchLocalInspectionTo @Override public void visitClass(PsiClass aClass) { // Don't go into classes (anonymous, locals). if (!aClass.hasModifierProperty(PsiModifier.ABSTRACT)) { - final LanguageLevel effectiveLanguageLevel = getEffectiveLanguageLevel(ModuleUtilCore.findModuleForPsiElement(aClass)); - if (!effectiveLanguageLevel.isAtLeast(LanguageLevel.JDK_1_8) && + final Module module = ModuleUtilCore.findModuleForPsiElement(aClass); + final LanguageLevel effectiveLanguageLevel = module != null ? getEffectiveLanguageLevel(module) : null; + if (effectiveLanguageLevel != null && + !effectiveLanguageLevel.isAtLeast(LanguageLevel.JDK_1_8) && JavaVersionService.getInstance().getJavaSdkVersion(aClass).isAtLeast(JavaSdkVersion.JDK_1_8)) { final List methods = new ArrayList(); for (HierarchicalMethodSignature methodSignature : aClass.getVisibleSignatures()) { From d9bd3fba6010bf6677c0d5c0412b7dcb34972f4a Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Mon, 6 Oct 2014 09:07:49 +0200 Subject: [PATCH 04/28] type annotations in generics brace matching (IDEA-COMMUNITY-CR-664) --- .../codeInsight/highlighting/JavaPairedBraceMatcher.java | 3 ++- .../codeInsight/highlighting/JavaBraceMatcherTest.java | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/highlighting/JavaPairedBraceMatcher.java b/java/java-impl/src/com/intellij/codeInsight/highlighting/JavaPairedBraceMatcher.java index e0ba601a07cf..82d5ddb07997 100644 --- a/java/java-impl/src/com/intellij/codeInsight/highlighting/JavaPairedBraceMatcher.java +++ b/java/java-impl/src/com/intellij/codeInsight/highlighting/JavaPairedBraceMatcher.java @@ -28,7 +28,8 @@ import com.intellij.psi.tree.TokenSet; public class JavaPairedBraceMatcher extends PairedBraceMatcherAdapter { private static final TokenSet TYPE_TOKENS = TokenSet.orSet(StdTokenSets.WHITE_SPACE_OR_COMMENT_BIT_SET, - TokenSet.create(JavaTokenType.IDENTIFIER, JavaTokenType.COMMA, + TokenSet.create(JavaTokenType.IDENTIFIER, JavaTokenType.COMMA, + JavaTokenType.AT,//anno JavaTokenType.RBRACKET, JavaTokenType.LBRACKET, //arrays JavaTokenType.QUEST, JavaTokenType.EXTENDS_KEYWORD, JavaTokenType.SUPER_KEYWORD));//wildcards diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/highlighting/JavaBraceMatcherTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/highlighting/JavaBraceMatcherTest.java index d90b336cff4d..30188c16f0cf 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/highlighting/JavaBraceMatcherTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/highlighting/JavaBraceMatcherTest.java @@ -24,10 +24,10 @@ public class JavaBraceMatcherTest extends LightCodeInsightFixtureTestCase { public void testGenerics() { myFixture.configureByText("a.java", "import java.util.ArrayList;" + "class A {" + - " ArrayList f;" + + " ArrayList f;" + "}"); final int offset = BraceMatchingUtil.getMatchedBraceOffset(myFixture.getEditor(), true, myFixture.getFile()); - assertEquals(66, offset); + assertEquals(72, offset); } public void testBrokenText() { From 39154531ec86ad5b68f93bdf1ef92a4e095ada9e Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Mon, 6 Oct 2014 10:39:43 +0200 Subject: [PATCH 05/28] unchecked warning: do not traverse through lambda bounds (IDEA-130810) --- .../UncheckedWarningLocalInspectionBase.java | 3 +- ...kedWarningInsideLambdaReturnStatement.java | 65 +++++++++++++++++++ .../lambda/GenericsHighlighting8Test.java | 4 ++ 3 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/UncheckedWarningInsideLambdaReturnStatement.java diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/uncheckedWarnings/UncheckedWarningLocalInspectionBase.java b/java/java-analysis-impl/src/com/intellij/codeInspection/uncheckedWarnings/UncheckedWarningLocalInspectionBase.java index fa2789880371..b24f152537a5 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/uncheckedWarnings/UncheckedWarningLocalInspectionBase.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/uncheckedWarnings/UncheckedWarningLocalInspectionBase.java @@ -375,8 +375,9 @@ public class UncheckedWarningLocalInspectionBase extends BaseJavaBatchLocalInspe public void visitReturnStatement(PsiReturnStatement statement) { super.visitReturnStatement(statement); if (IGNORE_UNCHECKED_ASSIGNMENT) return; + final PsiLambdaExpression lambdaExpression = PsiTreeUtil.getParentOfType(statement, PsiLambdaExpression.class); final PsiMethod method = PsiTreeUtil.getParentOfType(statement, PsiMethod.class); - if (method != null) { + if (method != null && (lambdaExpression == null || PsiTreeUtil.isAncestor(lambdaExpression, method, true))) { final PsiType returnType = method.getReturnType(); if (returnType != null && returnType != PsiType.VOID) { final PsiExpression returnValue = statement.getReturnValue(); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/UncheckedWarningInsideLambdaReturnStatement.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/UncheckedWarningInsideLambdaReturnStatement.java new file mode 100644 index 000000000000..856523a80fb5 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/UncheckedWarningInsideLambdaReturnStatement.java @@ -0,0 +1,65 @@ +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Stream; + +class Test { + + private Repository repository = null; + + public Stream test() { + return repository.all() + .flatMap(foo -> { + + class AB { + List a() { + return new ArrayList(); + } + } + + AB ab = new AB(); + System.out.println(ab); + + if (foo != null) { + return repository.update(); + } + return Stream.empty(); + }) + .map(UpdateResult::getPerson); + } + + + public static class Repository { + + public Stream all() { + return Stream.empty(); + } + + public Stream update() { + return Stream.empty(); + } + + } + + public static class Person { + } + + public static class UpdateResult { + + private final Person person; + + private final Object metadata; + + public UpdateResult(Person person, Object metadata) { + this.person = person; + this.metadata = metadata; + } + + public Person getPerson() { + return person; + } + + public Object getMetadata() { + return metadata; + } + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GenericsHighlighting8Test.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GenericsHighlighting8Test.java index a919843a3164..49027135eecf 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GenericsHighlighting8Test.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GenericsHighlighting8Test.java @@ -762,6 +762,10 @@ public class GenericsHighlighting8Test extends LightDaemonAnalyzerTestCase { public void testIDEA78402() { doTest(); } + public void testUncheckedWarningInsideLambdaReturnStatement() throws Exception { + doTest(true); + } + private void doTest() { doTest(false); } From 88904acb50f519c2b25c961cb614892a50f9aef8 Mon Sep 17 00:00:00 2001 From: "Gregory.Shrago" Date: Mon, 6 Oct 2014 12:47:33 +0400 Subject: [PATCH 06/28] fix the confusion between "injected" vs "unescaped" offsets --- .../intention/impl/QuickEditAction.java | 3 ++- .../injected/editor/DocumentWindowImpl.java | 21 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/QuickEditAction.java b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/QuickEditAction.java index d168002f97a7..5e4f9b315042 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/QuickEditAction.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/QuickEditAction.java @@ -18,6 +18,7 @@ package com.intellij.codeInsight.intention.impl; import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.codeInsight.intention.LowPriorityAction; import com.intellij.injected.editor.DocumentWindow; +import com.intellij.injected.editor.DocumentWindowImpl; import com.intellij.lang.Language; import com.intellij.lang.injection.InjectedLanguageManager; import com.intellij.openapi.application.ApplicationManager; @@ -106,7 +107,7 @@ public class QuickEditAction implements IntentionAction, LowPriorityAction { if (!ApplicationManager.getApplication().isUnitTestMode()) { DocumentWindow documentWindow = InjectedLanguageUtil.getDocumentWindow(injectedFile); if (documentWindow != null) { - handler.navigate(documentWindow.hostToInjected(offset)); + handler.navigate(((DocumentWindowImpl)documentWindow).hostToUnescaped(offset)); } } return handler; diff --git a/platform/lang-impl/src/com/intellij/injected/editor/DocumentWindowImpl.java b/platform/lang-impl/src/com/intellij/injected/editor/DocumentWindowImpl.java index 724de4f480ec..3ed4e0a16022 100644 --- a/platform/lang-impl/src/com/intellij/injected/editor/DocumentWindowImpl.java +++ b/platform/lang-impl/src/com/intellij/injected/editor/DocumentWindowImpl.java @@ -648,6 +648,27 @@ public class DocumentWindowImpl extends UserDataHolderBase implements Disposable @Override public int hostToInjected(int hostOffset) { + synchronized (myLock) { + Segment hostRangeMarker = myShreds.get(0).getHostRangeMarker(); + if (hostRangeMarker == null || hostOffset < hostRangeMarker.getStartOffset()) return myShreds.get(0).getPrefix().length(); + int offset = 0; + for (int i = 0; i < myShreds.size(); i++) { + offset += myShreds.get(i).getPrefix().length(); + Segment currentRange = myShreds.get(i).getHostRangeMarker(); + if (currentRange == null) continue; + Segment nextRange = i == myShreds.size() - 1 ? null : myShreds.get(i + 1).getHostRangeMarker(); + if (nextRange == null || hostOffset < nextRange.getStartOffset()) { + if (hostOffset >= currentRange.getEndOffset()) hostOffset = currentRange.getEndOffset(); + return offset + hostOffset - currentRange.getStartOffset(); + } + offset += currentRange.getEndOffset() - currentRange.getStartOffset(); + offset += myShreds.get(i).getSuffix().length(); + } + return getTextLength() - myShreds.get(myShreds.size() - 1).getSuffix().length(); + } + } + + public int hostToUnescaped(int hostOffset) { synchronized (myLock) { Segment hostRangeMarker = myShreds.get(0).getHostRangeMarker(); if (hostRangeMarker == null || hostOffset < hostRangeMarker.getStartOffset()) return myShreds.get(0).getPrefix().length(); From 42f3de186fc3bcf90c935f20c84a23f1d91fe3e3 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Mon, 6 Oct 2014 11:23:17 +0200 Subject: [PATCH 07/28] invert boolean: cancel refactoring on cancel, fix read-only status change (IDEA-130836) --- .../invertBoolean/InvertBooleanHandler.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/java/java-impl/src/com/intellij/refactoring/invertBoolean/InvertBooleanHandler.java b/java/java-impl/src/com/intellij/refactoring/invertBoolean/InvertBooleanHandler.java index df8b69cb7064..70d4570a9ced 100644 --- a/java/java-impl/src/com/intellij/refactoring/invertBoolean/InvertBooleanHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/invertBoolean/InvertBooleanHandler.java @@ -56,13 +56,11 @@ public class InvertBooleanHandler implements RefactoringActionHandler { return; } - if (!CommonRefactoringUtil.checkReadOnlyStatus(project, var)) return; if (var instanceof PsiParameter && ((PsiParameter)var).getDeclarationScope() instanceof PsiMethod) { final PsiMethod method = (PsiMethod)((PsiParameter)var).getDeclarationScope(); final PsiMethod superMethod = SuperMethodWarningUtil.checkSuperMethod(method, RefactoringBundle.message("to.refactor")); - if (superMethod != null) { - var = superMethod.getParameterList().getParameters()[method.getParameterList().getParameterIndex((PsiParameter)var)]; - } + if (superMethod == null) return; + var = superMethod.getParameterList().getParameters()[method.getParameterList().getParameterIndex((PsiParameter)var)]; } new InvertBooleanDialog(var).show(); @@ -87,9 +85,8 @@ public class InvertBooleanHandler implements RefactoringActionHandler { } final PsiMethod superMethod = SuperMethodWarningUtil.checkSuperMethod(method, RefactoringBundle.message("to.refactor")); - if (superMethod != null) method = superMethod; - - if (!CommonRefactoringUtil.checkReadOnlyStatus(project, method)) return; + if (superMethod == null) return; + method = superMethod; new InvertBooleanDialog(method).show(); } From 52138b574bcf2f3398a11897c353df2513c8374b Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Mon, 6 Oct 2014 13:42:16 +0400 Subject: [PATCH 08/28] reverted ConcurrentIntHashMap --- .../util/src/com/intellij/util/containers/ContainerUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/util/src/com/intellij/util/containers/ContainerUtil.java b/platform/util/src/com/intellij/util/containers/ContainerUtil.java index d61dc2424be3..5dd3697d4e32 100644 --- a/platform/util/src/com/intellij/util/containers/ContainerUtil.java +++ b/platform/util/src/com/intellij/util/containers/ContainerUtil.java @@ -2220,7 +2220,7 @@ public class ContainerUtil extends ContainerUtilRt { @NotNull @Contract(pure=true) public static ConcurrentIntObjectMap createConcurrentIntObjectMap() { - return new ConcurrentIntObjectHashMap(); + return new StripedLockIntObjectConcurrentHashMap(); } @NotNull From 929bb90059b81eb9c2dbaf5b166b67bb957cda4b Mon Sep 17 00:00:00 2001 From: Rustam Vishnyakov Date: Mon, 6 Oct 2014 13:49:55 +0400 Subject: [PATCH 09/28] Provide compatibility with old OTHER_INDENT_OPTIONS section (IDEA-130601) --- .../psi/codeStyle/CommonCodeStyleSettings.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettings.java b/platform/lang-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettings.java index 7a8d84e018be..6b8b9ed34617 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettings.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettings.java @@ -918,7 +918,15 @@ public class CommonCodeStyleSettings { @Override public void writeExternal(Element element) throws WriteExternalException { - DefaultJDOMExternalizer.writeExternal(this, element, new DifferenceFilter(this, new IndentOptions())); + DefaultJDOMExternalizer.writeExternal(this, element, new DefaultJDOMExternalizer.JDOMFilter() { + @Override + public boolean isAccept(@NotNull Field field) { + if ("KEEP_INDENTS_ON_EMPTY_LINES".equals(field.getName())) { + return KEEP_INDENTS_ON_EMPTY_LINES; + } + return true; + } + }); } public void serialize(Element indentOptionsElement, final IndentOptions defaultOptions) { From 83c50b56581928a7a945345c080ad585b60a4402 Mon Sep 17 00:00:00 2001 From: "Maxim.Mossienko" Date: Mon, 6 Oct 2014 11:59:04 +0200 Subject: [PATCH 10/28] trunk is 140 --- build.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.txt b/build.txt index fbe9662c6076..d6241f2dc103 100644 --- a/build.txt +++ b/build.txt @@ -1 +1 @@ -138.SNAPSHOT +140.SNAPSHOT From b3b0563466892f580cc306b73d4746df29813b81 Mon Sep 17 00:00:00 2001 From: nik Date: Mon, 6 Oct 2014 14:22:29 +0400 Subject: [PATCH 11/28] build scripts: include optimizedFileManager.jar to classpath to speed up compilation --- build/gant.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/build/gant.xml b/build/gant.xml index 4b56378f1652..88f2749a3f13 100644 --- a/build/gant.xml +++ b/build/gant.xml @@ -12,6 +12,7 @@ + From 12644c13ff915487a235fe90960fc4ecbbb23946 Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Mon, 6 Oct 2014 14:19:18 +0400 Subject: [PATCH 12/28] IDEA-130812 Settings / Keymap: custom scheme is shown selected, but all shortcuts are from Default (regression) --- .../options/newEditor/SpotlightPainter.java | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SpotlightPainter.java b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SpotlightPainter.java index 374b4d10374d..61dc1deae6a1 100644 --- a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SpotlightPainter.java +++ b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SpotlightPainter.java @@ -80,19 +80,17 @@ abstract class SpotlightPainter extends AbstractPainter { myGlassPanel.clear(); String text = filter.getFilterText(); myVisible = !text.isEmpty(); - if (myVisible) { - try { - SearchableConfigurable searchable = new SearchableConfigurable.Delegate(configurable); - SearchUtil.lightOptions(searchable, component, text, myGlassPanel).run(); - Runnable search = searchable.enableSearch(text); - if (search != null && !filter.contains(configurable) && !text.equals(myConfigurableOption.get(configurable))) { - search.run(); - } - } - finally { - myConfigurableOption.put(configurable, text); + try { + SearchableConfigurable searchable = new SearchableConfigurable.Delegate(configurable); + SearchUtil.lightOptions(searchable, component, text, myGlassPanel).run(); + Runnable search = searchable.enableSearch(text); // execute for empty string too + if (search != null && !filter.contains(configurable) && !text.equals(myConfigurableOption.get(configurable))) { + search.run(); } } + finally { + myConfigurableOption.put(configurable, text); + } } else if (!ApplicationManager.getApplication().isUnitTestMode()) { updateLater(); From 26849411f95995230919687bc988adffe8ef1ef3 Mon Sep 17 00:00:00 2001 From: "Maxim.Mossienko" Date: Mon, 6 Oct 2014 12:27:50 +0200 Subject: [PATCH 13/28] trunk is 140 --- python/pluginResources/META-INF/plugin.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/pluginResources/META-INF/plugin.xml b/python/pluginResources/META-INF/plugin.xml index 4539edaa107b..3d8550e82b34 100644 --- a/python/pluginResources/META-INF/plugin.xml +++ b/python/pluginResources/META-INF/plugin.xml @@ -4,7 +4,7 @@ PythonCore Python Community Edition - + Date: Mon, 6 Oct 2014 15:20:35 +0400 Subject: [PATCH 14/28] [git] Fix auto-fill of the author field on cherry-pick It was broken during some recent author field improvements. Pre-filled author should be placed to the combobox during editor creation. --- .../checkin/GitCheckinEnvironment.java | 37 ++++++++++--------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/plugins/git4idea/src/git4idea/checkin/GitCheckinEnvironment.java b/plugins/git4idea/src/git4idea/checkin/GitCheckinEnvironment.java index 705e40384c9a..9f4e77af6c5a 100644 --- a/plugins/git4idea/src/git4idea/checkin/GitCheckinEnvironment.java +++ b/plugins/git4idea/src/git4idea/checkin/GitCheckinEnvironment.java @@ -576,9 +576,10 @@ public class GitCheckinEnvironment implements CheckinEnvironment { private class GitCheckinOptions extends DvcsCommitAdditionalComponent implements CheckinChangeListSpecificComponent { private final GitVcs myVcs; - private final ComboBox myAuthor; + private final ComboBox myAuthorField; - private Date myAuthorDate; + @Nullable private Date myAuthorDate; + @Nullable private String myAuthor; GitCheckinOptions(@NotNull final Project project, @NotNull CheckinProjectPanel panel) { super(project, panel); @@ -606,27 +607,27 @@ public class GitCheckinEnvironment implements CheckinEnvironment { List list = new ArrayList(authors); Collections.sort(list); - myAuthor = new ComboBox(ArrayUtil.toObjectArray(list)) { + myAuthorField = new ComboBox(ArrayUtil.toObjectArray(list)) { @Override public void addNotify() { super.addNotify(); // adding in addNotify to make sure the editor is ready for further customization - StringComboboxEditor comboboxEditor = new StringComboboxEditor(project, FileTypes.PLAIN_TEXT, myAuthor, true); - myAuthor.setEditor(comboboxEditor); + StringComboboxEditor comboboxEditor = new StringComboboxEditor(project, FileTypes.PLAIN_TEXT, myAuthorField, true); + myAuthorField.setEditor(comboboxEditor); EditorEx editor = (EditorEx)comboboxEditor.getEditor(); assert editor != null; SpellCheckingEditorCustomization.getInstance(false).customize(editor); + + myAuthorField.insertItemAt(myAuthor == null ? "" : myAuthor, 0); + myAuthorField.setSelectedIndex(0); } }; - myAuthor.setMinimumAndPreferredWidth(100); - - myAuthor.insertItemAt("", 0); - myAuthor.setSelectedItem(""); - myAuthor.setEditable(true); - authorLabel.setLabelFor(myAuthor); - myAuthor.setToolTipText(GitBundle.getString("commit.author.tooltip")); - myPanel.add(myAuthor, c); + myAuthorField.setMinimumAndPreferredWidth(100); + myAuthorField.setEditable(true); + authorLabel.setLabelFor(myAuthorField); + myAuthorField.setToolTipText(GitBundle.getString("commit.author.tooltip")); + myPanel.add(myAuthorField, c); } @Override @@ -667,13 +668,14 @@ public class GitCheckinEnvironment implements CheckinEnvironment { @Override public void refresh() { super.refresh(); - myAuthor.setSelectedItem(""); + myAuthor = null; + myAuthorDate = null; reset(); } @Override public void saveState() { - String author = (String)myAuthor.getEditor().getItem(); + String author = (String)myAuthorField.getEditor().getItem(); if (StringUtil.isEmptyOrSpaces(author)) { myNextCommitAuthor = null; } @@ -695,9 +697,8 @@ public class GitCheckinEnvironment implements CheckinEnvironment { Object data = list.getData(); if (data instanceof VcsFullCommitDetails) { VcsFullCommitDetails commit = (VcsFullCommitDetails)data; - String author = String.format("%s <%s>", commit.getAuthor().getName(), commit.getAuthor().getEmail()); - myAuthor.getEditor().setItem(author); - myAuthorDate = new Date(commit.getTimestamp()); + myAuthor = String.format("%s <%s>", commit.getAuthor().getName(), commit.getAuthor().getEmail()); + myAuthorDate = new Date(commit.getAuthorTime()); } } } From 355eccc1cbc55707a66c912c7b00e262ad975b27 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Mon, 6 Oct 2014 15:24:40 +0400 Subject: [PATCH 15/28] [git] Don't mention repository in branch popup when sync & diverged Since recently, we still show only common branches in the popup, if repositories are synchronized, even if they are diverged. => "current" repository shouldn't be mentioned in the popup title in this case. --- .../src/com/intellij/dvcs/branch/DvcsBranchPopup.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/branch/DvcsBranchPopup.java b/platform/dvcs-impl/src/com/intellij/dvcs/branch/DvcsBranchPopup.java index e4b52fea4683..c3c98afa34dc 100644 --- a/platform/dvcs-impl/src/com/intellij/dvcs/branch/DvcsBranchPopup.java +++ b/platform/dvcs-impl/src/com/intellij/dvcs/branch/DvcsBranchPopup.java @@ -87,8 +87,7 @@ public abstract class DvcsBranchPopup { @NotNull private String createPopupTitle(@NotNull Repo currentRepository) { String title = myVcs.getDisplayName() + " Branches"; - if (myRepositoryManager.moreThanOneRoot() && - (myMultiRootBranchConfig.diverged() || myVcsSettings.getSyncSetting() == DvcsSyncSettings.Value.DONT_SYNC)) { + if (myRepositoryManager.moreThanOneRoot() && myVcsSettings.getSyncSetting() == DvcsSyncSettings.Value.DONT_SYNC) { title += " in " + DvcsUtil.getShortRepositoryName(currentRepository); } return title; From e3a8044f771427330d88f13b6550fea0e66e4cff Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Mon, 6 Oct 2014 12:02:46 +0200 Subject: [PATCH 16/28] avoid sorting during pattern tests run (IDEA-127052) --- .../intellij/execution/junit/JUnitConfiguration.java | 8 ++++---- .../src/com/intellij/execution/junit/TestObject.java | 6 +++--- .../testng/configuration/SearchingForTestsTask.java | 12 ++++++------ .../testng/configuration/TestNGConfiguration.java | 4 ++-- .../com/theoryinpractice/testng/model/TestData.java | 6 +++--- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/plugins/junit/src/com/intellij/execution/junit/JUnitConfiguration.java b/plugins/junit/src/com/intellij/execution/junit/JUnitConfiguration.java index 0b7ab14a151d..d1edefd03f21 100644 --- a/plugins/junit/src/com/intellij/execution/junit/JUnitConfiguration.java +++ b/plugins/junit/src/com/intellij/execution/junit/JUnitConfiguration.java @@ -310,7 +310,7 @@ public class JUnitConfiguration extends ModuleBasedConfiguration tests = new LinkedHashSet(); + final LinkedHashSet tests = new LinkedHashSet(); for (Object o : patternsElement.getChildren(PATTERN_EL_NAME)) { Element patternElement = (Element)o; tests.add(patternElement.getAttributeValue(TEST_CLASS_ATT_NAME)); @@ -403,7 +403,7 @@ public class JUnitConfiguration extends ModuleBasedConfiguration classes, PsiMethod method) { myData.TEST_OBJECT = TEST_PATTERN; - final Set patterns = new HashSet(); + final LinkedHashSet patterns = new LinkedHashSet(); final String methodSufiix; if (method != null) { myData.METHOD_NAME = method.getName(); @@ -437,7 +437,7 @@ public class JUnitConfiguration extends ModuleBasedConfiguration myPattern = new LinkedHashSet(); + private LinkedHashSet myPattern = new LinkedHashSet(); //iws/ipr compatibility public String ENV_VARIABLES; private Map myEnvs = new LinkedHashMap(); @@ -581,7 +581,7 @@ public class JUnitConfiguration extends ModuleBasedConfiguration pattern) { + public void setPatterns(LinkedHashSet pattern) { myPattern = pattern; } diff --git a/plugins/junit/src/com/intellij/execution/junit/TestObject.java b/plugins/junit/src/com/intellij/execution/junit/TestObject.java index e1b74d5452ef..eb9de875c346 100644 --- a/plugins/junit/src/com/intellij/execution/junit/TestObject.java +++ b/plugins/junit/src/com/intellij/execution/junit/TestObject.java @@ -509,18 +509,18 @@ public abstract class TestObject implements JavaCommandLine { testNames.add(name); } } + final JUnitConfiguration.Data data = myConfiguration.getPersistentData(); if (perModule != null) { for (List perModuleClasses : perModule.values()) { Collections.sort(perModuleClasses); testNames.addAll(perModuleClasses); } } - else { + else if (JUnitConfiguration.TEST_PACKAGE.equals(data.TEST_OBJECT)) { Collections.sort(testNames); //sort tests in FQN order } - final JUnitConfiguration.Data data = myConfiguration.getPersistentData(); - final String category = data.TEST_OBJECT == JUnitConfiguration.TEST_CATEGORY ? data.getCategory() : ""; + final String category = JUnitConfiguration.TEST_CATEGORY.equals(data.TEST_OBJECT) ? data.getCategory() : ""; JUnitStarter.printClassesList(testNames, packageName, category, myTempFile); if (perModule != null && perModule.size() > 1) { diff --git a/plugins/testng/src/com/theoryinpractice/testng/configuration/SearchingForTestsTask.java b/plugins/testng/src/com/theoryinpractice/testng/configuration/SearchingForTestsTask.java index 8358fcd253dd..ccc820a83817 100644 --- a/plugins/testng/src/com/theoryinpractice/testng/configuration/SearchingForTestsTask.java +++ b/plugins/testng/src/com/theoryinpractice/testng/configuration/SearchingForTestsTask.java @@ -83,7 +83,7 @@ public class SearchingForTestsTask extends Task.Backgroundable { myServerSocket = serverSocket; myConfig = config; myTempFile = tempFile; - myClasses = new HashMap>(); + myClasses = new LinkedHashMap>(); } public void run(@NotNull ProgressIndicator indicator) { @@ -190,13 +190,13 @@ public class SearchingForTestsTask extends Task.Backgroundable { } private void composeTestSuiteFromClasses() { - Map> map = new HashMap>(); + Map> map = new LinkedHashMap>(); final boolean findTestMethodsForClass = shouldSearchForTestMethods(); for (final Map.Entry> entry : myClasses.entrySet()) { final Collection depMethods = entry.getValue(); - Collection methods = new HashSet(depMethods.size()); + Collection methods = new LinkedHashSet(depMethods.size()); for (PsiMethod method : depMethods) { methods.add(method.getName()); } @@ -523,7 +523,7 @@ public class SearchingForTestsTask extends Task.Backgroundable { final Set alreadyMarkedToBeChecked, @Nullable final PsiClass... classes) { if (classes != null && classes.length > 0) { - final Set groupDependencies = new HashSet(); + final Set groupDependencies = new LinkedHashSet(); TestNGUtil.collectAnnotationValues(groupDependencies, "dependsOnGroups", methods, classes); final Set membersToCheckNow = new LinkedHashSet(); if (!groupDependencies.isEmpty()) { @@ -574,7 +574,7 @@ public class SearchingForTestsTask extends Task.Backgroundable { final PsiClass... classes) { final PsiClass[] psiClasses; if (methods != null && methods.length > 0) { - final Set containingClasses = new HashSet(); + final Set containingClasses = new LinkedHashSet(); for (PsiMethod method : methods) { containingClasses.add(method.getContainingClass()); } @@ -583,7 +583,7 @@ public class SearchingForTestsTask extends Task.Backgroundable { psiClasses = classes; } for (final PsiClass containingClass : psiClasses) { - final Set testMethodDependencies = new HashSet(); + final Set testMethodDependencies = new LinkedHashSet(); TestNGUtil.collectAnnotationValues(testMethodDependencies, "dependsOnMethods", methods, containingClass); if (!testMethodDependencies.isEmpty()) { ApplicationManager.getApplication().runReadAction(new Runnable() { diff --git a/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGConfiguration.java b/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGConfiguration.java index cc87a11d2e3c..70b5693be574 100644 --- a/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGConfiguration.java +++ b/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGConfiguration.java @@ -269,7 +269,7 @@ public class TestNGConfiguration extends ModuleBasedConfiguration patterns = new LinkedHashSet(); + LinkedHashSet patterns = new LinkedHashSet(); for (PsiClass pattern : classes) { patterns.add(JavaExecutionUtil.getRuntimeQualifiedName(pattern) + suffix); } @@ -373,7 +373,7 @@ public class TestNGConfiguration extends ModuleBasedConfiguration tests = new LinkedHashSet(); + final LinkedHashSet tests = new LinkedHashSet(); for (Object o : patternsElement.getChildren(PATTERN_EL_NAME)) { Element patternElement = (Element)o; tests.add(patternElement.getAttributeValue(TEST_CLASS_ATT_NAME)); diff --git a/plugins/testng/src/com/theoryinpractice/testng/model/TestData.java b/plugins/testng/src/com/theoryinpractice/testng/model/TestData.java index b40ab4c3ef03..2a75977483bb 100644 --- a/plugins/testng/src/com/theoryinpractice/testng/model/TestData.java +++ b/plugins/testng/src/com/theoryinpractice/testng/model/TestData.java @@ -57,7 +57,7 @@ public class TestData implements Cloneable public List TEST_LISTENERS = new ArrayList(); public boolean USE_DEFAULT_REPORTERS = false; public String PROPERTIES_FILE; - private Set myPatterns = new LinkedHashSet(); + private LinkedHashSet myPatterns = new LinkedHashSet(); public TestData() { TEST_OBJECT = TestType.CLASS.getType(); @@ -168,7 +168,7 @@ public class TestData implements Cloneable data.USE_DEFAULT_REPORTERS = USE_DEFAULT_REPORTERS; data.ENVS = new LinkedHashMap(ENVS); - data.myPatterns = new HashSet(); + data.myPatterns = new LinkedHashSet(); data.myPatterns.addAll(myPatterns); data.setScope(getScope()); return data; @@ -251,7 +251,7 @@ public class TestData implements Cloneable return myPatterns; } - public void setPatterns(Set set) { + public void setPatterns(LinkedHashSet set) { myPatterns = set; } } From 09e34e8d14591c17d2522584f832a7f3938a235d Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Mon, 6 Oct 2014 12:47:27 +0200 Subject: [PATCH 17/28] side effects check should process inc/dec operators (IDEA-130789) --- .../quickfix/RemoveUnusedVariableUtil.java | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/RemoveUnusedVariableUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/RemoveUnusedVariableUtil.java index 59f7cad05f12..a024ba343962 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/RemoveUnusedVariableUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/RemoveUnusedVariableUtil.java @@ -16,6 +16,7 @@ package com.intellij.codeInsight.daemon.impl.quickfix; import com.intellij.psi.*; +import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.InheritanceUtil; import com.intellij.psi.util.PropertyUtil; import com.intellij.psi.util.PsiUtil; @@ -104,7 +105,25 @@ public class RemoveUnusedVariableUtil { sideEffects.add(element); return true; } - PsiElement[] children = element.getChildren(); + + IElementType tokenType = null; + PsiExpression operand = null; + if (element instanceof PsiPrefixExpression) { + operand = ((PsiPrefixExpression)element).getOperand(); + tokenType = ((PsiPrefixExpression)element).getOperationTokenType(); + } else if (element instanceof PsiPostfixExpression) { + operand = ((PsiPostfixExpression)element).getOperand(); + tokenType = ((PsiPostfixExpression)element).getOperationTokenType(); + } + + if (JavaTokenType.MINUSMINUS.equals(tokenType) || JavaTokenType.PLUSPLUS.equals(tokenType)) { + operand = PsiUtil.deparenthesizeExpression(operand); + if (!(operand instanceof PsiReferenceExpression && ((PsiReferenceExpression)operand).resolve() == variable)) { + sideEffects.add(element); + return true; + } + } + PsiElement[] children = element.getChildren(); for (PsiElement child : children) { checkSideEffects(child, variable, sideEffects); From c40185b945de48b60e8b1c85681a82ef187dc4fe Mon Sep 17 00:00:00 2001 From: "Vladimir.Orlov" Date: Mon, 6 Oct 2014 15:41:24 +0400 Subject: [PATCH 18/28] IDEA-128187 Error updating IDEA on Windows - Regression of IDEA-99538 IDEA-130625 Failed to apply patch --- .../intellij/updater/BaseUpdateAction.java | 8 +- .../com/intellij/updater/CreateAction.java | 10 +- .../com/intellij/updater/DeleteAction.java | 12 ++- .../src/com/intellij/updater/Digester.java | 3 +- updater/src/com/intellij/updater/Runner.java | 78 ++++++++++++--- .../com/intellij/updater/SwingUpdaterUI.java | 99 +++++++++++++++++-- updater/src/com/intellij/updater/Utils.java | 36 ++++++- 7 files changed, 220 insertions(+), 26 deletions(-) diff --git a/updater/src/com/intellij/updater/BaseUpdateAction.java b/updater/src/com/intellij/updater/BaseUpdateAction.java index 1d5e5a1cc78f..67a16f8eb4ca 100644 --- a/updater/src/com/intellij/updater/BaseUpdateAction.java +++ b/updater/src/com/intellij/updater/BaseUpdateAction.java @@ -35,7 +35,13 @@ public abstract class BaseUpdateAction extends PatchAction { protected void replaceUpdated(File from, File dest) throws IOException { // on OS X code signing caches seem to be associated with specific file ids, so we need to remove the original file. - if (!dest.delete()) throw new IOException("Cannot delete file " + dest); + if (!dest.delete()) { + if (Utils.isWindows()) { + throw new RetryException("Cannot delete file " + dest); + } else { + throw new IOException("Cannot delete file " + dest); + } + } Utils.copy(from, dest); } diff --git a/updater/src/com/intellij/updater/CreateAction.java b/updater/src/com/intellij/updater/CreateAction.java index e1a3fa1dabdc..5b0f8df595a5 100644 --- a/updater/src/com/intellij/updater/CreateAction.java +++ b/updater/src/com/intellij/updater/CreateAction.java @@ -59,7 +59,15 @@ public class CreateAction extends PatchAction { private static void prepareToWriteFile(File file) throws IOException { if (file.exists()) { - Utils.delete(file); + try { + Utils.delete(file); + } catch (IOException e) { + if (Utils.isWindows() && file.exists()) { + throw new RetryException(e); + } else { + throw e; + } + } return; } diff --git a/updater/src/com/intellij/updater/DeleteAction.java b/updater/src/com/intellij/updater/DeleteAction.java index 8bc43ac41bb1..e47588e150ee 100644 --- a/updater/src/com/intellij/updater/DeleteAction.java +++ b/updater/src/com/intellij/updater/DeleteAction.java @@ -43,13 +43,23 @@ public class DeleteAction extends PatchAction { @Override protected void doApply(ZipFile patchFile, File toFile) throws IOException { - Utils.delete(toFile); + try { + Utils.delete(toFile); + } catch (IOException e) { + if (Utils.isWindows() && toFile.exists()) { + throw new RetryException(e); + } else { + throw e; + } + } } + @Override protected void doBackup(File toFile, File backupFile) throws IOException { Utils.copy(toFile, backupFile); } + @Override protected void doRevert(File toFile, File backupFile) throws IOException { if (!toFile.exists() || isModified(toFile)) { Utils.delete(toFile); // make sure there is no directory remained on this path (may remain from previous 'create' actions diff --git a/updater/src/com/intellij/updater/Digester.java b/updater/src/com/intellij/updater/Digester.java index 00792ce00321..ba6a4703e241 100644 --- a/updater/src/com/intellij/updater/Digester.java +++ b/updater/src/com/intellij/updater/Digester.java @@ -28,7 +28,8 @@ public class Digester { zipFile = new ZipFile(file); } catch (IOException e) { - Runner.printStackTrace(e); + // If this isn't a zip file, this isn't really an error, merely an info. + Runner.infoStackTrace("Can't open file as zip file: " + file.getPath() + "\n", e); return doDigestRegularFile(file); } diff --git a/updater/src/com/intellij/updater/Runner.java b/updater/src/com/intellij/updater/Runner.java index 39e58e5c9e36..56a331b5ebc8 100644 --- a/updater/src/com/intellij/updater/Runner.java +++ b/updater/src/com/intellij/updater/Runner.java @@ -38,11 +38,22 @@ public class Runner { create(oldVersionDesc, newVersionDesc, oldFolder, newFolder, patchFile, ignoredFiles, criticalFiles, optionalFiles); } else if (args.length >= 2 && "install".equals(args[0])) { - String destFolder = args[1]; + // install [--exit0] + int nextArg = 1; + + // Default install exit code is SwingUpdaterUI.RESULT_REQUIRES_RESTART (42) unless overridden to be 0. + // This is used by testUI/build.gradle as gradle expects a javaexec to exit with code 0. + boolean useExitCode0 = false; + if (args[nextArg].equals("--exit0")) { + useExitCode0 = true; + nextArg++; + } + + String destFolder = args[nextArg++]; initLogger(); logger.info("destFolder: " + destFolder); - install(destFolder); + install(useExitCode0, destFolder); } else { printUsage(); @@ -93,6 +104,10 @@ public class Runner { } } + public static void infoStackTrace(String msg, Throwable e){ + logger.info(msg, e); + } + public static void printStackTrace(Throwable e){ logger.error(e.getMessage(), e); } @@ -115,8 +130,8 @@ public class Runner { private static void printUsage() { System.err.println("Usage:\n" + "create " + - " [ignored=file1;file2;...] [critical=file1;file2;...] [optional=file1;file2;...]\n" + - "install [log_directory]\n"); + " [ignored=file1;file2;...] [critical=file1;file2;...] [optional=file1;file2;...]\n" + + "install [--exit0] [log_directory]\n"); } private static void create(String oldBuildDesc, @@ -127,9 +142,31 @@ public class Runner { List ignoredFiles, List criticalFiles, List optionalFiles) throws IOException, OperationCancelledException { - UpdaterUI ui = new ConsoleUpdaterUI(); + File tempPatchFile = Utils.createTempFile(); + createImpl(oldBuildDesc, + newBuildDesc, + oldFolder, + newFolder, + patchFile, + tempPatchFile, + ignoredFiles, + criticalFiles, + optionalFiles, + new ConsoleUpdaterUI(), resolveJarFile()); + } + + static void createImpl(String oldBuildDesc, + String newBuildDesc, + String oldFolder, + String newFolder, + String outPatchJar, + File tempPatchFile, + List ignoredFiles, + List criticalFiles, + List optionalFiles, + UpdaterUI ui, + File resolvedJar) throws IOException, OperationCancelledException { try { - File tempPatchFile = Utils.createTempFile(); PatchFileCreator.create(new File(oldFolder), new File(newFolder), tempPatchFile, @@ -138,13 +175,13 @@ public class Runner { optionalFiles, ui); - logger.info("Packing JAR file: " + patchFile ); - ui.startProcess("Packing JAR file '" + patchFile + "'..."); + logger.info("Packing JAR file: " + outPatchJar ); + ui.startProcess("Packing JAR file '" + outPatchJar + "'..."); - FileOutputStream fileOut = new FileOutputStream(patchFile); + FileOutputStream fileOut = new FileOutputStream(outPatchJar); try { ZipOutputWrapper out = new ZipOutputWrapper(fileOut); - ZipInputStream in = new ZipInputStream(new FileInputStream(resolveJarFile())); + ZipInputStream in = new ZipInputStream(new FileInputStream(resolvedJar)); try { ZipEntry e; while ((e = in.getNextEntry()) != null) { @@ -186,7 +223,7 @@ public class Runner { Utils.cleanup(); } - private static void install(final String destFolder) throws Exception { + private static void install(final boolean useExitCode0, final String destFolder) throws Exception { InputStream in = Runner.class.getResourceAsStream("/" + PATCH_PROPERTIES_ENTRY); Properties props = new Properties(); try { @@ -213,7 +250,9 @@ public class Runner { new SwingUpdaterUI(props.getProperty(OLD_BUILD_DESCRIPTION), props.getProperty(NEW_BUILD_DESCRIPTION), + useExitCode0 ? 0 : SwingUpdaterUI.RESULT_REQUIRES_RESTART, new SwingUpdaterUI.InstallOperation() { + @Override public boolean execute(UpdaterUI ui) throws OperationCancelledException { logger.info("installing patch to the " + destFolder); return doInstall(ui, destFolder); @@ -221,11 +260,26 @@ public class Runner { }); } + interface IJarResolver { + File resolveJar() throws IOException; + } + private static boolean doInstall(UpdaterUI ui, String destFolder) throws OperationCancelledException { + return doInstallImpl(ui, destFolder, new IJarResolver() { + @Override + public File resolveJar() throws IOException { + return resolveJarFile(); + } + }); + } + + static boolean doInstallImpl(UpdaterUI ui, + String destFolder, + IJarResolver jarResolver) throws OperationCancelledException { try { try { File patchFile = Utils.createTempFile(); - ZipFile jarFile = new ZipFile(resolveJarFile()); + ZipFile jarFile = new ZipFile(jarResolver.resolveJar()); logger.info("Extracting patch file..."); ui.startProcess("Extracting patch file..."); diff --git a/updater/src/com/intellij/updater/SwingUpdaterUI.java b/updater/src/com/intellij/updater/SwingUpdaterUI.java index d44fc2e094f1..749dcc2fc350 100644 --- a/updater/src/com/intellij/updater/SwingUpdaterUI.java +++ b/updater/src/com/intellij/updater/SwingUpdaterUI.java @@ -10,6 +10,7 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; +import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import java.lang.reflect.InvocationTargetException; @@ -19,7 +20,7 @@ import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicBoolean; public class SwingUpdaterUI implements UpdaterUI { - private static final int RESULT_REQUIRES_RESTART = 42; + static final int RESULT_REQUIRES_RESTART = 42; private static final EmptyBorder FRAME_BORDER = new EmptyBorder(8, 8, 8, 8); private static final EmptyBorder LABEL_BORDER = new EmptyBorder(0, 0, 5, 0); @@ -32,6 +33,7 @@ public class SwingUpdaterUI implements UpdaterUI { private static final String PROCEED_BUTTON_TITLE = "Proceed"; + private final int mySuccessExitCode; private final InstallOperation myOperation; private final JLabel myProcessTitle; @@ -40,16 +42,30 @@ public class SwingUpdaterUI implements UpdaterUI { private final JTextArea myConsole; private final JPanel myConsolePane; + private final JButton myRetryButton; private final JButton myCancelButton; private final ConcurrentLinkedQueue myQueue = new ConcurrentLinkedQueue(); private final AtomicBoolean isCancelled = new AtomicBoolean(false); private final AtomicBoolean isRunning = new AtomicBoolean(false); private final AtomicBoolean hasError = new AtomicBoolean(false); + private final AtomicBoolean hasRetry = new AtomicBoolean(false); private final JFrame myFrame; private boolean myApplied; - public SwingUpdaterUI(String oldBuildDesc, String newBuildDesc, InstallOperation operation) { + /** + * Displays the updater UI and asynchronously runs the operation list. + * + * @param oldBuildDesc The old build description, for display purposes. + * @param newBuildDesc The new build description, for display purposes. + * @param successExitCode The desired exit code on success. Default is {@link #RESULT_REQUIRES_RESTART}. + * @param operation The install operations to perform. + */ + public SwingUpdaterUI(String oldBuildDesc, + String newBuildDesc, + int successExitCode, + InstallOperation operation) { + mySuccessExitCode = successExitCode; myOperation = operation; myProcessTitle = new JLabel(" "); @@ -58,6 +74,10 @@ public class SwingUpdaterUI implements UpdaterUI { myCancelButton = new JButton(CANCEL_BUTTON_TITLE); + myRetryButton = new JButton("Retry"); + myRetryButton.setEnabled(false); + myRetryButton.setVisible(false); + myConsole = new JTextArea(); myConsole.setLineWrap(true); myConsole.setWrapStyleWord(true); @@ -70,11 +90,19 @@ public class SwingUpdaterUI implements UpdaterUI { myConsolePane.setVisible(false); myCancelButton.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { doCancel(); } }); + myRetryButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + doRetry(); + } + }); + myFrame = new JFrame(); myFrame.setTitle(TITLE); @@ -104,6 +132,7 @@ public class SwingUpdaterUI implements UpdaterUI { buttonsPanel.setBorder(BUTTONS_BORDER); buttonsPanel.setLayout(new BoxLayout(buttonsPanel, BoxLayout.X_AXIS)); buttonsPanel.add(Box.createHorizontalGlue()); + buttonsPanel.add(myRetryButton); buttonsPanel.add(myCancelButton); myProcessTitle.setText("Updating " + oldBuildDesc + " to " + newBuildDesc + "..."); @@ -129,6 +158,7 @@ public class SwingUpdaterUI implements UpdaterUI { private void startRequestDispatching() { new Thread(new Runnable() { + @Override public void run() { while (true) { try { @@ -146,6 +176,7 @@ public class SwingUpdaterUI implements UpdaterUI { } SwingUtilities.invokeLater(new Runnable() { + @Override public void run() { for (UpdateRequest each : pendingRequests) { each.perform(); @@ -172,10 +203,28 @@ public class SwingUpdaterUI implements UpdaterUI { } } + private void doRetry() { + hasError.set(false); + hasRetry.set(false); + isCancelled.set(false); + myQueue.add(new UpdateRequest() { + @Override + public void perform() { + myConsole.setText(""); + myConsolePane.setVisible(false); + myConsolePane.setPreferredSize(new Dimension(10, 200)); + myRetryButton.setEnabled(false); + myCancelButton.setEnabled(true); + } + }); + doPerform(); + } + private void doPerform() { isRunning.set(true); new Thread(new Runnable() { + @Override public void run() { try { myApplied = myOperation.execute(SwingUpdaterUI.this); @@ -190,6 +239,10 @@ public class SwingUpdaterUI implements UpdaterUI { finally { isRunning.set(false); + if (hasRetry.get()) { + myRetryButton.setVisible(true); + myRetryButton.setEnabled(true); + } if (hasError.get()) { startProcess("Failed to apply patch"); setProgress(100); @@ -204,15 +257,17 @@ public class SwingUpdaterUI implements UpdaterUI { } private void exit() { - System.exit(myApplied ? RESULT_REQUIRES_RESTART : 0); + System.exit(myApplied ? mySuccessExitCode : 0); } + @Override public Map askUser(final List validationResults) throws OperationCancelledException { if (validationResults.isEmpty()) return Collections.emptyMap(); final Map result = new HashMap(); try { SwingUtilities.invokeAndWait(new Runnable() { + @Override public void run() { final JDialog dialog = new JDialog(myFrame, TITLE, true); dialog.setLayout(new BorderLayout()); @@ -224,6 +279,7 @@ public class SwingUpdaterUI implements UpdaterUI { buttonsPanel.add(Box.createHorizontalGlue()); JButton proceedButton = new JButton(PROCEED_BUTTON_TITLE); proceedButton.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { dialog.setVisible(false); } @@ -231,6 +287,7 @@ public class SwingUpdaterUI implements UpdaterUI { JButton cancelButton = new JButton(CANCEL_BUTTON_TITLE); cancelButton.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { isCancelled.set(true); myCancelButton.setEnabled(false); @@ -287,8 +344,10 @@ public class SwingUpdaterUI implements UpdaterUI { return result; } + @Override public void startProcess(final String title) { myQueue.add(new UpdateRequest() { + @Override public void perform() { myProcessStatus.setText(title); myProcessProgress.setIndeterminate(false); @@ -297,8 +356,10 @@ public class SwingUpdaterUI implements UpdaterUI { }); } + @Override public void setProgress(final int percentage) { myQueue.add(new UpdateRequest() { + @Override public void perform() { myProcessProgress.setIndeterminate(false); myProcessProgress.setValue(percentage); @@ -306,21 +367,43 @@ public class SwingUpdaterUI implements UpdaterUI { }); } + @Override public void setProgressIndeterminate() { myQueue.add(new UpdateRequest() { + @Override public void perform() { myProcessProgress.setIndeterminate(true); } }); } + @Override public void setStatus(final String status) { } + @Override public void showError(final Throwable e) { hasError.set(true); + StringWriter w = new StringWriter(); + + if (e instanceof RetryException) { + hasRetry.set(true); + + w.write("+----------------\n"); + w.write("| A file operation failed.\n"); + w.write("| This might be due to a file being locked by another\n"); + w.write("| application. Please try closing any application\n"); + w.write("| that uses the files being updated then press 'Retry'.\n"); + w.write("+----------------\n"); + w.write("\n\n"); + } + + e.printStackTrace(new PrintWriter(w)); + + final String content = w.getBuffer().toString(); myQueue.add(new UpdateRequest() { + @Override public void perform() { StringWriter w = new StringWriter(); if (!myConsolePane.isVisible()) { @@ -328,9 +411,8 @@ public class SwingUpdaterUI implements UpdaterUI { w.write(System.getProperty("java.io.tmpdir")); w.write("\n\n"); } - e.printStackTrace(new PrintWriter(w)); - w.append("\n"); myConsole.append(w.getBuffer().toString()); + myConsole.append(content); if (!myConsolePane.isVisible()) { myConsole.setCaretPosition(0); myConsolePane.setVisible(true); @@ -341,6 +423,7 @@ public class SwingUpdaterUI implements UpdaterUI { }); } + @Override public void checkCancelled() throws OperationCancelledException { if (isCancelled.get()) throw new OperationCancelledException(); } @@ -354,7 +437,8 @@ public class SwingUpdaterUI implements UpdaterUI { } public static void main(String[] args) { - new SwingUpdaterUI("xxx", "yyy", new InstallOperation() { + new SwingUpdaterUI("xxx", "yyy", RESULT_REQUIRES_RESTART, new InstallOperation() { + @Override public boolean execute(UpdaterUI ui) throws OperationCancelledException { ui.startProcess("Process1"); ui.checkCancelled(); @@ -438,6 +522,7 @@ public class SwingUpdaterUI implements UpdaterUI { } } + @Override public int getColumnCount() { return COLUMNS.length; } @@ -464,6 +549,7 @@ public class SwingUpdaterUI implements UpdaterUI { return super.getColumnClass(columnIndex); } + @Override public int getRowCount() { return myItems.size(); } @@ -480,6 +566,7 @@ public class SwingUpdaterUI implements UpdaterUI { } } + @Override public Object getValueAt(int rowIndex, int columnIndex) { Item item = myItems.get(rowIndex); switch (columnIndex) { diff --git a/updater/src/com/intellij/updater/Utils.java b/updater/src/com/intellij/updater/Utils.java index 959a93cee1c2..b5ad212ac1a9 100644 --- a/updater/src/com/intellij/updater/Utils.java +++ b/updater/src/com/intellij/updater/Utils.java @@ -10,10 +10,19 @@ public class Utils { private static final byte[] BUFFER = new byte[64 * 1024]; private static File myTempDir; + public static boolean isWindows() { + return System.getProperty("os.name").startsWith("Windows"); + } + public static boolean isZipFile(String fileName) { return fileName.endsWith(".zip") || fileName.endsWith(".jar"); } + /** + * Creates a new temp file.
+ * All the temp files created here are located in a unique root temp directory + * that is automatically deleted by {@link #cleanup()}. + */ @SuppressWarnings({"SSBasedInspection"}) public static File createTempFile() throws IOException { if (myTempDir == null) { @@ -26,6 +35,12 @@ public class Utils { return File.createTempFile("temp.", ".tmp", myTempDir); } + + /** + * Creates a new temp directory.
+ * All the temp directories created here are located in a unique root temp directory + * that is automatically deleted by {@link #cleanup()}. + */ public static File createTempDir() throws IOException { File result = createTempFile(); delete(result); @@ -42,6 +57,15 @@ public class Utils { myTempDir = null; } + /** + * Deletes a file or directory with a default timeout of 100 milliseconds. + * Directories are deleted recursively. The timeout occurs on each file. + * If one of the files fails to be deleted, the recursive directory deletion + * is aborted and not retried. + * + * @param file The file or directory to delete. + * @throws IOException + */ public static void delete(File file) throws IOException { if (file.isDirectory()) { File[] files = file.listFiles(); @@ -52,16 +76,20 @@ public class Utils { } } } + for (int i = 0; i < 10; i++) { - if (file.delete() || !file.exists()) return; + if (file.delete() || !file.exists()) { + return; + } try { Thread.sleep(10); - } - catch (InterruptedException ignore) { + } catch (InterruptedException ignore) { Runner.printStackTrace(ignore); } } - if (file.exists()) throw new IOException("Cannot delete file " + file); + if (file.exists()) { + throw new IOException("Cannot delete file " + file); + } } public static void setExecutable(File file, boolean executable) throws IOException { From b462a5c762bb9a47978663d0f485381d31c423c8 Mon Sep 17 00:00:00 2001 From: Valentin Fondaratov Date: Mon, 6 Oct 2014 15:39:28 +0400 Subject: [PATCH 19/28] MasqueradingPsiBuilderAdapter now tries to assign whitespace&foreign to as high parent as possible (fixes WEB-13621) --- .../MasqueradingPsiBuilderAdapter.java | 100 +++++++++++++----- 1 file changed, 71 insertions(+), 29 deletions(-) diff --git a/xml/xml-psi-impl/src/com/intellij/embedding/MasqueradingPsiBuilderAdapter.java b/xml/xml-psi-impl/src/com/intellij/embedding/MasqueradingPsiBuilderAdapter.java index a262c5558e19..ca45d1ecf98e 100644 --- a/xml/xml-psi-impl/src/com/intellij/embedding/MasqueradingPsiBuilderAdapter.java +++ b/xml/xml-psi-impl/src/com/intellij/embedding/MasqueradingPsiBuilderAdapter.java @@ -18,6 +18,7 @@ package com.intellij.embedding; import com.intellij.lang.*; import com.intellij.lang.impl.PsiBuilderAdapter; import com.intellij.lang.impl.PsiBuilderImpl; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.psi.TokenType; import com.intellij.psi.tree.IElementType; @@ -26,7 +27,6 @@ import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; -import java.util.logging.Logger; /** * A delegate PsiBuilder that hides or substitutes some tokens (namely, the ones provided by {@link MasqueradingLexer}) @@ -68,45 +68,65 @@ public class MasqueradingPsiBuilderAdapter extends PsiBuilderAdapter { @Override public void advanceLexer() { -// logPos(); myLexPosition++; + skipWhitespace(); - synchronizePositions(); -// logPos(); + synchronizePositions(false); } - private void synchronizePositions() { + /** + * @param exact if true then positions should be equal; + * else delegate should be behind, not including exactly all foreign (skipped) tokens + */ + private void synchronizePositions(boolean exact) { final PsiBuilder delegate = getDelegate(); - while (!delegate.eof() || myLexPosition < myShrunkSequence.size()) { - if (myLexPosition >= myShrunkSequence.size()) { + + if (myLexPosition >= myShrunkSequence.size() || delegate.eof()) { + myLexPosition = myShrunkSequence.size(); + while (!delegate.eof()) { delegate.advanceLexer(); - continue; - } - if (delegate.eof()) { - myLexPosition = myShrunkSequence.size(); - break; } + return; + } + + if (delegate.getCurrentOffset() > myShrunkSequence.get(myLexPosition).realStart) { + Logger.getInstance(getClass()).error("delegate is ahead of my builder!"); + return; + } + + final int keepUpPosition = getKeepUpPosition(exact); + + while (!delegate.eof()) { final int delegatePosition = delegate.getCurrentOffset(); - final int myPosition = myShrunkSequence.get(myLexPosition).realStart; - if (delegatePosition < myPosition) { + if (delegatePosition < keepUpPosition) { delegate.advanceLexer(); } - else if (delegatePosition > myPosition) { - myLexPosition++; - } else { break; } } } + private int getKeepUpPosition(boolean exact) { + if (exact) { + return myShrunkSequence.get(myLexPosition).realStart; + } + + int lexPosition = myLexPosition; + while (lexPosition > 0 && (myShrunkSequence.get(lexPosition - 1).shrunkStart == myShrunkSequence.get(lexPosition).shrunkStart + || isWhiteSpaceOnPos(lexPosition - 1))) { + lexPosition--; + } + if (lexPosition == 0) { + return myShrunkSequence.get(lexPosition).realStart; + } + return myShrunkSequence.get(lexPosition - 1).realStart + 1; + } + @Override public IElementType lookAhead(int steps) { - final PsiBuilderImpl delegate = (PsiBuilderImpl)getDelegate(); - synchronizePositions(); - if (eof()) { // ensure we skip over whitespace if it's needed return null; } @@ -114,7 +134,7 @@ public class MasqueradingPsiBuilderAdapter extends PsiBuilderAdapter { while (steps > 0) { ++cur; - while (cur < myShrunkSequence.size() && delegate.whitespaceOrComment(myShrunkSequence.get(cur).elementType)) { + while (cur < myShrunkSequence.size() && isWhiteSpaceOnPos(cur)) { cur++; } @@ -154,7 +174,7 @@ public class MasqueradingPsiBuilderAdapter extends PsiBuilderAdapter { if (allIsEmpty()) { return TokenType.DUMMY_HOLDER; } - checkWhitespace(); + skipWhitespace(); return myLexPosition < myShrunkSequence.size() ? myShrunkSequence.get(myLexPosition).elementType : null; } @@ -165,7 +185,7 @@ public class MasqueradingPsiBuilderAdapter extends PsiBuilderAdapter { if (allIsEmpty()) { return getDelegate().getOriginalText().toString(); } - checkWhitespace(); + skipWhitespace(); if (myLexPosition >= myShrunkSequence.size()) { return null; @@ -175,8 +195,24 @@ public class MasqueradingPsiBuilderAdapter extends PsiBuilderAdapter { return myShrunkCharSequence.subSequence(token.shrunkStart, token.shrunkEnd).toString(); } + @Override + public boolean eof() { + boolean isEof = myLexPosition >= myShrunkSequence.size(); + if (!isEof) { + return false; + } + + synchronizePositions(true); + return true; + } + @Override public Marker mark() { + // In the case of the topmost node all should be inserted + if (myLexPosition != 0) { + synchronizePositions(true); + } + final Marker mark = super.mark(); return new MyMarker(mark, myLexPosition); } @@ -185,12 +221,14 @@ public class MasqueradingPsiBuilderAdapter extends PsiBuilderAdapter { return myShrunkSequence.isEmpty() && getDelegate().getOriginalText().length() != 0; } - private void checkWhitespace() { - while (myLexPosition < myShrunkSequence.size() && - ((PsiBuilderImpl)myDelegate).whitespaceOrComment(myShrunkSequence.get(myLexPosition).elementType)) { + private void skipWhitespace() { + while (myLexPosition < myShrunkSequence.size() && isWhiteSpaceOnPos(myLexPosition)) { myLexPosition++; } - synchronizePositions(); + } + + private boolean isWhiteSpaceOnPos(int pos) { + return ((PsiBuilderImpl)myDelegate).whitespaceOrComment(myShrunkSequence.get(pos).elementType); } protected void initShrunkSequence() { @@ -199,7 +237,6 @@ public class MasqueradingPsiBuilderAdapter extends PsiBuilderAdapter { initTokenListAndCharSequence(lexer); myLexPosition = 0; -// synchronizePositions(); } private void initTokenListAndCharSequence(MasqueradingLexer lexer) { @@ -235,7 +272,7 @@ public class MasqueradingPsiBuilderAdapter extends PsiBuilderAdapter { @SuppressWarnings({"StringConcatenationInsideStringBufferAppend", "UnusedDeclaration"}) private void logPos() { - final Logger log = Logger.getLogger(this.getClass().getSimpleName()); + final Logger log = Logger.getInstance(getClass()); StringBuilder sb = new StringBuilder(); sb.append("\nmyLexPosition=" + myLexPosition + "/" + myShrunkSequence.size()); if (myLexPosition < myShrunkSequence.size()) { @@ -271,6 +308,11 @@ public class MasqueradingPsiBuilderAdapter extends PsiBuilderAdapter { this.shrunkStart = shrunkStart; this.shrunkEnd = shrunkEnd; } + + @Override + public String toString() { + return "MSTk: [" + realStart + ", " + realEnd + "] -> [" + shrunkStart + ", " + shrunkEnd + "]: " + elementType.toString(); + } } private class MyMarker extends DelegateMarker { From be0dd75d97ee6f69010a643605d0214068050bb1 Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Mon, 6 Oct 2014 15:39:38 +0400 Subject: [PATCH 20/28] IDEA-130682 Preferences : Code style: Can't scroll the page on Mac --- .../application/options/GeneralCodeStylePanel.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) 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 d0e1558abd41..a521067dbfd1 100644 --- a/platform/lang-impl/src/com/intellij/application/options/GeneralCodeStylePanel.java +++ b/platform/lang-impl/src/com/intellij/application/options/GeneralCodeStylePanel.java @@ -37,9 +37,9 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiFile; import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.ui.IdeBorderFactory; +import com.intellij.ui.ScrollPaneFactory; import com.intellij.ui.awt.RelativePoint; import com.intellij.ui.components.JBLabel; -import com.intellij.ui.components.JBScrollPane; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -77,7 +77,7 @@ public class GeneralCodeStylePanel extends CodeStyleAbstractPanel { private JPanel myAdditionalSettingsPanel; private JCheckBox myAutodetectIndentsBox; private final SmartIndentOptionsEditor myIndentOptionsEditor; - private final JBScrollPane myScrollPane; + private final JScrollPane myScrollPane; public GeneralCodeStylePanel(CodeStyleSettings settings) { @@ -106,9 +106,7 @@ public class GeneralCodeStylePanel extends CodeStyleAbstractPanel { ApplicationBundle.message("settings.code.style.general.formatter.marker.title"), true)); myMarkerOptionsPanel.setBorder( IdeBorderFactory.createTitledBorder(ApplicationBundle.message("settings.code.style.general.formatter.marker.options.title"), true)); - myScrollPane = new JBScrollPane(myPanel, - ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); - myScrollPane.setBorder(IdeBorderFactory.createEmptyBorder()); + myScrollPane = ScrollPaneFactory.createScrollPane(myPanel, true); myAdditionalSettingsPanel.setLayout(new VerticalFlowLayout(true, true)); myAdditionalSettingsPanel.removeAll(); From 00b17e88c3b85bde7e27cdf610dc50cebefce424 Mon Sep 17 00:00:00 2001 From: nik Date: Mon, 6 Oct 2014 16:01:29 +0400 Subject: [PATCH 21/28] 'excluded' to 'ignored' conversion: do not mark as ignored content roots of inner modules explicitly excluded from outer module (IDEA-129864) --- .../openapi/vcs/changes/ChangeListManagerImpl.java | 8 ++++++++ .../vcs/changes/ConvertExcludedToIgnoredTest.java | 9 +++++++++ 2 files changed, 17 insertions(+) diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListManagerImpl.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListManagerImpl.java index 87d39a539254..1947e8c36bc1 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListManagerImpl.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListManagerImpl.java @@ -31,6 +31,7 @@ import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.DumbAwareRunnable; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ModuleRootManager; +import com.intellij.openapi.roots.ProjectFileIndex; import com.intellij.openapi.roots.impl.DirectoryIndexExcludePolicy; import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.ui.Messages; @@ -328,8 +329,15 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec } } + ProjectFileIndex fileIndex = ProjectFileIndex.SERVICE.getInstance(myProject); + VirtualFileManager virtualFileManager = VirtualFileManager.getInstance(); for (Module module : ModuleManager.getInstance(myProject).getModules()) { for (String url : ModuleRootManager.getInstance(module).getExcludeRootUrls()) { + VirtualFile file = virtualFileManager.findFileByUrl(url); + if (file != null && !fileIndex.isExcluded(file)) { + //root is included into some inner module so it shouldn't be ignored + continue; + } addDirectoryToIgnoreImplicitly(VfsUtilCore.urlToPath(url)); } } diff --git a/platform/vcs-impl/testSrc/com/intellij/openapi/vcs/changes/ConvertExcludedToIgnoredTest.java b/platform/vcs-impl/testSrc/com/intellij/openapi/vcs/changes/ConvertExcludedToIgnoredTest.java index 4ec5ea4bcdad..e2721e3aeb8d 100644 --- a/platform/vcs-impl/testSrc/com/intellij/openapi/vcs/changes/ConvertExcludedToIgnoredTest.java +++ b/platform/vcs-impl/testSrc/com/intellij/openapi/vcs/changes/ConvertExcludedToIgnoredTest.java @@ -1,5 +1,6 @@ package com.intellij.openapi.vcs.changes; +import com.intellij.openapi.module.ModuleType; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.CompilerProjectExtension; import com.intellij.openapi.vfs.VirtualFile; @@ -71,6 +72,14 @@ public class ConvertExcludedToIgnoredTest extends PlatformTestCase { assertIgnored(excluded); } + public void testDoNotIgnoreInnerModuleExplicitlyMarkedAsExcludedFromOuterModule() throws IOException { + VirtualFile inner = createChildDirectory(myContentRoot, "inner"); + PsiTestUtil.addModule(myProject, ModuleType.EMPTY, "inner", inner); + PsiTestUtil.addExcludedRoot(myModule, inner); + getChangeListManager().convertExcludedToIgnored(); + assertFalse(getChangeListManager().isIgnoredFile(inner)); + } + private void assertIgnored(VirtualFile... ignoredDirs) { assertIgnoredDirectories(getProject(), ignoredDirs); } From 88f6718c4c78658dbe9fcc382cc1c8938a5f2f24 Mon Sep 17 00:00:00 2001 From: Andrey Vokin Date: Mon, 6 Oct 2014 16:34:11 +0400 Subject: [PATCH 22/28] Cucumber. Gherkin keywords are taken from built-in json file --- build/scripts/libLicenses.gant | 1 + 1 file changed, 1 insertion(+) diff --git a/build/scripts/libLicenses.gant b/build/scripts/libLicenses.gant index 70e22cda7d1d..3065c26d756c 100644 --- a/build/scripts/libLicenses.gant +++ b/build/scripts/libLicenses.gant @@ -280,6 +280,7 @@ libraryLicense(name: "ReflectASM", libraryName: "reflectasm-1.0.7.jar", version: libraryLicense(name: "Objenesis", libraryName: "objenesis-1.2.jar", version: "1.2", license: "Apache 2.0", url: "http://objenesis.org/", licenseUrl: "http://apache.org/licenses/LICENSE-2.0") libraryLicense(name: "EditorConfig Java Core", libraryName: "editorconfig-core-java.jar", version: "1.0", license: "Apache 2.0", url: "https://github.com/editorconfig/editorconfig-core-java/", licenseUrl: "https://github.com/editorconfig/editorconfig-core-java/blob/master/LICENSE") libraryLicense(name: "Fest", libraryName: "fest", version: "", license: "Apache 2.0", licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0.txt", url: "https://code.google.com/p/fest/") +libraryLicense(name: "Gherkin", libraryName: "Gherkin", version: "2.12.2", license: "MIT", licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0.txt", url: "https://github.com/cucumber/gherkin") jetbrainsLibrary("Coverage") jetbrainsLibrary("CoverageReport") jetbrainsLibrary("JPS") From 5db072679930f73edac7501151604f4f40d97fb1 Mon Sep 17 00:00:00 2001 From: "Vladimir.Orlov" Date: Mon, 6 Oct 2014 16:44:17 +0400 Subject: [PATCH 23/28] IDEA-128187 Error updating IDEA on Windows - Regression of IDEA-99538 IDEA-130625 Failed to apply patch --- .../com/intellij/updater/RetryException.java | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 updater/src/com/intellij/updater/RetryException.java diff --git a/updater/src/com/intellij/updater/RetryException.java b/updater/src/com/intellij/updater/RetryException.java new file mode 100644 index 000000000000..e13c4eb0f2c8 --- /dev/null +++ b/updater/src/com/intellij/updater/RetryException.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * 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.updater; + +import java.io.IOException; + +/** + * Exception thrown when an IOException arises when performing a patch + * action and it's likely that retrying will be successful. + */ +public class RetryException extends IOException { + public RetryException() { + } + + public RetryException(String message) { + super(message); + } + + public RetryException(String message, Throwable cause) { + super(message, cause); + } + + public RetryException(Throwable cause) { + super(cause); + } +} From c63ea1bf2a5ecdec6f2bd379f7d06d73326e8954 Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Mon, 6 Oct 2014 17:16:29 +0400 Subject: [PATCH 24/28] no need to create tmp dir file every time --- .../util/src/com/intellij/openapi/util/io/FileUtil.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/platform/util/src/com/intellij/openapi/util/io/FileUtil.java b/platform/util/src/com/intellij/openapi/util/io/FileUtil.java index 4324deee35d4..d7d632377ab4 100644 --- a/platform/util/src/com/intellij/openapi/util/io/FileUtil.java +++ b/platform/util/src/com/intellij/openapi/util/io/FileUtil.java @@ -383,10 +383,10 @@ public class FileUtil extends FileUtilRt { @Nullable private static File renameToTempFileOrDelete(@NotNull File file) { - final File tempDir = new File(getTempDirectory()); + String tempDir = getTempDirectory(); boolean isSameDrive = true; if (SystemInfo.isWindows) { - String tempDirDrive = tempDir.getAbsolutePath().substring(0, 2); + String tempDirDrive = tempDir.substring(0, 2); String fileDrive = file.getAbsolutePath().substring(0, 2); isSameDrive = tempDirDrive.equalsIgnoreCase(fileDrive); } @@ -405,7 +405,7 @@ public class FileUtil extends FileUtilRt { return null; } - private static File getTempFile(@NotNull String originalFileName, @NotNull File parent) { + private static File getTempFile(@NotNull String originalFileName, @NotNull String parent) { int randomSuffix = (int)(System.currentTimeMillis() % 1000); for (int i = randomSuffix; ; i++) { @NonNls String name = "___" + originalFileName + i + ASYNC_DELETE_EXTENSION; From 1c618bf947296c2c37ab63b57243c7d0dfdf09bb Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Mon, 6 Oct 2014 16:46:21 +0400 Subject: [PATCH 25/28] installers fixed: do not instantiate ProgressWindow in headless environment --- .../com/intellij/openapi/application/impl/ApplicationImpl.java | 1 + 1 file changed, 1 insertion(+) diff --git a/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java b/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java index 67f868deda91..cf87cd8c24d6 100644 --- a/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java @@ -594,6 +594,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App boolean writeAccessAllowed = isInsideWriteActionEDTOnly(); if (writeAccessAllowed // Disallow running process in separate thread from under write action. // The thread will deadlock trying to get read action otherwise. + || isHeadlessEnvironment() && !isUnitTestMode() ) { LOG.debug("Starting process with progress from within write action makes no sense"); try { From cfcc46a9c0de75ec9510bb25029e7338b90372f1 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Mon, 6 Oct 2014 16:46:49 +0400 Subject: [PATCH 26/28] assertion for duplicate visitors accidentally registered --- .../codeInsight/daemon/impl/GeneralHighlightingPass.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/GeneralHighlightingPass.java b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/GeneralHighlightingPass.java index 757a3f63bfda..ea35f552da73 100644 --- a/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/GeneralHighlightingPass.java +++ b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/GeneralHighlightingPass.java @@ -86,7 +86,12 @@ public class GeneralHighlightingPass extends ProgressableTextEditorHighlightingP private static final Comparator VISITOR_ORDER_COMPARATOR = new Comparator() { @Override public int compare(final HighlightVisitor o1, final HighlightVisitor o2) { - return o1.order() - o2.order(); + int delta = o1.order() - o2.order(); + if (delta != 0) return delta; + if (o1.getClass() == o2.getClass()) { + LOG.error("Duplicate visitors registered: "+o1 +" and "+o2 + " ("+o1.getClass()+")"); + } + return 0; } }; protected final EditorColorsScheme myGlobalScheme; From b9a02c8cfc4627faa66985b2b81be3624e9c23f4 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Mon, 6 Oct 2014 16:51:27 +0400 Subject: [PATCH 27/28] cleanup --- .../intention/impl/AddOverrideAnnotationAction.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddOverrideAnnotationAction.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddOverrideAnnotationAction.java index b9bd7cd8b019..f2609b2a4433 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddOverrideAnnotationAction.java +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddOverrideAnnotationAction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,7 +31,6 @@ import org.jetbrains.annotations.NotNull; * @author ven */ public class AddOverrideAnnotationAction implements IntentionAction { - private static final String JAVA_LANG_OVERRIDE = "java.lang.Override"; @Override @NotNull @@ -51,11 +50,11 @@ public class AddOverrideAnnotationAction implements IntentionAction { if (!file.getManager().isInProject(file)) return false; PsiMethod method = findMethod(file, editor.getCaretModel().getOffset()); if (method == null) return false; - if (method.getModifierList().findAnnotation(JAVA_LANG_OVERRIDE) != null) return false; + if (method.getModifierList().findAnnotation(CommonClassNames.JAVA_LANG_OVERRIDE) != null) return false; PsiMethod[] superMethods = method.findSuperMethods(); for (PsiMethod superMethod : superMethods) { if (!superMethod.hasModifierProperty(PsiModifier.ABSTRACT) - && new AddAnnotationFix(JAVA_LANG_OVERRIDE, method).isAvailable(project, editor, file)) { + && new AddAnnotationFix(CommonClassNames.JAVA_LANG_OVERRIDE, method).isAvailable(project, editor, file)) { return true; } } @@ -67,7 +66,7 @@ public class AddOverrideAnnotationAction implements IntentionAction { public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { PsiMethod method = findMethod(file, editor.getCaretModel().getOffset()); if (method != null) { - new AddAnnotationFix(JAVA_LANG_OVERRIDE, method).invoke(project, editor, file); + new AddAnnotationFix(CommonClassNames.JAVA_LANG_OVERRIDE, method).invoke(project, editor, file); } } From c02bf6506fffe5929025661a307719365c13009f Mon Sep 17 00:00:00 2001 From: "Svetlana.Zemlyanskay" Date: Mon, 6 Oct 2014 17:26:47 +0400 Subject: [PATCH 28/28] IDEA-95126 Arrangement: Provide ability to negate conditions --- .../arrangement/ArrangementUtil.java | 6 +- .../ByModifierArrangementEntryMatcher.java | 17 ++++-- .../match/ByTypeArrangementEntryMatcher.java | 19 ++++-- ...aultArrangementEntryMatcherSerializer.java | 23 ++++++- .../match/StdArrangementEntryMatcher.java | 25 ++++---- .../match/StdArrangementMatchRule.java | 24 +++++--- .../model/ArrangementAtomMatchCondition.java | 23 ++----- .../ArrangementStandardSettingsManager.java | 15 +++-- .../std/ArrangementUiComponent.java | 17 +++++- .../InvertibleArrangementSettingsToken.java | 33 ++++++++++ .../std/StdArrangementSettingsToken.java | 6 +- .../arrangement/std/StdArrangementTokens.java | 59 ++++++++++-------- ...StdInvertibleArrangementSettingsToken.java | 44 ++++++++++++++ .../AbstractArrangementUiComponent.java | 5 ++ ...ArrangementAndMatchConditionComponent.java | 16 ++++- ...rrangementAtomMatchConditionComponent.java | 60 +++++++++++++++++-- .../ArrangementCheckBoxUiComponent.java | 7 ++- .../ArrangementComboBoxUiComponent.java | 5 ++ .../ArrangementLabelUiComponent.java | 5 ++ .../ArrangementTextFieldUiComponent.java | 9 ++- .../match/ArrangementMatchingRuleEditor.java | 6 +- .../util/ArrangementListRowDecorator.java | 10 ++++ .../arrangement/AbstractRearrangerTest.java | 4 ++ 23 files changed, 338 insertions(+), 100 deletions(-) create mode 100644 platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/std/InvertibleArrangementSettingsToken.java create mode 100644 platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/std/StdInvertibleArrangementSettingsToken.java diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/ArrangementUtil.java b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/ArrangementUtil.java index 2bc92f71fe94..174db45b2f11 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/ArrangementUtil.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/ArrangementUtil.java @@ -205,7 +205,7 @@ public class ArrangementUtil { public void visit(@NotNull ArrangementAtomMatchCondition condition) { ArrangementSettingsToken type = condition.getType(); Object value = condition.getValue(); - result.put(condition.getType(), type.equals(value) ? null : value); + result.put(condition.getType(), type.equals(value) ? null : value); } @Override @@ -260,10 +260,10 @@ public class ArrangementUtil { @Nullable public static ArrangementEntryMatcher buildMatcher(@NotNull ArrangementAtomMatchCondition condition) { if (StdArrangementTokenType.ENTRY_TYPE.is(condition.getType())) { - return new ByTypeArrangementEntryMatcher(condition.getType()); + return new ByTypeArrangementEntryMatcher(condition); } else if (StdArrangementTokenType.MODIFIER.is(condition.getType())) { - return new ByModifierArrangementEntryMatcher(condition.getType()); + return new ByModifierArrangementEntryMatcher(condition); } else if (StdArrangementTokens.Regexp.NAME.equals(condition.getType())) { return new ByNameArrangementEntryMatcher(condition.getValue().toString()); diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/match/ByModifierArrangementEntryMatcher.java b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/match/ByModifierArrangementEntryMatcher.java index d972eb824fb1..ec58bffb9003 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/match/ByModifierArrangementEntryMatcher.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/match/ByModifierArrangementEntryMatcher.java @@ -17,6 +17,7 @@ package com.intellij.psi.codeStyle.arrangement.match; import com.intellij.psi.codeStyle.arrangement.ArrangementEntry; import com.intellij.psi.codeStyle.arrangement.ModifierAwareArrangementEntry; +import com.intellij.psi.codeStyle.arrangement.model.ArrangementAtomMatchCondition; import com.intellij.psi.codeStyle.arrangement.std.ArrangementSettingsToken; import com.intellij.util.containers.ContainerUtilRt; import org.jetbrains.annotations.NotNull; @@ -30,20 +31,28 @@ import java.util.Set; */ public class ByModifierArrangementEntryMatcher implements ArrangementEntryMatcher { - @NotNull private final Set myModifiers = ContainerUtilRt.newHashSet(); + @NotNull private final Set myModifiers = ContainerUtilRt.newHashSet(); - public ByModifierArrangementEntryMatcher(@NotNull ArrangementSettingsToken interestedModifier) { + public ByModifierArrangementEntryMatcher(@NotNull ArrangementAtomMatchCondition interestedModifier) { myModifiers.add(interestedModifier); } - public ByModifierArrangementEntryMatcher(@NotNull Collection interestedModifiers) { + public ByModifierArrangementEntryMatcher(@NotNull Collection interestedModifiers) { myModifiers.addAll(interestedModifiers); } @Override public boolean isMatched(@NotNull ArrangementEntry entry) { if (entry instanceof ModifierAwareArrangementEntry) { - return ((ModifierAwareArrangementEntry)entry).getModifiers().containsAll(myModifiers); + final Set modifiers = ((ModifierAwareArrangementEntry)entry).getModifiers(); + for (ArrangementAtomMatchCondition condition : myModifiers) { + final Object value = condition.getValue(); + boolean isInverted = value instanceof Boolean && !((Boolean)value); + if (isInverted == modifiers.contains(condition.getType())) { + return false; + } + } + return true; } return false; } diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/match/ByTypeArrangementEntryMatcher.java b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/match/ByTypeArrangementEntryMatcher.java index 14a429fbc80a..b994490fb60a 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/match/ByTypeArrangementEntryMatcher.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/match/ByTypeArrangementEntryMatcher.java @@ -17,6 +17,7 @@ package com.intellij.psi.codeStyle.arrangement.match; import com.intellij.psi.codeStyle.arrangement.ArrangementEntry; import com.intellij.psi.codeStyle.arrangement.TypeAwareArrangementEntry; +import com.intellij.psi.codeStyle.arrangement.model.ArrangementAtomMatchCondition; import com.intellij.psi.codeStyle.arrangement.std.ArrangementSettingsToken; import com.intellij.util.containers.ContainerUtilRt; import org.jetbrains.annotations.NotNull; @@ -36,26 +37,34 @@ import java.util.Set; */ public class ByTypeArrangementEntryMatcher implements ArrangementEntryMatcher { - @NotNull private final Set myTypes = ContainerUtilRt.newHashSet(); + @NotNull private final Set myTypes = ContainerUtilRt.newHashSet(); - public ByTypeArrangementEntryMatcher(@NotNull ArrangementSettingsToken interestedType) { + public ByTypeArrangementEntryMatcher(@NotNull ArrangementAtomMatchCondition interestedType) { myTypes.add(interestedType); } - public ByTypeArrangementEntryMatcher(@NotNull Collection interestedTypes) { + public ByTypeArrangementEntryMatcher(@NotNull Collection interestedTypes) { myTypes.addAll(interestedTypes); } @Override public boolean isMatched(@NotNull ArrangementEntry entry) { if (entry instanceof TypeAwareArrangementEntry) { - return ((TypeAwareArrangementEntry)entry).getTypes().containsAll(myTypes); + final Set types = ((TypeAwareArrangementEntry)entry).getTypes(); + for (ArrangementAtomMatchCondition condition : myTypes) { + final Object value = condition.getValue(); + boolean isInverted = value instanceof Boolean && !((Boolean)value); + if (isInverted == types.contains(condition.getType())) { + return false; + } + } + return true; } return false; } @NotNull - public Set getTypes() { + public Set getTypes() { return myTypes; } diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/match/DefaultArrangementEntryMatcherSerializer.java b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/match/DefaultArrangementEntryMatcherSerializer.java index b99f2aa45057..2584ec148ef1 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/match/DefaultArrangementEntryMatcherSerializer.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/match/DefaultArrangementEntryMatcherSerializer.java @@ -150,12 +150,30 @@ public class DefaultArrangementEntryMatcherSerializer { if (text != null && processInnerText) { text = StringUtil.unescapeStringCharacters(matcherElement.getText()); if (!StringUtil.isEmpty(text)) { - value = text; + final Boolean booleanValue = parseBooleanValue(text); + if (booleanValue != null) { + value = booleanValue; + } + else { + value = text; + } } } return new ArrangementAtomMatchCondition(token, value); } + @Nullable + private static Boolean parseBooleanValue(@NotNull String text) { + if (StringUtil.equalsIgnoreCase(text, Boolean.TRUE.toString())) { + return true; + } + + if (StringUtil.equalsIgnoreCase(text, Boolean.FALSE.toString())) { + return false; + } + return null; + } + private static class MySerializationVisitor implements ArrangementMatchConditionVisitor { Element result; @@ -168,6 +186,9 @@ public class DefaultArrangementEntryMatcherSerializer { if (StdArrangementTokenType.REG_EXP.is(type)) { element.setText(StringUtil.escapeStringCharacters(condition.getValue().toString())); } + else if (condition.getValue() instanceof Boolean) { + element.setText(condition.getValue().toString()); + } register(element); } diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/match/StdArrangementEntryMatcher.java b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/match/StdArrangementEntryMatcher.java index 3225405b94cb..9d4819677803 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/match/StdArrangementEntryMatcher.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/match/StdArrangementEntryMatcher.java @@ -18,10 +18,7 @@ package com.intellij.psi.codeStyle.arrangement.match; import com.intellij.openapi.util.MultiValuesMap; import com.intellij.psi.codeStyle.arrangement.ArrangementEntry; import com.intellij.psi.codeStyle.arrangement.model.*; -import com.intellij.psi.codeStyle.arrangement.std.ArrangementSettingsToken; -import com.intellij.psi.codeStyle.arrangement.std.StdArrangementSettingsToken; -import com.intellij.psi.codeStyle.arrangement.std.StdArrangementTokenType; -import com.intellij.psi.codeStyle.arrangement.std.StdArrangementTokens; +import com.intellij.psi.codeStyle.arrangement.std.*; import com.intellij.util.containers.ContainerUtilRt; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -129,8 +126,8 @@ public class StdArrangementEntryMatcher implements ArrangementEntryMatcher { * Maps token type to all arrangement tokens that were encountered so far by parsing conditions with * {@link #onCondition(ArrangementAtomMatchCondition) onCondition} calls. */ - @NotNull protected final MultiValuesMap context = - new MultiValuesMap(); + @NotNull protected final MultiValuesMap context = + new MultiValuesMap(); @Nullable private String myNamePattern; @Nullable private String myNamespacePattern; @Nullable private String myText; @@ -139,9 +136,9 @@ public class StdArrangementEntryMatcher implements ArrangementEntryMatcher { * Adds given entry to context by given entry type. * @param token token added to context */ - protected void addToContext(@NotNull StdArrangementSettingsToken token) { + protected void addToContext(@NotNull StdArrangementSettingsToken token, @NotNull ArrangementAtomMatchCondition condition) { StdArrangementTokenType tokenType = token.getTokenType(); - context.put(tokenType, token); + context.put(tokenType, condition); } @Override @@ -157,10 +154,10 @@ public class StdArrangementEntryMatcher implements ArrangementEntryMatcher { myText = condition.getValue().toString(); } Object v = condition.getValue(); - //Process any StdArrangementSettingsToken. No need to change it when new types of tokens will be processed. - if (v instanceof StdArrangementSettingsToken) { - StdArrangementSettingsToken token = (StdArrangementSettingsToken)v; - addToContext(token); + final ArrangementSettingsToken type = condition.getType(); + if (type instanceof StdArrangementSettingsToken) { + //Process any StdArrangementSettingsToken. No need to change it when new types of tokens will be processed. + addToContext((StdArrangementSettingsToken)type, condition); } } @@ -168,11 +165,11 @@ public class StdArrangementEntryMatcher implements ArrangementEntryMatcher { @Override public Collection buildMatchers() { List result = ContainerUtilRt.newArrayList(myMatchers); - Collection entryTokens = context.get(StdArrangementTokenType.ENTRY_TYPE); + Collection entryTokens = context.get(StdArrangementTokenType.ENTRY_TYPE); if (entryTokens!= null) { result.add(new ByTypeArrangementEntryMatcher(entryTokens)); } - Collection modifierTokens = context.get(StdArrangementTokenType.MODIFIER); + Collection modifierTokens = context.get(StdArrangementTokenType.MODIFIER); if (modifierTokens != null) { result.add(new ByModifierArrangementEntryMatcher(modifierTokens)); } diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/match/StdArrangementMatchRule.java b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/match/StdArrangementMatchRule.java index 220f143010cc..26eb9d65ba63 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/match/StdArrangementMatchRule.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/match/StdArrangementMatchRule.java @@ -22,6 +22,7 @@ import com.intellij.psi.codeStyle.arrangement.std.StdArrangementTokenType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Map; import java.util.Set; /** @@ -55,8 +56,10 @@ public class StdArrangementMatchRule extends ArrangementMatchRule implements Clo @Override public int compareTo(@NotNull StdArrangementMatchRule o) { - final Set tokens = ArrangementUtil.extractTokens(getMatcher().getCondition()).keySet(); - final Set tokens1 = ArrangementUtil.extractTokens(o.getMatcher().getCondition()).keySet(); + final Map tokenValues = ArrangementUtil.extractTokens(getMatcher().getCondition()); + final Map tokenValues1 = ArrangementUtil.extractTokens(o.getMatcher().getCondition()); + final Set tokens = tokenValues.keySet(); + final Set tokens1 = tokenValues1.keySet(); if (tokens1.containsAll(tokens)) { return tokens.containsAll(tokens1) ? 0 : 1; } @@ -65,9 +68,9 @@ public class StdArrangementMatchRule extends ArrangementMatchRule implements Clo return -1; } - final String entryType = getEntryType(tokens); - final String entryType1 = getEntryType(tokens1); - final int compare = StringUtil.compare(entryType, entryType1, false); + final String entryType = getEntryType(tokenValues); + final String entryType1 = getEntryType(tokenValues1); + final int compare = StringUtil.compare(entryType1, entryType, false); if (compare != 0 || tokens.size() == tokens1.size()) { return compare; } @@ -76,10 +79,13 @@ public class StdArrangementMatchRule extends ArrangementMatchRule implements Clo } @Nullable - private static String getEntryType(@NotNull Set tokens) { - for (ArrangementSettingsToken token : tokens) { - if (StdArrangementTokenType.ENTRY_TYPE.is(token)) { - return token.getId(); + private static String getEntryType(@NotNull Map tokens) { + for (Map.Entry token : tokens.entrySet()) { + if (StdArrangementTokenType.ENTRY_TYPE.is(token.getKey())) { + final Object value = token.getValue(); + if (!(value instanceof Boolean) || (Boolean)value) { + return token.getKey().getId(); + } } } return null; diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/model/ArrangementAtomMatchCondition.java b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/model/ArrangementAtomMatchCondition.java index 31673d17586e..64f7ead73931 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/model/ArrangementAtomMatchCondition.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/model/ArrangementAtomMatchCondition.java @@ -16,6 +16,7 @@ package com.intellij.psi.codeStyle.arrangement.model; import com.intellij.psi.codeStyle.arrangement.std.ArrangementSettingsToken; +import com.intellij.psi.codeStyle.arrangement.std.InvertibleArrangementSettingsToken; import org.jetbrains.annotations.NotNull; /** @@ -31,10 +32,8 @@ public class ArrangementAtomMatchCondition implements ArrangementMatchCondition @NotNull private final ArrangementSettingsToken myType; @NotNull private final Object myValue; - private boolean myInverted; - public ArrangementAtomMatchCondition(@NotNull ArrangementSettingsToken type) { - this(type, type); + this(type, type instanceof InvertibleArrangementSettingsToken ? Boolean.TRUE : type); } public ArrangementAtomMatchCondition(@NotNull ArrangementSettingsToken type, @NotNull Object value) { @@ -57,15 +56,10 @@ public class ArrangementAtomMatchCondition implements ArrangementMatchCondition visitor.visit(this); } - public void setInverted(boolean inverted) { - myInverted = inverted; - } - @Override public int hashCode() { int result = myType.hashCode(); result = 31 * result + myValue.hashCode(); - result = 31 * result + (myInverted ? 1 : 0); return result; } @@ -80,9 +74,6 @@ public class ArrangementAtomMatchCondition implements ArrangementMatchCondition ArrangementAtomMatchCondition setting = (ArrangementAtomMatchCondition)o; - if (myInverted != setting.myInverted) { - return false; - } if (!myType.equals(setting.myType)) { return false; } @@ -96,18 +87,16 @@ public class ArrangementAtomMatchCondition implements ArrangementMatchCondition @NotNull @Override public ArrangementAtomMatchCondition clone() { - ArrangementAtomMatchCondition result = new ArrangementAtomMatchCondition(myType, myValue); - result.setInverted(myInverted); - return result; + return new ArrangementAtomMatchCondition(myType, myValue); } @Override public String toString() { - if (myType.equals(myValue)) { - return String.format("%s%s", myInverted ? "not " : "", myType.getRepresentationValue()); + if (myValue instanceof Boolean) { + return String.format("%s%s", (Boolean)myValue ? "" : "not " , myType.getRepresentationValue()); } else { - return String.format("%s: %s%s", myType.getRepresentationValue(), myInverted ? "not " : "", myValue.toString().toLowerCase()); + return String.format("%s: %s", myType.getRepresentationValue(), myValue.toString().toLowerCase()); } } } diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/std/ArrangementStandardSettingsManager.java b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/std/ArrangementStandardSettingsManager.java index 55883c0d3b4b..5b3ccac7d3c8 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/std/ArrangementStandardSettingsManager.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/std/ArrangementStandardSettingsManager.java @@ -164,15 +164,22 @@ public class ArrangementStandardSettingsManager { private int parseWidth(@NotNull ArrangementSettingsToken token, @NotNull SimpleColoredComponent renderer) { renderer.clear(); - renderer.append(token.getRepresentationValue(), - SimpleTextAttributes.fromTextAttributes(myColorsProvider.getTextAttributes(token, true))); + final String value = getPresentationValue(token); + renderer.append(value, SimpleTextAttributes.fromTextAttributes(myColorsProvider.getTextAttributes(token, true))); int result = renderer.getPreferredSize().width; renderer.clear(); - renderer.append(token.getRepresentationValue(), - SimpleTextAttributes.fromTextAttributes(myColorsProvider.getTextAttributes(token, false))); + renderer.append(value, SimpleTextAttributes.fromTextAttributes(myColorsProvider.getTextAttributes(token, false))); return Math.max(result, renderer.getPreferredSize().width); } + + @NotNull + private static String getPresentationValue(@NotNull ArrangementSettingsToken token) { + if (token instanceof InvertibleArrangementSettingsToken) { + return ((InvertibleArrangementSettingsToken)token).getInvertedRepresentationValue(); + } + return token.getRepresentationValue(); + } public List sort(@NotNull Collection tokens) { List result = ContainerUtilRt.newArrayList(tokens); diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/std/ArrangementUiComponent.java b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/std/ArrangementUiComponent.java index b752647c12d8..e76818e3cf48 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/std/ArrangementUiComponent.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/std/ArrangementUiComponent.java @@ -36,7 +36,7 @@ import java.util.Set; * @since 3/11/13 10:22 AM */ public interface ArrangementUiComponent { - + @Nullable ArrangementSettingsToken getToken(); @NotNull Set getAvailableTokens(); @@ -107,7 +107,20 @@ public interface ArrangementUiComponent { int getBaselineToUse(int width, int height); void setListener(@NotNull Listener listener); - + + /** + * Method to process second click on the component, + * e.g. we can deselect the component or invert it condition + */ + void handleMouseClickOnSelected(); + + /** + * For condition that can't be disabled, + * e.g. 'not public' can be used with any other rule like 'private' or 'not private' + * @return + */ + boolean alwaysCanBeActive(); + interface Factory { ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.rearranger.ui"); diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/std/InvertibleArrangementSettingsToken.java b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/std/InvertibleArrangementSettingsToken.java new file mode 100644 index 000000000000..0298ab9184b2 --- /dev/null +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/std/InvertibleArrangementSettingsToken.java @@ -0,0 +1,33 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.psi.codeStyle.arrangement.std; + +import org.jetbrains.annotations.NotNull; + +/** + * Tokens that can be used in conditions in inverted state, + * e.g. 'public' -> 'not public' unlike 'order' or 'name' that can't be inverted + * + * @author Svetlana.Zemlyanskaya + */ +public interface InvertibleArrangementSettingsToken { + + /** + * Inverted representation value that will be used in UI + */ + @NotNull + String getInvertedRepresentationValue(); +} diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/std/StdArrangementSettingsToken.java b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/std/StdArrangementSettingsToken.java index d6503f56e6f3..2ddbf02c9aec 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/std/StdArrangementSettingsToken.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/std/StdArrangementSettingsToken.java @@ -52,9 +52,9 @@ public class StdArrangementSettingsToken extends ArrangementSettingsToken { return myTokenType; } - private StdArrangementSettingsToken(@NotNull String id, - @NotNull String uiName, - @NotNull StdArrangementTokenType tokenType) { + protected StdArrangementSettingsToken(@NotNull String id, + @NotNull String uiName, + @NotNull StdArrangementTokenType tokenType) { super(id, uiName); myTokenType = tokenType; } diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/std/StdArrangementTokens.java b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/std/StdArrangementTokens.java index 61ebcdb97ace..15770aded615 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/std/StdArrangementTokens.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/std/StdArrangementTokens.java @@ -87,6 +87,12 @@ public class StdArrangementTokens { }; } + private static StdArrangementSettingsToken invertible(@NotNull String id, @NotNull StdArrangementTokenType type) { + StdArrangementSettingsToken result = StdInvertibleArrangementSettingsToken.invertibleTokenById(id, type); + TOKENS_BY_ID.put(id, result); + return result; + } + private static StdArrangementSettingsToken token(@NotNull String id, @NotNull StdArrangementTokenType type) { StdArrangementSettingsToken result = StdArrangementSettingsToken.tokenById(id, type); TOKENS_BY_ID.put(id, result); @@ -132,20 +138,23 @@ public class StdArrangementTokens { } } public static class EntryType { - @NotNull public static final ArrangementSettingsToken CLASS = token("CLASS", StdArrangementTokenType.ENTRY_TYPE); - @NotNull public static final ArrangementSettingsToken ANONYMOUS_CLASS = token("ANONYMOUS_CLASS", StdArrangementTokenType.ENTRY_TYPE); - @NotNull public static final ArrangementSettingsToken FIELD = token("FIELD", StdArrangementTokenType.ENTRY_TYPE); - @NotNull public static final ArrangementSettingsToken CONSTRUCTOR = token("CONSTRUCTOR", StdArrangementTokenType.ENTRY_TYPE); - @NotNull public static final ArrangementSettingsToken METHOD = token("METHOD", StdArrangementTokenType.ENTRY_TYPE); - @NotNull public static final ArrangementSettingsToken ENUM = token("ENUM", StdArrangementTokenType.ENTRY_TYPE); - @NotNull public static final ArrangementSettingsToken INTERFACE = token("INTERFACE", StdArrangementTokenType.ENTRY_TYPE); - @NotNull public static final ArrangementSettingsToken CONST = token("CONST", StdArrangementTokenType.ENTRY_TYPE); - @NotNull public static final ArrangementSettingsToken VAR = token("VAR", StdArrangementTokenType.ENTRY_TYPE); - @NotNull public static final ArrangementSettingsToken PROPERTY = token("PROPERTY", StdArrangementTokenType.ENTRY_TYPE); - @NotNull public static final ArrangementSettingsToken EVENT_HANDLER = token("EVENT_HANDLER", StdArrangementTokenType.ENTRY_TYPE); - @NotNull public static final ArrangementSettingsToken STATIC_INIT = token("STATIC_INIT", StdArrangementTokenType.ENTRY_TYPE); - @NotNull public static final ArrangementSettingsToken NAMESPACE = token("NAMESPACE", StdArrangementTokenType.ENTRY_TYPE); - @NotNull public static final ArrangementSettingsToken TRAIT = token("TRAIT", StdArrangementTokenType.ENTRY_TYPE); + @NotNull public static final ArrangementSettingsToken CLASS = invertible("CLASS", StdArrangementTokenType.ENTRY_TYPE); + @NotNull public static final ArrangementSettingsToken ANONYMOUS_CLASS = invertible("ANONYMOUS_CLASS", + StdArrangementTokenType.ENTRY_TYPE); + @NotNull public static final ArrangementSettingsToken FIELD = invertible("FIELD", StdArrangementTokenType.ENTRY_TYPE); + @NotNull public static final ArrangementSettingsToken CONSTRUCTOR = invertible("CONSTRUCTOR", StdArrangementTokenType.ENTRY_TYPE); + @NotNull public static final ArrangementSettingsToken METHOD = invertible("METHOD", StdArrangementTokenType.ENTRY_TYPE); + @NotNull public static final ArrangementSettingsToken ENUM = invertible("ENUM", StdArrangementTokenType.ENTRY_TYPE); + @NotNull public static final ArrangementSettingsToken INTERFACE = invertible("INTERFACE", StdArrangementTokenType.ENTRY_TYPE); + @NotNull public static final ArrangementSettingsToken CONST = invertible("CONST", StdArrangementTokenType.ENTRY_TYPE); + @NotNull public static final ArrangementSettingsToken VAR = invertible("VAR", StdArrangementTokenType.ENTRY_TYPE); + @NotNull public static final ArrangementSettingsToken PROPERTY = invertible("PROPERTY", StdArrangementTokenType.ENTRY_TYPE); + @NotNull public static final ArrangementSettingsToken EVENT_HANDLER = invertible("EVENT_HANDLER", StdArrangementTokenType.ENTRY_TYPE); + @NotNull public static final ArrangementSettingsToken STATIC_INIT = invertible("STATIC_INIT", StdArrangementTokenType.ENTRY_TYPE); + @NotNull public static final ArrangementSettingsToken NAMESPACE = invertible("NAMESPACE", StdArrangementTokenType.ENTRY_TYPE); + @NotNull public static final ArrangementSettingsToken TRAIT = invertible("TRAIT", StdArrangementTokenType.ENTRY_TYPE); + + // xml use only two entry types -> invertible tokens make no sense @NotNull public static final ArrangementSettingsToken XML_TAG = token("XML_TAG", "arrangement.settings.text.entry.type.xml.tag", StdArrangementTokenType.ENTRY_TYPE); @NotNull public static final StdArrangementSettingsToken XML_ATTRIBUTE = @@ -162,17 +171,17 @@ public class StdArrangementTokens { } } public static class Modifier { - @NotNull public static final ArrangementSettingsToken PUBLIC = token("PUBLIC", StdArrangementTokenType.MODIFIER); - @NotNull public static final ArrangementSettingsToken PROTECTED = token("PROTECTED", StdArrangementTokenType.MODIFIER); - @NotNull public static final ArrangementSettingsToken PRIVATE = token("PRIVATE", StdArrangementTokenType.MODIFIER); - @NotNull public static final ArrangementSettingsToken PACKAGE_PRIVATE = token("PACKAGE_PRIVATE", StdArrangementTokenType.MODIFIER); - @NotNull public static final ArrangementSettingsToken STATIC = token("STATIC", StdArrangementTokenType.MODIFIER); - @NotNull public static final ArrangementSettingsToken FINAL = token("FINAL", StdArrangementTokenType.MODIFIER); - @NotNull public static final ArrangementSettingsToken TRANSIENT = token("TRANSIENT", StdArrangementTokenType.MODIFIER); - @NotNull public static final ArrangementSettingsToken VOLATILE = token("VOLATILE", StdArrangementTokenType.MODIFIER); - @NotNull public static final ArrangementSettingsToken SYNCHRONIZED = token("SYNCHRONIZED", StdArrangementTokenType.MODIFIER); - @NotNull public static final ArrangementSettingsToken ABSTRACT = token("ABSTRACT", StdArrangementTokenType.MODIFIER); - @NotNull public static final ArrangementSettingsToken OVERRIDE = token("OVERRIDE", StdArrangementTokenType.MODIFIER); + @NotNull public static final ArrangementSettingsToken PUBLIC = invertible("PUBLIC", StdArrangementTokenType.MODIFIER); + @NotNull public static final ArrangementSettingsToken PROTECTED = invertible("PROTECTED", StdArrangementTokenType.MODIFIER); + @NotNull public static final ArrangementSettingsToken PRIVATE = invertible("PRIVATE", StdArrangementTokenType.MODIFIER); + @NotNull public static final ArrangementSettingsToken PACKAGE_PRIVATE = invertible("PACKAGE_PRIVATE", StdArrangementTokenType.MODIFIER); + @NotNull public static final ArrangementSettingsToken STATIC = invertible("STATIC", StdArrangementTokenType.MODIFIER); + @NotNull public static final ArrangementSettingsToken FINAL = invertible("FINAL", StdArrangementTokenType.MODIFIER); + @NotNull public static final ArrangementSettingsToken TRANSIENT = invertible("TRANSIENT", StdArrangementTokenType.MODIFIER); + @NotNull public static final ArrangementSettingsToken VOLATILE = invertible("VOLATILE", StdArrangementTokenType.MODIFIER); + @NotNull public static final ArrangementSettingsToken SYNCHRONIZED = invertible("SYNCHRONIZED", StdArrangementTokenType.MODIFIER); + @NotNull public static final ArrangementSettingsToken ABSTRACT = invertible("ABSTRACT", StdArrangementTokenType.MODIFIER); + @NotNull public static final ArrangementSettingsToken OVERRIDE = invertible("OVERRIDE", StdArrangementTokenType.MODIFIER); private static final NotNullLazyValue> TOKENS = collectFields(Modifier.class); private Modifier() { diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/std/StdInvertibleArrangementSettingsToken.java b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/std/StdInvertibleArrangementSettingsToken.java new file mode 100644 index 000000000000..3a1fbab38851 --- /dev/null +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/std/StdInvertibleArrangementSettingsToken.java @@ -0,0 +1,44 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.psi.codeStyle.arrangement.std; + +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; + +/** + * @author Svetlana.Zemlyanskaya + */ +public class StdInvertibleArrangementSettingsToken extends StdArrangementSettingsToken implements InvertibleArrangementSettingsToken { + private static final String NOT = "not "; + + private StdInvertibleArrangementSettingsToken(@NotNull String id, + @NotNull String uiName, + @NotNull StdArrangementTokenType tokenType) { + super(id, uiName, tokenType); + } + + @NotNull + public static StdInvertibleArrangementSettingsToken invertibleTokenById(@NonNls @NotNull String id, + @NotNull StdArrangementTokenType tokenType) { + return new StdInvertibleArrangementSettingsToken(id, id.toLowerCase().replace("_", " "), tokenType); + } + + @NotNull + @Override + public String getInvertedRepresentationValue() { + return NOT + getRepresentationValue(); + } +} diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/component/AbstractArrangementUiComponent.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/component/AbstractArrangementUiComponent.java index ca508a8f86df..094e6c53e04a 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/component/AbstractArrangementUiComponent.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/component/AbstractArrangementUiComponent.java @@ -175,4 +175,9 @@ public abstract class AbstractArrangementUiComponent implements ArrangementUiCom } protected abstract void doReset(); + + @Override + public boolean alwaysCanBeActive() { + return false; + } } diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/component/ArrangementAndMatchConditionComponent.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/component/ArrangementAndMatchConditionComponent.java index 44b640dbea08..137519fc2742 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/component/ArrangementAndMatchConditionComponent.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/component/ArrangementAndMatchConditionComponent.java @@ -16,7 +16,7 @@ package com.intellij.application.options.codeStyle.arrangement.component; import com.intellij.application.options.codeStyle.arrangement.ArrangementConstants; -import com.intellij.psi.codeStyle.arrangement.std.ArrangementStandardSettingsManager; +import com.intellij.psi.codeStyle.arrangement.std.*; import com.intellij.application.options.codeStyle.arrangement.match.ArrangementMatchNodeComponentFactory; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.codeStyle.arrangement.match.StdArrangementMatchRule; @@ -24,8 +24,6 @@ import com.intellij.psi.codeStyle.arrangement.model.ArrangementAtomMatchConditio import com.intellij.psi.codeStyle.arrangement.model.ArrangementCompositeMatchCondition; import com.intellij.psi.codeStyle.arrangement.model.ArrangementMatchCondition; import com.intellij.psi.codeStyle.arrangement.model.ArrangementMatchConditionVisitor; -import com.intellij.psi.codeStyle.arrangement.std.ArrangementSettingsToken; -import com.intellij.psi.codeStyle.arrangement.std.ArrangementUiComponent; import com.intellij.util.containers.ContainerUtilRt; import com.intellij.util.ui.GridBag; import com.intellij.util.ui.UIUtil; @@ -265,6 +263,18 @@ public class ArrangementAndMatchConditionComponent extends JPanel implements Arr } } + @Override + public void handleMouseClickOnSelected() { + for (ArrangementUiComponent component : myComponents) { + component.handleMouseClickOnSelected(); + } + } + + @Override + public boolean alwaysCanBeActive() { + return false; + } + @Override public String toString() { return String.format("(%s)", StringUtil.join(myComponents, " and ")); diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/component/ArrangementAtomMatchConditionComponent.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/component/ArrangementAtomMatchConditionComponent.java index f863088fc07b..d77225868c70 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/component/ArrangementAtomMatchConditionComponent.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/component/ArrangementAtomMatchConditionComponent.java @@ -22,6 +22,7 @@ import com.intellij.application.options.codeStyle.arrangement.color.ArrangementC import com.intellij.application.options.codeStyle.arrangement.util.InsetsPanel; import com.intellij.openapi.actionSystem.impl.ActionButton; import com.intellij.openapi.editor.markup.TextAttributes; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.codeStyle.arrangement.model.ArrangementAtomMatchCondition; import com.intellij.psi.codeStyle.arrangement.std.*; import com.intellij.ui.IdeBorderFactory; @@ -97,10 +98,15 @@ public class ArrangementAtomMatchConditionComponent implements ArrangementUiComp @Nullable private Rectangle myScreenBounds; @Nullable private Listener myListener; + private boolean myInverted = false; private boolean myEnabled = true; private boolean mySelected; private boolean myCloseButtonHovered; + // cached value for inverted atom condition, e.g. condition: 'static', opposite: 'not static' + @Nullable private ArrangementAtomMatchCondition myOppositeCondition; + @Nullable private String myInvertedText; + public ArrangementAtomMatchConditionComponent(@NotNull ArrangementStandardSettingsManager manager, @NotNull ArrangementColorsProvider colorsProvider, @NotNull ArrangementAtomMatchCondition condition, @@ -117,7 +123,7 @@ public class ArrangementAtomMatchConditionComponent implements ArrangementUiComp else { myBorderStrategy = PREDEFINED_BORDER_STRATEGY; } - if (type.equals(condition.getValue())) { + if (type.equals(condition.getValue()) || condition.getValue() instanceof Boolean) { myText = type.getRepresentationValue(); } else if (StdArrangementTokenType.REG_EXP.is(type)) { @@ -225,17 +231,27 @@ public class ArrangementAtomMatchConditionComponent implements ArrangementUiComp if (myCloseButton != null) { myCloseButton.setVisible(false); } + setData(myCondition.getValue()); } @NotNull @Override public ArrangementAtomMatchCondition getMatchCondition() { + if (myInverted == myCondition.getValue()) { + if (myOppositeCondition == null) { + myOppositeCondition = new ArrangementAtomMatchCondition(myCondition.getType(), !myInverted); + } + return myOppositeCondition; + } return myCondition; } @Override public void setData(@NotNull Object data) { - // Do nothing + if (data instanceof Boolean && myCondition.getType() instanceof InvertibleArrangementSettingsToken) { + myInverted = !((Boolean)data); + updateComponentText(mySelected); + } } @NotNull @@ -259,9 +275,7 @@ public class ArrangementAtomMatchConditionComponent implements ArrangementUiComp public void setSelected(boolean selected) { boolean notifyListener = selected != mySelected; mySelected = selected; - myTextControl.clear(); - TextAttributes attributes = myColorsProvider.getTextAttributes(myCondition.getType(), selected); - myTextControl.append(myText, SimpleTextAttributes.fromTextAttributes(attributes)); + TextAttributes attributes = updateComponentText(selected); myBorder.setColor(myColorsProvider.getBorderColor(selected)); myBackgroundColor = attributes.getBackgroundColor(); if (notifyListener && myListener != null) { @@ -269,6 +283,26 @@ public class ArrangementAtomMatchConditionComponent implements ArrangementUiComp } } + @NotNull + private TextAttributes updateComponentText(boolean selected) { + myTextControl.clear(); + TextAttributes attributes = myColorsProvider.getTextAttributes(myCondition.getType(), selected); + myTextControl.append(getComponentText(), SimpleTextAttributes.fromTextAttributes(attributes)); + return attributes; + } + + private String getComponentText() { + if (myInverted) { + if (StringUtil.isEmpty(myInvertedText)) { + final ArrangementSettingsToken token = myCondition.getType(); + assert token instanceof InvertibleArrangementSettingsToken; + myInvertedText = ((InvertibleArrangementSettingsToken)token).getInvertedRepresentationValue(); + } + return myInvertedText; + } + return myText; + } + @Override public boolean isEnabled() { return myEnabled; @@ -349,7 +383,7 @@ public class ArrangementAtomMatchConditionComponent implements ArrangementUiComp @Override public String toString() { - return myText; + return getComponentText(); } @NotNull @@ -377,6 +411,7 @@ public class ArrangementAtomMatchConditionComponent implements ArrangementUiComp @Override public void reset() { setSelected(false); + setData(true); } @Override @@ -390,6 +425,19 @@ public class ArrangementAtomMatchConditionComponent implements ArrangementUiComp myListener = listener; } + @Override + public void handleMouseClickOnSelected() { + if (myInverted) { + setSelected(false); + } + setData(myInverted); + } + + @Override + public boolean alwaysCanBeActive() { + return myInverted; + } + private interface BorderStrategy { RoundedLineBorder create(); void setup(@NotNull Graphics2D g); diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/component/ArrangementCheckBoxUiComponent.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/component/ArrangementCheckBoxUiComponent.java index 214b036ce845..053585c7c854 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/component/ArrangementCheckBoxUiComponent.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/component/ArrangementCheckBoxUiComponent.java @@ -115,11 +115,16 @@ public class ArrangementCheckBoxUiComponent extends AbstractArrangementUiCompone @Override public void setSelected(boolean selected) { - myCheckBox.setSelected(selected); + myCheckBox.setSelected(selected); } @Override public int getBaselineToUse(int width, int height) { return myTextLabel.getBaseline(width, height); } + + @Override + public void handleMouseClickOnSelected() { + setSelected(false); + } } diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/component/ArrangementComboBoxUiComponent.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/component/ArrangementComboBoxUiComponent.java index cad3fc88ca22..9cfce2abc0ab 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/component/ArrangementComboBoxUiComponent.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/component/ArrangementComboBoxUiComponent.java @@ -123,4 +123,9 @@ public class ArrangementComboBoxUiComponent extends AbstractArrangementUiCompone public int getBaselineToUse(int width, int height) { return -1; } + + @Override + public void handleMouseClickOnSelected() { + setSelected(false); + } } diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/component/ArrangementLabelUiComponent.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/component/ArrangementLabelUiComponent.java index 9d89b728e40d..bdb7503f53c1 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/component/ArrangementLabelUiComponent.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/component/ArrangementLabelUiComponent.java @@ -85,4 +85,9 @@ public class ArrangementLabelUiComponent extends AbstractArrangementUiComponent public int getBaselineToUse(int width, int height) { return myLabel.getBaseline(width, height); } + + @Override + public void handleMouseClickOnSelected() { + setSelected(false); + } } diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/component/ArrangementTextFieldUiComponent.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/component/ArrangementTextFieldUiComponent.java index dae8d6ba8a88..0e93b8a97ba1 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/component/ArrangementTextFieldUiComponent.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/component/ArrangementTextFieldUiComponent.java @@ -114,7 +114,9 @@ public class ArrangementTextFieldUiComponent extends AbstractArrangementUiCompon @Override public void setData(@NotNull Object data) { - myTextField.setText(data.toString()); + if (data instanceof String) { + myTextField.setText(data.toString()); + } } @Override @@ -126,4 +128,9 @@ public class ArrangementTextFieldUiComponent extends AbstractArrangementUiCompon public int getBaselineToUse(int width, int height) { return myTextField.getBaseline(width, height); } + + @Override + public void handleMouseClickOnSelected() { + setSelected(false); + } } diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/match/ArrangementMatchingRuleEditor.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/match/ArrangementMatchingRuleEditor.java index 4f2ed17842e2..0c51dd5fc0ea 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/match/ArrangementMatchingRuleEditor.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/match/ArrangementMatchingRuleEditor.java @@ -378,7 +378,8 @@ public class ArrangementMatchingRuleEditor extends JPanel implements Arrangement // don't allow to remove start/end section indication final Set mutexes = ArrangementSectionRuleManager.getSectionMutexes(); if (!mutexes.contains(component.getToken())) { - removeCondition(component); + component.handleMouseClickOnSelected(); + refreshConditions(); } } else { @@ -417,7 +418,7 @@ public class ArrangementMatchingRuleEditor extends JPanel implements Arrangement continue; } ArrangementUiComponent c = myComponents.get(key); - if (c != null && c.isEnabled()) { + if (c != null && c.isEnabled() && !c.alwaysCanBeActive()) { removeCondition(c); } } @@ -425,6 +426,7 @@ public class ArrangementMatchingRuleEditor extends JPanel implements Arrangement private void removeCondition(@NotNull ArrangementUiComponent component) { component.setSelected(false); + component.setData(true); refreshConditions(); } diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/util/ArrangementListRowDecorator.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/util/ArrangementListRowDecorator.java index 5bbba9eb8a7c..897c9cd22fd3 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/util/ArrangementListRowDecorator.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/util/ArrangementListRowDecorator.java @@ -280,6 +280,16 @@ public class ArrangementListRowDecorator extends JPanel implements ArrangementUi myDelegate.setListener(listener); } + @Override + public void handleMouseClickOnSelected() { + myDelegate.handleMouseClickOnSelected(); + } + + @Override + public boolean alwaysCanBeActive() { + return false; + } + @Override public String toString() { return "list row decorator for " + myDelegate.toString(); diff --git a/platform/testFramework/testSrc/com/intellij/psi/codeStyle/arrangement/AbstractRearrangerTest.java b/platform/testFramework/testSrc/com/intellij/psi/codeStyle/arrangement/AbstractRearrangerTest.java index 92c2723ce3b5..b503f5cf1e59 100644 --- a/platform/testFramework/testSrc/com/intellij/psi/codeStyle/arrangement/AbstractRearrangerTest.java +++ b/platform/testFramework/testSrc/com/intellij/psi/codeStyle/arrangement/AbstractRearrangerTest.java @@ -142,6 +142,10 @@ public abstract class AbstractRearrangerTest extends LightPlatformCodeInsightFix return new ArrangementAtomMatchCondition(token); } + protected static ArrangementAtomMatchCondition atom(@NotNull ArrangementSettingsToken token, boolean included) { + return new ArrangementAtomMatchCondition(token, included); + } + @NotNull protected static ArrangementAtomMatchCondition atom(@NotNull String nameFilter) { return new ArrangementAtomMatchCondition(StdArrangementTokens.Regexp.NAME, nameFilter);